/**
* Native WordPress post-lock coordinator for live FrontEdit sessions.
*
* Reads: SFE.Api.apiCall, SFE.ManagerData.postId
* Exposes: SFE.PostLockManager { beginLockClaim, ensureLock, handleLockedError }
*/
(function() {
'use strict';
window.MWP = window.MWP || {};
window.MWP.SFE = window.MWP.SFE || {};
const SFE = window.MWP.SFE;
let ownsLock = false;
let refreshTimer = null;
let pendingClaim = null;
/**
* Prevent editor and draft-preview Escape handlers from closing an active
* editing session while the post-lock decision is on screen.
*
* Window capture runs before the document-level editor lifecycle handlers.
*
* @param {KeyboardEvent} event Keyboard event.
* @returns {void}
*/
window.addEventListener('keydown', (event) => {
if (
event.key === 'Escape' &&
document.querySelector('.mwp-sfe-post-lock-modal.is-open')
) {
event.preventDefault();
event.stopImmediatePropagation();
}
}, true);
function escapeHtml(value) {
return String(value).replace(/[&<>"']/g, (char) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' })[char]);
}
function showLockModal(owner = {}) {
return new Promise((resolve) => {
const modal = document.createElement('div');
modal.className = 'mwp-sfe-post-lock-modal is-open';
modal.setAttribute('data-mwp-sfe-control', 'post-lock-modal');
modal.innerHTML = `
Post is being edited
${escapeHtml(owner.name || 'Another user')} is currently working on this post, which means you cannot make changes, unless you take over.
If you take over, the other user will lose editing control to the post, but their changes will be saved.
`;
document.body.appendChild(modal);
modal.querySelector('.mwp-sfe-post-lock-cancel').addEventListener('click', () => { modal.remove(); resolve(false); });
modal.querySelector('.mwp-sfe-post-lock-takeover').addEventListener('click', () => { modal.remove(); resolve(true); });
});
}
function beginRefresh() {
if (refreshTimer) return;
refreshTimer = window.setInterval(async () => {
if (!ownsLock) return;
try {
await SFE.Api.apiCall('/post-lock/claim', { post_id: SFE.ManagerData.postId });
} catch (error) {
ownsLock = false;
clearInterval(refreshTimer);
refreshTimer = null;
}
}, 60000);
}
/**
* Start one shared lock-claim operation for the current post.
*
* Opening an editor does not need to wait for this request, but every
* published-content mutation must await the returned promise before it
* reaches the server. Sharing the promise keeps concurrent editor opens and
* saves from issuing competing claims or bypassing the pending decision.
*
* @returns {Promise} Whether this user holds the post lock.
*/
function beginLockClaim() {
if (ownsLock) return Promise.resolve(true);
if (pendingClaim) return pendingClaim;
pendingClaim = (async () => {
try {
await SFE.Api.apiCall('/post-lock/claim', { post_id: SFE.ManagerData.postId });
} catch (error) {
if (error.message !== 'POST_LOCKED' || !await showLockModal(error?.payload?.lock?.owner)) return false;
try {
await SFE.Api.apiCall('/post-lock/claim', { post_id: SFE.ManagerData.postId, take_over: true });
} catch (_) {
return false;
}
}
ownsLock = true;
beginRefresh();
return true;
})();
pendingClaim.finally(() => {
pendingClaim = null;
});
return pendingClaim;
}
/**
* Wait until the current user's native WordPress post lock is held.
*
* @returns {Promise} Whether this user holds the post lock.
*/
async function ensureLock() {
return beginLockClaim();
}
async function handleLockedError(error) {
ownsLock = false;
if (error?.message !== 'POST_LOCKED') return false;
if (!await showLockModal(error?.payload?.lock?.owner)) return false;
try {
await SFE.Api.apiCall('/post-lock/claim', {
post_id: SFE.ManagerData.postId,
take_over: true
});
ownsLock = true;
beginRefresh();
return true;
} catch (_) {
return false;
}
}
SFE.PostLockManager = { beginLockClaim, ensureLock, handleLockedError };
})();
Courses – Zoe's Continuing Education And Certification
https://zoece.com
A Continuing Education and Certificate Site for the Beauty and Haircare ProfessionalsSun, 09 Nov 2025 21:27:00 +0000en-US
hourly
1 Package (A) – Designed for Cosmetologists and Nail Technicians
https://zoece.com/course/course-template-2/
Sat, 13 Sep 2025 03:51:22 +0000https://zoece.com/?post_type=course&p=1702Package (B) – Designed for Cosmetologists, Barbers, and Hair Designers
https://zoece.com/course/course-template-2-2/
Fri, 07 Nov 2025 19:33:27 +0000https://zoece.com/?post_type=course&p=1904Package (C) – Designed for Cosmetologists and Estheticians
https://zoece.com/course/course-template-2-2-2/
Fri, 07 Nov 2025 19:37:39 +0000https://zoece.com/?post_type=course&p=1908Package (D) – Designed for Cometologists, Barbers, Hair Designers, Nail Technicians, and Esthetician Instructors
https://zoece.com/course/course-template-2-2-2-2/
Fri, 07 Nov 2025 19:43:49 +0000https://zoece.com/?post_type=course&p=1914Package (E) – Designed for Salons, Barber Shops, Schools, Suites, and Spa Business Owners
https://zoece.com/course/course-template-2-2-2-2-2/
Fri, 07 Nov 2025 19:54:15 +0000https://zoece.com/?post_type=course&p=1921