/******/ (() => { // 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',
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 = `
${window.lpCourseBuilder?.i18n?.click_to_upload || 'Click to upload'}
${window.lpCourseBuilder?.i18n?.image_hint || 'JPG, JPEG, PNG less than 1MB'}
`;
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: 'max(350px, 65vw)',
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}`);
// Avoid duplicate AJAX: loadAJAX.js handles fresh elements; skip if already loaded. Set timeout to ensure DOM is ready handle.
setTimeout(() => {
const elLoadAjaxElement = elLPTarget.closest('.lp-load-ajax-element:not(.loaded)');
if (!elLoadAjaxElement) {
return;
}
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();
}
});
}
}, 1);
}
}).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 */ fullScreenView: () => (/* binding */ fullScreenView),
/* 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 */ toggleEnable: () => (/* binding */ toggleEnable)
/* harmony export */ });
/**
* Utils functions
*
* @param url
* @param data
* @param functions
* @since 4.2.5.1
* @version 1.0.7
*/
const lpClassName = {
hidden: 'lp-hidden',
loading: 'loading',
elCollapse: 'lp-collapse',
elSectionToggle: '.lp-section-toggle',
elTriggerToggle: '.lp-trigger-toggle',
elBtnFullScreen: '.lp-btn-full-screen-view',
elFullScreen: 'lp-full-screen-view',
elBtnFullScreenClose: 'lp-full-screen-view__close'
};
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);
};
};
/**
* Initialize lp-toggle-enable components.
*
* Finds all `.lp-toggle-enable` elements and wires up toggle behavior.
* Reads initial state from `data-enabled` attribute ("true"/"false").
* Calls `data-on-toggle` callback (if provided via options) on state change.
*
* HTML structure:
*
*
* @param {string} selector CSS selector for toggle elements (default: '.lp-toggle-enable')
* @param {Function} onToggle Optional callback( el, isEnabled ) called on state change
* @since 4.4.5
* @version 1.0.0
*/
window.lpToggleEnableInit = 0;
const toggleEnable = (onToggle = null) => {
if (window.lpToggleEnableInit) {
return;
}
window.lpToggleEnableInit = 1;
const selector = '.lp-toggle-enable';
const updateUI = (toggle, isEnabled) => {
toggle.classList.toggle('is-enabled', isEnabled);
const input = toggle.querySelector('.lp-toggle-enable__input');
if (input) {
input.checked = isEnabled;
input.value = isEnabled ? '1' : '0';
}
};
// Delegate click handling via eventHandlers.
eventHandlers('click', [{
selector,
callBack: args => {
const {
e,
target
} = args;
const toggle = target.closest(selector);
if (!toggle || toggle.classList.contains('is-disabled')) {
return;
}
e.preventDefault();
const isEnabled = !toggle.classList.contains('is-enabled');
updateUI(toggle, isEnabled);
if ('function' === typeof onToggle) {
onToggle(toggle, isEnabled);
}
}
}]);
};
/**
* Initialize custom fullscreen view buttons.
*
* Delegates clicks on `.lp-btn-full-screen-view` buttons to
* `lpToggleFullscreenView`. Reads the `data-target` attribute to find the
* target element. Falls back to the button's parent element when
* `data-target` is not provided.
*
* @since 4.4.5
* @version 1.0.0
*/
window.lpFullScreenViewInit = 0;
const fullScreenView = () => {
if (window.lpFullScreenViewInit) {
return;
}
window.lpFullScreenViewInit = 1;
let lastScrollY = 0;
const lpToggleFullscreenView = (elTarget, elBtnFullScreen = null) => {
const isFullscreen = elTarget.classList.contains(lpClassName.elFullScreen);
if (isFullscreen) {
elTarget.classList.remove(lpClassName.elFullScreen);
document.documentElement.classList.remove('lp-full-screen-active');
window.scrollTo(0, lastScrollY);
} else {
lastScrollY = window.scrollY;
elTarget.classList.add(lpClassName.elFullScreen);
document.documentElement.classList.add('lp-full-screen-active');
}
if (!isFullscreen) {
if (!elTarget.querySelector(`.${lpClassName.elBtnFullScreenClose}`)) {
const closeButton = document.createElement('button');
closeButton.type = 'button';
closeButton.className = lpClassName.elBtnFullScreenClose;
closeButton.setAttribute('aria-label', 'Close');
closeButton.innerHTML = lpData.i18n.closeButtonFullScreen || 'Close ×';
closeButton.addEventListener('click', e => {
e.preventDefault();
lpToggleFullscreenView(elTarget);
});
elTarget.appendChild(closeButton);
}
} else {
const closeButton = elTarget.querySelector(`.${lpClassName.elBtnFullScreenClose}`);
if (closeButton) {
closeButton.remove();
}
}
};
eventHandlers('click', [{
selector: lpClassName.elBtnFullScreen,
callBack: args => {
const {
e,
target
} = args;
const elBtnFullScreen = target.closest(lpClassName.elBtnFullScreen);
if (!elBtnFullScreen) {
console.log('No full screen button found');
return;
}
e.preventDefault();
let elTarget = null;
const targetSelector = elBtnFullScreen.dataset.targetFullscreen;
console.log(targetSelector);
if (targetSelector) {
elTarget = document.querySelector(targetSelector);
}
if (!elTarget) {
console.log('No target element found');
return;
}
lpToggleFullscreenView(elTarget, elBtnFullScreen);
}
}]);
};
/***/ },
/***/ "./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];
//