(function( factory ) { if ( typeof define === "function" && define.amd ) { define( ["jquery", "../jquery.validate"], factory ); } else if (typeof module === "object" && module.exports) { module.exports = factory( require( "jquery" ) ); } else { factory( jQuery ); } }(function( $ ) { /* * Translated default messages for the jQuery validation plugin. * Locale: AR (Arabic; العربية) */ $.extend( $.validator.messages, { required: "هذا الحقل إلزامي", remote: "يرجى تصحيح هذا الحقل للمتابعة", email: "رجاء إدخال عنوان بريد إلكتروني صحيح", url: "رجاء إدخال عنوان موقع إلكتروني صحيح", date: "رجاء إدخال تاريخ صحيح", dateISO: "رجاء إدخال تاريخ صحيح (ISO)", number: "رجاء إدخال عدد بطريقة صحيحة", digits: "رجاء إدخال أرقام فقط", creditcard: "رجاء إدخال رقم بطاقة ائتمان صحيح", equalTo: "رجاء إدخال نفس القيمة", extension: "رجاء إدخال ملف بامتداد موافق عليه", maxlength: $.validator.format( "الحد الأقصى لعدد الحروف هو {0}" ), minlength: $.validator.format( "الحد الأدنى لعدد الحروف هو {0}" ), rangelength: $.validator.format( "عدد الحروف يجب أن يكون بين {0} و {1}" ), range: $.validator.format( "رجاء إدخال عدد قيمته بين {0} و {1}" ), max: $.validator.format( "رجاء إدخال عدد أقل من أو يساوي {0}" ), min: $.validator.format( "رجاء إدخال عدد أكبر من أو يساوي {0}" ) } ); return $; })); Hello world! – Tagarela Digital /** * Action Bar Dock - Docked save/submit UI for batch edit mode * * After the first editor is opened in a batch session the action bar gains * a "dock" position fixed to the left of the mode-toggle bar. Whenever no * element is hovered or active the bar transitions to this dock showing a * Save / Submit-for-Review button. When the user hovers an element the bar * slides back down from the dock and up to the element using the same * mwp-sfe-slide animations used everywhere else. * * Transition rules * element → dock : mwp-sfe-slide-down-reverse (out), then mwp-sfe-slide-up (in at dock) * dock → element : mwp-sfe-slide-down-reverse (out from dock), then mwp-sfe-slide-up (in at element) * --mwp-sfe-transition-position is NEVER used between dock and element (suppressed via * bar._suppressPositionTransition flag read by action-bar.js). * * Cancellation & redirect rules * Docking animation (element → dock) : cancelled immediately when a new hover or click * arrives, matching the existing editor-close cancel * behavior. * Undocking animation (dock → element): NOT cancelled on new hover. Instead the target * is silently redirected (latestUndockCallback) so * the animation runs once and lands on the most * recent hovered element. Rapid N-element hovers * all collapse to the last one. * Forced cancellation (click-to-edit via * cancelAnimation(true)) still clears everything. * * Preview mode * A CSS rule in frontend-inline.css keeps the docked bar at display:flex but * opacity:0 during body.mwp-sfe-preview-mode so it fades in/out using the * existing opacity transition on .mwp-sfe-inline-actions, identical to the * active-editor preview behavior. * * Activation * The dock is inactive unless the shared BatchEditManager reports an enabled, * active session with at least one editor opened. Single-block editing keeps * the normal action-bar behavior. * * Reads (via globals): * SFE.Context - .actionBar * SFE.BatchEditManager - .isSessionActive, .isEnabled, .handleBatchSave * SFE.ManagerData - .permissions * SFE.TIMING * * Exposes: SFE.ActionBarDock * { notifyEditorOpened, notifySessionReset, * shouldHandleHide, handleHide, * shouldHandleShow, handleShow, * shouldHandleReset, handleReset, * cancelAnimation, refreshPosition } */ (function () { 'use strict'; window.MWP = window.MWP || {}; window.MWP.SFE = window.MWP.SFE || {}; const SFE = window.MWP.SFE; SFE.ManagerData = SFE.ManagerData || {}; // ── Module state ────────────────────────────────────────────────────────── /** True once the first editor has been opened in the current batch session. */ let sessionHasEdited = false; /** True when the action bar is fully positioned at the dock. */ let isDocked = false; /** * Current animation direction, or null when idle. * 'docking' - element → dock (phase 1 close, phase 2 slide-up to dock) * 'undocking' - dock → element (phase 1 close, phase 2 slide-up to element) */ let animationPhase = null; /** Timeout handle for the in-progress two-phase animation. */ let dockAnimTimeout = null; /** * The onDone callback for the current undock animation. * Replaced by every subsequent hover so rapid hovers collapse to the last * target without restarting the animation. */ let latestUndockCallback = null; // ── Internal helpers ────────────────────────────────────────────────────── function getBatchManager() { return SFE.BatchEditManager || null; } function getActionBar() { return SFE.Context ? SFE.Context.actionBar : null; } function getBar() { var ab = getActionBar(); return ab ? ab.activeBar : null; } function getToggleBar() { return document.querySelector('.mwp-sfe-mode-toggle-bar'); } function TIMING() { return SFE.TIMING || { TRANSITION_DURATION: 200 }; } /** * Clamp a number into an inclusive range. * * @param {number} value Candidate numeric value. * @param {number} min Minimum allowed value. * @param {number} max Maximum allowed value. * @returns {number} Clamped numeric value. */ function clamp(value, min, max) { if (value < min) return min; if (value > max) return max; return value; } /** * Returns true when dock behavior should be active: * - a batch edit session is enabled and currently active, AND * - the user has opened at least one editor in this session. */ function isDockActive() { var bm = getBatchManager(); return !!( sessionHasEdited && bm && typeof bm.isEnabled === 'function' && bm.isEnabled() && typeof bm.isSessionActive === 'function' && bm.isSessionActive() ); } /** * Clears the in-progress animation timeout and resets all phase tracking. * Only call when taking full ownership of bar state. */ function _clearAnimationState() { if (dockAnimTimeout) { clearTimeout(dockAnimTimeout); dockAnimTimeout = null; } animationPhase = null; latestUndockCallback = null; } /** * Calculate the viewport-relative position for the docked bar. * * Preferred placement is on the left side of the mode toggle bar. When that * would push the dock beyond the left edge of the viewport, the dock flips to * the right side instead. Final coordinates are clamped to the viewport so * the dock remains visible even after the toggle bar has been moved. */ function getDockCoords(bar) { var toggleBar = getToggleBar(); if (!toggleBar || !bar) return null; var tRect = toggleBar.getBoundingClientRect(); var barRect = bar.getBoundingClientRect(); var GAP = 10; var viewportWidth = document.documentElement.clientWidth || window.innerWidth; var viewportHeight = document.documentElement.clientHeight || window.innerHeight; var preferredLeft = tRect.left - barRect.width - GAP; var preferredRight = tRect.right + GAP; var shouldFlipRight = preferredLeft < 0; var maxLeft = Math.max(0, viewportWidth - barRect.width); var maxTop = Math.max(0, viewportHeight - barRect.height); return { top : clamp(tRect.top, 0, maxTop), left: clamp(shouldFlipRight ? preferredRight : preferredLeft, 0, maxLeft), side: shouldFlipRight ? 'right' : 'left' }; } /** * Apply fixed-position dock coordinates to the bar. * Switches the element away from PositionManager's absolute positioning. */ function applyDockPosition(bar) { var coords = getDockCoords(bar); if (!coords) return; bar.style.position = 'fixed'; bar.style.top = coords.top + 'px'; bar.style.left = coords.left + 'px'; bar.style.right = ''; bar.style.width = 'fit-content'; bar.style.maxWidth = ''; bar.dataset.mwpSfeDockSide = coords.side; } /** * Build the dock-state content (header + save/submit button) inside the bar. * Clears existing content and removes all mwp-sfe-state-* classes first. */ function buildDockContent(bar) { var bm = getBatchManager(); var perms = (SFE.ManagerData && SFE.ManagerData.permissions) || {}; var canPublish = !!perms.can_publish; var headerText = canPublish ? 'Save Your Changes' : 'Submit for Review'; var buttonText = canPublish ? 'Save Changes' : 'Submit for Review'; bar.innerHTML = ''; Array.from(bar.classList) .filter(function(c) { return c.startsWith('mwp-sfe-state-'); }) .forEach(function(c) { bar.classList.remove(c); }); bar.classList.add('mwp-sfe-state-dock'); var row = document.createElement('div'); row.className = 'mwp-sfe-single-element-row'; var headerEl = document.createElement('div'); headerEl.className = 'mwp-sfe-single-element-header'; headerEl.textContent = headerText; var buttonsEl = document.createElement('div'); buttonsEl.className = 'mwp-sfe-single-element-buttons'; var btn = document.createElement('button'); btn.className = 'mwp-sfe-btn mwp-sfe-btn-primary-inline'; btn.textContent = buttonText; // If a save is already in progress when the dock is (re)built, start disabled. if (SFE.Context && SFE.Context.isSaving) btn.disabled = true; btn.onclick = function(e) { e.preventDefault(); e.stopPropagation(); if (bm && typeof bm.handleBatchSave === 'function') { bm.handleBatchSave(btn); } }; buttonsEl.appendChild(btn); row.appendChild(headerEl); row.appendChild(buttonsEl); bar.appendChild(row); } /** * Force the mwp-sfe-slide-up animation to replay from scratch. */ function retriggerSlideUp(bar) { bar.style.animation = 'none'; void bar.offsetWidth; bar.style.animation = ''; } // ── Dock transition (element/edit → dock) ───────────────────────────────── /** * Transition the action bar from its current position to the dock. * Phase 1: play mwp-sfe-slide-down-reverse at the current position. * Phase 2: reposition to dock (fixed), replay mwp-sfe-slide-up. */ function startDocking(bar, ab) { if (!bar) return; _clearAnimationState(); animationPhase = 'docking'; // Remove scroll listener - the docked bar follows a fixed position. ab._removeScrollListener(bar); if (bar._multiElements) { delete bar._multiElements; delete bar._currentFocusIndex; } ab.activeElement = null; if (SFE.hoverTracker) { SFE.hoverTracker.currentGroupId = null; SFE.hoverTracker.bottommostElement = null; SFE.hoverTracker.lastHoveredElements = []; } // Phase 1: slide-down-reverse out of current position. bar.classList.add('mwp-sfe-no-position-transition'); bar.classList.add('mwp-sfe-closing'); var T = TIMING(); dockAnimTimeout = setTimeout(function() { dockAnimTimeout = null; animationPhase = null; if (!bar.classList.contains('mwp-sfe-closing')) return; bar.classList.remove('mwp-sfe-closing'); // Phase 2: build content, position at dock, slide-up in. buildDockContent(bar); bar.style.display = 'flex'; bar.style.pointerEvents = 'auto'; applyDockPosition(bar); bar.classList.add('mwp-sfe-no-position-transition'); retriggerSlideUp(bar); isDocked = true; bar._isDocked = true; requestAnimationFrame(function() { bar.classList.remove('mwp-sfe-no-position-transition'); }); }, T.TRANSITION_DURATION); } // ── Undock transition (dock → element) ──────────────────────────────────── /** * Transition the action bar from the dock back to an element. * Phase 1: play mwp-sfe-slide-down-reverse at the dock position. * Phase 2: call latestUndockCallback (most recent hovered element target). * * Rapid hovers during phase 1 only update latestUndockCallback - the * animation runs once and delivers the bar to the latest target. */ function startUndocking(bar, ab, onDone) { if (!bar) { if (typeof onDone === 'function') onDone(); return; } _clearAnimationState(); animationPhase = 'undocking'; latestUndockCallback = onDone; // Mark not-docked immediately so shouldHandleShow can distinguish // "fully docked" from "undocking in progress" via animationPhase. isDocked = false; bar._isDocked = false; // Phase 1: slide-down-reverse out of dock position. bar.classList.add('mwp-sfe-no-position-transition'); bar.classList.add('mwp-sfe-closing'); var T = TIMING(); dockAnimTimeout = setTimeout(function() { dockAnimTimeout = null; animationPhase = null; // Use the latest target - may have been redirected by rapid hovers. var resolvedCallback = latestUndockCallback; latestUndockCallback = null; if (!bar.classList.contains('mwp-sfe-closing')) { // Another flow already took control; let it handle everything. if (typeof resolvedCallback === 'function') resolvedCallback(); return; } bar.classList.remove('mwp-sfe-closing'); // Switch back to absolute so PositionManager can take over. bar.style.position = 'absolute'; bar.style.left = ''; bar.style.right = ''; // Signal _continueShowActionBar to suppress position transitions so // the bar doesn't CSS-slide from dock coords to element coords. bar._suppressPositionTransition = true; // Retrigger slide-up before resolvedCallback positions the bar so // the bar is invisible (opacity:0/translateY:10px) during the jump. retriggerSlideUp(bar); if (typeof resolvedCallback === 'function') resolvedCallback(); requestAnimationFrame(function() { delete bar._suppressPositionTransition; bar.classList.remove('mwp-sfe-no-position-transition'); // After landing, if we aren't hovering anymore, trigger the // standard hide logic so it plays the closing animation. const isHoveringBar = bar.matches(':hover'); // ab is the ActionBar instance passed into startUndocking const isHoveringElement = ab.activeElement && ab.activeElement.matches(':hover'); const isMultiHover = bar._multiElements && bar._multiElements.some(el => el.matches(':hover')); if (!isHoveringBar && !isHoveringElement && !isMultiHover) { // This triggers the standard ActionBar._hideActionBar() logic, // which will handle the HOVER_DELAY and the 'mwp-sfe-closing' animation. ab.hide(); } }); }, T.TRANSITION_DURATION); } // ── Resize handler ──────────────────────────────────────────────────────── window.addEventListener('resize', function() { if (!isDocked) return; var bar = getBar(); if (bar) applyDockPosition(bar); }); /** * Reposition the dock immediately when the mode toggle bar moves. * * @returns {void} */ function refreshPosition() { if (!isDocked) return; var bar = getBar(); if (bar) applyDockPosition(bar); } // ── Public API ──────────────────────────────────────────────────────────── /** * Cancel the in-progress dock/undock animation. * * @param {boolean} force When false (default) only cancels a *docking* * animation; an undocking animation is left running * so its target can be silently redirected by the * next handleShow() call. * When true (_updateActionBarState on click-to-edit) * cancels everything unconditionally. */ function cancelAnimation(force) { if (!dockAnimTimeout) return; if (force || animationPhase === 'docking') { // When force-cancelling an undocking animation (e.g. user clicked to // edit while the bar was sliding down from the dock), reset the bar // to a clean position:absolute state and retrigger slide-up so the // bar animates into its new edit position rather than flying from // the dock's fixed coordinates. if (force && animationPhase === 'undocking') { var bar = getBar(); if (bar) { bar.classList.remove('mwp-sfe-closing'); bar.style.position = 'absolute'; bar.style.left = ''; bar.style.right = ''; // SIGNAL SUPPRESSION: prevent CSS top/left transition from dock coords bar._suppressPositionTransition = true; requestAnimationFrame(function() { delete bar._suppressPositionTransition; bar.classList.remove('mwp-sfe-no-position-transition'); }); retriggerSlideUp(bar); } } _clearAnimationState(); } // If animationPhase === 'undocking' and !force, leave the timeout // running; the next handleShow() call will redirect latestUndockCallback. } /** * Called by BatchEditManager.startOrSwitchEditing after the editor state * object is created. Enables dock behavior from this point forward. */ function notifyEditorOpened() { sessionHasEdited = true; } /** * Called by BatchEditManager._resetSession after a successful batch save. * Disables the dock and cleans up the bar if it was docked. */ function notifySessionReset() { var wasDockedOnReset = isDocked; var wasDockingInProgress = (animationPhase === 'docking'); sessionHasEdited = false; isDocked = false; _clearAnimationState(); var bar = getBar(); if (!bar) return; bar._isDocked = false; bar.classList.remove('mwp-sfe-state-dock'); var T = TIMING(); if (wasDockedOnReset) { bar.classList.add('mwp-sfe-closing'); setTimeout(function() { if (bar.classList.contains('mwp-sfe-closing')) { bar.classList.remove('mwp-sfe-closing'); bar.style.display = 'none'; bar.style.position = 'absolute'; bar.style.left = ''; bar.style.right = ''; bar.style.top = ''; } }, T.TRANSITION_DURATION); } else if (wasDockingInProgress) { bar.classList.remove('mwp-sfe-closing'); bar.style.display = 'none'; bar.style.position = 'absolute'; bar.style.left = ''; bar.style.right = ''; bar.style.top = ''; } } /** * Called inside _hideActionBar's deferred check (after HOVER_DELAY). * Returns true when the dock should receive the bar instead of hiding it. */ function shouldHandleHide(bar) { return isDockActive() && !!bar; } /** * Called when shouldHandleHide() returns true. * Force-cancels any in-progress animation (including undocking) and starts * a fresh docking transition. */ function handleHide(bar, ab) { // Force-clear all animation state so startDocking starts clean. // This handles the edge case where the user leaves an element while // an undock animation is still in phase 1. if (dockAnimTimeout) { clearTimeout(dockAnimTimeout); dockAnimTimeout = null; } animationPhase = null; latestUndockCallback = null; // Remove any stale closing class from the aborted undock so // startDocking replays the animation from scratch. bar.classList.remove('mwp-sfe-closing'); bar.style.display = 'flex'; void bar.offsetWidth; startDocking(bar, ab); } /** * Called at the start of _showActionBar. * Returns true when the bar is fully docked OR when an undocking animation * is running (so we can redirect its target instead of flying). */ function shouldHandleShow() { return isDocked || animationPhase === 'undocking'; } /** * Called when shouldHandleShow() returns true. * * - If fully docked: start the two-phase undock animation. * - If already undocking: silently redirect to the new target. The running * animation delivers the bar to the most recent target at completion. */ function handleShow(bar, ab, onDone) { if (isDocked) { startUndocking(bar, ab, onDone); } else if (animationPhase === 'undocking') { // Redirect - existing phase-1 timeout runs uninterrupted. latestUndockCallback = onDone; } } /** * Called inside _resetActionBar when the mouse is not over any editable. * Returns true when the dock should receive the bar instead of closing it. */ function shouldHandleReset(bar) { return isDockActive() && !!bar; } function handleReset(bar, ab) { startDocking(bar, ab); } SFE.ActionBarDock = { notifyEditorOpened, notifySessionReset, shouldHandleHide, handleHide, shouldHandleShow, handleShow, shouldHandleReset, handleReset, cancelAnimation, refreshPosition, }; })();
Ir para o conteúdo
Tagarela Digital
  • Início
  • Sobre
  • Work
  • Contato
  • Início
  • Sobre
  • Work
  • Contato
Pesquisar neste site