/******/ (() => { // webpackBootstrap /******/ var __webpack_modules__ = ({ /***/ "./assets/src/js/admin/courses/generate-with-ai.js" /*!*********************************************************!*\ !*** ./assets/src/js/admin/courses/generate-with-ai.js ***! \*********************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CreateCourseViaAI: () => (/* binding */ CreateCourseViaAI) /* harmony export */ }); /* harmony import */ var lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lpAssetsJsPath/utils.js */ "./assets/src/js/utils.js"); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! sweetalert2 */ "./node_modules/sweetalert2/dist/sweetalert2.all.js"); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(sweetalert2__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! lpAssetsJsPath/lpToastify.js */ "./assets/src/js/lpToastify.js"); /** * Create course with AI */ let lp_structure_course; let lp_is_generating_course_data = false; const lp_course_ai_setting = JSON.parse(localStorage.getItem('lp_course_ai_setting')) || {}; class CreateCourseViaAI { constructor(options = {}) { this.options = { autoInsertButton: true, isCourseBuilder: false, redirectDelayMs: 2000, ...options }; this.init(); } static selectors = { elGenerateDataAiWrap: '.lp-generate-data-ai-wrap' }; init() { if (this.options.autoInsertButton) { if (!lpData?.enable_open_ai) { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady('.page-title-action', el => { el.insertAdjacentHTML('afterend', ``); }); } else { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady('.page-title-action', el => { el.insertAdjacentHTML('afterend', ``); }); } } this.events(); } events() { if (CreateCourseViaAI._loadedEvents) { return; } CreateCourseViaAI._loadedEvents = true; lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('click', [{ selector: '.lp-btn-warning-enable-ai', class: this, callBack: this.showPopupEnableAI.name }, { selector: '.lp-btn-generate-course-with-ai', class: this, callBack: this.showPopupCreateFullCourse.name }, { selector: '.lp-btn-step', class: this, callBack: this.showStep.name }, { selector: '.lp-btn-generate-prompt', class: this, callBack: this.generatePrompt.name }, { selector: '.lp-btn-call-open-ai', class: this, callBack: this.generateDataCourse.name }, { selector: '.lp-btn-create-course', class: this, callBack: this.createCourse.name }, { selector: '.lp-btn-close-ai-popup', //class: this, callBack: args => { const { e, target } = args; const message = lpData?.i18n?.confirm_close_ai || 'Are you sure you want to close? Generate data will stop.'; if (!lp_is_generating_course_data) { sweetalert2__WEBPACK_IMPORTED_MODULE_1___default().close(); } else if (confirm(message)) { sweetalert2__WEBPACK_IMPORTED_MODULE_1___default().close(); } // Testing custom confirm box /*if ( confirm( message ) ) { SweetAlert.close(); }*/ } }]); } // Show popup warning enable AI before using. showPopupEnableAI() { const modalTemplate = document.querySelector('#lp-tmpl-must-enable-ai'); if (!modalTemplate) { console.error('Enable OpenAI Modal Template not found!'); return; } sweetalert2__WEBPACK_IMPORTED_MODULE_1___default().fire({ html: modalTemplate.innerHTML, width: '420px', showCloseButton: false, showConfirmButton: false }); } showPopupCreateFullCourse() { const modalTemplate = document.querySelector('#lp-tmpl-create-course-ai'); if (!modalTemplate) { console.error('AI Create Full Course Modal Template not found!'); return; } sweetalert2__WEBPACK_IMPORTED_MODULE_1___default().fire({ html: modalTemplate.innerHTML, width: '60%', showCloseButton: false, showConfirmButton: false, allowOutsideClick: false, allowEscapeKey: false, didOpen: () => { const popup = sweetalert2__WEBPACK_IMPORTED_MODULE_1___default().getPopup(); popup.click(); const targetAudience = popup.querySelector('select[name="target_audience"]'); if (targetAudience && lp_course_ai_setting?.target_audience) { targetAudience.tomselect.setValue(lp_course_ai_setting.target_audience); } const tone = popup.querySelector('select[name="tone"]'); if (tone && lp_course_ai_setting?.tone) { tone.tomselect.setValue(lp_course_ai_setting.tone); } const language = popup.querySelector('select[name="language"]'); if (language && lp_course_ai_setting?.language) { language.tomselect.setValue(lp_course_ai_setting.language); } targetAudience.addEventListener('change', event => { lp_course_ai_setting.target_audience = targetAudience.tomselect.getValue(); localStorage.setItem('lp_course_ai_setting', JSON.stringify(lp_course_ai_setting)); }); tone.addEventListener('change', event => { lp_course_ai_setting.tone = tone.tomselect.getValue(); localStorage.setItem('lp_course_ai_setting', JSON.stringify(lp_course_ai_setting)); }); language.addEventListener('change', event => { const value = language.tomselect.getValue(); lp_course_ai_setting.language = value ? [value] : []; localStorage.setItem('lp_course_ai_setting', JSON.stringify(lp_course_ai_setting)); }); } }).then(result => { if (result.isDismissed) { if (lp_is_generating_course_data) { lp_is_generating_course_data = false; } } }); } showStep(args) { const { e, target } = args; e.preventDefault(); const elBtnActions = target.closest('.button-actions'); const elCreateCourseAIWrap = elBtnActions.closest(CreateCourseViaAI.selectors.elGenerateDataAiWrap); let step = parseInt(elBtnActions.dataset.step); const stepAction = target.dataset.action; if (stepAction === 'next') { step++; } else if (stepAction === 'prev') { step--; } elBtnActions.dataset.step = step; const elForm = target.closest('form'); const elContentStep = elForm.querySelector(`.step-content[data-step="${step}"]`); const elItemStep = elCreateCourseAIWrap.querySelector(`.step-item[data-step="${step}"]`); elForm.querySelectorAll('.step-content').forEach(el => el.classList.remove('active')); elContentStep.classList.add('active'); elCreateCourseAIWrap.querySelectorAll('.step-item').forEach(el => el.classList.remove('active')); elItemStep.classList.add('active'); // Get all buttons step to show/hide const form = target.closest('form'); const elBtnSteps = form.querySelectorAll('button[data-step-show]'); elBtnSteps.forEach(el => { const stepsShow = el.dataset.stepShow.split(',').map(s => parseInt(s.trim())); if (stepsShow.includes(step)) { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(el, 1); } else { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(el, 0); } }); } /** * Create prompt from data config * @param args */ generatePrompt(args) { const { e, target } = args; e.preventDefault(); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(target, true); // Get dataSend const form = target.closest('form'); let dataSend = JSON.parse(target.dataset.send); dataSend = lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.mergeDataWithDatForm(form, dataSend); // Ajax to generate prompt const callBack = { success: response => { const { message, status, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_2__.show(message, status); if (status === 'success') { const elBtnNext = form.querySelector('.lp-btn-step[data-action=next]'); elBtnNext.click(); const elPromptTextarea = form.querySelector('textarea[name=lp-openai-prompt-generated-field]'); elPromptTextarea.value = data; } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_2__.show(error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(target, false); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } /** * Submit prompt to OpenAI to generate course data * @param args */ generateDataCourse(args) { const { e, target } = args; e.preventDefault(); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(target, true); // Get dataSend const form = target.closest('form'); let dataSend = JSON.parse(target.dataset.send); dataSend = lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.mergeDataWithDatForm(form, dataSend); const btnPrev = form.querySelector('.lp-btn-step[data-action=prev]'); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(btnPrev, 0); // Ajax to generate prompt const callBack = { success: response => { const { message, status, data } = response; if (lp_is_generating_course_data) { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_2__.show(message, status); } if (status === 'success') { // Save structure data lp_structure_course = data.lp_structure_course; // Set preview HTML const elResults = form.querySelector('.lp-ai-generated-results'); elResults.innerHTML = data.lp_html_preview; const elBtnNext = form.querySelector('.lp-btn-step[data-action=next]'); elBtnNext.click(); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_2__.show(error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(target, false); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(btnPrev, 1); lp_is_generating_course_data = false; } }; lp_is_generating_course_data = true; window.lpAJAXG.fetchAJAX(dataSend, callBack); } /** * Create course with data of OpenAI * @param args */ createCourse(args) { const { e, target } = args; e.preventDefault(); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(target, true); // Get dataSend const dataSend = JSON.parse(target.dataset.send); dataSend.lp_structure_course = lp_structure_course; if (this.options.isCourseBuilder) { dataSend.is_course_builder = 1; } const form = target.closest('form'); const elBtnPrev = form.querySelector('.lp-btn-step[data-action=prev]'); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(elBtnPrev, 0); const windowWidth = window.outerWidth; let alertWidth; if (windowWidth < 768) { alertWidth = '90%'; } else { alertWidth = '30%'; } const creatingCourseAiModal = document.querySelector('#lp-tmpl-creating-course-ai'); sweetalert2__WEBPACK_IMPORTED_MODULE_1___default().fire({ html: creatingCourseAiModal.innerHTML, showCloseButton: false, showConfirmButton: false, allowOutsideClick: false, width: alertWidth }); // Ajax to generate prompt const callBack = { success: response => { const { message, status, data } = response; sweetalert2__WEBPACK_IMPORTED_MODULE_1___default().close(); lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_2__.show(message, status); if (status === 'success') { setTimeout(() => { window.location.href = data.edit_course_url; }, this.options.redirectDelayMs); } else { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(elBtnPrev, 1); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_2__.show(error, 'error'); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(elBtnPrev, 1); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(target, false); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } } /***/ }, /***/ "./assets/src/js/admin/edit-course/edit-curriculum.js" /*!************************************************************!*\ !*** ./assets/src/js/admin/edit-course/edit-curriculum.js ***! \************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ EditCourseCurriculum: () => (/* binding */ EditCourseCurriculum) /* harmony export */ }); /* harmony import */ var _edit_curriculum_edit_section_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./edit-curriculum/edit-section.js */ "./assets/src/js/admin/edit-course/edit-curriculum/edit-section.js"); /* harmony import */ var _edit_curriculum_edit_section_item_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./edit-curriculum/edit-section-item.js */ "./assets/src/js/admin/edit-course/edit-curriculum/edit-section-item.js"); /* harmony import */ var lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! lpAssetsJsPath/utils.js */ "./assets/src/js/utils.js"); /** * Edit Curriculum JS handler. * * @since 4.2.8.6 * @version 1.0.2 */ const sectionEdit = new _edit_curriculum_edit_section_js__WEBPACK_IMPORTED_MODULE_0__.EditSection(); const sectionItemEdit = new _edit_curriculum_edit_section_item_js__WEBPACK_IMPORTED_MODULE_1__.EditSectionItem(); class EditCourseCurriculum { constructor() { this.init(); } static selectors = { idElEditCurriculum: '#lp-course-edit-curriculum', elCurriculumSections: '.curriculum-sections', elToggleAllSections: '.course-toggle-all-sections', LPTarget: '.lp-target', elCollapse: 'lp-collapse' }; init() { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.lpOnElementReady(`${EditCourseCurriculum.selectors.idElEditCurriculum}`, elEditCurriculum => { // Set variables use for section edit sectionEdit.init(); // Set variables use for edit section item sectionItemEdit.init(); }); } } /***/ }, /***/ "./assets/src/js/admin/edit-course/edit-curriculum/edit-curriculum-ai.js" /*!*******************************************************************************!*\ !*** ./assets/src/js/admin/edit-course/edit-curriculum/edit-curriculum-ai.js ***! \*******************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ EditCurriculumAi: () => (/* binding */ EditCurriculumAi) /* harmony export */ }); /* harmony import */ var lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lpAssetsJsPath/utils.js */ "./assets/src/js/utils.js"); /* harmony import */ var lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! lpAssetsJsPath/lpToastify.js */ "./assets/src/js/lpToastify.js"); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! sweetalert2 */ "./node_modules/sweetalert2/dist/sweetalert2.all.js"); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(sweetalert2__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _edit_section_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./edit-section.js */ "./assets/src/js/admin/edit-course/edit-curriculum/edit-section.js"); /* harmony import */ var _edit_section_item_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./edit-section-item.js */ "./assets/src/js/admin/edit-course/edit-curriculum/edit-section-item.js"); /* harmony import */ var lpAssetsJsPath_admin_edit_course_edit_curriculum_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! lpAssetsJsPath/admin/edit-course/edit-curriculum.js */ "./assets/src/js/admin/edit-course/edit-curriculum.js"); /** * Generate data with OpenAI */ let editSection = null; let editSectionItem = null; class EditCurriculumAi { constructor(options = {}) { this.options = { isCourseBuilder: false, ...options }; this.init(); } static selectors = { elBtnApplyCurriculum: '.lp-btn-apply-curriculum' }; init() { if (!lpData?.enable_open_ai) { return; } if (this.options.isCourseBuilder) { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady(lpAssetsJsPath_admin_edit_course_edit_curriculum_js__WEBPACK_IMPORTED_MODULE_5__.EditCourseCurriculum.selectors.idElEditCurriculum, el => { const elCountSections = el.querySelector(_edit_section_js__WEBPACK_IMPORTED_MODULE_3__.EditSection.selectors.elCountSections); elCountSections.insertAdjacentHTML('beforebegin', ``); }); } else { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady(lpAssetsJsPath_admin_edit_course_edit_curriculum_js__WEBPACK_IMPORTED_MODULE_5__.EditCourseCurriculum.selectors.idElEditCurriculum, el => { const elCountSections = el.querySelector(_edit_section_js__WEBPACK_IMPORTED_MODULE_3__.EditSection.selectors.elCountSections); elCountSections.insertAdjacentHTML('afterend', ``); }); } this.events(); } events() { if (EditCurriculumAi._loadedEvents) { return; } EditCurriculumAi._loadedEvents = true; lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('click', [{ selector: EditCurriculumAi.selectors.elBtnApplyCurriculum, class: this, callBack: this.applyData.name }]); } async applyData(args) { const { e, target } = args; let dataSend = JSON.parse(target.dataset.send); dataSend = lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.mergeDataWithDatForm(target.closest('form'), dataSend); if (!dataSend['lp-openai-generated-data']) { return; } const data = JSON.parse(dataSend['lp-openai-generated-data']); //console.log( 'Generated Data:', data ); const sections = data[0].sections; if (!sections || sections.length === 0) { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show('No sections found in the generated data.', 'error'); } // console.log( 'Generated Sections:', sections ); sweetalert2__WEBPACK_IMPORTED_MODULE_2___default().close(); // Wait half second to ensure SweetAlert is closed completely await new Promise(resolve => setTimeout(resolve, 500)); // New edit section instance editSection = new _edit_section_js__WEBPACK_IMPORTED_MODULE_3__.EditSection(); editSection.init(); // New edit section item instance editSectionItem = new _edit_section_item_js__WEBPACK_IMPORTED_MODULE_4__.EditSectionItem(); editSectionItem.init(); // Scroll to element add section const elEditCurriculum = document.querySelector(lpAssetsJsPath_admin_edit_course_edit_curriculum_js__WEBPACK_IMPORTED_MODULE_5__.EditCourseCurriculum.selectors.idElEditCurriculum); const elDivAddNewSection = elEditCurriculum.querySelector(_edit_section_js__WEBPACK_IMPORTED_MODULE_3__.EditSection.selectors.elDivAddNewSection); elDivAddNewSection.scrollIntoView({ behavior: 'smooth', block: 'center' }); // Wait 800ms to ensure scroll completely await new Promise(resolve => setTimeout(resolve, 800)); for (const sectionData of sections) { // Set title const elSectionTitleNewInput = elEditCurriculum.querySelector(_edit_section_js__WEBPACK_IMPORTED_MODULE_3__.EditSection.selectors.elSectionTitleNewInput); const elBtnAddSection = elEditCurriculum.querySelector(_edit_section_js__WEBPACK_IMPORTED_MODULE_3__.EditSection.selectors.elBtnAddSection); elSectionTitleNewInput.value = sectionData.section_title || ''; await new Promise(resolve => { editSection.addSection({ e: new PointerEvent('click'), target: elBtnAddSection, callBackNest: this.updateSectionDescription({ sectionData, elEditCurriculum }), resolve }); }); } } /** * Update section description after create new section * @param args */ updateSectionDescription(args) { const { sectionData, elEditCurriculum } = args; return { success: async args => { const { elSection } = args; await new Promise(resolve => setTimeout(resolve, 1000)); // Set description for the new section const elSectionDesInput = elSection.querySelector(_edit_section_js__WEBPACK_IMPORTED_MODULE_3__.EditSection.selectors.elSectionDesInput); elSectionDesInput.value = sectionData.section_description || ''; // Call AJAX to save description await new Promise(resolve => { editSection.updateSectionDescription({ e: new PointerEvent('click'), target: elSectionDesInput, callBackNest: this.addSectionItems({ sectionData, elEditCurriculum }), resolve }); }); setTimeout(args.resolve, 1); }, error: error => {}, completed: () => {} }; } addSectionItems(args) { const { sectionData, elEditCurriculum } = args; const lessons = sectionData.lessons || []; const quizzes = sectionData.quizzes || []; return { success: async args => { //await new Promise( ( resolve ) => setTimeout( resolve, 1000 ) ); const { elSection } = args; const elBtnSelectItemTypeLesson = elSection.querySelector(`${_edit_section_item_js__WEBPACK_IMPORTED_MODULE_4__.EditSectionItem.selectors.elBtnSelectItemType}[data-item-type=lp_lesson]`); const elBtnSelectItemTypeQuiz = elSection.querySelector(`${_edit_section_item_js__WEBPACK_IMPORTED_MODULE_4__.EditSectionItem.selectors.elBtnSelectItemType}[data-item-type=lp_quiz]`); for (const itemData of lessons) { elBtnSelectItemTypeLesson.click(); await this.addItemToSection({ itemData, elSection, elEditCurriculum }); } for (const itemData of quizzes) { elBtnSelectItemTypeQuiz.click(); await this.addItemToSection({ itemData, elSection, elEditCurriculum }); } setTimeout(args.resolve, 1); }, error: error => {}, completed: () => {} }; } async addItemToSection(args) { const { itemData, elSection, elEditCurriculum } = args; const elBtnAddItem = elSection.querySelector(_edit_section_item_js__WEBPACK_IMPORTED_MODULE_4__.EditSectionItem.selectors.elBtnAddItem); const elAddItemTypeTitleInput = elSection.querySelector(_edit_section_item_js__WEBPACK_IMPORTED_MODULE_4__.EditSectionItem.selectors.elAddItemTypeTitleInput); elAddItemTypeTitleInput.value = itemData.lesson_title || itemData.quiz_title || ''; // Scroll to element add item elBtnAddItem.scrollIntoView({ behavior: 'smooth', block: 'center' }); // Call AJAX to add item to section await new Promise(resolve => { editSectionItem.addItemToSection({ e: new PointerEvent('click'), target: elBtnAddItem, resolve, callBackNest: { completed: async args => { setTimeout(resolve, 1000); } } }); }); setTimeout(args.resolve, 1); } } /***/ }, /***/ "./assets/src/js/admin/edit-course/edit-curriculum/edit-section-item.js" /*!******************************************************************************!*\ !*** ./assets/src/js/admin/edit-course/edit-curriculum/edit-section-item.js ***! \******************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ EditSectionItem: () => (/* binding */ EditSectionItem) /* harmony export */ }); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! sweetalert2 */ "./node_modules/sweetalert2/dist/sweetalert2.all.js"); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(sweetalert2__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var sortablejs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! sortablejs */ "./node_modules/sortablejs/modular/sortable.esm.js"); /* harmony import */ var lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! lpAssetsJsPath/utils.js */ "./assets/src/js/utils.js"); /* harmony import */ var lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! lpAssetsJsPath/lpToastify.js */ "./assets/src/js/lpToastify.js"); /* harmony import */ var _edit_curriculum_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../edit-curriculum.js */ "./assets/src/js/admin/edit-course/edit-curriculum.js"); /* harmony import */ var _edit_section_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./edit-section.js */ "./assets/src/js/admin/edit-course/edit-curriculum/edit-section.js"); /* harmony import */ var lpAssetsJsPath_lpPopupSelectItemToAdd_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! lpAssetsJsPath/lpPopupSelectItemToAdd.js */ "./assets/src/js/lpPopupSelectItemToAdd.js"); /** * Edit Section item Script on Curriculum * * @version 1.0.3 * @since 4.2.8.6 */ const idUrlHandle = 'edit-course-curriculum'; const lpPopupSelectItemToAdd = new lpAssetsJsPath_lpPopupSelectItemToAdd_js__WEBPACK_IMPORTED_MODULE_6__.LpPopupSelectItemToAdd(); class EditSectionItem { constructor() { this.courseId = null; this.elCurriculumSections = null; this.sectionIdSelected = null; } static selectors = { elSectionListItems: '.section-list-items', elItemClone: '.section-item.clone', elSectionItem: '.section-item', elBtnSelectItemType: '.lp-btn-select-item-type', elAddItemTypeClone: '.lp-add-item-type.clone', elSectionActions: '.section-actions', elAddItemType: '.lp-add-item-type', elAddItemTypeTitleInput: '.lp-add-item-type-title-input', elBtnAddItemCancel: '.lp-btn-add-item-cancel', elBtnAddItem: '.lp-btn-add-item', elItemTitleInput: '.lp-item-title-input', elBtnUpdateItemTitle: '.lp-btn-update-item-title', elBtnCancelUpdateTitle: '.lp-btn-cancel-update-item-title', elBtnDeleteItem: '.lp-btn-delete-item', elBtnSetPreviewItem: '.lp-btn-set-preview-item' }; init() { this.elEditCurriculum = document.querySelector(`${_edit_curriculum_js__WEBPACK_IMPORTED_MODULE_4__.EditCourseCurriculum.selectors.idElEditCurriculum}`); this.elCurriculumSections = this.elEditCurriculum.querySelector(`${_edit_curriculum_js__WEBPACK_IMPORTED_MODULE_4__.EditCourseCurriculum.selectors.elCurriculumSections}`); const elLPTarget = this.elEditCurriculum.closest(`${_edit_curriculum_js__WEBPACK_IMPORTED_MODULE_4__.EditCourseCurriculum.selectors.LPTarget}`); const dataSend = window.lpAJAXG.getDataSetCurrent(elLPTarget); this.courseId = dataSend.args.course_id; this.events(); this.sortAbleItem(); lpPopupSelectItemToAdd.init(); } /* Events */ events() { // Check and attach events only once if (EditSectionItem._loadedEvents) { return; } EditSectionItem._loadedEvents = this; // Click events lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.eventHandlers('click', [{ selector: EditSectionItem.selectors.elBtnSelectItemType, class: this, callBack: this.addItemType.name }, { selector: EditSectionItem.selectors.elBtnAddItem, class: this, callBack: this.addItemToSection.name }, { selector: EditSectionItem.selectors.elBtnAddItemCancel, class: this, callBack: this.cancelAddItemType.name }, { selector: EditSectionItem.selectors.elBtnUpdateItemTitle, class: this, callBack: this.updateTitle.name }, { selector: EditSectionItem.selectors.elBtnCancelUpdateTitle, class: this, callBack: this.cancelUpdateTitle.name }, { selector: EditSectionItem.selectors.elBtnDeleteItem, class: this, callBack: this.deleteItem.name }, { selector: lpAssetsJsPath_lpPopupSelectItemToAdd_js__WEBPACK_IMPORTED_MODULE_6__.LpPopupSelectItemToAdd.selectors.elBtnShowPopupItemsToSelect, class: this, callBack: this.handleShowPopupItemsToSelect.name }, { selector: lpAssetsJsPath_lpPopupSelectItemToAdd_js__WEBPACK_IMPORTED_MODULE_6__.LpPopupSelectItemToAdd.selectors.elBtnAddItemsSelected, class: lpPopupSelectItemToAdd, callBack: lpPopupSelectItemToAdd.addItemsSelectedToSection.name, callBackHandle: this.addItemsSelectedToSection.bind(this) }, { selector: EditSectionItem.selectors.elBtnSetPreviewItem, class: this, callBack: this.updatePreviewItem.name }]); // Keyup events lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.eventHandlers('keyup', [{ selector: EditSectionItem.selectors.elItemTitleInput, class: this, callBack: this.changeTitle.name }, { selector: EditSectionItem.selectors.elAddItemTypeTitleInput, class: this, callBack: this.changeTitleAddNew.name }]); // Keydown events lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.eventHandlers('keydown', [{ selector: EditSectionItem.selectors.elAddItemTypeTitleInput, class: this, callBack: this.addItemToSection.name, checkIsEventEnter: true }, { selector: EditSectionItem.selectors.elItemTitleInput, class: this, callBack: this.updateTitle.name, checkIsEventEnter: true }]); // Focusin events lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.eventHandlers('focusin', [{ selector: EditSectionItem.selectors.elItemTitleInput, class: this, callBack: this.focusTitleInput.name }]); // Focusout events lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.eventHandlers('focusout', [{ selector: EditSectionItem.selectors.elItemTitleInput, class: this, callBack: this.focusTitleInput.name, focusIn: false }]); } /* Handle show popup items to select - set sectionIdSelected */ handleShowPopupItemsToSelect(args) { const { e, target } = args; const elQuizWrap = target.closest('.lp-edit-quiz-wrap'); if (elQuizWrap) { this.sectionIdSelected = null; return; } const elSection = target.closest(_edit_section_js__WEBPACK_IMPORTED_MODULE_5__.EditSection.selectors.elSection); const elEditCurriculum = target.closest('#lp-course-edit-curriculum') || target.closest('.lp-edit-curriculum-wrap'); if (elSection && elEditCurriculum) { this.sectionIdSelected = elSection.dataset.sectionId; } else { this.sectionIdSelected = null; } } /* Add item type */ addItemType(args) { const { e, target } = args; const elBtnSelectItemType = target; const itemType = elBtnSelectItemType.dataset.itemType; const itemPlaceholder = elBtnSelectItemType.dataset.placeholder; const itemBtnAddText = elBtnSelectItemType.dataset.buttonAddText; const elSection = elBtnSelectItemType.closest(`${_edit_section_js__WEBPACK_IMPORTED_MODULE_5__.EditSection.selectors.elSection}`); const elSectionActions = elSection.querySelector(`${EditSectionItem.selectors.elSectionActions}`); // Insert input item type to add const elAddItemTypeClone = elSectionActions.querySelector(`${EditSectionItem.selectors.elAddItemTypeClone}`); const elNewItemByType = elAddItemTypeClone.cloneNode(true); const elAddItemTypeInput = elNewItemByType.querySelector(`${EditSectionItem.selectors.elAddItemTypeTitleInput}`); const elBtnAddItem = elNewItemByType.querySelector(`${EditSectionItem.selectors.elBtnAddItem}`); elNewItemByType.classList.remove('clone'); elNewItemByType.classList.add(itemType); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.lpShowHideEl(elNewItemByType, 1); elAddItemTypeInput.setAttribute('placeholder', itemPlaceholder); elAddItemTypeInput.dataset.itemType = itemType; elBtnAddItem.textContent = itemBtnAddText; elSectionActions.insertAdjacentElement('beforebegin', elNewItemByType); elAddItemTypeInput.focus(); } /* Cancel add item type */ cancelAddItemType(args) { const { e, target } = args; const elAddItemType = target.closest(`${EditSectionItem.selectors.elAddItemType}`); if (elAddItemType) { elAddItemType.remove(); } } /* Add item to section */ addItemToSection(args) { const { e, target, callBackNest } = args; e.preventDefault(); const elAddItemType = target.closest(`${EditSectionItem.selectors.elAddItemType}`); const elSection = elAddItemType.closest(`${_edit_section_js__WEBPACK_IMPORTED_MODULE_5__.EditSection.selectors.elSection}`); const sectionId = elSection.dataset.sectionId; const elAddItemTypeTitleInput = elAddItemType.querySelector(`${EditSectionItem.selectors.elAddItemTypeTitleInput}`); const titleValue = elAddItemTypeTitleInput.value.trim(); const typeValue = elAddItemTypeTitleInput.dataset.itemType; const message = elAddItemTypeTitleInput.dataset.messEmptyTitle; if (titleValue.length === 0) { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_3__.show(message, 'error'); return; } // Clone new section item const elItemClone = elSection.querySelector(`${EditSectionItem.selectors.elItemClone}`); const elItemNew = elItemClone.cloneNode(true); const elItemTitleInput = elItemNew.querySelector(`${EditSectionItem.selectors.elItemTitleInput}`); elItemNew.classList.remove('clone'); elItemNew.classList.add(typeValue); elItemNew.dataset.itemType = typeValue; lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.lpShowHideEl(elItemNew, 1); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.lpSetLoadingEl(elItemNew, 1); elItemTitleInput.value = titleValue; elItemTitleInput.dataset.old = titleValue; elItemClone.insertAdjacentElement('beforebegin', elItemNew); elAddItemType.remove(); // Call ajax to add item to section const callBack = { success: response => { const { message, status, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_3__.show(message, status); if (status === 'error') { elItemNew.remove(); } else if (status === 'success') { const { section_item, item_link } = data || {}; const itemId = section_item.item_id || 0; elItemNew.dataset.itemId = itemId; elItemNew.querySelector('.edit-link').setAttribute('href', item_link || ''); // Add popup attributes for Course Builder context this.addPopupAttributesToItem(elItemNew, itemId, typeValue); // Call callback nest if exists if (callBackNest && typeof callBackNest.success === 'function') { args.elItemNew = elItemNew; callBackNest.success(args); } } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_3__.show(error, 'error'); elItemNew.remove(); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.lpSetLoadingEl(elItemNew, 0); this.updateCountItems(elSection); // Call callback nest if exists if (callBackNest && typeof callBackNest.completed === 'function') { args.elItemNew = elItemNew; callBackNest.completed(args); } } }; const dataSend = { course_id: this.courseId, action: 'create_item_add_to_section', section_id: sectionId, item_title: titleValue, item_type: typeValue, args: { id_url: idUrlHandle } }; if (document.querySelector('#lp-course-builder')) { dataSend.is_course_builder = 1; } window.lpAJAXG.fetchAJAX(dataSend, callBack); } /* Typing in title input */ changeTitle(args) { const { target } = args; const elItemTitleInput = target.closest(`${EditSectionItem.selectors.elItemTitleInput}`); if (!elItemTitleInput) { return; } const elSectionItem = elItemTitleInput.closest(`${EditSectionItem.selectors.elSectionItem}`); if (!elSectionItem) { return; } const titleValue = elItemTitleInput.value.trim(); const titleValueOld = elItemTitleInput.dataset.old || ''; if (titleValue === titleValueOld) { elSectionItem.classList.remove('editing'); } else { elSectionItem.classList.add('editing'); } } /* Focus in item title input */ focusTitleInput(args) { const { target, focusIn = true } = args; const elItemTitleInput = target.closest(`${EditSectionItem.selectors.elItemTitleInput}`); if (!elItemTitleInput) { return; } const elSectionItem = elItemTitleInput.closest(`${EditSectionItem.selectors.elSectionItem}`); if (!elSectionItem) { return; } if (focusIn) { elSectionItem.classList.add('focus'); } else { elSectionItem.classList.remove('focus'); } } changeTitleAddNew(args) { const { target } = args; const elAddItemTypeTitleInput = target.closest(`${EditSectionItem.selectors.elAddItemTypeTitleInput}`); if (!elAddItemTypeTitleInput) { return; } const elAddItemType = elAddItemTypeTitleInput.closest(`${EditSectionItem.selectors.elAddItemType}`); if (!elAddItemType) { return; } const elBtnAddItem = elAddItemType.querySelector(`${EditSectionItem.selectors.elBtnAddItem}`); if (!elBtnAddItem) { return; } const titleValue = elAddItemTypeTitleInput.value.trim(); if (titleValue.length === 0) { elBtnAddItem.classList.remove('active'); } else { elBtnAddItem.classList.add('active'); } } /* Update item title */ updateTitle(args) { const { e, target } = args; e.preventDefault(); const elSectionItem = target.closest(`${EditSectionItem.selectors.elSectionItem}`); if (!elSectionItem) { return; } const elSection = elSectionItem.closest(`${_edit_section_js__WEBPACK_IMPORTED_MODULE_5__.EditSection.selectors.elSection}`); if (!elSection) { return; } const elItemTitleInput = elSectionItem.querySelector(`${EditSectionItem.selectors.elItemTitleInput}`); if (!elItemTitleInput) { return; } const itemId = elSectionItem.dataset.itemId; const itemType = elSectionItem.dataset.itemType; const itemTitleValue = elItemTitleInput.value.trim(); const titleOld = elItemTitleInput.dataset.old; const message = elItemTitleInput.dataset.messEmptyTitle; if (itemTitleValue.length === 0) { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_3__.show(message, 'error'); return; } if (itemTitleValue === titleOld) { return; } // Un-focus input item title elItemTitleInput.blur(); // show loading lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.lpSetLoadingEl(elSectionItem, 1); // Call ajax to update item title const callBack = { success: response => { const { message, status } = response; if (status === 'success') { elItemTitleInput.dataset.old = itemTitleValue; } else { elItemTitleInput.value = titleOld; } lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_3__.show(message, status); }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_3__.show(error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.lpSetLoadingEl(elSectionItem, 0); elSectionItem.classList.remove('editing'); } }; const dataSend = { course_id: this.courseId, action: 'update_item_of_section', section_id: elSection.dataset.sectionId, item_id: itemId, item_type: itemType, item_title: itemTitleValue, args: { id_url: idUrlHandle } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } /* Cancel update item title */ cancelUpdateTitle(args) { const { e, target } = args; const elBtnCancelUpdateTitle = target.closest(`${EditSectionItem.selectors.elBtnCancelUpdateTitle}`); if (!elBtnCancelUpdateTitle) { return; } const elSectionItem = elBtnCancelUpdateTitle.closest(`${EditSectionItem.selectors.elSectionItem}`); const elItemTitleInput = elSectionItem.querySelector(`${EditSectionItem.selectors.elItemTitleInput}`); elItemTitleInput.value = elItemTitleInput.dataset.old || ''; elSectionItem.classList.remove('editing'); } /* Delete item from section */ deleteItem(args) { const { e, target } = args; const elBtnDeleteItem = target.closest(`${EditSectionItem.selectors.elBtnDeleteItem}`); if (!elBtnDeleteItem) { return; } const elSectionItem = elBtnDeleteItem.closest(`${EditSectionItem.selectors.elSectionItem}`); if (!elSectionItem) { return; } const itemId = elSectionItem.dataset.itemId; const elSection = elSectionItem.closest(`${_edit_section_js__WEBPACK_IMPORTED_MODULE_5__.EditSection.selectors.elSection}`); const sectionId = elSection.dataset.sectionId; sweetalert2__WEBPACK_IMPORTED_MODULE_0___default().fire({ title: elBtnDeleteItem.dataset.title, text: elBtnDeleteItem.dataset.content, icon: 'warning', showCloseButton: true, showCancelButton: true, cancelButtonText: lpData.i18n.cancel, confirmButtonText: lpData.i18n.yes, reverseButtons: true }).then(result => { if (result.isConfirmed) { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.lpSetLoadingEl(elSectionItem, 1); // Call ajax to delete item from section const callBack = { success: response => { const { message, status } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_3__.show(message, status); if (status === 'success') { elSectionItem.remove(); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_3__.show(error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.lpSetLoadingEl(elSectionItem, 0); this.updateCountItems(elSection); } }; const dataSend = { course_id: this.courseId, action: 'delete_item_from_section', section_id: sectionId, item_id: itemId, args: { id_url: idUrlHandle } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } }); } /* Sortable items, can drop on multiple sections */ sortAbleItem() { const elSectionListItems = this.elCurriculumSections.querySelectorAll(`${EditSectionItem.selectors.elSectionListItems}`); let itemIdChoose = 0; let elSectionChoose; let sectionIdChoose = 0; let sectionIdEnd = 0; let timeout; elSectionListItems.forEach(elItem => { new sortablejs__WEBPACK_IMPORTED_MODULE_1__["default"](elItem, { handle: '.drag', animation: 150, group: { name: 'shared' }, onEnd: evt => { const dataSectionsItems = []; const elItemDragged = evt.item; sectionIdEnd = elItemDragged.closest(`${_edit_section_js__WEBPACK_IMPORTED_MODULE_5__.EditSection.selectors.elSection}`).dataset.sectionId; const dataSend = { course_id: this.courseId, args: { id_url: idUrlHandle } }; dataSend.action = 'update_item_section_and_position'; dataSend.item_id_change = itemIdChoose; dataSend.section_id_new_of_item = sectionIdEnd; dataSend.section_id_old_of_item = sectionIdChoose; // Send list items position const section = this.elCurriculumSections.querySelector(`.section[data-section-id="${sectionIdEnd}"]`); const items = section.querySelectorAll(`${EditSectionItem.selectors.elSectionItem}`); items.forEach(elItem => { const itemId = parseInt(elItem.dataset.itemId || 0); if (itemId === 0) { return; } dataSectionsItems.push(itemId); }); dataSend.items_position = dataSectionsItems; // Call ajax to update items position const callBack = { success: response => { const { message, status } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_3__.show(message, status); }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_3__.show(error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.lpSetLoadingEl(elItemDragged, 0); this.updateCountItems(section); if (sectionIdChoose !== sectionIdEnd) { this.updateCountItems(elSectionChoose); } } }; lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.lpSetLoadingEl(elItemDragged, 1); window.lpAJAXG.fetchAJAX(dataSend, callBack); }, onMove: (/*evt*/) => {}, onChoose: evt => { const elChooseItem = evt.item; itemIdChoose = elChooseItem.dataset.itemId; elSectionChoose = elChooseItem.closest(`${_edit_section_js__WEBPACK_IMPORTED_MODULE_5__.EditSection.selectors.elSection}`); sectionIdChoose = elSectionChoose.dataset.sectionId; }, onUpdate: (/*evt*/) => {} }); }); } /* Add items selected to section */ addItemsSelectedToSection(itemsSelectedData) { // Skip if not in curriculum context (e.g., quiz popup) if (!this.sectionIdSelected) { return; } const elSection = document.querySelector(`.section[data-section-id="${this.sectionIdSelected}"]`); // Skip if section element not found if (!elSection) { return; } const elItemClone = elSection.querySelector(`${EditSectionItem.selectors.elItemClone}`); // Check if we're in Course Builder context const isCourseBuilder = document.querySelector('#lp-course-builder') !== null; itemsSelectedData.forEach(item => { const elItemNew = elItemClone.cloneNode(true); const elInputTitleNew = elItemNew.querySelector(`${EditSectionItem.selectors.elItemTitleInput}`); elItemNew.dataset.itemId = item.id; elItemNew.classList.add(item.type); elItemNew.classList.remove('clone'); elItemNew.dataset.itemType = item.type; elItemNew.querySelector('.edit-link').setAttribute('href', item.editLink || ''); elInputTitleNew.value = item.titleSelected || ''; lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.lpSetLoadingEl(elItemNew, 1); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.lpShowHideEl(elItemNew, 1); elItemClone.insertAdjacentElement('beforebegin', elItemNew); }); sweetalert2__WEBPACK_IMPORTED_MODULE_0___default().close(); const dataSend = { course_id: this.courseId, action: 'add_items_to_section', section_id: this.sectionIdSelected, items: itemsSelectedData, is_course_builder: isCourseBuilder ? 1 : 0, args: { id_url: idUrlHandle } }; window.lpAJAXG.fetchAJAX(dataSend, { success: response => { const { message, status, data } = response; const { html } = data || ''; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_3__.show(message, status); itemsSelectedData.forEach(item => { const elItemAdded = elSection.querySelector(`${EditSectionItem.selectors.elSectionItem}[data-item-id="${item.id}"]`); if (elItemAdded) { elItemAdded.remove(); } }); if (status === 'success' && html) { // Server returns HTML with popup attributes already included when is_course_builder=1 elItemClone.insertAdjacentHTML('beforebegin', html); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_3__.show(error, 'error'); }, completed: () => { this.updateCountItems(elSection); } }); } /* Enable/disable preview item */ updatePreviewItem(args) { const { e, target } = args; const elBtnSetPreviewItem = target.closest(`${EditSectionItem.selectors.elBtnSetPreviewItem}`); if (!elBtnSetPreviewItem) { return; } const elSectionItem = elBtnSetPreviewItem.closest(`${EditSectionItem.selectors.elSectionItem}`); if (!elSectionItem) { return; } const icon = elBtnSetPreviewItem.querySelector('a'); icon.classList.toggle('lp-icon-eye'); icon.classList.toggle('lp-icon-eye-slash'); const enablePreview = !icon.classList.contains('lp-icon-eye-slash'); const itemId = elSectionItem.dataset.itemId; const itemType = elSectionItem.dataset.itemType; lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.lpSetLoadingEl(elSectionItem, 1); // Call ajax to update item preview const callBack = { success: response => { const { message, status } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_3__.show(message, status); if (status === 'error') { icon.classList.toggle('lp-icon-eye'); icon.classList.toggle('lp-icon-eye-slash'); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_3__.show(error, 'error'); icon.classList.toggle('lp-icon-eye'); icon.classList.toggle('lp-icon-eye-slash'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.lpSetLoadingEl(elSectionItem, 0); } }; const dataSend = { course_id: this.courseId, action: 'update_item_preview', item_id: itemId, item_type: itemType, enable_preview: enablePreview ? 1 : 0, args: { id_url: idUrlHandle } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } /* Update count items when item add/delete or section delete */ updateCountItems(elSection) { const elEditCurriculum = this.elEditCurriculum; const elCountItemsAll = elEditCurriculum.querySelector('.total-items'); const elItemsAll = elEditCurriculum.querySelectorAll(`${EditSectionItem.selectors.elSectionItem}:not(.clone)`); const itemsAllCount = elItemsAll.length; elCountItemsAll.dataset.count = itemsAllCount; elCountItemsAll.querySelector('.count').textContent = itemsAllCount; // Count items in section const elSectionItemsCount = elSection.querySelector('.section-items-counts'); const elItems = elSection.querySelectorAll(`${EditSectionItem.selectors.elSectionItem}:not(.clone)`); const itemsCount = elItems.length; elSectionItemsCount.dataset.count = itemsCount; elSectionItemsCount.querySelector('.count').textContent = itemsCount; } /** * Add popup attributes to item element for Course Builder context. * Only applies when in Course Builder (not admin edit course page). * * @param {HTMLElement} elItem - The item element * @param {number} itemId - The item ID * @param {string} itemType - The item type (lp_lesson, lp_quiz, lp_assignment) */ addPopupAttributesToItem(elItem, itemId, itemType) { // Check if we're in Course Builder context const isCourseBuilder = document.querySelector('#lp-course-builder') !== null; if (!isCourseBuilder || !itemId) { return; } const popupType = itemType.replace(/^lp_/, ''); const templateSelector = `#lp-tmpl-builder-popup-curriculum-${popupType}-course-${this.courseId}`; if (!popupType || !document.querySelector(templateSelector)) { return; } // Find the edit link element - it's an with class 'edit-link' inside .item-actions const editLink = elItem.querySelector('.item-actions .edit-link'); if (!editLink) { return; } // Get the parent
  • element of the edit link const editBtn = editLink.closest('li'); if (!editBtn) { return; } // Add popup data attributes based on item type if (itemType === 'lp_lesson') { editBtn.setAttribute('data-popup-lesson', itemId); } else if (itemType === 'lp_quiz') { editBtn.setAttribute('data-popup-quiz', itemId); } // Add popup class to the
  • element editBtn.classList.add('lp-btn-edit-item-popup'); // Update edit link: remove target="_blank" and update classes for popup behavior editLink.removeAttribute('target'); editLink.removeAttribute('href'); editLink.classList.add('edit-popup-link'); // Store additional data for popup on the
  • element editBtn.setAttribute('data-course-id', this.courseId); editBtn.setAttribute('data-popup-type', popupType); editBtn.setAttribute('data-popup-id', itemId); editBtn.setAttribute('data-template', templateSelector); } } /***/ }, /***/ "./assets/src/js/admin/edit-course/edit-curriculum/edit-section.js" /*!*************************************************************************!*\ !*** ./assets/src/js/admin/edit-course/edit-curriculum/edit-section.js ***! \*************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ EditSection: () => (/* binding */ EditSection) /* harmony export */ }); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! sweetalert2 */ "./node_modules/sweetalert2/dist/sweetalert2.all.js"); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(sweetalert2__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var sortablejs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! sortablejs */ "./node_modules/sortablejs/modular/sortable.esm.js"); /* harmony import */ var lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! lpAssetsJsPath/utils.js */ "./assets/src/js/utils.js"); /* harmony import */ var lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! lpAssetsJsPath/lpToastify.js */ "./assets/src/js/lpToastify.js"); /* harmony import */ var _edit_section_item_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./edit-section-item.js */ "./assets/src/js/admin/edit-course/edit-curriculum/edit-section-item.js"); /* harmony import */ var _edit_curriculum_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../edit-curriculum.js */ "./assets/src/js/admin/edit-course/edit-curriculum.js"); /** * Edit Section Script on Curriculum * * @since 4.2.8.6 * @version 1.0.3 */ class EditSection { constructor() { this.courseId = null; this.elEditCurriculum = null; this.elCurriculumSections = null; this.editSectionItem = new _edit_section_item_js__WEBPACK_IMPORTED_MODULE_4__.EditSectionItem(); } static selectors = { elSection: '.section', elDivAddNewSection: '.add-new-section', elSectionClone: '.section.clone', elSectionTitleNewInput: '.lp-section-title-new-input', elSectionTitleInput: '.lp-section-title-input', etBtnEditTitle: '.lp-btn-edit-section-title', elSectionDesInput: '.lp-section-description-input', elBtnAddSection: '.lp-btn-add-section', elBtnUpdateTitle: '.lp-btn-update-section-title', elBtnUpdateDes: '.lp-btn-update-section-description', elBtnCancelUpdateTitle: '.lp-btn-cancel-update-section-title', elBtnCancelUpdateDes: '.lp-btn-cancel-update-section-description', elBtnDeleteSection: '.lp-btn-delete-section', elSectionDesc: '.section-description', elSectionToggle: '.section-toggle', elCountSections: '.count-sections' }; init() { this.elEditCurriculum = document.querySelector(`${_edit_curriculum_js__WEBPACK_IMPORTED_MODULE_5__.EditCourseCurriculum.selectors.idElEditCurriculum}`); this.elCurriculumSections = this.elEditCurriculum.querySelector(`${_edit_curriculum_js__WEBPACK_IMPORTED_MODULE_5__.EditCourseCurriculum.selectors.elCurriculumSections}`); const elLPTarget = this.elEditCurriculum.closest(`${_edit_curriculum_js__WEBPACK_IMPORTED_MODULE_5__.EditCourseCurriculum.selectors.LPTarget}`); const dataSend = window.lpAJAXG.getDataSetCurrent(elLPTarget); this.courseId = dataSend.args.course_id; this.editSectionItem.init(); this.events(); this.sortAbleSection(); } events() { // Check and attach events only once if (EditSection._loadedEvents) { return; } EditSection._loadedEvents = this; // Click events lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.eventHandlers('click', [{ selector: EditSection.selectors.elBtnAddSection, class: this, callBack: this.addSection.name }, { selector: `${EditSection.selectors.elBtnUpdateDes}`, class: this, callBack: this.updateSectionDescription.name }, { selector: `${EditSection.selectors.etBtnEditTitle}`, class: this, callBack: this.setFocusTitleInput.name }, { selector: `${EditSection.selectors.elSectionToggle}`, class: this, callBack: this.toggleSection.name }, { selector: `${EditSection.selectors.elBtnCancelUpdateDes}`, class: this, callBack: this.cancelSectionDescription.name }, { selector: `${EditSection.selectors.elBtnDeleteSection}`, class: this, callBack: this.deleteSection.name }, { selector: `${EditSection.selectors.elBtnUpdateTitle}`, class: this, callBack: this.updateSectionTitle.name }, { selector: `${EditSection.selectors.elBtnCancelUpdateTitle}`, class: this, callBack: this.cancelSectionTitle.name }, { selector: _edit_curriculum_js__WEBPACK_IMPORTED_MODULE_5__.EditCourseCurriculum.selectors.elToggleAllSections, class: this, callBack: this.toggleSectionAll.name }]); // Keyup events lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.eventHandlers('keyup', [{ selector: EditSection.selectors.elSectionTitleNewInput, class: this, callBack: this.changeTitleBeforeAdd.name }, { selector: EditSection.selectors.elSectionTitleInput, class: this, callBack: this.changeTitle.name }, { selector: EditSection.selectors.elSectionDesInput, class: this, callBack: this.changeDescription.name }]); // Keydown events lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.eventHandlers('keydown', [{ selector: EditSection.selectors.elSectionTitleNewInput, class: this, callBack: this.addSection.name, checkIsEventEnter: true }, { selector: EditSection.selectors.elSectionDesInput, class: this, callBack: this.updateSectionDescription.name, checkIsEventEnter: true }, { selector: EditSection.selectors.elSectionTitleInput, class: this, callBack: this.updateSectionTitle.name, checkIsEventEnter: true }]); // Focusin events lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.eventHandlers('focusin', [{ selector: EditSection.selectors.elSectionTitleNewInput, class: this, callBack: this.focusTitleNewInput.name }, { selector: EditSection.selectors.elSectionTitleInput, class: this, callBack: this.focusTitleInput.name }]); // Focusin events lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.eventHandlers('focusout', [{ selector: EditSection.selectors.elSectionTitleNewInput, class: this, callBack: this.focusTitleNewInput.name, focusIn: false }, { selector: `${EditSection.selectors.elSectionTitleInput}`, class: this, callBack: this.focusTitleInput.name, focusIn: false }]); } /* Typing in new section title input */ changeTitleBeforeAdd(args) { const { e, target } = args; const elSectionTitleNewInput = target; const elAddNewSection = elSectionTitleNewInput.closest(`${EditSection.selectors.elDivAddNewSection}`); if (!elAddNewSection) { return; } const elBtnAddSection = elAddNewSection.querySelector(`${EditSection.selectors.elBtnAddSection}`); const titleValue = elSectionTitleNewInput.value.trim(); if (titleValue.length === 0) { elBtnAddSection.classList.remove('active'); } else { elBtnAddSection.classList.add('active'); } } /* Focus on new section title input */ focusTitleNewInput(args) { const { e, target, focusIn = true } = args; const elAddNewSection = target.closest(`${EditSection.selectors.elDivAddNewSection}`); if (!elAddNewSection) { return; } if (focusIn) { elAddNewSection.classList.add('focus'); } else { elAddNewSection.classList.remove('focus'); } } /* Add new section */ addSection(args) { const { e, target, callBackNest } = args; const elDivAddNewSection = target.closest(`${EditSection.selectors.elDivAddNewSection}`); if (!elDivAddNewSection) { return; } e.preventDefault(); const elSectionTitleNewInput = elDivAddNewSection.querySelector(`${EditSection.selectors.elSectionTitleNewInput}`); const titleValue = elSectionTitleNewInput.value.trim(); const message = elSectionTitleNewInput.dataset.messEmptyTitle; if (titleValue.length === 0) { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_3__.show(message, 'error'); return; } // Clear input after add elSectionTitleNewInput.value = ''; elSectionTitleNewInput.blur(); // Add and set data for new section const elSectionClone = this.elCurriculumSections.querySelector(`${EditSection.selectors.elSectionClone}`); const newSection = elSectionClone.cloneNode(true); newSection.classList.remove('clone'); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.lpShowHideEl(newSection, 1); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.lpSetLoadingEl(newSection, 1); const elSectionTitleInput = newSection.querySelector(`${EditSection.selectors.elSectionTitleInput}`); elSectionTitleInput.value = titleValue; this.elCurriculumSections.insertAdjacentElement('beforeend', newSection); // End // Call ajax to add new section const callBack = { success: response => { const { message, status, data } = response; if (status === 'error') { newSection.remove(); throw message; } else if (status === 'success') { const { section } = data; newSection.dataset.sectionId = section.section_id || ''; // Initialize EditSectionItem for the new section to make its items sortable this.editSectionItem.sortAbleItem(); if (callBackNest && typeof callBackNest.success === 'function') { args.elSection = newSection; args.response = response; callBackNest.success(args); } } lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_3__.show(message, status); }, error: error => { newSection.remove(); lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_3__.show(error, 'error'); if (callBackNest && typeof callBackNest.error === 'function') { args.error = error; callBackNest.error(args); } }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.lpSetLoadingEl(newSection, 0); newSection.classList.remove(`${_edit_curriculum_js__WEBPACK_IMPORTED_MODULE_5__.EditCourseCurriculum.selectors.elCollapse}`); const elSectionDesInput = newSection.querySelector(`${EditSection.selectors.elSectionDesInput}`); elSectionDesInput.focus(); this.updateCountSections(this.elEditCurriculum); if (callBackNest && typeof callBackNest.completed === 'function') { args.elSection = newSection; callBackNest.completed(args); } } }; const dataSend = JSON.parse(elSectionTitleNewInput.dataset.send); dataSend.section_name = titleValue; window.lpAJAXG.fetchAJAX(dataSend, callBack); } /* Delete section */ deleteSection(args) { const { e, target } = args; const elBtnDeleteSection = target; const elEditCurriculum = elBtnDeleteSection.closest(`${_edit_curriculum_js__WEBPACK_IMPORTED_MODULE_5__.EditCourseCurriculum.selectors.idElEditCurriculum}`); sweetalert2__WEBPACK_IMPORTED_MODULE_0___default().fire({ title: elBtnDeleteSection.dataset.title, text: elBtnDeleteSection.dataset.content, icon: 'warning', showCloseButton: true, showCancelButton: true, cancelButtonText: lpData.i18n.cancel, confirmButtonText: lpData.i18n.yes, reverseButtons: true }).then(result => { if (result.isConfirmed) { const elSection = elBtnDeleteSection.closest('.section'); const sectionId = elSection.dataset.sectionId; lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.lpSetLoadingEl(elSection, 1); // Call ajax to delete section const callBack = { success: response => { const { message, status } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_3__.show(message, status); }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_3__.show(error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.lpSetLoadingEl(elSection, 0); elSection.remove(); this.editSectionItem.updateCountItems(elSection); this.updateCountSections(elEditCurriculum); } }; const dataSend = JSON.parse(elBtnDeleteSection.dataset.send); dataSend.section_id = sectionId; window.lpAJAXG.fetchAJAX(dataSend, callBack); } }); } /* Focus on section title input */ focusTitleInput(args) { const { e, target, focusIn = true } = args; const elSection = target.closest(`${EditSection.selectors.elSection}`); if (!elSection) { return; } if (focusIn) { elSection.classList.add('focus'); } else { elSection.classList.remove('focus'); } } /* Set focus on section title input */ setFocusTitleInput(args) { const { e, target } = args; const elSection = target.closest(`${EditSection.selectors.elSection}`); if (!elSection) { return; } const elSectionTitleInput = elSection.querySelector(`${EditSection.selectors.elSectionTitleInput}`); elSectionTitleInput.setSelectionRange(elSectionTitleInput.value.length, elSectionTitleInput.value.length); elSectionTitleInput.focus(); } /* Typing in section title input */ changeTitle(args) { const { e, target } = args; const elSectionTitleInput = target; const elSection = elSectionTitleInput.closest(`${EditSection.selectors.elSection}`); const titleValue = elSectionTitleInput.value.trim(); const titleValueOld = elSectionTitleInput.dataset.old || ''; if (titleValue === titleValueOld) { elSection.classList.remove('editing'); } else { elSection.classList.add('editing'); } } /* Update section title to server */ updateSectionTitle(args) { const { e, target } = args; const elSection = target.closest(`${EditSection.selectors.elSection}`); if (!elSection) { return; } e.preventDefault(); const elSectionTitleInput = elSection.querySelector(`${EditSection.selectors.elSectionTitleInput}`); if (!elSectionTitleInput) { return; } const sectionId = elSection.dataset.sectionId; const titleValue = elSectionTitleInput.value.trim(); const titleValueOld = elSectionTitleInput.dataset.old || ''; const message = elSectionTitleInput.dataset.messEmptyTitle; if (titleValue.length === 0) { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_3__.show(message, 'error'); return; } if (titleValue === titleValueOld) { return; } elSectionTitleInput.blur(); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.lpSetLoadingEl(elSection, 1); // Call ajax to update section title const callBack = { success: response => { const { message, status } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_3__.show(message, status); if (status === 'success') { elSectionTitleInput.dataset.old = titleValue; } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_3__.show(error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.lpSetLoadingEl(elSection, 0); elSection.classList.remove('editing'); } }; const dataSend = JSON.parse(elSectionTitleInput.dataset.send); dataSend.section_id = sectionId; dataSend.section_name = titleValue; window.lpAJAXG.fetchAJAX(dataSend, callBack); } /* Cancel updating section title */ cancelSectionTitle(args) { const { e, target } = args; const elBtnCancelUpdateTitle = target.closest(`${EditSection.selectors.elBtnCancelUpdateTitle}`); if (!elBtnCancelUpdateTitle) { return; } const elSection = elBtnCancelUpdateTitle.closest(`${EditSection.selectors.elSection}`); const elSectionTitleInput = elSection.querySelector(`${EditSection.selectors.elSectionTitleInput}`); elSectionTitleInput.value = elSectionTitleInput.dataset.old || ''; elSection.classList.remove('editing'); } /* Update section description to server */ updateSectionDescription(args) { const { e, target, callBackNest } = args; const elSectionDesc = target.closest(`${EditSection.selectors.elSectionDesc}`); if (!elSectionDesc) { return; } const elSectionDesInput = elSectionDesc.querySelector(`${EditSection.selectors.elSectionDesInput}`); if (!elSectionDesInput) { return; } e.preventDefault(); const elSection = elSectionDesInput.closest(`${EditSection.selectors.elSection}`); const sectionId = elSection.dataset.sectionId; const descValue = elSectionDesInput.value.trim(); const descValueOld = elSectionDesInput.dataset.old || ''; if (descValue === descValueOld) { return; } lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.lpSetLoadingEl(elSection, 1); const callBack = { success: response => { const { message, status } = response; if (callBackNest && typeof callBackNest.success === 'function') { args.elSection = elSection; args.response = response; callBackNest.success(args); } lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_3__.show(message, status); }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_3__.show(error, 'error'); if (callBackNest && typeof callBackNest.error === 'function') { callBackNest.error(elSection, error); } }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.lpSetLoadingEl(elSection, 0); const elSectionDesc = elSectionDesInput.closest(`${EditSection.selectors.elSectionDesc}`); elSectionDesc.classList.remove('editing'); elSectionDesInput.dataset.old = descValue; if (callBackNest && typeof callBackNest.completed === 'function') { callBackNest.completed(elSection); } } }; const dataSend = JSON.parse(elSectionDesInput.dataset.send); dataSend.section_id = sectionId; dataSend.section_description = descValue; window.lpAJAXG.fetchAJAX(dataSend, callBack); } /* Cancel updating section description */ cancelSectionDescription(args) { const { e, target } = args; const elSectionDesc = target.closest(`${EditSection.selectors.elSectionDesc}`); const elSectionDesInput = elSectionDesc.querySelector(`${EditSection.selectors.elSectionDesInput}`); elSectionDesInput.value = elSectionDesInput.dataset.old || ''; elSectionDesc.classList.remove('editing'); } /* Typing in description input */ changeDescription(ags) { const { e, target } = ags; const elSectionDesInput = target.closest(`${EditSection.selectors.elSectionDesInput}`); if (!elSectionDesInput) { return; } const elSectionDesc = elSectionDesInput.closest(`${EditSection.selectors.elSectionDesc}`); const descValue = elSectionDesInput.value.trim(); const descValueOld = elSectionDesInput.dataset.old || ''; if (descValue === descValueOld) { elSectionDesc.classList.remove('editing'); } else { elSectionDesc.classList.add('editing'); } } toggleSectionAll(args) { const { e, target } = args; const elToggleAllSections = target.closest(`${_edit_curriculum_js__WEBPACK_IMPORTED_MODULE_5__.EditCourseCurriculum.selectors.elToggleAllSections}`); if (!elToggleAllSections) { return; } const elEditCurriculum = elToggleAllSections.closest(`${_edit_curriculum_js__WEBPACK_IMPORTED_MODULE_5__.EditCourseCurriculum.selectors.idElEditCurriculum}`); const elSections = elEditCurriculum.querySelectorAll(`${EditSection.selectors.elSection}:not(.clone)`); elToggleAllSections.classList.toggle(`${_edit_curriculum_js__WEBPACK_IMPORTED_MODULE_5__.EditCourseCurriculum.selectors.elCollapse}`); elSections.forEach(el => { const shouldCollapse = elToggleAllSections.classList.contains(`${_edit_curriculum_js__WEBPACK_IMPORTED_MODULE_5__.EditCourseCurriculum.selectors.elCollapse}`); el.classList.toggle(`${_edit_curriculum_js__WEBPACK_IMPORTED_MODULE_5__.EditCourseCurriculum.selectors.elCollapse}`, shouldCollapse); }); } /* Toggle section */ toggleSection(args) { const { e, target } = args; const elSection = target.closest(`${EditSection.selectors.elSection}`); const elCurriculumSections = elSection.closest(`${_edit_curriculum_js__WEBPACK_IMPORTED_MODULE_5__.EditCourseCurriculum.selectors.elCurriculumSections}`); if (!elCurriculumSections) { return; } // Toggle section elSection.classList.toggle(`${_edit_curriculum_js__WEBPACK_IMPORTED_MODULE_5__.EditCourseCurriculum.selectors.elCollapse}`); // Check all sections collapsed this.checkAllSectionsCollapsed(); } /* Check if all sections are collapsed */ checkAllSectionsCollapsed() { const elSections = this.elEditCurriculum.querySelectorAll(`${EditSection.selectors.elSection}:not(.clone)`); const elToggleAllSections = this.elEditCurriculum.querySelector(`${_edit_curriculum_js__WEBPACK_IMPORTED_MODULE_5__.EditCourseCurriculum.selectors.elToggleAllSections}`); let isAllExpand = true; elSections.forEach(el => { if (el.classList.contains(`${_edit_curriculum_js__WEBPACK_IMPORTED_MODULE_5__.EditCourseCurriculum.selectors.elCollapse}`)) { isAllExpand = false; return false; // Break the loop } }); if (isAllExpand) { elToggleAllSections.classList.remove(`${_edit_curriculum_js__WEBPACK_IMPORTED_MODULE_5__.EditCourseCurriculum.selectors.elCollapse}`); } else { elToggleAllSections.classList.add(`${_edit_curriculum_js__WEBPACK_IMPORTED_MODULE_5__.EditCourseCurriculum.selectors.elCollapse}`); } } /* Sortable sections, drag and drop to change section position */ sortAbleSection() { let isUpdateSectionPosition = 0; let timeout; new sortablejs__WEBPACK_IMPORTED_MODULE_1__["default"](this.elCurriculumSections, { handle: '.drag', animation: 150, onEnd: evt => { const target = evt.item; if (!isUpdateSectionPosition) { return; } const elSection = target.closest(`${EditSection.selectors.elSection}`); const elSections = this.elCurriculumSections.querySelectorAll(`${EditSection.selectors.elSection}`); const sectionIds = []; elSections.forEach(elSection => { const sectionId = elSection.dataset.sectionId; sectionIds.push(sectionId); }); // Call ajax to update section position const callBack = { success: response => { const { message, status } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_3__.show(message, status); }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_3__.show(error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.lpSetLoadingEl(elSection, 0); isUpdateSectionPosition = 0; } }; const dataSend = { action: 'course_update_section_position', course_id: this.courseId, new_position: sectionIds, args: { id_url: 'course-update-section-position' } }; clearTimeout(timeout); timeout = setTimeout(() => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_2__.lpSetLoadingEl(elSection, 1); window.lpAJAXG.fetchAJAX(dataSend, callBack); }, 1000); }, onMove: evt => { clearTimeout(timeout); }, onUpdate: evt => { isUpdateSectionPosition = 1; } }); } /* Update count sections, when add or delete section */ updateCountSections(elEditCurriculum) { const elCountSections = elEditCurriculum.querySelector(`${EditSection.selectors.elCountSections}`); const elSections = elEditCurriculum.querySelectorAll(`${EditSection.selectors.elSection}:not(.clone)`); const sectionsCount = elSections.length; elCountSections.dataset.count = sectionsCount; elCountSections.querySelector('.count').textContent = sectionsCount; } } /***/ }, /***/ "./assets/src/js/admin/edit-question.js" /*!**********************************************!*\ !*** ./assets/src/js/admin/edit-question.js ***! \**********************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ EditQuestion: () => (/* binding */ EditQuestion) /* harmony export */ }); /* harmony import */ var lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lpAssetsJsPath/utils.js */ "./assets/src/js/utils.js"); /* harmony import */ var lpAssetsJsPath_lpToastify__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! lpAssetsJsPath/lpToastify */ "./assets/src/js/lpToastify.js"); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! sweetalert2 */ "./node_modules/sweetalert2/dist/sweetalert2.all.js"); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(sweetalert2__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var sortablejs__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! sortablejs */ "./node_modules/sortablejs/modular/sortable.esm.js"); /** * Edit question JS handler. * * @since 4.2.9 * @version 1.0.0 */ const idUrlHandle = 'edit-question'; let fibSelection; let timeoutAutoUpdateAnswer, timeoutAutoUpdateFib, timeoutAutoUpdateQuestion; // EditQuestion class class EditQuestion { static selectors = { elEditQuestionWrap: '.lp-edit-question-wrap', elQuestionEditMain: '.lp-question-edit-main', elQuestionToggleAll: '.lp-question-toggle-all', elEditListQuestions: '.lp-edit-list-questions', elQuestionToggle: '.lp-question-toggle', elBtnShowPopupItemsToSelect: '.lp-btn-show-popup-items-to-select', elPopupItemsToSelectClone: '.lp-popup-items-to-select.clone', elBtnAddQuestion: '.lp-btn-add-question', elBtnRemoveQuestion: '.lp-btn-remove-question', elBtnUpdateQuestionTitle: '.lp-btn-update-question-title', elBtnUpdateQuestionDes: '.lp-btn-update-question-des', elBtnUpdateQuestionHint: '.lp-btn-update-question-hint', elBtnUpdateQuestionExplain: '.lp-btn-update-question-explanation', elQuestionTitleNewInput: '.lp-question-title-new-input', elQuestionTitleInput: '.lp-question-title-input', elQuestionTypeLabel: '.lp-question-type-label', elQuestionTypeNew: '.lp-question-type-new', elAddNewQuestion: 'add-new-question', elQuestionClone: '.lp-question-item.clone', elAnswersConfig: '.lp-answers-config', elBtnAddAnswer: '.lp-btn-add-question-answer', elQuestionAnswerItemAddNew: '.lp-question-answer-item-add-new', elQuestionAnswerTitleNewInput: '.lp-question-answer-title-new-input', elQuestionAnswerTitleInput: '.lp-question-answer-title-input', elBtnDeleteAnswer: '.lp-btn-delete-question-answer', elQuestionByType: '.lp-question-by-type', elInputAnswerSetTrue: '.lp-input-answer-set-true', elQuestionAnswerItem: '.lp-question-answer-item', elBtnUpdateQuestionAnswer: '.lp-btn-update-question-answer', elBtnFibInsertBlank: '.lp-btn-fib-insert-blank', elBtnFibDeleteAllBlanks: '.lp-btn-fib-delete-all-blanks', elBtnFibSaveContent: '.lp-btn-fib-save-content', elBtnFibClearAllContent: '.lp-btn-fib-clear-all-content', elFibOptionTitleInput: '.lp-question-fib-option-title-input', elFibBlankOptions: '.lp-question-fib-blank-options', elFibBlankOptionItem: '.lp-question-fib-blank-option-item', elFibBlankOptionItemClone: '.lp-question-fib-blank-option-item.clone', elFibBlankOptionIndex: '.lp-question-fib-option-index', elBtnFibOptionDelete: '.lp-btn-fib-option-delete', elFibOptionMatchCaseWrap: '.lp-question-fib-option-match-case-wrap', elFibOptionMatchCaseInput: '.lp-question-fib-option-match-case-input', elQuestionFibOptionDetail: '.lp-question-fib-option-detail', elFibOptionComparisonInput: '.lp-question-fib-option-comparison-input', elAutoSaveFib: '.lp-auto-save-fib', LPTarget: '.lp-target', elCollapse: 'lp-collapse', elSectionToggle: '.lp-section-toggle', elTriggerToggle: '.lp-trigger-toggle', elAutoSaveQuestion: '.lp-auto-save-question', elAutoSaveAnswer: '.lp-auto-save-question-answer', elQuestionFibInput: 'lp-question-fib-input', elBtnQuestionCreateType: '.lp-btn-question-create-type' }; constructor() {} init() { this.events(); this.initTinyMCE().then(); } events() { if (EditQuestion._loadedEvents) { return; } EditQuestion._loadedEvents = true; // Sortable answers's question const elQuestionEditMains = document.querySelectorAll(`${EditQuestion.selectors.elQuestionEditMain}`); elQuestionEditMains.forEach(elQuestionEditMain => { this.sortAbleQuestionAnswer(elQuestionEditMain); }); // End sortable // Event click lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('click', [{ selector: EditQuestion.selectors.elBtnQuestionCreateType, callBack: this.createQuestionType.name, class: this }, { selector: EditQuestion.selectors.elBtnAddAnswer, callBack: this.addQuestionAnswer.name, class: this }, { selector: EditQuestion.selectors.elBtnDeleteAnswer, callBack: this.deleteQuestionAnswer.name, class: this }, { selector: EditQuestion.selectors.elBtnFibInsertBlank, callBack: this.fibInsertBlank.name, class: this }, { selector: EditQuestion.selectors.elBtnFibDeleteAllBlanks, callBack: this.fibDeleteAllBlanks.name, class: this }, { selector: EditQuestion.selectors.elBtnFibSaveContent, callBack: this.fibSaveContent.name, class: this }, { selector: EditQuestion.selectors.elBtnFibClearAllContent, callBack: this.fibClearContent.name, class: this }, { selector: EditQuestion.selectors.elBtnFibOptionDelete, callBack: this.fibDeleteBlank.name, class: this }, { selector: EditQuestion.selectors.elFibOptionMatchCaseInput, callBack: this.fibShowHideMatchCaseOption.name, class: this }, { selector: EditQuestion.selectors.elFibOptionComparisonInput, callBack: args => { const { e, target } = args; const elQuestionEditMain = target.closest(`${EditQuestion.selectors.elQuestionEditMain}`); const elBtnFibSaveContent = elQuestionEditMain.querySelector(`${EditQuestion.selectors.elBtnFibSaveContent}`); elBtnFibSaveContent.click(); } }]); // Toggle collapse document.addEventListener('click', e => { const target = e.target; lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.toggleCollapse(e, target, EditQuestion.selectors.elTriggerToggle); }); // Event keyup lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('keyup', [{ selector: EditQuestion.selectors.elQuestionAnswerTitleNewInput, callBack: this.checkCanAddAnswer.name, class: this }, { selector: EditQuestion.selectors.elFibOptionTitleInput, callBack: this.fibOptionTitleInputChange.name, class: this }, { selector: EditQuestion.selectors.elAutoSaveQuestion, callBack: this.autoUpdateQuestion.name, class: this }]); // Event keydown lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('keydown', [{ selector: EditQuestion.selectors.elQuestionAnswerTitleNewInput, callBack: this.addQuestionAnswer.name, class: this, checkIsEventEnter: true }]); // Event change lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('change', [{ selector: EditQuestion.selectors.elAutoSaveAnswer, callBack: this.autoUpdateAnswer.name, class: this }]); // TinyMCE events this.eventEditorTinymce(); } // Run async to re-init all TinyMCE editors, because it slow if have many editors async initTinyMCE() { const elTextareas = document.querySelectorAll('.lp-editor-tinymce'); elTextareas.forEach(elTextarea => { const idTextarea = elTextarea.id; this.reInitTinymce(idTextarea); }); } reInitTinymce(id) { window.tinymce.execCommand('mceRemoveEditor', true, id); window.tinymce.execCommand('mceAddEditor', true, id); } reInitQuickTags(id) { const toolbar = document.getElementById(`qt_${id}_toolbar`); if (!toolbar || toolbar.children.length || !window.quicktags) { return; } const settings = window.tinyMCEPreInit?.qtInit?.[id] || { id }; window.quicktags(settings); if (window.QTags?._buttonsInit) { window.QTags._buttonsInit(); } } setDefaultEditorTab(id) { const wrapEditor = document.getElementById(`wp-${id}-wrap`); if (!wrapEditor) { return; } if (wrapEditor.classList.contains('html-active') && window.switchEditors?.go) { window.switchEditors.go(id, 'tmce'); const elTextarea = document.getElementById(id); if (elTextarea) { elTextarea.style.visibility = ''; } } wrapEditor.classList.add('tmce-active'); wrapEditor.classList.remove('html-active'); const visualTab = document.getElementById(`${id}-tmce`); const codeTab = document.getElementById(`${id}-html`); visualTab?.setAttribute('aria-pressed', 'true'); codeTab?.setAttribute('aria-pressed', 'false'); } // Events for TinyMCE editor eventEditorTinymce() { window.tinymce.on('AddEditor', eEditor => { const id = eEditor.editor.id; const editor = window.tinymce.get(id); if (!editor) { return; } if (id === 'content') { return; } const elTextarea = document.getElementById(id); if (!elTextarea) { return; } const elQuestionEditMain = elTextarea.closest(`${EditQuestion.selectors.elQuestionEditMain}`); // Skip if not in question edit context if (!elQuestionEditMain) { return; } const questionId = elQuestionEditMain.dataset.questionId; editor.settings.force_p_newlines = false; editor.settings.forced_root_block = ''; editor.settings.force_br_newlines = true; // Config use absolute url editor.settings.relative_urls = false; editor.settings.remove_script_host = false; editor.settings.convert_urls = true; editor.settings.document_base_url = lpData.site_url; // End config use absolute url // Add quick tags this.reInitQuickTags(id); // Events focus in TinyMCE editor editor.on('change keyup', e => { // Auto save if it has class lp-auto-save elTextarea.value = editor.getContent(); this.autoUpdateQuestion({ e, target: elTextarea }); }); editor.on('blur', e => { //console.log( 'Editor blurred:', e.target.id ); }); editor.on('focusin', e => {}); editor.on('init', () => { // Add style editor.dom.addStyle(` body { line-height: 2.2 !important; } .${EditQuestion.selectors.elQuestionFibInput} { border: 1px dashed rebeccapurple; padding: 5px; } `); // Set default tab visual this.setDefaultEditorTab(id); }); editor.on('setcontent', e => { const uniquid = this.randomString(); const elementg = editor.dom.select(`.${EditQuestion.selectors.elQuestionFibInput}[data-id="${uniquid}"]`); if (elementg[0]) { elementg[0].focus(); } editor.dom.bind(elementg[0], 'input', e => { //console.log( 'Input changed:', e.target.value ); }); }); editor.on('selectionchange', e => { fibSelection = editor.selection; // Check selection is blank, check empty blank content if (fibSelection.getNode().classList.contains(`${EditQuestion.selectors.elQuestionFibInput}`)) { const blankId = fibSelection.getNode().dataset.id; const textBlank = fibSelection.getNode().textContent.trim(); if (textBlank.length === 0) { const editorId = editor.id; const questionId = editorId.replace(`${EditQuestion.selectors.elQuestionFibInput}-`, ''); const elQuestionEditMain = document.querySelector(`${EditQuestion.selectors.elQuestionEditMain}[data-question-id="${questionId}"]`); const elQuestionBlankOptions = elQuestionEditMain.querySelector(`${EditQuestion.selectors.elFibBlankOptions}`); const elFibBlankOptionItem = elQuestionBlankOptions.querySelector(`${EditQuestion.selectors.elFibBlankOptionItem}[data-id="${blankId}"]`); if (elFibBlankOptionItem) { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(elFibBlankOptionItem, 0); } } else { const elTextarea = document.getElementById(id); const elAnswersConfig = elTextarea.closest(`${EditQuestion.selectors.elAnswersConfig}`); const elFibBlankOptionItem = elAnswersConfig.querySelector(`${EditQuestion.selectors.elFibBlankOptionItem}[data-id="${blankId}"]`); if (elFibBlankOptionItem) { const elFibOptionTitleInput = elFibBlankOptionItem.querySelector(`${EditQuestion.selectors.elFibOptionTitleInput}`); if (elFibOptionTitleInput) { elFibOptionTitleInput.value = textBlank; } } } } }); editor.on('Undo', e => { const contentUndo = editor.getContent(); const selection = editor.selection; const nodeUndo = selection.getNode(); if (nodeUndo.classList.contains(`${EditQuestion.selectors.elQuestionFibInput}`)) { const blankId = nodeUndo.dataset.id; const elFibBlankOptionItem = document.querySelector(`${EditQuestion.selectors.elFibBlankOptionItem}[data-id="${blankId}"]`); if (elFibBlankOptionItem) { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(elFibBlankOptionItem, 1); } } }); editor.on('Redo', e => {}); }); } autoUpdateQuestion(args) { let { e, target, key, value } = args; const elAutoSave = target.closest(`${EditQuestion.selectors.elAutoSaveQuestion}`); if (!elAutoSave) { return; } const elQuestionEditMain = elAutoSave.closest(`${EditQuestion.selectors.elQuestionEditMain}`); const questionId = elQuestionEditMain.dataset.questionId; clearTimeout(timeoutAutoUpdateQuestion); timeoutAutoUpdateQuestion = setTimeout(() => { // Call ajax to update question description const callBack = { success: response => { const { message, status } = response; if (status === 'success') { lpAssetsJsPath_lpToastify__WEBPACK_IMPORTED_MODULE_1__.show(message, status); } else { throw `Error: ${message}`; } }, error: error => { lpAssetsJsPath_lpToastify__WEBPACK_IMPORTED_MODULE_1__.show(error, 'error'); }, completed: () => {} }; const dataSend = { action: 'update_question', question_id: questionId, args: { id_url: idUrlHandle } }; if (undefined === key) { key = elAutoSave.dataset.keyAutoSave; if (!key) { if (!elAutoSave.classList.contains('lp-editor-tinymce')) { return; } const textAreaId = elAutoSave.id; key = textAreaId.replace(/lp-/g, '').replace(`-${questionId}`, '').replace(/-/g, '_'); if (!key) { return; } } value = elAutoSave.value; } dataSend[key] = value; window.lpAJAXG.fetchAJAX(dataSend, callBack); }, 700); } // Create question type createQuestionType(args) { const { e, target } = args; const elBtnQuestionCreateType = target.closest(`${EditQuestion.selectors.elBtnQuestionCreateType}`); if (!elBtnQuestionCreateType) { return; } const elQuestionEditMain = elBtnQuestionCreateType.closest(`${EditQuestion.selectors.elQuestionEditMain}`); if (!elQuestionEditMain) { return; } const questionId = elQuestionEditMain.dataset.questionId; const elQuestionTypeNew = elQuestionEditMain.querySelector(`${EditQuestion.selectors.elQuestionTypeNew}`); if (!elQuestionTypeNew) { return; } const questionType = elQuestionTypeNew.value.trim(); if (!questionType) { const message = elQuestionTypeNew.dataset.messEmptyType; lpAssetsJsPath_lpToastify__WEBPACK_IMPORTED_MODULE_1__.show(message, 'error'); return; } // Call ajax to create new question type const callBack = { success: response => { const { message, status, data } = response; if (status === 'success') { const { html_option_answers } = data; const elAnswersConfig = elQuestionEditMain.querySelector(`${EditQuestion.selectors.elAnswersConfig}`); elAnswersConfig.outerHTML = html_option_answers; this.initTinyMCE(); this.sortAbleQuestionAnswer(elQuestionEditMain); lpAssetsJsPath_lpToastify__WEBPACK_IMPORTED_MODULE_1__.show(message, status); } else { throw `Error: ${message}`; } }, error: error => { lpAssetsJsPath_lpToastify__WEBPACK_IMPORTED_MODULE_1__.show(error, 'error'); }, completed: () => {} }; const dataSend = { action: 'update_question', question_id: questionId, question_type: questionType, args: { id_url: idUrlHandle } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } addQuestionAnswer(args) { const { e, target } = args; const elQuestionAnswerItemAddNew = target.closest(`${EditQuestion.selectors.elQuestionAnswerItemAddNew}`); if (!elQuestionAnswerItemAddNew) { return; } e.preventDefault(); const elQuestionAnswerTitleNewInput = elQuestionAnswerItemAddNew.querySelector(`${EditQuestion.selectors.elQuestionAnswerTitleNewInput}`); if (!elQuestionAnswerTitleNewInput.value.trim()) { const message = elQuestionAnswerTitleNewInput.dataset.messEmptyTitle; lpAssetsJsPath_lpToastify__WEBPACK_IMPORTED_MODULE_1__.show(message, 'error'); return; } const elQuestionEditMain = target.closest(`${EditQuestion.selectors.elQuestionEditMain}`); const elQuestionAnswerClone = elQuestionEditMain.querySelector(`${EditQuestion.selectors.elQuestionAnswerItem}.clone`); const elQuestionAnswerNew = elQuestionAnswerClone.cloneNode(true); const elQuestionAnswerTitleInputNew = elQuestionAnswerNew.querySelector(`${EditQuestion.selectors.elQuestionAnswerTitleInput}`); elQuestionAnswerNew.classList.remove('clone'); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(elQuestionAnswerNew, 1); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elQuestionAnswerNew, 1); elQuestionAnswerClone.insertAdjacentElement('beforebegin', elQuestionAnswerNew); const answerTitle = elQuestionAnswerTitleNewInput.value.trim(); elQuestionAnswerTitleInputNew.value = answerTitle; elQuestionAnswerTitleNewInput.value = ''; const questionId = elQuestionEditMain.dataset.questionId; // Call ajax to add new question answer const callBack = { success: response => { const { message, status, data } = response; if (status === 'success') { const { question_answer } = data; elQuestionAnswerNew.dataset.answerId = question_answer.question_answer_id; lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elQuestionAnswerNew, 0); // Set data lp-answers-config const dataAnswers = this.getDataAnswersConfig(elQuestionEditMain); dataAnswers.push(question_answer); this.setDataAnswersConfig(elQuestionEditMain, dataAnswers); } else { throw `Error: ${message}`; } lpAssetsJsPath_lpToastify__WEBPACK_IMPORTED_MODULE_1__.show(message, status); }, error: error => { elQuestionAnswerNew.remove(); lpAssetsJsPath_lpToastify__WEBPACK_IMPORTED_MODULE_1__.show(error, 'error'); }, completed: () => {} }; const dataSend = { action: 'add_question_answer', question_id: questionId, answer_title: answerTitle, args: { id_url: idUrlHandle } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } // Check to enable or disable add new question button checkCanAddAnswer(args) { const { e, target } = args; const elTrigger = target.closest(EditQuestion.selectors.elQuestionAnswerTitleNewInput); if (!elTrigger) { return; } const elQuestionAnswerItemAddNew = elTrigger.closest(`${EditQuestion.selectors.elQuestionAnswerItemAddNew}`); if (!elQuestionAnswerItemAddNew) { return; } const elBtnAddAnswer = elQuestionAnswerItemAddNew.querySelector(`${EditQuestion.selectors.elBtnAddAnswer}`); if (!elBtnAddAnswer) { return; } const titleValue = elTrigger.value.trim(); if (titleValue) { elBtnAddAnswer.classList.add('active'); } else { elBtnAddAnswer.classList.remove('active'); } } // Auto update question answer autoUpdateAnswer(args) { const { e, target } = args; const elAutoSaveAnswer = target.closest(`${EditQuestion.selectors.elAutoSaveAnswer}`); if (!elAutoSaveAnswer) { return; } const elQuestionAnswerItem = elAutoSaveAnswer.closest(`${EditQuestion.selectors.elQuestionAnswerItem}`); clearTimeout(timeoutAutoUpdateAnswer); timeoutAutoUpdateAnswer = setTimeout(() => { const elQuestionEditMain = elAutoSaveAnswer.closest(`${EditQuestion.selectors.elQuestionEditMain}`); const questionId = elQuestionEditMain.dataset.questionId; const dataAnswers = this.getDataAnswersConfig(elQuestionEditMain); const elAnswersConfig = elQuestionEditMain.querySelector(`${EditQuestion.selectors.elAnswersConfig}`); // For both radio and checkbox. const dataAnswersOld = structuredClone(dataAnswers); // Get position of answers const elQuestionAnswerItems = elAnswersConfig.querySelectorAll(`${EditQuestion.selectors.elQuestionAnswerItem}:not(.clone)`); const answersPosition = {}; elQuestionAnswerItems.forEach((elQuestionAnswerItem, index) => { answersPosition[elQuestionAnswerItem.dataset.answerId] = index + 1; // Start from 1 }); //console.log( 'answersPosition', answersPosition ); dataAnswers.map((answer, k) => { const elQuestionAnswerItem = elQuestionEditMain.querySelector(`${EditQuestion.selectors.elQuestionAnswerItem}[data-answer-id="${answer.question_answer_id}"]`); const elInputAnswerSetTrue = elQuestionAnswerItem.querySelector(`${EditQuestion.selectors.elInputAnswerSetTrue}`); const elInputAnswerTitle = elQuestionAnswerItem.querySelector(`${EditQuestion.selectors.elQuestionAnswerTitleInput}`); // Set title if (elInputAnswerTitle) { answer.title = elInputAnswerTitle.value.trim(); } // Set true answer if (elInputAnswerSetTrue) { if (elInputAnswerSetTrue.checked) { answer.is_true = 'yes'; } else { answer.is_true = ''; } } // Set position if (answersPosition[answer.question_answer_id]) { answer.order = answersPosition[answer.question_answer_id]; } return answer; }); //console.log( dataAnswers ); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elQuestionAnswerItem, 1); // Call ajax to update answers config const callBack = { success: response => { const { message, status } = response; if (status === 'success') {} else { throw `Error: ${message}`; } lpAssetsJsPath_lpToastify__WEBPACK_IMPORTED_MODULE_1__.show(message, status); }, error: error => { // rollback changes to old data dataAnswersOld.forEach(answer => { const elAnswerItem = elQuestionEditMain.querySelector(`${EditQuestion.selectors.elQuestionAnswerItem}[data-answer-id="${answer.question_answer_id}"]`); const inputAnswerSetTrue = elAnswerItem.querySelector(`${EditQuestion.selectors.elInputAnswerSetTrue}`); if (answer.is_true === 'yes') { inputAnswerSetTrue.checked = true; } return answer; }); lpAssetsJsPath_lpToastify__WEBPACK_IMPORTED_MODULE_1__.show(error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elQuestionAnswerItem, 0); } }; const dataSend = { action: 'update_question_answers_config', question_id: questionId, answers: dataAnswers, args: { id_url: idUrlHandle } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); }, 700); } // Sortable answers's question sortAbleQuestionAnswer(elQuestionEditMain) { let isUpdateSectionPosition = 0; let timeout; const elQuestionAnswers = elQuestionEditMain.querySelectorAll(`${EditQuestion.selectors.elAnswersConfig}`); elQuestionAnswers.forEach(elAnswersConfig => { new sortablejs__WEBPACK_IMPORTED_MODULE_3__["default"](elAnswersConfig, { handle: '.drag', animation: 150, onEnd: evt => { const elQuestionAnswerItem = evt.item; if (!isUpdateSectionPosition) { // No change in section position, do nothing return; } clearTimeout(timeout); timeout = setTimeout(() => { const elAutoSaveAnswer = elQuestionAnswerItem.querySelector(`${EditQuestion.selectors.elAutoSaveAnswer}`); this.autoUpdateAnswer({ e: null, target: elAutoSaveAnswer }); }, 1000); }, onMove: evt => { clearTimeout(timeout); }, onUpdate: evt => { isUpdateSectionPosition = 1; } }); }); } // Delete question answer deleteQuestionAnswer(args) { const { e, target } = args; const elBtnDeleteAnswer = target.closest(`${EditQuestion.selectors.elBtnDeleteAnswer}`); if (!elBtnDeleteAnswer) { return; } const elQuestionAnswerItem = elBtnDeleteAnswer.closest(`${EditQuestion.selectors.elQuestionAnswerItem}`); if (!elQuestionAnswerItem) { return; } const elQuestionEditMain = elBtnDeleteAnswer.closest(`${EditQuestion.selectors.elQuestionEditMain}`); const questionId = elQuestionEditMain.dataset.questionId; const questionAnswerId = elQuestionAnswerItem.dataset.answerId; if (!questionId || !questionAnswerId) { return; } sweetalert2__WEBPACK_IMPORTED_MODULE_2___default().fire({ title: elBtnDeleteAnswer.dataset.title || 'Are you sure?', text: elBtnDeleteAnswer.dataset.content || 'Do you want to delete this answer?', icon: 'warning', showCloseButton: true, showCancelButton: true, cancelButtonText: lpData.i18n.cancel, confirmButtonText: lpData.i18n.yes, reverseButtons: true }).then(result => { if (result.isConfirmed) { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elQuestionAnswerItem, 1); // Call ajax to delete item from section const callBack = { success: response => { const { message, status } = response; lpAssetsJsPath_lpToastify__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (status === 'success') { const elQuestionAnswerId = parseInt(elQuestionAnswerItem.dataset.answerId); elQuestionAnswerItem.remove(); const dataAnswers = this.getDataAnswersConfig(elQuestionEditMain); if (dataAnswers) { const updatedAnswers = dataAnswers.filter(answer => parseInt(answer.question_answer_id) !== elQuestionAnswerId); this.setDataAnswersConfig(elQuestionEditMain, updatedAnswers); } } }, error: error => { lpAssetsJsPath_lpToastify__WEBPACK_IMPORTED_MODULE_1__.show(error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elQuestionAnswerItem, 0); } }; const dataSend = { action: 'delete_question_answer', question_id: questionId, question_answer_id: questionAnswerId, args: { id_url: idUrlHandle } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } }); } // Get data answers config getDataAnswersConfig(elQuestionEditMain) { const elAnswersConfig = elQuestionEditMain.querySelector(`${EditQuestion.selectors.elAnswersConfig}`); if (!elAnswersConfig) { return null; } let dataAnswers = elAnswersConfig.dataset.answers || '[]'; try { dataAnswers = JSON.parse(dataAnswers); } catch (e) { dataAnswers = []; } if (!dataAnswers.meta_data) { dataAnswers.meta_data = {}; } return dataAnswers; } // Set data answers config setDataAnswersConfig(elQuestionEditMain, dataAnswers) { const elAnswersConfig = elQuestionEditMain.querySelector(`${EditQuestion.selectors.elAnswersConfig}`); if (!elAnswersConfig) { return; } if (!dataAnswers || typeof dataAnswers !== 'object') { dataAnswers = {}; } elAnswersConfig.dataset.answers = JSON.stringify(dataAnswers); } /***** Fill in the blank question type *****/ // For FIB question type fibInsertBlank = args => { const { e, target } = args; const elBtnFibInsertBlank = target.closest(EditQuestion.selectors.elBtnFibInsertBlank); if (!elBtnFibInsertBlank) { return; } const textPlaceholder = elBtnFibInsertBlank.dataset.defaultText; const elQuestionEditMain = elBtnFibInsertBlank.closest(EditQuestion.selectors.elQuestionEditMain); const questionId = elQuestionEditMain.dataset.questionId; const messErrInserted = elBtnFibInsertBlank.dataset.messInserted; const messErrRequireSelectText = elBtnFibInsertBlank.dataset.messRequireSelectText; const idEditor = `${EditQuestion.selectors.elQuestionFibInput}-${questionId}`; const uniquid = this.randomString(); let selectedText; if (fibSelection) { const elNode = fibSelection.getNode(); if (!elNode) { lpAssetsJsPath_lpToastify__WEBPACK_IMPORTED_MODULE_1__.show('Event insert blank has error, please try again', 'error'); return; } const findParent = elNode.closest(`body[data-id="${idEditor}"]`); if (!findParent) { lpAssetsJsPath_lpToastify__WEBPACK_IMPORTED_MODULE_1__.show(messErrRequireSelectText, 'error'); return; } if (elNode.classList.contains(`${EditQuestion.selectors.elQuestionFibInput}`)) { lpAssetsJsPath_lpToastify__WEBPACK_IMPORTED_MODULE_1__.show(messErrInserted, 'error'); return; } selectedText = fibSelection.getContent(); if (selectedText.length === 0) { selectedText = textPlaceholder; } const elInputNew = `${selectedText}`; fibSelection.setContent(elInputNew); } else { lpAssetsJsPath_lpToastify__WEBPACK_IMPORTED_MODULE_1__.show(messErrRequireSelectText, 'error'); return; } const dataAnswers = this.getDataAnswersConfig(elQuestionEditMain); dataAnswers.meta_data = dataAnswers.meta_data || {}; // Convert array to object if (Object.keys(dataAnswers.meta_data).length === 0) { dataAnswers.meta_data = {}; } dataAnswers.meta_data[uniquid] = { id: uniquid, match_case: 0, comparison: 'equal', fill: selectedText, index: 1, open: false }; this.setDataAnswersConfig(elQuestionEditMain, dataAnswers); // Clone blank options const elFibBlankOptions = elQuestionEditMain.querySelector(`${EditQuestion.selectors.elFibBlankOptions}`); const elFibBlankOptionItemClone = elQuestionEditMain.querySelector(`${EditQuestion.selectors.elFibBlankOptionItemClone}`); const elFibBlankOptionItemNew = elFibBlankOptionItemClone.cloneNode(true); const countOptions = elFibBlankOptions.querySelectorAll(`${EditQuestion.selectors.elFibBlankOptionItem}:not(.clone)`).length; const elFibBlankOptionIndex = elFibBlankOptionItemNew.querySelector(`${EditQuestion.selectors.elFibBlankOptionIndex}`); const elFibOptionTitleInput = elFibBlankOptionItemNew.querySelector(`${EditQuestion.selectors.elFibOptionTitleInput}`); const elFibOptionMatchCaseInput = elFibBlankOptionItemNew.querySelector(`${EditQuestion.selectors.elFibOptionMatchCaseInput}`); const elFibOptionComparisonInput = elFibBlankOptionItemNew.querySelectorAll(`${EditQuestion.selectors.elFibOptionComparisonInput}`); elFibBlankOptionItemNew.dataset.id = uniquid; elFibOptionTitleInput.name = `${EditQuestion.selectors.elFibOptionTitleInput}-${uniquid}`; elFibOptionTitleInput.value = this.decodeHtml(selectedText); elFibBlankOptionIndex.textContent = countOptions + 1 + '.'; elFibOptionMatchCaseInput.name = `${EditQuestion.selectors.elFibOptionMatchCaseInput}-${uniquid}`.replace(/\./g, ''); elFibOptionComparisonInput.forEach(elInput => { elInput.name = `${EditQuestion.selectors.elFibOptionComparisonInput}-${uniquid}`.replace(/\./g, ''); if (elInput.value === 'equal') { elInput.checked = true; } }); elFibBlankOptionItemClone.insertAdjacentElement('beforebegin', elFibBlankOptionItemNew); elFibBlankOptionItemNew.classList.remove('clone'); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(elFibBlankOptionItemNew, 1); // End clone blank options const elBtnFibSaveContent = elQuestionEditMain.querySelector(`${EditQuestion.selectors.elBtnFibSaveContent}`); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elBtnFibInsertBlank, 1); this.fibSaveContent({ e: null, target: elBtnFibSaveContent, callBackCompleted: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elBtnFibInsertBlank, 0); } }); }; // Delete all blanks fibDeleteAllBlanks(args) { const { e, target } = args; const elBtnFibDeleteAllBlanks = target.closest(`${EditQuestion.selectors.elBtnFibDeleteAllBlanks}`); if (!elBtnFibDeleteAllBlanks) { return; } const elQuestionEditMain = elBtnFibDeleteAllBlanks.closest(`${EditQuestion.selectors.elQuestionEditMain}`); if (!elQuestionEditMain) { return; } const questionId = elQuestionEditMain.dataset.questionId; const dataAnswers = this.getDataAnswersConfig(elQuestionEditMain); sweetalert2__WEBPACK_IMPORTED_MODULE_2___default().fire({ title: elBtnFibDeleteAllBlanks.dataset.title, text: elBtnFibDeleteAllBlanks.dataset.content, icon: 'warning', showCloseButton: true, showCancelButton: true, cancelButtonText: lpData.i18n.cancel, confirmButtonText: lpData.i18n.yes, reverseButtons: true }).then(result => { if (result.isConfirmed) { const editor = window.tinymce.get(`${EditQuestion.selectors.elQuestionFibInput}-${questionId}`); const elBlanks = editor.dom.select(`.${EditQuestion.selectors.elQuestionFibInput}`); elBlanks.forEach(elBlank => { editor.dom.remove(elBlank, true); }); dataAnswers.meta_data = {}; this.setDataAnswersConfig(elQuestionEditMain, dataAnswers); const elFibBlankOptions = elQuestionEditMain.querySelector(`${EditQuestion.selectors.elFibBlankOptions}`); const elFibBlankOptionItems = elFibBlankOptions.querySelectorAll(`${EditQuestion.selectors.elFibBlankOptionItem}:not(.clone)`); elFibBlankOptionItems.forEach(elFibBlankOptionItem => { elFibBlankOptionItem.remove(); }); const elBtnFibSaveContent = elQuestionEditMain.querySelector(`${EditQuestion.selectors.elBtnFibSaveContent}`); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elBtnFibDeleteAllBlanks, 1); this.fibSaveContent({ e: null, target: elBtnFibSaveContent, callBackCompleted: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elBtnFibDeleteAllBlanks, 0); } }); } }); } // Clear content FIB question fibClearContent(args) { const { e, target } = args; const elBtnFibClearAllContent = target.closest(`${EditQuestion.selectors.elBtnFibClearAllContent}`); if (!elBtnFibClearAllContent) { return; } const elQuestionEditMain = elBtnFibClearAllContent.closest(`${EditQuestion.selectors.elQuestionEditMain}`); if (!elQuestionEditMain) { return; } const questionId = elQuestionEditMain.dataset.questionId; const dataAnswers = this.getDataAnswersConfig(elQuestionEditMain); sweetalert2__WEBPACK_IMPORTED_MODULE_2___default().fire({ title: elBtnFibClearAllContent.dataset.title, text: elBtnFibClearAllContent.dataset.content, icon: 'warning', showCloseButton: true, showCancelButton: true, cancelButtonText: lpData.i18n.cancel, confirmButtonText: lpData.i18n.yes, reverseButtons: true }).then(result => { if (result.isConfirmed) { const editor = window.tinymce.get(`lp-question-fib-input-${questionId}`); editor.setContent(''); dataAnswers.meta_data = {}; this.setDataAnswersConfig(elQuestionEditMain, dataAnswers); const elFibBlankOptions = elQuestionEditMain.querySelector(`${EditQuestion.selectors.elFibBlankOptions}`); const elFibBlankOptionItems = elFibBlankOptions.querySelectorAll(`${EditQuestion.selectors.elFibBlankOptionItem}:not(.clone)`); elFibBlankOptionItems.forEach(elFibBlankOptionItem => { elFibBlankOptionItem.remove(); }); const elBtnFibSaveContent = elQuestionEditMain.querySelector(`${EditQuestion.selectors.elBtnFibSaveContent}`); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elBtnFibClearAllContent, 1); this.fibSaveContent({ e: null, target: elBtnFibSaveContent, callBackCompleted: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elBtnFibClearAllContent, 0); } }); } }); } // Remove blank fibDeleteBlank(args) { const { e, target } = args; const elBtnFibOptionDelete = target.closest(`${EditQuestion.selectors.elBtnFibOptionDelete}`); if (!elBtnFibOptionDelete) { return; } const elQuestionEditMain = elBtnFibOptionDelete.closest(`${EditQuestion.selectors.elQuestionEditMain}`); if (!elQuestionEditMain) { return; } const questionId = elQuestionEditMain.dataset.questionId; const elAnswersConfig = elQuestionEditMain.querySelector(`${EditQuestion.selectors.elAnswersConfig}`); const dataAnswers = this.getDataAnswersConfig(elQuestionEditMain); const elFibBlankOptionItem = elBtnFibOptionDelete.closest(`${EditQuestion.selectors.elFibBlankOptionItem}`); const blankId = elFibBlankOptionItem.dataset.id; sweetalert2__WEBPACK_IMPORTED_MODULE_2___default().fire({ title: elBtnFibOptionDelete.dataset.title, text: elBtnFibOptionDelete.dataset.content, icon: 'warning', showCloseButton: true, showCancelButton: true, cancelButtonText: lpData.i18n.cancel, confirmButtonText: lpData.i18n.yes, reverseButtons: true }).then(result => { if (result.isConfirmed) { // Find span with id on editor and remove it const editor = window.tinymce.get(`${EditQuestion.selectors.elQuestionFibInput}-${questionId}`); const elBlank = editor.dom.select(`.${EditQuestion.selectors.elQuestionFibInput}[data-id="${blankId}"]`); if (elBlank[0]) { // Remove tag html but keep content editor.dom.remove(elBlank[0], true); } elFibBlankOptionItem.remove(); dataAnswers.meta_data = dataAnswers.meta_data || {}; if (dataAnswers.meta_data[blankId]) { delete dataAnswers.meta_data[blankId]; } this.setDataAnswersConfig(elQuestionEditMain, dataAnswers); const elBtnFibSaveContent = elQuestionEditMain.querySelector(`${EditQuestion.selectors.elBtnFibSaveContent}`); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elFibBlankOptionItem, 1); this.fibSaveContent({ e: null, target: elBtnFibSaveContent, callBackCompleted: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elFibBlankOptionItem, 0); } }); } }); } // Change title of blank option fibOptionTitleInputChange(args) { const { e, target } = args; const elFibOptionTitleInput = target.closest(`${EditQuestion.selectors.elFibOptionTitleInput}`); if (!elFibOptionTitleInput) { return; } const elQuestionFibOptionItem = elFibOptionTitleInput.closest(`${EditQuestion.selectors.elFibBlankOptionItem}`); if (!elQuestionFibOptionItem) { return; } const elQuestionEditMain = elFibOptionTitleInput.closest(`${EditQuestion.selectors.elQuestionEditMain}`); if (!elQuestionEditMain) { return; } const value = elFibOptionTitleInput.value.trim(); const blankId = elQuestionFibOptionItem.dataset.id; const questionId = elQuestionEditMain.dataset.questionId; const editor = window.tinymce.get(`lp-question-fib-input-${questionId}`); const elBlank = editor.dom.select(`.lp-question-fib-input[data-id="${blankId}"]`); if (elBlank[0]) { // Update content of blank elBlank[0].textContent = value; } clearTimeout(timeoutAutoUpdateFib); timeoutAutoUpdateFib = setTimeout(() => { // Call ajax to update question description const elBtnFibSaveContent = elQuestionEditMain.querySelector(`${EditQuestion.selectors.elBtnFibSaveContent}`); this.fibSaveContent({ e: null, target: elBtnFibSaveContent }); }, 700); } // Save content FIB question fibSaveContent(args) { const { e, target, callBackCompleted = null } = args; const elBtnFibSaveContent = target.closest(`${EditQuestion.selectors.elBtnFibSaveContent}`); if (!elBtnFibSaveContent) { return; } const elQuestionEditMain = elBtnFibSaveContent.closest(`${EditQuestion.selectors.elQuestionEditMain}`); const questionId = elQuestionEditMain.dataset.questionId; const dataAnswers = this.getDataAnswersConfig(elQuestionEditMain); if (!dataAnswers) { return; } const editor = window.tinymce.get(`${EditQuestion.selectors.elQuestionFibInput}-${questionId}`); dataAnswers.title = editor.getContent(); const elFibBlankOptionItems = elQuestionEditMain.querySelectorAll(`${EditQuestion.selectors.elFibBlankOptionItem}:not(.clone)`); if (elFibBlankOptionItems) { elFibBlankOptionItems.forEach(elFibBlankOptionItem => { const blankId = elFibBlankOptionItem.dataset.id; const elFibOptionMatchCaseInput = elFibBlankOptionItem.querySelector(`${EditQuestion.selectors.elFibOptionMatchCaseInput}`); const elFibOptionComparisonInput = elFibBlankOptionItem.querySelector(`${EditQuestion.selectors.elFibOptionComparisonInput}:checked`); dataAnswers.meta_data[blankId].match_case = elFibOptionMatchCaseInput.checked ? 1 : 0; dataAnswers.meta_data[blankId].comparison = elFibOptionComparisonInput.value; }); } //console.log( 'dataAnswers', dataAnswers ); if (!callBackCompleted) { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elBtnFibSaveContent, 1); } // Call ajax to update answers config const callBack = { success: response => { const { message, status } = response; if (status === 'success') { this.setDataAnswersConfig(elQuestionEditMain, dataAnswers); } else { throw `Error: ${message}`; } lpAssetsJsPath_lpToastify__WEBPACK_IMPORTED_MODULE_1__.show(message, status); }, error: error => { lpAssetsJsPath_lpToastify__WEBPACK_IMPORTED_MODULE_1__.show(error, 'error'); }, completed: () => { if (callBackCompleted && typeof callBackCompleted === 'function') { callBackCompleted(); } else { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elBtnFibSaveContent, 0); } } }; //console.log( 'dataAnswers', dataAnswers ); const dataSend = { action: 'update_question_answers_config', question_id: questionId, answers: dataAnswers, args: { id_url: idUrlHandle } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } // Show/hide match case option fibShowHideMatchCaseOption(args) { const { e, target } = args; const elFibOptionMatchCaseInput = target.closest(`${EditQuestion.selectors.elFibOptionMatchCaseInput}`); if (!elFibOptionMatchCaseInput) { return; } const elQuestionFibOptionDetail = elFibOptionMatchCaseInput.closest(`${EditQuestion.selectors.elQuestionFibOptionDetail}`); const elFibOptionMatchCaseWrap = elQuestionFibOptionDetail.querySelector(`${EditQuestion.selectors.elFibOptionMatchCaseWrap}`); if (!elQuestionFibOptionDetail || !elFibOptionMatchCaseWrap) { return; } if (elFibOptionMatchCaseInput.checked) { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(elFibOptionMatchCaseWrap, 1); } else { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(elFibOptionMatchCaseWrap, 0); } const elQuestionEditMain = elFibOptionMatchCaseInput.closest(`${EditQuestion.selectors.elQuestionEditMain}`); const elBtnFibSaveContent = elQuestionEditMain.querySelector(`${EditQuestion.selectors.elBtnFibSaveContent}`); elBtnFibSaveContent.click(); } /***** End Fill in the blank question type *****/ // Generate a random string of specified length, for set unique id randomString(length = 10) { const chars = 'abcdefghijklmnopqrstuvwxyz0123456789'; let result = ''; for (let i = 0; i < length; i++) { result += chars.charAt(Math.floor(Math.random() * chars.length)); } return result; } // Decode HTML entities decodeHtml(html) { const txt = document.createElement('textarea'); txt.innerHTML = html; return txt.value; } } const editQuestion = new EditQuestion(); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady(EditQuestion.selectors.elEditQuestionWrap, elEditQuestionWrap => { const findClass = EditQuestion.selectors.elQuestionEditMain.replace('.', ''); if (!elEditQuestionWrap.classList.contains(findClass)) { return; } editQuestion.init(); }); /***/ }, /***/ "./assets/src/js/admin/generate-with-openai.js" /*!*****************************************************!*\ !*** ./assets/src/js/admin/generate-with-openai.js ***! \*****************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ GenerateWithOpenai: () => (/* binding */ GenerateWithOpenai) /* harmony export */ }); /* harmony import */ var _utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./../utils.js */ "./assets/src/js/utils.js"); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! sweetalert2 */ "./node_modules/sweetalert2/dist/sweetalert2.all.js"); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(sweetalert2__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! lpAssetsJsPath/lpToastify.js */ "./assets/src/js/lpToastify.js"); /** * Generate data with OpenAI */ let lp_structure_course; let popupSweetAlert = null; let lp_is_generating_course_data = false; const lp_course_ai_setting = JSON.parse(localStorage.getItem('lp_course_ai_setting')) || {}; let isLayoutGutenberg = false; let selectGutenberg; let dispatchGutenberg; let editorGutenberg; class GenerateWithOpenai { constructor(options = {}) { this.options = { autoInsertButtons: true, isCourseBuilder: false, titleInputSelector: 'input[name=post_title]', courseBuilderTitleInputSelector: 'input[name=course_title]', editorIdClassic: 'content', editorIdCourseBuilder: 'course_description_editor', ...options }; this.init(); } static selectors = { elBtnGenerateWithAi: '.lp-btn-generate-with-ai', elGenerateDataAiWrap: '.lp-generate-data-ai-wrap' }; init() { if (!lpData?.enable_open_ai) { return; } if (this.options.autoInsertButtons) { _utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady('#titlewrap', el => { el.insertAdjacentHTML('afterend', ``); }); _utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady('#wp-content-media-buttons', el => { el.insertAdjacentHTML('beforeend', ``); }); _utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady('#postimagediv', el => { const elInside = el.querySelector('.postbox-header'); elInside.insertAdjacentHTML('afterend', ``); }); // Check is layout Gutenberg if (wp.data && wp.data.select('core/editor')) { isLayoutGutenberg = true; selectGutenberg = wp.data.select; dispatchGutenberg = wp.data.dispatch; editorGutenberg = selectGutenberg('core/editor'); // For layout Gutenberg - button for title _utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady('.editor-document-bar', el => { el.insertAdjacentHTML('afterend', ``); }); // For layout Gutenberg - button for description _utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady('.editor-post-featured-image', el => { el.insertAdjacentHTML('beforebegin', ``); }); // For layout Gutenberg - button for image _utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady('.editor-post-featured-image', el => { el.insertAdjacentHTML('afterend', ``); }); } } this.events(); } getTitleInputSelector() { return this.options.isCourseBuilder ? this.options.courseBuilderTitleInputSelector : this.options.titleInputSelector; } getEditorId() { return this.options.isCourseBuilder ? this.options.editorIdCourseBuilder : this.options.editorIdClassic; } setCourseBuilderPostId(form) { if (!this.options.isCourseBuilder || !form) { return; } const postIdInput = form.querySelector('[name="post-id"]'); if (!postIdInput) { return; } const courseEditWrap = document.querySelector('.cb-section__course-edit[data-course-id]'); const courseId = courseEditWrap?.dataset?.courseId || ''; if (courseId) { postIdInput.value = courseId; } } extractImageSourceFromHtml(html) { if (!html) { return ''; } const tempWrapper = document.createElement('div'); tempWrapper.innerHTML = html; return tempWrapper.querySelector('img')?.getAttribute('src') || ''; } applyCourseBuilderFeaturedImage(attachmentId, imageSrc) { if (!attachmentId || !imageSrc) { return false; } document.dispatchEvent(new CustomEvent('lp-course-builder/ai-featured-image-applied', { detail: { attachmentId, imageSrc } })); return true; } events() { _utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('click', [{ selector: GenerateWithOpenai.selectors.elBtnGenerateWithAi, class: this, callBack: this.showPopup.name }, { selector: '.lp-btn-step', class: this, callBack: this.showStep.name }, { selector: '.lp-btn-generate-prompt', class: this, callBack: this.generatePrompt.name }, { selector: '.lp-btn-call-open-ai', class: this, callBack: this.generateData.name }, { selector: '.lp-btn-copy', class: this, callBack: this.copyGeneratedData.name }, { selector: '.lp-btn-apply', class: this, callBack: this.applyGeneratedData.name }, { selector: '.lp-btn-ai-apply-image', class: this, callBack: this.applyImageData.name }, { selector: '.lp-btn-close-ai-popup', //class: this, callBack: args => { const { e, target } = args; const message = lpData.i18n.confirm_close_ai; if (!lp_is_generating_course_data) { sweetalert2__WEBPACK_IMPORTED_MODULE_1___default().close(); } else if (confirm(message)) { sweetalert2__WEBPACK_IMPORTED_MODULE_1___default().close(); } // Testing custom confirm box /*if ( confirm( message ) ) { SweetAlert.close(); }*/ } }]); } showPopup(args) { const { e, target } = args; const templateId = target.dataset.template || target.closest('.lp-btn-generate-with-ai').dataset.template || target.closest('.lp-generate-data-ai-wrap').dataset.template || ''; const modalTemplate = document.querySelector(templateId); if (!modalTemplate) { console.error(`Template ${templateId} not found!`); return; } sweetalert2__WEBPACK_IMPORTED_MODULE_1___default().fire({ html: modalTemplate.innerHTML, width: '60%', showCloseButton: false, showConfirmButton: false, allowOutsideClick: false, allowEscapeKey: false, didOpen: () => { popupSweetAlert = sweetalert2__WEBPACK_IMPORTED_MODULE_1___default().getPopup(); // Click to show tomSelect style popupSweetAlert.click(); // Set post title and post content to hidden fields of form to AI prompt reference const elPostTitleInput = document.querySelector(this.getTitleInputSelector()); let post_title = ''; if (elPostTitleInput) { post_title = elPostTitleInput.value; } else if (isLayoutGutenberg) { const elGutenbergTitle = document.querySelector('.editor-post-card-panel__title-name'); if (elGutenbergTitle) { post_title = elGutenbergTitle.textContent; } } let post_content = ''; if (!isLayoutGutenberg) { const editorId = this.getEditorId(); if (!window.tinymce || !window.tinymce.get(editorId)) { const editorElement = document.querySelector(`#${editorId}`); post_content = editorElement ? editorElement.value : ''; } else { post_content = window.tinymce.get(editorId).getContent({ format: 'text' }); } } else { const content = editorGutenberg.getEditedPostContent(); post_content = content.replace(/(<([^>]+)>)/gi, ''); // Remove HTML tags } const form = popupSweetAlert.querySelector('form'); this.setCourseBuilderPostId(form); const elPostTitle = form.querySelector('[name=post-title]'); if (elPostTitle) { elPostTitle.value = post_title; if (!post_title) { const elGroup = elPostTitle.closest('.form-group'); const elReferWarning = elGroup.querySelector('.lp-ai-warning-refer'); if (elReferWarning) { _utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(elReferWarning, 1); } } } const elPostContent = form.querySelector('[name=post-content]'); if (elPostContent) { elPostContent.value = post_content; if (post_content.length < 2) { const elGroup = elPostContent.closest('.form-group'); const elReferWarning = elGroup.querySelector('.lp-ai-warning-refer'); if (elReferWarning) { _utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(elReferWarning, 1); } } } const targetAudience = popupSweetAlert.querySelector('select[name="target_audience"]'); if (targetAudience) { if (lp_course_ai_setting?.target_audience) { targetAudience.tomselect.setValue(lp_course_ai_setting.target_audience); } targetAudience.addEventListener('change', event => { lp_course_ai_setting.target_audience = targetAudience.tomselect.getValue(); localStorage.setItem('lp_course_ai_setting', JSON.stringify(lp_course_ai_setting)); }); } const tone = popupSweetAlert.querySelector('select[name="tone"]'); if (tone) { if (lp_course_ai_setting?.tone) { tone.tomselect.setValue(lp_course_ai_setting.tone); } tone.addEventListener('change', event => { lp_course_ai_setting.tone = tone.tomselect.getValue(); localStorage.setItem('lp_course_ai_setting', JSON.stringify(lp_course_ai_setting)); }); } const language = popupSweetAlert.querySelector('select[name="language"]'); if (language) { if (lp_course_ai_setting?.language) { language.tomselect.setValue(lp_course_ai_setting.language); } language.addEventListener('change', event => { const value = language.tomselect.getValue(); lp_course_ai_setting.language = value ? [value] : []; localStorage.setItem('lp_course_ai_setting', JSON.stringify(lp_course_ai_setting)); }); } } }).then(result => { if (result.isDismissed) { if (lp_is_generating_course_data) { lp_is_generating_course_data = false; } } }); } showStep(args) { const { e, target } = args; e.preventDefault(); const elBtnActions = target.closest('.button-actions'); const elCreateCourseAIWrap = elBtnActions.closest(GenerateWithOpenai.selectors.elGenerateDataAiWrap); let step = parseInt(elBtnActions.dataset.step); const stepAction = target.dataset.action; if (stepAction === 'next') { step++; } else if (stepAction === 'prev') { step--; } elBtnActions.dataset.step = step; const elForm = target.closest('form'); const elContentStep = elForm.querySelector(`.step-content[data-step="${step}"]`); const elItemStep = elCreateCourseAIWrap.querySelector(`.step-item[data-step="${step}"]`); elForm.querySelectorAll('.step-content').forEach(el => el.classList.remove('active')); elContentStep.classList.add('active'); elCreateCourseAIWrap.querySelectorAll('.step-item').forEach(el => el.classList.remove('active')); elItemStep.classList.add('active'); // Get all buttons step to show/hide const form = target.closest('form'); const elBtnSteps = form.querySelectorAll('button[data-step-show]'); elBtnSteps.forEach(el => { const stepsShow = el.dataset.stepShow.split(',').map(s => parseInt(s.trim())); if (stepsShow.includes(step)) { _utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(el, 1); } else { _utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(el, 0); } }); } /** * Create prompt from data config * @param args */ generatePrompt(args) { const { e, target } = args; e.preventDefault(); _utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(target, true); // Get dataSend const form = target.closest('form'); let dataSend = JSON.parse(target.dataset.send); dataSend = _utils_js__WEBPACK_IMPORTED_MODULE_0__.mergeDataWithDatForm(form, dataSend); // Ajax to generate prompt const callBack = { success: response => { const { message, status, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_2__.show(message, status); if (status === 'success') { const elPromptTextarea = form.querySelector('textarea[name=lp-openai-prompt-generated-field]'); elPromptTextarea.value = data; const elBtnNext = form.querySelector('.lp-btn-step[data-action=next]'); elBtnNext.click(); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_2__.show(error, 'error'); }, completed: () => { _utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(target, false); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } /** * Submit prompt to OpenAI to generate course data * @param args */ generateData(args) { const { e, target } = args; e.preventDefault(); _utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(target, true); // Get dataSend const form = target.closest('form'); let dataSend = JSON.parse(target.dataset.send); dataSend = _utils_js__WEBPACK_IMPORTED_MODULE_0__.mergeDataWithDatForm(form, dataSend); const btnPrev = form.querySelector('.lp-btn-step[data-action=prev]'); _utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(btnPrev, 0); // Ajax to generate prompt const callBack = { success: response => { const { message, status, data } = response; if (lp_is_generating_course_data) { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_2__.show(message, status); } if (status === 'success') { // Save structure data lp_structure_course = data.lp_structure_course; // Set preview HTML const elResults = form.querySelector('.lp-ai-generated-results'); elResults.innerHTML = data.lp_html_preview; const elBtnNext = form.querySelector('.lp-btn-step[data-action=next]'); elBtnNext.click(); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_2__.show(error, 'error'); }, completed: () => { _utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(target, false); _utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(btnPrev, 1); lp_is_generating_course_data = false; } }; lp_is_generating_course_data = true; window.lpAJAXG.fetchAJAX(dataSend, callBack); } applyGeneratedData(args) { const { e, target } = args; e.preventDefault(); const dataApply = target.dataset.apply; const dataTarget = target.dataset.target; if (dataTarget) { if (!isLayoutGutenberg) { if (dataTarget === 'set-wp-editor-content') { this.setWPEditorContent(dataApply); } else if (dataTarget === 'set-wp-title') { const elTitleInput = document.querySelector(this.getTitleInputSelector()); if (elTitleInput) { elTitleInput.value = dataApply; elTitleInput.dispatchEvent(new Event('input', { bubbles: true })); } } } else if (dataTarget === 'set-wp-editor-content') { dispatchGutenberg('core/editor').editPost({ content: dataApply }); } else if (dataTarget === 'set-wp-title') { dispatchGutenberg('core/editor').editPost({ title: dataApply }); } } if (popupSweetAlert) { sweetalert2__WEBPACK_IMPORTED_MODULE_1___default().close(); } } copyGeneratedData(args) { const { e, target } = args; e.preventDefault(); const dataCopy = target.dataset.copy; if (navigator.clipboard) { navigator.clipboard.writeText(dataCopy).then(() => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_2__.show('Copied to clipboard!', 'success'); }).catch(err => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_2__.show('Failed to copy text: ' + err, 'error'); }); } else { // Fallback when clipboard API is unavailable const textarea = document.createElement('textarea'); textarea.value = dataCopy; textarea.style.position = 'fixed'; textarea.style.left = '-9999px'; document.body.appendChild(textarea); textarea.select(); try { const successful = document.execCommand('copy'); lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_2__.show(successful ? 'Copied to clipboard!' : 'Failed to copy text', successful ? 'success' : 'error'); } catch (err) { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_2__.show('Failed to copy text: ' + err, 'error'); } document.body.removeChild(textarea); } /*navigator.clipboard.writeText( dataCopy ).then( () => { lpToastify.show( 'Copied to clipboard!', 'success' ); } ).catch( ( err ) => { lpToastify.show( 'Failed to copy text: ' + err, 'error' ); } );*/ } setWPEditorContent(htmlContent) { const editorId = this.getEditorId(); const editor = window.tinymce?.get(editorId); if (editor) { editor.setContent(htmlContent); return; } const editorElement = document.querySelector(`#${editorId}`); if (editorElement) { editorElement.value = htmlContent; editorElement.dispatchEvent(new Event('input', { bubbles: true })); } } applyImageData(args) { const { e, target } = args; let dataSend = JSON.parse(target.dataset.send); dataSend = _utils_js__WEBPACK_IMPORTED_MODULE_0__.mergeDataWithDatForm(target.closest('form'), dataSend); //e.preventDefault(); _utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(target, true); // Ajax to generate prompt const callBack = { success: response => { const { message, status, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_2__.show(message, status); if (status === 'success') { if (this.options.isCourseBuilder) { const attachmentId = parseInt(data?.attachment_id || 0, 10); const imageSrc = this.extractImageSourceFromHtml(data?.html_image || ''); const applied = this.applyCourseBuilderFeaturedImage(attachmentId, imageSrc); if (!applied) { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_2__.show('Failed to apply image to course featured image.', 'error'); return; } } else if (!isLayoutGutenberg) { // Set image const elImagePreview = document.querySelector('#postimagediv .inside'); elImagePreview.outerHTML = data.html_image; } else { dispatchGutenberg('core/editor').editPost({ featured_media: data.attachment_id }); } if (popupSweetAlert) { sweetalert2__WEBPACK_IMPORTED_MODULE_1___default().close(); } } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_2__.show(error, 'error'); }, completed: () => { _utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(target, false); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } } /***/ }, /***/ "./assets/src/js/admin/init-tom-select.js" /*!************************************************!*\ !*** ./assets/src/js/admin/init-tom-select.js ***! \************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ initElsTomSelect: () => (/* binding */ initElsTomSelect), /* harmony export */ initTomSelect: () => (/* binding */ initTomSelect), /* harmony export */ searchUserOnListPost: () => (/* binding */ searchUserOnListPost) /* harmony export */ }); /* harmony import */ var _utils_admin_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utils-admin.js */ "./assets/src/js/admin/utils-admin.js"); /** * Handle data response from API for tom-select * * @param {*} response * @param {*} tomSelectEl * @param dataStruct * @param fetchAPI * @param customOptions * @param {*} callBack */ const handleResponse = (response, tomSelectEl, dataStruct, fetchAPI, customOptions = {}, callBack) => { if (!response || !tomSelectEl || !dataStruct || !fetchAPI || !callBack) { return; } //Function format render data const getTextOption = data => { if (!dataStruct.keyGetValue?.text || !dataStruct.keyGetValue.key_render) { return; } let text = dataStruct.keyGetValue.text; for (const [key, value] of Object.entries(dataStruct.keyGetValue.key_render)) { text = text.replace(new RegExp(`{{${value}}}`, 'g'), data[value]); } return text; }; // Get default item tom-select const defaultIds = tomSelectEl.dataset?.saved ? JSON.parse(tomSelectEl.dataset.saved) : 0; let options = []; // Format response data set option tom-select if (response.data[dataStruct.dataType].length > 0) { options = response.data[dataStruct.dataType].map(item => ({ value: item[dataStruct.keyGetValue.value], text: getTextOption(item) })); } // Setting option tom-select const settingOption = { items: defaultIds, render: { item(data, escape) { return `` + `
  • ${data.text}
  • `; } }, onChange: data => { if (data.length < 1) { tomSelectEl.value = ''; } }, ...customOptions, options }; if (null != tomSelectEl.tomSelectInstance) { tomSelectEl.tomSelectInstance.addOptions(options); return options; } tomSelectEl.tomSelectInstance = _utils_admin_js__WEBPACK_IMPORTED_MODULE_0__.AdminUtilsFunctions.buildTomSelect(tomSelectEl, settingOption, fetchAPI, {}, callBack); return options; }; //Init Tom-select with available options const initTomSelectWithOption = (tomSelectEl, settingTomSelect = {}) => { if (!tomSelectEl) { return null; } if (null != tomSelectEl.tomSelectInstance) { return null; } tomSelectEl.tomSelectInstance = _utils_admin_js__WEBPACK_IMPORTED_MODULE_0__.AdminUtilsFunctions.buildTomSelect(tomSelectEl, settingTomSelect); }; // Init Tom-select const initTomSelect = (tomSelectEl, customOptions = {}, customParams = {}) => { var _dataStruct$dataSendA, _dataStruct$urlApi; if (!tomSelectEl) { return; } if (tomSelectEl.classList.contains('loaded')) { return; } tomSelectEl.classList.add('loaded'); const defaultIds = tomSelectEl.dataset?.saved ? JSON.parse(tomSelectEl.dataset.saved) : 0; const dataStruct = tomSelectEl?.dataset?.struct ? JSON.parse(tomSelectEl.dataset.struct) : ''; if (!dataStruct) { initTomSelectWithOption(tomSelectEl); return; } const getParentElByTagName = (tag, el) => { const newEl = el.parentElement; if (newEl.tagName.toLowerCase() === tag) { return newEl; } if (newEl.tagName.toLowerCase() === 'html') { return false; } return getParentElByTagName(tag, newEl); }; const formParent = getParentElByTagName('form', tomSelectEl); if (formParent) { const elInput = formParent.querySelector('input[name="' + tomSelectEl.getAttribute('name') + '"]'); if (elInput) { elInput.remove(); } } const dataSendApi = (_dataStruct$dataSendA = dataStruct.dataSendApi) !== null && _dataStruct$dataSendA !== void 0 ? _dataStruct$dataSendA : ''; const urlApi = (_dataStruct$urlApi = dataStruct.urlApi) !== null && _dataStruct$urlApi !== void 0 ? _dataStruct$urlApi : ''; const settingTomSelect = { ...dataStruct.setting, ...customOptions }; if (!urlApi) { initTomSelectWithOption(tomSelectEl, settingTomSelect); return; } const fetchFunction = (keySearch = '', customParams, callback) => { const url = urlApi; const dataSend = { current_ids: defaultIds, ...dataSendApi, ...customParams }; dataSend.search = keySearch; const params = { headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': lpData.nonce }, method: 'POST', body: JSON.stringify(dataSend) }; _utils_admin_js__WEBPACK_IMPORTED_MODULE_0__.Utils.lpFetchAPI(url, params, callback); }; const callBackApi = { success: response => { handleResponse(response, tomSelectEl, dataStruct, fetchFunction, settingTomSelect, callBackApi); } }; // Fetch data for first load tom-select // Get ids selected, and show list without ids selected with limit. let idNotIn = []; if (typeof defaultIds === 'object') { idNotIn = Object.entries(defaultIds).map(([key, value]) => ({ key, value })); } if (dataSendApi?.id_not_in) { idNotIn = [...idNotIn, ...dataSendApi.id_not_in]; } customParams.id_not_in = idNotIn.join(','); fetchFunction('', customParams, callBackApi); }; // Init Tom-select user in admin const searchUserOnListPost = () => { if (lpData.show_search_author_field === '0') { return; } const elPostFilter = document.querySelector('#posts-filter'); if (!elPostFilter) { return; } let elSearchPost = elPostFilter.querySelector('.search-box'); if (!elSearchPost) { elPostFilter.insertAdjacentHTML('afterbegin', lpData.show_search_author_field); elSearchPost = elPostFilter.querySelector('.search-box'); } if (!elSearchPost) { return; } const selectNew = elSearchPost.querySelector('select#author'); if (selectNew) { return; } const createSelectUserHtml = () => { let defaultId = ''; const authorIdFilter = lpData.urlParams.author; if (authorIdFilter) { defaultId = JSON.stringify(authorIdFilter); } const dataStruct = { urlApi: _utils_admin_js__WEBPACK_IMPORTED_MODULE_0__.Api.admin.apiSearchUsers, dataType: 'users', keyGetValue: { value: 'ID', text: '{{display_name}}(#{{ID}}) - {{user_email}}', key_render: { display_name: 'display_name', user_email: 'user_email', ID: 'ID' } }, setting: { placeholder: 'Choose user' } }; const dataStructJson = JSON.stringify(dataStruct); const htmlSelectUser = `` + ``; const elInputSearch = elSearchPost.querySelector('input[name="s"]'); if (elInputSearch) { elInputSearch.insertAdjacentHTML('afterend', htmlSelectUser); } // Remove input hide default of WP. const elInputAuthor = elPostFilter.querySelector('input[name="author"]'); if (elInputAuthor) { elInputAuthor.remove(); } }; createSelectUserHtml(); }; const initElsTomSelect = () => { const tomSelectEls = document.querySelectorAll('select.lp-tom-select:not(.loaded)'); if (tomSelectEls.length) { tomSelectEls.forEach(tomSelectEl => { // Not build elements tom-select in Widget left classic of WordPress. if (tomSelectEl.closest('.widget-liquid-left')) { return; } initTomSelect(tomSelectEl); }); } }; /***/ }, /***/ "./assets/src/js/admin/utils-admin.js" /*!********************************************!*\ !*** ./assets/src/js/admin/utils-admin.js ***! \********************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ AdminUtilsFunctions: () => (/* binding */ AdminUtilsFunctions), /* harmony export */ Api: () => (/* reexport safe */ _api_js__WEBPACK_IMPORTED_MODULE_2__["default"]), /* harmony export */ Utils: () => (/* reexport module object */ _utils_js__WEBPACK_IMPORTED_MODULE_0__) /* harmony export */ }); /* harmony import */ var _utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../utils.js */ "./assets/src/js/utils.js"); /* harmony import */ var tom_select__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! tom-select */ "./node_modules/tom-select/dist/esm/tom-select.complete.js"); /* harmony import */ var _api_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../api.js */ "./assets/src/js/api.js"); /** * Library run on Admin * * @since 4.2.6.9 * @version 1.0.1 */ const AdminUtilsFunctions = { buildTomSelect(elTomSelect, options, fetchAPI, dataSend, callBackHandleData) { if (!elTomSelect) { return; } const optionDefault = { plugins: { remove_button: { title: 'Remove this item' }, dropdown_input: {} }, onInitialize() {}, onItemAdd(e) { // Get list without current item. if (fetchAPI) { const selectedOptions = Array.from(elTomSelect.selectedOptions); const selectedValues = selectedOptions.map(option => option.value); selectedValues.push(e); dataSend.id_not_in = selectedValues.join(','); fetchAPI('', dataSend, callBackHandleData); } } }; if (fetchAPI) { optionDefault.load = (keySearch, callbackTom) => { const selectedOptions = Array.from(elTomSelect.selectedOptions); const selectedValues = selectedOptions.map(option => option.value); dataSend.id_not_in = selectedValues.join(','); fetchAPI(keySearch, dataSend, AdminUtilsFunctions.callBackTomSelectSearchAPI(callbackTom, callBackHandleData)); }; } options = { ...optionDefault, ...options }; const items_selected = options.options; /*if ( options?.options?.length > 20 ) { const chunkSize = 20; const length = options.options.length; let i = 0; const chunkedOptions = { ...options }; chunkedOptions.options = items_selected.slice( i, chunkSize ); const tomSelect = new TomSelect( elTomSelect, chunkedOptions ); i += chunkSize; const interval = setInterval( () => { if ( i > ( length - 1 ) ) { clearInterval( interval ); } const optionsSlice = items_selected.slice( i, i + chunkSize ); i += chunkSize; tomSelect.addOptions( optionsSlice ); tomSelect.setValue( options.items ); }, 200 ); return tomSelect; }*/ return new tom_select__WEBPACK_IMPORTED_MODULE_1__["default"](elTomSelect, options); }, callBackTomSelectSearchAPI(callbackTom, callBackHandleData) { return { success: response => { const options = callBackHandleData.success(response); callbackTom(options); } }; }, fetchCourses(keySearch = '', dataSend = {}, callback) { const url = _api_js__WEBPACK_IMPORTED_MODULE_2__["default"].admin.apiSearchCourses; dataSend.search = keySearch; const params = { headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': lpDataAdmin.nonce }, method: 'POST', body: JSON.stringify(dataSend) }; _utils_js__WEBPACK_IMPORTED_MODULE_0__.lpFetchAPI(url, params, callback); }, fetchUsers(keySearch = '', dataSend = {}, callback) { const url = _api_js__WEBPACK_IMPORTED_MODULE_2__["default"].admin.apiSearchUsers; dataSend.search = keySearch; const params = { headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': lpDataAdmin.nonce }, method: 'POST', body: JSON.stringify(dataSend) }; _utils_js__WEBPACK_IMPORTED_MODULE_0__.lpFetchAPI(url, params, callback); } }; /***/ }, /***/ "./assets/src/js/api.js" /*!******************************!*\ !*** ./assets/src/js/api.js ***! \******************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /** * List API on backend * * @since 4.2.6 * @version 1.0.2 */ const lplistAPI = {}; let lp_rest_url; if ('undefined' !== typeof lpDataAdmin) { lp_rest_url = lpDataAdmin.lp_rest_url; lplistAPI.admin = { apiAdminNotice: lp_rest_url + 'lp/v1/admin/tools/admin-notices', apiAddons: lp_rest_url + 'lp/v1/addon/all', apiAddonAction: lp_rest_url + 'lp/v1/addon/action-n', apiAddonsPurchase: lp_rest_url + 'lp/v1/addon/info-addons-purchase', apiSearchCourses: lp_rest_url + 'lp/v1/admin/tools/search-course', apiSearchUsers: lp_rest_url + 'lp/v1/admin/tools/search-user', apiAssignUserCourse: lp_rest_url + 'lp/v1/admin/tools/assign-user-course', apiUnAssignUserCourse: lp_rest_url + 'lp/v1/admin/tools/unassign-user-course' }; } if ('undefined' !== typeof lpData) { lp_rest_url = lpData.lp_rest_url; lplistAPI.frontend = { apiWidgets: lp_rest_url + 'lp/v1/widgets/api', apiCourses: lp_rest_url + 'lp/v1/courses/archive-course', // Deprecated API, don't load from v4.3.7 apiAJAX: lp_rest_url + 'lp/v1/load_content_via_ajax/', // Deprecated since 4.3.0 apiProfileCoverImage: lp_rest_url + 'lp/v1/profile/cover-image' }; } if (lp_rest_url) { lplistAPI.apiCourses = lp_rest_url + 'lp/v1/courses/'; lplistAPI.apiEditCoursesArchiveBlock = lp_rest_url + 'lp/v1/courses/edit-archive-block'; lplistAPI.apiCoursesSuggest = lp_rest_url + 'lp/v1/courses/courses-suggest'; } /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (lplistAPI); /***/ }, /***/ "./assets/src/js/frontend/course-builder/builder-course/builder-edit-course.js" /*!*************************************************************************************!*\ !*** ./assets/src/js/frontend/course-builder/builder-course/builder-edit-course.js ***! \*************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ BuilderEditCourse: () => (/* binding */ BuilderEditCourse) /* harmony export */ }); /* harmony import */ var lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lpAssetsJsPath/utils.js */ "./assets/src/js/utils.js"); /* harmony import */ var lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! lpAssetsJsPath/lpToastify.js */ "./assets/src/js/lpToastify.js"); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! sweetalert2 */ "./node_modules/sweetalert2/dist/sweetalert2.all.js"); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(sweetalert2__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var lpAssetsJsPath_admin_edit_course_edit_curriculum__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! lpAssetsJsPath/admin/edit-course/edit-curriculum */ "./assets/src/js/admin/edit-course/edit-curriculum.js"); /* harmony import */ var _extra_info_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./extra-info.js */ "./assets/src/js/frontend/course-builder/builder-course/extra-info.js"); /* harmony import */ var _builder_form_state_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../builder-form-state.js */ "./assets/src/js/frontend/course-builder/builder-form-state.js"); /* harmony import */ var _swal_icons_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../swal-icons.js */ "./assets/src/js/frontend/course-builder/swal-icons.js"); class BuilderEditCourse { constructor() { // Only initialize on course edit pages, not quiz/question/lesson edit pages const isCourseEditPage = document.querySelector('.cb-section__course-edit'); if (!isCourseEditPage) { return; } this.init(); } static selectors = { elCBContent: '.lp-cb-content', elTabLinks: '.lp-meta-box__course-tab__tabs li a', elTabItems: '.lp-meta-box__course-tab__tabs li', elTabPanels: '.lp-meta-box-course-panels', elDataCourse: '.cb-section__course-edit', elBtnUpdateCourse: '.cb-btn-update', elBtnHeaderSave: '.lp-cb-save-btn', elBtnDraftCourse: '.cb-btn-darft', elBtnPublishCourse: '.cb-btn-publish', elBtnPendingCourse: '.cb-btn-pending', elBtnDropdownAction: '.cb-dropdown-item[data-status]', elBtnMainAction: '.cb-btn-main-action', elBtnDuplicateCourse: '.cb-btn-duplicate-course', elBtnTrashCourse: '.cb-btn-trash', elBtnSaveSettings: '.cb-btn-save-settings', elDropdownToggle: '.cb-btn-dropdown-toggle', elDropdownMenu: '.cb-dropdown-menu', elHeaderActionsDropdown: '.cb-header-actions-dropdown', elTitleInput: '#title', elTitleCharCount: '.cb-course-edit-title__char-count', elDescEditor: '#course_description_editor', elDescWordCount: '.cb-course-edit-desc__word-count', elStatus: '.course-status', elFormSetting: '.lp-form-setting-course', elCategoryTabs: '#course_category-tabs li a', elCategoryPanels: '#taxonomy-course_category .tabs-panel', elBtnToggleAddCategory: '#course_category-add-toggle', elFormCategoryWrapper: '#course_category-add', elInputNewCategory: '#newcourse_category', elSelectParentCategory: '#newcourse_category_parent', elBtnSubmitCategory: '#course_category-add-submit', elCategoryChecklist: '#course_categorychecklist', // New custom category add form selectors elBtnAddCategoryNew: '.cb-course-edit-category__btn-add-new', elFormCategoryAddNew: '.cb-course-edit-terms__form-add-category', elInputAddCategory: '.cb-course-edit-category__input', elSelectAddCategoryParent: '.cb-course-edit-category__select-parent', elBtnSaveCategory: '.cb-course-edit-category__btn-save', elBtnCancelCategoryNew: '.cb-course-edit-category__btn-cancel', elCategorySearchInput: '.cb-course-edit-category__search-input', elBtnToggleTermsSearch: '.cb-terms-header__btn-search', elTermsSearchToolbar: '.cb-terms-search-toolbar', elWrapperCheckBoxTag: '.cb-course-edit-tags__checkbox-wrapper', elFormTagAddNew: '.cb-course-edit-terms__form-add-tag', elBtnAddTagNew: '.cb-course-edit-tag__btn-add-new', elBtnCancelTagNew: '.cb-course-edit-tag__btn-cancel', elBtnSaveTag: '.cb-course-edit-tags__btn-save', elInputAddTag: '.cb-course-edit-tags__input', elTagsWrapper: '.cb-course-edit-tags__wrapper', elTagChip: '.cb-tag-chip', elTagSearchInput: '.cb-course-edit-tags__search-input', elTagEmptyState: '.cb-course-edit-tags__empty', elBtnRemoveFeatured: '.cb-remove-featured-image', elBtnSetFeatured: '.cb-featured-image-dropzone:not(.has-image)', elBtnChangeFeatured: '.cb-change-featured-image', elFeaturedImageDropzone: '.cb-featured-image-dropzone', elFeaturedImageLink: '.cb-featured-image-link', elThumbnailInput: '#course_thumbnail_id', elFeaturedImageContainer: '.cb-featured-image-container', elPublishPanel: '.cb-course-edit-publish', elPublishStatusSelect: '#cb-course-publish-status', elPublishVisibilitySelect: '#cb-course-publish-visibility', elPublishPasswordRow: '.cb-course-edit-publish__password-row', elPublishPasswordInput: '#cb-course-publish-password', elPublishDateLabel: '#cb-course-publish-date-label', elPublishDateInput: '#cb-course-publish-date', elPriceCourseData: '#price_course_data', elSaleDatesFields: '.lp_sale_dates_fields', elSalePriceScheduleBtn: '.lp_sale_price_schedule', elCancelSaleScheduleBtn: '.lp_cancel_sale_schedule', elRegularPriceInput: '#_lp_regular_price', elSalePriceInput: '#_lp_sale_price', elPriceInput: '#_lp_price', elFormField: '.form-field', elTipFloating: '.learn-press-tip-floating', elCategoryDiv: '#taxonomy-course_category', elCourseResultRadio: 'input[type="radio"][name="_lp_course_result"]', elPassingConditionField: '._lp_passing_condition_field', elBtnGetFinalQuiz: '.lp-metabox-get-final-quiz', elFinalQuizMessage: '.lp-metabox-evaluate-final_quiz', elExtraMetaInput: '.lp_course_extra_meta_box__input', elFaqMetaInput: '.lp_course_faq_meta_box__field input', elCBHorizontalTabs: '.lp-cb-tabs__item', elCBTabPanels: '.lp-cb-tab-panel', // Permalink component elPermalinkDisplay: '.cb-permalink-display', elPermalinkEditor: '.cb-permalink-editor', elPermalinkEditBtn: '.cb-permalink-edit-btn', elPermalinkOkBtn: '.cb-permalink-ok-btn', elPermalinkCancelBtn: '.cb-permalink-cancel-btn', elPermalinkSlugInput: '.cb-permalink-slug-input', elPermalinkUrl: '.cb-permalink-url', elPermalinkBaseUrl: '#cb-permalink-base-url', // Preview and Admin link elements elBtnPreview: '.cb-button.cb-btn-preview', elAdminLink: '.lp-cb-admin-link' }; init() { this.isSavingCourse = false; const editCourseCurriculum = new lpAssetsJsPath_admin_edit_course_edit_curriculum__WEBPACK_IMPORTED_MODULE_3__.EditCourseCurriculum(); const metaboxExtraInfo = new _extra_info_js__WEBPACK_IMPORTED_MODULE_4__.MetaboxExtraInfo(); editCourseCurriculum.init(); metaboxExtraInfo.init(); this.initTabs(); this.initTabTitles(); this.initCategoryTabs(); this.initCategoryTree(); this.applyCategorySearch(); this.initTagManagement(); this.initSalePriceLayout(); this.initAssessmentMetaboxFeatures(); this.initTitleCharCount(); this.initDescWordCount(); this.syncPublishStatusOptions(); this.syncPublishDateLabel(); this.syncPublishVisibilityControls(false); this.initHeaderActionsDropdown(); this.bindAiFeaturedImageListener(); this.events(); } bindAiFeaturedImageListener() { if (BuilderEditCourse._boundAiFeaturedImageListener) { return; } document.addEventListener('lp-course-builder/ai-featured-image-applied', event => { this.handleAiFeaturedImageApplied(event); }); BuilderEditCourse._boundAiFeaturedImageListener = true; } handleAiFeaturedImageApplied(event) { const attachmentId = parseInt(event?.detail?.attachmentId || 0, 10); const imageSrc = event?.detail?.imageSrc || ''; if (!attachmentId || !imageSrc) { return; } this.setFeaturedImage({ id: attachmentId, url: imageSrc, sizes: { medium: { url: imageSrc } } }); } events() { if (BuilderEditCourse._loadedEvents) { return; } BuilderEditCourse._loadedEvents = true; lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('click', [{ selector: BuilderEditCourse.selectors.elTabLinks, class: this, callBack: this.handleTabClick.name }, { selector: BuilderEditCourse.selectors.elCategoryTabs, class: this, callBack: this.handleCategoryTabClick.name }, { selector: BuilderEditCourse.selectors.elCBHorizontalTabs, class: this, callBack: this.handleCBHorizontalTabClick.name }, { selector: BuilderEditCourse.selectors.elBtnToggleAddCategory, class: this, callBack: this.toggleAddCategoryForm.name }, { selector: BuilderEditCourse.selectors.elBtnSubmitCategory, class: this, callBack: this.addNewCategory.name }, // Custom category add form handlers { selector: BuilderEditCourse.selectors.elBtnAddCategoryNew, class: this, callBack: this.toggleCustomAddCategoryForm.name }, { selector: BuilderEditCourse.selectors.elBtnToggleTermsSearch, class: this, callBack: this.toggleTermsSearchToolbar.name }, { selector: BuilderEditCourse.selectors.elBtnCancelCategoryNew, class: this, callBack: this.toggleCustomAddCategoryForm.name }, { selector: BuilderEditCourse.selectors.elBtnSaveCategory, class: this, callBack: this.addNewCategoryCustom.name }, { selector: BuilderEditCourse.selectors.elBtnMainAction, class: this, callBack: this.updateCourse.name }, { selector: BuilderEditCourse.selectors.elBtnHeaderSave, class: this, callBack: this.updateCourse.name }, { selector: BuilderEditCourse.selectors.elBtnDropdownAction, class: this, callBack: this.updateCourse.name }, { selector: BuilderEditCourse.selectors.elBtnDuplicateCourse, class: this, callBack: this.duplicateCourse.name }, { selector: BuilderEditCourse.selectors.elBtnTrashCourse, class: this, callBack: this.trashCourse.name }, { selector: BuilderEditCourse.selectors.elBtnSaveSettings, class: this, callBack: this.saveSettings.name }, { selector: BuilderEditCourse.selectors.elBtnGetFinalQuiz, class: this, callBack: this.getFinalQuiz.name }, { selector: BuilderEditCourse.selectors.elBtnAddTagNew, class: this, callBack: this.toggleAddTagForm.name }, { selector: BuilderEditCourse.selectors.elBtnCancelTagNew, class: this, callBack: this.toggleAddTagForm.name }, { selector: BuilderEditCourse.selectors.elBtnSaveTag, class: this, callBack: this.addNewTag.name }, { selector: BuilderEditCourse.selectors.elBtnSetFeatured, class: this, callBack: this.openMediaUploader.name }, { selector: BuilderEditCourse.selectors.elFeaturedImageLink, class: this, callBack: this.openMediaUploader.name }, { selector: BuilderEditCourse.selectors.elBtnChangeFeatured, class: this, callBack: this.openMediaUploader.name }, { selector: BuilderEditCourse.selectors.elBtnRemoveFeatured, class: this, callBack: this.removeFeaturedImage.name }, { selector: BuilderEditCourse.selectors.elSalePriceScheduleBtn, class: this, callBack: this.handleScheduleClick.name }, { selector: BuilderEditCourse.selectors.elCancelSaleScheduleBtn, class: this, callBack: this.handleCancelSchedule.name }, // Permalink component events { selector: BuilderEditCourse.selectors.elPermalinkEditBtn, class: this, callBack: this.handlePermalinkEdit.name }, { selector: BuilderEditCourse.selectors.elPermalinkOkBtn, class: this, callBack: this.handlePermalinkOk.name }, { selector: BuilderEditCourse.selectors.elPermalinkCancelBtn, class: this, callBack: this.handlePermalinkCancel.name }]); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('change', [{ selector: '.lp-meta-box input, .forminp input', class: this, callBack: this.showHideOptionsDependency.name }, { selector: '#course_category-pop input[type="checkbox"]', class: this, callBack: this.handleMostUsedChange.name }, { selector: 'input[name="course_tags[]"]', class: this, callBack: this.handleTagSelectionChange.name }, { selector: BuilderEditCourse.selectors.elCourseResultRadio, class: this, callBack: this.handleCourseResultChange.name }, { selector: BuilderEditCourse.selectors.elPublishVisibilitySelect, class: this, callBack: this.handlePublishVisibilityChange.name }, { selector: BuilderEditCourse.selectors.elPublishStatusSelect, class: this, callBack: this.handlePublishStatusChange.name }, { selector: BuilderEditCourse.selectors.elPublishDateInput, class: this, callBack: this.handlePublishDateChange.name }]); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('input', [{ selector: BuilderEditCourse.selectors.elPriceCourseData, class: this, callBack: this.validateSalePrice.name }, { selector: BuilderEditCourse.selectors.elTitleInput, class: this, callBack: this.handleTitleInput.name }, { selector: BuilderEditCourse.selectors.elTagSearchInput, class: this, callBack: this.handleTagSearchInput.name }, { selector: BuilderEditCourse.selectors.elCategorySearchInput, class: this, callBack: this.handleCategorySearchInput.name }]); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('keydown', [{ selector: BuilderEditCourse.selectors.elInputNewCategory, class: this, callBack: this.addNewCategory.name, checkIsEventEnter: true }, { selector: BuilderEditCourse.selectors.elInputAddCategory, class: this, callBack: this.addNewCategoryCustom.name, checkIsEventEnter: true }, { selector: BuilderEditCourse.selectors.elInputAddTag, class: this, callBack: this.addNewTag.name, checkIsEventEnter: true }, { selector: BuilderEditCourse.selectors.elExtraMetaInput, class: this, callBack: this.preventEnterSubmitInMetaInput.name, checkIsEventEnter: true }, { selector: BuilderEditCourse.selectors.elFaqMetaInput, class: this, callBack: this.preventEnterSubmitInMetaInput.name, checkIsEventEnter: true }]); } initAssessmentMetaboxFeatures() { this.updatePassingConditionVisibility(); } handleCourseResultChange() { this.updatePassingConditionVisibility(); } updatePassingConditionVisibility() { const listHides = ['evaluate_final_quiz', 'evaluate_final_assignment']; const checkedEvaluation = document.querySelector(`${BuilderEditCourse.selectors.elCourseResultRadio}:checked`); const shouldHidePassing = checkedEvaluation ? listHides.includes(checkedEvaluation.value) : false; document.querySelectorAll(BuilderEditCourse.selectors.elPassingConditionField).forEach(el => { el.style.display = shouldHidePassing ? 'none' : ''; }); } preventEnterSubmitInMetaInput(args) { const { e, target } = args; e.preventDefault(); if (target?.blur) { target.blur(); } } async getFinalQuiz(args) { const { e, target } = args; e.preventDefault(); const btn = target.closest(BuilderEditCourse.selectors.elBtnGetFinalQuiz); if (!btn || btn.dataset.loadingState === 'yes') { return; } const defaultText = btn.textContent; const loadingText = btn.dataset.loading || defaultText; const currentMessage = btn.parentNode?.querySelector(BuilderEditCourse.selectors.elFinalQuizMessage) || document.querySelector(BuilderEditCourse.selectors.elFinalQuizMessage); if (currentMessage) { currentMessage.remove(); } btn.dataset.loadingState = 'yes'; btn.textContent = loadingText; try { const response = await this.requestFinalQuiz(btn.dataset.postid || ''); const message = response?.data || response?.message || ''; btn.textContent = defaultText; const messageNode = document.createElement('div'); messageNode.className = 'lp-metabox-evaluate-final_quiz'; messageNode.innerHTML = message; btn.parentNode.insertBefore(messageNode, btn.nextSibling); } catch (error) { btn.textContent = defaultText; if (error?.message) { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message, 'error'); } } finally { delete btn.dataset.loadingState; } } async requestFinalQuiz(courseId = '') { if (typeof wp !== 'undefined' && typeof wp.apiFetch === 'function') { return wp.apiFetch({ path: 'lp/v1/admin/course/get_final_quiz', method: 'POST', data: { courseId, isCourseBuilder: true } }); } const restBase = window.lpGlobalSettings?.rest || window.lpData?.lp_rest_url || '/wp-json/'; const restNonce = window.lpGlobalSettings?.nonce || window.lpData?.nonce || ''; const normalizedRestBase = restBase.endsWith('/') ? restBase : `${restBase}/`; const response = await fetch(`${normalizedRestBase}lp/v1/admin/course/get_final_quiz`, { method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/json', ...(restNonce ? { 'X-WP-Nonce': restNonce } : {}) }, body: JSON.stringify({ courseId, isCourseBuilder: true }) }); let responseData = {}; try { responseData = await response.json(); } catch (error) { throw new Error('Cannot parse final quiz response'); } if (!response.ok) { throw new Error(responseData?.message || `Request failed (${response.status})`); } return responseData; } initTagManagement() { this.syncTagManagement(); } getTagManagementElements() { const wrapper = document.querySelector(BuilderEditCourse.selectors.elTagsWrapper); if (!wrapper) { return null; } return { wrapper, searchInput: wrapper.querySelector(BuilderEditCourse.selectors.elTagSearchInput), list: wrapper.querySelector(BuilderEditCourse.selectors.elWrapperCheckBoxTag), emptyState: wrapper.querySelector(BuilderEditCourse.selectors.elTagEmptyState) }; } getTagChipName(chip) { return chip.dataset.tagName || chip.querySelector('.cb-tag-chip__name')?.textContent?.trim()?.toLowerCase() || ''; } updateTagEmptyState(emptyState, searchTerm = '', visibleCount = 0) { if (!emptyState) { return; } const emptyDefault = emptyState.dataset.emptyDefault || ''; const emptySearch = emptyState.dataset.emptySearch || emptyDefault; emptyState.textContent = searchTerm ? emptySearch : emptyDefault; emptyState.classList.toggle('lp-hidden', visibleCount > 0); } syncTagManagement() { const elements = this.getTagManagementElements(); if (!elements || !elements.list) { return; } const searchTerm = elements.searchInput?.value?.trim().toLowerCase() || ''; const chips = Array.from(elements.wrapper.querySelectorAll(BuilderEditCourse.selectors.elTagChip)).sort((chipA, chipB) => { const chipASelected = chipA.querySelector('input[name="course_tags[]"]')?.checked ? 1 : 0; const chipBSelected = chipB.querySelector('input[name="course_tags[]"]')?.checked ? 1 : 0; if (chipASelected !== chipBSelected) { return chipBSelected - chipASelected; } return this.getTagChipName(chipA).localeCompare(this.getTagChipName(chipB)); }); let visibleCount = 0; chips.forEach(chip => { const matchesSearch = !searchTerm || this.getTagChipName(chip).includes(searchTerm); const shouldShow = matchesSearch; chip.classList.toggle('lp-hidden', !shouldShow); elements.list.appendChild(chip); if (shouldShow) { visibleCount += 1; } }); this.updateTagEmptyState(elements.emptyState, searchTerm, visibleCount); } handleTagSelectionChange() { this.syncTagManagement(); } handleTagSearchInput() { this.syncTagManagement(); } handleCategorySearchInput() { this.applyCategorySearch(); } toggleTermsSearchToolbar(args) { const { e, target } = args; if (e) e.preventDefault(); const btnSearch = target?.closest(BuilderEditCourse.selectors.elBtnToggleTermsSearch); if (!btnSearch) { return; } const toolbarTarget = btnSearch.dataset.toggleTarget || ''; const toolbar = toolbarTarget ? document.querySelector(toolbarTarget) : null; if (!toolbar) { return; } const willOpen = !toolbar.classList.contains('is-open'); toolbar.classList.toggle('is-open', willOpen); btnSearch.setAttribute('aria-expanded', willOpen ? 'true' : 'false'); const searchInput = toolbar.querySelector('input[type="search"]'); if (willOpen) { if (searchInput) { setTimeout(() => searchInput.focus(), 220); } return; } if (searchInput) { searchInput.value = ''; } if (searchInput?.matches(BuilderEditCourse.selectors.elCategorySearchInput)) { this.applyCategorySearch(); } else if (searchInput?.matches(BuilderEditCourse.selectors.elTagSearchInput)) { this.syncTagManagement(); } } getDirectChildByTagName(element, tagName) { return Array.from(element?.children || []).find(child => child.tagName === tagName); } getCategoryLabelText(li) { const label = this.getDirectChildByTagName(li, 'LABEL'); return label?.textContent?.trim()?.toLowerCase() || ''; } filterCategoryItem(li, searchTerm) { const childList = Array.from(li.children).find(child => child.tagName === 'UL' && child.classList.contains('children')); const childItems = childList ? Array.from(childList.children).filter(child => child.tagName === 'LI') : []; const selfMatch = !searchTerm || this.getCategoryLabelText(li).includes(searchTerm); const childMatch = childItems.some(child => this.filterCategoryItem(child, searchTerm)); const shouldShow = !searchTerm || selfMatch || childMatch; li.classList.toggle('lp-hidden', !shouldShow); if (searchTerm && childList) { li.classList.toggle('children-visible', selfMatch || childMatch); } return shouldShow; } applyCategorySearch() { const wrapper = document.querySelector(BuilderEditCourse.selectors.elCategoryDiv); const searchInput = document.querySelector(BuilderEditCourse.selectors.elCategorySearchInput); if (!wrapper || !searchInput) { return; } const searchTerm = searchInput.value.trim().toLowerCase(); const panels = wrapper.querySelectorAll('.tabs-panel'); panels.forEach(panel => { const rootLists = Array.from(panel.children).filter(child => child.tagName === 'UL'); const items = rootLists.reduce((result, list) => { return result.concat(Array.from(list.children).filter(child => child.tagName === 'LI')); }, []); if (items.length) { items.forEach(item => this.filterCategoryItem(item, searchTerm)); } }); if (!searchTerm) { this.expandCheckedCategories(wrapper); } } initCategoryTabs() { const allTab = document.querySelector('#course_category-tabs a[href="#course_category-all"]'); if (allTab) { allTab.closest('li').classList.add('tabs'); const panelAll = document.querySelector('#course_category-all'); if (panelAll) panelAll.style.display = 'block'; } } handleCategoryTabClick(args) { const { e, target } = args; e.preventDefault(); const link = target.closest('a'); if (!link) return; const wrapper = document.querySelector(BuilderEditCourse.selectors.elCategoryDiv); const tabs = wrapper.querySelectorAll('.category-tabs li'); const panels = wrapper.querySelectorAll('.tabs-panel'); const targetId = link.getAttribute('href'); tabs.forEach(t => t.classList.remove('tabs', 'active')); panels.forEach(p => p.style.display = 'none'); link.closest('li').classList.add('tabs'); const targetPanel = wrapper.querySelector(targetId); if (targetPanel) targetPanel.style.display = 'block'; if (targetId === '#course_category-pop') { this.syncMostUsedTabs(); } this.applyCategorySearch(); } syncMostUsedTabs() { const allPanel = document.querySelector('#course_category-all'); const popPanel = document.querySelector('#course_category-pop'); if (!allPanel || !popPanel) return; const popInputs = popPanel.querySelectorAll('input[type="checkbox"]'); popInputs.forEach(popInput => { const termId = popInput.value; const allInput = allPanel.querySelector(`input[value="${termId}"]`); if (allInput) { popInput.checked = allInput.checked; } }); } handleMostUsedChange(args) { const { target } = args; const termId = target.value; const isChecked = target.checked; const allInput = document.querySelector(`#course_category-all input[value="${termId}"]`); if (allInput) { allInput.checked = isChecked; if (isChecked) { const parentLi = allInput.closest('li'); if (parentLi) parentLi.classList.add('children-visible'); let current = parentLi; while (current && current.parentElement.closest('li')) { current = current.parentElement.closest('li'); current.classList.add('children-visible'); } } } } toggleAddCategoryForm(args) { const { e } = args; if (e) e.preventDefault(); const form = document.querySelector(BuilderEditCourse.selectors.elFormCategoryWrapper); const input = document.querySelector(BuilderEditCourse.selectors.elInputNewCategory); if (form) { const isHidden = window.getComputedStyle(form).display === 'none'; if (isHidden) { form.style.display = 'block'; if (input) setTimeout(() => { input.focus(); input.value = ''; }, 100); } else { form.style.display = 'none'; } } } initCategoryTree() { const wrapper = document.querySelector(BuilderEditCourse.selectors.elCategoryDiv); if (!wrapper) return; const childLists = wrapper.querySelectorAll('ul.children'); childLists.forEach(ul => { const parentLi = ul.parentElement; if (parentLi && parentLi.tagName === 'LI') { this.addToggleBtnToLi(parentLi); } }); if (!BuilderEditCourse._treeEventAttached) { wrapper.addEventListener('click', e => { if (e.target.classList.contains('lp-cat-toggle')) { e.preventDefault(); e.stopPropagation(); const li = e.target.closest('li'); li.classList.toggle('children-visible'); } }); wrapper.addEventListener('change', e => { if (e.target.type === 'checkbox') { const li = e.target.closest('li'); if (li && e.target.checked) { li.classList.add('children-visible'); } } }); BuilderEditCourse._treeEventAttached = true; } this.expandCheckedCategories(wrapper); } expandCheckedCategories(wrapper) { const checkedInputs = wrapper.querySelectorAll('input[type="checkbox"]:checked'); checkedInputs.forEach(input => { let currentLi = input.closest('li'); while (currentLi) { const parentUl = currentLi.closest('ul'); if (parentUl && parentUl.classList.contains('children')) { const parentCategoryLi = parentUl.closest('li'); if (parentCategoryLi) { parentCategoryLi.classList.add('children-visible'); currentLi = parentCategoryLi; } else { currentLi = null; } } else { currentLi = null; } } }); } addToggleBtnToLi(li) { const label = li.querySelector('label'); if (!label || label.querySelector('.lp-cat-toggle')) return; const toggleBtn = document.createElement('span'); toggleBtn.className = 'lp-cat-toggle'; toggleBtn.title = 'Toggle sub-categories'; label.appendChild(toggleBtn); } addNewCategory(args) { const { e } = args; if (e) e.preventDefault(); const elInput = document.querySelector(BuilderEditCourse.selectors.elInputNewCategory); const elParent = document.querySelector(BuilderEditCourse.selectors.elSelectParentCategory); const btnSave = document.querySelector(BuilderEditCourse.selectors.elBtnSubmitCategory); const categoryName = elInput?.value?.trim(); if (!categoryName) { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show('Please enter category name', 'error'); return; } const parentId = elParent ? parseInt(elParent.value) : 0; lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(btnSave, 1); const dataSend = { action: 'add_course_category', args: { id_url: 'add-course-category' }, name: categoryName, parent: parentId }; const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (data?.html) { const checklist = document.querySelector(BuilderEditCourse.selectors.elCategoryChecklist); if (data.parent && data.parent > 0) { const parentInput = checklist.querySelector(`input[value="${data.parent}"]`); if (parentInput) { const parentLi = parentInput.closest('li'); parentLi.classList.add('children-visible'); let ulChildren = parentLi.querySelector(':scope > ul.children'); if (!ulChildren) { ulChildren = document.createElement('ul'); ulChildren.className = 'children'; parentLi.appendChild(ulChildren); this.addToggleBtnToLi(parentLi); } ulChildren.insertAdjacentHTML('beforeend', data.html); } else { checklist.insertAdjacentHTML('afterbegin', data.html); } } else { checklist.insertAdjacentHTML('afterbegin', data.html); } elInput.value = ''; if (elParent) elParent.value = '0'; this.applyCategorySearch(); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(btnSave, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } /** * Toggle custom category add form (between header and WP meta box). * Shows/hides the form and toggles the Add New button. */ toggleCustomAddCategoryForm(args) { const { target } = args; const elBtnAdd = document.querySelector(BuilderEditCourse.selectors.elBtnAddCategoryNew); const form = document.querySelector(BuilderEditCourse.selectors.elFormCategoryAddNew); const isOpening = target.closest(BuilderEditCourse.selectors.elBtnAddCategoryNew); if (form) { if (isOpening) { form.style.display = 'flex'; if (elBtnAdd) elBtnAdd.style.display = 'none'; const input = form.querySelector(BuilderEditCourse.selectors.elInputAddCategory); if (input) setTimeout(() => input.focus(), 100); } else { form.style.display = 'none'; if (elBtnAdd) elBtnAdd.style.display = 'inline-flex'; } } } /** * Add new category via custom form (outside WP meta box). * Uses the same AJAX endpoint but reads from custom form fields. */ addNewCategoryCustom(args) { const { e } = args; if (e) e.preventDefault(); const elInput = document.querySelector(BuilderEditCourse.selectors.elInputAddCategory); const elParent = document.querySelector(BuilderEditCourse.selectors.elSelectAddCategoryParent); const btnSave = document.querySelector(BuilderEditCourse.selectors.elBtnSaveCategory); const categoryName = elInput?.value?.trim(); if (!categoryName) { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show('Please enter category name', 'error'); return; } const parentId = elParent ? parseInt(elParent.value) : 0; lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(btnSave, 1); const dataSend = { action: 'add_course_category', args: { id_url: 'add-course-category' }, name: categoryName, parent: parentId }; const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (data?.html) { const checklist = document.querySelector(BuilderEditCourse.selectors.elCategoryChecklist); if (checklist) { if (data.parent && data.parent > 0) { const parentInput = checklist.querySelector(`input[value="${data.parent}"]`); if (parentInput) { const parentLi = parentInput.closest('li'); parentLi.classList.add('children-visible'); let ulChildren = parentLi.querySelector(':scope > ul.children'); if (!ulChildren) { ulChildren = document.createElement('ul'); ulChildren.className = 'children'; parentLi.appendChild(ulChildren); this.addToggleBtnToLi(parentLi); } ulChildren.insertAdjacentHTML('beforeend', data.html); } else { checklist.insertAdjacentHTML('afterbegin', data.html); } } else { checklist.insertAdjacentHTML('afterbegin', data.html); } } // Also update the parent select dropdown with the new category if (data.term_id && elParent) { const newOption = document.createElement('option'); newOption.value = data.term_id; newOption.textContent = categoryName; elParent.appendChild(newOption); } elInput.value = ''; if (elParent) elParent.value = '0'; this.applyCategorySearch(); // Close the form after successful add const elBtnCancel = document.querySelector(BuilderEditCourse.selectors.elBtnCancelCategoryNew); if (elBtnCancel) elBtnCancel.click(); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(btnSave, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } initSalePriceLayout() { const wrap = document.querySelector(BuilderEditCourse.selectors.elPriceCourseData); if (!wrap) return; const saleDatesFields = wrap.querySelectorAll(BuilderEditCourse.selectors.elSaleDatesFields); const scheduleBtn = wrap.querySelector(BuilderEditCourse.selectors.elSalePriceScheduleBtn); const cancelBtn = wrap.querySelector(BuilderEditCourse.selectors.elCancelSaleScheduleBtn); let saleScheduleSet = false; const allInputs = wrap.querySelectorAll(`${BuilderEditCourse.selectors.elSaleDatesFields} input`); allInputs.forEach(input => { if (input.value && input.value.trim() !== '') { saleScheduleSet = true; } }); if (saleScheduleSet) { if (scheduleBtn) scheduleBtn.style.display = 'none'; if (cancelBtn) cancelBtn.style.display = 'inline-block'; saleDatesFields.forEach(field => field.style.display = 'block'); } else { if (scheduleBtn) scheduleBtn.style.display = 'inline-block'; if (cancelBtn) cancelBtn.style.display = 'none'; saleDatesFields.forEach(field => field.style.display = 'none'); } } handleScheduleClick(args) { const { e, target } = args; e.preventDefault(); const btn = target.closest(BuilderEditCourse.selectors.elSalePriceScheduleBtn); const wrap = btn.closest(BuilderEditCourse.selectors.elPriceCourseData); if (!wrap) return; const cancelBtn = wrap.querySelector(BuilderEditCourse.selectors.elCancelSaleScheduleBtn); const saleDatesFields = wrap.querySelectorAll(BuilderEditCourse.selectors.elSaleDatesFields); btn.style.display = 'none'; if (cancelBtn) cancelBtn.style.display = 'inline-block'; saleDatesFields.forEach(field => field.style.display = 'block'); } handleCancelSchedule(args) { const { e, target } = args; e.preventDefault(); const btn = target.closest(BuilderEditCourse.selectors.elCancelSaleScheduleBtn); const wrap = btn.closest(BuilderEditCourse.selectors.elPriceCourseData); if (!wrap) return; const scheduleBtn = wrap.querySelector(BuilderEditCourse.selectors.elSalePriceScheduleBtn); const saleDatesFields = wrap.querySelectorAll(BuilderEditCourse.selectors.elSaleDatesFields); const allInputs = wrap.querySelectorAll(`${BuilderEditCourse.selectors.elSaleDatesFields} input`); btn.style.display = 'none'; if (scheduleBtn) scheduleBtn.style.display = 'inline-block'; saleDatesFields.forEach(field => field.style.display = 'none'); allInputs.forEach(input => input.value = ''); } validateSalePrice(args) { const { target } = args; const wrapper = target.closest(BuilderEditCourse.selectors.elPriceCourseData); if (!wrapper) return; const regularPriceInput = wrapper.querySelector(BuilderEditCourse.selectors.elRegularPriceInput); const salePriceInput = wrapper.querySelector(BuilderEditCourse.selectors.elSalePriceInput); const existingTips = wrapper.querySelectorAll(BuilderEditCourse.selectors.elTipFloating); existingTips.forEach(tip => tip.remove()); if (!regularPriceInput || !salePriceInput) return; const regularVal = parseFloat(regularPriceInput.value) || 0; const saleVal = parseFloat(salePriceInput.value) || 0; if (salePriceInput.value !== '' && saleVal > regularVal) { const targetId = target.getAttribute('id'); const formField = target.closest(BuilderEditCourse.selectors.elFormField); const i18n = typeof lpAdminCourseEditorSettings !== 'undefined' && lpAdminCourseEditorSettings.i18n ? lpAdminCourseEditorSettings.i18n : { notice_price: 'Regular price must be greater than sale price.', notice_sale_price: 'Sale price must be less than regular price.' }; const tip = document.createElement('div'); tip.className = 'learn-press-tip-floating'; if (targetId === BuilderEditCourse.selectors.elPriceInput) { tip.innerHTML = i18n.notice_price; } else if (targetId === BuilderEditCourse.selectors.elSalePriceInput) { tip.innerHTML = i18n.notice_sale_price; } if (formField && tip.innerHTML) { formField.appendChild(tip); } } } showHideOptionsDependency(args) { const { target } = args; if (target.tagName === 'INPUT') { if (target.closest('.forminp ')) { const nameInput = target.name; const classDependency = nameInput.replace('learn_press_', ''); const elClassDependency = document.querySelectorAll(`.show_if_${classDependency}`); if (elClassDependency) { elClassDependency.forEach(el => { el.classList.toggle('lp-option-disabled'); }); } } else if (target.closest('.lp-meta-box')) { const elLPMetaBox = target.closest('.lp-meta-box'); const nameInput = target.name; const elClassDependency = elLPMetaBox.querySelectorAll(`[data-dependency="${nameInput}"]`); if (elClassDependency) { elClassDependency.forEach(el => { el.classList.toggle('lp-option-disabled'); }); } } } } initTabs() { const tabLinks = document.querySelectorAll(BuilderEditCourse.selectors.elTabLinks); if (tabLinks.length > 0) { this.activateTab(tabLinks[0]); } } handleTabClick(args) { const { e, target } = args; e.preventDefault(); const linkElement = target.closest('a'); if (linkElement) { this.activateTab(linkElement); } } activateTab(linkElement) { const tabItems = document.querySelectorAll(BuilderEditCourse.selectors.elTabItems); const panels = document.querySelectorAll(BuilderEditCourse.selectors.elTabPanels); const targetId = linkElement.getAttribute('href').substring(1); const targetPanel = document.getElementById(targetId); if (!targetPanel) return; tabItems.forEach(li => li.classList.remove('active')); panels.forEach(panel => panel.style.display = 'none'); linkElement.parentElement.classList.add('active'); targetPanel.style.display = 'block'; } /** * Handle horizontal tab click for client-side tab switching. * Uses lpShowHideEl with lp-hidden class. * * @param {Object} args - Event args containing e and target */ handleCBHorizontalTabClick(args) { const { e, target } = args; e.preventDefault(); const tab = target.closest(BuilderEditCourse.selectors.elCBHorizontalTabs); if (!tab) return; const sectionSlug = tab.dataset.tabSection; if (!sectionSlug) return; // Update active tab const allTabs = document.querySelectorAll(BuilderEditCourse.selectors.elCBHorizontalTabs); allTabs.forEach(t => t.classList.remove('is-active')); tab.classList.add('is-active'); const url = new URL(window.location.href); url.searchParams.set('tab', sectionSlug); window.history.replaceState({}, '', url); // Show/hide panels using lpShowHideEl const allPanels = document.querySelectorAll(BuilderEditCourse.selectors.elCBTabPanels); allPanels.forEach(panel => { const isTarget = panel.dataset.section === sectionSlug; lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(panel, isTarget ? 1 : 0); }); } /** * Collect course data from all tabs for update. * Since all tabs are now rendered in DOM (client-side tab switching), * this method collects data from Overview tab (title, desc, categories, tags, thumbnail) * and Settings tab (form fields) when present. * * @return {Object} Course data object */ getCourseDataForUpdate() { const data = {}; // Get course ID from wrapper (could be in any tab panel) const wrapperEl = document.querySelector(BuilderEditCourse.selectors.elDataCourse); data.course_id = wrapperEl ? parseInt(wrapperEl.dataset.courseId) || 0 : 0; // --- Overview Tab Data --- // Title const titleInput = document.querySelector(BuilderEditCourse.selectors.elTitleInput); data.course_title = titleInput ? titleInput.value : ''; // Description (TinyMCE or textarea) const descEditor = document.querySelector(BuilderEditCourse.selectors.elDescEditor); data.course_description = descEditor ? descEditor.value : ''; if (typeof tinymce !== 'undefined') { const editor = tinymce.get('course_description_editor'); if (editor) { data.course_description = editor.getContent(); } } // Categories data.course_categories = []; document.querySelectorAll('#taxonomy-course_category input[name*="course_category"]:checked').forEach(checkbox => data.course_categories.push(checkbox.value)); // Tags data.course_tags = []; document.querySelectorAll('input[name="course_tags[]"]:checked').forEach(checkbox => data.course_tags.push(checkbox.value)); // Thumbnail const thumbnailInput = document.querySelector(BuilderEditCourse.selectors.elThumbnailInput); data.course_thumbnail_id = thumbnailInput ? thumbnailInput.value : '0'; // Permalink/Slug const permalinkInput = document.querySelector(BuilderEditCourse.selectors.elPermalinkSlugInput); if (permalinkInput && permalinkInput.value) { data.course_permalink = permalinkInput.value; } // --- Settings Tab Data --- const elFormSetting = document.querySelector(BuilderEditCourse.selectors.elFormSetting); if (elFormSetting) { data.course_settings = true; const formElements = elFormSetting.querySelectorAll('input, select, textarea'); formElements.forEach(element => { const name = element.name || element.id; if (!name) return; // Skip WP nonce and referer fields if (name === 'learnpress_meta_box_nonce' || name === '_wp_http_referer') return; const isArray = name.endsWith('[]'); const fieldName = name.replace('[]', ''); if (element.type === 'checkbox') { if (isArray) { if (!data[fieldName]) data[fieldName] = []; if (element.checked) { data[fieldName].push(element.value); } } else { data[fieldName] = element.checked ? 'yes' : 'no'; } } else if (element.type === 'radio') { if (element.checked) { data[fieldName] = element.value; } } else if (element.type === 'select-multiple') { // Collect every selected option, not just the first one (element.value). const selectedValues = Array.from(element.selectedOptions).map(option => option.value).filter(value => value !== ''); if (!Array.isArray(data[fieldName])) { data[fieldName] = []; } data[fieldName].push(...selectedValues); } else if (element.type === 'file') { if (element.files && element.files.length > 0) { data[fieldName] = element.files; } } else { if (isArray) { if (!data.hasOwnProperty(fieldName)) { data[fieldName] = []; } if (Array.isArray(data[fieldName])) { data[fieldName].push(element.value); } } else { // Only set if not already set (first value wins) if (!data.hasOwnProperty(fieldName)) { data[fieldName] = element.value; } } } }); } // Convert settings arrays to comma-separated strings for API // Exclude course_categories and course_tags - they're handled separately. // Exclude the extra-info fields too: their values are free text that may // contain commas, so they must stay as arrays (one entry per input) and // not be comma-joined, or the server splits a single value into several. const excludeFromConversion = ['course_categories', 'course_tags', '_lp_requirements', '_lp_target_audiences', '_lp_key_features', '_lp_faqs_question', '_lp_faqs_answer']; Object.keys(data).forEach(key => { if (Array.isArray(data[key]) && !excludeFromConversion.includes(key)) { data[key] = data[key].join(','); } }); return data; } updateCourse(args) { // Context check: only handle if on course edit page if (!document.querySelector(BuilderEditCourse.selectors.elDataCourse)) { return; } // Prevent double submit while request is running. if (this.isSavingCourse) { return; } const { e, target } = args; if (e) { e.preventDefault(); } // Find which button was clicked and determine status from data attribute const elBtnMainAction = target.closest(BuilderEditCourse.selectors.elBtnMainAction); const elBtnHeaderSave = target.closest(BuilderEditCourse.selectors.elBtnHeaderSave); const elBtnDropdownAction = target.closest(BuilderEditCourse.selectors.elBtnDropdownAction); let targetStatus = 'publish'; let elBtn = null; // Determine status from the clicked button's data-status attribute or class if (elBtnMainAction) { targetStatus = elBtnMainAction.dataset.status || 'publish'; elBtn = elBtnMainAction; } else if (elBtnDropdownAction) { targetStatus = elBtnDropdownAction.dataset.status || 'publish'; elBtn = elBtnDropdownAction; } else if (elBtnHeaderSave) { // Header save button uses current main action status const mainBtn = document.querySelector(BuilderEditCourse.selectors.elBtnMainAction); targetStatus = mainBtn?.dataset.status || 'publish'; elBtn = elBtnHeaderSave; } if (!elBtn) return; // Course publish status is controlled by the Publish panel when available. if (elBtnMainAction || elBtnHeaderSave) { targetStatus = this.getStatusFromPublishPanel(targetStatus); } const publishVisibilityEl = document.querySelector(BuilderEditCourse.selectors.elPublishVisibilitySelect); const publishPasswordEl = document.querySelector(BuilderEditCourse.selectors.elPublishPasswordInput); const publishVisibility = publishVisibilityEl?.value || ''; const publishPassword = publishPasswordEl?.value?.trim?.() || ''; if (publishVisibility === 'password' && !publishPassword) { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show('Password is required when visibility is password protected.', 'error'); publishPasswordEl?.focus?.(); return; } // Check if drafting a published course if (targetStatus === 'draft') { const statusEl = document.querySelector(BuilderEditCourse.selectors.elStatus); const isPublished = statusEl && statusEl.classList.contains('publish'); if (isPublished) { const confirmMsg = elBtn.dataset.confirmUnpublish || 'Saving as draft will unpublish this item. Are you sure?'; if (!confirm(confirmMsg)) { return; } } } const setActionLoadingState = isLoading => { const elsToToggle = []; const elHeaderSave = document.querySelector(BuilderEditCourse.selectors.elBtnHeaderSave); const elMainAction = document.querySelector(BuilderEditCourse.selectors.elBtnMainAction); const elDropdownToggle = document.querySelector(BuilderEditCourse.selectors.elDropdownToggle); if (elHeaderSave) { elsToToggle.push(elHeaderSave); } if (elMainAction) { elsToToggle.push(elMainAction); } if (elDropdownToggle) { elsToToggle.push(elDropdownToggle); } if (elBtn) { elsToToggle.push(elBtn); } // Keep only unique elements. const uniqueEls = [...new Set(elsToToggle.filter(Boolean))]; uniqueEls.forEach(el => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(el, isLoading ? 1 : 0); el.classList.toggle('lp-loading', Boolean(isLoading)); if (isLoading) { el.setAttribute('aria-disabled', 'true'); } else { el.removeAttribute('aria-disabled'); } }); if (isLoading && elDropdownToggle) { elDropdownToggle.setAttribute('aria-expanded', 'false'); } }; this.isSavingCourse = true; setActionLoadingState(true); const courseData = this.getCourseDataForUpdate(); const dataSend = { ...courseData, course_status: targetStatus, action: 'cb_save_course', args: { id_url: 'cb-save-course' } }; if (typeof lpCourseBuilder !== 'undefined' && lpCourseBuilder.nonce) { dataSend.nonce = lpCourseBuilder.nonce; } // Handle course_categories - may be array or already a string if (courseData.course_categories) { dataSend.course_categories = Array.isArray(courseData.course_categories) ? courseData.course_categories.join(',') : courseData.course_categories; } // Handle course_tags - may be array or already a string if (courseData.course_tags) { dataSend.course_tags = Array.isArray(courseData.course_tags) ? courseData.course_tags.join(',') : courseData.course_tags; } if (courseData.course_thumbnail_id) { dataSend.course_thumbnail_id = courseData.course_thumbnail_id; } if (publishVisibility) { dataSend.course_visibility = publishVisibility; dataSend.course_password = publishVisibility === 'password' ? publishPassword : ''; } const publishDateInput = document.querySelector(BuilderEditCourse.selectors.elPublishDateInput); if (publishDateInput && publishDateInput.value) { dataSend.course_post_date = publishDateInput.value; } const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (status === 'success') { this.updateHeaderTitle(courseData.course_title); // Dispatch event to reset form state (remove unsaved changes warning) document.dispatchEvent(new CustomEvent('lp-course-builder-saved')); if (data?.html) { const elContent = elBtnMainAction.closest(BuilderEditCourse.selectors.elCBContent); const newHtml = new DOMParser().parseFromString(data.html, 'text/html'); if (elContent) { // elContent.outerHTML = data.html; // Temporary change each elements const elements = [".lp-cb-header", ".cb-course-edit-column--left"]; for (const elementNew of elements) { const el = elContent.querySelector(elementNew); if (el) { el.innerHTML = newHtml.querySelector(elementNew).innerHTML; } } } } } // Use redirect_url from backend if available (for new courses) if (data?.redirect_url) { window.location.href = data.redirect_url; } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { this.isSavingCourse = false; setActionLoadingState(false); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } /** * Resolve immediate UI status after save to avoid stale action labels * in review-only course workflow. * * @param {string|undefined} savedStatus * @param {string} requestedStatus * @return {string} */ resolveStatusForUIAfterSave(savedStatus, requestedStatus) { const normalizedSavedStatus = typeof savedStatus === 'string' ? savedStatus.trim().toLowerCase() : ''; const normalizedRequestedStatus = typeof requestedStatus === 'string' ? requestedStatus.trim().toLowerCase() : ''; const dropdown = document.querySelector(BuilderEditCourse.selectors.elHeaderActionsDropdown); const reviewOnlyCourseAttr = (dropdown?.dataset?.reviewOnlyCourse || '').toLowerCase(); const isReviewOnlyCourse = ['yes', 'true', '1'].includes(reviewOnlyCourseAttr); if (isReviewOnlyCourse && ['publish', 'private', 'future'].includes(normalizedRequestedStatus)) { return 'pending'; } return normalizedSavedStatus || normalizedRequestedStatus || 'draft'; } /** * Resolve target status from Publish panel controls. * * @param {string} fallbackStatus * @return {string} */ getStatusFromPublishPanel(fallbackStatus = 'publish') { const statusSelect = document.querySelector(BuilderEditCourse.selectors.elPublishStatusSelect); const visibilitySelect = document.querySelector(BuilderEditCourse.selectors.elPublishVisibilitySelect); let status = statusSelect?.value || fallbackStatus || 'publish'; const visibility = visibilitySelect?.value || 'public'; if (visibility === 'private' && status !== 'pending') { status = 'private'; } if (['public', 'password'].includes(visibility) && status === 'private') { status = 'publish'; } const allowedStatuses = ['publish', 'future', 'draft', 'pending', 'private']; if (!allowedStatuses.includes(status)) { return 'publish'; } return status; } /** * Sync Publish panel controls after save/trash. * * @param {string} status */ syncPublishPanelStatus(status, visibility = '') { const statusSelect = document.querySelector(BuilderEditCourse.selectors.elPublishStatusSelect); const visibilitySelect = document.querySelector(BuilderEditCourse.selectors.elPublishVisibilitySelect); if (!statusSelect && !visibilitySelect) { return; } const normalized = (status || '').toString().toLowerCase(); const currentPrimaryStatus = (statusSelect?.dataset?.primaryStatus || '').toString().toLowerCase(); let primaryStatusToKeep = ['future', 'publish'].includes(currentPrimaryStatus) ? currentPrimaryStatus : 'publish'; if (normalized === 'future') { primaryStatusToKeep = 'future'; } else if (['publish', 'private'].includes(normalized)) { primaryStatusToKeep = 'publish'; } if (statusSelect) { statusSelect.dataset.primaryStatus = primaryStatusToKeep; } if (statusSelect) { if (normalized === 'private') { statusSelect.value = 'publish'; } else if (['publish', 'future', 'draft', 'pending'].includes(normalized)) { statusSelect.value = normalized; } } this.syncPublishStatusOptions(normalized); if (visibilitySelect) { let visibilityToSet = visibility || visibilitySelect.value || 'public'; if (normalized === 'private') { visibilityToSet = 'private'; } else if (visibilityToSet === 'private') { visibilityToSet = 'public'; } visibilitySelect.value = visibilityToSet; } this.syncPublishVisibilityControls(); this.syncPublishDateLabel(); } handlePublishVisibilityChange() { this.syncPublishVisibilityControls(true); } handlePublishStatusChange() { this.syncPublishStatusOptions(); this.syncPublishDateLabel(); } handlePublishDateChange() { this.syncPublishDateLabel(); } syncPublishVisibilityControls(focusPassword = false) { const visibilitySelect = document.querySelector(BuilderEditCourse.selectors.elPublishVisibilitySelect); const passwordRow = document.querySelector(BuilderEditCourse.selectors.elPublishPasswordRow); const passwordInput = document.querySelector(BuilderEditCourse.selectors.elPublishPasswordInput); if (!visibilitySelect || !passwordRow) { return; } const isPassword = visibilitySelect.value === 'password'; passwordRow.classList.toggle('lp-hidden', !isPassword); if (focusPassword && isPassword && passwordInput) { passwordInput.focus(); } } syncPublishDateLabel() { const dateInput = document.querySelector(BuilderEditCourse.selectors.elPublishDateInput); const dateLabel = document.querySelector(BuilderEditCourse.selectors.elPublishDateLabel); if (!dateLabel) { return; } const dateValue = (dateInput?.value || '').toString().trim(); let isFutureDate = false; if (dateValue) { const parsedDate = new Date(dateValue); if (!Number.isNaN(parsedDate.getTime())) { isFutureDate = parsedDate.getTime() > Date.now(); } } dateLabel.textContent = isFutureDate ? 'Scheduled for' : 'Published on'; } syncPublishStatusOptions(preferredStatus = '') { const statusSelect = document.querySelector(BuilderEditCourse.selectors.elPublishStatusSelect); if (!statusSelect) { return; } const publishLabel = statusSelect.dataset.publishLabel || 'Published'; const futureLabel = statusSelect.dataset.futureLabel || 'Scheduled'; const selectedStatus = (preferredStatus || statusSelect.value || '').toLowerCase(); const currentPrimaryStatus = (statusSelect.dataset.primaryStatus || '').toLowerCase(); const draftLabel = statusSelect.querySelector('option[value="draft"]')?.textContent || 'Draft'; const pendingLabel = statusSelect.querySelector('option[value="pending"]')?.textContent || 'Pending Review'; const hasFutureOption = !!statusSelect.querySelector('option[value="future"]'); const hasPublishOption = !!statusSelect.querySelector('option[value="publish"]'); let primaryValue = 'publish'; if (['future', 'publish'].includes(selectedStatus)) { primaryValue = selectedStatus; } else if (['future', 'publish'].includes(currentPrimaryStatus)) { primaryValue = currentPrimaryStatus; } else if (hasFutureOption && !hasPublishOption) { primaryValue = 'future'; } const primaryLabel = primaryValue === 'future' ? futureLabel : publishLabel; const valueToSelect = ['draft', 'pending', 'future', 'publish'].includes(selectedStatus) ? selectedStatus : primaryValue; statusSelect.dataset.primaryStatus = primaryValue; statusSelect.innerHTML = ''; [{ value: primaryValue, label: primaryLabel }, { value: 'draft', label: draftLabel }, { value: 'pending', label: pendingLabel }].forEach(optionData => { const option = document.createElement('option'); option.value = optionData.value; option.textContent = optionData.label; statusSelect.appendChild(option); }); statusSelect.value = valueToSelect; } formatStatusLabel(status) { const normalized = (status || '').toString().toLowerCase(); return normalized === 'future' ? 'scheduled' : normalized; } /** * Update action buttons after status change. * Swaps main button and dropdown item based on new status. * * @param {string} newStatus - The new course status */ updateActionButtons(newStatus) { const dropdown = document.querySelector(BuilderEditCourse.selectors.elHeaderActionsDropdown); if (!dropdown) return; const mainBtn = dropdown.querySelector('.cb-btn-main-action'); const dropdownMenu = dropdown.querySelector(BuilderEditCourse.selectors.elDropdownMenu); if (!mainBtn) return; const hasSingleCourseAction = dropdown.classList.contains('cb-header-actions-dropdown--single') || !dropdownMenu; if (hasSingleCourseAction) { mainBtn.className = 'cb-btn-update cb-btn-primary cb-btn-main-action'; mainBtn.dataset.status = this.getStatusFromPublishPanel('publish'); mainBtn.textContent = mainBtn.dataset.titleUpdate || 'Update'; dropdown.dataset.currentStatus = newStatus; return; } const reviewOnlyCourseAttr = (dropdown.dataset.reviewOnlyCourse || '').toLowerCase(); const isReviewOnlyCourse = ['yes', 'true', '1'].includes(reviewOnlyCourseAttr); // Status configuration for button labels and classes const statusConfig = { publish: { mainLabel: mainBtn.dataset.titleUpdate || 'Update', mainClass: 'cb-btn-update', mainStatus: 'publish', dropdownLabel: mainBtn.dataset.titleDraft || 'Save Draft', dropdownClass: 'cb-btn-darft', dropdownStatus: 'draft', dropdownIcon: 'dashicons-media-default' }, draft: { mainLabel: mainBtn.dataset.titleDraft || 'Save Draft', mainClass: 'cb-btn-darft', mainStatus: 'draft', dropdownLabel: mainBtn.dataset.titlePublish || 'Publish', dropdownClass: 'cb-btn-publish', dropdownStatus: 'publish', dropdownIcon: 'dashicons-visibility' }, pending: { mainLabel: mainBtn.dataset.titlePublish || 'Publish', mainClass: 'cb-btn-publish', mainStatus: 'publish', dropdownLabel: mainBtn.dataset.titleDraft || 'Save Draft', dropdownClass: 'cb-btn-darft', dropdownStatus: 'draft', dropdownIcon: 'dashicons-media-default' }, trash: { mainLabel: mainBtn.dataset.titleDraft || 'Save Draft', mainClass: 'cb-btn-darft', mainStatus: 'draft', dropdownLabel: mainBtn.dataset.titlePublish || 'Publish', dropdownClass: 'cb-btn-publish', dropdownStatus: 'publish', dropdownIcon: 'dashicons-visibility' } }; const reviewStatusConfig = { publish: { mainLabel: mainBtn.dataset.titleUpdate || 'Update', mainClass: 'cb-btn-update', mainStatus: 'publish', dropdownLabel: mainBtn.dataset.titleDraft || 'Save Draft', dropdownClass: 'cb-btn-darft', dropdownStatus: 'draft', dropdownIcon: 'dashicons-media-default' }, draft: { mainLabel: mainBtn.dataset.titleDraft || 'Save Draft', mainClass: 'cb-btn-darft', mainStatus: 'draft', dropdownLabel: mainBtn.dataset.titleSubmitReview || 'Submit for Review', dropdownClass: 'cb-btn-pending', dropdownStatus: 'pending', dropdownIcon: 'dashicons-clock' }, pending: { mainLabel: mainBtn.dataset.titleSubmitReview || 'Submit for Review', mainClass: 'cb-btn-pending', mainStatus: 'pending', dropdownLabel: mainBtn.dataset.titleDraft || 'Save Draft', dropdownClass: 'cb-btn-darft', dropdownStatus: 'draft', dropdownIcon: 'dashicons-media-default' }, 'auto-draft': { mainLabel: mainBtn.dataset.titleSubmitReview || 'Submit for Review', mainClass: 'cb-btn-pending', mainStatus: 'pending', dropdownLabel: mainBtn.dataset.titleDraft || 'Save Draft', dropdownClass: 'cb-btn-darft', dropdownStatus: 'draft', dropdownIcon: 'dashicons-media-default' }, trash: { mainLabel: mainBtn.dataset.titleDraft || 'Save Draft', mainClass: 'cb-btn-darft', mainStatus: 'draft', dropdownLabel: mainBtn.dataset.titleSubmitReview || 'Submit for Review', dropdownClass: 'cb-btn-pending', dropdownStatus: 'pending', dropdownIcon: 'dashicons-clock' }, private: { mainLabel: mainBtn.dataset.titleSubmitReview || 'Submit for Review', mainClass: 'cb-btn-pending', mainStatus: 'pending', dropdownLabel: mainBtn.dataset.titleDraft || 'Save Draft', dropdownClass: 'cb-btn-darft', dropdownStatus: 'draft', dropdownIcon: 'dashicons-media-default' } }; const config = isReviewOnlyCourse ? reviewStatusConfig[newStatus] || reviewStatusConfig.draft : statusConfig[newStatus] || statusConfig.draft; // Update main button mainBtn.className = `${config.mainClass} cb-btn-primary cb-btn-main-action`; mainBtn.dataset.status = config.mainStatus; mainBtn.textContent = config.mainLabel; // Update dropdown item (first item, excluding trash) const dropdownItems = dropdownMenu.querySelectorAll('.cb-dropdown-item:not(.cb-btn-trash)'); if (dropdownItems.length > 0) { const firstItem = dropdownItems[0]; firstItem.className = `cb-dropdown-item ${config.dropdownClass}`; firstItem.dataset.status = config.dropdownStatus; firstItem.innerHTML = `${config.dropdownLabel}`; } // Keep dropdown color/state aligned with the main action button. dropdown.dataset.currentStatus = config.mainStatus; } /** * Toggle visibility of preview button and admin link based on status. * Hide when status is 'trash', show otherwise. * * @param {string} status - Current course status */ toggleTrashElements(status) { const elBtnPreview = document.querySelector(BuilderEditCourse.selectors.elBtnPreview); const elAdminLink = document.querySelector(BuilderEditCourse.selectors.elAdminLink); const isTrash = status === 'trash'; if (elBtnPreview) { elBtnPreview.style.display = isTrash ? 'none' : ''; } if (elAdminLink) { elAdminLink.style.display = isTrash ? 'none' : ''; } } async duplicateCourse(args) { // Context check: only handle if on course edit page if (!document.querySelector(BuilderEditCourse.selectors.elDataCourse)) { return; } const { target } = args; const elBtnDuplicateCourse = target.closest(BuilderEditCourse.selectors.elBtnDuplicateCourse); if (!elBtnDuplicateCourse) { return; } const courseData = this.getCourseDataForUpdate(); const courseId = parseInt(courseData?.course_id, 10) || 0; if (!courseId) { return; } const result = await sweetalert2__WEBPACK_IMPORTED_MODULE_2___default().fire({ title: elBtnDuplicateCourse.dataset.title || 'Are you sure?', text: elBtnDuplicateCourse.dataset.content || 'Are you sure you want to duplicate this course?', iconHtml: _swal_icons_js__WEBPACK_IMPORTED_MODULE_6__.SWAL_ICON_DUPLICATE, customClass: { icon: 'lp-cb-swal-icon-html' }, showCloseButton: true, showCancelButton: true, cancelButtonText: lpData.i18n.cancel, confirmButtonText: lpData.i18n.yes, reverseButtons: true }); if (!result.isConfirmed) { return; } lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elBtnDuplicateCourse, 1); const dataSend = { action: 'duplicate_course', args: { id_url: 'duplicate-course' }, course_id: courseId }; const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message || 'Duplicated successfully!', status); if (status === 'success' && data?.redirect_url) { window.location.href = data.redirect_url; } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elBtnDuplicateCourse, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } trashCourse(args) { // Context check: only handle if on course edit page if (!document.querySelector(BuilderEditCourse.selectors.elDataCourse)) { return; } const { target } = args; const elBtnTrashCourse = target.closest(BuilderEditCourse.selectors.elBtnTrashCourse); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elBtnTrashCourse, 1); const courseData = this.getCourseDataForUpdate(); const dataSend = { action: 'move_trash_course', args: { id_url: 'move-trash-course' }, course_id: courseData.course_id }; const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (data?.button_title) { const elBtnUpdate = document.querySelector(BuilderEditCourse.selectors.elBtnUpdateCourse); if (elBtnUpdate) elBtnUpdate.textContent = data.button_title; } if (data?.status) { const elStatus = document.querySelector(BuilderEditCourse.selectors.elStatus); if (elStatus) { elStatus.className = 'course-status ' + data.status; elStatus.textContent = this.formatStatusLabel(data.status); } this.syncPublishPanelStatus(data.status); // Toggle preview/admin link visibility for trash status this.toggleTrashElements(data.status); // Update action buttons to show "Save Draft" for trash status this.updateActionButtons(data.status); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elBtnTrashCourse, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } saveSettings(args) { const { target } = args; const elBtnSaveSettings = target.closest(BuilderEditCourse.selectors.elBtnSaveSettings); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elBtnSaveSettings, 1); const courseData = this.getCourseDataForUpdate(); const dataSend = { ...courseData, action: 'save_course_settings', args: { id_url: 'save-course-settings' } }; if (typeof lpCourseBuilder !== 'undefined' && lpCourseBuilder.nonce) { dataSend.nonce = lpCourseBuilder.nonce; } const callBack = { success: response => { const { status, message } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elBtnSaveSettings, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } toggleAddTagForm(args) { const { target } = args; const elBtnAdd = document.querySelector(BuilderEditCourse.selectors.elBtnAddTagNew); const form = document.querySelector(BuilderEditCourse.selectors.elFormTagAddNew); const isOpening = target.closest(BuilderEditCourse.selectors.elBtnAddTagNew); if (form) { if (isOpening) { form.style.display = 'flex'; if (elBtnAdd) elBtnAdd.style.display = 'none'; const input = form.querySelector(BuilderEditCourse.selectors.elInputAddTag); if (input) setTimeout(() => input.focus(), 100); } else { form.style.display = 'none'; if (elBtnAdd) elBtnAdd.style.display = 'inline-flex'; } } } addNewTag(args) { var _elInput$value$trim; const { e } = args; const elInput = document.querySelector(BuilderEditCourse.selectors.elInputAddTag); const btnSave = document.querySelector(BuilderEditCourse.selectors.elBtnSaveTag); const tagName = (_elInput$value$trim = elInput?.value?.trim()) !== null && _elInput$value$trim !== void 0 ? _elInput$value$trim : ''; if (!tagName) { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show('Please enter tag name', 'error'); return; } lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(btnSave, 1); const dataSend = { action: 'add_course_tag', args: { id_url: 'add-course-tag' }, name: tagName }; const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (data?.html) { const wrapper = document.querySelector(BuilderEditCourse.selectors.elWrapperCheckBoxTag); wrapper.insertAdjacentHTML('beforeend', data.html); this.syncTagManagement(); elInput.value = ''; const elBtnCancel = document.querySelector(BuilderEditCourse.selectors.elBtnCancelTagNew); if (elBtnCancel) elBtnCancel.click(); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(btnSave, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } openMediaUploader(args) { if (typeof wp === 'undefined' || typeof wp.media === 'undefined') return; const mediaUploader = wp.media({ title: 'Select Featured Image', button: { text: 'Use this image' }, multiple: false, library: { type: 'image' } }); mediaUploader.on('select', () => { const attachment = mediaUploader.state().get('selection').first().toJSON(); this.setFeaturedImage(attachment); }); mediaUploader.open(); } setFeaturedImage(attachment) { const dropzone = document.querySelector(BuilderEditCourse.selectors.elFeaturedImageDropzone); const thumbnailInput = document.querySelector(BuilderEditCourse.selectors.elThumbnailInput); const actionsContainer = document.querySelector('.cb-featured-image-actions'); if (!dropzone || !thumbnailInput) return; thumbnailInput.value = attachment.id; // Mark form as having unsaved changes (0,_builder_form_state_js__WEBPACK_IMPORTED_MODULE_5__.getFormState)().markAsChanged(); const imgUrl = attachment.sizes?.medium?.url || attachment.sizes?.thumbnail?.url || attachment.url; // Clear dropzone content dropzone.innerHTML = ''; // Add image const img = document.createElement('img'); img.src = imgUrl; img.className = 'cb-featured-image-preview__img'; img.alt = attachment.alt || ''; dropzone.appendChild(img); dropzone.classList.add('has-image'); // Show/create action buttons (order must match PHP: Remove icon first, Replace text second) if (actionsContainer) { actionsContainer.innerHTML = ` `; } } removeFeaturedImage(args) { const { e } = args; if (e) e.preventDefault(); const dropzone = document.querySelector(BuilderEditCourse.selectors.elFeaturedImageDropzone); const thumbnailInput = document.querySelector(BuilderEditCourse.selectors.elThumbnailInput); const actionsContainer = document.querySelector('.cb-featured-image-actions'); if (!dropzone) return; // Clear dropzone and show upload content dropzone.innerHTML = `
    `; dropzone.classList.remove('has-image'); // Clear thumbnail ID if (thumbnailInput) { thumbnailInput.value = ''; // Mark form as having unsaved changes (0,_builder_form_state_js__WEBPACK_IMPORTED_MODULE_5__.getFormState)().markAsChanged(); } // Hide action buttons if (actionsContainer) { actionsContainer.innerHTML = ''; } } buildPermalinkDisplayUrl(baseUrl = '', slug = '', fallbackUrl = '') { const normalizedBaseUrl = typeof baseUrl === 'string' ? baseUrl : ''; const normalizedSlug = typeof slug === 'string' ? slug.trim() : ''; if (normalizedBaseUrl && normalizedSlug) { return `${normalizedBaseUrl}${normalizedSlug}`; } return typeof fallbackUrl === 'string' ? fallbackUrl : ''; } /** * Handle permalink Edit button click. * Shows editor mode, hides display mode. */ handlePermalinkEdit(args) { const { e } = args; if (e) e.preventDefault(); const display = document.querySelector(BuilderEditCourse.selectors.elPermalinkDisplay); const editor = document.querySelector(BuilderEditCourse.selectors.elPermalinkEditor); const input = document.querySelector(BuilderEditCourse.selectors.elPermalinkSlugInput); if (!display || !editor || !input) return; // Store original value for cancel input.dataset.originalValue = input.value; // Toggle visibility display.classList.add('lp-hidden'); editor.classList.remove('lp-hidden'); // Focus input and select text input.focus(); input.select(); } /** * Handle permalink OK button click. * Validates and sanitizes slug, updates display. */ handlePermalinkOk(args) { const { e } = args; if (e) e.preventDefault(); const display = document.querySelector(BuilderEditCourse.selectors.elPermalinkDisplay); const editor = document.querySelector(BuilderEditCourse.selectors.elPermalinkEditor); const input = document.querySelector(BuilderEditCourse.selectors.elPermalinkSlugInput); const urlLink = document.querySelector(BuilderEditCourse.selectors.elPermalinkUrl); const baseUrlInput = document.querySelector(BuilderEditCourse.selectors.elPermalinkBaseUrl); if (!display || !editor || !input || !urlLink) return; // Sanitize the slug let newSlug = input.value.trim(); // If empty after sanitizing, restore original if (!newSlug) { newSlug = input.dataset.originalValue || 'course'; } // Update input value with sanitized slug input.value = newSlug; // Get base URL const baseUrl = baseUrlInput ? baseUrlInput.value : ''; const newUrl = this.buildPermalinkDisplayUrl(baseUrl, newSlug, urlLink.textContent || ''); // Keep href as the current saved link and only update display text. urlLink.textContent = newUrl; // Toggle visibility back to display mode editor.classList.add('lp-hidden'); display.classList.remove('lp-hidden'); // Mark form as changed if slug differs from original if (newSlug !== input.dataset.originalValue) { (0,_builder_form_state_js__WEBPACK_IMPORTED_MODULE_5__.getFormState)().markAsChanged(); } } /** * Handle permalink Cancel button click. * Restores original value and returns to display mode. */ handlePermalinkCancel(args) { const { e } = args; if (e) e.preventDefault(); const display = document.querySelector(BuilderEditCourse.selectors.elPermalinkDisplay); const editor = document.querySelector(BuilderEditCourse.selectors.elPermalinkEditor); const input = document.querySelector(BuilderEditCourse.selectors.elPermalinkSlugInput); if (!display || !editor || !input) return; // Restore original value input.value = input.dataset.originalValue || ''; // Toggle visibility back to display mode editor.classList.add('lp-hidden'); display.classList.remove('lp-hidden'); } initTabTitles() { const tabLinks = document.querySelectorAll(BuilderEditCourse.selectors.elTabLinks); tabLinks.forEach(link => { const textSpan = link.querySelector('span'); const title = textSpan ? textSpan.textContent.trim() : link.textContent.trim(); const href = link.getAttribute('href'); if (!href) return; const targetId = href.substring(1); const panel = document.getElementById(targetId); if (panel) { panel.setAttribute('data-tab-title', title); } }); } initTitleCharCount() { const titleInput = document.querySelector(BuilderEditCourse.selectors.elTitleInput); if (titleInput) { this.updateTitleCharCount(titleInput.value); } } updateTitleCharCount(text) { const charCountEl = document.querySelector(BuilderEditCourse.selectors.elTitleCharCount); if (!charCountEl) return; const charCount = text.length; const charText = charCount === 1 ? 'character' : 'characters'; charCountEl.textContent = `${charCount} ${charText}`; } handleTitleInput(args) { const { target } = args; this.updateTitleCharCount(target.value); } initDescWordCount() { // Wait for TinyMCE to be ready if (typeof tinymce !== 'undefined') { tinymce.on('AddEditor', e => { if (e.editor.id === 'course_description_editor') { e.editor.on('init', () => { this.updateDescWordCount(e.editor); // Listen for content changes e.editor.on('keyup change input NodeChange', () => { this.updateDescWordCount(e.editor); }); }); } }); // If editor already exists const existingEditor = tinymce.get('course_description_editor'); if (existingEditor) { this.updateDescWordCount(existingEditor); existingEditor.on('keyup change input NodeChange', () => { this.updateDescWordCount(existingEditor); }); } } } updateDescWordCount(editor) { const wordCountEl = document.querySelector(BuilderEditCourse.selectors.elDescWordCount); if (!wordCountEl) return; // Use TinyMCE's built-in word count plugin const wordcount = editor.plugins.wordcount; let count = 0; if (wordcount && typeof wordcount.body !== 'undefined') { count = wordcount.body.getWordCount(); } else if (wordcount && typeof wordcount.getCount !== 'undefined') { count = wordcount.getCount(); } else { // Fallback: manual count const content = editor.getContent({ format: 'text' }); count = this.countWords(content); } const wordText = count === 1 ? 'word' : 'words'; wordCountEl.textContent = `${count} ${wordText}`; } updateHeaderTitle(title) { const headerTitle = document.querySelector('.lp-cb-header__title'); if (headerTitle && title) { headerTitle.textContent = title; } } countWords(text) { const trimmedText = text.replace(/<[^>]*>/g, '').trim(); if (trimmedText.length === 0) return 0; const words = trimmedText.split(/\s+/).filter(word => word.length > 0); return words.length; } /** * Initialize Header Actions Dropdown * Handles toggle open/close for dropdown menu in header actions */ initHeaderActionsDropdown() { const dropdownWrapper = document.querySelector(BuilderEditCourse.selectors.elHeaderActionsDropdown); if (!dropdownWrapper) return; const toggleBtn = dropdownWrapper.querySelector(BuilderEditCourse.selectors.elDropdownToggle); const dropdownMenu = dropdownWrapper.querySelector(BuilderEditCourse.selectors.elDropdownMenu); if (!toggleBtn || !dropdownMenu) return; // Toggle dropdown on button click toggleBtn.addEventListener('click', e => { e.stopPropagation(); const isOpen = dropdownMenu.classList.contains('is-open'); if (isOpen) { this.closeHeaderDropdown(toggleBtn, dropdownMenu); } else { this.openHeaderDropdown(toggleBtn, dropdownMenu); } }); // Close dropdown when clicking outside document.addEventListener('click', e => { if (!dropdownWrapper.contains(e.target)) { this.closeHeaderDropdown(toggleBtn, dropdownMenu); } }); // Close dropdown on Escape key document.addEventListener('keydown', e => { if (e.key === 'Escape') { this.closeHeaderDropdown(toggleBtn, dropdownMenu); } }); // Close dropdown after clicking an item (except when it triggers an action that keeps page) const dropdownItems = dropdownMenu.querySelectorAll('.cb-dropdown-item'); dropdownItems.forEach(item => { item.addEventListener('click', () => { // Small delay to allow action to process before closing setTimeout(() => { this.closeHeaderDropdown(toggleBtn, dropdownMenu); }, 100); }); }); } openHeaderDropdown(toggleBtn, dropdownMenu) { dropdownMenu.classList.add('is-open'); toggleBtn.setAttribute('aria-expanded', 'true'); } closeHeaderDropdown(toggleBtn, dropdownMenu) { dropdownMenu.classList.remove('is-open'); toggleBtn.setAttribute('aria-expanded', 'false'); } } /***/ }, /***/ "./assets/src/js/frontend/course-builder/builder-course/builder-tab-course.js" /*!************************************************************************************!*\ !*** ./assets/src/js/frontend/course-builder/builder-course/builder-tab-course.js ***! \************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ BuilderTabCourse: () => (/* binding */ BuilderTabCourse) /* harmony export */ }); /* harmony import */ var lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lpAssetsJsPath/utils.js */ "./assets/src/js/utils.js"); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! sweetalert2 */ "./node_modules/sweetalert2/dist/sweetalert2.all.js"); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(sweetalert2__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! lpAssetsJsPath/lpToastify.js */ "./assets/src/js/lpToastify.js"); /* harmony import */ var _swal_icons_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../swal-icons.js */ "./assets/src/js/frontend/course-builder/swal-icons.js"); class BuilderTabCourse { constructor() { this.init(); } static selectors = { elBtnCreateCourse: 'a.cb-btn-add-new[href]', elCourseItem: '.course-item', elCourseExpandedItems: '.course-action-expanded__items', elCourseDuplicate: '.course-action-expanded__duplicate', elCourseTrash: '.course-action-expanded__trash', elCourseDraft: '.course-action-expanded__draft', elCourseDelete: '.course-action-expanded__delete', elCourseActionExpanded: '.course-action-expanded', elCourseStatus: '.course-status' }; init() { this.events(); } events() { if (BuilderTabCourse._loadedEvents) { return; } BuilderTabCourse._loadedEvents = true; lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('click', [{ selector: BuilderTabCourse.selectors.elCourseDuplicate, class: this, callBack: this.duplicateCourse.name }, { selector: BuilderTabCourse.selectors.elCourseTrash, class: this, callBack: this.trashCourse.name }, { selector: BuilderTabCourse.selectors.elCourseDraft, class: this, callBack: this.draftCourse.name }, { selector: BuilderTabCourse.selectors.elCourseDelete, class: this, callBack: this.deleteCourse.name }, { selector: BuilderTabCourse.selectors.elCourseActionExpanded, class: this, callBack: this.toggleExpandedAction.name }, { selector: BuilderTabCourse.selectors.elBtnCreateCourse, callBack: args => { const { target } = args; const elBtnCreateCourse = target.closest(BuilderTabCourse.selectors.elBtnCreateCourse); if (!elBtnCreateCourse) { return; } lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elBtnCreateCourse, 1); } }]); document.addEventListener('click', e => { if (!e.target.closest(BuilderTabCourse.selectors.elCourseActionExpanded)) { this.closeAllExpanded(); } }); } duplicateCourse(args) { const { target } = args; const elCourseDuplicate = target.closest(BuilderTabCourse.selectors.elCourseDuplicate); const elCourseItem = elCourseDuplicate.closest(BuilderTabCourse.selectors.elCourseItem); if (!elCourseItem) { return; } const courseId = elCourseItem.dataset.courseId || ''; if (!courseId) { return; } sweetalert2__WEBPACK_IMPORTED_MODULE_1___default().fire({ title: elCourseDuplicate.dataset.title || 'Duplicate Course', text: elCourseDuplicate.dataset.content || 'Are you sure you want to duplicate this course?', iconHtml: _swal_icons_js__WEBPACK_IMPORTED_MODULE_3__.SWAL_ICON_DUPLICATE, customClass: { icon: 'lp-cb-swal-icon-html' }, showCloseButton: true, showCancelButton: true, cancelButtonText: lpData.i18n.cancel, confirmButtonText: lpData.i18n.yes, reverseButtons: true }).then(result => { if (result.isConfirmed) { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elCourseDuplicate, 1); const dataSend = { action: 'duplicate_course', args: { id_url: 'duplicate-course' }, course_id: courseId }; const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_2__.show(message || 'Duplicated successfully!', status); if (data?.html) { const elCourse = elCourseDuplicate.closest('.course'); const elCourseList = elCourse.closest('.courses-list') || elCourse.parentElement; if (elCourseList) { elCourseList.insertAdjacentHTML('afterbegin', data.html); const newCourse = elCourseList.firstElementChild; if (newCourse) { newCourse.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); newCourse.classList.add('highlight-new-course'); setTimeout(() => { newCourse.classList.remove('highlight-new-course'); }, 1500); } } } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_2__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elCourseDuplicate, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } }); } trashCourse(args) { const { target } = args; const elCourseTrash = target.closest(BuilderTabCourse.selectors.elCourseTrash); const elCourseItem = elCourseTrash.closest(BuilderTabCourse.selectors.elCourseItem); if (!elCourseItem) { return; } const courseId = elCourseItem.dataset.courseId || ''; sweetalert2__WEBPACK_IMPORTED_MODULE_1___default().fire({ title: elCourseTrash.dataset.title || 'Trash Course', text: elCourseTrash.dataset.content || 'Are you sure you want to move this course to trash?', iconHtml: _swal_icons_js__WEBPACK_IMPORTED_MODULE_3__.SWAL_ICON_TRASH_DRAFT, customClass: { icon: 'lp-cb-swal-icon-html' }, showCloseButton: true, showCancelButton: true, cancelButtonText: lpData.i18n.cancel, confirmButtonText: lpData.i18n.yes, reverseButtons: true }).then(result => { if (result.isConfirmed) { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elCourseTrash, 1); const dataSend = { action: 'move_trash_course', args: { id_url: 'move-trash-course' }, course_id: courseId }; const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_2__.show(message, status); if (data?.status) { const elCourse = elCourseTrash.closest('.course'); this.updateStatusUI(elCourse, data.status); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_2__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elCourseTrash, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } }); } draftCourse(args) { const { target } = args; const elCourseDraft = target.closest(BuilderTabCourse.selectors.elCourseDraft); const elCourseItem = elCourseDraft.closest(BuilderTabCourse.selectors.elCourseItem); if (!elCourseItem) { return; } // Check if published to show confirm unpublish modal const statusEl = elCourseItem.querySelector(BuilderTabCourse.selectors.elCourseStatus); const isPublished = statusEl && statusEl.classList.contains('publish'); if (isPublished) { const confirmMsg = elCourseDraft.dataset.confirmUnpublish || 'Saving as draft will unpublish this item. Are you sure?'; sweetalert2__WEBPACK_IMPORTED_MODULE_1___default().fire({ title: 'Draft Course', text: confirmMsg, iconHtml: _swal_icons_js__WEBPACK_IMPORTED_MODULE_3__.SWAL_ICON_TRASH_DRAFT, customClass: { icon: 'lp-cb-swal-icon-html' }, showCloseButton: true, showCancelButton: true, cancelButtonText: lpData.i18n.cancel, confirmButtonText: lpData.i18n.yes, reverseButtons: true }).then(result => { if (result.isConfirmed) { this.draftCourseExecute(elCourseDraft, elCourseItem); } }); return; } this.draftCourseExecute(elCourseDraft, elCourseItem); } draftCourseExecute(elCourseDraft, elCourseItem) { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elCourseDraft, 1); const courseId = elCourseItem.dataset.courseId || ''; const dataSend = { action: 'move_trash_course', args: { id_url: 'move-trash-course' }, course_id: courseId || 0, status: 'draft' }; const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_2__.show(message, status); if (data?.status) { const elCourse = elCourseDraft.closest('.course'); this.updateStatusUI(elCourse, data.status); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_2__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elCourseDraft, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } deleteCourse(args) { const { target } = args; const elCourseDelete = target.closest(BuilderTabCourse.selectors.elCourseDelete); const elCourseItem = elCourseDelete.closest(BuilderTabCourse.selectors.elCourseItem); if (!elCourseItem) { return; } const courseId = elCourseItem.dataset.courseId || ''; if (!courseId) { return; } sweetalert2__WEBPACK_IMPORTED_MODULE_1___default().fire({ title: elCourseDelete.dataset.title || 'Delete Course', text: elCourseDelete.dataset.content || 'Are you sure you want to permanently delete this course?', iconHtml: _swal_icons_js__WEBPACK_IMPORTED_MODULE_3__.SWAL_ICON_DELETE, customClass: { icon: 'lp-cb-swal-icon-html' }, showCloseButton: true, showCancelButton: true, cancelButtonText: lpData.i18n.cancel, confirmButtonText: lpData.i18n.yes, reverseButtons: true }).then(result => { if (result.isConfirmed) { const dataSend = { action: 'move_trash_course', args: { id_url: 'move-trash-course' }, course_id: courseId, status: 'delete' }; const callBack = { success: response => { const { status, message } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_2__.show(message, status); const elCourse = elCourseDelete.closest('.course'); elCourse.style.transition = 'opacity 0.4s ease-out, transform 0.4s ease-out'; elCourse.style.opacity = '0'; elCourse.style.transform = 'translateX(160px)'; setTimeout(() => { elCourse.remove(); }, 400); }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_2__.show(error.message || error, 'error'); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } }); } toggleExpandedAction(args) { const { target } = args; const elCourseActionExpanded = target.closest(BuilderTabCourse.selectors.elCourseActionExpanded); if (!elCourseActionExpanded) { return; } const elCourseItem = elCourseActionExpanded.closest(BuilderTabCourse.selectors.elCourseItem); if (!elCourseItem) { return; } const elExpandedItems = elCourseItem.querySelector(BuilderTabCourse.selectors.elCourseExpandedItems); if (!elExpandedItems) { return; } // Close others this.closeAllExpanded(elExpandedItems); elExpandedItems.classList.toggle('active'); elCourseActionExpanded.classList.toggle('active'); } closeAllExpanded(excludeElement = null) { const allExpandedItems = document.querySelectorAll(`${BuilderTabCourse.selectors.elCourseExpandedItems}.active`); allExpandedItems.forEach(item => { if (item === excludeElement) { return; } item.classList.remove('active'); const courseItem = item.closest(BuilderTabCourse.selectors.elCourseItem); if (!courseItem) { return; } const expandedBtn = courseItem.querySelector(BuilderTabCourse.selectors.elCourseActionExpanded); if (expandedBtn) { expandedBtn.classList.remove('active'); } }); } updateStatusUI(elCourse, status) { const elStatus = elCourse.querySelector(BuilderTabCourse.selectors.elCourseStatus); const elSpanStatus = elCourse.querySelector(`${BuilderTabCourse.selectors.elCourseStatus} span`); if (elSpanStatus && elStatus) { elStatus.className = 'course-status ' + status; elSpanStatus.textContent = status; } } } /***/ }, /***/ "./assets/src/js/frontend/course-builder/builder-course/extra-info.js" /*!****************************************************************************!*\ !*** ./assets/src/js/frontend/course-builder/builder-course/extra-info.js ***! \****************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ MetaboxExtraInfo: () => (/* binding */ MetaboxExtraInfo) /* harmony export */ }); /* harmony import */ var lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lpAssetsJsPath/utils.js */ "./assets/src/js/utils.js"); /* harmony import */ var sortablejs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! sortablejs */ "./node_modules/sortablejs/modular/sortable.esm.js"); class MetaboxExtraInfo { constructor() { this.init(); } static selectors = { elExtraMetaboxAdd: '.lp_course_extra_meta_box__add', elExtraMetaboxContent: '.lp_course_extra_meta_box__content', elExtraMetaboxFields: '.lp_course_extra_meta_box__fields', elExtraMetaboxField: '.lp_course_extra_meta_box__field', elExtraMetaboxDelete: '.lp_course_extra_meta_box__fields a.delete', elFaqMetaboxAdd: '.lp_course_faq_meta_box__add', elFaqMetaboxContent: '.lp_course_faq_meta_box__content', elFaqMetaboxFields: '.lp_course_faq_meta_box__fields', elFaqMetaboxField: '.lp_course_faq_meta_box__field', elFaqMetaboxDelete: '.lp_course_faq_meta_box__fields a.delete' }; init() { this.initSortable(); this.events(); } events() { if (MetaboxExtraInfo._loadedEvents) { return; } MetaboxExtraInfo._loadedEvents = true; lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('click', [{ selector: MetaboxExtraInfo.selectors.elExtraMetaboxAdd, class: this, callBack: this.handleExtraMetaboxAdd.name }, { selector: MetaboxExtraInfo.selectors.elExtraMetaboxDelete, class: this, callBack: this.handleExtraMetaboxDelete.name }, { selector: MetaboxExtraInfo.selectors.elFaqMetaboxAdd, class: this, callBack: this.handleFaqMetaboxAdd.name }, { selector: MetaboxExtraInfo.selectors.elFaqMetaboxDelete, class: this, callBack: this.handleFaqMetaboxDelete.name }]); } handleExtraMetaboxAdd(args) { const { e, target } = args; e.preventDefault(); const content = target.closest(MetaboxExtraInfo.selectors.elExtraMetaboxContent); if (!content) return; const fields = content.querySelector(MetaboxExtraInfo.selectors.elExtraMetaboxFields); const addData = target.dataset.add; if (fields && addData) { fields.insertAdjacentHTML('beforeend', addData); const lastField = fields.querySelector(`${MetaboxExtraInfo.selectors.elExtraMetaboxField}:last-child`); if (lastField) { const input = lastField.querySelector('input'); if (input) { setTimeout(() => input.focus(), 100); } } } return false; } handleExtraMetaboxDelete(args) { const { e, target } = args; e.preventDefault(); const field = target.closest(MetaboxExtraInfo.selectors.elExtraMetaboxField); if (field) { field.remove(); } return false; } handleFaqMetaboxAdd(args) { const { e, target } = args; e.preventDefault(); const content = target.closest(MetaboxExtraInfo.selectors.elFaqMetaboxContent); if (!content) return; const fields = content.querySelector(MetaboxExtraInfo.selectors.elFaqMetaboxFields); const addData = target.dataset.add; if (fields && addData) { fields.insertAdjacentHTML('beforeend', addData); } return false; } handleFaqMetaboxDelete(args) { const { e, target } = args; e.preventDefault(); const field = target.closest(MetaboxExtraInfo.selectors.elFaqMetaboxField); if (field) { field.remove(); } return false; } initSortable() { const extraFieldsContainers = document.querySelectorAll('.lp_course_extra_meta_box__fields'); extraFieldsContainers.forEach(container => { new sortablejs__WEBPACK_IMPORTED_MODULE_1__["default"](container, { animation: 150, handle: '.sort', draggable: '.lp_course_extra_meta_box__field', ghostClass: 'sortable-ghost', chosenClass: 'sortable-chosen', dragClass: 'sortable-drag', forceFallback: false, scrollSensitivity: 40, onStart: evt => { evt.item.classList.add('is-dragging'); }, onEnd: evt => { evt.item.classList.remove('is-dragging'); } }); }); const faqFieldsContainers = document.querySelectorAll('.lp_course_faq_meta_box__fields'); faqFieldsContainers.forEach(container => { new sortablejs__WEBPACK_IMPORTED_MODULE_1__["default"](container, { animation: 150, handle: '.sort', draggable: '.lp_course_faq_meta_box__field', ghostClass: 'sortable-ghost', chosenClass: 'sortable-chosen', dragClass: 'sortable-drag', forceFallback: false, scrollSensitivity: 40, onStart: evt => { evt.item.classList.add('is-dragging'); }, onEnd: evt => { evt.item.classList.remove('is-dragging'); } }); }); } } /***/ }, /***/ "./assets/src/js/frontend/course-builder/builder-dashboard.js" /*!********************************************************************!*\ !*** ./assets/src/js/frontend/course-builder/builder-dashboard.js ***! \********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ BuilderDashboard: () => (/* binding */ BuilderDashboard) /* harmony export */ }); /* harmony import */ var chart_js_auto__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! chart.js/auto */ "./node_modules/chart.js/auto/auto.js"); /** * Dashboard charts and interactions for Course Builder. * * @since 4.3.0 * @version 1.0.0 */ class BuilderDashboard { constructor() { this.charts = {}; this.init(); } init() { const dataEl = document.getElementById('lp-cb-dashboard-chart-data'); if (!dataEl) { return; } try { this.chartData = JSON.parse(dataEl.textContent); } catch (e) { console.warn('Dashboard: Failed to parse chart data', e); return; } this.initSalesChart(); this.initStudentsChart(); this.bindFilterEvents(); } createGradient(ctx, color) { const gradient = ctx.createLinearGradient(0, 0, 0, ctx.canvas.height); gradient.addColorStop(0, color + '40'); gradient.addColorStop(1, color + '05'); return gradient; } getChartConfig(labels, data, color, prefix = '', isInteger = false) { return { type: 'line', data: { labels, datasets: [{ data, borderColor: color, borderWidth: 2.5, backgroundColor: context => { const { ctx } = context.chart; return this.createGradient(ctx, color); }, fill: true, tension: 0.4, pointBackgroundColor: color, pointBorderColor: '#fff', pointBorderWidth: 2, pointRadius: 0, pointHoverRadius: 6, pointHoverBorderWidth: 2 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false }, tooltip: { backgroundColor: '#1e1e1e', titleColor: '#fff', bodyColor: '#fff', borderColor: 'rgba(255,255,255,0.1)', borderWidth: 1, cornerRadius: 8, padding: 12, displayColors: false, callbacks: { label: context => { const val = context.parsed.y || 0; return prefix + val.toLocaleString(); } } } }, scales: { x: { grid: { display: false }, ticks: { color: '#9ca3af', font: { size: 11 }, maxRotation: 0 }, border: { display: false } }, y: { grid: { color: 'rgba(0,0,0,0.04)', drawBorder: false }, ticks: { stepSize: isInteger ? 1 : undefined, color: '#9ca3af', font: { size: 11 }, callback: value => prefix + value.toLocaleString() }, border: { display: false }, beginAtZero: true } }, interaction: { intersect: false, mode: 'index' } } }; } initSalesChart() { const canvas = document.getElementById('lp-cb-chart-sales'); if (!canvas) { return; } const { labels = [], data = [] } = this.chartData.sales || {}; const config = this.getChartConfig(labels, data, '#10b981', '$'); this.charts.sales = new chart_js_auto__WEBPACK_IMPORTED_MODULE_0__["default"](canvas, config); } initStudentsChart() { const canvas = document.getElementById('lp-cb-chart-students'); if (!canvas) { return; } const { labels = [], data = [] } = this.chartData.students || {}; const config = this.getChartConfig(labels, data, '#f59e0b', '', true); this.charts.students = new chart_js_auto__WEBPACK_IMPORTED_MODULE_0__["default"](canvas, config); } bindFilterEvents() { const filters = document.querySelectorAll('.chart-card__filter'); filters.forEach(select => { select.addEventListener('change', e => { const chartType = e.target.dataset.chart; const period = e.target.value; this.fetchChartData(chartType, period); }); }); } async fetchChartData(chartType, period) { const chart = this.charts[chartType]; if (!chart) { return; } const formData = new FormData(); formData.append('action', 'lp_cb_dashboard_chart_data'); formData.append('chart_type', chartType); formData.append('period', period); formData.append('nonce', this.chartData.nonce); try { const response = await fetch(this.chartData.ajaxUrl, { method: 'POST', body: formData }); const result = await response.json(); if (result.success && result.data) { chart.data.labels = result.data.labels || []; chart.data.datasets[0].data = result.data.data || []; chart.update('none'); } } catch (e) { console.warn('Dashboard: Failed to fetch chart data', e); } } } /***/ }, /***/ "./assets/src/js/frontend/course-builder/builder-form-state.js" /*!*********************************************************************!*\ !*** ./assets/src/js/frontend/course-builder/builder-form-state.js ***! \*********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ BuilderFormState: () => (/* binding */ BuilderFormState), /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__), /* harmony export */ getFormState: () => (/* binding */ getFormState) /* harmony export */ }); /** * Course Builder - Form State Management * Track unsaved changes and handle tab navigation * * @since 4.3.0 * @version 1.0.0 */ class BuilderFormState { constructor() { this.hasUnsavedChanges = false; this.formElements = []; this.originalValues = new Map(); this.init(); } init() { this.bindEvents(); this.captureOriginalValues(); } /** * Capture original form values for comparison */ captureOriginalValues() { const forms = document.querySelectorAll('.cb-section__course-edit, .lp-cb-tab-content'); forms.forEach(form => { const inputs = form.querySelectorAll('input, textarea, select'); inputs.forEach(input => { const key = input.name || input.id; if (key) { this.originalValues.set(key, this.getInputValue(input)); } }); }); } /** * Get input value based on type */ getInputValue(input) { if (input.type === 'checkbox') { return input.checked; } if (input.type === 'radio') { return input.checked ? input.value : null; } return input.value; } /** * Bind all events */ bindEvents() { // Track form changes document.addEventListener('input', this.handleFormChange.bind(this)); document.addEventListener('change', this.handleFormChange.bind(this)); // TinyMCE changes (if available) this.bindTinyMCEChanges(); // Tab navigation warning document.addEventListener('click', this.handleTabClick.bind(this)); // Browser navigation warning window.addEventListener('beforeunload', this.handleBeforeUnload.bind(this)); // Reset state after successful save document.addEventListener('lp-course-builder-saved', this.resetState.bind(this)); } /** * Bind TinyMCE editor changes */ bindTinyMCEChanges() { // Wait for TinyMCE to be ready if (typeof tinymce !== 'undefined') { tinymce.on('AddEditor', e => { e.editor.on('change', () => { this.markAsChanged(); }); e.editor.on('keyup', () => { this.markAsChanged(); }); }); } } /** * Handle form input changes */ handleFormChange(e) { const target = e.target; // Ignore curriculum changes if (target.closest('#lp-course-edit-curriculum')) { return; } // Ignore question settings form - it auto-saves via AJAX if (target.closest('.lp-form-setting-question')) { return; } // Ignore lesson settings form - it auto-saves via AJAX if (target.closest('.lp-form-setting-lesson')) { return; } // Ignore quiz questions list - question changes are tracked separately if (target.closest('.lp-quiz-questions-list') || target.closest('.lp-edit-quiz-wrap')) { return; } // Check if target is within course builder forms if (target.closest('.cb-section__course-edit') || target.closest('.lp-cb-tab-content') || target.closest('.lp-form-setting-course') || target.closest('.lp-form-setting-quiz') || target.closest('.cb-section__quiz-edit')) { this.markAsChanged(); } } /** * Mark form as having unsaved changes */ markAsChanged() { if (!this.hasUnsavedChanges) { this.hasUnsavedChanges = true; this.updateSaveButtonState(); } } /** * Update save button visual state */ updateSaveButtonState() { const saveButtons = document.querySelectorAll('.cb-btn-update, .lp-cb-save-btn, .cb-btn-main-action'); saveButtons.forEach(btn => { if (this.hasUnsavedChanges) { btn.classList.add('has-changes'); } else { btn.classList.remove('has-changes'); } }); } /** * Handle tab navigation click */ handleTabClick(e) { const tabLink = e.target.closest('.lp-cb-tabs__item, .lp-cb-sidebar__item a'); if (!tabLink) { return; } if (tabLink.hasAttribute('data-tab-section') || tabLink.getAttribute('href') === '#') { return; } if (tabLink.classList.contains('is-active') || tabLink.closest('.is-active')) { return; } if (this.hasUnsavedChanges) { const confirmLeave = confirm(wp?.i18n?.__('You have unsaved changes. Are you sure you want to leave this page?', 'learnpress') || 'You have unsaved changes. Are you sure you want to leave this page?'); if (!confirmLeave) { e.preventDefault(); e.stopPropagation(); return false; } } } /** * Handle browser back/forward/close */ handleBeforeUnload(e) { if (this.hasUnsavedChanges) { e.preventDefault(); e.returnValue = ''; return ''; } } /** * Reset state after successful save */ resetState() { this.hasUnsavedChanges = false; this.updateSaveButtonState(); this.captureOriginalValues(); } /** * Check if form has unsaved changes */ hasChanges() { return this.hasUnsavedChanges; } /** * Manually set changed state */ setChanged(changed = true) { this.hasUnsavedChanges = changed; this.updateSaveButtonState(); } } // Export singleton instance let formStateInstance = null; const getFormState = () => { if (!formStateInstance) { formStateInstance = new BuilderFormState(); } return formStateInstance; }; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (BuilderFormState); /***/ }, /***/ "./assets/src/js/frontend/course-builder/builder-lesson/builder-edit-lesson.js" /*!*************************************************************************************!*\ !*** ./assets/src/js/frontend/course-builder/builder-lesson/builder-edit-lesson.js ***! \*************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ BuilderEditLesson: () => (/* binding */ BuilderEditLesson) /* harmony export */ }); /* harmony import */ var lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lpAssetsJsPath/utils.js */ "./assets/src/js/utils.js"); /* harmony import */ var lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! lpAssetsJsPath/lpToastify.js */ "./assets/src/js/lpToastify.js"); class BuilderEditLesson { constructor() { // Events use document-level event delegation, so always register them // The page context check happens in individual handlers via target.closest() this.init(); } static selectors = { // Context selector - indicates we're on lesson edit page elDataLesson: '.cb-section__lesson-edit', // Shared header action buttons (generic selectors) elBtnMainAction: '.cb-btn-main-action', elBtnUpdate: '.cb-btn-update, .cb-btn-publish', elBtnDraft: '.cb-btn-darft, .cb-dropdown-item[data-status="draft"]', elBtnTrash: '.cb-btn-trash', // Status badge elLessonStatus: '.lesson-status', // Form fields idTitle: 'title', idDescEditor: 'lesson_description_editor', elFormSetting: '.lp-form-setting-lesson', // Permalink component elPermalinkDisplay: '.cb-permalink-display', elPermalinkEditor: '.cb-permalink-editor', elPermalinkEditBtn: '.cb-permalink-edit-btn', elPermalinkOkBtn: '.cb-permalink-ok-btn', elPermalinkCancelBtn: '.cb-permalink-cancel-btn', elPermalinkSlugInput: '.cb-permalink-slug-input', elPermalinkUrl: '.cb-permalink-url', elPermalinkBaseUrl: '#cb-permalink-base-url', elPermalinkRoot: '.cb-item-edit-permalink, .cb-course-edit-permalink', elPermalinkPlaceholder: '.cb-item-edit-permalink__placeholder', // Tab handling selectors elCBHorizontalTabs: '.lp-cb-tabs__item', elCBTabPanels: '.lp-cb-tab-panel', // Dropdown selectors elDropdownToggle: '.cb-btn-dropdown-toggle', elDropdownMenu: '.cb-dropdown-menu', elHeaderActionsDropdown: '.cb-header-actions-dropdown' }; init() { this.initTabs(); this.initHeaderActionsDropdown(); this.events(); } /** * Initialize header actions dropdown (toggle behavior) */ initHeaderActionsDropdown() { // Close dropdown when clicking outside document.addEventListener('click', e => { const dropdown = document.querySelector(BuilderEditLesson.selectors.elHeaderActionsDropdown); if (dropdown && !dropdown.contains(e.target)) { const menu = dropdown.querySelector(BuilderEditLesson.selectors.elDropdownMenu); const toggle = dropdown.querySelector(BuilderEditLesson.selectors.elDropdownToggle); if (menu) { menu.classList.remove('is-open'); } if (toggle) { toggle.setAttribute('aria-expanded', 'false'); } } }); } /** * Handle dropdown toggle click */ handleDropdownToggle(args) { const { target } = args; const toggleBtn = target.closest(BuilderEditLesson.selectors.elDropdownToggle); if (!toggleBtn) { return; } const dropdown = toggleBtn.closest(BuilderEditLesson.selectors.elHeaderActionsDropdown); if (!dropdown) { return; } const menu = dropdown.querySelector(BuilderEditLesson.selectors.elDropdownMenu); if (menu) { menu.classList.toggle('is-open'); const isOpen = menu.classList.contains('is-open'); toggleBtn.setAttribute('aria-expanded', isOpen ? 'true' : 'false'); } } /** * Initialize horizontal tabs for client-side tab switching */ initTabs() { const tabs = document.querySelectorAll(BuilderEditLesson.selectors.elCBHorizontalTabs); if (tabs.length === 0) { return; } // Activate first tab by default if none is active const activeTab = document.querySelector(`${BuilderEditLesson.selectors.elCBHorizontalTabs}.is-active`); if (!activeTab && tabs.length > 0) { tabs[0].classList.add('is-active'); const section = tabs[0].getAttribute('data-tab-section'); if (section) { const panel = document.querySelector(`${BuilderEditLesson.selectors.elCBTabPanels}[data-section="${section}"]`); if (panel) { panel.classList.remove('lp-hidden'); } } } } /** * Handle horizontal tab click for client-side tab switching */ handleTabClick(args) { const { e, target } = args; const tabLink = target.closest(BuilderEditLesson.selectors.elCBHorizontalTabs); if (!tabLink) { return; } e.preventDefault(); const section = tabLink.getAttribute('data-tab-section'); if (!section) { return; } // Update active tab const allTabs = document.querySelectorAll(BuilderEditLesson.selectors.elCBHorizontalTabs); allTabs.forEach(tab => tab.classList.remove('is-active')); tabLink.classList.add('is-active'); // Show/hide panels const allPanels = document.querySelectorAll(BuilderEditLesson.selectors.elCBTabPanels); allPanels.forEach(panel => { if (panel.getAttribute('data-section') === section) { panel.classList.remove('lp-hidden'); } else { panel.classList.add('lp-hidden'); } }); } events() { if (BuilderEditLesson._loadedEvents) { return; } BuilderEditLesson._loadedEvents = true; lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('click', [{ selector: BuilderEditLesson.selectors.elBtnMainAction, class: this, callBack: this.updateLesson.name }, { selector: BuilderEditLesson.selectors.elBtnDraft, class: this, callBack: this.saveDraftLesson.name }, { selector: BuilderEditLesson.selectors.elBtnTrash, class: this, callBack: this.trashLesson.name }, { selector: BuilderEditLesson.selectors.elCBHorizontalTabs, class: this, callBack: this.handleTabClick.name }, { selector: BuilderEditLesson.selectors.elDropdownToggle, class: this, callBack: this.handleDropdownToggle.name }, { selector: BuilderEditLesson.selectors.elPermalinkEditBtn, class: this, callBack: this.handlePermalinkEdit.name }, { selector: BuilderEditLesson.selectors.elPermalinkOkBtn, class: this, callBack: this.handlePermalinkOk.name }, { selector: BuilderEditLesson.selectors.elPermalinkCancelBtn, class: this, callBack: this.handlePermalinkCancel.name }]); } /** * Validate title is not empty before update * @return {boolean} True if valid, false if invalid */ validateTitleBeforeUpdate() { const titleInput = document.getElementById(BuilderEditLesson.selectors.idTitle); if (!titleInput) { return true; } const title = titleInput.value.trim(); if (!title) { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show('Lesson title is required.', 'error'); titleInput.focus(); return false; } return true; } /** * Update action button text after status change * @param {string} newStatus - The new lesson status */ updateActionButtons(newStatus) { const elBtnUpdate = document.querySelector(BuilderEditLesson.selectors.elBtnMainAction); if (!elBtnUpdate) { return; } const titleUpdate = elBtnUpdate.getAttribute('data-title-update') || 'Update'; const titlePublish = elBtnUpdate.getAttribute('data-title-publish') || 'Publish'; if (newStatus === 'publish') { elBtnUpdate.textContent = titleUpdate; } else { elBtnUpdate.textContent = titlePublish; } } /** * Check if we're in lesson edit context * @return {boolean} */ isLessonContext() { return !!document.querySelector(BuilderEditLesson.selectors.elDataLesson); } slugify(str) { return (str || '').toString().normalize('NFD').replace(/[\u0300-\u036f]/g, '').replace(/đ/g, 'd').replace(/Đ/g, 'D').toLowerCase().replace(/\s+/g, '-').replace(/[^\w-]+/g, '').replace(/--+/g, '-').replace(/^-+/, '').replace(/-+$/, ''); } buildPermalinkDisplayUrl(baseUrl = '', slug = '', fallbackUrl = '') { const normalizedBaseUrl = typeof baseUrl === 'string' ? baseUrl : ''; const normalizedSlug = typeof slug === 'string' ? slug.trim() : ''; if (normalizedBaseUrl && normalizedSlug) { return `${normalizedBaseUrl}${normalizedSlug}`; } return typeof fallbackUrl === 'string' ? fallbackUrl : ''; } getPermalinkRoot(target = null) { if (target?.closest) { const fromTarget = target.closest(BuilderEditLesson.selectors.elPermalinkRoot); if (fromTarget) { return fromTarget; } } return document.querySelector(`.cb-section__lesson-edit ${BuilderEditLesson.selectors.elPermalinkRoot}`); } isDescriptionEditorInCodeMode() { const editorId = BuilderEditLesson.selectors.idDescEditor; const wrapper = document.getElementById(`wp-${editorId}-wrap`) || document.getElementById(`${editorId}-wrap`); if (wrapper?.classList.contains('html-active')) { return true; } const editor = typeof tinymce !== 'undefined' ? tinymce.get(editorId) : null; return !!(editor?.isHidden && editor.isHidden()); } getDescriptionContentForUpdate() { const editorId = BuilderEditLesson.selectors.idDescEditor; const descEditor = document.getElementById(editorId); if (this.isDescriptionEditorInCodeMode()) { return descEditor ? descEditor.value : ''; } if (typeof tinymce !== 'undefined') { const editor = tinymce.get(editorId); if (editor) { return editor.getContent(); } } return descEditor ? descEditor.value : ''; } showPermalinkUnavailable(permalinkRoot, message = '') { if (!permalinkRoot) { return; } const label = permalinkRoot.querySelector('.cb-item-edit-permalink__label') || permalinkRoot.querySelector('.cb-permalink-label'); const display = permalinkRoot.querySelector(BuilderEditLesson.selectors.elPermalinkDisplay); const editor = permalinkRoot.querySelector(BuilderEditLesson.selectors.elPermalinkEditor); let placeholder = permalinkRoot.querySelector(BuilderEditLesson.selectors.elPermalinkPlaceholder); if (!placeholder) { placeholder = document.createElement('span'); placeholder.className = 'cb-item-edit-permalink__placeholder'; if (label) { label.insertAdjacentElement('afterend', placeholder); } else { permalinkRoot.prepend(placeholder); } } placeholder.textContent = message || 'Permalink is only available if the item is already assigned to a course.'; placeholder.classList.remove('lp-hidden'); if (display) { display.classList.add('lp-hidden'); } if (editor) { editor.classList.add('lp-hidden'); } } getLessonDataForUpdate() { const data = {}; const wrapperEl = document.querySelector(BuilderEditLesson.selectors.elDataLesson); data.lesson_id = wrapperEl ? parseInt(wrapperEl.dataset.lessonId) || 0 : 0; const titleInput = document.getElementById(BuilderEditLesson.selectors.idTitle); data.lesson_title = titleInput ? titleInput.value : ''; data.lesson_description = this.getDescriptionContentForUpdate(); const permalinkInput = document.querySelector(`input[name="lesson_permalink"], #lesson_permalink, ${BuilderEditLesson.selectors.elPermalinkSlugInput}`); if (permalinkInput && permalinkInput.value) { data.lesson_permalink = permalinkInput.value; } const elFormSetting = document.querySelector(BuilderEditLesson.selectors.elFormSetting); if (elFormSetting) { data.lesson_settings = true; const formElements = elFormSetting.querySelectorAll('input, select, textarea'); formElements.forEach(element => { const name = element.name || element.id; if (!name || name === 'learnpress_meta_box_nonce' || name === '_wp_http_referer') { return; } if (element.type === 'checkbox') { const fieldName = name.replace('[]', ''); if (!data.hasOwnProperty(fieldName)) { data[fieldName] = element.checked ? 'yes' : 'no'; } } else if (element.type === 'radio') { if (element.checked) { const fieldName = name.replace('[]', ''); data[fieldName] = element.value; } } else if (element.type === 'file') { const fieldName = name.replace('[]', ''); if (element.files && element.files.length > 0) { data[fieldName] = element.files; } } else { const fieldName = name.replace('[]', ''); if (name.endsWith('[]')) { if (!data.hasOwnProperty(fieldName)) { data[fieldName] = []; } if (Array.isArray(data[fieldName])) { data[fieldName].push(element.value); } } else { if (!data.hasOwnProperty(fieldName)) { data[fieldName] = element.value; } } } }); Object.keys(data).forEach(key => { if (Array.isArray(data[key])) { data[key] = data[key].join(','); } }); } return data; } updatePermalinkUIAfterSave(data = {}) { const permalinkRoot = this.getPermalinkRoot(); if (!permalinkRoot) { return; } const slugInput = permalinkRoot.querySelector(BuilderEditLesson.selectors.elPermalinkSlugInput); const urlLink = permalinkRoot.querySelector(BuilderEditLesson.selectors.elPermalinkUrl); const baseUrlInput = permalinkRoot.querySelector(BuilderEditLesson.selectors.elPermalinkBaseUrl); const display = permalinkRoot.querySelector(BuilderEditLesson.selectors.elPermalinkDisplay); const placeholder = permalinkRoot.querySelector(BuilderEditLesson.selectors.elPermalinkPlaceholder); const permalinkDisplayUrl = this.buildPermalinkDisplayUrl(baseUrlInput ? baseUrlInput.value : '', data?.lesson_slug, data?.lesson_permalink); if (slugInput && data?.lesson_slug) { slugInput.value = data.lesson_slug; slugInput.dataset.originalValue = data.lesson_slug; } const shouldShowUnavailable = data?.permalink_available === false || data?.status === 'draft' || data?.status === 'trash' || !data?.lesson_permalink; if (shouldShowUnavailable) { this.showPermalinkUnavailable(permalinkRoot, data?.permalink_notice); return; } if (placeholder) { placeholder.classList.add('lp-hidden'); } if (display) { display.classList.remove('lp-hidden'); } if (urlLink && data?.lesson_permalink) { urlLink.href = data.lesson_permalink; urlLink.textContent = permalinkDisplayUrl || data.lesson_permalink; } else if (urlLink && permalinkDisplayUrl) { urlLink.textContent = permalinkDisplayUrl; } } handlePermalinkEdit(args) { if (!this.isLessonContext()) { return; } const { e, target } = args; if (e) e.preventDefault(); const trigger = target?.closest(BuilderEditLesson.selectors.elPermalinkEditBtn); const lessonRoot = trigger?.closest(BuilderEditLesson.selectors.elDataLesson) || document.querySelector(BuilderEditLesson.selectors.elDataLesson); if (!lessonRoot) { return; } const display = lessonRoot.querySelector(BuilderEditLesson.selectors.elPermalinkDisplay); const editor = lessonRoot.querySelector(BuilderEditLesson.selectors.elPermalinkEditor); const input = lessonRoot.querySelector(BuilderEditLesson.selectors.elPermalinkSlugInput); if (!display || !editor || !input) { return; } input.dataset.originalValue = input.value; display.classList.add('lp-hidden'); editor.classList.remove('lp-hidden'); input.focus(); input.select(); } handlePermalinkOk(args) { if (!this.isLessonContext()) { return; } const { e, target } = args; if (e) e.preventDefault(); const trigger = target?.closest(BuilderEditLesson.selectors.elPermalinkOkBtn); const lessonRoot = trigger?.closest(BuilderEditLesson.selectors.elDataLesson) || document.querySelector(BuilderEditLesson.selectors.elDataLesson); if (!lessonRoot) { return; } const display = lessonRoot.querySelector(BuilderEditLesson.selectors.elPermalinkDisplay); const editor = lessonRoot.querySelector(BuilderEditLesson.selectors.elPermalinkEditor); const input = lessonRoot.querySelector(BuilderEditLesson.selectors.elPermalinkSlugInput); const urlLink = lessonRoot.querySelector(BuilderEditLesson.selectors.elPermalinkUrl); const baseUrlInput = lessonRoot.querySelector(BuilderEditLesson.selectors.elPermalinkBaseUrl); if (!display || !editor || !input || !urlLink) { return; } let newSlug = this.slugify(input.value.trim()); if (!newSlug) { newSlug = input.dataset.originalValue || 'lesson'; } input.value = newSlug; const baseUrl = baseUrlInput ? baseUrlInput.value : ''; const newUrl = this.buildPermalinkDisplayUrl(baseUrl, newSlug, urlLink.textContent || ''); // Keep href as the current saved link and only update display text. urlLink.textContent = newUrl; editor.classList.add('lp-hidden'); display.classList.remove('lp-hidden'); } handlePermalinkCancel(args) { if (!this.isLessonContext()) { return; } const { e, target } = args; if (e) e.preventDefault(); const trigger = target?.closest(BuilderEditLesson.selectors.elPermalinkCancelBtn); const lessonRoot = trigger?.closest(BuilderEditLesson.selectors.elDataLesson) || document.querySelector(BuilderEditLesson.selectors.elDataLesson); if (!lessonRoot) { return; } const display = lessonRoot.querySelector(BuilderEditLesson.selectors.elPermalinkDisplay); const editor = lessonRoot.querySelector(BuilderEditLesson.selectors.elPermalinkEditor); const input = lessonRoot.querySelector(BuilderEditLesson.selectors.elPermalinkSlugInput); if (!display || !editor || !input) { return; } input.value = input.dataset.originalValue || ''; editor.classList.add('lp-hidden'); display.classList.remove('lp-hidden'); } updateLesson(args) { // Context check: only handle if on lesson edit page if (!this.isLessonContext()) { return; } const { target } = args; const elBtnUpdateLesson = target.closest(BuilderEditLesson.selectors.elBtnMainAction); if (!elBtnUpdateLesson) { return; } // Validate title before update if (!this.validateTitleBeforeUpdate()) { return; } lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elBtnUpdateLesson, 1); const lessonData = this.getLessonDataForUpdate(); const targetStatus = elBtnUpdateLesson.dataset.status || 'publish'; const dataSend = { ...lessonData, action: 'builder_update_lesson', args: { id_url: 'builder-update-lesson' }, lesson_status: targetStatus }; if (typeof lpLessonBuilder !== 'undefined' && lpLessonBuilder.nonce) { dataSend.nonce = lpLessonBuilder.nonce; } const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (status === 'success') { // Update action button text this.updateActionButtons(targetStatus); if (data?.lesson_id_new) { const currentUrl = window.location.href; window.location.href = currentUrl.replace(/post-new\/?/, `${data.lesson_id_new}/`); } if (data?.status) { const elStatus = document.querySelector(BuilderEditLesson.selectors.elLessonStatus); if (elStatus) { elStatus.className = 'lesson-status ' + data.status; elStatus.textContent = data.status; } if (data.status === 'trash' || data.status === 'draft') { const curriculumItem = document.querySelector(`.lesson-item[data-lesson-id="${lessonData.lesson_id}"]`); if (curriculumItem) { const elCurriculumLesson = curriculumItem.closest('.lesson'); if (elCurriculumLesson) { elCurriculumLesson.remove(); } } } } this.updatePermalinkUIAfterSave(data); // Reset form state to prevent "leave site" warning document.dispatchEvent(new CustomEvent('lp-course-builder-saved')); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elBtnUpdateLesson, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } saveDraftLesson(args) { // Context check: only handle if on lesson edit page if (!this.isLessonContext()) { return; } const { target } = args; const elBtnDraftLesson = target.closest(BuilderEditLesson.selectors.elBtnDraft); if (!elBtnDraftLesson) { return; } // Check if published to show confirm unpublish modal const statusEl = document.querySelector(BuilderEditLesson.selectors.elLessonStatus); const isPublished = statusEl && statusEl.classList.contains('publish'); if (isPublished) { const confirmMsg = elBtnDraftLesson.dataset.confirmUnpublish || 'Saving as draft will unpublish this item. Are you sure?'; if (!confirm(confirmMsg)) { return; } } // Validate title before saving draft if (!this.validateTitleBeforeUpdate()) { return; } lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elBtnDraftLesson, 1); const lessonData = this.getLessonDataForUpdate(); const dataSend = { ...lessonData, action: 'builder_update_lesson', args: { id_url: 'builder-update-lesson' }, lesson_status: 'draft' }; if (typeof lpLessonBuilder !== 'undefined' && lpLessonBuilder.nonce) { dataSend.nonce = lpLessonBuilder.nonce; } const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (status === 'success') { // Update action button text this.updateActionButtons('draft'); if (data?.lesson_id_new) { const currentUrl = window.location.href; window.location.href = currentUrl.replace(/post-new\/?/, `${data.lesson_id_new}/`); } if (data?.status) { const elStatus = document.querySelector(BuilderEditLesson.selectors.elLessonStatus); if (elStatus) { elStatus.className = 'lesson-status ' + data.status; elStatus.textContent = data.status; } if (data.status === 'trash' || data.status === 'draft') { const curriculumItem = document.querySelector(`.lesson-item[data-lesson-id="${lessonData.lesson_id}"]`); if (curriculumItem) { const elCurriculumLesson = curriculumItem.closest('.lesson'); if (elCurriculumLesson) { elCurriculumLesson.remove(); } } } } this.updatePermalinkUIAfterSave(data); // Reset form state to prevent "leave site" warning document.dispatchEvent(new CustomEvent('lp-course-builder-saved')); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elBtnDraftLesson, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } trashLesson(args) { // Context check: only handle if on lesson edit page if (!this.isLessonContext()) { return; } const { target } = args; const elBtnTrashLesson = target.closest(BuilderEditLesson.selectors.elBtnTrash); if (!elBtnTrashLesson) { return; } if (!confirm('Are you sure you want to trash this lesson?')) { return; } lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elBtnTrashLesson, 1); const lessonData = this.getLessonDataForUpdate(); const dataSend = { action: 'move_trash_lesson', args: { id_url: 'move-trash-lesson' }, lesson_id: lessonData.lesson_id }; const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (status === 'success') { if (data?.redirect_url) { window.location.href = data.redirect_url; } if (data?.status) { const elStatus = document.querySelector(BuilderEditLesson.selectors.elLessonStatus); if (elStatus) { elStatus.className = 'lesson-status ' + data.status; elStatus.textContent = data.status; } if (data.status === 'trash' || data.status === 'draft') { const curriculumItem = document.querySelector(`.lesson-item[data-lesson-id="${lessonData.lesson_id}"]`); if (curriculumItem) { const elCurriculumLesson = curriculumItem.closest('.lesson'); if (elCurriculumLesson) { elCurriculumLesson.remove(); } } } } this.updatePermalinkUIAfterSave(data); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elBtnTrashLesson, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } } /***/ }, /***/ "./assets/src/js/frontend/course-builder/builder-lesson/builder-material.js" /*!**********************************************************************************!*\ !*** ./assets/src/js/frontend/course-builder/builder-lesson/builder-material.js ***! \**********************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ BuilderMaterial: () => (/* binding */ BuilderMaterial), /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /** * Builder Material Handler * Handles material upload and management for lesson popup in course builder. * Pure JavaScript implementation with optimizations * * @since 4.3.0 * @version 1.0.0 */ class BuilderMaterial { constructor(container = null) { this.container = container; this.initialized = false; this.eventsBound = false; this.sortable = null; // Store references for cleanup this.boundHandlers = { handleAddMaterial: null, handleChange: null, handleClick: null, handleSaveAll: null, handleDelete: null, handleDragStart: null, handleDragOver: null, handleDrop: null, handleDragEnd: null }; // Cache DOM elements this.elements = {}; if (this.container) { this.init(); } } /** * Reinitialize with new container (called from BuilderPopup) */ reinit(container) { if (this.initialized) { this.destroy(); } this.container = container; if (this.container) { this.init(); } } /** * Cache all DOM elements for better performance */ cacheElements() { const el = this.elements; el.postId = this.container.querySelector('#current-material-post-id'); el.maxFileSize = this.container.querySelector('#material-max-file-size'); el.uploadField = this.container.querySelector('.lp-material--field-upload'); el.canUpload = this.container.querySelector('#available-to-upload'); el.addBtn = this.container.querySelector('#btn-lp--add-material'); el.groupTemplate = this.container.querySelector('#lp-material--add-material-template'); el.groupContainer = this.container.querySelector('#lp-material--group-container'); el.materialTab = this.container.querySelector('#lp-material-container') || this.container; el.saveBtn = this.container.querySelector('#btn-lp--save-material'); el.uploadTemplate = this.container.querySelector('#lp-material--upload-field-template'); el.externalTemplate = this.container.querySelector('#lp-material--external-field-template'); el.deleteText = this.container.querySelector('#delete-material-row-text'); el.deleteMessage = this.container.querySelector('#delete-material-message'); el.materialTable = this.container.querySelector('.lp-material--table'); el.tbody = el.materialTable?.querySelector('tbody'); el.thead = el.materialTable?.querySelector('thead'); } init() { if (!this.container) return; // Cache all elements this.cacheElements(); const { postId, materialTab } = this.elements; // Validate required elements if (!postId || !materialTab) return; // Store config values this.postID = postId.value; this.maxFileSize = this.elements.maxFileSize?.value || 10; this.acceptFile = this.elements.uploadField ? this.elements.uploadField.getAttribute('accept')?.split(',').map(s => s.trim()) || [] : []; // Load existing materials this.loadMaterials(); // Bind events this.bindEvents(); // Initialize native drag & drop sortable this.initSortable(); this.initialized = true; } /** * Load materials from API with better error handling */ async loadMaterials() { const { materialTab, tbody } = this.elements; if (!materialTab || !this.postID || !tbody) return; try { const restUrl = this.getRestUrl(); const url = `${restUrl}lp/v1/material/item-materials/${this.postID}`; const response = await fetch(url, { method: 'GET', headers: { 'X-WP-Nonce': this.getNonce(), 'Content-Type': 'application/json' } }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const result = await response.json(); const { data, status } = result; if (status !== 'success') { console.error(result.message); return; } if (data?.items?.length > 0) { // Remove skeleton loader const skeleton = materialTab.querySelector('.lp-skeleton-animation'); skeleton?.remove(); // Use DocumentFragment for better performance const fragment = document.createDocumentFragment(); data.items.forEach(item => { const row = this.createRow(item); fragment.appendChild(row); }); tbody.appendChild(fragment); // Reinit sortable after loading data this.initSortable(); } } catch (error) { console.error('Load materials error:', error.message); } } /** * Create a table row element (more efficient than insertAdjacentHTML) */ createRow(data) { const tr = document.createElement('tr'); tr.dataset.id = data.file_id; tr.dataset.sort = data.orders; tr.draggable = true; const deleteBtnText = this.elements.deleteText?.value || 'Delete'; tr.innerHTML = ` ${this.escapeHtml(data.file_name)} ${this.capitalizeFirstChar(data.method)} ${deleteBtnText} `; return tr; } /** * Escape HTML to prevent XSS */ escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } capitalizeFirstChar(str) { return str.charAt(0).toUpperCase() + str.substring(1); } /** * Bind all events with delegation for better performance */ bindEvents() { if (this.eventsBound) return; const { addBtn, materialTab, saveBtn } = this.elements; // Create bound handlers for later removal this.boundHandlers.handleAddMaterial = () => this.handleAddMaterial(); this.boundHandlers.handleChange = e => this.handleChange(e); this.boundHandlers.handleClick = e => this.handleClick(e); this.boundHandlers.handleSaveAll = () => this.handleSaveAll(); this.boundHandlers.handleDelete = e => this.handleDelete(e); // Add material button addBtn?.addEventListener('click', this.boundHandlers.handleAddMaterial); // Use event delegation on materialTab if (materialTab) { materialTab.addEventListener('change', this.boundHandlers.handleChange); materialTab.addEventListener('click', this.boundHandlers.handleClick); } // Save all button saveBtn?.addEventListener('click', this.boundHandlers.handleSaveAll); // Delete material (use event delegation on container) this.container.addEventListener('click', this.boundHandlers.handleDelete); this.eventsBound = true; } /** * Handle add material button click */ handleAddMaterial() { const { addBtn, groupContainer, groupTemplate } = this.elements; if (!addBtn || !groupContainer || !groupTemplate) return; const canUploadData = parseInt(addBtn.getAttribute('can-upload')) || 0; const groups = groupContainer.querySelectorAll('.lp-material--group').length; if (groups >= canUploadData) return; groupContainer.insertAdjacentHTML('afterbegin', groupTemplate.innerHTML); } /** * Handle change events with delegation */ handleChange(event) { const target = event.target; // Switch between upload and external if (target.classList.contains('lp-material--field-method')) { this.handleMethodSwitch(target); } // File validation if (target.classList.contains('lp-material--field-upload')) { this.validateFile(target); } } /** * Handle method switch (upload/external) */ handleMethodSwitch(target) { const method = target.value; const { uploadTemplate, externalTemplate } = this.elements; if (!uploadTemplate || !externalTemplate) return; const group = target.closest('.lp-material--group'); if (!group) return; switch (method) { case 'upload': target.parentNode.insertAdjacentHTML('afterend', uploadTemplate.innerHTML); group.querySelector('.lp-material--external-wrap')?.remove(); break; case 'external': target.parentNode.insertAdjacentHTML('afterend', externalTemplate.innerHTML); group.querySelector('.lp-material--upload-wrap')?.remove(); break; } } /** * Validate uploaded file */ validateFile(target) { if (!target.value || !target.files?.length) { this.resetUploadLabel(target); return; } const file = target.files[0]; if (this.acceptFile.length > 0 && !this.acceptFile.includes(file.type)) { alert('This file is not allowed! Please choose another file!'); target.value = ''; this.resetUploadLabel(target); return; } if (file.size > this.maxFileSize * 1024 * 1024) { alert(`This file size is greater than ${this.maxFileSize}MB! Please choose another file!`); target.value = ''; this.resetUploadLabel(target); return; } this.updateUploadLabel(target, file.name); } /** * Update upload label to show selected file name */ updateUploadLabel(target, fileName) { if (!fileName) return; const uploadLabel = target.closest('.lp-material--upload-wrap')?.querySelector('label'); if (!uploadLabel) return; uploadLabel.classList.add('has-selected-file'); uploadLabel.setAttribute('data-file-name', fileName); uploadLabel.setAttribute('title', fileName); } /** * Reset upload label state */ resetUploadLabel(target) { const uploadLabel = target?.closest('.lp-material--upload-wrap')?.querySelector('label'); if (!uploadLabel) return; uploadLabel.classList.remove('has-selected-file'); uploadLabel.removeAttribute('data-file-name'); uploadLabel.removeAttribute('title'); } /** * Handle click events with delegation */ handleClick(event) { const target = event.target; // Delete group if (target.classList.contains('lp-material--delete') && target.nodeName === 'BUTTON') { target.closest('.lp-material--group')?.remove(); return; } // Save single material if (target.classList.contains('lp-material-save-field')) { const material = target.closest('.lp-material--group'); if (material) { this.saveMaterial([material], true, target); } } } /** * Handle save all button */ handleSaveAll() { const { groupContainer, saveBtn } = this.elements; if (!groupContainer) return; const materials = Array.from(groupContainer.querySelectorAll('.lp-material--group')); if (materials.length > 0) { this.saveMaterial(materials, false, saveBtn); } } /** * Save material(s) with improved validation */ async saveMaterial(materials, isSingle = false, targetBtn) { if (!materials.length) return; const materialData = []; const formData = new FormData(); let isValid = true; for (const ele of materials) { const label = ele.querySelector('.lp-material--field-title')?.value; const method = ele.querySelector('.lp-material--field-method')?.value; const externalField = ele.querySelector('.lp-material--field-external-link'); const uploadField = ele.querySelector('.lp-material--field-upload'); if (!label) { isValid = false; break; } let file = ''; let link = ''; switch (method) { case 'upload': if (uploadField?.value && uploadField.files?.length > 0) { file = uploadField.files[0].name; formData.append('file[]', uploadField.files[0]); } else { isValid = false; } break; case 'external': link = externalField?.value || ''; if (!link) { isValid = false; } break; } if (!isValid) break; materialData.push({ label, method, file, link }); } if (!isValid) { alert('Enter file title, choose file or enter file link!'); return; } formData.append('data', JSON.stringify(materialData)); targetBtn?.classList.add('loading'); try { const restUrl = this.getRestUrl(); const url = `${restUrl}lp/v1/material/item-materials/${this.postID}`; const response = await fetch(url, { method: 'POST', headers: { 'X-WP-Nonce': this.getNonce() }, body: formData }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const text = await response.text(); let res; try { res = JSON.parse(text); } catch (e) { console.error('Response is not valid JSON:', text.substring(0, 200)); throw new Error('Server returned invalid response. Check console for details.'); } // Clear or remove materials if (!isSingle) { materials.forEach(ele => { ele.querySelector('.lp-material--field-title').value = ''; const uploadField = ele.querySelector('.lp-material--field-upload'); if (uploadField) { uploadField.value = ''; this.resetUploadLabel(uploadField); } const externalField = ele.querySelector('.lp-material--field-external-link'); if (externalField) externalField.value = ''; }); } else { materials[0].remove(); } const { message, data, status } = res; // console.log( message ); if (status === 'success' && data?.length > 0) { const { thead, tbody } = this.elements; thead?.classList.remove('hidden'); if (tbody) { const fragment = document.createDocumentFragment(); data.forEach(row => { fragment.appendChild(this.createRow(row)); }); tbody.appendChild(fragment); } this.updateCanUploadCount(-data.length); this.initSortable(); } } catch (err) { console.error('Save material error:', err); alert('Error saving material: ' + err.message); } finally { targetBtn?.classList.remove('loading'); } } /** * Handle delete material */ async handleDelete(e) { const target = e.target; if (!target.classList.contains('delete-material-row') || target.nodeName !== 'A') { return; } e.preventDefault(); const rowID = target.dataset.id; const message = this.elements.deleteMessage?.value || 'Are you sure you want to delete this material?'; if (!confirm(message)) return; try { const restUrl = this.getRestUrl(); const url = `${restUrl}lp/v1/material/${rowID}`; const response = await fetch(url, { method: 'DELETE', headers: { 'X-WP-Nonce': this.getNonce(), 'Content-Type': 'application/json' }, body: JSON.stringify({ item_id: this.postID }) }); const res = await response.json(); if (res.status !== 200 || !res.delete) { alert(res.message); } else { target.closest('tr')?.remove(); this.updateCanUploadCount(1); } } catch (err) { console.error('Delete material error:', err); alert('Error deleting material: ' + err.message); } } /** * Update can upload count */ updateCanUploadCount(delta) { const { canUpload, addBtn } = this.elements; if (canUpload && addBtn) { const newCount = parseInt(canUpload.textContent) + delta; canUpload.textContent = newCount; addBtn.setAttribute('can-upload', newCount); } } /** * Initialize native drag & drop sortable (no jQuery) */ initSortable() { const { tbody } = this.elements; if (!tbody) return; // Remove existing listeners this.destroySortable(); const rows = tbody.querySelectorAll('tr'); // Create bound handlers this.boundHandlers.handleDragStart = e => this.handleDragStart(e); this.boundHandlers.handleDragOver = e => this.handleDragOver(e); this.boundHandlers.handleDrop = e => this.handleDrop(e); this.boundHandlers.handleDragEnd = () => this.handleDragEnd(); rows.forEach(row => { row.draggable = true; row.addEventListener('dragstart', this.boundHandlers.handleDragStart); row.addEventListener('dragover', this.boundHandlers.handleDragOver); row.addEventListener('drop', this.boundHandlers.handleDrop); row.addEventListener('dragend', this.boundHandlers.handleDragEnd); }); this.sortable = { tbody, rows }; } handleDragStart(e) { this.draggedElement = e.currentTarget; e.currentTarget.style.opacity = '0.4'; e.dataTransfer.effectAllowed = 'move'; e.dataTransfer.setData('text/html', e.currentTarget.innerHTML); } handleDragOver(e) { if (e.preventDefault) { e.preventDefault(); } e.dataTransfer.dropEffect = 'move'; const target = e.currentTarget; if (this.draggedElement !== target) { const rect = target.getBoundingClientRect(); const next = (e.clientY - rect.top) / (rect.bottom - rect.top) > 0.5; target.parentNode.insertBefore(this.draggedElement, next ? target.nextSibling : target); } return false; } handleDrop(e) { if (e.stopPropagation) { e.stopPropagation(); } return false; } handleDragEnd() { this.draggedElement.style.opacity = '1'; this.draggedElement = null; // Update sort order after drag ends this.updateSort(); } /** * Update sort order */ async updateSort() { const { tbody } = this.elements; if (!tbody) return; const items = tbody.querySelectorAll('tr'); const data = Array.from(items).map((item, index) => { item.dataset.sort = index + 1; return { file_id: parseInt(item.dataset.id), orders: index + 1 }; }); try { const restUrl = this.getRestUrl(); const url = `${restUrl}lp/v1/material/item-materials/${this.postID}`; const response = await fetch(url, { method: 'PUT', headers: { 'X-WP-Nonce': this.getNonce(), 'Content-Type': 'application/json' }, body: JSON.stringify({ sort_arr: JSON.stringify(data) }) }); const res = await response.json(); if (res.status !== 200) { console.error('Sort table fail.'); } } catch (err) { console.error('Update sort error:', err); } } /** * Helper methods for REST URL and nonce */ getRestUrl() { return window.lpGlobalSettings?.rest || window.lpData?.lp_rest_url || '/wp-json/'; } getNonce() { return window.lpGlobalSettings?.nonce || window.lpData?.nonce || ''; } /** * Destroy sortable */ destroySortable() { if (!this.sortable) return; const { rows } = this.sortable; rows?.forEach(row => { row.removeEventListener('dragstart', this.boundHandlers.handleDragStart); row.removeEventListener('dragover', this.boundHandlers.handleDragOver); row.removeEventListener('drop', this.boundHandlers.handleDrop); row.removeEventListener('dragend', this.boundHandlers.handleDragEnd); }); this.sortable = null; } /** * Destroy instance and cleanup */ destroy() { const { addBtn, materialTab, saveBtn } = this.elements; // Remove event listeners if (addBtn) { addBtn.removeEventListener('click', this.boundHandlers.handleAddMaterial); } if (materialTab) { materialTab.removeEventListener('change', this.boundHandlers.handleChange); materialTab.removeEventListener('click', this.boundHandlers.handleClick); } if (saveBtn) { saveBtn.removeEventListener('click', this.boundHandlers.handleSaveAll); } if (this.container) { this.container.removeEventListener('click', this.boundHandlers.handleDelete); } // Destroy sortable this.destroySortable(); // Reset bound handlers this.boundHandlers = { handleAddMaterial: null, handleChange: null, handleClick: null, handleSaveAll: null, handleDelete: null, handleDragStart: null, handleDragOver: null, handleDrop: null, handleDragEnd: null }; // Clear cached elements this.elements = {}; this.initialized = false; this.eventsBound = false; } } /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (BuilderMaterial); /***/ }, /***/ "./assets/src/js/frontend/course-builder/builder-lesson/builder-tab-lesson.js" /*!************************************************************************************!*\ !*** ./assets/src/js/frontend/course-builder/builder-lesson/builder-tab-lesson.js ***! \************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ BuilderTabLesson: () => (/* binding */ BuilderTabLesson) /* harmony export */ }); /* harmony import */ var lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lpAssetsJsPath/utils.js */ "./assets/src/js/utils.js"); /* harmony import */ var lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! lpAssetsJsPath/lpToastify.js */ "./assets/src/js/lpToastify.js"); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! sweetalert2 */ "./node_modules/sweetalert2/dist/sweetalert2.all.js"); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(sweetalert2__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _swal_icons_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../swal-icons.js */ "./assets/src/js/frontend/course-builder/swal-icons.js"); class BuilderTabLesson { constructor() { this.init(); } static selectors = { elLessonItem: '.lesson-item', elLessonExpandedItems: '.lesson-action-expanded__items', elLessonDuplicate: '.lesson-action-expanded__duplicate', elLessonTrash: '.lesson-action-expanded__trash', elLessonRestore: '.lesson-action-expanded__restore', elLessonPublish: '.lesson-action-expanded__publish', elLessonDelete: '.lesson-action-expanded__delete', elLessonActionExpanded: '.lesson-action-expanded', elLessonStatus: '.lesson-status', elLessonPreview: '.lesson__preview.lp-btn-set-preview-item' }; init() { this.events(); } events() { if (BuilderTabLesson._loadedEvents) { return; } BuilderTabLesson._loadedEvents = true; lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('click', [{ selector: BuilderTabLesson.selectors.elLessonDuplicate, class: this, callBack: this.duplicateLesson.name }, { selector: BuilderTabLesson.selectors.elLessonTrash, class: this, callBack: this.trashLesson.name }, { selector: BuilderTabLesson.selectors.elLessonPublish, class: this, callBack: this.publishLesson.name }, { selector: BuilderTabLesson.selectors.elLessonRestore, class: this, callBack: this.restoreLesson.name }, { selector: BuilderTabLesson.selectors.elLessonDelete, class: this, callBack: this.deleteLesson.name }, { selector: BuilderTabLesson.selectors.elLessonActionExpanded, class: this, callBack: this.toggleExpandedAction.name }, { selector: BuilderTabLesson.selectors.elLessonPreview, class: this, callBack: this.toggleLessonPreview.name }]); document.addEventListener('click', e => { if (!e.target.closest(BuilderTabLesson.selectors.elLessonActionExpanded)) { this.closeAllExpanded(); } }); document.addEventListener('lp-builder-popup-saved', e => { const { type, id, data } = e.detail; if (type !== 'lesson' || !data?.list_item_html) return; const elItem = document.querySelector(`.lesson-item[data-lesson-id="${id}"]`); if (elItem) { this.replaceItemHtml(elItem.closest('.lesson'), data.list_item_html); } }); document.addEventListener('lp-builder-popup-trashed', e => { const { type, id, data } = e.detail; if (type !== 'lesson' || !data?.html) return; const elItem = document.querySelector(`.lesson-item[data-lesson-id="${id}"]`); if (elItem) { this.replaceItemHtml(elItem.closest('.lesson'), data.html); } }); } duplicateLesson(args) { const { target } = args; const elLessonDuplicate = target.closest(BuilderTabLesson.selectors.elLessonDuplicate); const elLessonItem = elLessonDuplicate.closest(BuilderTabLesson.selectors.elLessonItem); if (!elLessonItem) { return; } const elActionExpanded = elLessonItem.querySelector(BuilderTabLesson.selectors.elLessonActionExpanded); const lessonId = elLessonItem.dataset.lessonId || ''; sweetalert2__WEBPACK_IMPORTED_MODULE_2___default().fire({ title: elLessonDuplicate.dataset.title || 'Duplicate Lesson', text: elLessonDuplicate.dataset.content || 'Are you sure you want to duplicate this lesson?', iconHtml: _swal_icons_js__WEBPACK_IMPORTED_MODULE_3__.SWAL_ICON_DUPLICATE, customClass: { icon: 'lp-cb-swal-icon-html' }, showCloseButton: true, showCancelButton: true, cancelButtonText: lpData.i18n.cancel, confirmButtonText: lpData.i18n.yes, reverseButtons: true }).then(result => { if (result.isConfirmed) { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 1); const dataSend = { action: 'duplicate_lesson', args: { id_url: 'duplicate-lesson' }, lesson_id: lessonId }; const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message || 'Duplicated successfully!', status); if (data?.html) { const elLesson = elLessonDuplicate.closest('.lesson'); const elLessonList = elLesson.closest('.lessons-list') || elLesson.parentElement; if (elLessonList) { elLessonList.insertAdjacentHTML('afterbegin', data.html); const newLesson = elLessonList.firstElementChild; if (newLesson) { newLesson.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); newLesson.classList.add('highlight-new-lesson'); setTimeout(() => { newLesson.classList.remove('highlight-new-lesson'); }, 1500); } } } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } }); } trashLesson(args) { const { target } = args; const elLessonTrash = target.closest(BuilderTabLesson.selectors.elLessonTrash); const elLessonItem = elLessonTrash.closest(BuilderTabLesson.selectors.elLessonItem); if (!elLessonItem) { return; } const elActionExpanded = elLessonItem.querySelector(BuilderTabLesson.selectors.elLessonActionExpanded); const lessonId = elLessonItem.dataset.lessonId || ''; sweetalert2__WEBPACK_IMPORTED_MODULE_2___default().fire({ title: elLessonTrash.dataset.title || 'Trash Lesson', text: elLessonTrash.dataset.content || 'Are you sure? Moving it to the trash will cause this item to be removed from the course.', iconHtml: _swal_icons_js__WEBPACK_IMPORTED_MODULE_3__.SWAL_ICON_TRASH_DRAFT, customClass: { icon: 'lp-cb-swal-icon-html' }, showCloseButton: true, showCancelButton: true, cancelButtonText: lpData.i18n.cancel, confirmButtonText: lpData.i18n.yes, reverseButtons: true }).then(result => { if (result.isConfirmed) { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 1); const dataSend = { action: 'move_trash_lesson', args: { id_url: 'move-trash-lesson' }, lesson_id: lessonId }; const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (data?.html) { this.replaceItemHtml(elLessonTrash.closest('.lesson'), data.html); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } }); } publishLesson(args) { const { target } = args; const elLessonPublish = target.closest(BuilderTabLesson.selectors.elLessonPublish); const elLessonItem = elLessonPublish.closest(BuilderTabLesson.selectors.elLessonItem); if (!elLessonItem) { return; } const elActionExpanded = elLessonItem.querySelector(BuilderTabLesson.selectors.elLessonActionExpanded); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 1); const lessonId = elLessonItem.dataset.lessonId || ''; const dataSend = { action: 'move_trash_lesson', args: { id_url: 'move-trash-lesson' }, lesson_id: lessonId, status: 'publish' }; const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (data?.html) { this.replaceItemHtml(elLessonPublish.closest('.lesson'), data.html); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } restoreLesson(args) { const { target } = args; const elLessonRestore = target.closest(BuilderTabLesson.selectors.elLessonRestore); const elLessonItem = elLessonRestore.closest(BuilderTabLesson.selectors.elLessonItem); if (!elLessonItem) { return; } const elActionExpanded = elLessonItem.querySelector(BuilderTabLesson.selectors.elLessonActionExpanded); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 1); const lessonId = elLessonItem.dataset.lessonId || ''; const dataSend = { action: 'move_trash_lesson', args: { id_url: 'move-trash-lesson' }, lesson_id: lessonId, status: 'draft' }; const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (data?.html) { this.replaceItemHtml(elLessonRestore.closest('.lesson'), data.html); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } deleteLesson(args) { const { target } = args; const elLessonDelete = target.closest(BuilderTabLesson.selectors.elLessonDelete); const elLessonItem = elLessonDelete.closest(BuilderTabLesson.selectors.elLessonItem); if (!elLessonItem) { return; } const elActionExpanded = elLessonItem.querySelector(BuilderTabLesson.selectors.elLessonActionExpanded); const lessonId = elLessonItem.dataset.lessonId || ''; if (!lessonId) { return; } sweetalert2__WEBPACK_IMPORTED_MODULE_2___default().fire({ title: elLessonDelete.dataset.title || 'Delete Lesson', text: elLessonDelete.dataset.content || 'Are you sure you want to permanently delete this lesson?', iconHtml: _swal_icons_js__WEBPACK_IMPORTED_MODULE_3__.SWAL_ICON_DELETE, customClass: { icon: 'lp-cb-swal-icon-html' }, showCloseButton: true, showCancelButton: true, cancelButtonText: lpData.i18n.cancel, confirmButtonText: lpData.i18n.yes, reverseButtons: true }).then(result => { if (result.isConfirmed) { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 1); const dataSend = { action: 'move_trash_lesson', args: { id_url: 'move-trash-lesson' }, lesson_id: lessonId, status: 'delete' }; const callBack = { success: response => { const { status, message } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (status === 'success') { const elLesson = elLessonDelete.closest('.lesson'); elLesson.style.transition = 'opacity 0.4s ease-out, transform 0.4s ease-out'; elLesson.style.opacity = '0'; elLesson.style.transform = 'translateX(160px)'; setTimeout(() => { elLesson.remove(); }, 400); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } }); } toggleExpandedAction(args) { const { target } = args; const elLessonActionExpanded = target.closest(BuilderTabLesson.selectors.elLessonActionExpanded); if (!elLessonActionExpanded) { return; } const elLessonItem = elLessonActionExpanded.closest(BuilderTabLesson.selectors.elLessonItem); if (!elLessonItem) { return; } const elExpandedItems = elLessonItem.querySelector(BuilderTabLesson.selectors.elLessonExpandedItems); if (!elExpandedItems) { return; } this.closeAllExpanded(elExpandedItems); const willOpen = !elExpandedItems.classList.contains('active'); if (willOpen) { elExpandedItems.classList.add('active'); elLessonActionExpanded.classList.add('active'); this.setExpandedDirection(elExpandedItems); } else { elExpandedItems.classList.remove('active'); elExpandedItems.classList.remove('is-dropup'); elLessonActionExpanded.classList.remove('active'); } } closeAllExpanded(excludeElement = null) { const allExpandedItems = document.querySelectorAll(`${BuilderTabLesson.selectors.elLessonExpandedItems}.active`); allExpandedItems.forEach(item => { if (item === excludeElement) { return; } item.classList.remove('active'); item.classList.remove('is-dropup'); const lessonItem = item.closest(BuilderTabLesson.selectors.elLessonItem); if (!lessonItem) { return; } const expandedBtn = lessonItem.querySelector(BuilderTabLesson.selectors.elLessonActionExpanded); if (expandedBtn) { expandedBtn.classList.remove('active'); } }); } setExpandedDirection(elExpandedItems) { if (!elExpandedItems) { return; } elExpandedItems.classList.remove('is-dropup'); const elLesson = elExpandedItems.closest('.lesson'); if (!elLesson) { return; } if (elLesson.matches(':last-child')) { elExpandedItems.classList.add('is-dropup'); } } /* Toggle preview for a lesson in the lesson list */ toggleLessonPreview(args) { const { target } = args; const elPreviewBtn = target.closest(BuilderTabLesson.selectors.elLessonPreview); if (!elPreviewBtn) { return; } if (elPreviewBtn.classList.contains('loading') || elPreviewBtn.classList.contains('lp-loading')) { return; } const elLessonItem = elPreviewBtn.closest(BuilderTabLesson.selectors.elLessonItem); if (!elLessonItem) { return; } const icon = elPreviewBtn.querySelector('a'); if (!icon) { return; } const lessonId = elLessonItem.dataset.lessonId || elPreviewBtn.dataset.id || ''; if (!lessonId) { return; } // Optimistic toggle icon.classList.toggle('lp-icon-eye'); icon.classList.toggle('lp-icon-eye-slash'); const enablePreview = icon.classList.contains('lp-icon-eye'); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elPreviewBtn, 1); elPreviewBtn.classList.add('lp-loading'); const dataSend = { action: 'builder_update_lesson', args: { id_url: 'builder-update-lesson' }, lesson_id: lessonId, lesson_settings: true, _lp_preview: enablePreview ? 'yes' : '' }; const callBack = { success: response => { const { status, message } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (status === 'error') { // Revert on error icon.classList.toggle('lp-icon-eye'); icon.classList.toggle('lp-icon-eye-slash'); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); icon.classList.toggle('lp-icon-eye'); icon.classList.toggle('lp-icon-eye-slash'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elPreviewBtn, 0); elPreviewBtn.classList.remove('lp-loading'); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } replaceItemHtml(elLesson, html) { if (!elLesson || !html) { return; } const tmp = document.createElement('div'); tmp.innerHTML = html; const newEl = tmp.firstElementChild; if (newEl) { elLesson.replaceWith(newEl); } } } /***/ }, /***/ "./assets/src/js/frontend/course-builder/builder-popup.js" /*!****************************************************************!*\ !*** ./assets/src/js/frontend/course-builder/builder-popup.js ***! \****************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ BuilderPopup: () => (/* binding */ BuilderPopup), /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lpAssetsJsPath/utils.js */ "./assets/src/js/utils.js"); /* harmony import */ var lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! lpAssetsJsPath/lpToastify.js */ "./assets/src/js/lpToastify.js"); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! sweetalert2 */ "./node_modules/sweetalert2/dist/sweetalert2.all.js"); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(sweetalert2__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _swal_icons_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./swal-icons.js */ "./assets/src/js/frontend/course-builder/swal-icons.js"); /* harmony import */ var _builder_quiz_builder_edit_quiz_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./builder-quiz/builder-edit-quiz.js */ "./assets/src/js/frontend/course-builder/builder-quiz/builder-edit-quiz.js"); /* harmony import */ var _builder_question_builder_edit_question_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./builder-question/builder-edit-question.js */ "./assets/src/js/frontend/course-builder/builder-question/builder-edit-question.js"); /* harmony import */ var _builder_lesson_builder_material_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./builder-lesson/builder-material.js */ "./assets/src/js/frontend/course-builder/builder-lesson/builder-material.js"); /** * Builder Popup Handler * Handles AJAX popup loading for lesson, quiz, and question builders. * * @since 4.3.0 * @version 1.0.1 */ class BuilderPopup { constructor() { this.popupContainer = null; this.currentType = null; this.currentId = null; this.currentTemplate = ''; this.isNewItem = false; this.savedData = null; this.openContext = this.getDefaultOpenContext(); this.builderEditQuiz = null; this.builderEditQuestion = null; this.builderMaterial = null; this.loadedTabAssets = new Set(); this.initializedTabs = new Map(); this.init(); } static selectors = { popupContainer: '#lp-builder-popup-container', popupOverlay: '.lp-builder-popup-overlay', popup: '.lp-builder-popup', closeBtn: '.lp-builder-popup__close', resizeBtn: '.lp-builder-popup__resize', cancelBtn: '.lp-builder-popup__btn--cancel', saveBtn: '.lp-builder-popup__btn--save', draftBtn: '.lp-builder-popup__btn--draft', trashBtn: '.lp-builder-popup__btn--trash', tabs: '.lp-builder-popup__tabs', tab: '.lp-builder-popup__tab', tabPane: '.lp-builder-popup__tab-pane', permalinkSlugInput: '.cb-permalink-slug-input', permalinkUrl: '.cb-permalink-url', permalinkBaseUrl: '#cb-permalink-base-url', permalinkDisplay: '.cb-permalink-display', permalinkEditor: '.cb-permalink-editor', permalinkRoot: '.cb-item-edit-permalink, .cb-course-edit-permalink', permalinkPlaceholder: '.cb-item-edit-permalink__placeholder', // Trigger buttons popupTrigger: '[data-popup-lesson], [data-popup-quiz], [data-popup-question], [data-add-new-lesson], [data-template][data-popup-type]', triggerLesson: '[data-popup-lesson]', triggerQuiz: '[data-popup-quiz]', triggerQuestion: '[data-popup-question]', // Add new buttons addNewLesson: '[data-add-new-lesson]' }; init() { let popupContainer = document.querySelector(BuilderPopup.selectors.popupContainer); if (!popupContainer) { popupContainer = document.createElement('div'); popupContainer.id = 'lp-builder-popup-container'; document.body.appendChild(popupContainer); } this.popupContainer = popupContainer; this.events(); } events() { if (BuilderPopup._loadedEvents) { return; } BuilderPopup._loadedEvents = true; lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('click', [{ selector: BuilderPopup.selectors.popupTrigger, class: this, callBack: this.openPopup.name }, { selector: `${BuilderPopup.selectors.closeBtn}, ${BuilderPopup.selectors.cancelBtn}, ${BuilderPopup.selectors.popupOverlay}`, class: this, callBack: this.closePopup.name, conditionBeforeCallBack: () => this.isPopupOpen() }, { selector: BuilderPopup.selectors.resizeBtn, class: this, callBack: this.toggleFullscreen.name, conditionBeforeCallBack: () => this.isPopupOpen() }, { selector: BuilderPopup.selectors.tab, class: this, callBack: this.switchTab.name, conditionBeforeCallBack: () => this.isPopupOpen() }, { selector: BuilderPopup.selectors.saveBtn, class: this, callBack: this.handleSave.name, conditionBeforeCallBack: () => this.isPopupOpen() }, { selector: BuilderPopup.selectors.draftBtn, class: this, callBack: this.handleDraft.name, conditionBeforeCallBack: () => this.isPopupOpen() }, { selector: BuilderPopup.selectors.trashBtn, class: this, callBack: this.handleTrash.name, conditionBeforeCallBack: () => this.isPopupOpen() }]); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('keydown', [{ selector: 'body', class: this, callBack: this.closePopup.name, conditionBeforeCallBack: args => args.e.key === 'Escape' && this.isPopupOpen() }]); } /** * Toggle fullscreen mode for popup */ toggleFullscreen() { const popup = this.popupContainer.querySelector(BuilderPopup.selectors.popup); if (!popup) { return; } popup.classList.toggle('lp-builder-popup--fullscreen'); // Update resize button icon const resizeBtn = popup.querySelector(BuilderPopup.selectors.resizeBtn); if (resizeBtn) { const icon = resizeBtn.querySelector('i'); if (icon) { const isFullscreen = popup.classList.contains('lp-builder-popup--fullscreen'); icon.classList.toggle('lp-icon-expand', !isFullscreen); icon.classList.toggle('lp-icon-compress', isFullscreen); } } document.dispatchEvent(new CustomEvent('lp-builder-popup-fullscreen-toggled', { detail: { isFullscreen: popup.classList.contains('lp-builder-popup--fullscreen'), type: this.currentType, id: this.currentId } })); } openPopup(args) { const { target } = args; const triggerEl = target.closest(BuilderPopup.selectors.popupTrigger); if (!triggerEl) { return; } let type = ''; let id = 0; if (triggerEl.matches(BuilderPopup.selectors.addNewLesson)) { type = 'lesson'; } else if (triggerEl.dataset.popupType) { type = triggerEl.dataset.popupType; id = parseInt(triggerEl.dataset.popupId) || 0; } else if (triggerEl.dataset.popupLesson !== undefined) { type = 'lesson'; id = parseInt(triggerEl.dataset.popupLesson) || 0; } else if (triggerEl.dataset.popupQuiz !== undefined) { type = 'quiz'; id = parseInt(triggerEl.dataset.popupQuiz) || 0; } else if (triggerEl.dataset.popupQuestion !== undefined) { type = 'question'; id = parseInt(triggerEl.dataset.popupQuestion) || 0; } if (!type) { return; } this.showPopup(triggerEl, type, id, this.resolveOpenContext(triggerEl)); } getDefaultOpenContext() { return { isCurriculum: false, courseId: 0 }; } resolveOpenContext(triggerEl) { const isCurriculumContainer = !!triggerEl?.closest('#lp-course-edit-curriculum') || !!triggerEl?.closest('.lp-edit-curriculum-wrap'); const courseId = parseInt(triggerEl?.dataset?.courseId) || 0; const isCurriculum = isCurriculumContainer && courseId > 0; return { isCurriculum, courseId }; } showPopup(triggerEl, type, id, openContext = null) { const templateId = triggerEl?.dataset?.template || ''; const templateEl = document.querySelector(templateId); if (!templateId || !templateEl) { return; } this.currentType = type; this.currentId = id; this.currentTemplate = templateId; this.isNewItem = id === 0; this.openContext = openContext ? { ...openContext } : this.getDefaultOpenContext(); if (!this.popupContainer) { return; } this.popupContainer.innerHTML = templateEl.innerHTML; this.popupContainer.classList.add('active'); document.body.classList.add('lp-popup-open'); const elLPTarget = this.popupContainer.querySelector('.lp-target'); if (!elLPTarget || !window.lpAJAXG) { return; } const dataSend = window.lpAJAXG.getDataSetCurrent(elLPTarget); dataSend.args = dataSend.args || {}; dataSend.args[`${type}_id`] = id; window.lpAJAXG.setDataSetCurrent(elLPTarget, dataSend); this.requestPopupContent(dataSend); } reloadCurrentPopup() { if (!this.currentTemplate || !this.currentType) { return; } const templateEl = document.querySelector(this.currentTemplate); if (!templateEl) { return; } if (!this.popupContainer) { return; } this.popupContainer.innerHTML = templateEl.innerHTML; this.popupContainer.classList.add('active'); document.body.classList.add('lp-popup-open'); const elLPTarget = this.popupContainer.querySelector('.lp-target'); if (!elLPTarget || !window.lpAJAXG) { return; } const dataSend = window.lpAJAXG.getDataSetCurrent(elLPTarget); dataSend.args = dataSend.args || {}; dataSend.args[`${this.currentType}_id`] = this.currentId; window.lpAJAXG.setDataSetCurrent(elLPTarget, dataSend); this.requestPopupContent(dataSend); } requestPopupContent(dataSend) { if (!this.popupContainer || !window.lpAJAXG) { return; } const callBack = { success: response => { const { status, data } = response; if (status === 'success' && data?.content) { this.popupContainer.innerHTML = data.content; this.popupContainer.classList.add('active'); document.body.classList.add('lp-popup-open'); this.loadedTabAssets.clear(); this.initializedTabs.clear(); // Clear initialized tabs cache const ajaxElements = this.popupContainer.querySelectorAll('.lp-load-ajax-element.loaded'); ajaxElements.forEach(el => el.classList.remove('loaded')); setTimeout(() => window.lpAJAXG.getElements(), 50); const popup = this.popupContainer.querySelector(BuilderPopup.selectors.popup); const activeTab = popup?.querySelector(`${BuilderPopup.selectors.tab}.active`); const activeTabName = activeTab?.dataset.tab || 'overview'; const activePane = popup?.querySelector(`${BuilderPopup.selectors.tabPane}[data-tab="${activeTabName}"]`); if (activePane) { this.loadTabAssets(activeTabName, activePane); } if (activeTabName === 'overview') { setTimeout(() => this.initTinyMCE(), 50); } if (this.currentType === 'quiz') { if (!this.builderEditQuiz) { this.builderEditQuiz = new _builder_quiz_builder_edit_quiz_js__WEBPACK_IMPORTED_MODULE_4__.BuilderEditQuiz(); } if (activeTabName === 'questions') { const tabKey = `${this.currentType}-${activeTabName}`; setTimeout(() => { this.triggerAjaxLoadForTab(activePane); this.builderEditQuiz.reinit(this.popupContainer); this.initializedTabs.set(tabKey, true); }, 100); } } else if (this.currentType === 'question') { if (!this.builderEditQuestion) { this.builderEditQuestion = new _builder_question_builder_edit_question_js__WEBPACK_IMPORTED_MODULE_5__.BuilderEditQuestion(); } if (activeTabName === 'settings') { const tabKey = `${this.currentType}-${activeTabName}`; setTimeout(() => { this.triggerAjaxLoadForTab(activePane); this.builderEditQuestion.reinit(this.popupContainer); this.initializedTabs.set(tabKey, true); }, 100); } } else if (this.currentType === 'lesson') { if (!this.builderMaterial) { this.builderMaterial = new _builder_lesson_builder_material_js__WEBPACK_IMPORTED_MODULE_6__.BuilderMaterial(); } if (activeTabName === 'settings') { const tabKey = `${this.currentType}-${activeTabName}`; setTimeout(() => { this.triggerAjaxLoadForTab(activePane); this.builderMaterial.reinit(this.popupContainer); this.initializedTabs.set(tabKey, true); }, 100); } } document.dispatchEvent(new CustomEvent('lp-builder-popup-opened', { detail: { type: this.currentType, id: this.currentId, isNew: this.isNewItem } })); } else { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(response.message || 'Failed to load popup', 'error'); this.popupContainer.innerHTML = ''; this.popupContainer.classList.remove('active'); document.body.classList.remove('lp-popup-open'); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || 'Failed to load popup', 'error'); this.popupContainer.innerHTML = ''; this.popupContainer.classList.remove('active'); document.body.classList.remove('lp-popup-open'); }, completed: () => { // Loading hidden in success/error } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } /** * Close popup */ closePopup() { const closedType = this.currentType; const closedId = this.currentId; const savedData = this.savedData; this.destroyAllTinyMCE(); this.popupContainer.innerHTML = ''; this.popupContainer.classList.remove('active'); document.body.classList.remove('lp-popup-open'); this.loadedTabAssets.clear(); this.initializedTabs.clear(); // Clear initialized tabs cache if (savedData && closedId) { this.updateListItem(closedType, closedId, savedData); } document.dispatchEvent(new CustomEvent('lp-builder-popup-closed', { detail: { type: closedType, id: closedId, savedData } })); this.currentType = null; this.currentId = null; this.currentTemplate = ''; this.isNewItem = false; this.savedData = null; this.openContext = this.getDefaultOpenContext(); } /** * Update list item in the background list */ updateListItem(type, id, savedData) { if (!type || !id || !savedData) { return; } const { formData, data, wasNewItem } = savedData; let listItems = this.findListItems(type, id); // New items created from popup need to be inserted into the list first. if ((!listItems || listItems.length === 0) && wasNewItem) { const newItem = this.insertNewListItem(type, id, data?.list_item_html); if (newItem) { listItems = [newItem]; } } if (!listItems || listItems.length === 0) { return; } listItems.forEach(listItem => { let currentItem = listItem; // Replace the entire item HTML if returned from the server if (data?.section_item_html && currentItem.classList.contains('section-item')) { const template = document.createElement('template'); template.innerHTML = data.section_item_html.trim(); const newListItem = template.content.firstElementChild; if (newListItem) { currentItem.replaceWith(newListItem); currentItem = newListItem; } } else if (data?.list_item_html && !currentItem.classList.contains('section-item')) { const template = document.createElement('template'); template.innerHTML = data.list_item_html.trim(); const newListItem = template.content.firstElementChild; if (newListItem) { currentItem.replaceWith(newListItem); currentItem = newListItem; } } else { // Fallback: manually update elements if HTML replacement isn't used // Update title const newTitle = formData[`${type}_title`]; if (newTitle) { this.updateElementText(currentItem, ['.item-title', '.lp-item-title', `.lp-${type}-title`, '.curriculum-item-title', '.item-name', 'span.title', '.lp-question-title-input', '.section-item-title input', '.section-item-title span', '.lp-item-title-input'], newTitle); } // Update status if (data?.status) { this.updateElementClass(currentItem, [`.${type}-status`, '.item-status', '.post-status'], data.status); } if (type === 'lesson') { const duration = formData._lp_duration || data?.duration; if (duration) { this.updateDuration(currentItem, duration); } const preview = formData._lp_preview || data?.preview; const isPreview = preview === 'yes' || preview === true || preview === '1'; const previewEl = currentItem.querySelector('.lp-btn-set-preview-item a, .course-item-preview'); if (previewEl) { if (isPreview) { previewEl.classList.remove('lp-icon-eye-slash'); previewEl.classList.add('lp-icon-eye'); } else { previewEl.classList.remove('lp-icon-eye'); previewEl.classList.add('lp-icon-eye-slash'); } } const checkbox = currentItem.querySelector('input[type="checkbox"].preview-checkbox'); if (checkbox) { checkbox.checked = isPreview; } currentItem.classList.toggle('is-preview', isPreview); currentItem.classList.toggle('preview-item', isPreview); } else if (type === 'quiz') { const duration = formData._lp_duration || data?.duration; if (duration) { this.updateDuration(currentItem, duration); } const questionCount = data?.question_count || data?.questions_count; if (questionCount !== null && questionCount !== undefined) { const questionCountEl = currentItem.querySelector('.question-count'); if (questionCountEl) { questionCountEl.textContent = `${questionCount} ${questionCount === 1 ? 'Question' : 'Questions'}`; } } const passingGrade = formData._lp_passing_grade || data?.passing_grade; if (passingGrade) { const passingGradeEl = currentItem.querySelector('.passing-grade'); if (passingGradeEl) { passingGradeEl.textContent = `${passingGrade}%`; } } } else if (type === 'question') { const questionType = formData._lp_type || data?.type; if (questionType) { const typeMap = { true_or_false: 'True or False', single_choice: 'Single Choice', multi_choice: 'Multi Choice', fill_in_blanks: 'Fill in Blanks' }; this.updateElementText(currentItem, ['.question-type', '.item-type'], typeMap[questionType] || questionType); const typeClasses = ['true_or_false', 'single_choice', 'multi_choice', 'fill_in_blanks']; typeClasses.forEach(cls => currentItem.classList.remove(cls)); currentItem.classList.add(questionType); } const mark = formData._lp_mark || data?.mark; if (mark) { const questionMarkEl = currentItem.querySelector('.question-mark'); if (questionMarkEl) { questionMarkEl.textContent = mark; } } } } }); document.dispatchEvent(new CustomEvent('lp-builder-list-item-updated', { detail: { type, id, formData, data } })); } /** * Find all instances of a list item by type and ID */ findListItems(type, id) { const selectors = [`[data-${type}-id="${id}"]`, `[data-id="${id}"]`, `[data-popup-${type}="${id}"]`, `[data-item-id="${id}"]`, `.section-item[data-item-id="${id}"]`, `.lp-${type}-item[data-id="${id}"]`]; const foundItems = new Set(); for (const selector of selectors) { const items = document.querySelectorAll(selector); for (const item of items) { // Ensure we don't select elements inside the popup itself if (!item.closest('#lp-builder-popup-container')) { // Exclude elements that are merely trigger buttons but not the list item container itself // If it's just a generic button to open a popup, it might not be the actual item container. // However, some UI lists use the trigger button as the container. We rely on the DOM structure. // We can assume `.section-item` and `.lp-lesson-item` and `.cb-list-item` are containers. if (item.classList.contains('section-item') || item.classList.contains(`lp-${type}-item`) || item.classList.contains('list-item') || item.classList.contains('cb-list-item') || item.tagName === 'LI') { foundItems.add(item); } else { // If it's a wrapper, like a div in Content Bank if (item.closest('ul')) { foundItems.add(item); } } } } } return Array.from(foundItems); } /** * Insert a newly created list item into the current tab list. */ insertNewListItem(type, id, listItemHtml) { if (!listItemHtml) { return null; } const existingListItems = this.findListItems(type, id); if (existingListItems && existingListItems.length > 0) { return existingListItems[0]; } const listContainer = this.findListContainer(type); if (!listContainer) { return null; } const template = document.createElement('template'); template.innerHTML = listItemHtml.trim(); const newListItem = template.content.firstElementChild; if (!newListItem) { return null; } listContainer.prepend(newListItem); const highlightClassByType = { lesson: 'highlight-new-lesson', quiz: 'highlight-new-quiz', question: 'highlight-new-question' }; const highlightClass = highlightClassByType[type]; if (highlightClass) { newListItem.classList.add(highlightClass); newListItem.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); setTimeout(() => { newListItem.classList.remove(highlightClass); }, 1500); } const finalListItems = this.findListItems(type, id); return finalListItems && finalListItems.length > 0 ? finalListItems[0] : newListItem; } /** * Find list container for type; create one if tab currently shows empty message. */ findListContainer(type) { const listSelectorByType = { lesson: '.cb-list-lesson', quiz: '.cb-list-quiz', question: '.cb-list-question' }; const tabSelectorByType = { lesson: '.courses-builder__lesson-tab', quiz: '.courses-builder__quiz-tab', question: '.courses-builder__question-tab' }; const listClassByType = { lesson: 'cb-list-lesson', quiz: 'cb-list-quiz', question: 'cb-list-question' }; const listSelector = listSelectorByType[type] || `.cb-list-${type}, [data-builder-list="${type}"]`; if (!listSelector) { return null; } const existingList = document.querySelector(listSelector); if (existingList) { return existingList; } const tabContainer = document.querySelector(tabSelectorByType[type] || `.courses-builder__${type}-tab, [data-builder-tab="${type}"]`); const listClass = listClassByType[type] || `cb-list-${type}`; if (!tabContainer || !listClass) { return null; } const emptyMessage = tabContainer.querySelector('.learn-press-message'); if (emptyMessage) { emptyMessage.remove(); } const listContainer = document.createElement('ul'); listContainer.className = listClass; tabContainer.appendChild(listContainer); return listContainer; } /** * Update element text (input value or textContent) */ updateElementText(parent, selectors, newText) { for (const selector of selectors) { const el = parent.querySelector(selector); if (el) { if (el.tagName === 'INPUT') { el.value = newText; } else { el.textContent = newText; } return true; } } return false; } /** * Update element class */ updateElementClass(parent, selectors, newClass) { for (const selector of selectors) { const el = parent.querySelector(selector); if (el) { const baseClass = selector.replace('.', ''); el.className = el.className.replace(/\b(publish|draft|pending|trash)\b/g, '').trim(); el.classList.add(baseClass, newClass); el.textContent = newClass; return true; } } return false; } /** * Update duration meta */ updateDuration(listItem, duration) { const durationStr = this.formatDuration(duration); const updated = this.updateElementText(listItem, ['.item-meta.duration', '.duration', '.course-item-duration', '.meta-duration'], durationStr); if (!updated && durationStr) { const metaContainer = listItem.querySelector('.course-item__right, .item-meta-container, .course-item-meta'); if (metaContainer) { let durationEl = metaContainer.querySelector('.duration'); if (!durationEl) { durationEl = document.createElement('span'); durationEl.className = 'duration'; metaContainer.insertBefore(durationEl, metaContainer.firstChild); } durationEl.textContent = durationStr; } } } /** * Format duration value */ formatDuration(duration) { if (!duration) { return ''; } if (typeof duration === 'string' && duration.match(/\d+\s+\w+/)) { return duration; } const parts = String(duration).trim().split(/\s+/); if (parts.length >= 2) { const value = parseInt(parts[0]) || 0; const unit = parts[1].toLowerCase(); if (value === 0) { return ''; } const unitMap = { minute: value === 1 ? 'Minute' : 'Minutes', hour: value === 1 ? 'Hour' : 'Hours', day: value === 1 ? 'Day' : 'Days', week: value === 1 ? 'Week' : 'Weeks' }; return `${value} ${unitMap[unit] || unit}`; } const numValue = parseInt(duration) || 0; return numValue > 0 ? `${numValue} ${numValue === 1 ? 'Minute' : 'Minutes'}` : ''; } /** * Check if popup is open */ isPopupOpen() { return this.popupContainer?.classList.contains('active'); } /** * Switch tab with dynamic asset loading */ switchTab(args) { const tabEl = args?.target ? args.target.closest(BuilderPopup.selectors.tab) : args; if (!tabEl) { return; } const tabName = tabEl.dataset.tab; const popup = tabEl.closest(BuilderPopup.selectors.popup); if (!popup || !tabName) { return; } // Sync TinyMCE before switching this.syncAllTinyMCE(); // Update tab states popup.querySelectorAll(BuilderPopup.selectors.tab).forEach(tab => { tab.classList.remove('active'); }); tabEl.classList.add('active'); // Update pane states popup.querySelectorAll(BuilderPopup.selectors.tabPane).forEach(pane => { pane.classList.remove('active'); }); const targetPane = popup.querySelector(`${BuilderPopup.selectors.tabPane}[data-tab="${tabName}"]`); if (!targetPane) { return; } targetPane.classList.add('active'); this.loadTabAssets(tabName, targetPane); const tabKey = `${this.currentType}-${tabName}`; if (!this.initializedTabs.has(tabKey)) { if (tabName === 'overview') { setTimeout(() => this.initTinyMCE(), 100); this.initializedTabs.set(tabKey, true); } else if (tabName === 'questions' && this.currentType === 'quiz') { this.triggerAjaxLoadForTab(targetPane); if (this.builderEditQuiz) { setTimeout(() => { this.builderEditQuiz.reinit(this.popupContainer); this.initializedTabs.set(tabKey, true); }, 100); } } else if (tabName === 'settings' && this.currentType === 'question') { this.triggerAjaxLoadForTab(targetPane); if (this.builderEditQuestion) { setTimeout(() => { this.builderEditQuestion.reinit(this.popupContainer); this.initializedTabs.set(tabKey, true); }, 100); } } else if (tabName === 'settings' && this.currentType === 'lesson') { this.triggerAjaxLoadForTab(targetPane); if (this.builderMaterial) { setTimeout(() => { this.builderMaterial.reinit(this.popupContainer); this.initializedTabs.set(tabKey, true); }, 100); } } } document.dispatchEvent(new CustomEvent('lp-builder-tab-switched', { detail: { tabName, type: this.currentType, id: this.currentId } })); } /** * Trigger AJAX loading for tab elements */ triggerAjaxLoadForTab(tabPane) { if (!tabPane || !window.lpAJAXG) { return; } const ajaxElements = tabPane.querySelectorAll('.lp-load-ajax-element:not(.loaded)'); if (ajaxElements.length > 0) { ajaxElements.forEach(el => el.classList.remove('loaded')); window.lpAJAXG.getElements(); } } /** * Initialize TinyMCE for current popup type */ initTinyMCE() { const editorId = `${this.currentType}_description_editor`; const textarea = document.getElementById(editorId); if (!textarea || typeof tinymce === 'undefined') { return; } this.destroyTinyMCE(editorId); if (typeof wp !== 'undefined' && wp.editor?.initialize) { wp.editor.initialize(editorId, { tinymce: { wpautop: true, content_style: "body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif; font-size: 14px; line-height: 1.6; color: #1e1e1e; }", plugins: 'charmap colorpicker compat3x directionality fullscreen hr image lists media paste tabfocus textcolor wordpress wpautoresize wplink wptextpattern', toolbar1: 'formatselect,bold,italic,underline,bullist,numlist,blockquote,alignleft,aligncenter,alignright,link,unlink,spellchecker,wp_adv', toolbar2: 'strikethrough,hr,forecolor,pastetext,removeformat,charmap,outdent,indent,undo,redo,wp_help', wordpress_adv_hidden: true }, quicktags: { buttons: 'strong,em,link,block,del,ins,img,ul,ol,li,code,more,close' }, mediaButtons: true }); } else { tinymce.init({ selector: '#' + editorId, height: 300, menubar: false, content_style: "body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif; font-size: 14px; line-height: 1.6; color: #1e1e1e; }", plugins: ['advlist autolink lists link image charmap print preview anchor', 'searchreplace visualblocks code fullscreen', 'insertdatetime media table paste code help wordcount'], toolbar: 'undo redo | formatselect | bold italic backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | removeformat | help' }); } } /** * Sync all TinyMCE instances */ syncAllTinyMCE() { if (typeof tinymce === 'undefined' || !this.currentType) { return; } const editorId = `${this.currentType}_description_editor`; const editor = tinymce.get(editorId); if (editor && !this.isEditorInCodeMode(editorId)) { editor.save(); } // Sync additional editors tinymce.editors.forEach(ed => { if (ed.id?.includes(this.currentType) && !this.isEditorInCodeMode(ed.id)) { ed.save(); } }); } isEditorInCodeMode(editorId) { const wrapper = document.getElementById(`wp-${editorId}-wrap`) || document.getElementById(`${editorId}-wrap`); if (wrapper?.classList.contains('html-active')) { return true; } const editor = typeof tinymce !== 'undefined' ? tinymce.get(editorId) : null; return !!(editor?.isHidden && editor.isHidden()); } getEditorContent(editorId, root = document) { const textarea = root?.querySelector?.(`#${editorId}`) || document.getElementById(editorId); if (this.isEditorInCodeMode(editorId)) { return textarea ? textarea.value : ''; } if (typeof tinymce !== 'undefined') { const editor = tinymce.get(editorId); if (editor) { return editor.getContent(); } } return textarea ? textarea.value : ''; } /** * Destroy specific TinyMCE instance */ destroyTinyMCE(editorId) { if (typeof tinymce !== 'undefined') { const editor = tinymce.get(editorId); if (editor) { editor.remove(); } } if (typeof wp !== 'undefined' && wp.editor?.remove) { wp.editor.remove(editorId); } } /** * Destroy all TinyMCE editors in popup */ destroyAllTinyMCE() { if (!this.currentType || typeof tinymce === 'undefined') { return; } const editorId = `${this.currentType}_description_editor`; this.destroyTinyMCE(editorId); const editorsToRemove = []; tinymce.editors.forEach(ed => { if (ed.id && this.popupContainer?.querySelector(`#${ed.id}`)) { editorsToRemove.push(ed.id); } }); editorsToRemove.forEach(id => this.destroyTinyMCE(id)); } getStatusFromPublishPanel(fallbackStatus = 'publish') { if (!this.currentType || !this.popupContainer) { return fallbackStatus; } const statusSelect = this.popupContainer.querySelector(`#cb-${this.currentType}-publish-status`); if (!statusSelect) { return fallbackStatus; } const selectedStatus = statusSelect.value; if (selectedStatus === 'publish' || selectedStatus === 'draft') { return selectedStatus; } return fallbackStatus; } syncPublishPanelStatus(status) { if (!this.currentType || !this.popupContainer) { return; } const statusSelect = this.popupContainer.querySelector(`#cb-${this.currentType}-publish-status`); if (!statusSelect) { return; } statusSelect.value = status === 'publish' ? 'publish' : 'draft'; } /** * Handle save action */ handleSave(args) { const saveBtn = args?.target ? args.target.closest(BuilderPopup.selectors.saveBtn) : args; if (!saveBtn) { return; } if (!this.currentType) { return; } const publishLabel = (saveBtn?.dataset?.titlePublish || '').toString().trim().toLowerCase(); const currentLabel = (saveBtn?.textContent || '').toString().trim().toLowerCase(); const forcePublish = !!publishLabel && currentLabel === publishLabel; const targetStatus = forcePublish ? 'publish' : this.getStatusFromPublishPanel('publish'); if (forcePublish) { this.syncPublishPanelStatus('publish'); } this.syncAllTinyMCE(); const formData = this.getFormData(); const validation = this.validateFormData(formData); if (!validation.valid) { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(validation.errors.join('. '), 'error'); return; } lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(saveBtn, 1); const actionMap = { lesson: 'builder_update_lesson', quiz: 'builder_update_quiz', question: 'builder_update_question' }; const wasNewItem = this.isNewItem; const dataSend = { ...formData, action: actionMap[this.currentType] || `builder_update_${this.currentType}`, args: { id_url: `builder-update-${this.currentType}` }, [`${this.currentType}_status`]: targetStatus, return_html: 'yes' }; const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (status === 'success') { this.handleSaveSuccess(data, formData, wasNewItem); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || 'Save failed', 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(saveBtn, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } /** * Handle save as draft action */ async handleDraft(args) { const draftBtn = args?.target ? args.target.closest(BuilderPopup.selectors.draftBtn) : args; if (!draftBtn) { return; } if (!this.currentType) { return; } // Check if published to show confirm unpublish modal const statusEl = this.popupContainer.querySelector(`.${this.currentType}-status`); const isPublished = statusEl && statusEl.classList.contains('publish'); if (isPublished) { const confirmMsg = draftBtn.dataset.confirmUnpublish || 'Saving as draft will unpublish this item from the course.'; const result = await sweetalert2__WEBPACK_IMPORTED_MODULE_2___default().fire({ title: 'Are you sure?', text: confirmMsg, iconHtml: _swal_icons_js__WEBPACK_IMPORTED_MODULE_3__.SWAL_ICON_TRASH_DRAFT, customClass: { icon: 'lp-cb-swal-icon-html' }, showCloseButton: true, showCancelButton: true, cancelButtonText: lpData.i18n.cancel, confirmButtonText: lpData.i18n.yes, reverseButtons: true }); if (!result.isConfirmed) { return; } } this.syncAllTinyMCE(); const formData = this.getFormData(); const validation = this.validateFormData(formData); if (!validation.valid) { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(validation.errors.join('. '), 'error'); return; } lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(draftBtn, 1); const actionMap = { lesson: 'builder_update_lesson', quiz: 'builder_update_quiz', question: 'builder_update_question' }; const wasNewItem = this.isNewItem; const dataSend = { ...formData, action: actionMap[this.currentType] || `builder_update_${this.currentType}`, args: { id_url: `builder-update-${this.currentType}` }, [`${this.currentType}_status`]: 'draft', return_html: 'yes' }; const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (status === 'success') { this.handleSaveSuccess(data, formData, wasNewItem); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || 'Save draft failed', 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(draftBtn, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } /** * Handle save success */ handleSaveSuccess(data, formData, wasNewItem) { if (data?.button_title) { const primarySaveBtn = this.popupContainer.querySelector(BuilderPopup.selectors.saveBtn); if (primarySaveBtn) { primarySaveBtn.textContent = data.button_title; } } // Update status if (data?.status) { this.syncPublishPanelStatus(data.status); const statusEl = this.popupContainer.querySelector(`.${this.currentType}-status`); if (statusEl) { statusEl.className = `${this.currentType}-status ${data.status}`; statusEl.textContent = data.status; } if (this.shouldRemoveFromCurriculum(data.status)) { this.removeItemFromCurriculum(this.currentId); } if (this.shouldRemoveQuestionFromAssignedQuiz(data.status)) { this.removeQuestionFromAssignedQuiz(this.currentId); } } this.updatePermalinkUIAfterSave(data); // Handle new item const newIdKey = `${this.currentType}_id_new`; if (data?.[newIdKey]) { const newId = data[newIdKey]; this.currentId = newId; this.isNewItem = false; const wrapper = this.popupContainer.querySelector(`[data-${this.currentType}-id]`); if (wrapper) { wrapper.dataset[`${this.currentType}Id`] = newId; } const popup = this.popupContainer.querySelector(BuilderPopup.selectors.popup); if (popup) { popup.dataset[`${this.currentType}Id`] = newId; } } // Store saved data this.savedData = { formData, data, wasNewItem }; // Update the list item immediately this.updateListItem(this.currentType, this.currentId, this.savedData); // Handle new item creation if (wasNewItem && this.currentId) { document.dispatchEvent(new CustomEvent('lp-builder-popup-saved', { detail: { type: this.currentType, id: this.currentId, data, formData, wasNewItem, listItemHtml: data?.list_item_html || null } })); // Reload popup to show all tabs setTimeout(() => { this.destroyAllTinyMCE(); this.reloadCurrentPopup(); }, 300); } else { document.dispatchEvent(new CustomEvent('lp-builder-popup-saved', { detail: { type: this.currentType, id: this.currentId, data, formData, wasNewItem: false } })); } } /** * Handle trash action */ async handleTrash(args) { const trashBtn = args?.target ? args.target.closest(BuilderPopup.selectors.trashBtn) : args; if (!trashBtn) { return; } if (!this.currentType || !this.currentId) { return; } const confirmMsg = trashBtn.dataset.confirmTrash || 'Moving it to the trash will cause this item to be removed from the course.'; const result = await sweetalert2__WEBPACK_IMPORTED_MODULE_2___default().fire({ title: 'Are you sure?', text: confirmMsg, iconHtml: _swal_icons_js__WEBPACK_IMPORTED_MODULE_3__.SWAL_ICON_TRASH_DRAFT, customClass: { icon: 'lp-cb-swal-icon-html' }, showCloseButton: true, showCancelButton: true, cancelButtonText: lpData.i18n.cancel, confirmButtonText: lpData.i18n.yes, reverseButtons: true }); if (!result.isConfirmed) { return; } lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(trashBtn, 1); const actionMap = { lesson: 'move_trash_lesson', quiz: 'move_trash_quiz', question: 'move_trash_question' }; const dataSend = { action: actionMap[this.currentType] || `move_trash_${this.currentType}`, args: { id_url: `move-trash-${this.currentType}` }, [`${this.currentType}_id`]: this.currentId }; if (!!this.openContext?.isCurriculum && (parseInt(this.openContext?.courseId) || 0) > 0) { dataSend.course_id = parseInt(this.openContext.courseId) || 0; } const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (status === 'success') { if (data?.button_title) { const saveBtn = this.popupContainer.querySelector(BuilderPopup.selectors.saveBtn); if (saveBtn) { saveBtn.textContent = data.button_title; } } if (data?.status) { const statusEl = this.popupContainer.querySelector(`.${this.currentType}-status`); if (statusEl) { statusEl.className = `${this.currentType}-status ${data.status}`; statusEl.textContent = data.status; } if (this.shouldRemoveFromCurriculum(data.status)) { this.removeItemFromCurriculum(this.currentId); } if (this.shouldRemoveQuestionFromAssignedQuiz(data.status)) { this.removeQuestionFromAssignedQuiz(this.currentId); } } this.updatePermalinkUIAfterSave(data); this.savedData = { formData: this.getFormData(), data, wasNewItem: false }; document.dispatchEvent(new CustomEvent('lp-builder-popup-trashed', { detail: { type: this.currentType, id: this.currentId, data } })); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || 'Trash failed', 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(trashBtn, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } shouldRemoveFromCurriculum(status) { const normalizedStatus = (status || '').toString().toLowerCase(); const removableStatuses = ['draft', 'trash']; return !!this.openContext?.isCurriculum && removableStatuses.includes(normalizedStatus) && (parseInt(this.currentId) || 0) > 0; } shouldRemoveQuestionFromAssignedQuiz(status) { const normalizedStatus = (status || '').toString().toLowerCase(); return this.currentType === 'question' && ['draft', 'trash'].includes(normalizedStatus) && (parseInt(this.currentId) || 0) > 0; } removeItemFromCurriculum(itemId) { const parsedItemId = parseInt(itemId) || 0; if (parsedItemId <= 0) { return; } const curriculumRoot = document.querySelector('#lp-course-edit-curriculum') || document.querySelector('.lp-edit-curriculum-wrap'); if (!curriculumRoot) { return; } const items = curriculumRoot.querySelectorAll(`.section-item[data-item-id="${parsedItemId}"]`); if (!items.length) { return; } const sectionsToUpdate = new Set(); items.forEach(item => { const section = item.closest('.section'); if (section) { sectionsToUpdate.add(section); } item.remove(); }); this.syncCurriculumCounters(curriculumRoot, sectionsToUpdate); } removeQuestionFromAssignedQuiz(questionId) { const parsedQuestionId = parseInt(questionId) || 0; if (parsedQuestionId <= 0) { return; } const questionItems = document.querySelectorAll(`.lp-question-item[data-question-id="${parsedQuestionId}"]`); questionItems.forEach(item => item.remove()); } syncCurriculumCounters(curriculumRoot, sectionsToUpdate = new Set()) { if (!curriculumRoot) { return; } const allItems = curriculumRoot.querySelectorAll('.section-item:not(.clone)'); const totalItemsCount = allItems.length; const totalItemsEl = curriculumRoot.querySelector('.total-items'); if (totalItemsEl) { totalItemsEl.dataset.count = totalItemsCount; const totalItemsCountEl = totalItemsEl.querySelector('.count'); if (totalItemsCountEl) { totalItemsCountEl.textContent = totalItemsCount; } } const sections = sectionsToUpdate.size > 0 ? Array.from(sectionsToUpdate) : Array.from(curriculumRoot.querySelectorAll('.section')); sections.forEach(section => { const sectionItemsCountEl = section.querySelector('.section-items-counts'); if (!sectionItemsCountEl) { return; } const sectionItemsCount = section.querySelectorAll('.section-item:not(.clone)').length; sectionItemsCountEl.dataset.count = sectionItemsCount; const countEl = sectionItemsCountEl.querySelector('.count'); if (countEl) { countEl.textContent = sectionItemsCount; } }); } /** * Validate form data */ validateFormData(formData) { const errors = []; const titleKey = `${this.currentType}_title`; const title = formData[titleKey] || ''; if (!title.trim()) { errors.push(`${this.currentType.charAt(0).toUpperCase() + this.currentType.slice(1)} title is required`); } if (title.length > 200) { errors.push('Title must be less than 200 characters'); } return { valid: errors.length === 0, errors }; } /** * Get form data from popup */ getFormData() { const data = {}; const popup = this.popupContainer.querySelector(BuilderPopup.selectors.popup); if (!popup) { return data; } const idKey = `${this.currentType}_id`; data[idKey] = this.currentId || 0; if (!!this.openContext?.isCurriculum && (parseInt(this.openContext?.courseId) || 0) > 0) { data.course_id = parseInt(this.openContext.courseId) || 0; } // Get title const titleInput = popup.querySelector('input[name$="_title"], #title, #' + this.currentType + '_title'); if (titleInput) { data[`${this.currentType}_title`] = titleInput.value; } // Get description const editorId = `${this.currentType}_description_editor`; const descContent = this.getEditorContent(editorId, popup); data[`${this.currentType}_description`] = descContent; // Get form settings const formSettings = popup.querySelector(`.lp-form-setting-${this.currentType}`); if (formSettings) { data[`${this.currentType}_settings`] = true; this.collectFormData(formSettings, data); } // Capture permalink slug in overview tab (quiz/question popup). const permalinkInput = popup.querySelector(`input[name="${this.currentType}_permalink"], #${this.currentType}_permalink, ${BuilderPopup.selectors.permalinkSlugInput}`); if (permalinkInput && permalinkInput.value) { data[`${this.currentType}_permalink`] = permalinkInput.value; } return data; } updatePermalinkUIAfterSave(data = {}) { if (!this.currentType || !this.popupContainer) { return; } const popup = this.popupContainer.querySelector(BuilderPopup.selectors.popup); if (!popup) { return; } const slugInput = popup.querySelector(`input[name="${this.currentType}_permalink"], #${this.currentType}_permalink, ${BuilderPopup.selectors.permalinkSlugInput}`); const permalinkRoot = popup.querySelector(BuilderPopup.selectors.permalinkRoot); const permalinkPlaceholder = permalinkRoot?.querySelector(BuilderPopup.selectors.permalinkPlaceholder); const responseSlug = data?.[`${this.currentType}_slug`]; if (slugInput && responseSlug) { slugInput.value = responseSlug; slugInput.dataset.originalValue = responseSlug; } const responsePermalink = data?.[`${this.currentType}_permalink`]; const isCourseItem = ['lesson', 'quiz'].includes(this.currentType); const shouldShowUnavailable = data?.permalink_available === false || isCourseItem && (data?.status === 'draft' || data?.status === 'trash' || !responsePermalink); if (shouldShowUnavailable) { if (!permalinkRoot) { return; } const permalinkDisplay = permalinkRoot.querySelector(BuilderPopup.selectors.permalinkDisplay); const label = permalinkRoot.querySelector('.cb-item-edit-permalink__label') || permalinkRoot.querySelector('.cb-permalink-label'); const editor = permalinkRoot.querySelector(BuilderPopup.selectors.permalinkEditor); let placeholder = permalinkPlaceholder; if (!placeholder) { placeholder = document.createElement('span'); placeholder.className = 'cb-item-edit-permalink__placeholder'; if (label) { label.insertAdjacentElement('afterend', placeholder); } else { permalinkRoot.prepend(placeholder); } } placeholder.textContent = data?.permalink_notice || 'Permalink is only available if the item is already assigned to a course.'; placeholder.classList.remove('lp-hidden'); if (permalinkDisplay) { permalinkDisplay.classList.add('lp-hidden'); } if (editor) { editor.classList.add('lp-hidden'); } return; } const urlLink = popup.querySelector(BuilderPopup.selectors.permalinkUrl); const permalinkDisplay = permalinkRoot?.querySelector(BuilderPopup.selectors.permalinkDisplay); const baseUrlInput = popup.querySelector(BuilderPopup.selectors.permalinkBaseUrl); const normalizedBaseUrl = typeof baseUrlInput?.value === 'string' ? baseUrlInput.value : ''; const normalizedSlug = typeof responseSlug === 'string' ? responseSlug.trim() : ''; let permalinkDisplayUrl = ''; if (normalizedBaseUrl && normalizedSlug) { permalinkDisplayUrl = `${normalizedBaseUrl}${normalizedSlug}`; } else if (typeof responsePermalink === 'string') { permalinkDisplayUrl = responsePermalink; } if (permalinkPlaceholder) { permalinkPlaceholder.classList.add('lp-hidden'); } if (permalinkDisplay) { permalinkDisplay.classList.remove('lp-hidden'); } if (urlLink && responsePermalink) { urlLink.href = responsePermalink; urlLink.textContent = permalinkDisplayUrl || responsePermalink; } else if (urlLink && permalinkDisplayUrl) { urlLink.textContent = permalinkDisplayUrl; } } /** * Collect form data from form element */ collectFormData(form, data) { const formElements = form.querySelectorAll('input, select, textarea'); formElements.forEach(element => { const name = element.name || element.id; if (!name || name === 'learnpress_meta_box_nonce' || name === '_wp_http_referer') { return; } const fieldName = name.replace('[]', ''); if (element.type === 'checkbox') { if (!data.hasOwnProperty(fieldName)) { data[fieldName] = element.checked ? 'yes' : 'no'; } } else if (element.type === 'radio') { if (element.checked) { data[fieldName] = element.value; } } else if (element.type === 'file') { if (element.files?.length > 0) { data[fieldName] = element.files; } } else if (name.endsWith('[]')) { if (!data.hasOwnProperty(fieldName)) { data[fieldName] = []; } if (Array.isArray(data[fieldName])) { data[fieldName].push(element.value); } } else if (!data.hasOwnProperty(fieldName)) { data[fieldName] = element.value; } }); // Convert arrays to comma-separated strings Object.keys(data).forEach(key => { if (Array.isArray(data[key])) { data[key] = data[key].join(','); } }); } /** * Load tab-specific assets (CSS/JS) */ loadTabAssets(tabName, tabPane) { const tabKey = `${this.currentType}-${tabName}`; if (this.loadedTabAssets.has(tabKey)) { return; } const assetsData = tabPane.dataset.tabAssets; if (!assetsData) { this.loadedTabAssets.add(tabKey); return; } try { const assets = JSON.parse(assetsData); // Load CSS if (assets.css && Array.isArray(assets.css)) { assets.css.forEach(cssUrl => { if (!document.querySelector(`link[href="${cssUrl}"]`)) { const link = document.createElement('link'); link.rel = 'stylesheet'; link.href = cssUrl; link.dataset.tabAsset = tabKey; document.head.appendChild(link); } }); } // Load JS if (assets.js && Array.isArray(assets.js)) { assets.js.forEach(jsUrl => { if (!document.querySelector(`script[src="${jsUrl}"]`)) { const script = document.createElement('script'); script.src = jsUrl; script.dataset.tabAsset = tabKey; document.head.appendChild(script); } }); } this.loadedTabAssets.add(tabKey); } catch (e) { console.warn(`Failed to load assets for tab "${tabName}":`, e); this.loadedTabAssets.add(tabKey); } } /** * Static method to open popup programmatically */ static open(type, id = 0) { if (!BuilderPopup._instance) { BuilderPopup._instance = new BuilderPopup(); } const selectors = { lesson: id ? `[data-popup-lesson="${id}"]` : BuilderPopup.selectors.addNewLesson, quiz: id ? `[data-popup-quiz="${id}"]` : '', question: id ? `[data-popup-question="${id}"]` : '' }; const triggerSelector = selectors[type] || (id ? `[data-popup-type="${type}"][data-popup-id="${id}"]` : `[data-popup-type="${type}"][data-template]`); if (!triggerSelector) { return; } const triggerEl = document.querySelector(triggerSelector); if (!triggerEl) { return; } BuilderPopup._instance.showPopup(triggerEl, type, id, BuilderPopup._instance.resolveOpenContext(triggerEl)); } /** * Static method to close popup programmatically */ static close() { if (BuilderPopup._instance) { BuilderPopup._instance.closePopup(); } } } // Auto-initialize document.addEventListener('DOMContentLoaded', () => { BuilderPopup._instance = new BuilderPopup(); }); /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (BuilderPopup); /***/ }, /***/ "./assets/src/js/frontend/course-builder/builder-question/builder-edit-question.js" /*!*****************************************************************************************!*\ !*** ./assets/src/js/frontend/course-builder/builder-question/builder-edit-question.js ***! \*****************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ BuilderEditQuestion: () => (/* binding */ BuilderEditQuestion) /* harmony export */ }); /* harmony import */ var lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lpAssetsJsPath/utils.js */ "./assets/src/js/utils.js"); /* harmony import */ var lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! lpAssetsJsPath/lpToastify.js */ "./assets/src/js/lpToastify.js"); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! sweetalert2 */ "./node_modules/sweetalert2/dist/sweetalert2.all.js"); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(sweetalert2__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var lpAssetsJsPath_admin_edit_question_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! lpAssetsJsPath/admin/edit-question.js */ "./assets/src/js/admin/edit-question.js"); /* harmony import */ var _swal_icons_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../swal-icons.js */ "./assets/src/js/frontend/course-builder/swal-icons.js"); /* harmony import */ var _builder_form_state_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../builder-form-state.js */ "./assets/src/js/frontend/course-builder/builder-form-state.js"); class BuilderEditQuestion { constructor() { this.editQuestion = null; // Events use document-level event delegation, so always register them // The page context check happens in individual handlers via target.closest() this.init(); } static selectors = { elDataQuestion: '.cb-section__question-edit', elBtnUpdateQuestion: '.cb-btn-update', elBtnDraftQuestion: '.cb-btn-draft', elBtnDuplicateQuestion: '.cb-btn-duplicate-question', elBtnTrashQuestion: '.cb-btn-trash', elBtnMainAction: '.cb-btn-main-action', elQuestionStatus: '.question-status', idTitle: 'title', idDescEditor: 'question_description_editor', elPublishStatusSelect: '#cb-question-publish-status', elFormSetting: '.lp-form-setting-question', // Permalink component elPermalinkDisplay: '.cb-permalink-display', elPermalinkEditor: '.cb-permalink-editor', elPermalinkEditBtn: '.cb-permalink-edit-btn', elPermalinkOkBtn: '.cb-permalink-ok-btn', elPermalinkCancelBtn: '.cb-permalink-cancel-btn', elPermalinkSlugInput: '.cb-permalink-slug-input', elPermalinkUrl: '.cb-permalink-url', elPermalinkBaseUrl: '#cb-permalink-base-url', // Question edit selectors elEditQuestionWrap: '.lp-edit-question-wrap', elQuestionEditMain: '.lp-question-edit-main', // Tab handling selectors elCBHorizontalTabs: '.lp-cb-tabs__item', elCBTabPanels: '.lp-cb-tab-panel', // Dropdown selectors elDropdownToggle: '.cb-btn-dropdown-toggle', elDropdownMenu: '.cb-dropdown-menu', elDropdownItem: '.cb-dropdown-item', elHeaderActionsDropdown: '.cb-header-actions-dropdown', elQuestionActionExpanded: '.course-action-expanded' }; init() { this.initQuestionAnswersSettings(); this.initTabs(); this.initHeaderActionsDropdown(); this.syncHeaderActionWithPublishPanel(); this.events(); } /** * Initialize header actions dropdown (toggle behavior) */ initHeaderActionsDropdown() { // Close dropdown when clicking outside document.addEventListener('click', e => { const dropdown = document.querySelector(BuilderEditQuestion.selectors.elHeaderActionsDropdown); if (dropdown && !dropdown.contains(e.target)) { const menu = dropdown.querySelector(BuilderEditQuestion.selectors.elDropdownMenu); const toggle = dropdown.querySelector(BuilderEditQuestion.selectors.elDropdownToggle); if (menu) { menu.classList.remove('is-open'); } if (toggle) { toggle.setAttribute('aria-expanded', 'false'); } } }); } /** * Handle dropdown toggle click */ handleDropdownToggle(args) { if (this.hasPublishDrivenSingleAction()) { return; } const { target } = args; const toggleBtn = target.closest(BuilderEditQuestion.selectors.elDropdownToggle); if (!toggleBtn) { return; } const dropdown = toggleBtn.closest(BuilderEditQuestion.selectors.elHeaderActionsDropdown); if (!dropdown) { return; } const menu = dropdown.querySelector(BuilderEditQuestion.selectors.elDropdownMenu); if (menu) { menu.classList.toggle('is-open'); const isOpen = menu.classList.contains('is-open'); toggleBtn.setAttribute('aria-expanded', isOpen ? 'true' : 'false'); } } /** * Handle dropdown item click (Save Draft, Publish from dropdown menu) */ handleDropdownItemClick(args) { // Context check: only handle if on question edit page if (!this.isQuestionContext()) { return; } if (this.hasPublishDrivenSingleAction()) { return; } const { target } = args; const dropdownItem = target.closest(BuilderEditQuestion.selectors.elDropdownItem); if (!dropdownItem) { return; } // Skip if this is trash button - it has its own handler if (dropdownItem.classList.contains('cb-btn-trash') || dropdownItem.classList.contains('cb-btn-duplicate-question')) { return; } const status = dropdownItem.dataset.status; if (!status) { return; } // Close the dropdown menu const menu = dropdownItem.closest(BuilderEditQuestion.selectors.elDropdownMenu); if (menu) { menu.classList.remove('is-open'); } // Save with the specified status this.saveQuestionWithStatus(dropdownItem, status); } /** * Save question with specified status (publish/draft) * @param {HTMLElement} btnEl - The button element that was clicked * @param {string} status - The status to save (publish/draft) */ async saveQuestionWithStatus(btnEl, status) { const canContinue = await this.confirmUnpublishIfNeeded(status, btnEl); if (!canContinue) { return; } // Validate title before saving if (!this.validateTitleBeforeUpdate()) { return; } lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(btnEl, 1); const questionData = this.getQuestionDataForUpdate(); const dataSend = { ...questionData, action: 'builder_update_question', args: { id_url: 'builder-update-question' }, question_status: status }; if (typeof lpQuestionBuilder !== 'undefined' && lpQuestionBuilder.nonce) { dataSend.nonce = lpQuestionBuilder.nonce; } const callBack = { success: response => { const { status: respStatus, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, respStatus); if (respStatus === 'success') { // Update action button text this.updateActionButtons(data?.status || status); this.syncPublishPanelStatus(data?.status || status); this.updatePermalinkUIAfterSave(data); // Reset form state before potential redirect. document.dispatchEvent(new CustomEvent('lp-course-builder-saved')); if (data?.redirect_url) { window.location.href = data.redirect_url; } if (data?.status) { const elStatus = document.querySelector(BuilderEditQuestion.selectors.elQuestionStatus); if (elStatus) { elStatus.className = 'question-status ' + data.status; elStatus.textContent = data.status; } if (data.status === 'trash' || data.status === 'draft') { const curriculumItem = document.querySelector(`.question-item[data-question-id="${questionData.question_id}"]`); if (curriculumItem) { const elCurriculumQuestion = curriculumItem.closest('.question'); if (elCurriculumQuestion) { elCurriculumQuestion.remove(); } } } } } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(btnEl, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } /** * Initialize horizontal tabs for client-side tab switching */ initTabs() { const tabs = document.querySelectorAll(BuilderEditQuestion.selectors.elCBHorizontalTabs); if (tabs.length === 0) { return; } // Activate first tab by default if none is active const activeTab = document.querySelector(`${BuilderEditQuestion.selectors.elCBHorizontalTabs}.is-active`); if (!activeTab && tabs.length > 0) { tabs[0].classList.add('is-active'); const section = tabs[0].getAttribute('data-tab-section'); if (section) { const panel = document.querySelector(`${BuilderEditQuestion.selectors.elCBTabPanels}[data-section="${section}"]`); if (panel) { panel.classList.remove('lp-hidden'); } } } } /** * Handle horizontal tab click for client-side tab switching */ handleTabClick(args) { const { e, target } = args; const tabLink = target.closest(BuilderEditQuestion.selectors.elCBHorizontalTabs); if (!tabLink) { return; } e.preventDefault(); const section = tabLink.getAttribute('data-tab-section'); if (!section) { return; } // Update active tab const allTabs = document.querySelectorAll(BuilderEditQuestion.selectors.elCBHorizontalTabs); allTabs.forEach(tab => tab.classList.remove('is-active')); tabLink.classList.add('is-active'); const url = new URL(window.location.href); url.searchParams.set('tab', section); window.history.replaceState({}, '', url); // Show/hide panels const allPanels = document.querySelectorAll(BuilderEditQuestion.selectors.elCBTabPanels); allPanels.forEach(panel => { if (panel.getAttribute('data-section') === section) { panel.classList.remove('lp-hidden'); } else { panel.classList.add('lp-hidden'); } }); } /** * Initialize Question Answers Settings * This will init EditQuestion class for the question answer management */ initQuestionAnswersSettings() { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpOnElementReady(BuilderEditQuestion.selectors.elQuestionEditMain, elQuestionEditMain => { // Initialize EditQuestion for question answer editing if (!this.editQuestion) { this.editQuestion = new lpAssetsJsPath_admin_edit_question_js__WEBPACK_IMPORTED_MODULE_3__.EditQuestion(); this.editQuestion.init(); } // Init sortable for question answers if (this.editQuestion) { this.editQuestion.sortAbleQuestionAnswer(elQuestionEditMain); } }); } /** * Re-initialize when question type changes */ reinitQuestionHandlers(elQuestionEditMain) { if (this.editQuestion && elQuestionEditMain) { this.editQuestion.sortAbleQuestionAnswer(elQuestionEditMain); this.editQuestion.initTinyMCE(); } } /** * Re-initialize for popup context * This is called when popup is opened multiple times to ensure * TinyMCE and other handlers are properly re-initialized * * @param {HTMLElement} container - The popup container element */ reinit(container) { const elQuestionEditMain = container ? container.querySelector(BuilderEditQuestion.selectors.elQuestionEditMain) : document.querySelector(BuilderEditQuestion.selectors.elQuestionEditMain); if (!elQuestionEditMain) { return; } // Re-create EditQuestion instance to ensure fresh initialization // This is necessary because TinyMCE instances were destroyed when popup closed if (this.editQuestion) { // Destroy existing TinyMCE instances in the container first if (typeof tinymce !== 'undefined' && container) { const textareas = container.querySelectorAll('textarea.lp-meta-box__editor'); textareas.forEach(textarea => { const editorId = textarea.id; if (editorId) { const editor = tinymce.get(editorId); if (editor) { editor.remove(); } if (typeof wp !== 'undefined' && wp.editor && wp.editor.remove) { wp.editor.remove(editorId); } } }); } } // Create fresh EditQuestion instance this.editQuestion = new lpAssetsJsPath_admin_edit_question_js__WEBPACK_IMPORTED_MODULE_3__.EditQuestion(); this.editQuestion.init(); // Re-init sortable and TinyMCE this.editQuestion.sortAbleQuestionAnswer(elQuestionEditMain); // Use setTimeout to ensure DOM is ready for TinyMCE setTimeout(() => { if (this.editQuestion) { this.editQuestion.initTinyMCE(); } }, 100); } events() { if (BuilderEditQuestion._loadedEvents) { return; } BuilderEditQuestion._loadedEvents = true; lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('click', [{ selector: BuilderEditQuestion.selectors.elBtnMainAction, class: this, callBack: this.updateQuestion.name }, { selector: BuilderEditQuestion.selectors.elBtnDraftQuestion, class: this, callBack: this.saveDraftQuestion.name }, { selector: BuilderEditQuestion.selectors.elBtnDuplicateQuestion, class: this, callBack: this.duplicateQuestion.name }, { selector: BuilderEditQuestion.selectors.elBtnTrashQuestion, class: this, callBack: this.trashQuestion.name }, { selector: BuilderEditQuestion.selectors.elCBHorizontalTabs, class: this, callBack: this.handleTabClick.name }, { selector: BuilderEditQuestion.selectors.elDropdownToggle, class: this, callBack: this.handleDropdownToggle.name }, { selector: BuilderEditQuestion.selectors.elDropdownItem, class: this, callBack: this.handleDropdownItemClick.name }, { selector: BuilderEditQuestion.selectors.elPermalinkEditBtn, class: this, callBack: this.handlePermalinkEdit.name }, { selector: BuilderEditQuestion.selectors.elPermalinkOkBtn, class: this, callBack: this.handlePermalinkOk.name }, { selector: BuilderEditQuestion.selectors.elPermalinkCancelBtn, class: this, callBack: this.handlePermalinkCancel.name }]); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('change', [{ selector: BuilderEditQuestion.selectors.elPublishStatusSelect, class: this, callBack: this.handlePublishStatusChange.name }]); } handlePublishStatusChange() { this.syncHeaderActionWithPublishPanel(); (0,_builder_form_state_js__WEBPACK_IMPORTED_MODULE_5__.getFormState)().markAsChanged(); } /** * Validate title is not empty before update * @return {boolean} True if valid, false if invalid */ validateTitleBeforeUpdate() { const titleInput = document.getElementById(BuilderEditQuestion.selectors.idTitle); if (!titleInput) { return true; } const title = titleInput.value.trim(); if (!title) { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show('Question title is required.', 'error'); titleInput.focus(); return false; } return true; } /** * Update action buttons after status change, matching course edit logic. * Updates both main button and dropdown items based on new status. * @param {string} newStatus - The new question status */ updateActionButtons(newStatus) { const dropdown = document.querySelector(BuilderEditQuestion.selectors.elHeaderActionsDropdown); if (!dropdown) return; const mainBtn = dropdown.querySelector('.cb-btn-main-action'); const dropdownMenu = dropdown.querySelector(BuilderEditQuestion.selectors.elDropdownMenu); if (!mainBtn) return; if (this.hasPublishDrivenSingleAction()) { this.syncHeaderActionWithPublishPanel(); return; } if (!dropdownMenu) return; // Status configuration for button labels and classes const statusConfig = { publish: { mainLabel: mainBtn.dataset.titleUpdate || 'Update', mainClass: 'cb-btn-update', mainStatus: 'publish', dropdownLabel: mainBtn.dataset.titleDraft || 'Save Draft', dropdownClass: 'cb-btn-darft', dropdownStatus: 'draft', dropdownIcon: 'dashicons-media-default' }, draft: { mainLabel: mainBtn.dataset.titleDraft || 'Save Draft', mainClass: 'cb-btn-darft', mainStatus: 'draft', dropdownLabel: mainBtn.dataset.titlePublish || 'Publish', dropdownClass: 'cb-btn-publish', dropdownStatus: 'publish', dropdownIcon: 'dashicons-visibility' }, pending: { mainLabel: 'Submit for Review', mainClass: 'cb-btn-pending', mainStatus: 'pending', dropdownLabel: mainBtn.dataset.titleDraft || 'Save Draft', dropdownClass: 'cb-btn-darft', dropdownStatus: 'draft', dropdownIcon: 'dashicons-media-default' } }; const config = statusConfig[newStatus] || statusConfig.draft; // Update main button mainBtn.className = `${config.mainClass} cb-btn-primary cb-btn-main-action`; mainBtn.dataset.status = config.mainStatus; mainBtn.textContent = config.mainLabel; // Update dropdown item (first item, excluding trash) const dropdownItems = dropdownMenu.querySelectorAll('.cb-dropdown-item:not(.cb-btn-trash)'); if (dropdownItems.length > 0) { const firstItem = dropdownItems[0]; firstItem.className = `cb-dropdown-item ${config.dropdownClass}`; firstItem.dataset.status = config.dropdownStatus; firstItem.innerHTML = `${config.dropdownLabel}`; } // Update dropdown data-current-status dropdown.dataset.currentStatus = newStatus; } /** * Check if we're in question edit context * @return {boolean} */ isQuestionContext() { return !!document.querySelector(BuilderEditQuestion.selectors.elDataQuestion); } getQuestionDataForUpdate() { const data = {}; const wrapperEl = document.querySelector(BuilderEditQuestion.selectors.elDataQuestion); data.question_id = wrapperEl ? parseInt(wrapperEl.dataset.questionId) || 0 : 0; const titleInput = document.getElementById(BuilderEditQuestion.selectors.idTitle); data.question_title = titleInput ? titleInput.value : ''; const descEditor = document.getElementById(BuilderEditQuestion.selectors.idDescEditor); data.question_description = descEditor ? descEditor.value : ''; if (typeof tinymce !== 'undefined') { const editor = tinymce.get(BuilderEditQuestion.selectors.idDescEditor); if (editor) { data.question_description = editor.getContent(); } } const permalinkInput = document.querySelector(BuilderEditQuestion.selectors.elPermalinkSlugInput); if (permalinkInput && permalinkInput.value) { data.question_permalink = permalinkInput.value; } const elFormSetting = document.querySelector(BuilderEditQuestion.selectors.elFormSetting); if (elFormSetting) { data.question_settings = true; const formElements = elFormSetting.querySelectorAll('input, select, textarea'); formElements.forEach(element => { const name = element.name || element.id; if (!name) { return; } if (name === 'learnpress_meta_box_nonce' || name === '_wp_http_referer') { return; } if (element.type === 'checkbox') { const fieldName = name.replace('[]', ''); if (!data.hasOwnProperty(fieldName)) { data[fieldName] = element.checked ? 'yes' : 'no'; } } else if (element.type === 'radio') { if (element.checked) { const fieldName = name.replace('[]', ''); data[fieldName] = element.value; } } else if (element.type === 'file') { const fieldName = name.replace('[]', ''); if (element.files && element.files.length > 0) { data[fieldName] = element.files; } } else { const fieldName = name.replace('[]', ''); if (name.endsWith('[]')) { if (!data.hasOwnProperty(fieldName)) { data[fieldName] = []; } if (Array.isArray(data[fieldName])) { data[fieldName].push(element.value); } } else { if (!data.hasOwnProperty(fieldName)) { data[fieldName] = element.value; } } } }); Object.keys(data).forEach(key => { if (Array.isArray(data[key])) { data[key] = data[key].join(','); } }); } return data; } getStatusFromPublishPanel(fallbackStatus = 'publish') { const statusSelect = document.querySelector(BuilderEditQuestion.selectors.elPublishStatusSelect); if (!statusSelect) { return fallbackStatus; } const selectedStatus = statusSelect.value; if (selectedStatus === 'publish' || selectedStatus === 'draft') { return selectedStatus; } return fallbackStatus; } hasPublishDrivenSingleAction() { if (!document.querySelector(BuilderEditQuestion.selectors.elPublishStatusSelect)) { return false; } const wrapperEl = document.querySelector(BuilderEditQuestion.selectors.elDataQuestion); const questionId = wrapperEl ? parseInt(wrapperEl.dataset.questionId) || 0 : 0; return questionId > 0; } syncHeaderActionWithPublishPanel() { if (!this.hasPublishDrivenSingleAction()) { return; } const dropdown = document.querySelector(BuilderEditQuestion.selectors.elHeaderActionsDropdown); if (!dropdown) { return; } const mainBtn = dropdown.querySelector('.cb-btn-main-action'); if (!mainBtn) { return; } const toggleBtn = dropdown.querySelector(BuilderEditQuestion.selectors.elDropdownToggle); const dropdownMenu = dropdown.querySelector(BuilderEditQuestion.selectors.elDropdownMenu); const status = this.getStatusFromPublishPanel(mainBtn.dataset.status || 'publish'); mainBtn.classList.remove('cb-btn-darft', 'cb-btn-publish', 'cb-btn-pending'); mainBtn.classList.add('cb-btn-update', 'cb-btn-primary', 'cb-btn-main-action'); mainBtn.textContent = mainBtn.dataset.titleUpdate || 'Update'; mainBtn.dataset.status = status; dropdown.dataset.currentStatus = status; dropdown.classList.add('cb-header-actions-dropdown--single'); if (toggleBtn) { toggleBtn.style.display = 'none'; } if (dropdownMenu) { dropdownMenu.style.display = 'none'; } } syncPublishPanelStatus(status) { const statusSelect = document.querySelector(BuilderEditQuestion.selectors.elPublishStatusSelect); if (!statusSelect) { return; } statusSelect.value = status === 'publish' ? 'publish' : 'draft'; this.syncHeaderActionWithPublishPanel(); } updatePermalinkUIAfterSave(data = {}) { const slugInput = document.querySelector(BuilderEditQuestion.selectors.elPermalinkSlugInput); const urlLink = document.querySelector(BuilderEditQuestion.selectors.elPermalinkUrl); const baseUrlInput = document.querySelector(BuilderEditQuestion.selectors.elPermalinkBaseUrl); const permalinkDisplayUrl = this.buildPermalinkDisplayUrl(baseUrlInput ? baseUrlInput.value : '', data?.question_slug, data?.question_permalink); if (slugInput && data?.question_slug) { slugInput.value = data.question_slug; slugInput.dataset.originalValue = data.question_slug; } if (urlLink && data?.question_permalink) { urlLink.href = data.question_permalink; urlLink.textContent = permalinkDisplayUrl || data.question_permalink; } else if (urlLink && permalinkDisplayUrl) { urlLink.textContent = permalinkDisplayUrl; } } slugify(str) { return (str || '').toString().normalize('NFD').replace(/[\u0300-\u036f]/g, '').replace(/đ/g, 'd').replace(/Đ/g, 'D').toLowerCase().replace(/\s+/g, '-').replace(/[^\w-]+/g, '').replace(/--+/g, '-').replace(/^-+/, '').replace(/-+$/, ''); } buildPermalinkDisplayUrl(baseUrl = '', slug = '', fallbackUrl = '') { const normalizedBaseUrl = typeof baseUrl === 'string' ? baseUrl : ''; const normalizedSlug = typeof slug === 'string' ? slug.trim() : ''; if (normalizedBaseUrl && normalizedSlug) { return `${normalizedBaseUrl}${normalizedSlug}`; } return typeof fallbackUrl === 'string' ? fallbackUrl : ''; } handlePermalinkEdit(args) { if (!this.isQuestionContext()) { return; } const { e } = args; if (e) e.preventDefault(); const display = document.querySelector(BuilderEditQuestion.selectors.elPermalinkDisplay); const editor = document.querySelector(BuilderEditQuestion.selectors.elPermalinkEditor); const input = document.querySelector(BuilderEditQuestion.selectors.elPermalinkSlugInput); if (!display || !editor || !input) return; input.dataset.originalValue = input.value; display.classList.add('lp-hidden'); editor.classList.remove('lp-hidden'); input.focus(); input.select(); } handlePermalinkOk(args) { if (!this.isQuestionContext()) { return; } const { e } = args; if (e) e.preventDefault(); const display = document.querySelector(BuilderEditQuestion.selectors.elPermalinkDisplay); const editor = document.querySelector(BuilderEditQuestion.selectors.elPermalinkEditor); const input = document.querySelector(BuilderEditQuestion.selectors.elPermalinkSlugInput); const urlLink = document.querySelector(BuilderEditQuestion.selectors.elPermalinkUrl); const baseUrlInput = document.querySelector(BuilderEditQuestion.selectors.elPermalinkBaseUrl); if (!display || !editor || !input || !urlLink) return; let newSlug = this.slugify(input.value.trim()); if (!newSlug) { newSlug = input.dataset.originalValue || 'question'; } input.value = newSlug; const baseUrl = baseUrlInput ? baseUrlInput.value : ''; const newUrl = this.buildPermalinkDisplayUrl(baseUrl, newSlug, urlLink.textContent || ''); // Keep href as the current saved link and only update display text. urlLink.textContent = newUrl; editor.classList.add('lp-hidden'); display.classList.remove('lp-hidden'); if (newSlug !== input.dataset.originalValue) { (0,_builder_form_state_js__WEBPACK_IMPORTED_MODULE_5__.getFormState)().markAsChanged(); } } handlePermalinkCancel(args) { if (!this.isQuestionContext()) { return; } const { e } = args; if (e) e.preventDefault(); const display = document.querySelector(BuilderEditQuestion.selectors.elPermalinkDisplay); const editor = document.querySelector(BuilderEditQuestion.selectors.elPermalinkEditor); const input = document.querySelector(BuilderEditQuestion.selectors.elPermalinkSlugInput); if (!display || !editor || !input) return; input.value = input.dataset.originalValue || ''; editor.classList.add('lp-hidden'); display.classList.remove('lp-hidden'); } async updateQuestion(args) { // Context check: only handle if on question edit page if (!this.isQuestionContext()) { return; } const { target } = args; const elBtnMainAction = target.closest(BuilderEditQuestion.selectors.elBtnMainAction); if (!elBtnMainAction) { return; } // Validate title before update if (!this.validateTitleBeforeUpdate()) { return; } // Resolve status from Overview publish panel first, fallback to button data-status. const targetStatus = this.getStatusFromPublishPanel(elBtnMainAction.dataset.status || 'publish'); const canContinue = await this.confirmUnpublishIfNeeded(targetStatus, elBtnMainAction); if (!canContinue) { return; } lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elBtnMainAction, 1); const questionData = this.getQuestionDataForUpdate(); const dataSend = { ...questionData, action: 'builder_update_question', args: { id_url: 'builder-update-question' }, question_status: targetStatus }; if (typeof lpQuestionBuilder !== 'undefined' && lpQuestionBuilder.nonce) { dataSend.nonce = lpQuestionBuilder.nonce; } const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (status === 'success') { // Update action button text with actual status from server this.updateActionButtons(data?.status || targetStatus); this.syncPublishPanelStatus(data?.status || targetStatus); this.updatePermalinkUIAfterSave(data); // Reset form state before potential redirect. document.dispatchEvent(new CustomEvent('lp-course-builder-saved')); if (data?.redirect_url) { window.location.href = data.redirect_url; } if (data?.status) { const elStatus = document.querySelector(BuilderEditQuestion.selectors.elQuestionStatus); if (elStatus) { elStatus.className = 'question-status ' + data.status; elStatus.textContent = data.status; } if (data.status === 'trash' || data.status === 'draft') { const curriculumItem = document.querySelector(`.question-item[data-question-id="${questionData.question_id}"]`); if (curriculumItem) { const elCurriculumQuestion = curriculumItem.closest('.question'); if (elCurriculumQuestion) { elCurriculumQuestion.remove(); } } } } } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elBtnMainAction, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } async confirmUnpublishIfNeeded(targetStatus, triggerEl) { if (targetStatus !== 'draft') { return true; } const statusEl = document.querySelector(BuilderEditQuestion.selectors.elQuestionStatus); const isPublished = statusEl && statusEl.classList.contains('publish'); if (!isPublished) { return true; } const confirmMsg = triggerEl?.dataset?.confirmUnpublish || 'Saving as draft will unpublish this item. Are you sure?'; const result = await sweetalert2__WEBPACK_IMPORTED_MODULE_2___default().fire({ title: confirmMsg, iconHtml: _swal_icons_js__WEBPACK_IMPORTED_MODULE_4__.SWAL_ICON_TRASH_DRAFT, customClass: { icon: 'lp-cb-swal-icon-html' }, showCloseButton: true, showCancelButton: true, cancelButtonText: lpData.i18n.cancel, confirmButtonText: lpData.i18n.yes, reverseButtons: true }); return !!result.isConfirmed; } async saveDraftQuestion(args) { // Context check: only handle if on question edit page if (!this.isQuestionContext()) { return; } const { target } = args; const elBtnDraftQuestion = target.closest(BuilderEditQuestion.selectors.elBtnDraftQuestion); if (!elBtnDraftQuestion) { return; } // Check if published to show confirm unpublish modal const statusEl = document.querySelector(BuilderEditQuestion.selectors.elQuestionStatus); const isPublished = statusEl && statusEl.classList.contains('publish'); if (isPublished) { const confirmMsg = elBtnDraftQuestion.dataset.confirmUnpublish || 'Saving as draft will unpublish this item. Are you sure?'; const result = await sweetalert2__WEBPACK_IMPORTED_MODULE_2___default().fire({ title: confirmMsg, iconHtml: _swal_icons_js__WEBPACK_IMPORTED_MODULE_4__.SWAL_ICON_TRASH_DRAFT, customClass: { icon: 'lp-cb-swal-icon-html' }, showCloseButton: true, showCancelButton: true, cancelButtonText: lpData.i18n.cancel, confirmButtonText: lpData.i18n.yes, reverseButtons: true }); if (!result.isConfirmed) { return; } } // Validate title before saving draft if (!this.validateTitleBeforeUpdate()) { return; } const elActionExpanded = document.querySelector(BuilderEditQuestion.selectors.elQuestionActionExpanded); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 1); const questionData = this.getQuestionDataForUpdate(); const dataSend = { ...questionData, action: 'builder_update_question', args: { id_url: 'builder-update-question' }, question_status: 'draft' }; if (typeof lpQuestionBuilder !== 'undefined' && lpQuestionBuilder.nonce) { dataSend.nonce = lpQuestionBuilder.nonce; } const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (status === 'success') { // Update action button text this.updateActionButtons('draft'); this.syncPublishPanelStatus(data?.status || 'draft'); this.updatePermalinkUIAfterSave(data); // Reset form state before potential redirect. document.dispatchEvent(new CustomEvent('lp-course-builder-saved')); if (data?.redirect_url) { window.location.href = data.redirect_url; } if (data?.status) { const elStatus = document.querySelector(BuilderEditQuestion.selectors.elQuestionStatus); if (elStatus) { elStatus.className = 'question-status ' + data.status; elStatus.textContent = data.status; } if (data.status === 'trash' || data.status === 'draft') { const curriculumItem = document.querySelector(`.question-item[data-question-id="${questionData.question_id}"]`); if (curriculumItem) { const elCurriculumQuestion = curriculumItem.closest('.question'); if (elCurriculumQuestion) { elCurriculumQuestion.remove(); } } } } } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } async trashQuestion(args) { // Context check: only handle if on question edit page if (!this.isQuestionContext()) { return; } const { target } = args; const elBtnTrashQuestion = target.closest(BuilderEditQuestion.selectors.elBtnTrashQuestion); if (!elBtnTrashQuestion) { return; } const result = await sweetalert2__WEBPACK_IMPORTED_MODULE_2___default().fire({ title: 'Are you sure you want to trash this question?', iconHtml: _swal_icons_js__WEBPACK_IMPORTED_MODULE_4__.SWAL_ICON_TRASH_DRAFT, customClass: { icon: 'lp-cb-swal-icon-html' }, showCloseButton: true, showCancelButton: true, cancelButtonText: lpData.i18n.cancel, confirmButtonText: lpData.i18n.yes, reverseButtons: true }); if (!result.isConfirmed) { return; } const elActionExpanded = document.querySelector(BuilderEditQuestion.selectors.elQuestionActionExpanded); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 1); const questionData = this.getQuestionDataForUpdate(); const dataSend = { action: 'move_trash_question', args: { id_url: 'move-trash-question' }, question_id: questionData.question_id || 0 }; const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (status === 'success') { if (data?.redirect_url) { window.location.href = data.redirect_url; } if (data?.status) { const elStatus = document.querySelector(BuilderEditQuestion.selectors.elQuestionStatus); if (elStatus) { elStatus.className = 'question-status ' + data.status; elStatus.textContent = data.status; } if (data.status === 'trash' || data.status === 'draft') { const curriculumItem = document.querySelector(`.question-item[data-question-id="${questionData.question_id}"]`); if (curriculumItem) { const elCurriculumQuestion = curriculumItem.closest('.question'); if (elCurriculumQuestion) { elCurriculumQuestion.remove(); } } } } } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } async duplicateQuestion(args) { // Context check: only handle if on question edit page if (!this.isQuestionContext()) { return; } const { target } = args; const elBtnDuplicateQuestion = target.closest(BuilderEditQuestion.selectors.elBtnDuplicateQuestion); if (!elBtnDuplicateQuestion) { return; } const questionData = this.getQuestionDataForUpdate(); const questionId = parseInt(questionData?.question_id, 10) || 0; if (!questionId) { return; } const result = await sweetalert2__WEBPACK_IMPORTED_MODULE_2___default().fire({ title: elBtnDuplicateQuestion.dataset.title || 'Are you sure?', text: elBtnDuplicateQuestion.dataset.content || 'Are you sure you want to duplicate this question?', iconHtml: _swal_icons_js__WEBPACK_IMPORTED_MODULE_4__.SWAL_ICON_DUPLICATE, customClass: { icon: 'lp-cb-swal-icon-html' }, showCloseButton: true, showCancelButton: true, cancelButtonText: lpData.i18n.cancel, confirmButtonText: lpData.i18n.yes, reverseButtons: true }); if (!result.isConfirmed) { return; } const elActionExpanded = document.querySelector(BuilderEditQuestion.selectors.elQuestionActionExpanded); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 1); const dataSend = { action: 'duplicate_question', args: { id_url: 'duplicate-question' }, question_id: questionId }; const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message || 'Duplicated successfully!', status); if (status === 'success' && data?.redirect_url) { window.location.href = data.redirect_url; } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } } /***/ }, /***/ "./assets/src/js/frontend/course-builder/builder-question/builder-tab-question.js" /*!****************************************************************************************!*\ !*** ./assets/src/js/frontend/course-builder/builder-question/builder-tab-question.js ***! \****************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ BuilderTabQuestion: () => (/* binding */ BuilderTabQuestion) /* harmony export */ }); /* harmony import */ var lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lpAssetsJsPath/utils.js */ "./assets/src/js/utils.js"); /* harmony import */ var lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! lpAssetsJsPath/lpToastify.js */ "./assets/src/js/lpToastify.js"); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! sweetalert2 */ "./node_modules/sweetalert2/dist/sweetalert2.all.js"); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(sweetalert2__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _swal_icons_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../swal-icons.js */ "./assets/src/js/frontend/course-builder/swal-icons.js"); class BuilderTabQuestion { constructor() { this.init(); } static selectors = { elQuestionItem: '.question-item', elQuestionExpandedItems: '.question-action-expanded__items', elQuestionDuplicate: '.question-action-expanded__duplicate', elQuestionTrash: '.question-action-expanded__trash', elQuestionRestore: '.question-action-expanded__restore', elQuestionPublish: '.question-action-expanded__publish', elQuestionDelete: '.question-action-expanded__delete', elQuestionActionExpanded: '.question-action-expanded', elQuestionStatus: '.question-status', elBtnEditQuestion: '.btn-edit-question' }; init() { this.events(); } events() { if (BuilderTabQuestion._loadedEvents) { return; } BuilderTabQuestion._loadedEvents = true; lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('click', [{ selector: BuilderTabQuestion.selectors.elQuestionDuplicate, class: this, callBack: this.duplicateQuestion.name }, { selector: BuilderTabQuestion.selectors.elQuestionTrash, class: this, callBack: this.trashQuestion.name }, { selector: BuilderTabQuestion.selectors.elQuestionPublish, class: this, callBack: this.publishQuestion.name }, { selector: BuilderTabQuestion.selectors.elQuestionRestore, class: this, callBack: this.restoreQuestion.name }, { selector: BuilderTabQuestion.selectors.elQuestionDelete, class: this, callBack: this.deleteQuestion.name }, { selector: BuilderTabQuestion.selectors.elQuestionActionExpanded, class: this, callBack: this.toggleExpandedAction.name }, { selector: BuilderTabQuestion.selectors.elBtnEditQuestion, class: this, callBack: this.editQuestion.name }]); document.addEventListener('click', e => { if (!e.target.closest(BuilderTabQuestion.selectors.elQuestionActionExpanded)) { this.closeAllExpanded(); } }); } editQuestion(args) { const { target } = args; const elBtnEditQuestion = target.closest(BuilderTabQuestion.selectors.elBtnEditQuestion); if (!elBtnEditQuestion) { return; } lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elBtnEditQuestion, 1); } duplicateQuestion(args) { const { target } = args; const elQuestionDuplicate = target.closest(BuilderTabQuestion.selectors.elQuestionDuplicate); const elQuestionItem = elQuestionDuplicate.closest(BuilderTabQuestion.selectors.elQuestionItem); if (!elQuestionItem) { return; } const elActionExpanded = elQuestionItem.querySelector(BuilderTabQuestion.selectors.elQuestionActionExpanded); const questionId = elQuestionItem.dataset.questionId || ''; sweetalert2__WEBPACK_IMPORTED_MODULE_2___default().fire({ title: elQuestionDuplicate.dataset.title || 'Duplicate Question', text: elQuestionDuplicate.dataset.content || 'Are you sure you want to duplicate this question?', iconHtml: _swal_icons_js__WEBPACK_IMPORTED_MODULE_3__.SWAL_ICON_DUPLICATE, customClass: { icon: 'lp-cb-swal-icon-html' }, showCloseButton: true, showCancelButton: true, cancelButtonText: lpData.i18n.cancel, confirmButtonText: lpData.i18n.yes, reverseButtons: true }).then(result => { if (result.isConfirmed) { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 1); const dataSend = { action: 'duplicate_question', args: { id_url: 'duplicate-question' }, question_id: questionId }; const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message || 'Duplicated successfully!', status); if (status === 'success' && data?.redirect_url) { window.location.href = data.redirect_url; } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } }); } trashQuestion(args) { const { target } = args; const elQuestionTrash = target.closest(BuilderTabQuestion.selectors.elQuestionTrash); const elQuestionItem = elQuestionTrash.closest(BuilderTabQuestion.selectors.elQuestionItem); if (!elQuestionItem) { return; } const elActionExpanded = elQuestionItem.querySelector(BuilderTabQuestion.selectors.elQuestionActionExpanded); const questionId = elQuestionItem.dataset.questionId || ''; sweetalert2__WEBPACK_IMPORTED_MODULE_2___default().fire({ title: elQuestionTrash.dataset.title || 'Trash Question', text: elQuestionTrash.dataset.content || 'Are you sure you want to move this question to trash?', iconHtml: _swal_icons_js__WEBPACK_IMPORTED_MODULE_3__.SWAL_ICON_TRASH_DRAFT, customClass: { icon: 'lp-cb-swal-icon-html' }, showCloseButton: true, showCancelButton: true, cancelButtonText: lpData.i18n.cancel, confirmButtonText: lpData.i18n.yes, reverseButtons: true }).then(result => { if (result.isConfirmed) { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 1); const dataSend = { action: 'move_trash_question', args: { id_url: 'move-trash-question' }, question_id: questionId }; const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (data?.html) { this.replaceItemHtml(elQuestionTrash.closest('.question'), data.html); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } }); } publishQuestion(args) { const { target } = args; const elQuestionPublish = target.closest(BuilderTabQuestion.selectors.elQuestionPublish); const elQuestionItem = elQuestionPublish.closest(BuilderTabQuestion.selectors.elQuestionItem); if (!elQuestionItem) { return; } const elActionExpanded = elQuestionItem.querySelector(BuilderTabQuestion.selectors.elQuestionActionExpanded); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 1); const questionId = elQuestionItem.dataset.questionId || ''; const dataSend = { action: 'move_trash_question', args: { id_url: 'move-trash-question' }, question_id: questionId, status: 'publish' }; const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (data?.html) { this.replaceItemHtml(elQuestionPublish.closest('.question'), data.html); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } restoreQuestion(args) { const { target } = args; const elQuestionRestore = target.closest(BuilderTabQuestion.selectors.elQuestionRestore); const elQuestionItem = elQuestionRestore.closest(BuilderTabQuestion.selectors.elQuestionItem); if (!elQuestionItem) { return; } const elActionExpanded = elQuestionItem.querySelector(BuilderTabQuestion.selectors.elQuestionActionExpanded); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 1); const questionId = elQuestionItem.dataset.questionId || ''; const dataSend = { action: 'move_trash_question', args: { id_url: 'move-trash-question' }, question_id: questionId, status: 'draft' }; const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (data?.html) { this.replaceItemHtml(elQuestionRestore.closest('.question'), data.html); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } deleteQuestion(args) { const { target } = args; const elQuestionDelete = target.closest(BuilderTabQuestion.selectors.elQuestionDelete); const elQuestionItem = elQuestionDelete.closest(BuilderTabQuestion.selectors.elQuestionItem); if (!elQuestionItem) { return; } const elActionExpanded = elQuestionItem.querySelector(BuilderTabQuestion.selectors.elQuestionActionExpanded); const questionId = elQuestionItem.dataset.questionId || ''; if (!questionId) { return; } sweetalert2__WEBPACK_IMPORTED_MODULE_2___default().fire({ title: elQuestionDelete.dataset.title || 'Delete Question', text: elQuestionDelete.dataset.content || 'Are you sure you want to permanently delete this question?', iconHtml: _swal_icons_js__WEBPACK_IMPORTED_MODULE_3__.SWAL_ICON_DELETE, customClass: { icon: 'lp-cb-swal-icon-html' }, showCloseButton: true, showCancelButton: true, cancelButtonText: lpData.i18n.cancel, confirmButtonText: lpData.i18n.yes, reverseButtons: true }).then(result => { if (result.isConfirmed) { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 1); const dataSend = { action: 'move_trash_question', args: { id_url: 'move-trash-question' }, question_id: questionId, status: 'delete' }; const callBack = { success: response => { const { status, message } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (status === 'success') { const elQuestion = elQuestionDelete.closest('.question'); elQuestion.style.transition = 'opacity 0.4s ease-out, transform 0.4s ease-out'; elQuestion.style.opacity = '0'; elQuestion.style.transform = 'translateX(160px)'; setTimeout(() => { elQuestion.remove(); }, 400); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } }); } toggleExpandedAction(args) { const { target } = args; const elQuestionActionExpanded = target.closest(BuilderTabQuestion.selectors.elQuestionActionExpanded); if (!elQuestionActionExpanded) { return; } const elQuestionItem = elQuestionActionExpanded.closest(BuilderTabQuestion.selectors.elQuestionItem); if (!elQuestionItem) { return; } const elExpandedItems = elQuestionItem.querySelector(BuilderTabQuestion.selectors.elQuestionExpandedItems); if (!elExpandedItems) { return; } this.closeAllExpanded(elExpandedItems); const willOpen = !elExpandedItems.classList.contains('active'); if (willOpen) { elExpandedItems.classList.add('active'); elQuestionActionExpanded.classList.add('active'); this.setExpandedDirection(elExpandedItems); } else { elExpandedItems.classList.remove('active'); elExpandedItems.classList.remove('is-dropup'); elQuestionActionExpanded.classList.remove('active'); } } closeAllExpanded(excludeElement = null) { const allExpandedItems = document.querySelectorAll(`${BuilderTabQuestion.selectors.elQuestionExpandedItems}.active`); allExpandedItems.forEach(item => { if (item === excludeElement) { return; } item.classList.remove('active'); item.classList.remove('is-dropup'); const questionItem = item.closest(BuilderTabQuestion.selectors.elQuestionItem); if (!questionItem) { return; } const expandedBtn = questionItem.querySelector(BuilderTabQuestion.selectors.elQuestionActionExpanded); if (expandedBtn) { expandedBtn.classList.remove('active'); } }); } setExpandedDirection(elExpandedItems) { if (!elExpandedItems) { return; } elExpandedItems.classList.remove('is-dropup'); const elQuestion = elExpandedItems.closest('.question'); if (!elQuestion) { return; } if (elQuestion.matches(':last-child')) { elExpandedItems.classList.add('is-dropup'); } } replaceItemHtml(elQuestion, html) { if (!elQuestion || !html) { return; } const tmp = document.createElement('div'); tmp.innerHTML = html; const newEl = tmp.firstElementChild; if (newEl) { elQuestion.replaceWith(newEl); } } } /***/ }, /***/ "./assets/src/js/frontend/course-builder/builder-quiz/builder-edit-quiz.js" /*!*********************************************************************************!*\ !*** ./assets/src/js/frontend/course-builder/builder-quiz/builder-edit-quiz.js ***! \*********************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ BuilderEditQuiz: () => (/* binding */ BuilderEditQuiz) /* harmony export */ }); /* harmony import */ var lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lpAssetsJsPath/utils.js */ "./assets/src/js/utils.js"); /* harmony import */ var lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! lpAssetsJsPath/lpToastify.js */ "./assets/src/js/lpToastify.js"); /* harmony import */ var lpAssetsJsPath_lpPopupSelectItemToAdd_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! lpAssetsJsPath/lpPopupSelectItemToAdd.js */ "./assets/src/js/lpPopupSelectItemToAdd.js"); /* harmony import */ var lpAssetsJsPath_admin_edit_question_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! lpAssetsJsPath/admin/edit-question.js */ "./assets/src/js/admin/edit-question.js"); /* harmony import */ var sortablejs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! sortablejs */ "./node_modules/sortablejs/modular/sortable.esm.js"); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! sweetalert2 */ "./node_modules/sweetalert2/dist/sweetalert2.all.js"); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(sweetalert2__WEBPACK_IMPORTED_MODULE_5__); /** * Builder Edit Quiz Handler * * Important separation note: * - This file is the Question-tab engine (question CRUD, sorting, TinyMCE, question bank). * - It is reused in multiple contexts (standalone quiz page and popup quiz editor). * - Keep this file focused on question-tab internals; page-level save/publish flow belongs to BuilderStandaloneQuiz. * * @since 4.3.0 * @version 1.0.0 */ class BuilderEditQuiz { constructor() { this.elEditQuizWrap = null; this.elEditListQuestions = null; this.quizID = null; this.lpPopupSelectItemToAdd = null; this.sortableInstance = null; this.sortableAnswerInstances = []; this.editQuestion = null; this.initPromise = null; this.tinyMCEInitToken = null; this.isInitialized = false; } static selectors = { elEditQuizWrap: '.lp-edit-quiz-wrap', elQuestionEditMain: '.lp-question-edit-main', elEditListQuestions: '.lp-edit-list-questions', elQuestionItem: '.lp-question-item', elQuestionToggle: '.lp-question-toggle', elQuestionToggleAll: '.lp-question-toggle-all', elBtnAddQuestion: '.lp-btn-add-question', elBtnRemoveQuestion: '.lp-btn-remove-question', elBtnUpdateQuestionTitle: '.lp-btn-update-question-title', elBtnCancelUpdateQuestionTitle: '.lp-btn-cancel-update-question-title', elQuestionTitleNewInput: '.lp-question-title-new-input', elQuestionTitleInput: '.lp-question-title-input', elQuestionTypeNew: '.lp-question-type-new', elAddNewQuestion: 'add-new-question', LPTarget: '.lp-target', elCollapse: 'lp-collapse', elAnswersConfig: '.lp-answers-config', elQuestionTinymce: '.lp-question-edit-main .lp-editor-tinymce' }; init(container = null) { this.initQuizQuestionsTab(container); this.events(); } /** * Reinitialize for new quiz context */ reinit(container = null) { this.cleanup(); this.events(); // Use async init with proper error handling this.initQuizQuestionsTabAsync(container).catch(error => { // Silently handle error - element might not exist yet console.debug('BuilderEditQuiz: Quiz questions tab not found', error.message); }); } /** * Cleanup all instances and state */ cleanup() { // Cancel pending promise if exists if (this.initPromise && typeof this.initPromise === 'object') { this.initPromise.cancelled = true; } this.initPromise = null; this.tinyMCEInitToken = null; this.elEditQuizWrap = null; this.elEditListQuestions = null; this.quizID = null; this.isInitialized = false; // Destroy sortable instances if (this.sortableInstance?.destroy) { try { this.sortableInstance.destroy(); } catch (e) { console.warn('Error destroying sortable instance:', e); } this.sortableInstance = null; } // Destroy answer sortable instances this.sortableAnswerInstances.forEach(instance => { if (instance?.destroy) { try { instance.destroy(); } catch (e) { console.warn('Error destroying answer sortable:', e); } } }); this.sortableAnswerInstances = []; } /** * Initialize Quiz Questions Tab */ initQuizQuestionsTab(container = null) { const searchContainer = container || document; const elEditQuizWrap = searchContainer.querySelector(BuilderEditQuiz.selectors.elEditQuizWrap); if (elEditQuizWrap) { this._initQuizQuestionsTabElement(elEditQuizWrap); } } /** * Initialize Quiz Questions Tab asynchronously */ initQuizQuestionsTabAsync(container = null, maxAttempts = 50, interval = 200) { // Cancel previous promise if exists if (this.initPromise && typeof this.initPromise === 'object') { this.initPromise.cancelled = true; } // Create new promise this.initPromise = new Promise((resolve, reject) => { let attempts = 0; const searchContainer = container || document; const checkElement = () => { // Check if cancelled if (this.initPromise && this.initPromise.cancelled) { reject(new Error('Init cancelled')); return; } attempts++; const elEditQuizWrap = searchContainer.querySelector(BuilderEditQuiz.selectors.elEditQuizWrap); if (elEditQuizWrap) { this._initQuizQuestionsTabElement(elEditQuizWrap); resolve(elEditQuizWrap); } else if (attempts >= maxAttempts) { reject(new Error(`Quiz questions tab not found after ${maxAttempts} attempts`)); } else { setTimeout(checkElement, interval); } }; checkElement(); }); // Add cancelled flag to promise object this.initPromise.cancelled = false; return this.initPromise; } /** * Initialize quiz questions tab element */ _initQuizQuestionsTabElement(elEditQuizWrap) { if (!elEditQuizWrap) { return; } // Prevent double initialization if (this.isInitialized && this.elEditQuizWrap === elEditQuizWrap) { return; } this.elEditQuizWrap = elEditQuizWrap; this.elEditListQuestions = elEditQuizWrap.querySelector(BuilderEditQuiz.selectors.elEditListQuestions); this._getQuizID(elEditQuizWrap); // Initialize popup select items if (!this.lpPopupSelectItemToAdd) { this.lpPopupSelectItemToAdd = new lpAssetsJsPath_lpPopupSelectItemToAdd_js__WEBPACK_IMPORTED_MODULE_2__.LpPopupSelectItemToAdd(); this.lpPopupSelectItemToAdd.init(); } // Init sortables this.sortAbleQuestion(); this._initAnswerSortables(elEditQuizWrap); // Init EditQuestion this._initEditQuestion(elEditQuizWrap); // Init TinyMCE asynchronously after EditQuestion events are registered. this._initTinyMCEAsync(elEditQuizWrap); this.isInitialized = true; } /** * Get Quiz ID from various sources */ _getQuizID(elEditQuizWrap) { // Try from lp-target const elLPTarget = elEditQuizWrap.closest(BuilderEditQuiz.selectors.LPTarget); if (elLPTarget && window.lpAJAXG) { try { const dataSend = window.lpAJAXG.getDataSetCurrent(elLPTarget); this.quizID = dataSend?.args?.quiz_id || 0; } catch (e) { console.warn('Error getting quiz ID from lpAJAXG:', e); } } // Try from popup if (!this.quizID) { const popup = elEditQuizWrap.closest('.lp-builder-popup'); this.quizID = popup?.dataset.quizId || 0; } // Try from wrapper if (!this.quizID) { const wrapper = elEditQuizWrap.closest('[data-quiz-id]'); this.quizID = wrapper?.dataset.quizId || 0; } } /** * Initialize EditQuestion for answer management */ _initEditQuestion(elEditQuizWrap) { if (!elEditQuizWrap) { return; } // Create EditQuestion instance if not exists if (!this.editQuestion) { this.editQuestion = new lpAssetsJsPath_admin_edit_question_js__WEBPACK_IMPORTED_MODULE_3__.EditQuestion(); } // Initialize sortable for answers const elQuestionEditMains = elEditQuizWrap.querySelectorAll(BuilderEditQuiz.selectors.elQuestionEditMain); elQuestionEditMains.forEach(elQuestionEditMain => { if (elQuestionEditMain && this.editQuestion?.sortAbleQuestionAnswer) { try { this.editQuestion.sortAbleQuestionAnswer(elQuestionEditMain); } catch (e) { console.warn('Error initializing answer sortable:', e); } } }); // Register events if not loaded if (!lpAssetsJsPath_admin_edit_question_js__WEBPACK_IMPORTED_MODULE_3__.EditQuestion._loadedEvents && this.editQuestion?.events) { try { this.editQuestion.events(); } catch (e) { console.warn('Error registering EditQuestion events:', e); } } } /** * Initialize answer sortables */ _initAnswerSortables(elEditQuizWrap) { if (!elEditQuizWrap) { return; } const elQuestionEditMains = elEditQuizWrap.querySelectorAll(BuilderEditQuiz.selectors.elQuestionEditMain); elQuestionEditMains.forEach(elQuestionEditMain => { if (elQuestionEditMain) { this._sortAbleQuestionAnswer(elQuestionEditMain); } }); } /** * Make question answers sortable */ _sortAbleQuestionAnswer(elQuestionEditMain) { if (!elQuestionEditMain) { return; } const elAnswersConfig = elQuestionEditMain.querySelector(BuilderEditQuiz.selectors.elAnswersConfig); if (!elAnswersConfig) { return; } try { const instance = new sortablejs__WEBPACK_IMPORTED_MODULE_4__["default"](elAnswersConfig, { handle: '.drag', animation: 150, onEnd: evt => { if (!evt?.item) { return; } const elAutoSaveAnswer = evt.item.querySelector('.lp-auto-save-question-answer'); if (elAutoSaveAnswer) { elAutoSaveAnswer.dispatchEvent(new Event('change', { bubbles: true })); } } }); this.sortableAnswerInstances.push(instance); } catch (e) { console.warn('Error creating answer sortable:', e); } } /** * Initialize TinyMCE asynchronously */ _initTinyMCEAsync(elEditQuizWrap) { if (!elEditQuizWrap) { return; } const elTextareas = Array.from(elEditQuizWrap.querySelectorAll(`${BuilderEditQuiz.selectors.elQuestionItem}:not(.${BuilderEditQuiz.selectors.elCollapse}) ${BuilderEditQuiz.selectors.elQuestionTinymce}`)); if (!elTextareas.length) { return; } const chunkSize = 2; let index = 0; const initToken = {}; this.tinyMCEInitToken = initToken; const queueInit = callback => { if (window.requestIdleCallback) { window.requestIdleCallback(() => callback(), { timeout: 100 }); } else { setTimeout(() => callback(), 50); } }; const processChunk = (attempts = 0) => { if (this.tinyMCEInitToken !== initToken) { return; } if (typeof window.tinymce === 'undefined') { if (attempts < 20) { setTimeout(() => processChunk(attempts + 1), 100); } return; } const chunk = elTextareas.slice(index, index + chunkSize); chunk.forEach(elTextarea => { if (elTextarea?.id) { this._reInitTinymce(elTextarea.id); } }); index += chunkSize; if (index < elTextareas.length) { queueInit(processChunk); } }; queueInit(processChunk); } /** * Reinitialize single TinyMCE editor */ _reInitTinymce(id) { if (!window.tinymce || !id) { return; } const elTextarea = document.getElementById(id); if (!elTextarea?.closest('.lp-question-edit-main')) { return; } // Use EditQuestion.reInitTinymce to properly register events if (this.editQuestion?.reInitTinymce) { try { this.editQuestion.reInitTinymce(id); } catch (e) { console.warn('TinyMCE reinit via EditQuestion error:', e); // Fallback to manual reinit without events this._manualReInitTinymce(id); } } else { // Fallback if editQuestion not available this._manualReInitTinymce(id); } } /** * Manual TinyMCE reinit (fallback without events) */ _manualReInitTinymce(id) { try { window.tinymce.execCommand('mceRemoveEditor', true, id); window.tinymce.execCommand('mceAddEditor', true, id); this.editQuestion?.setDefaultEditorTab?.(id); } catch (e) { console.warn('Manual TinyMCE init error:', e); } } /** * Reinitialize handlers for new question */ reinitQuestionHandlers(elQuestionEditMain) { if (!elQuestionEditMain) { return; } // Init answer sortable this._sortAbleQuestionAnswer(elQuestionEditMain); this._initQuestionTinymce(elQuestionEditMain.closest(BuilderEditQuiz.selectors.elQuestionItem)); // Init answer sortable via EditQuestion if (this.editQuestion?.sortAbleQuestionAnswer) { try { this.editQuestion.sortAbleQuestionAnswer(elQuestionEditMain); } catch (e) { console.warn('Error initializing answer sortable:', e); } } } /** * Initialize TinyMCE only after a question item is expanded. */ _initQuestionTinymce(elQuestionItem) { if (!elQuestionItem || elQuestionItem.classList.contains(BuilderEditQuiz.selectors.elCollapse)) { return; } const elTextareas = elQuestionItem.querySelectorAll(BuilderEditQuiz.selectors.elQuestionTinymce); elTextareas.forEach(elTextarea => { if (elTextarea?.id) { this._reInitTinymce(elTextarea.id); } }); } events() { if (BuilderEditQuiz._loadedEvents) { return; } BuilderEditQuiz._loadedEvents = true; // Click events lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('click', [{ selector: BuilderEditQuiz.selectors.elQuestionToggleAll, class: this, callBack: this.toggleQuestionAll.name }, { selector: BuilderEditQuiz.selectors.elBtnAddQuestion, class: this, callBack: this.addQuestion.name }, { selector: BuilderEditQuiz.selectors.elBtnRemoveQuestion, class: this, callBack: this.removeQuestion.name }, { selector: BuilderEditQuiz.selectors.elBtnUpdateQuestionTitle, class: this, callBack: this.updateQuestionTitle.name }, { selector: BuilderEditQuiz.selectors.elBtnCancelUpdateQuestionTitle, class: this, callBack: this.cancelChangeTitleQuestion.name }, { selector: lpAssetsJsPath_lpPopupSelectItemToAdd_js__WEBPACK_IMPORTED_MODULE_2__.LpPopupSelectItemToAdd.selectors.elBtnShowPopupItemsToSelect, class: this, callBack: this.handleShowPopupQuestionBank.name }, { selector: lpAssetsJsPath_lpPopupSelectItemToAdd_js__WEBPACK_IMPORTED_MODULE_2__.LpPopupSelectItemToAdd.selectors.elBtnAddItemsSelected, class: this, callBack: this.handleAddItemsSelected.name }]); // Keydown events lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('keydown', [{ selector: BuilderEditQuiz.selectors.elQuestionTitleInput, class: this, callBack: this.updateQuestionTitle.name, checkIsEventEnter: true }, { selector: BuilderEditQuiz.selectors.elQuestionTitleNewInput, class: this, callBack: this.addQuestion.name, checkIsEventEnter: true }]); // Keyup events lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('keyup', [{ selector: BuilderEditQuiz.selectors.elQuestionTitleInput, class: this, callBack: this.changeTitleQuestion.name }, { selector: `${BuilderEditQuiz.selectors.elQuestionTitleNewInput}, ${BuilderEditQuiz.selectors.elQuestionTypeNew}`, class: this, callBack: this.checkCanAddQuestion.name }]); // Change events lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('change', [{ selector: BuilderEditQuiz.selectors.elQuestionTypeNew, class: this, callBack: this.checkCanAddQuestion.name }]); // Toggle collapse document.addEventListener('click', e => { const target = e.target; lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.toggleCollapse(e, target, BuilderEditQuiz.selectors.elQuestionToggle, [], elQuestionItem => { this._initQuestionTinymce(elQuestionItem); this.checkAllQuestionsCollapsed(); }); }); } /** * Handle show popup question bank - track quiz context */ handleShowPopupQuestionBank(args) { const { target } = args; // Only handle if button is inside Quiz popup context const elQuizWrap = target.closest(BuilderEditQuiz.selectors.elEditQuizWrap); const elBuilderPopup = target.closest('.lp-builder-popup'); if (elQuizWrap || elBuilderPopup) { // Store reference that we're in quiz context BuilderEditQuiz._isQuizPopupContext = true; // Store quiz wrap reference for later use if (elQuizWrap) { this.elEditQuizWrap = elQuizWrap; this._getQuizID(elQuizWrap); this.elEditListQuestions = elQuizWrap.querySelector(BuilderEditQuiz.selectors.elEditListQuestions); } } else { BuilderEditQuiz._isQuizPopupContext = false; } } /** * Handle add items selected from Question Bank popup */ handleAddItemsSelected(args) { const { target } = args; // Only handle if we're in quiz context if (!BuilderEditQuiz._isQuizPopupContext) { return; } // Get items selected from popup const elPopup = sweetalert2__WEBPACK_IMPORTED_MODULE_5___default().getPopup(); if (!elPopup) { return; } // Get selected items from checkboxes const itemsSelected = []; const elListItems = elPopup.querySelector('.list-items'); if (elListItems) { const elCheckedInputs = elListItems.querySelectorAll('input[type="checkbox"]:checked'); elCheckedInputs.forEach(elInput => { itemsSelected.push({ ...elInput.dataset }); }); } // Also check from list-items-selected (if user is viewing selected items) const elListItemsSelected = elPopup.querySelector('.list-items-selected'); if (elListItemsSelected) { const elSelectedItems = elListItemsSelected.querySelectorAll('.li-item-selected:not(.clone)'); elSelectedItems.forEach(elItem => { const itemData = { ...elItem.dataset }; // Avoid duplicates if (!itemsSelected.some(item => item.id === itemData.id)) { itemsSelected.push(itemData); } }); } // If still no items, try to get from LpPopupSelectItemToAdd internal state if (itemsSelected.length === 0) { // Get from data attribute on lp-target const elLPTarget = elPopup.querySelector('.lp-target'); if (elLPTarget && window.lpAJAXG) { try { const dataSend = window.lpAJAXG.getDataSetCurrent(elLPTarget); if (dataSend?.args?.item_selecting && Array.isArray(dataSend.args.item_selecting)) { itemsSelected.push(...dataSend.args.item_selecting); } } catch (e) { console.warn('Error getting item_selecting:', e); } } } if (itemsSelected.length === 0) { console.warn('BuilderEditQuiz: No items selected'); return; } // Close popup and add questions sweetalert2__WEBPACK_IMPORTED_MODULE_5___default().close(); // Reset context flag BuilderEditQuiz._isQuizPopupContext = false; // Add questions to quiz this.addQuestionsSelectedToQuiz(itemsSelected); } /** * Add questions selected from Question Bank popup to quiz */ addQuestionsSelectedToQuiz(itemsSelected) { if (!itemsSelected || itemsSelected.length === 0) { console.warn('BuilderEditQuiz: No items to add'); return; } // Ensure elEditQuizWrap is available - try to find it if (!this.elEditQuizWrap) { // Try to find from builder popup first const builderPopup = document.querySelector('.lp-builder-popup'); if (builderPopup) { this.elEditQuizWrap = builderPopup.querySelector(BuilderEditQuiz.selectors.elEditQuizWrap); } // Fallback to document if (!this.elEditQuizWrap) { this.elEditQuizWrap = document.querySelector(BuilderEditQuiz.selectors.elEditQuizWrap); } } if (!this.elEditQuizWrap) { console.error('BuilderEditQuiz: elEditQuizWrap not found'); return; } // Ensure quizID is available if (!this.quizID) { this._getQuizID(this.elEditQuizWrap); } if (!this.quizID) { console.error('BuilderEditQuiz: quizID not found'); return; } // Ensure elEditListQuestions is available if (!this.elEditListQuestions) { this.elEditListQuestions = this.elEditQuizWrap.querySelector(BuilderEditQuiz.selectors.elEditListQuestions); } if (!this.elEditListQuestions) { console.error('BuilderEditQuiz: elEditListQuestions not found'); return; } const questionIds = []; const placeholderItems = []; // Create placeholder items itemsSelected.forEach(item => { const elQuestionItemClone = this.elEditQuizWrap.querySelector(`${BuilderEditQuiz.selectors.elQuestionItem}.clone`); if (!elQuestionItemClone) { console.error('BuilderEditQuiz: Question clone element not found'); return; } questionIds.push(item.id); const elQuestionItemNew = elQuestionItemClone.cloneNode(true); const elQuestionItemTitleInput = elQuestionItemNew.querySelector(BuilderEditQuiz.selectors.elQuestionTitleInput); elQuestionItemNew.classList.remove('clone'); elQuestionItemNew.dataset.questionId = item.id; // Use title from dataset const questionTitle = item.title || ''; if (elQuestionItemTitleInput) { elQuestionItemTitleInput.value = questionTitle; } lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elQuestionItemNew, 1); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(elQuestionItemNew, 1); elQuestionItemClone.insertAdjacentElement('beforebegin', elQuestionItemNew); placeholderItems.push(elQuestionItemNew); }); if (questionIds.length === 0) { console.warn('BuilderEditQuiz: No questions to add'); return; } const callBack = { success: response => { const { message, status, data } = response; if (status !== 'success') { throw new Error(message || 'Failed to add questions'); } lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); const { html_edit_question } = data; if (!html_edit_question || typeof html_edit_question !== 'object') { throw new Error('Invalid response: missing html_edit_question'); } // Replace placeholder items with actual HTML Object.entries(html_edit_question).forEach(([question_id, item_html]) => { if (!item_html) { console.warn(`Empty HTML for question ${question_id}`); return; } const elQuestionItemPlaceholder = this.elEditQuizWrap.querySelector(`${BuilderEditQuiz.selectors.elQuestionItem}[data-question-id="${question_id}"]`); if (!elQuestionItemPlaceholder) { console.warn(`Placeholder not found for question ${question_id}`); return; } // Replace with actual HTML elQuestionItemPlaceholder.outerHTML = item_html; // Get the newly created element after outerHTML replacement const elQuestionItemCreated = this.elEditQuizWrap.querySelector(`${BuilderEditQuiz.selectors.elQuestionItem}[data-question-id="${question_id}"]`); // Initialize handlers for new question if (elQuestionItemCreated) { const elQuestionEditMain = elQuestionItemCreated.querySelector(BuilderEditQuiz.selectors.elQuestionEditMain); this.reinitQuestionHandlers(elQuestionEditMain); } }); this.updateCountItems(); }, error: error => { console.error('Error adding questions:', error); // Remove placeholder items on error placeholderItems.forEach(elPlaceholder => { if (elPlaceholder && elPlaceholder.parentNode) { elPlaceholder.remove(); } }); lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error?.message || error || 'Failed to add questions', 'error'); }, completed: () => { // Remove loading state from all items (if still exist) questionIds.forEach(question_id => { const elQuestionItem = this.elEditQuizWrap.querySelector(`${BuilderEditQuiz.selectors.elQuestionItem}[data-question-id="${question_id}"]`); if (elQuestionItem) { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elQuestionItem, 0); } }); } }; const dataSend = { action: 'add_questions_to_quiz', quiz_id: this.quizID, question_ids: questionIds, args: { id_url: 'edit-quiz-questions' } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } /** * Toggle all questions */ toggleQuestionAll(args) { const { target } = args; const elQuestionToggleAll = target.closest(BuilderEditQuiz.selectors.elQuestionToggleAll); if (!elQuestionToggleAll || !this.elEditQuizWrap) { return; } const elQuestionItems = this.elEditQuizWrap.querySelectorAll(`${BuilderEditQuiz.selectors.elQuestionItem}:not(.clone)`); elQuestionToggleAll.classList.toggle(BuilderEditQuiz.selectors.elCollapse); const shouldCollapse = elQuestionToggleAll.classList.contains(BuilderEditQuiz.selectors.elCollapse); elQuestionItems.forEach(el => { if (el) { el.classList.toggle(BuilderEditQuiz.selectors.elCollapse, shouldCollapse); if (!shouldCollapse) { this._initQuestionTinymce(el); } } }); } /** * Check if all questions are collapsed */ checkAllQuestionsCollapsed() { if (!this.elEditQuizWrap) { return; } const elQuestionItems = this.elEditQuizWrap.querySelectorAll(`${BuilderEditQuiz.selectors.elQuestionItem}:not(.clone)`); const elQuestionToggleAll = this.elEditQuizWrap.querySelector(BuilderEditQuiz.selectors.elQuestionToggleAll); if (!elQuestionToggleAll) { return; } const isAllExpand = Array.from(elQuestionItems).every(el => el && !el.classList.contains(BuilderEditQuiz.selectors.elCollapse)); elQuestionToggleAll.classList.toggle(BuilderEditQuiz.selectors.elCollapse, !isAllExpand); } /** * Update question count */ updateCountItems() { if (!this.elEditQuizWrap) { return; } const elCountItemsAll = this.elEditQuizWrap.querySelector('.total-items'); const elItemsAll = this.elEditQuizWrap.querySelectorAll(`${BuilderEditQuiz.selectors.elQuestionItem}:not(.clone)`); const itemsAllCount = elItemsAll.length; if (elCountItemsAll) { elCountItemsAll.dataset.count = itemsAllCount; const countEl = elCountItemsAll.querySelector('.count'); if (countEl) { countEl.textContent = itemsAllCount; } } } /** * Add question to quiz */ addQuestion(args) { const { e, target, callBackNest } = args; e.preventDefault(); const elAddNewQuestion = target.closest(`.${BuilderEditQuiz.selectors.elAddNewQuestion}`); if (!elAddNewQuestion || !this.elEditListQuestions) { return; } const elQuestionTitleNewInput = elAddNewQuestion.querySelector(BuilderEditQuiz.selectors.elQuestionTitleNewInput); const questionTitle = elQuestionTitleNewInput?.value?.trim(); if (!questionTitle) { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(elQuestionTitleNewInput?.dataset?.messEmptyTitle || 'Title is required', 'error'); return; } const elQuestionType = elAddNewQuestion.querySelector(BuilderEditQuiz.selectors.elQuestionTypeNew); const questionType = elQuestionType?.value; if (!questionType) { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(elQuestionType?.dataset?.messEmptyType || 'Type is required', 'error'); return; } const elQuestionClone = this.elEditListQuestions.querySelector(`${BuilderEditQuiz.selectors.elQuestionItem}.clone`); if (!elQuestionClone) { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show('Question template not found', 'error'); return; } const newQuestionItem = elQuestionClone.cloneNode(true); const elQuestionTitleInput = newQuestionItem.querySelector(BuilderEditQuiz.selectors.elQuestionTitleInput); if (elQuestionTitleInput) { elQuestionTitleInput.value = questionTitle; } elQuestionTitleNewInput.value = ''; newQuestionItem.classList.remove('clone'); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(newQuestionItem, 1); elQuestionClone.insertAdjacentElement('beforebegin', newQuestionItem); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(newQuestionItem, 1); const callBack = { success: response => { const { message, status, data } = response; if (status === 'error') { throw new Error(message); } if (status === 'success' && data?.question) { const { question, html_edit_question } = data; newQuestionItem.dataset.questionId = question.ID; newQuestionItem.dataset.questionType = question.meta_data?._lp_type || ''; newQuestionItem.outerHTML = html_edit_question; const elQuestionItemCreated = this.elEditListQuestions.querySelector(`${BuilderEditQuiz.selectors.elQuestionItem}[data-question-id="${question.ID}"]`); if (elQuestionItemCreated) { elQuestionItemCreated.classList.remove(BuilderEditQuiz.selectors.elCollapse); this.updateCountItems(); const elQuestionEditMain = elQuestionItemCreated.querySelector(BuilderEditQuiz.selectors.elQuestionEditMain); this.reinitQuestionHandlers(elQuestionEditMain); if (callBackNest?.success) { callBackNest.success({ response, elQuestionItemCreated }); } } } lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); }, error: error => { newQuestionItem.remove(); lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error?.message || error || 'Failed to add question', 'error'); if (callBackNest?.error) { callBackNest.error({ error, newQuestionItem }); } }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(newQuestionItem, 0); this.checkCanAddQuestion({ e, target: elQuestionTitleNewInput }); if (callBackNest?.completed) { callBackNest.completed({ newQuestionItem }); } } }; try { let dataSend = JSON.parse(elQuestionTitleNewInput.dataset.send || '{}'); dataSend = { ...dataSend, question_title: questionTitle, question_type: questionType }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } catch (e) { console.error('Error adding question:', e); newQuestionItem.remove(); lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show('Failed to add question', 'error'); } } /** * Check if can add question */ checkCanAddQuestion(args) { const { target } = args; const elTrigger = target?.closest(BuilderEditQuiz.selectors.elQuestionTitleNewInput) || target?.closest(BuilderEditQuiz.selectors.elQuestionTypeNew); if (!elTrigger) { return; } const elAddNewQuestion = elTrigger.closest(`.${BuilderEditQuiz.selectors.elAddNewQuestion}`); const elBtnAddQuestion = elAddNewQuestion?.querySelector(BuilderEditQuiz.selectors.elBtnAddQuestion); if (!elBtnAddQuestion) { return; } const elQuestionTitleInput = elAddNewQuestion.querySelector(BuilderEditQuiz.selectors.elQuestionTitleNewInput); const elQuestionTypeNew = elAddNewQuestion.querySelector(BuilderEditQuiz.selectors.elQuestionTypeNew); const questionTitle = elQuestionTitleInput?.value?.trim(); const questionType = elQuestionTypeNew?.value; elBtnAddQuestion.classList.toggle('active', !!(questionTitle && questionType)); } /** * Remove question from quiz */ removeQuestion(args) { const { target } = args; const elBtnRemoveQuestion = target.closest(BuilderEditQuiz.selectors.elBtnRemoveQuestion); if (!elBtnRemoveQuestion) { return; } const elQuestionItem = elBtnRemoveQuestion.closest(BuilderEditQuiz.selectors.elQuestionItem); if (!elQuestionItem) { return; } const questionId = elQuestionItem.dataset.questionId; if (!questionId) { return; } const i18n = window.lpDataAdmin?.i18n || window.lpData?.i18n || { cancel: 'Cancel', yes: 'Yes' }; sweetalert2__WEBPACK_IMPORTED_MODULE_5___default().fire({ title: elBtnRemoveQuestion.dataset.title || 'Are you sure?', text: elBtnRemoveQuestion.dataset.content || 'Do you want to remove this question?', icon: 'warning', showCloseButton: true, showCancelButton: true, cancelButtonText: i18n.cancel, confirmButtonText: i18n.yes, reverseButtons: true }).then(result => { if (result.isConfirmed) { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elQuestionItem, 1); const callBack = { success: response => { const { message, status } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (status === 'success') { elQuestionItem.remove(); this.updateCountItems(); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error?.message || error || 'Failed to remove question', 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elQuestionItem, 0); } }; const dataSend = { quiz_id: this.quizID, action: 'remove_question_from_quiz', question_id: questionId, args: { id_url: 'edit-quiz-questions' } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } }); } /** * Update question title */ updateQuestionTitle(args) { const { e, target } = args; const canHandle = target.closest(BuilderEditQuiz.selectors.elBtnUpdateQuestionTitle) || target.closest(BuilderEditQuiz.selectors.elQuestionTitleInput) && e.key === 'Enter'; if (!canHandle) { return; } e.preventDefault(); const elQuestionItem = target.closest(BuilderEditQuiz.selectors.elQuestionItem); const elQuestionTitleInput = elQuestionItem?.querySelector(BuilderEditQuiz.selectors.elQuestionTitleInput); if (!elQuestionTitleInput) { return; } const questionId = elQuestionItem.dataset.questionId; const questionTitleValue = elQuestionTitleInput.value.trim(); const titleOld = elQuestionTitleInput.dataset.old; if (!questionTitleValue) { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(elQuestionTitleInput.dataset.messEmptyTitle || 'Title is required', 'error'); return; } if (questionTitleValue === titleOld) { return; } elQuestionTitleInput.blur(); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elQuestionItem, 1); const callBack = { success: response => { const { message, status } = response; if (status === 'success') { elQuestionTitleInput.dataset.old = questionTitleValue; } else { elQuestionTitleInput.value = titleOld; } lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error?.message || error || 'Failed to update title', 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elQuestionItem, 0); elQuestionItem.classList.remove('editing'); } }; const dataSend = { quiz_id: this.quizID, action: 'update_question', question_id: questionId, question_title: questionTitleValue, args: { id_url: 'edit-quiz-questions' } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } /** * Handle title change */ changeTitleQuestion(args) { const { target } = args; const elQuestionTitleInput = target.closest(BuilderEditQuiz.selectors.elQuestionTitleInput); if (!elQuestionTitleInput) { return; } const elQuestionItem = elQuestionTitleInput.closest(BuilderEditQuiz.selectors.elQuestionItem); if (!elQuestionItem) { return; } const titleValue = elQuestionTitleInput.value.trim(); const titleValueOld = elQuestionTitleInput.dataset.old || ''; elQuestionItem.classList.toggle('editing', titleValue !== titleValueOld); } /** * Cancel title change */ cancelChangeTitleQuestion(args) { const { target } = args; const elBtnCancel = target.closest(BuilderEditQuiz.selectors.elBtnCancelUpdateQuestionTitle); if (!elBtnCancel) { return; } const elQuestionItem = elBtnCancel.closest(BuilderEditQuiz.selectors.elQuestionItem); if (!elQuestionItem) { return; } const elQuestionTitleInput = elQuestionItem.querySelector(BuilderEditQuiz.selectors.elQuestionTitleInput); if (elQuestionTitleInput) { elQuestionTitleInput.value = elQuestionTitleInput.dataset.old || ''; } elQuestionItem.classList.remove('editing'); } /** * Make questions sortable */ sortAbleQuestion() { if (!this.elEditListQuestions) { return; } // Destroy existing instance first if (this.sortableInstance?.destroy) { try { this.sortableInstance.destroy(); } catch (e) { console.warn('Error destroying sortable:', e); } this.sortableInstance = null; } let isUpdateSectionPosition = 0; let timeout; try { this.sortableInstance = new sortablejs__WEBPACK_IMPORTED_MODULE_4__["default"](this.elEditListQuestions, { handle: '.drag', animation: 150, onEnd: evt => { const elQuestionItem = evt.item; if (!isUpdateSectionPosition) { return; } clearTimeout(timeout); timeout = setTimeout(() => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elQuestionItem, 1); const questionIds = []; const elQuestionItems = this.elEditListQuestions.querySelectorAll(`${BuilderEditQuiz.selectors.elQuestionItem}:not(.clone)`); elQuestionItems.forEach(elItem => { const questionId = elItem?.dataset?.questionId; if (questionId) { questionIds.push(questionId); } }); const callBack = { success: response => { const { message, status } = response; if (status === 'success') { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); } else { throw new Error(message); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error?.message || error || 'Failed to update order', 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elQuestionItem, 0); isUpdateSectionPosition = 0; } }; const dataSend = { quiz_id: this.quizID, action: 'update_questions_position', question_ids: questionIds, args: { id_url: 'edit-quiz-questions' } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); }, 1000); }, onMove: () => { clearTimeout(timeout); }, onUpdate: () => { isUpdateSectionPosition = 1; } }); } catch (e) { console.error('Error creating sortable:', e); } } } /***/ }, /***/ "./assets/src/js/frontend/course-builder/builder-quiz/builder-standalone-quiz.js" /*!***************************************************************************************!*\ !*** ./assets/src/js/frontend/course-builder/builder-quiz/builder-standalone-quiz.js ***! \***************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ BuilderStandaloneQuiz: () => (/* binding */ BuilderStandaloneQuiz) /* harmony export */ }); /* harmony import */ var lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lpAssetsJsPath/utils.js */ "./assets/src/js/utils.js"); /* harmony import */ var lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! lpAssetsJsPath/lpToastify.js */ "./assets/src/js/lpToastify.js"); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! sweetalert2 */ "./node_modules/sweetalert2/dist/sweetalert2.all.js"); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(sweetalert2__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _builder_edit_quiz_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./builder-edit-quiz.js */ "./assets/src/js/frontend/course-builder/builder-quiz/builder-edit-quiz.js"); /* harmony import */ var _swal_icons_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../swal-icons.js */ "./assets/src/js/frontend/course-builder/swal-icons.js"); /* harmony import */ var _builder_form_state_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../builder-form-state.js */ "./assets/src/js/frontend/course-builder/builder-form-state.js"); /** * Builder Standalone Quiz Handler * Handles standalone quiz edit page (not popup) * * Important separation note: * - This file handles standalone quiz page orchestration (header actions, publish/draft/trash, permalink, tabs). * - Question-tab internals are delegated to BuilderEditQuiz. * - Do not merge the two responsibilities into one file unless there is a strong architectural reason. * * @since 4.3.0 * @version 1.0.0 */ class BuilderStandaloneQuiz { constructor() { // BuilderEditQuiz instance for handling Question tab this.builderEditQuiz = null; // Events use document-level event delegation, so always register them // The page context check happens in individual handlers via target.closest() this.init(); } static selectors = { // Context selector - indicates we're on quiz edit page elDataQuiz: '.cb-section__quiz-edit', // Shared header action buttons (generic selectors) elBtnMainAction: '.cb-btn-main-action', elBtnUpdate: '.cb-btn-update, .cb-btn-publish', elBtnDraft: '.cb-btn-darft, .cb-dropdown-item[data-status="draft"]', elBtnDuplicate: '.cb-btn-duplicate-quiz', elBtnTrash: '.cb-btn-trash', // Status badge elQuizStatus: '.quiz-status, .quizze-status', // Form fields idTitle: 'title', idDescEditor: 'quiz_description_editor', elPublishStatusSelect: '#cb-quiz-publish-status', elFormSetting: '.lp-form-setting-quiz', // Permalink component elPermalinkDisplay: '.cb-permalink-display', elPermalinkEditor: '.cb-permalink-editor', elPermalinkEditBtn: '.cb-permalink-edit-btn', elPermalinkOkBtn: '.cb-permalink-ok-btn', elPermalinkCancelBtn: '.cb-permalink-cancel-btn', elPermalinkSlugInput: '.cb-permalink-slug-input', elPermalinkUrl: '.cb-permalink-url', elPermalinkBaseUrl: '#cb-permalink-base-url', elPermalinkRoot: '.cb-item-edit-permalink, .cb-course-edit-permalink', elPermalinkPlaceholder: '.cb-item-edit-permalink__placeholder', // Tab handling selectors elCBHorizontalTabs: '.lp-cb-tabs__item', elCBTabPanels: '.lp-cb-tab-panel', // Dropdown selectors elDropdownToggle: '.cb-btn-dropdown-toggle', elDropdownMenu: '.cb-dropdown-menu', elDropdownItem: '.cb-dropdown-item', elHeaderActionsDropdown: '.cb-header-actions-dropdown', elQuizActionExpanded: '.course-action-expanded' }; init() { this.initTabs(); this.initHeaderActionsDropdown(); this.initQuestionTabHandler(); this.syncHeaderActionWithPublishPanel(); this.events(); } /** * Initialize Question tab handler * Listen for AJAX completed to initialize BuilderEditQuiz when Question tab content loads */ initQuestionTabHandler() { // Only run on quiz edit page context if (!this.isQuizContext()) { return; } // Listen for WordPress lp-ajax-completed hook when AJAX content loads if (typeof wp !== 'undefined' && wp.hooks) { wp.hooks.addAction('lp-ajax-completed', 'lp-course-builder', (element, dataSend) => { // Check if this is the quiz question tab content if (!dataSend?.callback?.method || dataSend.callback.method !== 'render_edit_quiz') { return; } // Initialize BuilderEditQuiz for the loaded content this.initBuilderEditQuiz(element); }); } } /** * Initialize BuilderEditQuiz for question editing functionality * @param {HTMLElement} container - The container element where AJAX content was loaded */ initBuilderEditQuiz(container = null) { if (!this.builderEditQuiz) { this.builderEditQuiz = new _builder_edit_quiz_js__WEBPACK_IMPORTED_MODULE_3__.BuilderEditQuiz(); } // Reinitialize for the new content this.builderEditQuiz.reinit(container); } /** * Initialize header actions dropdown (toggle behavior) */ initHeaderActionsDropdown() { // Close dropdown when clicking outside document.addEventListener('click', e => { const dropdown = document.querySelector(BuilderStandaloneQuiz.selectors.elHeaderActionsDropdown); if (dropdown && !dropdown.contains(e.target)) { const menu = dropdown.querySelector(BuilderStandaloneQuiz.selectors.elDropdownMenu); const toggle = dropdown.querySelector(BuilderStandaloneQuiz.selectors.elDropdownToggle); if (menu) { menu.classList.remove('is-open'); } if (toggle) { toggle.setAttribute('aria-expanded', 'false'); } } }); } /** * Handle dropdown toggle click */ handleDropdownToggle(args) { if (this.hasPublishDrivenSingleAction()) { return; } const { target } = args; const toggleBtn = target.closest(BuilderStandaloneQuiz.selectors.elDropdownToggle); if (!toggleBtn) { return; } const dropdown = toggleBtn.closest(BuilderStandaloneQuiz.selectors.elHeaderActionsDropdown); if (!dropdown) { return; } const menu = dropdown.querySelector(BuilderStandaloneQuiz.selectors.elDropdownMenu); if (menu) { menu.classList.toggle('is-open'); const isOpen = menu.classList.contains('is-open'); toggleBtn.setAttribute('aria-expanded', isOpen ? 'true' : 'false'); } } /** * Handle dropdown item click (Save Draft, Publish from dropdown menu) */ handleDropdownItemClick(args) { // Context check: only handle if on quiz edit page if (!this.isQuizContext()) { return; } if (this.hasPublishDrivenSingleAction()) { return; } const { target } = args; const dropdownItem = target.closest(BuilderStandaloneQuiz.selectors.elDropdownItem); if (!dropdownItem) { return; } // Skip if this is trash button - it has its own handler if (dropdownItem.classList.contains('cb-btn-trash') || dropdownItem.classList.contains('cb-btn-duplicate-quiz')) { return; } const status = dropdownItem.dataset.status; if (!status) { return; } // Close the dropdown menu const menu = dropdownItem.closest(BuilderStandaloneQuiz.selectors.elDropdownMenu); if (menu) { menu.classList.remove('is-open'); } // Save with the specified status this.saveQuizWithStatus(dropdownItem, status); } /** * Save quiz with specified status (publish/draft) * @param {HTMLElement} btnEl - The button element that was clicked * @param {string} status - The status to save (publish/draft) */ async saveQuizWithStatus(btnEl, status) { const canContinue = await this.confirmUnpublishIfNeeded(status, btnEl); if (!canContinue) { return; } // Validate title before saving if (!this.validateTitleBeforeUpdate()) { return; } lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(btnEl, 1); const quizData = this.getQuizDataForUpdate(); const dataSend = { ...quizData, action: 'builder_update_quiz', args: { id_url: 'builder-update-quiz' }, quiz_status: status }; const callBack = { success: response => { const { status: respStatus, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, respStatus); if (respStatus === 'success') { // Update action button text this.updateActionButtons(data?.status || status); this.syncPublishPanelStatus(data?.status || status); // Reset form state before potential redirect. document.dispatchEvent(new CustomEvent('lp-course-builder-saved')); if (data?.redirect_url) { window.location.href = data.redirect_url; } if (data?.status) { const elStatus = document.querySelector(BuilderStandaloneQuiz.selectors.elQuizStatus); if (elStatus) { elStatus.className = 'quizze-status ' + data.status; elStatus.textContent = data.status; } } this.updatePermalinkUIAfterSave(data); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(btnEl, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } /** * Initialize horizontal tabs for client-side tab switching */ initTabs() { const tabs = document.querySelectorAll(BuilderStandaloneQuiz.selectors.elCBHorizontalTabs); if (tabs.length === 0) { return; } // Activate first tab by default if none is active const activeTab = document.querySelector(`${BuilderStandaloneQuiz.selectors.elCBHorizontalTabs}.is-active`); if (!activeTab && tabs.length > 0) { tabs[0].classList.add('is-active'); const section = tabs[0].getAttribute('data-tab-section'); if (section) { const panel = document.querySelector(`${BuilderStandaloneQuiz.selectors.elCBTabPanels}[data-section="${section}"]`); if (panel) { panel.classList.remove('lp-hidden'); } } } } /** * Handle horizontal tab click for client-side tab switching */ handleTabClick(args) { const { e, target } = args; const tabLink = target.closest(BuilderStandaloneQuiz.selectors.elCBHorizontalTabs); if (!tabLink) { return; } e.preventDefault(); const section = tabLink.getAttribute('data-tab-section'); if (!section) { return; } // Update active tab const allTabs = document.querySelectorAll(BuilderStandaloneQuiz.selectors.elCBHorizontalTabs); allTabs.forEach(tab => tab.classList.remove('is-active')); tabLink.classList.add('is-active'); const url = new URL(window.location.href); url.searchParams.set('tab', section); window.history.replaceState({}, '', url); // Show/hide panels const allPanels = document.querySelectorAll(BuilderStandaloneQuiz.selectors.elCBTabPanels); allPanels.forEach(panel => { if (panel.getAttribute('data-section') === section) { panel.classList.remove('lp-hidden'); } else { panel.classList.add('lp-hidden'); } }); } events() { if (BuilderStandaloneQuiz._loadedEvents) { return; } BuilderStandaloneQuiz._loadedEvents = true; lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('click', [{ selector: BuilderStandaloneQuiz.selectors.elBtnMainAction, class: this, callBack: this.updateQuiz.name }, { selector: BuilderStandaloneQuiz.selectors.elBtnDuplicate, class: this, callBack: this.duplicateQuiz.name }, { selector: BuilderStandaloneQuiz.selectors.elBtnTrash, class: this, callBack: this.trashQuiz.name }, { selector: BuilderStandaloneQuiz.selectors.elCBHorizontalTabs, class: this, callBack: this.handleTabClick.name }, { selector: BuilderStandaloneQuiz.selectors.elDropdownToggle, class: this, callBack: this.handleDropdownToggle.name }, { selector: BuilderStandaloneQuiz.selectors.elDropdownItem, class: this, callBack: this.handleDropdownItemClick.name }, { selector: BuilderStandaloneQuiz.selectors.elPermalinkEditBtn, class: this, callBack: this.handlePermalinkEdit.name }, { selector: BuilderStandaloneQuiz.selectors.elPermalinkOkBtn, class: this, callBack: this.handlePermalinkOk.name }, { selector: BuilderStandaloneQuiz.selectors.elPermalinkCancelBtn, class: this, callBack: this.handlePermalinkCancel.name }]); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('change', [{ selector: BuilderStandaloneQuiz.selectors.elPublishStatusSelect, class: this, callBack: this.handlePublishStatusChange.name }]); } handlePublishStatusChange() { this.syncHeaderActionWithPublishPanel(); (0,_builder_form_state_js__WEBPACK_IMPORTED_MODULE_5__.getFormState)().markAsChanged(); } /** * Validate title is not empty before update * @return {boolean} True if valid, false if invalid */ validateTitleBeforeUpdate() { const titleInput = document.getElementById(BuilderStandaloneQuiz.selectors.idTitle); if (!titleInput) { return true; } const title = titleInput.value.trim(); if (!title) { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show('Quiz title is required.', 'error'); titleInput.focus(); return false; } return true; } getQuizDataForUpdate() { const data = {}; const wrapperEl = document.querySelector(BuilderStandaloneQuiz.selectors.elDataQuiz); data.quiz_id = wrapperEl ? parseInt(wrapperEl.dataset.quizId) || 0 : 0; const titleInput = document.getElementById(BuilderStandaloneQuiz.selectors.idTitle); data.quiz_title = titleInput ? titleInput.value : ''; const descEditor = document.getElementById(BuilderStandaloneQuiz.selectors.idDescEditor); data.quiz_description = descEditor ? descEditor.value : ''; if (typeof tinymce !== 'undefined') { const editor = tinymce.get(BuilderStandaloneQuiz.selectors.idDescEditor); if (editor) { data.quiz_description = editor.getContent(); } } const permalinkInput = document.querySelector(BuilderStandaloneQuiz.selectors.elPermalinkSlugInput); if (permalinkInput && permalinkInput.value) { data.quiz_permalink = permalinkInput.value; } const elFormSetting = document.querySelector(BuilderStandaloneQuiz.selectors.elFormSetting); if (elFormSetting) { data.quiz_settings = true; const formElements = elFormSetting.querySelectorAll('input, select, textarea'); formElements.forEach(element => { const name = element.name || element.id; if (!name) { return; } if (name === 'learnpress_meta_box_nonce' || name === '_wp_http_referer') { return; } if (element.type === 'checkbox') { const fieldName = name.replace('[]', ''); if (!data.hasOwnProperty(fieldName)) { data[fieldName] = element.checked ? 'yes' : 'no'; } } else if (element.type === 'radio') { if (element.checked) { const fieldName = name.replace('[]', ''); data[fieldName] = element.value; } } else if (element.type === 'file') { const fieldName = name.replace('[]', ''); if (element.files && element.files.length > 0) { data[fieldName] = element.files; } } else { const fieldName = name.replace('[]', ''); if (name.endsWith('[]')) { if (!data.hasOwnProperty(fieldName)) { data[fieldName] = []; } if (Array.isArray(data[fieldName])) { data[fieldName].push(element.value); } } else { if (!data.hasOwnProperty(fieldName)) { data[fieldName] = element.value; } } } }); Object.keys(data).forEach(key => { if (Array.isArray(data[key])) { data[key] = data[key].join(','); } }); } return data; } getStatusFromPublishPanel(fallbackStatus = 'publish') { const statusSelect = document.querySelector(BuilderStandaloneQuiz.selectors.elPublishStatusSelect); if (!statusSelect) { return fallbackStatus; } const selectedStatus = statusSelect.value; if (selectedStatus === 'publish' || selectedStatus === 'draft') { return selectedStatus; } return fallbackStatus; } hasPublishDrivenSingleAction() { if (!document.querySelector(BuilderStandaloneQuiz.selectors.elPublishStatusSelect)) { return false; } const wrapperEl = document.querySelector(BuilderStandaloneQuiz.selectors.elDataQuiz); const quizId = wrapperEl ? parseInt(wrapperEl.dataset.quizId) || 0 : 0; return quizId > 0; } syncHeaderActionWithPublishPanel() { if (!this.hasPublishDrivenSingleAction()) { return; } const dropdown = document.querySelector(BuilderStandaloneQuiz.selectors.elHeaderActionsDropdown); if (!dropdown) { return; } const mainBtn = dropdown.querySelector('.cb-btn-main-action'); if (!mainBtn) { return; } const toggleBtn = dropdown.querySelector(BuilderStandaloneQuiz.selectors.elDropdownToggle); const dropdownMenu = dropdown.querySelector(BuilderStandaloneQuiz.selectors.elDropdownMenu); const status = this.getStatusFromPublishPanel(mainBtn.dataset.status || 'publish'); mainBtn.classList.remove('cb-btn-darft', 'cb-btn-publish', 'cb-btn-pending'); mainBtn.classList.add('cb-btn-update', 'cb-btn-primary', 'cb-btn-main-action'); mainBtn.textContent = mainBtn.dataset.titleUpdate || 'Update'; mainBtn.dataset.status = status; dropdown.dataset.currentStatus = status; dropdown.classList.add('cb-header-actions-dropdown--single'); if (toggleBtn) { toggleBtn.style.display = 'none'; } if (dropdownMenu) { dropdownMenu.style.display = 'none'; } } syncPublishPanelStatus(status) { const statusSelect = document.querySelector(BuilderStandaloneQuiz.selectors.elPublishStatusSelect); if (!statusSelect) { return; } statusSelect.value = status === 'publish' ? 'publish' : 'draft'; this.syncHeaderActionWithPublishPanel(); } updatePermalinkUIAfterSave(data = {}) { const permalinkRoot = this.getPermalinkRoot(); if (!permalinkRoot) { return; } const { slugInput, urlLink, baseUrlInput, display, placeholder } = this.getPermalinkElements(permalinkRoot); const permalinkDisplayUrl = this.buildPermalinkDisplayUrl(baseUrlInput ? baseUrlInput.value : '', data?.quiz_slug, data?.quiz_permalink); if (slugInput && data?.quiz_slug) { slugInput.value = data.quiz_slug; slugInput.dataset.originalValue = data.quiz_slug; } const shouldShowUnavailable = data?.permalink_available === false || data?.status === 'draft' || data?.status === 'trash' || !data?.quiz_permalink; if (shouldShowUnavailable) { this.showPermalinkUnavailable(permalinkRoot, data?.permalink_notice); return; } if (placeholder) { placeholder.classList.add('lp-hidden'); } if (display) { display.classList.remove('lp-hidden'); } if (urlLink && data?.quiz_permalink) { urlLink.href = data.quiz_permalink; urlLink.textContent = permalinkDisplayUrl || data.quiz_permalink; } else if (urlLink && permalinkDisplayUrl) { urlLink.textContent = permalinkDisplayUrl; } } slugify(str) { return (str || '').toString().normalize('NFD').replace(/[\u0300-\u036f]/g, '').replace(/đ/g, 'd').replace(/Đ/g, 'D').toLowerCase().replace(/\s+/g, '-').replace(/[^\w-]+/g, '').replace(/--+/g, '-').replace(/^-+/, '').replace(/-+$/, ''); } buildPermalinkDisplayUrl(baseUrl = '', slug = '', fallbackUrl = '') { const normalizedBaseUrl = typeof baseUrl === 'string' ? baseUrl : ''; const normalizedSlug = typeof slug === 'string' ? slug.trim() : ''; if (normalizedBaseUrl && normalizedSlug) { return `${normalizedBaseUrl}${normalizedSlug}`; } return typeof fallbackUrl === 'string' ? fallbackUrl : ''; } getPermalinkRoot(target = null) { if (target?.closest) { const fromTarget = target.closest(BuilderStandaloneQuiz.selectors.elPermalinkRoot); if (fromTarget) { return fromTarget; } } return document.querySelector(`.cb-section__quiz-edit ${BuilderStandaloneQuiz.selectors.elPermalinkRoot}`); } getPermalinkElements(permalinkRoot) { if (!permalinkRoot) { return {}; } return { display: permalinkRoot.querySelector(BuilderStandaloneQuiz.selectors.elPermalinkDisplay), editor: permalinkRoot.querySelector(BuilderStandaloneQuiz.selectors.elPermalinkEditor), placeholder: permalinkRoot.querySelector(BuilderStandaloneQuiz.selectors.elPermalinkPlaceholder), input: permalinkRoot.querySelector(BuilderStandaloneQuiz.selectors.elPermalinkSlugInput), slugInput: permalinkRoot.querySelector(BuilderStandaloneQuiz.selectors.elPermalinkSlugInput), urlLink: permalinkRoot.querySelector(BuilderStandaloneQuiz.selectors.elPermalinkUrl), baseUrlInput: permalinkRoot.querySelector(BuilderStandaloneQuiz.selectors.elPermalinkBaseUrl) }; } showPermalinkUnavailable(permalinkRoot, message = '') { if (!permalinkRoot) { return; } const label = permalinkRoot.querySelector('.cb-item-edit-permalink__label') || permalinkRoot.querySelector('.cb-permalink-label'); const { display, editor } = this.getPermalinkElements(permalinkRoot); let placeholder = permalinkRoot.querySelector(BuilderStandaloneQuiz.selectors.elPermalinkPlaceholder); if (!placeholder) { placeholder = document.createElement('span'); placeholder.className = 'cb-item-edit-permalink__placeholder'; if (label) { label.insertAdjacentElement('afterend', placeholder); } else { permalinkRoot.prepend(placeholder); } } placeholder.textContent = message || 'Permalink is only available if the item is already assigned to a course.'; placeholder.classList.remove('lp-hidden'); if (display) { display.classList.add('lp-hidden'); } if (editor) { editor.classList.add('lp-hidden'); } } handlePermalinkEdit(args) { if (!this.isQuizContext()) { return; } const { e, target } = args; if (e) e.preventDefault(); const permalinkRoot = this.getPermalinkRoot(target); const { display, editor, input } = this.getPermalinkElements(permalinkRoot); if (!display || !editor || !input) return; input.dataset.originalValue = input.value; display.classList.add('lp-hidden'); editor.classList.remove('lp-hidden'); input.focus(); input.select(); } handlePermalinkOk(args) { if (!this.isQuizContext()) { return; } const { e, target } = args; if (e) e.preventDefault(); const permalinkRoot = this.getPermalinkRoot(target); const { display, editor, input, urlLink, baseUrlInput } = this.getPermalinkElements(permalinkRoot); if (!display || !editor || !input || !urlLink) return; let newSlug = this.slugify(input.value.trim()); if (!newSlug) { newSlug = input.dataset.originalValue || 'quiz'; } input.value = newSlug; const baseUrl = baseUrlInput ? baseUrlInput.value : ''; const newUrl = this.buildPermalinkDisplayUrl(baseUrl, newSlug, urlLink.textContent || ''); // Keep href as the current saved link and only update display text. urlLink.textContent = newUrl; editor.classList.add('lp-hidden'); display.classList.remove('lp-hidden'); if (newSlug !== input.dataset.originalValue) { (0,_builder_form_state_js__WEBPACK_IMPORTED_MODULE_5__.getFormState)().markAsChanged(); } } handlePermalinkCancel(args) { if (!this.isQuizContext()) { return; } const { e, target } = args; if (e) e.preventDefault(); const permalinkRoot = this.getPermalinkRoot(target); const { display, editor, input } = this.getPermalinkElements(permalinkRoot); if (!display || !editor || !input) return; input.value = input.dataset.originalValue || ''; editor.classList.add('lp-hidden'); display.classList.remove('lp-hidden'); } /** * Update action buttons after status change, matching course edit logic. * Updates both main button and dropdown items based on new status. * @param {string} newStatus - The new quiz status */ updateActionButtons(newStatus) { const dropdown = document.querySelector(BuilderStandaloneQuiz.selectors.elHeaderActionsDropdown); if (!dropdown) return; const mainBtn = dropdown.querySelector('.cb-btn-main-action'); const dropdownMenu = dropdown.querySelector(BuilderStandaloneQuiz.selectors.elDropdownMenu); if (!mainBtn) return; if (this.hasPublishDrivenSingleAction()) { this.syncHeaderActionWithPublishPanel(); return; } if (!dropdownMenu) return; // Status configuration for button labels and classes const statusConfig = { publish: { mainLabel: mainBtn.dataset.titleUpdate || 'Update', mainClass: 'cb-btn-update', mainStatus: 'publish', dropdownLabel: mainBtn.dataset.titleDraft || 'Save Draft', dropdownClass: 'cb-btn-darft', dropdownStatus: 'draft', dropdownIcon: 'dashicons-media-default' }, draft: { mainLabel: mainBtn.dataset.titleDraft || 'Save Draft', mainClass: 'cb-btn-darft', mainStatus: 'draft', dropdownLabel: mainBtn.dataset.titlePublish || 'Publish', dropdownClass: 'cb-btn-publish', dropdownStatus: 'publish', dropdownIcon: 'dashicons-visibility' }, pending: { mainLabel: 'Submit for Review', mainClass: 'cb-btn-pending', mainStatus: 'pending', dropdownLabel: mainBtn.dataset.titleDraft || 'Save Draft', dropdownClass: 'cb-btn-darft', dropdownStatus: 'draft', dropdownIcon: 'dashicons-media-default' }, trash: { mainLabel: mainBtn.dataset.titleDraft || 'Save Draft', mainClass: 'cb-btn-darft', mainStatus: 'draft', dropdownLabel: mainBtn.dataset.titlePublish || 'Publish', dropdownClass: 'cb-btn-publish', dropdownStatus: 'publish', dropdownIcon: 'dashicons-visibility' } }; const config = statusConfig[newStatus] || statusConfig.draft; // Update main button mainBtn.className = `${config.mainClass} cb-btn-primary cb-btn-main-action`; mainBtn.dataset.status = config.mainStatus; mainBtn.textContent = config.mainLabel; // Update dropdown item (first item, excluding trash) const dropdownItems = dropdownMenu.querySelectorAll('.cb-dropdown-item:not(.cb-btn-trash)'); if (dropdownItems.length > 0) { const firstItem = dropdownItems[0]; firstItem.className = `cb-dropdown-item ${config.dropdownClass}`; firstItem.dataset.status = config.dropdownStatus; firstItem.innerHTML = `${config.dropdownLabel}`; } // Update dropdown data-current-status dropdown.dataset.currentStatus = newStatus; } /** * Check if we're in quiz edit context * @return {boolean} */ isQuizContext() { return !!document.querySelector(BuilderStandaloneQuiz.selectors.elDataQuiz); } async updateQuiz(args) { // Context check: only handle if on quiz edit page if (!this.isQuizContext()) { return; } const { target } = args; const elBtnUpdateQuiz = target.closest(BuilderStandaloneQuiz.selectors.elBtnMainAction); if (!elBtnUpdateQuiz) { return; } // Validate title before update if (!this.validateTitleBeforeUpdate()) { return; } // Resolve status from Overview publish panel first, fallback to button data-status. const targetStatus = this.getStatusFromPublishPanel(elBtnUpdateQuiz.dataset.status || 'publish'); const canContinue = await this.confirmUnpublishIfNeeded(targetStatus, elBtnUpdateQuiz); if (!canContinue) { return; } lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elBtnUpdateQuiz, 1); const quizData = this.getQuizDataForUpdate(); const dataSend = { ...quizData, action: 'builder_update_quiz', args: { id_url: 'builder-update-quiz' }, quiz_status: targetStatus }; const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (status === 'success') { // Update action buttons with actual status from server this.updateActionButtons(data?.status || targetStatus); this.syncPublishPanelStatus(data?.status || targetStatus); // Reset form state before potential redirect. document.dispatchEvent(new CustomEvent('lp-course-builder-saved')); if (data?.redirect_url) { window.location.href = data.redirect_url; } if (data?.status) { const elStatus = document.querySelector(BuilderStandaloneQuiz.selectors.elQuizStatus); if (elStatus) { elStatus.className = 'quizze-status ' + data.status; elStatus.textContent = data.status; } if (data.status === 'trash' || data.status === 'draft') { const curriculumItem = document.querySelector(`.quiz-item[data-quiz-id="${quizData.quiz_id}"]`); if (curriculumItem) { const elCurriculumQuiz = curriculumItem.closest('.quiz'); if (elCurriculumQuiz) { elCurriculumQuiz.remove(); } } } } this.updatePermalinkUIAfterSave(data); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elBtnUpdateQuiz, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } async confirmUnpublishIfNeeded(targetStatus, triggerEl) { if (targetStatus !== 'draft') { return true; } const statusEl = document.querySelector(BuilderStandaloneQuiz.selectors.elQuizStatus); const isPublished = statusEl && statusEl.className.includes('publish'); if (!isPublished) { return true; } const confirmMsg = triggerEl?.dataset?.confirmUnpublish || 'Saving as draft will unpublish this item. Are you sure?'; const result = await sweetalert2__WEBPACK_IMPORTED_MODULE_2___default().fire({ title: confirmMsg, iconHtml: _swal_icons_js__WEBPACK_IMPORTED_MODULE_4__.SWAL_ICON_TRASH_DRAFT, customClass: { icon: 'lp-cb-swal-icon-html' }, showCloseButton: true, showCancelButton: true, cancelButtonText: lpData.i18n.cancel, confirmButtonText: lpData.i18n.yes, reverseButtons: true }); return !!result.isConfirmed; } async saveDraftQuiz(args) { // Context check: only handle if on quiz edit page if (!this.isQuizContext()) { return; } const { target } = args; const elBtnDraftQuiz = target.closest(BuilderStandaloneQuiz.selectors.elBtnDraft); if (!elBtnDraftQuiz) { return; } // Check if published to show confirm unpublish modal const statusEl = document.querySelector(BuilderStandaloneQuiz.selectors.elQuizStatus); // Status might use quiz-status or quizze-status class based on element logic const isPublished = statusEl && statusEl.className.includes('publish'); if (isPublished) { const confirmMsg = elBtnDraftQuiz.dataset.confirmUnpublish || 'Saving as draft will unpublish this item. Are you sure?'; const result = await sweetalert2__WEBPACK_IMPORTED_MODULE_2___default().fire({ title: confirmMsg, iconHtml: _swal_icons_js__WEBPACK_IMPORTED_MODULE_4__.SWAL_ICON_TRASH_DRAFT, customClass: { icon: 'lp-cb-swal-icon-html' }, showCloseButton: true, showCancelButton: true, cancelButtonText: lpData.i18n.cancel, confirmButtonText: lpData.i18n.yes, reverseButtons: true }); if (!result.isConfirmed) { return; } } // Validate title before saving draft if (!this.validateTitleBeforeUpdate()) { return; } const elQuizActionExpanded = document.querySelector(BuilderStandaloneQuiz.selectors.elQuizActionExpanded); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elQuizActionExpanded, 1); const quizData = this.getQuizDataForUpdate(); const dataSend = { ...quizData, action: 'builder_update_quiz', args: { id_url: 'builder-update-quiz' }, quiz_status: 'draft' }; const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (status === 'success') { // Update action button text this.updateActionButtons('draft'); this.syncPublishPanelStatus(data?.status || 'draft'); // Reset form state before potential redirect. document.dispatchEvent(new CustomEvent('lp-course-builder-saved')); if (data?.redirect_url) { window.location.href = data.redirect_url; } if (data?.status) { const elStatus = document.querySelector(BuilderStandaloneQuiz.selectors.elQuizStatus); if (elStatus) { elStatus.className = 'quizze-status ' + data.status; elStatus.textContent = data.status; } if (data.status === 'trash' || data.status === 'draft') { const curriculumItem = document.querySelector(`.quiz-item[data-quiz-id="${quizData.quiz_id}"]`); if (curriculumItem) { const elCurriculumQuiz = curriculumItem.closest('.quiz'); if (elCurriculumQuiz) { elCurriculumQuiz.remove(); } } } } this.updatePermalinkUIAfterSave(data); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elQuizActionExpanded, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } async trashQuiz(args) { // Context check: only handle if on quiz edit page if (!this.isQuizContext()) { return; } const { target } = args; const elBtnTrashQuiz = target.closest(BuilderStandaloneQuiz.selectors.elBtnTrash); if (!elBtnTrashQuiz) { return; } const result = await sweetalert2__WEBPACK_IMPORTED_MODULE_2___default().fire({ title: 'Are you sure you want to trash this quiz?', iconHtml: _swal_icons_js__WEBPACK_IMPORTED_MODULE_4__.SWAL_ICON_TRASH_DRAFT, customClass: { icon: 'lp-cb-swal-icon-html' }, showCloseButton: true, showCancelButton: true, cancelButtonText: lpData.i18n.cancel, confirmButtonText: lpData.i18n.yes, reverseButtons: true }); if (!result.isConfirmed) { return; } const elQuizActionExpanded = document.querySelector(BuilderStandaloneQuiz.selectors.elQuizActionExpanded); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elQuizActionExpanded, 1); const wrapperEl = document.querySelector(BuilderStandaloneQuiz.selectors.elDataQuiz); const quizId = wrapperEl ? parseInt(wrapperEl.dataset.quizId) || 0 : 0; const dataSend = { quiz_id: quizId, action: 'move_trash_quiz', args: { id_url: 'builder-trash-quiz' } }; const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (status === 'success') { // Update status badge and action buttons if trash was successful if (data?.status) { const elStatus = document.querySelector(BuilderStandaloneQuiz.selectors.elQuizStatus); if (elStatus) { elStatus.className = 'quizze-status ' + data.status; elStatus.textContent = data.status; } if (data.status === 'trash' || data.status === 'draft') { const curriculumItem = document.querySelector(`.quiz-item[data-quiz-id="${quizId}"]`); if (curriculumItem) { const elCurriculumQuiz = curriculumItem.closest('.quiz'); if (elCurriculumQuiz) { elCurriculumQuiz.remove(); } } } // Update action buttons to show correct state for trash status this.updateActionButtons(data.status); } this.updatePermalinkUIAfterSave(data); // Redirect if URL is provided, otherwise stay on page with updated UI if (data?.redirect_url) { window.location.href = data.redirect_url; } } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elQuizActionExpanded, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } async duplicateQuiz(args) { // Context check: only handle if on quiz edit page if (!this.isQuizContext()) { return; } const { target } = args; const elBtnDuplicateQuiz = target.closest(BuilderStandaloneQuiz.selectors.elBtnDuplicate); if (!elBtnDuplicateQuiz) { return; } const wrapperEl = document.querySelector(BuilderStandaloneQuiz.selectors.elDataQuiz); const quizId = wrapperEl ? parseInt(wrapperEl.dataset.quizId, 10) || 0 : 0; if (!quizId) { return; } const result = await sweetalert2__WEBPACK_IMPORTED_MODULE_2___default().fire({ title: elBtnDuplicateQuiz.dataset.title || 'Are you sure?', text: elBtnDuplicateQuiz.dataset.content || 'Are you sure you want to duplicate this quiz?', iconHtml: _swal_icons_js__WEBPACK_IMPORTED_MODULE_4__.SWAL_ICON_DUPLICATE, customClass: { icon: 'lp-cb-swal-icon-html' }, showCloseButton: true, showCancelButton: true, cancelButtonText: lpData.i18n.cancel, confirmButtonText: lpData.i18n.yes, reverseButtons: true }); if (!result.isConfirmed) { return; } const elQuizActionExpanded = document.querySelector(BuilderStandaloneQuiz.selectors.elQuizActionExpanded); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elQuizActionExpanded, 1); const dataSend = { quiz_id: quizId, action: 'duplicate_quiz', args: { id_url: 'duplicate-quiz' } }; const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message || 'Duplicated successfully!', status); if (status === 'success' && data?.redirect_url) { window.location.href = data.redirect_url; } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elQuizActionExpanded, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } } /***/ }, /***/ "./assets/src/js/frontend/course-builder/builder-quiz/builder-tab-quiz.js" /*!********************************************************************************!*\ !*** ./assets/src/js/frontend/course-builder/builder-quiz/builder-tab-quiz.js ***! \********************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ BuilderTabQuiz: () => (/* binding */ BuilderTabQuiz) /* harmony export */ }); /* harmony import */ var lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lpAssetsJsPath/utils.js */ "./assets/src/js/utils.js"); /* harmony import */ var lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! lpAssetsJsPath/lpToastify.js */ "./assets/src/js/lpToastify.js"); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! sweetalert2 */ "./node_modules/sweetalert2/dist/sweetalert2.all.js"); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(sweetalert2__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _swal_icons_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../swal-icons.js */ "./assets/src/js/frontend/course-builder/swal-icons.js"); class BuilderTabQuiz { constructor() { this.init(); } static selectors = { elQuizItem: '.quiz-item', elQuizExpandedItems: '.quiz-action-expanded__items', elQuizDuplicate: '.quiz-action-expanded__duplicate', elQuizTrash: '.quiz-action-expanded__trash', elQuizRestore: '.quiz-action-expanded__restore', elQuizPublish: '.quiz-action-expanded__publish', elQuizDelete: '.quiz-action-expanded__delete', elQuizActionExpanded: '.quiz-action-expanded', elQuizStatus: '.quiz-status', elBtnEditQuiz: '.btn-edit-quiz' }; init() { this.events(); } events() { if (BuilderTabQuiz._loadedEvents) { return; } BuilderTabQuiz._loadedEvents = true; lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('click', [{ selector: BuilderTabQuiz.selectors.elQuizDuplicate, class: this, callBack: this.duplicateQuiz.name }, { selector: BuilderTabQuiz.selectors.elQuizTrash, class: this, callBack: this.trashQuiz.name }, { selector: BuilderTabQuiz.selectors.elQuizPublish, class: this, callBack: this.publishQuiz.name }, { selector: BuilderTabQuiz.selectors.elQuizRestore, class: this, callBack: this.restoreQuiz.name }, { selector: BuilderTabQuiz.selectors.elQuizDelete, class: this, callBack: this.deleteQuiz.name }, { selector: BuilderTabQuiz.selectors.elQuizActionExpanded, class: this, callBack: this.toggleExpandedAction.name }, { selector: BuilderTabQuiz.selectors.elBtnEditQuiz, class: this, callBack: this.editQuiz.name }]); document.addEventListener('click', e => { if (!e.target.closest(BuilderTabQuiz.selectors.elQuizActionExpanded)) { this.closeAllExpanded(); } }); } editQuiz(args) { const { target } = args; const elBtnEditQuiz = target.closest(BuilderTabQuiz.selectors.elBtnEditQuiz); if (!elBtnEditQuiz) { return; } lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elBtnEditQuiz, 1); } duplicateQuiz(args) { const { target } = args; const elQuizDuplicate = target.closest(BuilderTabQuiz.selectors.elQuizDuplicate); const elQuizItem = elQuizDuplicate.closest(BuilderTabQuiz.selectors.elQuizItem); if (!elQuizItem) { return; } const elActionExpanded = elQuizItem.querySelector(BuilderTabQuiz.selectors.elQuizActionExpanded); const quizId = elQuizItem.dataset.quizId || ''; sweetalert2__WEBPACK_IMPORTED_MODULE_2___default().fire({ title: elQuizDuplicate.dataset.title || 'Duplicate Quiz', text: elQuizDuplicate.dataset.content || 'Are you sure you want to duplicate this quiz?', iconHtml: _swal_icons_js__WEBPACK_IMPORTED_MODULE_3__.SWAL_ICON_DUPLICATE, customClass: { icon: 'lp-cb-swal-icon-html' }, showCloseButton: true, showCancelButton: true, cancelButtonText: lpData.i18n.cancel, confirmButtonText: lpData.i18n.yes, reverseButtons: true }).then(result => { if (result.isConfirmed) { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 1); const dataSend = { action: 'duplicate_quiz', args: { id_url: 'duplicate-quiz' }, quiz_id: quizId }; const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message || 'Duplicated successfully!', status); if (status === 'success' && data?.redirect_url) { window.location.href = data.redirect_url; } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } }); } trashQuiz(args) { const { target } = args; const elQuizTrash = target.closest(BuilderTabQuiz.selectors.elQuizTrash); const elQuizItem = elQuizTrash.closest(BuilderTabQuiz.selectors.elQuizItem); if (!elQuizItem) { return; } const elActionExpanded = elQuizItem.querySelector(BuilderTabQuiz.selectors.elQuizActionExpanded); const quizId = elQuizItem.dataset.quizId || ''; sweetalert2__WEBPACK_IMPORTED_MODULE_2___default().fire({ title: elQuizTrash.dataset.title || 'Trash Quiz', text: elQuizTrash.dataset.content || 'Are you sure you want to move this quiz to trash?', iconHtml: _swal_icons_js__WEBPACK_IMPORTED_MODULE_3__.SWAL_ICON_TRASH_DRAFT, customClass: { icon: 'lp-cb-swal-icon-html' }, showCloseButton: true, showCancelButton: true, cancelButtonText: lpData.i18n.cancel, confirmButtonText: lpData.i18n.yes, reverseButtons: true }).then(result => { if (result.isConfirmed) { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 1); const dataSend = { action: 'move_trash_quiz', args: { id_url: 'move-trash-quiz' }, quiz_id: quizId }; const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (data?.html) { this.replaceItemHtml(elQuizTrash.closest('.quiz'), data.html); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } }); } publishQuiz(args) { const { target } = args; const elQuizPublish = target.closest(BuilderTabQuiz.selectors.elQuizPublish); const elQuizItem = elQuizPublish.closest(BuilderTabQuiz.selectors.elQuizItem); if (!elQuizItem) { return; } const elActionExpanded = elQuizItem.querySelector(BuilderTabQuiz.selectors.elQuizActionExpanded); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 1); const quizId = elQuizItem.dataset.quizId || ''; const dataSend = { action: 'move_trash_quiz', args: { id_url: 'move-trash-quiz' }, quiz_id: quizId, status: 'publish' }; const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (data?.html) { this.replaceItemHtml(elQuizPublish.closest('.quiz'), data.html); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } restoreQuiz(args) { const { target } = args; const elQuizRestore = target.closest(BuilderTabQuiz.selectors.elQuizRestore); const elQuizItem = elQuizRestore.closest(BuilderTabQuiz.selectors.elQuizItem); if (!elQuizItem) { return; } const elActionExpanded = elQuizItem.querySelector(BuilderTabQuiz.selectors.elQuizActionExpanded); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 1); const quizId = elQuizItem.dataset.quizId || ''; const dataSend = { action: 'move_trash_quiz', args: { id_url: 'move-trash-quiz' }, quiz_id: quizId, status: 'draft' }; const callBack = { success: response => { const { status, message, data } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (data?.html) { this.replaceItemHtml(elQuizRestore.closest('.quiz'), data.html); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } deleteQuiz(args) { const { target } = args; const elQuizDelete = target.closest(BuilderTabQuiz.selectors.elQuizDelete); const elQuizItem = elQuizDelete.closest(BuilderTabQuiz.selectors.elQuizItem); if (!elQuizItem) { return; } const elActionExpanded = elQuizItem.querySelector(BuilderTabQuiz.selectors.elQuizActionExpanded); const quizId = elQuizItem.dataset.quizId || ''; if (!quizId) { return; } sweetalert2__WEBPACK_IMPORTED_MODULE_2___default().fire({ title: elQuizDelete.dataset.title || 'Delete Quiz', text: elQuizDelete.dataset.content || 'Are you sure you want to permanently delete this quiz?', iconHtml: _swal_icons_js__WEBPACK_IMPORTED_MODULE_3__.SWAL_ICON_DELETE, customClass: { icon: 'lp-cb-swal-icon-html' }, showCloseButton: true, showCancelButton: true, cancelButtonText: lpData.i18n.cancel, confirmButtonText: lpData.i18n.yes, reverseButtons: true }).then(result => { if (result.isConfirmed) { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 1); const dataSend = { action: 'move_trash_quiz', args: { id_url: 'move-trash-quiz' }, quiz_id: quizId, status: 'delete' }; const callBack = { success: response => { const { status, message } = response; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(message, status); if (status === 'success') { const elQuiz = elQuizDelete.closest('.quiz'); elQuiz.style.transition = 'opacity 0.4s ease-out, transform 0.4s ease-out'; elQuiz.style.opacity = '0'; elQuiz.style.transform = 'translateX(160px)'; setTimeout(() => { elQuiz.remove(); }, 400); } }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error.message || error, 'error'); }, completed: () => { lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpSetLoadingEl(elActionExpanded, 0); } }; window.lpAJAXG.fetchAJAX(dataSend, callBack); } }); } toggleExpandedAction(args) { const { target } = args; const elQuizActionExpanded = target.closest(BuilderTabQuiz.selectors.elQuizActionExpanded); if (!elQuizActionExpanded) { return; } const elQuizItem = elQuizActionExpanded.closest(BuilderTabQuiz.selectors.elQuizItem); if (!elQuizItem) { return; } const elExpandedItems = elQuizItem.querySelector(BuilderTabQuiz.selectors.elQuizExpandedItems); if (!elExpandedItems) { return; } this.closeAllExpanded(elExpandedItems); const willOpen = !elExpandedItems.classList.contains('active'); if (willOpen) { elExpandedItems.classList.add('active'); elQuizActionExpanded.classList.add('active'); this.setExpandedDirection(elExpandedItems); } else { elExpandedItems.classList.remove('active'); elExpandedItems.classList.remove('is-dropup'); elQuizActionExpanded.classList.remove('active'); } } closeAllExpanded(excludeElement = null) { const allExpandedItems = document.querySelectorAll(`${BuilderTabQuiz.selectors.elQuizExpandedItems}.active`); allExpandedItems.forEach(item => { if (item === excludeElement) { return; } item.classList.remove('active'); item.classList.remove('is-dropup'); const quizItem = item.closest(BuilderTabQuiz.selectors.elQuizItem); if (!quizItem) { return; } const expandedBtn = quizItem.querySelector(BuilderTabQuiz.selectors.elQuizActionExpanded); if (expandedBtn) { expandedBtn.classList.remove('active'); } }); } setExpandedDirection(elExpandedItems) { if (!elExpandedItems) { return; } elExpandedItems.classList.remove('is-dropup'); const elQuiz = elExpandedItems.closest('.quiz'); if (!elQuiz) { return; } if (elQuiz.matches(':last-child')) { elExpandedItems.classList.add('is-dropup'); } } replaceItemHtml(elQuiz, html) { if (!elQuiz || !html) { return; } const tmp = document.createElement('div'); tmp.innerHTML = html; const newEl = tmp.firstElementChild; if (newEl) { elQuiz.replaceWith(newEl); } } } /***/ }, /***/ "./assets/src/js/frontend/course-builder/builder-settings.js" /*!*******************************************************************!*\ !*** ./assets/src/js/frontend/course-builder/builder-settings.js ***! \*******************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ BuilderSettings: () => (/* binding */ BuilderSettings) /* harmony export */ }); /* harmony import */ var lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lpAssetsJsPath/lpToastify.js */ "./assets/src/js/lpToastify.js"); /** * Settings tab JS handler for Course Builder. * * @since 4.3.x * @version 1.2.0 */ class BuilderSettings { constructor() { this.form = null; this.debounceTimer = null; this.debounceDelay = 600; this.isSaving = false; this.isDirty = false; this.shouldRetryOnCompleted = false; this.lastSavedState = ''; this.mediaUploader = null; this.init(); } static selectors = { elForm: '#lp-cb-settings-form', elCheckbox: 'input[name="hide_instructor_access_admin_screen"]', elBadge: '[data-setting-badge]', elHeaderLogoLink: '.lp-cb-top-header__logo a', elLogoSetting: '[data-cb-logo-setting]', elDefaultLogoTemplate: '#lp-cb-default-logo-template', elLogoPreviewDefault: '[data-cb-logo-preview-default]', elLogoPreviewImage: '[data-cb-logo-preview-image]', elLogoChooseBtn: '[data-cb-logo-choose]', elLogoRemoveBtn: '[data-cb-logo-remove]', elLogoIdInput: 'input[name="course_builder_logo_id"]', elLogoRemoveInput: 'input[name="course_builder_logo_remove"]' }; init() { this.form = document.querySelector(BuilderSettings.selectors.elForm); if (!this.form) { return; } this.cacheElements(); this.updateBadge(this.getCurrentValue()); this.hydrateDefaultLogoPreview(); this.setLogoVisibility(this.getLogoId() > 0); this.lastSavedState = this.getStateFingerprint(); this.events(); } cacheElements() { this.headerLogoLink = document.querySelector(BuilderSettings.selectors.elHeaderLogoLink); this.logoSetting = this.form?.querySelector(BuilderSettings.selectors.elLogoSetting); this.logoPreviewDefault = this.form?.querySelector(BuilderSettings.selectors.elLogoPreviewDefault); this.logoPreviewImage = this.form?.querySelector(BuilderSettings.selectors.elLogoPreviewImage); this.logoChooseBtn = this.form?.querySelector(BuilderSettings.selectors.elLogoChooseBtn); this.logoRemoveBtn = this.form?.querySelector(BuilderSettings.selectors.elLogoRemoveBtn); this.logoIdInput = this.form?.querySelector(BuilderSettings.selectors.elLogoIdInput); this.logoRemoveInput = this.form?.querySelector(BuilderSettings.selectors.elLogoRemoveInput); this.defaultLogoURL = this.logoSetting?.dataset?.cbDefaultLogoUrl || ''; } events() { if (BuilderSettings._loadedEvents) { return; } BuilderSettings._loadedEvents = true; if (!this.form) { return; } this.form.addEventListener('change', e => { if (e.target.matches(BuilderSettings.selectors.elCheckbox)) { this.handleSettingChange(); } }); if (this.logoChooseBtn) { this.logoChooseBtn.addEventListener('click', e => { e.preventDefault(); this.openLogoMediaUploader(); }); } if (this.logoRemoveBtn) { this.logoRemoveBtn.addEventListener('click', e => { e.preventDefault(); this.removeLogo(); }); } } handleSettingChange() { this.isDirty = true; if (this.isSaving) { this.shouldRetryOnCompleted = true; } this.updateBadge(this.getCurrentValue()); this.queueSave(); } queueSave() { window.clearTimeout(this.debounceTimer); this.debounceTimer = window.setTimeout(() => { this.flushSave(); }, this.debounceDelay); } flushSave() { if (!this.isDirty) { return; } const currentState = this.getStateFingerprint(); if (currentState === this.lastSavedState) { this.isDirty = false; return; } if (this.isSaving) { return; } this.isSaving = true; this.shouldRetryOnCompleted = false; lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_0__.show('Updating settings...', 'info', { duration: 1800 }); window.lpAJAXG.fetchAJAX(this.getPayloadForSave(), { success: response => { if (response?.status !== 'success') { this.handleSaveError(response?.message || 'Could not save changes.'); return; } this.applySaveResponse(response); this.isDirty = false; this.lastSavedState = this.getStateFingerprint(); this.updateBadge(this.getCurrentValue()); lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_0__.show(response?.message || 'Saved', 'success'); }, error: error => { this.handleSaveError(error?.message || error || 'An error occurred.'); }, completed: () => { this.isSaving = false; if (this.shouldRetryOnCompleted) { this.queueSave(); } } }); } getPayloadForSave() { return { action: 'save_global_settings', args: { id_url: 'save-global-settings' }, hide_instructor_access_admin_screen: this.getCurrentValue(), course_builder_logo_id: this.getLogoId(), course_builder_logo_remove: this.getLogoRemoveValue() }; } applySaveResponse(response) { var _data$course_builder_; const data = response?.data || {}; const savedLogoID = parseInt((_data$course_builder_ = data.course_builder_logo_id) !== null && _data$course_builder_ !== void 0 ? _data$course_builder_ : this.getLogoId(), 10) || 0; const savedLogoSrc = data.course_builder_logo_url || ''; if (this.logoIdInput) { this.logoIdInput.value = savedLogoID; } if (this.logoRemoveInput) { this.logoRemoveInput.value = 'no'; } if (savedLogoID > 0 && savedLogoSrc) { this.setLogoImageSource(savedLogoSrc); this.setLogoVisibility(true); } else if (savedLogoID === 0) { this.clearLogoUI(); } this.syncHeaderLogo(savedLogoID > 0 ? savedLogoSrc : ''); } handleSaveError(message) { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_0__.show(message, 'error'); } getCurrentValue() { const checkbox = this.form?.querySelector(BuilderSettings.selectors.elCheckbox); return checkbox && checkbox.checked ? 'yes' : 'no'; } updateBadge(value) { const badgeEl = this.form?.querySelector(BuilderSettings.selectors.elBadge); if (!badgeEl) { return; } const isEnabled = value === 'yes'; badgeEl.dataset.state = isEnabled ? 'enabled' : 'disabled'; badgeEl.textContent = isEnabled ? 'Enabled' : 'Disabled'; } getStateFingerprint() { return JSON.stringify({ hide_instructor_access_admin_screen: this.getCurrentValue(), course_builder_logo_id: this.getLogoId(), course_builder_logo_remove: this.getLogoRemoveValue() }); } getLogoId() { return parseInt(this.logoIdInput?.value || '0', 10) || 0; } getLogoRemoveValue() { return this.logoRemoveInput?.value === 'yes' ? 'yes' : 'no'; } openLogoMediaUploader() { if (typeof wp === 'undefined' || typeof wp.media === 'undefined') { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_0__.show('Media library is unavailable.', 'error'); return; } if (this.mediaUploader) { this.mediaUploader.open(); return; } this.mediaUploader = wp.media({ title: 'Select logo image', button: { text: 'Use this image' }, multiple: false, library: { type: 'image' } }); this.mediaUploader.on('select', () => { const attachment = this.mediaUploader.state().get('selection').first().toJSON(); const imageURL = attachment?.sizes?.full?.url || attachment?.url || ''; if (!imageURL) { return; } if (this.logoIdInput) { this.logoIdInput.value = attachment?.id || 0; } if (this.logoRemoveInput) { this.logoRemoveInput.value = 'no'; } this.setLogoImageSource(imageURL); this.setLogoVisibility(true); this.handleSettingChange(); }); this.mediaUploader.open(); } setLogoImageSource(source) { if (this.logoPreviewImage) { if (source) { this.logoPreviewImage.src = source; } else { this.logoPreviewImage.removeAttribute('src'); } } } setLogoVisibility(visible) { if (this.logoPreviewImage) { this.logoPreviewImage.classList.toggle('is-hidden', !visible); } if (this.logoPreviewDefault) { this.logoPreviewDefault.classList.toggle('is-hidden', visible); } if (this.logoRemoveBtn) { this.logoRemoveBtn.classList.toggle('is-hidden', !visible); } } hydrateDefaultLogoPreview() { if (!this.logoPreviewDefault || this.logoPreviewDefault.children.length > 0) { return; } const defaultLogoTemplate = document.querySelector(BuilderSettings.selectors.elDefaultLogoTemplate); const defaultLogoSVG = defaultLogoTemplate?.content?.querySelector('svg') || defaultLogoTemplate?.querySelector('svg') || document.querySelector('.lp-cb-top-header__logo svg'); if (!defaultLogoSVG && !this.defaultLogoURL) { return; } const svgPreviewImage = document.createElement('img'); svgPreviewImage.classList.add('lp-cb-logo-setting__preview-default-image'); svgPreviewImage.setAttribute('aria-hidden', 'true'); svgPreviewImage.alt = 'Course Builder default logo'; if (defaultLogoSVG) { svgPreviewImage.src = `data:image/svg+xml;charset=UTF-8,${encodeURIComponent(defaultLogoSVG.outerHTML)}`; } else { svgPreviewImage.src = this.defaultLogoURL; } this.logoPreviewDefault.appendChild(svgPreviewImage); } removeLogo() { if (!this.logoIdInput) { return; } this.clearLogoUI(); if (this.logoRemoveInput) { this.logoRemoveInput.value = 'yes'; } this.handleSettingChange(); } clearLogoUI() { if (this.logoPreviewImage) { this.logoPreviewImage.src = ''; } if (this.logoIdInput) { this.logoIdInput.value = 0; } this.setLogoVisibility(false); } syncHeaderLogo(source = '') { if (!this.headerLogoLink) { return; } const logoSource = source || this.defaultLogoURL; if (!logoSource) { return; } let logoImage = this.headerLogoLink.querySelector('.lp-cb-top-header__logo-image'); if (!logoImage) { logoImage = document.createElement('img'); logoImage.classList.add('lp-cb-top-header__logo-image'); logoImage.alt = 'Course Builder'; logoImage.loading = 'eager'; logoImage.decoding = 'async'; this.headerLogoLink.textContent = ''; this.headerLogoLink.appendChild(logoImage); } logoImage.removeAttribute('srcset'); logoImage.removeAttribute('sizes'); logoImage.src = logoSource; } } /***/ }, /***/ "./assets/src/js/frontend/course-builder/swal-icons.js" /*!*************************************************************!*\ !*** ./assets/src/js/frontend/course-builder/swal-icons.js ***! \*************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ SWAL_ICON_DELETE: () => (/* binding */ SWAL_ICON_DELETE), /* harmony export */ SWAL_ICON_DUPLICATE: () => (/* binding */ SWAL_ICON_DUPLICATE), /* harmony export */ SWAL_ICON_TRASH_DRAFT: () => (/* binding */ SWAL_ICON_TRASH_DRAFT) /* harmony export */ }); const SWAL_ICON_TRASH_DRAFT = ``; const SWAL_ICON_DUPLICATE = ``; const SWAL_ICON_DELETE = ``; /***/ }, /***/ "./assets/src/js/lpPopupSelectItemToAdd.js" /*!*************************************************!*\ !*** ./assets/src/js/lpPopupSelectItemToAdd.js ***! \*************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LpPopupSelectItemToAdd: () => (/* binding */ LpPopupSelectItemToAdd) /* harmony export */ }); /* harmony import */ var lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lpAssetsJsPath/utils.js */ "./assets/src/js/utils.js"); /* harmony import */ var lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! lpAssetsJsPath/lpToastify.js */ "./assets/src/js/lpToastify.js"); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! sweetalert2 */ "./node_modules/sweetalert2/dist/sweetalert2.all.js"); /* harmony import */ var sweetalert2__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(sweetalert2__WEBPACK_IMPORTED_MODULE_2__); /** * LearnPress Popup Select Item * * Handles load(search) item from API, show in popup and select item. */ let itemsSelectedData = []; let elPopup; let timeSearchTitleItem; class LpPopupSelectItemToAdd { constructor() { this.init(); } static selectors = { elBtnShowPopupItemsToSelect: '.lp-btn-show-popup-items-to-select', elBtnAddItemsSelected: '.lp-btn-add-items-selected', elBtnCountItemsSelected: '.lp-btn-count-items-selected', elHeaderCountItemSelected: '.header-count-items-selected', elSelectItem: '.lp-select-item', elListItems: '.list-items', elPopupItemsToSelect: '.lp-popup-items-to-select', elSearchTitleItem: '.lp-search-title-item', elBtnBackListItems: '.lp-btn-back-to-select-items', elListItemsWrap: '.list-items-wrap', elListItemsSelected: '.list-items-selected', elItemSelectedClone: '.li-item-selected.clone', elItemSelected: '.li-item-selected', LPTarget: '.lp-target' }; init() { this.events(); } events = () => { if (LpPopupSelectItemToAdd._loadedEvents) { return; } LpPopupSelectItemToAdd._loadedEvents = true; lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('click', [{ selector: LpPopupSelectItemToAdd.selectors.elBtnShowPopupItemsToSelect, callBack: this.showPopupItemsToSelect.name, class: this }, { selector: LpPopupSelectItemToAdd.selectors.elSelectItem, callBack: this.selectItemsFromList.name, class: this }, { selector: LpPopupSelectItemToAdd.selectors.elBtnCountItemsSelected, callBack: this.showItemsSelected.name, class: this }, { selector: LpPopupSelectItemToAdd.selectors.elBtnBackListItems, callBack: this.backToSelectItems.name, class: this }, { selector: LpPopupSelectItemToAdd.selectors.elItemSelected, callBack: this.removeItemSelected.name, class: this }, { selector: '.tabs .tab', callBack: this.chooseTabItemsType.name, class: this }]); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.eventHandlers('keyup', [{ selector: LpPopupSelectItemToAdd.selectors.elSearchTitleItem, callBack: this.searchTitleItemToSelect.name, class: this }]); }; // Show popup items to select showPopupItemsToSelect = args => { const { e, target = false, callBack } = args; const elBtnShowPopupItemsToSelect = target.closest(`${LpPopupSelectItemToAdd.selectors.elBtnShowPopupItemsToSelect}`); if (!elBtnShowPopupItemsToSelect) { return; } // Reset items selected data when opening popup itemsSelectedData = []; const templateId = target.dataset.template || ''; const modalTemplate = document.querySelector(templateId); sweetalert2__WEBPACK_IMPORTED_MODULE_2___default().fire({ html: modalTemplate.innerHTML, showConfirmButton: false, showCloseButton: true, width: '60%', customClass: { popup: 'lp-select-items-popup', htmlContainer: 'lp-select-items-html-container', container: 'lp-select-items-container' }, willOpen: () => { elPopup = sweetalert2__WEBPACK_IMPORTED_MODULE_2___default().getPopup(); const elLPTarget = elPopup.querySelector(`${LpPopupSelectItemToAdd.selectors.LPTarget}`); if (elLPTarget) { const dataSend = window.lpAJAXG.getDataSetCurrent(elLPTarget); dataSend.args.paged = 1; dataSend.args.item_selecting = itemsSelectedData || []; window.lpAJAXG.setDataSetCurrent(elLPTarget, dataSend); window.lpAJAXG.fetchAJAX(dataSend, { success: response => { const { data } = response; const elSkeleton = elPopup.querySelector('.lp-skeleton-animation'); elSkeleton.remove(); elLPTarget.innerHTML = data.content || ''; this.watchItemsSelectedDataChange(); } }); } } }).then(result => { if (result.isDismissed) {} }); }; // Choose tab items type chooseTabItemsType = args => { const { e, target, callBack } = args; const elTabType = target.closest('.tab'); if (!elTabType) { return; } e.preventDefault(); const elTabs = elTabType.closest('.tabs'); if (!elTabs) { return; } const elSelectItemsToAdd = elTabs.closest(`${LpPopupSelectItemToAdd.selectors.elPopupItemsToSelect}`); const elInputSearch = elSelectItemsToAdd.querySelector(`${LpPopupSelectItemToAdd.selectors.elSearchTitleItem}`); const itemType = elTabType.dataset.type; const elTabLis = elTabs.querySelectorAll('.tab'); elTabLis.forEach(elTabLi => { if (elTabLi.classList.contains('active')) { elTabLi.classList.remove('active'); } }); elTabType.classList.add('active'); // Reset search input elInputSearch.value = ''; const elLPTarget = elSelectItemsToAdd.querySelector(`${LpPopupSelectItemToAdd.selectors.LPTarget}`); const dataSend = window.lpAJAXG.getDataSetCurrent(elLPTarget); dataSend.args.item_type = itemType; dataSend.args.paged = 1; dataSend.args.item_selecting = itemsSelectedData || []; window.lpAJAXG.setDataSetCurrent(elLPTarget, dataSend); window.lpAJAXG.showHideLoading(elLPTarget, 1); window.lpAJAXG.fetchAJAX(dataSend, { success: response => { const { data } = response; elLPTarget.innerHTML = data.content || ''; }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error, 'error'); }, completed: () => { window.lpAJAXG.showHideLoading(elLPTarget, 0); this.watchItemsSelectedDataChange(); } }); }; // Choice items to add list items selected before adding to section selectItemsFromList = args => { const { e, target } = args; const elItemAttend = target.closest(`${LpPopupSelectItemToAdd.selectors.elSelectItem}`); if (!elItemAttend) { return; } const elInput = elItemAttend.querySelector('input[type="checkbox"]'); if (target.tagName !== 'INPUT') { elInput.click(); return; } const elUl = elItemAttend.closest(`${LpPopupSelectItemToAdd.selectors.elListItems}`); if (!elUl) { return; } const itemSelected = { ...elInput.dataset }; //console.log( 'itemSelected', itemSelected ); if (elInput.checked) { const exists = itemsSelectedData.some(item => item.id === itemSelected.id); if (!exists) { itemsSelectedData.push(itemSelected); } } else { const index = itemsSelectedData.findIndex(item => item.id === itemSelected.id); if (index !== -1) { itemsSelectedData.splice(index, 1); } } this.watchItemsSelectedDataChange(); }; // Search title item searchTitleItemToSelect = args => { const { e, target } = args; const elInputSearch = target.closest(LpPopupSelectItemToAdd.selectors.elSearchTitleItem); if (!elInputSearch) { return; } const elLPTarget = elPopup.querySelector(`${LpPopupSelectItemToAdd.selectors.LPTarget}`); clearTimeout(timeSearchTitleItem); timeSearchTitleItem = setTimeout(() => { const dataSet = window.lpAJAXG.getDataSetCurrent(elLPTarget); dataSet.args.search_title = elInputSearch.value.trim(); dataSet.args.item_selecting = itemsSelectedData; dataSet.args.paged = 1; window.lpAJAXG.setDataSetCurrent(elLPTarget, dataSet); // Show loading window.lpAJAXG.showHideLoading(elLPTarget, 1); window.lpAJAXG.fetchAJAX(dataSet, { success: response => { const { data } = response; elLPTarget.innerHTML = data.content || ''; }, error: error => { lpAssetsJsPath_lpToastify_js__WEBPACK_IMPORTED_MODULE_1__.show(error, 'error'); }, completed: () => { window.lpAJAXG.showHideLoading(elLPTarget, 0); } }); }, 800); }; // Show list of items, to choose items to add to section showItemsSelected = args => { const { e, target } = args; const elBtnCountItemsSelected = target.closest(`${LpPopupSelectItemToAdd.selectors.elBtnCountItemsSelected}`); if (!elBtnCountItemsSelected) { return; } const elBtnBack = elPopup.querySelector(`${LpPopupSelectItemToAdd.selectors.elBtnBackListItems}`); const elTabs = elPopup.querySelector('.tabs'); const elListItemsWrap = elPopup.querySelector(`${LpPopupSelectItemToAdd.selectors.elListItemsWrap}`); const elHeaderItemsSelected = elPopup.querySelector(`${LpPopupSelectItemToAdd.selectors.elHeaderCountItemSelected}`); const elListItemsSelected = elPopup.querySelector(`${LpPopupSelectItemToAdd.selectors.elListItemsSelected}`); const elItemClone = elListItemsSelected.querySelector(`${LpPopupSelectItemToAdd.selectors.elItemSelectedClone}`); elHeaderItemsSelected.innerHTML = elBtnCountItemsSelected.innerHTML; lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(elListItemsWrap, 0); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(elBtnCountItemsSelected, 0); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(elTabs, 0); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(elBtnBack, 1); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(elHeaderItemsSelected, 1); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(elListItemsSelected, 1); elListItemsSelected.querySelectorAll(`${LpPopupSelectItemToAdd.selectors.elItemSelected}:not(.clone)`).forEach(elItem => { elItem.remove(); }); itemsSelectedData.forEach(item => { const elItemSelected = elItemClone.cloneNode(true); elItemSelected.classList.remove('clone'); Object.entries(item).forEach(([key, value]) => { elItemSelected.dataset[key] = value; }); const elTitleDisplay = elItemSelected.querySelector('.title-display'); elTitleDisplay.innerHTML = item.title; lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(elItemSelected, 1); elItemClone.insertAdjacentElement('beforebegin', elItemSelected); }); }; // Back to list of items backToSelectItems = args => { const { e, target } = args; const elBtnBack = target.closest(`${LpPopupSelectItemToAdd.selectors.elBtnBackListItems}`); if (!elBtnBack) { return; } const elBtnCountItemsSelected = elPopup.querySelector(`${LpPopupSelectItemToAdd.selectors.elBtnCountItemsSelected}`); const elTabs = elPopup.querySelector('.tabs'); const elListItemsWrap = elPopup.querySelector(`${LpPopupSelectItemToAdd.selectors.elListItemsWrap}`); const elHeaderCountItemSelected = elPopup.querySelector(`${LpPopupSelectItemToAdd.selectors.elHeaderCountItemSelected}`); const elListItemsSelected = elPopup.querySelector(`${LpPopupSelectItemToAdd.selectors.elListItemsSelected}`); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(elBtnCountItemsSelected, 1); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(elListItemsWrap, 1); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(elTabs, 1); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(elBtnBack, 0); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(elHeaderCountItemSelected, 0); lpAssetsJsPath_utils_js__WEBPACK_IMPORTED_MODULE_0__.lpShowHideEl(elListItemsSelected, 0); }; // Remove item selected from list items selected removeItemSelected = args => { const { e, target } = args; const elRemoveItemSelected = target.closest(`${LpPopupSelectItemToAdd.selectors.elItemSelected}`); if (!elRemoveItemSelected) { return; } const itemRemove = elRemoveItemSelected.dataset; const index = itemsSelectedData.findIndex(item => item.id === itemRemove.id); if (index !== -1) { itemsSelectedData.splice(index, 1); } elRemoveItemSelected.remove(); this.watchItemsSelectedDataChange(); }; // Watch items selected when data change watchItemsSelectedDataChange = () => { // Update count items selected, disable/enable buttons const elBtnAddItemsSelected = elPopup.querySelector(`${LpPopupSelectItemToAdd.selectors.elBtnAddItemsSelected}`); const elBtnCountItemsSelected = elPopup.querySelector(`${LpPopupSelectItemToAdd.selectors.elBtnCountItemsSelected}`); const elSpanCount = elBtnCountItemsSelected.querySelector('span'); const elHeaderCount = elPopup.querySelector(`${LpPopupSelectItemToAdd.selectors.elHeaderCountItemSelected}`); const elTarget = elPopup.querySelector(`${LpPopupSelectItemToAdd.selectors.LPTarget}`); if (itemsSelectedData.length !== 0) { elBtnCountItemsSelected.disabled = false; elBtnAddItemsSelected.disabled = false; elBtnAddItemsSelected.classList.add('active'); elSpanCount.textContent = `(${itemsSelectedData.length})`; elHeaderCount.innerHTML = elBtnCountItemsSelected.innerHTML; } else { elBtnCountItemsSelected.disabled = true; elBtnAddItemsSelected.disabled = true; elBtnAddItemsSelected.classList.remove('active'); elSpanCount.textContent = ''; elHeaderCount.textContent = ''; } // Update list input checked, when items removed, or change tab type const elListItems = elPopup.querySelector(`${LpPopupSelectItemToAdd.selectors.elListItems}`); const elInputs = elListItems.querySelectorAll('input[type="checkbox"]'); elInputs.forEach(elInputItem => { const itemSelected = elInputItem.dataset; const exists = itemsSelectedData.some(item => item.id === itemSelected.id); elInputItem.checked = exists; }); // Set item selecting data to dataset for query. const dataSet = window.lpAJAXG.getDataSetCurrent(elTarget); dataSet.args.item_selecting = itemsSelectedData; window.lpAJAXG.setDataSetCurrent(elTarget, dataSet); }; // Add items selected to section addItemsSelectedToSection = args => { const { e, target, callBackHandle } = args; if (!elPopup) { return; } sweetalert2__WEBPACK_IMPORTED_MODULE_2___default().close(); if (typeof callBackHandle === 'function') { callBackHandle(itemsSelectedData); itemsSelectedData = []; } }; } /***/ }, /***/ "./assets/src/js/lpToastify.js" /*!*************************************!*\ !*** ./assets/src/js/lpToastify.js ***! \*************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ show: () => (/* binding */ show) /* harmony export */ }); /* harmony import */ var toastify_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! toastify-js */ "./node_modules/toastify-js/src/toastify.js"); /* harmony import */ var toastify_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(toastify_js__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var toastify_js_src_toastify_css__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! toastify-js/src/toastify.css */ "./node_modules/toastify-js/src/toastify.css"); /** * Utils functions * * @param url * @param data * @param functions * @since 4.3.0 * @version 1.0.0 */ const argsToastify = { text: '', gravity: lpData.toast.gravity, // `top` or `bottom` position: lpData.toast.position, // `left`, `center` or `right` className: `${lpData.toast.classPrefix}`, close: lpData.toast.close == 1, stopOnFocus: lpData.toast.stopOnFocus == 1, duration: lpData.toast.duration }; const show = (message, status = 'success', argsCustom) => { let args = argsToastify; if (argsCustom) { args = { ...args, ...argsCustom }; } const toastify = new (toastify_js__WEBPACK_IMPORTED_MODULE_0___default())({ ...args, text: message, className: `${lpData.toast.classPrefix} ${status}` }); toastify.showToast(); }; /***/ }, /***/ "./assets/src/js/utils.js" /*!********************************!*\ !*** ./assets/src/js/utils.js ***! \********************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ debounce: () => (/* binding */ debounce), /* harmony export */ eventHandlers: () => (/* binding */ eventHandlers), /* harmony export */ getDataOfForm: () => (/* binding */ getDataOfForm), /* harmony export */ getFieldKeysOfForm: () => (/* binding */ getFieldKeysOfForm), /* harmony export */ listenElementCreated: () => (/* binding */ listenElementCreated), /* harmony export */ listenElementViewed: () => (/* binding */ listenElementViewed), /* harmony export */ lpAddQueryArgs: () => (/* binding */ lpAddQueryArgs), /* harmony export */ lpAjaxParseJsonOld: () => (/* binding */ lpAjaxParseJsonOld), /* harmony export */ lpClassName: () => (/* binding */ lpClassName), /* harmony export */ lpFetchAPI: () => (/* binding */ lpFetchAPI), /* harmony export */ lpGetCurrentURLNoParam: () => (/* binding */ lpGetCurrentURLNoParam), /* harmony export */ lpOnElementReady: () => (/* binding */ lpOnElementReady), /* harmony export */ lpSetLoadingEl: () => (/* binding */ lpSetLoadingEl), /* harmony export */ lpShowHideEl: () => (/* binding */ lpShowHideEl), /* harmony export */ mergeDataWithDatForm: () => (/* binding */ mergeDataWithDatForm), /* harmony export */ toggleCollapse: () => (/* binding */ toggleCollapse) /* harmony export */ }); /** * Utils functions * * @param url * @param data * @param functions * @since 4.2.5.1 * @version 1.0.6 */ const lpClassName = { hidden: 'lp-hidden', loading: 'loading', elCollapse: 'lp-collapse', elSectionToggle: '.lp-section-toggle', elTriggerToggle: '.lp-trigger-toggle' }; const lpFetchAPI = (url, data = {}, functions = {}) => { if ('function' === typeof functions.before) { functions.before(); } fetch(url, { method: 'GET', ...data }).then(response => response.json()).then(response => { if ('function' === typeof functions.success) { functions.success(response); } }).catch(err => { if ('function' === typeof functions.error) { functions.error(err); } }).finally(() => { if ('function' === typeof functions.completed) { functions.completed(); } }); }; /** * Get current URL without params. * * @since 4.2.5.1 */ const lpGetCurrentURLNoParam = () => { let currentUrl = window.location.href; const hasParams = currentUrl.includes('?'); if (hasParams) { currentUrl = currentUrl.split('?')[0]; } return currentUrl; }; const lpAddQueryArgs = (endpoint, args) => { const url = new URL(endpoint); Object.keys(args).forEach(arg => { url.searchParams.set(arg, args[arg]); }); return url; }; /** * Listen element viewed. * * @param el * @param callback * @since 4.2.5.8 */ const listenElementViewed = (el, callback) => { const observerSeeItem = new IntersectionObserver(function (entries) { for (const entry of entries) { if (entry.isIntersecting) { callback(entry); } } }); observerSeeItem.observe(el); }; /** * Listen element created. * * @param callback * @since 4.2.5.8 */ const listenElementCreated = callback => { const observerCreateItem = new MutationObserver(function (mutations) { mutations.forEach(function (mutation) { if (mutation.addedNodes) { mutation.addedNodes.forEach(function (node) { if (node.nodeType === 1) { callback(node); } }); } }); }); observerCreateItem.observe(document, { childList: true, subtree: true }); // End. }; /** * Listen element created. * * @param selector * @param callback * @since 4.2.7.1 */ const lpOnElementReady = (selector, callback) => { const element = document.querySelector(selector); if (element) { callback(element); return; } const observer = new MutationObserver((mutations, obs) => { const element = document.querySelector(selector); if (element) { obs.disconnect(); callback(element); } }); observer.observe(document.documentElement, { childList: true, subtree: true }); }; // Parse JSON from string with content include LP_AJAX_START. const lpAjaxParseJsonOld = data => { if (typeof data !== 'string') { return data; } const m = String.raw({ raw: data }).match(/<-- LP_AJAX_START -->(.*)<-- LP_AJAX_END -->/s); try { if (m) { data = JSON.parse(m[1].replace(/(?:\r\n|\r|\n)/g, '')); } else { data = JSON.parse(data); } } catch (e) { data = {}; } return data; }; // status 0: hide, 1: show const lpShowHideEl = (el, status = 0) => { if (!el) { return; } if (!status) { el.classList.add(lpClassName.hidden); } else { el.classList.remove(lpClassName.hidden); } }; // status 0: hide, 1: show const lpSetLoadingEl = (el, status) => { if (!el) { return; } if (!status) { el.classList.remove(lpClassName.loading); } else { el.classList.add(lpClassName.loading); } }; // Toggle collapse section const toggleCollapse = (e, target, elTriggerClassName = '', elsExclude = [], callback) => { if (!elTriggerClassName) { elTriggerClassName = lpClassName.elTriggerToggle; } // Exclude elements, which should not trigger the collapse toggle if (elsExclude && elsExclude.length > 0) { for (const elExclude of elsExclude) { if (target.closest(elExclude)) { return; } } } const elTrigger = target.closest(elTriggerClassName); if (!elTrigger) { return; } //console.log( 'elTrigger', elTrigger ); const elSectionToggle = elTrigger.closest(`${lpClassName.elSectionToggle}`); if (!elSectionToggle) { return; } elSectionToggle.classList.toggle(`${lpClassName.elCollapse}`); if ('function' === typeof callback) { callback(elSectionToggle); } }; // Get data of form const getDataOfForm = form => { const dataSend = {}; const formData = new FormData(form); for (const pair of formData.entries()) { const key = pair[0]; const value = formData.getAll(key); if (!dataSend.hasOwnProperty(key)) { // Convert value array to string. dataSend[key] = value.join(','); } } return dataSend; }; // Get field keys of form const getFieldKeysOfForm = form => { const keys = []; const elements = form.elements; for (let i = 0; i < elements.length; i++) { const name = elements[i].name; if (name && !keys.includes(name)) { keys.push(name); } } return keys; }; // Merge data handle with data form. const mergeDataWithDatForm = (elForm, dataHandle) => { const dataForm = getDataOfForm(elForm); const keys = getFieldKeysOfForm(elForm); keys.forEach(key => { if (!dataForm.hasOwnProperty(key)) { delete dataHandle[key]; } else if (dataForm[key][0] === '') { delete dataForm[key]; delete dataHandle[key]; } }); dataHandle = { ...dataHandle, ...dataForm }; return dataHandle; }; /** * Event trigger * For each list of event handlers, listen event on document. * * eventName: 'click', 'change', ... * eventHandlers = [ { selector: '.lp-button', callBack: function(){}, class: object } ] * * @param eventName * @param eventHandlers */ const eventHandlers = (eventName, eventHandlers) => { document.addEventListener(eventName, e => { const target = e.target; let args = { e, target }; eventHandlers.forEach(eventHandler => { args = { ...args, ...eventHandler }; //console.log( args ); // Check condition before call back if (eventHandler.conditionBeforeCallBack) { if (eventHandler.conditionBeforeCallBack(args) !== true) { return; } } // Special check for keydown event with checkIsEventEnter = true if (eventName === 'keydown' && eventHandler.checkIsEventEnter) { if (e.key !== 'Enter') { return; } } if (target.closest(eventHandler.selector)) { if (eventHandler.class) { // Call method of class, function callBack will understand exactly {this} is class object. eventHandler.class[eventHandler.callBack](args); } else { // For send args is objected, {this} is eventHandler object, not class object. eventHandler.callBack(args); } } }); }); }; /** * Debounce - delays function execution until after `wait` ms of inactivity. * * Each call resets the timer. Only the last call in a burst executes. * * USE CASES: * - Search inputs, form validation, window resize * - Multiple elements need independent timers * - When you need to call with different arguments * * EXAMPLES: * const debouncedSearch = debounce( (query) => fetchResults(query), 300 ); * searchInput.addEventListener('input', (e) => debouncedSearch(e.target.value)); * * const debouncedResize = debounce( recalculateLayout, 250 ); * window.addEventListener('resize', debouncedResize); * * ⚠️ Create ONCE outside event handlers, not inside. * * @param {Function} func - Function to debounce (can be anonymous) * @param {number} wait - Milliseconds to wait (default: 500) * @return {Function} Debounced wrapper function * @since 4.3.7 * @version 1.0.0 */ const debounce = (func, wait = 500) => { let timer; return args => { clearTimeout(timer); timer = setTimeout(() => func(args), wait); }; }; /***/ }, /***/ "./node_modules/css-loader/dist/cjs.js!./node_modules/toastify-js/src/toastify.css" /*!*****************************************************************************************!*\ !*** ./node_modules/css-loader/dist/cjs.js!./node_modules/toastify-js/src/toastify.css ***! \*****************************************************************************************/ (module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var _css_loader_dist_runtime_sourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../css-loader/dist/runtime/sourceMaps.js */ "./node_modules/css-loader/dist/runtime/sourceMaps.js"); /* harmony import */ var _css_loader_dist_runtime_sourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_css_loader_dist_runtime_sourceMaps_js__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../css-loader/dist/runtime/api.js */ "./node_modules/css-loader/dist/runtime/api.js"); /* harmony import */ var _css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__); // Imports var ___CSS_LOADER_EXPORT___ = _css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_css_loader_dist_runtime_sourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default())); // Module ___CSS_LOADER_EXPORT___.push([module.id, `/*! * Toastify js 1.12.0 * https://github.com/apvarun/toastify-js * @license MIT licensed * * Copyright (C) 2018 Varun A P */ .toastify { padding: 12px 20px; color: #ffffff; display: inline-block; box-shadow: 0 3px 6px -1px rgba(0, 0, 0, 0.12), 0 10px 36px -4px rgba(77, 96, 232, 0.3); background: -webkit-linear-gradient(315deg, #73a5ff, #5477f5); background: linear-gradient(135deg, #73a5ff, #5477f5); position: fixed; opacity: 0; transition: all 0.4s cubic-bezier(0.215, 0.61, 0.355, 1); border-radius: 2px; cursor: pointer; text-decoration: none; max-width: calc(50% - 20px); z-index: 2147483647; } .toastify.on { opacity: 1; } .toast-close { background: transparent; border: 0; color: white; cursor: pointer; font-family: inherit; font-size: 1em; opacity: 0.4; padding: 0 5px; } .toastify-right { right: 15px; } .toastify-left { left: 15px; } .toastify-top { top: -150px; } .toastify-bottom { bottom: -150px; } .toastify-rounded { border-radius: 25px; } .toastify-avatar { width: 1.5em; height: 1.5em; margin: -7px 5px; border-radius: 2px; } .toastify-center { margin-left: auto; margin-right: auto; left: 0; right: 0; max-width: fit-content; max-width: -moz-fit-content; } @media only screen and (max-width: 360px) { .toastify-right, .toastify-left { margin-left: auto; margin-right: auto; left: 0; right: 0; max-width: fit-content; } } `, "",{"version":3,"sources":["webpack://./node_modules/toastify-js/src/toastify.css"],"names":[],"mappings":"AAAA;;;;;;EAME;;AAEF;IACI,kBAAkB;IAClB,cAAc;IACd,qBAAqB;IACrB,uFAAuF;IACvF,6DAA6D;IAC7D,qDAAqD;IACrD,eAAe;IACf,UAAU;IACV,wDAAwD;IACxD,kBAAkB;IAClB,eAAe;IACf,qBAAqB;IACrB,2BAA2B;IAC3B,mBAAmB;AACvB;;AAEA;IACI,UAAU;AACd;;AAEA;IACI,uBAAuB;IACvB,SAAS;IACT,YAAY;IACZ,eAAe;IACf,oBAAoB;IACpB,cAAc;IACd,YAAY;IACZ,cAAc;AAClB;;AAEA;IACI,WAAW;AACf;;AAEA;IACI,UAAU;AACd;;AAEA;IACI,WAAW;AACf;;AAEA;IACI,cAAc;AAClB;;AAEA;IACI,mBAAmB;AACvB;;AAEA;IACI,YAAY;IACZ,aAAa;IACb,gBAAgB;IAChB,kBAAkB;AACtB;;AAEA;IACI,iBAAiB;IACjB,kBAAkB;IAClB,OAAO;IACP,QAAQ;IACR,sBAAsB;IACtB,2BAA2B;AAC/B;;AAEA;IACI;QACI,iBAAiB;QACjB,kBAAkB;QAClB,OAAO;QACP,QAAQ;QACR,sBAAsB;IAC1B;AACJ","sourcesContent":["/*!\n * Toastify js 1.12.0\n * https://github.com/apvarun/toastify-js\n * @license MIT licensed\n *\n * Copyright (C) 2018 Varun A P\n */\n\n.toastify {\n padding: 12px 20px;\n color: #ffffff;\n display: inline-block;\n box-shadow: 0 3px 6px -1px rgba(0, 0, 0, 0.12), 0 10px 36px -4px rgba(77, 96, 232, 0.3);\n background: -webkit-linear-gradient(315deg, #73a5ff, #5477f5);\n background: linear-gradient(135deg, #73a5ff, #5477f5);\n position: fixed;\n opacity: 0;\n transition: all 0.4s cubic-bezier(0.215, 0.61, 0.355, 1);\n border-radius: 2px;\n cursor: pointer;\n text-decoration: none;\n max-width: calc(50% - 20px);\n z-index: 2147483647;\n}\n\n.toastify.on {\n opacity: 1;\n}\n\n.toast-close {\n background: transparent;\n border: 0;\n color: white;\n cursor: pointer;\n font-family: inherit;\n font-size: 1em;\n opacity: 0.4;\n padding: 0 5px;\n}\n\n.toastify-right {\n right: 15px;\n}\n\n.toastify-left {\n left: 15px;\n}\n\n.toastify-top {\n top: -150px;\n}\n\n.toastify-bottom {\n bottom: -150px;\n}\n\n.toastify-rounded {\n border-radius: 25px;\n}\n\n.toastify-avatar {\n width: 1.5em;\n height: 1.5em;\n margin: -7px 5px;\n border-radius: 2px;\n}\n\n.toastify-center {\n margin-left: auto;\n margin-right: auto;\n left: 0;\n right: 0;\n max-width: fit-content;\n max-width: -moz-fit-content;\n}\n\n@media only screen and (max-width: 360px) {\n .toastify-right, .toastify-left {\n margin-left: auto;\n margin-right: auto;\n left: 0;\n right: 0;\n max-width: fit-content;\n }\n}\n"],"sourceRoot":""}]); // Exports /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___); /***/ }, /***/ "./node_modules/css-loader/dist/runtime/api.js" /*!*****************************************************!*\ !*** ./node_modules/css-loader/dist/runtime/api.js ***! \*****************************************************/ (module) { "use strict"; /* MIT License http://www.opensource.org/licenses/mit-license.php Author Tobias Koppers @sokra */ module.exports = function (cssWithMappingToString) { var list = []; // return the list of modules as css string list.toString = function toString() { return this.map(function (item) { var content = ""; var needLayer = typeof item[5] !== "undefined"; if (item[4]) { content += "@supports (".concat(item[4], ") {"); } if (item[2]) { content += "@media ".concat(item[2], " {"); } if (needLayer) { content += "@layer".concat(item[5].length > 0 ? " ".concat(item[5]) : "", " {"); } content += cssWithMappingToString(item); if (needLayer) { content += "}"; } if (item[2]) { content += "}"; } if (item[4]) { content += "}"; } return content; }).join(""); }; // import a list of modules into the list list.i = function i(modules, media, dedupe, supports, layer) { if (typeof modules === "string") { modules = [[null, modules, undefined]]; } var alreadyImportedModules = {}; if (dedupe) { for (var k = 0; k < this.length; k++) { var id = this[k][0]; if (id != null) { alreadyImportedModules[id] = true; } } } for (var _k = 0; _k < modules.length; _k++) { var item = [].concat(modules[_k]); if (dedupe && alreadyImportedModules[item[0]]) { continue; } if (typeof layer !== "undefined") { if (typeof item[5] === "undefined") { item[5] = layer; } else { item[1] = "@layer".concat(item[5].length > 0 ? " ".concat(item[5]) : "", " {").concat(item[1], "}"); item[5] = layer; } } if (media) { if (!item[2]) { item[2] = media; } else { item[1] = "@media ".concat(item[2], " {").concat(item[1], "}"); item[2] = media; } } if (supports) { if (!item[4]) { item[4] = "".concat(supports); } else { item[1] = "@supports (".concat(item[4], ") {").concat(item[1], "}"); item[4] = supports; } } list.push(item); } }; return list; }; /***/ }, /***/ "./node_modules/css-loader/dist/runtime/sourceMaps.js" /*!************************************************************!*\ !*** ./node_modules/css-loader/dist/runtime/sourceMaps.js ***! \************************************************************/ (module) { "use strict"; module.exports = function (item) { var content = item[1]; var cssMapping = item[3]; if (!cssMapping) { return content; } if (typeof btoa === "function") { var base64 = btoa(unescape(encodeURIComponent(JSON.stringify(cssMapping)))); var data = "sourceMappingURL=data:application/json;charset=utf-8;base64,".concat(base64); var sourceMapping = "/*# ".concat(data, " */"); return [content].concat([sourceMapping]).join("\n"); } return [content].join("\n"); }; /***/ }, /***/ "./node_modules/sortablejs/modular/sortable.esm.js" /*!*********************************************************!*\ !*** ./node_modules/sortablejs/modular/sortable.esm.js ***! \*********************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ MultiDrag: () => (/* binding */ MultiDragPlugin), /* harmony export */ Sortable: () => (/* binding */ Sortable), /* harmony export */ Swap: () => (/* binding */ SwapPlugin), /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /**! * Sortable 1.15.7 * @author RubaXa * @author owenm * @license MIT */ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread2(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; } function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; } function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); } function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } var version = "1.15.7"; function userAgent(pattern) { if (typeof window !== 'undefined' && window.navigator) { return !! /*@__PURE__*/navigator.userAgent.match(pattern); } } var IE11OrLess = userAgent(/(?:Trident.*rv[ :]?11\.|msie|iemobile|Windows Phone)/i); var Edge = userAgent(/Edge/i); var FireFox = userAgent(/firefox/i); var Safari = userAgent(/safari/i) && !userAgent(/chrome/i) && !userAgent(/android/i); var IOS = userAgent(/iP(ad|od|hone)/i); var ChromeForAndroid = userAgent(/chrome/i) && userAgent(/android/i); var captureMode = { capture: false, passive: false }; function on(el, event, fn) { el.addEventListener(event, fn, !IE11OrLess && captureMode); } function off(el, event, fn) { el.removeEventListener(event, fn, !IE11OrLess && captureMode); } function matches( /**HTMLElement*/el, /**String*/selector) { if (!selector) return; selector[0] === '>' && (selector = selector.substring(1)); if (el) { try { if (el.matches) { return el.matches(selector); } else if (el.msMatchesSelector) { return el.msMatchesSelector(selector); } else if (el.webkitMatchesSelector) { return el.webkitMatchesSelector(selector); } } catch (_) { return false; } } return false; } function getParentOrHost(el) { return el.host && el !== document && el.host.nodeType && el.host !== el ? el.host : el.parentNode; } function closest( /**HTMLElement*/el, /**String*/selector, /**HTMLElement*/ctx, includeCTX) { if (el) { ctx = ctx || document; do { if (selector != null && (selector[0] === '>' ? el.parentNode === ctx && matches(el, selector) : matches(el, selector)) || includeCTX && el === ctx) { return el; } if (el === ctx) break; /* jshint boss:true */ } while (el = getParentOrHost(el)); } return null; } var R_SPACE = /\s+/g; function toggleClass(el, name, state) { if (el && name) { if (el.classList) { el.classList[state ? 'add' : 'remove'](name); } else { var className = (' ' + el.className + ' ').replace(R_SPACE, ' ').replace(' ' + name + ' ', ' '); el.className = (className + (state ? ' ' + name : '')).replace(R_SPACE, ' '); } } } function css(el, prop, val) { var style = el && el.style; if (style) { if (val === void 0) { if (document.defaultView && document.defaultView.getComputedStyle) { val = document.defaultView.getComputedStyle(el, ''); } else if (el.currentStyle) { val = el.currentStyle; } return prop === void 0 ? val : val[prop]; } else { if (!(prop in style) && prop.indexOf('webkit') === -1) { prop = '-webkit-' + prop; } style[prop] = val + (typeof val === 'string' ? '' : 'px'); } } } function matrix(el, selfOnly) { var appliedTransforms = ''; if (typeof el === 'string') { appliedTransforms = el; } else { do { var transform = css(el, 'transform'); if (transform && transform !== 'none') { appliedTransforms = transform + ' ' + appliedTransforms; } /* jshint boss:true */ } while (!selfOnly && (el = el.parentNode)); } var matrixFn = window.DOMMatrix || window.WebKitCSSMatrix || window.CSSMatrix || window.MSCSSMatrix; /*jshint -W056 */ return matrixFn && new matrixFn(appliedTransforms); } function find(ctx, tagName, iterator) { if (ctx) { var list = ctx.getElementsByTagName(tagName), i = 0, n = list.length; if (iterator) { for (; i < n; i++) { iterator(list[i], i); } } return list; } return []; } function getWindowScrollingElement() { var scrollingElement = document.scrollingElement; if (scrollingElement) { return scrollingElement; } else { return document.documentElement; } } /** * Returns the "bounding client rect" of given element * @param {HTMLElement} el The element whose boundingClientRect is wanted * @param {[Boolean]} relativeToContainingBlock Whether the rect should be relative to the containing block of (including) the container * @param {[Boolean]} relativeToNonStaticParent Whether the rect should be relative to the relative parent of (including) the contaienr * @param {[Boolean]} undoScale Whether the container's scale() should be undone * @param {[HTMLElement]} container The parent the element will be placed in * @return {Object} The boundingClientRect of el, with specified adjustments */ function getRect(el, relativeToContainingBlock, relativeToNonStaticParent, undoScale, container) { if (!el.getBoundingClientRect && el !== window) return; var elRect, top, left, bottom, right, height, width; if (el !== window && el.parentNode && el !== getWindowScrollingElement()) { elRect = el.getBoundingClientRect(); top = elRect.top; left = elRect.left; bottom = elRect.bottom; right = elRect.right; height = elRect.height; width = elRect.width; } else { top = 0; left = 0; bottom = window.innerHeight; right = window.innerWidth; height = window.innerHeight; width = window.innerWidth; } if ((relativeToContainingBlock || relativeToNonStaticParent) && el !== window) { // Adjust for translate() container = container || el.parentNode; // solves #1123 (see: https://stackoverflow.com/a/37953806/6088312) // Not needed on <= IE11 if (!IE11OrLess) { do { if (container && container.getBoundingClientRect && (css(container, 'transform') !== 'none' || relativeToNonStaticParent && css(container, 'position') !== 'static')) { var containerRect = container.getBoundingClientRect(); // Set relative to edges of padding box of container top -= containerRect.top + parseInt(css(container, 'border-top-width')); left -= containerRect.left + parseInt(css(container, 'border-left-width')); bottom = top + elRect.height; right = left + elRect.width; break; } /* jshint boss:true */ } while (container = container.parentNode); } } if (undoScale && el !== window) { // Adjust for scale() var elMatrix = matrix(container || el), scaleX = elMatrix && elMatrix.a, scaleY = elMatrix && elMatrix.d; if (elMatrix) { top /= scaleY; left /= scaleX; width /= scaleX; height /= scaleY; bottom = top + height; right = left + width; } } return { top: top, left: left, bottom: bottom, right: right, width: width, height: height }; } /** * Checks if a side of an element is scrolled past a side of its parents * @param {HTMLElement} el The element who's side being scrolled out of view is in question * @param {String} elSide Side of the element in question ('top', 'left', 'right', 'bottom') * @param {String} parentSide Side of the parent in question ('top', 'left', 'right', 'bottom') * @return {HTMLElement} The parent scroll element that the el's side is scrolled past, or null if there is no such element */ function isScrolledPast(el, elSide, parentSide) { var parent = getParentAutoScrollElement(el, true), elSideVal = getRect(el)[elSide]; /* jshint boss:true */ while (parent) { var parentSideVal = getRect(parent)[parentSide], visible = void 0; if (parentSide === 'top' || parentSide === 'left') { visible = elSideVal >= parentSideVal; } else { visible = elSideVal <= parentSideVal; } if (!visible) return parent; if (parent === getWindowScrollingElement()) break; parent = getParentAutoScrollElement(parent, false); } return false; } /** * Gets nth child of el, ignoring hidden children, sortable's elements (does not ignore clone if it's visible) * and non-draggable elements * @param {HTMLElement} el The parent element * @param {Number} childNum The index of the child * @param {Object} options Parent Sortable's options * @return {HTMLElement} The child at index childNum, or null if not found */ function getChild(el, childNum, options, includeDragEl) { var currentChild = 0, i = 0, children = el.children; while (i < children.length) { if (children[i].style.display !== 'none' && children[i] !== Sortable.ghost && (includeDragEl || children[i] !== Sortable.dragged) && closest(children[i], options.draggable, el, false)) { if (currentChild === childNum) { return children[i]; } currentChild++; } i++; } return null; } /** * Gets the last child in the el, ignoring ghostEl or invisible elements (clones) * @param {HTMLElement} el Parent element * @param {selector} selector Any other elements that should be ignored * @return {HTMLElement} The last child, ignoring ghostEl */ function lastChild(el, selector) { var last = el.lastElementChild; while (last && (last === Sortable.ghost || css(last, 'display') === 'none' || selector && !matches(last, selector))) { last = last.previousElementSibling; } return last || null; } /** * Returns the index of an element within its parent for a selected set of * elements * @param {HTMLElement} el * @param {selector} selector * @return {number} */ function index(el, selector) { var index = 0; if (!el || !el.parentNode) { return -1; } /* jshint boss:true */ while (el = el.previousElementSibling) { if (el.nodeName.toUpperCase() !== 'TEMPLATE' && el !== Sortable.clone && (!selector || matches(el, selector))) { index++; } } return index; } /** * Returns the scroll offset of the given element, added with all the scroll offsets of parent elements. * The value is returned in real pixels. * @param {HTMLElement} el * @return {Array} Offsets in the format of [left, top] */ function getRelativeScrollOffset(el) { var offsetLeft = 0, offsetTop = 0, winScroller = getWindowScrollingElement(); if (el) { do { var elMatrix = matrix(el), scaleX = elMatrix.a, scaleY = elMatrix.d; offsetLeft += el.scrollLeft * scaleX; offsetTop += el.scrollTop * scaleY; } while (el !== winScroller && (el = el.parentNode)); } return [offsetLeft, offsetTop]; } /** * Returns the index of the object within the given array * @param {Array} arr Array that may or may not hold the object * @param {Object} obj An object that has a key-value pair unique to and identical to a key-value pair in the object you want to find * @return {Number} The index of the object in the array, or -1 */ function indexOfObject(arr, obj) { for (var i in arr) { if (!arr.hasOwnProperty(i)) continue; for (var key in obj) { if (obj.hasOwnProperty(key) && obj[key] === arr[i][key]) return Number(i); } } return -1; } function getParentAutoScrollElement(el, includeSelf) { // skip to window if (!el || !el.getBoundingClientRect) return getWindowScrollingElement(); var elem = el; var gotSelf = false; do { // we don't need to get elem css if it isn't even overflowing in the first place (performance) if (elem.clientWidth < elem.scrollWidth || elem.clientHeight < elem.scrollHeight) { var elemCSS = css(elem); if (elem.clientWidth < elem.scrollWidth && (elemCSS.overflowX == 'auto' || elemCSS.overflowX == 'scroll') || elem.clientHeight < elem.scrollHeight && (elemCSS.overflowY == 'auto' || elemCSS.overflowY == 'scroll')) { if (!elem.getBoundingClientRect || elem === document.body) return getWindowScrollingElement(); if (gotSelf || includeSelf) return elem; gotSelf = true; } } /* jshint boss:true */ } while (elem = elem.parentNode); return getWindowScrollingElement(); } function extend(dst, src) { if (dst && src) { for (var key in src) { if (src.hasOwnProperty(key)) { dst[key] = src[key]; } } } return dst; } function isRectEqual(rect1, rect2) { return Math.round(rect1.top) === Math.round(rect2.top) && Math.round(rect1.left) === Math.round(rect2.left) && Math.round(rect1.height) === Math.round(rect2.height) && Math.round(rect1.width) === Math.round(rect2.width); } var _throttleTimeout; function throttle(callback, ms) { return function () { if (!_throttleTimeout) { var args = arguments, _this = this; if (args.length === 1) { callback.call(_this, args[0]); } else { callback.apply(_this, args); } _throttleTimeout = setTimeout(function () { _throttleTimeout = void 0; }, ms); } }; } function cancelThrottle() { clearTimeout(_throttleTimeout); _throttleTimeout = void 0; } function scrollBy(el, x, y) { el.scrollLeft += x; el.scrollTop += y; } function clone(el) { var Polymer = window.Polymer; var $ = window.jQuery || window.Zepto; if (Polymer && Polymer.dom) { return Polymer.dom(el).cloneNode(true); } else if ($) { return $(el).clone(true)[0]; } else { return el.cloneNode(true); } } function setRect(el, rect) { css(el, 'position', 'absolute'); css(el, 'top', rect.top); css(el, 'left', rect.left); css(el, 'width', rect.width); css(el, 'height', rect.height); } function unsetRect(el) { css(el, 'position', ''); css(el, 'top', ''); css(el, 'left', ''); css(el, 'width', ''); css(el, 'height', ''); } function getChildContainingRectFromElement(container, options, ghostEl) { var rect = {}; Array.from(container.children).forEach(function (child) { var _rect$left, _rect$top, _rect$right, _rect$bottom; if (!closest(child, options.draggable, container, false) || child.animated || child === ghostEl) return; var childRect = getRect(child); rect.left = Math.min((_rect$left = rect.left) !== null && _rect$left !== void 0 ? _rect$left : Infinity, childRect.left); rect.top = Math.min((_rect$top = rect.top) !== null && _rect$top !== void 0 ? _rect$top : Infinity, childRect.top); rect.right = Math.max((_rect$right = rect.right) !== null && _rect$right !== void 0 ? _rect$right : -Infinity, childRect.right); rect.bottom = Math.max((_rect$bottom = rect.bottom) !== null && _rect$bottom !== void 0 ? _rect$bottom : -Infinity, childRect.bottom); }); rect.width = rect.right - rect.left; rect.height = rect.bottom - rect.top; rect.x = rect.left; rect.y = rect.top; return rect; } var expando = 'Sortable' + new Date().getTime(); function AnimationStateManager() { var animationStates = [], animationCallbackId; return { captureAnimationState: function captureAnimationState() { animationStates = []; if (!this.options.animation) return; var children = [].slice.call(this.el.children); children.forEach(function (child) { if (css(child, 'display') === 'none' || child === Sortable.ghost) return; animationStates.push({ target: child, rect: getRect(child) }); var fromRect = _objectSpread2({}, animationStates[animationStates.length - 1].rect); // If animating: compensate for current animation if (child.thisAnimationDuration) { var childMatrix = matrix(child, true); if (childMatrix) { fromRect.top -= childMatrix.f; fromRect.left -= childMatrix.e; } } child.fromRect = fromRect; }); }, addAnimationState: function addAnimationState(state) { animationStates.push(state); }, removeAnimationState: function removeAnimationState(target) { animationStates.splice(indexOfObject(animationStates, { target: target }), 1); }, animateAll: function animateAll(callback) { var _this = this; if (!this.options.animation) { clearTimeout(animationCallbackId); if (typeof callback === 'function') callback(); return; } var animating = false, animationTime = 0; animationStates.forEach(function (state) { var time = 0, target = state.target, fromRect = target.fromRect, toRect = getRect(target), prevFromRect = target.prevFromRect, prevToRect = target.prevToRect, animatingRect = state.rect, targetMatrix = matrix(target, true); if (targetMatrix) { // Compensate for current animation toRect.top -= targetMatrix.f; toRect.left -= targetMatrix.e; } target.toRect = toRect; if (target.thisAnimationDuration) { // Could also check if animatingRect is between fromRect and toRect if (isRectEqual(prevFromRect, toRect) && !isRectEqual(fromRect, toRect) && // Make sure animatingRect is on line between toRect & fromRect (animatingRect.top - toRect.top) / (animatingRect.left - toRect.left) === (fromRect.top - toRect.top) / (fromRect.left - toRect.left)) { // If returning to same place as started from animation and on same axis time = calculateRealTime(animatingRect, prevFromRect, prevToRect, _this.options); } } // if fromRect != toRect: animate if (!isRectEqual(toRect, fromRect)) { target.prevFromRect = fromRect; target.prevToRect = toRect; if (!time) { time = _this.options.animation; } _this.animate(target, animatingRect, toRect, time); } if (time) { animating = true; animationTime = Math.max(animationTime, time); clearTimeout(target.animationResetTimer); target.animationResetTimer = setTimeout(function () { target.animationTime = 0; target.prevFromRect = null; target.fromRect = null; target.prevToRect = null; target.thisAnimationDuration = null; }, time); target.thisAnimationDuration = time; } }); clearTimeout(animationCallbackId); if (!animating) { if (typeof callback === 'function') callback(); } else { animationCallbackId = setTimeout(function () { if (typeof callback === 'function') callback(); }, animationTime); } animationStates = []; }, animate: function animate(target, currentRect, toRect, duration) { if (duration) { css(target, 'transition', ''); css(target, 'transform', ''); var elMatrix = matrix(this.el), scaleX = elMatrix && elMatrix.a, scaleY = elMatrix && elMatrix.d, translateX = (currentRect.left - toRect.left) / (scaleX || 1), translateY = (currentRect.top - toRect.top) / (scaleY || 1); target.animatingX = !!translateX; target.animatingY = !!translateY; css(target, 'transform', 'translate3d(' + translateX + 'px,' + translateY + 'px,0)'); this.forRepaintDummy = repaint(target); // repaint css(target, 'transition', 'transform ' + duration + 'ms' + (this.options.easing ? ' ' + this.options.easing : '')); css(target, 'transform', 'translate3d(0,0,0)'); typeof target.animated === 'number' && clearTimeout(target.animated); target.animated = setTimeout(function () { css(target, 'transition', ''); css(target, 'transform', ''); target.animated = false; target.animatingX = false; target.animatingY = false; }, duration); } } }; } function repaint(target) { return target.offsetWidth; } function calculateRealTime(animatingRect, fromRect, toRect, options) { return Math.sqrt(Math.pow(fromRect.top - animatingRect.top, 2) + Math.pow(fromRect.left - animatingRect.left, 2)) / Math.sqrt(Math.pow(fromRect.top - toRect.top, 2) + Math.pow(fromRect.left - toRect.left, 2)) * options.animation; } var plugins = []; var defaults = { initializeByDefault: true }; var PluginManager = { mount: function mount(plugin) { // Set default static properties for (var option in defaults) { if (defaults.hasOwnProperty(option) && !(option in plugin)) { plugin[option] = defaults[option]; } } plugins.forEach(function (p) { if (p.pluginName === plugin.pluginName) { throw "Sortable: Cannot mount plugin ".concat(plugin.pluginName, " more than once"); } }); plugins.push(plugin); }, pluginEvent: function pluginEvent(eventName, sortable, evt) { var _this = this; this.eventCanceled = false; evt.cancel = function () { _this.eventCanceled = true; }; var eventNameGlobal = eventName + 'Global'; plugins.forEach(function (plugin) { if (!sortable[plugin.pluginName]) return; // Fire global events if it exists in this sortable if (sortable[plugin.pluginName][eventNameGlobal]) { sortable[plugin.pluginName][eventNameGlobal](_objectSpread2({ sortable: sortable }, evt)); } // Only fire plugin event if plugin is enabled in this sortable, // and plugin has event defined if (sortable.options[plugin.pluginName] && sortable[plugin.pluginName][eventName]) { sortable[plugin.pluginName][eventName](_objectSpread2({ sortable: sortable }, evt)); } }); }, initializePlugins: function initializePlugins(sortable, el, defaults, options) { plugins.forEach(function (plugin) { var pluginName = plugin.pluginName; if (!sortable.options[pluginName] && !plugin.initializeByDefault) return; var initialized = new plugin(sortable, el, sortable.options); initialized.sortable = sortable; initialized.options = sortable.options; sortable[pluginName] = initialized; // Add default options from plugin _extends(defaults, initialized.defaults); }); for (var option in sortable.options) { if (!sortable.options.hasOwnProperty(option)) continue; var modified = this.modifyOption(sortable, option, sortable.options[option]); if (typeof modified !== 'undefined') { sortable.options[option] = modified; } } }, getEventProperties: function getEventProperties(name, sortable) { var eventProperties = {}; plugins.forEach(function (plugin) { if (typeof plugin.eventProperties !== 'function') return; _extends(eventProperties, plugin.eventProperties.call(sortable[plugin.pluginName], name)); }); return eventProperties; }, modifyOption: function modifyOption(sortable, name, value) { var modifiedValue; plugins.forEach(function (plugin) { // Plugin must exist on the Sortable if (!sortable[plugin.pluginName]) return; // If static option listener exists for this option, call in the context of the Sortable's instance of this plugin if (plugin.optionListeners && typeof plugin.optionListeners[name] === 'function') { modifiedValue = plugin.optionListeners[name].call(sortable[plugin.pluginName], value); } }); return modifiedValue; } }; function dispatchEvent(_ref) { var sortable = _ref.sortable, rootEl = _ref.rootEl, name = _ref.name, targetEl = _ref.targetEl, cloneEl = _ref.cloneEl, toEl = _ref.toEl, fromEl = _ref.fromEl, oldIndex = _ref.oldIndex, newIndex = _ref.newIndex, oldDraggableIndex = _ref.oldDraggableIndex, newDraggableIndex = _ref.newDraggableIndex, originalEvent = _ref.originalEvent, putSortable = _ref.putSortable, extraEventProperties = _ref.extraEventProperties; sortable = sortable || rootEl && rootEl[expando]; if (!sortable) return; var evt, options = sortable.options, onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1); // Support for new CustomEvent feature if (window.CustomEvent && !IE11OrLess && !Edge) { evt = new CustomEvent(name, { bubbles: true, cancelable: true }); } else { evt = document.createEvent('Event'); evt.initEvent(name, true, true); } evt.to = toEl || rootEl; evt.from = fromEl || rootEl; evt.item = targetEl || rootEl; evt.clone = cloneEl; evt.oldIndex = oldIndex; evt.newIndex = newIndex; evt.oldDraggableIndex = oldDraggableIndex; evt.newDraggableIndex = newDraggableIndex; evt.originalEvent = originalEvent; evt.pullMode = putSortable ? putSortable.lastPutMode : undefined; var allEventProperties = _objectSpread2(_objectSpread2({}, extraEventProperties), PluginManager.getEventProperties(name, sortable)); for (var option in allEventProperties) { evt[option] = allEventProperties[option]; } if (rootEl) { rootEl.dispatchEvent(evt); } if (options[onName]) { options[onName].call(sortable, evt); } } var _excluded = ["evt"]; var pluginEvent = function pluginEvent(eventName, sortable) { var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}, originalEvent = _ref.evt, data = _objectWithoutProperties(_ref, _excluded); PluginManager.pluginEvent.bind(Sortable)(eventName, sortable, _objectSpread2({ dragEl: dragEl, parentEl: parentEl, ghostEl: ghostEl, rootEl: rootEl, nextEl: nextEl, lastDownEl: lastDownEl, cloneEl: cloneEl, cloneHidden: cloneHidden, dragStarted: moved, putSortable: putSortable, activeSortable: Sortable.active, originalEvent: originalEvent, oldIndex: oldIndex, oldDraggableIndex: oldDraggableIndex, newIndex: newIndex, newDraggableIndex: newDraggableIndex, hideGhostForTarget: _hideGhostForTarget, unhideGhostForTarget: _unhideGhostForTarget, cloneNowHidden: function cloneNowHidden() { cloneHidden = true; }, cloneNowShown: function cloneNowShown() { cloneHidden = false; }, dispatchSortableEvent: function dispatchSortableEvent(name) { _dispatchEvent({ sortable: sortable, name: name, originalEvent: originalEvent }); } }, data)); }; function _dispatchEvent(info) { dispatchEvent(_objectSpread2({ putSortable: putSortable, cloneEl: cloneEl, targetEl: dragEl, rootEl: rootEl, oldIndex: oldIndex, oldDraggableIndex: oldDraggableIndex, newIndex: newIndex, newDraggableIndex: newDraggableIndex }, info)); } var dragEl, parentEl, ghostEl, rootEl, nextEl, lastDownEl, cloneEl, cloneHidden, oldIndex, newIndex, oldDraggableIndex, newDraggableIndex, activeGroup, putSortable, awaitingDragStarted = false, ignoreNextClick = false, sortables = [], tapEvt, touchEvt, lastDx, lastDy, tapDistanceLeft, tapDistanceTop, moved, lastTarget, lastDirection, pastFirstInvertThresh = false, isCircumstantialInvert = false, targetMoveDistance, // For positioning ghost absolutely ghostRelativeParent, ghostRelativeParentInitialScroll = [], // (left, top) _silent = false, savedInputChecked = []; /** @const */ var documentExists = typeof document !== 'undefined', PositionGhostAbsolutely = IOS, CSSFloatProperty = Edge || IE11OrLess ? 'cssFloat' : 'float', // This will not pass for IE9, because IE9 DnD only works on anchors supportDraggable = documentExists && !ChromeForAndroid && !IOS && 'draggable' in document.createElement('div'), supportCssPointerEvents = function () { if (!documentExists) return; // false when <= IE11 if (IE11OrLess) { return false; } var el = document.createElement('x'); el.style.cssText = 'pointer-events:auto'; return el.style.pointerEvents === 'auto'; }(), _detectDirection = function _detectDirection(el, options) { var elCSS = css(el), elWidth = parseInt(elCSS.width) - parseInt(elCSS.paddingLeft) - parseInt(elCSS.paddingRight) - parseInt(elCSS.borderLeftWidth) - parseInt(elCSS.borderRightWidth), child1 = getChild(el, 0, options), child2 = getChild(el, 1, options), firstChildCSS = child1 && css(child1), secondChildCSS = child2 && css(child2), firstChildWidth = firstChildCSS && parseInt(firstChildCSS.marginLeft) + parseInt(firstChildCSS.marginRight) + getRect(child1).width, secondChildWidth = secondChildCSS && parseInt(secondChildCSS.marginLeft) + parseInt(secondChildCSS.marginRight) + getRect(child2).width; if (elCSS.display === 'flex') { return elCSS.flexDirection === 'column' || elCSS.flexDirection === 'column-reverse' ? 'vertical' : 'horizontal'; } if (elCSS.display === 'grid') { return elCSS.gridTemplateColumns.split(' ').length <= 1 ? 'vertical' : 'horizontal'; } if (child1 && firstChildCSS["float"] && firstChildCSS["float"] !== 'none') { var touchingSideChild2 = firstChildCSS["float"] === 'left' ? 'left' : 'right'; return child2 && (secondChildCSS.clear === 'both' || secondChildCSS.clear === touchingSideChild2) ? 'vertical' : 'horizontal'; } return child1 && (firstChildCSS.display === 'block' || firstChildCSS.display === 'flex' || firstChildCSS.display === 'table' || firstChildCSS.display === 'grid' || firstChildWidth >= elWidth && elCSS[CSSFloatProperty] === 'none' || child2 && elCSS[CSSFloatProperty] === 'none' && firstChildWidth + secondChildWidth > elWidth) ? 'vertical' : 'horizontal'; }, _dragElInRowColumn = function _dragElInRowColumn(dragRect, targetRect, vertical) { var dragElS1Opp = vertical ? dragRect.left : dragRect.top, dragElS2Opp = vertical ? dragRect.right : dragRect.bottom, dragElOppLength = vertical ? dragRect.width : dragRect.height, targetS1Opp = vertical ? targetRect.left : targetRect.top, targetS2Opp = vertical ? targetRect.right : targetRect.bottom, targetOppLength = vertical ? targetRect.width : targetRect.height; return dragElS1Opp === targetS1Opp || dragElS2Opp === targetS2Opp || dragElS1Opp + dragElOppLength / 2 === targetS1Opp + targetOppLength / 2; }, /** * Detects first nearest empty sortable to X and Y position using emptyInsertThreshold. * @param {Number} x X position * @param {Number} y Y position * @return {HTMLElement} Element of the first found nearest Sortable */ _detectNearestEmptySortable = function _detectNearestEmptySortable(x, y) { var ret; sortables.some(function (sortable) { var threshold = sortable[expando].options.emptyInsertThreshold; if (!threshold || lastChild(sortable)) return; var rect = getRect(sortable), insideHorizontally = x >= rect.left - threshold && x <= rect.right + threshold, insideVertically = y >= rect.top - threshold && y <= rect.bottom + threshold; if (insideHorizontally && insideVertically) { return ret = sortable; } }); return ret; }, _prepareGroup = function _prepareGroup(options) { function toFn(value, pull) { return function (to, from, dragEl, evt) { var sameGroup = to.options.group.name && from.options.group.name && to.options.group.name === from.options.group.name; if (value == null && (pull || sameGroup)) { // Default pull value // Default pull and put value if same group return true; } else if (value == null || value === false) { return false; } else if (pull && value === 'clone') { return value; } else if (typeof value === 'function') { return toFn(value(to, from, dragEl, evt), pull)(to, from, dragEl, evt); } else { var otherGroup = (pull ? to : from).options.group.name; return value === true || typeof value === 'string' && value === otherGroup || value.join && value.indexOf(otherGroup) > -1; } }; } var group = {}; var originalGroup = options.group; if (!originalGroup || _typeof(originalGroup) != 'object') { originalGroup = { name: originalGroup }; } group.name = originalGroup.name; group.checkPull = toFn(originalGroup.pull, true); group.checkPut = toFn(originalGroup.put); group.revertClone = originalGroup.revertClone; options.group = group; }, _hideGhostForTarget = function _hideGhostForTarget() { if (!supportCssPointerEvents && ghostEl) { css(ghostEl, 'display', 'none'); } }, _unhideGhostForTarget = function _unhideGhostForTarget() { if (!supportCssPointerEvents && ghostEl) { css(ghostEl, 'display', ''); } }; // #1184 fix - Prevent click event on fallback if dragged but item not changed position if (documentExists && !ChromeForAndroid) { document.addEventListener('click', function (evt) { if (ignoreNextClick) { evt.preventDefault(); evt.stopPropagation && evt.stopPropagation(); evt.stopImmediatePropagation && evt.stopImmediatePropagation(); ignoreNextClick = false; return false; } }, true); } var nearestEmptyInsertDetectEvent = function nearestEmptyInsertDetectEvent(evt) { if (dragEl) { evt = evt.touches ? evt.touches[0] : evt; var nearest = _detectNearestEmptySortable(evt.clientX, evt.clientY); if (nearest) { // Create imitation event var event = {}; for (var i in evt) { if (evt.hasOwnProperty(i)) { event[i] = evt[i]; } } event.target = event.rootEl = nearest; event.preventDefault = void 0; event.stopPropagation = void 0; nearest[expando]._onDragOver(event); } } }; var _checkOutsideTargetEl = function _checkOutsideTargetEl(evt) { if (dragEl) { dragEl.parentNode[expando]._isOutsideThisEl(evt.target); } }; /** * @class Sortable * @param {HTMLElement} el * @param {Object} [options] */ function Sortable(el, options) { if (!(el && el.nodeType && el.nodeType === 1)) { throw "Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(el)); } this.el = el; // root element this.options = options = _extends({}, options); // Export instance el[expando] = this; var defaults = { group: null, sort: true, disabled: false, store: null, handle: null, draggable: /^[uo]l$/i.test(el.nodeName) ? '>li' : '>*', swapThreshold: 1, // percentage; 0 <= x <= 1 invertSwap: false, // invert always invertedSwapThreshold: null, // will be set to same as swapThreshold if default removeCloneOnHide: true, direction: function direction() { return _detectDirection(el, this.options); }, ghostClass: 'sortable-ghost', chosenClass: 'sortable-chosen', dragClass: 'sortable-drag', ignore: 'a, img', filter: null, preventOnFilter: true, animation: 0, easing: null, setData: function setData(dataTransfer, dragEl) { dataTransfer.setData('Text', dragEl.textContent); }, dropBubble: false, dragoverBubble: false, dataIdAttr: 'data-id', delay: 0, delayOnTouchOnly: false, touchStartThreshold: (Number.parseInt ? Number : window).parseInt(window.devicePixelRatio, 10) || 1, forceFallback: false, fallbackClass: 'sortable-fallback', fallbackOnBody: false, fallbackTolerance: 0, fallbackOffset: { x: 0, y: 0 }, // Disabled on Safari: #1571; Enabled on Safari IOS: #2244 supportPointer: Sortable.supportPointer !== false && 'PointerEvent' in window && (!Safari || IOS), emptyInsertThreshold: 5 }; PluginManager.initializePlugins(this, el, defaults); // Set default options for (var name in defaults) { !(name in options) && (options[name] = defaults[name]); } _prepareGroup(options); // Bind all private methods for (var fn in this) { if (fn.charAt(0) === '_' && typeof this[fn] === 'function') { this[fn] = this[fn].bind(this); } } // Setup drag mode this.nativeDraggable = options.forceFallback ? false : supportDraggable; if (this.nativeDraggable) { // Touch start threshold cannot be greater than the native dragstart threshold this.options.touchStartThreshold = 1; } // Bind events if (options.supportPointer) { on(el, 'pointerdown', this._onTapStart); } else { on(el, 'mousedown', this._onTapStart); on(el, 'touchstart', this._onTapStart); } if (this.nativeDraggable) { on(el, 'dragover', this); on(el, 'dragenter', this); } sortables.push(this.el); // Restore sorting options.store && options.store.get && this.sort(options.store.get(this) || []); // Add animation state manager _extends(this, AnimationStateManager()); } Sortable.prototype = /** @lends Sortable.prototype */{ constructor: Sortable, _isOutsideThisEl: function _isOutsideThisEl(target) { if (!this.el.contains(target) && target !== this.el) { lastTarget = null; } }, _getDirection: function _getDirection(evt, target) { return typeof this.options.direction === 'function' ? this.options.direction.call(this, evt, target, dragEl) : this.options.direction; }, _onTapStart: function _onTapStart( /** Event|TouchEvent */evt) { if (!evt.cancelable) return; var _this = this, el = this.el, options = this.options, preventOnFilter = options.preventOnFilter, type = evt.type, touch = evt.touches && evt.touches[0] || evt.pointerType && evt.pointerType === 'touch' && evt, target = (touch || evt).target, originalTarget = evt.target.shadowRoot && (evt.path && evt.path[0] || evt.composedPath && evt.composedPath()[0]) || target, filter = options.filter; _saveInputCheckedState(el); // Don't trigger start event when an element is been dragged, otherwise the evt.oldindex always wrong when set option.group. if (dragEl) { return; } if (/mousedown|pointerdown/.test(type) && evt.button !== 0 || options.disabled) { return; // only left button and enabled } // cancel dnd if original target is content editable if (originalTarget.isContentEditable) { return; } // Safari ignores further event handling after mousedown if (!this.nativeDraggable && Safari && target && target.tagName.toUpperCase() === 'SELECT') { return; } target = closest(target, options.draggable, el, false); if (target && target.animated) { return; } if (lastDownEl === target) { // Ignoring duplicate `down` return; } // Get the index of the dragged element within its parent oldIndex = index(target); oldDraggableIndex = index(target, options.draggable); // Check filter if (typeof filter === 'function') { if (filter.call(this, evt, target, this)) { _dispatchEvent({ sortable: _this, rootEl: originalTarget, name: 'filter', targetEl: target, toEl: el, fromEl: el }); pluginEvent('filter', _this, { evt: evt }); preventOnFilter && evt.preventDefault(); return; // cancel dnd } } else if (filter) { filter = filter.split(',').some(function (criteria) { criteria = closest(originalTarget, criteria.trim(), el, false); if (criteria) { _dispatchEvent({ sortable: _this, rootEl: criteria, name: 'filter', targetEl: target, fromEl: el, toEl: el }); pluginEvent('filter', _this, { evt: evt }); return true; } }); if (filter) { preventOnFilter && evt.preventDefault(); return; // cancel dnd } } if (options.handle && !closest(originalTarget, options.handle, el, false)) { return; } // Prepare `dragstart` this._prepareDragStart(evt, touch, target); }, _prepareDragStart: function _prepareDragStart( /** Event */evt, /** Touch */touch, /** HTMLElement */target) { var _this = this, el = _this.el, options = _this.options, ownerDocument = el.ownerDocument, dragStartFn; if (target && !dragEl && target.parentNode === el) { var dragRect = getRect(target); rootEl = el; dragEl = target; parentEl = dragEl.parentNode; nextEl = dragEl.nextSibling; lastDownEl = target; activeGroup = options.group; Sortable.dragged = dragEl; tapEvt = { target: dragEl, clientX: (touch || evt).clientX, clientY: (touch || evt).clientY }; tapDistanceLeft = tapEvt.clientX - dragRect.left; tapDistanceTop = tapEvt.clientY - dragRect.top; this._lastX = (touch || evt).clientX; this._lastY = (touch || evt).clientY; dragEl.style['will-change'] = 'all'; dragStartFn = function dragStartFn() { pluginEvent('delayEnded', _this, { evt: evt }); if (Sortable.eventCanceled) { _this._onDrop(); return; } // Delayed drag has been triggered // we can re-enable the events: touchmove/mousemove _this._disableDelayedDragEvents(); if (!FireFox && _this.nativeDraggable) { dragEl.draggable = true; } // Bind the events: dragstart/dragend _this._triggerDragStart(evt, touch); // Drag start event _dispatchEvent({ sortable: _this, name: 'choose', originalEvent: evt }); // Chosen item toggleClass(dragEl, options.chosenClass, true); }; // Disable "draggable" options.ignore.split(',').forEach(function (criteria) { find(dragEl, criteria.trim(), _disableDraggable); }); on(ownerDocument, 'dragover', nearestEmptyInsertDetectEvent); on(ownerDocument, 'mousemove', nearestEmptyInsertDetectEvent); on(ownerDocument, 'touchmove', nearestEmptyInsertDetectEvent); if (options.supportPointer) { on(ownerDocument, 'pointerup', _this._onDrop); // Native D&D triggers pointercancel !this.nativeDraggable && on(ownerDocument, 'pointercancel', _this._onDrop); } else { on(ownerDocument, 'mouseup', _this._onDrop); on(ownerDocument, 'touchend', _this._onDrop); on(ownerDocument, 'touchcancel', _this._onDrop); } // Make dragEl draggable (must be before delay for FireFox) if (FireFox && this.nativeDraggable) { this.options.touchStartThreshold = 4; dragEl.draggable = true; } pluginEvent('delayStart', this, { evt: evt }); // Delay is impossible for native DnD in Edge or IE if (options.delay && (!options.delayOnTouchOnly || touch) && (!this.nativeDraggable || !(Edge || IE11OrLess))) { if (Sortable.eventCanceled) { this._onDrop(); return; } // If the user moves the pointer or let go the click or touch // before the delay has been reached: // disable the delayed drag if (options.supportPointer) { on(ownerDocument, 'pointerup', _this._disableDelayedDrag); on(ownerDocument, 'pointercancel', _this._disableDelayedDrag); } else { on(ownerDocument, 'mouseup', _this._disableDelayedDrag); on(ownerDocument, 'touchend', _this._disableDelayedDrag); on(ownerDocument, 'touchcancel', _this._disableDelayedDrag); } on(ownerDocument, 'mousemove', _this._delayedDragTouchMoveHandler); on(ownerDocument, 'touchmove', _this._delayedDragTouchMoveHandler); options.supportPointer && on(ownerDocument, 'pointermove', _this._delayedDragTouchMoveHandler); _this._dragStartTimer = setTimeout(dragStartFn, options.delay); } else { dragStartFn(); } } }, _delayedDragTouchMoveHandler: function _delayedDragTouchMoveHandler( /** TouchEvent|PointerEvent **/e) { var touch = e.touches ? e.touches[0] : e; if (Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) >= Math.floor(this.options.touchStartThreshold / (this.nativeDraggable && window.devicePixelRatio || 1))) { this._disableDelayedDrag(); } }, _disableDelayedDrag: function _disableDelayedDrag() { dragEl && _disableDraggable(dragEl); clearTimeout(this._dragStartTimer); this._disableDelayedDragEvents(); }, _disableDelayedDragEvents: function _disableDelayedDragEvents() { var ownerDocument = this.el.ownerDocument; off(ownerDocument, 'mouseup', this._disableDelayedDrag); off(ownerDocument, 'touchend', this._disableDelayedDrag); off(ownerDocument, 'touchcancel', this._disableDelayedDrag); off(ownerDocument, 'pointerup', this._disableDelayedDrag); off(ownerDocument, 'pointercancel', this._disableDelayedDrag); off(ownerDocument, 'mousemove', this._delayedDragTouchMoveHandler); off(ownerDocument, 'touchmove', this._delayedDragTouchMoveHandler); off(ownerDocument, 'pointermove', this._delayedDragTouchMoveHandler); }, _triggerDragStart: function _triggerDragStart( /** Event */evt, /** Touch */touch) { touch = touch || evt.pointerType == 'touch' && evt; if (!this.nativeDraggable || touch) { if (this.options.supportPointer) { on(document, 'pointermove', this._onTouchMove); } else if (touch) { on(document, 'touchmove', this._onTouchMove); } else { on(document, 'mousemove', this._onTouchMove); } } else { on(dragEl, 'dragend', this); on(rootEl, 'dragstart', this._onDragStart); } try { if (document.selection) { _nextTick(function () { document.selection.empty(); }); } else { window.getSelection().removeAllRanges(); } } catch (err) {} }, _dragStarted: function _dragStarted(fallback, evt) { awaitingDragStarted = false; if (rootEl && dragEl) { pluginEvent('dragStarted', this, { evt: evt }); if (this.nativeDraggable) { on(document, 'dragover', _checkOutsideTargetEl); } var options = this.options; // Apply effect !fallback && toggleClass(dragEl, options.dragClass, false); toggleClass(dragEl, options.ghostClass, true); Sortable.active = this; fallback && this._appendGhost(); // Drag start event _dispatchEvent({ sortable: this, name: 'start', originalEvent: evt }); } else { this._nulling(); } }, _emulateDragOver: function _emulateDragOver() { if (touchEvt) { this._lastX = touchEvt.clientX; this._lastY = touchEvt.clientY; _hideGhostForTarget(); var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY); var parent = target; while (target && target.shadowRoot) { target = target.shadowRoot.elementFromPoint(touchEvt.clientX, touchEvt.clientY); if (target === parent) break; parent = target; } dragEl.parentNode[expando]._isOutsideThisEl(target); if (parent) { do { if (parent[expando]) { var inserted = void 0; inserted = parent[expando]._onDragOver({ clientX: touchEvt.clientX, clientY: touchEvt.clientY, target: target, rootEl: parent }); if (inserted && !this.options.dragoverBubble) { break; } } target = parent; // store last element } /* jshint boss:true */ while (parent = getParentOrHost(parent)); } _unhideGhostForTarget(); } }, _onTouchMove: function _onTouchMove( /**TouchEvent*/evt) { if (tapEvt) { var options = this.options, fallbackTolerance = options.fallbackTolerance, fallbackOffset = options.fallbackOffset, touch = evt.touches ? evt.touches[0] : evt, ghostMatrix = ghostEl && matrix(ghostEl, true), scaleX = ghostEl && ghostMatrix && ghostMatrix.a, scaleY = ghostEl && ghostMatrix && ghostMatrix.d, relativeScrollOffset = PositionGhostAbsolutely && ghostRelativeParent && getRelativeScrollOffset(ghostRelativeParent), dx = (touch.clientX - tapEvt.clientX + fallbackOffset.x) / (scaleX || 1) + (relativeScrollOffset ? relativeScrollOffset[0] - ghostRelativeParentInitialScroll[0] : 0) / (scaleX || 1), dy = (touch.clientY - tapEvt.clientY + fallbackOffset.y) / (scaleY || 1) + (relativeScrollOffset ? relativeScrollOffset[1] - ghostRelativeParentInitialScroll[1] : 0) / (scaleY || 1); // only set the status to dragging, when we are actually dragging if (!Sortable.active && !awaitingDragStarted) { if (fallbackTolerance && Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) < fallbackTolerance) { return; } this._onDragStart(evt, true); } if (ghostEl) { if (ghostMatrix) { ghostMatrix.e += dx - (lastDx || 0); ghostMatrix.f += dy - (lastDy || 0); } else { ghostMatrix = { a: 1, b: 0, c: 0, d: 1, e: dx, f: dy }; } var cssMatrix = "matrix(".concat(ghostMatrix.a, ",").concat(ghostMatrix.b, ",").concat(ghostMatrix.c, ",").concat(ghostMatrix.d, ",").concat(ghostMatrix.e, ",").concat(ghostMatrix.f, ")"); css(ghostEl, 'webkitTransform', cssMatrix); css(ghostEl, 'mozTransform', cssMatrix); css(ghostEl, 'msTransform', cssMatrix); css(ghostEl, 'transform', cssMatrix); lastDx = dx; lastDy = dy; touchEvt = touch; } evt.cancelable && evt.preventDefault(); } }, _appendGhost: function _appendGhost() { // Bug if using scale(): https://stackoverflow.com/questions/2637058 // Not being adjusted for if (!ghostEl) { var container = this.options.fallbackOnBody ? document.body : rootEl, rect = getRect(dragEl, true, PositionGhostAbsolutely, true, container), options = this.options; // Position absolutely if (PositionGhostAbsolutely) { // Get relatively positioned parent ghostRelativeParent = container; while (css(ghostRelativeParent, 'position') === 'static' && css(ghostRelativeParent, 'transform') === 'none' && ghostRelativeParent !== document) { ghostRelativeParent = ghostRelativeParent.parentNode; } if (ghostRelativeParent !== document.body && ghostRelativeParent !== document.documentElement) { if (ghostRelativeParent === document) ghostRelativeParent = getWindowScrollingElement(); rect.top += ghostRelativeParent.scrollTop; rect.left += ghostRelativeParent.scrollLeft; } else { ghostRelativeParent = getWindowScrollingElement(); } ghostRelativeParentInitialScroll = getRelativeScrollOffset(ghostRelativeParent); } ghostEl = dragEl.cloneNode(true); toggleClass(ghostEl, options.ghostClass, false); toggleClass(ghostEl, options.fallbackClass, true); toggleClass(ghostEl, options.dragClass, true); css(ghostEl, 'transition', ''); css(ghostEl, 'transform', ''); css(ghostEl, 'box-sizing', 'border-box'); css(ghostEl, 'margin', 0); css(ghostEl, 'top', rect.top); css(ghostEl, 'left', rect.left); css(ghostEl, 'width', rect.width); css(ghostEl, 'height', rect.height); css(ghostEl, 'opacity', '0.8'); css(ghostEl, 'position', PositionGhostAbsolutely ? 'absolute' : 'fixed'); css(ghostEl, 'zIndex', '100000'); css(ghostEl, 'pointerEvents', 'none'); Sortable.ghost = ghostEl; container.appendChild(ghostEl); // Set transform-origin css(ghostEl, 'transform-origin', tapDistanceLeft / parseInt(ghostEl.style.width) * 100 + '% ' + tapDistanceTop / parseInt(ghostEl.style.height) * 100 + '%'); } }, _onDragStart: function _onDragStart( /**Event*/evt, /**boolean*/fallback) { var _this = this; var dataTransfer = evt.dataTransfer; var options = _this.options; pluginEvent('dragStart', this, { evt: evt }); if (Sortable.eventCanceled) { this._onDrop(); return; } pluginEvent('setupClone', this); if (!Sortable.eventCanceled) { cloneEl = clone(dragEl); cloneEl.removeAttribute("id"); cloneEl.draggable = false; cloneEl.style['will-change'] = ''; this._hideClone(); toggleClass(cloneEl, this.options.chosenClass, false); Sortable.clone = cloneEl; } // #1143: IFrame support workaround _this.cloneId = _nextTick(function () { pluginEvent('clone', _this); if (Sortable.eventCanceled) return; if (!_this.options.removeCloneOnHide) { rootEl.insertBefore(cloneEl, dragEl); } _this._hideClone(); _dispatchEvent({ sortable: _this, name: 'clone' }); }); !fallback && toggleClass(dragEl, options.dragClass, true); // Set proper drop events if (fallback) { ignoreNextClick = true; _this._loopId = setInterval(_this._emulateDragOver, 50); } else { // Undo what was set in _prepareDragStart before drag started off(document, 'mouseup', _this._onDrop); off(document, 'touchend', _this._onDrop); off(document, 'touchcancel', _this._onDrop); if (dataTransfer) { dataTransfer.effectAllowed = 'move'; options.setData && options.setData.call(_this, dataTransfer, dragEl); } on(document, 'drop', _this); // #1276 fix: css(dragEl, 'transform', 'translateZ(0)'); } awaitingDragStarted = true; _this._dragStartId = _nextTick(_this._dragStarted.bind(_this, fallback, evt)); on(document, 'selectstart', _this); moved = true; window.getSelection().removeAllRanges(); if (Safari) { css(document.body, 'user-select', 'none'); } }, // Returns true - if no further action is needed (either inserted or another condition) _onDragOver: function _onDragOver( /**Event*/evt) { var el = this.el, target = evt.target, dragRect, targetRect, revert, options = this.options, group = options.group, activeSortable = Sortable.active, isOwner = activeGroup === group, canSort = options.sort, fromSortable = putSortable || activeSortable, vertical, _this = this, completedFired = false; if (_silent) return; function dragOverEvent(name, extra) { pluginEvent(name, _this, _objectSpread2({ evt: evt, isOwner: isOwner, axis: vertical ? 'vertical' : 'horizontal', revert: revert, dragRect: dragRect, targetRect: targetRect, canSort: canSort, fromSortable: fromSortable, target: target, completed: completed, onMove: function onMove(target, after) { return _onMove(rootEl, el, dragEl, dragRect, target, getRect(target), evt, after); }, changed: changed }, extra)); } // Capture animation state function capture() { dragOverEvent('dragOverAnimationCapture'); _this.captureAnimationState(); if (_this !== fromSortable) { fromSortable.captureAnimationState(); } } // Return invocation when dragEl is inserted (or completed) function completed(insertion) { dragOverEvent('dragOverCompleted', { insertion: insertion }); if (insertion) { // Clones must be hidden before folding animation to capture dragRectAbsolute properly if (isOwner) { activeSortable._hideClone(); } else { activeSortable._showClone(_this); } if (_this !== fromSortable) { // Set ghost class to new sortable's ghost class toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : activeSortable.options.ghostClass, false); toggleClass(dragEl, options.ghostClass, true); } if (putSortable !== _this && _this !== Sortable.active) { putSortable = _this; } else if (_this === Sortable.active && putSortable) { putSortable = null; } // Animation if (fromSortable === _this) { _this._ignoreWhileAnimating = target; } _this.animateAll(function () { dragOverEvent('dragOverAnimationComplete'); _this._ignoreWhileAnimating = null; }); if (_this !== fromSortable) { fromSortable.animateAll(); fromSortable._ignoreWhileAnimating = null; } } // Null lastTarget if it is not inside a previously swapped element if (target === dragEl && !dragEl.animated || target === el && !target.animated) { lastTarget = null; } // no bubbling and not fallback if (!options.dragoverBubble && !evt.rootEl && target !== document) { dragEl.parentNode[expando]._isOutsideThisEl(evt.target); // Do not detect for empty insert if already inserted !insertion && nearestEmptyInsertDetectEvent(evt); } !options.dragoverBubble && evt.stopPropagation && evt.stopPropagation(); return completedFired = true; } // Call when dragEl has been inserted function changed() { newIndex = index(dragEl); newDraggableIndex = index(dragEl, options.draggable); _dispatchEvent({ sortable: _this, name: 'change', toEl: el, newIndex: newIndex, newDraggableIndex: newDraggableIndex, originalEvent: evt }); } if (evt.preventDefault !== void 0) { evt.cancelable && evt.preventDefault(); } target = closest(target, options.draggable, el, true); dragOverEvent('dragOver'); if (Sortable.eventCanceled) return completedFired; if (dragEl.contains(evt.target) || target.animated && target.animatingX && target.animatingY || _this._ignoreWhileAnimating === target) { return completed(false); } ignoreNextClick = false; if (activeSortable && !options.disabled && (isOwner ? canSort || (revert = parentEl !== rootEl) // Reverting item into the original list : putSortable === this || (this.lastPutMode = activeGroup.checkPull(this, activeSortable, dragEl, evt)) && group.checkPut(this, activeSortable, dragEl, evt))) { vertical = this._getDirection(evt, target) === 'vertical'; dragRect = getRect(dragEl); dragOverEvent('dragOverValid'); if (Sortable.eventCanceled) return completedFired; if (revert) { parentEl = rootEl; // actualization capture(); this._hideClone(); dragOverEvent('revert'); if (!Sortable.eventCanceled) { if (nextEl) { rootEl.insertBefore(dragEl, nextEl); } else { rootEl.appendChild(dragEl); } } return completed(true); } var elLastChild = lastChild(el, options.draggable); if (!elLastChild || _ghostIsLast(evt, vertical, this) && !elLastChild.animated) { // Insert to end of list // If already at end of list: Do not insert if (elLastChild === dragEl) { return completed(false); } // if there is a last element, it is the target if (elLastChild && el === evt.target) { target = elLastChild; } if (target) { targetRect = getRect(target); } if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, !!target) !== false) { capture(); if (elLastChild && elLastChild.nextSibling) { // the last draggable element is not the last node el.insertBefore(dragEl, elLastChild.nextSibling); } else { el.appendChild(dragEl); } parentEl = el; // actualization changed(); return completed(true); } } else if (elLastChild && _ghostIsFirst(evt, vertical, this)) { // Insert to start of list var firstChild = getChild(el, 0, options, true); if (firstChild === dragEl) { return completed(false); } target = firstChild; targetRect = getRect(target); if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, false) !== false) { capture(); el.insertBefore(dragEl, firstChild); parentEl = el; // actualization changed(); return completed(true); } } else if (target.parentNode === el) { targetRect = getRect(target); var direction = 0, targetBeforeFirstSwap, differentLevel = dragEl.parentNode !== el, differentRowCol = !_dragElInRowColumn(dragEl.animated && dragEl.toRect || dragRect, target.animated && target.toRect || targetRect, vertical), side1 = vertical ? 'top' : 'left', scrolledPastTop = isScrolledPast(target, 'top', 'top') || isScrolledPast(dragEl, 'top', 'top'), scrollBefore = scrolledPastTop ? scrolledPastTop.scrollTop : void 0; if (lastTarget !== target) { targetBeforeFirstSwap = targetRect[side1]; pastFirstInvertThresh = false; isCircumstantialInvert = !differentRowCol && options.invertSwap || differentLevel; } direction = _getSwapDirection(evt, target, targetRect, vertical, differentRowCol ? 1 : options.swapThreshold, options.invertedSwapThreshold == null ? options.swapThreshold : options.invertedSwapThreshold, isCircumstantialInvert, lastTarget === target); var sibling; if (direction !== 0) { // Check if target is beside dragEl in respective direction (ignoring hidden elements) var dragIndex = index(dragEl); do { dragIndex -= direction; sibling = parentEl.children[dragIndex]; } while (sibling && (css(sibling, 'display') === 'none' || sibling === ghostEl)); } // If dragEl is already beside target: Do not insert if (direction === 0 || sibling === target) { return completed(false); } lastTarget = target; lastDirection = direction; var nextSibling = target.nextElementSibling, after = false; after = direction === 1; var moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, after); if (moveVector !== false) { if (moveVector === 1 || moveVector === -1) { after = moveVector === 1; } _silent = true; setTimeout(_unsilent, 30); capture(); if (after && !nextSibling) { el.appendChild(dragEl); } else { target.parentNode.insertBefore(dragEl, after ? nextSibling : target); } // Undo chrome's scroll adjustment (has no effect on other browsers) if (scrolledPastTop) { scrollBy(scrolledPastTop, 0, scrollBefore - scrolledPastTop.scrollTop); } parentEl = dragEl.parentNode; // actualization // must be done before animation if (targetBeforeFirstSwap !== undefined && !isCircumstantialInvert) { targetMoveDistance = Math.abs(targetBeforeFirstSwap - getRect(target)[side1]); } changed(); return completed(true); } } if (el.contains(dragEl)) { return completed(false); } } return false; }, _ignoreWhileAnimating: null, _offMoveEvents: function _offMoveEvents() { off(document, 'mousemove', this._onTouchMove); off(document, 'touchmove', this._onTouchMove); off(document, 'pointermove', this._onTouchMove); off(document, 'dragover', nearestEmptyInsertDetectEvent); off(document, 'mousemove', nearestEmptyInsertDetectEvent); off(document, 'touchmove', nearestEmptyInsertDetectEvent); }, _offUpEvents: function _offUpEvents() { var ownerDocument = this.el.ownerDocument; off(ownerDocument, 'mouseup', this._onDrop); off(ownerDocument, 'touchend', this._onDrop); off(ownerDocument, 'pointerup', this._onDrop); off(ownerDocument, 'pointercancel', this._onDrop); off(ownerDocument, 'touchcancel', this._onDrop); off(document, 'selectstart', this); }, _onDrop: function _onDrop( /**Event*/evt) { var el = this.el, options = this.options; // Get the index of the dragged element within its parent newIndex = index(dragEl); newDraggableIndex = index(dragEl, options.draggable); pluginEvent('drop', this, { evt: evt }); parentEl = dragEl && dragEl.parentNode; // Get again after plugin event newIndex = index(dragEl); newDraggableIndex = index(dragEl, options.draggable); if (Sortable.eventCanceled) { this._nulling(); return; } awaitingDragStarted = false; isCircumstantialInvert = false; pastFirstInvertThresh = false; clearInterval(this._loopId); clearTimeout(this._dragStartTimer); _cancelNextTick(this.cloneId); _cancelNextTick(this._dragStartId); // Unbind events if (this.nativeDraggable) { off(document, 'drop', this); off(el, 'dragstart', this._onDragStart); } this._offMoveEvents(); this._offUpEvents(); if (Safari) { css(document.body, 'user-select', ''); } css(dragEl, 'transform', ''); if (evt) { if (moved) { evt.cancelable && evt.preventDefault(); !options.dropBubble && evt.stopPropagation(); } ghostEl && ghostEl.parentNode && ghostEl.parentNode.removeChild(ghostEl); if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') { // Remove clone(s) cloneEl && cloneEl.parentNode && cloneEl.parentNode.removeChild(cloneEl); } if (dragEl) { if (this.nativeDraggable) { off(dragEl, 'dragend', this); } _disableDraggable(dragEl); dragEl.style['will-change'] = ''; // Remove classes // ghostClass is added in dragStarted if (moved && !awaitingDragStarted) { toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : this.options.ghostClass, false); } toggleClass(dragEl, this.options.chosenClass, false); // Drag stop event _dispatchEvent({ sortable: this, name: 'unchoose', toEl: parentEl, newIndex: null, newDraggableIndex: null, originalEvent: evt }); if (rootEl !== parentEl) { if (newIndex >= 0) { // Add event _dispatchEvent({ rootEl: parentEl, name: 'add', toEl: parentEl, fromEl: rootEl, originalEvent: evt }); // Remove event _dispatchEvent({ sortable: this, name: 'remove', toEl: parentEl, originalEvent: evt }); // drag from one list and drop into another _dispatchEvent({ rootEl: parentEl, name: 'sort', toEl: parentEl, fromEl: rootEl, originalEvent: evt }); _dispatchEvent({ sortable: this, name: 'sort', toEl: parentEl, originalEvent: evt }); } putSortable && putSortable.save(); } else { if (newIndex !== oldIndex) { if (newIndex >= 0) { // drag & drop within the same list _dispatchEvent({ sortable: this, name: 'update', toEl: parentEl, originalEvent: evt }); _dispatchEvent({ sortable: this, name: 'sort', toEl: parentEl, originalEvent: evt }); } } } if (Sortable.active) { /* jshint eqnull:true */ if (newIndex == null || newIndex === -1) { newIndex = oldIndex; newDraggableIndex = oldDraggableIndex; } _dispatchEvent({ sortable: this, name: 'end', toEl: parentEl, originalEvent: evt }); // Save sorting this.save(); } } } this._nulling(); }, _nulling: function _nulling() { pluginEvent('nulling', this); rootEl = dragEl = parentEl = ghostEl = nextEl = cloneEl = lastDownEl = cloneHidden = tapEvt = touchEvt = moved = newIndex = newDraggableIndex = oldIndex = oldDraggableIndex = lastTarget = lastDirection = putSortable = activeGroup = Sortable.dragged = Sortable.ghost = Sortable.clone = Sortable.active = null; var el = this.el; savedInputChecked.forEach(function (checkEl) { if (el.contains(checkEl)) { checkEl.checked = true; } }); savedInputChecked.length = lastDx = lastDy = 0; }, handleEvent: function handleEvent( /**Event*/evt) { switch (evt.type) { case 'drop': case 'dragend': this._onDrop(evt); break; case 'dragenter': case 'dragover': if (dragEl) { this._onDragOver(evt); _globalDragOver(evt); } break; case 'selectstart': evt.preventDefault(); break; } }, /** * Serializes the item into an array of string. * @returns {String[]} */ toArray: function toArray() { var order = [], el, children = this.el.children, i = 0, n = children.length, options = this.options; for (; i < n; i++) { el = children[i]; if (closest(el, options.draggable, this.el, false)) { order.push(el.getAttribute(options.dataIdAttr) || _generateId(el)); } } return order; }, /** * Sorts the elements according to the array. * @param {String[]} order order of the items */ sort: function sort(order, useAnimation) { var items = {}, rootEl = this.el; this.toArray().forEach(function (id, i) { var el = rootEl.children[i]; if (closest(el, this.options.draggable, rootEl, false)) { items[id] = el; } }, this); useAnimation && this.captureAnimationState(); order.forEach(function (id) { if (items[id]) { rootEl.removeChild(items[id]); rootEl.appendChild(items[id]); } }); useAnimation && this.animateAll(); }, /** * Save the current sorting */ save: function save() { var store = this.options.store; store && store.set && store.set(this); }, /** * For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree. * @param {HTMLElement} el * @param {String} [selector] default: `options.draggable` * @returns {HTMLElement|null} */ closest: function closest$1(el, selector) { return closest(el, selector || this.options.draggable, this.el, false); }, /** * Set/get option * @param {string} name * @param {*} [value] * @returns {*} */ option: function option(name, value) { var options = this.options; if (value === void 0) { return options[name]; } else { var modifiedValue = PluginManager.modifyOption(this, name, value); if (typeof modifiedValue !== 'undefined') { options[name] = modifiedValue; } else { options[name] = value; } if (name === 'group') { _prepareGroup(options); } } }, /** * Destroy */ destroy: function destroy() { pluginEvent('destroy', this); var el = this.el; el[expando] = null; off(el, 'mousedown', this._onTapStart); off(el, 'touchstart', this._onTapStart); off(el, 'pointerdown', this._onTapStart); if (this.nativeDraggable) { off(el, 'dragover', this); off(el, 'dragenter', this); } // Remove draggable attributes Array.prototype.forEach.call(el.querySelectorAll('[draggable]'), function (el) { el.removeAttribute('draggable'); }); this._onDrop(); this._disableDelayedDragEvents(); sortables.splice(sortables.indexOf(this.el), 1); this.el = el = null; }, _hideClone: function _hideClone() { if (!cloneHidden) { pluginEvent('hideClone', this); if (Sortable.eventCanceled) return; css(cloneEl, 'display', 'none'); if (this.options.removeCloneOnHide && cloneEl.parentNode) { cloneEl.parentNode.removeChild(cloneEl); } cloneHidden = true; } }, _showClone: function _showClone(putSortable) { if (putSortable.lastPutMode !== 'clone') { this._hideClone(); return; } if (cloneHidden) { pluginEvent('showClone', this); if (Sortable.eventCanceled) return; // show clone at dragEl or original position if (dragEl.parentNode == rootEl && !this.options.group.revertClone) { rootEl.insertBefore(cloneEl, dragEl); } else if (nextEl) { rootEl.insertBefore(cloneEl, nextEl); } else { rootEl.appendChild(cloneEl); } if (this.options.group.revertClone) { this.animate(dragEl, cloneEl); } css(cloneEl, 'display', ''); cloneHidden = false; } } }; function _globalDragOver( /**Event*/evt) { if (evt.dataTransfer) { evt.dataTransfer.dropEffect = 'move'; } evt.cancelable && evt.preventDefault(); } function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, originalEvent, willInsertAfter) { var evt, sortable = fromEl[expando], onMoveFn = sortable.options.onMove, retVal; // Support for new CustomEvent feature if (window.CustomEvent && !IE11OrLess && !Edge) { evt = new CustomEvent('move', { bubbles: true, cancelable: true }); } else { evt = document.createEvent('Event'); evt.initEvent('move', true, true); } evt.to = toEl; evt.from = fromEl; evt.dragged = dragEl; evt.draggedRect = dragRect; evt.related = targetEl || toEl; evt.relatedRect = targetRect || getRect(toEl); evt.willInsertAfter = willInsertAfter; evt.originalEvent = originalEvent; fromEl.dispatchEvent(evt); if (onMoveFn) { retVal = onMoveFn.call(sortable, evt, originalEvent); } return retVal; } function _disableDraggable(el) { el.draggable = false; } function _unsilent() { _silent = false; } function _ghostIsFirst(evt, vertical, sortable) { var firstElRect = getRect(getChild(sortable.el, 0, sortable.options, true)); var childContainingRect = getChildContainingRectFromElement(sortable.el, sortable.options, ghostEl); var spacer = 10; return vertical ? evt.clientX < childContainingRect.left - spacer || evt.clientY < firstElRect.top && evt.clientX < firstElRect.right : evt.clientY < childContainingRect.top - spacer || evt.clientY < firstElRect.bottom && evt.clientX < firstElRect.left; } function _ghostIsLast(evt, vertical, sortable) { var lastElRect = getRect(lastChild(sortable.el, sortable.options.draggable)); var childContainingRect = getChildContainingRectFromElement(sortable.el, sortable.options, ghostEl); var spacer = 10; return vertical ? evt.clientX > childContainingRect.right + spacer || evt.clientY > lastElRect.bottom && evt.clientX > lastElRect.left : evt.clientY > childContainingRect.bottom + spacer || evt.clientX > lastElRect.right && evt.clientY > lastElRect.top; } function _getSwapDirection(evt, target, targetRect, vertical, swapThreshold, invertedSwapThreshold, invertSwap, isLastTarget) { var mouseOnAxis = vertical ? evt.clientY : evt.clientX, targetLength = vertical ? targetRect.height : targetRect.width, targetS1 = vertical ? targetRect.top : targetRect.left, targetS2 = vertical ? targetRect.bottom : targetRect.right, invert = false; if (!invertSwap) { // Never invert or create dragEl shadow when target movemenet causes mouse to move past the end of regular swapThreshold if (isLastTarget && targetMoveDistance < targetLength * swapThreshold) { // multiplied only by swapThreshold because mouse will already be inside target by (1 - threshold) * targetLength / 2 // check if past first invert threshold on side opposite of lastDirection if (!pastFirstInvertThresh && (lastDirection === 1 ? mouseOnAxis > targetS1 + targetLength * invertedSwapThreshold / 2 : mouseOnAxis < targetS2 - targetLength * invertedSwapThreshold / 2)) { // past first invert threshold, do not restrict inverted threshold to dragEl shadow pastFirstInvertThresh = true; } if (!pastFirstInvertThresh) { // dragEl shadow (target move distance shadow) if (lastDirection === 1 ? mouseOnAxis < targetS1 + targetMoveDistance // over dragEl shadow : mouseOnAxis > targetS2 - targetMoveDistance) { return -lastDirection; } } else { invert = true; } } else { // Regular if (mouseOnAxis > targetS1 + targetLength * (1 - swapThreshold) / 2 && mouseOnAxis < targetS2 - targetLength * (1 - swapThreshold) / 2) { return _getInsertDirection(target); } } } invert = invert || invertSwap; if (invert) { // Invert of regular if (mouseOnAxis < targetS1 + targetLength * invertedSwapThreshold / 2 || mouseOnAxis > targetS2 - targetLength * invertedSwapThreshold / 2) { return mouseOnAxis > targetS1 + targetLength / 2 ? 1 : -1; } } return 0; } /** * Gets the direction dragEl must be swapped relative to target in order to make it * seem that dragEl has been "inserted" into that element's position * @param {HTMLElement} target The target whose position dragEl is being inserted at * @return {Number} Direction dragEl must be swapped */ function _getInsertDirection(target) { if (index(dragEl) < index(target)) { return 1; } else { return -1; } } /** * Generate id * @param {HTMLElement} el * @returns {String} * @private */ function _generateId(el) { var str = el.tagName + el.className + el.src + el.href + el.textContent, i = str.length, sum = 0; while (i--) { sum += str.charCodeAt(i); } return sum.toString(36); } function _saveInputCheckedState(root) { savedInputChecked.length = 0; var inputs = root.getElementsByTagName('input'); var idx = inputs.length; while (idx--) { var el = inputs[idx]; el.checked && savedInputChecked.push(el); } } function _nextTick(fn) { return setTimeout(fn, 0); } function _cancelNextTick(id) { return clearTimeout(id); } // Fixed #973: if (documentExists) { on(document, 'touchmove', function (evt) { if ((Sortable.active || awaitingDragStarted) && evt.cancelable) { evt.preventDefault(); } }); } // Export utils Sortable.utils = { on: on, off: off, css: css, find: find, is: function is(el, selector) { return !!closest(el, selector, el, false); }, extend: extend, throttle: throttle, closest: closest, toggleClass: toggleClass, clone: clone, index: index, nextTick: _nextTick, cancelNextTick: _cancelNextTick, detectDirection: _detectDirection, getChild: getChild, expando: expando }; /** * Get the Sortable instance of an element * @param {HTMLElement} element The element * @return {Sortable|undefined} The instance of Sortable */ Sortable.get = function (element) { return element[expando]; }; /** * Mount a plugin to Sortable * @param {...SortablePlugin|SortablePlugin[]} plugins Plugins being mounted */ Sortable.mount = function () { for (var _len = arguments.length, plugins = new Array(_len), _key = 0; _key < _len; _key++) { plugins[_key] = arguments[_key]; } if (plugins[0].constructor === Array) plugins = plugins[0]; plugins.forEach(function (plugin) { if (!plugin.prototype || !plugin.prototype.constructor) { throw "Sortable: Mounted plugin must be a constructor function, not ".concat({}.toString.call(plugin)); } if (plugin.utils) Sortable.utils = _objectSpread2(_objectSpread2({}, Sortable.utils), plugin.utils); PluginManager.mount(plugin); }); }; /** * Create sortable instance * @param {HTMLElement} el * @param {Object} [options] */ Sortable.create = function (el, options) { return new Sortable(el, options); }; // Export Sortable.version = version; var autoScrolls = [], scrollEl, scrollRootEl, scrolling = false, lastAutoScrollX, lastAutoScrollY, touchEvt$1, pointerElemChangedInterval; function AutoScrollPlugin() { function AutoScroll() { this.defaults = { scroll: true, forceAutoScrollFallback: false, scrollSensitivity: 30, scrollSpeed: 10, bubbleScroll: true }; // Bind all private methods for (var fn in this) { if (fn.charAt(0) === '_' && typeof this[fn] === 'function') { this[fn] = this[fn].bind(this); } } } AutoScroll.prototype = { dragStarted: function dragStarted(_ref) { var originalEvent = _ref.originalEvent; if (this.sortable.nativeDraggable) { on(document, 'dragover', this._handleAutoScroll); } else { if (this.options.supportPointer) { on(document, 'pointermove', this._handleFallbackAutoScroll); } else if (originalEvent.touches) { on(document, 'touchmove', this._handleFallbackAutoScroll); } else { on(document, 'mousemove', this._handleFallbackAutoScroll); } } }, dragOverCompleted: function dragOverCompleted(_ref2) { var originalEvent = _ref2.originalEvent; // For when bubbling is canceled and using fallback (fallback 'touchmove' always reached) if (!this.options.dragOverBubble && !originalEvent.rootEl) { this._handleAutoScroll(originalEvent); } }, drop: function drop() { if (this.sortable.nativeDraggable) { off(document, 'dragover', this._handleAutoScroll); } else { off(document, 'pointermove', this._handleFallbackAutoScroll); off(document, 'touchmove', this._handleFallbackAutoScroll); off(document, 'mousemove', this._handleFallbackAutoScroll); } clearPointerElemChangedInterval(); clearAutoScrolls(); cancelThrottle(); }, nulling: function nulling() { touchEvt$1 = scrollRootEl = scrollEl = scrolling = pointerElemChangedInterval = lastAutoScrollX = lastAutoScrollY = null; autoScrolls.length = 0; }, _handleFallbackAutoScroll: function _handleFallbackAutoScroll(evt) { this._handleAutoScroll(evt, true); }, _handleAutoScroll: function _handleAutoScroll(evt, fallback) { var _this = this; var x = (evt.touches ? evt.touches[0] : evt).clientX, y = (evt.touches ? evt.touches[0] : evt).clientY, elem = document.elementFromPoint(x, y); touchEvt$1 = evt; // IE does not seem to have native autoscroll, // Edge's autoscroll seems too conditional, // MACOS Safari does not have autoscroll, // Firefox and Chrome are good if (fallback || this.options.forceAutoScrollFallback || Edge || IE11OrLess || Safari) { autoScroll(evt, this.options, elem, fallback); // Listener for pointer element change var ogElemScroller = getParentAutoScrollElement(elem, true); if (scrolling && (!pointerElemChangedInterval || x !== lastAutoScrollX || y !== lastAutoScrollY)) { pointerElemChangedInterval && clearPointerElemChangedInterval(); // Detect for pointer elem change, emulating native DnD behaviour pointerElemChangedInterval = setInterval(function () { var newElem = getParentAutoScrollElement(document.elementFromPoint(x, y), true); if (newElem !== ogElemScroller) { ogElemScroller = newElem; clearAutoScrolls(); } autoScroll(evt, _this.options, newElem, fallback); }, 10); lastAutoScrollX = x; lastAutoScrollY = y; } } else { // if DnD is enabled (and browser has good autoscrolling), first autoscroll will already scroll, so get parent autoscroll of first autoscroll if (!this.options.bubbleScroll || getParentAutoScrollElement(elem, true) === getWindowScrollingElement()) { clearAutoScrolls(); return; } autoScroll(evt, this.options, getParentAutoScrollElement(elem, false), false); } } }; return _extends(AutoScroll, { pluginName: 'scroll', initializeByDefault: true }); } function clearAutoScrolls() { autoScrolls.forEach(function (autoScroll) { clearInterval(autoScroll.pid); }); autoScrolls = []; } function clearPointerElemChangedInterval() { clearInterval(pointerElemChangedInterval); } var autoScroll = throttle(function (evt, options, rootEl, isFallback) { // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521 if (!options.scroll) return; var x = (evt.touches ? evt.touches[0] : evt).clientX, y = (evt.touches ? evt.touches[0] : evt).clientY, sens = options.scrollSensitivity, speed = options.scrollSpeed, winScroller = getWindowScrollingElement(); var scrollThisInstance = false, scrollCustomFn; // New scroll root, set scrollEl if (scrollRootEl !== rootEl) { scrollRootEl = rootEl; clearAutoScrolls(); scrollEl = options.scroll; scrollCustomFn = options.scrollFn; if (scrollEl === true) { scrollEl = getParentAutoScrollElement(rootEl, true); } } var layersOut = 0; var currentParent = scrollEl; do { var el = currentParent, rect = getRect(el), top = rect.top, bottom = rect.bottom, left = rect.left, right = rect.right, width = rect.width, height = rect.height, canScrollX = void 0, canScrollY = void 0, scrollWidth = el.scrollWidth, scrollHeight = el.scrollHeight, elCSS = css(el), scrollPosX = el.scrollLeft, scrollPosY = el.scrollTop; if (el === winScroller) { canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll' || elCSS.overflowX === 'visible'); canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll' || elCSS.overflowY === 'visible'); } else { canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll'); canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll'); } var vx = canScrollX && (Math.abs(right - x) <= sens && scrollPosX + width < scrollWidth) - (Math.abs(left - x) <= sens && !!scrollPosX); var vy = canScrollY && (Math.abs(bottom - y) <= sens && scrollPosY + height < scrollHeight) - (Math.abs(top - y) <= sens && !!scrollPosY); if (!autoScrolls[layersOut]) { for (var i = 0; i <= layersOut; i++) { if (!autoScrolls[i]) { autoScrolls[i] = {}; } } } if (autoScrolls[layersOut].vx != vx || autoScrolls[layersOut].vy != vy || autoScrolls[layersOut].el !== el) { autoScrolls[layersOut].el = el; autoScrolls[layersOut].vx = vx; autoScrolls[layersOut].vy = vy; clearInterval(autoScrolls[layersOut].pid); if (vx != 0 || vy != 0) { scrollThisInstance = true; /* jshint loopfunc:true */ autoScrolls[layersOut].pid = setInterval(function () { // emulate drag over during autoscroll (fallback), emulating native DnD behaviour if (isFallback && this.layer === 0) { Sortable.active._onTouchMove(touchEvt$1); // To move ghost if it is positioned absolutely } var scrollOffsetY = autoScrolls[this.layer].vy ? autoScrolls[this.layer].vy * speed : 0; var scrollOffsetX = autoScrolls[this.layer].vx ? autoScrolls[this.layer].vx * speed : 0; if (typeof scrollCustomFn === 'function') { if (scrollCustomFn.call(Sortable.dragged.parentNode[expando], scrollOffsetX, scrollOffsetY, evt, touchEvt$1, autoScrolls[this.layer].el) !== 'continue') { return; } } scrollBy(autoScrolls[this.layer].el, scrollOffsetX, scrollOffsetY); }.bind({ layer: layersOut }), 24); } } layersOut++; } while (options.bubbleScroll && currentParent !== winScroller && (currentParent = getParentAutoScrollElement(currentParent, false))); scrolling = scrollThisInstance; // in case another function catches scrolling as false in between when it is not }, 30); var drop = function drop(_ref) { var originalEvent = _ref.originalEvent, putSortable = _ref.putSortable, dragEl = _ref.dragEl, activeSortable = _ref.activeSortable, dispatchSortableEvent = _ref.dispatchSortableEvent, hideGhostForTarget = _ref.hideGhostForTarget, unhideGhostForTarget = _ref.unhideGhostForTarget; if (!originalEvent) return; var toSortable = putSortable || activeSortable; hideGhostForTarget(); var touch = originalEvent.changedTouches && originalEvent.changedTouches.length ? originalEvent.changedTouches[0] : originalEvent; var target = document.elementFromPoint(touch.clientX, touch.clientY); unhideGhostForTarget(); if (toSortable && !toSortable.el.contains(target)) { dispatchSortableEvent('spill'); this.onSpill({ dragEl: dragEl, putSortable: putSortable }); } }; function Revert() {} Revert.prototype = { startIndex: null, dragStart: function dragStart(_ref2) { var oldDraggableIndex = _ref2.oldDraggableIndex; this.startIndex = oldDraggableIndex; }, onSpill: function onSpill(_ref3) { var dragEl = _ref3.dragEl, putSortable = _ref3.putSortable; this.sortable.captureAnimationState(); if (putSortable) { putSortable.captureAnimationState(); } var nextSibling = getChild(this.sortable.el, this.startIndex, this.options); if (nextSibling) { this.sortable.el.insertBefore(dragEl, nextSibling); } else { this.sortable.el.appendChild(dragEl); } this.sortable.animateAll(); if (putSortable) { putSortable.animateAll(); } }, drop: drop }; _extends(Revert, { pluginName: 'revertOnSpill' }); function Remove() {} Remove.prototype = { onSpill: function onSpill(_ref4) { var dragEl = _ref4.dragEl, putSortable = _ref4.putSortable; var parentSortable = putSortable || this.sortable; parentSortable.captureAnimationState(); dragEl.parentNode && dragEl.parentNode.removeChild(dragEl); parentSortable.animateAll(); }, drop: drop }; _extends(Remove, { pluginName: 'removeOnSpill' }); var lastSwapEl; function SwapPlugin() { function Swap() { this.defaults = { swapClass: 'sortable-swap-highlight' }; } Swap.prototype = { dragStart: function dragStart(_ref) { var dragEl = _ref.dragEl; lastSwapEl = dragEl; }, dragOverValid: function dragOverValid(_ref2) { var completed = _ref2.completed, target = _ref2.target, onMove = _ref2.onMove, activeSortable = _ref2.activeSortable, changed = _ref2.changed, cancel = _ref2.cancel; if (!activeSortable.options.swap) return; var el = this.sortable.el, options = this.options; if (target && target !== el) { var prevSwapEl = lastSwapEl; if (onMove(target) !== false) { toggleClass(target, options.swapClass, true); lastSwapEl = target; } else { lastSwapEl = null; } if (prevSwapEl && prevSwapEl !== lastSwapEl) { toggleClass(prevSwapEl, options.swapClass, false); } } changed(); completed(true); cancel(); }, drop: function drop(_ref3) { var activeSortable = _ref3.activeSortable, putSortable = _ref3.putSortable, dragEl = _ref3.dragEl; var toSortable = putSortable || this.sortable; var options = this.options; lastSwapEl && toggleClass(lastSwapEl, options.swapClass, false); if (lastSwapEl && (options.swap || putSortable && putSortable.options.swap)) { if (dragEl !== lastSwapEl) { toSortable.captureAnimationState(); if (toSortable !== activeSortable) activeSortable.captureAnimationState(); swapNodes(dragEl, lastSwapEl); toSortable.animateAll(); if (toSortable !== activeSortable) activeSortable.animateAll(); } } }, nulling: function nulling() { lastSwapEl = null; } }; return _extends(Swap, { pluginName: 'swap', eventProperties: function eventProperties() { return { swapItem: lastSwapEl }; } }); } function swapNodes(n1, n2) { var p1 = n1.parentNode, p2 = n2.parentNode, i1, i2; if (!p1 || !p2 || p1.isEqualNode(n2) || p2.isEqualNode(n1)) return; i1 = index(n1); i2 = index(n2); if (p1.isEqualNode(p2) && i1 < i2) { i2++; } p1.insertBefore(n2, p1.children[i1]); p2.insertBefore(n1, p2.children[i2]); } var multiDragElements = [], multiDragClones = [], lastMultiDragSelect, // for selection with modifier key down (SHIFT) multiDragSortable, initialFolding = false, // Initial multi-drag fold when drag started folding = false, // Folding any other time dragStarted = false, dragEl$1, clonesFromRect, clonesHidden; function MultiDragPlugin() { function MultiDrag(sortable) { // Bind all private methods for (var fn in this) { if (fn.charAt(0) === '_' && typeof this[fn] === 'function') { this[fn] = this[fn].bind(this); } } if (!sortable.options.avoidImplicitDeselect) { if (sortable.options.supportPointer) { on(document, 'pointerup', this._deselectMultiDrag); } else { on(document, 'mouseup', this._deselectMultiDrag); on(document, 'touchend', this._deselectMultiDrag); } } on(document, 'keydown', this._checkKeyDown); on(document, 'keyup', this._checkKeyUp); this.defaults = { selectedClass: 'sortable-selected', multiDragKey: null, avoidImplicitDeselect: false, setData: function setData(dataTransfer, dragEl) { var data = ''; if (multiDragElements.length && multiDragSortable === sortable) { multiDragElements.forEach(function (multiDragElement, i) { data += (!i ? '' : ', ') + multiDragElement.textContent; }); } else { data = dragEl.textContent; } dataTransfer.setData('Text', data); } }; } MultiDrag.prototype = { multiDragKeyDown: false, isMultiDrag: false, delayStartGlobal: function delayStartGlobal(_ref) { var dragged = _ref.dragEl; dragEl$1 = dragged; }, delayEnded: function delayEnded() { this.isMultiDrag = ~multiDragElements.indexOf(dragEl$1); }, setupClone: function setupClone(_ref2) { var sortable = _ref2.sortable, cancel = _ref2.cancel; if (!this.isMultiDrag) return; for (var i = 0; i < multiDragElements.length; i++) { multiDragClones.push(clone(multiDragElements[i])); multiDragClones[i].sortableIndex = multiDragElements[i].sortableIndex; multiDragClones[i].draggable = false; multiDragClones[i].style['will-change'] = ''; toggleClass(multiDragClones[i], this.options.selectedClass, false); multiDragElements[i] === dragEl$1 && toggleClass(multiDragClones[i], this.options.chosenClass, false); } sortable._hideClone(); cancel(); }, clone: function clone(_ref3) { var sortable = _ref3.sortable, rootEl = _ref3.rootEl, dispatchSortableEvent = _ref3.dispatchSortableEvent, cancel = _ref3.cancel; if (!this.isMultiDrag) return; if (!this.options.removeCloneOnHide) { if (multiDragElements.length && multiDragSortable === sortable) { insertMultiDragClones(true, rootEl); dispatchSortableEvent('clone'); cancel(); } } }, showClone: function showClone(_ref4) { var cloneNowShown = _ref4.cloneNowShown, rootEl = _ref4.rootEl, cancel = _ref4.cancel; if (!this.isMultiDrag) return; insertMultiDragClones(false, rootEl); multiDragClones.forEach(function (clone) { css(clone, 'display', ''); }); cloneNowShown(); clonesHidden = false; cancel(); }, hideClone: function hideClone(_ref5) { var _this = this; var sortable = _ref5.sortable, cloneNowHidden = _ref5.cloneNowHidden, cancel = _ref5.cancel; if (!this.isMultiDrag) return; multiDragClones.forEach(function (clone) { css(clone, 'display', 'none'); if (_this.options.removeCloneOnHide && clone.parentNode) { clone.parentNode.removeChild(clone); } }); cloneNowHidden(); clonesHidden = true; cancel(); }, dragStartGlobal: function dragStartGlobal(_ref6) { var sortable = _ref6.sortable; if (!this.isMultiDrag && multiDragSortable) { multiDragSortable.multiDrag._deselectMultiDrag(); } multiDragElements.forEach(function (multiDragElement) { multiDragElement.sortableIndex = index(multiDragElement); }); // Sort multi-drag elements multiDragElements = multiDragElements.sort(function (a, b) { return a.sortableIndex - b.sortableIndex; }); dragStarted = true; }, dragStarted: function dragStarted(_ref7) { var _this2 = this; var sortable = _ref7.sortable; if (!this.isMultiDrag) return; if (this.options.sort) { // Capture rects, // hide multi drag elements (by positioning them absolute), // set multi drag elements rects to dragRect, // show multi drag elements, // animate to rects, // unset rects & remove from DOM sortable.captureAnimationState(); if (this.options.animation) { multiDragElements.forEach(function (multiDragElement) { if (multiDragElement === dragEl$1) return; css(multiDragElement, 'position', 'absolute'); }); var dragRect = getRect(dragEl$1, false, true, true); multiDragElements.forEach(function (multiDragElement) { if (multiDragElement === dragEl$1) return; setRect(multiDragElement, dragRect); }); folding = true; initialFolding = true; } } sortable.animateAll(function () { folding = false; initialFolding = false; if (_this2.options.animation) { multiDragElements.forEach(function (multiDragElement) { unsetRect(multiDragElement); }); } // Remove all auxiliary multidrag items from el, if sorting enabled if (_this2.options.sort) { removeMultiDragElements(); } }); }, dragOver: function dragOver(_ref8) { var target = _ref8.target, completed = _ref8.completed, cancel = _ref8.cancel; if (folding && ~multiDragElements.indexOf(target)) { completed(false); cancel(); } }, revert: function revert(_ref9) { var fromSortable = _ref9.fromSortable, rootEl = _ref9.rootEl, sortable = _ref9.sortable, dragRect = _ref9.dragRect; if (multiDragElements.length > 1) { // Setup unfold animation multiDragElements.forEach(function (multiDragElement) { sortable.addAnimationState({ target: multiDragElement, rect: folding ? getRect(multiDragElement) : dragRect }); unsetRect(multiDragElement); multiDragElement.fromRect = dragRect; fromSortable.removeAnimationState(multiDragElement); }); folding = false; insertMultiDragElements(!this.options.removeCloneOnHide, rootEl); } }, dragOverCompleted: function dragOverCompleted(_ref10) { var sortable = _ref10.sortable, isOwner = _ref10.isOwner, insertion = _ref10.insertion, activeSortable = _ref10.activeSortable, parentEl = _ref10.parentEl, putSortable = _ref10.putSortable; var options = this.options; if (insertion) { // Clones must be hidden before folding animation to capture dragRectAbsolute properly if (isOwner) { activeSortable._hideClone(); } initialFolding = false; // If leaving sort:false root, or already folding - Fold to new location if (options.animation && multiDragElements.length > 1 && (folding || !isOwner && !activeSortable.options.sort && !putSortable)) { // Fold: Set all multi drag elements's rects to dragEl's rect when multi-drag elements are invisible var dragRectAbsolute = getRect(dragEl$1, false, true, true); multiDragElements.forEach(function (multiDragElement) { if (multiDragElement === dragEl$1) return; setRect(multiDragElement, dragRectAbsolute); // Move element(s) to end of parentEl so that it does not interfere with multi-drag clones insertion if they are inserted // while folding, and so that we can capture them again because old sortable will no longer be fromSortable parentEl.appendChild(multiDragElement); }); folding = true; } // Clones must be shown (and check to remove multi drags) after folding when interfering multiDragElements are moved out if (!isOwner) { // Only remove if not folding (folding will remove them anyways) if (!folding) { removeMultiDragElements(); } if (multiDragElements.length > 1) { var clonesHiddenBefore = clonesHidden; activeSortable._showClone(sortable); // Unfold animation for clones if showing from hidden if (activeSortable.options.animation && !clonesHidden && clonesHiddenBefore) { multiDragClones.forEach(function (clone) { activeSortable.addAnimationState({ target: clone, rect: clonesFromRect }); clone.fromRect = clonesFromRect; clone.thisAnimationDuration = null; }); } } else { activeSortable._showClone(sortable); } } } }, dragOverAnimationCapture: function dragOverAnimationCapture(_ref11) { var dragRect = _ref11.dragRect, isOwner = _ref11.isOwner, activeSortable = _ref11.activeSortable; multiDragElements.forEach(function (multiDragElement) { multiDragElement.thisAnimationDuration = null; }); if (activeSortable.options.animation && !isOwner && activeSortable.multiDrag.isMultiDrag) { clonesFromRect = _extends({}, dragRect); var dragMatrix = matrix(dragEl$1, true); clonesFromRect.top -= dragMatrix.f; clonesFromRect.left -= dragMatrix.e; } }, dragOverAnimationComplete: function dragOverAnimationComplete() { if (folding) { folding = false; removeMultiDragElements(); } }, drop: function drop(_ref12) { var evt = _ref12.originalEvent, rootEl = _ref12.rootEl, parentEl = _ref12.parentEl, sortable = _ref12.sortable, dispatchSortableEvent = _ref12.dispatchSortableEvent, oldIndex = _ref12.oldIndex, putSortable = _ref12.putSortable; var toSortable = putSortable || this.sortable; if (!evt) return; var options = this.options, children = parentEl.children; // Multi-drag selection if (!dragStarted) { if (options.multiDragKey && !this.multiDragKeyDown) { this._deselectMultiDrag(); } toggleClass(dragEl$1, options.selectedClass, !~multiDragElements.indexOf(dragEl$1)); if (!~multiDragElements.indexOf(dragEl$1)) { multiDragElements.push(dragEl$1); dispatchEvent({ sortable: sortable, rootEl: rootEl, name: 'select', targetEl: dragEl$1, originalEvent: evt }); // Modifier activated, select from last to dragEl if (evt.shiftKey && lastMultiDragSelect && sortable.el.contains(lastMultiDragSelect)) { var lastIndex = index(lastMultiDragSelect), currentIndex = index(dragEl$1); if (~lastIndex && ~currentIndex && lastIndex !== currentIndex) { (function () { // Must include lastMultiDragSelect (select it), in case modified selection from no selection // (but previous selection existed) var n, i; if (currentIndex > lastIndex) { i = lastIndex; n = currentIndex; } else { i = currentIndex; n = lastIndex + 1; } var filter = options.filter; for (; i < n; i++) { if (~multiDragElements.indexOf(children[i])) continue; // Check if element is draggable if (!closest(children[i], options.draggable, parentEl, false)) continue; // Check if element is filtered var filtered = filter && (typeof filter === 'function' ? filter.call(sortable, evt, children[i], sortable) : filter.split(',').some(function (criteria) { return closest(children[i], criteria.trim(), parentEl, false); })); if (filtered) continue; toggleClass(children[i], options.selectedClass, true); multiDragElements.push(children[i]); dispatchEvent({ sortable: sortable, rootEl: rootEl, name: 'select', targetEl: children[i], originalEvent: evt }); } })(); } } else { lastMultiDragSelect = dragEl$1; } multiDragSortable = toSortable; } else { multiDragElements.splice(multiDragElements.indexOf(dragEl$1), 1); lastMultiDragSelect = null; dispatchEvent({ sortable: sortable, rootEl: rootEl, name: 'deselect', targetEl: dragEl$1, originalEvent: evt }); } } // Multi-drag drop if (dragStarted && this.isMultiDrag) { folding = false; // Do not "unfold" after around dragEl if reverted if ((parentEl[expando].options.sort || parentEl !== rootEl) && multiDragElements.length > 1) { var dragRect = getRect(dragEl$1), multiDragIndex = index(dragEl$1, ':not(.' + this.options.selectedClass + ')'); if (!initialFolding && options.animation) dragEl$1.thisAnimationDuration = null; toSortable.captureAnimationState(); if (!initialFolding) { if (options.animation) { dragEl$1.fromRect = dragRect; multiDragElements.forEach(function (multiDragElement) { multiDragElement.thisAnimationDuration = null; if (multiDragElement !== dragEl$1) { var rect = folding ? getRect(multiDragElement) : dragRect; multiDragElement.fromRect = rect; // Prepare unfold animation toSortable.addAnimationState({ target: multiDragElement, rect: rect }); } }); } // Multi drag elements are not necessarily removed from the DOM on drop, so to reinsert // properly they must all be removed removeMultiDragElements(); multiDragElements.forEach(function (multiDragElement) { if (children[multiDragIndex]) { parentEl.insertBefore(multiDragElement, children[multiDragIndex]); } else { parentEl.appendChild(multiDragElement); } multiDragIndex++; }); // If initial folding is done, the elements may have changed position because they are now // unfolding around dragEl, even though dragEl may not have his index changed, so update event // must be fired here as Sortable will not. if (oldIndex === index(dragEl$1)) { var update = false; multiDragElements.forEach(function (multiDragElement) { if (multiDragElement.sortableIndex !== index(multiDragElement)) { update = true; return; } }); if (update) { dispatchSortableEvent('update'); dispatchSortableEvent('sort'); } } } // Must be done after capturing individual rects (scroll bar) multiDragElements.forEach(function (multiDragElement) { unsetRect(multiDragElement); }); toSortable.animateAll(); } multiDragSortable = toSortable; } // Remove clones if necessary if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') { multiDragClones.forEach(function (clone) { clone.parentNode && clone.parentNode.removeChild(clone); }); } }, nullingGlobal: function nullingGlobal() { this.isMultiDrag = dragStarted = false; multiDragClones.length = 0; }, destroyGlobal: function destroyGlobal() { this._deselectMultiDrag(); off(document, 'pointerup', this._deselectMultiDrag); off(document, 'mouseup', this._deselectMultiDrag); off(document, 'touchend', this._deselectMultiDrag); off(document, 'keydown', this._checkKeyDown); off(document, 'keyup', this._checkKeyUp); }, _deselectMultiDrag: function _deselectMultiDrag(evt) { if (typeof dragStarted !== "undefined" && dragStarted) return; // Only deselect if selection is in this sortable if (multiDragSortable !== this.sortable) return; // Only deselect if target is not item in this sortable if (evt && closest(evt.target, this.options.draggable, this.sortable.el, false)) return; // Only deselect if left click if (evt && evt.button !== 0) return; while (multiDragElements.length) { var el = multiDragElements[0]; toggleClass(el, this.options.selectedClass, false); multiDragElements.shift(); dispatchEvent({ sortable: this.sortable, rootEl: this.sortable.el, name: 'deselect', targetEl: el, originalEvent: evt }); } }, _checkKeyDown: function _checkKeyDown(evt) { if (evt.key === this.options.multiDragKey) { this.multiDragKeyDown = true; } }, _checkKeyUp: function _checkKeyUp(evt) { if (evt.key === this.options.multiDragKey) { this.multiDragKeyDown = false; } } }; return _extends(MultiDrag, { // Static methods & properties pluginName: 'multiDrag', utils: { /** * Selects the provided multi-drag item * @param {HTMLElement} el The element to be selected */ select: function select(el) { var sortable = el.parentNode[expando]; if (!sortable || !sortable.options.multiDrag || ~multiDragElements.indexOf(el)) return; if (multiDragSortable && multiDragSortable !== sortable) { multiDragSortable.multiDrag._deselectMultiDrag(); multiDragSortable = sortable; } toggleClass(el, sortable.options.selectedClass, true); multiDragElements.push(el); }, /** * Deselects the provided multi-drag item * @param {HTMLElement} el The element to be deselected */ deselect: function deselect(el) { var sortable = el.parentNode[expando], index = multiDragElements.indexOf(el); if (!sortable || !sortable.options.multiDrag || !~index) return; toggleClass(el, sortable.options.selectedClass, false); multiDragElements.splice(index, 1); } }, eventProperties: function eventProperties() { var _this3 = this; var oldIndicies = [], newIndicies = []; multiDragElements.forEach(function (multiDragElement) { oldIndicies.push({ multiDragElement: multiDragElement, index: multiDragElement.sortableIndex }); // multiDragElements will already be sorted if folding var newIndex; if (folding && multiDragElement !== dragEl$1) { newIndex = -1; } else if (folding) { newIndex = index(multiDragElement, ':not(.' + _this3.options.selectedClass + ')'); } else { newIndex = index(multiDragElement); } newIndicies.push({ multiDragElement: multiDragElement, index: newIndex }); }); return { items: _toConsumableArray(multiDragElements), clones: [].concat(multiDragClones), oldIndicies: oldIndicies, newIndicies: newIndicies }; }, optionListeners: { multiDragKey: function multiDragKey(key) { key = key.toLowerCase(); if (key === 'ctrl') { key = 'Control'; } else if (key.length > 1) { key = key.charAt(0).toUpperCase() + key.substr(1); } return key; } } }); } function insertMultiDragElements(clonesInserted, rootEl) { multiDragElements.forEach(function (multiDragElement, i) { var target = rootEl.children[multiDragElement.sortableIndex + (clonesInserted ? Number(i) : 0)]; if (target) { rootEl.insertBefore(multiDragElement, target); } else { rootEl.appendChild(multiDragElement); } }); } /** * Insert multi-drag clones * @param {[Boolean]} elementsInserted Whether the multi-drag elements are inserted * @param {HTMLElement} rootEl */ function insertMultiDragClones(elementsInserted, rootEl) { multiDragClones.forEach(function (clone, i) { var target = rootEl.children[clone.sortableIndex + (elementsInserted ? Number(i) : 0)]; if (target) { rootEl.insertBefore(clone, target); } else { rootEl.appendChild(clone); } }); } function removeMultiDragElements() { multiDragElements.forEach(function (multiDragElement) { if (multiDragElement === dragEl$1) return; multiDragElement.parentNode && multiDragElement.parentNode.removeChild(multiDragElement); }); } Sortable.mount(new AutoScrollPlugin()); Sortable.mount(Remove, Revert); /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Sortable); /***/ }, /***/ "./node_modules/toastify-js/src/toastify.css" /*!***************************************************!*\ !*** ./node_modules/toastify-js/src/toastify.css ***! \***************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var _style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! !../../style-loader/dist/runtime/injectStylesIntoStyleTag.js */ "./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js"); /* harmony import */ var _style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! !../../style-loader/dist/runtime/styleDomAPI.js */ "./node_modules/style-loader/dist/runtime/styleDomAPI.js"); /* harmony import */ var _style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! !../../style-loader/dist/runtime/insertBySelector.js */ "./node_modules/style-loader/dist/runtime/insertBySelector.js"); /* harmony import */ var _style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! !../../style-loader/dist/runtime/setAttributesWithoutAttributes.js */ "./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js"); /* harmony import */ var _style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__); /* harmony import */ var _style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! !../../style-loader/dist/runtime/insertStyleElement.js */ "./node_modules/style-loader/dist/runtime/insertStyleElement.js"); /* harmony import */ var _style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__); /* harmony import */ var _style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! !../../style-loader/dist/runtime/styleTagTransform.js */ "./node_modules/style-loader/dist/runtime/styleTagTransform.js"); /* harmony import */ var _style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__); /* harmony import */ var _css_loader_dist_cjs_js_toastify_css__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! !!../../css-loader/dist/cjs.js!./toastify.css */ "./node_modules/css-loader/dist/cjs.js!./node_modules/toastify-js/src/toastify.css"); var options = {}; options.styleTagTransform = (_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default()); options.setAttributes = (_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default()); options.insert = _style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default().bind(null, "head"); options.domAPI = (_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default()); options.insertStyleElement = (_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default()); var update = _style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default()(_css_loader_dist_cjs_js_toastify_css__WEBPACK_IMPORTED_MODULE_6__["default"], options); /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_css_loader_dist_cjs_js_toastify_css__WEBPACK_IMPORTED_MODULE_6__["default"] && _css_loader_dist_cjs_js_toastify_css__WEBPACK_IMPORTED_MODULE_6__["default"].locals ? _css_loader_dist_cjs_js_toastify_css__WEBPACK_IMPORTED_MODULE_6__["default"].locals : undefined); /***/ }, /***/ "./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js" /*!****************************************************************************!*\ !*** ./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js ***! \****************************************************************************/ (module) { "use strict"; var stylesInDOM = []; function getIndexByIdentifier(identifier) { var result = -1; for (var i = 0; i < stylesInDOM.length; i++) { if (stylesInDOM[i].identifier === identifier) { result = i; break; } } return result; } function modulesToDom(list, options) { var idCountMap = {}; var identifiers = []; for (var i = 0; i < list.length; i++) { var item = list[i]; var id = options.base ? item[0] + options.base : item[0]; var count = idCountMap[id] || 0; var identifier = "".concat(id, " ").concat(count); idCountMap[id] = count + 1; var indexByIdentifier = getIndexByIdentifier(identifier); var obj = { css: item[1], media: item[2], sourceMap: item[3], supports: item[4], layer: item[5] }; if (indexByIdentifier !== -1) { stylesInDOM[indexByIdentifier].references++; stylesInDOM[indexByIdentifier].updater(obj); } else { var updater = addElementStyle(obj, options); options.byIndex = i; stylesInDOM.splice(i, 0, { identifier: identifier, updater: updater, references: 1 }); } identifiers.push(identifier); } return identifiers; } function addElementStyle(obj, options) { var api = options.domAPI(options); api.update(obj); var updater = function updater(newObj) { if (newObj) { if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap && newObj.supports === obj.supports && newObj.layer === obj.layer) { return; } api.update(obj = newObj); } else { api.remove(); } }; return updater; } module.exports = function (list, options) { options = options || {}; list = list || []; var lastIdentifiers = modulesToDom(list, options); return function update(newList) { newList = newList || []; for (var i = 0; i < lastIdentifiers.length; i++) { var identifier = lastIdentifiers[i]; var index = getIndexByIdentifier(identifier); stylesInDOM[index].references--; } var newLastIdentifiers = modulesToDom(newList, options); for (var _i = 0; _i < lastIdentifiers.length; _i++) { var _identifier = lastIdentifiers[_i]; var _index = getIndexByIdentifier(_identifier); if (stylesInDOM[_index].references === 0) { stylesInDOM[_index].updater(); stylesInDOM.splice(_index, 1); } } lastIdentifiers = newLastIdentifiers; }; }; /***/ }, /***/ "./node_modules/style-loader/dist/runtime/insertBySelector.js" /*!********************************************************************!*\ !*** ./node_modules/style-loader/dist/runtime/insertBySelector.js ***! \********************************************************************/ (module) { "use strict"; var memo = {}; /* istanbul ignore next */ function getTarget(target) { if (typeof memo[target] === "undefined") { var styleTarget = document.querySelector(target); // Special case to return head of iframe instead of iframe itself if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) { try { // This will throw an exception if access to iframe is blocked // due to cross-origin restrictions styleTarget = styleTarget.contentDocument.head; } catch (e) { // istanbul ignore next styleTarget = null; } } memo[target] = styleTarget; } return memo[target]; } /* istanbul ignore next */ function insertBySelector(insert, style) { var target = getTarget(insert); if (!target) { throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid."); } target.appendChild(style); } module.exports = insertBySelector; /***/ }, /***/ "./node_modules/style-loader/dist/runtime/insertStyleElement.js" /*!**********************************************************************!*\ !*** ./node_modules/style-loader/dist/runtime/insertStyleElement.js ***! \**********************************************************************/ (module) { "use strict"; /* istanbul ignore next */ function insertStyleElement(options) { var element = document.createElement("style"); options.setAttributes(element, options.attributes); options.insert(element, options.options); return element; } module.exports = insertStyleElement; /***/ }, /***/ "./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js" /*!**********************************************************************************!*\ !*** ./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js ***! \**********************************************************************************/ (module, __unused_webpack_exports, __webpack_require__) { "use strict"; /* istanbul ignore next */ function setAttributesWithoutAttributes(styleElement) { var nonce = true ? __webpack_require__.nc : 0; if (nonce) { styleElement.setAttribute("nonce", nonce); } } module.exports = setAttributesWithoutAttributes; /***/ }, /***/ "./node_modules/style-loader/dist/runtime/styleDomAPI.js" /*!***************************************************************!*\ !*** ./node_modules/style-loader/dist/runtime/styleDomAPI.js ***! \***************************************************************/ (module) { "use strict"; /* istanbul ignore next */ function apply(styleElement, options, obj) { var css = ""; if (obj.supports) { css += "@supports (".concat(obj.supports, ") {"); } if (obj.media) { css += "@media ".concat(obj.media, " {"); } var needLayer = typeof obj.layer !== "undefined"; if (needLayer) { css += "@layer".concat(obj.layer.length > 0 ? " ".concat(obj.layer) : "", " {"); } css += obj.css; if (needLayer) { css += "}"; } if (obj.media) { css += "}"; } if (obj.supports) { css += "}"; } var sourceMap = obj.sourceMap; if (sourceMap && typeof btoa !== "undefined") { css += "\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))), " */"); } // For old IE /* istanbul ignore if */ options.styleTagTransform(css, styleElement, options.options); } function removeStyleElement(styleElement) { // istanbul ignore if if (styleElement.parentNode === null) { return false; } styleElement.parentNode.removeChild(styleElement); } /* istanbul ignore next */ function domAPI(options) { if (typeof document === "undefined") { return { update: function update() {}, remove: function remove() {} }; } var styleElement = options.insertStyleElement(options); return { update: function update(obj) { apply(styleElement, options, obj); }, remove: function remove() { removeStyleElement(styleElement); } }; } module.exports = domAPI; /***/ }, /***/ "./node_modules/style-loader/dist/runtime/styleTagTransform.js" /*!*********************************************************************!*\ !*** ./node_modules/style-loader/dist/runtime/styleTagTransform.js ***! \*********************************************************************/ (module) { "use strict"; /* istanbul ignore next */ function styleTagTransform(css, styleElement) { if (styleElement.styleSheet) { styleElement.styleSheet.cssText = css; } else { while (styleElement.firstChild) { styleElement.removeChild(styleElement.firstChild); } styleElement.appendChild(document.createTextNode(css)); } } module.exports = styleTagTransform; /***/ }, /***/ "./node_modules/sweetalert2/dist/sweetalert2.all.js" /*!**********************************************************!*\ !*** ./node_modules/sweetalert2/dist/sweetalert2.all.js ***! \**********************************************************/ (module) { /*! * sweetalert2 v11.26.17 * Released under the MIT License. */ (function (global, factory) { true ? module.exports = factory() : 0; })(this, (function () { 'use strict'; function _assertClassBrand(e, t, n) { if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n; throw new TypeError("Private element is not present on this object"); } function _checkPrivateRedeclaration(e, t) { if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object"); } function _classPrivateFieldGet2(s, a) { return s.get(_assertClassBrand(s, a)); } function _classPrivateFieldInitSpec(e, t, a) { _checkPrivateRedeclaration(e, t), t.set(e, a); } function _classPrivateFieldSet2(s, a, r) { return s.set(_assertClassBrand(s, a), r), r; } const RESTORE_FOCUS_TIMEOUT = 100; /** @type {GlobalState} */ const globalState = {}; const focusPreviousActiveElement = () => { if (globalState.previousActiveElement instanceof HTMLElement) { globalState.previousActiveElement.focus(); globalState.previousActiveElement = null; } else if (document.body) { document.body.focus(); } }; /** * Restore previous active (focused) element * * @param {boolean} returnFocus * @returns {Promise} */ const restoreActiveElement = returnFocus => { return new Promise(resolve => { if (!returnFocus) { return resolve(); } const x = window.scrollX; const y = window.scrollY; globalState.restoreFocusTimeout = setTimeout(() => { focusPreviousActiveElement(); resolve(); }, RESTORE_FOCUS_TIMEOUT); // issues/900 window.scrollTo(x, y); }); }; const swalPrefix = 'swal2-'; /** * @typedef {Record} SwalClasses */ /** * @typedef {'success' | 'warning' | 'info' | 'question' | 'error'} SwalIcon * @typedef {Record} SwalIcons */ /** @type {SwalClass[]} */ const classNames = ['container', 'shown', 'height-auto', 'iosfix', 'popup', 'modal', 'no-backdrop', 'no-transition', 'toast', 'toast-shown', 'show', 'hide', 'close', 'title', 'html-container', 'actions', 'confirm', 'deny', 'cancel', 'footer', 'icon', 'icon-content', 'image', 'input', 'file', 'range', 'select', 'radio', 'checkbox', 'label', 'textarea', 'inputerror', 'input-label', 'validation-message', 'progress-steps', 'active-progress-step', 'progress-step', 'progress-step-line', 'loader', 'loading', 'styled', 'top', 'top-start', 'top-end', 'top-left', 'top-right', 'center', 'center-start', 'center-end', 'center-left', 'center-right', 'bottom', 'bottom-start', 'bottom-end', 'bottom-left', 'bottom-right', 'grow-row', 'grow-column', 'grow-fullscreen', 'rtl', 'timer-progress-bar', 'timer-progress-bar-container', 'scrollbar-measure', 'icon-success', 'icon-warning', 'icon-info', 'icon-question', 'icon-error', 'draggable', 'dragging']; const swalClasses = classNames.reduce((acc, className) => { acc[className] = swalPrefix + className; return acc; }, /** @type {SwalClasses} */{}); /** @type {SwalIcon[]} */ const icons = ['success', 'warning', 'info', 'question', 'error']; const iconTypes = icons.reduce((acc, icon) => { acc[icon] = swalPrefix + icon; return acc; }, /** @type {SwalIcons} */{}); const consolePrefix = 'SweetAlert2:'; /** * Capitalize the first letter of a string * * @param {string} str * @returns {string} */ const capitalizeFirstLetter = str => str.charAt(0).toUpperCase() + str.slice(1); /** * Standardize console warnings * * @param {string | string[]} message */ const warn = message => { console.warn(`${consolePrefix} ${typeof message === 'object' ? message.join(' ') : message}`); }; /** * Standardize console errors * * @param {string} message */ const error = message => { console.error(`${consolePrefix} ${message}`); }; /** * Private global state for `warnOnce` * * @type {string[]} * @private */ const previousWarnOnceMessages = []; /** * Show a console warning, but only if it hasn't already been shown * * @param {string} message */ const warnOnce = message => { if (!previousWarnOnceMessages.includes(message)) { previousWarnOnceMessages.push(message); warn(message); } }; /** * Show a one-time console warning about deprecated params/methods * * @param {string} deprecatedParam * @param {string?} useInstead */ const warnAboutDeprecation = (deprecatedParam, useInstead = null) => { warnOnce(`"${deprecatedParam}" is deprecated and will be removed in the next major release.${useInstead ? ` Use "${useInstead}" instead.` : ''}`); }; /** * If `arg` is a function, call it (with no arguments or context) and return the result. * Otherwise, just pass the value through * * @param {(() => *) | *} arg * @returns {*} */ const callIfFunction = arg => typeof arg === 'function' ? arg() : arg; /** * @param {*} arg * @returns {boolean} */ const hasToPromiseFn = arg => arg && typeof arg.toPromise === 'function'; /** * @param {*} arg * @returns {Promise<*>} */ const asPromise = arg => hasToPromiseFn(arg) ? arg.toPromise() : Promise.resolve(arg); /** * @param {*} arg * @returns {boolean} */ const isPromise = arg => arg && Promise.resolve(arg) === arg; /** * Gets the popup container which contains the backdrop and the popup itself. * * @returns {HTMLElement | null} */ const getContainer = () => document.body.querySelector(`.${swalClasses.container}`); /** * @param {string} selectorString * @returns {HTMLElement | null} */ const elementBySelector = selectorString => { const container = getContainer(); return container ? container.querySelector(selectorString) : null; }; /** * @param {string} className * @returns {HTMLElement | null} */ const elementByClass = className => { return elementBySelector(`.${className}`); }; /** * @returns {HTMLElement | null} */ const getPopup = () => elementByClass(swalClasses.popup); /** * @returns {HTMLElement | null} */ const getIcon = () => elementByClass(swalClasses.icon); /** * @returns {HTMLElement | null} */ const getIconContent = () => elementByClass(swalClasses['icon-content']); /** * @returns {HTMLElement | null} */ const getTitle = () => elementByClass(swalClasses.title); /** * @returns {HTMLElement | null} */ const getHtmlContainer = () => elementByClass(swalClasses['html-container']); /** * @returns {HTMLElement | null} */ const getImage = () => elementByClass(swalClasses.image); /** * @returns {HTMLElement | null} */ const getProgressSteps = () => elementByClass(swalClasses['progress-steps']); /** * @returns {HTMLElement | null} */ const getValidationMessage = () => elementByClass(swalClasses['validation-message']); /** * @returns {HTMLButtonElement | null} */ const getConfirmButton = () => (/** @type {HTMLButtonElement} */elementBySelector(`.${swalClasses.actions} .${swalClasses.confirm}`)); /** * @returns {HTMLButtonElement | null} */ const getCancelButton = () => (/** @type {HTMLButtonElement} */elementBySelector(`.${swalClasses.actions} .${swalClasses.cancel}`)); /** * @returns {HTMLButtonElement | null} */ const getDenyButton = () => (/** @type {HTMLButtonElement} */elementBySelector(`.${swalClasses.actions} .${swalClasses.deny}`)); /** * @returns {HTMLElement | null} */ const getInputLabel = () => elementByClass(swalClasses['input-label']); /** * @returns {HTMLElement | null} */ const getLoader = () => elementBySelector(`.${swalClasses.loader}`); /** * @returns {HTMLElement | null} */ const getActions = () => elementByClass(swalClasses.actions); /** * @returns {HTMLElement | null} */ const getFooter = () => elementByClass(swalClasses.footer); /** * @returns {HTMLElement | null} */ const getTimerProgressBar = () => elementByClass(swalClasses['timer-progress-bar']); /** * @returns {HTMLElement | null} */ const getCloseButton = () => elementByClass(swalClasses.close); // https://github.com/jkup/focusable/blob/master/index.js const focusable = ` a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex="0"], [contenteditable], audio[controls], video[controls], summary `; /** * @returns {HTMLElement[]} */ const getFocusableElements = () => { const popup = getPopup(); if (!popup) { return []; } /** @type {NodeListOf} */ const focusableElementsWithTabindex = popup.querySelectorAll('[tabindex]:not([tabindex="-1"]):not([tabindex="0"])'); const focusableElementsWithTabindexSorted = Array.from(focusableElementsWithTabindex) // sort according to tabindex .sort((a, b) => { const tabindexA = parseInt(a.getAttribute('tabindex') || '0'); const tabindexB = parseInt(b.getAttribute('tabindex') || '0'); if (tabindexA > tabindexB) { return 1; } else if (tabindexA < tabindexB) { return -1; } return 0; }); /** @type {NodeListOf} */ const otherFocusableElements = popup.querySelectorAll(focusable); const otherFocusableElementsFiltered = Array.from(otherFocusableElements).filter(el => el.getAttribute('tabindex') !== '-1'); return [...new Set(focusableElementsWithTabindexSorted.concat(otherFocusableElementsFiltered))].filter(el => isVisible$1(el)); }; /** * @returns {boolean} */ const isModal = () => { return hasClass(document.body, swalClasses.shown) && !hasClass(document.body, swalClasses['toast-shown']) && !hasClass(document.body, swalClasses['no-backdrop']); }; /** * @returns {boolean} */ const isToast = () => { const popup = getPopup(); if (!popup) { return false; } return hasClass(popup, swalClasses.toast); }; /** * @returns {boolean} */ const isLoading = () => { const popup = getPopup(); if (!popup) { return false; } return popup.hasAttribute('data-loading'); }; /** * Securely set innerHTML of an element * https://github.com/sweetalert2/sweetalert2/issues/1926 * * @param {HTMLElement} elem * @param {string} html */ const setInnerHtml = (elem, html) => { elem.textContent = ''; if (html) { const parser = new DOMParser(); const parsed = parser.parseFromString(html, `text/html`); const head = parsed.querySelector('head'); if (head) { Array.from(head.childNodes).forEach(child => { elem.appendChild(child); }); } const body = parsed.querySelector('body'); if (body) { Array.from(body.childNodes).forEach(child => { if (child instanceof HTMLVideoElement || child instanceof HTMLAudioElement) { elem.appendChild(child.cloneNode(true)); // https://github.com/sweetalert2/sweetalert2/issues/2507 } else { elem.appendChild(child); } }); } } }; /** * @param {HTMLElement} elem * @param {string} className * @returns {boolean} */ const hasClass = (elem, className) => { if (!className) { return false; } const classList = className.split(/\s+/); for (let i = 0; i < classList.length; i++) { if (!elem.classList.contains(classList[i])) { return false; } } return true; }; /** * @param {HTMLElement} elem * @param {SweetAlertOptions} params */ const removeCustomClasses = (elem, params) => { Array.from(elem.classList).forEach(className => { if (!Object.values(swalClasses).includes(className) && !Object.values(iconTypes).includes(className) && !Object.values(params.showClass || {}).includes(className)) { elem.classList.remove(className); } }); }; /** * @param {HTMLElement} elem * @param {SweetAlertOptions} params * @param {string} className */ const applyCustomClass = (elem, params, className) => { removeCustomClasses(elem, params); if (!params.customClass) { return; } const customClass = params.customClass[(/** @type {keyof SweetAlertCustomClass} */className)]; if (!customClass) { return; } if (typeof customClass !== 'string' && !customClass.forEach) { warn(`Invalid type of customClass.${className}! Expected string or iterable object, got "${typeof customClass}"`); return; } addClass(elem, customClass); }; /** * @param {HTMLElement} popup * @param {import('./renderers/renderInput').InputClass | SweetAlertInput} inputClass * @returns {HTMLInputElement | null} */ const getInput$1 = (popup, inputClass) => { if (!inputClass) { return null; } switch (inputClass) { case 'select': case 'textarea': case 'file': return popup.querySelector(`.${swalClasses.popup} > .${swalClasses[inputClass]}`); case 'checkbox': return popup.querySelector(`.${swalClasses.popup} > .${swalClasses.checkbox} input`); case 'radio': return popup.querySelector(`.${swalClasses.popup} > .${swalClasses.radio} input:checked`) || popup.querySelector(`.${swalClasses.popup} > .${swalClasses.radio} input:first-child`); case 'range': return popup.querySelector(`.${swalClasses.popup} > .${swalClasses.range} input`); default: return popup.querySelector(`.${swalClasses.popup} > .${swalClasses.input}`); } }; /** * @param {HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement} input */ const focusInput = input => { input.focus(); // place cursor at end of text in text input if (input.type !== 'file') { // http://stackoverflow.com/a/2345915 const val = input.value; input.value = ''; input.value = val; } }; /** * @param {HTMLElement | HTMLElement[] | null} target * @param {string | string[] | readonly string[] | undefined} classList * @param {boolean} condition */ const toggleClass = (target, classList, condition) => { if (!target || !classList) { return; } if (typeof classList === 'string') { classList = classList.split(/\s+/).filter(Boolean); } classList.forEach(className => { if (Array.isArray(target)) { target.forEach(elem => { if (condition) { elem.classList.add(className); } else { elem.classList.remove(className); } }); } else { if (condition) { target.classList.add(className); } else { target.classList.remove(className); } } }); }; /** * @param {HTMLElement | HTMLElement[] | null} target * @param {string | string[] | readonly string[] | undefined} classList */ const addClass = (target, classList) => { toggleClass(target, classList, true); }; /** * @param {HTMLElement | HTMLElement[] | null} target * @param {string | string[] | readonly string[] | undefined} classList */ const removeClass = (target, classList) => { toggleClass(target, classList, false); }; /** * Get direct child of an element by class name * * @param {HTMLElement} elem * @param {string} className * @returns {HTMLElement | undefined} */ const getDirectChildByClass = (elem, className) => { const children = Array.from(elem.children); for (let i = 0; i < children.length; i++) { const child = children[i]; if (child instanceof HTMLElement && hasClass(child, className)) { return child; } } }; /** * @param {HTMLElement} elem * @param {string} property * @param {string | number | null | undefined} value */ const applyNumericalStyle = (elem, property, value) => { if (value === `${parseInt(`${value}`)}`) { value = parseInt(value); } if (value || parseInt(`${value}`) === 0) { elem.style.setProperty(property, typeof value === 'number' ? `${value}px` : (/** @type {string} */value)); } else { elem.style.removeProperty(property); } }; /** * @param {HTMLElement | null} elem * @param {string} display */ const show = (elem, display = 'flex') => { if (!elem) { return; } elem.style.display = display; }; /** * @param {HTMLElement | null} elem */ const hide = elem => { if (!elem) { return; } elem.style.display = 'none'; }; /** * @param {HTMLElement | null} elem * @param {string} display */ const showWhenInnerHtmlPresent = (elem, display = 'block') => { if (!elem) { return; } new MutationObserver(() => { toggle(elem, elem.innerHTML, display); }).observe(elem, { childList: true, subtree: true }); }; /** * @param {HTMLElement} parent * @param {string} selector * @param {string} property * @param {string} value */ const setStyle = (parent, selector, property, value) => { /** @type {HTMLElement | null} */ const el = parent.querySelector(selector); if (el) { el.style.setProperty(property, value); } }; /** * @param {HTMLElement} elem * @param {boolean | string | null | undefined} condition * @param {string} display */ const toggle = (elem, condition, display = 'flex') => { if (condition) { show(elem, display); } else { hide(elem); } }; /** * borrowed from jquery $(elem).is(':visible') implementation * * @param {HTMLElement | null} elem * @returns {boolean} */ const isVisible$1 = elem => Boolean(elem && (elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length)); /** * @returns {boolean} */ const allButtonsAreHidden = () => !isVisible$1(getConfirmButton()) && !isVisible$1(getDenyButton()) && !isVisible$1(getCancelButton()); /** * @param {HTMLElement} elem * @returns {boolean} */ const isScrollable = elem => Boolean(elem.scrollHeight > elem.clientHeight); /** * @param {HTMLElement} element * @param {HTMLElement} stopElement * @returns {boolean} */ const selfOrParentIsScrollable = (element, stopElement) => { let parent = /** @type {HTMLElement | null} */element; while (parent && parent !== stopElement) { if (isScrollable(parent)) { return true; } parent = parent.parentElement; } return false; }; /** * borrowed from https://stackoverflow.com/a/46352119 * * @param {HTMLElement} elem * @returns {boolean} */ const hasCssAnimation = elem => { const style = window.getComputedStyle(elem); const animDuration = parseFloat(style.getPropertyValue('animation-duration') || '0'); const transDuration = parseFloat(style.getPropertyValue('transition-duration') || '0'); return animDuration > 0 || transDuration > 0; }; /** * @param {number} timer * @param {boolean} reset */ const animateTimerProgressBar = (timer, reset = false) => { const timerProgressBar = getTimerProgressBar(); if (!timerProgressBar) { return; } if (isVisible$1(timerProgressBar)) { if (reset) { timerProgressBar.style.transition = 'none'; timerProgressBar.style.width = '100%'; } setTimeout(() => { timerProgressBar.style.transition = `width ${timer / 1000}s linear`; timerProgressBar.style.width = '0%'; }, 10); } }; const stopTimerProgressBar = () => { const timerProgressBar = getTimerProgressBar(); if (!timerProgressBar) { return; } const timerProgressBarWidth = parseInt(window.getComputedStyle(timerProgressBar).width); timerProgressBar.style.removeProperty('transition'); timerProgressBar.style.width = '100%'; const timerProgressBarFullWidth = parseInt(window.getComputedStyle(timerProgressBar).width); const timerProgressBarPercent = timerProgressBarWidth / timerProgressBarFullWidth * 100; timerProgressBar.style.width = `${timerProgressBarPercent}%`; }; /** * Detect Node env * * @returns {boolean} */ const isNodeEnv = () => typeof window === 'undefined' || typeof document === 'undefined'; const sweetHTML = `

      `.replace(/(^|\n)\s*/g, ''); /** * @returns {boolean} */ const resetOldContainer = () => { const oldContainer = getContainer(); if (!oldContainer) { return false; } oldContainer.remove(); removeClass([document.documentElement, document.body], [swalClasses['no-backdrop'], swalClasses['toast-shown'], // @ts-ignore: 'has-column' is not defined in swalClasses but may be set dynamically swalClasses['has-column']]); return true; }; const resetValidationMessage$1 = () => { if (globalState.currentInstance) { globalState.currentInstance.resetValidationMessage(); } }; const addInputChangeListeners = () => { const popup = getPopup(); if (!popup) { return; } const input = getDirectChildByClass(popup, swalClasses.input); const file = getDirectChildByClass(popup, swalClasses.file); /** @type {HTMLInputElement | null} */ const range = popup.querySelector(`.${swalClasses.range} input`); /** @type {HTMLOutputElement | null} */ const rangeOutput = popup.querySelector(`.${swalClasses.range} output`); const select = getDirectChildByClass(popup, swalClasses.select); /** @type {HTMLInputElement | null} */ const checkbox = popup.querySelector(`.${swalClasses.checkbox} input`); const textarea = getDirectChildByClass(popup, swalClasses.textarea); if (input) { input.oninput = resetValidationMessage$1; } if (file) { file.onchange = resetValidationMessage$1; } if (select) { select.onchange = resetValidationMessage$1; } if (checkbox) { checkbox.onchange = resetValidationMessage$1; } if (textarea) { textarea.oninput = resetValidationMessage$1; } if (range && rangeOutput) { range.oninput = () => { resetValidationMessage$1(); rangeOutput.value = range.value; }; range.onchange = () => { resetValidationMessage$1(); rangeOutput.value = range.value; }; } }; /** * @param {string | HTMLElement} target * @returns {HTMLElement} */ const getTarget = target => { if (typeof target === 'string') { const element = document.querySelector(target); if (!element) { throw new Error(`Target element "${target}" not found`); } return /** @type {HTMLElement} */element; } return target; }; /** * @param {SweetAlertOptions} params */ const setupAccessibility = params => { const popup = getPopup(); if (!popup) { return; } popup.setAttribute('role', params.toast ? 'alert' : 'dialog'); popup.setAttribute('aria-live', params.toast ? 'polite' : 'assertive'); if (!params.toast) { popup.setAttribute('aria-modal', 'true'); } }; /** * @param {HTMLElement} targetElement */ const setupRTL = targetElement => { if (window.getComputedStyle(targetElement).direction === 'rtl') { addClass(getContainer(), swalClasses.rtl); globalState.isRTL = true; } }; /** * Add modal + backdrop to DOM * * @param {SweetAlertOptions} params */ const init = params => { // Clean up the old popup container if it exists const oldContainerExisted = resetOldContainer(); if (isNodeEnv()) { error('SweetAlert2 requires document to initialize'); return; } const container = document.createElement('div'); container.className = swalClasses.container; if (oldContainerExisted) { addClass(container, swalClasses['no-transition']); } setInnerHtml(container, sweetHTML); container.dataset['swal2Theme'] = params.theme; const targetElement = getTarget(params.target || 'body'); targetElement.appendChild(container); if (params.topLayer) { container.setAttribute('popover', ''); container.showPopover(); } setupAccessibility(params); setupRTL(targetElement); addInputChangeListeners(); }; /** * @param {HTMLElement | object | string} param * @param {HTMLElement} target */ const parseHtmlToContainer = (param, target) => { // DOM element if (param instanceof HTMLElement) { target.appendChild(param); } // Object else if (typeof param === 'object') { handleObject(param, target); } // Plain string else if (param) { setInnerHtml(target, param); } }; /** * @param {object} param * @param {HTMLElement} target */ const handleObject = (param, target) => { // JQuery element(s) if ('jquery' in param) { handleJqueryElem(target, param); } // For other objects use their string representation else { setInnerHtml(target, param.toString()); } }; /** * @param {HTMLElement} target * @param {any} elem */ const handleJqueryElem = (target, elem) => { target.textContent = ''; if (0 in elem) { for (let i = 0; i in elem; i++) { target.appendChild(elem[i].cloneNode(true)); } } else { target.appendChild(elem.cloneNode(true)); } }; /** * @param {SweetAlert} instance * @param {SweetAlertOptions} params */ const renderActions = (instance, params) => { const actions = getActions(); const loader = getLoader(); if (!actions || !loader) { return; } // Actions (buttons) wrapper if (!params.showConfirmButton && !params.showDenyButton && !params.showCancelButton) { hide(actions); } else { show(actions); } // Custom class applyCustomClass(actions, params, 'actions'); // Render all the buttons renderButtons(actions, loader, params); // Loader setInnerHtml(loader, params.loaderHtml || ''); applyCustomClass(loader, params, 'loader'); }; /** * @param {HTMLElement} actions * @param {HTMLElement} loader * @param {SweetAlertOptions} params */ function renderButtons(actions, loader, params) { const confirmButton = getConfirmButton(); const denyButton = getDenyButton(); const cancelButton = getCancelButton(); if (!confirmButton || !denyButton || !cancelButton) { return; } // Render buttons renderButton(confirmButton, 'confirm', params); renderButton(denyButton, 'deny', params); renderButton(cancelButton, 'cancel', params); handleButtonsStyling(confirmButton, denyButton, cancelButton, params); if (params.reverseButtons) { if (params.toast) { actions.insertBefore(cancelButton, confirmButton); actions.insertBefore(denyButton, confirmButton); } else { actions.insertBefore(cancelButton, loader); actions.insertBefore(denyButton, loader); actions.insertBefore(confirmButton, loader); } } } /** * @param {HTMLElement} confirmButton * @param {HTMLElement} denyButton * @param {HTMLElement} cancelButton * @param {SweetAlertOptions} params */ function handleButtonsStyling(confirmButton, denyButton, cancelButton, params) { if (!params.buttonsStyling) { removeClass([confirmButton, denyButton, cancelButton], swalClasses.styled); return; } addClass([confirmButton, denyButton, cancelButton], swalClasses.styled); // Apply custom background colors to action buttons if (params.confirmButtonColor) { confirmButton.style.setProperty('--swal2-confirm-button-background-color', params.confirmButtonColor); } if (params.denyButtonColor) { denyButton.style.setProperty('--swal2-deny-button-background-color', params.denyButtonColor); } if (params.cancelButtonColor) { cancelButton.style.setProperty('--swal2-cancel-button-background-color', params.cancelButtonColor); } // Apply the outline color to action buttons applyOutlineColor(confirmButton); applyOutlineColor(denyButton); applyOutlineColor(cancelButton); } /** * @param {HTMLElement} button */ function applyOutlineColor(button) { const buttonStyle = window.getComputedStyle(button); if (buttonStyle.getPropertyValue('--swal2-action-button-focus-box-shadow')) { // If the button already has a custom outline color, no need to change it return; } const outlineColor = buttonStyle.backgroundColor.replace(/rgba?\((\d+), (\d+), (\d+).*/, 'rgba($1, $2, $3, 0.5)'); button.style.setProperty('--swal2-action-button-focus-box-shadow', buttonStyle.getPropertyValue('--swal2-outline').replace(/ rgba\(.*/, ` ${outlineColor}`)); } /** * @param {HTMLElement} button * @param {'confirm' | 'deny' | 'cancel'} buttonType * @param {SweetAlertOptions} params */ function renderButton(button, buttonType, params) { const buttonName = /** @type {'Confirm' | 'Deny' | 'Cancel'} */capitalizeFirstLetter(buttonType); toggle(button, params[`show${buttonName}Button`], 'inline-block'); setInnerHtml(button, params[`${buttonType}ButtonText`] || ''); // Set caption text button.setAttribute('aria-label', params[`${buttonType}ButtonAriaLabel`] || ''); // ARIA label // Add buttons custom classes button.className = swalClasses[buttonType]; applyCustomClass(button, params, `${buttonType}Button`); } /** * @param {SweetAlert} instance * @param {SweetAlertOptions} params */ const renderCloseButton = (instance, params) => { const closeButton = getCloseButton(); if (!closeButton) { return; } setInnerHtml(closeButton, params.closeButtonHtml || ''); // Custom class applyCustomClass(closeButton, params, 'closeButton'); toggle(closeButton, params.showCloseButton); closeButton.setAttribute('aria-label', params.closeButtonAriaLabel || ''); }; /** * @param {SweetAlert} instance * @param {SweetAlertOptions} params */ const renderContainer = (instance, params) => { const container = getContainer(); if (!container) { return; } handleBackdropParam(container, params.backdrop); handlePositionParam(container, params.position); handleGrowParam(container, params.grow); // Custom class applyCustomClass(container, params, 'container'); }; /** * @param {HTMLElement} container * @param {SweetAlertOptions['backdrop']} backdrop */ function handleBackdropParam(container, backdrop) { if (typeof backdrop === 'string') { container.style.background = backdrop; } else if (!backdrop) { addClass([document.documentElement, document.body], swalClasses['no-backdrop']); } } /** * @param {HTMLElement} container * @param {SweetAlertOptions['position']} position */ function handlePositionParam(container, position) { if (!position) { return; } if (position in swalClasses) { addClass(container, swalClasses[position]); } else { warn('The "position" parameter is not valid, defaulting to "center"'); addClass(container, swalClasses.center); } } /** * @param {HTMLElement} container * @param {SweetAlertOptions['grow']} grow */ function handleGrowParam(container, grow) { if (!grow) { return; } addClass(container, swalClasses[`grow-${grow}`]); } /** * This module contains `WeakMap`s for each effectively-"private property" that a `Swal` has. * For example, to set the private property "foo" of `this` to "bar", you can `privateProps.foo.set(this, 'bar')` * This is the approach that Babel will probably take to implement private methods/fields * https://github.com/tc39/proposal-private-methods * https://github.com/babel/babel/pull/7555 * Once we have the changes from that PR in Babel, and our core class fits reasonable in *one module* * then we can use that language feature. */ var privateProps = { innerParams: new WeakMap(), domCache: new WeakMap() }; /// /** @type {InputClass[]} */ const inputClasses = ['input', 'file', 'range', 'select', 'radio', 'checkbox', 'textarea']; /** * @param {SweetAlert} instance * @param {SweetAlertOptions} params */ const renderInput = (instance, params) => { const popup = getPopup(); if (!popup) { return; } const innerParams = privateProps.innerParams.get(instance); const rerender = !innerParams || params.input !== innerParams.input; inputClasses.forEach(inputClass => { const inputContainer = getDirectChildByClass(popup, swalClasses[inputClass]); if (!inputContainer) { return; } // set attributes setAttributes(inputClass, params.inputAttributes); // set class inputContainer.className = swalClasses[inputClass]; if (rerender) { hide(inputContainer); } }); if (params.input) { if (rerender) { showInput(params); } // set custom class setCustomClass(params); } }; /** * @param {SweetAlertOptions} params */ const showInput = params => { if (!params.input) { return; } if (!renderInputType[params.input]) { error(`Unexpected type of input! Expected ${Object.keys(renderInputType).join(' | ')}, got "${params.input}"`); return; } const inputContainer = getInputContainer(params.input); if (!inputContainer) { return; } const input = renderInputType[params.input](inputContainer, params); show(inputContainer); // input autofocus if (params.inputAutoFocus) { setTimeout(() => { focusInput(input); }); } }; /** * @param {HTMLInputElement} input */ const removeAttributes = input => { for (let i = 0; i < input.attributes.length; i++) { const attrName = input.attributes[i].name; if (!['id', 'type', 'value', 'style'].includes(attrName)) { input.removeAttribute(attrName); } } }; /** * @param {InputClass} inputClass * @param {SweetAlertOptions['inputAttributes']} inputAttributes */ const setAttributes = (inputClass, inputAttributes) => { const popup = getPopup(); if (!popup) { return; } const input = getInput$1(popup, inputClass); if (!input) { return; } removeAttributes(input); for (const attr in inputAttributes) { input.setAttribute(attr, inputAttributes[attr]); } }; /** * @param {SweetAlertOptions} params */ const setCustomClass = params => { if (!params.input) { return; } const inputContainer = getInputContainer(params.input); if (inputContainer) { applyCustomClass(inputContainer, params, 'input'); } }; /** * @param {HTMLInputElement | HTMLTextAreaElement} input * @param {SweetAlertOptions} params */ const setInputPlaceholder = (input, params) => { if (!input.placeholder && params.inputPlaceholder) { input.placeholder = params.inputPlaceholder; } }; /** * @param {Input} input * @param {Input} prependTo * @param {SweetAlertOptions} params */ const setInputLabel = (input, prependTo, params) => { if (params.inputLabel) { const label = document.createElement('label'); const labelClass = swalClasses['input-label']; label.setAttribute('for', input.id); label.className = labelClass; if (typeof params.customClass === 'object') { addClass(label, params.customClass.inputLabel); } label.innerText = params.inputLabel; prependTo.insertAdjacentElement('beforebegin', label); } }; /** * @param {SweetAlertInput} inputType * @returns {HTMLElement | undefined} */ const getInputContainer = inputType => { const popup = getPopup(); if (!popup) { return; } return getDirectChildByClass(popup, swalClasses[(/** @type {SwalClass} */inputType)] || swalClasses.input); }; /** * @param {HTMLInputElement | HTMLOutputElement | HTMLTextAreaElement} input * @param {SweetAlertOptions['inputValue']} inputValue */ const checkAndSetInputValue = (input, inputValue) => { if (['string', 'number'].includes(typeof inputValue)) { input.value = `${inputValue}`; } else if (!isPromise(inputValue)) { warn(`Unexpected type of inputValue! Expected "string", "number" or "Promise", got "${typeof inputValue}"`); } }; /** @type {Record Input>} */ const renderInputType = {}; /** * @param {Input | HTMLElement} input * @param {SweetAlertOptions} params * @returns {Input} */ renderInputType.text = renderInputType.email = renderInputType.password = renderInputType.number = renderInputType.tel = renderInputType.url = renderInputType.search = renderInputType.date = renderInputType['datetime-local'] = renderInputType.time = renderInputType.week = renderInputType.month = /** @type {(input: Input | HTMLElement, params: SweetAlertOptions) => Input} */ (input, params) => { const inputElement = /** @type {HTMLInputElement} */input; checkAndSetInputValue(inputElement, params.inputValue); setInputLabel(inputElement, inputElement, params); setInputPlaceholder(inputElement, params); inputElement.type = /** @type {string} */params.input; return inputElement; }; /** * @param {Input | HTMLElement} input * @param {SweetAlertOptions} params * @returns {Input} */ renderInputType.file = (input, params) => { const inputElement = /** @type {HTMLInputElement} */input; setInputLabel(inputElement, inputElement, params); setInputPlaceholder(inputElement, params); return inputElement; }; /** * @param {Input | HTMLElement} range * @param {SweetAlertOptions} params * @returns {Input} */ renderInputType.range = (range, params) => { const rangeContainer = /** @type {HTMLElement} */range; const rangeInput = rangeContainer.querySelector('input'); const rangeOutput = rangeContainer.querySelector('output'); if (rangeInput) { checkAndSetInputValue(rangeInput, params.inputValue); rangeInput.type = /** @type {string} */params.input; setInputLabel(rangeInput, /** @type {Input} */range, params); } if (rangeOutput) { checkAndSetInputValue(rangeOutput, params.inputValue); } return /** @type {Input} */range; }; /** * @param {Input | HTMLElement} select * @param {SweetAlertOptions} params * @returns {Input} */ renderInputType.select = (select, params) => { const selectElement = /** @type {HTMLSelectElement} */select; selectElement.textContent = ''; if (params.inputPlaceholder) { const placeholder = document.createElement('option'); setInnerHtml(placeholder, params.inputPlaceholder); placeholder.value = ''; placeholder.disabled = true; placeholder.selected = true; selectElement.appendChild(placeholder); } setInputLabel(selectElement, selectElement, params); return selectElement; }; /** * @param {Input | HTMLElement} radio * @returns {Input} */ renderInputType.radio = radio => { const radioElement = /** @type {HTMLElement} */radio; radioElement.textContent = ''; return /** @type {Input} */radio; }; /** * @param {Input | HTMLElement} checkboxContainer * @param {SweetAlertOptions} params * @returns {Input} */ renderInputType.checkbox = (checkboxContainer, params) => { const popup = getPopup(); if (!popup) { throw new Error('Popup not found'); } const checkbox = getInput$1(popup, 'checkbox'); if (!checkbox) { throw new Error('Checkbox input not found'); } checkbox.value = '1'; checkbox.checked = Boolean(params.inputValue); const containerElement = /** @type {HTMLElement} */checkboxContainer; const label = containerElement.querySelector('span'); if (label) { const placeholderOrLabel = params.inputPlaceholder || params.inputLabel; if (placeholderOrLabel) { setInnerHtml(label, placeholderOrLabel); } } return checkbox; }; /** * @param {Input | HTMLElement} textarea * @param {SweetAlertOptions} params * @returns {Input} */ renderInputType.textarea = (textarea, params) => { const textareaElement = /** @type {HTMLTextAreaElement} */textarea; checkAndSetInputValue(textareaElement, params.inputValue); setInputPlaceholder(textareaElement, params); setInputLabel(textareaElement, textareaElement, params); /** * @param {HTMLElement} el * @returns {number} */ const getMargin = el => parseInt(window.getComputedStyle(el).marginLeft) + parseInt(window.getComputedStyle(el).marginRight); // https://github.com/sweetalert2/sweetalert2/issues/2291 setTimeout(() => { // https://github.com/sweetalert2/sweetalert2/issues/1699 if ('MutationObserver' in window) { const popup = getPopup(); if (!popup) { return; } const initialPopupWidth = parseInt(window.getComputedStyle(popup).width); const textareaResizeHandler = () => { // check if texarea is still in document (i.e. popup wasn't closed in the meantime) if (!document.body.contains(textareaElement)) { return; } const textareaWidth = textareaElement.offsetWidth + getMargin(textareaElement); const popupElement = getPopup(); if (popupElement) { if (textareaWidth > initialPopupWidth) { popupElement.style.width = `${textareaWidth}px`; } else { applyNumericalStyle(popupElement, 'width', params.width); } } }; new MutationObserver(textareaResizeHandler).observe(textareaElement, { attributes: true, attributeFilter: ['style'] }); } }); return textareaElement; }; /** * @param {SweetAlert} instance * @param {SweetAlertOptions} params */ const renderContent = (instance, params) => { const htmlContainer = getHtmlContainer(); if (!htmlContainer) { return; } showWhenInnerHtmlPresent(htmlContainer); applyCustomClass(htmlContainer, params, 'htmlContainer'); // Content as HTML if (params.html) { parseHtmlToContainer(params.html, htmlContainer); show(htmlContainer, 'block'); } // Content as plain text else if (params.text) { htmlContainer.textContent = params.text; show(htmlContainer, 'block'); } // No content else { hide(htmlContainer); } renderInput(instance, params); }; /** * @param {SweetAlert} instance * @param {SweetAlertOptions} params */ const renderFooter = (instance, params) => { const footer = getFooter(); if (!footer) { return; } showWhenInnerHtmlPresent(footer); toggle(footer, Boolean(params.footer), 'block'); if (params.footer) { parseHtmlToContainer(params.footer, footer); } // Custom class applyCustomClass(footer, params, 'footer'); }; /** * @param {SweetAlert} instance * @param {SweetAlertOptions} params */ const renderIcon = (instance, params) => { const innerParams = privateProps.innerParams.get(instance); const icon = getIcon(); if (!icon) { return; } // if the given icon already rendered, apply the styling without re-rendering the icon if (innerParams && params.icon === innerParams.icon) { // Custom or default content setContent(icon, params); applyStyles(icon, params); return; } if (!params.icon && !params.iconHtml) { hide(icon); return; } if (params.icon && Object.keys(iconTypes).indexOf(params.icon) === -1) { error(`Unknown icon! Expected "success", "error", "warning", "info" or "question", got "${params.icon}"`); hide(icon); return; } show(icon); // Custom or default content setContent(icon, params); applyStyles(icon, params); // Animate icon addClass(icon, params.showClass && params.showClass.icon); // Re-adjust the success icon on system theme change const colorSchemeQueryList = window.matchMedia('(prefers-color-scheme: dark)'); colorSchemeQueryList.addEventListener('change', adjustSuccessIconBackgroundColor); }; /** * @param {HTMLElement} icon * @param {SweetAlertOptions} params */ const applyStyles = (icon, params) => { for (const [iconType, iconClassName] of Object.entries(iconTypes)) { if (params.icon !== iconType) { removeClass(icon, iconClassName); } } addClass(icon, params.icon && iconTypes[params.icon]); // Icon color setColor(icon, params); // Success icon background color adjustSuccessIconBackgroundColor(); // Custom class applyCustomClass(icon, params, 'icon'); }; // Adjust success icon background color to match the popup background color const adjustSuccessIconBackgroundColor = () => { const popup = getPopup(); if (!popup) { return; } const popupBackgroundColor = window.getComputedStyle(popup).getPropertyValue('background-color'); /** @type {NodeListOf} */ const successIconParts = popup.querySelectorAll('[class^=swal2-success-circular-line], .swal2-success-fix'); for (let i = 0; i < successIconParts.length; i++) { successIconParts[i].style.backgroundColor = popupBackgroundColor; } }; /** * * @param {SweetAlertOptions} params * @returns {string} */ const successIconHtml = params => ` ${params.animation ? '
      ' : ''}
      ${params.animation ? '
      ' : ''} ${params.animation ? '
      ' : ''} `; const errorIconHtml = ` `; /** * @param {HTMLElement} icon * @param {SweetAlertOptions} params */ const setContent = (icon, params) => { if (!params.icon && !params.iconHtml) { return; } let oldContent = icon.innerHTML; let newContent = ''; if (params.iconHtml) { newContent = iconContent(params.iconHtml); } else if (params.icon === 'success') { newContent = successIconHtml(params); oldContent = oldContent.replace(/ style=".*?"/g, ''); // undo adjustSuccessIconBackgroundColor() } else if (params.icon === 'error') { newContent = errorIconHtml; } else if (params.icon) { const defaultIconHtml = { question: '?', warning: '!', info: 'i' }; newContent = iconContent(defaultIconHtml[params.icon]); } if (oldContent.trim() !== newContent.trim()) { setInnerHtml(icon, newContent); } }; /** * @param {HTMLElement} icon * @param {SweetAlertOptions} params */ const setColor = (icon, params) => { if (!params.iconColor) { return; } icon.style.color = params.iconColor; icon.style.borderColor = params.iconColor; for (const sel of ['.swal2-success-line-tip', '.swal2-success-line-long', '.swal2-x-mark-line-left', '.swal2-x-mark-line-right']) { setStyle(icon, sel, 'background-color', params.iconColor); } setStyle(icon, '.swal2-success-ring', 'border-color', params.iconColor); }; /** * @param {string} content * @returns {string} */ const iconContent = content => `
      ${content}
      `; /** * @param {SweetAlert} instance * @param {SweetAlertOptions} params */ const renderImage = (instance, params) => { const image = getImage(); if (!image) { return; } if (!params.imageUrl) { hide(image); return; } show(image, ''); // Src, alt image.setAttribute('src', params.imageUrl); image.setAttribute('alt', params.imageAlt || ''); // Width, height applyNumericalStyle(image, 'width', params.imageWidth); applyNumericalStyle(image, 'height', params.imageHeight); // Class image.className = swalClasses.image; applyCustomClass(image, params, 'image'); }; let dragging = false; let mousedownX = 0; let mousedownY = 0; let initialX = 0; let initialY = 0; /** * @param {HTMLElement} popup */ const addDraggableListeners = popup => { popup.addEventListener('mousedown', down); document.body.addEventListener('mousemove', move); popup.addEventListener('mouseup', up); popup.addEventListener('touchstart', down); document.body.addEventListener('touchmove', move); popup.addEventListener('touchend', up); }; /** * @param {HTMLElement} popup */ const removeDraggableListeners = popup => { popup.removeEventListener('mousedown', down); document.body.removeEventListener('mousemove', move); popup.removeEventListener('mouseup', up); popup.removeEventListener('touchstart', down); document.body.removeEventListener('touchmove', move); popup.removeEventListener('touchend', up); }; /** * @param {MouseEvent | TouchEvent} event */ const down = event => { const popup = getPopup(); if (!popup) { return; } const icon = getIcon(); if (event.target === popup || icon && icon.contains(/** @type {HTMLElement} */event.target)) { dragging = true; const clientXY = getClientXY(event); mousedownX = clientXY.clientX; mousedownY = clientXY.clientY; initialX = parseInt(popup.style.insetInlineStart) || 0; initialY = parseInt(popup.style.insetBlockStart) || 0; addClass(popup, 'swal2-dragging'); } }; /** * @param {MouseEvent | TouchEvent} event */ const move = event => { const popup = getPopup(); if (!popup) { return; } if (dragging) { let { clientX, clientY } = getClientXY(event); const deltaX = clientX - mousedownX; // In RTL mode, negate the horizontal delta since insetInlineStart refers to the right edge popup.style.insetInlineStart = `${initialX + (globalState.isRTL ? -deltaX : deltaX)}px`; popup.style.insetBlockStart = `${initialY + (clientY - mousedownY)}px`; } }; const up = () => { const popup = getPopup(); dragging = false; removeClass(popup, 'swal2-dragging'); }; /** * @param {MouseEvent | TouchEvent} event * @returns {{ clientX: number, clientY: number }} */ const getClientXY = event => { let clientX = 0, clientY = 0; if (event.type.startsWith('mouse')) { clientX = /** @type {MouseEvent} */event.clientX; clientY = /** @type {MouseEvent} */event.clientY; } else if (event.type.startsWith('touch')) { clientX = /** @type {TouchEvent} */event.touches[0].clientX; clientY = /** @type {TouchEvent} */event.touches[0].clientY; } return { clientX, clientY }; }; /** * @param {SweetAlert} instance * @param {SweetAlertOptions} params */ const renderPopup = (instance, params) => { const container = getContainer(); const popup = getPopup(); if (!container || !popup) { return; } // Width // https://github.com/sweetalert2/sweetalert2/issues/2170 if (params.toast) { applyNumericalStyle(container, 'width', params.width); popup.style.width = '100%'; const loader = getLoader(); if (loader) { popup.insertBefore(loader, getIcon()); } } else { applyNumericalStyle(popup, 'width', params.width); } // Padding applyNumericalStyle(popup, 'padding', params.padding); // Color if (params.color) { popup.style.color = params.color; } // Background if (params.background) { popup.style.background = params.background; } hide(getValidationMessage()); // Classes addClasses$1(popup, params); if (params.draggable && !params.toast) { addClass(popup, swalClasses.draggable); addDraggableListeners(popup); } else { removeClass(popup, swalClasses.draggable); removeDraggableListeners(popup); } }; /** * @param {HTMLElement} popup * @param {SweetAlertOptions} params */ const addClasses$1 = (popup, params) => { const showClass = params.showClass || {}; // Default Class + showClass when updating Swal.update({}) popup.className = `${swalClasses.popup} ${isVisible$1(popup) ? showClass.popup : ''}`; if (params.toast) { addClass([document.documentElement, document.body], swalClasses['toast-shown']); addClass(popup, swalClasses.toast); } else { addClass(popup, swalClasses.modal); } // Custom class applyCustomClass(popup, params, 'popup'); // TODO: remove in the next major if (typeof params.customClass === 'string') { addClass(popup, params.customClass); } // Icon class (#1842) if (params.icon) { addClass(popup, swalClasses[`icon-${params.icon}`]); } }; /** * @param {SweetAlert} instance * @param {SweetAlertOptions} params */ const renderProgressSteps = (instance, params) => { const progressStepsContainer = getProgressSteps(); if (!progressStepsContainer) { return; } const { progressSteps, currentProgressStep } = params; if (!progressSteps || progressSteps.length === 0 || currentProgressStep === undefined) { hide(progressStepsContainer); return; } show(progressStepsContainer); progressStepsContainer.textContent = ''; if (currentProgressStep >= progressSteps.length) { warn('Invalid currentProgressStep parameter, it should be less than progressSteps.length ' + '(currentProgressStep like JS arrays starts from 0)'); } progressSteps.forEach((step, index) => { const stepEl = createStepElement(step); progressStepsContainer.appendChild(stepEl); if (index === currentProgressStep) { addClass(stepEl, swalClasses['active-progress-step']); } if (index !== progressSteps.length - 1) { const lineEl = createLineElement(params); progressStepsContainer.appendChild(lineEl); } }); }; /** * @param {string} step * @returns {HTMLLIElement} */ const createStepElement = step => { const stepEl = document.createElement('li'); addClass(stepEl, swalClasses['progress-step']); setInnerHtml(stepEl, step); return stepEl; }; /** * @param {SweetAlertOptions} params * @returns {HTMLLIElement} */ const createLineElement = params => { const lineEl = document.createElement('li'); addClass(lineEl, swalClasses['progress-step-line']); if (params.progressStepsDistance) { applyNumericalStyle(lineEl, 'width', params.progressStepsDistance); } return lineEl; }; /** * @param {SweetAlert} instance * @param {SweetAlertOptions} params */ const renderTitle = (instance, params) => { const title = getTitle(); if (!title) { return; } showWhenInnerHtmlPresent(title); toggle(title, Boolean(params.title || params.titleText), 'block'); if (params.title) { parseHtmlToContainer(params.title, title); } if (params.titleText) { title.innerText = params.titleText; } // Custom class applyCustomClass(title, params, 'title'); }; /** * @param {SweetAlert} instance * @param {SweetAlertOptions} params */ const render = (instance, params) => { var _globalState$eventEmi; renderPopup(instance, params); renderContainer(instance, params); renderProgressSteps(instance, params); renderIcon(instance, params); renderImage(instance, params); renderTitle(instance, params); renderCloseButton(instance, params); renderContent(instance, params); renderActions(instance, params); renderFooter(instance, params); const popup = getPopup(); if (typeof params.didRender === 'function' && popup) { params.didRender(popup); } (_globalState$eventEmi = globalState.eventEmitter) === null || _globalState$eventEmi === void 0 || _globalState$eventEmi.emit('didRender', popup); }; /* * Global function to determine if SweetAlert2 popup is shown */ const isVisible = () => { return isVisible$1(getPopup()); }; /* * Global function to click 'Confirm' button */ const clickConfirm = () => { var _dom$getConfirmButton; return (_dom$getConfirmButton = getConfirmButton()) === null || _dom$getConfirmButton === void 0 ? void 0 : _dom$getConfirmButton.click(); }; /* * Global function to click 'Deny' button */ const clickDeny = () => { var _dom$getDenyButton; return (_dom$getDenyButton = getDenyButton()) === null || _dom$getDenyButton === void 0 ? void 0 : _dom$getDenyButton.click(); }; /* * Global function to click 'Cancel' button */ const clickCancel = () => { var _dom$getCancelButton; return (_dom$getCancelButton = getCancelButton()) === null || _dom$getCancelButton === void 0 ? void 0 : _dom$getCancelButton.click(); }; /** @type {Record} */ const DismissReason = Object.freeze({ cancel: 'cancel', backdrop: 'backdrop', close: 'close', esc: 'esc', timer: 'timer' }); /** * @param {GlobalState} globalState */ const removeKeydownHandler = globalState => { if (globalState.keydownTarget && globalState.keydownHandlerAdded && globalState.keydownHandler) { const handler = /** @type {EventListenerOrEventListenerObject} */ /** @type {unknown} */globalState.keydownHandler; globalState.keydownTarget.removeEventListener('keydown', handler, { capture: globalState.keydownListenerCapture }); globalState.keydownHandlerAdded = false; } }; /** * @param {GlobalState} globalState * @param {SweetAlertOptions} innerParams * @param {(dismiss: DismissReason) => void} dismissWith */ const addKeydownHandler = (globalState, innerParams, dismissWith) => { removeKeydownHandler(globalState); if (!innerParams.toast) { /** @type {(this: HTMLElement, event: KeyboardEvent) => void} */ const handler = e => keydownHandler(innerParams, e, dismissWith); globalState.keydownHandler = handler; const target = innerParams.keydownListenerCapture ? window : getPopup(); if (target) { globalState.keydownTarget = target; globalState.keydownListenerCapture = innerParams.keydownListenerCapture; const eventHandler = /** @type {EventListenerOrEventListenerObject} */ /** @type {unknown} */handler; globalState.keydownTarget.addEventListener('keydown', eventHandler, { capture: globalState.keydownListenerCapture }); globalState.keydownHandlerAdded = true; } } }; /** * @param {number} index * @param {number} increment */ const setFocus = (index, increment) => { var _dom$getPopup; const focusableElements = getFocusableElements(); // search for visible elements and select the next possible match if (focusableElements.length) { index = index + increment; // shift + tab when .swal2-popup is focused if (index === -2) { index = focusableElements.length - 1; } // rollover to first item if (index === focusableElements.length) { index = 0; // go to last item } else if (index === -1) { index = focusableElements.length - 1; } focusableElements[index].focus(); return; } // no visible focusable elements, focus the popup (_dom$getPopup = getPopup()) === null || _dom$getPopup === void 0 || _dom$getPopup.focus(); }; const arrowKeysNextButton = ['ArrowRight', 'ArrowDown']; const arrowKeysPreviousButton = ['ArrowLeft', 'ArrowUp']; /** * @param {SweetAlertOptions} innerParams * @param {KeyboardEvent} event * @param {(dismiss: DismissReason) => void} dismissWith */ const keydownHandler = (innerParams, event, dismissWith) => { if (!innerParams) { return; // This instance has already been destroyed } // Ignore keydown during IME composition // https://developer.mozilla.org/en-US/docs/Web/API/Document/keydown_event#ignoring_keydown_during_ime_composition // https://github.com/sweetalert2/sweetalert2/issues/720 // https://github.com/sweetalert2/sweetalert2/issues/2406 if (event.isComposing || event.keyCode === 229) { return; } if (innerParams.stopKeydownPropagation) { event.stopPropagation(); } // ENTER if (event.key === 'Enter') { handleEnter(event, innerParams); } // TAB else if (event.key === 'Tab') { handleTab(event); } // ARROWS - switch focus between buttons else if ([...arrowKeysNextButton, ...arrowKeysPreviousButton].includes(event.key)) { handleArrows(event.key); } // ESC else if (event.key === 'Escape') { handleEsc(event, innerParams, dismissWith); } }; /** * @param {KeyboardEvent} event * @param {SweetAlertOptions} innerParams */ const handleEnter = (event, innerParams) => { // https://github.com/sweetalert2/sweetalert2/issues/2386 if (!callIfFunction(innerParams.allowEnterKey)) { return; } const popup = getPopup(); if (!popup || !innerParams.input) { return; } const input = getInput$1(popup, innerParams.input); if (event.target && input && event.target instanceof HTMLElement && event.target.outerHTML === input.outerHTML) { if (['textarea', 'file'].includes(innerParams.input)) { return; // do not submit } clickConfirm(); event.preventDefault(); } }; /** * @param {KeyboardEvent} event */ const handleTab = event => { const targetElement = event.target; const focusableElements = getFocusableElements(); let btnIndex = -1; for (let i = 0; i < focusableElements.length; i++) { if (targetElement === focusableElements[i]) { btnIndex = i; break; } } // Cycle to the next button if (!event.shiftKey) { setFocus(btnIndex, 1); } // Cycle to the prev button else { setFocus(btnIndex, -1); } event.stopPropagation(); event.preventDefault(); }; /** * @param {string} key */ const handleArrows = key => { const actions = getActions(); const confirmButton = getConfirmButton(); const denyButton = getDenyButton(); const cancelButton = getCancelButton(); if (!actions || !confirmButton || !denyButton || !cancelButton) { return; } /** @type HTMLElement[] */ const buttons = [confirmButton, denyButton, cancelButton]; if (document.activeElement instanceof HTMLElement && !buttons.includes(document.activeElement)) { return; } const sibling = arrowKeysNextButton.includes(key) ? 'nextElementSibling' : 'previousElementSibling'; let buttonToFocus = document.activeElement; if (!buttonToFocus) { return; } for (let i = 0; i < actions.children.length; i++) { buttonToFocus = buttonToFocus[sibling]; if (!buttonToFocus) { return; } if (buttonToFocus instanceof HTMLButtonElement && isVisible$1(buttonToFocus)) { break; } } if (buttonToFocus instanceof HTMLButtonElement) { buttonToFocus.focus(); } }; /** * @param {KeyboardEvent} event * @param {SweetAlertOptions} innerParams * @param {(dismiss: DismissReason) => void} dismissWith */ const handleEsc = (event, innerParams, dismissWith) => { event.preventDefault(); if (callIfFunction(innerParams.allowEscapeKey)) { dismissWith(DismissReason.esc); } }; /** * This module contains `WeakMap`s for each effectively-"private property" that a `Swal` has. * For example, to set the private property "foo" of `this` to "bar", you can `privateProps.foo.set(this, 'bar')` * This is the approach that Babel will probably take to implement private methods/fields * https://github.com/tc39/proposal-private-methods * https://github.com/babel/babel/pull/7555 * Once we have the changes from that PR in Babel, and our core class fits reasonable in *one module* * then we can use that language feature. */ var privateMethods = { swalPromiseResolve: new WeakMap(), swalPromiseReject: new WeakMap() }; // From https://developer.paciellogroup.com/blog/2018/06/the-current-state-of-modal-dialog-accessibility/ // Adding aria-hidden="true" to elements outside of the active modal dialog ensures that // elements not within the active modal dialog will not be surfaced if a user opens a screen // reader’s list of elements (headings, form controls, landmarks, etc.) in the document. const setAriaHidden = () => { const container = getContainer(); const bodyChildren = Array.from(document.body.children); bodyChildren.forEach(el => { if (el.contains(container)) { return; } if (el.hasAttribute('aria-hidden')) { el.setAttribute('data-previous-aria-hidden', el.getAttribute('aria-hidden') || ''); } el.setAttribute('aria-hidden', 'true'); }); }; const unsetAriaHidden = () => { const bodyChildren = Array.from(document.body.children); bodyChildren.forEach(el => { if (el.hasAttribute('data-previous-aria-hidden')) { el.setAttribute('aria-hidden', el.getAttribute('data-previous-aria-hidden') || ''); el.removeAttribute('data-previous-aria-hidden'); } else { el.removeAttribute('aria-hidden'); } }); }; // @ts-ignore const isSafariOrIOS = typeof window !== 'undefined' && Boolean(window.GestureEvent); // true for Safari desktop + all iOS browsers https://stackoverflow.com/a/70585394 /** * Fix iOS scrolling * http://stackoverflow.com/q/39626302 */ const iOSfix = () => { if (isSafariOrIOS && !hasClass(document.body, swalClasses.iosfix)) { const offset = document.body.scrollTop; document.body.style.top = `${offset * -1}px`; addClass(document.body, swalClasses.iosfix); lockBodyScroll(); } }; /** * https://github.com/sweetalert2/sweetalert2/issues/1246 */ const lockBodyScroll = () => { const container = getContainer(); if (!container) { return; } /** @type {boolean} */ let preventTouchMove; /** * @param {TouchEvent} event */ container.ontouchstart = event => { preventTouchMove = shouldPreventTouchMove(event); }; /** * @param {TouchEvent} event */ container.ontouchmove = event => { if (preventTouchMove) { event.preventDefault(); event.stopPropagation(); } }; }; /** * @param {TouchEvent} event * @returns {boolean} */ const shouldPreventTouchMove = event => { const target = event.target; const container = getContainer(); const htmlContainer = getHtmlContainer(); if (!container || !htmlContainer) { return false; } if (isStylus(event) || isZoom(event)) { return false; } if (target === container) { return true; } if (!isScrollable(container) && target instanceof HTMLElement && !selfOrParentIsScrollable(target, htmlContainer) && // #2823 target.tagName !== 'INPUT' && // #1603 target.tagName !== 'TEXTAREA' && // #2266 !(isScrollable(htmlContainer) && // #1944 htmlContainer.contains(target))) { return true; } return false; }; /** * https://github.com/sweetalert2/sweetalert2/issues/1786 * * @param {TouchEvent} event * @returns {boolean} */ const isStylus = event => { return Boolean(event.touches && event.touches.length && // @ts-ignore - touchType is not a standard property event.touches[0].touchType === 'stylus'); }; /** * https://github.com/sweetalert2/sweetalert2/issues/1891 * * @param {TouchEvent} event * @returns {boolean} */ const isZoom = event => { return event.touches && event.touches.length > 1; }; const undoIOSfix = () => { if (hasClass(document.body, swalClasses.iosfix)) { const offset = parseInt(document.body.style.top, 10); removeClass(document.body, swalClasses.iosfix); document.body.style.top = ''; document.body.scrollTop = offset * -1; } }; /** * Measure scrollbar width for padding body during modal show/hide * https://github.com/twbs/bootstrap/blob/master/js/src/modal.js * * @returns {number} */ const measureScrollbar = () => { const scrollDiv = document.createElement('div'); scrollDiv.className = swalClasses['scrollbar-measure']; document.body.appendChild(scrollDiv); const scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth; document.body.removeChild(scrollDiv); return scrollbarWidth; }; /** * Remember state in cases where opening and handling a modal will fiddle with it. * @type {number | null} */ let previousBodyPadding = null; /** * @param {string} initialBodyOverflow */ const replaceScrollbarWithPadding = initialBodyOverflow => { // for queues, do not do this more than once if (previousBodyPadding !== null) { return; } // if the body has overflow if (document.body.scrollHeight > window.innerHeight || initialBodyOverflow === 'scroll' // https://github.com/sweetalert2/sweetalert2/issues/2663 ) { // add padding so the content doesn't shift after removal of scrollbar previousBodyPadding = parseInt(window.getComputedStyle(document.body).getPropertyValue('padding-right')); document.body.style.paddingRight = `${previousBodyPadding + measureScrollbar()}px`; } }; const undoReplaceScrollbarWithPadding = () => { if (previousBodyPadding !== null) { document.body.style.paddingRight = `${previousBodyPadding}px`; previousBodyPadding = null; } }; /** * @param {SweetAlert} instance * @param {HTMLElement} container * @param {boolean} returnFocus * @param {(() => void) | undefined} didClose */ function removePopupAndResetState(instance, container, returnFocus, didClose) { if (isToast()) { triggerDidCloseAndDispose(instance, didClose); } else { restoreActiveElement(returnFocus).then(() => triggerDidCloseAndDispose(instance, didClose)); removeKeydownHandler(globalState); } // workaround for https://github.com/sweetalert2/sweetalert2/issues/2088 // for some reason removing the container in Safari will scroll the document to bottom if (isSafariOrIOS) { container.setAttribute('style', 'display:none !important'); container.removeAttribute('class'); container.innerHTML = ''; } else { container.remove(); } if (isModal()) { undoReplaceScrollbarWithPadding(); undoIOSfix(); unsetAriaHidden(); } removeBodyClasses(); } /** * Remove SweetAlert2 classes from body */ function removeBodyClasses() { removeClass([document.documentElement, document.body], [swalClasses.shown, swalClasses['height-auto'], swalClasses['no-backdrop'], swalClasses['toast-shown']]); } /** * Instance method to close sweetAlert * * @param {SweetAlertResult | undefined} resolveValue * @this {SweetAlert} */ function close(resolveValue) { resolveValue = prepareResolveValue(resolveValue); const swalPromiseResolve = privateMethods.swalPromiseResolve.get(this); const didClose = triggerClosePopup(this); if (this.isAwaitingPromise) { // A swal awaiting for a promise (after a click on Confirm or Deny) cannot be dismissed anymore #2335 if (!resolveValue.isDismissed) { handleAwaitingPromise(this); swalPromiseResolve(resolveValue); } } else if (didClose) { // Resolve Swal promise swalPromiseResolve(resolveValue); } } /** * @param {SweetAlert} instance * @returns {boolean} */ const triggerClosePopup = instance => { const popup = getPopup(); if (!popup) { return false; } const innerParams = privateProps.innerParams.get(instance); if (!innerParams || hasClass(popup, innerParams.hideClass.popup)) { return false; } removeClass(popup, innerParams.showClass.popup); addClass(popup, innerParams.hideClass.popup); const backdrop = getContainer(); removeClass(backdrop, innerParams.showClass.backdrop); addClass(backdrop, innerParams.hideClass.backdrop); handlePopupAnimation(instance, popup, innerParams); return true; }; /** * @param {Error | string} error * @this {SweetAlert} */ function rejectPromise(error) { const rejectPromise = privateMethods.swalPromiseReject.get(this); handleAwaitingPromise(this); if (rejectPromise) { // Reject Swal promise rejectPromise(error); } } /** * @param {SweetAlert} instance */ const handleAwaitingPromise = instance => { if (instance.isAwaitingPromise) { // @ts-ignore delete instance.isAwaitingPromise; // The instance might have been previously partly destroyed, we must resume the destroy process in this case #2335 if (!privateProps.innerParams.get(instance)) { instance._destroy(); } } }; /** * @param {SweetAlertResult | undefined} resolveValue * @returns {SweetAlertResult} */ const prepareResolveValue = resolveValue => { // When user calls Swal.close() if (typeof resolveValue === 'undefined') { return { isConfirmed: false, isDenied: false, isDismissed: true }; } return Object.assign({ isConfirmed: false, isDenied: false, isDismissed: false }, resolveValue); }; /** * @param {SweetAlert} instance * @param {HTMLElement} popup * @param {SweetAlertOptions} innerParams */ const handlePopupAnimation = (instance, popup, innerParams) => { var _globalState$eventEmi; const container = getContainer(); // If animation is supported, animate const animationIsSupported = hasCssAnimation(popup); if (typeof innerParams.willClose === 'function') { innerParams.willClose(popup); } (_globalState$eventEmi = globalState.eventEmitter) === null || _globalState$eventEmi === void 0 || _globalState$eventEmi.emit('willClose', popup); if (animationIsSupported && container) { animatePopup(instance, popup, container, Boolean(innerParams.returnFocus), innerParams.didClose); } else if (container) { // Otherwise, remove immediately removePopupAndResetState(instance, container, Boolean(innerParams.returnFocus), innerParams.didClose); } }; /** * @param {SweetAlert} instance * @param {HTMLElement} popup * @param {HTMLElement} container * @param {boolean} returnFocus * @param {(() => void) | undefined} didClose */ const animatePopup = (instance, popup, container, returnFocus, didClose) => { globalState.swalCloseEventFinishedCallback = removePopupAndResetState.bind(null, instance, container, returnFocus, didClose); /** * @param {AnimationEvent | TransitionEvent} e */ const swalCloseAnimationFinished = function (e) { if (e.target === popup) { var _globalState$swalClos; (_globalState$swalClos = globalState.swalCloseEventFinishedCallback) === null || _globalState$swalClos === void 0 || _globalState$swalClos.call(globalState); delete globalState.swalCloseEventFinishedCallback; popup.removeEventListener('animationend', swalCloseAnimationFinished); popup.removeEventListener('transitionend', swalCloseAnimationFinished); } }; popup.addEventListener('animationend', swalCloseAnimationFinished); popup.addEventListener('transitionend', swalCloseAnimationFinished); }; /** * @param {SweetAlert} instance * @param {(() => void) | undefined} didClose */ const triggerDidCloseAndDispose = (instance, didClose) => { setTimeout(() => { var _globalState$eventEmi2; if (typeof didClose === 'function') { didClose.bind(instance.params)(); } (_globalState$eventEmi2 = globalState.eventEmitter) === null || _globalState$eventEmi2 === void 0 || _globalState$eventEmi2.emit('didClose'); // instance might have been destroyed already if (instance._destroy) { instance._destroy(); } }); }; /** * Shows loader (spinner), this is useful with AJAX requests. * By default the loader be shown instead of the "Confirm" button. * * @param {HTMLButtonElement | null} [buttonToReplace] */ const showLoading = buttonToReplace => { let popup = getPopup(); if (!popup) { new Swal(); } popup = getPopup(); if (!popup) { return; } const loader = getLoader(); if (isToast()) { hide(getIcon()); } else { replaceButton(popup, buttonToReplace); } show(loader); popup.setAttribute('data-loading', 'true'); popup.setAttribute('aria-busy', 'true'); popup.focus(); }; /** * @param {HTMLElement} popup * @param {HTMLButtonElement | null} [buttonToReplace] */ const replaceButton = (popup, buttonToReplace) => { const actions = getActions(); const loader = getLoader(); if (!actions || !loader) { return; } if (!buttonToReplace && isVisible$1(getConfirmButton())) { buttonToReplace = getConfirmButton(); } show(actions); if (buttonToReplace) { hide(buttonToReplace); loader.setAttribute('data-button-to-replace', buttonToReplace.className); actions.insertBefore(loader, buttonToReplace); } addClass([popup, actions], swalClasses.loading); }; /** * @param {SweetAlert} instance * @param {SweetAlertOptions} params */ const handleInputOptionsAndValue = (instance, params) => { if (params.input === 'select' || params.input === 'radio') { handleInputOptions(instance, params); } else if (['text', 'email', 'number', 'tel', 'textarea'].some(i => i === params.input) && (hasToPromiseFn(params.inputValue) || isPromise(params.inputValue))) { showLoading(getConfirmButton()); handleInputValue(instance, params); } }; /** * @param {SweetAlert} instance * @param {SweetAlertOptions} innerParams * @returns {SweetAlertInputValue} */ const getInputValue = (instance, innerParams) => { const input = instance.getInput(); if (!input) { return null; } switch (innerParams.input) { case 'checkbox': return getCheckboxValue(input); case 'radio': return getRadioValue(input); case 'file': return getFileValue(input); default: return innerParams.inputAutoTrim ? input.value.trim() : input.value; } }; /** * @param {HTMLInputElement} input * @returns {number} */ const getCheckboxValue = input => input.checked ? 1 : 0; /** * @param {HTMLInputElement} input * @returns {string | null} */ const getRadioValue = input => input.checked ? input.value : null; /** * @param {HTMLInputElement} input * @returns {FileList | File | null} */ const getFileValue = input => input.files && input.files.length ? input.getAttribute('multiple') !== null ? input.files : input.files[0] : null; /** * @param {SweetAlert} instance * @param {SweetAlertOptions} params */ const handleInputOptions = (instance, params) => { const popup = getPopup(); if (!popup) { return; } /** * @param {*} inputOptions */ const processInputOptions = inputOptions => { if (params.input === 'select') { populateSelectOptions(popup, formatInputOptions(inputOptions), params); } else if (params.input === 'radio') { populateRadioOptions(popup, formatInputOptions(inputOptions), params); } }; if (hasToPromiseFn(params.inputOptions) || isPromise(params.inputOptions)) { showLoading(getConfirmButton()); asPromise(params.inputOptions).then(inputOptions => { instance.hideLoading(); processInputOptions(inputOptions); }); } else if (typeof params.inputOptions === 'object') { processInputOptions(params.inputOptions); } else { error(`Unexpected type of inputOptions! Expected object, Map or Promise, got ${typeof params.inputOptions}`); } }; /** * @param {SweetAlert} instance * @param {SweetAlertOptions} params */ const handleInputValue = (instance, params) => { const input = instance.getInput(); if (!input) { return; } hide(input); asPromise(params.inputValue).then(inputValue => { input.value = params.input === 'number' ? `${parseFloat(inputValue) || 0}` : `${inputValue}`; show(input); input.focus(); instance.hideLoading(); }).catch(err => { error(`Error in inputValue promise: ${err}`); input.value = ''; show(input); input.focus(); instance.hideLoading(); }); }; /** * @param {HTMLElement} popup * @param {InputOptionFlattened[]} inputOptions * @param {SweetAlertOptions} params */ function populateSelectOptions(popup, inputOptions, params) { const select = getDirectChildByClass(popup, swalClasses.select); if (!select) { return; } /** * @param {HTMLElement} parent * @param {string} optionLabel * @param {string} optionValue */ const renderOption = (parent, optionLabel, optionValue) => { const option = document.createElement('option'); option.value = optionValue; setInnerHtml(option, optionLabel); option.selected = isSelected(optionValue, params.inputValue); parent.appendChild(option); }; inputOptions.forEach(inputOption => { const optionValue = inputOption[0]; const optionLabel = inputOption[1]; // spec: // https://www.w3.org/TR/html401/interact/forms.html#h-17.6 // "...all OPTGROUP elements must be specified directly within a SELECT element (i.e., groups may not be nested)..." // check whether this is a if (Array.isArray(optionLabel)) { // if it is an array, then it is an const optgroup = document.createElement('optgroup'); optgroup.label = optionValue; optgroup.disabled = false; // not configurable for now select.appendChild(optgroup); optionLabel.forEach(o => renderOption(optgroup, o[1], o[0])); } else { // case of valueFormatted = formatInputOptions(valueFormatted); } result.push([key, valueFormatted]); }); } else { Object.keys(inputOptions).forEach(key => { let valueFormatted = inputOptions[key]; if (typeof valueFormatted === 'object') { // case of valueFormatted = formatInputOptions(valueFormatted); } result.push([key, valueFormatted]); }); } return result; }; /** * @param {string} optionValue * @param {SweetAlertInputValue} inputValue * @returns {boolean} */ const isSelected = (optionValue, inputValue) => { return Boolean(inputValue) && inputValue !== null && inputValue !== undefined && inputValue.toString() === optionValue.toString(); }; /** * @param {SweetAlert} instance */ const handleConfirmButtonClick = instance => { const innerParams = privateProps.innerParams.get(instance); instance.disableButtons(); if (innerParams.input) { handleConfirmOrDenyWithInput(instance, 'confirm'); } else { confirm(instance, true); } }; /** * @param {SweetAlert} instance */ const handleDenyButtonClick = instance => { const innerParams = privateProps.innerParams.get(instance); instance.disableButtons(); if (innerParams.returnInputValueOnDeny) { handleConfirmOrDenyWithInput(instance, 'deny'); } else { deny(instance, false); } }; /** * @param {SweetAlert} instance * @param {(dismiss: DismissReason) => void} dismissWith */ const handleCancelButtonClick = (instance, dismissWith) => { instance.disableButtons(); dismissWith(DismissReason.cancel); }; /** * @param {SweetAlert} instance * @param {'confirm' | 'deny'} type */ const handleConfirmOrDenyWithInput = (instance, type) => { const innerParams = privateProps.innerParams.get(instance); if (!innerParams.input) { error(`The "input" parameter is needed to be set when using returnInputValueOn${capitalizeFirstLetter(type)}`); return; } const input = instance.getInput(); const inputValue = getInputValue(instance, innerParams); if (innerParams.inputValidator) { handleInputValidator(instance, inputValue, type); } else if (input && !input.checkValidity()) { instance.enableButtons(); instance.showValidationMessage(innerParams.validationMessage || input.validationMessage); } else if (type === 'deny') { deny(instance, inputValue); } else { confirm(instance, inputValue); } }; /** * @param {SweetAlert} instance * @param {SweetAlertInputValue} inputValue * @param {'confirm' | 'deny'} type */ const handleInputValidator = (instance, inputValue, type) => { const innerParams = privateProps.innerParams.get(instance); instance.disableInput(); const validationPromise = Promise.resolve().then(() => asPromise(innerParams.inputValidator(inputValue, innerParams.validationMessage))); validationPromise.then(validationMessage => { instance.enableButtons(); instance.enableInput(); if (validationMessage) { instance.showValidationMessage(validationMessage); } else if (type === 'deny') { deny(instance, inputValue); } else { confirm(instance, inputValue); } }); }; /** * @param {SweetAlert} instance * @param {*} value */ const deny = (instance, value) => { const innerParams = privateProps.innerParams.get(instance); if (innerParams.showLoaderOnDeny) { showLoading(getDenyButton()); } if (innerParams.preDeny) { instance.isAwaitingPromise = true; // Flagging the instance as awaiting a promise so it's own promise's reject/resolve methods doesn't get destroyed until the result from this preDeny's promise is received const preDenyPromise = Promise.resolve().then(() => asPromise(innerParams.preDeny(value, innerParams.validationMessage))); preDenyPromise.then(preDenyValue => { if (preDenyValue === false) { instance.hideLoading(); handleAwaitingPromise(instance); } else { instance.close(/** @type SweetAlertResult */{ isDenied: true, value: typeof preDenyValue === 'undefined' ? value : preDenyValue }); } }).catch(error => rejectWith(instance, error)); } else { instance.close(/** @type SweetAlertResult */{ isDenied: true, value }); } }; /** * @param {SweetAlert} instance * @param {*} value */ const succeedWith = (instance, value) => { instance.close(/** @type SweetAlertResult */{ isConfirmed: true, value }); }; /** * * @param {SweetAlert} instance * @param {string} error */ const rejectWith = (instance, error) => { instance.rejectPromise(error); }; /** * * @param {SweetAlert} instance * @param {*} value */ const confirm = (instance, value) => { const innerParams = privateProps.innerParams.get(instance); if (innerParams.showLoaderOnConfirm) { showLoading(); } if (innerParams.preConfirm) { instance.resetValidationMessage(); instance.isAwaitingPromise = true; // Flagging the instance as awaiting a promise so it's own promise's reject/resolve methods doesn't get destroyed until the result from this preConfirm's promise is received const preConfirmPromise = Promise.resolve().then(() => asPromise(innerParams.preConfirm(value, innerParams.validationMessage))); preConfirmPromise.then(preConfirmValue => { if (isVisible$1(getValidationMessage()) || preConfirmValue === false) { instance.hideLoading(); handleAwaitingPromise(instance); } else { succeedWith(instance, typeof preConfirmValue === 'undefined' ? value : preConfirmValue); } }).catch(error => rejectWith(instance, error)); } else { succeedWith(instance, value); } }; /** * Hides loader and shows back the button which was hidden by .showLoading() * @this {SweetAlert} */ function hideLoading() { // do nothing if popup is closed const innerParams = privateProps.innerParams.get(this); if (!innerParams) { return; } const domCache = privateProps.domCache.get(this); hide(domCache.loader); if (isToast()) { if (innerParams.icon) { show(getIcon()); } } else { showRelatedButton(domCache); } removeClass([domCache.popup, domCache.actions], swalClasses.loading); domCache.popup.removeAttribute('aria-busy'); domCache.popup.removeAttribute('data-loading'); domCache.confirmButton.disabled = false; domCache.denyButton.disabled = false; domCache.cancelButton.disabled = false; } /** * @param {DomCache} domCache */ const showRelatedButton = domCache => { const dataButtonToReplace = domCache.loader.getAttribute('data-button-to-replace'); const buttonToReplace = dataButtonToReplace ? domCache.popup.getElementsByClassName(dataButtonToReplace) : []; if (buttonToReplace.length) { show(/** @type {HTMLElement} */buttonToReplace[0], 'inline-block'); } else if (allButtonsAreHidden()) { hide(domCache.actions); } }; /** * Gets the input DOM node, this method works with input parameter. * * @returns {HTMLInputElement | null} * @this {SweetAlert} */ function getInput() { const innerParams = privateProps.innerParams.get(this); const domCache = privateProps.domCache.get(this); if (!domCache) { return null; } return getInput$1(domCache.popup, innerParams.input); } /** * @param {SweetAlert} instance * @param {string[]} buttons * @param {boolean} disabled */ function setButtonsDisabled(instance, buttons, disabled) { const domCache = privateProps.domCache.get(instance); buttons.forEach(button => { domCache[button].disabled = disabled; }); } /** * @param {HTMLInputElement | null} input * @param {boolean} disabled */ function setInputDisabled(input, disabled) { const popup = getPopup(); if (!popup || !input) { return; } if (input.type === 'radio') { /** @type {NodeListOf} */ const radios = popup.querySelectorAll(`[name="${swalClasses.radio}"]`); for (let i = 0; i < radios.length; i++) { radios[i].disabled = disabled; } } else { input.disabled = disabled; } } /** * Enable all the buttons * @this {SweetAlert} */ function enableButtons() { setButtonsDisabled(this, ['confirmButton', 'denyButton', 'cancelButton'], false); } /** * Disable all the buttons * @this {SweetAlert} */ function disableButtons() { setButtonsDisabled(this, ['confirmButton', 'denyButton', 'cancelButton'], true); } /** * Enable the input field * @this {SweetAlert} */ function enableInput() { setInputDisabled(this.getInput(), false); } /** * Disable the input field * @this {SweetAlert} */ function disableInput() { setInputDisabled(this.getInput(), true); } /** * Show block with validation message * * @param {string} error * @this {SweetAlert} */ function showValidationMessage(error) { const domCache = privateProps.domCache.get(this); const params = privateProps.innerParams.get(this); setInnerHtml(domCache.validationMessage, error); domCache.validationMessage.className = swalClasses['validation-message']; if (params.customClass && params.customClass.validationMessage) { addClass(domCache.validationMessage, params.customClass.validationMessage); } show(domCache.validationMessage); const input = this.getInput(); if (input) { input.setAttribute('aria-invalid', 'true'); input.setAttribute('aria-describedby', swalClasses['validation-message']); focusInput(input); addClass(input, swalClasses.inputerror); } } /** * Hide block with validation message * * @this {SweetAlert} */ function resetValidationMessage() { const domCache = privateProps.domCache.get(this); if (domCache.validationMessage) { hide(domCache.validationMessage); } const input = this.getInput(); if (input) { input.removeAttribute('aria-invalid'); input.removeAttribute('aria-describedby'); removeClass(input, swalClasses.inputerror); } } const defaultParams = { title: '', titleText: '', text: '', html: '', footer: '', icon: undefined, iconColor: undefined, iconHtml: undefined, template: undefined, toast: false, draggable: false, animation: true, theme: 'light', showClass: { popup: 'swal2-show', backdrop: 'swal2-backdrop-show', icon: 'swal2-icon-show' }, hideClass: { popup: 'swal2-hide', backdrop: 'swal2-backdrop-hide', icon: 'swal2-icon-hide' }, customClass: {}, target: 'body', color: undefined, backdrop: true, heightAuto: true, allowOutsideClick: true, allowEscapeKey: true, allowEnterKey: true, stopKeydownPropagation: true, keydownListenerCapture: false, showConfirmButton: true, showDenyButton: false, showCancelButton: false, preConfirm: undefined, preDeny: undefined, confirmButtonText: 'OK', confirmButtonAriaLabel: '', confirmButtonColor: undefined, denyButtonText: 'No', denyButtonAriaLabel: '', denyButtonColor: undefined, cancelButtonText: 'Cancel', cancelButtonAriaLabel: '', cancelButtonColor: undefined, buttonsStyling: true, reverseButtons: false, focusConfirm: true, focusDeny: false, focusCancel: false, returnFocus: true, showCloseButton: false, closeButtonHtml: '×', closeButtonAriaLabel: 'Close this dialog', loaderHtml: '', showLoaderOnConfirm: false, showLoaderOnDeny: false, imageUrl: undefined, imageWidth: undefined, imageHeight: undefined, imageAlt: '', timer: undefined, timerProgressBar: false, width: undefined, padding: undefined, background: undefined, input: undefined, inputPlaceholder: '', inputLabel: '', inputValue: '', inputOptions: {}, inputAutoFocus: true, inputAutoTrim: true, inputAttributes: {}, inputValidator: undefined, returnInputValueOnDeny: false, validationMessage: undefined, grow: false, position: 'center', progressSteps: [], currentProgressStep: undefined, progressStepsDistance: undefined, willOpen: undefined, didOpen: undefined, didRender: undefined, willClose: undefined, didClose: undefined, didDestroy: undefined, scrollbarPadding: true, topLayer: false }; const updatableParams = ['allowEscapeKey', 'allowOutsideClick', 'background', 'buttonsStyling', 'cancelButtonAriaLabel', 'cancelButtonColor', 'cancelButtonText', 'closeButtonAriaLabel', 'closeButtonHtml', 'color', 'confirmButtonAriaLabel', 'confirmButtonColor', 'confirmButtonText', 'currentProgressStep', 'customClass', 'denyButtonAriaLabel', 'denyButtonColor', 'denyButtonText', 'didClose', 'didDestroy', 'draggable', 'footer', 'hideClass', 'html', 'icon', 'iconColor', 'iconHtml', 'imageAlt', 'imageHeight', 'imageUrl', 'imageWidth', 'preConfirm', 'preDeny', 'progressSteps', 'returnFocus', 'reverseButtons', 'showCancelButton', 'showCloseButton', 'showConfirmButton', 'showDenyButton', 'text', 'title', 'titleText', 'theme', 'willClose']; /** @type {Record} */ const deprecatedParams = { allowEnterKey: undefined }; const toastIncompatibleParams = ['allowOutsideClick', 'allowEnterKey', 'backdrop', 'draggable', 'focusConfirm', 'focusDeny', 'focusCancel', 'returnFocus', 'heightAuto', 'keydownListenerCapture']; /** * Is valid parameter * * @param {string} paramName * @returns {boolean} */ const isValidParameter = paramName => { return Object.prototype.hasOwnProperty.call(defaultParams, paramName); }; /** * Is valid parameter for Swal.update() method * * @param {string} paramName * @returns {boolean} */ const isUpdatableParameter = paramName => { return updatableParams.indexOf(paramName) !== -1; }; /** * Is deprecated parameter * * @param {string} paramName * @returns {string | undefined} */ const isDeprecatedParameter = paramName => { return deprecatedParams[paramName]; }; /** * @param {string} param */ const checkIfParamIsValid = param => { if (!isValidParameter(param)) { warn(`Unknown parameter "${param}"`); } }; /** * @param {string} param */ const checkIfToastParamIsValid = param => { if (toastIncompatibleParams.includes(param)) { warn(`The parameter "${param}" is incompatible with toasts`); } }; /** * @param {string} param */ const checkIfParamIsDeprecated = param => { const isDeprecated = isDeprecatedParameter(param); if (isDeprecated) { warnAboutDeprecation(param, isDeprecated); } }; /** * Show relevant warnings for given params * * @param {SweetAlertOptions} params */ const showWarningsForParams = params => { if (params.backdrop === false && params.allowOutsideClick) { warn('"allowOutsideClick" parameter requires `backdrop` parameter to be set to `true`'); } if (params.theme && !['light', 'dark', 'auto', 'minimal', 'borderless', 'bootstrap-4', 'bootstrap-4-light', 'bootstrap-4-dark', 'bootstrap-5', 'bootstrap-5-light', 'bootstrap-5-dark', 'material-ui', 'material-ui-light', 'material-ui-dark', 'embed-iframe', 'bulma', 'bulma-light', 'bulma-dark'].includes(params.theme)) { warn(`Invalid theme "${params.theme}"`); } for (const param in params) { checkIfParamIsValid(param); if (params.toast) { checkIfToastParamIsValid(param); } checkIfParamIsDeprecated(param); } }; /** * Updates popup parameters. * * @this {any} * @param {SweetAlertOptions} params */ function update(params) { const container = getContainer(); const popup = getPopup(); const innerParams = privateProps.innerParams.get(this); if (!popup || hasClass(popup, innerParams.hideClass.popup)) { warn(`You're trying to update the closed or closing popup, that won't work. Use the update() method in preConfirm parameter or show a new popup.`); return; } const validUpdatableParams = filterValidParams(params); const updatedParams = Object.assign({}, innerParams, validUpdatableParams); showWarningsForParams(updatedParams); if (container) { container.dataset['swal2Theme'] = updatedParams.theme; } render(this, updatedParams); privateProps.innerParams.set(this, updatedParams); Object.defineProperties(this, { params: { value: Object.assign({}, this.params, params), writable: false, enumerable: true } }); } /** * @param {SweetAlertOptions} params * @returns {SweetAlertOptions} */ const filterValidParams = params => { /** @type {Record} */ const validUpdatableParams = {}; Object.keys(params).forEach(param => { if (isUpdatableParameter(param)) { const typedParams = /** @type {Record} */params; validUpdatableParams[param] = typedParams[param]; } else { warn(`Invalid parameter to update: ${param}`); } }); return validUpdatableParams; }; /** * Dispose the current SweetAlert2 instance * @this {SweetAlert} */ function _destroy() { var _globalState$eventEmi; const domCache = privateProps.domCache.get(this); const innerParams = privateProps.innerParams.get(this); if (!innerParams) { disposeWeakMaps(this); // The WeakMaps might have been partly destroyed, we must recall it to dispose any remaining WeakMaps #2335 return; // This instance has already been destroyed } // Check if there is another Swal closing if (domCache.popup && globalState.swalCloseEventFinishedCallback) { globalState.swalCloseEventFinishedCallback(); delete globalState.swalCloseEventFinishedCallback; } if (typeof innerParams.didDestroy === 'function') { innerParams.didDestroy(); } (_globalState$eventEmi = globalState.eventEmitter) === null || _globalState$eventEmi === void 0 || _globalState$eventEmi.emit('didDestroy'); disposeSwal(this); } /** * @param {SweetAlert} instance */ const disposeSwal = instance => { disposeWeakMaps(instance); // Unset this.params so GC will dispose it (#1569) // @ts-ignore delete instance.params; // Unset globalState props so GC will dispose globalState (#1569) delete globalState.keydownHandler; delete globalState.keydownTarget; // Unset currentInstance delete globalState.currentInstance; }; /** * @param {SweetAlert} instance */ const disposeWeakMaps = instance => { // If the current instance is awaiting a promise result, we keep the privateMethods to call them once the promise result is retrieved #2335 if (instance.isAwaitingPromise) { unsetWeakMaps(privateProps, instance); instance.isAwaitingPromise = true; } else { unsetWeakMaps(privateMethods, instance); unsetWeakMaps(privateProps, instance); // @ts-ignore delete instance.isAwaitingPromise; // Unset instance methods // @ts-ignore delete instance.disableButtons; // @ts-ignore delete instance.enableButtons; // @ts-ignore delete instance.getInput; // @ts-ignore delete instance.disableInput; // @ts-ignore delete instance.enableInput; // @ts-ignore delete instance.hideLoading; // @ts-ignore delete instance.disableLoading; // @ts-ignore delete instance.showValidationMessage; // @ts-ignore delete instance.resetValidationMessage; // @ts-ignore delete instance.close; // @ts-ignore delete instance.closePopup; // @ts-ignore delete instance.closeModal; // @ts-ignore delete instance.closeToast; // @ts-ignore delete instance.rejectPromise; // @ts-ignore delete instance.update; // @ts-ignore delete instance._destroy; } }; /** * @param {Record>} obj * @param {SweetAlert} instance */ const unsetWeakMaps = (obj, instance) => { for (const i in obj) { obj[i].delete(instance); } }; var instanceMethods = /*#__PURE__*/Object.freeze({ __proto__: null, _destroy: _destroy, close: close, closeModal: close, closePopup: close, closeToast: close, disableButtons: disableButtons, disableInput: disableInput, disableLoading: hideLoading, enableButtons: enableButtons, enableInput: enableInput, getInput: getInput, handleAwaitingPromise: handleAwaitingPromise, hideLoading: hideLoading, rejectPromise: rejectPromise, resetValidationMessage: resetValidationMessage, showValidationMessage: showValidationMessage, update: update }); /** * @param {SweetAlertOptions} innerParams * @param {DomCache} domCache * @param {(dismiss: DismissReason) => void} dismissWith */ const handlePopupClick = (innerParams, domCache, dismissWith) => { if (innerParams.toast) { handleToastClick(innerParams, domCache, dismissWith); } else { // Ignore click events that had mousedown on the popup but mouseup on the container // This can happen when the user drags a slider handleModalMousedown(domCache); // Ignore click events that had mousedown on the container but mouseup on the popup handleContainerMousedown(domCache); handleModalClick(innerParams, domCache, dismissWith); } }; /** * @param {SweetAlertOptions} innerParams * @param {DomCache} domCache * @param {(dismiss: DismissReason) => void} dismissWith */ const handleToastClick = (innerParams, domCache, dismissWith) => { // Closing toast by internal click domCache.popup.onclick = () => { if (innerParams && (isAnyButtonShown(innerParams) || innerParams.timer || innerParams.input)) { return; } dismissWith(DismissReason.close); }; }; /** * @param {SweetAlertOptions} innerParams * @returns {boolean} */ const isAnyButtonShown = innerParams => { return Boolean(innerParams.showConfirmButton || innerParams.showDenyButton || innerParams.showCancelButton || innerParams.showCloseButton); }; let ignoreOutsideClick = false; /** * @param {DomCache} domCache */ const handleModalMousedown = domCache => { domCache.popup.onmousedown = () => { domCache.container.onmouseup = function (e) { domCache.container.onmouseup = () => {}; // We only check if the mouseup target is the container because usually it doesn't // have any other direct children aside of the popup if (e.target === domCache.container) { ignoreOutsideClick = true; } }; }; }; /** * @param {DomCache} domCache */ const handleContainerMousedown = domCache => { domCache.container.onmousedown = e => { // prevent the modal text from being selected on double click on the container (allowOutsideClick: false) if (e.target === domCache.container) { e.preventDefault(); } domCache.popup.onmouseup = function (e) { domCache.popup.onmouseup = () => {}; // We also need to check if the mouseup target is a child of the popup if (e.target === domCache.popup || e.target instanceof HTMLElement && domCache.popup.contains(e.target)) { ignoreOutsideClick = true; } }; }; }; /** * @param {SweetAlertOptions} innerParams * @param {DomCache} domCache * @param {(dismiss: DismissReason) => void} dismissWith */ const handleModalClick = (innerParams, domCache, dismissWith) => { domCache.container.onclick = e => { if (ignoreOutsideClick) { ignoreOutsideClick = false; return; } if (e.target === domCache.container && callIfFunction(innerParams.allowOutsideClick)) { dismissWith(DismissReason.backdrop); } }; }; /** * @param {any} elem * @returns {boolean} */ const isJqueryElement = elem => typeof elem === 'object' && elem.jquery; /** * @param {any} elem * @returns {boolean} */ const isElement = elem => elem instanceof Element || isJqueryElement(elem); /** * @param {any[]} args * @returns {SweetAlertOptions} */ const argsToParams = args => { /** @type {Record} */ const params = {}; if (typeof args[0] === 'object' && !isElement(args[0])) { Object.assign(params, args[0]); } else { ['title', 'html', 'icon'].forEach((name, index) => { const arg = args[index]; if (typeof arg === 'string' || isElement(arg)) { params[name] = arg; } else if (arg !== undefined) { error(`Unexpected type of ${name}! Expected "string" or "Element", got ${typeof arg}`); } }); } return params; }; /** * Main method to create a new SweetAlert2 popup * * @this {new (...args: any[]) => any} * @param {...SweetAlertOptions} args * @returns {Promise} */ function fire(...args) { return new this(...args); } /** * Returns an extended version of `Swal` containing `params` as defaults. * Useful for reusing Swal configuration. * * For example: * * Before: * const textPromptOptions = { input: 'text', showCancelButton: true } * const {value: firstName} = await Swal.fire({ ...textPromptOptions, title: 'What is your first name?' }) * const {value: lastName} = await Swal.fire({ ...textPromptOptions, title: 'What is your last name?' }) * * After: * const TextPrompt = Swal.mixin({ input: 'text', showCancelButton: true }) * const {value: firstName} = await TextPrompt('What is your first name?') * const {value: lastName} = await TextPrompt('What is your last name?') * * @param {SweetAlertOptions} mixinParams * @returns {SweetAlert} * @this {typeof import('../SweetAlert.js').SweetAlert} */ function mixin(mixinParams) { // @ts-ignore: 'this' refers to the SweetAlert constructor class MixinSwal extends this { /** * @param {any} params * @param {any} priorityMixinParams */ _main(params, priorityMixinParams) { return super._main(params, Object.assign({}, mixinParams, priorityMixinParams)); } } // @ts-ignore return MixinSwal; } /** * If `timer` parameter is set, returns number of milliseconds of timer remained. * Otherwise, returns undefined. * * @returns {number | undefined} */ const getTimerLeft = () => { return globalState.timeout && globalState.timeout.getTimerLeft(); }; /** * Stop timer. Returns number of milliseconds of timer remained. * If `timer` parameter isn't set, returns undefined. * * @returns {number | undefined} */ const stopTimer = () => { if (globalState.timeout) { stopTimerProgressBar(); return globalState.timeout.stop(); } }; /** * Resume timer. Returns number of milliseconds of timer remained. * If `timer` parameter isn't set, returns undefined. * * @returns {number | undefined} */ const resumeTimer = () => { if (globalState.timeout) { const remaining = globalState.timeout.start(); animateTimerProgressBar(remaining); return remaining; } }; /** * Resume timer. Returns number of milliseconds of timer remained. * If `timer` parameter isn't set, returns undefined. * * @returns {number | undefined} */ const toggleTimer = () => { const timer = globalState.timeout; return timer && (timer.running ? stopTimer() : resumeTimer()); }; /** * Increase timer. Returns number of milliseconds of an updated timer. * If `timer` parameter isn't set, returns undefined. * * @param {number} ms * @returns {number | undefined} */ const increaseTimer = ms => { if (globalState.timeout) { const remaining = globalState.timeout.increase(ms); animateTimerProgressBar(remaining, true); return remaining; } }; /** * Check if timer is running. Returns true if timer is running * or false if timer is paused or stopped. * If `timer` parameter isn't set, returns undefined * * @returns {boolean} */ const isTimerRunning = () => { return Boolean(globalState.timeout && globalState.timeout.isRunning()); }; let bodyClickListenerAdded = false; /** @type {Record} */ const clickHandlers = {}; /** * @this {any} * @param {string} attr */ function bindClickHandler(attr = 'data-swal-template') { clickHandlers[attr] = this; if (!bodyClickListenerAdded) { document.body.addEventListener('click', bodyClickListener); bodyClickListenerAdded = true; } } /** * @param {MouseEvent} event */ const bodyClickListener = event => { for (let el = /** @type {any} */event.target; el && el !== document; el = el.parentNode) { for (const attr in clickHandlers) { const template = el.getAttribute && el.getAttribute(attr); if (template) { clickHandlers[attr].fire({ template }); return; } } } }; // Source: https://gist.github.com/mudge/5830382?permalink_comment_id=2691957#gistcomment-2691957 class EventEmitter { constructor() { /** @type {Events} */ this.events = {}; } /** * @param {string} eventName * @returns {EventHandlers} */ _getHandlersByEventName(eventName) { if (typeof this.events[eventName] === 'undefined') { // not Set because we need to keep the FIFO order // https://github.com/sweetalert2/sweetalert2/pull/2763#discussion_r1748990334 this.events[eventName] = []; } return this.events[eventName]; } /** * @param {string} eventName * @param {EventHandler} eventHandler */ on(eventName, eventHandler) { const currentHandlers = this._getHandlersByEventName(eventName); if (!currentHandlers.includes(eventHandler)) { currentHandlers.push(eventHandler); } } /** * @param {string} eventName * @param {EventHandler} eventHandler */ once(eventName, eventHandler) { /** * @param {...any} args */ const onceFn = (...args) => { this.removeListener(eventName, onceFn); // @ts-ignore eventHandler.apply(this, args); }; this.on(eventName, onceFn); } /** * @param {string} eventName * @param {...any} args */ emit(eventName, ...args) { this._getHandlersByEventName(eventName).forEach( /** * @param {EventHandler} eventHandler */ eventHandler => { try { // @ts-ignore eventHandler.apply(this, args); } catch (error) { console.error(error); } }); } /** * @param {string} eventName * @param {EventHandler} eventHandler */ removeListener(eventName, eventHandler) { const currentHandlers = this._getHandlersByEventName(eventName); const index = currentHandlers.indexOf(eventHandler); if (index > -1) { currentHandlers.splice(index, 1); } } /** * @param {string} eventName */ removeAllListeners(eventName) { if (this.events[eventName] !== undefined) { // https://github.com/sweetalert2/sweetalert2/pull/2763#discussion_r1749239222 this.events[eventName].length = 0; } } reset() { this.events = {}; } } globalState.eventEmitter = new EventEmitter(); /** * @param {string} eventName * @param {EventHandler} eventHandler */ const on = (eventName, eventHandler) => { if (globalState.eventEmitter) { globalState.eventEmitter.on(eventName, eventHandler); } }; /** * @param {string} eventName * @param {EventHandler} eventHandler */ const once = (eventName, eventHandler) => { if (globalState.eventEmitter) { globalState.eventEmitter.once(eventName, eventHandler); } }; /** * @param {string} [eventName] * @param {EventHandler} [eventHandler] */ const off = (eventName, eventHandler) => { if (!globalState.eventEmitter) { return; } // Remove all handlers for all events if (!eventName) { globalState.eventEmitter.reset(); return; } if (eventHandler) { // Remove a specific handler globalState.eventEmitter.removeListener(eventName, eventHandler); } else { // Remove all handlers for a specific event globalState.eventEmitter.removeAllListeners(eventName); } }; var staticMethods = /*#__PURE__*/Object.freeze({ __proto__: null, argsToParams: argsToParams, bindClickHandler: bindClickHandler, clickCancel: clickCancel, clickConfirm: clickConfirm, clickDeny: clickDeny, enableLoading: showLoading, fire: fire, getActions: getActions, getCancelButton: getCancelButton, getCloseButton: getCloseButton, getConfirmButton: getConfirmButton, getContainer: getContainer, getDenyButton: getDenyButton, getFocusableElements: getFocusableElements, getFooter: getFooter, getHtmlContainer: getHtmlContainer, getIcon: getIcon, getIconContent: getIconContent, getImage: getImage, getInputLabel: getInputLabel, getLoader: getLoader, getPopup: getPopup, getProgressSteps: getProgressSteps, getTimerLeft: getTimerLeft, getTimerProgressBar: getTimerProgressBar, getTitle: getTitle, getValidationMessage: getValidationMessage, increaseTimer: increaseTimer, isDeprecatedParameter: isDeprecatedParameter, isLoading: isLoading, isTimerRunning: isTimerRunning, isUpdatableParameter: isUpdatableParameter, isValidParameter: isValidParameter, isVisible: isVisible, mixin: mixin, off: off, on: on, once: once, resumeTimer: resumeTimer, showLoading: showLoading, stopTimer: stopTimer, toggleTimer: toggleTimer }); class Timer { /** * @param {() => void} callback * @param {number} delay */ constructor(callback, delay) { this.callback = callback; this.remaining = delay; this.running = false; this.start(); } /** * @returns {number} */ start() { if (!this.running) { this.running = true; this.started = new Date(); this.id = setTimeout(this.callback, this.remaining); } return this.remaining; } /** * @returns {number} */ stop() { if (this.started && this.running) { this.running = false; clearTimeout(this.id); this.remaining -= new Date().getTime() - this.started.getTime(); } return this.remaining; } /** * @param {number} n * @returns {number} */ increase(n) { const running = this.running; if (running) { this.stop(); } this.remaining += n; if (running) { this.start(); } return this.remaining; } /** * @returns {number} */ getTimerLeft() { if (this.running) { this.stop(); this.start(); } return this.remaining; } /** * @returns {boolean} */ isRunning() { return this.running; } } const swalStringParams = ['swal-title', 'swal-html', 'swal-footer']; /** * @param {SweetAlertOptions} params * @returns {SweetAlertOptions} */ const getTemplateParams = params => { const template = typeof params.template === 'string' ? (/** @type {HTMLTemplateElement} */document.querySelector(params.template)) : params.template; if (!template) { return {}; } /** @type {DocumentFragment} */ const templateContent = template.content; showWarningsForElements(templateContent); const result = Object.assign(getSwalParams(templateContent), getSwalFunctionParams(templateContent), getSwalButtons(templateContent), getSwalImage(templateContent), getSwalIcon(templateContent), getSwalInput(templateContent), getSwalStringParams(templateContent, swalStringParams)); return result; }; /** * @param {DocumentFragment} templateContent * @returns {Record} */ const getSwalParams = templateContent => { /** @type {Record} */ const result = {}; /** @type {HTMLElement[]} */ const swalParams = Array.from(templateContent.querySelectorAll('swal-param')); swalParams.forEach(param => { showWarningsForAttributes(param, ['name', 'value']); const paramName = /** @type {keyof SweetAlertOptions} */param.getAttribute('name'); const value = param.getAttribute('value'); if (!paramName || !value) { return; } if (paramName in defaultParams && typeof defaultParams[(/** @type {keyof typeof defaultParams} */paramName)] === 'boolean') { result[paramName] = value !== 'false'; } else if (paramName in defaultParams && typeof defaultParams[(/** @type {keyof typeof defaultParams} */paramName)] === 'object') { result[paramName] = JSON.parse(value); } else { result[paramName] = value; } }); return result; }; /** * @param {DocumentFragment} templateContent * @returns {Record void>} */ const getSwalFunctionParams = templateContent => { /** @type {Record void>} */ const result = {}; /** @type {HTMLElement[]} */ const swalFunctions = Array.from(templateContent.querySelectorAll('swal-function-param')); swalFunctions.forEach(param => { const paramName = /** @type {keyof SweetAlertOptions} */param.getAttribute('name'); const value = param.getAttribute('value'); if (!paramName || !value) { return; } result[paramName] = new Function(`return ${value}`)(); }); return result; }; /** * @param {DocumentFragment} templateContent * @returns {Record} */ const getSwalButtons = templateContent => { /** @type {Record} */ const result = {}; /** @type {HTMLElement[]} */ const swalButtons = Array.from(templateContent.querySelectorAll('swal-button')); swalButtons.forEach(button => { showWarningsForAttributes(button, ['type', 'color', 'aria-label']); const type = button.getAttribute('type'); if (!type || !['confirm', 'cancel', 'deny'].includes(type)) { return; } result[`${type}ButtonText`] = button.innerHTML; result[`show${capitalizeFirstLetter(type)}Button`] = true; if (button.hasAttribute('color')) { const color = button.getAttribute('color'); if (color !== null) { result[`${type}ButtonColor`] = color; } } if (button.hasAttribute('aria-label')) { const ariaLabel = button.getAttribute('aria-label'); if (ariaLabel !== null) { result[`${type}ButtonAriaLabel`] = ariaLabel; } } }); return result; }; /** * @param {DocumentFragment} templateContent * @returns {Pick} */ const getSwalImage = templateContent => { const result = {}; /** @type {HTMLElement | null} */ const image = templateContent.querySelector('swal-image'); if (image) { showWarningsForAttributes(image, ['src', 'width', 'height', 'alt']); if (image.hasAttribute('src')) { result.imageUrl = image.getAttribute('src') || undefined; } if (image.hasAttribute('width')) { result.imageWidth = image.getAttribute('width') || undefined; } if (image.hasAttribute('height')) { result.imageHeight = image.getAttribute('height') || undefined; } if (image.hasAttribute('alt')) { result.imageAlt = image.getAttribute('alt') || undefined; } } return result; }; /** * @param {DocumentFragment} templateContent * @returns {object} */ const getSwalIcon = templateContent => { const result = {}; /** @type {HTMLElement | null} */ const icon = templateContent.querySelector('swal-icon'); if (icon) { showWarningsForAttributes(icon, ['type', 'color']); if (icon.hasAttribute('type')) { result.icon = icon.getAttribute('type'); } if (icon.hasAttribute('color')) { result.iconColor = icon.getAttribute('color'); } result.iconHtml = icon.innerHTML; } return result; }; /** * @param {DocumentFragment} templateContent * @returns {object} */ const getSwalInput = templateContent => { /** @type {Record} */ const result = {}; /** @type {HTMLElement | null} */ const input = templateContent.querySelector('swal-input'); if (input) { showWarningsForAttributes(input, ['type', 'label', 'placeholder', 'value']); result.input = input.getAttribute('type') || 'text'; if (input.hasAttribute('label')) { result.inputLabel = input.getAttribute('label'); } if (input.hasAttribute('placeholder')) { result.inputPlaceholder = input.getAttribute('placeholder'); } if (input.hasAttribute('value')) { result.inputValue = input.getAttribute('value'); } } /** @type {HTMLElement[]} */ const inputOptions = Array.from(templateContent.querySelectorAll('swal-input-option')); if (inputOptions.length) { result.inputOptions = {}; inputOptions.forEach(option => { showWarningsForAttributes(option, ['value']); const optionValue = option.getAttribute('value'); if (!optionValue) { return; } const optionName = option.innerHTML; result.inputOptions[optionValue] = optionName; }); } return result; }; /** * @param {DocumentFragment} templateContent * @param {string[]} paramNames * @returns {Record} */ const getSwalStringParams = (templateContent, paramNames) => { /** @type {Record} */ const result = {}; for (const i in paramNames) { const paramName = paramNames[i]; /** @type {HTMLElement | null} */ const tag = templateContent.querySelector(paramName); if (tag) { showWarningsForAttributes(tag, []); result[paramName.replace(/^swal-/, '')] = tag.innerHTML.trim(); } } return result; }; /** * @param {DocumentFragment} templateContent */ const showWarningsForElements = templateContent => { const allowedElements = swalStringParams.concat(['swal-param', 'swal-function-param', 'swal-button', 'swal-image', 'swal-icon', 'swal-input', 'swal-input-option']); Array.from(templateContent.children).forEach(el => { const tagName = el.tagName.toLowerCase(); if (!allowedElements.includes(tagName)) { warn(`Unrecognized element <${tagName}>`); } }); }; /** * @param {HTMLElement} el * @param {string[]} allowedAttributes */ const showWarningsForAttributes = (el, allowedAttributes) => { Array.from(el.attributes).forEach(attribute => { if (allowedAttributes.indexOf(attribute.name) === -1) { warn([`Unrecognized attribute "${attribute.name}" on <${el.tagName.toLowerCase()}>.`, `${allowedAttributes.length ? `Allowed attributes are: ${allowedAttributes.join(', ')}` : 'To set the value, use HTML within the element.'}`]); } }); }; const SHOW_CLASS_TIMEOUT = 10; /** * Open popup, add necessary classes and styles, fix scrollbar * * @param {SweetAlertOptions} params */ const openPopup = params => { var _globalState$eventEmi, _globalState$eventEmi2; const container = getContainer(); const popup = getPopup(); if (!container || !popup) { return; } if (typeof params.willOpen === 'function') { params.willOpen(popup); } (_globalState$eventEmi = globalState.eventEmitter) === null || _globalState$eventEmi === void 0 || _globalState$eventEmi.emit('willOpen', popup); const bodyStyles = window.getComputedStyle(document.body); const initialBodyOverflow = bodyStyles.overflowY; addClasses(container, popup, params); // scrolling is 'hidden' until animation is done, after that 'auto' setTimeout(() => { setScrollingVisibility(container, popup); }, SHOW_CLASS_TIMEOUT); if (isModal()) { // Using ternary instead of ?? operator for Webpack 4 compatibility fixScrollContainer(container, params.scrollbarPadding !== undefined ? params.scrollbarPadding : false, initialBodyOverflow); setAriaHidden(); } if (!isToast() && !globalState.previousActiveElement) { globalState.previousActiveElement = document.activeElement; } if (typeof params.didOpen === 'function') { const didOpen = params.didOpen; setTimeout(() => didOpen(popup)); } (_globalState$eventEmi2 = globalState.eventEmitter) === null || _globalState$eventEmi2 === void 0 || _globalState$eventEmi2.emit('didOpen', popup); }; /** * @param {Event} event */ const swalOpenAnimationFinished = event => { const popup = getPopup(); if (!popup || event.target !== popup) { return; } const container = getContainer(); if (!container) { return; } popup.removeEventListener('animationend', swalOpenAnimationFinished); popup.removeEventListener('transitionend', swalOpenAnimationFinished); container.style.overflowY = 'auto'; // no-transition is added in init() in case one swal is opened right after another removeClass(container, swalClasses['no-transition']); }; /** * @param {HTMLElement} container * @param {HTMLElement} popup */ const setScrollingVisibility = (container, popup) => { if (hasCssAnimation(popup)) { container.style.overflowY = 'hidden'; popup.addEventListener('animationend', swalOpenAnimationFinished); popup.addEventListener('transitionend', swalOpenAnimationFinished); } else { container.style.overflowY = 'auto'; } }; /** * @param {HTMLElement} container * @param {boolean} scrollbarPadding * @param {string} initialBodyOverflow */ const fixScrollContainer = (container, scrollbarPadding, initialBodyOverflow) => { iOSfix(); if (scrollbarPadding && initialBodyOverflow !== 'hidden') { replaceScrollbarWithPadding(initialBodyOverflow); } // sweetalert2/issues/1247 setTimeout(() => { container.scrollTop = 0; }); }; /** * @param {HTMLElement} container * @param {HTMLElement} popup * @param {SweetAlertOptions} params */ const addClasses = (container, popup, params) => { var _params$showClass; if ((_params$showClass = params.showClass) !== null && _params$showClass !== void 0 && _params$showClass.backdrop) { addClass(container, params.showClass.backdrop); } if (params.animation) { // this workaround with opacity is needed for https://github.com/sweetalert2/sweetalert2/issues/2059 popup.style.setProperty('opacity', '0', 'important'); show(popup, 'grid'); setTimeout(() => { var _params$showClass2; // Animate popup right after showing it if ((_params$showClass2 = params.showClass) !== null && _params$showClass2 !== void 0 && _params$showClass2.popup) { addClass(popup, params.showClass.popup); } // and remove the opacity workaround popup.style.removeProperty('opacity'); }, SHOW_CLASS_TIMEOUT); // 10ms in order to fix #2062 } else { show(popup, 'grid'); } addClass([document.documentElement, document.body], swalClasses.shown); if (params.heightAuto && params.backdrop && !params.toast) { addClass([document.documentElement, document.body], swalClasses['height-auto']); } }; var defaultInputValidators = { /** * @param {string} string * @param {string} [validationMessage] * @returns {Promise} */ email: (string, validationMessage) => { return /^[a-zA-Z0-9.+_'-]+@[a-zA-Z0-9.-]+\.[a-zA-Z0-9-]+$/.test(string) ? Promise.resolve() : Promise.resolve(validationMessage || 'Invalid email address'); }, /** * @param {string} string * @param {string} [validationMessage] * @returns {Promise} */ url: (string, validationMessage) => { // taken from https://stackoverflow.com/a/3809435 with a small change from #1306 and #2013 return /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-z]{2,63}\b([-a-zA-Z0-9@:%_+.~#?&/=]*)$/.test(string) ? Promise.resolve() : Promise.resolve(validationMessage || 'Invalid URL'); } }; /** * @param {SweetAlertOptions} params */ function setDefaultInputValidators(params) { // Use default `inputValidator` for supported input types if not provided if (params.inputValidator) { return; } if (params.input === 'email') { params.inputValidator = defaultInputValidators['email']; } if (params.input === 'url') { params.inputValidator = defaultInputValidators['url']; } } /** * @param {SweetAlertOptions} params */ function validateCustomTargetElement(params) { // Determine if the custom target element is valid if (!params.target || typeof params.target === 'string' && !document.querySelector(params.target) || typeof params.target !== 'string' && !params.target.appendChild) { warn('Target parameter is not valid, defaulting to "body"'); params.target = 'body'; } } /** * Set type, text and actions on popup * * @param {SweetAlertOptions} params */ function setParameters(params) { setDefaultInputValidators(params); // showLoaderOnConfirm && preConfirm if (params.showLoaderOnConfirm && !params.preConfirm) { warn('showLoaderOnConfirm is set to true, but preConfirm is not defined.\n' + 'showLoaderOnConfirm should be used together with preConfirm, see usage example:\n' + 'https://sweetalert2.github.io/#ajax-request'); } validateCustomTargetElement(params); // Replace newlines with
      in title if (typeof params.title === 'string') { params.title = params.title.split('\n').join('
      '); } init(params); } /** @type {SweetAlert} */ let currentInstance; var _promise = /*#__PURE__*/new WeakMap(); class SweetAlert { /** * @param {...(SweetAlertOptions | string)} args * @this {SweetAlert} */ constructor(...args) { /** * @type {Promise} */ _classPrivateFieldInitSpec(this, _promise, /** @type {Promise} */Promise.resolve({ isConfirmed: false, isDenied: false, isDismissed: true })); // Prevent run in Node env if (typeof window === 'undefined') { return; } currentInstance = this; // @ts-ignore const outerParams = Object.freeze(this.constructor.argsToParams(args)); /** @type {Readonly} */ this.params = outerParams; /** @type {boolean} */ this.isAwaitingPromise = false; _classPrivateFieldSet2(_promise, this, this._main(currentInstance.params)); } /** * @param {any} userParams * @param {any} mixinParams */ _main(userParams, mixinParams = {}) { showWarningsForParams(Object.assign({}, mixinParams, userParams)); if (globalState.currentInstance) { const swalPromiseResolve = privateMethods.swalPromiseResolve.get(globalState.currentInstance); const { isAwaitingPromise } = globalState.currentInstance; globalState.currentInstance._destroy(); if (!isAwaitingPromise) { swalPromiseResolve({ isDismissed: true }); } if (isModal()) { unsetAriaHidden(); } } globalState.currentInstance = currentInstance; const innerParams = prepareParams(userParams, mixinParams); setParameters(innerParams); Object.freeze(innerParams); // clear the previous timer if (globalState.timeout) { globalState.timeout.stop(); delete globalState.timeout; } // clear the restore focus timeout clearTimeout(globalState.restoreFocusTimeout); const domCache = populateDomCache(currentInstance); render(currentInstance, innerParams); privateProps.innerParams.set(currentInstance, innerParams); return swalPromise(currentInstance, domCache, innerParams); } // `catch` cannot be the name of a module export, so we define our thenable methods here instead /** * @param {any} onFulfilled */ then(onFulfilled) { return _classPrivateFieldGet2(_promise, this).then(onFulfilled); } /** * @param {any} onFinally */ finally(onFinally) { return _classPrivateFieldGet2(_promise, this).finally(onFinally); } } /** * @param {SweetAlert} instance * @param {DomCache} domCache * @param {SweetAlertOptions} innerParams * @returns {Promise} */ const swalPromise = (instance, domCache, innerParams) => { return new Promise((resolve, reject) => { // functions to handle all closings/dismissals /** * @param {DismissReason} dismiss */ const dismissWith = dismiss => { instance.close({ isDismissed: true, dismiss, isConfirmed: false, isDenied: false }); }; privateMethods.swalPromiseResolve.set(instance, resolve); privateMethods.swalPromiseReject.set(instance, reject); domCache.confirmButton.onclick = () => { handleConfirmButtonClick(instance); }; domCache.denyButton.onclick = () => { handleDenyButtonClick(instance); }; domCache.cancelButton.onclick = () => { handleCancelButtonClick(instance, dismissWith); }; domCache.closeButton.onclick = () => { dismissWith(DismissReason.close); }; handlePopupClick(innerParams, domCache, dismissWith); addKeydownHandler(globalState, innerParams, dismissWith); handleInputOptionsAndValue(instance, innerParams); openPopup(innerParams); setupTimer(globalState, innerParams, dismissWith); initFocus(domCache, innerParams); // Scroll container to top on open (#1247, #1946) setTimeout(() => { domCache.container.scrollTop = 0; }); }); }; /** * @param {SweetAlertOptions} userParams * @param {SweetAlertOptions} mixinParams * @returns {SweetAlertOptions} */ const prepareParams = (userParams, mixinParams) => { const templateParams = getTemplateParams(userParams); const params = Object.assign({}, defaultParams, mixinParams, templateParams, userParams); // precedence is described in #2131 params.showClass = Object.assign({}, defaultParams.showClass, params.showClass); params.hideClass = Object.assign({}, defaultParams.hideClass, params.hideClass); if (params.animation === false) { params.showClass = { backdrop: 'swal2-noanimation' }; params.hideClass = {}; } return params; }; /** * @param {SweetAlert} instance * @returns {DomCache} */ const populateDomCache = instance => { const domCache = /** @type {DomCache} */{ popup: (/** @type {HTMLElement} */getPopup()), container: (/** @type {HTMLElement} */getContainer()), actions: (/** @type {HTMLElement} */getActions()), confirmButton: (/** @type {HTMLElement} */getConfirmButton()), denyButton: (/** @type {HTMLElement} */getDenyButton()), cancelButton: (/** @type {HTMLElement} */getCancelButton()), loader: (/** @type {HTMLElement} */getLoader()), closeButton: (/** @type {HTMLElement} */getCloseButton()), validationMessage: (/** @type {HTMLElement} */getValidationMessage()), progressSteps: (/** @type {HTMLElement} */getProgressSteps()) }; privateProps.domCache.set(instance, domCache); return domCache; }; /** * @param {GlobalState} globalState * @param {SweetAlertOptions} innerParams * @param {(dismiss: DismissReason) => void} dismissWith */ const setupTimer = (globalState, innerParams, dismissWith) => { const timerProgressBar = getTimerProgressBar(); hide(timerProgressBar); if (innerParams.timer) { globalState.timeout = new Timer(() => { dismissWith('timer'); delete globalState.timeout; }, innerParams.timer); if (innerParams.timerProgressBar && timerProgressBar) { show(timerProgressBar); applyCustomClass(timerProgressBar, innerParams, 'timerProgressBar'); setTimeout(() => { if (globalState.timeout && globalState.timeout.running) { // timer can be already stopped or unset at this point animateTimerProgressBar(/** @type {number} */innerParams.timer); } }); } } }; /** * Initialize focus in the popup: * * 1. If `toast` is `true`, don't steal focus from the document. * 2. Else if there is an [autofocus] element, focus it. * 3. Else if `focusConfirm` is `true` and confirm button is visible, focus it. * 4. Else if `focusDeny` is `true` and deny button is visible, focus it. * 5. Else if `focusCancel` is `true` and cancel button is visible, focus it. * 6. Else focus the first focusable element in a popup (if any). * * @param {DomCache} domCache * @param {SweetAlertOptions} innerParams */ const initFocus = (domCache, innerParams) => { if (innerParams.toast) { return; } // TODO: this is dumb, remove `allowEnterKey` param in the next major version if (!callIfFunction(innerParams.allowEnterKey)) { warnAboutDeprecation('allowEnterKey'); blurActiveElement(); return; } if (focusAutofocus(domCache)) { return; } if (focusButton(domCache, innerParams)) { return; } setFocus(-1, 1); }; /** * @param {DomCache} domCache * @returns {boolean} */ const focusAutofocus = domCache => { const autofocusElements = Array.from(domCache.popup.querySelectorAll('[autofocus]')); for (const autofocusElement of autofocusElements) { if (autofocusElement instanceof HTMLElement && isVisible$1(autofocusElement)) { autofocusElement.focus(); return true; } } return false; }; /** * @param {DomCache} domCache * @param {SweetAlertOptions} innerParams * @returns {boolean} */ const focusButton = (domCache, innerParams) => { if (innerParams.focusDeny && isVisible$1(domCache.denyButton)) { domCache.denyButton.focus(); return true; } if (innerParams.focusCancel && isVisible$1(domCache.cancelButton)) { domCache.cancelButton.focus(); return true; } if (innerParams.focusConfirm && isVisible$1(domCache.confirmButton)) { domCache.confirmButton.focus(); return true; } return false; }; const blurActiveElement = () => { if (document.activeElement instanceof HTMLElement && typeof document.activeElement.blur === 'function') { document.activeElement.blur(); } }; // Assign instance methods from src/instanceMethods/*.js to prototype SweetAlert.prototype.disableButtons = disableButtons; SweetAlert.prototype.enableButtons = enableButtons; SweetAlert.prototype.getInput = getInput; SweetAlert.prototype.disableInput = disableInput; SweetAlert.prototype.enableInput = enableInput; SweetAlert.prototype.hideLoading = hideLoading; SweetAlert.prototype.disableLoading = hideLoading; SweetAlert.prototype.showValidationMessage = showValidationMessage; SweetAlert.prototype.resetValidationMessage = resetValidationMessage; SweetAlert.prototype.close = close; SweetAlert.prototype.closePopup = close; SweetAlert.prototype.closeModal = close; SweetAlert.prototype.closeToast = close; SweetAlert.prototype.rejectPromise = rejectPromise; SweetAlert.prototype.update = update; SweetAlert.prototype._destroy = _destroy; // Assign static methods from src/staticMethods/*.js to constructor Object.assign(SweetAlert, staticMethods); // Proxy to instance methods to constructor, for now, for backwards compatibility Object.keys(instanceMethods).forEach(key => { /** * @param {...(SweetAlertOptions | string | undefined)} args * @returns {SweetAlertResult | Promise | undefined} */ // @ts-ignore: Dynamic property assignment for backwards compatibility SweetAlert[key] = function (...args) { // @ts-ignore if (currentInstance && currentInstance[key]) { // @ts-ignore return currentInstance[key](...args); } return undefined; }; }); SweetAlert.DismissReason = DismissReason; SweetAlert.version = '11.26.17'; const Swal = SweetAlert; // @ts-ignore Swal.default = Swal; return Swal; })); if (typeof this !== 'undefined' && this.Sweetalert2){this.swal = this.sweetAlert = this.Swal = this.SweetAlert = this.Sweetalert2} "undefined"!=typeof document&&function(e,t){var n=e.createElement("style");if(e.getElementsByTagName("head")[0].appendChild(n),n.styleSheet)n.styleSheet.disabled||(n.styleSheet.cssText=t);else try{n.innerHTML=t}catch(e){n.innerText=t}}(document,":root{--swal2-outline: 0 0 0 3px rgba(100, 150, 200, 0.5);--swal2-container-padding: 0.625em;--swal2-backdrop: rgba(0, 0, 0, 0.4);--swal2-backdrop-transition: background-color 0.15s;--swal2-width: 32em;--swal2-padding: 0 0 1.25em;--swal2-border: none;--swal2-border-radius: 0.3125rem;--swal2-background: white;--swal2-color: #545454;--swal2-show-animation: swal2-show 0.3s;--swal2-hide-animation: swal2-hide 0.15s forwards;--swal2-icon-zoom: 1;--swal2-icon-animations: true;--swal2-title-padding: 0.8em 1em 0;--swal2-html-container-padding: 1em 1.6em 0.3em;--swal2-input-border: 1px solid #d9d9d9;--swal2-input-border-radius: 0.1875em;--swal2-input-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.06), 0 0 0 3px transparent;--swal2-input-background: transparent;--swal2-input-transition: border-color 0.2s, box-shadow 0.2s;--swal2-input-hover-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.06), 0 0 0 3px transparent;--swal2-input-focus-border: 1px solid #b4dbed;--swal2-input-focus-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.06), 0 0 0 3px rgba(100, 150, 200, 0.5);--swal2-progress-step-background: #add8e6;--swal2-validation-message-background: #f0f0f0;--swal2-validation-message-color: #666;--swal2-footer-border-color: #eee;--swal2-footer-background: transparent;--swal2-footer-color: inherit;--swal2-timer-progress-bar-background: rgba(0, 0, 0, 0.3);--swal2-close-button-position: initial;--swal2-close-button-inset: auto;--swal2-close-button-font-size: 2.5em;--swal2-close-button-color: #ccc;--swal2-close-button-transition: color 0.2s, box-shadow 0.2s;--swal2-close-button-outline: initial;--swal2-close-button-box-shadow: inset 0 0 0 3px transparent;--swal2-close-button-focus-box-shadow: inset var(--swal2-outline);--swal2-close-button-hover-transform: none;--swal2-actions-justify-content: center;--swal2-actions-width: auto;--swal2-actions-margin: 1.25em auto 0;--swal2-actions-padding: 0;--swal2-actions-border-radius: 0;--swal2-actions-background: transparent;--swal2-action-button-transition: background-color 0.2s, box-shadow 0.2s;--swal2-action-button-hover: black 10%;--swal2-action-button-active: black 10%;--swal2-confirm-button-box-shadow: none;--swal2-confirm-button-border-radius: 0.25em;--swal2-confirm-button-background-color: #7066e0;--swal2-confirm-button-color: #fff;--swal2-deny-button-box-shadow: none;--swal2-deny-button-border-radius: 0.25em;--swal2-deny-button-background-color: #dc3741;--swal2-deny-button-color: #fff;--swal2-cancel-button-box-shadow: none;--swal2-cancel-button-border-radius: 0.25em;--swal2-cancel-button-background-color: #6e7881;--swal2-cancel-button-color: #fff;--swal2-toast-show-animation: swal2-toast-show 0.5s;--swal2-toast-hide-animation: swal2-toast-hide 0.1s forwards;--swal2-toast-border: none;--swal2-toast-box-shadow: 0 0 1px hsl(0deg 0% 0% / 0.075), 0 1px 2px hsl(0deg 0% 0% / 0.075), 1px 2px 4px hsl(0deg 0% 0% / 0.075), 1px 3px 8px hsl(0deg 0% 0% / 0.075), 2px 4px 16px hsl(0deg 0% 0% / 0.075)}[data-swal2-theme=dark]{--swal2-dark-theme-black: #19191a;--swal2-dark-theme-white: #e1e1e1;--swal2-background: var(--swal2-dark-theme-black);--swal2-color: var(--swal2-dark-theme-white);--swal2-footer-border-color: #555;--swal2-input-background: color-mix(in srgb, var(--swal2-dark-theme-black), var(--swal2-dark-theme-white) 10%);--swal2-validation-message-background: color-mix( in srgb, var(--swal2-dark-theme-black), var(--swal2-dark-theme-white) 10% );--swal2-validation-message-color: var(--swal2-dark-theme-white);--swal2-timer-progress-bar-background: rgba(255, 255, 255, 0.7)}@media(prefers-color-scheme: dark){[data-swal2-theme=auto]{--swal2-dark-theme-black: #19191a;--swal2-dark-theme-white: #e1e1e1;--swal2-background: var(--swal2-dark-theme-black);--swal2-color: var(--swal2-dark-theme-white);--swal2-footer-border-color: #555;--swal2-input-background: color-mix(in srgb, var(--swal2-dark-theme-black), var(--swal2-dark-theme-white) 10%);--swal2-validation-message-background: color-mix( in srgb, var(--swal2-dark-theme-black), var(--swal2-dark-theme-white) 10% );--swal2-validation-message-color: var(--swal2-dark-theme-white);--swal2-timer-progress-bar-background: rgba(255, 255, 255, 0.7)}}body.swal2-shown:not(.swal2-no-backdrop,.swal2-toast-shown){overflow:hidden}body.swal2-height-auto{height:auto !important}body.swal2-no-backdrop .swal2-container{background-color:rgba(0,0,0,0) !important;pointer-events:none}body.swal2-no-backdrop .swal2-container .swal2-popup{pointer-events:all}body.swal2-no-backdrop .swal2-container .swal2-modal{box-shadow:0 0 10px var(--swal2-backdrop)}body.swal2-toast-shown .swal2-container{box-sizing:border-box;width:360px;max-width:100%;background-color:rgba(0,0,0,0);pointer-events:none}body.swal2-toast-shown .swal2-container.swal2-top{inset:0 auto auto 50%;transform:translateX(-50%)}body.swal2-toast-shown .swal2-container.swal2-top-end,body.swal2-toast-shown .swal2-container.swal2-top-right{inset:0 0 auto auto}body.swal2-toast-shown .swal2-container.swal2-top-start,body.swal2-toast-shown .swal2-container.swal2-top-left{inset:0 auto auto 0}body.swal2-toast-shown .swal2-container.swal2-center-start,body.swal2-toast-shown .swal2-container.swal2-center-left{inset:50% auto auto 0;transform:translateY(-50%)}body.swal2-toast-shown .swal2-container.swal2-center{inset:50% auto auto 50%;transform:translate(-50%, -50%)}body.swal2-toast-shown .swal2-container.swal2-center-end,body.swal2-toast-shown .swal2-container.swal2-center-right{inset:50% 0 auto auto;transform:translateY(-50%)}body.swal2-toast-shown .swal2-container.swal2-bottom-start,body.swal2-toast-shown .swal2-container.swal2-bottom-left{inset:auto auto 0 0}body.swal2-toast-shown .swal2-container.swal2-bottom{inset:auto auto 0 50%;transform:translateX(-50%)}body.swal2-toast-shown .swal2-container.swal2-bottom-end,body.swal2-toast-shown .swal2-container.swal2-bottom-right{inset:auto 0 0 auto}@media print{body.swal2-shown:not(.swal2-no-backdrop,.swal2-toast-shown){overflow-y:scroll !important}body.swal2-shown:not(.swal2-no-backdrop,.swal2-toast-shown)>[aria-hidden=true]{display:none}body.swal2-shown:not(.swal2-no-backdrop,.swal2-toast-shown) .swal2-container{position:static !important}}div:where(.swal2-container){display:grid;position:fixed;z-index:1060;inset:0;box-sizing:border-box;grid-template-areas:\"top-start top top-end\" \"center-start center center-end\" \"bottom-start bottom-center bottom-end\";grid-template-rows:minmax(min-content, auto) minmax(min-content, auto) minmax(min-content, auto);height:100%;padding:var(--swal2-container-padding);overflow-x:hidden;transition:var(--swal2-backdrop-transition);-webkit-overflow-scrolling:touch}div:where(.swal2-container).swal2-backdrop-show,div:where(.swal2-container).swal2-noanimation{background:var(--swal2-backdrop)}div:where(.swal2-container).swal2-backdrop-hide{background:rgba(0,0,0,0) !important}div:where(.swal2-container).swal2-top-start,div:where(.swal2-container).swal2-center-start,div:where(.swal2-container).swal2-bottom-start{grid-template-columns:minmax(0, 1fr) auto auto}div:where(.swal2-container).swal2-top,div:where(.swal2-container).swal2-center,div:where(.swal2-container).swal2-bottom{grid-template-columns:auto minmax(0, 1fr) auto}div:where(.swal2-container).swal2-top-end,div:where(.swal2-container).swal2-center-end,div:where(.swal2-container).swal2-bottom-end{grid-template-columns:auto auto minmax(0, 1fr)}div:where(.swal2-container).swal2-top-start>.swal2-popup{align-self:start}div:where(.swal2-container).swal2-top>.swal2-popup{grid-column:2;place-self:start center}div:where(.swal2-container).swal2-top-end>.swal2-popup,div:where(.swal2-container).swal2-top-right>.swal2-popup{grid-column:3;place-self:start end}div:where(.swal2-container).swal2-center-start>.swal2-popup,div:where(.swal2-container).swal2-center-left>.swal2-popup{grid-row:2;align-self:center}div:where(.swal2-container).swal2-center>.swal2-popup{grid-column:2;grid-row:2;place-self:center center}div:where(.swal2-container).swal2-center-end>.swal2-popup,div:where(.swal2-container).swal2-center-right>.swal2-popup{grid-column:3;grid-row:2;place-self:center end}div:where(.swal2-container).swal2-bottom-start>.swal2-popup,div:where(.swal2-container).swal2-bottom-left>.swal2-popup{grid-column:1;grid-row:3;align-self:end}div:where(.swal2-container).swal2-bottom>.swal2-popup{grid-column:2;grid-row:3;place-self:end center}div:where(.swal2-container).swal2-bottom-end>.swal2-popup,div:where(.swal2-container).swal2-bottom-right>.swal2-popup{grid-column:3;grid-row:3;place-self:end end}div:where(.swal2-container).swal2-grow-row>.swal2-popup,div:where(.swal2-container).swal2-grow-fullscreen>.swal2-popup{grid-column:1/4;width:100%}div:where(.swal2-container).swal2-grow-column>.swal2-popup,div:where(.swal2-container).swal2-grow-fullscreen>.swal2-popup{grid-row:1/4;align-self:stretch}div:where(.swal2-container).swal2-no-transition{transition:none !important}div:where(.swal2-container)[popover]{width:auto;border:0}div:where(.swal2-container) div:where(.swal2-popup){display:none;position:relative;box-sizing:border-box;grid-template-columns:minmax(0, 100%);width:var(--swal2-width);max-width:100%;padding:var(--swal2-padding);border:var(--swal2-border);border-radius:var(--swal2-border-radius);background:var(--swal2-background);color:var(--swal2-color);font-family:inherit;font-size:1rem;container-name:swal2-popup}div:where(.swal2-container) div:where(.swal2-popup):focus{outline:none}div:where(.swal2-container) div:where(.swal2-popup).swal2-loading{overflow-y:hidden}div:where(.swal2-container) div:where(.swal2-popup).swal2-draggable{cursor:grab}div:where(.swal2-container) div:where(.swal2-popup).swal2-draggable div:where(.swal2-icon){cursor:grab}div:where(.swal2-container) div:where(.swal2-popup).swal2-dragging{cursor:grabbing}div:where(.swal2-container) div:where(.swal2-popup).swal2-dragging div:where(.swal2-icon){cursor:grabbing}div:where(.swal2-container) h2:where(.swal2-title){position:relative;max-width:100%;margin:0;padding:var(--swal2-title-padding);color:inherit;font-size:1.875em;font-weight:600;text-align:center;text-transform:none;overflow-wrap:break-word;cursor:initial}div:where(.swal2-container) div:where(.swal2-actions){display:flex;z-index:1;box-sizing:border-box;flex-wrap:wrap;align-items:center;justify-content:var(--swal2-actions-justify-content);width:var(--swal2-actions-width);margin:var(--swal2-actions-margin);padding:var(--swal2-actions-padding);border-radius:var(--swal2-actions-border-radius);background:var(--swal2-actions-background)}div:where(.swal2-container) div:where(.swal2-loader){display:none;align-items:center;justify-content:center;width:2.2em;height:2.2em;margin:0 1.875em;animation:swal2-rotate-loading 1.5s linear 0s infinite normal;border-width:.25em;border-style:solid;border-radius:100%;border-color:#2778c4 rgba(0,0,0,0) #2778c4 rgba(0,0,0,0)}div:where(.swal2-container) button:where(.swal2-styled){margin:.3125em;padding:.625em 1.1em;transition:var(--swal2-action-button-transition);border:none;box-shadow:0 0 0 3px rgba(0,0,0,0);font-weight:500}div:where(.swal2-container) button:where(.swal2-styled):not([disabled]){cursor:pointer}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-confirm){border-radius:var(--swal2-confirm-button-border-radius);background:initial;background-color:var(--swal2-confirm-button-background-color);box-shadow:var(--swal2-confirm-button-box-shadow);color:var(--swal2-confirm-button-color);font-size:1em}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-confirm):hover{background-color:color-mix(in srgb, var(--swal2-confirm-button-background-color), var(--swal2-action-button-hover))}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-confirm):active{background-color:color-mix(in srgb, var(--swal2-confirm-button-background-color), var(--swal2-action-button-active))}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-deny){border-radius:var(--swal2-deny-button-border-radius);background:initial;background-color:var(--swal2-deny-button-background-color);box-shadow:var(--swal2-deny-button-box-shadow);color:var(--swal2-deny-button-color);font-size:1em}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-deny):hover{background-color:color-mix(in srgb, var(--swal2-deny-button-background-color), var(--swal2-action-button-hover))}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-deny):active{background-color:color-mix(in srgb, var(--swal2-deny-button-background-color), var(--swal2-action-button-active))}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-cancel){border-radius:var(--swal2-cancel-button-border-radius);background:initial;background-color:var(--swal2-cancel-button-background-color);box-shadow:var(--swal2-cancel-button-box-shadow);color:var(--swal2-cancel-button-color);font-size:1em}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-cancel):hover{background-color:color-mix(in srgb, var(--swal2-cancel-button-background-color), var(--swal2-action-button-hover))}div:where(.swal2-container) button:where(.swal2-styled):where(.swal2-cancel):active{background-color:color-mix(in srgb, var(--swal2-cancel-button-background-color), var(--swal2-action-button-active))}div:where(.swal2-container) button:where(.swal2-styled):focus-visible{outline:none;box-shadow:var(--swal2-action-button-focus-box-shadow)}div:where(.swal2-container) button:where(.swal2-styled)[disabled]:not(.swal2-loading){opacity:.4}div:where(.swal2-container) button:where(.swal2-styled)::-moz-focus-inner{border:0}div:where(.swal2-container) div:where(.swal2-footer){margin:1em 0 0;padding:1em 1em 0;border-top:1px solid var(--swal2-footer-border-color);background:var(--swal2-footer-background);color:var(--swal2-footer-color);font-size:1em;text-align:center;cursor:initial}div:where(.swal2-container) .swal2-timer-progress-bar-container{position:absolute;right:0;bottom:0;left:0;grid-column:auto !important;overflow:hidden;border-bottom-right-radius:var(--swal2-border-radius);border-bottom-left-radius:var(--swal2-border-radius)}div:where(.swal2-container) div:where(.swal2-timer-progress-bar){width:100%;height:.25em;background:var(--swal2-timer-progress-bar-background)}div:where(.swal2-container) img:where(.swal2-image){max-width:100%;margin:2em auto 1em;cursor:initial}div:where(.swal2-container) button:where(.swal2-close){position:var(--swal2-close-button-position);inset:var(--swal2-close-button-inset);z-index:2;align-items:center;justify-content:center;width:1.2em;height:1.2em;margin-top:0;margin-right:0;margin-bottom:-1.2em;padding:0;overflow:hidden;transition:var(--swal2-close-button-transition);border:none;border-radius:var(--swal2-border-radius);outline:var(--swal2-close-button-outline);background:rgba(0,0,0,0);color:var(--swal2-close-button-color);font-family:monospace;font-size:var(--swal2-close-button-font-size);cursor:pointer;justify-self:end}div:where(.swal2-container) button:where(.swal2-close):hover{transform:var(--swal2-close-button-hover-transform);background:rgba(0,0,0,0);color:#f27474}div:where(.swal2-container) button:where(.swal2-close):focus-visible{outline:none;box-shadow:var(--swal2-close-button-focus-box-shadow)}div:where(.swal2-container) button:where(.swal2-close)::-moz-focus-inner{border:0}div:where(.swal2-container) div:where(.swal2-html-container){z-index:1;justify-content:center;margin:0;padding:var(--swal2-html-container-padding);overflow:auto;color:inherit;font-size:1.125em;font-weight:normal;line-height:normal;text-align:center;overflow-wrap:break-word;word-break:break-word;cursor:initial}div:where(.swal2-container) input:where(.swal2-input),div:where(.swal2-container) input:where(.swal2-file),div:where(.swal2-container) textarea:where(.swal2-textarea),div:where(.swal2-container) select:where(.swal2-select),div:where(.swal2-container) div:where(.swal2-radio),div:where(.swal2-container) label:where(.swal2-checkbox){margin:1em 2em 3px}div:where(.swal2-container) input:where(.swal2-input),div:where(.swal2-container) input:where(.swal2-file),div:where(.swal2-container) textarea:where(.swal2-textarea){box-sizing:border-box;width:auto;transition:var(--swal2-input-transition);border:var(--swal2-input-border);border-radius:var(--swal2-input-border-radius);background:var(--swal2-input-background);box-shadow:var(--swal2-input-box-shadow);color:inherit;font-size:1.125em}div:where(.swal2-container) input:where(.swal2-input).swal2-inputerror,div:where(.swal2-container) input:where(.swal2-file).swal2-inputerror,div:where(.swal2-container) textarea:where(.swal2-textarea).swal2-inputerror{border-color:#f27474 !important;box-shadow:0 0 2px #f27474 !important}div:where(.swal2-container) input:where(.swal2-input):hover,div:where(.swal2-container) input:where(.swal2-file):hover,div:where(.swal2-container) textarea:where(.swal2-textarea):hover{box-shadow:var(--swal2-input-hover-box-shadow)}div:where(.swal2-container) input:where(.swal2-input):focus,div:where(.swal2-container) input:where(.swal2-file):focus,div:where(.swal2-container) textarea:where(.swal2-textarea):focus{border:var(--swal2-input-focus-border);outline:none;box-shadow:var(--swal2-input-focus-box-shadow)}div:where(.swal2-container) input:where(.swal2-input)::placeholder,div:where(.swal2-container) input:where(.swal2-file)::placeholder,div:where(.swal2-container) textarea:where(.swal2-textarea)::placeholder{color:#ccc}div:where(.swal2-container) .swal2-range{margin:1em 2em 3px;background:var(--swal2-background)}div:where(.swal2-container) .swal2-range input{width:80%}div:where(.swal2-container) .swal2-range output{width:20%;color:inherit;font-weight:600;text-align:center}div:where(.swal2-container) .swal2-range input,div:where(.swal2-container) .swal2-range output{height:2.625em;padding:0;font-size:1.125em;line-height:2.625em}div:where(.swal2-container) .swal2-input{height:2.625em;padding:0 .75em}div:where(.swal2-container) .swal2-file{width:75%;margin-right:auto;margin-left:auto;background:var(--swal2-input-background);font-size:1.125em}div:where(.swal2-container) .swal2-textarea{height:6.75em;padding:.75em}div:where(.swal2-container) .swal2-select{min-width:50%;max-width:100%;padding:.375em .625em;background:var(--swal2-input-background);color:inherit;font-size:1.125em}div:where(.swal2-container) .swal2-radio,div:where(.swal2-container) .swal2-checkbox{align-items:center;justify-content:center;background:var(--swal2-background);color:inherit}div:where(.swal2-container) .swal2-radio label,div:where(.swal2-container) .swal2-checkbox label{margin:0 .6em;font-size:1.125em}div:where(.swal2-container) .swal2-radio input,div:where(.swal2-container) .swal2-checkbox input{flex-shrink:0;margin:0 .4em}div:where(.swal2-container) label:where(.swal2-input-label){display:flex;justify-content:center;margin:1em auto 0}div:where(.swal2-container) div:where(.swal2-validation-message){align-items:center;justify-content:center;margin:1em 0 0;padding:.625em;overflow:hidden;background:var(--swal2-validation-message-background);color:var(--swal2-validation-message-color);font-size:1em;font-weight:300}div:where(.swal2-container) div:where(.swal2-validation-message)::before{content:\"!\";display:inline-block;width:1.5em;min-width:1.5em;height:1.5em;margin:0 .625em;border-radius:50%;background-color:#f27474;color:#fff;font-weight:600;line-height:1.5em;text-align:center}div:where(.swal2-container) .swal2-progress-steps{flex-wrap:wrap;align-items:center;max-width:100%;margin:1.25em auto;padding:0;background:rgba(0,0,0,0);font-weight:600}div:where(.swal2-container) .swal2-progress-steps li{display:inline-block;position:relative}div:where(.swal2-container) .swal2-progress-steps .swal2-progress-step{z-index:20;flex-shrink:0;width:2em;height:2em;border-radius:2em;background:#2778c4;color:#fff;line-height:2em;text-align:center}div:where(.swal2-container) .swal2-progress-steps .swal2-progress-step.swal2-active-progress-step{background:#2778c4}div:where(.swal2-container) .swal2-progress-steps .swal2-progress-step.swal2-active-progress-step~.swal2-progress-step{background:var(--swal2-progress-step-background);color:#fff}div:where(.swal2-container) .swal2-progress-steps .swal2-progress-step.swal2-active-progress-step~.swal2-progress-step-line{background:var(--swal2-progress-step-background)}div:where(.swal2-container) .swal2-progress-steps .swal2-progress-step-line{z-index:10;flex-shrink:0;width:2.5em;height:.4em;margin:0 -1px;background:#2778c4}div:where(.swal2-icon){position:relative;box-sizing:content-box;justify-content:center;width:5em;height:5em;margin:2.5em auto .6em;zoom:var(--swal2-icon-zoom);border:.25em solid rgba(0,0,0,0);border-radius:50%;border-color:#000;font-family:inherit;line-height:5em;cursor:default;user-select:none}div:where(.swal2-icon) .swal2-icon-content{display:flex;align-items:center;font-size:3.75em}div:where(.swal2-icon).swal2-error{border-color:#f27474;color:#f27474}div:where(.swal2-icon).swal2-error .swal2-x-mark{position:relative;flex-grow:1}div:where(.swal2-icon).swal2-error [class^=swal2-x-mark-line]{display:block;position:absolute;top:2.3125em;width:2.9375em;height:.3125em;border-radius:.125em;background-color:#f27474}div:where(.swal2-icon).swal2-error [class^=swal2-x-mark-line][class$=left]{left:1.0625em;transform:rotate(45deg)}div:where(.swal2-icon).swal2-error [class^=swal2-x-mark-line][class$=right]{right:1em;transform:rotate(-45deg)}@container swal2-popup style(--swal2-icon-animations:true){div:where(.swal2-icon).swal2-error.swal2-icon-show{animation:swal2-animate-error-icon .5s}div:where(.swal2-icon).swal2-error.swal2-icon-show .swal2-x-mark{animation:swal2-animate-error-x-mark .5s}}div:where(.swal2-icon).swal2-warning{border-color:#f8bb86;color:#f8bb86}@container swal2-popup style(--swal2-icon-animations:true){div:where(.swal2-icon).swal2-warning.swal2-icon-show{animation:swal2-animate-error-icon .5s}div:where(.swal2-icon).swal2-warning.swal2-icon-show .swal2-icon-content{animation:swal2-animate-i-mark .5s}}div:where(.swal2-icon).swal2-info{border-color:#3fc3ee;color:#3fc3ee}@container swal2-popup style(--swal2-icon-animations:true){div:where(.swal2-icon).swal2-info.swal2-icon-show{animation:swal2-animate-error-icon .5s}div:where(.swal2-icon).swal2-info.swal2-icon-show .swal2-icon-content{animation:swal2-animate-i-mark .8s}}div:where(.swal2-icon).swal2-question{border-color:#87adbd;color:#87adbd}@container swal2-popup style(--swal2-icon-animations:true){div:where(.swal2-icon).swal2-question.swal2-icon-show{animation:swal2-animate-error-icon .5s}div:where(.swal2-icon).swal2-question.swal2-icon-show .swal2-icon-content{animation:swal2-animate-question-mark .8s}}div:where(.swal2-icon).swal2-success{border-color:#a5dc86;color:#a5dc86}div:where(.swal2-icon).swal2-success [class^=swal2-success-circular-line]{position:absolute;width:3.75em;height:7.5em;border-radius:50%}div:where(.swal2-icon).swal2-success [class^=swal2-success-circular-line][class$=left]{top:-0.4375em;left:-2.0635em;transform:rotate(-45deg);transform-origin:3.75em 3.75em;border-radius:7.5em 0 0 7.5em}div:where(.swal2-icon).swal2-success [class^=swal2-success-circular-line][class$=right]{top:-0.6875em;left:1.875em;transform:rotate(-45deg);transform-origin:0 3.75em;border-radius:0 7.5em 7.5em 0}div:where(.swal2-icon).swal2-success .swal2-success-ring{position:absolute;z-index:2;top:-0.25em;left:-0.25em;box-sizing:content-box;width:100%;height:100%;border:.25em solid rgba(165,220,134,.3);border-radius:50%}div:where(.swal2-icon).swal2-success .swal2-success-fix{position:absolute;z-index:1;top:.5em;left:1.625em;width:.4375em;height:5.625em;transform:rotate(-45deg)}div:where(.swal2-icon).swal2-success [class^=swal2-success-line]{display:block;position:absolute;z-index:2;height:.3125em;border-radius:.125em;background-color:#a5dc86}div:where(.swal2-icon).swal2-success [class^=swal2-success-line][class$=tip]{top:2.875em;left:.8125em;width:1.5625em;transform:rotate(45deg)}div:where(.swal2-icon).swal2-success [class^=swal2-success-line][class$=long]{top:2.375em;right:.5em;width:2.9375em;transform:rotate(-45deg)}@container swal2-popup style(--swal2-icon-animations:true){div:where(.swal2-icon).swal2-success.swal2-icon-show .swal2-success-line-tip{animation:swal2-animate-success-line-tip .75s}div:where(.swal2-icon).swal2-success.swal2-icon-show .swal2-success-line-long{animation:swal2-animate-success-line-long .75s}div:where(.swal2-icon).swal2-success.swal2-icon-show .swal2-success-circular-line-right{animation:swal2-rotate-success-circular-line 4.25s ease-in}}[class^=swal2]{-webkit-tap-highlight-color:rgba(0,0,0,0)}.swal2-show{animation:var(--swal2-show-animation)}.swal2-hide{animation:var(--swal2-hide-animation)}.swal2-noanimation{transition:none}.swal2-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}.swal2-rtl .swal2-close{margin-right:initial;margin-left:0}.swal2-rtl .swal2-timer-progress-bar{right:0;left:auto}.swal2-toast{box-sizing:border-box;grid-column:1/4 !important;grid-row:1/4 !important;grid-template-columns:min-content auto min-content;padding:1em;overflow-y:hidden;border:var(--swal2-toast-border);background:var(--swal2-background);box-shadow:var(--swal2-toast-box-shadow);pointer-events:all}.swal2-toast>*{grid-column:2}.swal2-toast h2:where(.swal2-title){margin:.5em 1em;padding:0;font-size:1em;text-align:initial}.swal2-toast .swal2-loading{justify-content:center}.swal2-toast input:where(.swal2-input){height:2em;margin:.5em;font-size:1em}.swal2-toast .swal2-validation-message{font-size:1em}.swal2-toast div:where(.swal2-footer){margin:.5em 0 0;padding:.5em 0 0;font-size:.8em}.swal2-toast button:where(.swal2-close){grid-column:3/3;grid-row:1/99;align-self:center;width:.8em;height:.8em;margin:0;font-size:2em}.swal2-toast div:where(.swal2-html-container){margin:.5em 1em;padding:0;overflow:initial;font-size:1em;text-align:initial}.swal2-toast div:where(.swal2-html-container):empty{padding:0}.swal2-toast .swal2-loader{grid-column:1;grid-row:1/99;align-self:center;width:2em;height:2em;margin:.25em}.swal2-toast .swal2-icon{grid-column:1;grid-row:1/99;align-self:center;width:2em;min-width:2em;height:2em;margin:0 .5em 0 0}.swal2-toast .swal2-icon .swal2-icon-content{display:flex;align-items:center;font-size:1.8em;font-weight:bold}.swal2-toast .swal2-icon.swal2-success .swal2-success-ring{width:2em;height:2em}.swal2-toast .swal2-icon.swal2-error [class^=swal2-x-mark-line]{top:.875em;width:1.375em}.swal2-toast .swal2-icon.swal2-error [class^=swal2-x-mark-line][class$=left]{left:.3125em}.swal2-toast .swal2-icon.swal2-error [class^=swal2-x-mark-line][class$=right]{right:.3125em}.swal2-toast div:where(.swal2-actions){justify-content:flex-start;height:auto;margin:0;margin-top:.5em;padding:0 .5em}.swal2-toast button:where(.swal2-styled){margin:.25em .5em;padding:.4em .6em;font-size:1em}.swal2-toast .swal2-success{border-color:#a5dc86}.swal2-toast .swal2-success [class^=swal2-success-circular-line]{position:absolute;width:1.6em;height:3em;border-radius:50%}.swal2-toast .swal2-success [class^=swal2-success-circular-line][class$=left]{top:-0.8em;left:-0.5em;transform:rotate(-45deg);transform-origin:2em 2em;border-radius:4em 0 0 4em}.swal2-toast .swal2-success [class^=swal2-success-circular-line][class$=right]{top:-0.25em;left:.9375em;transform-origin:0 1.5em;border-radius:0 4em 4em 0}.swal2-toast .swal2-success .swal2-success-ring{width:2em;height:2em}.swal2-toast .swal2-success .swal2-success-fix{top:0;left:.4375em;width:.4375em;height:2.6875em}.swal2-toast .swal2-success [class^=swal2-success-line]{height:.3125em}.swal2-toast .swal2-success [class^=swal2-success-line][class$=tip]{top:1.125em;left:.1875em;width:.75em}.swal2-toast .swal2-success [class^=swal2-success-line][class$=long]{top:.9375em;right:.1875em;width:1.375em}@container swal2-popup style(--swal2-icon-animations:true){.swal2-toast .swal2-success.swal2-icon-show .swal2-success-line-tip{animation:swal2-toast-animate-success-line-tip .75s}.swal2-toast .swal2-success.swal2-icon-show .swal2-success-line-long{animation:swal2-toast-animate-success-line-long .75s}}.swal2-toast.swal2-show{animation:var(--swal2-toast-show-animation)}.swal2-toast.swal2-hide{animation:var(--swal2-toast-hide-animation)}@keyframes swal2-show{0%{transform:translate3d(0, -50px, 0) scale(0.9);opacity:0}100%{transform:translate3d(0, 0, 0) scale(1);opacity:1}}@keyframes swal2-hide{0%{transform:translate3d(0, 0, 0) scale(1);opacity:1}100%{transform:translate3d(0, -50px, 0) scale(0.9);opacity:0}}@keyframes swal2-animate-success-line-tip{0%{top:1.1875em;left:.0625em;width:0}54%{top:1.0625em;left:.125em;width:0}70%{top:2.1875em;left:-0.375em;width:3.125em}84%{top:3em;left:1.3125em;width:1.0625em}100%{top:2.8125em;left:.8125em;width:1.5625em}}@keyframes swal2-animate-success-line-long{0%{top:3.375em;right:2.875em;width:0}65%{top:3.375em;right:2.875em;width:0}84%{top:2.1875em;right:0;width:3.4375em}100%{top:2.375em;right:.5em;width:2.9375em}}@keyframes swal2-rotate-success-circular-line{0%{transform:rotate(-45deg)}5%{transform:rotate(-45deg)}12%{transform:rotate(-405deg)}100%{transform:rotate(-405deg)}}@keyframes swal2-animate-error-x-mark{0%{margin-top:1.625em;transform:scale(0.4);opacity:0}50%{margin-top:1.625em;transform:scale(0.4);opacity:0}80%{margin-top:-0.375em;transform:scale(1.15)}100%{margin-top:0;transform:scale(1);opacity:1}}@keyframes swal2-animate-error-icon{0%{transform:rotateX(100deg);opacity:0}100%{transform:rotateX(0deg);opacity:1}}@keyframes swal2-rotate-loading{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}@keyframes swal2-animate-question-mark{0%{transform:rotateY(-360deg)}100%{transform:rotateY(0)}}@keyframes swal2-animate-i-mark{0%{transform:rotateZ(45deg);opacity:0}25%{transform:rotateZ(-25deg);opacity:.4}50%{transform:rotateZ(15deg);opacity:.8}75%{transform:rotateZ(-5deg);opacity:1}100%{transform:rotateX(0);opacity:1}}@keyframes swal2-toast-show{0%{transform:translateY(-0.625em) rotateZ(2deg)}33%{transform:translateY(0) rotateZ(-2deg)}66%{transform:translateY(0.3125em) rotateZ(2deg)}100%{transform:translateY(0) rotateZ(0deg)}}@keyframes swal2-toast-hide{100%{transform:rotateZ(1deg);opacity:0}}@keyframes swal2-toast-animate-success-line-tip{0%{top:.5625em;left:.0625em;width:0}54%{top:.125em;left:.125em;width:0}70%{top:.625em;left:-0.25em;width:1.625em}84%{top:1.0625em;left:.75em;width:.5em}100%{top:1.125em;left:.1875em;width:.75em}}@keyframes swal2-toast-animate-success-line-long{0%{top:1.625em;right:1.375em;width:0}65%{top:1.25em;right:.9375em;width:0}84%{top:.9375em;right:0;width:1.125em}100%{top:.9375em;right:.1875em;width:1.375em}}"); /***/ }, /***/ "./node_modules/toastify-js/src/toastify.js" /*!**************************************************!*\ !*** ./node_modules/toastify-js/src/toastify.js ***! \**************************************************/ (module) { /*! * Toastify js 1.12.0 * https://github.com/apvarun/toastify-js * @license MIT licensed * * Copyright (C) 2018 Varun A P */ (function(root, factory) { if ( true && module.exports) { module.exports = factory(); } else { root.Toastify = factory(); } })(this, function(global) { // Object initialization var Toastify = function(options) { // Returning a new init object return new Toastify.lib.init(options); }, // Library version version = "1.12.0"; // Set the default global options Toastify.defaults = { oldestFirst: true, text: "Toastify is awesome!", node: undefined, duration: 3000, selector: undefined, callback: function () { }, destination: undefined, newWindow: false, close: false, gravity: "toastify-top", positionLeft: false, position: '', backgroundColor: '', avatar: "", className: "", stopOnFocus: true, onClick: function () { }, offset: {x: 0, y: 0}, escapeMarkup: true, ariaLive: 'polite', style: {background: ''} }; // Defining the prototype of the object Toastify.lib = Toastify.prototype = { toastify: version, constructor: Toastify, // Initializing the object with required parameters init: function(options) { // Verifying and validating the input object if (!options) { options = {}; } // Creating the options object this.options = {}; this.toastElement = null; // Validating the options this.options.text = options.text || Toastify.defaults.text; // Display message this.options.node = options.node || Toastify.defaults.node; // Display content as node this.options.duration = options.duration === 0 ? 0 : options.duration || Toastify.defaults.duration; // Display duration this.options.selector = options.selector || Toastify.defaults.selector; // Parent selector this.options.callback = options.callback || Toastify.defaults.callback; // Callback after display this.options.destination = options.destination || Toastify.defaults.destination; // On-click destination this.options.newWindow = options.newWindow || Toastify.defaults.newWindow; // Open destination in new window this.options.close = options.close || Toastify.defaults.close; // Show toast close icon this.options.gravity = options.gravity === "bottom" ? "toastify-bottom" : Toastify.defaults.gravity; // toast position - top or bottom this.options.positionLeft = options.positionLeft || Toastify.defaults.positionLeft; // toast position - left or right this.options.position = options.position || Toastify.defaults.position; // toast position - left or right this.options.backgroundColor = options.backgroundColor || Toastify.defaults.backgroundColor; // toast background color this.options.avatar = options.avatar || Toastify.defaults.avatar; // img element src - url or a path this.options.className = options.className || Toastify.defaults.className; // additional class names for the toast this.options.stopOnFocus = options.stopOnFocus === undefined ? Toastify.defaults.stopOnFocus : options.stopOnFocus; // stop timeout on focus this.options.onClick = options.onClick || Toastify.defaults.onClick; // Callback after click this.options.offset = options.offset || Toastify.defaults.offset; // toast offset this.options.escapeMarkup = options.escapeMarkup !== undefined ? options.escapeMarkup : Toastify.defaults.escapeMarkup; this.options.ariaLive = options.ariaLive || Toastify.defaults.ariaLive; this.options.style = options.style || Toastify.defaults.style; if(options.backgroundColor) { this.options.style.background = options.backgroundColor; } // Returning the current object for chaining functions return this; }, // Building the DOM element buildToast: function() { // Validating if the options are defined if (!this.options) { throw "Toastify is not initialized"; } // Creating the DOM object var divElement = document.createElement("div"); divElement.className = "toastify on " + this.options.className; // Positioning toast to left or right or center if (!!this.options.position) { divElement.className += " toastify-" + this.options.position; } else { // To be depreciated in further versions if (this.options.positionLeft === true) { divElement.className += " toastify-left"; console.warn('Property `positionLeft` will be depreciated in further versions. Please use `position` instead.') } else { // Default position divElement.className += " toastify-right"; } } // Assigning gravity of element divElement.className += " " + this.options.gravity; if (this.options.backgroundColor) { // This is being deprecated in favor of using the style HTML DOM property console.warn('DEPRECATION NOTICE: "backgroundColor" is being deprecated. Please use the "style.background" property.'); } // Loop through our style object and apply styles to divElement for (var property in this.options.style) { divElement.style[property] = this.options.style[property]; } // Announce the toast to screen readers if (this.options.ariaLive) { divElement.setAttribute('aria-live', this.options.ariaLive) } // Adding the toast message/node if (this.options.node && this.options.node.nodeType === Node.ELEMENT_NODE) { // If we have a valid node, we insert it divElement.appendChild(this.options.node) } else { if (this.options.escapeMarkup) { divElement.innerText = this.options.text; } else { divElement.innerHTML = this.options.text; } if (this.options.avatar !== "") { var avatarElement = document.createElement("img"); avatarElement.src = this.options.avatar; avatarElement.className = "toastify-avatar"; if (this.options.position == "left" || this.options.positionLeft === true) { // Adding close icon on the left of content divElement.appendChild(avatarElement); } else { // Adding close icon on the right of content divElement.insertAdjacentElement("afterbegin", avatarElement); } } } // Adding a close icon to the toast if (this.options.close === true) { // Create a span for close element var closeElement = document.createElement("button"); closeElement.type = "button"; closeElement.setAttribute("aria-label", "Close"); closeElement.className = "toast-close"; closeElement.innerHTML = "✖"; // Triggering the removal of toast from DOM on close click closeElement.addEventListener( "click", function(event) { event.stopPropagation(); this.removeElement(this.toastElement); window.clearTimeout(this.toastElement.timeOutValue); }.bind(this) ); //Calculating screen width var width = window.innerWidth > 0 ? window.innerWidth : screen.width; // Adding the close icon to the toast element // Display on the right if screen width is less than or equal to 360px if ((this.options.position == "left" || this.options.positionLeft === true) && width > 360) { // Adding close icon on the left of content divElement.insertAdjacentElement("afterbegin", closeElement); } else { // Adding close icon on the right of content divElement.appendChild(closeElement); } } // Clear timeout while toast is focused if (this.options.stopOnFocus && this.options.duration > 0) { var self = this; // stop countdown divElement.addEventListener( "mouseover", function(event) { window.clearTimeout(divElement.timeOutValue); } ) // add back the timeout divElement.addEventListener( "mouseleave", function() { divElement.timeOutValue = window.setTimeout( function() { // Remove the toast from DOM self.removeElement(divElement); }, self.options.duration ) } ) } // Adding an on-click destination path if (typeof this.options.destination !== "undefined") { divElement.addEventListener( "click", function(event) { event.stopPropagation(); if (this.options.newWindow === true) { window.open(this.options.destination, "_blank"); } else { window.location = this.options.destination; } }.bind(this) ); } if (typeof this.options.onClick === "function" && typeof this.options.destination === "undefined") { divElement.addEventListener( "click", function(event) { event.stopPropagation(); this.options.onClick(); }.bind(this) ); } // Adding offset if(typeof this.options.offset === "object") { var x = getAxisOffsetAValue("x", this.options); var y = getAxisOffsetAValue("y", this.options); var xOffset = this.options.position == "left" ? x : "-" + x; var yOffset = this.options.gravity == "toastify-top" ? y : "-" + y; divElement.style.transform = "translate(" + xOffset + "," + yOffset + ")"; } // Returning the generated element return divElement; }, // Displaying the toast showToast: function() { // Creating the DOM object for the toast this.toastElement = this.buildToast(); // Getting the root element to with the toast needs to be added var rootElement; if (typeof this.options.selector === "string") { rootElement = document.getElementById(this.options.selector); } else if (this.options.selector instanceof HTMLElement || (typeof ShadowRoot !== 'undefined' && this.options.selector instanceof ShadowRoot)) { rootElement = this.options.selector; } else { rootElement = document.body; } // Validating if root element is present in DOM if (!rootElement) { throw "Root element is not defined"; } // Adding the DOM element var elementToInsert = Toastify.defaults.oldestFirst ? rootElement.firstChild : rootElement.lastChild; rootElement.insertBefore(this.toastElement, elementToInsert); // Repositioning the toasts in case multiple toasts are present Toastify.reposition(); if (this.options.duration > 0) { this.toastElement.timeOutValue = window.setTimeout( function() { // Remove the toast from DOM this.removeElement(this.toastElement); }.bind(this), this.options.duration ); // Binding `this` for function invocation } // Supporting function chaining return this; }, hideToast: function() { if (this.toastElement.timeOutValue) { clearTimeout(this.toastElement.timeOutValue); } this.removeElement(this.toastElement); }, // Removing the element from the DOM removeElement: function(toastElement) { // Hiding the element // toastElement.classList.remove("on"); toastElement.className = toastElement.className.replace(" on", ""); // Removing the element from DOM after transition end window.setTimeout( function() { // remove options node if any if (this.options.node && this.options.node.parentNode) { this.options.node.parentNode.removeChild(this.options.node); } // Remove the element from the DOM, only when the parent node was not removed before. if (toastElement.parentNode) { toastElement.parentNode.removeChild(toastElement); } // Calling the callback function this.options.callback.call(toastElement); // Repositioning the toasts again Toastify.reposition(); }.bind(this), 400 ); // Binding `this` for function invocation }, }; // Positioning the toasts on the DOM Toastify.reposition = function() { // Top margins with gravity var topLeftOffsetSize = { top: 15, bottom: 15, }; var topRightOffsetSize = { top: 15, bottom: 15, }; var offsetSize = { top: 15, bottom: 15, }; // Get all toast messages on the DOM var allToasts = document.getElementsByClassName("toastify"); var classUsed; // Modifying the position of each toast element for (var i = 0; i < allToasts.length; i++) { // Getting the applied gravity if (containsClass(allToasts[i], "toastify-top") === true) { classUsed = "toastify-top"; } else { classUsed = "toastify-bottom"; } var height = allToasts[i].offsetHeight; classUsed = classUsed.substr(9, classUsed.length-1) // Spacing between toasts var offset = 15; var width = window.innerWidth > 0 ? window.innerWidth : screen.width; // Show toast in center if screen with less than or equal to 360px if (width <= 360) { // Setting the position allToasts[i].style[classUsed] = offsetSize[classUsed] + "px"; offsetSize[classUsed] += height + offset; } else { if (containsClass(allToasts[i], "toastify-left") === true) { // Setting the position allToasts[i].style[classUsed] = topLeftOffsetSize[classUsed] + "px"; topLeftOffsetSize[classUsed] += height + offset; } else { // Setting the position allToasts[i].style[classUsed] = topRightOffsetSize[classUsed] + "px"; topRightOffsetSize[classUsed] += height + offset; } } } // Supporting function chaining return this; }; // Helper function to get offset. function getAxisOffsetAValue(axis, options) { if(options.offset[axis]) { if(isNaN(options.offset[axis])) { return options.offset[axis]; } else { return options.offset[axis] + 'px'; } } return '0px'; } function containsClass(elem, yourClass) { if (!elem || typeof yourClass !== "string") { return false; } else if ( elem.className && elem.className .trim() .split(/\s+/gi) .indexOf(yourClass) > -1 ) { return true; } else { return false; } } // Setting up the prototype for the init object Toastify.lib.init.prototype = Toastify.lib; // Returning the Toastify function to be assigned to the window object/module return Toastify; }); /***/ }, /***/ "./node_modules/@kurkle/color/dist/color.esm.js" /*!******************************************************!*\ !*** ./node_modules/@kurkle/color/dist/color.esm.js ***! \******************************************************/ (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ Color: () => (/* binding */ Color), /* harmony export */ b2n: () => (/* binding */ b2n), /* harmony export */ b2p: () => (/* binding */ b2p), /* harmony export */ "default": () => (/* binding */ index_esm), /* harmony export */ hexParse: () => (/* binding */ hexParse), /* harmony export */ hexString: () => (/* binding */ hexString), /* harmony export */ hsl2rgb: () => (/* binding */ hsl2rgb), /* harmony export */ hslString: () => (/* binding */ hslString), /* harmony export */ hsv2rgb: () => (/* binding */ hsv2rgb), /* harmony export */ hueParse: () => (/* binding */ hueParse), /* harmony export */ hwb2rgb: () => (/* binding */ hwb2rgb), /* harmony export */ lim: () => (/* binding */ lim), /* harmony export */ n2b: () => (/* binding */ n2b), /* harmony export */ n2p: () => (/* binding */ n2p), /* harmony export */ nameParse: () => (/* binding */ nameParse), /* harmony export */ p2b: () => (/* binding */ p2b), /* harmony export */ rgb2hsl: () => (/* binding */ rgb2hsl), /* harmony export */ rgbParse: () => (/* binding */ rgbParse), /* harmony export */ rgbString: () => (/* binding */ rgbString), /* harmony export */ rotate: () => (/* binding */ rotate), /* harmony export */ round: () => (/* binding */ round) /* harmony export */ }); /*! * @kurkle/color v0.3.4 * https://github.com/kurkle/color#readme * (c) 2024 Jukka Kurkela * Released under the MIT License */ function round(v) { return v + 0.5 | 0; } const lim = (v, l, h) => Math.max(Math.min(v, h), l); function p2b(v) { return lim(round(v * 2.55), 0, 255); } function b2p(v) { return lim(round(v / 2.55), 0, 100); } function n2b(v) { return lim(round(v * 255), 0, 255); } function b2n(v) { return lim(round(v / 2.55) / 100, 0, 1); } function n2p(v) { return lim(round(v * 100), 0, 100); } const map$1 = {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, A: 10, B: 11, C: 12, D: 13, E: 14, F: 15, a: 10, b: 11, c: 12, d: 13, e: 14, f: 15}; const hex = [...'0123456789ABCDEF']; const h1 = b => hex[b & 0xF]; const h2 = b => hex[(b & 0xF0) >> 4] + hex[b & 0xF]; const eq = b => ((b & 0xF0) >> 4) === (b & 0xF); const isShort = v => eq(v.r) && eq(v.g) && eq(v.b) && eq(v.a); function hexParse(str) { var len = str.length; var ret; if (str[0] === '#') { if (len === 4 || len === 5) { ret = { r: 255 & map$1[str[1]] * 17, g: 255 & map$1[str[2]] * 17, b: 255 & map$1[str[3]] * 17, a: len === 5 ? map$1[str[4]] * 17 : 255 }; } else if (len === 7 || len === 9) { ret = { r: map$1[str[1]] << 4 | map$1[str[2]], g: map$1[str[3]] << 4 | map$1[str[4]], b: map$1[str[5]] << 4 | map$1[str[6]], a: len === 9 ? (map$1[str[7]] << 4 | map$1[str[8]]) : 255 }; } } return ret; } const alpha = (a, f) => a < 255 ? f(a) : ''; function hexString(v) { var f = isShort(v) ? h1 : h2; return v ? '#' + f(v.r) + f(v.g) + f(v.b) + alpha(v.a, f) : undefined; } const HUE_RE = /^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/; function hsl2rgbn(h, s, l) { const a = s * Math.min(l, 1 - l); const f = (n, k = (n + h / 30) % 12) => l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1); return [f(0), f(8), f(4)]; } function hsv2rgbn(h, s, v) { const f = (n, k = (n + h / 60) % 6) => v - v * s * Math.max(Math.min(k, 4 - k, 1), 0); return [f(5), f(3), f(1)]; } function hwb2rgbn(h, w, b) { const rgb = hsl2rgbn(h, 1, 0.5); let i; if (w + b > 1) { i = 1 / (w + b); w *= i; b *= i; } for (i = 0; i < 3; i++) { rgb[i] *= 1 - w - b; rgb[i] += w; } return rgb; } function hueValue(r, g, b, d, max) { if (r === max) { return ((g - b) / d) + (g < b ? 6 : 0); } if (g === max) { return (b - r) / d + 2; } return (r - g) / d + 4; } function rgb2hsl(v) { const range = 255; const r = v.r / range; const g = v.g / range; const b = v.b / range; const max = Math.max(r, g, b); const min = Math.min(r, g, b); const l = (max + min) / 2; let h, s, d; if (max !== min) { d = max - min; s = l > 0.5 ? d / (2 - max - min) : d / (max + min); h = hueValue(r, g, b, d, max); h = h * 60 + 0.5; } return [h | 0, s || 0, l]; } function calln(f, a, b, c) { return ( Array.isArray(a) ? f(a[0], a[1], a[2]) : f(a, b, c) ).map(n2b); } function hsl2rgb(h, s, l) { return calln(hsl2rgbn, h, s, l); } function hwb2rgb(h, w, b) { return calln(hwb2rgbn, h, w, b); } function hsv2rgb(h, s, v) { return calln(hsv2rgbn, h, s, v); } function hue(h) { return (h % 360 + 360) % 360; } function hueParse(str) { const m = HUE_RE.exec(str); let a = 255; let v; if (!m) { return; } if (m[5] !== v) { a = m[6] ? p2b(+m[5]) : n2b(+m[5]); } const h = hue(+m[2]); const p1 = +m[3] / 100; const p2 = +m[4] / 100; if (m[1] === 'hwb') { v = hwb2rgb(h, p1, p2); } else if (m[1] === 'hsv') { v = hsv2rgb(h, p1, p2); } else { v = hsl2rgb(h, p1, p2); } return { r: v[0], g: v[1], b: v[2], a: a }; } function rotate(v, deg) { var h = rgb2hsl(v); h[0] = hue(h[0] + deg); h = hsl2rgb(h); v.r = h[0]; v.g = h[1]; v.b = h[2]; } function hslString(v) { if (!v) { return; } const a = rgb2hsl(v); const h = a[0]; const s = n2p(a[1]); const l = n2p(a[2]); return v.a < 255 ? `hsla(${h}, ${s}%, ${l}%, ${b2n(v.a)})` : `hsl(${h}, ${s}%, ${l}%)`; } const map = { x: 'dark', Z: 'light', Y: 're', X: 'blu', W: 'gr', V: 'medium', U: 'slate', A: 'ee', T: 'ol', S: 'or', B: 'ra', C: 'lateg', D: 'ights', R: 'in', Q: 'turquois', E: 'hi', P: 'ro', O: 'al', N: 'le', M: 'de', L: 'yello', F: 'en', K: 'ch', G: 'arks', H: 'ea', I: 'ightg', J: 'wh' }; const names$1 = { OiceXe: 'f0f8ff', antiquewEte: 'faebd7', aqua: 'ffff', aquamarRe: '7fffd4', azuY: 'f0ffff', beige: 'f5f5dc', bisque: 'ffe4c4', black: '0', blanKedOmond: 'ffebcd', Xe: 'ff', XeviTet: '8a2be2', bPwn: 'a52a2a', burlywood: 'deb887', caMtXe: '5f9ea0', KartYuse: '7fff00', KocTate: 'd2691e', cSO: 'ff7f50', cSnflowerXe: '6495ed', cSnsilk: 'fff8dc', crimson: 'dc143c', cyan: 'ffff', xXe: '8b', xcyan: '8b8b', xgTMnPd: 'b8860b', xWay: 'a9a9a9', xgYF: '6400', xgYy: 'a9a9a9', xkhaki: 'bdb76b', xmagFta: '8b008b', xTivegYF: '556b2f', xSange: 'ff8c00', xScEd: '9932cc', xYd: '8b0000', xsOmon: 'e9967a', xsHgYF: '8fbc8f', xUXe: '483d8b', xUWay: '2f4f4f', xUgYy: '2f4f4f', xQe: 'ced1', xviTet: '9400d3', dAppRk: 'ff1493', dApskyXe: 'bfff', dimWay: '696969', dimgYy: '696969', dodgerXe: '1e90ff', fiYbrick: 'b22222', flSOwEte: 'fffaf0', foYstWAn: '228b22', fuKsia: 'ff00ff', gaRsbSo: 'dcdcdc', ghostwEte: 'f8f8ff', gTd: 'ffd700', gTMnPd: 'daa520', Way: '808080', gYF: '8000', gYFLw: 'adff2f', gYy: '808080', honeyMw: 'f0fff0', hotpRk: 'ff69b4', RdianYd: 'cd5c5c', Rdigo: '4b0082', ivSy: 'fffff0', khaki: 'f0e68c', lavFMr: 'e6e6fa', lavFMrXsh: 'fff0f5', lawngYF: '7cfc00', NmoncEffon: 'fffacd', ZXe: 'add8e6', ZcSO: 'f08080', Zcyan: 'e0ffff', ZgTMnPdLw: 'fafad2', ZWay: 'd3d3d3', ZgYF: '90ee90', ZgYy: 'd3d3d3', ZpRk: 'ffb6c1', ZsOmon: 'ffa07a', ZsHgYF: '20b2aa', ZskyXe: '87cefa', ZUWay: '778899', ZUgYy: '778899', ZstAlXe: 'b0c4de', ZLw: 'ffffe0', lime: 'ff00', limegYF: '32cd32', lRF: 'faf0e6', magFta: 'ff00ff', maPon: '800000', VaquamarRe: '66cdaa', VXe: 'cd', VScEd: 'ba55d3', VpurpN: '9370db', VsHgYF: '3cb371', VUXe: '7b68ee', VsprRggYF: 'fa9a', VQe: '48d1cc', VviTetYd: 'c71585', midnightXe: '191970', mRtcYam: 'f5fffa', mistyPse: 'ffe4e1', moccasR: 'ffe4b5', navajowEte: 'ffdead', navy: '80', Tdlace: 'fdf5e6', Tive: '808000', TivedBb: '6b8e23', Sange: 'ffa500', SangeYd: 'ff4500', ScEd: 'da70d6', pOegTMnPd: 'eee8aa', pOegYF: '98fb98', pOeQe: 'afeeee', pOeviTetYd: 'db7093', papayawEp: 'ffefd5', pHKpuff: 'ffdab9', peru: 'cd853f', pRk: 'ffc0cb', plum: 'dda0dd', powMrXe: 'b0e0e6', purpN: '800080', YbeccapurpN: '663399', Yd: 'ff0000', Psybrown: 'bc8f8f', PyOXe: '4169e1', saddNbPwn: '8b4513', sOmon: 'fa8072', sandybPwn: 'f4a460', sHgYF: '2e8b57', sHshell: 'fff5ee', siFna: 'a0522d', silver: 'c0c0c0', skyXe: '87ceeb', UXe: '6a5acd', UWay: '708090', UgYy: '708090', snow: 'fffafa', sprRggYF: 'ff7f', stAlXe: '4682b4', tan: 'd2b48c', teO: '8080', tEstN: 'd8bfd8', tomato: 'ff6347', Qe: '40e0d0', viTet: 'ee82ee', JHt: 'f5deb3', wEte: 'ffffff', wEtesmoke: 'f5f5f5', Lw: 'ffff00', LwgYF: '9acd32' }; function unpack() { const unpacked = {}; const keys = Object.keys(names$1); const tkeys = Object.keys(map); let i, j, k, ok, nk; for (i = 0; i < keys.length; i++) { ok = nk = keys[i]; for (j = 0; j < tkeys.length; j++) { k = tkeys[j]; nk = nk.replace(k, map[k]); } k = parseInt(names$1[ok], 16); unpacked[nk] = [k >> 16 & 0xFF, k >> 8 & 0xFF, k & 0xFF]; } return unpacked; } let names; function nameParse(str) { if (!names) { names = unpack(); names.transparent = [0, 0, 0, 0]; } const a = names[str.toLowerCase()]; return a && { r: a[0], g: a[1], b: a[2], a: a.length === 4 ? a[3] : 255 }; } const RGB_RE = /^rgba?\(\s*([-+.\d]+)(%)?[\s,]+([-+.e\d]+)(%)?[\s,]+([-+.e\d]+)(%)?(?:[\s,/]+([-+.e\d]+)(%)?)?\s*\)$/; function rgbParse(str) { const m = RGB_RE.exec(str); let a = 255; let r, g, b; if (!m) { return; } if (m[7] !== r) { const v = +m[7]; a = m[8] ? p2b(v) : lim(v * 255, 0, 255); } r = +m[1]; g = +m[3]; b = +m[5]; r = 255 & (m[2] ? p2b(r) : lim(r, 0, 255)); g = 255 & (m[4] ? p2b(g) : lim(g, 0, 255)); b = 255 & (m[6] ? p2b(b) : lim(b, 0, 255)); return { r: r, g: g, b: b, a: a }; } function rgbString(v) { return v && ( v.a < 255 ? `rgba(${v.r}, ${v.g}, ${v.b}, ${b2n(v.a)})` : `rgb(${v.r}, ${v.g}, ${v.b})` ); } const to = v => v <= 0.0031308 ? v * 12.92 : Math.pow(v, 1.0 / 2.4) * 1.055 - 0.055; const from = v => v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4); function interpolate(rgb1, rgb2, t) { const r = from(b2n(rgb1.r)); const g = from(b2n(rgb1.g)); const b = from(b2n(rgb1.b)); return { r: n2b(to(r + t * (from(b2n(rgb2.r)) - r))), g: n2b(to(g + t * (from(b2n(rgb2.g)) - g))), b: n2b(to(b + t * (from(b2n(rgb2.b)) - b))), a: rgb1.a + t * (rgb2.a - rgb1.a) }; } function modHSL(v, i, ratio) { if (v) { let tmp = rgb2hsl(v); tmp[i] = Math.max(0, Math.min(tmp[i] + tmp[i] * ratio, i === 0 ? 360 : 1)); tmp = hsl2rgb(tmp); v.r = tmp[0]; v.g = tmp[1]; v.b = tmp[2]; } } function clone(v, proto) { return v ? Object.assign(proto || {}, v) : v; } function fromObject(input) { var v = {r: 0, g: 0, b: 0, a: 255}; if (Array.isArray(input)) { if (input.length >= 3) { v = {r: input[0], g: input[1], b: input[2], a: 255}; if (input.length > 3) { v.a = n2b(input[3]); } } } else { v = clone(input, {r: 0, g: 0, b: 0, a: 1}); v.a = n2b(v.a); } return v; } function functionParse(str) { if (str.charAt(0) === 'r') { return rgbParse(str); } return hueParse(str); } class Color { constructor(input) { if (input instanceof Color) { return input; } const type = typeof input; let v; if (type === 'object') { v = fromObject(input); } else if (type === 'string') { v = hexParse(input) || nameParse(input) || functionParse(input); } this._rgb = v; this._valid = !!v; } get valid() { return this._valid; } get rgb() { var v = clone(this._rgb); if (v) { v.a = b2n(v.a); } return v; } set rgb(obj) { this._rgb = fromObject(obj); } rgbString() { return this._valid ? rgbString(this._rgb) : undefined; } hexString() { return this._valid ? hexString(this._rgb) : undefined; } hslString() { return this._valid ? hslString(this._rgb) : undefined; } mix(color, weight) { if (color) { const c1 = this.rgb; const c2 = color.rgb; let w2; const p = weight === w2 ? 0.5 : weight; const w = 2 * p - 1; const a = c1.a - c2.a; const w1 = ((w * a === -1 ? w : (w + a) / (1 + w * a)) + 1) / 2.0; w2 = 1 - w1; c1.r = 0xFF & w1 * c1.r + w2 * c2.r + 0.5; c1.g = 0xFF & w1 * c1.g + w2 * c2.g + 0.5; c1.b = 0xFF & w1 * c1.b + w2 * c2.b + 0.5; c1.a = p * c1.a + (1 - p) * c2.a; this.rgb = c1; } return this; } interpolate(color, t) { if (color) { this._rgb = interpolate(this._rgb, color._rgb, t); } return this; } clone() { return new Color(this.rgb); } alpha(a) { this._rgb.a = n2b(a); return this; } clearer(ratio) { const rgb = this._rgb; rgb.a *= 1 - ratio; return this; } greyscale() { const rgb = this._rgb; const val = round(rgb.r * 0.3 + rgb.g * 0.59 + rgb.b * 0.11); rgb.r = rgb.g = rgb.b = val; return this; } opaquer(ratio) { const rgb = this._rgb; rgb.a *= 1 + ratio; return this; } negate() { const v = this._rgb; v.r = 255 - v.r; v.g = 255 - v.g; v.b = 255 - v.b; return this; } lighten(ratio) { modHSL(this._rgb, 2, ratio); return this; } darken(ratio) { modHSL(this._rgb, 2, -ratio); return this; } saturate(ratio) { modHSL(this._rgb, 1, ratio); return this; } desaturate(ratio) { modHSL(this._rgb, 1, -ratio); return this; } rotate(deg) { rotate(this._rgb, deg); return this; } } function index_esm(input) { return new Color(input); } /***/ }, /***/ "./node_modules/@orchidjs/sifter/dist/esm/sifter.js" /*!**********************************************************!*\ !*** ./node_modules/@orchidjs/sifter/dist/esm/sifter.js ***! \**********************************************************/ (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ Sifter: () => (/* binding */ Sifter), /* harmony export */ cmp: () => (/* reexport safe */ _utils_js__WEBPACK_IMPORTED_MODULE_0__.cmp), /* harmony export */ getAttr: () => (/* reexport safe */ _utils_js__WEBPACK_IMPORTED_MODULE_0__.getAttr), /* harmony export */ getAttrNesting: () => (/* reexport safe */ _utils_js__WEBPACK_IMPORTED_MODULE_0__.getAttrNesting), /* harmony export */ getPattern: () => (/* reexport safe */ _orchidjs_unicode_variants__WEBPACK_IMPORTED_MODULE_1__.getPattern), /* harmony export */ iterate: () => (/* reexport safe */ _utils_js__WEBPACK_IMPORTED_MODULE_0__.iterate), /* harmony export */ propToArray: () => (/* reexport safe */ _utils_js__WEBPACK_IMPORTED_MODULE_0__.propToArray), /* harmony export */ scoreValue: () => (/* reexport safe */ _utils_js__WEBPACK_IMPORTED_MODULE_0__.scoreValue) /* harmony export */ }); /* harmony import */ var _utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utils.js */ "./node_modules/@orchidjs/sifter/dist/esm/utils.js"); /* harmony import */ var _orchidjs_unicode_variants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @orchidjs/unicode-variants */ "./node_modules/@orchidjs/unicode-variants/dist/esm/index.js"); /* harmony import */ var _types_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./types.js */ "./node_modules/@orchidjs/sifter/dist/esm/types.js"); /** * sifter.js * Copyright (c) 2013–2020 Brian Reavis & contributors * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this * file except in compliance with the License. You may obtain a copy of the License at: * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF * ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. * * @author Brian Reavis */ class Sifter { items; // []|{}; settings; /** * Textually searches arrays and hashes of objects * by property (or multiple properties). Designed * specifically for autocomplete. * */ constructor(items, settings) { this.items = items; this.settings = settings || { diacritics: true }; } ; /** * Splits a search string into an array of individual * regexps to be used to match results. * */ tokenize(query, respect_word_boundaries, weights) { if (!query || !query.length) return []; const tokens = []; const words = query.split(/\s+/); var field_regex; if (weights) { field_regex = new RegExp('^(' + Object.keys(weights).map(_orchidjs_unicode_variants__WEBPACK_IMPORTED_MODULE_1__.escape_regex).join('|') + ')\:(.*)$'); } words.forEach((word) => { let field_match; let field = null; let regex = null; // look for "field:query" tokens if (field_regex && (field_match = word.match(field_regex))) { field = field_match[1]; word = field_match[2]; } if (word.length > 0) { if (this.settings.diacritics) { regex = (0,_orchidjs_unicode_variants__WEBPACK_IMPORTED_MODULE_1__.getPattern)(word) || null; } else { regex = (0,_orchidjs_unicode_variants__WEBPACK_IMPORTED_MODULE_1__.escape_regex)(word); } if (regex && respect_word_boundaries) regex = "\\b" + regex; } tokens.push({ string: word, regex: regex ? new RegExp(regex, 'iu') : null, field: field, }); }); return tokens; } ; /** * Returns a function to be used to score individual results. * * Good matches will have a higher score than poor matches. * If an item is not a match, 0 will be returned by the function. * * @returns {T.ScoreFn} */ getScoreFunction(query, options) { var search = this.prepareSearch(query, options); return this._getScoreFunction(search); } /** * @returns {T.ScoreFn} * */ _getScoreFunction(search) { const tokens = search.tokens, token_count = tokens.length; if (!token_count) { return function () { return 0; }; } const fields = search.options.fields, weights = search.weights, field_count = fields.length, getAttrFn = search.getAttrFn; if (!field_count) { return function () { return 1; }; } /** * Calculates the score of an object * against the search query. * */ const scoreObject = (function () { if (field_count === 1) { return function (token, data) { const field = fields[0].field; return (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.scoreValue)(getAttrFn(data, field), token, weights[field] || 1); }; } return function (token, data) { var sum = 0; // is the token specific to a field? if (token.field) { const value = getAttrFn(data, token.field); if (!token.regex && value) { sum += (1 / field_count); } else { sum += (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.scoreValue)(value, token, 1); } } else { (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.iterate)(weights, (weight, field) => { sum += (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.scoreValue)(getAttrFn(data, field), token, weight); }); } return sum / field_count; }; })(); if (token_count === 1) { return function (data) { return scoreObject(tokens[0], data); }; } if (search.options.conjunction === 'and') { return function (data) { var score, sum = 0; for (let token of tokens) { score = scoreObject(token, data); if (score <= 0) return 0; sum += score; } return sum / token_count; }; } else { return function (data) { var sum = 0; (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.iterate)(tokens, (token) => { sum += scoreObject(token, data); }); return sum / token_count; }; } } ; /** * Returns a function that can be used to compare two * results, for sorting purposes. If no sorting should * be performed, `null` will be returned. * * @return function(a,b) */ getSortFunction(query, options) { var search = this.prepareSearch(query, options); return this._getSortFunction(search); } _getSortFunction(search) { var implicit_score, sort_flds = []; const self = this, options = search.options, sort = (!search.query && options.sort_empty) ? options.sort_empty : options.sort; if (typeof sort == 'function') { return sort.bind(this); } /** * Fetches the specified sort field value * from a search result item. * */ const get_field = function (name, result) { if (name === '$score') return result.score; return search.getAttrFn(self.items[result.id], name); }; // parse options if (sort) { for (let s of sort) { if (search.query || s.field !== '$score') { sort_flds.push(s); } } } // the "$score" field is implied to be the primary // sort field, unless it's manually specified if (search.query) { implicit_score = true; for (let fld of sort_flds) { if (fld.field === '$score') { implicit_score = false; break; } } if (implicit_score) { sort_flds.unshift({ field: '$score', direction: 'desc' }); } // without a search.query, all items will have the same score } else { sort_flds = sort_flds.filter((fld) => fld.field !== '$score'); } // build function const sort_flds_count = sort_flds.length; if (!sort_flds_count) { return null; } return function (a, b) { var result, field; for (let sort_fld of sort_flds) { field = sort_fld.field; let multiplier = sort_fld.direction === 'desc' ? -1 : 1; result = multiplier * (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.cmp)(get_field(field, a), get_field(field, b)); if (result) return result; } return 0; }; } ; /** * Parses a search query and returns an object * with tokens and fields ready to be populated * with results. * */ prepareSearch(query, optsUser) { const weights = {}; var options = Object.assign({}, optsUser); (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.propToArray)(options, 'sort'); (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.propToArray)(options, 'sort_empty'); // convert fields to new format if (options.fields) { (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.propToArray)(options, 'fields'); const fields = []; options.fields.forEach((field) => { if (typeof field == 'string') { field = { field: field, weight: 1 }; } fields.push(field); weights[field.field] = ('weight' in field) ? field.weight : 1; }); options.fields = fields; } return { options: options, query: query.toLowerCase().trim(), tokens: this.tokenize(query, options.respect_word_boundaries, weights), total: 0, items: [], weights: weights, getAttrFn: (options.nesting) ? _utils_js__WEBPACK_IMPORTED_MODULE_0__.getAttrNesting : _utils_js__WEBPACK_IMPORTED_MODULE_0__.getAttr, }; } ; /** * Searches through all items and returns a sorted array of matches. * */ search(query, options) { var self = this, score, search; search = this.prepareSearch(query, options); options = search.options; query = search.query; // generate result scoring function const fn_score = options.score || self._getScoreFunction(search); // perform search and sort if (query.length) { (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.iterate)(self.items, (item, id) => { score = fn_score(item); if (options.filter === false || score > 0) { search.items.push({ 'score': score, 'id': id }); } }); } else { (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.iterate)(self.items, (_, id) => { search.items.push({ 'score': 1, 'id': id }); }); } const fn_sort = self._getSortFunction(search); if (fn_sort) search.items.sort(fn_sort); // apply limits search.total = search.items.length; if (typeof options.limit === 'number') { search.items = search.items.slice(0, options.limit); } return search; } ; } //# sourceMappingURL=sifter.js.map /***/ }, /***/ "./node_modules/@orchidjs/sifter/dist/esm/types.js" /*!*********************************************************!*\ !*** ./node_modules/@orchidjs/sifter/dist/esm/types.js ***! \*********************************************************/ (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); //# sourceMappingURL=types.js.map /***/ }, /***/ "./node_modules/@orchidjs/sifter/dist/esm/utils.js" /*!*********************************************************!*\ !*** ./node_modules/@orchidjs/sifter/dist/esm/utils.js ***! \*********************************************************/ (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ cmp: () => (/* binding */ cmp), /* harmony export */ getAttr: () => (/* binding */ getAttr), /* harmony export */ getAttrNesting: () => (/* binding */ getAttrNesting), /* harmony export */ iterate: () => (/* binding */ iterate), /* harmony export */ propToArray: () => (/* binding */ propToArray), /* harmony export */ scoreValue: () => (/* binding */ scoreValue) /* harmony export */ }); /* harmony import */ var _orchidjs_unicode_variants__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @orchidjs/unicode-variants */ "./node_modules/@orchidjs/unicode-variants/dist/esm/index.js"); /** * A property getter resolving dot-notation * @param {Object} obj The root object to fetch property on * @param {String} name The optionally dotted property name to fetch * @return {Object} The resolved property value */ const getAttr = (obj, name) => { if (!obj) return; return obj[name]; }; /** * A property getter resolving dot-notation * @param {Object} obj The root object to fetch property on * @param {String} name The optionally dotted property name to fetch * @return {Object} The resolved property value */ const getAttrNesting = (obj, name) => { if (!obj) return; var part, names = name.split("."); while ((part = names.shift()) && (obj = obj[part])) ; return obj; }; /** * Calculates how close of a match the * given value is against a search token. * */ const scoreValue = (value, token, weight) => { var score, pos; if (!value) return 0; value = value + ''; if (token.regex == null) return 0; pos = value.search(token.regex); if (pos === -1) return 0; score = token.string.length / value.length; if (pos === 0) score += 0.5; return score * weight; }; /** * Cast object property to an array if it exists and has a value * */ const propToArray = (obj, key) => { var value = obj[key]; if (typeof value == 'function') return value; if (value && !Array.isArray(value)) { obj[key] = [value]; } }; /** * Iterates over arrays and hashes. * * ``` * iterate(this.items, function(item, id) { * // invoked for each item * }); * ``` * */ const iterate = (object, callback) => { if (Array.isArray(object)) { object.forEach(callback); } else { for (var key in object) { if (object.hasOwnProperty(key)) { callback(object[key], key); } } } }; const cmp = (a, b) => { if (typeof a === 'number' && typeof b === 'number') { return a > b ? 1 : (a < b ? -1 : 0); } a = (0,_orchidjs_unicode_variants__WEBPACK_IMPORTED_MODULE_0__.asciifold)(a + '').toLowerCase(); b = (0,_orchidjs_unicode_variants__WEBPACK_IMPORTED_MODULE_0__.asciifold)(b + '').toLowerCase(); if (a > b) return 1; if (b > a) return -1; return 0; }; //# sourceMappingURL=utils.js.map /***/ }, /***/ "./node_modules/@orchidjs/unicode-variants/dist/esm/index.js" /*!*******************************************************************!*\ !*** ./node_modules/@orchidjs/unicode-variants/dist/esm/index.js ***! \*******************************************************************/ (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ _asciifold: () => (/* binding */ _asciifold), /* harmony export */ asciifold: () => (/* binding */ asciifold), /* harmony export */ code_points: () => (/* binding */ code_points), /* harmony export */ escape_regex: () => (/* reexport safe */ _regex_js__WEBPACK_IMPORTED_MODULE_0__.escape_regex), /* harmony export */ generateMap: () => (/* binding */ generateMap), /* harmony export */ generateSets: () => (/* binding */ generateSets), /* harmony export */ generator: () => (/* binding */ generator), /* harmony export */ getPattern: () => (/* binding */ getPattern), /* harmony export */ initialize: () => (/* binding */ initialize), /* harmony export */ mapSequence: () => (/* binding */ mapSequence), /* harmony export */ normalize: () => (/* binding */ normalize), /* harmony export */ substringsToPattern: () => (/* binding */ substringsToPattern), /* harmony export */ unicode_map: () => (/* binding */ unicode_map) /* harmony export */ }); /* harmony import */ var _regex_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./regex.js */ "./node_modules/@orchidjs/unicode-variants/dist/esm/regex.js"); /* harmony import */ var _strings_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./strings.js */ "./node_modules/@orchidjs/unicode-variants/dist/esm/strings.js"); const code_points = [[0, 65535]]; const accent_pat = '[\u0300-\u036F\u{b7}\u{2be}\u{2bc}]'; let unicode_map; let multi_char_reg; const max_char_length = 3; const latin_convert = {}; const latin_condensed = { '/': '⁄∕', '0': '߀', "a": "ⱥɐɑ", "aa": "ꜳ", "ae": "æǽǣ", "ao": "ꜵ", "au": "ꜷ", "av": "ꜹꜻ", "ay": "ꜽ", "b": "ƀɓƃ", "c": "ꜿƈȼↄ", "d": "đɗɖᴅƌꮷԁɦ", "e": "ɛǝᴇɇ", "f": "ꝼƒ", "g": "ǥɠꞡᵹꝿɢ", "h": "ħⱨⱶɥ", "i": "ɨı", "j": "ɉȷ", "k": "ƙⱪꝁꝃꝅꞣ", "l": "łƚɫⱡꝉꝇꞁɭ", "m": "ɱɯϻ", "n": "ꞥƞɲꞑᴎлԉ", "o": "øǿɔɵꝋꝍᴑ", "oe": "œ", "oi": "ƣ", "oo": "ꝏ", "ou": "ȣ", "p": "ƥᵽꝑꝓꝕρ", "q": "ꝗꝙɋ", "r": "ɍɽꝛꞧꞃ", "s": "ßȿꞩꞅʂ", "t": "ŧƭʈⱦꞇ", "th": "þ", "tz": "ꜩ", "u": "ʉ", "v": "ʋꝟʌ", "vy": "ꝡ", "w": "ⱳ", "y": "ƴɏỿ", "z": "ƶȥɀⱬꝣ", "hv": "ƕ" }; for (let latin in latin_condensed) { let unicode = latin_condensed[latin] || ''; for (let i = 0; i < unicode.length; i++) { let char = unicode.substring(i, i + 1); latin_convert[char] = latin; } } const convert_pat = new RegExp(Object.keys(latin_convert).join('|') + '|' + accent_pat, 'gu'); /** * Initialize the unicode_map from the give code point ranges */ const initialize = (_code_points) => { if (unicode_map !== undefined) return; unicode_map = generateMap(_code_points || code_points); }; /** * Helper method for normalize a string * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize */ const normalize = (str, form = 'NFKD') => str.normalize(form); /** * Remove accents without reordering string * calling str.normalize('NFKD') on \u{594}\u{595}\u{596} becomes \u{596}\u{594}\u{595} * via https://github.com/krisk/Fuse/issues/133#issuecomment-318692703 */ const asciifold = (str) => { return Array.from(str).reduce( /** * @param {string} result * @param {string} char */ (result, char) => { return result + _asciifold(char); }, ''); }; const _asciifold = (str) => { str = normalize(str) .toLowerCase() .replace(convert_pat, (/** @type {string} */ char) => { return latin_convert[char] || ''; }); //return str; return normalize(str, 'NFC'); }; /** * Generate a list of unicode variants from the list of code points */ function* generator(code_points) { for (const [code_point_min, code_point_max] of code_points) { for (let i = code_point_min; i <= code_point_max; i++) { let composed = String.fromCharCode(i); let folded = asciifold(composed); if (folded == composed.toLowerCase()) { continue; } // skip when folded is a string longer than 3 characters long // bc the resulting regex patterns will be long // eg: // folded صلى الله عليه وسلم length 18 code point 65018 // folded جل جلاله length 8 code point 65019 if (folded.length > max_char_length) { continue; } if (folded.length == 0) { continue; } yield { folded: folded, composed: composed, code_point: i }; } } } /** * Generate a unicode map from the list of code points */ const generateSets = (code_points) => { const unicode_sets = {}; const addMatching = (folded, to_add) => { /** @type {Set} */ const folded_set = unicode_sets[folded] || new Set(); const patt = new RegExp('^' + (0,_regex_js__WEBPACK_IMPORTED_MODULE_0__.setToPattern)(folded_set) + '$', 'iu'); if (to_add.match(patt)) { return; } folded_set.add((0,_regex_js__WEBPACK_IMPORTED_MODULE_0__.escape_regex)(to_add)); unicode_sets[folded] = folded_set; }; for (let value of generator(code_points)) { addMatching(value.folded, value.folded); addMatching(value.folded, value.composed); } return unicode_sets; }; /** * Generate a unicode map from the list of code points * ae => (?:(?:ae|Æ|Ǽ|Ǣ)|(?:A|Ⓐ|A...)(?:E|ɛ|Ⓔ...)) */ const generateMap = (code_points) => { const unicode_sets = generateSets(code_points); const unicode_map = {}; let multi_char = []; for (let folded in unicode_sets) { let set = unicode_sets[folded]; if (set) { unicode_map[folded] = (0,_regex_js__WEBPACK_IMPORTED_MODULE_0__.setToPattern)(set); } if (folded.length > 1) { multi_char.push((0,_regex_js__WEBPACK_IMPORTED_MODULE_0__.escape_regex)(folded)); } } multi_char.sort((a, b) => b.length - a.length); const multi_char_patt = (0,_regex_js__WEBPACK_IMPORTED_MODULE_0__.arrayToPattern)(multi_char); multi_char_reg = new RegExp('^' + multi_char_patt, 'u'); return unicode_map; }; /** * Map each element of an array from its folded value to all possible unicode matches */ const mapSequence = (strings, min_replacement = 1) => { let chars_replaced = 0; strings = strings.map((str) => { if (unicode_map[str]) { chars_replaced += str.length; } return unicode_map[str] || str; }); if (chars_replaced >= min_replacement) { return (0,_regex_js__WEBPACK_IMPORTED_MODULE_0__.sequencePattern)(strings); } return ''; }; /** * Convert a short string and split it into all possible patterns * Keep a pattern only if min_replacement is met * * 'abc' * => [['abc'],['ab','c'],['a','bc'],['a','b','c']] * => ['abc-pattern','ab-c-pattern'...] */ const substringsToPattern = (str, min_replacement = 1) => { min_replacement = Math.max(min_replacement, str.length - 1); return (0,_regex_js__WEBPACK_IMPORTED_MODULE_0__.arrayToPattern)((0,_strings_js__WEBPACK_IMPORTED_MODULE_1__.allSubstrings)(str).map((sub_pat) => { return mapSequence(sub_pat, min_replacement); })); }; /** * Convert an array of sequences into a pattern * [{start:0,end:3,length:3,substr:'iii'}...] => (?:iii...) */ const sequencesToPattern = (sequences, all = true) => { let min_replacement = sequences.length > 1 ? 1 : 0; return (0,_regex_js__WEBPACK_IMPORTED_MODULE_0__.arrayToPattern)(sequences.map((sequence) => { let seq = []; const len = all ? sequence.length() : sequence.length() - 1; for (let j = 0; j < len; j++) { seq.push(substringsToPattern(sequence.substrs[j] || '', min_replacement)); } return (0,_regex_js__WEBPACK_IMPORTED_MODULE_0__.sequencePattern)(seq); })); }; /** * Return true if the sequence is already in the sequences */ const inSequences = (needle_seq, sequences) => { for (const seq of sequences) { if (seq.start != needle_seq.start || seq.end != needle_seq.end) { continue; } if (seq.substrs.join('') !== needle_seq.substrs.join('')) { continue; } let needle_parts = needle_seq.parts; const filter = (part) => { for (const needle_part of needle_parts) { if (needle_part.start === part.start && needle_part.substr === part.substr) { return false; } if (part.length == 1 || needle_part.length == 1) { continue; } // check for overlapping parts // a = ['::=','=='] // b = ['::','==='] // a = ['r','sm'] // b = ['rs','m'] if (part.start < needle_part.start && part.end > needle_part.start) { return true; } if (needle_part.start < part.start && needle_part.end > part.start) { return true; } } return false; }; let filtered = seq.parts.filter(filter); if (filtered.length > 0) { continue; } return true; } return false; }; class Sequence { parts; substrs; start; end; constructor() { this.parts = []; this.substrs = []; this.start = 0; this.end = 0; } add(part) { if (part) { this.parts.push(part); this.substrs.push(part.substr); this.start = Math.min(part.start, this.start); this.end = Math.max(part.end, this.end); } } last() { return this.parts[this.parts.length - 1]; } length() { return this.parts.length; } clone(position, last_piece) { let clone = new Sequence(); let parts = JSON.parse(JSON.stringify(this.parts)); let last_part = parts.pop(); for (const part of parts) { clone.add(part); } let last_substr = last_piece.substr.substring(0, position - last_part.start); let clone_last_len = last_substr.length; clone.add({ start: last_part.start, end: last_part.start + clone_last_len, length: clone_last_len, substr: last_substr }); return clone; } } /** * Expand a regular expression pattern to include unicode variants * eg /a/ becomes /aⓐaẚàáâầấẫẩãāăằắẵẳȧǡäǟảåǻǎȁȃạậặḁąⱥɐɑAⒶAÀÁÂẦẤẪẨÃĀĂẰẮẴẲȦǠÄǞẢÅǺǍȀȂẠẬẶḀĄȺⱯ/ * * Issue: * ﺊﺋ [ 'ﺊ = \\u{fe8a}', 'ﺋ = \\u{fe8b}' ] * becomes: ئئ [ 'ي = \\u{64a}', 'ٔ = \\u{654}', 'ي = \\u{64a}', 'ٔ = \\u{654}' ] * * İIJ = IIJ = ⅡJ * * 1/2/4 */ const getPattern = (str) => { initialize(); str = asciifold(str); let pattern = ''; let sequences = [new Sequence()]; for (let i = 0; i < str.length; i++) { let substr = str.substring(i); let match = substr.match(multi_char_reg); const char = str.substring(i, i + 1); const match_str = match ? match[0] : null; // loop through sequences // add either the char or multi_match let overlapping = []; let added_types = new Set(); for (const sequence of sequences) { const last_piece = sequence.last(); if (!last_piece || last_piece.length == 1 || last_piece.end <= i) { // if we have a multi match if (match_str) { const len = match_str.length; sequence.add({ start: i, end: i + len, length: len, substr: match_str }); added_types.add('1'); } else { sequence.add({ start: i, end: i + 1, length: 1, substr: char }); added_types.add('2'); } } else if (match_str) { let clone = sequence.clone(i, last_piece); const len = match_str.length; clone.add({ start: i, end: i + len, length: len, substr: match_str }); overlapping.push(clone); } else { // don't add char // adding would create invalid patterns: 234 => [2,34,4] added_types.add('3'); } } // if we have overlapping if (overlapping.length > 0) { // ['ii','iii'] before ['i','i','iii'] overlapping = overlapping.sort((a, b) => { return a.length() - b.length(); }); for (let clone of overlapping) { // don't add if we already have an equivalent sequence if (inSequences(clone, sequences)) { continue; } sequences.push(clone); } continue; } // if we haven't done anything unique // clean up the patterns // helps keep patterns smaller // if str = 'r₨㎧aarss', pattern will be 446 instead of 655 if (i > 0 && added_types.size == 1 && !added_types.has('3')) { pattern += sequencesToPattern(sequences, false); let new_seq = new Sequence(); const old_seq = sequences[0]; if (old_seq) { new_seq.add(old_seq.last()); } sequences = [new_seq]; } } pattern += sequencesToPattern(sequences, true); return pattern; }; //# sourceMappingURL=index.js.map /***/ }, /***/ "./node_modules/@orchidjs/unicode-variants/dist/esm/regex.js" /*!*******************************************************************!*\ !*** ./node_modules/@orchidjs/unicode-variants/dist/esm/regex.js ***! \*******************************************************************/ (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ arrayToPattern: () => (/* binding */ arrayToPattern), /* harmony export */ escape_regex: () => (/* binding */ escape_regex), /* harmony export */ hasDuplicates: () => (/* binding */ hasDuplicates), /* harmony export */ maxValueLength: () => (/* binding */ maxValueLength), /* harmony export */ sequencePattern: () => (/* binding */ sequencePattern), /* harmony export */ setToPattern: () => (/* binding */ setToPattern), /* harmony export */ unicodeLength: () => (/* binding */ unicodeLength) /* harmony export */ }); /** * Convert array of strings to a regular expression * ex ['ab','a'] => (?:ab|a) * ex ['a','b'] => [ab] */ const arrayToPattern = (chars) => { chars = chars.filter(Boolean); if (chars.length < 2) { return chars[0] || ''; } return (maxValueLength(chars) == 1) ? '[' + chars.join('') + ']' : '(?:' + chars.join('|') + ')'; }; const sequencePattern = (array) => { if (!hasDuplicates(array)) { return array.join(''); } let pattern = ''; let prev_char_count = 0; const prev_pattern = () => { if (prev_char_count > 1) { pattern += '{' + prev_char_count + '}'; } }; array.forEach((char, i) => { if (char === array[i - 1]) { prev_char_count++; return; } prev_pattern(); pattern += char; prev_char_count = 1; }); prev_pattern(); return pattern; }; /** * Convert array of strings to a regular expression * ex ['ab','a'] => (?:ab|a) * ex ['a','b'] => [ab] */ const setToPattern = (chars) => { let array = Array.from(chars); return arrayToPattern(array); }; /** * https://stackoverflow.com/questions/7376598/in-javascript-how-do-i-check-if-an-array-has-duplicate-values */ const hasDuplicates = (array) => { return (new Set(array)).size !== array.length; }; /** * https://stackoverflow.com/questions/63006601/why-does-u-throw-an-invalid-escape-error */ const escape_regex = (str) => { return (str + '').replace(/([\$\(\)\*\+\.\?\[\]\^\{\|\}\\])/gu, '\\$1'); }; /** * Return the max length of array values */ const maxValueLength = (array) => { return array.reduce((longest, value) => Math.max(longest, unicodeLength(value)), 0); }; const unicodeLength = (str) => { return Array.from(str).length; }; //# sourceMappingURL=regex.js.map /***/ }, /***/ "./node_modules/@orchidjs/unicode-variants/dist/esm/strings.js" /*!*********************************************************************!*\ !*** ./node_modules/@orchidjs/unicode-variants/dist/esm/strings.js ***! \*********************************************************************/ (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ allSubstrings: () => (/* binding */ allSubstrings) /* harmony export */ }); /** * Get all possible combinations of substrings that add up to the given string * https://stackoverflow.com/questions/30169587/find-all-the-combination-of-substrings-that-add-up-to-the-given-string */ const allSubstrings = (input) => { if (input.length === 1) return [[input]]; let result = []; const start = input.substring(1); const suba = allSubstrings(start); suba.forEach(function (subresult) { let tmp = subresult.slice(0); tmp[0] = input.charAt(0) + tmp[0]; result.push(tmp); tmp = subresult.slice(0); tmp.unshift(input.charAt(0)); result.push(tmp); }); return result; }; //# sourceMappingURL=strings.js.map /***/ }, /***/ "./node_modules/chart.js/auto/auto.js" /*!********************************************!*\ !*** ./node_modules/chart.js/auto/auto.js ***! \********************************************/ (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ Animation: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Animation), /* harmony export */ Animations: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Animations), /* harmony export */ ArcElement: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.ArcElement), /* harmony export */ BarController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.BarController), /* harmony export */ BarElement: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.BarElement), /* harmony export */ BasePlatform: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.BasePlatform), /* harmony export */ BasicPlatform: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.BasicPlatform), /* harmony export */ BubbleController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.BubbleController), /* harmony export */ CategoryScale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.CategoryScale), /* harmony export */ Chart: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Chart), /* harmony export */ Colors: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Colors), /* harmony export */ DatasetController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.DatasetController), /* harmony export */ Decimation: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Decimation), /* harmony export */ DomPlatform: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.DomPlatform), /* harmony export */ DoughnutController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.DoughnutController), /* harmony export */ Element: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Element), /* harmony export */ Filler: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Filler), /* harmony export */ Interaction: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Interaction), /* harmony export */ Legend: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Legend), /* harmony export */ LineController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.LineController), /* harmony export */ LineElement: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.LineElement), /* harmony export */ LinearScale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.LinearScale), /* harmony export */ LogarithmicScale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.LogarithmicScale), /* harmony export */ PieController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.PieController), /* harmony export */ PointElement: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.PointElement), /* harmony export */ PolarAreaController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.PolarAreaController), /* harmony export */ RadarController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.RadarController), /* harmony export */ RadialLinearScale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.RadialLinearScale), /* harmony export */ Scale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Scale), /* harmony export */ ScatterController: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.ScatterController), /* harmony export */ SubTitle: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.SubTitle), /* harmony export */ Ticks: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Ticks), /* harmony export */ TimeScale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.TimeScale), /* harmony export */ TimeSeriesScale: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.TimeSeriesScale), /* harmony export */ Title: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Title), /* harmony export */ Tooltip: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Tooltip), /* harmony export */ _adapters: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__._adapters), /* harmony export */ _detectPlatform: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__._detectPlatform), /* harmony export */ animator: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.animator), /* harmony export */ controllers: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.controllers), /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__), /* harmony export */ defaults: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.defaults), /* harmony export */ elements: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.elements), /* harmony export */ layouts: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.layouts), /* harmony export */ plugins: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.plugins), /* harmony export */ registerables: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.registerables), /* harmony export */ registry: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.registry), /* harmony export */ scales: () => (/* reexport safe */ _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.scales) /* harmony export */ }); /* harmony import */ var _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../dist/chart.js */ "./node_modules/chart.js/dist/chart.js"); _dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Chart.register(..._dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.registerables); /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_dist_chart_js__WEBPACK_IMPORTED_MODULE_0__.Chart); /***/ }, /***/ "./node_modules/chart.js/dist/chart.js" /*!*********************************************!*\ !*** ./node_modules/chart.js/dist/chart.js ***! \*********************************************/ (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ Animation: () => (/* binding */ Animation), /* harmony export */ Animations: () => (/* binding */ Animations), /* harmony export */ ArcElement: () => (/* binding */ ArcElement), /* harmony export */ BarController: () => (/* binding */ BarController), /* harmony export */ BarElement: () => (/* binding */ BarElement), /* harmony export */ BasePlatform: () => (/* binding */ BasePlatform), /* harmony export */ BasicPlatform: () => (/* binding */ BasicPlatform), /* harmony export */ BubbleController: () => (/* binding */ BubbleController), /* harmony export */ CategoryScale: () => (/* binding */ CategoryScale), /* harmony export */ Chart: () => (/* binding */ Chart), /* harmony export */ Colors: () => (/* binding */ plugin_colors), /* harmony export */ DatasetController: () => (/* binding */ DatasetController), /* harmony export */ Decimation: () => (/* binding */ plugin_decimation), /* harmony export */ DomPlatform: () => (/* binding */ DomPlatform), /* harmony export */ DoughnutController: () => (/* binding */ DoughnutController), /* harmony export */ Element: () => (/* binding */ Element), /* harmony export */ Filler: () => (/* binding */ index), /* harmony export */ Interaction: () => (/* binding */ Interaction), /* harmony export */ Legend: () => (/* binding */ plugin_legend), /* harmony export */ LineController: () => (/* binding */ LineController), /* harmony export */ LineElement: () => (/* binding */ LineElement), /* harmony export */ LinearScale: () => (/* binding */ LinearScale), /* harmony export */ LogarithmicScale: () => (/* binding */ LogarithmicScale), /* harmony export */ PieController: () => (/* binding */ PieController), /* harmony export */ PointElement: () => (/* binding */ PointElement), /* harmony export */ PolarAreaController: () => (/* binding */ PolarAreaController), /* harmony export */ RadarController: () => (/* binding */ RadarController), /* harmony export */ RadialLinearScale: () => (/* binding */ RadialLinearScale), /* harmony export */ Scale: () => (/* binding */ Scale), /* harmony export */ ScatterController: () => (/* binding */ ScatterController), /* harmony export */ SubTitle: () => (/* binding */ plugin_subtitle), /* harmony export */ Ticks: () => (/* reexport safe */ _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aM), /* harmony export */ TimeScale: () => (/* binding */ TimeScale), /* harmony export */ TimeSeriesScale: () => (/* binding */ TimeSeriesScale), /* harmony export */ Title: () => (/* binding */ plugin_title), /* harmony export */ Tooltip: () => (/* binding */ plugin_tooltip), /* harmony export */ _adapters: () => (/* binding */ adapters), /* harmony export */ _detectPlatform: () => (/* binding */ _detectPlatform), /* harmony export */ animator: () => (/* binding */ animator), /* harmony export */ controllers: () => (/* binding */ controllers), /* harmony export */ defaults: () => (/* reexport safe */ _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d), /* harmony export */ elements: () => (/* binding */ elements), /* harmony export */ layouts: () => (/* binding */ layouts), /* harmony export */ plugins: () => (/* binding */ plugins), /* harmony export */ registerables: () => (/* binding */ registerables), /* harmony export */ registry: () => (/* binding */ registry), /* harmony export */ scales: () => (/* binding */ scales) /* harmony export */ }); /* harmony import */ var _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./chunks/helpers.dataset.js */ "./node_modules/chart.js/dist/chunks/helpers.dataset.js"); /*! * Chart.js v4.5.1 * https://www.chartjs.org * (c) 2025 Chart.js Contributors * Released under the MIT License */ class Animator { constructor(){ this._request = null; this._charts = new Map(); this._running = false; this._lastDate = undefined; } _notify(chart, anims, date, type) { const callbacks = anims.listeners[type]; const numSteps = anims.duration; callbacks.forEach((fn)=>fn({ chart, initial: anims.initial, numSteps, currentStep: Math.min(date - anims.start, numSteps) })); } _refresh() { if (this._request) { return; } this._running = true; this._request = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.r.call(window, ()=>{ this._update(); this._request = null; if (this._running) { this._refresh(); } }); } _update(date = Date.now()) { let remaining = 0; this._charts.forEach((anims, chart)=>{ if (!anims.running || !anims.items.length) { return; } const items = anims.items; let i = items.length - 1; let draw = false; let item; for(; i >= 0; --i){ item = items[i]; if (item._active) { if (item._total > anims.duration) { anims.duration = item._total; } item.tick(date); draw = true; } else { items[i] = items[items.length - 1]; items.pop(); } } if (draw) { chart.draw(); this._notify(chart, anims, date, 'progress'); } if (!items.length) { anims.running = false; this._notify(chart, anims, date, 'complete'); anims.initial = false; } remaining += items.length; }); this._lastDate = date; if (remaining === 0) { this._running = false; } } _getAnims(chart) { const charts = this._charts; let anims = charts.get(chart); if (!anims) { anims = { running: false, initial: true, items: [], listeners: { complete: [], progress: [] } }; charts.set(chart, anims); } return anims; } listen(chart, event, cb) { this._getAnims(chart).listeners[event].push(cb); } add(chart, items) { if (!items || !items.length) { return; } this._getAnims(chart).items.push(...items); } has(chart) { return this._getAnims(chart).items.length > 0; } start(chart) { const anims = this._charts.get(chart); if (!anims) { return; } anims.running = true; anims.start = Date.now(); anims.duration = anims.items.reduce((acc, cur)=>Math.max(acc, cur._duration), 0); this._refresh(); } running(chart) { if (!this._running) { return false; } const anims = this._charts.get(chart); if (!anims || !anims.running || !anims.items.length) { return false; } return true; } stop(chart) { const anims = this._charts.get(chart); if (!anims || !anims.items.length) { return; } const items = anims.items; let i = items.length - 1; for(; i >= 0; --i){ items[i].cancel(); } anims.items = []; this._notify(chart, anims, Date.now(), 'complete'); } remove(chart) { return this._charts.delete(chart); } } var animator = /* #__PURE__ */ new Animator(); const transparent = 'transparent'; const interpolators = { boolean (from, to, factor) { return factor > 0.5 ? to : from; }, color (from, to, factor) { const c0 = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.c)(from || transparent); const c1 = c0.valid && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.c)(to || transparent); return c1 && c1.valid ? c1.mix(c0, factor).hexString() : to; }, number (from, to, factor) { return from + (to - from) * factor; } }; class Animation { constructor(cfg, target, prop, to){ const currentValue = target[prop]; to = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a)([ cfg.to, to, currentValue, cfg.from ]); const from = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a)([ cfg.from, currentValue, to ]); this._active = true; this._fn = cfg.fn || interpolators[cfg.type || typeof from]; this._easing = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.e[cfg.easing] || _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.e.linear; this._start = Math.floor(Date.now() + (cfg.delay || 0)); this._duration = this._total = Math.floor(cfg.duration); this._loop = !!cfg.loop; this._target = target; this._prop = prop; this._from = from; this._to = to; this._promises = undefined; } active() { return this._active; } update(cfg, to, date) { if (this._active) { this._notify(false); const currentValue = this._target[this._prop]; const elapsed = date - this._start; const remain = this._duration - elapsed; this._start = date; this._duration = Math.floor(Math.max(remain, cfg.duration)); this._total += elapsed; this._loop = !!cfg.loop; this._to = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a)([ cfg.to, to, currentValue, cfg.from ]); this._from = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a)([ cfg.from, currentValue, to ]); } } cancel() { if (this._active) { this.tick(Date.now()); this._active = false; this._notify(false); } } tick(date) { const elapsed = date - this._start; const duration = this._duration; const prop = this._prop; const from = this._from; const loop = this._loop; const to = this._to; let factor; this._active = from !== to && (loop || elapsed < duration); if (!this._active) { this._target[prop] = to; this._notify(true); return; } if (elapsed < 0) { this._target[prop] = from; return; } factor = elapsed / duration % 2; factor = loop && factor > 1 ? 2 - factor : factor; factor = this._easing(Math.min(1, Math.max(0, factor))); this._target[prop] = this._fn(from, to, factor); } wait() { const promises = this._promises || (this._promises = []); return new Promise((res, rej)=>{ promises.push({ res, rej }); }); } _notify(resolved) { const method = resolved ? 'res' : 'rej'; const promises = this._promises || []; for(let i = 0; i < promises.length; i++){ promises[i][method](); } } } class Animations { constructor(chart, config){ this._chart = chart; this._properties = new Map(); this.configure(config); } configure(config) { if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(config)) { return; } const animationOptions = Object.keys(_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.animation); const animatedProps = this._properties; Object.getOwnPropertyNames(config).forEach((key)=>{ const cfg = config[key]; if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(cfg)) { return; } const resolved = {}; for (const option of animationOptions){ resolved[option] = cfg[option]; } ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(cfg.properties) && cfg.properties || [ key ]).forEach((prop)=>{ if (prop === key || !animatedProps.has(prop)) { animatedProps.set(prop, resolved); } }); }); } _animateOptions(target, values) { const newOptions = values.options; const options = resolveTargetOptions(target, newOptions); if (!options) { return []; } const animations = this._createAnimations(options, newOptions); if (newOptions.$shared) { awaitAll(target.options.$animations, newOptions).then(()=>{ target.options = newOptions; }, ()=>{ }); } return animations; } _createAnimations(target, values) { const animatedProps = this._properties; const animations = []; const running = target.$animations || (target.$animations = {}); const props = Object.keys(values); const date = Date.now(); let i; for(i = props.length - 1; i >= 0; --i){ const prop = props[i]; if (prop.charAt(0) === '$') { continue; } if (prop === 'options') { animations.push(...this._animateOptions(target, values)); continue; } const value = values[prop]; let animation = running[prop]; const cfg = animatedProps.get(prop); if (animation) { if (cfg && animation.active()) { animation.update(cfg, value, date); continue; } else { animation.cancel(); } } if (!cfg || !cfg.duration) { target[prop] = value; continue; } running[prop] = animation = new Animation(cfg, target, prop, value); animations.push(animation); } return animations; } update(target, values) { if (this._properties.size === 0) { Object.assign(target, values); return; } const animations = this._createAnimations(target, values); if (animations.length) { animator.add(this._chart, animations); return true; } } } function awaitAll(animations, properties) { const running = []; const keys = Object.keys(properties); for(let i = 0; i < keys.length; i++){ const anim = animations[keys[i]]; if (anim && anim.active()) { running.push(anim.wait()); } } return Promise.all(running); } function resolveTargetOptions(target, newOptions) { if (!newOptions) { return; } let options = target.options; if (!options) { target.options = newOptions; return; } if (options.$shared) { target.options = options = Object.assign({}, options, { $shared: false, $animations: {} }); } return options; } function scaleClip(scale, allowedOverflow) { const opts = scale && scale.options || {}; const reverse = opts.reverse; const min = opts.min === undefined ? allowedOverflow : 0; const max = opts.max === undefined ? allowedOverflow : 0; return { start: reverse ? max : min, end: reverse ? min : max }; } function defaultClip(xScale, yScale, allowedOverflow) { if (allowedOverflow === false) { return false; } const x = scaleClip(xScale, allowedOverflow); const y = scaleClip(yScale, allowedOverflow); return { top: y.end, right: x.end, bottom: y.start, left: x.start }; } function toClip(value) { let t, r, b, l; if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(value)) { t = value.top; r = value.right; b = value.bottom; l = value.left; } else { t = r = b = l = value; } return { top: t, right: r, bottom: b, left: l, disabled: value === false }; } function getSortedDatasetIndices(chart, filterVisible) { const keys = []; const metasets = chart._getSortedDatasetMetas(filterVisible); let i, ilen; for(i = 0, ilen = metasets.length; i < ilen; ++i){ keys.push(metasets[i].index); } return keys; } function applyStack(stack, value, dsIndex, options = {}) { const keys = stack.keys; const singleMode = options.mode === 'single'; let i, ilen, datasetIndex, otherValue; if (value === null) { return; } let found = false; for(i = 0, ilen = keys.length; i < ilen; ++i){ datasetIndex = +keys[i]; if (datasetIndex === dsIndex) { found = true; if (options.all) { continue; } break; } otherValue = stack.values[datasetIndex]; if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(otherValue) && (singleMode || value === 0 || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.s)(value) === (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.s)(otherValue))) { value += otherValue; } } if (!found && !options.all) { return 0; } return value; } function convertObjectDataToArray(data, meta) { const { iScale , vScale } = meta; const iAxisKey = iScale.axis === 'x' ? 'x' : 'y'; const vAxisKey = vScale.axis === 'x' ? 'x' : 'y'; const keys = Object.keys(data); const adata = new Array(keys.length); let i, ilen, key; for(i = 0, ilen = keys.length; i < ilen; ++i){ key = keys[i]; adata[i] = { [iAxisKey]: key, [vAxisKey]: data[key] }; } return adata; } function isStacked(scale, meta) { const stacked = scale && scale.options.stacked; return stacked || stacked === undefined && meta.stack !== undefined; } function getStackKey(indexScale, valueScale, meta) { return `${indexScale.id}.${valueScale.id}.${meta.stack || meta.type}`; } function getUserBounds(scale) { const { min , max , minDefined , maxDefined } = scale.getUserBounds(); return { min: minDefined ? min : Number.NEGATIVE_INFINITY, max: maxDefined ? max : Number.POSITIVE_INFINITY }; } function getOrCreateStack(stacks, stackKey, indexValue) { const subStack = stacks[stackKey] || (stacks[stackKey] = {}); return subStack[indexValue] || (subStack[indexValue] = {}); } function getLastIndexInStack(stack, vScale, positive, type) { for (const meta of vScale.getMatchingVisibleMetas(type).reverse()){ const value = stack[meta.index]; if (positive && value > 0 || !positive && value < 0) { return meta.index; } } return null; } function updateStacks(controller, parsed) { const { chart , _cachedMeta: meta } = controller; const stacks = chart._stacks || (chart._stacks = {}); const { iScale , vScale , index: datasetIndex } = meta; const iAxis = iScale.axis; const vAxis = vScale.axis; const key = getStackKey(iScale, vScale, meta); const ilen = parsed.length; let stack; for(let i = 0; i < ilen; ++i){ const item = parsed[i]; const { [iAxis]: index , [vAxis]: value } = item; const itemStacks = item._stacks || (item._stacks = {}); stack = itemStacks[vAxis] = getOrCreateStack(stacks, key, index); stack[datasetIndex] = value; stack._top = getLastIndexInStack(stack, vScale, true, meta.type); stack._bottom = getLastIndexInStack(stack, vScale, false, meta.type); const visualValues = stack._visualValues || (stack._visualValues = {}); visualValues[datasetIndex] = value; } } function getFirstScaleId(chart, axis) { const scales = chart.scales; return Object.keys(scales).filter((key)=>scales[key].axis === axis).shift(); } function createDatasetContext(parent, index) { return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(parent, { active: false, dataset: undefined, datasetIndex: index, index, mode: 'default', type: 'dataset' }); } function createDataContext(parent, index, element) { return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(parent, { active: false, dataIndex: index, parsed: undefined, raw: undefined, element, index, mode: 'default', type: 'data' }); } function clearStacks(meta, items) { const datasetIndex = meta.controller.index; const axis = meta.vScale && meta.vScale.axis; if (!axis) { return; } items = items || meta._parsed; for (const parsed of items){ const stacks = parsed._stacks; if (!stacks || stacks[axis] === undefined || stacks[axis][datasetIndex] === undefined) { return; } delete stacks[axis][datasetIndex]; if (stacks[axis]._visualValues !== undefined && stacks[axis]._visualValues[datasetIndex] !== undefined) { delete stacks[axis]._visualValues[datasetIndex]; } } } const isDirectUpdateMode = (mode)=>mode === 'reset' || mode === 'none'; const cloneIfNotShared = (cached, shared)=>shared ? cached : Object.assign({}, cached); const createStack = (canStack, meta, chart)=>canStack && !meta.hidden && meta._stacked && { keys: getSortedDatasetIndices(chart, true), values: null }; class DatasetController { static defaults = {}; static datasetElementType = null; static dataElementType = null; constructor(chart, datasetIndex){ this.chart = chart; this._ctx = chart.ctx; this.index = datasetIndex; this._cachedDataOpts = {}; this._cachedMeta = this.getMeta(); this._type = this._cachedMeta.type; this.options = undefined; this._parsing = false; this._data = undefined; this._objectData = undefined; this._sharedOptions = undefined; this._drawStart = undefined; this._drawCount = undefined; this.enableOptionSharing = false; this.supportsDecimation = false; this.$context = undefined; this._syncList = []; this.datasetElementType = new.target.datasetElementType; this.dataElementType = new.target.dataElementType; this.initialize(); } initialize() { const meta = this._cachedMeta; this.configure(); this.linkScales(); meta._stacked = isStacked(meta.vScale, meta); this.addElements(); if (this.options.fill && !this.chart.isPluginEnabled('filler')) { console.warn("Tried to use the 'fill' option without the 'Filler' plugin enabled. Please import and register the 'Filler' plugin and make sure it is not disabled in the options"); } } updateIndex(datasetIndex) { if (this.index !== datasetIndex) { clearStacks(this._cachedMeta); } this.index = datasetIndex; } linkScales() { const chart = this.chart; const meta = this._cachedMeta; const dataset = this.getDataset(); const chooseId = (axis, x, y, r)=>axis === 'x' ? x : axis === 'r' ? r : y; const xid = meta.xAxisID = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(dataset.xAxisID, getFirstScaleId(chart, 'x')); const yid = meta.yAxisID = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(dataset.yAxisID, getFirstScaleId(chart, 'y')); const rid = meta.rAxisID = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(dataset.rAxisID, getFirstScaleId(chart, 'r')); const indexAxis = meta.indexAxis; const iid = meta.iAxisID = chooseId(indexAxis, xid, yid, rid); const vid = meta.vAxisID = chooseId(indexAxis, yid, xid, rid); meta.xScale = this.getScaleForId(xid); meta.yScale = this.getScaleForId(yid); meta.rScale = this.getScaleForId(rid); meta.iScale = this.getScaleForId(iid); meta.vScale = this.getScaleForId(vid); } getDataset() { return this.chart.data.datasets[this.index]; } getMeta() { return this.chart.getDatasetMeta(this.index); } getScaleForId(scaleID) { return this.chart.scales[scaleID]; } _getOtherScale(scale) { const meta = this._cachedMeta; return scale === meta.iScale ? meta.vScale : meta.iScale; } reset() { this._update('reset'); } _destroy() { const meta = this._cachedMeta; if (this._data) { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.u)(this._data, this); } if (meta._stacked) { clearStacks(meta); } } _dataCheck() { const dataset = this.getDataset(); const data = dataset.data || (dataset.data = []); const _data = this._data; if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(data)) { const meta = this._cachedMeta; this._data = convertObjectDataToArray(data, meta); } else if (_data !== data) { if (_data) { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.u)(_data, this); const meta = this._cachedMeta; clearStacks(meta); meta._parsed = []; } if (data && Object.isExtensible(data)) { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.l)(data, this); } this._syncList = []; this._data = data; } } addElements() { const meta = this._cachedMeta; this._dataCheck(); if (this.datasetElementType) { meta.dataset = new this.datasetElementType(); } } buildOrUpdateElements(resetNewElements) { const meta = this._cachedMeta; const dataset = this.getDataset(); let stackChanged = false; this._dataCheck(); const oldStacked = meta._stacked; meta._stacked = isStacked(meta.vScale, meta); if (meta.stack !== dataset.stack) { stackChanged = true; clearStacks(meta); meta.stack = dataset.stack; } this._resyncElements(resetNewElements); if (stackChanged || oldStacked !== meta._stacked) { updateStacks(this, meta._parsed); meta._stacked = isStacked(meta.vScale, meta); } } configure() { const config = this.chart.config; const scopeKeys = config.datasetScopeKeys(this._type); const scopes = config.getOptionScopes(this.getDataset(), scopeKeys, true); this.options = config.createResolver(scopes, this.getContext()); this._parsing = this.options.parsing; this._cachedDataOpts = {}; } parse(start, count) { const { _cachedMeta: meta , _data: data } = this; const { iScale , _stacked } = meta; const iAxis = iScale.axis; let sorted = start === 0 && count === data.length ? true : meta._sorted; let prev = start > 0 && meta._parsed[start - 1]; let i, cur, parsed; if (this._parsing === false) { meta._parsed = data; meta._sorted = true; parsed = data; } else { if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(data[start])) { parsed = this.parseArrayData(meta, data, start, count); } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(data[start])) { parsed = this.parseObjectData(meta, data, start, count); } else { parsed = this.parsePrimitiveData(meta, data, start, count); } const isNotInOrderComparedToPrev = ()=>cur[iAxis] === null || prev && cur[iAxis] < prev[iAxis]; for(i = 0; i < count; ++i){ meta._parsed[i + start] = cur = parsed[i]; if (sorted) { if (isNotInOrderComparedToPrev()) { sorted = false; } prev = cur; } } meta._sorted = sorted; } if (_stacked) { updateStacks(this, parsed); } } parsePrimitiveData(meta, data, start, count) { const { iScale , vScale } = meta; const iAxis = iScale.axis; const vAxis = vScale.axis; const labels = iScale.getLabels(); const singleScale = iScale === vScale; const parsed = new Array(count); let i, ilen, index; for(i = 0, ilen = count; i < ilen; ++i){ index = i + start; parsed[i] = { [iAxis]: singleScale || iScale.parse(labels[index], index), [vAxis]: vScale.parse(data[index], index) }; } return parsed; } parseArrayData(meta, data, start, count) { const { xScale , yScale } = meta; const parsed = new Array(count); let i, ilen, index, item; for(i = 0, ilen = count; i < ilen; ++i){ index = i + start; item = data[index]; parsed[i] = { x: xScale.parse(item[0], index), y: yScale.parse(item[1], index) }; } return parsed; } parseObjectData(meta, data, start, count) { const { xScale , yScale } = meta; const { xAxisKey ='x' , yAxisKey ='y' } = this._parsing; const parsed = new Array(count); let i, ilen, index, item; for(i = 0, ilen = count; i < ilen; ++i){ index = i + start; item = data[index]; parsed[i] = { x: xScale.parse((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.f)(item, xAxisKey), index), y: yScale.parse((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.f)(item, yAxisKey), index) }; } return parsed; } getParsed(index) { return this._cachedMeta._parsed[index]; } getDataElement(index) { return this._cachedMeta.data[index]; } applyStack(scale, parsed, mode) { const chart = this.chart; const meta = this._cachedMeta; const value = parsed[scale.axis]; const stack = { keys: getSortedDatasetIndices(chart, true), values: parsed._stacks[scale.axis]._visualValues }; return applyStack(stack, value, meta.index, { mode }); } updateRangeFromParsed(range, scale, parsed, stack) { const parsedValue = parsed[scale.axis]; let value = parsedValue === null ? NaN : parsedValue; const values = stack && parsed._stacks[scale.axis]; if (stack && values) { stack.values = values; value = applyStack(stack, parsedValue, this._cachedMeta.index); } range.min = Math.min(range.min, value); range.max = Math.max(range.max, value); } getMinMax(scale, canStack) { const meta = this._cachedMeta; const _parsed = meta._parsed; const sorted = meta._sorted && scale === meta.iScale; const ilen = _parsed.length; const otherScale = this._getOtherScale(scale); const stack = createStack(canStack, meta, this.chart); const range = { min: Number.POSITIVE_INFINITY, max: Number.NEGATIVE_INFINITY }; const { min: otherMin , max: otherMax } = getUserBounds(otherScale); let i, parsed; function _skip() { parsed = _parsed[i]; const otherValue = parsed[otherScale.axis]; return !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(parsed[scale.axis]) || otherMin > otherValue || otherMax < otherValue; } for(i = 0; i < ilen; ++i){ if (_skip()) { continue; } this.updateRangeFromParsed(range, scale, parsed, stack); if (sorted) { break; } } if (sorted) { for(i = ilen - 1; i >= 0; --i){ if (_skip()) { continue; } this.updateRangeFromParsed(range, scale, parsed, stack); break; } } return range; } getAllParsedValues(scale) { const parsed = this._cachedMeta._parsed; const values = []; let i, ilen, value; for(i = 0, ilen = parsed.length; i < ilen; ++i){ value = parsed[i][scale.axis]; if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(value)) { values.push(value); } } return values; } getMaxOverflow() { return false; } getLabelAndValue(index) { const meta = this._cachedMeta; const iScale = meta.iScale; const vScale = meta.vScale; const parsed = this.getParsed(index); return { label: iScale ? '' + iScale.getLabelForValue(parsed[iScale.axis]) : '', value: vScale ? '' + vScale.getLabelForValue(parsed[vScale.axis]) : '' }; } _update(mode) { const meta = this._cachedMeta; this.update(mode || 'default'); meta._clip = toClip((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(this.options.clip, defaultClip(meta.xScale, meta.yScale, this.getMaxOverflow()))); } update(mode) {} draw() { const ctx = this._ctx; const chart = this.chart; const meta = this._cachedMeta; const elements = meta.data || []; const area = chart.chartArea; const active = []; const start = this._drawStart || 0; const count = this._drawCount || elements.length - start; const drawActiveElementsOnTop = this.options.drawActiveElementsOnTop; let i; if (meta.dataset) { meta.dataset.draw(ctx, area, start, count); } for(i = start; i < start + count; ++i){ const element = elements[i]; if (element.hidden) { continue; } if (element.active && drawActiveElementsOnTop) { active.push(element); } else { element.draw(ctx, area); } } for(i = 0; i < active.length; ++i){ active[i].draw(ctx, area); } } getStyle(index, active) { const mode = active ? 'active' : 'default'; return index === undefined && this._cachedMeta.dataset ? this.resolveDatasetElementOptions(mode) : this.resolveDataElementOptions(index || 0, mode); } getContext(index, active, mode) { const dataset = this.getDataset(); let context; if (index >= 0 && index < this._cachedMeta.data.length) { const element = this._cachedMeta.data[index]; context = element.$context || (element.$context = createDataContext(this.getContext(), index, element)); context.parsed = this.getParsed(index); context.raw = dataset.data[index]; context.index = context.dataIndex = index; } else { context = this.$context || (this.$context = createDatasetContext(this.chart.getContext(), this.index)); context.dataset = dataset; context.index = context.datasetIndex = this.index; } context.active = !!active; context.mode = mode; return context; } resolveDatasetElementOptions(mode) { return this._resolveElementOptions(this.datasetElementType.id, mode); } resolveDataElementOptions(index, mode) { return this._resolveElementOptions(this.dataElementType.id, mode, index); } _resolveElementOptions(elementType, mode = 'default', index) { const active = mode === 'active'; const cache = this._cachedDataOpts; const cacheKey = elementType + '-' + mode; const cached = cache[cacheKey]; const sharing = this.enableOptionSharing && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.h)(index); if (cached) { return cloneIfNotShared(cached, sharing); } const config = this.chart.config; const scopeKeys = config.datasetElementScopeKeys(this._type, elementType); const prefixes = active ? [ `${elementType}Hover`, 'hover', elementType, '' ] : [ elementType, '' ]; const scopes = config.getOptionScopes(this.getDataset(), scopeKeys); const names = Object.keys(_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.elements[elementType]); const context = ()=>this.getContext(index, active, mode); const values = config.resolveNamedOptions(scopes, names, context, prefixes); if (values.$shared) { values.$shared = sharing; cache[cacheKey] = Object.freeze(cloneIfNotShared(values, sharing)); } return values; } _resolveAnimations(index, transition, active) { const chart = this.chart; const cache = this._cachedDataOpts; const cacheKey = `animation-${transition}`; const cached = cache[cacheKey]; if (cached) { return cached; } let options; if (chart.options.animation !== false) { const config = this.chart.config; const scopeKeys = config.datasetAnimationScopeKeys(this._type, transition); const scopes = config.getOptionScopes(this.getDataset(), scopeKeys); options = config.createResolver(scopes, this.getContext(index, active, transition)); } const animations = new Animations(chart, options && options.animations); if (options && options._cacheable) { cache[cacheKey] = Object.freeze(animations); } return animations; } getSharedOptions(options) { if (!options.$shared) { return; } return this._sharedOptions || (this._sharedOptions = Object.assign({}, options)); } includeOptions(mode, sharedOptions) { return !sharedOptions || isDirectUpdateMode(mode) || this.chart._animationsDisabled; } _getSharedOptions(start, mode) { const firstOpts = this.resolveDataElementOptions(start, mode); const previouslySharedOptions = this._sharedOptions; const sharedOptions = this.getSharedOptions(firstOpts); const includeOptions = this.includeOptions(mode, sharedOptions) || sharedOptions !== previouslySharedOptions; this.updateSharedOptions(sharedOptions, mode, firstOpts); return { sharedOptions, includeOptions }; } updateElement(element, index, properties, mode) { if (isDirectUpdateMode(mode)) { Object.assign(element, properties); } else { this._resolveAnimations(index, mode).update(element, properties); } } updateSharedOptions(sharedOptions, mode, newOptions) { if (sharedOptions && !isDirectUpdateMode(mode)) { this._resolveAnimations(undefined, mode).update(sharedOptions, newOptions); } } _setStyle(element, index, mode, active) { element.active = active; const options = this.getStyle(index, active); this._resolveAnimations(index, mode, active).update(element, { options: !active && this.getSharedOptions(options) || options }); } removeHoverStyle(element, datasetIndex, index) { this._setStyle(element, index, 'active', false); } setHoverStyle(element, datasetIndex, index) { this._setStyle(element, index, 'active', true); } _removeDatasetHoverStyle() { const element = this._cachedMeta.dataset; if (element) { this._setStyle(element, undefined, 'active', false); } } _setDatasetHoverStyle() { const element = this._cachedMeta.dataset; if (element) { this._setStyle(element, undefined, 'active', true); } } _resyncElements(resetNewElements) { const data = this._data; const elements = this._cachedMeta.data; for (const [method, arg1, arg2] of this._syncList){ this[method](arg1, arg2); } this._syncList = []; const numMeta = elements.length; const numData = data.length; const count = Math.min(numData, numMeta); if (count) { this.parse(0, count); } if (numData > numMeta) { this._insertElements(numMeta, numData - numMeta, resetNewElements); } else if (numData < numMeta) { this._removeElements(numData, numMeta - numData); } } _insertElements(start, count, resetNewElements = true) { const meta = this._cachedMeta; const data = meta.data; const end = start + count; let i; const move = (arr)=>{ arr.length += count; for(i = arr.length - 1; i >= end; i--){ arr[i] = arr[i - count]; } }; move(data); for(i = start; i < end; ++i){ data[i] = new this.dataElementType(); } if (this._parsing) { move(meta._parsed); } this.parse(start, count); if (resetNewElements) { this.updateElements(data, start, count, 'reset'); } } updateElements(element, start, count, mode) {} _removeElements(start, count) { const meta = this._cachedMeta; if (this._parsing) { const removed = meta._parsed.splice(start, count); if (meta._stacked) { clearStacks(meta, removed); } } meta.data.splice(start, count); } _sync(args) { if (this._parsing) { this._syncList.push(args); } else { const [method, arg1, arg2] = args; this[method](arg1, arg2); } this.chart._dataChanges.push([ this.index, ...args ]); } _onDataPush() { const count = arguments.length; this._sync([ '_insertElements', this.getDataset().data.length - count, count ]); } _onDataPop() { this._sync([ '_removeElements', this._cachedMeta.data.length - 1, 1 ]); } _onDataShift() { this._sync([ '_removeElements', 0, 1 ]); } _onDataSplice(start, count) { if (count) { this._sync([ '_removeElements', start, count ]); } const newCount = arguments.length - 2; if (newCount) { this._sync([ '_insertElements', start, newCount ]); } } _onDataUnshift() { this._sync([ '_insertElements', 0, arguments.length ]); } } function getAllScaleValues(scale, type) { if (!scale._cache.$bar) { const visibleMetas = scale.getMatchingVisibleMetas(type); let values = []; for(let i = 0, ilen = visibleMetas.length; i < ilen; i++){ values = values.concat(visibleMetas[i].controller.getAllParsedValues(scale)); } scale._cache.$bar = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__._)(values.sort((a, b)=>a - b)); } return scale._cache.$bar; } function computeMinSampleSize(meta) { const scale = meta.iScale; const values = getAllScaleValues(scale, meta.type); let min = scale._length; let i, ilen, curr, prev; const updateMinAndPrev = ()=>{ if (curr === 32767 || curr === -32768) { return; } if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.h)(prev)) { min = Math.min(min, Math.abs(curr - prev) || min); } prev = curr; }; for(i = 0, ilen = values.length; i < ilen; ++i){ curr = scale.getPixelForValue(values[i]); updateMinAndPrev(); } prev = undefined; for(i = 0, ilen = scale.ticks.length; i < ilen; ++i){ curr = scale.getPixelForTick(i); updateMinAndPrev(); } return min; } function computeFitCategoryTraits(index, ruler, options, stackCount) { const thickness = options.barThickness; let size, ratio; if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(thickness)) { size = ruler.min * options.categoryPercentage; ratio = options.barPercentage; } else { size = thickness * stackCount; ratio = 1; } return { chunk: size / stackCount, ratio, start: ruler.pixels[index] - size / 2 }; } function computeFlexCategoryTraits(index, ruler, options, stackCount) { const pixels = ruler.pixels; const curr = pixels[index]; let prev = index > 0 ? pixels[index - 1] : null; let next = index < pixels.length - 1 ? pixels[index + 1] : null; const percent = options.categoryPercentage; if (prev === null) { prev = curr - (next === null ? ruler.end - ruler.start : next - curr); } if (next === null) { next = curr + curr - prev; } const start = curr - (curr - Math.min(prev, next)) / 2 * percent; const size = Math.abs(next - prev) / 2 * percent; return { chunk: size / stackCount, ratio: options.barPercentage, start }; } function parseFloatBar(entry, item, vScale, i) { const startValue = vScale.parse(entry[0], i); const endValue = vScale.parse(entry[1], i); const min = Math.min(startValue, endValue); const max = Math.max(startValue, endValue); let barStart = min; let barEnd = max; if (Math.abs(min) > Math.abs(max)) { barStart = max; barEnd = min; } item[vScale.axis] = barEnd; item._custom = { barStart, barEnd, start: startValue, end: endValue, min, max }; } function parseValue(entry, item, vScale, i) { if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(entry)) { parseFloatBar(entry, item, vScale, i); } else { item[vScale.axis] = vScale.parse(entry, i); } return item; } function parseArrayOrPrimitive(meta, data, start, count) { const iScale = meta.iScale; const vScale = meta.vScale; const labels = iScale.getLabels(); const singleScale = iScale === vScale; const parsed = []; let i, ilen, item, entry; for(i = start, ilen = start + count; i < ilen; ++i){ entry = data[i]; item = {}; item[iScale.axis] = singleScale || iScale.parse(labels[i], i); parsed.push(parseValue(entry, item, vScale, i)); } return parsed; } function isFloatBar(custom) { return custom && custom.barStart !== undefined && custom.barEnd !== undefined; } function barSign(size, vScale, actualBase) { if (size !== 0) { return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.s)(size); } return (vScale.isHorizontal() ? 1 : -1) * (vScale.min >= actualBase ? 1 : -1); } function borderProps(properties) { let reverse, start, end, top, bottom; if (properties.horizontal) { reverse = properties.base > properties.x; start = 'left'; end = 'right'; } else { reverse = properties.base < properties.y; start = 'bottom'; end = 'top'; } if (reverse) { top = 'end'; bottom = 'start'; } else { top = 'start'; bottom = 'end'; } return { start, end, reverse, top, bottom }; } function setBorderSkipped(properties, options, stack, index) { let edge = options.borderSkipped; const res = {}; if (!edge) { properties.borderSkipped = res; return; } if (edge === true) { properties.borderSkipped = { top: true, right: true, bottom: true, left: true }; return; } const { start , end , reverse , top , bottom } = borderProps(properties); if (edge === 'middle' && stack) { properties.enableBorderRadius = true; if ((stack._top || 0) === index) { edge = top; } else if ((stack._bottom || 0) === index) { edge = bottom; } else { res[parseEdge(bottom, start, end, reverse)] = true; edge = top; } } res[parseEdge(edge, start, end, reverse)] = true; properties.borderSkipped = res; } function parseEdge(edge, a, b, reverse) { if (reverse) { edge = swap(edge, a, b); edge = startEnd(edge, b, a); } else { edge = startEnd(edge, a, b); } return edge; } function swap(orig, v1, v2) { return orig === v1 ? v2 : orig === v2 ? v1 : orig; } function startEnd(v, start, end) { return v === 'start' ? start : v === 'end' ? end : v; } function setInflateAmount(properties, { inflateAmount }, ratio) { properties.inflateAmount = inflateAmount === 'auto' ? ratio === 1 ? 0.33 : 0 : inflateAmount; } class BarController extends DatasetController { static id = 'bar'; static defaults = { datasetElementType: false, dataElementType: 'bar', categoryPercentage: 0.8, barPercentage: 0.9, grouped: true, animations: { numbers: { type: 'number', properties: [ 'x', 'y', 'base', 'width', 'height' ] } } }; static overrides = { scales: { _index_: { type: 'category', offset: true, grid: { offset: true } }, _value_: { type: 'linear', beginAtZero: true } } }; parsePrimitiveData(meta, data, start, count) { return parseArrayOrPrimitive(meta, data, start, count); } parseArrayData(meta, data, start, count) { return parseArrayOrPrimitive(meta, data, start, count); } parseObjectData(meta, data, start, count) { const { iScale , vScale } = meta; const { xAxisKey ='x' , yAxisKey ='y' } = this._parsing; const iAxisKey = iScale.axis === 'x' ? xAxisKey : yAxisKey; const vAxisKey = vScale.axis === 'x' ? xAxisKey : yAxisKey; const parsed = []; let i, ilen, item, obj; for(i = start, ilen = start + count; i < ilen; ++i){ obj = data[i]; item = {}; item[iScale.axis] = iScale.parse((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.f)(obj, iAxisKey), i); parsed.push(parseValue((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.f)(obj, vAxisKey), item, vScale, i)); } return parsed; } updateRangeFromParsed(range, scale, parsed, stack) { super.updateRangeFromParsed(range, scale, parsed, stack); const custom = parsed._custom; if (custom && scale === this._cachedMeta.vScale) { range.min = Math.min(range.min, custom.min); range.max = Math.max(range.max, custom.max); } } getMaxOverflow() { return 0; } getLabelAndValue(index) { const meta = this._cachedMeta; const { iScale , vScale } = meta; const parsed = this.getParsed(index); const custom = parsed._custom; const value = isFloatBar(custom) ? '[' + custom.start + ', ' + custom.end + ']' : '' + vScale.getLabelForValue(parsed[vScale.axis]); return { label: '' + iScale.getLabelForValue(parsed[iScale.axis]), value }; } initialize() { this.enableOptionSharing = true; super.initialize(); const meta = this._cachedMeta; meta.stack = this.getDataset().stack; } update(mode) { const meta = this._cachedMeta; this.updateElements(meta.data, 0, meta.data.length, mode); } updateElements(bars, start, count, mode) { const reset = mode === 'reset'; const { index , _cachedMeta: { vScale } } = this; const base = vScale.getBasePixel(); const horizontal = vScale.isHorizontal(); const ruler = this._getRuler(); const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode); for(let i = start; i < start + count; i++){ const parsed = this.getParsed(i); const vpixels = reset || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(parsed[vScale.axis]) ? { base, head: base } : this._calculateBarValuePixels(i); const ipixels = this._calculateBarIndexPixels(i, ruler); const stack = (parsed._stacks || {})[vScale.axis]; const properties = { horizontal, base: vpixels.base, enableBorderRadius: !stack || isFloatBar(parsed._custom) || index === stack._top || index === stack._bottom, x: horizontal ? vpixels.head : ipixels.center, y: horizontal ? ipixels.center : vpixels.head, height: horizontal ? ipixels.size : Math.abs(vpixels.size), width: horizontal ? Math.abs(vpixels.size) : ipixels.size }; if (includeOptions) { properties.options = sharedOptions || this.resolveDataElementOptions(i, bars[i].active ? 'active' : mode); } const options = properties.options || bars[i].options; setBorderSkipped(properties, options, stack, index); setInflateAmount(properties, options, ruler.ratio); this.updateElement(bars[i], i, properties, mode); } } _getStacks(last, dataIndex) { const { iScale } = this._cachedMeta; const metasets = iScale.getMatchingVisibleMetas(this._type).filter((meta)=>meta.controller.options.grouped); const stacked = iScale.options.stacked; const stacks = []; const currentParsed = this._cachedMeta.controller.getParsed(dataIndex); const iScaleValue = currentParsed && currentParsed[iScale.axis]; const skipNull = (meta)=>{ const parsed = meta._parsed.find((item)=>item[iScale.axis] === iScaleValue); const val = parsed && parsed[meta.vScale.axis]; if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(val) || isNaN(val)) { return true; } }; for (const meta of metasets){ if (dataIndex !== undefined && skipNull(meta)) { continue; } if (stacked === false || stacks.indexOf(meta.stack) === -1 || stacked === undefined && meta.stack === undefined) { stacks.push(meta.stack); } if (meta.index === last) { break; } } if (!stacks.length) { stacks.push(undefined); } return stacks; } _getStackCount(index) { return this._getStacks(undefined, index).length; } _getAxisCount() { return this._getAxis().length; } getFirstScaleIdForIndexAxis() { const scales = this.chart.scales; const indexScaleId = this.chart.options.indexAxis; return Object.keys(scales).filter((key)=>scales[key].axis === indexScaleId).shift(); } _getAxis() { const axis = {}; const firstScaleAxisId = this.getFirstScaleIdForIndexAxis(); for (const dataset of this.chart.data.datasets){ axis[(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(this.chart.options.indexAxis === 'x' ? dataset.xAxisID : dataset.yAxisID, firstScaleAxisId)] = true; } return Object.keys(axis); } _getStackIndex(datasetIndex, name, dataIndex) { const stacks = this._getStacks(datasetIndex, dataIndex); const index = name !== undefined ? stacks.indexOf(name) : -1; return index === -1 ? stacks.length - 1 : index; } _getRuler() { const opts = this.options; const meta = this._cachedMeta; const iScale = meta.iScale; const pixels = []; let i, ilen; for(i = 0, ilen = meta.data.length; i < ilen; ++i){ pixels.push(iScale.getPixelForValue(this.getParsed(i)[iScale.axis], i)); } const barThickness = opts.barThickness; const min = barThickness || computeMinSampleSize(meta); return { min, pixels, start: iScale._startPixel, end: iScale._endPixel, stackCount: this._getStackCount(), scale: iScale, grouped: opts.grouped, ratio: barThickness ? 1 : opts.categoryPercentage * opts.barPercentage }; } _calculateBarValuePixels(index) { const { _cachedMeta: { vScale , _stacked , index: datasetIndex } , options: { base: baseValue , minBarLength } } = this; const actualBase = baseValue || 0; const parsed = this.getParsed(index); const custom = parsed._custom; const floating = isFloatBar(custom); let value = parsed[vScale.axis]; let start = 0; let length = _stacked ? this.applyStack(vScale, parsed, _stacked) : value; let head, size; if (length !== value) { start = length - value; length = value; } if (floating) { value = custom.barStart; length = custom.barEnd - custom.barStart; if (value !== 0 && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.s)(value) !== (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.s)(custom.barEnd)) { start = 0; } start += value; } const startValue = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(baseValue) && !floating ? baseValue : start; let base = vScale.getPixelForValue(startValue); if (this.chart.getDataVisibility(index)) { head = vScale.getPixelForValue(start + length); } else { head = base; } size = head - base; if (Math.abs(size) < minBarLength) { size = barSign(size, vScale, actualBase) * minBarLength; if (value === actualBase) { base -= size / 2; } const startPixel = vScale.getPixelForDecimal(0); const endPixel = vScale.getPixelForDecimal(1); const min = Math.min(startPixel, endPixel); const max = Math.max(startPixel, endPixel); base = Math.max(Math.min(base, max), min); head = base + size; if (_stacked && !floating) { parsed._stacks[vScale.axis]._visualValues[datasetIndex] = vScale.getValueForPixel(head) - vScale.getValueForPixel(base); } } if (base === vScale.getPixelForValue(actualBase)) { const halfGrid = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.s)(size) * vScale.getLineWidthForValue(actualBase) / 2; base += halfGrid; size -= halfGrid; } return { size, base, head, center: head + size / 2 }; } _calculateBarIndexPixels(index, ruler) { const scale = ruler.scale; const options = this.options; const skipNull = options.skipNull; const maxBarThickness = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(options.maxBarThickness, Infinity); let center, size; const axisCount = this._getAxisCount(); if (ruler.grouped) { const stackCount = skipNull ? this._getStackCount(index) : ruler.stackCount; const range = options.barThickness === 'flex' ? computeFlexCategoryTraits(index, ruler, options, stackCount * axisCount) : computeFitCategoryTraits(index, ruler, options, stackCount * axisCount); const axisID = this.chart.options.indexAxis === 'x' ? this.getDataset().xAxisID : this.getDataset().yAxisID; const axisNumber = this._getAxis().indexOf((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(axisID, this.getFirstScaleIdForIndexAxis())); const stackIndex = this._getStackIndex(this.index, this._cachedMeta.stack, skipNull ? index : undefined) + axisNumber; center = range.start + range.chunk * stackIndex + range.chunk / 2; size = Math.min(maxBarThickness, range.chunk * range.ratio); } else { center = scale.getPixelForValue(this.getParsed(index)[scale.axis], index); size = Math.min(maxBarThickness, ruler.min * ruler.ratio); } return { base: center - size / 2, head: center + size / 2, center, size }; } draw() { const meta = this._cachedMeta; const vScale = meta.vScale; const rects = meta.data; const ilen = rects.length; let i = 0; for(; i < ilen; ++i){ if (this.getParsed(i)[vScale.axis] !== null && !rects[i].hidden) { rects[i].draw(this._ctx); } } } } class BubbleController extends DatasetController { static id = 'bubble'; static defaults = { datasetElementType: false, dataElementType: 'point', animations: { numbers: { type: 'number', properties: [ 'x', 'y', 'borderWidth', 'radius' ] } } }; static overrides = { scales: { x: { type: 'linear' }, y: { type: 'linear' } } }; initialize() { this.enableOptionSharing = true; super.initialize(); } parsePrimitiveData(meta, data, start, count) { const parsed = super.parsePrimitiveData(meta, data, start, count); for(let i = 0; i < parsed.length; i++){ parsed[i]._custom = this.resolveDataElementOptions(i + start).radius; } return parsed; } parseArrayData(meta, data, start, count) { const parsed = super.parseArrayData(meta, data, start, count); for(let i = 0; i < parsed.length; i++){ const item = data[start + i]; parsed[i]._custom = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(item[2], this.resolveDataElementOptions(i + start).radius); } return parsed; } parseObjectData(meta, data, start, count) { const parsed = super.parseObjectData(meta, data, start, count); for(let i = 0; i < parsed.length; i++){ const item = data[start + i]; parsed[i]._custom = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(item && item.r && +item.r, this.resolveDataElementOptions(i + start).radius); } return parsed; } getMaxOverflow() { const data = this._cachedMeta.data; let max = 0; for(let i = data.length - 1; i >= 0; --i){ max = Math.max(max, data[i].size(this.resolveDataElementOptions(i)) / 2); } return max > 0 && max; } getLabelAndValue(index) { const meta = this._cachedMeta; const labels = this.chart.data.labels || []; const { xScale , yScale } = meta; const parsed = this.getParsed(index); const x = xScale.getLabelForValue(parsed.x); const y = yScale.getLabelForValue(parsed.y); const r = parsed._custom; return { label: labels[index] || '', value: '(' + x + ', ' + y + (r ? ', ' + r : '') + ')' }; } update(mode) { const points = this._cachedMeta.data; this.updateElements(points, 0, points.length, mode); } updateElements(points, start, count, mode) { const reset = mode === 'reset'; const { iScale , vScale } = this._cachedMeta; const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode); const iAxis = iScale.axis; const vAxis = vScale.axis; for(let i = start; i < start + count; i++){ const point = points[i]; const parsed = !reset && this.getParsed(i); const properties = {}; const iPixel = properties[iAxis] = reset ? iScale.getPixelForDecimal(0.5) : iScale.getPixelForValue(parsed[iAxis]); const vPixel = properties[vAxis] = reset ? vScale.getBasePixel() : vScale.getPixelForValue(parsed[vAxis]); properties.skip = isNaN(iPixel) || isNaN(vPixel); if (includeOptions) { properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode); if (reset) { properties.options.radius = 0; } } this.updateElement(point, i, properties, mode); } } resolveDataElementOptions(index, mode) { const parsed = this.getParsed(index); let values = super.resolveDataElementOptions(index, mode); if (values.$shared) { values = Object.assign({}, values, { $shared: false }); } const radius = values.radius; if (mode !== 'active') { values.radius = 0; } values.radius += (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(parsed && parsed._custom, radius); return values; } } function getRatioAndOffset(rotation, circumference, cutout) { let ratioX = 1; let ratioY = 1; let offsetX = 0; let offsetY = 0; if (circumference < _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T) { const startAngle = rotation; const endAngle = startAngle + circumference; const startX = Math.cos(startAngle); const startY = Math.sin(startAngle); const endX = Math.cos(endAngle); const endY = Math.sin(endAngle); const calcMax = (angle, a, b)=>(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.p)(angle, startAngle, endAngle, true) ? 1 : Math.max(a, a * cutout, b, b * cutout); const calcMin = (angle, a, b)=>(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.p)(angle, startAngle, endAngle, true) ? -1 : Math.min(a, a * cutout, b, b * cutout); const maxX = calcMax(0, startX, endX); const maxY = calcMax(_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H, startY, endY); const minX = calcMin(_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P, startX, endX); const minY = calcMin(_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H, startY, endY); ratioX = (maxX - minX) / 2; ratioY = (maxY - minY) / 2; offsetX = -(maxX + minX) / 2; offsetY = -(maxY + minY) / 2; } return { ratioX, ratioY, offsetX, offsetY }; } class DoughnutController extends DatasetController { static id = 'doughnut'; static defaults = { datasetElementType: false, dataElementType: 'arc', animation: { animateRotate: true, animateScale: false }, animations: { numbers: { type: 'number', properties: [ 'circumference', 'endAngle', 'innerRadius', 'outerRadius', 'startAngle', 'x', 'y', 'offset', 'borderWidth', 'spacing' ] } }, cutout: '50%', rotation: 0, circumference: 360, radius: '100%', spacing: 0, indexAxis: 'r' }; static descriptors = { _scriptable: (name)=>name !== 'spacing', _indexable: (name)=>name !== 'spacing' && !name.startsWith('borderDash') && !name.startsWith('hoverBorderDash') }; static overrides = { aspectRatio: 1, plugins: { legend: { labels: { generateLabels (chart) { const data = chart.data; const { labels: { pointStyle , textAlign , color , useBorderRadius , borderRadius } } = chart.legend.options; if (data.labels.length && data.datasets.length) { return data.labels.map((label, i)=>{ const meta = chart.getDatasetMeta(0); const style = meta.controller.getStyle(i); return { text: label, fillStyle: style.backgroundColor, fontColor: color, hidden: !chart.getDataVisibility(i), lineDash: style.borderDash, lineDashOffset: style.borderDashOffset, lineJoin: style.borderJoinStyle, lineWidth: style.borderWidth, strokeStyle: style.borderColor, textAlign: textAlign, pointStyle: pointStyle, borderRadius: useBorderRadius && (borderRadius || style.borderRadius), index: i }; }); } return []; } }, onClick (e, legendItem, legend) { legend.chart.toggleDataVisibility(legendItem.index); legend.chart.update(); } } } }; constructor(chart, datasetIndex){ super(chart, datasetIndex); this.enableOptionSharing = true; this.innerRadius = undefined; this.outerRadius = undefined; this.offsetX = undefined; this.offsetY = undefined; } linkScales() {} parse(start, count) { const data = this.getDataset().data; const meta = this._cachedMeta; if (this._parsing === false) { meta._parsed = data; } else { let getter = (i)=>+data[i]; if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(data[start])) { const { key ='value' } = this._parsing; getter = (i)=>+(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.f)(data[i], key); } let i, ilen; for(i = start, ilen = start + count; i < ilen; ++i){ meta._parsed[i] = getter(i); } } } _getRotation() { return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.options.rotation - 90); } _getCircumference() { return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.options.circumference); } _getRotationExtents() { let min = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T; let max = -_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T; for(let i = 0; i < this.chart.data.datasets.length; ++i){ if (this.chart.isDatasetVisible(i) && this.chart.getDatasetMeta(i).type === this._type) { const controller = this.chart.getDatasetMeta(i).controller; const rotation = controller._getRotation(); const circumference = controller._getCircumference(); min = Math.min(min, rotation); max = Math.max(max, rotation + circumference); } } return { rotation: min, circumference: max - min }; } update(mode) { const chart = this.chart; const { chartArea } = chart; const meta = this._cachedMeta; const arcs = meta.data; const spacing = this.getMaxBorderWidth() + this.getMaxOffset(arcs) + this.options.spacing; const maxSize = Math.max((Math.min(chartArea.width, chartArea.height) - spacing) / 2, 0); const cutout = Math.min((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.m)(this.options.cutout, maxSize), 1); const chartWeight = this._getRingWeight(this.index); const { circumference , rotation } = this._getRotationExtents(); const { ratioX , ratioY , offsetX , offsetY } = getRatioAndOffset(rotation, circumference, cutout); const maxWidth = (chartArea.width - spacing) / ratioX; const maxHeight = (chartArea.height - spacing) / ratioY; const maxRadius = Math.max(Math.min(maxWidth, maxHeight) / 2, 0); const outerRadius = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.n)(this.options.radius, maxRadius); const innerRadius = Math.max(outerRadius * cutout, 0); const radiusLength = (outerRadius - innerRadius) / this._getVisibleDatasetWeightTotal(); this.offsetX = offsetX * outerRadius; this.offsetY = offsetY * outerRadius; meta.total = this.calculateTotal(); this.outerRadius = outerRadius - radiusLength * this._getRingWeightOffset(this.index); this.innerRadius = Math.max(this.outerRadius - radiusLength * chartWeight, 0); this.updateElements(arcs, 0, arcs.length, mode); } _circumference(i, reset) { const opts = this.options; const meta = this._cachedMeta; const circumference = this._getCircumference(); if (reset && opts.animation.animateRotate || !this.chart.getDataVisibility(i) || meta._parsed[i] === null || meta.data[i].hidden) { return 0; } return this.calculateCircumference(meta._parsed[i] * circumference / _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T); } updateElements(arcs, start, count, mode) { const reset = mode === 'reset'; const chart = this.chart; const chartArea = chart.chartArea; const opts = chart.options; const animationOpts = opts.animation; const centerX = (chartArea.left + chartArea.right) / 2; const centerY = (chartArea.top + chartArea.bottom) / 2; const animateScale = reset && animationOpts.animateScale; const innerRadius = animateScale ? 0 : this.innerRadius; const outerRadius = animateScale ? 0 : this.outerRadius; const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode); let startAngle = this._getRotation(); let i; for(i = 0; i < start; ++i){ startAngle += this._circumference(i, reset); } for(i = start; i < start + count; ++i){ const circumference = this._circumference(i, reset); const arc = arcs[i]; const properties = { x: centerX + this.offsetX, y: centerY + this.offsetY, startAngle, endAngle: startAngle + circumference, circumference, outerRadius, innerRadius }; if (includeOptions) { properties.options = sharedOptions || this.resolveDataElementOptions(i, arc.active ? 'active' : mode); } startAngle += circumference; this.updateElement(arc, i, properties, mode); } } calculateTotal() { const meta = this._cachedMeta; const metaData = meta.data; let total = 0; let i; for(i = 0; i < metaData.length; i++){ const value = meta._parsed[i]; if (value !== null && !isNaN(value) && this.chart.getDataVisibility(i) && !metaData[i].hidden) { total += Math.abs(value); } } return total; } calculateCircumference(value) { const total = this._cachedMeta.total; if (total > 0 && !isNaN(value)) { return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T * (Math.abs(value) / total); } return 0; } getLabelAndValue(index) { const meta = this._cachedMeta; const chart = this.chart; const labels = chart.data.labels || []; const value = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.o)(meta._parsed[index], chart.options.locale); return { label: labels[index] || '', value }; } getMaxBorderWidth(arcs) { let max = 0; const chart = this.chart; let i, ilen, meta, controller, options; if (!arcs) { for(i = 0, ilen = chart.data.datasets.length; i < ilen; ++i){ if (chart.isDatasetVisible(i)) { meta = chart.getDatasetMeta(i); arcs = meta.data; controller = meta.controller; break; } } } if (!arcs) { return 0; } for(i = 0, ilen = arcs.length; i < ilen; ++i){ options = controller.resolveDataElementOptions(i); if (options.borderAlign !== 'inner') { max = Math.max(max, options.borderWidth || 0, options.hoverBorderWidth || 0); } } return max; } getMaxOffset(arcs) { let max = 0; for(let i = 0, ilen = arcs.length; i < ilen; ++i){ const options = this.resolveDataElementOptions(i); max = Math.max(max, options.offset || 0, options.hoverOffset || 0); } return max; } _getRingWeightOffset(datasetIndex) { let ringWeightOffset = 0; for(let i = 0; i < datasetIndex; ++i){ if (this.chart.isDatasetVisible(i)) { ringWeightOffset += this._getRingWeight(i); } } return ringWeightOffset; } _getRingWeight(datasetIndex) { return Math.max((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(this.chart.data.datasets[datasetIndex].weight, 1), 0); } _getVisibleDatasetWeightTotal() { return this._getRingWeightOffset(this.chart.data.datasets.length) || 1; } } class LineController extends DatasetController { static id = 'line'; static defaults = { datasetElementType: 'line', dataElementType: 'point', showLine: true, spanGaps: false }; static overrides = { scales: { _index_: { type: 'category' }, _value_: { type: 'linear' } } }; initialize() { this.enableOptionSharing = true; this.supportsDecimation = true; super.initialize(); } update(mode) { const meta = this._cachedMeta; const { dataset: line , data: points = [] , _dataset } = meta; const animationsDisabled = this.chart._animationsDisabled; let { start , count } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.q)(meta, points, animationsDisabled); this._drawStart = start; this._drawCount = count; if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.w)(meta)) { start = 0; count = points.length; } line._chart = this.chart; line._datasetIndex = this.index; line._decimated = !!_dataset._decimated; line.points = points; const options = this.resolveDatasetElementOptions(mode); if (!this.options.showLine) { options.borderWidth = 0; } options.segment = this.options.segment; this.updateElement(line, undefined, { animated: !animationsDisabled, options }, mode); this.updateElements(points, start, count, mode); } updateElements(points, start, count, mode) { const reset = mode === 'reset'; const { iScale , vScale , _stacked , _dataset } = this._cachedMeta; const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode); const iAxis = iScale.axis; const vAxis = vScale.axis; const { spanGaps , segment } = this.options; const maxGapLength = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.x)(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY; const directUpdate = this.chart._animationsDisabled || reset || mode === 'none'; const end = start + count; const pointsCount = points.length; let prevParsed = start > 0 && this.getParsed(start - 1); for(let i = 0; i < pointsCount; ++i){ const point = points[i]; const properties = directUpdate ? point : {}; if (i < start || i >= end) { properties.skip = true; continue; } const parsed = this.getParsed(i); const nullData = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(parsed[vAxis]); const iPixel = properties[iAxis] = iScale.getPixelForValue(parsed[iAxis], i); const vPixel = properties[vAxis] = reset || nullData ? vScale.getBasePixel() : vScale.getPixelForValue(_stacked ? this.applyStack(vScale, parsed, _stacked) : parsed[vAxis], i); properties.skip = isNaN(iPixel) || isNaN(vPixel) || nullData; properties.stop = i > 0 && Math.abs(parsed[iAxis] - prevParsed[iAxis]) > maxGapLength; if (segment) { properties.parsed = parsed; properties.raw = _dataset.data[i]; } if (includeOptions) { properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode); } if (!directUpdate) { this.updateElement(point, i, properties, mode); } prevParsed = parsed; } } getMaxOverflow() { const meta = this._cachedMeta; const dataset = meta.dataset; const border = dataset.options && dataset.options.borderWidth || 0; const data = meta.data || []; if (!data.length) { return border; } const firstPoint = data[0].size(this.resolveDataElementOptions(0)); const lastPoint = data[data.length - 1].size(this.resolveDataElementOptions(data.length - 1)); return Math.max(border, firstPoint, lastPoint) / 2; } draw() { const meta = this._cachedMeta; meta.dataset.updateControlPoints(this.chart.chartArea, meta.iScale.axis); super.draw(); } } class PolarAreaController extends DatasetController { static id = 'polarArea'; static defaults = { dataElementType: 'arc', animation: { animateRotate: true, animateScale: true }, animations: { numbers: { type: 'number', properties: [ 'x', 'y', 'startAngle', 'endAngle', 'innerRadius', 'outerRadius' ] } }, indexAxis: 'r', startAngle: 0 }; static overrides = { aspectRatio: 1, plugins: { legend: { labels: { generateLabels (chart) { const data = chart.data; if (data.labels.length && data.datasets.length) { const { labels: { pointStyle , color } } = chart.legend.options; return data.labels.map((label, i)=>{ const meta = chart.getDatasetMeta(0); const style = meta.controller.getStyle(i); return { text: label, fillStyle: style.backgroundColor, strokeStyle: style.borderColor, fontColor: color, lineWidth: style.borderWidth, pointStyle: pointStyle, hidden: !chart.getDataVisibility(i), index: i }; }); } return []; } }, onClick (e, legendItem, legend) { legend.chart.toggleDataVisibility(legendItem.index); legend.chart.update(); } } }, scales: { r: { type: 'radialLinear', angleLines: { display: false }, beginAtZero: true, grid: { circular: true }, pointLabels: { display: false }, startAngle: 0 } } }; constructor(chart, datasetIndex){ super(chart, datasetIndex); this.innerRadius = undefined; this.outerRadius = undefined; } getLabelAndValue(index) { const meta = this._cachedMeta; const chart = this.chart; const labels = chart.data.labels || []; const value = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.o)(meta._parsed[index].r, chart.options.locale); return { label: labels[index] || '', value }; } parseObjectData(meta, data, start, count) { return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.y.bind(this)(meta, data, start, count); } update(mode) { const arcs = this._cachedMeta.data; this._updateRadius(); this.updateElements(arcs, 0, arcs.length, mode); } getMinMax() { const meta = this._cachedMeta; const range = { min: Number.POSITIVE_INFINITY, max: Number.NEGATIVE_INFINITY }; meta.data.forEach((element, index)=>{ const parsed = this.getParsed(index).r; if (!isNaN(parsed) && this.chart.getDataVisibility(index)) { if (parsed < range.min) { range.min = parsed; } if (parsed > range.max) { range.max = parsed; } } }); return range; } _updateRadius() { const chart = this.chart; const chartArea = chart.chartArea; const opts = chart.options; const minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top); const outerRadius = Math.max(minSize / 2, 0); const innerRadius = Math.max(opts.cutoutPercentage ? outerRadius / 100 * opts.cutoutPercentage : 1, 0); const radiusLength = (outerRadius - innerRadius) / chart.getVisibleDatasetCount(); this.outerRadius = outerRadius - radiusLength * this.index; this.innerRadius = this.outerRadius - radiusLength; } updateElements(arcs, start, count, mode) { const reset = mode === 'reset'; const chart = this.chart; const opts = chart.options; const animationOpts = opts.animation; const scale = this._cachedMeta.rScale; const centerX = scale.xCenter; const centerY = scale.yCenter; const datasetStartAngle = scale.getIndexAngle(0) - 0.5 * _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P; let angle = datasetStartAngle; let i; const defaultAngle = 360 / this.countVisibleElements(); for(i = 0; i < start; ++i){ angle += this._computeAngle(i, mode, defaultAngle); } for(i = start; i < start + count; i++){ const arc = arcs[i]; let startAngle = angle; let endAngle = angle + this._computeAngle(i, mode, defaultAngle); let outerRadius = chart.getDataVisibility(i) ? scale.getDistanceFromCenterForValue(this.getParsed(i).r) : 0; angle = endAngle; if (reset) { if (animationOpts.animateScale) { outerRadius = 0; } if (animationOpts.animateRotate) { startAngle = endAngle = datasetStartAngle; } } const properties = { x: centerX, y: centerY, innerRadius: 0, outerRadius, startAngle, endAngle, options: this.resolveDataElementOptions(i, arc.active ? 'active' : mode) }; this.updateElement(arc, i, properties, mode); } } countVisibleElements() { const meta = this._cachedMeta; let count = 0; meta.data.forEach((element, index)=>{ if (!isNaN(this.getParsed(index).r) && this.chart.getDataVisibility(index)) { count++; } }); return count; } _computeAngle(index, mode, defaultAngle) { return this.chart.getDataVisibility(index) ? (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.resolveDataElementOptions(index, mode).angle || defaultAngle) : 0; } } class PieController extends DoughnutController { static id = 'pie'; static defaults = { cutout: 0, rotation: 0, circumference: 360, radius: '100%' }; } class RadarController extends DatasetController { static id = 'radar'; static defaults = { datasetElementType: 'line', dataElementType: 'point', indexAxis: 'r', showLine: true, elements: { line: { fill: 'start' } } }; static overrides = { aspectRatio: 1, scales: { r: { type: 'radialLinear' } } }; getLabelAndValue(index) { const vScale = this._cachedMeta.vScale; const parsed = this.getParsed(index); return { label: vScale.getLabels()[index], value: '' + vScale.getLabelForValue(parsed[vScale.axis]) }; } parseObjectData(meta, data, start, count) { return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.y.bind(this)(meta, data, start, count); } update(mode) { const meta = this._cachedMeta; const line = meta.dataset; const points = meta.data || []; const labels = meta.iScale.getLabels(); line.points = points; if (mode !== 'resize') { const options = this.resolveDatasetElementOptions(mode); if (!this.options.showLine) { options.borderWidth = 0; } const properties = { _loop: true, _fullLoop: labels.length === points.length, options }; this.updateElement(line, undefined, properties, mode); } this.updateElements(points, 0, points.length, mode); } updateElements(points, start, count, mode) { const scale = this._cachedMeta.rScale; const reset = mode === 'reset'; for(let i = start; i < start + count; i++){ const point = points[i]; const options = this.resolveDataElementOptions(i, point.active ? 'active' : mode); const pointPosition = scale.getPointPositionForValue(i, this.getParsed(i).r); const x = reset ? scale.xCenter : pointPosition.x; const y = reset ? scale.yCenter : pointPosition.y; const properties = { x, y, angle: pointPosition.angle, skip: isNaN(x) || isNaN(y), options }; this.updateElement(point, i, properties, mode); } } } class ScatterController extends DatasetController { static id = 'scatter'; static defaults = { datasetElementType: false, dataElementType: 'point', showLine: false, fill: false }; static overrides = { interaction: { mode: 'point' }, scales: { x: { type: 'linear' }, y: { type: 'linear' } } }; getLabelAndValue(index) { const meta = this._cachedMeta; const labels = this.chart.data.labels || []; const { xScale , yScale } = meta; const parsed = this.getParsed(index); const x = xScale.getLabelForValue(parsed.x); const y = yScale.getLabelForValue(parsed.y); return { label: labels[index] || '', value: '(' + x + ', ' + y + ')' }; } update(mode) { const meta = this._cachedMeta; const { data: points = [] } = meta; const animationsDisabled = this.chart._animationsDisabled; let { start , count } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.q)(meta, points, animationsDisabled); this._drawStart = start; this._drawCount = count; if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.w)(meta)) { start = 0; count = points.length; } if (this.options.showLine) { if (!this.datasetElementType) { this.addElements(); } const { dataset: line , _dataset } = meta; line._chart = this.chart; line._datasetIndex = this.index; line._decimated = !!_dataset._decimated; line.points = points; const options = this.resolveDatasetElementOptions(mode); options.segment = this.options.segment; this.updateElement(line, undefined, { animated: !animationsDisabled, options }, mode); } else if (this.datasetElementType) { delete meta.dataset; this.datasetElementType = false; } this.updateElements(points, start, count, mode); } addElements() { const { showLine } = this.options; if (!this.datasetElementType && showLine) { this.datasetElementType = this.chart.registry.getElement('line'); } super.addElements(); } updateElements(points, start, count, mode) { const reset = mode === 'reset'; const { iScale , vScale , _stacked , _dataset } = this._cachedMeta; const firstOpts = this.resolveDataElementOptions(start, mode); const sharedOptions = this.getSharedOptions(firstOpts); const includeOptions = this.includeOptions(mode, sharedOptions); const iAxis = iScale.axis; const vAxis = vScale.axis; const { spanGaps , segment } = this.options; const maxGapLength = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.x)(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY; const directUpdate = this.chart._animationsDisabled || reset || mode === 'none'; let prevParsed = start > 0 && this.getParsed(start - 1); for(let i = start; i < start + count; ++i){ const point = points[i]; const parsed = this.getParsed(i); const properties = directUpdate ? point : {}; const nullData = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(parsed[vAxis]); const iPixel = properties[iAxis] = iScale.getPixelForValue(parsed[iAxis], i); const vPixel = properties[vAxis] = reset || nullData ? vScale.getBasePixel() : vScale.getPixelForValue(_stacked ? this.applyStack(vScale, parsed, _stacked) : parsed[vAxis], i); properties.skip = isNaN(iPixel) || isNaN(vPixel) || nullData; properties.stop = i > 0 && Math.abs(parsed[iAxis] - prevParsed[iAxis]) > maxGapLength; if (segment) { properties.parsed = parsed; properties.raw = _dataset.data[i]; } if (includeOptions) { properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode); } if (!directUpdate) { this.updateElement(point, i, properties, mode); } prevParsed = parsed; } this.updateSharedOptions(sharedOptions, mode, firstOpts); } getMaxOverflow() { const meta = this._cachedMeta; const data = meta.data || []; if (!this.options.showLine) { let max = 0; for(let i = data.length - 1; i >= 0; --i){ max = Math.max(max, data[i].size(this.resolveDataElementOptions(i)) / 2); } return max > 0 && max; } const dataset = meta.dataset; const border = dataset.options && dataset.options.borderWidth || 0; if (!data.length) { return border; } const firstPoint = data[0].size(this.resolveDataElementOptions(0)); const lastPoint = data[data.length - 1].size(this.resolveDataElementOptions(data.length - 1)); return Math.max(border, firstPoint, lastPoint) / 2; } } var controllers = /*#__PURE__*/Object.freeze({ __proto__: null, BarController: BarController, BubbleController: BubbleController, DoughnutController: DoughnutController, LineController: LineController, PieController: PieController, PolarAreaController: PolarAreaController, RadarController: RadarController, ScatterController: ScatterController }); /** * @namespace Chart._adapters * @since 2.8.0 * @private */ function abstract() { throw new Error('This method is not implemented: Check that a complete date adapter is provided.'); } /** * Date adapter (current used by the time scale) * @namespace Chart._adapters._date * @memberof Chart._adapters * @private */ class DateAdapterBase { /** * Override default date adapter methods. * Accepts type parameter to define options type. * @example * Chart._adapters._date.override<{myAdapterOption: string}>({ * init() { * console.log(this.options.myAdapterOption); * } * }) */ static override(members) { Object.assign(DateAdapterBase.prototype, members); } options; constructor(options){ this.options = options || {}; } // eslint-disable-next-line @typescript-eslint/no-empty-function init() {} formats() { return abstract(); } parse() { return abstract(); } format() { return abstract(); } add() { return abstract(); } diff() { return abstract(); } startOf() { return abstract(); } endOf() { return abstract(); } } var adapters = { _date: DateAdapterBase }; function binarySearch(metaset, axis, value, intersect) { const { controller , data , _sorted } = metaset; const iScale = controller._cachedMeta.iScale; const spanGaps = metaset.dataset ? metaset.dataset.options ? metaset.dataset.options.spanGaps : null : null; if (iScale && axis === iScale.axis && axis !== 'r' && _sorted && data.length) { const lookupMethod = iScale._reversePixels ? _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.A : _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.B; if (!intersect) { const result = lookupMethod(data, axis, value); if (spanGaps) { const { vScale } = controller._cachedMeta; const { _parsed } = metaset; const distanceToDefinedLo = _parsed.slice(0, result.lo + 1).reverse().findIndex((point)=>!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(point[vScale.axis])); result.lo -= Math.max(0, distanceToDefinedLo); const distanceToDefinedHi = _parsed.slice(result.hi).findIndex((point)=>!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(point[vScale.axis])); result.hi += Math.max(0, distanceToDefinedHi); } return result; } else if (controller._sharedOptions) { const el = data[0]; const range = typeof el.getRange === 'function' && el.getRange(axis); if (range) { const start = lookupMethod(data, axis, value - range); const end = lookupMethod(data, axis, value + range); return { lo: start.lo, hi: end.hi }; } } } return { lo: 0, hi: data.length - 1 }; } function evaluateInteractionItems(chart, axis, position, handler, intersect) { const metasets = chart.getSortedVisibleDatasetMetas(); const value = position[axis]; for(let i = 0, ilen = metasets.length; i < ilen; ++i){ const { index , data } = metasets[i]; const { lo , hi } = binarySearch(metasets[i], axis, value, intersect); for(let j = lo; j <= hi; ++j){ const element = data[j]; if (!element.skip) { handler(element, index, j); } } } } function getDistanceMetricForAxis(axis) { const useX = axis.indexOf('x') !== -1; const useY = axis.indexOf('y') !== -1; return function(pt1, pt2) { const deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0; const deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0; return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2)); }; } function getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible) { const items = []; if (!includeInvisible && !chart.isPointInArea(position)) { return items; } const evaluationFunc = function(element, datasetIndex, index) { if (!includeInvisible && !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)(element, chart.chartArea, 0)) { return; } if (element.inRange(position.x, position.y, useFinalPosition)) { items.push({ element, datasetIndex, index }); } }; evaluateInteractionItems(chart, axis, position, evaluationFunc, true); return items; } function getNearestRadialItems(chart, position, axis, useFinalPosition) { let items = []; function evaluationFunc(element, datasetIndex, index) { const { startAngle , endAngle } = element.getProps([ 'startAngle', 'endAngle' ], useFinalPosition); const { angle } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.D)(element, { x: position.x, y: position.y }); if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.p)(angle, startAngle, endAngle)) { items.push({ element, datasetIndex, index }); } } evaluateInteractionItems(chart, axis, position, evaluationFunc); return items; } function getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition, includeInvisible) { let items = []; const distanceMetric = getDistanceMetricForAxis(axis); let minDistance = Number.POSITIVE_INFINITY; function evaluationFunc(element, datasetIndex, index) { const inRange = element.inRange(position.x, position.y, useFinalPosition); if (intersect && !inRange) { return; } const center = element.getCenterPoint(useFinalPosition); const pointInArea = !!includeInvisible || chart.isPointInArea(center); if (!pointInArea && !inRange) { return; } const distance = distanceMetric(position, center); if (distance < minDistance) { items = [ { element, datasetIndex, index } ]; minDistance = distance; } else if (distance === minDistance) { items.push({ element, datasetIndex, index }); } } evaluateInteractionItems(chart, axis, position, evaluationFunc); return items; } function getNearestItems(chart, position, axis, intersect, useFinalPosition, includeInvisible) { if (!includeInvisible && !chart.isPointInArea(position)) { return []; } return axis === 'r' && !intersect ? getNearestRadialItems(chart, position, axis, useFinalPosition) : getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition, includeInvisible); } function getAxisItems(chart, position, axis, intersect, useFinalPosition) { const items = []; const rangeMethod = axis === 'x' ? 'inXRange' : 'inYRange'; let intersectsItem = false; evaluateInteractionItems(chart, axis, position, (element, datasetIndex, index)=>{ if (element[rangeMethod] && element[rangeMethod](position[axis], useFinalPosition)) { items.push({ element, datasetIndex, index }); intersectsItem = intersectsItem || element.inRange(position.x, position.y, useFinalPosition); } }); if (intersect && !intersectsItem) { return []; } return items; } var Interaction = { evaluateInteractionItems, modes: { index (chart, e, options, useFinalPosition) { const position = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(e, chart); const axis = options.axis || 'x'; const includeInvisible = options.includeInvisible || false; const items = options.intersect ? getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible) : getNearestItems(chart, position, axis, false, useFinalPosition, includeInvisible); const elements = []; if (!items.length) { return []; } chart.getSortedVisibleDatasetMetas().forEach((meta)=>{ const index = items[0].index; const element = meta.data[index]; if (element && !element.skip) { elements.push({ element, datasetIndex: meta.index, index }); } }); return elements; }, dataset (chart, e, options, useFinalPosition) { const position = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(e, chart); const axis = options.axis || 'xy'; const includeInvisible = options.includeInvisible || false; let items = options.intersect ? getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible) : getNearestItems(chart, position, axis, false, useFinalPosition, includeInvisible); if (items.length > 0) { const datasetIndex = items[0].datasetIndex; const data = chart.getDatasetMeta(datasetIndex).data; items = []; for(let i = 0; i < data.length; ++i){ items.push({ element: data[i], datasetIndex, index: i }); } } return items; }, point (chart, e, options, useFinalPosition) { const position = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(e, chart); const axis = options.axis || 'xy'; const includeInvisible = options.includeInvisible || false; return getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible); }, nearest (chart, e, options, useFinalPosition) { const position = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(e, chart); const axis = options.axis || 'xy'; const includeInvisible = options.includeInvisible || false; return getNearestItems(chart, position, axis, options.intersect, useFinalPosition, includeInvisible); }, x (chart, e, options, useFinalPosition) { const position = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(e, chart); return getAxisItems(chart, position, 'x', options.intersect, useFinalPosition); }, y (chart, e, options, useFinalPosition) { const position = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(e, chart); return getAxisItems(chart, position, 'y', options.intersect, useFinalPosition); } } }; const STATIC_POSITIONS = [ 'left', 'top', 'right', 'bottom' ]; function filterByPosition(array, position) { return array.filter((v)=>v.pos === position); } function filterDynamicPositionByAxis(array, axis) { return array.filter((v)=>STATIC_POSITIONS.indexOf(v.pos) === -1 && v.box.axis === axis); } function sortByWeight(array, reverse) { return array.sort((a, b)=>{ const v0 = reverse ? b : a; const v1 = reverse ? a : b; return v0.weight === v1.weight ? v0.index - v1.index : v0.weight - v1.weight; }); } function wrapBoxes(boxes) { const layoutBoxes = []; let i, ilen, box, pos, stack, stackWeight; for(i = 0, ilen = (boxes || []).length; i < ilen; ++i){ box = boxes[i]; ({ position: pos , options: { stack , stackWeight =1 } } = box); layoutBoxes.push({ index: i, box, pos, horizontal: box.isHorizontal(), weight: box.weight, stack: stack && pos + stack, stackWeight }); } return layoutBoxes; } function buildStacks(layouts) { const stacks = {}; for (const wrap of layouts){ const { stack , pos , stackWeight } = wrap; if (!stack || !STATIC_POSITIONS.includes(pos)) { continue; } const _stack = stacks[stack] || (stacks[stack] = { count: 0, placed: 0, weight: 0, size: 0 }); _stack.count++; _stack.weight += stackWeight; } return stacks; } function setLayoutDims(layouts, params) { const stacks = buildStacks(layouts); const { vBoxMaxWidth , hBoxMaxHeight } = params; let i, ilen, layout; for(i = 0, ilen = layouts.length; i < ilen; ++i){ layout = layouts[i]; const { fullSize } = layout.box; const stack = stacks[layout.stack]; const factor = stack && layout.stackWeight / stack.weight; if (layout.horizontal) { layout.width = factor ? factor * vBoxMaxWidth : fullSize && params.availableWidth; layout.height = hBoxMaxHeight; } else { layout.width = vBoxMaxWidth; layout.height = factor ? factor * hBoxMaxHeight : fullSize && params.availableHeight; } } return stacks; } function buildLayoutBoxes(boxes) { const layoutBoxes = wrapBoxes(boxes); const fullSize = sortByWeight(layoutBoxes.filter((wrap)=>wrap.box.fullSize), true); const left = sortByWeight(filterByPosition(layoutBoxes, 'left'), true); const right = sortByWeight(filterByPosition(layoutBoxes, 'right')); const top = sortByWeight(filterByPosition(layoutBoxes, 'top'), true); const bottom = sortByWeight(filterByPosition(layoutBoxes, 'bottom')); const centerHorizontal = filterDynamicPositionByAxis(layoutBoxes, 'x'); const centerVertical = filterDynamicPositionByAxis(layoutBoxes, 'y'); return { fullSize, leftAndTop: left.concat(top), rightAndBottom: right.concat(centerVertical).concat(bottom).concat(centerHorizontal), chartArea: filterByPosition(layoutBoxes, 'chartArea'), vertical: left.concat(right).concat(centerVertical), horizontal: top.concat(bottom).concat(centerHorizontal) }; } function getCombinedMax(maxPadding, chartArea, a, b) { return Math.max(maxPadding[a], chartArea[a]) + Math.max(maxPadding[b], chartArea[b]); } function updateMaxPadding(maxPadding, boxPadding) { maxPadding.top = Math.max(maxPadding.top, boxPadding.top); maxPadding.left = Math.max(maxPadding.left, boxPadding.left); maxPadding.bottom = Math.max(maxPadding.bottom, boxPadding.bottom); maxPadding.right = Math.max(maxPadding.right, boxPadding.right); } function updateDims(chartArea, params, layout, stacks) { const { pos , box } = layout; const maxPadding = chartArea.maxPadding; if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(pos)) { if (layout.size) { chartArea[pos] -= layout.size; } const stack = stacks[layout.stack] || { size: 0, count: 1 }; stack.size = Math.max(stack.size, layout.horizontal ? box.height : box.width); layout.size = stack.size / stack.count; chartArea[pos] += layout.size; } if (box.getPadding) { updateMaxPadding(maxPadding, box.getPadding()); } const newWidth = Math.max(0, params.outerWidth - getCombinedMax(maxPadding, chartArea, 'left', 'right')); const newHeight = Math.max(0, params.outerHeight - getCombinedMax(maxPadding, chartArea, 'top', 'bottom')); const widthChanged = newWidth !== chartArea.w; const heightChanged = newHeight !== chartArea.h; chartArea.w = newWidth; chartArea.h = newHeight; return layout.horizontal ? { same: widthChanged, other: heightChanged } : { same: heightChanged, other: widthChanged }; } function handleMaxPadding(chartArea) { const maxPadding = chartArea.maxPadding; function updatePos(pos) { const change = Math.max(maxPadding[pos] - chartArea[pos], 0); chartArea[pos] += change; return change; } chartArea.y += updatePos('top'); chartArea.x += updatePos('left'); updatePos('right'); updatePos('bottom'); } function getMargins(horizontal, chartArea) { const maxPadding = chartArea.maxPadding; function marginForPositions(positions) { const margin = { left: 0, top: 0, right: 0, bottom: 0 }; positions.forEach((pos)=>{ margin[pos] = Math.max(chartArea[pos], maxPadding[pos]); }); return margin; } return horizontal ? marginForPositions([ 'left', 'right' ]) : marginForPositions([ 'top', 'bottom' ]); } function fitBoxes(boxes, chartArea, params, stacks) { const refitBoxes = []; let i, ilen, layout, box, refit, changed; for(i = 0, ilen = boxes.length, refit = 0; i < ilen; ++i){ layout = boxes[i]; box = layout.box; box.update(layout.width || chartArea.w, layout.height || chartArea.h, getMargins(layout.horizontal, chartArea)); const { same , other } = updateDims(chartArea, params, layout, stacks); refit |= same && refitBoxes.length; changed = changed || other; if (!box.fullSize) { refitBoxes.push(layout); } } return refit && fitBoxes(refitBoxes, chartArea, params, stacks) || changed; } function setBoxDims(box, left, top, width, height) { box.top = top; box.left = left; box.right = left + width; box.bottom = top + height; box.width = width; box.height = height; } function placeBoxes(boxes, chartArea, params, stacks) { const userPadding = params.padding; let { x , y } = chartArea; for (const layout of boxes){ const box = layout.box; const stack = stacks[layout.stack] || { count: 1, placed: 0, weight: 1 }; const weight = layout.stackWeight / stack.weight || 1; if (layout.horizontal) { const width = chartArea.w * weight; const height = stack.size || box.height; if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.h)(stack.start)) { y = stack.start; } if (box.fullSize) { setBoxDims(box, userPadding.left, y, params.outerWidth - userPadding.right - userPadding.left, height); } else { setBoxDims(box, chartArea.left + stack.placed, y, width, height); } stack.start = y; stack.placed += width; y = box.bottom; } else { const height = chartArea.h * weight; const width = stack.size || box.width; if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.h)(stack.start)) { x = stack.start; } if (box.fullSize) { setBoxDims(box, x, userPadding.top, width, params.outerHeight - userPadding.bottom - userPadding.top); } else { setBoxDims(box, x, chartArea.top + stack.placed, width, height); } stack.start = x; stack.placed += height; x = box.right; } } chartArea.x = x; chartArea.y = y; } var layouts = { addBox (chart, item) { if (!chart.boxes) { chart.boxes = []; } item.fullSize = item.fullSize || false; item.position = item.position || 'top'; item.weight = item.weight || 0; item._layers = item._layers || function() { return [ { z: 0, draw (chartArea) { item.draw(chartArea); } } ]; }; chart.boxes.push(item); }, removeBox (chart, layoutItem) { const index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1; if (index !== -1) { chart.boxes.splice(index, 1); } }, configure (chart, item, options) { item.fullSize = options.fullSize; item.position = options.position; item.weight = options.weight; }, update (chart, width, height, minPadding) { if (!chart) { return; } const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(chart.options.layout.padding); const availableWidth = Math.max(width - padding.width, 0); const availableHeight = Math.max(height - padding.height, 0); const boxes = buildLayoutBoxes(chart.boxes); const verticalBoxes = boxes.vertical; const horizontalBoxes = boxes.horizontal; (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(chart.boxes, (box)=>{ if (typeof box.beforeLayout === 'function') { box.beforeLayout(); } }); const visibleVerticalBoxCount = verticalBoxes.reduce((total, wrap)=>wrap.box.options && wrap.box.options.display === false ? total : total + 1, 0) || 1; const params = Object.freeze({ outerWidth: width, outerHeight: height, padding, availableWidth, availableHeight, vBoxMaxWidth: availableWidth / 2 / visibleVerticalBoxCount, hBoxMaxHeight: availableHeight / 2 }); const maxPadding = Object.assign({}, padding); updateMaxPadding(maxPadding, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(minPadding)); const chartArea = Object.assign({ maxPadding, w: availableWidth, h: availableHeight, x: padding.left, y: padding.top }, padding); const stacks = setLayoutDims(verticalBoxes.concat(horizontalBoxes), params); fitBoxes(boxes.fullSize, chartArea, params, stacks); fitBoxes(verticalBoxes, chartArea, params, stacks); if (fitBoxes(horizontalBoxes, chartArea, params, stacks)) { fitBoxes(verticalBoxes, chartArea, params, stacks); } handleMaxPadding(chartArea); placeBoxes(boxes.leftAndTop, chartArea, params, stacks); chartArea.x += chartArea.w; chartArea.y += chartArea.h; placeBoxes(boxes.rightAndBottom, chartArea, params, stacks); chart.chartArea = { left: chartArea.left, top: chartArea.top, right: chartArea.left + chartArea.w, bottom: chartArea.top + chartArea.h, height: chartArea.h, width: chartArea.w }; (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(boxes.chartArea, (layout)=>{ const box = layout.box; Object.assign(box, chart.chartArea); box.update(chartArea.w, chartArea.h, { left: 0, top: 0, right: 0, bottom: 0 }); }); } }; class BasePlatform { acquireContext(canvas, aspectRatio) {} releaseContext(context) { return false; } addEventListener(chart, type, listener) {} removeEventListener(chart, type, listener) {} getDevicePixelRatio() { return 1; } getMaximumSize(element, width, height, aspectRatio) { width = Math.max(0, width || element.width); height = height || element.height; return { width, height: Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height) }; } isAttached(canvas) { return true; } updateConfig(config) { } } class BasicPlatform extends BasePlatform { acquireContext(item) { return item && item.getContext && item.getContext('2d') || null; } updateConfig(config) { config.options.animation = false; } } const EXPANDO_KEY = '$chartjs'; const EVENT_TYPES = { touchstart: 'mousedown', touchmove: 'mousemove', touchend: 'mouseup', pointerenter: 'mouseenter', pointerdown: 'mousedown', pointermove: 'mousemove', pointerup: 'mouseup', pointerleave: 'mouseout', pointerout: 'mouseout' }; const isNullOrEmpty = (value)=>value === null || value === ''; function initCanvas(canvas, aspectRatio) { const style = canvas.style; const renderHeight = canvas.getAttribute('height'); const renderWidth = canvas.getAttribute('width'); canvas[EXPANDO_KEY] = { initial: { height: renderHeight, width: renderWidth, style: { display: style.display, height: style.height, width: style.width } } }; style.display = style.display || 'block'; style.boxSizing = style.boxSizing || 'border-box'; if (isNullOrEmpty(renderWidth)) { const displayWidth = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.J)(canvas, 'width'); if (displayWidth !== undefined) { canvas.width = displayWidth; } } if (isNullOrEmpty(renderHeight)) { if (canvas.style.height === '') { canvas.height = canvas.width / (aspectRatio || 2); } else { const displayHeight = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.J)(canvas, 'height'); if (displayHeight !== undefined) { canvas.height = displayHeight; } } } return canvas; } const eventListenerOptions = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.K ? { passive: true } : false; function addListener(node, type, listener) { if (node) { node.addEventListener(type, listener, eventListenerOptions); } } function removeListener(chart, type, listener) { if (chart && chart.canvas) { chart.canvas.removeEventListener(type, listener, eventListenerOptions); } } function fromNativeEvent(event, chart) { const type = EVENT_TYPES[event.type] || event.type; const { x , y } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.z)(event, chart); return { type, chart, native: event, x: x !== undefined ? x : null, y: y !== undefined ? y : null }; } function nodeListContains(nodeList, canvas) { for (const node of nodeList){ if (node === canvas || node.contains(canvas)) { return true; } } } function createAttachObserver(chart, type, listener) { const canvas = chart.canvas; const observer = new MutationObserver((entries)=>{ let trigger = false; for (const entry of entries){ trigger = trigger || nodeListContains(entry.addedNodes, canvas); trigger = trigger && !nodeListContains(entry.removedNodes, canvas); } if (trigger) { listener(); } }); observer.observe(document, { childList: true, subtree: true }); return observer; } function createDetachObserver(chart, type, listener) { const canvas = chart.canvas; const observer = new MutationObserver((entries)=>{ let trigger = false; for (const entry of entries){ trigger = trigger || nodeListContains(entry.removedNodes, canvas); trigger = trigger && !nodeListContains(entry.addedNodes, canvas); } if (trigger) { listener(); } }); observer.observe(document, { childList: true, subtree: true }); return observer; } const drpListeningCharts = new Map(); let oldDevicePixelRatio = 0; function onWindowResize() { const dpr = window.devicePixelRatio; if (dpr === oldDevicePixelRatio) { return; } oldDevicePixelRatio = dpr; drpListeningCharts.forEach((resize, chart)=>{ if (chart.currentDevicePixelRatio !== dpr) { resize(); } }); } function listenDevicePixelRatioChanges(chart, resize) { if (!drpListeningCharts.size) { window.addEventListener('resize', onWindowResize); } drpListeningCharts.set(chart, resize); } function unlistenDevicePixelRatioChanges(chart) { drpListeningCharts.delete(chart); if (!drpListeningCharts.size) { window.removeEventListener('resize', onWindowResize); } } function createResizeObserver(chart, type, listener) { const canvas = chart.canvas; const container = canvas && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.I)(canvas); if (!container) { return; } const resize = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.L)((width, height)=>{ const w = container.clientWidth; listener(width, height); if (w < container.clientWidth) { listener(); } }, window); const observer = new ResizeObserver((entries)=>{ const entry = entries[0]; const width = entry.contentRect.width; const height = entry.contentRect.height; if (width === 0 && height === 0) { return; } resize(width, height); }); observer.observe(container); listenDevicePixelRatioChanges(chart, resize); return observer; } function releaseObserver(chart, type, observer) { if (observer) { observer.disconnect(); } if (type === 'resize') { unlistenDevicePixelRatioChanges(chart); } } function createProxyAndListen(chart, type, listener) { const canvas = chart.canvas; const proxy = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.L)((event)=>{ if (chart.ctx !== null) { listener(fromNativeEvent(event, chart)); } }, chart); addListener(canvas, type, proxy); return proxy; } class DomPlatform extends BasePlatform { acquireContext(canvas, aspectRatio) { const context = canvas && canvas.getContext && canvas.getContext('2d'); if (context && context.canvas === canvas) { initCanvas(canvas, aspectRatio); return context; } return null; } releaseContext(context) { const canvas = context.canvas; if (!canvas[EXPANDO_KEY]) { return false; } const initial = canvas[EXPANDO_KEY].initial; [ 'height', 'width' ].forEach((prop)=>{ const value = initial[prop]; if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(value)) { canvas.removeAttribute(prop); } else { canvas.setAttribute(prop, value); } }); const style = initial.style || {}; Object.keys(style).forEach((key)=>{ canvas.style[key] = style[key]; }); canvas.width = canvas.width; delete canvas[EXPANDO_KEY]; return true; } addEventListener(chart, type, listener) { this.removeEventListener(chart, type); const proxies = chart.$proxies || (chart.$proxies = {}); const handlers = { attach: createAttachObserver, detach: createDetachObserver, resize: createResizeObserver }; const handler = handlers[type] || createProxyAndListen; proxies[type] = handler(chart, type, listener); } removeEventListener(chart, type) { const proxies = chart.$proxies || (chart.$proxies = {}); const proxy = proxies[type]; if (!proxy) { return; } const handlers = { attach: releaseObserver, detach: releaseObserver, resize: releaseObserver }; const handler = handlers[type] || removeListener; handler(chart, type, proxy); proxies[type] = undefined; } getDevicePixelRatio() { return window.devicePixelRatio; } getMaximumSize(canvas, width, height, aspectRatio) { return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.G)(canvas, width, height, aspectRatio); } isAttached(canvas) { const container = canvas && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.I)(canvas); return !!(container && container.isConnected); } } function _detectPlatform(canvas) { if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.M)() || typeof OffscreenCanvas !== 'undefined' && canvas instanceof OffscreenCanvas) { return BasicPlatform; } return DomPlatform; } class Element { static defaults = {}; static defaultRoutes = undefined; x; y; active = false; options; $animations; tooltipPosition(useFinalPosition) { const { x , y } = this.getProps([ 'x', 'y' ], useFinalPosition); return { x, y }; } hasValue() { return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.x)(this.x) && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.x)(this.y); } getProps(props, final) { const anims = this.$animations; if (!final || !anims) { // let's not create an object, if not needed return this; } const ret = {}; props.forEach((prop)=>{ ret[prop] = anims[prop] && anims[prop].active() ? anims[prop]._to : this[prop]; }); return ret; } } function autoSkip(scale, ticks) { const tickOpts = scale.options.ticks; const determinedMaxTicks = determineMaxTicks(scale); const ticksLimit = Math.min(tickOpts.maxTicksLimit || determinedMaxTicks, determinedMaxTicks); const majorIndices = tickOpts.major.enabled ? getMajorIndices(ticks) : []; const numMajorIndices = majorIndices.length; const first = majorIndices[0]; const last = majorIndices[numMajorIndices - 1]; const newTicks = []; if (numMajorIndices > ticksLimit) { skipMajors(ticks, newTicks, majorIndices, numMajorIndices / ticksLimit); return newTicks; } const spacing = calculateSpacing(majorIndices, ticks, ticksLimit); if (numMajorIndices > 0) { let i, ilen; const avgMajorSpacing = numMajorIndices > 1 ? Math.round((last - first) / (numMajorIndices - 1)) : null; skip(ticks, newTicks, spacing, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(avgMajorSpacing) ? 0 : first - avgMajorSpacing, first); for(i = 0, ilen = numMajorIndices - 1; i < ilen; i++){ skip(ticks, newTicks, spacing, majorIndices[i], majorIndices[i + 1]); } skip(ticks, newTicks, spacing, last, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(avgMajorSpacing) ? ticks.length : last + avgMajorSpacing); return newTicks; } skip(ticks, newTicks, spacing); return newTicks; } function determineMaxTicks(scale) { const offset = scale.options.offset; const tickLength = scale._tickSize(); const maxScale = scale._length / tickLength + (offset ? 0 : 1); const maxChart = scale._maxLength / tickLength; return Math.floor(Math.min(maxScale, maxChart)); } function calculateSpacing(majorIndices, ticks, ticksLimit) { const evenMajorSpacing = getEvenSpacing(majorIndices); const spacing = ticks.length / ticksLimit; if (!evenMajorSpacing) { return Math.max(spacing, 1); } const factors = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.N)(evenMajorSpacing); for(let i = 0, ilen = factors.length - 1; i < ilen; i++){ const factor = factors[i]; if (factor > spacing) { return factor; } } return Math.max(spacing, 1); } function getMajorIndices(ticks) { const result = []; let i, ilen; for(i = 0, ilen = ticks.length; i < ilen; i++){ if (ticks[i].major) { result.push(i); } } return result; } function skipMajors(ticks, newTicks, majorIndices, spacing) { let count = 0; let next = majorIndices[0]; let i; spacing = Math.ceil(spacing); for(i = 0; i < ticks.length; i++){ if (i === next) { newTicks.push(ticks[i]); count++; next = majorIndices[count * spacing]; } } } function skip(ticks, newTicks, spacing, majorStart, majorEnd) { const start = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(majorStart, 0); const end = Math.min((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(majorEnd, ticks.length), ticks.length); let count = 0; let length, i, next; spacing = Math.ceil(spacing); if (majorEnd) { length = majorEnd - majorStart; spacing = length / Math.floor(length / spacing); } next = start; while(next < 0){ count++; next = Math.round(start + count * spacing); } for(i = Math.max(start, 0); i < end; i++){ if (i === next) { newTicks.push(ticks[i]); count++; next = Math.round(start + count * spacing); } } } function getEvenSpacing(arr) { const len = arr.length; let i, diff; if (len < 2) { return false; } for(diff = arr[0], i = 1; i < len; ++i){ if (arr[i] - arr[i - 1] !== diff) { return false; } } return diff; } const reverseAlign = (align)=>align === 'left' ? 'right' : align === 'right' ? 'left' : align; const offsetFromEdge = (scale, edge, offset)=>edge === 'top' || edge === 'left' ? scale[edge] + offset : scale[edge] - offset; const getTicksLimit = (ticksLength, maxTicksLimit)=>Math.min(maxTicksLimit || ticksLength, ticksLength); function sample(arr, numItems) { const result = []; const increment = arr.length / numItems; const len = arr.length; let i = 0; for(; i < len; i += increment){ result.push(arr[Math.floor(i)]); } return result; } function getPixelForGridLine(scale, index, offsetGridLines) { const length = scale.ticks.length; const validIndex = Math.min(index, length - 1); const start = scale._startPixel; const end = scale._endPixel; const epsilon = 1e-6; let lineValue = scale.getPixelForTick(validIndex); let offset; if (offsetGridLines) { if (length === 1) { offset = Math.max(lineValue - start, end - lineValue); } else if (index === 0) { offset = (scale.getPixelForTick(1) - lineValue) / 2; } else { offset = (lineValue - scale.getPixelForTick(validIndex - 1)) / 2; } lineValue += validIndex < index ? offset : -offset; if (lineValue < start - epsilon || lineValue > end + epsilon) { return; } } return lineValue; } function garbageCollect(caches, length) { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(caches, (cache)=>{ const gc = cache.gc; const gcLen = gc.length / 2; let i; if (gcLen > length) { for(i = 0; i < gcLen; ++i){ delete cache.data[gc[i]]; } gc.splice(0, gcLen); } }); } function getTickMarkLength(options) { return options.drawTicks ? options.tickLength : 0; } function getTitleHeight(options, fallback) { if (!options.display) { return 0; } const font = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.font, fallback); const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(options.padding); const lines = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(options.text) ? options.text.length : 1; return lines * font.lineHeight + padding.height; } function createScaleContext(parent, scale) { return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(parent, { scale, type: 'scale' }); } function createTickContext(parent, index, tick) { return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(parent, { tick, index, type: 'tick' }); } function titleAlign(align, position, reverse) { let ret = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a1)(align); if (reverse && position !== 'right' || !reverse && position === 'right') { ret = reverseAlign(ret); } return ret; } function titleArgs(scale, offset, position, align) { const { top , left , bottom , right , chart } = scale; const { chartArea , scales } = chart; let rotation = 0; let maxWidth, titleX, titleY; const height = bottom - top; const width = right - left; if (scale.isHorizontal()) { titleX = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, left, right); if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) { const positionAxisID = Object.keys(position)[0]; const value = position[positionAxisID]; titleY = scales[positionAxisID].getPixelForValue(value) + height - offset; } else if (position === 'center') { titleY = (chartArea.bottom + chartArea.top) / 2 + height - offset; } else { titleY = offsetFromEdge(scale, position, offset); } maxWidth = right - left; } else { if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) { const positionAxisID = Object.keys(position)[0]; const value = position[positionAxisID]; titleX = scales[positionAxisID].getPixelForValue(value) - width + offset; } else if (position === 'center') { titleX = (chartArea.left + chartArea.right) / 2 - width + offset; } else { titleX = offsetFromEdge(scale, position, offset); } titleY = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, bottom, top); rotation = position === 'left' ? -_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H : _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H; } return { titleX, titleY, maxWidth, rotation }; } class Scale extends Element { constructor(cfg){ super(); this.id = cfg.id; this.type = cfg.type; this.options = undefined; this.ctx = cfg.ctx; this.chart = cfg.chart; this.top = undefined; this.bottom = undefined; this.left = undefined; this.right = undefined; this.width = undefined; this.height = undefined; this._margins = { left: 0, right: 0, top: 0, bottom: 0 }; this.maxWidth = undefined; this.maxHeight = undefined; this.paddingTop = undefined; this.paddingBottom = undefined; this.paddingLeft = undefined; this.paddingRight = undefined; this.axis = undefined; this.labelRotation = undefined; this.min = undefined; this.max = undefined; this._range = undefined; this.ticks = []; this._gridLineItems = null; this._labelItems = null; this._labelSizes = null; this._length = 0; this._maxLength = 0; this._longestTextCache = {}; this._startPixel = undefined; this._endPixel = undefined; this._reversePixels = false; this._userMax = undefined; this._userMin = undefined; this._suggestedMax = undefined; this._suggestedMin = undefined; this._ticksLength = 0; this._borderValue = 0; this._cache = {}; this._dataLimitsCached = false; this.$context = undefined; } init(options) { this.options = options.setContext(this.getContext()); this.axis = options.axis; this._userMin = this.parse(options.min); this._userMax = this.parse(options.max); this._suggestedMin = this.parse(options.suggestedMin); this._suggestedMax = this.parse(options.suggestedMax); } parse(raw, index) { return raw; } getUserBounds() { let { _userMin , _userMax , _suggestedMin , _suggestedMax } = this; _userMin = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(_userMin, Number.POSITIVE_INFINITY); _userMax = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(_userMax, Number.NEGATIVE_INFINITY); _suggestedMin = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(_suggestedMin, Number.POSITIVE_INFINITY); _suggestedMax = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(_suggestedMax, Number.NEGATIVE_INFINITY); return { min: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(_userMin, _suggestedMin), max: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(_userMax, _suggestedMax), minDefined: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(_userMin), maxDefined: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(_userMax) }; } getMinMax(canStack) { let { min , max , minDefined , maxDefined } = this.getUserBounds(); let range; if (minDefined && maxDefined) { return { min, max }; } const metas = this.getMatchingVisibleMetas(); for(let i = 0, ilen = metas.length; i < ilen; ++i){ range = metas[i].controller.getMinMax(this, canStack); if (!minDefined) { min = Math.min(min, range.min); } if (!maxDefined) { max = Math.max(max, range.max); } } min = maxDefined && min > max ? max : min; max = minDefined && min > max ? min : max; return { min: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(min, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(max, min)), max: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(max, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(min, max)) }; } getPadding() { return { left: this.paddingLeft || 0, top: this.paddingTop || 0, right: this.paddingRight || 0, bottom: this.paddingBottom || 0 }; } getTicks() { return this.ticks; } getLabels() { const data = this.chart.data; return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels || []; } getLabelItems(chartArea = this.chart.chartArea) { const items = this._labelItems || (this._labelItems = this._computeLabelItems(chartArea)); return items; } beforeLayout() { this._cache = {}; this._dataLimitsCached = false; } beforeUpdate() { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.beforeUpdate, [ this ]); } update(maxWidth, maxHeight, margins) { const { beginAtZero , grace , ticks: tickOpts } = this.options; const sampleSize = tickOpts.sampleSize; this.beforeUpdate(); this.maxWidth = maxWidth; this.maxHeight = maxHeight; this._margins = margins = Object.assign({ left: 0, right: 0, top: 0, bottom: 0 }, margins); this.ticks = null; this._labelSizes = null; this._gridLineItems = null; this._labelItems = null; this.beforeSetDimensions(); this.setDimensions(); this.afterSetDimensions(); this._maxLength = this.isHorizontal() ? this.width + margins.left + margins.right : this.height + margins.top + margins.bottom; if (!this._dataLimitsCached) { this.beforeDataLimits(); this.determineDataLimits(); this.afterDataLimits(); this._range = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.R)(this, grace, beginAtZero); this._dataLimitsCached = true; } this.beforeBuildTicks(); this.ticks = this.buildTicks() || []; this.afterBuildTicks(); const samplingEnabled = sampleSize < this.ticks.length; this._convertTicksToLabels(samplingEnabled ? sample(this.ticks, sampleSize) : this.ticks); this.configure(); this.beforeCalculateLabelRotation(); this.calculateLabelRotation(); this.afterCalculateLabelRotation(); if (tickOpts.display && (tickOpts.autoSkip || tickOpts.source === 'auto')) { this.ticks = autoSkip(this, this.ticks); this._labelSizes = null; this.afterAutoSkip(); } if (samplingEnabled) { this._convertTicksToLabels(this.ticks); } this.beforeFit(); this.fit(); this.afterFit(); this.afterUpdate(); } configure() { let reversePixels = this.options.reverse; let startPixel, endPixel; if (this.isHorizontal()) { startPixel = this.left; endPixel = this.right; } else { startPixel = this.top; endPixel = this.bottom; reversePixels = !reversePixels; } this._startPixel = startPixel; this._endPixel = endPixel; this._reversePixels = reversePixels; this._length = endPixel - startPixel; this._alignToPixels = this.options.alignToPixels; } afterUpdate() { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.afterUpdate, [ this ]); } beforeSetDimensions() { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.beforeSetDimensions, [ this ]); } setDimensions() { if (this.isHorizontal()) { this.width = this.maxWidth; this.left = 0; this.right = this.width; } else { this.height = this.maxHeight; this.top = 0; this.bottom = this.height; } this.paddingLeft = 0; this.paddingTop = 0; this.paddingRight = 0; this.paddingBottom = 0; } afterSetDimensions() { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.afterSetDimensions, [ this ]); } _callHooks(name) { this.chart.notifyPlugins(name, this.getContext()); (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options[name], [ this ]); } beforeDataLimits() { this._callHooks('beforeDataLimits'); } determineDataLimits() {} afterDataLimits() { this._callHooks('afterDataLimits'); } beforeBuildTicks() { this._callHooks('beforeBuildTicks'); } buildTicks() { return []; } afterBuildTicks() { this._callHooks('afterBuildTicks'); } beforeTickToLabelConversion() { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.beforeTickToLabelConversion, [ this ]); } generateTickLabels(ticks) { const tickOpts = this.options.ticks; let i, ilen, tick; for(i = 0, ilen = ticks.length; i < ilen; i++){ tick = ticks[i]; tick.label = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(tickOpts.callback, [ tick.value, i, ticks ], this); } } afterTickToLabelConversion() { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.afterTickToLabelConversion, [ this ]); } beforeCalculateLabelRotation() { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.beforeCalculateLabelRotation, [ this ]); } calculateLabelRotation() { const options = this.options; const tickOpts = options.ticks; const numTicks = getTicksLimit(this.ticks.length, options.ticks.maxTicksLimit); const minRotation = tickOpts.minRotation || 0; const maxRotation = tickOpts.maxRotation; let labelRotation = minRotation; let tickWidth, maxHeight, maxLabelDiagonal; if (!this._isVisible() || !tickOpts.display || minRotation >= maxRotation || numTicks <= 1 || !this.isHorizontal()) { this.labelRotation = minRotation; return; } const labelSizes = this._getLabelSizes(); const maxLabelWidth = labelSizes.widest.width; const maxLabelHeight = labelSizes.highest.height; const maxWidth = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(this.chart.width - maxLabelWidth, 0, this.maxWidth); tickWidth = options.offset ? this.maxWidth / numTicks : maxWidth / (numTicks - 1); if (maxLabelWidth + 6 > tickWidth) { tickWidth = maxWidth / (numTicks - (options.offset ? 0.5 : 1)); maxHeight = this.maxHeight - getTickMarkLength(options.grid) - tickOpts.padding - getTitleHeight(options.title, this.chart.options.font); maxLabelDiagonal = Math.sqrt(maxLabelWidth * maxLabelWidth + maxLabelHeight * maxLabelHeight); labelRotation = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.U)(Math.min(Math.asin((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)((labelSizes.highest.height + 6) / tickWidth, -1, 1)), Math.asin((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(maxHeight / maxLabelDiagonal, -1, 1)) - Math.asin((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(maxLabelHeight / maxLabelDiagonal, -1, 1)))); labelRotation = Math.max(minRotation, Math.min(maxRotation, labelRotation)); } this.labelRotation = labelRotation; } afterCalculateLabelRotation() { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.afterCalculateLabelRotation, [ this ]); } afterAutoSkip() {} beforeFit() { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.beforeFit, [ this ]); } fit() { const minSize = { width: 0, height: 0 }; const { chart , options: { ticks: tickOpts , title: titleOpts , grid: gridOpts } } = this; const display = this._isVisible(); const isHorizontal = this.isHorizontal(); if (display) { const titleHeight = getTitleHeight(titleOpts, chart.options.font); if (isHorizontal) { minSize.width = this.maxWidth; minSize.height = getTickMarkLength(gridOpts) + titleHeight; } else { minSize.height = this.maxHeight; minSize.width = getTickMarkLength(gridOpts) + titleHeight; } if (tickOpts.display && this.ticks.length) { const { first , last , widest , highest } = this._getLabelSizes(); const tickPadding = tickOpts.padding * 2; const angleRadians = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.labelRotation); const cos = Math.cos(angleRadians); const sin = Math.sin(angleRadians); if (isHorizontal) { const labelHeight = tickOpts.mirror ? 0 : sin * widest.width + cos * highest.height; minSize.height = Math.min(this.maxHeight, minSize.height + labelHeight + tickPadding); } else { const labelWidth = tickOpts.mirror ? 0 : cos * widest.width + sin * highest.height; minSize.width = Math.min(this.maxWidth, minSize.width + labelWidth + tickPadding); } this._calculatePadding(first, last, sin, cos); } } this._handleMargins(); if (isHorizontal) { this.width = this._length = chart.width - this._margins.left - this._margins.right; this.height = minSize.height; } else { this.width = minSize.width; this.height = this._length = chart.height - this._margins.top - this._margins.bottom; } } _calculatePadding(first, last, sin, cos) { const { ticks: { align , padding } , position } = this.options; const isRotated = this.labelRotation !== 0; const labelsBelowTicks = position !== 'top' && this.axis === 'x'; if (this.isHorizontal()) { const offsetLeft = this.getPixelForTick(0) - this.left; const offsetRight = this.right - this.getPixelForTick(this.ticks.length - 1); let paddingLeft = 0; let paddingRight = 0; if (isRotated) { if (labelsBelowTicks) { paddingLeft = cos * first.width; paddingRight = sin * last.height; } else { paddingLeft = sin * first.height; paddingRight = cos * last.width; } } else if (align === 'start') { paddingRight = last.width; } else if (align === 'end') { paddingLeft = first.width; } else if (align !== 'inner') { paddingLeft = first.width / 2; paddingRight = last.width / 2; } this.paddingLeft = Math.max((paddingLeft - offsetLeft + padding) * this.width / (this.width - offsetLeft), 0); this.paddingRight = Math.max((paddingRight - offsetRight + padding) * this.width / (this.width - offsetRight), 0); } else { let paddingTop = last.height / 2; let paddingBottom = first.height / 2; if (align === 'start') { paddingTop = 0; paddingBottom = first.height; } else if (align === 'end') { paddingTop = last.height; paddingBottom = 0; } this.paddingTop = paddingTop + padding; this.paddingBottom = paddingBottom + padding; } } _handleMargins() { if (this._margins) { this._margins.left = Math.max(this.paddingLeft, this._margins.left); this._margins.top = Math.max(this.paddingTop, this._margins.top); this._margins.right = Math.max(this.paddingRight, this._margins.right); this._margins.bottom = Math.max(this.paddingBottom, this._margins.bottom); } } afterFit() { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.afterFit, [ this ]); } isHorizontal() { const { axis , position } = this.options; return position === 'top' || position === 'bottom' || axis === 'x'; } isFullSize() { return this.options.fullSize; } _convertTicksToLabels(ticks) { this.beforeTickToLabelConversion(); this.generateTickLabels(ticks); let i, ilen; for(i = 0, ilen = ticks.length; i < ilen; i++){ if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(ticks[i].label)) { ticks.splice(i, 1); ilen--; i--; } } this.afterTickToLabelConversion(); } _getLabelSizes() { let labelSizes = this._labelSizes; if (!labelSizes) { const sampleSize = this.options.ticks.sampleSize; let ticks = this.ticks; if (sampleSize < ticks.length) { ticks = sample(ticks, sampleSize); } this._labelSizes = labelSizes = this._computeLabelSizes(ticks, ticks.length, this.options.ticks.maxTicksLimit); } return labelSizes; } _computeLabelSizes(ticks, length, maxTicksLimit) { const { ctx , _longestTextCache: caches } = this; const widths = []; const heights = []; const increment = Math.floor(length / getTicksLimit(length, maxTicksLimit)); let widestLabelSize = 0; let highestLabelSize = 0; let i, j, jlen, label, tickFont, fontString, cache, lineHeight, width, height, nestedLabel; for(i = 0; i < length; i += increment){ label = ticks[i].label; tickFont = this._resolveTickFontOptions(i); ctx.font = fontString = tickFont.string; cache = caches[fontString] = caches[fontString] || { data: {}, gc: [] }; lineHeight = tickFont.lineHeight; width = height = 0; if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(label) && !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(label)) { width = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.V)(ctx, cache.data, cache.gc, width, label); height = lineHeight; } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(label)) { for(j = 0, jlen = label.length; j < jlen; ++j){ nestedLabel = label[j]; if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(nestedLabel) && !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(nestedLabel)) { width = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.V)(ctx, cache.data, cache.gc, width, nestedLabel); height += lineHeight; } } } widths.push(width); heights.push(height); widestLabelSize = Math.max(width, widestLabelSize); highestLabelSize = Math.max(height, highestLabelSize); } garbageCollect(caches, length); const widest = widths.indexOf(widestLabelSize); const highest = heights.indexOf(highestLabelSize); const valueAt = (idx)=>({ width: widths[idx] || 0, height: heights[idx] || 0 }); return { first: valueAt(0), last: valueAt(length - 1), widest: valueAt(widest), highest: valueAt(highest), widths, heights }; } getLabelForValue(value) { return value; } getPixelForValue(value, index) { return NaN; } getValueForPixel(pixel) {} getPixelForTick(index) { const ticks = this.ticks; if (index < 0 || index > ticks.length - 1) { return null; } return this.getPixelForValue(ticks[index].value); } getPixelForDecimal(decimal) { if (this._reversePixels) { decimal = 1 - decimal; } const pixel = this._startPixel + decimal * this._length; return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.W)(this._alignToPixels ? (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(this.chart, pixel, 0) : pixel); } getDecimalForPixel(pixel) { const decimal = (pixel - this._startPixel) / this._length; return this._reversePixels ? 1 - decimal : decimal; } getBasePixel() { return this.getPixelForValue(this.getBaseValue()); } getBaseValue() { const { min , max } = this; return min < 0 && max < 0 ? max : min > 0 && max > 0 ? min : 0; } getContext(index) { const ticks = this.ticks || []; if (index >= 0 && index < ticks.length) { const tick = ticks[index]; return tick.$context || (tick.$context = createTickContext(this.getContext(), index, tick)); } return this.$context || (this.$context = createScaleContext(this.chart.getContext(), this)); } _tickSize() { const optionTicks = this.options.ticks; const rot = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.labelRotation); const cos = Math.abs(Math.cos(rot)); const sin = Math.abs(Math.sin(rot)); const labelSizes = this._getLabelSizes(); const padding = optionTicks.autoSkipPadding || 0; const w = labelSizes ? labelSizes.widest.width + padding : 0; const h = labelSizes ? labelSizes.highest.height + padding : 0; return this.isHorizontal() ? h * cos > w * sin ? w / cos : h / sin : h * sin < w * cos ? h / cos : w / sin; } _isVisible() { const display = this.options.display; if (display !== 'auto') { return !!display; } return this.getMatchingVisibleMetas().length > 0; } _computeGridLineItems(chartArea) { const axis = this.axis; const chart = this.chart; const options = this.options; const { grid , position , border } = options; const offset = grid.offset; const isHorizontal = this.isHorizontal(); const ticks = this.ticks; const ticksLength = ticks.length + (offset ? 1 : 0); const tl = getTickMarkLength(grid); const items = []; const borderOpts = border.setContext(this.getContext()); const axisWidth = borderOpts.display ? borderOpts.width : 0; const axisHalfWidth = axisWidth / 2; const alignBorderValue = function(pixel) { return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(chart, pixel, axisWidth); }; let borderValue, i, lineValue, alignedLineValue; let tx1, ty1, tx2, ty2, x1, y1, x2, y2; if (position === 'top') { borderValue = alignBorderValue(this.bottom); ty1 = this.bottom - tl; ty2 = borderValue - axisHalfWidth; y1 = alignBorderValue(chartArea.top) + axisHalfWidth; y2 = chartArea.bottom; } else if (position === 'bottom') { borderValue = alignBorderValue(this.top); y1 = chartArea.top; y2 = alignBorderValue(chartArea.bottom) - axisHalfWidth; ty1 = borderValue + axisHalfWidth; ty2 = this.top + tl; } else if (position === 'left') { borderValue = alignBorderValue(this.right); tx1 = this.right - tl; tx2 = borderValue - axisHalfWidth; x1 = alignBorderValue(chartArea.left) + axisHalfWidth; x2 = chartArea.right; } else if (position === 'right') { borderValue = alignBorderValue(this.left); x1 = chartArea.left; x2 = alignBorderValue(chartArea.right) - axisHalfWidth; tx1 = borderValue + axisHalfWidth; tx2 = this.left + tl; } else if (axis === 'x') { if (position === 'center') { borderValue = alignBorderValue((chartArea.top + chartArea.bottom) / 2 + 0.5); } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) { const positionAxisID = Object.keys(position)[0]; const value = position[positionAxisID]; borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value)); } y1 = chartArea.top; y2 = chartArea.bottom; ty1 = borderValue + axisHalfWidth; ty2 = ty1 + tl; } else if (axis === 'y') { if (position === 'center') { borderValue = alignBorderValue((chartArea.left + chartArea.right) / 2); } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) { const positionAxisID = Object.keys(position)[0]; const value = position[positionAxisID]; borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value)); } tx1 = borderValue - axisHalfWidth; tx2 = tx1 - tl; x1 = chartArea.left; x2 = chartArea.right; } const limit = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(options.ticks.maxTicksLimit, ticksLength); const step = Math.max(1, Math.ceil(ticksLength / limit)); for(i = 0; i < ticksLength; i += step){ const context = this.getContext(i); const optsAtIndex = grid.setContext(context); const optsAtIndexBorder = border.setContext(context); const lineWidth = optsAtIndex.lineWidth; const lineColor = optsAtIndex.color; const borderDash = optsAtIndexBorder.dash || []; const borderDashOffset = optsAtIndexBorder.dashOffset; const tickWidth = optsAtIndex.tickWidth; const tickColor = optsAtIndex.tickColor; const tickBorderDash = optsAtIndex.tickBorderDash || []; const tickBorderDashOffset = optsAtIndex.tickBorderDashOffset; lineValue = getPixelForGridLine(this, i, offset); if (lineValue === undefined) { continue; } alignedLineValue = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(chart, lineValue, lineWidth); if (isHorizontal) { tx1 = tx2 = x1 = x2 = alignedLineValue; } else { ty1 = ty2 = y1 = y2 = alignedLineValue; } items.push({ tx1, ty1, tx2, ty2, x1, y1, x2, y2, width: lineWidth, color: lineColor, borderDash, borderDashOffset, tickWidth, tickColor, tickBorderDash, tickBorderDashOffset }); } this._ticksLength = ticksLength; this._borderValue = borderValue; return items; } _computeLabelItems(chartArea) { const axis = this.axis; const options = this.options; const { position , ticks: optionTicks } = options; const isHorizontal = this.isHorizontal(); const ticks = this.ticks; const { align , crossAlign , padding , mirror } = optionTicks; const tl = getTickMarkLength(options.grid); const tickAndPadding = tl + padding; const hTickAndPadding = mirror ? -padding : tickAndPadding; const rotation = -(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.labelRotation); const items = []; let i, ilen, tick, label, x, y, textAlign, pixel, font, lineHeight, lineCount, textOffset; let textBaseline = 'middle'; if (position === 'top') { y = this.bottom - hTickAndPadding; textAlign = this._getXAxisLabelAlignment(); } else if (position === 'bottom') { y = this.top + hTickAndPadding; textAlign = this._getXAxisLabelAlignment(); } else if (position === 'left') { const ret = this._getYAxisLabelAlignment(tl); textAlign = ret.textAlign; x = ret.x; } else if (position === 'right') { const ret = this._getYAxisLabelAlignment(tl); textAlign = ret.textAlign; x = ret.x; } else if (axis === 'x') { if (position === 'center') { y = (chartArea.top + chartArea.bottom) / 2 + tickAndPadding; } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) { const positionAxisID = Object.keys(position)[0]; const value = position[positionAxisID]; y = this.chart.scales[positionAxisID].getPixelForValue(value) + tickAndPadding; } textAlign = this._getXAxisLabelAlignment(); } else if (axis === 'y') { if (position === 'center') { x = (chartArea.left + chartArea.right) / 2 - tickAndPadding; } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) { const positionAxisID = Object.keys(position)[0]; const value = position[positionAxisID]; x = this.chart.scales[positionAxisID].getPixelForValue(value); } textAlign = this._getYAxisLabelAlignment(tl).textAlign; } if (axis === 'y') { if (align === 'start') { textBaseline = 'top'; } else if (align === 'end') { textBaseline = 'bottom'; } } const labelSizes = this._getLabelSizes(); for(i = 0, ilen = ticks.length; i < ilen; ++i){ tick = ticks[i]; label = tick.label; const optsAtIndex = optionTicks.setContext(this.getContext(i)); pixel = this.getPixelForTick(i) + optionTicks.labelOffset; font = this._resolveTickFontOptions(i); lineHeight = font.lineHeight; lineCount = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(label) ? label.length : 1; const halfCount = lineCount / 2; const color = optsAtIndex.color; const strokeColor = optsAtIndex.textStrokeColor; const strokeWidth = optsAtIndex.textStrokeWidth; let tickTextAlign = textAlign; if (isHorizontal) { x = pixel; if (textAlign === 'inner') { if (i === ilen - 1) { tickTextAlign = !this.options.reverse ? 'right' : 'left'; } else if (i === 0) { tickTextAlign = !this.options.reverse ? 'left' : 'right'; } else { tickTextAlign = 'center'; } } if (position === 'top') { if (crossAlign === 'near' || rotation !== 0) { textOffset = -lineCount * lineHeight + lineHeight / 2; } else if (crossAlign === 'center') { textOffset = -labelSizes.highest.height / 2 - halfCount * lineHeight + lineHeight; } else { textOffset = -labelSizes.highest.height + lineHeight / 2; } } else { if (crossAlign === 'near' || rotation !== 0) { textOffset = lineHeight / 2; } else if (crossAlign === 'center') { textOffset = labelSizes.highest.height / 2 - halfCount * lineHeight; } else { textOffset = labelSizes.highest.height - lineCount * lineHeight; } } if (mirror) { textOffset *= -1; } if (rotation !== 0 && !optsAtIndex.showLabelBackdrop) { x += lineHeight / 2 * Math.sin(rotation); } } else { y = pixel; textOffset = (1 - lineCount) * lineHeight / 2; } let backdrop; if (optsAtIndex.showLabelBackdrop) { const labelPadding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(optsAtIndex.backdropPadding); const height = labelSizes.heights[i]; const width = labelSizes.widths[i]; let top = textOffset - labelPadding.top; let left = 0 - labelPadding.left; switch(textBaseline){ case 'middle': top -= height / 2; break; case 'bottom': top -= height; break; } switch(textAlign){ case 'center': left -= width / 2; break; case 'right': left -= width; break; case 'inner': if (i === ilen - 1) { left -= width; } else if (i > 0) { left -= width / 2; } break; } backdrop = { left, top, width: width + labelPadding.width, height: height + labelPadding.height, color: optsAtIndex.backdropColor }; } items.push({ label, font, textOffset, options: { rotation, color, strokeColor, strokeWidth, textAlign: tickTextAlign, textBaseline, translation: [ x, y ], backdrop } }); } return items; } _getXAxisLabelAlignment() { const { position , ticks } = this.options; const rotation = -(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.labelRotation); if (rotation) { return position === 'top' ? 'left' : 'right'; } let align = 'center'; if (ticks.align === 'start') { align = 'left'; } else if (ticks.align === 'end') { align = 'right'; } else if (ticks.align === 'inner') { align = 'inner'; } return align; } _getYAxisLabelAlignment(tl) { const { position , ticks: { crossAlign , mirror , padding } } = this.options; const labelSizes = this._getLabelSizes(); const tickAndPadding = tl + padding; const widest = labelSizes.widest.width; let textAlign; let x; if (position === 'left') { if (mirror) { x = this.right + padding; if (crossAlign === 'near') { textAlign = 'left'; } else if (crossAlign === 'center') { textAlign = 'center'; x += widest / 2; } else { textAlign = 'right'; x += widest; } } else { x = this.right - tickAndPadding; if (crossAlign === 'near') { textAlign = 'right'; } else if (crossAlign === 'center') { textAlign = 'center'; x -= widest / 2; } else { textAlign = 'left'; x = this.left; } } } else if (position === 'right') { if (mirror) { x = this.left + padding; if (crossAlign === 'near') { textAlign = 'right'; } else if (crossAlign === 'center') { textAlign = 'center'; x -= widest / 2; } else { textAlign = 'left'; x -= widest; } } else { x = this.left + tickAndPadding; if (crossAlign === 'near') { textAlign = 'left'; } else if (crossAlign === 'center') { textAlign = 'center'; x += widest / 2; } else { textAlign = 'right'; x = this.right; } } } else { textAlign = 'right'; } return { textAlign, x }; } _computeLabelArea() { if (this.options.ticks.mirror) { return; } const chart = this.chart; const position = this.options.position; if (position === 'left' || position === 'right') { return { top: 0, left: this.left, bottom: chart.height, right: this.right }; } if (position === 'top' || position === 'bottom') { return { top: this.top, left: 0, bottom: this.bottom, right: chart.width }; } } drawBackground() { const { ctx , options: { backgroundColor } , left , top , width , height } = this; if (backgroundColor) { ctx.save(); ctx.fillStyle = backgroundColor; ctx.fillRect(left, top, width, height); ctx.restore(); } } getLineWidthForValue(value) { const grid = this.options.grid; if (!this._isVisible() || !grid.display) { return 0; } const ticks = this.ticks; const index = ticks.findIndex((t)=>t.value === value); if (index >= 0) { const opts = grid.setContext(this.getContext(index)); return opts.lineWidth; } return 0; } drawGrid(chartArea) { const grid = this.options.grid; const ctx = this.ctx; const items = this._gridLineItems || (this._gridLineItems = this._computeGridLineItems(chartArea)); let i, ilen; const drawLine = (p1, p2, style)=>{ if (!style.width || !style.color) { return; } ctx.save(); ctx.lineWidth = style.width; ctx.strokeStyle = style.color; ctx.setLineDash(style.borderDash || []); ctx.lineDashOffset = style.borderDashOffset; ctx.beginPath(); ctx.moveTo(p1.x, p1.y); ctx.lineTo(p2.x, p2.y); ctx.stroke(); ctx.restore(); }; if (grid.display) { for(i = 0, ilen = items.length; i < ilen; ++i){ const item = items[i]; if (grid.drawOnChartArea) { drawLine({ x: item.x1, y: item.y1 }, { x: item.x2, y: item.y2 }, item); } if (grid.drawTicks) { drawLine({ x: item.tx1, y: item.ty1 }, { x: item.tx2, y: item.ty2 }, { color: item.tickColor, width: item.tickWidth, borderDash: item.tickBorderDash, borderDashOffset: item.tickBorderDashOffset }); } } } } drawBorder() { const { chart , ctx , options: { border , grid } } = this; const borderOpts = border.setContext(this.getContext()); const axisWidth = border.display ? borderOpts.width : 0; if (!axisWidth) { return; } const lastLineWidth = grid.setContext(this.getContext(0)).lineWidth; const borderValue = this._borderValue; let x1, x2, y1, y2; if (this.isHorizontal()) { x1 = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(chart, this.left, axisWidth) - axisWidth / 2; x2 = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(chart, this.right, lastLineWidth) + lastLineWidth / 2; y1 = y2 = borderValue; } else { y1 = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(chart, this.top, axisWidth) - axisWidth / 2; y2 = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.X)(chart, this.bottom, lastLineWidth) + lastLineWidth / 2; x1 = x2 = borderValue; } ctx.save(); ctx.lineWidth = borderOpts.width; ctx.strokeStyle = borderOpts.color; ctx.beginPath(); ctx.moveTo(x1, y1); ctx.lineTo(x2, y2); ctx.stroke(); ctx.restore(); } drawLabels(chartArea) { const optionTicks = this.options.ticks; if (!optionTicks.display) { return; } const ctx = this.ctx; const area = this._computeLabelArea(); if (area) { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Y)(ctx, area); } const items = this.getLabelItems(chartArea); for (const item of items){ const renderTextOptions = item.options; const tickFont = item.font; const label = item.label; const y = item.textOffset; (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, label, 0, y, tickFont, renderTextOptions); } if (area) { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.$)(ctx); } } drawTitle() { const { ctx , options: { position , title , reverse } } = this; if (!title.display) { return; } const font = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(title.font); const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(title.padding); const align = title.align; let offset = font.lineHeight / 2; if (position === 'bottom' || position === 'center' || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(position)) { offset += padding.bottom; if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(title.text)) { offset += font.lineHeight * (title.text.length - 1); } } else { offset += padding.top; } const { titleX , titleY , maxWidth , rotation } = titleArgs(this, offset, position, align); (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, title.text, 0, 0, font, { color: title.color, maxWidth, rotation, textAlign: titleAlign(align, position, reverse), textBaseline: 'middle', translation: [ titleX, titleY ] }); } draw(chartArea) { if (!this._isVisible()) { return; } this.drawBackground(); this.drawGrid(chartArea); this.drawBorder(); this.drawTitle(); this.drawLabels(chartArea); } _layers() { const opts = this.options; const tz = opts.ticks && opts.ticks.z || 0; const gz = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(opts.grid && opts.grid.z, -1); const bz = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(opts.border && opts.border.z, 0); if (!this._isVisible() || this.draw !== Scale.prototype.draw) { return [ { z: tz, draw: (chartArea)=>{ this.draw(chartArea); } } ]; } return [ { z: gz, draw: (chartArea)=>{ this.drawBackground(); this.drawGrid(chartArea); this.drawTitle(); } }, { z: bz, draw: ()=>{ this.drawBorder(); } }, { z: tz, draw: (chartArea)=>{ this.drawLabels(chartArea); } } ]; } getMatchingVisibleMetas(type) { const metas = this.chart.getSortedVisibleDatasetMetas(); const axisID = this.axis + 'AxisID'; const result = []; let i, ilen; for(i = 0, ilen = metas.length; i < ilen; ++i){ const meta = metas[i]; if (meta[axisID] === this.id && (!type || meta.type === type)) { result.push(meta); } } return result; } _resolveTickFontOptions(index) { const opts = this.options.ticks.setContext(this.getContext(index)); return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(opts.font); } _maxDigits() { const fontSize = this._resolveTickFontOptions(0).lineHeight; return (this.isHorizontal() ? this.width : this.height) / fontSize; } } class TypedRegistry { constructor(type, scope, override){ this.type = type; this.scope = scope; this.override = override; this.items = Object.create(null); } isForType(type) { return Object.prototype.isPrototypeOf.call(this.type.prototype, type.prototype); } register(item) { const proto = Object.getPrototypeOf(item); let parentScope; if (isIChartComponent(proto)) { parentScope = this.register(proto); } const items = this.items; const id = item.id; const scope = this.scope + '.' + id; if (!id) { throw new Error('class does not have id: ' + item); } if (id in items) { return scope; } items[id] = item; registerDefaults(item, scope, parentScope); if (this.override) { _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.override(item.id, item.overrides); } return scope; } get(id) { return this.items[id]; } unregister(item) { const items = this.items; const id = item.id; const scope = this.scope; if (id in items) { delete items[id]; } if (scope && id in _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d[scope]) { delete _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d[scope][id]; if (this.override) { delete _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a3[id]; } } } } function registerDefaults(item, scope, parentScope) { const itemDefaults = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a4)(Object.create(null), [ parentScope ? _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.get(parentScope) : {}, _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.get(scope), item.defaults ]); _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.set(scope, itemDefaults); if (item.defaultRoutes) { routeDefaults(scope, item.defaultRoutes); } if (item.descriptors) { _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.describe(scope, item.descriptors); } } function routeDefaults(scope, routes) { Object.keys(routes).forEach((property)=>{ const propertyParts = property.split('.'); const sourceName = propertyParts.pop(); const sourceScope = [ scope ].concat(propertyParts).join('.'); const parts = routes[property].split('.'); const targetName = parts.pop(); const targetScope = parts.join('.'); _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.route(sourceScope, sourceName, targetScope, targetName); }); } function isIChartComponent(proto) { return 'id' in proto && 'defaults' in proto; } class Registry { constructor(){ this.controllers = new TypedRegistry(DatasetController, 'datasets', true); this.elements = new TypedRegistry(Element, 'elements'); this.plugins = new TypedRegistry(Object, 'plugins'); this.scales = new TypedRegistry(Scale, 'scales'); this._typedRegistries = [ this.controllers, this.scales, this.elements ]; } add(...args) { this._each('register', args); } remove(...args) { this._each('unregister', args); } addControllers(...args) { this._each('register', args, this.controllers); } addElements(...args) { this._each('register', args, this.elements); } addPlugins(...args) { this._each('register', args, this.plugins); } addScales(...args) { this._each('register', args, this.scales); } getController(id) { return this._get(id, this.controllers, 'controller'); } getElement(id) { return this._get(id, this.elements, 'element'); } getPlugin(id) { return this._get(id, this.plugins, 'plugin'); } getScale(id) { return this._get(id, this.scales, 'scale'); } removeControllers(...args) { this._each('unregister', args, this.controllers); } removeElements(...args) { this._each('unregister', args, this.elements); } removePlugins(...args) { this._each('unregister', args, this.plugins); } removeScales(...args) { this._each('unregister', args, this.scales); } _each(method, args, typedRegistry) { [ ...args ].forEach((arg)=>{ const reg = typedRegistry || this._getRegistryForType(arg); if (typedRegistry || reg.isForType(arg) || reg === this.plugins && arg.id) { this._exec(method, reg, arg); } else { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(arg, (item)=>{ const itemReg = typedRegistry || this._getRegistryForType(item); this._exec(method, itemReg, item); }); } }); } _exec(method, registry, component) { const camelMethod = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a5)(method); (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(component['before' + camelMethod], [], component); registry[method](component); (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(component['after' + camelMethod], [], component); } _getRegistryForType(type) { for(let i = 0; i < this._typedRegistries.length; i++){ const reg = this._typedRegistries[i]; if (reg.isForType(type)) { return reg; } } return this.plugins; } _get(id, typedRegistry, type) { const item = typedRegistry.get(id); if (item === undefined) { throw new Error('"' + id + '" is not a registered ' + type + '.'); } return item; } } var registry = /* #__PURE__ */ new Registry(); class PluginService { constructor(){ this._init = undefined; } notify(chart, hook, args, filter) { if (hook === 'beforeInit') { this._init = this._createDescriptors(chart, true); this._notify(this._init, chart, 'install'); } if (this._init === undefined) { return; } const descriptors = filter ? this._descriptors(chart).filter(filter) : this._descriptors(chart); const result = this._notify(descriptors, chart, hook, args); if (hook === 'afterDestroy') { this._notify(descriptors, chart, 'stop'); this._notify(this._init, chart, 'uninstall'); this._init = undefined; } return result; } _notify(descriptors, chart, hook, args) { args = args || {}; for (const descriptor of descriptors){ const plugin = descriptor.plugin; const method = plugin[hook]; const params = [ chart, args, descriptor.options ]; if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(method, params, plugin) === false && args.cancelable) { return false; } } return true; } invalidate() { if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(this._cache)) { this._oldCache = this._cache; this._cache = undefined; } } _descriptors(chart) { if (this._cache) { return this._cache; } const descriptors = this._cache = this._createDescriptors(chart); this._notifyStateChanges(chart); return descriptors; } _createDescriptors(chart, all) { const config = chart && chart.config; const options = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(config.options && config.options.plugins, {}); const plugins = allPlugins(config); return options === false && !all ? [] : createDescriptors(chart, plugins, options, all); } _notifyStateChanges(chart) { const previousDescriptors = this._oldCache || []; const descriptors = this._cache; const diff = (a, b)=>a.filter((x)=>!b.some((y)=>x.plugin.id === y.plugin.id)); this._notify(diff(previousDescriptors, descriptors), chart, 'stop'); this._notify(diff(descriptors, previousDescriptors), chart, 'start'); } } function allPlugins(config) { const localIds = {}; const plugins = []; const keys = Object.keys(registry.plugins.items); for(let i = 0; i < keys.length; i++){ plugins.push(registry.getPlugin(keys[i])); } const local = config.plugins || []; for(let i = 0; i < local.length; i++){ const plugin = local[i]; if (plugins.indexOf(plugin) === -1) { plugins.push(plugin); localIds[plugin.id] = true; } } return { plugins, localIds }; } function getOpts(options, all) { if (!all && options === false) { return null; } if (options === true) { return {}; } return options; } function createDescriptors(chart, { plugins , localIds }, options, all) { const result = []; const context = chart.getContext(); for (const plugin of plugins){ const id = plugin.id; const opts = getOpts(options[id], all); if (opts === null) { continue; } result.push({ plugin, options: pluginOpts(chart.config, { plugin, local: localIds[id] }, opts, context) }); } return result; } function pluginOpts(config, { plugin , local }, opts, context) { const keys = config.pluginScopeKeys(plugin); const scopes = config.getOptionScopes(opts, keys); if (local && plugin.defaults) { scopes.push(plugin.defaults); } return config.createResolver(scopes, context, [ '' ], { scriptable: false, indexable: false, allKeys: true }); } function getIndexAxis(type, options) { const datasetDefaults = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.datasets[type] || {}; const datasetOptions = (options.datasets || {})[type] || {}; return datasetOptions.indexAxis || options.indexAxis || datasetDefaults.indexAxis || 'x'; } function getAxisFromDefaultScaleID(id, indexAxis) { let axis = id; if (id === '_index_') { axis = indexAxis; } else if (id === '_value_') { axis = indexAxis === 'x' ? 'y' : 'x'; } return axis; } function getDefaultScaleIDFromAxis(axis, indexAxis) { return axis === indexAxis ? '_index_' : '_value_'; } function idMatchesAxis(id) { if (id === 'x' || id === 'y' || id === 'r') { return id; } } function axisFromPosition(position) { if (position === 'top' || position === 'bottom') { return 'x'; } if (position === 'left' || position === 'right') { return 'y'; } } function determineAxis(id, ...scaleOptions) { if (idMatchesAxis(id)) { return id; } for (const opts of scaleOptions){ const axis = opts.axis || axisFromPosition(opts.position) || id.length > 1 && idMatchesAxis(id[0].toLowerCase()); if (axis) { return axis; } } throw new Error(`Cannot determine type of '${id}' axis. Please provide 'axis' or 'position' option.`); } function getAxisFromDataset(id, axis, dataset) { if (dataset[axis + 'AxisID'] === id) { return { axis }; } } function retrieveAxisFromDatasets(id, config) { if (config.data && config.data.datasets) { const boundDs = config.data.datasets.filter((d)=>d.xAxisID === id || d.yAxisID === id); if (boundDs.length) { return getAxisFromDataset(id, 'x', boundDs[0]) || getAxisFromDataset(id, 'y', boundDs[0]); } } return {}; } function mergeScaleConfig(config, options) { const chartDefaults = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a3[config.type] || { scales: {} }; const configScales = options.scales || {}; const chartIndexAxis = getIndexAxis(config.type, options); const scales = Object.create(null); Object.keys(configScales).forEach((id)=>{ const scaleConf = configScales[id]; if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(scaleConf)) { return console.error(`Invalid scale configuration for scale: ${id}`); } if (scaleConf._proxy) { return console.warn(`Ignoring resolver passed as options for scale: ${id}`); } const axis = determineAxis(id, scaleConf, retrieveAxisFromDatasets(id, config), _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.scales[scaleConf.type]); const defaultId = getDefaultScaleIDFromAxis(axis, chartIndexAxis); const defaultScaleOptions = chartDefaults.scales || {}; scales[id] = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ab)(Object.create(null), [ { axis }, scaleConf, defaultScaleOptions[axis], defaultScaleOptions[defaultId] ]); }); config.data.datasets.forEach((dataset)=>{ const type = dataset.type || config.type; const indexAxis = dataset.indexAxis || getIndexAxis(type, options); const datasetDefaults = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a3[type] || {}; const defaultScaleOptions = datasetDefaults.scales || {}; Object.keys(defaultScaleOptions).forEach((defaultID)=>{ const axis = getAxisFromDefaultScaleID(defaultID, indexAxis); const id = dataset[axis + 'AxisID'] || axis; scales[id] = scales[id] || Object.create(null); (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ab)(scales[id], [ { axis }, configScales[id], defaultScaleOptions[defaultID] ]); }); }); Object.keys(scales).forEach((key)=>{ const scale = scales[key]; (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ab)(scale, [ _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.scales[scale.type], _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.scale ]); }); return scales; } function initOptions(config) { const options = config.options || (config.options = {}); options.plugins = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(options.plugins, {}); options.scales = mergeScaleConfig(config, options); } function initData(data) { data = data || {}; data.datasets = data.datasets || []; data.labels = data.labels || []; return data; } function initConfig(config) { config = config || {}; config.data = initData(config.data); initOptions(config); return config; } const keyCache = new Map(); const keysCached = new Set(); function cachedKeys(cacheKey, generate) { let keys = keyCache.get(cacheKey); if (!keys) { keys = generate(); keyCache.set(cacheKey, keys); keysCached.add(keys); } return keys; } const addIfFound = (set, obj, key)=>{ const opts = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.f)(obj, key); if (opts !== undefined) { set.add(opts); } }; class Config { constructor(config){ this._config = initConfig(config); this._scopeCache = new Map(); this._resolverCache = new Map(); } get platform() { return this._config.platform; } get type() { return this._config.type; } set type(type) { this._config.type = type; } get data() { return this._config.data; } set data(data) { this._config.data = initData(data); } get options() { return this._config.options; } set options(options) { this._config.options = options; } get plugins() { return this._config.plugins; } update() { const config = this._config; this.clearCache(); initOptions(config); } clearCache() { this._scopeCache.clear(); this._resolverCache.clear(); } datasetScopeKeys(datasetType) { return cachedKeys(datasetType, ()=>[ [ `datasets.${datasetType}`, '' ] ]); } datasetAnimationScopeKeys(datasetType, transition) { return cachedKeys(`${datasetType}.transition.${transition}`, ()=>[ [ `datasets.${datasetType}.transitions.${transition}`, `transitions.${transition}` ], [ `datasets.${datasetType}`, '' ] ]); } datasetElementScopeKeys(datasetType, elementType) { return cachedKeys(`${datasetType}-${elementType}`, ()=>[ [ `datasets.${datasetType}.elements.${elementType}`, `datasets.${datasetType}`, `elements.${elementType}`, '' ] ]); } pluginScopeKeys(plugin) { const id = plugin.id; const type = this.type; return cachedKeys(`${type}-plugin-${id}`, ()=>[ [ `plugins.${id}`, ...plugin.additionalOptionScopes || [] ] ]); } _cachedScopes(mainScope, resetCache) { const _scopeCache = this._scopeCache; let cache = _scopeCache.get(mainScope); if (!cache || resetCache) { cache = new Map(); _scopeCache.set(mainScope, cache); } return cache; } getOptionScopes(mainScope, keyLists, resetCache) { const { options , type } = this; const cache = this._cachedScopes(mainScope, resetCache); const cached = cache.get(keyLists); if (cached) { return cached; } const scopes = new Set(); keyLists.forEach((keys)=>{ if (mainScope) { scopes.add(mainScope); keys.forEach((key)=>addIfFound(scopes, mainScope, key)); } keys.forEach((key)=>addIfFound(scopes, options, key)); keys.forEach((key)=>addIfFound(scopes, _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a3[type] || {}, key)); keys.forEach((key)=>addIfFound(scopes, _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d, key)); keys.forEach((key)=>addIfFound(scopes, _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a6, key)); }); const array = Array.from(scopes); if (array.length === 0) { array.push(Object.create(null)); } if (keysCached.has(keyLists)) { cache.set(keyLists, array); } return array; } chartOptionScopes() { const { options , type } = this; return [ options, _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a3[type] || {}, _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.datasets[type] || {}, { type }, _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d, _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a6 ]; } resolveNamedOptions(scopes, names, context, prefixes = [ '' ]) { const result = { $shared: true }; const { resolver , subPrefixes } = getResolver(this._resolverCache, scopes, prefixes); let options = resolver; if (needContext(resolver, names)) { result.$shared = false; context = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a7)(context) ? context() : context; const subResolver = this.createResolver(scopes, context, subPrefixes); options = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a8)(resolver, context, subResolver); } for (const prop of names){ result[prop] = options[prop]; } return result; } createResolver(scopes, context, prefixes = [ '' ], descriptorDefaults) { const { resolver } = getResolver(this._resolverCache, scopes, prefixes); return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(context) ? (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a8)(resolver, context, undefined, descriptorDefaults) : resolver; } } function getResolver(resolverCache, scopes, prefixes) { let cache = resolverCache.get(scopes); if (!cache) { cache = new Map(); resolverCache.set(scopes, cache); } const cacheKey = prefixes.join(); let cached = cache.get(cacheKey); if (!cached) { const resolver = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a9)(scopes, prefixes); cached = { resolver, subPrefixes: prefixes.filter((p)=>!p.toLowerCase().includes('hover')) }; cache.set(cacheKey, cached); } return cached; } const hasFunction = (value)=>(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(value) && Object.getOwnPropertyNames(value).some((key)=>(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a7)(value[key])); function needContext(proxy, names) { const { isScriptable , isIndexable } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aa)(proxy); for (const prop of names){ const scriptable = isScriptable(prop); const indexable = isIndexable(prop); const value = (indexable || scriptable) && proxy[prop]; if (scriptable && ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a7)(value) || hasFunction(value)) || indexable && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(value)) { return true; } } return false; } var version = "4.5.1"; const KNOWN_POSITIONS = [ 'top', 'bottom', 'left', 'right', 'chartArea' ]; function positionIsHorizontal(position, axis) { return position === 'top' || position === 'bottom' || KNOWN_POSITIONS.indexOf(position) === -1 && axis === 'x'; } function compare2Level(l1, l2) { return function(a, b) { return a[l1] === b[l1] ? a[l2] - b[l2] : a[l1] - b[l1]; }; } function onAnimationsComplete(context) { const chart = context.chart; const animationOptions = chart.options.animation; chart.notifyPlugins('afterRender'); (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(animationOptions && animationOptions.onComplete, [ context ], chart); } function onAnimationProgress(context) { const chart = context.chart; const animationOptions = chart.options.animation; (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(animationOptions && animationOptions.onProgress, [ context ], chart); } function getCanvas(item) { if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.M)() && typeof item === 'string') { item = document.getElementById(item); } else if (item && item.length) { item = item[0]; } if (item && item.canvas) { item = item.canvas; } return item; } const instances = {}; const getChart = (key)=>{ const canvas = getCanvas(key); return Object.values(instances).filter((c)=>c.canvas === canvas).pop(); }; function moveNumericKeys(obj, start, move) { const keys = Object.keys(obj); for (const key of keys){ const intKey = +key; if (intKey >= start) { const value = obj[key]; delete obj[key]; if (move > 0 || intKey > start) { obj[intKey + move] = value; } } } } function determineLastEvent(e, lastEvent, inChartArea, isClick) { if (!inChartArea || e.type === 'mouseout') { return null; } if (isClick) { return lastEvent; } return e; } class Chart { static defaults = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d; static instances = instances; static overrides = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a3; static registry = registry; static version = version; static getChart = getChart; static register(...items) { registry.add(...items); invalidatePlugins(); } static unregister(...items) { registry.remove(...items); invalidatePlugins(); } constructor(item, userConfig){ const config = this.config = new Config(userConfig); const initialCanvas = getCanvas(item); const existingChart = getChart(initialCanvas); if (existingChart) { throw new Error('Canvas is already in use. Chart with ID \'' + existingChart.id + '\'' + ' must be destroyed before the canvas with ID \'' + existingChart.canvas.id + '\' can be reused.'); } const options = config.createResolver(config.chartOptionScopes(), this.getContext()); this.platform = new (config.platform || _detectPlatform(initialCanvas))(); this.platform.updateConfig(config); const context = this.platform.acquireContext(initialCanvas, options.aspectRatio); const canvas = context && context.canvas; const height = canvas && canvas.height; const width = canvas && canvas.width; this.id = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ac)(); this.ctx = context; this.canvas = canvas; this.width = width; this.height = height; this._options = options; this._aspectRatio = this.aspectRatio; this._layers = []; this._metasets = []; this._stacks = undefined; this.boxes = []; this.currentDevicePixelRatio = undefined; this.chartArea = undefined; this._active = []; this._lastEvent = undefined; this._listeners = {}; this._responsiveListeners = undefined; this._sortedMetasets = []; this.scales = {}; this._plugins = new PluginService(); this.$proxies = {}; this._hiddenIndices = {}; this.attached = false; this._animationsDisabled = undefined; this.$context = undefined; this._doResize = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ad)((mode)=>this.update(mode), options.resizeDelay || 0); this._dataChanges = []; instances[this.id] = this; if (!context || !canvas) { console.error("Failed to create chart: can't acquire context from the given item"); return; } animator.listen(this, 'complete', onAnimationsComplete); animator.listen(this, 'progress', onAnimationProgress); this._initialize(); if (this.attached) { this.update(); } } get aspectRatio() { const { options: { aspectRatio , maintainAspectRatio } , width , height , _aspectRatio } = this; if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(aspectRatio)) { return aspectRatio; } if (maintainAspectRatio && _aspectRatio) { return _aspectRatio; } return height ? width / height : null; } get data() { return this.config.data; } set data(data) { this.config.data = data; } get options() { return this._options; } set options(options) { this.config.options = options; } get registry() { return registry; } _initialize() { this.notifyPlugins('beforeInit'); if (this.options.responsive) { this.resize(); } else { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ae)(this, this.options.devicePixelRatio); } this.bindEvents(); this.notifyPlugins('afterInit'); return this; } clear() { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.af)(this.canvas, this.ctx); return this; } stop() { animator.stop(this); return this; } resize(width, height) { if (!animator.running(this)) { this._resize(width, height); } else { this._resizeBeforeDraw = { width, height }; } } _resize(width, height) { const options = this.options; const canvas = this.canvas; const aspectRatio = options.maintainAspectRatio && this.aspectRatio; const newSize = this.platform.getMaximumSize(canvas, width, height, aspectRatio); const newRatio = options.devicePixelRatio || this.platform.getDevicePixelRatio(); const mode = this.width ? 'resize' : 'attach'; this.width = newSize.width; this.height = newSize.height; this._aspectRatio = this.aspectRatio; if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ae)(this, newRatio, true)) { return; } this.notifyPlugins('resize', { size: newSize }); (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(options.onResize, [ this, newSize ], this); if (this.attached) { if (this._doResize(mode)) { this.render(); } } } ensureScalesHaveIDs() { const options = this.options; const scalesOptions = options.scales || {}; (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(scalesOptions, (axisOptions, axisID)=>{ axisOptions.id = axisID; }); } buildOrUpdateScales() { const options = this.options; const scaleOpts = options.scales; const scales = this.scales; const updated = Object.keys(scales).reduce((obj, id)=>{ obj[id] = false; return obj; }, {}); let items = []; if (scaleOpts) { items = items.concat(Object.keys(scaleOpts).map((id)=>{ const scaleOptions = scaleOpts[id]; const axis = determineAxis(id, scaleOptions); const isRadial = axis === 'r'; const isHorizontal = axis === 'x'; return { options: scaleOptions, dposition: isRadial ? 'chartArea' : isHorizontal ? 'bottom' : 'left', dtype: isRadial ? 'radialLinear' : isHorizontal ? 'category' : 'linear' }; })); } (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(items, (item)=>{ const scaleOptions = item.options; const id = scaleOptions.id; const axis = determineAxis(id, scaleOptions); const scaleType = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(scaleOptions.type, item.dtype); if (scaleOptions.position === undefined || positionIsHorizontal(scaleOptions.position, axis) !== positionIsHorizontal(item.dposition)) { scaleOptions.position = item.dposition; } updated[id] = true; let scale = null; if (id in scales && scales[id].type === scaleType) { scale = scales[id]; } else { const scaleClass = registry.getScale(scaleType); scale = new scaleClass({ id, type: scaleType, ctx: this.ctx, chart: this }); scales[scale.id] = scale; } scale.init(scaleOptions, options); }); (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(updated, (hasUpdated, id)=>{ if (!hasUpdated) { delete scales[id]; } }); (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(scales, (scale)=>{ layouts.configure(this, scale, scale.options); layouts.addBox(this, scale); }); } _updateMetasets() { const metasets = this._metasets; const numData = this.data.datasets.length; const numMeta = metasets.length; metasets.sort((a, b)=>a.index - b.index); if (numMeta > numData) { for(let i = numData; i < numMeta; ++i){ this._destroyDatasetMeta(i); } metasets.splice(numData, numMeta - numData); } this._sortedMetasets = metasets.slice(0).sort(compare2Level('order', 'index')); } _removeUnreferencedMetasets() { const { _metasets: metasets , data: { datasets } } = this; if (metasets.length > datasets.length) { delete this._stacks; } metasets.forEach((meta, index)=>{ if (datasets.filter((x)=>x === meta._dataset).length === 0) { this._destroyDatasetMeta(index); } }); } buildOrUpdateControllers() { const newControllers = []; const datasets = this.data.datasets; let i, ilen; this._removeUnreferencedMetasets(); for(i = 0, ilen = datasets.length; i < ilen; i++){ const dataset = datasets[i]; let meta = this.getDatasetMeta(i); const type = dataset.type || this.config.type; if (meta.type && meta.type !== type) { this._destroyDatasetMeta(i); meta = this.getDatasetMeta(i); } meta.type = type; meta.indexAxis = dataset.indexAxis || getIndexAxis(type, this.options); meta.order = dataset.order || 0; meta.index = i; meta.label = '' + dataset.label; meta.visible = this.isDatasetVisible(i); if (meta.controller) { meta.controller.updateIndex(i); meta.controller.linkScales(); } else { const ControllerClass = registry.getController(type); const { datasetElementType , dataElementType } = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.datasets[type]; Object.assign(ControllerClass, { dataElementType: registry.getElement(dataElementType), datasetElementType: datasetElementType && registry.getElement(datasetElementType) }); meta.controller = new ControllerClass(this, i); newControllers.push(meta.controller); } } this._updateMetasets(); return newControllers; } _resetElements() { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this.data.datasets, (dataset, datasetIndex)=>{ this.getDatasetMeta(datasetIndex).controller.reset(); }, this); } reset() { this._resetElements(); this.notifyPlugins('reset'); } update(mode) { const config = this.config; config.update(); const options = this._options = config.createResolver(config.chartOptionScopes(), this.getContext()); const animsDisabled = this._animationsDisabled = !options.animation; this._updateScales(); this._checkEventBindings(); this._updateHiddenIndices(); this._plugins.invalidate(); if (this.notifyPlugins('beforeUpdate', { mode, cancelable: true }) === false) { return; } const newControllers = this.buildOrUpdateControllers(); this.notifyPlugins('beforeElementsUpdate'); let minPadding = 0; for(let i = 0, ilen = this.data.datasets.length; i < ilen; i++){ const { controller } = this.getDatasetMeta(i); const reset = !animsDisabled && newControllers.indexOf(controller) === -1; controller.buildOrUpdateElements(reset); minPadding = Math.max(+controller.getMaxOverflow(), minPadding); } minPadding = this._minPadding = options.layout.autoPadding ? minPadding : 0; this._updateLayout(minPadding); if (!animsDisabled) { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(newControllers, (controller)=>{ controller.reset(); }); } this._updateDatasets(mode); this.notifyPlugins('afterUpdate', { mode }); this._layers.sort(compare2Level('z', '_idx')); const { _active , _lastEvent } = this; if (_lastEvent) { this._eventHandler(_lastEvent, true); } else if (_active.length) { this._updateHoverStyles(_active, _active, true); } this.render(); } _updateScales() { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this.scales, (scale)=>{ layouts.removeBox(this, scale); }); this.ensureScalesHaveIDs(); this.buildOrUpdateScales(); } _checkEventBindings() { const options = this.options; const existingEvents = new Set(Object.keys(this._listeners)); const newEvents = new Set(options.events); if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ag)(existingEvents, newEvents) || !!this._responsiveListeners !== options.responsive) { this.unbindEvents(); this.bindEvents(); } } _updateHiddenIndices() { const { _hiddenIndices } = this; const changes = this._getUniformDataChanges() || []; for (const { method , start , count } of changes){ const move = method === '_removeElements' ? -count : count; moveNumericKeys(_hiddenIndices, start, move); } } _getUniformDataChanges() { const _dataChanges = this._dataChanges; if (!_dataChanges || !_dataChanges.length) { return; } this._dataChanges = []; const datasetCount = this.data.datasets.length; const makeSet = (idx)=>new Set(_dataChanges.filter((c)=>c[0] === idx).map((c, i)=>i + ',' + c.splice(1).join(','))); const changeSet = makeSet(0); for(let i = 1; i < datasetCount; i++){ if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ag)(changeSet, makeSet(i))) { return; } } return Array.from(changeSet).map((c)=>c.split(',')).map((a)=>({ method: a[1], start: +a[2], count: +a[3] })); } _updateLayout(minPadding) { if (this.notifyPlugins('beforeLayout', { cancelable: true }) === false) { return; } layouts.update(this, this.width, this.height, minPadding); const area = this.chartArea; const noArea = area.width <= 0 || area.height <= 0; this._layers = []; (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this.boxes, (box)=>{ if (noArea && box.position === 'chartArea') { return; } if (box.configure) { box.configure(); } this._layers.push(...box._layers()); }, this); this._layers.forEach((item, index)=>{ item._idx = index; }); this.notifyPlugins('afterLayout'); } _updateDatasets(mode) { if (this.notifyPlugins('beforeDatasetsUpdate', { mode, cancelable: true }) === false) { return; } for(let i = 0, ilen = this.data.datasets.length; i < ilen; ++i){ this.getDatasetMeta(i).controller.configure(); } for(let i = 0, ilen = this.data.datasets.length; i < ilen; ++i){ this._updateDataset(i, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a7)(mode) ? mode({ datasetIndex: i }) : mode); } this.notifyPlugins('afterDatasetsUpdate', { mode }); } _updateDataset(index, mode) { const meta = this.getDatasetMeta(index); const args = { meta, index, mode, cancelable: true }; if (this.notifyPlugins('beforeDatasetUpdate', args) === false) { return; } meta.controller._update(mode); args.cancelable = false; this.notifyPlugins('afterDatasetUpdate', args); } render() { if (this.notifyPlugins('beforeRender', { cancelable: true }) === false) { return; } if (animator.has(this)) { if (this.attached && !animator.running(this)) { animator.start(this); } } else { this.draw(); onAnimationsComplete({ chart: this }); } } draw() { let i; if (this._resizeBeforeDraw) { const { width , height } = this._resizeBeforeDraw; this._resizeBeforeDraw = null; this._resize(width, height); } this.clear(); if (this.width <= 0 || this.height <= 0) { return; } if (this.notifyPlugins('beforeDraw', { cancelable: true }) === false) { return; } const layers = this._layers; for(i = 0; i < layers.length && layers[i].z <= 0; ++i){ layers[i].draw(this.chartArea); } this._drawDatasets(); for(; i < layers.length; ++i){ layers[i].draw(this.chartArea); } this.notifyPlugins('afterDraw'); } _getSortedDatasetMetas(filterVisible) { const metasets = this._sortedMetasets; const result = []; let i, ilen; for(i = 0, ilen = metasets.length; i < ilen; ++i){ const meta = metasets[i]; if (!filterVisible || meta.visible) { result.push(meta); } } return result; } getSortedVisibleDatasetMetas() { return this._getSortedDatasetMetas(true); } _drawDatasets() { if (this.notifyPlugins('beforeDatasetsDraw', { cancelable: true }) === false) { return; } const metasets = this.getSortedVisibleDatasetMetas(); for(let i = metasets.length - 1; i >= 0; --i){ this._drawDataset(metasets[i]); } this.notifyPlugins('afterDatasetsDraw'); } _drawDataset(meta) { const ctx = this.ctx; const args = { meta, index: meta.index, cancelable: true }; const clip = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ah)(this, meta); if (this.notifyPlugins('beforeDatasetDraw', args) === false) { return; } if (clip) { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Y)(ctx, clip); } meta.controller.draw(); if (clip) { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.$)(ctx); } args.cancelable = false; this.notifyPlugins('afterDatasetDraw', args); } isPointInArea(point) { return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)(point, this.chartArea, this._minPadding); } getElementsAtEventForMode(e, mode, options, useFinalPosition) { const method = Interaction.modes[mode]; if (typeof method === 'function') { return method(this, e, options, useFinalPosition); } return []; } getDatasetMeta(datasetIndex) { const dataset = this.data.datasets[datasetIndex]; const metasets = this._metasets; let meta = metasets.filter((x)=>x && x._dataset === dataset).pop(); if (!meta) { meta = { type: null, data: [], dataset: null, controller: null, hidden: null, xAxisID: null, yAxisID: null, order: dataset && dataset.order || 0, index: datasetIndex, _dataset: dataset, _parsed: [], _sorted: false }; metasets.push(meta); } return meta; } getContext() { return this.$context || (this.$context = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(null, { chart: this, type: 'chart' })); } getVisibleDatasetCount() { return this.getSortedVisibleDatasetMetas().length; } isDatasetVisible(datasetIndex) { const dataset = this.data.datasets[datasetIndex]; if (!dataset) { return false; } const meta = this.getDatasetMeta(datasetIndex); return typeof meta.hidden === 'boolean' ? !meta.hidden : !dataset.hidden; } setDatasetVisibility(datasetIndex, visible) { const meta = this.getDatasetMeta(datasetIndex); meta.hidden = !visible; } toggleDataVisibility(index) { this._hiddenIndices[index] = !this._hiddenIndices[index]; } getDataVisibility(index) { return !this._hiddenIndices[index]; } _updateVisibility(datasetIndex, dataIndex, visible) { const mode = visible ? 'show' : 'hide'; const meta = this.getDatasetMeta(datasetIndex); const anims = meta.controller._resolveAnimations(undefined, mode); if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.h)(dataIndex)) { meta.data[dataIndex].hidden = !visible; this.update(); } else { this.setDatasetVisibility(datasetIndex, visible); anims.update(meta, { visible }); this.update((ctx)=>ctx.datasetIndex === datasetIndex ? mode : undefined); } } hide(datasetIndex, dataIndex) { this._updateVisibility(datasetIndex, dataIndex, false); } show(datasetIndex, dataIndex) { this._updateVisibility(datasetIndex, dataIndex, true); } _destroyDatasetMeta(datasetIndex) { const meta = this._metasets[datasetIndex]; if (meta && meta.controller) { meta.controller._destroy(); } delete this._metasets[datasetIndex]; } _stop() { let i, ilen; this.stop(); animator.remove(this); for(i = 0, ilen = this.data.datasets.length; i < ilen; ++i){ this._destroyDatasetMeta(i); } } destroy() { this.notifyPlugins('beforeDestroy'); const { canvas , ctx } = this; this._stop(); this.config.clearCache(); if (canvas) { this.unbindEvents(); (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.af)(canvas, ctx); this.platform.releaseContext(ctx); this.canvas = null; this.ctx = null; } delete instances[this.id]; this.notifyPlugins('afterDestroy'); } toBase64Image(...args) { return this.canvas.toDataURL(...args); } bindEvents() { this.bindUserEvents(); if (this.options.responsive) { this.bindResponsiveEvents(); } else { this.attached = true; } } bindUserEvents() { const listeners = this._listeners; const platform = this.platform; const _add = (type, listener)=>{ platform.addEventListener(this, type, listener); listeners[type] = listener; }; const listener = (e, x, y)=>{ e.offsetX = x; e.offsetY = y; this._eventHandler(e); }; (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this.options.events, (type)=>_add(type, listener)); } bindResponsiveEvents() { if (!this._responsiveListeners) { this._responsiveListeners = {}; } const listeners = this._responsiveListeners; const platform = this.platform; const _add = (type, listener)=>{ platform.addEventListener(this, type, listener); listeners[type] = listener; }; const _remove = (type, listener)=>{ if (listeners[type]) { platform.removeEventListener(this, type, listener); delete listeners[type]; } }; const listener = (width, height)=>{ if (this.canvas) { this.resize(width, height); } }; let detached; const attached = ()=>{ _remove('attach', attached); this.attached = true; this.resize(); _add('resize', listener); _add('detach', detached); }; detached = ()=>{ this.attached = false; _remove('resize', listener); this._stop(); this._resize(0, 0); _add('attach', attached); }; if (platform.isAttached(this.canvas)) { attached(); } else { detached(); } } unbindEvents() { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this._listeners, (listener, type)=>{ this.platform.removeEventListener(this, type, listener); }); this._listeners = {}; (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this._responsiveListeners, (listener, type)=>{ this.platform.removeEventListener(this, type, listener); }); this._responsiveListeners = undefined; } updateHoverStyle(items, mode, enabled) { const prefix = enabled ? 'set' : 'remove'; let meta, item, i, ilen; if (mode === 'dataset') { meta = this.getDatasetMeta(items[0].datasetIndex); meta.controller['_' + prefix + 'DatasetHoverStyle'](); } for(i = 0, ilen = items.length; i < ilen; ++i){ item = items[i]; const controller = item && this.getDatasetMeta(item.datasetIndex).controller; if (controller) { controller[prefix + 'HoverStyle'](item.element, item.datasetIndex, item.index); } } } getActiveElements() { return this._active || []; } setActiveElements(activeElements) { const lastActive = this._active || []; const active = activeElements.map(({ datasetIndex , index })=>{ const meta = this.getDatasetMeta(datasetIndex); if (!meta) { throw new Error('No dataset found at index ' + datasetIndex); } return { datasetIndex, element: meta.data[index], index }; }); const changed = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ai)(active, lastActive); if (changed) { this._active = active; this._lastEvent = null; this._updateHoverStyles(active, lastActive); } } notifyPlugins(hook, args, filter) { return this._plugins.notify(this, hook, args, filter); } isPluginEnabled(pluginId) { return this._plugins._cache.filter((p)=>p.plugin.id === pluginId).length === 1; } _updateHoverStyles(active, lastActive, replay) { const hoverOptions = this.options.hover; const diff = (a, b)=>a.filter((x)=>!b.some((y)=>x.datasetIndex === y.datasetIndex && x.index === y.index)); const deactivated = diff(lastActive, active); const activated = replay ? active : diff(active, lastActive); if (deactivated.length) { this.updateHoverStyle(deactivated, hoverOptions.mode, false); } if (activated.length && hoverOptions.mode) { this.updateHoverStyle(activated, hoverOptions.mode, true); } } _eventHandler(e, replay) { const args = { event: e, replay, cancelable: true, inChartArea: this.isPointInArea(e) }; const eventFilter = (plugin)=>(plugin.options.events || this.options.events).includes(e.native.type); if (this.notifyPlugins('beforeEvent', args, eventFilter) === false) { return; } const changed = this._handleEvent(e, replay, args.inChartArea); args.cancelable = false; this.notifyPlugins('afterEvent', args, eventFilter); if (changed || args.changed) { this.render(); } return this; } _handleEvent(e, replay, inChartArea) { const { _active: lastActive = [] , options } = this; const useFinalPosition = replay; const active = this._getActiveElements(e, lastActive, inChartArea, useFinalPosition); const isClick = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aj)(e); const lastEvent = determineLastEvent(e, this._lastEvent, inChartArea, isClick); if (inChartArea) { this._lastEvent = null; (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(options.onHover, [ e, active, this ], this); if (isClick) { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(options.onClick, [ e, active, this ], this); } } const changed = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ai)(active, lastActive); if (changed || replay) { this._active = active; this._updateHoverStyles(active, lastActive, replay); } this._lastEvent = lastEvent; return changed; } _getActiveElements(e, lastActive, inChartArea, useFinalPosition) { if (e.type === 'mouseout') { return []; } if (!inChartArea) { return lastActive; } const hoverOptions = this.options.hover; return this.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions, useFinalPosition); } } function invalidatePlugins() { return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(Chart.instances, (chart)=>chart._plugins.invalidate()); } function clipSelf(ctx, element, endAngle) { const { startAngle , x , y , outerRadius , innerRadius , options } = element; const { borderWidth , borderJoinStyle } = options; const outerAngleClip = Math.min(borderWidth / outerRadius, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(startAngle - endAngle)); ctx.beginPath(); ctx.arc(x, y, outerRadius - borderWidth / 2, startAngle + outerAngleClip / 2, endAngle - outerAngleClip / 2); if (innerRadius > 0) { const innerAngleClip = Math.min(borderWidth / innerRadius, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(startAngle - endAngle)); ctx.arc(x, y, innerRadius + borderWidth / 2, endAngle - innerAngleClip / 2, startAngle + innerAngleClip / 2, true); } else { const clipWidth = Math.min(borderWidth / 2, outerRadius * (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(startAngle - endAngle)); if (borderJoinStyle === 'round') { ctx.arc(x, y, clipWidth, endAngle - _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / 2, startAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / 2, true); } else if (borderJoinStyle === 'bevel') { const r = 2 * clipWidth * clipWidth; const endX = -r * Math.cos(endAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / 2) + x; const endY = -r * Math.sin(endAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / 2) + y; const startX = r * Math.cos(startAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / 2) + x; const startY = r * Math.sin(startAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / 2) + y; ctx.lineTo(endX, endY); ctx.lineTo(startX, startY); } } ctx.closePath(); ctx.moveTo(0, 0); ctx.rect(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.clip('evenodd'); } function clipArc(ctx, element, endAngle) { const { startAngle , pixelMargin , x , y , outerRadius , innerRadius } = element; let angleMargin = pixelMargin / outerRadius; // Draw an inner border by clipping the arc and drawing a double-width border // Enlarge the clipping arc by 0.33 pixels to eliminate glitches between borders ctx.beginPath(); ctx.arc(x, y, outerRadius, startAngle - angleMargin, endAngle + angleMargin); if (innerRadius > pixelMargin) { angleMargin = pixelMargin / innerRadius; ctx.arc(x, y, innerRadius, endAngle + angleMargin, startAngle - angleMargin, true); } else { ctx.arc(x, y, pixelMargin, endAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H, startAngle - _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H); } ctx.closePath(); ctx.clip(); } function toRadiusCorners(value) { return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.am)(value, [ 'outerStart', 'outerEnd', 'innerStart', 'innerEnd' ]); } /** * Parse border radius from the provided options */ function parseBorderRadius$1(arc, innerRadius, outerRadius, angleDelta) { const o = toRadiusCorners(arc.options.borderRadius); const halfThickness = (outerRadius - innerRadius) / 2; const innerLimit = Math.min(halfThickness, angleDelta * innerRadius / 2); // Outer limits are complicated. We want to compute the available angular distance at // a radius of outerRadius - borderRadius because for small angular distances, this term limits. // We compute at r = outerRadius - borderRadius because this circle defines the center of the border corners. // // If the borderRadius is large, that value can become negative. // This causes the outer borders to lose their radius entirely, which is rather unexpected. To solve that, if borderRadius > outerRadius // we know that the thickness term will dominate and compute the limits at that point const computeOuterLimit = (val)=>{ const outerArcLimit = (outerRadius - Math.min(halfThickness, val)) * angleDelta / 2; return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(val, 0, Math.min(halfThickness, outerArcLimit)); }; return { outerStart: computeOuterLimit(o.outerStart), outerEnd: computeOuterLimit(o.outerEnd), innerStart: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(o.innerStart, 0, innerLimit), innerEnd: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(o.innerEnd, 0, innerLimit) }; } /** * Convert (r, 𝜃) to (x, y) */ function rThetaToXY(r, theta, x, y) { return { x: x + r * Math.cos(theta), y: y + r * Math.sin(theta) }; } /** * Path the arc, respecting border radius by separating into left and right halves. * * Start End * * 1--->a--->2 Outer * / \ * 8 3 * | | * | | * 7 4 * \ / * 6<---b<---5 Inner */ function pathArc(ctx, element, offset, spacing, end, circular) { const { x , y , startAngle: start , pixelMargin , innerRadius: innerR } = element; const outerRadius = Math.max(element.outerRadius + spacing + offset - pixelMargin, 0); const innerRadius = innerR > 0 ? innerR + spacing + offset + pixelMargin : 0; let spacingOffset = 0; const alpha = end - start; if (spacing) { // When spacing is present, it is the same for all items // So we adjust the start and end angle of the arc such that // the distance is the same as it would be without the spacing const noSpacingInnerRadius = innerR > 0 ? innerR - spacing : 0; const noSpacingOuterRadius = outerRadius > 0 ? outerRadius - spacing : 0; const avNogSpacingRadius = (noSpacingInnerRadius + noSpacingOuterRadius) / 2; const adjustedAngle = avNogSpacingRadius !== 0 ? alpha * avNogSpacingRadius / (avNogSpacingRadius + spacing) : alpha; spacingOffset = (alpha - adjustedAngle) / 2; } const beta = Math.max(0.001, alpha * outerRadius - offset / _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P) / outerRadius; const angleOffset = (alpha - beta) / 2; const startAngle = start + angleOffset + spacingOffset; const endAngle = end - angleOffset - spacingOffset; const { outerStart , outerEnd , innerStart , innerEnd } = parseBorderRadius$1(element, innerRadius, outerRadius, endAngle - startAngle); const outerStartAdjustedRadius = outerRadius - outerStart; const outerEndAdjustedRadius = outerRadius - outerEnd; const outerStartAdjustedAngle = startAngle + outerStart / outerStartAdjustedRadius; const outerEndAdjustedAngle = endAngle - outerEnd / outerEndAdjustedRadius; const innerStartAdjustedRadius = innerRadius + innerStart; const innerEndAdjustedRadius = innerRadius + innerEnd; const innerStartAdjustedAngle = startAngle + innerStart / innerStartAdjustedRadius; const innerEndAdjustedAngle = endAngle - innerEnd / innerEndAdjustedRadius; ctx.beginPath(); if (circular) { // The first arc segments from point 1 to point a to point 2 const outerMidAdjustedAngle = (outerStartAdjustedAngle + outerEndAdjustedAngle) / 2; ctx.arc(x, y, outerRadius, outerStartAdjustedAngle, outerMidAdjustedAngle); ctx.arc(x, y, outerRadius, outerMidAdjustedAngle, outerEndAdjustedAngle); // The corner segment from point 2 to point 3 if (outerEnd > 0) { const pCenter = rThetaToXY(outerEndAdjustedRadius, outerEndAdjustedAngle, x, y); ctx.arc(pCenter.x, pCenter.y, outerEnd, outerEndAdjustedAngle, endAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H); } // The line from point 3 to point 4 const p4 = rThetaToXY(innerEndAdjustedRadius, endAngle, x, y); ctx.lineTo(p4.x, p4.y); // The corner segment from point 4 to point 5 if (innerEnd > 0) { const pCenter = rThetaToXY(innerEndAdjustedRadius, innerEndAdjustedAngle, x, y); ctx.arc(pCenter.x, pCenter.y, innerEnd, endAngle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H, innerEndAdjustedAngle + Math.PI); } // The inner arc from point 5 to point b to point 6 const innerMidAdjustedAngle = (endAngle - innerEnd / innerRadius + (startAngle + innerStart / innerRadius)) / 2; ctx.arc(x, y, innerRadius, endAngle - innerEnd / innerRadius, innerMidAdjustedAngle, true); ctx.arc(x, y, innerRadius, innerMidAdjustedAngle, startAngle + innerStart / innerRadius, true); // The corner segment from point 6 to point 7 if (innerStart > 0) { const pCenter = rThetaToXY(innerStartAdjustedRadius, innerStartAdjustedAngle, x, y); ctx.arc(pCenter.x, pCenter.y, innerStart, innerStartAdjustedAngle + Math.PI, startAngle - _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H); } // The line from point 7 to point 8 const p8 = rThetaToXY(outerStartAdjustedRadius, startAngle, x, y); ctx.lineTo(p8.x, p8.y); // The corner segment from point 8 to point 1 if (outerStart > 0) { const pCenter = rThetaToXY(outerStartAdjustedRadius, outerStartAdjustedAngle, x, y); ctx.arc(pCenter.x, pCenter.y, outerStart, startAngle - _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H, outerStartAdjustedAngle); } } else { ctx.moveTo(x, y); const outerStartX = Math.cos(outerStartAdjustedAngle) * outerRadius + x; const outerStartY = Math.sin(outerStartAdjustedAngle) * outerRadius + y; ctx.lineTo(outerStartX, outerStartY); const outerEndX = Math.cos(outerEndAdjustedAngle) * outerRadius + x; const outerEndY = Math.sin(outerEndAdjustedAngle) * outerRadius + y; ctx.lineTo(outerEndX, outerEndY); } ctx.closePath(); } function drawArc(ctx, element, offset, spacing, circular) { const { fullCircles , startAngle , circumference } = element; let endAngle = element.endAngle; if (fullCircles) { pathArc(ctx, element, offset, spacing, endAngle, circular); for(let i = 0; i < fullCircles; ++i){ ctx.fill(); } if (!isNaN(circumference)) { endAngle = startAngle + (circumference % _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T || _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T); } } pathArc(ctx, element, offset, spacing, endAngle, circular); ctx.fill(); return endAngle; } function drawBorder(ctx, element, offset, spacing, circular) { const { fullCircles , startAngle , circumference , options } = element; const { borderWidth , borderJoinStyle , borderDash , borderDashOffset , borderRadius } = options; const inner = options.borderAlign === 'inner'; if (!borderWidth) { return; } ctx.setLineDash(borderDash || []); ctx.lineDashOffset = borderDashOffset; if (inner) { ctx.lineWidth = borderWidth * 2; ctx.lineJoin = borderJoinStyle || 'round'; } else { ctx.lineWidth = borderWidth; ctx.lineJoin = borderJoinStyle || 'bevel'; } let endAngle = element.endAngle; if (fullCircles) { pathArc(ctx, element, offset, spacing, endAngle, circular); for(let i = 0; i < fullCircles; ++i){ ctx.stroke(); } if (!isNaN(circumference)) { endAngle = startAngle + (circumference % _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T || _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T); } } if (inner) { clipArc(ctx, element, endAngle); } if (options.selfJoin && endAngle - startAngle >= _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P && borderRadius === 0 && borderJoinStyle !== 'miter') { clipSelf(ctx, element, endAngle); } if (!fullCircles) { pathArc(ctx, element, offset, spacing, endAngle, circular); ctx.stroke(); } } class ArcElement extends Element { static id = 'arc'; static defaults = { borderAlign: 'center', borderColor: '#fff', borderDash: [], borderDashOffset: 0, borderJoinStyle: undefined, borderRadius: 0, borderWidth: 2, offset: 0, spacing: 0, angle: undefined, circular: true, selfJoin: false }; static defaultRoutes = { backgroundColor: 'backgroundColor' }; static descriptors = { _scriptable: true, _indexable: (name)=>name !== 'borderDash' }; circumference; endAngle; fullCircles; innerRadius; outerRadius; pixelMargin; startAngle; constructor(cfg){ super(); this.options = undefined; this.circumference = undefined; this.startAngle = undefined; this.endAngle = undefined; this.innerRadius = undefined; this.outerRadius = undefined; this.pixelMargin = 0; this.fullCircles = 0; if (cfg) { Object.assign(this, cfg); } } inRange(chartX, chartY, useFinalPosition) { const point = this.getProps([ 'x', 'y' ], useFinalPosition); const { angle , distance } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.D)(point, { x: chartX, y: chartY }); const { startAngle , endAngle , innerRadius , outerRadius , circumference } = this.getProps([ 'startAngle', 'endAngle', 'innerRadius', 'outerRadius', 'circumference' ], useFinalPosition); const rAdjust = (this.options.spacing + this.options.borderWidth) / 2; const _circumference = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(circumference, endAngle - startAngle); const nonZeroBetween = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.p)(angle, startAngle, endAngle) && startAngle !== endAngle; const betweenAngles = _circumference >= _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T || nonZeroBetween; const withinRadius = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ak)(distance, innerRadius + rAdjust, outerRadius + rAdjust); return betweenAngles && withinRadius; } getCenterPoint(useFinalPosition) { const { x , y , startAngle , endAngle , innerRadius , outerRadius } = this.getProps([ 'x', 'y', 'startAngle', 'endAngle', 'innerRadius', 'outerRadius' ], useFinalPosition); const { offset , spacing } = this.options; const halfAngle = (startAngle + endAngle) / 2; const halfRadius = (innerRadius + outerRadius + spacing + offset) / 2; return { x: x + Math.cos(halfAngle) * halfRadius, y: y + Math.sin(halfAngle) * halfRadius }; } tooltipPosition(useFinalPosition) { return this.getCenterPoint(useFinalPosition); } draw(ctx) { const { options , circumference } = this; const offset = (options.offset || 0) / 4; const spacing = (options.spacing || 0) / 2; const circular = options.circular; this.pixelMargin = options.borderAlign === 'inner' ? 0.33 : 0; this.fullCircles = circumference > _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T ? Math.floor(circumference / _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T) : 0; if (circumference === 0 || this.innerRadius < 0 || this.outerRadius < 0) { return; } ctx.save(); const halfAngle = (this.startAngle + this.endAngle) / 2; ctx.translate(Math.cos(halfAngle) * offset, Math.sin(halfAngle) * offset); const fix = 1 - Math.sin(Math.min(_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P, circumference || 0)); const radiusOffset = offset * fix; ctx.fillStyle = options.backgroundColor; ctx.strokeStyle = options.borderColor; drawArc(ctx, this, radiusOffset, spacing, circular); drawBorder(ctx, this, radiusOffset, spacing, circular); ctx.restore(); } } function setStyle(ctx, options, style = options) { ctx.lineCap = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(style.borderCapStyle, options.borderCapStyle); ctx.setLineDash((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(style.borderDash, options.borderDash)); ctx.lineDashOffset = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(style.borderDashOffset, options.borderDashOffset); ctx.lineJoin = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(style.borderJoinStyle, options.borderJoinStyle); ctx.lineWidth = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(style.borderWidth, options.borderWidth); ctx.strokeStyle = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(style.borderColor, options.borderColor); } function lineTo(ctx, previous, target) { ctx.lineTo(target.x, target.y); } function getLineMethod(options) { if (options.stepped) { return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.at; } if (options.tension || options.cubicInterpolationMode === 'monotone') { return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.au; } return lineTo; } function pathVars(points, segment, params = {}) { const count = points.length; const { start: paramsStart = 0 , end: paramsEnd = count - 1 } = params; const { start: segmentStart , end: segmentEnd } = segment; const start = Math.max(paramsStart, segmentStart); const end = Math.min(paramsEnd, segmentEnd); const outside = paramsStart < segmentStart && paramsEnd < segmentStart || paramsStart > segmentEnd && paramsEnd > segmentEnd; return { count, start, loop: segment.loop, ilen: end < start && !outside ? count + end - start : end - start }; } function pathSegment(ctx, line, segment, params) { const { points , options } = line; const { count , start , loop , ilen } = pathVars(points, segment, params); const lineMethod = getLineMethod(options); let { move =true , reverse } = params || {}; let i, point, prev; for(i = 0; i <= ilen; ++i){ point = points[(start + (reverse ? ilen - i : i)) % count]; if (point.skip) { continue; } else if (move) { ctx.moveTo(point.x, point.y); move = false; } else { lineMethod(ctx, prev, point, reverse, options.stepped); } prev = point; } if (loop) { point = points[(start + (reverse ? ilen : 0)) % count]; lineMethod(ctx, prev, point, reverse, options.stepped); } return !!loop; } function fastPathSegment(ctx, line, segment, params) { const points = line.points; const { count , start , ilen } = pathVars(points, segment, params); const { move =true , reverse } = params || {}; let avgX = 0; let countX = 0; let i, point, prevX, minY, maxY, lastY; const pointIndex = (index)=>(start + (reverse ? ilen - index : index)) % count; const drawX = ()=>{ if (minY !== maxY) { ctx.lineTo(avgX, maxY); ctx.lineTo(avgX, minY); ctx.lineTo(avgX, lastY); } }; if (move) { point = points[pointIndex(0)]; ctx.moveTo(point.x, point.y); } for(i = 0; i <= ilen; ++i){ point = points[pointIndex(i)]; if (point.skip) { continue; } const x = point.x; const y = point.y; const truncX = x | 0; if (truncX === prevX) { if (y < minY) { minY = y; } else if (y > maxY) { maxY = y; } avgX = (countX * avgX + x) / ++countX; } else { drawX(); ctx.lineTo(x, y); prevX = truncX; countX = 0; minY = maxY = y; } lastY = y; } drawX(); } function _getSegmentMethod(line) { const opts = line.options; const borderDash = opts.borderDash && opts.borderDash.length; const useFastPath = !line._decimated && !line._loop && !opts.tension && opts.cubicInterpolationMode !== 'monotone' && !opts.stepped && !borderDash; return useFastPath ? fastPathSegment : pathSegment; } function _getInterpolationMethod(options) { if (options.stepped) { return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aq; } if (options.tension || options.cubicInterpolationMode === 'monotone') { return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ar; } return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.as; } function strokePathWithCache(ctx, line, start, count) { let path = line._path; if (!path) { path = line._path = new Path2D(); if (line.path(path, start, count)) { path.closePath(); } } setStyle(ctx, line.options); ctx.stroke(path); } function strokePathDirect(ctx, line, start, count) { const { segments , options } = line; const segmentMethod = _getSegmentMethod(line); for (const segment of segments){ setStyle(ctx, options, segment.style); ctx.beginPath(); if (segmentMethod(ctx, line, segment, { start, end: start + count - 1 })) { ctx.closePath(); } ctx.stroke(); } } const usePath2D = typeof Path2D === 'function'; function draw(ctx, line, start, count) { if (usePath2D && !line.options.segment) { strokePathWithCache(ctx, line, start, count); } else { strokePathDirect(ctx, line, start, count); } } class LineElement extends Element { static id = 'line'; static defaults = { borderCapStyle: 'butt', borderDash: [], borderDashOffset: 0, borderJoinStyle: 'miter', borderWidth: 3, capBezierPoints: true, cubicInterpolationMode: 'default', fill: false, spanGaps: false, stepped: false, tension: 0 }; static defaultRoutes = { backgroundColor: 'backgroundColor', borderColor: 'borderColor' }; static descriptors = { _scriptable: true, _indexable: (name)=>name !== 'borderDash' && name !== 'fill' }; constructor(cfg){ super(); this.animated = true; this.options = undefined; this._chart = undefined; this._loop = undefined; this._fullLoop = undefined; this._path = undefined; this._points = undefined; this._segments = undefined; this._decimated = false; this._pointsUpdated = false; this._datasetIndex = undefined; if (cfg) { Object.assign(this, cfg); } } updateControlPoints(chartArea, indexAxis) { const options = this.options; if ((options.tension || options.cubicInterpolationMode === 'monotone') && !options.stepped && !this._pointsUpdated) { const loop = options.spanGaps ? this._loop : this._fullLoop; (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.an)(this._points, options, chartArea, loop, indexAxis); this._pointsUpdated = true; } } set points(points) { this._points = points; delete this._segments; delete this._path; this._pointsUpdated = false; } get points() { return this._points; } get segments() { return this._segments || (this._segments = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ao)(this, this.options.segment)); } first() { const segments = this.segments; const points = this.points; return segments.length && points[segments[0].start]; } last() { const segments = this.segments; const points = this.points; const count = segments.length; return count && points[segments[count - 1].end]; } interpolate(point, property) { const options = this.options; const value = point[property]; const points = this.points; const segments = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ap)(this, { property, start: value, end: value }); if (!segments.length) { return; } const result = []; const _interpolate = _getInterpolationMethod(options); let i, ilen; for(i = 0, ilen = segments.length; i < ilen; ++i){ const { start , end } = segments[i]; const p1 = points[start]; const p2 = points[end]; if (p1 === p2) { result.push(p1); continue; } const t = Math.abs((value - p1[property]) / (p2[property] - p1[property])); const interpolated = _interpolate(p1, p2, t, options.stepped); interpolated[property] = point[property]; result.push(interpolated); } return result.length === 1 ? result[0] : result; } pathSegment(ctx, segment, params) { const segmentMethod = _getSegmentMethod(this); return segmentMethod(ctx, this, segment, params); } path(ctx, start, count) { const segments = this.segments; const segmentMethod = _getSegmentMethod(this); let loop = this._loop; start = start || 0; count = count || this.points.length - start; for (const segment of segments){ loop &= segmentMethod(ctx, this, segment, { start, end: start + count - 1 }); } return !!loop; } draw(ctx, chartArea, start, count) { const options = this.options || {}; const points = this.points || []; if (points.length && options.borderWidth) { ctx.save(); draw(ctx, this, start, count); ctx.restore(); } if (this.animated) { this._pointsUpdated = false; this._path = undefined; } } } function inRange$1(el, pos, axis, useFinalPosition) { const options = el.options; const { [axis]: value } = el.getProps([ axis ], useFinalPosition); return Math.abs(pos - value) < options.radius + options.hitRadius; } class PointElement extends Element { static id = 'point'; parsed; skip; stop; /** * @type {any} */ static defaults = { borderWidth: 1, hitRadius: 1, hoverBorderWidth: 1, hoverRadius: 4, pointStyle: 'circle', radius: 3, rotation: 0 }; /** * @type {any} */ static defaultRoutes = { backgroundColor: 'backgroundColor', borderColor: 'borderColor' }; constructor(cfg){ super(); this.options = undefined; this.parsed = undefined; this.skip = undefined; this.stop = undefined; if (cfg) { Object.assign(this, cfg); } } inRange(mouseX, mouseY, useFinalPosition) { const options = this.options; const { x , y } = this.getProps([ 'x', 'y' ], useFinalPosition); return Math.pow(mouseX - x, 2) + Math.pow(mouseY - y, 2) < Math.pow(options.hitRadius + options.radius, 2); } inXRange(mouseX, useFinalPosition) { return inRange$1(this, mouseX, 'x', useFinalPosition); } inYRange(mouseY, useFinalPosition) { return inRange$1(this, mouseY, 'y', useFinalPosition); } getCenterPoint(useFinalPosition) { const { x , y } = this.getProps([ 'x', 'y' ], useFinalPosition); return { x, y }; } size(options) { options = options || this.options || {}; let radius = options.radius || 0; radius = Math.max(radius, radius && options.hoverRadius || 0); const borderWidth = radius && options.borderWidth || 0; return (radius + borderWidth) * 2; } draw(ctx, area) { const options = this.options; if (this.skip || options.radius < 0.1 || !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)(this, area, this.size(options) / 2)) { return; } ctx.strokeStyle = options.borderColor; ctx.lineWidth = options.borderWidth; ctx.fillStyle = options.backgroundColor; (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.av)(ctx, options, this.x, this.y); } getRange() { const options = this.options || {}; // @ts-expect-error Fallbacks should never be hit in practice return options.radius + options.hitRadius; } } function getBarBounds(bar, useFinalPosition) { const { x , y , base , width , height } = bar.getProps([ 'x', 'y', 'base', 'width', 'height' ], useFinalPosition); let left, right, top, bottom, half; if (bar.horizontal) { half = height / 2; left = Math.min(x, base); right = Math.max(x, base); top = y - half; bottom = y + half; } else { half = width / 2; left = x - half; right = x + half; top = Math.min(y, base); bottom = Math.max(y, base); } return { left, top, right, bottom }; } function skipOrLimit(skip, value, min, max) { return skip ? 0 : (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(value, min, max); } function parseBorderWidth(bar, maxW, maxH) { const value = bar.options.borderWidth; const skip = bar.borderSkipped; const o = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ax)(value); return { t: skipOrLimit(skip.top, o.top, 0, maxH), r: skipOrLimit(skip.right, o.right, 0, maxW), b: skipOrLimit(skip.bottom, o.bottom, 0, maxH), l: skipOrLimit(skip.left, o.left, 0, maxW) }; } function parseBorderRadius(bar, maxW, maxH) { const { enableBorderRadius } = bar.getProps([ 'enableBorderRadius' ]); const value = bar.options.borderRadius; const o = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(value); const maxR = Math.min(maxW, maxH); const skip = bar.borderSkipped; const enableBorder = enableBorderRadius || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(value); return { topLeft: skipOrLimit(!enableBorder || skip.top || skip.left, o.topLeft, 0, maxR), topRight: skipOrLimit(!enableBorder || skip.top || skip.right, o.topRight, 0, maxR), bottomLeft: skipOrLimit(!enableBorder || skip.bottom || skip.left, o.bottomLeft, 0, maxR), bottomRight: skipOrLimit(!enableBorder || skip.bottom || skip.right, o.bottomRight, 0, maxR) }; } function boundingRects(bar) { const bounds = getBarBounds(bar); const width = bounds.right - bounds.left; const height = bounds.bottom - bounds.top; const border = parseBorderWidth(bar, width / 2, height / 2); const radius = parseBorderRadius(bar, width / 2, height / 2); return { outer: { x: bounds.left, y: bounds.top, w: width, h: height, radius }, inner: { x: bounds.left + border.l, y: bounds.top + border.t, w: width - border.l - border.r, h: height - border.t - border.b, radius: { topLeft: Math.max(0, radius.topLeft - Math.max(border.t, border.l)), topRight: Math.max(0, radius.topRight - Math.max(border.t, border.r)), bottomLeft: Math.max(0, radius.bottomLeft - Math.max(border.b, border.l)), bottomRight: Math.max(0, radius.bottomRight - Math.max(border.b, border.r)) } } }; } function inRange(bar, x, y, useFinalPosition) { const skipX = x === null; const skipY = y === null; const skipBoth = skipX && skipY; const bounds = bar && !skipBoth && getBarBounds(bar, useFinalPosition); return bounds && (skipX || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ak)(x, bounds.left, bounds.right)) && (skipY || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ak)(y, bounds.top, bounds.bottom)); } function hasRadius(radius) { return radius.topLeft || radius.topRight || radius.bottomLeft || radius.bottomRight; } function addNormalRectPath(ctx, rect) { ctx.rect(rect.x, rect.y, rect.w, rect.h); } function inflateRect(rect, amount, refRect = {}) { const x = rect.x !== refRect.x ? -amount : 0; const y = rect.y !== refRect.y ? -amount : 0; const w = (rect.x + rect.w !== refRect.x + refRect.w ? amount : 0) - x; const h = (rect.y + rect.h !== refRect.y + refRect.h ? amount : 0) - y; return { x: rect.x + x, y: rect.y + y, w: rect.w + w, h: rect.h + h, radius: rect.radius }; } class BarElement extends Element { static id = 'bar'; static defaults = { borderSkipped: 'start', borderWidth: 0, borderRadius: 0, inflateAmount: 'auto', pointStyle: undefined }; static defaultRoutes = { backgroundColor: 'backgroundColor', borderColor: 'borderColor' }; constructor(cfg){ super(); this.options = undefined; this.horizontal = undefined; this.base = undefined; this.width = undefined; this.height = undefined; this.inflateAmount = undefined; if (cfg) { Object.assign(this, cfg); } } draw(ctx) { const { inflateAmount , options: { borderColor , backgroundColor } } = this; const { inner , outer } = boundingRects(this); const addRectPath = hasRadius(outer.radius) ? _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aw : addNormalRectPath; ctx.save(); if (outer.w !== inner.w || outer.h !== inner.h) { ctx.beginPath(); addRectPath(ctx, inflateRect(outer, inflateAmount, inner)); ctx.clip(); addRectPath(ctx, inflateRect(inner, -inflateAmount, outer)); ctx.fillStyle = borderColor; ctx.fill('evenodd'); } ctx.beginPath(); addRectPath(ctx, inflateRect(inner, inflateAmount)); ctx.fillStyle = backgroundColor; ctx.fill(); ctx.restore(); } inRange(mouseX, mouseY, useFinalPosition) { return inRange(this, mouseX, mouseY, useFinalPosition); } inXRange(mouseX, useFinalPosition) { return inRange(this, mouseX, null, useFinalPosition); } inYRange(mouseY, useFinalPosition) { return inRange(this, null, mouseY, useFinalPosition); } getCenterPoint(useFinalPosition) { const { x , y , base , horizontal } = this.getProps([ 'x', 'y', 'base', 'horizontal' ], useFinalPosition); return { x: horizontal ? (x + base) / 2 : x, y: horizontal ? y : (y + base) / 2 }; } getRange(axis) { return axis === 'x' ? this.width / 2 : this.height / 2; } } var elements = /*#__PURE__*/Object.freeze({ __proto__: null, ArcElement: ArcElement, BarElement: BarElement, LineElement: LineElement, PointElement: PointElement }); const BORDER_COLORS = [ 'rgb(54, 162, 235)', 'rgb(255, 99, 132)', 'rgb(255, 159, 64)', 'rgb(255, 205, 86)', 'rgb(75, 192, 192)', 'rgb(153, 102, 255)', 'rgb(201, 203, 207)' // grey ]; // Border colors with 50% transparency const BACKGROUND_COLORS = /* #__PURE__ */ BORDER_COLORS.map((color)=>color.replace('rgb(', 'rgba(').replace(')', ', 0.5)')); function getBorderColor(i) { return BORDER_COLORS[i % BORDER_COLORS.length]; } function getBackgroundColor(i) { return BACKGROUND_COLORS[i % BACKGROUND_COLORS.length]; } function colorizeDefaultDataset(dataset, i) { dataset.borderColor = getBorderColor(i); dataset.backgroundColor = getBackgroundColor(i); return ++i; } function colorizeDoughnutDataset(dataset, i) { dataset.backgroundColor = dataset.data.map(()=>getBorderColor(i++)); return i; } function colorizePolarAreaDataset(dataset, i) { dataset.backgroundColor = dataset.data.map(()=>getBackgroundColor(i++)); return i; } function getColorizer(chart) { let i = 0; return (dataset, datasetIndex)=>{ const controller = chart.getDatasetMeta(datasetIndex).controller; if (controller instanceof DoughnutController) { i = colorizeDoughnutDataset(dataset, i); } else if (controller instanceof PolarAreaController) { i = colorizePolarAreaDataset(dataset, i); } else if (controller) { i = colorizeDefaultDataset(dataset, i); } }; } function containsColorsDefinitions(descriptors) { let k; for(k in descriptors){ if (descriptors[k].borderColor || descriptors[k].backgroundColor) { return true; } } return false; } function containsColorsDefinition(descriptor) { return descriptor && (descriptor.borderColor || descriptor.backgroundColor); } function containsDefaultColorsDefenitions() { return _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.borderColor !== 'rgba(0,0,0,0.1)' || _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.backgroundColor !== 'rgba(0,0,0,0.1)'; } var plugin_colors = { id: 'colors', defaults: { enabled: true, forceOverride: false }, beforeLayout (chart, _args, options) { if (!options.enabled) { return; } const { data: { datasets } , options: chartOptions } = chart.config; const { elements } = chartOptions; const containsColorDefenition = containsColorsDefinitions(datasets) || containsColorsDefinition(chartOptions) || elements && containsColorsDefinitions(elements) || containsDefaultColorsDefenitions(); if (!options.forceOverride && containsColorDefenition) { return; } const colorizer = getColorizer(chart); datasets.forEach(colorizer); } }; function lttbDecimation(data, start, count, availableWidth, options) { const samples = options.samples || availableWidth; if (samples >= count) { return data.slice(start, start + count); } const decimated = []; const bucketWidth = (count - 2) / (samples - 2); let sampledIndex = 0; const endIndex = start + count - 1; let a = start; let i, maxAreaPoint, maxArea, area, nextA; decimated[sampledIndex++] = data[a]; for(i = 0; i < samples - 2; i++){ let avgX = 0; let avgY = 0; let j; const avgRangeStart = Math.floor((i + 1) * bucketWidth) + 1 + start; const avgRangeEnd = Math.min(Math.floor((i + 2) * bucketWidth) + 1, count) + start; const avgRangeLength = avgRangeEnd - avgRangeStart; for(j = avgRangeStart; j < avgRangeEnd; j++){ avgX += data[j].x; avgY += data[j].y; } avgX /= avgRangeLength; avgY /= avgRangeLength; const rangeOffs = Math.floor(i * bucketWidth) + 1 + start; const rangeTo = Math.min(Math.floor((i + 1) * bucketWidth) + 1, count) + start; const { x: pointAx , y: pointAy } = data[a]; maxArea = area = -1; for(j = rangeOffs; j < rangeTo; j++){ area = 0.5 * Math.abs((pointAx - avgX) * (data[j].y - pointAy) - (pointAx - data[j].x) * (avgY - pointAy)); if (area > maxArea) { maxArea = area; maxAreaPoint = data[j]; nextA = j; } } decimated[sampledIndex++] = maxAreaPoint; a = nextA; } decimated[sampledIndex++] = data[endIndex]; return decimated; } function minMaxDecimation(data, start, count, availableWidth) { let avgX = 0; let countX = 0; let i, point, x, y, prevX, minIndex, maxIndex, startIndex, minY, maxY; const decimated = []; const endIndex = start + count - 1; const xMin = data[start].x; const xMax = data[endIndex].x; const dx = xMax - xMin; for(i = start; i < start + count; ++i){ point = data[i]; x = (point.x - xMin) / dx * availableWidth; y = point.y; const truncX = x | 0; if (truncX === prevX) { if (y < minY) { minY = y; minIndex = i; } else if (y > maxY) { maxY = y; maxIndex = i; } avgX = (countX * avgX + point.x) / ++countX; } else { const lastIndex = i - 1; if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(minIndex) && !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(maxIndex)) { const intermediateIndex1 = Math.min(minIndex, maxIndex); const intermediateIndex2 = Math.max(minIndex, maxIndex); if (intermediateIndex1 !== startIndex && intermediateIndex1 !== lastIndex) { decimated.push({ ...data[intermediateIndex1], x: avgX }); } if (intermediateIndex2 !== startIndex && intermediateIndex2 !== lastIndex) { decimated.push({ ...data[intermediateIndex2], x: avgX }); } } if (i > 0 && lastIndex !== startIndex) { decimated.push(data[lastIndex]); } decimated.push(point); prevX = truncX; countX = 0; minY = maxY = y; minIndex = maxIndex = startIndex = i; } } return decimated; } function cleanDecimatedDataset(dataset) { if (dataset._decimated) { const data = dataset._data; delete dataset._decimated; delete dataset._data; Object.defineProperty(dataset, 'data', { configurable: true, enumerable: true, writable: true, value: data }); } } function cleanDecimatedData(chart) { chart.data.datasets.forEach((dataset)=>{ cleanDecimatedDataset(dataset); }); } function getStartAndCountOfVisiblePointsSimplified(meta, points) { const pointCount = points.length; let start = 0; let count; const { iScale } = meta; const { min , max , minDefined , maxDefined } = iScale.getUserBounds(); if (minDefined) { start = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.B)(points, iScale.axis, min).lo, 0, pointCount - 1); } if (maxDefined) { count = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.B)(points, iScale.axis, max).hi + 1, start, pointCount) - start; } else { count = pointCount - start; } return { start, count }; } var plugin_decimation = { id: 'decimation', defaults: { algorithm: 'min-max', enabled: false }, beforeElementsUpdate: (chart, args, options)=>{ if (!options.enabled) { cleanDecimatedData(chart); return; } const availableWidth = chart.width; chart.data.datasets.forEach((dataset, datasetIndex)=>{ const { _data , indexAxis } = dataset; const meta = chart.getDatasetMeta(datasetIndex); const data = _data || dataset.data; if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a)([ indexAxis, chart.options.indexAxis ]) === 'y') { return; } if (!meta.controller.supportsDecimation) { return; } const xAxis = chart.scales[meta.xAxisID]; if (xAxis.type !== 'linear' && xAxis.type !== 'time') { return; } if (chart.options.parsing) { return; } let { start , count } = getStartAndCountOfVisiblePointsSimplified(meta, data); const threshold = options.threshold || 4 * availableWidth; if (count <= threshold) { cleanDecimatedDataset(dataset); return; } if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(_data)) { dataset._data = data; delete dataset.data; Object.defineProperty(dataset, 'data', { configurable: true, enumerable: true, get: function() { return this._decimated; }, set: function(d) { this._data = d; } }); } let decimated; switch(options.algorithm){ case 'lttb': decimated = lttbDecimation(data, start, count, availableWidth, options); break; case 'min-max': decimated = minMaxDecimation(data, start, count, availableWidth); break; default: throw new Error(`Unsupported decimation algorithm '${options.algorithm}'`); } dataset._decimated = decimated; }); }, destroy (chart) { cleanDecimatedData(chart); } }; function _segments(line, target, property) { const segments = line.segments; const points = line.points; const tpoints = target.points; const parts = []; for (const segment of segments){ let { start , end } = segment; end = _findSegmentEnd(start, end, points); const bounds = _getBounds(property, points[start], points[end], segment.loop); if (!target.segments) { parts.push({ source: segment, target: bounds, start: points[start], end: points[end] }); continue; } const targetSegments = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ap)(target, bounds); for (const tgt of targetSegments){ const subBounds = _getBounds(property, tpoints[tgt.start], tpoints[tgt.end], tgt.loop); const fillSources = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.az)(segment, points, subBounds); for (const fillSource of fillSources){ parts.push({ source: fillSource, target: tgt, start: { [property]: _getEdge(bounds, subBounds, 'start', Math.max) }, end: { [property]: _getEdge(bounds, subBounds, 'end', Math.min) } }); } } } return parts; } function _getBounds(property, first, last, loop) { if (loop) { return; } let start = first[property]; let end = last[property]; if (property === 'angle') { start = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(start); end = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(end); } return { property, start, end }; } function _pointsFromSegments(boundary, line) { const { x =null , y =null } = boundary || {}; const linePoints = line.points; const points = []; line.segments.forEach(({ start , end })=>{ end = _findSegmentEnd(start, end, linePoints); const first = linePoints[start]; const last = linePoints[end]; if (y !== null) { points.push({ x: first.x, y }); points.push({ x: last.x, y }); } else if (x !== null) { points.push({ x, y: first.y }); points.push({ x, y: last.y }); } }); return points; } function _findSegmentEnd(start, end, points) { for(; end > start; end--){ const point = points[end]; if (!isNaN(point.x) && !isNaN(point.y)) { break; } } return end; } function _getEdge(a, b, prop, fn) { if (a && b) { return fn(a[prop], b[prop]); } return a ? a[prop] : b ? b[prop] : 0; } function _createBoundaryLine(boundary, line) { let points = []; let _loop = false; if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(boundary)) { _loop = true; points = boundary; } else { points = _pointsFromSegments(boundary, line); } return points.length ? new LineElement({ points, options: { tension: 0 }, _loop, _fullLoop: _loop }) : null; } function _shouldApplyFill(source) { return source && source.fill !== false; } function _resolveTarget(sources, index, propagate) { const source = sources[index]; let fill = source.fill; const visited = [ index ]; let target; if (!propagate) { return fill; } while(fill !== false && visited.indexOf(fill) === -1){ if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(fill)) { return fill; } target = sources[fill]; if (!target) { return false; } if (target.visible) { return fill; } visited.push(fill); fill = target.fill; } return false; } function _decodeFill(line, index, count) { const fill = parseFillOption(line); if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(fill)) { return isNaN(fill.value) ? false : fill; } let target = parseFloat(fill); if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(target) && Math.floor(target) === target) { return decodeTargetIndex(fill[0], index, target, count); } return [ 'origin', 'start', 'end', 'stack', 'shape' ].indexOf(fill) >= 0 && fill; } function decodeTargetIndex(firstCh, index, target, count) { if (firstCh === '-' || firstCh === '+') { target = index + target; } if (target === index || target < 0 || target >= count) { return false; } return target; } function _getTargetPixel(fill, scale) { let pixel = null; if (fill === 'start') { pixel = scale.bottom; } else if (fill === 'end') { pixel = scale.top; } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(fill)) { pixel = scale.getPixelForValue(fill.value); } else if (scale.getBasePixel) { pixel = scale.getBasePixel(); } return pixel; } function _getTargetValue(fill, scale, startValue) { let value; if (fill === 'start') { value = startValue; } else if (fill === 'end') { value = scale.options.reverse ? scale.min : scale.max; } else if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(fill)) { value = fill.value; } else { value = scale.getBaseValue(); } return value; } function parseFillOption(line) { const options = line.options; const fillOption = options.fill; let fill = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(fillOption && fillOption.target, fillOption); if (fill === undefined) { fill = !!options.backgroundColor; } if (fill === false || fill === null) { return false; } if (fill === true) { return 'origin'; } return fill; } function _buildStackLine(source) { const { scale , index , line } = source; const points = []; const segments = line.segments; const sourcePoints = line.points; const linesBelow = getLinesBelow(scale, index); linesBelow.push(_createBoundaryLine({ x: null, y: scale.bottom }, line)); for(let i = 0; i < segments.length; i++){ const segment = segments[i]; for(let j = segment.start; j <= segment.end; j++){ addPointsBelow(points, sourcePoints[j], linesBelow); } } return new LineElement({ points, options: {} }); } function getLinesBelow(scale, index) { const below = []; const metas = scale.getMatchingVisibleMetas('line'); for(let i = 0; i < metas.length; i++){ const meta = metas[i]; if (meta.index === index) { break; } if (!meta.hidden) { below.unshift(meta.dataset); } } return below; } function addPointsBelow(points, sourcePoint, linesBelow) { const postponed = []; for(let j = 0; j < linesBelow.length; j++){ const line = linesBelow[j]; const { first , last , point } = findPoint(line, sourcePoint, 'x'); if (!point || first && last) { continue; } if (first) { postponed.unshift(point); } else { points.push(point); if (!last) { break; } } } points.push(...postponed); } function findPoint(line, sourcePoint, property) { const point = line.interpolate(sourcePoint, property); if (!point) { return {}; } const pointValue = point[property]; const segments = line.segments; const linePoints = line.points; let first = false; let last = false; for(let i = 0; i < segments.length; i++){ const segment = segments[i]; const firstValue = linePoints[segment.start][property]; const lastValue = linePoints[segment.end][property]; if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ak)(pointValue, firstValue, lastValue)) { first = pointValue === firstValue; last = pointValue === lastValue; break; } } return { first, last, point }; } class simpleArc { constructor(opts){ this.x = opts.x; this.y = opts.y; this.radius = opts.radius; } pathSegment(ctx, bounds, opts) { const { x , y , radius } = this; bounds = bounds || { start: 0, end: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T }; ctx.arc(x, y, radius, bounds.end, bounds.start, true); return !opts.bounds; } interpolate(point) { const { x , y , radius } = this; const angle = point.angle; return { x: x + Math.cos(angle) * radius, y: y + Math.sin(angle) * radius, angle }; } } function _getTarget(source) { const { chart , fill , line } = source; if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(fill)) { return getLineByIndex(chart, fill); } if (fill === 'stack') { return _buildStackLine(source); } if (fill === 'shape') { return true; } const boundary = computeBoundary(source); if (boundary instanceof simpleArc) { return boundary; } return _createBoundaryLine(boundary, line); } function getLineByIndex(chart, index) { const meta = chart.getDatasetMeta(index); const visible = meta && chart.isDatasetVisible(index); return visible ? meta.dataset : null; } function computeBoundary(source) { const scale = source.scale || {}; if (scale.getPointPositionForValue) { return computeCircularBoundary(source); } return computeLinearBoundary(source); } function computeLinearBoundary(source) { const { scale ={} , fill } = source; const pixel = _getTargetPixel(fill, scale); if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(pixel)) { const horizontal = scale.isHorizontal(); return { x: horizontal ? pixel : null, y: horizontal ? null : pixel }; } return null; } function computeCircularBoundary(source) { const { scale , fill } = source; const options = scale.options; const length = scale.getLabels().length; const start = options.reverse ? scale.max : scale.min; const value = _getTargetValue(fill, scale, start); const target = []; if (options.grid.circular) { const center = scale.getPointPositionForValue(0, start); return new simpleArc({ x: center.x, y: center.y, radius: scale.getDistanceFromCenterForValue(value) }); } for(let i = 0; i < length; ++i){ target.push(scale.getPointPositionForValue(i, value)); } return target; } function _drawfill(ctx, source, area) { const target = _getTarget(source); const { chart , index , line , scale , axis } = source; const lineOpts = line.options; const fillOption = lineOpts.fill; const color = lineOpts.backgroundColor; const { above =color , below =color } = fillOption || {}; const meta = chart.getDatasetMeta(index); const clip = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ah)(chart, meta); if (target && line.points.length) { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Y)(ctx, area); doFill(ctx, { line, target, above, below, area, scale, axis, clip }); (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.$)(ctx); } } function doFill(ctx, cfg) { const { line , target , above , below , area , scale , clip } = cfg; const property = line._loop ? 'angle' : cfg.axis; ctx.save(); let fillColor = below; if (below !== above) { if (property === 'x') { clipVertical(ctx, target, area.top); fill(ctx, { line, target, color: above, scale, property, clip }); ctx.restore(); ctx.save(); clipVertical(ctx, target, area.bottom); } else if (property === 'y') { clipHorizontal(ctx, target, area.left); fill(ctx, { line, target, color: below, scale, property, clip }); ctx.restore(); ctx.save(); clipHorizontal(ctx, target, area.right); fillColor = above; } } fill(ctx, { line, target, color: fillColor, scale, property, clip }); ctx.restore(); } function clipVertical(ctx, target, clipY) { const { segments , points } = target; let first = true; let lineLoop = false; ctx.beginPath(); for (const segment of segments){ const { start , end } = segment; const firstPoint = points[start]; const lastPoint = points[_findSegmentEnd(start, end, points)]; if (first) { ctx.moveTo(firstPoint.x, firstPoint.y); first = false; } else { ctx.lineTo(firstPoint.x, clipY); ctx.lineTo(firstPoint.x, firstPoint.y); } lineLoop = !!target.pathSegment(ctx, segment, { move: lineLoop }); if (lineLoop) { ctx.closePath(); } else { ctx.lineTo(lastPoint.x, clipY); } } ctx.lineTo(target.first().x, clipY); ctx.closePath(); ctx.clip(); } function clipHorizontal(ctx, target, clipX) { const { segments , points } = target; let first = true; let lineLoop = false; ctx.beginPath(); for (const segment of segments){ const { start , end } = segment; const firstPoint = points[start]; const lastPoint = points[_findSegmentEnd(start, end, points)]; if (first) { ctx.moveTo(firstPoint.x, firstPoint.y); first = false; } else { ctx.lineTo(clipX, firstPoint.y); ctx.lineTo(firstPoint.x, firstPoint.y); } lineLoop = !!target.pathSegment(ctx, segment, { move: lineLoop }); if (lineLoop) { ctx.closePath(); } else { ctx.lineTo(clipX, lastPoint.y); } } ctx.lineTo(clipX, target.first().y); ctx.closePath(); ctx.clip(); } function fill(ctx, cfg) { const { line , target , property , color , scale , clip } = cfg; const segments = _segments(line, target, property); for (const { source: src , target: tgt , start , end } of segments){ const { style: { backgroundColor =color } = {} } = src; const notShape = target !== true; ctx.save(); ctx.fillStyle = backgroundColor; clipBounds(ctx, scale, clip, notShape && _getBounds(property, start, end)); ctx.beginPath(); const lineLoop = !!line.pathSegment(ctx, src); let loop; if (notShape) { if (lineLoop) { ctx.closePath(); } else { interpolatedLineTo(ctx, target, end, property); } const targetLoop = !!target.pathSegment(ctx, tgt, { move: lineLoop, reverse: true }); loop = lineLoop && targetLoop; if (!loop) { interpolatedLineTo(ctx, target, start, property); } } ctx.closePath(); ctx.fill(loop ? 'evenodd' : 'nonzero'); ctx.restore(); } } function clipBounds(ctx, scale, clip, bounds) { const chartArea = scale.chart.chartArea; const { property , start , end } = bounds || {}; if (property === 'x' || property === 'y') { let left, top, right, bottom; if (property === 'x') { left = start; top = chartArea.top; right = end; bottom = chartArea.bottom; } else { left = chartArea.left; top = start; right = chartArea.right; bottom = end; } ctx.beginPath(); if (clip) { left = Math.max(left, clip.left); right = Math.min(right, clip.right); top = Math.max(top, clip.top); bottom = Math.min(bottom, clip.bottom); } ctx.rect(left, top, right - left, bottom - top); ctx.clip(); } } function interpolatedLineTo(ctx, target, point, property) { const interpolatedPoint = target.interpolate(point, property); if (interpolatedPoint) { ctx.lineTo(interpolatedPoint.x, interpolatedPoint.y); } } var index = { id: 'filler', afterDatasetsUpdate (chart, _args, options) { const count = (chart.data.datasets || []).length; const sources = []; let meta, i, line, source; for(i = 0; i < count; ++i){ meta = chart.getDatasetMeta(i); line = meta.dataset; source = null; if (line && line.options && line instanceof LineElement) { source = { visible: chart.isDatasetVisible(i), index: i, fill: _decodeFill(line, i, count), chart, axis: meta.controller.options.indexAxis, scale: meta.vScale, line }; } meta.$filler = source; sources.push(source); } for(i = 0; i < count; ++i){ source = sources[i]; if (!source || source.fill === false) { continue; } source.fill = _resolveTarget(sources, i, options.propagate); } }, beforeDraw (chart, _args, options) { const draw = options.drawTime === 'beforeDraw'; const metasets = chart.getSortedVisibleDatasetMetas(); const area = chart.chartArea; for(let i = metasets.length - 1; i >= 0; --i){ const source = metasets[i].$filler; if (!source) { continue; } source.line.updateControlPoints(area, source.axis); if (draw && source.fill) { _drawfill(chart.ctx, source, area); } } }, beforeDatasetsDraw (chart, _args, options) { if (options.drawTime !== 'beforeDatasetsDraw') { return; } const metasets = chart.getSortedVisibleDatasetMetas(); for(let i = metasets.length - 1; i >= 0; --i){ const source = metasets[i].$filler; if (_shouldApplyFill(source)) { _drawfill(chart.ctx, source, chart.chartArea); } } }, beforeDatasetDraw (chart, args, options) { const source = args.meta.$filler; if (!_shouldApplyFill(source) || options.drawTime !== 'beforeDatasetDraw') { return; } _drawfill(chart.ctx, source, chart.chartArea); }, defaults: { propagate: true, drawTime: 'beforeDatasetDraw' } }; const getBoxSize = (labelOpts, fontSize)=>{ let { boxHeight =fontSize , boxWidth =fontSize } = labelOpts; if (labelOpts.usePointStyle) { boxHeight = Math.min(boxHeight, fontSize); boxWidth = labelOpts.pointStyleWidth || Math.min(boxWidth, fontSize); } return { boxWidth, boxHeight, itemHeight: Math.max(fontSize, boxHeight) }; }; const itemsEqual = (a, b)=>a !== null && b !== null && a.datasetIndex === b.datasetIndex && a.index === b.index; class Legend extends Element { constructor(config){ super(); this._added = false; this.legendHitBoxes = []; this._hoveredItem = null; this.doughnutMode = false; this.chart = config.chart; this.options = config.options; this.ctx = config.ctx; this.legendItems = undefined; this.columnSizes = undefined; this.lineWidths = undefined; this.maxHeight = undefined; this.maxWidth = undefined; this.top = undefined; this.bottom = undefined; this.left = undefined; this.right = undefined; this.height = undefined; this.width = undefined; this._margins = undefined; this.position = undefined; this.weight = undefined; this.fullSize = undefined; } update(maxWidth, maxHeight, margins) { this.maxWidth = maxWidth; this.maxHeight = maxHeight; this._margins = margins; this.setDimensions(); this.buildLabels(); this.fit(); } setDimensions() { if (this.isHorizontal()) { this.width = this.maxWidth; this.left = this._margins.left; this.right = this.width; } else { this.height = this.maxHeight; this.top = this._margins.top; this.bottom = this.height; } } buildLabels() { const labelOpts = this.options.labels || {}; let legendItems = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(labelOpts.generateLabels, [ this.chart ], this) || []; if (labelOpts.filter) { legendItems = legendItems.filter((item)=>labelOpts.filter(item, this.chart.data)); } if (labelOpts.sort) { legendItems = legendItems.sort((a, b)=>labelOpts.sort(a, b, this.chart.data)); } if (this.options.reverse) { legendItems.reverse(); } this.legendItems = legendItems; } fit() { const { options , ctx } = this; if (!options.display) { this.width = this.height = 0; return; } const labelOpts = options.labels; const labelFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(labelOpts.font); const fontSize = labelFont.size; const titleHeight = this._computeTitleHeight(); const { boxWidth , itemHeight } = getBoxSize(labelOpts, fontSize); let width, height; ctx.font = labelFont.string; if (this.isHorizontal()) { width = this.maxWidth; height = this._fitRows(titleHeight, fontSize, boxWidth, itemHeight) + 10; } else { height = this.maxHeight; width = this._fitCols(titleHeight, labelFont, boxWidth, itemHeight) + 10; } this.width = Math.min(width, options.maxWidth || this.maxWidth); this.height = Math.min(height, options.maxHeight || this.maxHeight); } _fitRows(titleHeight, fontSize, boxWidth, itemHeight) { const { ctx , maxWidth , options: { labels: { padding } } } = this; const hitboxes = this.legendHitBoxes = []; const lineWidths = this.lineWidths = [ 0 ]; const lineHeight = itemHeight + padding; let totalHeight = titleHeight; ctx.textAlign = 'left'; ctx.textBaseline = 'middle'; let row = -1; let top = -lineHeight; this.legendItems.forEach((legendItem, i)=>{ const itemWidth = boxWidth + fontSize / 2 + ctx.measureText(legendItem.text).width; if (i === 0 || lineWidths[lineWidths.length - 1] + itemWidth + 2 * padding > maxWidth) { totalHeight += lineHeight; lineWidths[lineWidths.length - (i > 0 ? 0 : 1)] = 0; top += lineHeight; row++; } hitboxes[i] = { left: 0, top, row, width: itemWidth, height: itemHeight }; lineWidths[lineWidths.length - 1] += itemWidth + padding; }); return totalHeight; } _fitCols(titleHeight, labelFont, boxWidth, _itemHeight) { const { ctx , maxHeight , options: { labels: { padding } } } = this; const hitboxes = this.legendHitBoxes = []; const columnSizes = this.columnSizes = []; const heightLimit = maxHeight - titleHeight; let totalWidth = padding; let currentColWidth = 0; let currentColHeight = 0; let left = 0; let col = 0; this.legendItems.forEach((legendItem, i)=>{ const { itemWidth , itemHeight } = calculateItemSize(boxWidth, labelFont, ctx, legendItem, _itemHeight); if (i > 0 && currentColHeight + itemHeight + 2 * padding > heightLimit) { totalWidth += currentColWidth + padding; columnSizes.push({ width: currentColWidth, height: currentColHeight }); left += currentColWidth + padding; col++; currentColWidth = currentColHeight = 0; } hitboxes[i] = { left, top: currentColHeight, col, width: itemWidth, height: itemHeight }; currentColWidth = Math.max(currentColWidth, itemWidth); currentColHeight += itemHeight + padding; }); totalWidth += currentColWidth; columnSizes.push({ width: currentColWidth, height: currentColHeight }); return totalWidth; } adjustHitBoxes() { if (!this.options.display) { return; } const titleHeight = this._computeTitleHeight(); const { legendHitBoxes: hitboxes , options: { align , labels: { padding } , rtl } } = this; const rtlHelper = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aA)(rtl, this.left, this.width); if (this.isHorizontal()) { let row = 0; let left = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.left + padding, this.right - this.lineWidths[row]); for (const hitbox of hitboxes){ if (row !== hitbox.row) { row = hitbox.row; left = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.left + padding, this.right - this.lineWidths[row]); } hitbox.top += this.top + titleHeight + padding; hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(left), hitbox.width); left += hitbox.width + padding; } } else { let col = 0; let top = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height); for (const hitbox of hitboxes){ if (hitbox.col !== col) { col = hitbox.col; top = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height); } hitbox.top = top; hitbox.left += this.left + padding; hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(hitbox.left), hitbox.width); top += hitbox.height + padding; } } } isHorizontal() { return this.options.position === 'top' || this.options.position === 'bottom'; } draw() { if (this.options.display) { const ctx = this.ctx; (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Y)(ctx, this); this._draw(); (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.$)(ctx); } } _draw() { const { options: opts , columnSizes , lineWidths , ctx } = this; const { align , labels: labelOpts } = opts; const defaultColor = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.color; const rtlHelper = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aA)(opts.rtl, this.left, this.width); const labelFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(labelOpts.font); const { padding } = labelOpts; const fontSize = labelFont.size; const halfFontSize = fontSize / 2; let cursor; this.drawTitle(); ctx.textAlign = rtlHelper.textAlign('left'); ctx.textBaseline = 'middle'; ctx.lineWidth = 0.5; ctx.font = labelFont.string; const { boxWidth , boxHeight , itemHeight } = getBoxSize(labelOpts, fontSize); const drawLegendBox = function(x, y, legendItem) { if (isNaN(boxWidth) || boxWidth <= 0 || isNaN(boxHeight) || boxHeight < 0) { return; } ctx.save(); const lineWidth = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.lineWidth, 1); ctx.fillStyle = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.fillStyle, defaultColor); ctx.lineCap = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.lineCap, 'butt'); ctx.lineDashOffset = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.lineDashOffset, 0); ctx.lineJoin = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.lineJoin, 'miter'); ctx.lineWidth = lineWidth; ctx.strokeStyle = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.strokeStyle, defaultColor); ctx.setLineDash((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(legendItem.lineDash, [])); if (labelOpts.usePointStyle) { const drawOptions = { radius: boxHeight * Math.SQRT2 / 2, pointStyle: legendItem.pointStyle, rotation: legendItem.rotation, borderWidth: lineWidth }; const centerX = rtlHelper.xPlus(x, boxWidth / 2); const centerY = y + halfFontSize; (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aE)(ctx, drawOptions, centerX, centerY, labelOpts.pointStyleWidth && boxWidth); } else { const yBoxTop = y + Math.max((fontSize - boxHeight) / 2, 0); const xBoxLeft = rtlHelper.leftForLtr(x, boxWidth); const borderRadius = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(legendItem.borderRadius); ctx.beginPath(); if (Object.values(borderRadius).some((v)=>v !== 0)) { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aw)(ctx, { x: xBoxLeft, y: yBoxTop, w: boxWidth, h: boxHeight, radius: borderRadius }); } else { ctx.rect(xBoxLeft, yBoxTop, boxWidth, boxHeight); } ctx.fill(); if (lineWidth !== 0) { ctx.stroke(); } } ctx.restore(); }; const fillText = function(x, y, legendItem) { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, legendItem.text, x, y + itemHeight / 2, labelFont, { strikethrough: legendItem.hidden, textAlign: rtlHelper.textAlign(legendItem.textAlign) }); }; const isHorizontal = this.isHorizontal(); const titleHeight = this._computeTitleHeight(); if (isHorizontal) { cursor = { x: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.left + padding, this.right - lineWidths[0]), y: this.top + padding + titleHeight, line: 0 }; } else { cursor = { x: this.left + padding, y: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.top + titleHeight + padding, this.bottom - columnSizes[0].height), line: 0 }; } (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aB)(this.ctx, opts.textDirection); const lineHeight = itemHeight + padding; this.legendItems.forEach((legendItem, i)=>{ ctx.strokeStyle = legendItem.fontColor; ctx.fillStyle = legendItem.fontColor; const textWidth = ctx.measureText(legendItem.text).width; const textAlign = rtlHelper.textAlign(legendItem.textAlign || (legendItem.textAlign = labelOpts.textAlign)); const width = boxWidth + halfFontSize + textWidth; let x = cursor.x; let y = cursor.y; rtlHelper.setWidth(this.width); if (isHorizontal) { if (i > 0 && x + width + padding > this.right) { y = cursor.y += lineHeight; cursor.line++; x = cursor.x = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.left + padding, this.right - lineWidths[cursor.line]); } } else if (i > 0 && y + lineHeight > this.bottom) { x = cursor.x = x + columnSizes[cursor.line].width + padding; cursor.line++; y = cursor.y = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, this.top + titleHeight + padding, this.bottom - columnSizes[cursor.line].height); } const realX = rtlHelper.x(x); drawLegendBox(realX, y, legendItem); x = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aC)(textAlign, x + boxWidth + halfFontSize, isHorizontal ? x + width : this.right, opts.rtl); fillText(rtlHelper.x(x), y, legendItem); if (isHorizontal) { cursor.x += width + padding; } else if (typeof legendItem.text !== 'string') { const fontLineHeight = labelFont.lineHeight; cursor.y += calculateLegendItemHeight(legendItem, fontLineHeight) + padding; } else { cursor.y += lineHeight; } }); (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aD)(this.ctx, opts.textDirection); } drawTitle() { const opts = this.options; const titleOpts = opts.title; const titleFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(titleOpts.font); const titlePadding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(titleOpts.padding); if (!titleOpts.display) { return; } const rtlHelper = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aA)(opts.rtl, this.left, this.width); const ctx = this.ctx; const position = titleOpts.position; const halfFontSize = titleFont.size / 2; const topPaddingPlusHalfFontSize = titlePadding.top + halfFontSize; let y; let left = this.left; let maxWidth = this.width; if (this.isHorizontal()) { maxWidth = Math.max(...this.lineWidths); y = this.top + topPaddingPlusHalfFontSize; left = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(opts.align, left, this.right - maxWidth); } else { const maxHeight = this.columnSizes.reduce((acc, size)=>Math.max(acc, size.height), 0); y = topPaddingPlusHalfFontSize + (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(opts.align, this.top, this.bottom - maxHeight - opts.labels.padding - this._computeTitleHeight()); } const x = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(position, left, left + maxWidth); ctx.textAlign = rtlHelper.textAlign((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a1)(position)); ctx.textBaseline = 'middle'; ctx.strokeStyle = titleOpts.color; ctx.fillStyle = titleOpts.color; ctx.font = titleFont.string; (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, titleOpts.text, x, y, titleFont); } _computeTitleHeight() { const titleOpts = this.options.title; const titleFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(titleOpts.font); const titlePadding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(titleOpts.padding); return titleOpts.display ? titleFont.lineHeight + titlePadding.height : 0; } _getLegendItemAt(x, y) { let i, hitBox, lh; if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ak)(x, this.left, this.right) && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ak)(y, this.top, this.bottom)) { lh = this.legendHitBoxes; for(i = 0; i < lh.length; ++i){ hitBox = lh[i]; if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ak)(x, hitBox.left, hitBox.left + hitBox.width) && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ak)(y, hitBox.top, hitBox.top + hitBox.height)) { return this.legendItems[i]; } } } return null; } handleEvent(e) { const opts = this.options; if (!isListened(e.type, opts)) { return; } const hoveredItem = this._getLegendItemAt(e.x, e.y); if (e.type === 'mousemove' || e.type === 'mouseout') { const previous = this._hoveredItem; const sameItem = itemsEqual(previous, hoveredItem); if (previous && !sameItem) { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(opts.onLeave, [ e, previous, this ], this); } this._hoveredItem = hoveredItem; if (hoveredItem && !sameItem) { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(opts.onHover, [ e, hoveredItem, this ], this); } } else if (hoveredItem) { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(opts.onClick, [ e, hoveredItem, this ], this); } } } function calculateItemSize(boxWidth, labelFont, ctx, legendItem, _itemHeight) { const itemWidth = calculateItemWidth(legendItem, boxWidth, labelFont, ctx); const itemHeight = calculateItemHeight(_itemHeight, legendItem, labelFont.lineHeight); return { itemWidth, itemHeight }; } function calculateItemWidth(legendItem, boxWidth, labelFont, ctx) { let legendItemText = legendItem.text; if (legendItemText && typeof legendItemText !== 'string') { legendItemText = legendItemText.reduce((a, b)=>a.length > b.length ? a : b); } return boxWidth + labelFont.size / 2 + ctx.measureText(legendItemText).width; } function calculateItemHeight(_itemHeight, legendItem, fontLineHeight) { let itemHeight = _itemHeight; if (typeof legendItem.text !== 'string') { itemHeight = calculateLegendItemHeight(legendItem, fontLineHeight); } return itemHeight; } function calculateLegendItemHeight(legendItem, fontLineHeight) { const labelHeight = legendItem.text ? legendItem.text.length : 0; return fontLineHeight * labelHeight; } function isListened(type, opts) { if ((type === 'mousemove' || type === 'mouseout') && (opts.onHover || opts.onLeave)) { return true; } if (opts.onClick && (type === 'click' || type === 'mouseup')) { return true; } return false; } var plugin_legend = { id: 'legend', _element: Legend, start (chart, _args, options) { const legend = chart.legend = new Legend({ ctx: chart.ctx, options, chart }); layouts.configure(chart, legend, options); layouts.addBox(chart, legend); }, stop (chart) { layouts.removeBox(chart, chart.legend); delete chart.legend; }, beforeUpdate (chart, _args, options) { const legend = chart.legend; layouts.configure(chart, legend, options); legend.options = options; }, afterUpdate (chart) { const legend = chart.legend; legend.buildLabels(); legend.adjustHitBoxes(); }, afterEvent (chart, args) { if (!args.replay) { chart.legend.handleEvent(args.event); } }, defaults: { display: true, position: 'top', align: 'center', fullSize: true, reverse: false, weight: 1000, onClick (e, legendItem, legend) { const index = legendItem.datasetIndex; const ci = legend.chart; if (ci.isDatasetVisible(index)) { ci.hide(index); legendItem.hidden = true; } else { ci.show(index); legendItem.hidden = false; } }, onHover: null, onLeave: null, labels: { color: (ctx)=>ctx.chart.options.color, boxWidth: 40, padding: 10, generateLabels (chart) { const datasets = chart.data.datasets; const { labels: { usePointStyle , pointStyle , textAlign , color , useBorderRadius , borderRadius } } = chart.legend.options; return chart._getSortedDatasetMetas().map((meta)=>{ const style = meta.controller.getStyle(usePointStyle ? 0 : undefined); const borderWidth = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(style.borderWidth); return { text: datasets[meta.index].label, fillStyle: style.backgroundColor, fontColor: color, hidden: !meta.visible, lineCap: style.borderCapStyle, lineDash: style.borderDash, lineDashOffset: style.borderDashOffset, lineJoin: style.borderJoinStyle, lineWidth: (borderWidth.width + borderWidth.height) / 4, strokeStyle: style.borderColor, pointStyle: pointStyle || style.pointStyle, rotation: style.rotation, textAlign: textAlign || style.textAlign, borderRadius: useBorderRadius && (borderRadius || style.borderRadius), datasetIndex: meta.index }; }, this); } }, title: { color: (ctx)=>ctx.chart.options.color, display: false, position: 'center', text: '' } }, descriptors: { _scriptable: (name)=>!name.startsWith('on'), labels: { _scriptable: (name)=>![ 'generateLabels', 'filter', 'sort' ].includes(name) } } }; class Title extends Element { constructor(config){ super(); this.chart = config.chart; this.options = config.options; this.ctx = config.ctx; this._padding = undefined; this.top = undefined; this.bottom = undefined; this.left = undefined; this.right = undefined; this.width = undefined; this.height = undefined; this.position = undefined; this.weight = undefined; this.fullSize = undefined; } update(maxWidth, maxHeight) { const opts = this.options; this.left = 0; this.top = 0; if (!opts.display) { this.width = this.height = this.right = this.bottom = 0; return; } this.width = this.right = maxWidth; this.height = this.bottom = maxHeight; const lineCount = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(opts.text) ? opts.text.length : 1; this._padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(opts.padding); const textSize = lineCount * (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(opts.font).lineHeight + this._padding.height; if (this.isHorizontal()) { this.height = textSize; } else { this.width = textSize; } } isHorizontal() { const pos = this.options.position; return pos === 'top' || pos === 'bottom'; } _drawArgs(offset) { const { top , left , bottom , right , options } = this; const align = options.align; let rotation = 0; let maxWidth, titleX, titleY; if (this.isHorizontal()) { titleX = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, left, right); titleY = top + offset; maxWidth = right - left; } else { if (options.position === 'left') { titleX = left + offset; titleY = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, bottom, top); rotation = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P * -0.5; } else { titleX = right - offset; titleY = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a2)(align, top, bottom); rotation = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P * 0.5; } maxWidth = bottom - top; } return { titleX, titleY, maxWidth, rotation }; } draw() { const ctx = this.ctx; const opts = this.options; if (!opts.display) { return; } const fontOpts = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(opts.font); const lineHeight = fontOpts.lineHeight; const offset = lineHeight / 2 + this._padding.top; const { titleX , titleY , maxWidth , rotation } = this._drawArgs(offset); (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, opts.text, 0, 0, fontOpts, { color: opts.color, maxWidth, rotation, textAlign: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a1)(opts.align), textBaseline: 'middle', translation: [ titleX, titleY ] }); } } function createTitle(chart, titleOpts) { const title = new Title({ ctx: chart.ctx, options: titleOpts, chart }); layouts.configure(chart, title, titleOpts); layouts.addBox(chart, title); chart.titleBlock = title; } var plugin_title = { id: 'title', _element: Title, start (chart, _args, options) { createTitle(chart, options); }, stop (chart) { const titleBlock = chart.titleBlock; layouts.removeBox(chart, titleBlock); delete chart.titleBlock; }, beforeUpdate (chart, _args, options) { const title = chart.titleBlock; layouts.configure(chart, title, options); title.options = options; }, defaults: { align: 'center', display: false, font: { weight: 'bold' }, fullSize: true, padding: 10, position: 'top', text: '', weight: 2000 }, defaultRoutes: { color: 'color' }, descriptors: { _scriptable: true, _indexable: false } }; const map = new WeakMap(); var plugin_subtitle = { id: 'subtitle', start (chart, _args, options) { const title = new Title({ ctx: chart.ctx, options, chart }); layouts.configure(chart, title, options); layouts.addBox(chart, title); map.set(chart, title); }, stop (chart) { layouts.removeBox(chart, map.get(chart)); map.delete(chart); }, beforeUpdate (chart, _args, options) { const title = map.get(chart); layouts.configure(chart, title, options); title.options = options; }, defaults: { align: 'center', display: false, font: { weight: 'normal' }, fullSize: true, padding: 0, position: 'top', text: '', weight: 1500 }, defaultRoutes: { color: 'color' }, descriptors: { _scriptable: true, _indexable: false } }; const positioners = { average (items) { if (!items.length) { return false; } let i, len; let xSet = new Set(); let y = 0; let count = 0; for(i = 0, len = items.length; i < len; ++i){ const el = items[i].element; if (el && el.hasValue()) { const pos = el.tooltipPosition(); xSet.add(pos.x); y += pos.y; ++count; } } if (count === 0 || xSet.size === 0) { return false; } const xAverage = [ ...xSet ].reduce((a, b)=>a + b) / xSet.size; return { x: xAverage, y: y / count }; }, nearest (items, eventPosition) { if (!items.length) { return false; } let x = eventPosition.x; let y = eventPosition.y; let minDistance = Number.POSITIVE_INFINITY; let i, len, nearestElement; for(i = 0, len = items.length; i < len; ++i){ const el = items[i].element; if (el && el.hasValue()) { const center = el.getCenterPoint(); const d = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aF)(eventPosition, center); if (d < minDistance) { minDistance = d; nearestElement = el; } } } if (nearestElement) { const tp = nearestElement.tooltipPosition(); x = tp.x; y = tp.y; } return { x, y }; } }; function pushOrConcat(base, toPush) { if (toPush) { if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(toPush)) { Array.prototype.push.apply(base, toPush); } else { base.push(toPush); } } return base; } function splitNewlines(str) { if ((typeof str === 'string' || str instanceof String) && str.indexOf('\n') > -1) { return str.split('\n'); } return str; } function createTooltipItem(chart, item) { const { element , datasetIndex , index } = item; const controller = chart.getDatasetMeta(datasetIndex).controller; const { label , value } = controller.getLabelAndValue(index); return { chart, label, parsed: controller.getParsed(index), raw: chart.data.datasets[datasetIndex].data[index], formattedValue: value, dataset: controller.getDataset(), dataIndex: index, datasetIndex, element }; } function getTooltipSize(tooltip, options) { const ctx = tooltip.chart.ctx; const { body , footer , title } = tooltip; const { boxWidth , boxHeight } = options; const bodyFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.bodyFont); const titleFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.titleFont); const footerFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.footerFont); const titleLineCount = title.length; const footerLineCount = footer.length; const bodyLineItemCount = body.length; const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(options.padding); let height = padding.height; let width = 0; let combinedBodyLength = body.reduce((count, bodyItem)=>count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length, 0); combinedBodyLength += tooltip.beforeBody.length + tooltip.afterBody.length; if (titleLineCount) { height += titleLineCount * titleFont.lineHeight + (titleLineCount - 1) * options.titleSpacing + options.titleMarginBottom; } if (combinedBodyLength) { const bodyLineHeight = options.displayColors ? Math.max(boxHeight, bodyFont.lineHeight) : bodyFont.lineHeight; height += bodyLineItemCount * bodyLineHeight + (combinedBodyLength - bodyLineItemCount) * bodyFont.lineHeight + (combinedBodyLength - 1) * options.bodySpacing; } if (footerLineCount) { height += options.footerMarginTop + footerLineCount * footerFont.lineHeight + (footerLineCount - 1) * options.footerSpacing; } let widthPadding = 0; const maxLineWidth = function(line) { width = Math.max(width, ctx.measureText(line).width + widthPadding); }; ctx.save(); ctx.font = titleFont.string; (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(tooltip.title, maxLineWidth); ctx.font = bodyFont.string; (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(tooltip.beforeBody.concat(tooltip.afterBody), maxLineWidth); widthPadding = options.displayColors ? boxWidth + 2 + options.boxPadding : 0; (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(body, (bodyItem)=>{ (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(bodyItem.before, maxLineWidth); (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(bodyItem.lines, maxLineWidth); (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(bodyItem.after, maxLineWidth); }); widthPadding = 0; ctx.font = footerFont.string; (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(tooltip.footer, maxLineWidth); ctx.restore(); width += padding.width; return { width, height }; } function determineYAlign(chart, size) { const { y , height } = size; if (y < height / 2) { return 'top'; } else if (y > chart.height - height / 2) { return 'bottom'; } return 'center'; } function doesNotFitWithAlign(xAlign, chart, options, size) { const { x , width } = size; const caret = options.caretSize + options.caretPadding; if (xAlign === 'left' && x + width + caret > chart.width) { return true; } if (xAlign === 'right' && x - width - caret < 0) { return true; } } function determineXAlign(chart, options, size, yAlign) { const { x , width } = size; const { width: chartWidth , chartArea: { left , right } } = chart; let xAlign = 'center'; if (yAlign === 'center') { xAlign = x <= (left + right) / 2 ? 'left' : 'right'; } else if (x <= width / 2) { xAlign = 'left'; } else if (x >= chartWidth - width / 2) { xAlign = 'right'; } if (doesNotFitWithAlign(xAlign, chart, options, size)) { xAlign = 'center'; } return xAlign; } function determineAlignment(chart, options, size) { const yAlign = size.yAlign || options.yAlign || determineYAlign(chart, size); return { xAlign: size.xAlign || options.xAlign || determineXAlign(chart, options, size, yAlign), yAlign }; } function alignX(size, xAlign) { let { x , width } = size; if (xAlign === 'right') { x -= width; } else if (xAlign === 'center') { x -= width / 2; } return x; } function alignY(size, yAlign, paddingAndSize) { let { y , height } = size; if (yAlign === 'top') { y += paddingAndSize; } else if (yAlign === 'bottom') { y -= height + paddingAndSize; } else { y -= height / 2; } return y; } function getBackgroundPoint(options, size, alignment, chart) { const { caretSize , caretPadding , cornerRadius } = options; const { xAlign , yAlign } = alignment; const paddingAndSize = caretSize + caretPadding; const { topLeft , topRight , bottomLeft , bottomRight } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(cornerRadius); let x = alignX(size, xAlign); const y = alignY(size, yAlign, paddingAndSize); if (yAlign === 'center') { if (xAlign === 'left') { x += paddingAndSize; } else if (xAlign === 'right') { x -= paddingAndSize; } } else if (xAlign === 'left') { x -= Math.max(topLeft, bottomLeft) + caretSize; } else if (xAlign === 'right') { x += Math.max(topRight, bottomRight) + caretSize; } return { x: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(x, 0, chart.width - size.width), y: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(y, 0, chart.height - size.height) }; } function getAlignedX(tooltip, align, options) { const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(options.padding); return align === 'center' ? tooltip.x + tooltip.width / 2 : align === 'right' ? tooltip.x + tooltip.width - padding.right : tooltip.x + padding.left; } function getBeforeAfterBodyLines(callback) { return pushOrConcat([], splitNewlines(callback)); } function createTooltipContext(parent, tooltip, tooltipItems) { return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(parent, { tooltip, tooltipItems, type: 'tooltip' }); } function overrideCallbacks(callbacks, context) { const override = context && context.dataset && context.dataset.tooltip && context.dataset.tooltip.callbacks; return override ? callbacks.override(override) : callbacks; } const defaultCallbacks = { beforeTitle: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG, title (tooltipItems) { if (tooltipItems.length > 0) { const item = tooltipItems[0]; const labels = item.chart.data.labels; const labelCount = labels ? labels.length : 0; if (this && this.options && this.options.mode === 'dataset') { return item.dataset.label || ''; } else if (item.label) { return item.label; } else if (labelCount > 0 && item.dataIndex < labelCount) { return labels[item.dataIndex]; } } return ''; }, afterTitle: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG, beforeBody: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG, beforeLabel: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG, label (tooltipItem) { if (this && this.options && this.options.mode === 'dataset') { return tooltipItem.label + ': ' + tooltipItem.formattedValue || tooltipItem.formattedValue; } let label = tooltipItem.dataset.label || ''; if (label) { label += ': '; } const value = tooltipItem.formattedValue; if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(value)) { label += value; } return label; }, labelColor (tooltipItem) { const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex); const options = meta.controller.getStyle(tooltipItem.dataIndex); return { borderColor: options.borderColor, backgroundColor: options.backgroundColor, borderWidth: options.borderWidth, borderDash: options.borderDash, borderDashOffset: options.borderDashOffset, borderRadius: 0 }; }, labelTextColor () { return this.options.bodyColor; }, labelPointStyle (tooltipItem) { const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex); const options = meta.controller.getStyle(tooltipItem.dataIndex); return { pointStyle: options.pointStyle, rotation: options.rotation }; }, afterLabel: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG, afterBody: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG, beforeFooter: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG, footer: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG, afterFooter: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aG }; function invokeCallbackWithFallback(callbacks, name, ctx, arg) { const result = callbacks[name].call(ctx, arg); if (typeof result === 'undefined') { return defaultCallbacks[name].call(ctx, arg); } return result; } class Tooltip extends Element { static positioners = positioners; constructor(config){ super(); this.opacity = 0; this._active = []; this._eventPosition = undefined; this._size = undefined; this._cachedAnimations = undefined; this._tooltipItems = []; this.$animations = undefined; this.$context = undefined; this.chart = config.chart; this.options = config.options; this.dataPoints = undefined; this.title = undefined; this.beforeBody = undefined; this.body = undefined; this.afterBody = undefined; this.footer = undefined; this.xAlign = undefined; this.yAlign = undefined; this.x = undefined; this.y = undefined; this.height = undefined; this.width = undefined; this.caretX = undefined; this.caretY = undefined; this.labelColors = undefined; this.labelPointStyles = undefined; this.labelTextColors = undefined; } initialize(options) { this.options = options; this._cachedAnimations = undefined; this.$context = undefined; } _resolveAnimations() { const cached = this._cachedAnimations; if (cached) { return cached; } const chart = this.chart; const options = this.options.setContext(this.getContext()); const opts = options.enabled && chart.options.animation && options.animations; const animations = new Animations(this.chart, opts); if (opts._cacheable) { this._cachedAnimations = Object.freeze(animations); } return animations; } getContext() { return this.$context || (this.$context = createTooltipContext(this.chart.getContext(), this, this._tooltipItems)); } getTitle(context, options) { const { callbacks } = options; const beforeTitle = invokeCallbackWithFallback(callbacks, 'beforeTitle', this, context); const title = invokeCallbackWithFallback(callbacks, 'title', this, context); const afterTitle = invokeCallbackWithFallback(callbacks, 'afterTitle', this, context); let lines = []; lines = pushOrConcat(lines, splitNewlines(beforeTitle)); lines = pushOrConcat(lines, splitNewlines(title)); lines = pushOrConcat(lines, splitNewlines(afterTitle)); return lines; } getBeforeBody(tooltipItems, options) { return getBeforeAfterBodyLines(invokeCallbackWithFallback(options.callbacks, 'beforeBody', this, tooltipItems)); } getBody(tooltipItems, options) { const { callbacks } = options; const bodyItems = []; (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(tooltipItems, (context)=>{ const bodyItem = { before: [], lines: [], after: [] }; const scoped = overrideCallbacks(callbacks, context); pushOrConcat(bodyItem.before, splitNewlines(invokeCallbackWithFallback(scoped, 'beforeLabel', this, context))); pushOrConcat(bodyItem.lines, invokeCallbackWithFallback(scoped, 'label', this, context)); pushOrConcat(bodyItem.after, splitNewlines(invokeCallbackWithFallback(scoped, 'afterLabel', this, context))); bodyItems.push(bodyItem); }); return bodyItems; } getAfterBody(tooltipItems, options) { return getBeforeAfterBodyLines(invokeCallbackWithFallback(options.callbacks, 'afterBody', this, tooltipItems)); } getFooter(tooltipItems, options) { const { callbacks } = options; const beforeFooter = invokeCallbackWithFallback(callbacks, 'beforeFooter', this, tooltipItems); const footer = invokeCallbackWithFallback(callbacks, 'footer', this, tooltipItems); const afterFooter = invokeCallbackWithFallback(callbacks, 'afterFooter', this, tooltipItems); let lines = []; lines = pushOrConcat(lines, splitNewlines(beforeFooter)); lines = pushOrConcat(lines, splitNewlines(footer)); lines = pushOrConcat(lines, splitNewlines(afterFooter)); return lines; } _createItems(options) { const active = this._active; const data = this.chart.data; const labelColors = []; const labelPointStyles = []; const labelTextColors = []; let tooltipItems = []; let i, len; for(i = 0, len = active.length; i < len; ++i){ tooltipItems.push(createTooltipItem(this.chart, active[i])); } if (options.filter) { tooltipItems = tooltipItems.filter((element, index, array)=>options.filter(element, index, array, data)); } if (options.itemSort) { tooltipItems = tooltipItems.sort((a, b)=>options.itemSort(a, b, data)); } (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(tooltipItems, (context)=>{ const scoped = overrideCallbacks(options.callbacks, context); labelColors.push(invokeCallbackWithFallback(scoped, 'labelColor', this, context)); labelPointStyles.push(invokeCallbackWithFallback(scoped, 'labelPointStyle', this, context)); labelTextColors.push(invokeCallbackWithFallback(scoped, 'labelTextColor', this, context)); }); this.labelColors = labelColors; this.labelPointStyles = labelPointStyles; this.labelTextColors = labelTextColors; this.dataPoints = tooltipItems; return tooltipItems; } update(changed, replay) { const options = this.options.setContext(this.getContext()); const active = this._active; let properties; let tooltipItems = []; if (!active.length) { if (this.opacity !== 0) { properties = { opacity: 0 }; } } else { const position = positioners[options.position].call(this, active, this._eventPosition); tooltipItems = this._createItems(options); this.title = this.getTitle(tooltipItems, options); this.beforeBody = this.getBeforeBody(tooltipItems, options); this.body = this.getBody(tooltipItems, options); this.afterBody = this.getAfterBody(tooltipItems, options); this.footer = this.getFooter(tooltipItems, options); const size = this._size = getTooltipSize(this, options); const positionAndSize = Object.assign({}, position, size); const alignment = determineAlignment(this.chart, options, positionAndSize); const backgroundPoint = getBackgroundPoint(options, positionAndSize, alignment, this.chart); this.xAlign = alignment.xAlign; this.yAlign = alignment.yAlign; properties = { opacity: 1, x: backgroundPoint.x, y: backgroundPoint.y, width: size.width, height: size.height, caretX: position.x, caretY: position.y }; } this._tooltipItems = tooltipItems; this.$context = undefined; if (properties) { this._resolveAnimations().update(this, properties); } if (changed && options.external) { options.external.call(this, { chart: this.chart, tooltip: this, replay }); } } drawCaret(tooltipPoint, ctx, size, options) { const caretPosition = this.getCaretPosition(tooltipPoint, size, options); ctx.lineTo(caretPosition.x1, caretPosition.y1); ctx.lineTo(caretPosition.x2, caretPosition.y2); ctx.lineTo(caretPosition.x3, caretPosition.y3); } getCaretPosition(tooltipPoint, size, options) { const { xAlign , yAlign } = this; const { caretSize , cornerRadius } = options; const { topLeft , topRight , bottomLeft , bottomRight } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(cornerRadius); const { x: ptX , y: ptY } = tooltipPoint; const { width , height } = size; let x1, x2, x3, y1, y2, y3; if (yAlign === 'center') { y2 = ptY + height / 2; if (xAlign === 'left') { x1 = ptX; x2 = x1 - caretSize; y1 = y2 + caretSize; y3 = y2 - caretSize; } else { x1 = ptX + width; x2 = x1 + caretSize; y1 = y2 - caretSize; y3 = y2 + caretSize; } x3 = x1; } else { if (xAlign === 'left') { x2 = ptX + Math.max(topLeft, bottomLeft) + caretSize; } else if (xAlign === 'right') { x2 = ptX + width - Math.max(topRight, bottomRight) - caretSize; } else { x2 = this.caretX; } if (yAlign === 'top') { y1 = ptY; y2 = y1 - caretSize; x1 = x2 - caretSize; x3 = x2 + caretSize; } else { y1 = ptY + height; y2 = y1 + caretSize; x1 = x2 + caretSize; x3 = x2 - caretSize; } y3 = y1; } return { x1, x2, x3, y1, y2, y3 }; } drawTitle(pt, ctx, options) { const title = this.title; const length = title.length; let titleFont, titleSpacing, i; if (length) { const rtlHelper = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aA)(options.rtl, this.x, this.width); pt.x = getAlignedX(this, options.titleAlign, options); ctx.textAlign = rtlHelper.textAlign(options.titleAlign); ctx.textBaseline = 'middle'; titleFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.titleFont); titleSpacing = options.titleSpacing; ctx.fillStyle = options.titleColor; ctx.font = titleFont.string; for(i = 0; i < length; ++i){ ctx.fillText(title[i], rtlHelper.x(pt.x), pt.y + titleFont.lineHeight / 2); pt.y += titleFont.lineHeight + titleSpacing; if (i + 1 === length) { pt.y += options.titleMarginBottom - titleSpacing; } } } } _drawColorBox(ctx, pt, i, rtlHelper, options) { const labelColor = this.labelColors[i]; const labelPointStyle = this.labelPointStyles[i]; const { boxHeight , boxWidth } = options; const bodyFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.bodyFont); const colorX = getAlignedX(this, 'left', options); const rtlColorX = rtlHelper.x(colorX); const yOffSet = boxHeight < bodyFont.lineHeight ? (bodyFont.lineHeight - boxHeight) / 2 : 0; const colorY = pt.y + yOffSet; if (options.usePointStyle) { const drawOptions = { radius: Math.min(boxWidth, boxHeight) / 2, pointStyle: labelPointStyle.pointStyle, rotation: labelPointStyle.rotation, borderWidth: 1 }; const centerX = rtlHelper.leftForLtr(rtlColorX, boxWidth) + boxWidth / 2; const centerY = colorY + boxHeight / 2; ctx.strokeStyle = options.multiKeyBackground; ctx.fillStyle = options.multiKeyBackground; (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.av)(ctx, drawOptions, centerX, centerY); ctx.strokeStyle = labelColor.borderColor; ctx.fillStyle = labelColor.backgroundColor; (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.av)(ctx, drawOptions, centerX, centerY); } else { ctx.lineWidth = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.i)(labelColor.borderWidth) ? Math.max(...Object.values(labelColor.borderWidth)) : labelColor.borderWidth || 1; ctx.strokeStyle = labelColor.borderColor; ctx.setLineDash(labelColor.borderDash || []); ctx.lineDashOffset = labelColor.borderDashOffset || 0; const outerX = rtlHelper.leftForLtr(rtlColorX, boxWidth); const innerX = rtlHelper.leftForLtr(rtlHelper.xPlus(rtlColorX, 1), boxWidth - 2); const borderRadius = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(labelColor.borderRadius); if (Object.values(borderRadius).some((v)=>v !== 0)) { ctx.beginPath(); ctx.fillStyle = options.multiKeyBackground; (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aw)(ctx, { x: outerX, y: colorY, w: boxWidth, h: boxHeight, radius: borderRadius }); ctx.fill(); ctx.stroke(); ctx.fillStyle = labelColor.backgroundColor; ctx.beginPath(); (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aw)(ctx, { x: innerX, y: colorY + 1, w: boxWidth - 2, h: boxHeight - 2, radius: borderRadius }); ctx.fill(); } else { ctx.fillStyle = options.multiKeyBackground; ctx.fillRect(outerX, colorY, boxWidth, boxHeight); ctx.strokeRect(outerX, colorY, boxWidth, boxHeight); ctx.fillStyle = labelColor.backgroundColor; ctx.fillRect(innerX, colorY + 1, boxWidth - 2, boxHeight - 2); } } ctx.fillStyle = this.labelTextColors[i]; } drawBody(pt, ctx, options) { const { body } = this; const { bodySpacing , bodyAlign , displayColors , boxHeight , boxWidth , boxPadding } = options; const bodyFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.bodyFont); let bodyLineHeight = bodyFont.lineHeight; let xLinePadding = 0; const rtlHelper = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aA)(options.rtl, this.x, this.width); const fillLineOfText = function(line) { ctx.fillText(line, rtlHelper.x(pt.x + xLinePadding), pt.y + bodyLineHeight / 2); pt.y += bodyLineHeight + bodySpacing; }; const bodyAlignForCalculation = rtlHelper.textAlign(bodyAlign); let bodyItem, textColor, lines, i, j, ilen, jlen; ctx.textAlign = bodyAlign; ctx.textBaseline = 'middle'; ctx.font = bodyFont.string; pt.x = getAlignedX(this, bodyAlignForCalculation, options); ctx.fillStyle = options.bodyColor; (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this.beforeBody, fillLineOfText); xLinePadding = displayColors && bodyAlignForCalculation !== 'right' ? bodyAlign === 'center' ? boxWidth / 2 + boxPadding : boxWidth + 2 + boxPadding : 0; for(i = 0, ilen = body.length; i < ilen; ++i){ bodyItem = body[i]; textColor = this.labelTextColors[i]; ctx.fillStyle = textColor; (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(bodyItem.before, fillLineOfText); lines = bodyItem.lines; if (displayColors && lines.length) { this._drawColorBox(ctx, pt, i, rtlHelper, options); bodyLineHeight = Math.max(bodyFont.lineHeight, boxHeight); } for(j = 0, jlen = lines.length; j < jlen; ++j){ fillLineOfText(lines[j]); bodyLineHeight = bodyFont.lineHeight; } (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(bodyItem.after, fillLineOfText); } xLinePadding = 0; bodyLineHeight = bodyFont.lineHeight; (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.F)(this.afterBody, fillLineOfText); pt.y -= bodySpacing; } drawFooter(pt, ctx, options) { const footer = this.footer; const length = footer.length; let footerFont, i; if (length) { const rtlHelper = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aA)(options.rtl, this.x, this.width); pt.x = getAlignedX(this, options.footerAlign, options); pt.y += options.footerMarginTop; ctx.textAlign = rtlHelper.textAlign(options.footerAlign); ctx.textBaseline = 'middle'; footerFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(options.footerFont); ctx.fillStyle = options.footerColor; ctx.font = footerFont.string; for(i = 0; i < length; ++i){ ctx.fillText(footer[i], rtlHelper.x(pt.x), pt.y + footerFont.lineHeight / 2); pt.y += footerFont.lineHeight + options.footerSpacing; } } } drawBackground(pt, ctx, tooltipSize, options) { const { xAlign , yAlign } = this; const { x , y } = pt; const { width , height } = tooltipSize; const { topLeft , topRight , bottomLeft , bottomRight } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(options.cornerRadius); ctx.fillStyle = options.backgroundColor; ctx.strokeStyle = options.borderColor; ctx.lineWidth = options.borderWidth; ctx.beginPath(); ctx.moveTo(x + topLeft, y); if (yAlign === 'top') { this.drawCaret(pt, ctx, tooltipSize, options); } ctx.lineTo(x + width - topRight, y); ctx.quadraticCurveTo(x + width, y, x + width, y + topRight); if (yAlign === 'center' && xAlign === 'right') { this.drawCaret(pt, ctx, tooltipSize, options); } ctx.lineTo(x + width, y + height - bottomRight); ctx.quadraticCurveTo(x + width, y + height, x + width - bottomRight, y + height); if (yAlign === 'bottom') { this.drawCaret(pt, ctx, tooltipSize, options); } ctx.lineTo(x + bottomLeft, y + height); ctx.quadraticCurveTo(x, y + height, x, y + height - bottomLeft); if (yAlign === 'center' && xAlign === 'left') { this.drawCaret(pt, ctx, tooltipSize, options); } ctx.lineTo(x, y + topLeft); ctx.quadraticCurveTo(x, y, x + topLeft, y); ctx.closePath(); ctx.fill(); if (options.borderWidth > 0) { ctx.stroke(); } } _updateAnimationTarget(options) { const chart = this.chart; const anims = this.$animations; const animX = anims && anims.x; const animY = anims && anims.y; if (animX || animY) { const position = positioners[options.position].call(this, this._active, this._eventPosition); if (!position) { return; } const size = this._size = getTooltipSize(this, options); const positionAndSize = Object.assign({}, position, this._size); const alignment = determineAlignment(chart, options, positionAndSize); const point = getBackgroundPoint(options, positionAndSize, alignment, chart); if (animX._to !== point.x || animY._to !== point.y) { this.xAlign = alignment.xAlign; this.yAlign = alignment.yAlign; this.width = size.width; this.height = size.height; this.caretX = position.x; this.caretY = position.y; this._resolveAnimations().update(this, point); } } } _willRender() { return !!this.opacity; } draw(ctx) { const options = this.options.setContext(this.getContext()); let opacity = this.opacity; if (!opacity) { return; } this._updateAnimationTarget(options); const tooltipSize = { width: this.width, height: this.height }; const pt = { x: this.x, y: this.y }; opacity = Math.abs(opacity) < 1e-3 ? 0 : opacity; const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(options.padding); const hasTooltipContent = this.title.length || this.beforeBody.length || this.body.length || this.afterBody.length || this.footer.length; if (options.enabled && hasTooltipContent) { ctx.save(); ctx.globalAlpha = opacity; this.drawBackground(pt, ctx, tooltipSize, options); (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aB)(ctx, options.textDirection); pt.y += padding.top; this.drawTitle(pt, ctx, options); this.drawBody(pt, ctx, options); this.drawFooter(pt, ctx, options); (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aD)(ctx, options.textDirection); ctx.restore(); } } getActiveElements() { return this._active || []; } setActiveElements(activeElements, eventPosition) { const lastActive = this._active; const active = activeElements.map(({ datasetIndex , index })=>{ const meta = this.chart.getDatasetMeta(datasetIndex); if (!meta) { throw new Error('Cannot find a dataset at index ' + datasetIndex); } return { datasetIndex, element: meta.data[index], index }; }); const changed = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ai)(lastActive, active); const positionChanged = this._positionChanged(active, eventPosition); if (changed || positionChanged) { this._active = active; this._eventPosition = eventPosition; this._ignoreReplayEvents = true; this.update(true); } } handleEvent(e, replay, inChartArea = true) { if (replay && this._ignoreReplayEvents) { return false; } this._ignoreReplayEvents = false; const options = this.options; const lastActive = this._active || []; const active = this._getActiveElements(e, lastActive, replay, inChartArea); const positionChanged = this._positionChanged(active, e); const changed = replay || !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ai)(active, lastActive) || positionChanged; if (changed) { this._active = active; if (options.enabled || options.external) { this._eventPosition = { x: e.x, y: e.y }; this.update(true, replay); } } return changed; } _getActiveElements(e, lastActive, replay, inChartArea) { const options = this.options; if (e.type === 'mouseout') { return []; } if (!inChartArea) { return lastActive.filter((i)=>this.chart.data.datasets[i.datasetIndex] && this.chart.getDatasetMeta(i.datasetIndex).controller.getParsed(i.index) !== undefined); } const active = this.chart.getElementsAtEventForMode(e, options.mode, options, replay); if (options.reverse) { active.reverse(); } return active; } _positionChanged(active, e) { const { caretX , caretY , options } = this; const position = positioners[options.position].call(this, active, e); return position !== false && (caretX !== position.x || caretY !== position.y); } } var plugin_tooltip = { id: 'tooltip', _element: Tooltip, positioners, afterInit (chart, _args, options) { if (options) { chart.tooltip = new Tooltip({ chart, options }); } }, beforeUpdate (chart, _args, options) { if (chart.tooltip) { chart.tooltip.initialize(options); } }, reset (chart, _args, options) { if (chart.tooltip) { chart.tooltip.initialize(options); } }, afterDraw (chart) { const tooltip = chart.tooltip; if (tooltip && tooltip._willRender()) { const args = { tooltip }; if (chart.notifyPlugins('beforeTooltipDraw', { ...args, cancelable: true }) === false) { return; } tooltip.draw(chart.ctx); chart.notifyPlugins('afterTooltipDraw', args); } }, afterEvent (chart, args) { if (chart.tooltip) { const useFinalPosition = args.replay; if (chart.tooltip.handleEvent(args.event, useFinalPosition, args.inChartArea)) { args.changed = true; } } }, defaults: { enabled: true, external: null, position: 'average', backgroundColor: 'rgba(0,0,0,0.8)', titleColor: '#fff', titleFont: { weight: 'bold' }, titleSpacing: 2, titleMarginBottom: 6, titleAlign: 'left', bodyColor: '#fff', bodySpacing: 2, bodyFont: {}, bodyAlign: 'left', footerColor: '#fff', footerSpacing: 2, footerMarginTop: 6, footerFont: { weight: 'bold' }, footerAlign: 'left', padding: 6, caretPadding: 2, caretSize: 5, cornerRadius: 6, boxHeight: (ctx, opts)=>opts.bodyFont.size, boxWidth: (ctx, opts)=>opts.bodyFont.size, multiKeyBackground: '#fff', displayColors: true, boxPadding: 0, borderColor: 'rgba(0,0,0,0)', borderWidth: 0, animation: { duration: 400, easing: 'easeOutQuart' }, animations: { numbers: { type: 'number', properties: [ 'x', 'y', 'width', 'height', 'caretX', 'caretY' ] }, opacity: { easing: 'linear', duration: 200 } }, callbacks: defaultCallbacks }, defaultRoutes: { bodyFont: 'font', footerFont: 'font', titleFont: 'font' }, descriptors: { _scriptable: (name)=>name !== 'filter' && name !== 'itemSort' && name !== 'external', _indexable: false, callbacks: { _scriptable: false, _indexable: false }, animation: { _fallback: false }, animations: { _fallback: 'animation' } }, additionalOptionScopes: [ 'interaction' ] }; var plugins = /*#__PURE__*/Object.freeze({ __proto__: null, Colors: plugin_colors, Decimation: plugin_decimation, Filler: index, Legend: plugin_legend, SubTitle: plugin_subtitle, Title: plugin_title, Tooltip: plugin_tooltip }); const addIfString = (labels, raw, index, addedLabels)=>{ if (typeof raw === 'string') { index = labels.push(raw) - 1; addedLabels.unshift({ index, label: raw }); } else if (isNaN(raw)) { index = null; } return index; }; function findOrAddLabel(labels, raw, index, addedLabels) { const first = labels.indexOf(raw); if (first === -1) { return addIfString(labels, raw, index, addedLabels); } const last = labels.lastIndexOf(raw); return first !== last ? index : first; } const validIndex = (index, max)=>index === null ? null : (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(Math.round(index), 0, max); function _getLabelForValue(value) { const labels = this.getLabels(); if (value >= 0 && value < labels.length) { return labels[value]; } return value; } class CategoryScale extends Scale { static id = 'category'; static defaults = { ticks: { callback: _getLabelForValue } }; constructor(cfg){ super(cfg); this._startValue = undefined; this._valueRange = 0; this._addedLabels = []; } init(scaleOptions) { const added = this._addedLabels; if (added.length) { const labels = this.getLabels(); for (const { index , label } of added){ if (labels[index] === label) { labels.splice(index, 1); } } this._addedLabels = []; } super.init(scaleOptions); } parse(raw, index) { if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(raw)) { return null; } const labels = this.getLabels(); index = isFinite(index) && labels[index] === raw ? index : findOrAddLabel(labels, raw, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(index, raw), this._addedLabels); return validIndex(index, labels.length - 1); } determineDataLimits() { const { minDefined , maxDefined } = this.getUserBounds(); let { min , max } = this.getMinMax(true); if (this.options.bounds === 'ticks') { if (!minDefined) { min = 0; } if (!maxDefined) { max = this.getLabels().length - 1; } } this.min = min; this.max = max; } buildTicks() { const min = this.min; const max = this.max; const offset = this.options.offset; const ticks = []; let labels = this.getLabels(); labels = min === 0 && max === labels.length - 1 ? labels : labels.slice(min, max + 1); this._valueRange = Math.max(labels.length - (offset ? 0 : 1), 1); this._startValue = this.min - (offset ? 0.5 : 0); for(let value = min; value <= max; value++){ ticks.push({ value }); } return ticks; } getLabelForValue(value) { return _getLabelForValue.call(this, value); } configure() { super.configure(); if (!this.isHorizontal()) { this._reversePixels = !this._reversePixels; } } getPixelForValue(value) { if (typeof value !== 'number') { value = this.parse(value); } return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange); } getPixelForTick(index) { const ticks = this.ticks; if (index < 0 || index > ticks.length - 1) { return null; } return this.getPixelForValue(ticks[index].value); } getValueForPixel(pixel) { return Math.round(this._startValue + this.getDecimalForPixel(pixel) * this._valueRange); } getBasePixel() { return this.bottom; } } function generateTicks$1(generationOptions, dataRange) { const ticks = []; const MIN_SPACING = 1e-14; const { bounds , step , min , max , precision , count , maxTicks , maxDigits , includeBounds } = generationOptions; const unit = step || 1; const maxSpaces = maxTicks - 1; const { min: rmin , max: rmax } = dataRange; const minDefined = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(min); const maxDefined = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(max); const countDefined = !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(count); const minSpacing = (rmax - rmin) / (maxDigits + 1); let spacing = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aI)((rmax - rmin) / maxSpaces / unit) * unit; let factor, niceMin, niceMax, numSpaces; if (spacing < MIN_SPACING && !minDefined && !maxDefined) { return [ { value: rmin }, { value: rmax } ]; } numSpaces = Math.ceil(rmax / spacing) - Math.floor(rmin / spacing); if (numSpaces > maxSpaces) { spacing = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aI)(numSpaces * spacing / maxSpaces / unit) * unit; } if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(precision)) { factor = Math.pow(10, precision); spacing = Math.ceil(spacing * factor) / factor; } if (bounds === 'ticks') { niceMin = Math.floor(rmin / spacing) * spacing; niceMax = Math.ceil(rmax / spacing) * spacing; } else { niceMin = rmin; niceMax = rmax; } if (minDefined && maxDefined && step && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aJ)((max - min) / step, spacing / 1000)) { numSpaces = Math.round(Math.min((max - min) / spacing, maxTicks)); spacing = (max - min) / numSpaces; niceMin = min; niceMax = max; } else if (countDefined) { niceMin = minDefined ? min : niceMin; niceMax = maxDefined ? max : niceMax; numSpaces = count - 1; spacing = (niceMax - niceMin) / numSpaces; } else { numSpaces = (niceMax - niceMin) / spacing; if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aK)(numSpaces, Math.round(numSpaces), spacing / 1000)) { numSpaces = Math.round(numSpaces); } else { numSpaces = Math.ceil(numSpaces); } } const decimalPlaces = Math.max((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aL)(spacing), (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aL)(niceMin)); factor = Math.pow(10, (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(precision) ? decimalPlaces : precision); niceMin = Math.round(niceMin * factor) / factor; niceMax = Math.round(niceMax * factor) / factor; let j = 0; if (minDefined) { if (includeBounds && niceMin !== min) { ticks.push({ value: min }); if (niceMin < min) { j++; } if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aK)(Math.round((niceMin + j * spacing) * factor) / factor, min, relativeLabelSize(min, minSpacing, generationOptions))) { j++; } } else if (niceMin < min) { j++; } } for(; j < numSpaces; ++j){ const tickValue = Math.round((niceMin + j * spacing) * factor) / factor; if (maxDefined && tickValue > max) { break; } ticks.push({ value: tickValue }); } if (maxDefined && includeBounds && niceMax !== max) { if (ticks.length && (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aK)(ticks[ticks.length - 1].value, max, relativeLabelSize(max, minSpacing, generationOptions))) { ticks[ticks.length - 1].value = max; } else { ticks.push({ value: max }); } } else if (!maxDefined || niceMax === max) { ticks.push({ value: niceMax }); } return ticks; } function relativeLabelSize(value, minSpacing, { horizontal , minRotation }) { const rad = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(minRotation); const ratio = (horizontal ? Math.sin(rad) : Math.cos(rad)) || 0.001; const length = 0.75 * minSpacing * ('' + value).length; return Math.min(minSpacing / ratio, length); } class LinearScaleBase extends Scale { constructor(cfg){ super(cfg); this.start = undefined; this.end = undefined; this._startValue = undefined; this._endValue = undefined; this._valueRange = 0; } parse(raw, index) { if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(raw)) { return null; } if ((typeof raw === 'number' || raw instanceof Number) && !isFinite(+raw)) { return null; } return +raw; } handleTickRangeOptions() { const { beginAtZero } = this.options; const { minDefined , maxDefined } = this.getUserBounds(); let { min , max } = this; const setMin = (v)=>min = minDefined ? min : v; const setMax = (v)=>max = maxDefined ? max : v; if (beginAtZero) { const minSign = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.s)(min); const maxSign = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.s)(max); if (minSign < 0 && maxSign < 0) { setMax(0); } else if (minSign > 0 && maxSign > 0) { setMin(0); } } if (min === max) { let offset = max === 0 ? 1 : Math.abs(max * 0.05); setMax(max + offset); if (!beginAtZero) { setMin(min - offset); } } this.min = min; this.max = max; } getTickLimit() { const tickOpts = this.options.ticks; let { maxTicksLimit , stepSize } = tickOpts; let maxTicks; if (stepSize) { maxTicks = Math.ceil(this.max / stepSize) - Math.floor(this.min / stepSize) + 1; if (maxTicks > 1000) { console.warn(`scales.${this.id}.ticks.stepSize: ${stepSize} would result generating up to ${maxTicks} ticks. Limiting to 1000.`); maxTicks = 1000; } } else { maxTicks = this.computeTickLimit(); maxTicksLimit = maxTicksLimit || 11; } if (maxTicksLimit) { maxTicks = Math.min(maxTicksLimit, maxTicks); } return maxTicks; } computeTickLimit() { return Number.POSITIVE_INFINITY; } buildTicks() { const opts = this.options; const tickOpts = opts.ticks; let maxTicks = this.getTickLimit(); maxTicks = Math.max(2, maxTicks); const numericGeneratorOptions = { maxTicks, bounds: opts.bounds, min: opts.min, max: opts.max, precision: tickOpts.precision, step: tickOpts.stepSize, count: tickOpts.count, maxDigits: this._maxDigits(), horizontal: this.isHorizontal(), minRotation: tickOpts.minRotation || 0, includeBounds: tickOpts.includeBounds !== false }; const dataRange = this._range || this; const ticks = generateTicks$1(numericGeneratorOptions, dataRange); if (opts.bounds === 'ticks') { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aH)(ticks, this, 'value'); } if (opts.reverse) { ticks.reverse(); this.start = this.max; this.end = this.min; } else { this.start = this.min; this.end = this.max; } return ticks; } configure() { const ticks = this.ticks; let start = this.min; let end = this.max; super.configure(); if (this.options.offset && ticks.length) { const offset = (end - start) / Math.max(ticks.length - 1, 1) / 2; start -= offset; end += offset; } this._startValue = start; this._endValue = end; this._valueRange = end - start; } getLabelForValue(value) { return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.o)(value, this.chart.options.locale, this.options.ticks.format); } } class LinearScale extends LinearScaleBase { static id = 'linear'; static defaults = { ticks: { callback: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aM.formatters.numeric } }; determineDataLimits() { const { min , max } = this.getMinMax(true); this.min = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(min) ? min : 0; this.max = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(max) ? max : 1; this.handleTickRangeOptions(); } computeTickLimit() { const horizontal = this.isHorizontal(); const length = horizontal ? this.width : this.height; const minRotation = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.options.ticks.minRotation); const ratio = (horizontal ? Math.sin(minRotation) : Math.cos(minRotation)) || 0.001; const tickFont = this._resolveTickFontOptions(0); return Math.ceil(length / Math.min(40, tickFont.lineHeight / ratio)); } getPixelForValue(value) { return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange); } getValueForPixel(pixel) { return this._startValue + this.getDecimalForPixel(pixel) * this._valueRange; } } const log10Floor = (v)=>Math.floor((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aN)(v)); const changeExponent = (v, m)=>Math.pow(10, log10Floor(v) + m); function isMajor(tickVal) { const remain = tickVal / Math.pow(10, log10Floor(tickVal)); return remain === 1; } function steps(min, max, rangeExp) { const rangeStep = Math.pow(10, rangeExp); const start = Math.floor(min / rangeStep); const end = Math.ceil(max / rangeStep); return end - start; } function startExp(min, max) { const range = max - min; let rangeExp = log10Floor(range); while(steps(min, max, rangeExp) > 10){ rangeExp++; } while(steps(min, max, rangeExp) < 10){ rangeExp--; } return Math.min(rangeExp, log10Floor(min)); } function generateTicks(generationOptions, { min , max }) { min = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(generationOptions.min, min); const ticks = []; const minExp = log10Floor(min); let exp = startExp(min, max); let precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1; const stepSize = Math.pow(10, exp); const base = minExp > exp ? Math.pow(10, minExp) : 0; const start = Math.round((min - base) * precision) / precision; const offset = Math.floor((min - base) / stepSize / 10) * stepSize * 10; let significand = Math.floor((start - offset) / Math.pow(10, exp)); let value = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(generationOptions.min, Math.round((base + offset + significand * Math.pow(10, exp)) * precision) / precision); while(value < max){ ticks.push({ value, major: isMajor(value), significand }); if (significand >= 10) { significand = significand < 15 ? 15 : 20; } else { significand++; } if (significand >= 20) { exp++; significand = 2; precision = exp >= 0 ? 1 : precision; } value = Math.round((base + offset + significand * Math.pow(10, exp)) * precision) / precision; } const lastTick = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.O)(generationOptions.max, value); ticks.push({ value: lastTick, major: isMajor(lastTick), significand }); return ticks; } class LogarithmicScale extends Scale { static id = 'logarithmic'; static defaults = { ticks: { callback: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aM.formatters.logarithmic, major: { enabled: true } } }; constructor(cfg){ super(cfg); this.start = undefined; this.end = undefined; this._startValue = undefined; this._valueRange = 0; } parse(raw, index) { const value = LinearScaleBase.prototype.parse.apply(this, [ raw, index ]); if (value === 0) { this._zero = true; return undefined; } return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(value) && value > 0 ? value : null; } determineDataLimits() { const { min , max } = this.getMinMax(true); this.min = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(min) ? Math.max(0, min) : null; this.max = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(max) ? Math.max(0, max) : null; if (this.options.beginAtZero) { this._zero = true; } if (this._zero && this.min !== this._suggestedMin && !(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(this._userMin)) { this.min = min === changeExponent(this.min, 0) ? changeExponent(this.min, -1) : changeExponent(this.min, 0); } this.handleTickRangeOptions(); } handleTickRangeOptions() { const { minDefined , maxDefined } = this.getUserBounds(); let min = this.min; let max = this.max; const setMin = (v)=>min = minDefined ? min : v; const setMax = (v)=>max = maxDefined ? max : v; if (min === max) { if (min <= 0) { setMin(1); setMax(10); } else { setMin(changeExponent(min, -1)); setMax(changeExponent(max, +1)); } } if (min <= 0) { setMin(changeExponent(max, -1)); } if (max <= 0) { setMax(changeExponent(min, +1)); } this.min = min; this.max = max; } buildTicks() { const opts = this.options; const generationOptions = { min: this._userMin, max: this._userMax }; const ticks = generateTicks(generationOptions, this); if (opts.bounds === 'ticks') { (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aH)(ticks, this, 'value'); } if (opts.reverse) { ticks.reverse(); this.start = this.max; this.end = this.min; } else { this.start = this.min; this.end = this.max; } return ticks; } getLabelForValue(value) { return value === undefined ? '0' : (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.o)(value, this.chart.options.locale, this.options.ticks.format); } configure() { const start = this.min; super.configure(); this._startValue = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aN)(start); this._valueRange = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aN)(this.max) - (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aN)(start); } getPixelForValue(value) { if (value === undefined || value === 0) { value = this.min; } if (value === null || isNaN(value)) { return NaN; } return this.getPixelForDecimal(value === this.min ? 0 : ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aN)(value) - this._startValue) / this._valueRange); } getValueForPixel(pixel) { const decimal = this.getDecimalForPixel(pixel); return Math.pow(10, this._startValue + decimal * this._valueRange); } } function getTickBackdropHeight(opts) { const tickOpts = opts.ticks; if (tickOpts.display && opts.display) { const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(tickOpts.backdropPadding); return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(tickOpts.font && tickOpts.font.size, _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.d.font.size) + padding.height; } return 0; } function measureLabelSize(ctx, font, label) { label = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.b)(label) ? label : [ label ]; return { w: (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aO)(ctx, font.string, label), h: label.length * font.lineHeight }; } function determineLimits(angle, pos, size, min, max) { if (angle === min || angle === max) { return { start: pos - size / 2, end: pos + size / 2 }; } else if (angle < min || angle > max) { return { start: pos - size, end: pos }; } return { start: pos, end: pos + size }; } function fitWithPointLabels(scale) { const orig = { l: scale.left + scale._padding.left, r: scale.right - scale._padding.right, t: scale.top + scale._padding.top, b: scale.bottom - scale._padding.bottom }; const limits = Object.assign({}, orig); const labelSizes = []; const padding = []; const valueCount = scale._pointLabels.length; const pointLabelOpts = scale.options.pointLabels; const additionalAngle = pointLabelOpts.centerPointLabels ? _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / valueCount : 0; for(let i = 0; i < valueCount; i++){ const opts = pointLabelOpts.setContext(scale.getPointLabelContext(i)); padding[i] = opts.padding; const pointPosition = scale.getPointPosition(i, scale.drawingArea + padding[i], additionalAngle); const plFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(opts.font); const textSize = measureLabelSize(scale.ctx, plFont, scale._pointLabels[i]); labelSizes[i] = textSize; const angleRadians = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(scale.getIndexAngle(i) + additionalAngle); const angle = Math.round((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.U)(angleRadians)); const hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180); const vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270); updateLimits(limits, orig, angleRadians, hLimits, vLimits); } scale.setCenterPoint(orig.l - limits.l, limits.r - orig.r, orig.t - limits.t, limits.b - orig.b); scale._pointLabelItems = buildPointLabelItems(scale, labelSizes, padding); } function updateLimits(limits, orig, angle, hLimits, vLimits) { const sin = Math.abs(Math.sin(angle)); const cos = Math.abs(Math.cos(angle)); let x = 0; let y = 0; if (hLimits.start < orig.l) { x = (orig.l - hLimits.start) / sin; limits.l = Math.min(limits.l, orig.l - x); } else if (hLimits.end > orig.r) { x = (hLimits.end - orig.r) / sin; limits.r = Math.max(limits.r, orig.r + x); } if (vLimits.start < orig.t) { y = (orig.t - vLimits.start) / cos; limits.t = Math.min(limits.t, orig.t - y); } else if (vLimits.end > orig.b) { y = (vLimits.end - orig.b) / cos; limits.b = Math.max(limits.b, orig.b + y); } } function createPointLabelItem(scale, index, itemOpts) { const outerDistance = scale.drawingArea; const { extra , additionalAngle , padding , size } = itemOpts; const pointLabelPosition = scale.getPointPosition(index, outerDistance + extra + padding, additionalAngle); const angle = Math.round((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.U)((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(pointLabelPosition.angle + _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H))); const y = yForAngle(pointLabelPosition.y, size.h, angle); const textAlign = getTextAlignForAngle(angle); const left = leftForTextAlign(pointLabelPosition.x, size.w, textAlign); return { visible: true, x: pointLabelPosition.x, y, textAlign, left, top: y, right: left + size.w, bottom: y + size.h }; } function isNotOverlapped(item, area) { if (!area) { return true; } const { left , top , right , bottom } = item; const apexesInArea = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)({ x: left, y: top }, area) || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)({ x: left, y: bottom }, area) || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)({ x: right, y: top }, area) || (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.C)({ x: right, y: bottom }, area); return !apexesInArea; } function buildPointLabelItems(scale, labelSizes, padding) { const items = []; const valueCount = scale._pointLabels.length; const opts = scale.options; const { centerPointLabels , display } = opts.pointLabels; const itemOpts = { extra: getTickBackdropHeight(opts) / 2, additionalAngle: centerPointLabels ? _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.P / valueCount : 0 }; let area; for(let i = 0; i < valueCount; i++){ itemOpts.padding = padding[i]; itemOpts.size = labelSizes[i]; const item = createPointLabelItem(scale, i, itemOpts); items.push(item); if (display === 'auto') { item.visible = isNotOverlapped(item, area); if (item.visible) { area = item; } } } return items; } function getTextAlignForAngle(angle) { if (angle === 0 || angle === 180) { return 'center'; } else if (angle < 180) { return 'left'; } return 'right'; } function leftForTextAlign(x, w, align) { if (align === 'right') { x -= w; } else if (align === 'center') { x -= w / 2; } return x; } function yForAngle(y, h, angle) { if (angle === 90 || angle === 270) { y -= h / 2; } else if (angle > 270 || angle < 90) { y -= h; } return y; } function drawPointLabelBox(ctx, opts, item) { const { left , top , right , bottom } = item; const { backdropColor } = opts; if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(backdropColor)) { const borderRadius = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ay)(opts.borderRadius); const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(opts.backdropPadding); ctx.fillStyle = backdropColor; const backdropLeft = left - padding.left; const backdropTop = top - padding.top; const backdropWidth = right - left + padding.width; const backdropHeight = bottom - top + padding.height; if (Object.values(borderRadius).some((v)=>v !== 0)) { ctx.beginPath(); (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aw)(ctx, { x: backdropLeft, y: backdropTop, w: backdropWidth, h: backdropHeight, radius: borderRadius }); ctx.fill(); } else { ctx.fillRect(backdropLeft, backdropTop, backdropWidth, backdropHeight); } } } function drawPointLabels(scale, labelCount) { const { ctx , options: { pointLabels } } = scale; for(let i = labelCount - 1; i >= 0; i--){ const item = scale._pointLabelItems[i]; if (!item.visible) { continue; } const optsAtIndex = pointLabels.setContext(scale.getPointLabelContext(i)); drawPointLabelBox(ctx, optsAtIndex, item); const plFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(optsAtIndex.font); const { x , y , textAlign } = item; (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, scale._pointLabels[i], x, y + plFont.lineHeight / 2, plFont, { color: optsAtIndex.color, textAlign: textAlign, textBaseline: 'middle' }); } } function pathRadiusLine(scale, radius, circular, labelCount) { const { ctx } = scale; if (circular) { ctx.arc(scale.xCenter, scale.yCenter, radius, 0, _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T); } else { let pointPosition = scale.getPointPosition(0, radius); ctx.moveTo(pointPosition.x, pointPosition.y); for(let i = 1; i < labelCount; i++){ pointPosition = scale.getPointPosition(i, radius); ctx.lineTo(pointPosition.x, pointPosition.y); } } } function drawRadiusLine(scale, gridLineOpts, radius, labelCount, borderOpts) { const ctx = scale.ctx; const circular = gridLineOpts.circular; const { color , lineWidth } = gridLineOpts; if (!circular && !labelCount || !color || !lineWidth || radius < 0) { return; } ctx.save(); ctx.strokeStyle = color; ctx.lineWidth = lineWidth; ctx.setLineDash(borderOpts.dash || []); ctx.lineDashOffset = borderOpts.dashOffset; ctx.beginPath(); pathRadiusLine(scale, radius, circular, labelCount); ctx.closePath(); ctx.stroke(); ctx.restore(); } function createPointLabelContext(parent, index, label) { return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.j)(parent, { label, index, type: 'pointLabel' }); } class RadialLinearScale extends LinearScaleBase { static id = 'radialLinear'; static defaults = { display: true, animate: true, position: 'chartArea', angleLines: { display: true, lineWidth: 1, borderDash: [], borderDashOffset: 0.0 }, grid: { circular: false }, startAngle: 0, ticks: { showLabelBackdrop: true, callback: _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aM.formatters.numeric }, pointLabels: { backdropColor: undefined, backdropPadding: 2, display: true, font: { size: 10 }, callback (label) { return label; }, padding: 5, centerPointLabels: false } }; static defaultRoutes = { 'angleLines.color': 'borderColor', 'pointLabels.color': 'color', 'ticks.color': 'color' }; static descriptors = { angleLines: { _fallback: 'grid' } }; constructor(cfg){ super(cfg); this.xCenter = undefined; this.yCenter = undefined; this.drawingArea = undefined; this._pointLabels = []; this._pointLabelItems = []; } setDimensions() { const padding = this._padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(getTickBackdropHeight(this.options) / 2); const w = this.width = this.maxWidth - padding.width; const h = this.height = this.maxHeight - padding.height; this.xCenter = Math.floor(this.left + w / 2 + padding.left); this.yCenter = Math.floor(this.top + h / 2 + padding.top); this.drawingArea = Math.floor(Math.min(w, h) / 2); } determineDataLimits() { const { min , max } = this.getMinMax(false); this.min = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(min) && !isNaN(min) ? min : 0; this.max = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(max) && !isNaN(max) ? max : 0; this.handleTickRangeOptions(); } computeTickLimit() { return Math.ceil(this.drawingArea / getTickBackdropHeight(this.options)); } generateTickLabels(ticks) { LinearScaleBase.prototype.generateTickLabels.call(this, ticks); this._pointLabels = this.getLabels().map((value, index)=>{ const label = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(this.options.pointLabels.callback, [ value, index ], this); return label || label === 0 ? label : ''; }).filter((v, i)=>this.chart.getDataVisibility(i)); } fit() { const opts = this.options; if (opts.display && opts.pointLabels.display) { fitWithPointLabels(this); } else { this.setCenterPoint(0, 0, 0, 0); } } setCenterPoint(leftMovement, rightMovement, topMovement, bottomMovement) { this.xCenter += Math.floor((leftMovement - rightMovement) / 2); this.yCenter += Math.floor((topMovement - bottomMovement) / 2); this.drawingArea -= Math.min(this.drawingArea / 2, Math.max(leftMovement, rightMovement, topMovement, bottomMovement)); } getIndexAngle(index) { const angleMultiplier = _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.T / (this._pointLabels.length || 1); const startAngle = this.options.startAngle || 0; return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.al)(index * angleMultiplier + (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(startAngle)); } getDistanceFromCenterForValue(value) { if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(value)) { return NaN; } const scalingFactor = this.drawingArea / (this.max - this.min); if (this.options.reverse) { return (this.max - value) * scalingFactor; } return (value - this.min) * scalingFactor; } getValueForDistanceFromCenter(distance) { if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(distance)) { return NaN; } const scaledDistance = distance / (this.drawingArea / (this.max - this.min)); return this.options.reverse ? this.max - scaledDistance : this.min + scaledDistance; } getPointLabelContext(index) { const pointLabels = this._pointLabels || []; if (index >= 0 && index < pointLabels.length) { const pointLabel = pointLabels[index]; return createPointLabelContext(this.getContext(), index, pointLabel); } } getPointPosition(index, distanceFromCenter, additionalAngle = 0) { const angle = this.getIndexAngle(index) - _chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.H + additionalAngle; return { x: Math.cos(angle) * distanceFromCenter + this.xCenter, y: Math.sin(angle) * distanceFromCenter + this.yCenter, angle }; } getPointPositionForValue(index, value) { return this.getPointPosition(index, this.getDistanceFromCenterForValue(value)); } getBasePosition(index) { return this.getPointPositionForValue(index || 0, this.getBaseValue()); } getPointLabelPosition(index) { const { left , top , right , bottom } = this._pointLabelItems[index]; return { left, top, right, bottom }; } drawBackground() { const { backgroundColor , grid: { circular } } = this.options; if (backgroundColor) { const ctx = this.ctx; ctx.save(); ctx.beginPath(); pathRadiusLine(this, this.getDistanceFromCenterForValue(this._endValue), circular, this._pointLabels.length); ctx.closePath(); ctx.fillStyle = backgroundColor; ctx.fill(); ctx.restore(); } } drawGrid() { const ctx = this.ctx; const opts = this.options; const { angleLines , grid , border } = opts; const labelCount = this._pointLabels.length; let i, offset, position; if (opts.pointLabels.display) { drawPointLabels(this, labelCount); } if (grid.display) { this.ticks.forEach((tick, index)=>{ if (index !== 0 || index === 0 && this.min < 0) { offset = this.getDistanceFromCenterForValue(tick.value); const context = this.getContext(index); const optsAtIndex = grid.setContext(context); const optsAtIndexBorder = border.setContext(context); drawRadiusLine(this, optsAtIndex, offset, labelCount, optsAtIndexBorder); } }); } if (angleLines.display) { ctx.save(); for(i = labelCount - 1; i >= 0; i--){ const optsAtIndex = angleLines.setContext(this.getPointLabelContext(i)); const { color , lineWidth } = optsAtIndex; if (!lineWidth || !color) { continue; } ctx.lineWidth = lineWidth; ctx.strokeStyle = color; ctx.setLineDash(optsAtIndex.borderDash); ctx.lineDashOffset = optsAtIndex.borderDashOffset; offset = this.getDistanceFromCenterForValue(opts.reverse ? this.min : this.max); position = this.getPointPosition(i, offset); ctx.beginPath(); ctx.moveTo(this.xCenter, this.yCenter); ctx.lineTo(position.x, position.y); ctx.stroke(); } ctx.restore(); } } drawBorder() {} drawLabels() { const ctx = this.ctx; const opts = this.options; const tickOpts = opts.ticks; if (!tickOpts.display) { return; } const startAngle = this.getIndexAngle(0); let offset, width; ctx.save(); ctx.translate(this.xCenter, this.yCenter); ctx.rotate(startAngle); ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; this.ticks.forEach((tick, index)=>{ if (index === 0 && this.min >= 0 && !opts.reverse) { return; } const optsAtIndex = tickOpts.setContext(this.getContext(index)); const tickFont = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.a0)(optsAtIndex.font); offset = this.getDistanceFromCenterForValue(this.ticks[index].value); if (optsAtIndex.showLabelBackdrop) { ctx.font = tickFont.string; width = ctx.measureText(tick.label).width; ctx.fillStyle = optsAtIndex.backdropColor; const padding = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.E)(optsAtIndex.backdropPadding); ctx.fillRect(-width / 2 - padding.left, -offset - tickFont.size / 2 - padding.top, width + padding.width, tickFont.size + padding.height); } (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Z)(ctx, tick.label, 0, -offset, tickFont, { color: optsAtIndex.color, strokeColor: optsAtIndex.textStrokeColor, strokeWidth: optsAtIndex.textStrokeWidth }); }); ctx.restore(); } drawTitle() {} } const INTERVALS = { millisecond: { common: true, size: 1, steps: 1000 }, second: { common: true, size: 1000, steps: 60 }, minute: { common: true, size: 60000, steps: 60 }, hour: { common: true, size: 3600000, steps: 24 }, day: { common: true, size: 86400000, steps: 30 }, week: { common: false, size: 604800000, steps: 4 }, month: { common: true, size: 2.628e9, steps: 12 }, quarter: { common: false, size: 7.884e9, steps: 4 }, year: { common: true, size: 3.154e10 } }; const UNITS = /* #__PURE__ */ Object.keys(INTERVALS); function sorter(a, b) { return a - b; } function parse(scale, input) { if ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.k)(input)) { return null; } const adapter = scale._adapter; const { parser , round , isoWeekday } = scale._parseOpts; let value = input; if (typeof parser === 'function') { value = parser(value); } if (!(0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(value)) { value = typeof parser === 'string' ? adapter.parse(value, parser) : adapter.parse(value); } if (value === null) { return null; } if (round) { value = round === 'week' && ((0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.x)(isoWeekday) || isoWeekday === true) ? adapter.startOf(value, 'isoWeek', isoWeekday) : adapter.startOf(value, round); } return +value; } function determineUnitForAutoTicks(minUnit, min, max, capacity) { const ilen = UNITS.length; for(let i = UNITS.indexOf(minUnit); i < ilen - 1; ++i){ const interval = INTERVALS[UNITS[i]]; const factor = interval.steps ? interval.steps : Number.MAX_SAFE_INTEGER; if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) { return UNITS[i]; } } return UNITS[ilen - 1]; } function determineUnitForFormatting(scale, numTicks, minUnit, min, max) { for(let i = UNITS.length - 1; i >= UNITS.indexOf(minUnit); i--){ const unit = UNITS[i]; if (INTERVALS[unit].common && scale._adapter.diff(max, min, unit) >= numTicks - 1) { return unit; } } return UNITS[minUnit ? UNITS.indexOf(minUnit) : 0]; } function determineMajorUnit(unit) { for(let i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i){ if (INTERVALS[UNITS[i]].common) { return UNITS[i]; } } } function addTick(ticks, time, timestamps) { if (!timestamps) { ticks[time] = true; } else if (timestamps.length) { const { lo , hi } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aQ)(timestamps, time); const timestamp = timestamps[lo] >= time ? timestamps[lo] : timestamps[hi]; ticks[timestamp] = true; } } function setMajorTicks(scale, ticks, map, majorUnit) { const adapter = scale._adapter; const first = +adapter.startOf(ticks[0].value, majorUnit); const last = ticks[ticks.length - 1].value; let major, index; for(major = first; major <= last; major = +adapter.add(major, 1, majorUnit)){ index = map[major]; if (index >= 0) { ticks[index].major = true; } } return ticks; } function ticksFromTimestamps(scale, values, majorUnit) { const ticks = []; const map = {}; const ilen = values.length; let i, value; for(i = 0; i < ilen; ++i){ value = values[i]; map[value] = i; ticks.push({ value, major: false }); } return ilen === 0 || !majorUnit ? ticks : setMajorTicks(scale, ticks, map, majorUnit); } class TimeScale extends Scale { static id = 'time'; static defaults = { bounds: 'data', adapters: {}, time: { parser: false, unit: false, round: false, isoWeekday: false, minUnit: 'millisecond', displayFormats: {} }, ticks: { source: 'auto', callback: false, major: { enabled: false } } }; constructor(props){ super(props); this._cache = { data: [], labels: [], all: [] }; this._unit = 'day'; this._majorUnit = undefined; this._offsets = {}; this._normalized = false; this._parseOpts = undefined; } init(scaleOpts, opts = {}) { const time = scaleOpts.time || (scaleOpts.time = {}); const adapter = this._adapter = new adapters._date(scaleOpts.adapters.date); adapter.init(opts); (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.ab)(time.displayFormats, adapter.formats()); this._parseOpts = { parser: time.parser, round: time.round, isoWeekday: time.isoWeekday }; super.init(scaleOpts); this._normalized = opts.normalized; } parse(raw, index) { if (raw === undefined) { return null; } return parse(this, raw); } beforeLayout() { super.beforeLayout(); this._cache = { data: [], labels: [], all: [] }; } determineDataLimits() { const options = this.options; const adapter = this._adapter; const unit = options.time.unit || 'day'; let { min , max , minDefined , maxDefined } = this.getUserBounds(); function _applyBounds(bounds) { if (!minDefined && !isNaN(bounds.min)) { min = Math.min(min, bounds.min); } if (!maxDefined && !isNaN(bounds.max)) { max = Math.max(max, bounds.max); } } if (!minDefined || !maxDefined) { _applyBounds(this._getLabelBounds()); if (options.bounds !== 'ticks' || options.ticks.source !== 'labels') { _applyBounds(this.getMinMax(false)); } } min = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(min) && !isNaN(min) ? min : +adapter.startOf(Date.now(), unit); max = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.g)(max) && !isNaN(max) ? max : +adapter.endOf(Date.now(), unit) + 1; this.min = Math.min(min, max - 1); this.max = Math.max(min + 1, max); } _getLabelBounds() { const arr = this.getLabelTimestamps(); let min = Number.POSITIVE_INFINITY; let max = Number.NEGATIVE_INFINITY; if (arr.length) { min = arr[0]; max = arr[arr.length - 1]; } return { min, max }; } buildTicks() { const options = this.options; const timeOpts = options.time; const tickOpts = options.ticks; const timestamps = tickOpts.source === 'labels' ? this.getLabelTimestamps() : this._generate(); if (options.bounds === 'ticks' && timestamps.length) { this.min = this._userMin || timestamps[0]; this.max = this._userMax || timestamps[timestamps.length - 1]; } const min = this.min; const max = this.max; const ticks = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.aP)(timestamps, min, max); this._unit = timeOpts.unit || (tickOpts.autoSkip ? determineUnitForAutoTicks(timeOpts.minUnit, this.min, this.max, this._getLabelCapacity(min)) : determineUnitForFormatting(this, ticks.length, timeOpts.minUnit, this.min, this.max)); this._majorUnit = !tickOpts.major.enabled || this._unit === 'year' ? undefined : determineMajorUnit(this._unit); this.initOffsets(timestamps); if (options.reverse) { ticks.reverse(); } return ticksFromTimestamps(this, ticks, this._majorUnit); } afterAutoSkip() { if (this.options.offsetAfterAutoskip) { this.initOffsets(this.ticks.map((tick)=>+tick.value)); } } initOffsets(timestamps = []) { let start = 0; let end = 0; let first, last; if (this.options.offset && timestamps.length) { first = this.getDecimalForValue(timestamps[0]); if (timestamps.length === 1) { start = 1 - first; } else { start = (this.getDecimalForValue(timestamps[1]) - first) / 2; } last = this.getDecimalForValue(timestamps[timestamps.length - 1]); if (timestamps.length === 1) { end = last; } else { end = (last - this.getDecimalForValue(timestamps[timestamps.length - 2])) / 2; } } const limit = timestamps.length < 3 ? 0.5 : 0.25; start = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(start, 0, limit); end = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.S)(end, 0, limit); this._offsets = { start, end, factor: 1 / (start + 1 + end) }; } _generate() { const adapter = this._adapter; const min = this.min; const max = this.max; const options = this.options; const timeOpts = options.time; const minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, this._getLabelCapacity(min)); const stepSize = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.v)(options.ticks.stepSize, 1); const weekday = minor === 'week' ? timeOpts.isoWeekday : false; const hasWeekday = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.x)(weekday) || weekday === true; const ticks = {}; let first = min; let time, count; if (hasWeekday) { first = +adapter.startOf(first, 'isoWeek', weekday); } first = +adapter.startOf(first, hasWeekday ? 'day' : minor); if (adapter.diff(max, min, minor) > 100000 * stepSize) { throw new Error(min + ' and ' + max + ' are too far apart with stepSize of ' + stepSize + ' ' + minor); } const timestamps = options.ticks.source === 'data' && this.getDataTimestamps(); for(time = first, count = 0; time < max; time = +adapter.add(time, stepSize, minor), count++){ addTick(ticks, time, timestamps); } if (time === max || options.bounds === 'ticks' || count === 1) { addTick(ticks, time, timestamps); } return Object.keys(ticks).sort(sorter).map((x)=>+x); } getLabelForValue(value) { const adapter = this._adapter; const timeOpts = this.options.time; if (timeOpts.tooltipFormat) { return adapter.format(value, timeOpts.tooltipFormat); } return adapter.format(value, timeOpts.displayFormats.datetime); } format(value, format) { const options = this.options; const formats = options.time.displayFormats; const unit = this._unit; const fmt = format || formats[unit]; return this._adapter.format(value, fmt); } _tickFormatFunction(time, index, ticks, format) { const options = this.options; const formatter = options.ticks.callback; if (formatter) { return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.Q)(formatter, [ time, index, ticks ], this); } const formats = options.time.displayFormats; const unit = this._unit; const majorUnit = this._majorUnit; const minorFormat = unit && formats[unit]; const majorFormat = majorUnit && formats[majorUnit]; const tick = ticks[index]; const major = majorUnit && majorFormat && tick && tick.major; return this._adapter.format(time, format || (major ? majorFormat : minorFormat)); } generateTickLabels(ticks) { let i, ilen, tick; for(i = 0, ilen = ticks.length; i < ilen; ++i){ tick = ticks[i]; tick.label = this._tickFormatFunction(tick.value, i, ticks); } } getDecimalForValue(value) { return value === null ? NaN : (value - this.min) / (this.max - this.min); } getPixelForValue(value) { const offsets = this._offsets; const pos = this.getDecimalForValue(value); return this.getPixelForDecimal((offsets.start + pos) * offsets.factor); } getValueForPixel(pixel) { const offsets = this._offsets; const pos = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end; return this.min + pos * (this.max - this.min); } _getLabelSize(label) { const ticksOpts = this.options.ticks; const tickLabelWidth = this.ctx.measureText(label).width; const angle = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.t)(this.isHorizontal() ? ticksOpts.maxRotation : ticksOpts.minRotation); const cosRotation = Math.cos(angle); const sinRotation = Math.sin(angle); const tickFontSize = this._resolveTickFontOptions(0).size; return { w: tickLabelWidth * cosRotation + tickFontSize * sinRotation, h: tickLabelWidth * sinRotation + tickFontSize * cosRotation }; } _getLabelCapacity(exampleTime) { const timeOpts = this.options.time; const displayFormats = timeOpts.displayFormats; const format = displayFormats[timeOpts.unit] || displayFormats.millisecond; const exampleLabel = this._tickFormatFunction(exampleTime, 0, ticksFromTimestamps(this, [ exampleTime ], this._majorUnit), format); const size = this._getLabelSize(exampleLabel); const capacity = Math.floor(this.isHorizontal() ? this.width / size.w : this.height / size.h) - 1; return capacity > 0 ? capacity : 1; } getDataTimestamps() { let timestamps = this._cache.data || []; let i, ilen; if (timestamps.length) { return timestamps; } const metas = this.getMatchingVisibleMetas(); if (this._normalized && metas.length) { return this._cache.data = metas[0].controller.getAllParsedValues(this); } for(i = 0, ilen = metas.length; i < ilen; ++i){ timestamps = timestamps.concat(metas[i].controller.getAllParsedValues(this)); } return this._cache.data = this.normalize(timestamps); } getLabelTimestamps() { const timestamps = this._cache.labels || []; let i, ilen; if (timestamps.length) { return timestamps; } const labels = this.getLabels(); for(i = 0, ilen = labels.length; i < ilen; ++i){ timestamps.push(parse(this, labels[i])); } return this._cache.labels = this._normalized ? timestamps : this.normalize(timestamps); } normalize(values) { return (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__._)(values.sort(sorter)); } } function interpolate(table, val, reverse) { let lo = 0; let hi = table.length - 1; let prevSource, nextSource, prevTarget, nextTarget; if (reverse) { if (val >= table[lo].pos && val <= table[hi].pos) { ({ lo , hi } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.B)(table, 'pos', val)); } ({ pos: prevSource , time: prevTarget } = table[lo]); ({ pos: nextSource , time: nextTarget } = table[hi]); } else { if (val >= table[lo].time && val <= table[hi].time) { ({ lo , hi } = (0,_chunks_helpers_dataset_js__WEBPACK_IMPORTED_MODULE_0__.B)(table, 'time', val)); } ({ time: prevSource , pos: prevTarget } = table[lo]); ({ time: nextSource , pos: nextTarget } = table[hi]); } const span = nextSource - prevSource; return span ? prevTarget + (nextTarget - prevTarget) * (val - prevSource) / span : prevTarget; } class TimeSeriesScale extends TimeScale { static id = 'timeseries'; static defaults = TimeScale.defaults; constructor(props){ super(props); this._table = []; this._minPos = undefined; this._tableRange = undefined; } initOffsets() { const timestamps = this._getTimestampsForTable(); const table = this._table = this.buildLookupTable(timestamps); this._minPos = interpolate(table, this.min); this._tableRange = interpolate(table, this.max) - this._minPos; super.initOffsets(timestamps); } buildLookupTable(timestamps) { const { min , max } = this; const items = []; const table = []; let i, ilen, prev, curr, next; for(i = 0, ilen = timestamps.length; i < ilen; ++i){ curr = timestamps[i]; if (curr >= min && curr <= max) { items.push(curr); } } if (items.length < 2) { return [ { time: min, pos: 0 }, { time: max, pos: 1 } ]; } for(i = 0, ilen = items.length; i < ilen; ++i){ next = items[i + 1]; prev = items[i - 1]; curr = items[i]; if (Math.round((next + prev) / 2) !== curr) { table.push({ time: curr, pos: i / (ilen - 1) }); } } return table; } _generate() { const min = this.min; const max = this.max; let timestamps = super.getDataTimestamps(); if (!timestamps.includes(min) || !timestamps.length) { timestamps.splice(0, 0, min); } if (!timestamps.includes(max) || timestamps.length === 1) { timestamps.push(max); } return timestamps.sort((a, b)=>a - b); } _getTimestampsForTable() { let timestamps = this._cache.all || []; if (timestamps.length) { return timestamps; } const data = this.getDataTimestamps(); const label = this.getLabelTimestamps(); if (data.length && label.length) { timestamps = this.normalize(data.concat(label)); } else { timestamps = data.length ? data : label; } timestamps = this._cache.all = timestamps; return timestamps; } getDecimalForValue(value) { return (interpolate(this._table, value) - this._minPos) / this._tableRange; } getValueForPixel(pixel) { const offsets = this._offsets; const decimal = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end; return interpolate(this._table, decimal * this._tableRange + this._minPos, true); } } var scales = /*#__PURE__*/Object.freeze({ __proto__: null, CategoryScale: CategoryScale, LinearScale: LinearScale, LogarithmicScale: LogarithmicScale, RadialLinearScale: RadialLinearScale, TimeScale: TimeScale, TimeSeriesScale: TimeSeriesScale }); const registerables = [ controllers, elements, plugins, scales ]; //# sourceMappingURL=chart.js.map /***/ }, /***/ "./node_modules/chart.js/dist/chunks/helpers.dataset.js" /*!**************************************************************!*\ !*** ./node_modules/chart.js/dist/chunks/helpers.dataset.js ***! \**************************************************************/ (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ $: () => (/* binding */ unclipArea), /* harmony export */ A: () => (/* binding */ _rlookupByKey), /* harmony export */ B: () => (/* binding */ _lookupByKey), /* harmony export */ C: () => (/* binding */ _isPointInArea), /* harmony export */ D: () => (/* binding */ getAngleFromPoint), /* harmony export */ E: () => (/* binding */ toPadding), /* harmony export */ F: () => (/* binding */ each), /* harmony export */ G: () => (/* binding */ getMaximumSize), /* harmony export */ H: () => (/* binding */ HALF_PI), /* harmony export */ I: () => (/* binding */ _getParentNode), /* harmony export */ J: () => (/* binding */ readUsedSize), /* harmony export */ K: () => (/* binding */ supportsEventListenerOptions), /* harmony export */ L: () => (/* binding */ throttled), /* harmony export */ M: () => (/* binding */ _isDomSupported), /* harmony export */ N: () => (/* binding */ _factorize), /* harmony export */ O: () => (/* binding */ finiteOrDefault), /* harmony export */ P: () => (/* binding */ PI), /* harmony export */ Q: () => (/* binding */ callback), /* harmony export */ R: () => (/* binding */ _addGrace), /* harmony export */ S: () => (/* binding */ _limitValue), /* harmony export */ T: () => (/* binding */ TAU), /* harmony export */ U: () => (/* binding */ toDegrees), /* harmony export */ V: () => (/* binding */ _measureText), /* harmony export */ W: () => (/* binding */ _int16Range), /* harmony export */ X: () => (/* binding */ _alignPixel), /* harmony export */ Y: () => (/* binding */ clipArea), /* harmony export */ Z: () => (/* binding */ renderText), /* harmony export */ _: () => (/* binding */ _arrayUnique), /* harmony export */ a: () => (/* binding */ resolve), /* harmony export */ a$: () => (/* binding */ getStyle), /* harmony export */ a0: () => (/* binding */ toFont), /* harmony export */ a1: () => (/* binding */ _toLeftRightCenter), /* harmony export */ a2: () => (/* binding */ _alignStartEnd), /* harmony export */ a3: () => (/* binding */ overrides), /* harmony export */ a4: () => (/* binding */ merge), /* harmony export */ a5: () => (/* binding */ _capitalize), /* harmony export */ a6: () => (/* binding */ descriptors), /* harmony export */ a7: () => (/* binding */ isFunction), /* harmony export */ a8: () => (/* binding */ _attachContext), /* harmony export */ a9: () => (/* binding */ _createResolver), /* harmony export */ aA: () => (/* binding */ getRtlAdapter), /* harmony export */ aB: () => (/* binding */ overrideTextDirection), /* harmony export */ aC: () => (/* binding */ _textX), /* harmony export */ aD: () => (/* binding */ restoreTextDirection), /* harmony export */ aE: () => (/* binding */ drawPointLegend), /* harmony export */ aF: () => (/* binding */ distanceBetweenPoints), /* harmony export */ aG: () => (/* binding */ noop), /* harmony export */ aH: () => (/* binding */ _setMinAndMaxByKey), /* harmony export */ aI: () => (/* binding */ niceNum), /* harmony export */ aJ: () => (/* binding */ almostWhole), /* harmony export */ aK: () => (/* binding */ almostEquals), /* harmony export */ aL: () => (/* binding */ _decimalPlaces), /* harmony export */ aM: () => (/* binding */ Ticks), /* harmony export */ aN: () => (/* binding */ log10), /* harmony export */ aO: () => (/* binding */ _longestText), /* harmony export */ aP: () => (/* binding */ _filterBetween), /* harmony export */ aQ: () => (/* binding */ _lookup), /* harmony export */ aR: () => (/* binding */ isPatternOrGradient), /* harmony export */ aS: () => (/* binding */ getHoverColor), /* harmony export */ aT: () => (/* binding */ clone), /* harmony export */ aU: () => (/* binding */ _merger), /* harmony export */ aV: () => (/* binding */ _mergerIf), /* harmony export */ aW: () => (/* binding */ _deprecated), /* harmony export */ aX: () => (/* binding */ _splitKey), /* harmony export */ aY: () => (/* binding */ toFontString), /* harmony export */ aZ: () => (/* binding */ splineCurve), /* harmony export */ a_: () => (/* binding */ splineCurveMonotone), /* harmony export */ aa: () => (/* binding */ _descriptors), /* harmony export */ ab: () => (/* binding */ mergeIf), /* harmony export */ ac: () => (/* binding */ uid), /* harmony export */ ad: () => (/* binding */ debounce), /* harmony export */ ae: () => (/* binding */ retinaScale), /* harmony export */ af: () => (/* binding */ clearCanvas), /* harmony export */ ag: () => (/* binding */ setsEqual), /* harmony export */ ah: () => (/* binding */ getDatasetClipArea), /* harmony export */ ai: () => (/* binding */ _elementsEqual), /* harmony export */ aj: () => (/* binding */ _isClickEvent), /* harmony export */ ak: () => (/* binding */ _isBetween), /* harmony export */ al: () => (/* binding */ _normalizeAngle), /* harmony export */ am: () => (/* binding */ _readValueToProps), /* harmony export */ an: () => (/* binding */ _updateBezierControlPoints), /* harmony export */ ao: () => (/* binding */ _computeSegments), /* harmony export */ ap: () => (/* binding */ _boundSegments), /* harmony export */ aq: () => (/* binding */ _steppedInterpolation), /* harmony export */ ar: () => (/* binding */ _bezierInterpolation), /* harmony export */ as: () => (/* binding */ _pointInLine), /* harmony export */ at: () => (/* binding */ _steppedLineTo), /* harmony export */ au: () => (/* binding */ _bezierCurveTo), /* harmony export */ av: () => (/* binding */ drawPoint), /* harmony export */ aw: () => (/* binding */ addRoundedRectPath), /* harmony export */ ax: () => (/* binding */ toTRBL), /* harmony export */ ay: () => (/* binding */ toTRBLCorners), /* harmony export */ az: () => (/* binding */ _boundSegment), /* harmony export */ b: () => (/* binding */ isArray), /* harmony export */ b0: () => (/* binding */ fontString), /* harmony export */ b1: () => (/* binding */ toLineHeight), /* harmony export */ b2: () => (/* binding */ PITAU), /* harmony export */ b3: () => (/* binding */ INFINITY), /* harmony export */ b4: () => (/* binding */ RAD_PER_DEG), /* harmony export */ b5: () => (/* binding */ QUARTER_PI), /* harmony export */ b6: () => (/* binding */ TWO_THIRDS_PI), /* harmony export */ b7: () => (/* binding */ _angleDiff), /* harmony export */ c: () => (/* binding */ color), /* harmony export */ d: () => (/* binding */ defaults), /* harmony export */ e: () => (/* binding */ effects), /* harmony export */ f: () => (/* binding */ resolveObjectKey), /* harmony export */ g: () => (/* binding */ isNumberFinite), /* harmony export */ h: () => (/* binding */ defined), /* harmony export */ i: () => (/* binding */ isObject), /* harmony export */ j: () => (/* binding */ createContext), /* harmony export */ k: () => (/* binding */ isNullOrUndef), /* harmony export */ l: () => (/* binding */ listenArrayEvents), /* harmony export */ m: () => (/* binding */ toPercentage), /* harmony export */ n: () => (/* binding */ toDimension), /* harmony export */ o: () => (/* binding */ formatNumber), /* harmony export */ p: () => (/* binding */ _angleBetween), /* harmony export */ q: () => (/* binding */ _getStartAndCountOfVisiblePoints), /* harmony export */ r: () => (/* binding */ requestAnimFrame), /* harmony export */ s: () => (/* binding */ sign), /* harmony export */ t: () => (/* binding */ toRadians), /* harmony export */ u: () => (/* binding */ unlistenArrayEvents), /* harmony export */ v: () => (/* binding */ valueOrDefault), /* harmony export */ w: () => (/* binding */ _scaleRangesChanged), /* harmony export */ x: () => (/* binding */ isNumber), /* harmony export */ y: () => (/* binding */ _parseObjectDataRadialScale), /* harmony export */ z: () => (/* binding */ getRelativePosition) /* harmony export */ }); /* harmony import */ var _kurkle_color__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @kurkle/color */ "./node_modules/@kurkle/color/dist/color.esm.js"); /*! * Chart.js v4.5.1 * https://www.chartjs.org * (c) 2025 Chart.js Contributors * Released under the MIT License */ /** * @namespace Chart.helpers */ /** * An empty function that can be used, for example, for optional callback. */ function noop() { /* noop */ } /** * Returns a unique id, sequentially generated from a global variable. */ const uid = (()=>{ let id = 0; return ()=>id++; })(); /** * Returns true if `value` is neither null nor undefined, else returns false. * @param value - The value to test. * @since 2.7.0 */ function isNullOrUndef(value) { return value === null || value === undefined; } /** * Returns true if `value` is an array (including typed arrays), else returns false. * @param value - The value to test. * @function */ function isArray(value) { if (Array.isArray && Array.isArray(value)) { return true; } const type = Object.prototype.toString.call(value); if (type.slice(0, 7) === '[object' && type.slice(-6) === 'Array]') { return true; } return false; } /** * Returns true if `value` is an object (excluding null), else returns false. * @param value - The value to test. * @since 2.7.0 */ function isObject(value) { return value !== null && Object.prototype.toString.call(value) === '[object Object]'; } /** * Returns true if `value` is a finite number, else returns false * @param value - The value to test. */ function isNumberFinite(value) { return (typeof value === 'number' || value instanceof Number) && isFinite(+value); } /** * Returns `value` if finite, else returns `defaultValue`. * @param value - The value to return if defined. * @param defaultValue - The value to return if `value` is not finite. */ function finiteOrDefault(value, defaultValue) { return isNumberFinite(value) ? value : defaultValue; } /** * Returns `value` if defined, else returns `defaultValue`. * @param value - The value to return if defined. * @param defaultValue - The value to return if `value` is undefined. */ function valueOrDefault(value, defaultValue) { return typeof value === 'undefined' ? defaultValue : value; } const toPercentage = (value, dimension)=>typeof value === 'string' && value.endsWith('%') ? parseFloat(value) / 100 : +value / dimension; const toDimension = (value, dimension)=>typeof value === 'string' && value.endsWith('%') ? parseFloat(value) / 100 * dimension : +value; /** * Calls `fn` with the given `args` in the scope defined by `thisArg` and returns the * value returned by `fn`. If `fn` is not a function, this method returns undefined. * @param fn - The function to call. * @param args - The arguments with which `fn` should be called. * @param [thisArg] - The value of `this` provided for the call to `fn`. */ function callback(fn, args, thisArg) { if (fn && typeof fn.call === 'function') { return fn.apply(thisArg, args); } } function each(loopable, fn, thisArg, reverse) { let i, len, keys; if (isArray(loopable)) { len = loopable.length; if (reverse) { for(i = len - 1; i >= 0; i--){ fn.call(thisArg, loopable[i], i); } } else { for(i = 0; i < len; i++){ fn.call(thisArg, loopable[i], i); } } } else if (isObject(loopable)) { keys = Object.keys(loopable); len = keys.length; for(i = 0; i < len; i++){ fn.call(thisArg, loopable[keys[i]], keys[i]); } } } /** * Returns true if the `a0` and `a1` arrays have the same content, else returns false. * @param a0 - The array to compare * @param a1 - The array to compare * @private */ function _elementsEqual(a0, a1) { let i, ilen, v0, v1; if (!a0 || !a1 || a0.length !== a1.length) { return false; } for(i = 0, ilen = a0.length; i < ilen; ++i){ v0 = a0[i]; v1 = a1[i]; if (v0.datasetIndex !== v1.datasetIndex || v0.index !== v1.index) { return false; } } return true; } /** * Returns a deep copy of `source` without keeping references on objects and arrays. * @param source - The value to clone. */ function clone(source) { if (isArray(source)) { return source.map(clone); } if (isObject(source)) { const target = Object.create(null); const keys = Object.keys(source); const klen = keys.length; let k = 0; for(; k < klen; ++k){ target[keys[k]] = clone(source[keys[k]]); } return target; } return source; } function isValidKey(key) { return [ '__proto__', 'prototype', 'constructor' ].indexOf(key) === -1; } /** * The default merger when Chart.helpers.merge is called without merger option. * Note(SB): also used by mergeConfig and mergeScaleConfig as fallback. * @private */ function _merger(key, target, source, options) { if (!isValidKey(key)) { return; } const tval = target[key]; const sval = source[key]; if (isObject(tval) && isObject(sval)) { // eslint-disable-next-line @typescript-eslint/no-use-before-define merge(tval, sval, options); } else { target[key] = clone(sval); } } function merge(target, source, options) { const sources = isArray(source) ? source : [ source ]; const ilen = sources.length; if (!isObject(target)) { return target; } options = options || {}; const merger = options.merger || _merger; let current; for(let i = 0; i < ilen; ++i){ current = sources[i]; if (!isObject(current)) { continue; } const keys = Object.keys(current); for(let k = 0, klen = keys.length; k < klen; ++k){ merger(keys[k], target, current, options); } } return target; } function mergeIf(target, source) { // eslint-disable-next-line @typescript-eslint/no-use-before-define return merge(target, source, { merger: _mergerIf }); } /** * Merges source[key] in target[key] only if target[key] is undefined. * @private */ function _mergerIf(key, target, source) { if (!isValidKey(key)) { return; } const tval = target[key]; const sval = source[key]; if (isObject(tval) && isObject(sval)) { mergeIf(tval, sval); } else if (!Object.prototype.hasOwnProperty.call(target, key)) { target[key] = clone(sval); } } /** * @private */ function _deprecated(scope, value, previous, current) { if (value !== undefined) { console.warn(scope + ': "' + previous + '" is deprecated. Please use "' + current + '" instead'); } } // resolveObjectKey resolver cache const keyResolvers = { // Chart.helpers.core resolveObjectKey should resolve empty key to root object '': (v)=>v, // default resolvers x: (o)=>o.x, y: (o)=>o.y }; /** * @private */ function _splitKey(key) { const parts = key.split('.'); const keys = []; let tmp = ''; for (const part of parts){ tmp += part; if (tmp.endsWith('\\')) { tmp = tmp.slice(0, -1) + '.'; } else { keys.push(tmp); tmp = ''; } } return keys; } function _getKeyResolver(key) { const keys = _splitKey(key); return (obj)=>{ for (const k of keys){ if (k === '') { break; } obj = obj && obj[k]; } return obj; }; } function resolveObjectKey(obj, key) { const resolver = keyResolvers[key] || (keyResolvers[key] = _getKeyResolver(key)); return resolver(obj); } /** * @private */ function _capitalize(str) { return str.charAt(0).toUpperCase() + str.slice(1); } const defined = (value)=>typeof value !== 'undefined'; const isFunction = (value)=>typeof value === 'function'; // Adapted from https://stackoverflow.com/questions/31128855/comparing-ecma6-sets-for-equality#31129384 const setsEqual = (a, b)=>{ if (a.size !== b.size) { return false; } for (const item of a){ if (!b.has(item)) { return false; } } return true; }; /** * @param e - The event * @private */ function _isClickEvent(e) { return e.type === 'mouseup' || e.type === 'click' || e.type === 'contextmenu'; } /** * @alias Chart.helpers.math * @namespace */ const PI = Math.PI; const TAU = 2 * PI; const PITAU = TAU + PI; const INFINITY = Number.POSITIVE_INFINITY; const RAD_PER_DEG = PI / 180; const HALF_PI = PI / 2; const QUARTER_PI = PI / 4; const TWO_THIRDS_PI = PI * 2 / 3; const log10 = Math.log10; const sign = Math.sign; function almostEquals(x, y, epsilon) { return Math.abs(x - y) < epsilon; } /** * Implementation of the nice number algorithm used in determining where axis labels will go */ function niceNum(range) { const roundedRange = Math.round(range); range = almostEquals(range, roundedRange, range / 1000) ? roundedRange : range; const niceRange = Math.pow(10, Math.floor(log10(range))); const fraction = range / niceRange; const niceFraction = fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 5 ? 5 : 10; return niceFraction * niceRange; } /** * Returns an array of factors sorted from 1 to sqrt(value) * @private */ function _factorize(value) { const result = []; const sqrt = Math.sqrt(value); let i; for(i = 1; i < sqrt; i++){ if (value % i === 0) { result.push(i); result.push(value / i); } } if (sqrt === (sqrt | 0)) { result.push(sqrt); } result.sort((a, b)=>a - b).pop(); return result; } /** * Verifies that attempting to coerce n to string or number won't throw a TypeError. */ function isNonPrimitive(n) { return typeof n === 'symbol' || typeof n === 'object' && n !== null && !(Symbol.toPrimitive in n || 'toString' in n || 'valueOf' in n); } function isNumber(n) { return !isNonPrimitive(n) && !isNaN(parseFloat(n)) && isFinite(n); } function almostWhole(x, epsilon) { const rounded = Math.round(x); return rounded - epsilon <= x && rounded + epsilon >= x; } /** * @private */ function _setMinAndMaxByKey(array, target, property) { let i, ilen, value; for(i = 0, ilen = array.length; i < ilen; i++){ value = array[i][property]; if (!isNaN(value)) { target.min = Math.min(target.min, value); target.max = Math.max(target.max, value); } } } function toRadians(degrees) { return degrees * (PI / 180); } function toDegrees(radians) { return radians * (180 / PI); } /** * Returns the number of decimal places * i.e. the number of digits after the decimal point, of the value of this Number. * @param x - A number. * @returns The number of decimal places. * @private */ function _decimalPlaces(x) { if (!isNumberFinite(x)) { return; } let e = 1; let p = 0; while(Math.round(x * e) / e !== x){ e *= 10; p++; } return p; } // Gets the angle from vertical upright to the point about a centre. function getAngleFromPoint(centrePoint, anglePoint) { const distanceFromXCenter = anglePoint.x - centrePoint.x; const distanceFromYCenter = anglePoint.y - centrePoint.y; const radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter); let angle = Math.atan2(distanceFromYCenter, distanceFromXCenter); if (angle < -0.5 * PI) { angle += TAU; // make sure the returned angle is in the range of (-PI/2, 3PI/2] } return { angle, distance: radialDistanceFromCenter }; } function distanceBetweenPoints(pt1, pt2) { return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2)); } /** * Shortest distance between angles, in either direction. * @private */ function _angleDiff(a, b) { return (a - b + PITAU) % TAU - PI; } /** * Normalize angle to be between 0 and 2*PI * @private */ function _normalizeAngle(a) { return (a % TAU + TAU) % TAU; } /** * @private */ function _angleBetween(angle, start, end, sameAngleIsFullCircle) { const a = _normalizeAngle(angle); const s = _normalizeAngle(start); const e = _normalizeAngle(end); const angleToStart = _normalizeAngle(s - a); const angleToEnd = _normalizeAngle(e - a); const startToAngle = _normalizeAngle(a - s); const endToAngle = _normalizeAngle(a - e); return a === s || a === e || sameAngleIsFullCircle && s === e || angleToStart > angleToEnd && startToAngle < endToAngle; } /** * Limit `value` between `min` and `max` * @param value * @param min * @param max * @private */ function _limitValue(value, min, max) { return Math.max(min, Math.min(max, value)); } /** * @param {number} value * @private */ function _int16Range(value) { return _limitValue(value, -32768, 32767); } /** * @param value * @param start * @param end * @param [epsilon] * @private */ function _isBetween(value, start, end, epsilon = 1e-6) { return value >= Math.min(start, end) - epsilon && value <= Math.max(start, end) + epsilon; } function _lookup(table, value, cmp) { cmp = cmp || ((index)=>table[index] < value); let hi = table.length - 1; let lo = 0; let mid; while(hi - lo > 1){ mid = lo + hi >> 1; if (cmp(mid)) { lo = mid; } else { hi = mid; } } return { lo, hi }; } /** * Binary search * @param table - the table search. must be sorted! * @param key - property name for the value in each entry * @param value - value to find * @param last - lookup last index * @private */ const _lookupByKey = (table, key, value, last)=>_lookup(table, value, last ? (index)=>{ const ti = table[index][key]; return ti < value || ti === value && table[index + 1][key] === value; } : (index)=>table[index][key] < value); /** * Reverse binary search * @param table - the table search. must be sorted! * @param key - property name for the value in each entry * @param value - value to find * @private */ const _rlookupByKey = (table, key, value)=>_lookup(table, value, (index)=>table[index][key] >= value); /** * Return subset of `values` between `min` and `max` inclusive. * Values are assumed to be in sorted order. * @param values - sorted array of values * @param min - min value * @param max - max value */ function _filterBetween(values, min, max) { let start = 0; let end = values.length; while(start < end && values[start] < min){ start++; } while(end > start && values[end - 1] > max){ end--; } return start > 0 || end < values.length ? values.slice(start, end) : values; } const arrayEvents = [ 'push', 'pop', 'shift', 'splice', 'unshift' ]; function listenArrayEvents(array, listener) { if (array._chartjs) { array._chartjs.listeners.push(listener); return; } Object.defineProperty(array, '_chartjs', { configurable: true, enumerable: false, value: { listeners: [ listener ] } }); arrayEvents.forEach((key)=>{ const method = '_onData' + _capitalize(key); const base = array[key]; Object.defineProperty(array, key, { configurable: true, enumerable: false, value (...args) { const res = base.apply(this, args); array._chartjs.listeners.forEach((object)=>{ if (typeof object[method] === 'function') { object[method](...args); } }); return res; } }); }); } function unlistenArrayEvents(array, listener) { const stub = array._chartjs; if (!stub) { return; } const listeners = stub.listeners; const index = listeners.indexOf(listener); if (index !== -1) { listeners.splice(index, 1); } if (listeners.length > 0) { return; } arrayEvents.forEach((key)=>{ delete array[key]; }); delete array._chartjs; } /** * @param items */ function _arrayUnique(items) { const set = new Set(items); if (set.size === items.length) { return items; } return Array.from(set); } function fontString(pixelSize, fontStyle, fontFamily) { return fontStyle + ' ' + pixelSize + 'px ' + fontFamily; } /** * Request animation polyfill */ const requestAnimFrame = function() { if (typeof window === 'undefined') { return function(callback) { return callback(); }; } return window.requestAnimationFrame; }(); /** * Throttles calling `fn` once per animation frame * Latest arguments are used on the actual call */ function throttled(fn, thisArg) { let argsToUse = []; let ticking = false; return function(...args) { // Save the args for use later argsToUse = args; if (!ticking) { ticking = true; requestAnimFrame.call(window, ()=>{ ticking = false; fn.apply(thisArg, argsToUse); }); } }; } /** * Debounces calling `fn` for `delay` ms */ function debounce(fn, delay) { let timeout; return function(...args) { if (delay) { clearTimeout(timeout); timeout = setTimeout(fn, delay, args); } else { fn.apply(this, args); } return delay; }; } /** * Converts 'start' to 'left', 'end' to 'right' and others to 'center' * @private */ const _toLeftRightCenter = (align)=>align === 'start' ? 'left' : align === 'end' ? 'right' : 'center'; /** * Returns `start`, `end` or `(start + end) / 2` depending on `align`. Defaults to `center` * @private */ const _alignStartEnd = (align, start, end)=>align === 'start' ? start : align === 'end' ? end : (start + end) / 2; /** * Returns `left`, `right` or `(left + right) / 2` depending on `align`. Defaults to `left` * @private */ const _textX = (align, left, right, rtl)=>{ const check = rtl ? 'left' : 'right'; return align === check ? right : align === 'center' ? (left + right) / 2 : left; }; /** * Return start and count of visible points. * @private */ function _getStartAndCountOfVisiblePoints(meta, points, animationsDisabled) { const pointCount = points.length; let start = 0; let count = pointCount; if (meta._sorted) { const { iScale , vScale , _parsed } = meta; const spanGaps = meta.dataset ? meta.dataset.options ? meta.dataset.options.spanGaps : null : null; const axis = iScale.axis; const { min , max , minDefined , maxDefined } = iScale.getUserBounds(); if (minDefined) { start = Math.min(// @ts-expect-error Need to type _parsed _lookupByKey(_parsed, axis, min).lo, // @ts-expect-error Need to fix types on _lookupByKey animationsDisabled ? pointCount : _lookupByKey(points, axis, iScale.getPixelForValue(min)).lo); if (spanGaps) { const distanceToDefinedLo = _parsed.slice(0, start + 1).reverse().findIndex((point)=>!isNullOrUndef(point[vScale.axis])); start -= Math.max(0, distanceToDefinedLo); } start = _limitValue(start, 0, pointCount - 1); } if (maxDefined) { let end = Math.max(// @ts-expect-error Need to type _parsed _lookupByKey(_parsed, iScale.axis, max, true).hi + 1, // @ts-expect-error Need to fix types on _lookupByKey animationsDisabled ? 0 : _lookupByKey(points, axis, iScale.getPixelForValue(max), true).hi + 1); if (spanGaps) { const distanceToDefinedHi = _parsed.slice(end - 1).findIndex((point)=>!isNullOrUndef(point[vScale.axis])); end += Math.max(0, distanceToDefinedHi); } count = _limitValue(end, start, pointCount) - start; } else { count = pointCount - start; } } return { start, count }; } /** * Checks if the scale ranges have changed. * @param {object} meta - dataset meta. * @returns {boolean} * @private */ function _scaleRangesChanged(meta) { const { xScale , yScale , _scaleRanges } = meta; const newRanges = { xmin: xScale.min, xmax: xScale.max, ymin: yScale.min, ymax: yScale.max }; if (!_scaleRanges) { meta._scaleRanges = newRanges; return true; } const changed = _scaleRanges.xmin !== xScale.min || _scaleRanges.xmax !== xScale.max || _scaleRanges.ymin !== yScale.min || _scaleRanges.ymax !== yScale.max; Object.assign(_scaleRanges, newRanges); return changed; } const atEdge = (t)=>t === 0 || t === 1; const elasticIn = (t, s, p)=>-(Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * TAU / p)); const elasticOut = (t, s, p)=>Math.pow(2, -10 * t) * Math.sin((t - s) * TAU / p) + 1; /** * Easing functions adapted from Robert Penner's easing equations. * @namespace Chart.helpers.easing.effects * @see http://www.robertpenner.com/easing/ */ const effects = { linear: (t)=>t, easeInQuad: (t)=>t * t, easeOutQuad: (t)=>-t * (t - 2), easeInOutQuad: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t : -0.5 * (--t * (t - 2) - 1), easeInCubic: (t)=>t * t * t, easeOutCubic: (t)=>(t -= 1) * t * t + 1, easeInOutCubic: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t * t : 0.5 * ((t -= 2) * t * t + 2), easeInQuart: (t)=>t * t * t * t, easeOutQuart: (t)=>-((t -= 1) * t * t * t - 1), easeInOutQuart: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t * t * t : -0.5 * ((t -= 2) * t * t * t - 2), easeInQuint: (t)=>t * t * t * t * t, easeOutQuint: (t)=>(t -= 1) * t * t * t * t + 1, easeInOutQuint: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t * t * t * t : 0.5 * ((t -= 2) * t * t * t * t + 2), easeInSine: (t)=>-Math.cos(t * HALF_PI) + 1, easeOutSine: (t)=>Math.sin(t * HALF_PI), easeInOutSine: (t)=>-0.5 * (Math.cos(PI * t) - 1), easeInExpo: (t)=>t === 0 ? 0 : Math.pow(2, 10 * (t - 1)), easeOutExpo: (t)=>t === 1 ? 1 : -Math.pow(2, -10 * t) + 1, easeInOutExpo: (t)=>atEdge(t) ? t : t < 0.5 ? 0.5 * Math.pow(2, 10 * (t * 2 - 1)) : 0.5 * (-Math.pow(2, -10 * (t * 2 - 1)) + 2), easeInCirc: (t)=>t >= 1 ? t : -(Math.sqrt(1 - t * t) - 1), easeOutCirc: (t)=>Math.sqrt(1 - (t -= 1) * t), easeInOutCirc: (t)=>(t /= 0.5) < 1 ? -0.5 * (Math.sqrt(1 - t * t) - 1) : 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1), easeInElastic: (t)=>atEdge(t) ? t : elasticIn(t, 0.075, 0.3), easeOutElastic: (t)=>atEdge(t) ? t : elasticOut(t, 0.075, 0.3), easeInOutElastic (t) { const s = 0.1125; const p = 0.45; return atEdge(t) ? t : t < 0.5 ? 0.5 * elasticIn(t * 2, s, p) : 0.5 + 0.5 * elasticOut(t * 2 - 1, s, p); }, easeInBack (t) { const s = 1.70158; return t * t * ((s + 1) * t - s); }, easeOutBack (t) { const s = 1.70158; return (t -= 1) * t * ((s + 1) * t + s) + 1; }, easeInOutBack (t) { let s = 1.70158; if ((t /= 0.5) < 1) { return 0.5 * (t * t * (((s *= 1.525) + 1) * t - s)); } return 0.5 * ((t -= 2) * t * (((s *= 1.525) + 1) * t + s) + 2); }, easeInBounce: (t)=>1 - effects.easeOutBounce(1 - t), easeOutBounce (t) { const m = 7.5625; const d = 2.75; if (t < 1 / d) { return m * t * t; } if (t < 2 / d) { return m * (t -= 1.5 / d) * t + 0.75; } if (t < 2.5 / d) { return m * (t -= 2.25 / d) * t + 0.9375; } return m * (t -= 2.625 / d) * t + 0.984375; }, easeInOutBounce: (t)=>t < 0.5 ? effects.easeInBounce(t * 2) * 0.5 : effects.easeOutBounce(t * 2 - 1) * 0.5 + 0.5 }; function isPatternOrGradient(value) { if (value && typeof value === 'object') { const type = value.toString(); return type === '[object CanvasPattern]' || type === '[object CanvasGradient]'; } return false; } function color(value) { return isPatternOrGradient(value) ? value : new _kurkle_color__WEBPACK_IMPORTED_MODULE_0__.Color(value); } function getHoverColor(value) { return isPatternOrGradient(value) ? value : new _kurkle_color__WEBPACK_IMPORTED_MODULE_0__.Color(value).saturate(0.5).darken(0.1).hexString(); } const numbers = [ 'x', 'y', 'borderWidth', 'radius', 'tension' ]; const colors = [ 'color', 'borderColor', 'backgroundColor' ]; function applyAnimationsDefaults(defaults) { defaults.set('animation', { delay: undefined, duration: 1000, easing: 'easeOutQuart', fn: undefined, from: undefined, loop: undefined, to: undefined, type: undefined }); defaults.describe('animation', { _fallback: false, _indexable: false, _scriptable: (name)=>name !== 'onProgress' && name !== 'onComplete' && name !== 'fn' }); defaults.set('animations', { colors: { type: 'color', properties: colors }, numbers: { type: 'number', properties: numbers } }); defaults.describe('animations', { _fallback: 'animation' }); defaults.set('transitions', { active: { animation: { duration: 400 } }, resize: { animation: { duration: 0 } }, show: { animations: { colors: { from: 'transparent' }, visible: { type: 'boolean', duration: 0 } } }, hide: { animations: { colors: { to: 'transparent' }, visible: { type: 'boolean', easing: 'linear', fn: (v)=>v | 0 } } } }); } function applyLayoutsDefaults(defaults) { defaults.set('layout', { autoPadding: true, padding: { top: 0, right: 0, bottom: 0, left: 0 } }); } const intlCache = new Map(); function getNumberFormat(locale, options) { options = options || {}; const cacheKey = locale + JSON.stringify(options); let formatter = intlCache.get(cacheKey); if (!formatter) { formatter = new Intl.NumberFormat(locale, options); intlCache.set(cacheKey, formatter); } return formatter; } function formatNumber(num, locale, options) { return getNumberFormat(locale, options).format(num); } const formatters = { values (value) { return isArray(value) ? value : '' + value; }, numeric (tickValue, index, ticks) { if (tickValue === 0) { return '0'; } const locale = this.chart.options.locale; let notation; let delta = tickValue; if (ticks.length > 1) { const maxTick = Math.max(Math.abs(ticks[0].value), Math.abs(ticks[ticks.length - 1].value)); if (maxTick < 1e-4 || maxTick > 1e+15) { notation = 'scientific'; } delta = calculateDelta(tickValue, ticks); } const logDelta = log10(Math.abs(delta)); const numDecimal = isNaN(logDelta) ? 1 : Math.max(Math.min(-1 * Math.floor(logDelta), 20), 0); const options = { notation, minimumFractionDigits: numDecimal, maximumFractionDigits: numDecimal }; Object.assign(options, this.options.ticks.format); return formatNumber(tickValue, locale, options); }, logarithmic (tickValue, index, ticks) { if (tickValue === 0) { return '0'; } const remain = ticks[index].significand || tickValue / Math.pow(10, Math.floor(log10(tickValue))); if ([ 1, 2, 3, 5, 10, 15 ].includes(remain) || index > 0.8 * ticks.length) { return formatters.numeric.call(this, tickValue, index, ticks); } return ''; } }; function calculateDelta(tickValue, ticks) { let delta = ticks.length > 3 ? ticks[2].value - ticks[1].value : ticks[1].value - ticks[0].value; if (Math.abs(delta) >= 1 && tickValue !== Math.floor(tickValue)) { delta = tickValue - Math.floor(tickValue); } return delta; } var Ticks = { formatters }; function applyScaleDefaults(defaults) { defaults.set('scale', { display: true, offset: false, reverse: false, beginAtZero: false, bounds: 'ticks', clip: true, grace: 0, grid: { display: true, lineWidth: 1, drawOnChartArea: true, drawTicks: true, tickLength: 8, tickWidth: (_ctx, options)=>options.lineWidth, tickColor: (_ctx, options)=>options.color, offset: false }, border: { display: true, dash: [], dashOffset: 0.0, width: 1 }, title: { display: false, text: '', padding: { top: 4, bottom: 4 } }, ticks: { minRotation: 0, maxRotation: 50, mirror: false, textStrokeWidth: 0, textStrokeColor: '', padding: 3, display: true, autoSkip: true, autoSkipPadding: 3, labelOffset: 0, callback: Ticks.formatters.values, minor: {}, major: {}, align: 'center', crossAlign: 'near', showLabelBackdrop: false, backdropColor: 'rgba(255, 255, 255, 0.75)', backdropPadding: 2 } }); defaults.route('scale.ticks', 'color', '', 'color'); defaults.route('scale.grid', 'color', '', 'borderColor'); defaults.route('scale.border', 'color', '', 'borderColor'); defaults.route('scale.title', 'color', '', 'color'); defaults.describe('scale', { _fallback: false, _scriptable: (name)=>!name.startsWith('before') && !name.startsWith('after') && name !== 'callback' && name !== 'parser', _indexable: (name)=>name !== 'borderDash' && name !== 'tickBorderDash' && name !== 'dash' }); defaults.describe('scales', { _fallback: 'scale' }); defaults.describe('scale.ticks', { _scriptable: (name)=>name !== 'backdropPadding' && name !== 'callback', _indexable: (name)=>name !== 'backdropPadding' }); } const overrides = Object.create(null); const descriptors = Object.create(null); function getScope$1(node, key) { if (!key) { return node; } const keys = key.split('.'); for(let i = 0, n = keys.length; i < n; ++i){ const k = keys[i]; node = node[k] || (node[k] = Object.create(null)); } return node; } function set(root, scope, values) { if (typeof scope === 'string') { return merge(getScope$1(root, scope), values); } return merge(getScope$1(root, ''), scope); } class Defaults { constructor(_descriptors, _appliers){ this.animation = undefined; this.backgroundColor = 'rgba(0,0,0,0.1)'; this.borderColor = 'rgba(0,0,0,0.1)'; this.color = '#666'; this.datasets = {}; this.devicePixelRatio = (context)=>context.chart.platform.getDevicePixelRatio(); this.elements = {}; this.events = [ 'mousemove', 'mouseout', 'click', 'touchstart', 'touchmove' ]; this.font = { family: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", size: 12, style: 'normal', lineHeight: 1.2, weight: null }; this.hover = {}; this.hoverBackgroundColor = (ctx, options)=>getHoverColor(options.backgroundColor); this.hoverBorderColor = (ctx, options)=>getHoverColor(options.borderColor); this.hoverColor = (ctx, options)=>getHoverColor(options.color); this.indexAxis = 'x'; this.interaction = { mode: 'nearest', intersect: true, includeInvisible: false }; this.maintainAspectRatio = true; this.onHover = null; this.onClick = null; this.parsing = true; this.plugins = {}; this.responsive = true; this.scale = undefined; this.scales = {}; this.showLine = true; this.drawActiveElementsOnTop = true; this.describe(_descriptors); this.apply(_appliers); } set(scope, values) { return set(this, scope, values); } get(scope) { return getScope$1(this, scope); } describe(scope, values) { return set(descriptors, scope, values); } override(scope, values) { return set(overrides, scope, values); } route(scope, name, targetScope, targetName) { const scopeObject = getScope$1(this, scope); const targetScopeObject = getScope$1(this, targetScope); const privateName = '_' + name; Object.defineProperties(scopeObject, { [privateName]: { value: scopeObject[name], writable: true }, [name]: { enumerable: true, get () { const local = this[privateName]; const target = targetScopeObject[targetName]; if (isObject(local)) { return Object.assign({}, target, local); } return valueOrDefault(local, target); }, set (value) { this[privateName] = value; } } }); } apply(appliers) { appliers.forEach((apply)=>apply(this)); } } var defaults = /* #__PURE__ */ new Defaults({ _scriptable: (name)=>!name.startsWith('on'), _indexable: (name)=>name !== 'events', hover: { _fallback: 'interaction' }, interaction: { _scriptable: false, _indexable: false } }, [ applyAnimationsDefaults, applyLayoutsDefaults, applyScaleDefaults ]); /** * Converts the given font object into a CSS font string. * @param font - A font object. * @return The CSS font string. See https://developer.mozilla.org/en-US/docs/Web/CSS/font * @private */ function toFontString(font) { if (!font || isNullOrUndef(font.size) || isNullOrUndef(font.family)) { return null; } return (font.style ? font.style + ' ' : '') + (font.weight ? font.weight + ' ' : '') + font.size + 'px ' + font.family; } /** * @private */ function _measureText(ctx, data, gc, longest, string) { let textWidth = data[string]; if (!textWidth) { textWidth = data[string] = ctx.measureText(string).width; gc.push(string); } if (textWidth > longest) { longest = textWidth; } return longest; } /** * @private */ // eslint-disable-next-line complexity function _longestText(ctx, font, arrayOfThings, cache) { cache = cache || {}; let data = cache.data = cache.data || {}; let gc = cache.garbageCollect = cache.garbageCollect || []; if (cache.font !== font) { data = cache.data = {}; gc = cache.garbageCollect = []; cache.font = font; } ctx.save(); ctx.font = font; let longest = 0; const ilen = arrayOfThings.length; let i, j, jlen, thing, nestedThing; for(i = 0; i < ilen; i++){ thing = arrayOfThings[i]; // Undefined strings and arrays should not be measured if (thing !== undefined && thing !== null && !isArray(thing)) { longest = _measureText(ctx, data, gc, longest, thing); } else if (isArray(thing)) { // if it is an array lets measure each element // to do maybe simplify this function a bit so we can do this more recursively? for(j = 0, jlen = thing.length; j < jlen; j++){ nestedThing = thing[j]; // Undefined strings and arrays should not be measured if (nestedThing !== undefined && nestedThing !== null && !isArray(nestedThing)) { longest = _measureText(ctx, data, gc, longest, nestedThing); } } } } ctx.restore(); const gcLen = gc.length / 2; if (gcLen > arrayOfThings.length) { for(i = 0; i < gcLen; i++){ delete data[gc[i]]; } gc.splice(0, gcLen); } return longest; } /** * Returns the aligned pixel value to avoid anti-aliasing blur * @param chart - The chart instance. * @param pixel - A pixel value. * @param width - The width of the element. * @returns The aligned pixel value. * @private */ function _alignPixel(chart, pixel, width) { const devicePixelRatio = chart.currentDevicePixelRatio; const halfWidth = width !== 0 ? Math.max(width / 2, 0.5) : 0; return Math.round((pixel - halfWidth) * devicePixelRatio) / devicePixelRatio + halfWidth; } /** * Clears the entire canvas. */ function clearCanvas(canvas, ctx) { if (!ctx && !canvas) { return; } ctx = ctx || canvas.getContext('2d'); ctx.save(); // canvas.width and canvas.height do not consider the canvas transform, // while clearRect does ctx.resetTransform(); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.restore(); } function drawPoint(ctx, options, x, y) { // eslint-disable-next-line @typescript-eslint/no-use-before-define drawPointLegend(ctx, options, x, y, null); } // eslint-disable-next-line complexity function drawPointLegend(ctx, options, x, y, w) { let type, xOffset, yOffset, size, cornerRadius, width, xOffsetW, yOffsetW; const style = options.pointStyle; const rotation = options.rotation; const radius = options.radius; let rad = (rotation || 0) * RAD_PER_DEG; if (style && typeof style === 'object') { type = style.toString(); if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') { ctx.save(); ctx.translate(x, y); ctx.rotate(rad); ctx.drawImage(style, -style.width / 2, -style.height / 2, style.width, style.height); ctx.restore(); return; } } if (isNaN(radius) || radius <= 0) { return; } ctx.beginPath(); switch(style){ // Default includes circle default: if (w) { ctx.ellipse(x, y, w / 2, radius, 0, 0, TAU); } else { ctx.arc(x, y, radius, 0, TAU); } ctx.closePath(); break; case 'triangle': width = w ? w / 2 : radius; ctx.moveTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius); rad += TWO_THIRDS_PI; ctx.lineTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius); rad += TWO_THIRDS_PI; ctx.lineTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius); ctx.closePath(); break; case 'rectRounded': // NOTE: the rounded rect implementation changed to use `arc` instead of // `quadraticCurveTo` since it generates better results when rect is // almost a circle. 0.516 (instead of 0.5) produces results with visually // closer proportion to the previous impl and it is inscribed in the // circle with `radius`. For more details, see the following PRs: // https://github.com/chartjs/Chart.js/issues/5597 // https://github.com/chartjs/Chart.js/issues/5858 cornerRadius = radius * 0.516; size = radius - cornerRadius; xOffset = Math.cos(rad + QUARTER_PI) * size; xOffsetW = Math.cos(rad + QUARTER_PI) * (w ? w / 2 - cornerRadius : size); yOffset = Math.sin(rad + QUARTER_PI) * size; yOffsetW = Math.sin(rad + QUARTER_PI) * (w ? w / 2 - cornerRadius : size); ctx.arc(x - xOffsetW, y - yOffset, cornerRadius, rad - PI, rad - HALF_PI); ctx.arc(x + yOffsetW, y - xOffset, cornerRadius, rad - HALF_PI, rad); ctx.arc(x + xOffsetW, y + yOffset, cornerRadius, rad, rad + HALF_PI); ctx.arc(x - yOffsetW, y + xOffset, cornerRadius, rad + HALF_PI, rad + PI); ctx.closePath(); break; case 'rect': if (!rotation) { size = Math.SQRT1_2 * radius; width = w ? w / 2 : size; ctx.rect(x - width, y - size, 2 * width, 2 * size); break; } rad += QUARTER_PI; /* falls through */ case 'rectRot': xOffsetW = Math.cos(rad) * (w ? w / 2 : radius); xOffset = Math.cos(rad) * radius; yOffset = Math.sin(rad) * radius; yOffsetW = Math.sin(rad) * (w ? w / 2 : radius); ctx.moveTo(x - xOffsetW, y - yOffset); ctx.lineTo(x + yOffsetW, y - xOffset); ctx.lineTo(x + xOffsetW, y + yOffset); ctx.lineTo(x - yOffsetW, y + xOffset); ctx.closePath(); break; case 'crossRot': rad += QUARTER_PI; /* falls through */ case 'cross': xOffsetW = Math.cos(rad) * (w ? w / 2 : radius); xOffset = Math.cos(rad) * radius; yOffset = Math.sin(rad) * radius; yOffsetW = Math.sin(rad) * (w ? w / 2 : radius); ctx.moveTo(x - xOffsetW, y - yOffset); ctx.lineTo(x + xOffsetW, y + yOffset); ctx.moveTo(x + yOffsetW, y - xOffset); ctx.lineTo(x - yOffsetW, y + xOffset); break; case 'star': xOffsetW = Math.cos(rad) * (w ? w / 2 : radius); xOffset = Math.cos(rad) * radius; yOffset = Math.sin(rad) * radius; yOffsetW = Math.sin(rad) * (w ? w / 2 : radius); ctx.moveTo(x - xOffsetW, y - yOffset); ctx.lineTo(x + xOffsetW, y + yOffset); ctx.moveTo(x + yOffsetW, y - xOffset); ctx.lineTo(x - yOffsetW, y + xOffset); rad += QUARTER_PI; xOffsetW = Math.cos(rad) * (w ? w / 2 : radius); xOffset = Math.cos(rad) * radius; yOffset = Math.sin(rad) * radius; yOffsetW = Math.sin(rad) * (w ? w / 2 : radius); ctx.moveTo(x - xOffsetW, y - yOffset); ctx.lineTo(x + xOffsetW, y + yOffset); ctx.moveTo(x + yOffsetW, y - xOffset); ctx.lineTo(x - yOffsetW, y + xOffset); break; case 'line': xOffset = w ? w / 2 : Math.cos(rad) * radius; yOffset = Math.sin(rad) * radius; ctx.moveTo(x - xOffset, y - yOffset); ctx.lineTo(x + xOffset, y + yOffset); break; case 'dash': ctx.moveTo(x, y); ctx.lineTo(x + Math.cos(rad) * (w ? w / 2 : radius), y + Math.sin(rad) * radius); break; case false: ctx.closePath(); break; } ctx.fill(); if (options.borderWidth > 0) { ctx.stroke(); } } /** * Returns true if the point is inside the rectangle * @param point - The point to test * @param area - The rectangle * @param margin - allowed margin * @private */ function _isPointInArea(point, area, margin) { margin = margin || 0.5; // margin - default is to match rounded decimals return !area || point && point.x > area.left - margin && point.x < area.right + margin && point.y > area.top - margin && point.y < area.bottom + margin; } function clipArea(ctx, area) { ctx.save(); ctx.beginPath(); ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top); ctx.clip(); } function unclipArea(ctx) { ctx.restore(); } /** * @private */ function _steppedLineTo(ctx, previous, target, flip, mode) { if (!previous) { return ctx.lineTo(target.x, target.y); } if (mode === 'middle') { const midpoint = (previous.x + target.x) / 2.0; ctx.lineTo(midpoint, previous.y); ctx.lineTo(midpoint, target.y); } else if (mode === 'after' !== !!flip) { ctx.lineTo(previous.x, target.y); } else { ctx.lineTo(target.x, previous.y); } ctx.lineTo(target.x, target.y); } /** * @private */ function _bezierCurveTo(ctx, previous, target, flip) { if (!previous) { return ctx.lineTo(target.x, target.y); } ctx.bezierCurveTo(flip ? previous.cp1x : previous.cp2x, flip ? previous.cp1y : previous.cp2y, flip ? target.cp2x : target.cp1x, flip ? target.cp2y : target.cp1y, target.x, target.y); } function setRenderOpts(ctx, opts) { if (opts.translation) { ctx.translate(opts.translation[0], opts.translation[1]); } if (!isNullOrUndef(opts.rotation)) { ctx.rotate(opts.rotation); } if (opts.color) { ctx.fillStyle = opts.color; } if (opts.textAlign) { ctx.textAlign = opts.textAlign; } if (opts.textBaseline) { ctx.textBaseline = opts.textBaseline; } } function decorateText(ctx, x, y, line, opts) { if (opts.strikethrough || opts.underline) { /** * Now that IE11 support has been dropped, we can use more * of the TextMetrics object. The actual bounding boxes * are unflagged in Chrome, Firefox, Edge, and Safari so they * can be safely used. * See https://developer.mozilla.org/en-US/docs/Web/API/TextMetrics#Browser_compatibility */ const metrics = ctx.measureText(line); const left = x - metrics.actualBoundingBoxLeft; const right = x + metrics.actualBoundingBoxRight; const top = y - metrics.actualBoundingBoxAscent; const bottom = y + metrics.actualBoundingBoxDescent; const yDecoration = opts.strikethrough ? (top + bottom) / 2 : bottom; ctx.strokeStyle = ctx.fillStyle; ctx.beginPath(); ctx.lineWidth = opts.decorationWidth || 2; ctx.moveTo(left, yDecoration); ctx.lineTo(right, yDecoration); ctx.stroke(); } } function drawBackdrop(ctx, opts) { const oldColor = ctx.fillStyle; ctx.fillStyle = opts.color; ctx.fillRect(opts.left, opts.top, opts.width, opts.height); ctx.fillStyle = oldColor; } /** * Render text onto the canvas */ function renderText(ctx, text, x, y, font, opts = {}) { const lines = isArray(text) ? text : [ text ]; const stroke = opts.strokeWidth > 0 && opts.strokeColor !== ''; let i, line; ctx.save(); ctx.font = font.string; setRenderOpts(ctx, opts); for(i = 0; i < lines.length; ++i){ line = lines[i]; if (opts.backdrop) { drawBackdrop(ctx, opts.backdrop); } if (stroke) { if (opts.strokeColor) { ctx.strokeStyle = opts.strokeColor; } if (!isNullOrUndef(opts.strokeWidth)) { ctx.lineWidth = opts.strokeWidth; } ctx.strokeText(line, x, y, opts.maxWidth); } ctx.fillText(line, x, y, opts.maxWidth); decorateText(ctx, x, y, line, opts); y += Number(font.lineHeight); } ctx.restore(); } /** * Add a path of a rectangle with rounded corners to the current sub-path * @param ctx - Context * @param rect - Bounding rect */ function addRoundedRectPath(ctx, rect) { const { x , y , w , h , radius } = rect; // top left arc ctx.arc(x + radius.topLeft, y + radius.topLeft, radius.topLeft, 1.5 * PI, PI, true); // line from top left to bottom left ctx.lineTo(x, y + h - radius.bottomLeft); // bottom left arc ctx.arc(x + radius.bottomLeft, y + h - radius.bottomLeft, radius.bottomLeft, PI, HALF_PI, true); // line from bottom left to bottom right ctx.lineTo(x + w - radius.bottomRight, y + h); // bottom right arc ctx.arc(x + w - radius.bottomRight, y + h - radius.bottomRight, radius.bottomRight, HALF_PI, 0, true); // line from bottom right to top right ctx.lineTo(x + w, y + radius.topRight); // top right arc ctx.arc(x + w - radius.topRight, y + radius.topRight, radius.topRight, 0, -HALF_PI, true); // line from top right to top left ctx.lineTo(x + radius.topLeft, y); } const LINE_HEIGHT = /^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/; const FONT_STYLE = /^(normal|italic|initial|inherit|unset|(oblique( -?[0-9]?[0-9]deg)?))$/; /** * @alias Chart.helpers.options * @namespace */ /** * Converts the given line height `value` in pixels for a specific font `size`. * @param value - The lineHeight to parse (eg. 1.6, '14px', '75%', '1.6em'). * @param size - The font size (in pixels) used to resolve relative `value`. * @returns The effective line height in pixels (size * 1.2 if value is invalid). * @see https://developer.mozilla.org/en-US/docs/Web/CSS/line-height * @since 2.7.0 */ function toLineHeight(value, size) { const matches = ('' + value).match(LINE_HEIGHT); if (!matches || matches[1] === 'normal') { return size * 1.2; } value = +matches[2]; switch(matches[3]){ case 'px': return value; case '%': value /= 100; break; } return size * value; } const numberOrZero = (v)=>+v || 0; function _readValueToProps(value, props) { const ret = {}; const objProps = isObject(props); const keys = objProps ? Object.keys(props) : props; const read = isObject(value) ? objProps ? (prop)=>valueOrDefault(value[prop], value[props[prop]]) : (prop)=>value[prop] : ()=>value; for (const prop of keys){ ret[prop] = numberOrZero(read(prop)); } return ret; } /** * Converts the given value into a TRBL object. * @param value - If a number, set the value to all TRBL component, * else, if an object, use defined properties and sets undefined ones to 0. * x / y are shorthands for same value for left/right and top/bottom. * @returns The padding values (top, right, bottom, left) * @since 3.0.0 */ function toTRBL(value) { return _readValueToProps(value, { top: 'y', right: 'x', bottom: 'y', left: 'x' }); } /** * Converts the given value into a TRBL corners object (similar with css border-radius). * @param value - If a number, set the value to all TRBL corner components, * else, if an object, use defined properties and sets undefined ones to 0. * @returns The TRBL corner values (topLeft, topRight, bottomLeft, bottomRight) * @since 3.0.0 */ function toTRBLCorners(value) { return _readValueToProps(value, [ 'topLeft', 'topRight', 'bottomLeft', 'bottomRight' ]); } /** * Converts the given value into a padding object with pre-computed width/height. * @param value - If a number, set the value to all TRBL component, * else, if an object, use defined properties and sets undefined ones to 0. * x / y are shorthands for same value for left/right and top/bottom. * @returns The padding values (top, right, bottom, left, width, height) * @since 2.7.0 */ function toPadding(value) { const obj = toTRBL(value); obj.width = obj.left + obj.right; obj.height = obj.top + obj.bottom; return obj; } /** * Parses font options and returns the font object. * @param options - A object that contains font options to be parsed. * @param fallback - A object that contains fallback font options. * @return The font object. * @private */ function toFont(options, fallback) { options = options || {}; fallback = fallback || defaults.font; let size = valueOrDefault(options.size, fallback.size); if (typeof size === 'string') { size = parseInt(size, 10); } let style = valueOrDefault(options.style, fallback.style); if (style && !('' + style).match(FONT_STYLE)) { console.warn('Invalid font style specified: "' + style + '"'); style = undefined; } const font = { family: valueOrDefault(options.family, fallback.family), lineHeight: toLineHeight(valueOrDefault(options.lineHeight, fallback.lineHeight), size), size, style, weight: valueOrDefault(options.weight, fallback.weight), string: '' }; font.string = toFontString(font); return font; } /** * Evaluates the given `inputs` sequentially and returns the first defined value. * @param inputs - An array of values, falling back to the last value. * @param context - If defined and the current value is a function, the value * is called with `context` as first argument and the result becomes the new input. * @param index - If defined and the current value is an array, the value * at `index` become the new input. * @param info - object to return information about resolution in * @param info.cacheable - Will be set to `false` if option is not cacheable. * @since 2.7.0 */ function resolve(inputs, context, index, info) { let cacheable = true; let i, ilen, value; for(i = 0, ilen = inputs.length; i < ilen; ++i){ value = inputs[i]; if (value === undefined) { continue; } if (context !== undefined && typeof value === 'function') { value = value(context); cacheable = false; } if (index !== undefined && isArray(value)) { value = value[index % value.length]; cacheable = false; } if (value !== undefined) { if (info && !cacheable) { info.cacheable = false; } return value; } } } /** * @param minmax * @param grace * @param beginAtZero * @private */ function _addGrace(minmax, grace, beginAtZero) { const { min , max } = minmax; const change = toDimension(grace, (max - min) / 2); const keepZero = (value, add)=>beginAtZero && value === 0 ? 0 : value + add; return { min: keepZero(min, -Math.abs(change)), max: keepZero(max, change) }; } function createContext(parentContext, context) { return Object.assign(Object.create(parentContext), context); } /** * Creates a Proxy for resolving raw values for options. * @param scopes - The option scopes to look for values, in resolution order * @param prefixes - The prefixes for values, in resolution order. * @param rootScopes - The root option scopes * @param fallback - Parent scopes fallback * @param getTarget - callback for getting the target for changed values * @returns Proxy * @private */ function _createResolver(scopes, prefixes = [ '' ], rootScopes, fallback, getTarget = ()=>scopes[0]) { const finalRootScopes = rootScopes || scopes; if (typeof fallback === 'undefined') { fallback = _resolve('_fallback', scopes); } const cache = { [Symbol.toStringTag]: 'Object', _cacheable: true, _scopes: scopes, _rootScopes: finalRootScopes, _fallback: fallback, _getTarget: getTarget, override: (scope)=>_createResolver([ scope, ...scopes ], prefixes, finalRootScopes, fallback) }; return new Proxy(cache, { /** * A trap for the delete operator. */ deleteProperty (target, prop) { delete target[prop]; // remove from cache delete target._keys; // remove cached keys delete scopes[0][prop]; // remove from top level scope return true; }, /** * A trap for getting property values. */ get (target, prop) { return _cached(target, prop, ()=>_resolveWithPrefixes(prop, prefixes, scopes, target)); }, /** * A trap for Object.getOwnPropertyDescriptor. * Also used by Object.hasOwnProperty. */ getOwnPropertyDescriptor (target, prop) { return Reflect.getOwnPropertyDescriptor(target._scopes[0], prop); }, /** * A trap for Object.getPrototypeOf. */ getPrototypeOf () { return Reflect.getPrototypeOf(scopes[0]); }, /** * A trap for the in operator. */ has (target, prop) { return getKeysFromAllScopes(target).includes(prop); }, /** * A trap for Object.getOwnPropertyNames and Object.getOwnPropertySymbols. */ ownKeys (target) { return getKeysFromAllScopes(target); }, /** * A trap for setting property values. */ set (target, prop, value) { const storage = target._storage || (target._storage = getTarget()); target[prop] = storage[prop] = value; // set to top level scope + cache delete target._keys; // remove cached keys return true; } }); } /** * Returns an Proxy for resolving option values with context. * @param proxy - The Proxy returned by `_createResolver` * @param context - Context object for scriptable/indexable options * @param subProxy - The proxy provided for scriptable options * @param descriptorDefaults - Defaults for descriptors * @private */ function _attachContext(proxy, context, subProxy, descriptorDefaults) { const cache = { _cacheable: false, _proxy: proxy, _context: context, _subProxy: subProxy, _stack: new Set(), _descriptors: _descriptors(proxy, descriptorDefaults), setContext: (ctx)=>_attachContext(proxy, ctx, subProxy, descriptorDefaults), override: (scope)=>_attachContext(proxy.override(scope), context, subProxy, descriptorDefaults) }; return new Proxy(cache, { /** * A trap for the delete operator. */ deleteProperty (target, prop) { delete target[prop]; // remove from cache delete proxy[prop]; // remove from proxy return true; }, /** * A trap for getting property values. */ get (target, prop, receiver) { return _cached(target, prop, ()=>_resolveWithContext(target, prop, receiver)); }, /** * A trap for Object.getOwnPropertyDescriptor. * Also used by Object.hasOwnProperty. */ getOwnPropertyDescriptor (target, prop) { return target._descriptors.allKeys ? Reflect.has(proxy, prop) ? { enumerable: true, configurable: true } : undefined : Reflect.getOwnPropertyDescriptor(proxy, prop); }, /** * A trap for Object.getPrototypeOf. */ getPrototypeOf () { return Reflect.getPrototypeOf(proxy); }, /** * A trap for the in operator. */ has (target, prop) { return Reflect.has(proxy, prop); }, /** * A trap for Object.getOwnPropertyNames and Object.getOwnPropertySymbols. */ ownKeys () { return Reflect.ownKeys(proxy); }, /** * A trap for setting property values. */ set (target, prop, value) { proxy[prop] = value; // set to proxy delete target[prop]; // remove from cache return true; } }); } /** * @private */ function _descriptors(proxy, defaults = { scriptable: true, indexable: true }) { const { _scriptable =defaults.scriptable , _indexable =defaults.indexable , _allKeys =defaults.allKeys } = proxy; return { allKeys: _allKeys, scriptable: _scriptable, indexable: _indexable, isScriptable: isFunction(_scriptable) ? _scriptable : ()=>_scriptable, isIndexable: isFunction(_indexable) ? _indexable : ()=>_indexable }; } const readKey = (prefix, name)=>prefix ? prefix + _capitalize(name) : name; const needsSubResolver = (prop, value)=>isObject(value) && prop !== 'adapters' && (Object.getPrototypeOf(value) === null || value.constructor === Object); function _cached(target, prop, resolve) { if (Object.prototype.hasOwnProperty.call(target, prop) || prop === 'constructor') { return target[prop]; } const value = resolve(); // cache the resolved value target[prop] = value; return value; } function _resolveWithContext(target, prop, receiver) { const { _proxy , _context , _subProxy , _descriptors: descriptors } = target; let value = _proxy[prop]; // resolve from proxy // resolve with context if (isFunction(value) && descriptors.isScriptable(prop)) { value = _resolveScriptable(prop, value, target, receiver); } if (isArray(value) && value.length) { value = _resolveArray(prop, value, target, descriptors.isIndexable); } if (needsSubResolver(prop, value)) { // if the resolved value is an object, create a sub resolver for it value = _attachContext(value, _context, _subProxy && _subProxy[prop], descriptors); } return value; } function _resolveScriptable(prop, getValue, target, receiver) { const { _proxy , _context , _subProxy , _stack } = target; if (_stack.has(prop)) { throw new Error('Recursion detected: ' + Array.from(_stack).join('->') + '->' + prop); } _stack.add(prop); let value = getValue(_context, _subProxy || receiver); _stack.delete(prop); if (needsSubResolver(prop, value)) { // When scriptable option returns an object, create a resolver on that. value = createSubResolver(_proxy._scopes, _proxy, prop, value); } return value; } function _resolveArray(prop, value, target, isIndexable) { const { _proxy , _context , _subProxy , _descriptors: descriptors } = target; if (typeof _context.index !== 'undefined' && isIndexable(prop)) { return value[_context.index % value.length]; } else if (isObject(value[0])) { // Array of objects, return array or resolvers const arr = value; const scopes = _proxy._scopes.filter((s)=>s !== arr); value = []; for (const item of arr){ const resolver = createSubResolver(scopes, _proxy, prop, item); value.push(_attachContext(resolver, _context, _subProxy && _subProxy[prop], descriptors)); } } return value; } function resolveFallback(fallback, prop, value) { return isFunction(fallback) ? fallback(prop, value) : fallback; } const getScope = (key, parent)=>key === true ? parent : typeof key === 'string' ? resolveObjectKey(parent, key) : undefined; function addScopes(set, parentScopes, key, parentFallback, value) { for (const parent of parentScopes){ const scope = getScope(key, parent); if (scope) { set.add(scope); const fallback = resolveFallback(scope._fallback, key, value); if (typeof fallback !== 'undefined' && fallback !== key && fallback !== parentFallback) { // When we reach the descriptor that defines a new _fallback, return that. // The fallback will resume to that new scope. return fallback; } } else if (scope === false && typeof parentFallback !== 'undefined' && key !== parentFallback) { // Fallback to `false` results to `false`, when falling back to different key. // For example `interaction` from `hover` or `plugins.tooltip` and `animation` from `animations` return null; } } return false; } function createSubResolver(parentScopes, resolver, prop, value) { const rootScopes = resolver._rootScopes; const fallback = resolveFallback(resolver._fallback, prop, value); const allScopes = [ ...parentScopes, ...rootScopes ]; const set = new Set(); set.add(value); let key = addScopesFromKey(set, allScopes, prop, fallback || prop, value); if (key === null) { return false; } if (typeof fallback !== 'undefined' && fallback !== prop) { key = addScopesFromKey(set, allScopes, fallback, key, value); if (key === null) { return false; } } return _createResolver(Array.from(set), [ '' ], rootScopes, fallback, ()=>subGetTarget(resolver, prop, value)); } function addScopesFromKey(set, allScopes, key, fallback, item) { while(key){ key = addScopes(set, allScopes, key, fallback, item); } return key; } function subGetTarget(resolver, prop, value) { const parent = resolver._getTarget(); if (!(prop in parent)) { parent[prop] = {}; } const target = parent[prop]; if (isArray(target) && isObject(value)) { // For array of objects, the object is used to store updated values return value; } return target || {}; } function _resolveWithPrefixes(prop, prefixes, scopes, proxy) { let value; for (const prefix of prefixes){ value = _resolve(readKey(prefix, prop), scopes); if (typeof value !== 'undefined') { return needsSubResolver(prop, value) ? createSubResolver(scopes, proxy, prop, value) : value; } } } function _resolve(key, scopes) { for (const scope of scopes){ if (!scope) { continue; } const value = scope[key]; if (typeof value !== 'undefined') { return value; } } } function getKeysFromAllScopes(target) { let keys = target._keys; if (!keys) { keys = target._keys = resolveKeysFromAllScopes(target._scopes); } return keys; } function resolveKeysFromAllScopes(scopes) { const set = new Set(); for (const scope of scopes){ for (const key of Object.keys(scope).filter((k)=>!k.startsWith('_'))){ set.add(key); } } return Array.from(set); } function _parseObjectDataRadialScale(meta, data, start, count) { const { iScale } = meta; const { key ='r' } = this._parsing; const parsed = new Array(count); let i, ilen, index, item; for(i = 0, ilen = count; i < ilen; ++i){ index = i + start; item = data[index]; parsed[i] = { r: iScale.parse(resolveObjectKey(item, key), index) }; } return parsed; } const EPSILON = Number.EPSILON || 1e-14; const getPoint = (points, i)=>i < points.length && !points[i].skip && points[i]; const getValueAxis = (indexAxis)=>indexAxis === 'x' ? 'y' : 'x'; function splineCurve(firstPoint, middlePoint, afterPoint, t) { // Props to Rob Spencer at scaled innovation for his post on splining between points // http://scaledinnovation.com/analytics/splines/aboutSplines.html // This function must also respect "skipped" points const previous = firstPoint.skip ? middlePoint : firstPoint; const current = middlePoint; const next = afterPoint.skip ? middlePoint : afterPoint; const d01 = distanceBetweenPoints(current, previous); const d12 = distanceBetweenPoints(next, current); let s01 = d01 / (d01 + d12); let s12 = d12 / (d01 + d12); // If all points are the same, s01 & s02 will be inf s01 = isNaN(s01) ? 0 : s01; s12 = isNaN(s12) ? 0 : s12; const fa = t * s01; // scaling factor for triangle Ta const fb = t * s12; return { previous: { x: current.x - fa * (next.x - previous.x), y: current.y - fa * (next.y - previous.y) }, next: { x: current.x + fb * (next.x - previous.x), y: current.y + fb * (next.y - previous.y) } }; } /** * Adjust tangents to ensure monotonic properties */ function monotoneAdjust(points, deltaK, mK) { const pointsLen = points.length; let alphaK, betaK, tauK, squaredMagnitude, pointCurrent; let pointAfter = getPoint(points, 0); for(let i = 0; i < pointsLen - 1; ++i){ pointCurrent = pointAfter; pointAfter = getPoint(points, i + 1); if (!pointCurrent || !pointAfter) { continue; } if (almostEquals(deltaK[i], 0, EPSILON)) { mK[i] = mK[i + 1] = 0; continue; } alphaK = mK[i] / deltaK[i]; betaK = mK[i + 1] / deltaK[i]; squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2); if (squaredMagnitude <= 9) { continue; } tauK = 3 / Math.sqrt(squaredMagnitude); mK[i] = alphaK * tauK * deltaK[i]; mK[i + 1] = betaK * tauK * deltaK[i]; } } function monotoneCompute(points, mK, indexAxis = 'x') { const valueAxis = getValueAxis(indexAxis); const pointsLen = points.length; let delta, pointBefore, pointCurrent; let pointAfter = getPoint(points, 0); for(let i = 0; i < pointsLen; ++i){ pointBefore = pointCurrent; pointCurrent = pointAfter; pointAfter = getPoint(points, i + 1); if (!pointCurrent) { continue; } const iPixel = pointCurrent[indexAxis]; const vPixel = pointCurrent[valueAxis]; if (pointBefore) { delta = (iPixel - pointBefore[indexAxis]) / 3; pointCurrent[`cp1${indexAxis}`] = iPixel - delta; pointCurrent[`cp1${valueAxis}`] = vPixel - delta * mK[i]; } if (pointAfter) { delta = (pointAfter[indexAxis] - iPixel) / 3; pointCurrent[`cp2${indexAxis}`] = iPixel + delta; pointCurrent[`cp2${valueAxis}`] = vPixel + delta * mK[i]; } } } /** * This function calculates Bézier control points in a similar way than |splineCurve|, * but preserves monotonicity of the provided data and ensures no local extremums are added * between the dataset discrete points due to the interpolation. * See : https://en.wikipedia.org/wiki/Monotone_cubic_interpolation */ function splineCurveMonotone(points, indexAxis = 'x') { const valueAxis = getValueAxis(indexAxis); const pointsLen = points.length; const deltaK = Array(pointsLen).fill(0); const mK = Array(pointsLen); // Calculate slopes (deltaK) and initialize tangents (mK) let i, pointBefore, pointCurrent; let pointAfter = getPoint(points, 0); for(i = 0; i < pointsLen; ++i){ pointBefore = pointCurrent; pointCurrent = pointAfter; pointAfter = getPoint(points, i + 1); if (!pointCurrent) { continue; } if (pointAfter) { const slopeDelta = pointAfter[indexAxis] - pointCurrent[indexAxis]; // In the case of two points that appear at the same x pixel, slopeDeltaX is 0 deltaK[i] = slopeDelta !== 0 ? (pointAfter[valueAxis] - pointCurrent[valueAxis]) / slopeDelta : 0; } mK[i] = !pointBefore ? deltaK[i] : !pointAfter ? deltaK[i - 1] : sign(deltaK[i - 1]) !== sign(deltaK[i]) ? 0 : (deltaK[i - 1] + deltaK[i]) / 2; } monotoneAdjust(points, deltaK, mK); monotoneCompute(points, mK, indexAxis); } function capControlPoint(pt, min, max) { return Math.max(Math.min(pt, max), min); } function capBezierPoints(points, area) { let i, ilen, point, inArea, inAreaPrev; let inAreaNext = _isPointInArea(points[0], area); for(i = 0, ilen = points.length; i < ilen; ++i){ inAreaPrev = inArea; inArea = inAreaNext; inAreaNext = i < ilen - 1 && _isPointInArea(points[i + 1], area); if (!inArea) { continue; } point = points[i]; if (inAreaPrev) { point.cp1x = capControlPoint(point.cp1x, area.left, area.right); point.cp1y = capControlPoint(point.cp1y, area.top, area.bottom); } if (inAreaNext) { point.cp2x = capControlPoint(point.cp2x, area.left, area.right); point.cp2y = capControlPoint(point.cp2y, area.top, area.bottom); } } } /** * @private */ function _updateBezierControlPoints(points, options, area, loop, indexAxis) { let i, ilen, point, controlPoints; // Only consider points that are drawn in case the spanGaps option is used if (options.spanGaps) { points = points.filter((pt)=>!pt.skip); } if (options.cubicInterpolationMode === 'monotone') { splineCurveMonotone(points, indexAxis); } else { let prev = loop ? points[points.length - 1] : points[0]; for(i = 0, ilen = points.length; i < ilen; ++i){ point = points[i]; controlPoints = splineCurve(prev, point, points[Math.min(i + 1, ilen - (loop ? 0 : 1)) % ilen], options.tension); point.cp1x = controlPoints.previous.x; point.cp1y = controlPoints.previous.y; point.cp2x = controlPoints.next.x; point.cp2y = controlPoints.next.y; prev = point; } } if (options.capBezierPoints) { capBezierPoints(points, area); } } /** * @private */ function _isDomSupported() { return typeof window !== 'undefined' && typeof document !== 'undefined'; } /** * @private */ function _getParentNode(domNode) { let parent = domNode.parentNode; if (parent && parent.toString() === '[object ShadowRoot]') { parent = parent.host; } return parent; } /** * convert max-width/max-height values that may be percentages into a number * @private */ function parseMaxStyle(styleValue, node, parentProperty) { let valueInPixels; if (typeof styleValue === 'string') { valueInPixels = parseInt(styleValue, 10); if (styleValue.indexOf('%') !== -1) { // percentage * size in dimension valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty]; } } else { valueInPixels = styleValue; } return valueInPixels; } const getComputedStyle = (element)=>element.ownerDocument.defaultView.getComputedStyle(element, null); function getStyle(el, property) { return getComputedStyle(el).getPropertyValue(property); } const positions = [ 'top', 'right', 'bottom', 'left' ]; function getPositionedStyle(styles, style, suffix) { const result = {}; suffix = suffix ? '-' + suffix : ''; for(let i = 0; i < 4; i++){ const pos = positions[i]; result[pos] = parseFloat(styles[style + '-' + pos + suffix]) || 0; } result.width = result.left + result.right; result.height = result.top + result.bottom; return result; } const useOffsetPos = (x, y, target)=>(x > 0 || y > 0) && (!target || !target.shadowRoot); /** * @param e * @param canvas * @returns Canvas position */ function getCanvasPosition(e, canvas) { const touches = e.touches; const source = touches && touches.length ? touches[0] : e; const { offsetX , offsetY } = source; let box = false; let x, y; if (useOffsetPos(offsetX, offsetY, e.target)) { x = offsetX; y = offsetY; } else { const rect = canvas.getBoundingClientRect(); x = source.clientX - rect.left; y = source.clientY - rect.top; box = true; } return { x, y, box }; } /** * Gets an event's x, y coordinates, relative to the chart area * @param event * @param chart * @returns x and y coordinates of the event */ function getRelativePosition(event, chart) { if ('native' in event) { return event; } const { canvas , currentDevicePixelRatio } = chart; const style = getComputedStyle(canvas); const borderBox = style.boxSizing === 'border-box'; const paddings = getPositionedStyle(style, 'padding'); const borders = getPositionedStyle(style, 'border', 'width'); const { x , y , box } = getCanvasPosition(event, canvas); const xOffset = paddings.left + (box && borders.left); const yOffset = paddings.top + (box && borders.top); let { width , height } = chart; if (borderBox) { width -= paddings.width + borders.width; height -= paddings.height + borders.height; } return { x: Math.round((x - xOffset) / width * canvas.width / currentDevicePixelRatio), y: Math.round((y - yOffset) / height * canvas.height / currentDevicePixelRatio) }; } function getContainerSize(canvas, width, height) { let maxWidth, maxHeight; if (width === undefined || height === undefined) { const container = canvas && _getParentNode(canvas); if (!container) { width = canvas.clientWidth; height = canvas.clientHeight; } else { const rect = container.getBoundingClientRect(); // this is the border box of the container const containerStyle = getComputedStyle(container); const containerBorder = getPositionedStyle(containerStyle, 'border', 'width'); const containerPadding = getPositionedStyle(containerStyle, 'padding'); width = rect.width - containerPadding.width - containerBorder.width; height = rect.height - containerPadding.height - containerBorder.height; maxWidth = parseMaxStyle(containerStyle.maxWidth, container, 'clientWidth'); maxHeight = parseMaxStyle(containerStyle.maxHeight, container, 'clientHeight'); } } return { width, height, maxWidth: maxWidth || INFINITY, maxHeight: maxHeight || INFINITY }; } const round1 = (v)=>Math.round(v * 10) / 10; // eslint-disable-next-line complexity function getMaximumSize(canvas, bbWidth, bbHeight, aspectRatio) { const style = getComputedStyle(canvas); const margins = getPositionedStyle(style, 'margin'); const maxWidth = parseMaxStyle(style.maxWidth, canvas, 'clientWidth') || INFINITY; const maxHeight = parseMaxStyle(style.maxHeight, canvas, 'clientHeight') || INFINITY; const containerSize = getContainerSize(canvas, bbWidth, bbHeight); let { width , height } = containerSize; if (style.boxSizing === 'content-box') { const borders = getPositionedStyle(style, 'border', 'width'); const paddings = getPositionedStyle(style, 'padding'); width -= paddings.width + borders.width; height -= paddings.height + borders.height; } width = Math.max(0, width - margins.width); height = Math.max(0, aspectRatio ? width / aspectRatio : height - margins.height); width = round1(Math.min(width, maxWidth, containerSize.maxWidth)); height = round1(Math.min(height, maxHeight, containerSize.maxHeight)); if (width && !height) { // https://github.com/chartjs/Chart.js/issues/4659 // If the canvas has width, but no height, default to aspectRatio of 2 (canvas default) height = round1(width / 2); } const maintainHeight = bbWidth !== undefined || bbHeight !== undefined; if (maintainHeight && aspectRatio && containerSize.height && height > containerSize.height) { height = containerSize.height; width = round1(Math.floor(height * aspectRatio)); } return { width, height }; } /** * @param chart * @param forceRatio * @param forceStyle * @returns True if the canvas context size or transformation has changed. */ function retinaScale(chart, forceRatio, forceStyle) { const pixelRatio = forceRatio || 1; const deviceHeight = round1(chart.height * pixelRatio); const deviceWidth = round1(chart.width * pixelRatio); chart.height = round1(chart.height); chart.width = round1(chart.width); const canvas = chart.canvas; // If no style has been set on the canvas, the render size is used as display size, // making the chart visually bigger, so let's enforce it to the "correct" values. // See https://github.com/chartjs/Chart.js/issues/3575 if (canvas.style && (forceStyle || !canvas.style.height && !canvas.style.width)) { canvas.style.height = `${chart.height}px`; canvas.style.width = `${chart.width}px`; } if (chart.currentDevicePixelRatio !== pixelRatio || canvas.height !== deviceHeight || canvas.width !== deviceWidth) { chart.currentDevicePixelRatio = pixelRatio; canvas.height = deviceHeight; canvas.width = deviceWidth; chart.ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0); return true; } return false; } /** * Detects support for options object argument in addEventListener. * https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support * @private */ const supportsEventListenerOptions = function() { let passiveSupported = false; try { const options = { get passive () { passiveSupported = true; return false; } }; if (_isDomSupported()) { window.addEventListener('test', null, options); window.removeEventListener('test', null, options); } } catch (e) { // continue regardless of error } return passiveSupported; }(); /** * The "used" size is the final value of a dimension property after all calculations have * been performed. This method uses the computed style of `element` but returns undefined * if the computed style is not expressed in pixels. That can happen in some cases where * `element` has a size relative to its parent and this last one is not yet displayed, * for example because of `display: none` on a parent node. * @see https://developer.mozilla.org/en-US/docs/Web/CSS/used_value * @returns Size in pixels or undefined if unknown. */ function readUsedSize(element, property) { const value = getStyle(element, property); const matches = value && value.match(/^(\d+)(\.\d+)?px$/); return matches ? +matches[1] : undefined; } /** * @private */ function _pointInLine(p1, p2, t, mode) { return { x: p1.x + t * (p2.x - p1.x), y: p1.y + t * (p2.y - p1.y) }; } /** * @private */ function _steppedInterpolation(p1, p2, t, mode) { return { x: p1.x + t * (p2.x - p1.x), y: mode === 'middle' ? t < 0.5 ? p1.y : p2.y : mode === 'after' ? t < 1 ? p1.y : p2.y : t > 0 ? p2.y : p1.y }; } /** * @private */ function _bezierInterpolation(p1, p2, t, mode) { const cp1 = { x: p1.cp2x, y: p1.cp2y }; const cp2 = { x: p2.cp1x, y: p2.cp1y }; const a = _pointInLine(p1, cp1, t); const b = _pointInLine(cp1, cp2, t); const c = _pointInLine(cp2, p2, t); const d = _pointInLine(a, b, t); const e = _pointInLine(b, c, t); return _pointInLine(d, e, t); } const getRightToLeftAdapter = function(rectX, width) { return { x (x) { return rectX + rectX + width - x; }, setWidth (w) { width = w; }, textAlign (align) { if (align === 'center') { return align; } return align === 'right' ? 'left' : 'right'; }, xPlus (x, value) { return x - value; }, leftForLtr (x, itemWidth) { return x - itemWidth; } }; }; const getLeftToRightAdapter = function() { return { x (x) { return x; }, setWidth (w) {}, textAlign (align) { return align; }, xPlus (x, value) { return x + value; }, leftForLtr (x, _itemWidth) { return x; } }; }; function getRtlAdapter(rtl, rectX, width) { return rtl ? getRightToLeftAdapter(rectX, width) : getLeftToRightAdapter(); } function overrideTextDirection(ctx, direction) { let style, original; if (direction === 'ltr' || direction === 'rtl') { style = ctx.canvas.style; original = [ style.getPropertyValue('direction'), style.getPropertyPriority('direction') ]; style.setProperty('direction', direction, 'important'); ctx.prevTextDirection = original; } } function restoreTextDirection(ctx, original) { if (original !== undefined) { delete ctx.prevTextDirection; ctx.canvas.style.setProperty('direction', original[0], original[1]); } } function propertyFn(property) { if (property === 'angle') { return { between: _angleBetween, compare: _angleDiff, normalize: _normalizeAngle }; } return { between: _isBetween, compare: (a, b)=>a - b, normalize: (x)=>x }; } function normalizeSegment({ start , end , count , loop , style }) { return { start: start % count, end: end % count, loop: loop && (end - start + 1) % count === 0, style }; } function getSegment(segment, points, bounds) { const { property , start: startBound , end: endBound } = bounds; const { between , normalize } = propertyFn(property); const count = points.length; let { start , end , loop } = segment; let i, ilen; if (loop) { start += count; end += count; for(i = 0, ilen = count; i < ilen; ++i){ if (!between(normalize(points[start % count][property]), startBound, endBound)) { break; } start--; end--; } start %= count; end %= count; } if (end < start) { end += count; } return { start, end, loop, style: segment.style }; } function _boundSegment(segment, points, bounds) { if (!bounds) { return [ segment ]; } const { property , start: startBound , end: endBound } = bounds; const count = points.length; const { compare , between , normalize } = propertyFn(property); const { start , end , loop , style } = getSegment(segment, points, bounds); const result = []; let inside = false; let subStart = null; let value, point, prevValue; const startIsBefore = ()=>between(startBound, prevValue, value) && compare(startBound, prevValue) !== 0; const endIsBefore = ()=>compare(endBound, value) === 0 || between(endBound, prevValue, value); const shouldStart = ()=>inside || startIsBefore(); const shouldStop = ()=>!inside || endIsBefore(); for(let i = start, prev = start; i <= end; ++i){ point = points[i % count]; if (point.skip) { continue; } value = normalize(point[property]); if (value === prevValue) { continue; } inside = between(value, startBound, endBound); if (subStart === null && shouldStart()) { subStart = compare(value, startBound) === 0 ? i : prev; } if (subStart !== null && shouldStop()) { result.push(normalizeSegment({ start: subStart, end: i, loop, count, style })); subStart = null; } prev = i; prevValue = value; } if (subStart !== null) { result.push(normalizeSegment({ start: subStart, end, loop, count, style })); } return result; } function _boundSegments(line, bounds) { const result = []; const segments = line.segments; for(let i = 0; i < segments.length; i++){ const sub = _boundSegment(segments[i], line.points, bounds); if (sub.length) { result.push(...sub); } } return result; } function findStartAndEnd(points, count, loop, spanGaps) { let start = 0; let end = count - 1; if (loop && !spanGaps) { while(start < count && !points[start].skip){ start++; } } while(start < count && points[start].skip){ start++; } start %= count; if (loop) { end += start; } while(end > start && points[end % count].skip){ end--; } end %= count; return { start, end }; } function solidSegments(points, start, max, loop) { const count = points.length; const result = []; let last = start; let prev = points[start]; let end; for(end = start + 1; end <= max; ++end){ const cur = points[end % count]; if (cur.skip || cur.stop) { if (!prev.skip) { loop = false; result.push({ start: start % count, end: (end - 1) % count, loop }); start = last = cur.stop ? end : null; } } else { last = end; if (prev.skip) { start = end; } } prev = cur; } if (last !== null) { result.push({ start: start % count, end: last % count, loop }); } return result; } function _computeSegments(line, segmentOptions) { const points = line.points; const spanGaps = line.options.spanGaps; const count = points.length; if (!count) { return []; } const loop = !!line._loop; const { start , end } = findStartAndEnd(points, count, loop, spanGaps); if (spanGaps === true) { return splitByStyles(line, [ { start, end, loop } ], points, segmentOptions); } const max = end < start ? end + count : end; const completeLoop = !!line._fullLoop && start === 0 && end === count - 1; return splitByStyles(line, solidSegments(points, start, max, completeLoop), points, segmentOptions); } function splitByStyles(line, segments, points, segmentOptions) { if (!segmentOptions || !segmentOptions.setContext || !points) { return segments; } return doSplitByStyles(line, segments, points, segmentOptions); } function doSplitByStyles(line, segments, points, segmentOptions) { const chartContext = line._chart.getContext(); const baseStyle = readStyle(line.options); const { _datasetIndex: datasetIndex , options: { spanGaps } } = line; const count = points.length; const result = []; let prevStyle = baseStyle; let start = segments[0].start; let i = start; function addStyle(s, e, l, st) { const dir = spanGaps ? -1 : 1; if (s === e) { return; } s += count; while(points[s % count].skip){ s -= dir; } while(points[e % count].skip){ e += dir; } if (s % count !== e % count) { result.push({ start: s % count, end: e % count, loop: l, style: st }); prevStyle = st; start = e % count; } } for (const segment of segments){ start = spanGaps ? start : segment.start; let prev = points[start % count]; let style; for(i = start + 1; i <= segment.end; i++){ const pt = points[i % count]; style = readStyle(segmentOptions.setContext(createContext(chartContext, { type: 'segment', p0: prev, p1: pt, p0DataIndex: (i - 1) % count, p1DataIndex: i % count, datasetIndex }))); if (styleChanged(style, prevStyle)) { addStyle(start, i - 1, segment.loop, prevStyle); } prev = pt; prevStyle = style; } if (start < i - 1) { addStyle(start, i - 1, segment.loop, prevStyle); } } return result; } function readStyle(options) { return { backgroundColor: options.backgroundColor, borderCapStyle: options.borderCapStyle, borderDash: options.borderDash, borderDashOffset: options.borderDashOffset, borderJoinStyle: options.borderJoinStyle, borderWidth: options.borderWidth, borderColor: options.borderColor }; } function styleChanged(style, prevStyle) { if (!prevStyle) { return false; } const cache = []; const replacer = function(key, value) { if (!isPatternOrGradient(value)) { return value; } if (!cache.includes(value)) { cache.push(value); } return cache.indexOf(value); }; return JSON.stringify(style, replacer) !== JSON.stringify(prevStyle, replacer); } function getSizeForArea(scale, chartArea, field) { return scale.options.clip ? scale[field] : chartArea[field]; } function getDatasetArea(meta, chartArea) { const { xScale , yScale } = meta; if (xScale && yScale) { return { left: getSizeForArea(xScale, chartArea, 'left'), right: getSizeForArea(xScale, chartArea, 'right'), top: getSizeForArea(yScale, chartArea, 'top'), bottom: getSizeForArea(yScale, chartArea, 'bottom') }; } return chartArea; } function getDatasetClipArea(chart, meta) { const clip = meta._clip; if (clip.disabled) { return false; } const area = getDatasetArea(meta, chart.chartArea); return { left: clip.left === false ? 0 : area.left - (clip.left === true ? 0 : clip.left), right: clip.right === false ? chart.width : area.right + (clip.right === true ? 0 : clip.right), top: clip.top === false ? 0 : area.top - (clip.top === true ? 0 : clip.top), bottom: clip.bottom === false ? chart.height : area.bottom + (clip.bottom === true ? 0 : clip.bottom) }; } //# sourceMappingURL=helpers.dataset.js.map /***/ }, /***/ "./node_modules/tom-select/dist/esm/constants.js" /*!*******************************************************!*\ !*** ./node_modules/tom-select/dist/esm/constants.js ***! \*******************************************************/ (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ IS_MAC: () => (/* binding */ IS_MAC), /* harmony export */ KEY_A: () => (/* binding */ KEY_A), /* harmony export */ KEY_BACKSPACE: () => (/* binding */ KEY_BACKSPACE), /* harmony export */ KEY_DELETE: () => (/* binding */ KEY_DELETE), /* harmony export */ KEY_DOWN: () => (/* binding */ KEY_DOWN), /* harmony export */ KEY_ESC: () => (/* binding */ KEY_ESC), /* harmony export */ KEY_LEFT: () => (/* binding */ KEY_LEFT), /* harmony export */ KEY_RETURN: () => (/* binding */ KEY_RETURN), /* harmony export */ KEY_RIGHT: () => (/* binding */ KEY_RIGHT), /* harmony export */ KEY_SHORTCUT: () => (/* binding */ KEY_SHORTCUT), /* harmony export */ KEY_TAB: () => (/* binding */ KEY_TAB), /* harmony export */ KEY_UP: () => (/* binding */ KEY_UP) /* harmony export */ }); const KEY_A = 65; const KEY_RETURN = 13; const KEY_ESC = 27; const KEY_LEFT = 37; const KEY_UP = 38; const KEY_RIGHT = 39; const KEY_DOWN = 40; const KEY_BACKSPACE = 8; const KEY_DELETE = 46; const KEY_TAB = 9; const IS_MAC = typeof navigator === 'undefined' ? false : /Mac/.test(navigator.userAgent); const KEY_SHORTCUT = IS_MAC ? 'metaKey' : 'ctrlKey'; // ctrl key or apple key for ma //# sourceMappingURL=constants.js.map /***/ }, /***/ "./node_modules/tom-select/dist/esm/contrib/highlight.js" /*!***************************************************************!*\ !*** ./node_modules/tom-select/dist/esm/contrib/highlight.js ***! \***************************************************************/ (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ highlight: () => (/* binding */ highlight), /* harmony export */ removeHighlight: () => (/* binding */ removeHighlight) /* harmony export */ }); /* harmony import */ var _vanilla_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../vanilla.js */ "./node_modules/tom-select/dist/esm/vanilla.js"); /** * highlight v3 | MIT license | Johann Burkard * Highlights arbitrary terms in a node. * * - Modified by Marshal 2011-6-24 (added regex) * - Modified by Brian Reavis 2012-8-27 (cleanup) */ const highlight = (element, regex) => { if (regex === null) return; // convet string to regex if (typeof regex === 'string') { if (!regex.length) return; regex = new RegExp(regex, 'i'); } // Wrap matching part of text node with highlighting , e.g. // Soccer -> Soccer for regex = /soc/i const highlightText = (node) => { var match = node.data.match(regex); if (match && node.data.length > 0) { var spannode = document.createElement('span'); spannode.className = 'highlight'; var middlebit = node.splitText(match.index); middlebit.splitText(match[0].length); var middleclone = middlebit.cloneNode(true); spannode.appendChild(middleclone); (0,_vanilla_js__WEBPACK_IMPORTED_MODULE_0__.replaceNode)(middlebit, spannode); return 1; } return 0; }; // Recurse element node, looking for child text nodes to highlight, unless element // is childless,