/*! For license information please see announcements-app.min.js.LICENSE.txt */ (()=>{var r={3073:(r,c,u)=>{"use strict";var l=u(96784);Object.defineProperty(c,"__esModule",{value:!0}),c.appsEventTrackingDispatch=c.AppsEventTracking=void 0;var p=l(u(85707)),_=l(u(39805)),m=l(u(40989)),y=l(u(71434));function ownKeys(r,c){var u=Object.keys(r);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(r);c&&(l=l.filter(function(c){return Object.getOwnPropertyDescriptor(r,c).enumerable})),u.push.apply(u,l)}return u}function _objectSpread(r){for(var c=1;c=r.length?{done:!0}:{done:!1,value:r[l++]}},e:function e(r){throw r},f:p}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var _,m=!0,y=!1;return{s:function s(){u=u.call(r)},n:function n(){var r=u.next();return m=r.done,r},e:function e(r){y=!0,_=r},f:function f(){try{m||null==u.return||u.return()}finally{if(y)throw _}}}}function _arrayLikeToArray(r,c){(null==c||c>r.length)&&(c=r.length);for(var u=0,l=Array(c);u0&&void 0!==arguments[0]?arguments[0]:null,c=!!r;return this.dispatchEvent(w,_objectSpread({kit_import_status:!c},c&&{kit_import_error:r.message}))}},{key:"sendKitCloudLibraryApply",value:function sendKitCloudLibraryApply(r,c){return this.dispatchEvent(x,_objectSpread({trigger:y.default.triggers.click,kit_cloud_id:r},c&&{kit_apply_url:c}))}},{key:"sendKitCloudLibraryDelete",value:function sendKitCloudLibraryDelete(){return this.dispatchEvent(k,{trigger:y.default.triggers.click})}},{key:"sendImportExportAdminAction",value:function sendImportExportAdminAction(r){return this.dispatchEvent(O,{trigger:y.default.triggers.click,action_type:r})}},{key:"sendKitImportUploadFile",value:function sendKitImportUploadFile(r){return this.dispatchEvent(P,{kit_import_upload_file_status:r})}}])}()},6269:(r,c,u)=>{"use strict";var l=u(12470).__,p=u(96784);Object.defineProperty(c,"__esModule",{value:!0}),c.default=AnnouncementsHeader;var _=p(u(41594)),m=p(u(62688));function AnnouncementsHeader(r){var c=r.onClose;return _.default.createElement("div",{className:"announcements-heading-container"},_.default.createElement("i",{className:"eicon-elementor","aria-hidden":"true"}),_.default.createElement("span",{className:"heading-title"},l("Notifications","elementor")),_.default.createElement("button",{className:"close-button",onClick:function onClick(){return c("close")}},_.default.createElement("i",{className:"eicon-close","aria-hidden":"true"})))}AnnouncementsHeader.propTypes={onClose:m.default.func.isRequired}},7470:(r,c,u)=>{"use strict";var l=u(75206);c.createRoot=l.createRoot,c.hydrateRoot=l.hydrateRoot},9535:(r,c,u)=>{var l=u(89736);function _regenerator(){var c,u,p="function"==typeof Symbol?Symbol:{},_=p.iterator||"@@iterator",m=p.toStringTag||"@@toStringTag";function i(r,p,_,m){var b=p&&p.prototype instanceof Generator?p:Generator,v=Object.create(b.prototype);return l(v,"_invoke",function(r,l,p){var _,m,b,v=0,g=p||[],h=!1,w={p:0,n:0,v:c,a:d,f:d.bind(c,4),d:function d(r,u){return _=r,m=0,b=c,w.n=u,y}};function d(r,l){for(m=r,b=l,u=0;!h&&v&&!p&&u3?(p=k===l)&&(b=_[(m=_[4])?5:(m=3,3)],_[4]=_[5]=c):_[0]<=x&&((p=r<2&&x<_[1])?(m=0,w.v=l,w.n=_[1]):xl||l>k)&&(_[4]=r,_[5]=l,w.n=k,m=0))}if(p||r>1)return y;throw h=!0,l}return function(p,g,x){if(v>1)throw TypeError("Generator is already running");for(h&&1===g&&d(g,x),m=g,b=x;(u=m<2?c:b)||!h;){_||(m?m<3?(m>1&&(w.n=-1),d(m,b)):w.n=b:w.v=b);try{if(v=2,_){if(m||(p="next"),u=_[p]){if(!(u=u.call(_,b)))throw TypeError("iterator result is not an object");if(!u.done)return u;b=u.value,m<2&&(m=0)}else 1===m&&(u=_.return)&&u.call(_),m<2&&(b=TypeError("The iterator does not provide a '"+p+"' method"),m=1);_=c}else if((u=(h=w.n<0)?b:r.call(l,w))!==y)break}catch(r){_=c,m=1,b=r}finally{v=1}}return{value:u,done:h}}}(r,_,m),!0),v}var y={};function Generator(){}function GeneratorFunction(){}function GeneratorFunctionPrototype(){}u=Object.getPrototypeOf;var b=[][_]?u(u([][_]())):(l(u={},_,function(){return this}),u),v=GeneratorFunctionPrototype.prototype=Generator.prototype=Object.create(b);function f(r){return Object.setPrototypeOf?Object.setPrototypeOf(r,GeneratorFunctionPrototype):(r.__proto__=GeneratorFunctionPrototype,l(r,m,"GeneratorFunction")),r.prototype=Object.create(v),r}return GeneratorFunction.prototype=GeneratorFunctionPrototype,l(v,"constructor",GeneratorFunctionPrototype),l(GeneratorFunctionPrototype,"constructor",GeneratorFunction),GeneratorFunction.displayName="GeneratorFunction",l(GeneratorFunctionPrototype,m,"GeneratorFunction"),l(v),l(v,m,"Generator"),l(v,_,function(){return this}),l(v,"toString",function(){return"[object Generator]"}),(r.exports=_regenerator=function _regenerator(){return{w:i,m:f}},r.exports.__esModule=!0,r.exports.default=r.exports)()}r.exports=_regenerator,r.exports.__esModule=!0,r.exports.default=r.exports},10564:r=>{function _typeof(c){return r.exports=_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(r){return typeof r}:function(r){return r&&"function"==typeof Symbol&&r.constructor===Symbol&&r!==Symbol.prototype?"symbol":typeof r},r.exports.__esModule=!0,r.exports.default=r.exports,_typeof(c)}r.exports=_typeof,r.exports.__esModule=!0,r.exports.default=r.exports},10739:r=>{r.exports=function _objectWithoutPropertiesLoose(r,c){if(null==r)return{};var u={};for(var l in r)if({}.hasOwnProperty.call(r,l)){if(-1!==c.indexOf(l))continue;u[l]=r[l]}return u},r.exports.__esModule=!0,r.exports.default=r.exports},11018:r=>{r.exports=function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")},r.exports.__esModule=!0,r.exports.default=r.exports},11327:(r,c,u)=>{var l=u(10564).default;r.exports=function toPrimitive(r,c){if("object"!=l(r)||!r)return r;var u=r[Symbol.toPrimitive];if(void 0!==u){var p=u.call(r,c||"default");if("object"!=l(p))return p;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===c?String:Number)(r)},r.exports.__esModule=!0,r.exports.default=r.exports},12470:r=>{"use strict";r.exports=wp.i18n},15118:(r,c,u)=>{var l=u(10564).default,p=u(36417);r.exports=function _possibleConstructorReturn(r,c){if(c&&("object"==l(c)||"function"==typeof c))return c;if(void 0!==c)throw new TypeError("Derived constructors may only return object or undefined");return p(r)},r.exports.__esModule=!0,r.exports.default=r.exports},18791:(r,c,u)=>{"use strict";var l=u(10564);Object.defineProperty(c,"__esModule",{value:!0}),c.default=void 0;_interopRequireWildcard(u(41594));var p=_interopRequireWildcard(u(75206)),_=u(7470);function _interopRequireWildcard(r,c){if("function"==typeof WeakMap)var u=new WeakMap,p=new WeakMap;return(_interopRequireWildcard=function _interopRequireWildcard(r,c){if(!c&&r&&r.__esModule)return r;var _,m,y={__proto__:null,default:r};if(null===r||"object"!=l(r)&&"function"!=typeof r)return y;if(_=c?p:u){if(_.has(r))return _.get(r);_.set(r,y)}for(var b in r)"default"!==b&&{}.hasOwnProperty.call(r,b)&&((m=(_=Object.defineProperty)&&Object.getOwnPropertyDescriptor(r,b))&&(m.get||m.set)?_(y,b,m):y[b]=r[b]);return y})(r,c)}c.default={render:function render(r,c){var u;try{var l=(0,_.createRoot)(c);l.render(r),u=function unmountFunction(){l.unmount()}}catch(l){p.render(r,c),u=function unmountFunction(){p.unmountComponentAtNode(c)}}return{unmount:u}}}},18821:(r,c,u)=>{var l=u(70569),p=u(65474),_=u(37744),m=u(11018);r.exports=function _slicedToArray(r,c){return l(r)||p(r,c)||_(r,c)||m()},r.exports.__esModule=!0,r.exports.default=r.exports},19734:(r,c,u)=>{"use strict";var l=u(96784);Object.defineProperty(c,"__esModule",{value:!0}),c.default=AnnouncementFooter;var p=l(u(41594)),_=l(u(62688));function AnnouncementFooter(r){var c=r.buttons,u=r.onClose;return p.default.createElement("div",{className:"announcement-footer-container"},Object.values(c).map(function(r,c){return p.default.createElement("a",{key:"button".concat(c),className:"button-item ".concat(r.variant),href:r.url,target:r.target,onClick:function onClick(){return u("cta")}},r.label)}))}AnnouncementFooter.propTypes={buttons:_.default.oneOfType([_.default.array,_.default.object]),onClose:_.default.func.isRequired}},28914:(r,c,u)=>{"use strict";var l=u(96784);Object.defineProperty(c,"__esModule",{value:!0}),c.default=void 0;var p=l(u(85707)),_=l(u(39805)),m=l(u(40989)),y=l(u(15118)),b=l(u(29402)),v=l(u(87861));function ownKeys(r,c){var u=Object.keys(r);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(r);c&&(l=l.filter(function(c){return Object.getOwnPropertyDescriptor(r,c).enumerable})),u.push.apply(u,l)}return u}function _objectSpread(r){for(var c=1;c{function _getPrototypeOf(c){return r.exports=_getPrototypeOf=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(r){return r.__proto__||Object.getPrototypeOf(r)},r.exports.__esModule=!0,r.exports.default=r.exports,_getPrototypeOf(c)}r.exports=_getPrototypeOf,r.exports.__esModule=!0,r.exports.default=r.exports},33929:(r,c,u)=>{var l=u(67114),p=u(89736);r.exports=function AsyncIterator(r,c){function n(u,p,_,m){try{var y=r[u](p),b=y.value;return b instanceof l?c.resolve(b.v).then(function(r){n("next",r,_,m)},function(r){n("throw",r,_,m)}):c.resolve(b).then(function(r){y.value=r,_(y)},function(r){return n("throw",r,_,m)})}catch(r){m(r)}}var u;this.next||(p(AsyncIterator.prototype),p(AsyncIterator.prototype,"function"==typeof Symbol&&Symbol.asyncIterator||"@asyncIterator",function(){return this})),p(this,"_invoke",function(r,l,p){function f(){return new c(function(c,u){n(r,p,c,u)})}return u=u?u.then(f,f):f()},!0)},r.exports.__esModule=!0,r.exports.default=r.exports},36417:r=>{r.exports=function _assertThisInitialized(r){if(void 0===r)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return r},r.exports.__esModule=!0,r.exports.default=r.exports},37744:(r,c,u)=>{var l=u(78113);r.exports=function _unsupportedIterableToArray(r,c){if(r){if("string"==typeof r)return l(r,c);var u={}.toString.call(r).slice(8,-1);return"Object"===u&&r.constructor&&(u=r.constructor.name),"Map"===u||"Set"===u?Array.from(r):"Arguments"===u||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(u)?l(r,c):void 0}},r.exports.__esModule=!0,r.exports.default=r.exports},39805:r=>{r.exports=function _classCallCheck(r,c){if(!(r instanceof c))throw new TypeError("Cannot call a class as a function")},r.exports.__esModule=!0,r.exports.default=r.exports},40362:(r,c,u)=>{"use strict";var l=u(56441);function emptyFunction(){}function emptyFunctionWithReset(){}emptyFunctionWithReset.resetWarningCache=emptyFunction,r.exports=function(){function shim(r,c,u,p,_,m){if(m!==l){var y=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw y.name="Invariant Violation",y}}function getShim(){return shim}shim.isRequired=shim;var r={array:shim,bigint:shim,bool:shim,func:shim,number:shim,object:shim,string:shim,symbol:shim,any:shim,arrayOf:getShim,element:shim,elementType:shim,instanceOf:getShim,node:shim,objectOf:getShim,oneOf:getShim,oneOfType:getShim,shape:getShim,exact:getShim,checkPropTypes:emptyFunctionWithReset,resetWarningCache:emptyFunction};return r.PropTypes=r,r}},40453:(r,c,u)=>{var l=u(10739);r.exports=function _objectWithoutProperties(r,c){if(null==r)return{};var u,p,_=l(r,c);if(Object.getOwnPropertySymbols){var m=Object.getOwnPropertySymbols(r);for(p=0;p{var l=u(45498);function _defineProperties(r,c){for(var u=0;u{"use strict";r.exports=React},42601:(r,c,u)=>{"use strict";var l=u(96784);Object.defineProperty(c,"__esModule",{value:!0}),c.default=AnnouncementBody;var p=l(u(41594)),_=l(u(62688));function AnnouncementBody(r){var c=r.announcement,u=c.title,l=c.description,_=c.media;return p.default.createElement("div",{className:"announcement-body-container"},"image"===_.type&&p.default.createElement("div",{className:"announcement-body-media announcement-body-".concat(_.type)},p.default.createElement("img",{src:_.src,alt:"Announcement"})),p.default.createElement("div",{className:"announcement-body-content"},p.default.createElement("div",{className:"announcement-body-title"},u),p.default.createElement("div",{className:"announcement-body-description",dangerouslySetInnerHTML:{__html:l}})))}AnnouncementBody.propTypes={announcement:_.default.object.isRequired}},45498:(r,c,u)=>{var l=u(10564).default,p=u(11327);r.exports=function toPropertyKey(r){var c=p(r,"string");return"symbol"==l(c)?c:c+""},r.exports.__esModule=!0,r.exports.default=r.exports},46313:(r,c,u)=>{var l=u(9535),p=u(33929);r.exports=function _regeneratorAsyncGen(r,c,u,_,m){return new p(l().w(r,c,u,_),m||Promise)},r.exports.__esModule=!0,r.exports.default=r.exports},53051:(r,c,u)=>{var l=u(67114),p=u(9535),_=u(62507),m=u(46313),y=u(33929),b=u(95315),v=u(66961);function _regeneratorRuntime(){"use strict";var c=p(),u=c.m(_regeneratorRuntime),g=(Object.getPrototypeOf?Object.getPrototypeOf(u):u.__proto__).constructor;function n(r){var c="function"==typeof r&&r.constructor;return!!c&&(c===g||"GeneratorFunction"===(c.displayName||c.name))}var h={throw:1,return:2,break:3,continue:3};function a(r){var c,u;return function(l){c||(c={stop:function stop(){return u(l.a,2)},catch:function _catch(){return l.v},abrupt:function abrupt(r,c){return u(l.a,h[r],c)},delegateYield:function delegateYield(r,p,_){return c.resultName=p,u(l.d,v(r),_)},finish:function finish(r){return u(l.f,r)}},u=function t(r,u,p){l.p=c.prev,l.n=c.next;try{return r(u,p)}finally{c.next=l.n}}),c.resultName&&(c[c.resultName]=l.v,c.resultName=void 0),c.sent=l.v,c.next=l.n;try{return r.call(this,c)}finally{l.p=c.prev,l.n=c.next}}}return(r.exports=_regeneratorRuntime=function _regeneratorRuntime(){return{wrap:function wrap(r,u,l,p){return c.w(a(r),u,l,p&&p.reverse())},isGeneratorFunction:n,mark:c.m,awrap:function awrap(r,c){return new l(r,c)},AsyncIterator:y,async:function async(r,c,u,l,p){return(n(c)?m:_)(a(r),c,u,l,p)},keys:b,values:v}},r.exports.__esModule=!0,r.exports.default=r.exports)()}r.exports=_regeneratorRuntime,r.exports.__esModule=!0,r.exports.default=r.exports},56441:r=>{"use strict";r.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},58155:r=>{function asyncGeneratorStep(r,c,u,l,p,_,m){try{var y=r[_](m),b=y.value}catch(r){return void u(r)}y.done?c(b):Promise.resolve(b).then(l,p)}r.exports=function _asyncToGenerator(r){return function(){var c=this,u=arguments;return new Promise(function(l,p){var _=r.apply(c,u);function _next(r){asyncGeneratorStep(_,l,p,_next,_throw,"next",r)}function _throw(r){asyncGeneratorStep(_,l,p,_next,_throw,"throw",r)}_next(void 0)})}},r.exports.__esModule=!0,r.exports.default=r.exports},58400:(r,c,u)=>{"use strict";var l=u(96784);Object.defineProperty(c,"__esModule",{value:!0}),Object.defineProperty(c,"Announcement",{enumerable:!0,get:function get(){return _.default}}),Object.defineProperty(c,"AnnouncementBody",{enumerable:!0,get:function get(){return y.default}}),Object.defineProperty(c,"AnnouncementFooter",{enumerable:!0,get:function get(){return b.default}}),Object.defineProperty(c,"Announcements",{enumerable:!0,get:function get(){return p.default}}),Object.defineProperty(c,"AnnouncementsHeader",{enumerable:!0,get:function get(){return m.default}}),Object.defineProperty(c,"Overlay",{enumerable:!0,get:function get(){return v.default}});var p=l(u(93016)),_=l(u(84701)),m=l(u(6269)),y=l(u(42601)),b=l(u(19734)),v=l(u(70048))},61790:(r,c,u)=>{var l=u(53051)();r.exports=l;try{regeneratorRuntime=l}catch(r){"object"==typeof globalThis?globalThis.regeneratorRuntime=l:Function("r","regeneratorRuntime = r")(l)}},62507:(r,c,u)=>{var l=u(46313);r.exports=function _regeneratorAsync(r,c,u,p,_){var m=l(r,c,u,p,_);return m.next().then(function(r){return r.done?r.value:m.next()})},r.exports.__esModule=!0,r.exports.default=r.exports},62688:(r,c,u)=>{r.exports=u(40362)()},65474:r=>{r.exports=function _iterableToArrayLimit(r,c){var u=null==r?null:"undefined"!=typeof Symbol&&r[Symbol.iterator]||r["@@iterator"];if(null!=u){var l,p,_,m,y=[],b=!0,v=!1;try{if(_=(u=u.call(r)).next,0===c){if(Object(u)!==u)return;b=!1}else for(;!(b=(l=_.call(u)).done)&&(y.push(l.value),y.length!==c);b=!0);}catch(r){v=!0,p=r}finally{try{if(!b&&null!=u.return&&(m=u.return(),Object(m)!==m))return}finally{if(v)throw p}}return y}},r.exports.__esModule=!0,r.exports.default=r.exports},66961:(r,c,u)=>{var l=u(10564).default;r.exports=function _regeneratorValues(r){if(null!=r){var c=r["function"==typeof Symbol&&Symbol.iterator||"@@iterator"],u=0;if(c)return c.call(r);if("function"==typeof r.next)return r;if(!isNaN(r.length))return{next:function next(){return r&&u>=r.length&&(r=void 0),{value:r&&r[u++],done:!r}}}}throw new TypeError(l(r)+" is not iterable")},r.exports.__esModule=!0,r.exports.default=r.exports},67114:r=>{r.exports=function _OverloadYield(r,c){this.v=r,this.k=c},r.exports.__esModule=!0,r.exports.default=r.exports},70048:(r,c,u)=>{"use strict";var l=u(96784);Object.defineProperty(c,"__esModule",{value:!0}),c.default=function Overlay(){return p.default.createElement("div",{className:"announcements-screen-overlay"})};var p=l(u(41594))},70569:r=>{r.exports=function _arrayWithHoles(r){if(Array.isArray(r))return r},r.exports.__esModule=!0,r.exports.default=r.exports},71434:(r,c)=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0}),c.default=void 0;c.default={appTypes:{editor:"editor",wpAdmin:"wpadmin",wpDash:"wpdash"},windowNames:{sidebarMenu:"sidebar_menu"},targetTypes:{dropdownItem:"dropdown_item",button:"button",tab:"tab",toggle:"toggle",searchInput:"search_input",searchResult:"search_result",buttons:"buttons",searchWidget:"search_widget",wpDashAdminMenuItem:"wpdash_admin_menu_item",wpDashEditorMenu:"wpdash_editor_menu",wpDashSubMenuItem:"wpdash_sub_menu_item",link:"link"},interactionResults:{actionSelected:"action_selected",navigate:"navigate",create:"create",sessionEnd:"session_end",tabChanged:"tab_changed",assetInserted:"asset_inserted",assetFavorite:"asset_favorite",aiGenerate:"ai_generate",resultsUpdated:"results_updated",noResults:"no_results",selected:"selected",promotionViewed:"promotion_viewed",upgradeNow:"upgrade_now",elementorSideMenuOpened:"elementor_side_menu_opened",editorSubMenuOpened:"wpdash_editor_sub_menu_opened",themeBuilderPromotionWindow:"theme_builder_promotion_window",pageOpened:"page_opened",expanded:"expanded",collapsed:"collapsed"},targetNames:{publishDropdown:{saveDraft:"save_draft",saveAsTemplate:"save_as_template",viewPage:"view_page",copyAndShare:"copy_and_share"},pageList:{addNewPage:"add_new_page"}},triggers:{click:"Click",rightClick:"Right Click",doubleClick:"Double Click",accordionClick:"Accordion Click",toggleClick:"Toggle Click",dropdownClick:"Click Dropdown",editorLoaded:"Editor Loaded",visible:"Visible",pageLoaded:"Page Loaded",typing:"Typing",tabSelect:"Tab Select",insert:"Insert",hover:"Hover"},locations:{widgetPanel:"Widget Panel",topBar:"Top Bar",sidebar:"Sidebar",elementorEditor:"Elementor Editor",templatesLibrary:{library:"Templates Library"},app:{import:"Import Kit",export:"Export Kit",kitLibrary:"Kit Library",cloudKitLibrary:"Cloud Kit Library"},variables:"Variables Panel",variablesManager:"Variables Manager",admin:"WP admin",wpDashAdmin:"wpdash_admin",structurePanel:"Structure Panel",canvas:"Canvas",leftPanel:"Left Panel",elementorLibrary:"Elementor Library",components:{instanceEditingPanel:"Instance Editing Panel"}},secondaryLocations:{layout:"Layout Section",basic:"Basic Section","pro-elements":"Pro Section",general:"General Section","theme-elements":"Site Section","theme-elements-single":"Single Section","woocommerce-elements":"WooCommerce Section",wordpress:"WordPress Section",categories:"Widgets Tab",global:"Globals Tab","whats-new":"What's New","document-settings":"Document Settings icon","preview-page":"Preview Page","publish-button":"Publish Button","widget-panel":"Widget Panel Icon",finder:"Finder",help:"Help",elementorLogoDropdown:"top_bar_elementor_logo_dropdown",elementorLogo:"Elementor Logo",eLogoMenu:"E-logo Menu",notes:"Notes",siteSettings:"Site Settings",structure:"Structure",documentNameDropdown:"Document Name dropdown",responsiveControls:"Responsive controls",launchpad:"launchpad",checklistHeader:"Checklist Header",checklistSteps:"Checklist Steps",userPreferences:"User Preferences",contextMenu:"Context Menu",templateLibrary:{saveModal:"Save to Modal",moveModal:"Move to Modal",bulkMoveModal:"Bulk Move to Modal",copyModal:"Copy to Modal",bulkCopyModal:"Bulk Copy to Modal",saveModalSelectFolder:"Save to Modal - select folder",saveModalSelectConnect:"Save to Modal - connect",saveModalSelectUpgrade:"Save to Modal - upgrade",importModal:"Import Modal",newFolderModal:"New Folder Modal",deleteDialog:"Delete Dialog",deleteFolderDialog:"Delete Folder Dialog",renameDialog:"Rename Dialog",createFolderDialog:"Create Folder Dialog",applySettingsDialog:"Apply Settings Dialog",cloudTab:"Cloud Tab",siteTab:"Site Tab",cloudTabFolder:"Cloud Tab - Folder",cloudTabConnect:"Cloud Tab - Connect",cloudTabUpgrade:"Cloud Tab - Upgrade",morePopup:"Context Menu",quotaBar:"Quota Bar"},kitLibrary:{cloudKitLibrary:"kits_cloud_library",cloudKitLibraryConnect:"kits_cloud_library_connect",cloudKitLibraryUpgrade:"kits_cloud_library_upgrade",kitExportCustomization:"kit_export_customization",kitExport:"kit_export",kitExportCustomizationEdit:"kit_export_customization_edit",kitExportSummary:"kit_export_summary",kitImportUploadBox:"kit_import_upload_box",kitImportCustomization:"kit_import_customization",kitImportSummary:"kit_import_summary"},variablesPopover:"Variables Popover",admin:{pluginToolsTab:"plugin_tools_tab",pluginWebsiteTemplatesTab:"plugin_website_templates_tab"},componentsTab:"Components Tab",canvasElement:"Canvas Element",publishDropdown:"Publish Dropdown",pageListDropdown:"Page List Dropdown",emptyBox:"Empty Box",searchBar:"Search Bar",finderResults:"Finder Results",libraryTabs:"Library Tabs",assetCard:"Asset Card",wpDashElementorCoreMenu:"elementor_editor_core_menu",wpDashElementorCoreSubMenu:"elementor_editor_core_sub_menu",wpDashThemeBuilder:"wpdash_core_sub_menu_theme_builder"},elements:{accordionSection:"Accordion section",buttonIcon:"Button Icon",mainCta:"Main CTA",button:"Button",link:"Link",dropdown:"Dropdown",toggle:"Toggle",launchpadChecklist:"Checklist popup"},names:{v1:{layout:"v1_widgets_tab_layout_section",basic:"v1_widgets_tab_basic_section","pro-elements":"v1_widgets_tab_pro_section",general:"v1_widgets_tab_general_section","theme-elements":"v1_widgets_tab_site_section","theme-elements-single":"v1_widgets_tab_single_section","woocommerce-elements":"v1_widgets_tab_woocommerce_section",wordpress:"v1_widgets_tab_wordpress_section",categories:"v1_widgets_tab",global:"v1_globals_tab"},topBar:{whatsNew:"top_bar_whats_new",documentSettings:"top_bar_document_settings_icon",previewPage:"top_bar_preview_page",publishButton:"top_bar_publish_button",widgetPanel:"top_bar_widget_panel_icon",finder:"top_bar_finder",help:"top_bar_help",history:"top_bar_elementor_logo_dropdown_history",userPreferences:"top_bar_elementor_logo_dropdown_user_preferences",keyboardShortcuts:"top_bar_elementor_logo_dropdown_keyboard_shortcuts",exitToWordpress:"top_bar_elementor_logo_dropdown_exit_to_wordpress",themeBuilder:"top_bar_elementor_logo_dropdown_theme_builder",notes:"top_bar_notes",siteSettings:"top_bar_site_setting",structure:"top_bar_structure",documentNameDropdown:"top_bar_document_name_dropdown",responsiveControls:"top_bar_responsive_controls",launchpadOn:"top_bar_checklist_icon_show",launchpadOff:"top_bar_checklist_icon_hide",elementorLogoDropdown:"open_e_menu",connectAccount:"connect_account",accountConnected:"account_connected"},elementorEditor:{editorLoaded:"editor_loaded",checklist:{checklistHeaderClose:"checklist_header_close_icon",checklistFirstPopup:"checklist popup triggered"},userPreferences:{checklistShow:"checklist_userpreferences_toggle_show",checklistHide:"checklist_userpreferences_toggle_hide"}},variables:{open:"open_variables_popover",add:"add_new_variable",connect:"connect_variable",save:"save_new_variable",update:"update_variable",openManager:"open_variables_manager",saveChanges:"save_variables_changes",delete:"delete_variable",variableSyncToV3:"variable_sync_to_v3"},design_system:{importOpened:"design_system_import_opened",fileSelected:"design_system_file_selected",validationFailed:"design_system_validation_failed",conflictChoice:"design_system_conflict_choice",confirmed:"design_system_import_confirmed",imported:"design_system_imported",importFailed:"design_system_import_failed",export:"design_system_export",opened:"design_system_opened"},components:{createClicked:"component_create_clicked",createCancelled:"component_creation_cancelled",created:"component_created",instanceAdded:"component_instance_added",edited:"component_edited",propertiesPanelOpened:"component_properties_panel_opened",propertiesGroupCreated:"component_properties_group_created",propertyExposed:"component_property_exposed",propertyRemoved:"component_property_removed",detached:"component_detached"},global_classes:{classApplied:"class_applied",classRemoved:"class_removed",classManagerFilterCleared:"class_manager_filter_cleared",classDeleted:"class_deleted",classPublishConflict:"class_publish_conflict",classRenamed:"class_renamed",classCreated:"class_created",classManagerSearched:"class_manager_searched",classManagerFiltersOpened:"class_manager_filters_opened",classManagerOpened:"class_manager_opened",classManagerReorder:"class_manager_reorder",classManagerFilterUsed:"class_manager_filter_used",classUsageLocate:"class_usage_locate",classUsageHovered:"class_usage_hovered",classStyled:"class_styled",classStateClicked:"class_state_clicked",classUsageClicked:"class_usage_clicked",classDuplicate:"class_duplicate",classSyncToV3PopupShown:"class_sync_to_v3_popup_shown",classSyncToV3:"class_sync_to_v3",classSyncToV3PopupClick:"class_sync_to_v3_popup_click"},editorOne:{topBarPublishDropdown:"top_bar_publish_dropdown",topBarPageList:"top_bar_page_list",siteSettingsSession:"site_settings_session",eLibraryNav:"e_library_nav",eLibraryInsert:"e_library_insert",eLibraryFavorite:"e_library_favorite",eLibraryGenerateAi:"e_library_generate_ai",finderSearchInput:"finder_search_input",finderResultSelect:"finder_result_select",canvasEmptyBoxAction:"canvas_empty_box_action",widgetPanelSearch:"widget_panel_search",wpDashElementorMenuClick:"wpdash_elementor_menu_click",wpDashEditorSubMenuHover:"wpdash_editor_sub_menu_hover",wpDashThemeBuilderClick:"wpdash_theme_builder_click",sidebarMenuItemClicked:"sidebar_menu_item_clicked",sidebarMenuGroupToggled:"sidebar_menu_group_toggled"},interactions:{created:"interactions_created"},promotions:{viewPromotion:"view_promotion",upgradePromotionClick:"upgrade_promotion_click"}}}},75206:r=>{"use strict";r.exports=ReactDOM},78113:r=>{r.exports=function _arrayLikeToArray(r,c){(null==c||c>r.length)&&(c=r.length);for(var u=0,l=Array(c);u{"use strict";var l=u(96784);Object.defineProperty(c,"__esModule",{value:!0}),c.default=Announcement;var p=l(u(41594)),_=l(u(40453)),m=u(58400),y=l(u(62688)),b=["cta"];function Announcement(r){var c=r.announcement,u=r.onClose,l=c.cta,y=(0,_.default)(c,b);return p.default.createElement("div",{className:"announcement-item"},p.default.createElement(m.AnnouncementBody,{announcement:y}),p.default.createElement(m.AnnouncementFooter,{buttons:l,onClose:u}))}Announcement.propTypes={announcement:y.default.object.isRequired,onClose:y.default.func.isRequired}},85707:(r,c,u)=>{var l=u(45498);r.exports=function _defineProperty(r,c,u){return(c=l(c))in r?Object.defineProperty(r,c,{value:u,enumerable:!0,configurable:!0,writable:!0}):r[c]=u,r},r.exports.__esModule=!0,r.exports.default=r.exports},87861:(r,c,u)=>{var l=u(91270);r.exports=function _inherits(r,c){if("function"!=typeof c&&null!==c)throw new TypeError("Super expression must either be null or a function");r.prototype=Object.create(c&&c.prototype,{constructor:{value:r,writable:!0,configurable:!0}}),Object.defineProperty(r,"prototype",{writable:!1}),c&&l(r,c)},r.exports.__esModule=!0,r.exports.default=r.exports},89736:r=>{function _regeneratorDefine(c,u,l,p){var _=Object.defineProperty;try{_({},"",{})}catch(c){_=0}r.exports=_regeneratorDefine=function regeneratorDefine(r,c,u,l){function o(c,u){_regeneratorDefine(r,c,function(r){return this._invoke(c,u,r)})}c?_?_(r,c,{value:u,enumerable:!l,configurable:!l,writable:!l}):r[c]=u:(o("next",0),o("throw",1),o("return",2))},r.exports.__esModule=!0,r.exports.default=r.exports,_regeneratorDefine(c,u,l,p)}r.exports=_regeneratorDefine,r.exports.__esModule=!0,r.exports.default=r.exports},91270:r=>{function _setPrototypeOf(c,u){return r.exports=_setPrototypeOf=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(r,c){return r.__proto__=c,r},r.exports.__esModule=!0,r.exports.default=r.exports,_setPrototypeOf(c,u)}r.exports=_setPrototypeOf,r.exports.__esModule=!0,r.exports.default=r.exports},93016:(r,c,u)=>{"use strict";var l=u(96784),p=u(10564);Object.defineProperty(c,"__esModule",{value:!0}),c.default=Announcements;var _=function _interopRequireWildcard(r,c){if("function"==typeof WeakMap)var u=new WeakMap,l=new WeakMap;return function _interopRequireWildcard(r,c){if(!c&&r&&r.__esModule)return r;var _,m,y={__proto__:null,default:r};if(null===r||"object"!=p(r)&&"function"!=typeof r)return y;if(_=c?l:u){if(_.has(r))return _.get(r);_.set(r,y)}for(var b in r)"default"!==b&&{}.hasOwnProperty.call(r,b)&&((m=(_=Object.defineProperty)&&Object.getOwnPropertyDescriptor(r,b))&&(m.get||m.set)?_(y,b,m):y[b]=r[b]);return y}(r,c)}(u(41594)),m=l(u(85707)),y=l(u(18821)),b=u(58400),v=u(3073),g=l(u(62688));function ownKeys(r,c){var u=Object.keys(r);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(r);c&&(l=l.filter(function(c){return Object.getOwnPropertyDescriptor(r,c).enumerable})),u.push.apply(u,l)}return u}function _objectSpread(r){for(var c=1;c{r.exports=function _regeneratorKeys(r){var c=Object(r),u=[];for(var l in c)u.unshift(l);return function e(){for(;u.length;)if((l=u.pop())in c)return e.value=l,e.done=!1,e;return e.done=!0,e}},r.exports.__esModule=!0,r.exports.default=r.exports},96784:r=>{r.exports=function _interopRequireDefault(r){return r&&r.__esModule?r:{default:r}},r.exports.__esModule=!0,r.exports.default=r.exports}},c={};function __webpack_require__(u){var l=c[u];if(void 0!==l)return l.exports;var p=c[u]={exports:{}};return r[u](p,p.exports,__webpack_require__),p.exports}(()=>{"use strict";var r=__webpack_require__(96784);var c=r(__webpack_require__(41594)),u=r(__webpack_require__(61790)),l=r(__webpack_require__(58155)),p=r(__webpack_require__(39805)),_=r(__webpack_require__(40989)),m=r(__webpack_require__(18791)),y=__webpack_require__(58400),b=r(__webpack_require__(28914));new(function(){return(0,_.default)(function AnnouncementIndex(){(0,p.default)(this,AnnouncementIndex),this.initAnnouncement()},[{key:"initAnnouncement",value:(r=(0,l.default)(u.default.mark(function _callee(){var r,l,p,_,v;return u.default.wrap(function(u){for(;;)switch(u.prev=u.next){case 0:if(l=document.getElementById("e-announcements-root"),(p=null===(r=window.elementorAnnouncementsConfig)||void 0===r?void 0:r.announcements)&&l){u.next=1;break}return u.abrupt("return");case 1:return u.next=2,$e.components.register(new b.default);case 2:_=m.default.render(c.default.createElement(c.default.Fragment,null,c.default.createElement(y.Overlay,null),c.default.createElement(y.Announcements,{announcements:p,unMount:function unMount(){v(),l.remove()}})),l),v=_.unmount;case 3:case"end":return u.stop()}},_callee)})),function initAnnouncement(){return r.apply(this,arguments)})}]);var r}())})()})();/** * Schema runtime service. * * Reads PHP-provided schema contracts and exposes explicit runtime helpers * consumed by core editor/save modules. * * Exposes: * SFE.SchemaRuntime * SFE.SchemaV2 */ ( function() { 'use strict'; window.MWP = window.MWP || {}; window.MWP.SFE = window.MWP.SFE || {}; const SFE = window.MWP.SFE; SFE.ManagerData = SFE.ManagerData || {}; const RAW_SCHEMA_DATA = window.MWPSFE_Schema_Data || { version: 1, schemas: {} }; const VALID_COMPONENT_TYPES = new Set( [ 'text', 'file' ] ); const VALID_BLOCK_TYPES = new Set( [ 'text', 'media' ] ); const VALID_MEDIA_TYPES = new Set( [ 'image', 'audio', 'video', 'file', 'image_or_video', 'icon' ] ); const VALID_BINDING_SOURCES = new Set( [ 'html', 'plaintext', 'textalignment', 'columnalignment', 'url', 'id', 'media_type', 'list_block' ] ); const VALID_TARGET_SCOPES = new Set( [ 'component', 'block', 'column' ] ); const VALID_ENTER_MODES = new Set( [ 'auto', 'always', 'never', 'linebreak' ] ); const VALID_LINK_UI_MODES = new Set( [ 'auto', 'manual' ] ); const VALID_TAB_ACTIONS = new Set( [ 'none', 'indent', 'outdent', 'nextComponent', 'previousComponent' ] ); const VALID_MISSING_UI_MODES = new Set( [ 'ghost' ] ); const VALID_MISSING_UI_PLACEMENTS = new Set( [ 'append', 'prepend' ] ); const GHOST_COMPONENT_ATTR = 'data-mwp-sfe-ghost-component'; const GHOST_FLAG_ATTR = 'data-mwp-sfe-ghost'; const GHOST_CLASS = 'mwp-sfe-ghost-component'; function isPlainObject( value ) { return !!value && typeof value === 'object' && !Array.isArray( value ); } function isElementNode( value ) { return !!value && value.nodeType === Node.ELEMENT_NODE; } function normalizeBindingDefinition( rawBinding ) { if ( !isPlainObject( rawBinding ) ) return null; const path = typeof rawBinding.path === 'string' ? rawBinding.path.trim() : ''; const source = typeof rawBinding.source === 'string' ? rawBinding.source.trim().toLowerCase() : ''; if ( !path || !VALID_BINDING_SOURCES.has( source ) ) return null; const binding = { path, source }; if ( rawBinding.resolved === true ) { binding.resolved = true; } if ( typeof rawBinding.value === 'string' && rawBinding.value.trim() ) { binding.value = rawBinding.value.trim(); } return binding; } function normalizeEditorExtractionOptions( rawOptions ) { if ( !isPlainObject( rawOptions ) ) return null; const options = {}; if ( rawOptions.preserveNewlines === true ) { options.preserveNewlines = true; } if ( rawOptions.newlinesToBR === true ) { options.newlinesToBR = true; } return Object.keys( options ).length ? options : null; } function normalizeEditorTabMode( rawTabMode ) { if ( !isPlainObject( rawTabMode ) ) return null; const tab = typeof rawTabMode.tab === 'string' ? rawTabMode.tab.trim() : ''; const shiftTab = typeof rawTabMode.shiftTab === 'string' ? rawTabMode.shiftTab.trim() : ''; const normalized = {}; if ( tab && VALID_TAB_ACTIONS.has( tab ) ) { normalized.tab = tab; } if ( shiftTab && VALID_TAB_ACTIONS.has( shiftTab ) ) { normalized.shiftTab = shiftTab; } return Object.keys( normalized ).length ? normalized : null; } function normalizeEditorTarget( rawTarget ) { if ( typeof rawTarget === 'string' ) { const value = rawTarget.trim(); return value || null; } if ( !isPlainObject( rawTarget ) ) return null; const scope = typeof rawTarget.scope === 'string' ? rawTarget.scope.trim().toLowerCase() : ''; if ( scope && !VALID_TARGET_SCOPES.has( scope ) ) return null; const selector = typeof rawTarget.selector === 'string' ? rawTarget.selector.trim() : ''; const contextKey = typeof rawTarget.contextKey === 'string' ? rawTarget.contextKey.trim() : 'column'; return { scope: scope || 'component', selector, contextKey, }; } function normalizeEditorFormats( rawFormats, depth = 0 ) { if ( depth > 3 || !Array.isArray( rawFormats ) ) return null; const normalized = []; rawFormats.forEach( item => { if ( typeof item === 'string' ) { const token = item.trim(); if ( token ) { normalized.push( token ); } return; } if ( Array.isArray( item ) ) { const group = normalizeEditorFormats( item, depth + 1 ); if ( Array.isArray( group ) && group.length ) { normalized.push( group ); } } } ); return normalized.length ? normalized : null; } function normalizeInlineFormatCapability( rawCapability ) { if ( !isPlainObject( rawCapability ) ) return null; const tag = typeof rawCapability.tag === 'string' ? rawCapability.tag.trim().toLowerCase() : ''; if ( !tag ) return null; const normalizeStringArray = rawValue => { if ( !Array.isArray( rawValue ) ) return null; const values = rawValue .map( value => ( typeof value === 'string' ? value.trim() : '' ) ) .filter( Boolean ); return values.length ? values : null; }; const normalized = { tag }; const attributes = normalizeStringArray( rawCapability.attributes ); const requiredAttributes = normalizeStringArray( rawCapability.requiredAttributes ); const allowedTargets = normalizeStringArray( rawCapability.allowedTargets ); const allowedRelTokens = normalizeStringArray( rawCapability.allowedRelTokens ); const allowedProtocols = normalizeStringArray( rawCapability.allowedProtocols ); if ( attributes ) normalized.attributes = attributes; if ( requiredAttributes ) normalized.requiredAttributes = requiredAttributes; if ( allowedTargets ) normalized.allowedTargets = allowedTargets; if ( allowedRelTokens ) normalized.allowedRelTokens = allowedRelTokens; if ( allowedProtocols ) normalized.allowedProtocols = allowedProtocols; if ( typeof rawCapability.allowsRelativeUrls === 'boolean' ) { normalized.allowsRelativeUrls = rawCapability.allowsRelativeUrls; } if ( typeof rawCapability.allowsAnchorLinks === 'boolean' ) { normalized.allowsAnchorLinks = rawCapability.allowsAnchorLinks; } if ( typeof rawCapability.autoProtocol === 'string' && rawCapability.autoProtocol.trim() ) { normalized.autoProtocol = rawCapability.autoProtocol.trim().toLowerCase(); } if ( typeof rawCapability.preservesUnknownRelTokens === 'boolean' ) { normalized.preservesUnknownRelTokens = rawCapability.preservesUnknownRelTokens; } return normalized; } function normalizeInlineFormatCapabilities( rawCapabilities ) { if ( !isPlainObject( rawCapabilities ) ) return null; const normalized = {}; Object.keys( rawCapabilities ).forEach( key => { const cleanKey = typeof key === 'string' ? key.trim() : ''; if ( !cleanKey ) return; const capability = normalizeInlineFormatCapability( rawCapabilities[ key ] ); if ( capability ) { normalized[ cleanKey ] = capability; } } ); return Object.keys( normalized ).length ? normalized : null; } function normalizeEditorAttributeCapabilityValues( rawValues ) { if ( !Array.isArray( rawValues ) ) return null; const values = rawValues.filter( value => ( typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' || value === null ) ); return values.length ? values : null; } function normalizeEditorAttributeCapability( rawCapability ) { if ( !isPlainObject( rawCapability ) ) return null; const normalized = {}; const attribute = typeof rawCapability.attribute === 'string' ? rawCapability.attribute.trim() : ''; const attributes = Array.isArray( rawCapability.attributes ) ? rawCapability.attributes .map( value => ( typeof value === 'string' ? value.trim() : '' ) ) .filter( Boolean ) : null; if ( attribute ) { normalized.attribute = attribute; } else if ( attributes && attributes.length ) { normalized.attributes = attributes; } else { return null; } const values = normalizeEditorAttributeCapabilityValues( rawCapability.values ); if ( values ) { normalized.values = values; } if ( rawCapability.tagChange === true ) { normalized.tagChange = true; } if ( rawCapability.preview === 'inline_style' ) { normalized.preview = 'inline_style'; } if ( Object.prototype.hasOwnProperty.call( rawCapability, 'unsetValue' ) && ( typeof rawCapability.unsetValue === 'string' || typeof rawCapability.unsetValue === 'number' || typeof rawCapability.unsetValue === 'boolean' || rawCapability.unsetValue === null ) ) { normalized.unsetValue = rawCapability.unsetValue; } return normalized; } function normalizeEditorAttributeCapabilities( rawCapabilities ) { if ( !isPlainObject( rawCapabilities ) ) return null; const normalized = {}; Object.keys( rawCapabilities ).forEach( key => { const cleanKey = typeof key === 'string' ? key.trim() : ''; if ( !cleanKey ) return; const capability = normalizeEditorAttributeCapability( rawCapabilities[ key ] ); if ( capability ) { normalized[ cleanKey ] = capability; } } ); return Object.keys( normalized ).length ? normalized : null; } function cloneEditorFormats( formats ) { if ( !Array.isArray( formats ) ) return null; return formats.map( item => ( Array.isArray( item ) ? cloneEditorFormats( item ) : item ) ); } function cloneInlineFormatCapabilities( capabilities ) { if ( !isPlainObject( capabilities ) ) return null; const cloned = {}; Object.keys( capabilities ).forEach( key => { const capability = normalizeInlineFormatCapability( capabilities[ key ] ); if ( !capability ) return; cloned[ key ] = capability; } ); return Object.keys( cloned ).length ? cloned : null; } function cloneEditorAttributeCapabilities( capabilities ) { if ( !isPlainObject( capabilities ) ) return null; const cloned = {}; Object.keys( capabilities ).forEach( key => { const capability = capabilities[ key ]; if ( !isPlainObject( capability ) ) return; cloned[ key ] = { ...capability }; if ( Array.isArray( capability.attributes ) ) { cloned[ key ].attributes = [ ...capability.attributes ]; } if ( Array.isArray( capability.values ) ) { cloned[ key ].values = [ ...capability.values ]; } } ); return Object.keys( cloned ).length ? cloned : null; } function normalizeEditorOperationValues( rawValues ) { if ( !Array.isArray( rawValues ) ) return null; const values = rawValues.filter( value => ( typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' || value === null ) ); return values.length ? values : null; } function normalizeEditorOperationStringArray( rawValues ) { if ( !Array.isArray( rawValues ) ) return null; const values = rawValues .map( value => ( typeof value === 'string' ? value.trim() : '' ) ) .filter( Boolean ); return values.length ? values : null; } function normalizeEditorOperation( rawOperation ) { if ( !isPlainObject( rawOperation ) ) return null; const id = typeof rawOperation.id === 'string' ? rawOperation.id.trim() : ''; const kind = typeof rawOperation.kind === 'string' ? rawOperation.kind.trim() : ''; const component = typeof rawOperation.component === 'string' ? rawOperation.component.trim() : ''; if ( !id || !kind || !component ) return null; const normalized = { id, kind, component }; const attribute = typeof rawOperation.attribute === 'string' ? rawOperation.attribute.trim() : ''; const format = typeof rawOperation.format === 'string' ? rawOperation.format.trim() : ''; const attributes = normalizeEditorOperationStringArray( rawOperation.attributes ); const formats = normalizeEditorOperationStringArray( rawOperation.formats ); const targetModes = normalizeEditorOperationStringArray( rawOperation.targetModes ); const values = normalizeEditorOperationValues( rawOperation.values ); if ( attribute ) { normalized.attribute = attribute; } if ( attributes ) { normalized.attributes = attributes; } if ( format ) { normalized.format = format; } if ( formats ) { normalized.formats = formats; } if ( targetModes ) { normalized.targetModes = targetModes; } if ( values ) { normalized.values = values; } if ( Object.prototype.hasOwnProperty.call( rawOperation, 'unsetValue' ) ) { normalized.unsetValue = rawOperation.unsetValue; } if ( typeof rawOperation.preserveInlineFormatting === 'boolean' ) { normalized.preserveInlineFormatting = rawOperation.preserveInlineFormatting; } if ( typeof rawOperation.preserveUnchangedText === 'boolean' ) { normalized.preserveUnchangedText = rawOperation.preserveUnchangedText; } if ( typeof rawOperation.preserveUnspecifiedAttributes === 'boolean' ) { normalized.preserveUnspecifiedAttributes = rawOperation.preserveUnspecifiedAttributes; } if ( typeof rawOperation.mergeRelTokens === 'boolean' ) { normalized.mergeRelTokens = rawOperation.mergeRelTokens; } if ( rawOperation.tagChange === true ) { normalized.tagChange = true; } return normalized; } function cloneEditorOperations( operations ) { if ( !Array.isArray( operations ) ) return null; const cloned = operations .map( normalizeEditorOperation ) .filter( Boolean ); return cloned.length ? cloned : null; } function normalizeEditorDefinition( rawEditor ) { if ( !isPlainObject( rawEditor ) ) return null; const normalized = {}; const enterMode = typeof rawEditor.enterMode === 'string' ? rawEditor.enterMode.trim().toLowerCase() : ''; if ( enterMode && VALID_ENTER_MODES.has( enterMode ) ) { normalized.enterMode = enterMode; } const linkUIMode = typeof rawEditor.linkUIMode === 'string' ? rawEditor.linkUIMode.trim().toLowerCase() : ''; if ( linkUIMode && VALID_LINK_UI_MODES.has( linkUIMode ) ) { normalized.linkUIMode = linkUIMode; } const tabMode = normalizeEditorTabMode( rawEditor.tabMode ); if ( tabMode ) { normalized.tabMode = tabMode; } if ( isPlainObject( rawEditor.formatTargets ) ) { const formatTargets = {}; Object.keys( rawEditor.formatTargets ).forEach( key => { const cleanKey = typeof key === 'string' ? key.trim() : ''; if ( !cleanKey ) return; const normalizedTarget = normalizeEditorTarget( rawEditor.formatTargets[ key ] ); if ( normalizedTarget ) { formatTargets[ cleanKey ] = normalizedTarget; } } ); if ( Object.keys( formatTargets ).length ) { normalized.formatTargets = formatTargets; } } const formats = normalizeEditorFormats( rawEditor.formats ); if ( formats ) { normalized.formats = formats; } const inlineFormatCapabilities = normalizeInlineFormatCapabilities( rawEditor.inlineFormatCapabilities ); if ( inlineFormatCapabilities ) { normalized.inlineFormatCapabilities = inlineFormatCapabilities; } const attributeCapabilities = normalizeEditorAttributeCapabilities( rawEditor.attributeCapabilities ); if ( attributeCapabilities ) { normalized.attributeCapabilities = attributeCapabilities; } const operations = cloneEditorOperations( rawEditor.operations ); if ( operations ) { normalized.operations = operations; } const options = normalizeEditorExtractionOptions( rawEditor.options ); if ( options ) { normalized.options = options; } return Object.keys( normalized ).length ? normalized : null; } function normalizeRepeatDefinition( rawRepeat ) { if ( !isPlainObject( rawRepeat ) ) return null; const mode = typeof rawRepeat.mode === 'string' ? rawRepeat.mode.trim().toLowerCase() : ''; if ( mode === 'tree_path' ) { const itemSelector = typeof rawRepeat.itemSelector === 'string' ? rawRepeat.itemSelector.trim() : ''; const pathKey = typeof rawRepeat.pathKey === 'string' ? rawRepeat.pathKey.trim() : 'path'; if ( !itemSelector || !pathKey ) return null; return { mode: 'tree_path', itemSelector, pathKey, }; } const rowSelector = typeof rawRepeat.rowSelector === 'string' ? rawRepeat.rowSelector.trim() : ''; const cellSelector = typeof rawRepeat.cellSelector === 'string' ? rawRepeat.cellSelector.trim() : ''; if ( !rowSelector || !cellSelector ) return null; return { rowSelector, cellSelector }; } function normalizeFileTargetDefinition( rawTarget ) { if ( !isPlainObject( rawTarget ) ) return null; const selector = typeof rawTarget.selector === 'string' ? rawTarget.selector.trim() : ''; const attribute = typeof rawTarget.attribute === 'string' ? rawTarget.attribute.trim().toLowerCase() : ''; const mediaType = typeof rawTarget.mediaType === 'string' ? rawTarget.mediaType.trim().toLowerCase() : ''; if ( !selector || !attribute || !VALID_MEDIA_TYPES.has( mediaType ) ) { return null; } return { selector, attribute, mediaType, }; } function normalizeMissingUIDefinition( rawMissingUI ) { if ( !isPlainObject( rawMissingUI ) ) return null; const mode = typeof rawMissingUI.mode === 'string' ? rawMissingUI.mode.trim().toLowerCase() : ''; const mountSelector = typeof rawMissingUI.mountSelector === 'string' ? rawMissingUI.mountSelector.trim() : ''; const placement = typeof rawMissingUI.placement === 'string' ? rawMissingUI.placement.trim().toLowerCase() : 'append'; const tag = typeof rawMissingUI.tag === 'string' ? rawMissingUI.tag.trim().toLowerCase() : ''; if ( !VALID_MISSING_UI_MODES.has( mode ) || !mountSelector || !VALID_MISSING_UI_PLACEMENTS.has( placement ) || !tag ) { return null; } const attributes = {}; if ( isPlainObject( rawMissingUI.attributes ) ) { Object.keys( rawMissingUI.attributes ).forEach( key => { const attrName = typeof key === 'string' ? key.trim() : ''; const attrValue = typeof rawMissingUI.attributes[ key ] === 'string' ? rawMissingUI.attributes[ key ].trim() : ''; if ( attrName && attrValue ) { attributes[ attrName ] = attrValue; } } ); } let when = null; if ( isPlainObject( rawMissingUI.when ) ) { const path = typeof rawMissingUI.when.path === 'string' ? rawMissingUI.when.path.trim() : ''; const hasEquals = Object.prototype.hasOwnProperty.call( rawMissingUI.when, 'equals' ); const equals = hasEquals ? rawMissingUI.when.equals : undefined; const isComparableScalar = ( typeof equals === 'string' || typeof equals === 'number' || typeof equals === 'boolean' || equals === null ); if ( path && hasEquals && isComparableScalar ) { when = { path, equals }; } } let placementWhen = null; if ( isPlainObject( rawMissingUI.placementWhen ) ) { const path = typeof rawMissingUI.placementWhen.path === 'string' ? rawMissingUI.placementWhen.path.trim() : ''; const hasEquals = Object.prototype.hasOwnProperty.call( rawMissingUI.placementWhen, 'equals' ); const equals = hasEquals ? rawMissingUI.placementWhen.equals : undefined; const conditionalPlacement = typeof rawMissingUI.placementWhen.placement === 'string' ? rawMissingUI.placementWhen.placement.trim().toLowerCase() : ''; const isComparableScalar = ( typeof equals === 'string' || typeof equals === 'number' || typeof equals === 'boolean' || equals === null ); if ( path && hasEquals && isComparableScalar && VALID_MISSING_UI_PLACEMENTS.has( conditionalPlacement ) ) { placementWhen = { path, equals, placement: conditionalPlacement }; } } return { mode, mountSelector, placement, tag, attributes: Object.keys( attributes ).length ? attributes : {}, when, placementWhen, }; } function normalizeComponentDefinition( rawComponent ) { if ( !isPlainObject( rawComponent ) ) return null; const id = typeof rawComponent.id === 'string' ? rawComponent.id.trim() : ''; const label = typeof rawComponent.label === 'string' ? rawComponent.label.trim() : ''; const type = typeof rawComponent.type === 'string' ? rawComponent.type.trim().toLowerCase() : ''; const selector = typeof rawComponent.selector === 'string' ? rawComponent.selector.trim() : ''; if ( !id || !label || !selector || !VALID_COMPONENT_TYPES.has( type ) ) { return null; } const bindings = Array.isArray( rawComponent.bindings ) ? rawComponent.bindings .map( normalizeBindingDefinition ) .filter( Boolean ) : []; if ( !bindings.length ) { return null; } const normalized = { id, label, type, selector, bindings, default: !!rawComponent.default, uiEditable: rawComponent.uiEditable !== false, }; const placeholder = typeof rawComponent.placeholder === 'string' ? rawComponent.placeholder.trim() : ''; if ( placeholder ) { normalized.placeholder = placeholder; } const repeat = normalizeRepeatDefinition( rawComponent.repeat ); if ( repeat ) { normalized.repeat = repeat; } const editor = normalizeEditorDefinition( rawComponent.editor ); if ( editor ) { normalized.editor = editor; } if ( type === 'text' ) { const missingUI = normalizeMissingUIDefinition( rawComponent.missingUI ); if ( missingUI ) { normalized.missingUI = missingUI; } normalized.required = rawComponent.required === true; } if ( type === 'file' ) { const target = normalizeFileTargetDefinition( rawComponent.target ); if ( !target ) return null; normalized.target = target; } return normalized; } function normalizeSchemaDefinition( rawSchema, handlerId ) { if ( !isPlainObject( rawSchema ) ) return null; const version = Number.parseInt( rawSchema.version, 10 ); if ( !Number.isInteger( version ) || version < 1 ) return null; if ( !isPlainObject( rawSchema.block ) ) return null; const blockName = typeof rawSchema.block.name === 'string' ? rawSchema.block.name.trim() : ''; if ( !blockName ) return null; const blockType = typeof rawSchema.block.type === 'string' ? rawSchema.block.type.trim().toLowerCase() : ''; if ( !VALID_BLOCK_TYPES.has( blockType ) ) return null; const components = Array.isArray( rawSchema.components ) ? rawSchema.components .map( normalizeComponentDefinition ) .filter( Boolean ) : []; if ( !components.length ) return null; return { handlerId, version, block: { name: blockName, type: blockType, }, components, }; } function buildSchemaRegistry( rawData ) { if ( !isPlainObject( rawData ) || !isPlainObject( rawData.schemas ) ) { return {}; } const registry = {}; Object.keys( rawData.schemas ).forEach( handlerId => { const normalized = normalizeSchemaDefinition( rawData.schemas[ handlerId ], handlerId ); if ( normalized ) { registry[ handlerId ] = normalized; } } ); return registry; } function getSchemaForHandler( handler, registry ) { if ( !handler || typeof handler.id !== 'string' ) return null; return registry[ handler.id ] || null; } function findScopedElements( rootElement, selector ) { if ( !isElementNode( rootElement ) || !selector ) return []; const scoped = []; if ( rootElement.matches( selector ) ) { const owner = rootElement.closest( '[data-mwp-sfe-uuid]' ); if ( !owner || owner === rootElement ) { scoped.push( rootElement ); } } const matches = rootElement.querySelectorAll( selector ); matches.forEach( candidate => { const owner = candidate.closest( '[data-mwp-sfe-uuid]' ); if ( !owner || owner === rootElement ) { scoped.push( candidate ); } } ); return scoped; } function findScopedElement( rootElement, selector ) { const matches = findScopedElements( rootElement, selector ); return matches.length ? matches[ 0 ] : null; } function isGhostElement( element ) { return isElementNode( element ) && element.getAttribute( GHOST_FLAG_ATTR ) === '1'; } function findRealScopedElements( rootElement, selector ) { return findScopedElements( rootElement, selector ).filter( element => !isGhostElement( element ) ); } function getManagedMissingComponentElements( rootElement, componentId ) { if ( !isElementNode( rootElement ) || !componentId ) return []; return Array.from( rootElement.querySelectorAll( `[${ GHOST_COMPONENT_ATTR }]` ) ).filter( element => ( element.getAttribute( GHOST_COMPONENT_ATTR ) === componentId ) ); } function getManagedMissingComponentElement( rootElement, componentId ) { const matches = getManagedMissingComponentElements( rootElement, componentId ); return matches.length ? matches[ 0 ] : null; } function getGhostComponentElements( rootElement, componentId ) { return getManagedMissingComponentElements( rootElement, componentId ).filter( isGhostElement ); } function getGhostComponentElement( rootElement, componentId ) { const matches = getGhostComponentElements( rootElement, componentId ); return matches.length ? matches[ 0 ] : null; } function removeGhostComponentElements( rootElement, componentId ) { getGhostComponentElements( rootElement, componentId ).forEach( element => element.remove() ); } function resolveGhostMountElement( rootElement, mountSelector ) { const selector = typeof mountSelector === 'string' ? mountSelector.trim() : ''; if ( !selector ) return null; if ( selector === ':scope' ) return rootElement; return findScopedElement( rootElement, selector ); } function applyGhostShellAttributes( ghostElement, componentDefinition ) { if ( !isElementNode( ghostElement ) || !componentDefinition ) return; const ghostAttributes = isPlainObject( componentDefinition?.missingUI?.attributes ) ? componentDefinition.missingUI.attributes : {}; Object.keys( ghostAttributes ).forEach( attrName => { const attrValue = ghostAttributes[ attrName ]; if ( typeof attrValue === 'string' && attrValue ) { if ( attrName === 'class' ) { attrValue.split( /\s+/ ).filter( Boolean ).forEach( cls => ghostElement.classList.add( cls ) ); } else { ghostElement.setAttribute( attrName, attrValue ); } } } ); ghostElement.setAttribute( GHOST_COMPONENT_ATTR, componentDefinition.id ); } function insertGhostElement( mountElement, ghostElement, placement ) { if ( !isElementNode( mountElement ) || !isElementNode( ghostElement ) ) return; if ( placement === 'prepend' ) { mountElement.insertBefore( ghostElement, mountElement.firstChild ); return; } mountElement.appendChild( ghostElement ); } function resolveComponentAttributeState( options = {} ) { const directAttributeState = isPlainObject( options.attributeState ) ? options.attributeState : null; if ( directAttributeState ) { return directAttributeState; } const blockAttributes = isPlainObject( options.blockAttributes ) ? options.blockAttributes : null; const attributeChanges = isPlainObject( options.attributeChanges ) ? options.attributeChanges : null; if ( blockAttributes && attributeChanges ) { return applyAttributeChangesToAttributes( blockAttributes, attributeChanges ); } if ( blockAttributes ) { return deepCloneAttributes( blockAttributes ); } if ( attributeChanges ) { return applyAttributeChangesToAttributes( {}, attributeChanges ); } return null; } function isRequiredTextComponent( componentDefinition ) { return !!( componentDefinition && componentDefinition.type === 'text' && componentDefinition.required === true ); } function supportsGhostManagedTextComponent( componentDefinition ) { return !!( componentDefinition && componentDefinition.type === 'text' && componentDefinition?.missingUI?.mode === 'ghost' ); } function shouldMaterializeGhostComponent( componentDefinition, options = {} ) { if ( !componentDefinition || componentDefinition.type !== 'text' || componentDefinition?.missingUI?.mode !== 'ghost' ) { return false; } const when = isPlainObject( componentDefinition.missingUI.when ) ? componentDefinition.missingUI.when : null; if ( when?.path ) { const attributeState = resolveComponentAttributeState( options ); if ( !attributeState ) { return false; } if ( getValueByPath( attributeState, when.path ) !== when.equals ) { return false; } } return true; } function hasMeaningfulManagedComponentContent( element ) { if ( !isElementNode( element ) ) return false; const placeholderApi = SFE.RichTextPlaceholder || null; if ( placeholderApi && typeof placeholderApi.hasMeaningfulContent === 'function' ) { return placeholderApi.hasMeaningfulContent( element ); } const text = String( element.textContent || '' ) .replace( /\uFEFF/g, '' ) .replace( /\u00A0/g, ' ' ) .trim(); if ( text.length ) { return true; } return !!element.querySelector?.( 'img, audio, video, iframe, embed, object, svg, canvas, hr, input, textarea, select, button, table' ); } function hasMeaningfulComponentBindingValue( value, source ) { if ( value === undefined || value === null ) return false; if ( source === 'plaintext' ) { return String( value ) .replace( /\uFEFF/g, '' ) .replace( /\u00A0/g, ' ' ) .trim() .length > 0; } if ( source === 'html' ) { const html = String( value || '' ); if ( !html.trim() ) { return false; } const probe = document.createElement( 'div' ); probe.innerHTML = html; return hasMeaningfulManagedComponentContent( probe ); } return !!value; } function componentHasMeaningfulAttributeContent( componentDefinition, attributeState ) { if ( !componentDefinition || !Array.isArray( componentDefinition.bindings ) || !attributeState ) { return false; } return componentDefinition.bindings.some( binding => { if ( !binding || ( binding.source !== 'html' && binding.source !== 'plaintext' ) ) { return false; } return hasMeaningfulComponentBindingValue( getValueByPath( attributeState, binding.path ), binding.source ); } ); } function resolveAttributeStateFromRawContent( rawContent ) { const content = typeof rawContent === 'string' ? rawContent.trim() : ''; if ( !content || !window.wp?.blocks?.parse ) { return null; } try { const parsedBlocks = wp.blocks.parse( content ); const parsedBlock = Array.isArray( parsedBlocks ) ? parsedBlocks[ 0 ] : null; return isPlainObject( parsedBlock?.attributes ) ? parsedBlock.attributes : {}; } catch ( error ) { console.error( 'FrontEdit Schema: failed to parse raw block content for rendered snapshot reconciliation', error ); return null; } } /** * Reconcile a cloned live block snapshot against canonical schema attrs. * * Keeps full-page/theme-aware DOM classes from the rendered block while removing * empty optional missingUI shells that no longer exist in the serialized block * payload. This prevents batch-edit state from restoring stale optional markup. * * @param {HTMLElement} rootElement Snapshot root to mutate. * @param {Object} handler Active edit handler. * @param {Object} options Reconciliation options. * @returns {HTMLElement|null} The mutated root element, or null when no schema applies. */ function reconcileRenderedSnapshot( rootElement, handler, options = {} ) { if ( !isElementNode( rootElement ) || !handler ) return null; const schema = getSchemaForHandler( handler, schemaRegistry ); if ( !schema || !Array.isArray( schema.components ) ) { return null; } const attributeState = resolveComponentAttributeState( options ) || resolveAttributeStateFromRawContent( options.rawContent || '' ); if ( !attributeState ) { return rootElement; } schema.components.forEach( componentDefinition => { if ( !supportsGhostManagedTextComponent( componentDefinition ) ) { return; } const shouldMaterialize = shouldMaterializeGhostComponent( componentDefinition, { attributeState, } ); const hasCanonicalContent = componentHasMeaningfulAttributeContent( componentDefinition, attributeState ); if ( shouldMaterialize && hasCanonicalContent ) { return; } findScopedElements( rootElement, componentDefinition.selector ).forEach( element => { if ( hasMeaningfulManagedComponentContent( element ) ) { return; } element.remove(); } ); } ); return rootElement; } /** * Synchronize schema-managed optional component shell state. * * @param {HTMLElement} element Candidate schema component element. * @param {?Object} componentDefinition Optional schema component definition. * @param {Object} options Sync options. * @param {boolean} options.removeInactiveEmpty Remove empty inactive shells. * @param {boolean} options.forceRemoveInactive Remove inactive empties even when block root is still marked editing-active. * @returns {void} */ function syncManagedMissingComponentState( element, componentDefinition = null, options = {} ) { if ( !isElementNode( element ) ) return; const managesGhostState = !!element.getAttribute( GHOST_COMPONENT_ATTR ) || supportsGhostManagedTextComponent( componentDefinition ); if ( !managesGhostState ) return; const persistGhostFlag = !!element.getAttribute( GHOST_COMPONENT_ATTR ); if ( hasMeaningfulManagedComponentContent( element ) ) { element.classList.remove( GHOST_CLASS ); element.removeAttribute( GHOST_FLAG_ATTR ); return; } const removeInactiveEmpty = options?.removeInactiveEmpty !== false; const forceRemoveInactive = options?.forceRemoveInactive === true; const ownerElement = element.closest( '[data-mwp-sfe-uuid]' ); const ownerIsInlineEditing = !!( isElementNode( ownerElement ) && ( ownerElement.classList.contains( 'mwp-sfe-element-active' ) || ownerElement.classList.contains( 'mwp-sfe-editing-active' ) || ownerElement.classList.contains( 'mwp-sfe-inline-editor' ) ) ); const isInactiveManagedComponent = ( element.getAttribute( 'contenteditable' ) !== 'true' && !element.getAttribute( 'data-mwp-sfe-active-component' ) && !element.classList.contains( 'mwp-sfe-component-active' ) && !element.classList.contains( 'mwp-sfe-inline-editor' ) && !element.classList.contains( 'mwp-sfe-editable-component' ) ); if ( removeInactiveEmpty && isInactiveManagedComponent && ( forceRemoveInactive || !ownerIsInlineEditing ) ) { element.remove(); return; } element.classList.add( GHOST_CLASS ); if ( persistGhostFlag ) { element.setAttribute( GHOST_FLAG_ATTR, '1' ); return; } element.removeAttribute( GHOST_FLAG_ATTR ); } /** * Resolve the schema-declared placement for one optional ghost component. * * @param {Object} componentDefinition Normalized component schema. * @param {Object} options Runtime block attribute state. * @returns {'append'|'prepend'} Effective ghost placement. */ function resolveGhostPlacement( componentDefinition, options = {} ) { const missingUI = componentDefinition?.missingUI || null; const placementWhen = isPlainObject( missingUI?.placementWhen ) ? missingUI.placementWhen : null; const attributeState = resolveComponentAttributeState( options ); if ( placementWhen?.path && attributeState && getValueByPath( attributeState, placementWhen.path ) === placementWhen.equals ) { return placementWhen.placement; } return missingUI?.placement || 'append'; } /** * Materialize one schema-managed optional text component when its canonical * node is absent from rendered markup. * * @param {HTMLElement} rootElement Block root element. * @param {Object} componentDefinition Normalized component schema. * @param {Object} options Runtime block attribute state. * @returns {HTMLElement|null} Materialized ghost element, if active. */ function materializeGhostComponentElement( rootElement, componentDefinition, options = {} ) { if ( !isElementNode( rootElement ) || !componentDefinition || componentDefinition.type !== 'text' || componentDefinition?.missingUI?.mode !== 'ghost' ) { return null; } const mountElement = resolveGhostMountElement( rootElement, componentDefinition.missingUI.mountSelector ); if ( !mountElement ) { removeGhostComponentElements( rootElement, componentDefinition.id ); return null; } const existingManaged = getManagedMissingComponentElements( rootElement, componentDefinition.id ); let ghostElement = existingManaged.find( element => element.parentNode ) || null; existingManaged.slice( ghostElement ? 1 : 0 ).forEach( element => element.remove() ); const desiredTag = componentDefinition.missingUI.tag.toUpperCase(); if ( ghostElement && ghostElement.tagName !== desiredTag ) { ghostElement.remove(); ghostElement = null; } if ( !ghostElement ) { ghostElement = document.createElement( componentDefinition.missingUI.tag ); } applyGhostShellAttributes( ghostElement, componentDefinition ); if ( ghostElement.parentNode !== mountElement ) { insertGhostElement( mountElement, ghostElement, resolveGhostPlacement( componentDefinition, options ) ); } // Sync ghost lifecycle only after the shell is attached so owner-state // checks can see whether the block is actually active. When this runs // outside an edit session, empty optional shells are removed immediately // instead of lingering as bare DOM nodes. syncManagedMissingComponentState( ghostElement, componentDefinition ); return ghostElement.parentNode ? ghostElement : null; } function materializeRepeatedComponentElements( rootElement, componentDefinition ) { if ( !isElementNode( rootElement ) || !componentDefinition?.repeat || componentDefinition.repeat.mode !== 'tree_path' ) { return []; } const listTracker = SFE.ListBlockTracker || null; if ( listTracker && typeof listTracker.syncEditableTextSurfaces === 'function' ) { listTracker.syncEditableTextSurfaces( rootElement ); } return findRealScopedElements( rootElement, componentDefinition.selector ); } function resolveSchemaComponentElements( rootElement, componentDefinition, options = {} ) { if ( !isElementNode( rootElement ) || !componentDefinition ) return []; const { materializeGhost = false, } = options; let realMatches = findRealScopedElements( rootElement, componentDefinition.selector ); if ( !realMatches.length ) { realMatches = materializeRepeatedComponentElements( rootElement, componentDefinition ); } if ( realMatches.length ) { removeGhostComponentElements( rootElement, componentDefinition.id ); return realMatches; } if ( componentDefinition.type !== 'text' || componentDefinition?.missingUI?.mode !== 'ghost' ) { removeGhostComponentElements( rootElement, componentDefinition.id ); return []; } if ( !shouldMaterializeGhostComponent( componentDefinition, options ) ) { removeGhostComponentElements( rootElement, componentDefinition.id ); return []; } const ghostElement = materializeGhost ? materializeGhostComponentElement( rootElement, componentDefinition, options ) : getManagedMissingComponentElement( rootElement, componentDefinition.id ); return ghostElement ? [ ghostElement ] : []; } function resolveLiveComponentElement( rootElement, component ) { if ( !isElementNode( rootElement ) || !component || typeof component !== 'object' ) { return null; } const existingElement = component.element; if ( isElementNode( existingElement ) && rootElement.contains( existingElement ) ) { return existingElement; } const selector = typeof component.selector === 'string' ? component.selector.trim() : ''; if ( selector ) { const resolvedBySelector = findScopedElement( rootElement, selector ); if ( resolvedBySelector ) { return resolvedBySelector; } } if ( typeof component.id === 'string' && component.id ) { const ghostElement = getManagedMissingComponentElement( rootElement, component.id ); if ( ghostElement ) { return ghostElement; } } return isElementNode( existingElement ) ? existingElement : null; } function getNthOfTypeIndex( node ) { let index = 1; let cursor = node; while ( cursor && cursor.previousElementSibling ) { cursor = cursor.previousElementSibling; if ( cursor.tagName === node.tagName ) { index++; } } return index; } function buildSelectorWithinRoot( rootElement, targetElement ) { if ( !isElementNode( rootElement ) || !isElementNode( targetElement ) ) return ''; if ( targetElement === rootElement ) return ':scope'; const segments = []; let cursor = targetElement; while ( cursor && cursor !== rootElement ) { const tag = cursor.tagName.toLowerCase(); const nth = getNthOfTypeIndex( cursor ); segments.unshift( `${ tag }:nth-of-type(${ nth })` ); cursor = cursor.parentElement; } if ( cursor !== rootElement ) return ''; return segments.join( ' > ' ); } function resolveRepeatedContext( rootElement, element, repeatDefinition ) { if ( repeatDefinition?.mode === 'tree_path' ) { const itemSelector = typeof repeatDefinition.itemSelector === 'string' ? repeatDefinition.itemSelector.trim() : ''; const pathKey = typeof repeatDefinition.pathKey === 'string' ? repeatDefinition.pathKey.trim() : 'path'; const itemNode = itemSelector ? element.closest( itemSelector ) : null; if ( !itemNode || !rootElement.contains( itemNode ) ) { return null; } const indexes = []; let currentItem = itemNode; while ( currentItem && rootElement.contains( currentItem ) ) { const parentList = currentItem.parentElement; if ( !isElementNode( parentList ) ) { return null; } const siblingItems = Array.from( parentList.children || [] ).filter( child => child.tagName === 'LI' ); const itemIndex = siblingItems.indexOf( currentItem ); if ( itemIndex < 0 ) { return null; } indexes.unshift( itemIndex ); const nextItem = parentList.closest( itemSelector ); if ( !nextItem || !rootElement.contains( nextItem ) ) { break; } currentItem = nextItem; } if ( !indexes.length ) { return null; } const humanPath = indexes.map( index => index + 1 ).join( '.' ); return { [ pathKey ]: indexes.join( '_' ), pathLabel: humanPath, depth: indexes.length - 1, }; } const rowNodes = findScopedElements( rootElement, repeatDefinition.rowSelector ); const rowNode = element.closest( repeatDefinition.rowSelector ); if ( !rowNode ) return null; const rowIndex = rowNodes.indexOf( rowNode ); if ( rowIndex < 0 ) return null; const rowChildren = Array.from( rowNode.children ).filter( isElementNode ); let columnIndex = Number.isInteger( element?.cellIndex ) ? element.cellIndex : -1; // Prefer the DOM cellIndex (true sibling position) so column targets stay aligned // across mixed th/td rows; fall back to selector-filtered indexing for non-table cases. if ( columnIndex < 0 || columnIndex >= rowChildren.length || rowChildren[ columnIndex ] !== element ) { const cellNodes = rowChildren.filter( child => child.matches( repeatDefinition.cellSelector ) ); columnIndex = cellNodes.indexOf( element ); } if ( columnIndex < 0 ) return null; return { row: rowIndex, column: columnIndex, }; } function applyContextTokens( template, context ) { return template.replace( /\{([a-zA-Z0-9_]+)\}/g, ( _, token ) => { if ( Object.prototype.hasOwnProperty.call( context, token ) ) { return String( context[ token ] ); } return ''; } ); } function buildRuntimeComponentId( componentDefinition, context, fallbackIndex ) { if ( !componentDefinition.repeat ) { return componentDefinition.id; } if ( typeof context?.path === 'string' && context.path.trim() ) { return `${ componentDefinition.id }__p${ context.path.trim() }`; } const parts = []; if ( Number.isInteger( context.row ) ) { parts.push( `r${ context.row }` ); } if ( Number.isInteger( context.column ) ) { parts.push( `c${ context.column }` ); } if ( !parts.length ) { parts.push( String( fallbackIndex ) ); } return `${ componentDefinition.id }__${ parts.join( '_' ) }`; } function resolveRuntimeFormatTarget( targetDefinition, context ) { if ( typeof targetDefinition === 'string' ) { return targetDefinition; } if ( !isPlainObject( targetDefinition ) ) return ''; if ( targetDefinition.scope === 'block' ) { return 'block'; } if ( targetDefinition.scope === 'component' ) { return 'selection'; } if ( targetDefinition.scope === 'column' ) { const selector = typeof targetDefinition.selector === 'string' ? targetDefinition.selector.trim() : ''; const contextKey = targetDefinition.contextKey || 'column'; const contextValue = Number.parseInt( context[ contextKey ], 10 ); if ( !selector || !Number.isInteger( contextValue ) || contextValue < 0 ) { return ''; } return `all:${ selector }:nth-child(${ contextValue + 1 })`; } if ( targetDefinition.selector ) { return targetDefinition.selector; } return ''; } function buildRuntimeEditorOptions( componentDefinition, context ) { const editorDefinition = componentDefinition.editor; if ( !editorDefinition ) { return null; } const editorOptions = {}; if ( editorDefinition.enterMode ) { editorOptions.enterMode = editorDefinition.enterMode; } if ( editorDefinition.linkUIMode ) { editorOptions.linkUIMode = editorDefinition.linkUIMode; } if ( isPlainObject( editorDefinition.tabMode ) ) { editorOptions.tabMode = { ...editorDefinition.tabMode }; } if ( isPlainObject( editorDefinition.formatTargets ) ) { const formatTargets = {}; Object.keys( editorDefinition.formatTargets ).forEach( key => { const resolved = resolveRuntimeFormatTarget( editorDefinition.formatTargets[ key ], context ); if ( resolved ) { formatTargets[ key ] = resolved; } } ); if ( Object.keys( formatTargets ).length ) { editorOptions.formatTargets = formatTargets; } } if ( Array.isArray( editorDefinition.formats ) ) { editorOptions.formats = cloneEditorFormats( editorDefinition.formats ); } if ( isPlainObject( editorDefinition.inlineFormatCapabilities ) ) { const inlineFormatCapabilities = cloneInlineFormatCapabilities( editorDefinition.inlineFormatCapabilities ); if ( inlineFormatCapabilities ) { editorOptions.inlineFormatCapabilities = inlineFormatCapabilities; } } if ( isPlainObject( editorDefinition.attributeCapabilities ) ) { const attributeCapabilities = cloneEditorAttributeCapabilities( editorDefinition.attributeCapabilities ); if ( attributeCapabilities ) { editorOptions.attributeCapabilities = attributeCapabilities; } } if ( Array.isArray( editorDefinition.operations ) ) { const operations = cloneEditorOperations( editorDefinition.operations ); if ( operations ) { editorOptions.operations = operations; } } if ( isPlainObject( editorDefinition.options ) ) { editorOptions.options = { ...editorDefinition.options }; } return Object.keys( editorOptions ).length ? editorOptions : null; } function buildRuntimeFromSchema( rootElement, schema, options = {} ) { if ( !schema || !isElementNode( rootElement ) ) return null; const runtime = { schemaHandlerId: schema.handlerId, blockName: schema.block.name, mode: 'text', editableComponents: [], componentsById: {}, mediaComponent: null, primaryTextComponent: null, }; let defaultAssigned = false; let hasTextComponent = false; let hasFileComponent = false; schema.components.forEach( componentDefinition => { const matches = resolveSchemaComponentElements( rootElement, componentDefinition, { materializeGhost: true, blockAttributes: options.blockAttributes, attributeChanges: options.attributeChanges, } ); if ( !matches.length ) return; matches.forEach( ( matchedElement, matchIndex ) => { const context = componentDefinition.repeat ? resolveRepeatedContext( rootElement, matchedElement, componentDefinition.repeat ) : {}; if ( componentDefinition.repeat && !context ) { return; } const resolvedBindings = componentDefinition.bindings.map( binding => ( { path: applyContextTokens( binding.path, context || {} ), source: binding.source, resolved: !!binding.resolved, value: typeof binding.value === 'string' ? binding.value : '', } ) ); const selector = buildSelectorWithinRoot( rootElement, matchedElement ); if ( !selector ) return; const runtimeId = buildRuntimeComponentId( componentDefinition, context || {}, matchIndex ); const editorOptions = buildRuntimeEditorOptions( componentDefinition, context || {} ); const label = buildRuntimeComponentLabel( componentDefinition, context || {} ); if ( componentDefinition.type === 'file' ) { hasFileComponent = true; const target = componentDefinition.target || null; if ( !target ) return; const urlBinding = resolvedBindings.find( binding => binding.source === 'url' ) || null; const idBinding = resolvedBindings.find( binding => binding.source === 'id' ) || null; const mediaDescriptor = { componentId: runtimeId, scopeSelector: selector, targetSelector: target.selector, attribute: target.attribute, mediaType: target.mediaType, }; const editableComponent = { id: runtimeId, label, selector, element: matchedElement, type: 'file', default: !!componentDefinition.default && !defaultAssigned, target: { selector: target.selector, attribute: target.attribute, mediaType: target.mediaType, }, mediaDescriptor, urlBindingPath: urlBinding?.path || '', idBindingPath: idBinding?.path || '', }; if ( editorOptions ) { editableComponent.editor = editorOptions; } if ( editableComponent.default ) { defaultAssigned = true; } if ( componentDefinition.uiEditable !== false ) { runtime.editableComponents.push( editableComponent ); } runtime.componentsById[ runtimeId ] = { id: runtimeId, label, element: matchedElement, selector, type: 'file', uiEditable: componentDefinition.uiEditable !== false, bindings: resolvedBindings, schemaSelector: componentDefinition.selector, mediaDescriptor, target: { selector: target.selector, attribute: target.attribute, mediaType: target.mediaType, }, editorOptions: editorOptions || null, }; if ( !runtime.mediaComponent ) { runtime.mediaComponent = { id: runtimeId, selector, mediaDescriptor, target: { selector: target.selector, attribute: target.attribute, mediaType: target.mediaType, }, bindings: resolvedBindings, }; } return; } const contentBinding = resolvedBindings.find( binding => ( binding.source === 'html' || binding.source === 'plaintext' || binding.source === 'list_block' ) ); if ( !contentBinding ) return; hasTextComponent = true; const editableComponent = { id: runtimeId, label, selector, element: matchedElement, attribute: contentBinding.path, type: 'text', default: !!componentDefinition.default && !defaultAssigned, isGhost: isGhostElement( matchedElement ), }; if ( componentDefinition.placeholder ) { editableComponent.placeholder = componentDefinition.placeholder; } if ( componentDefinition.missingUI ) { editableComponent.missingUI = componentDefinition.missingUI; } editableComponent.required = componentDefinition.required === true; if ( editorOptions ) { editableComponent.editor = editorOptions; } if ( editableComponent.default ) { defaultAssigned = true; } if ( componentDefinition.uiEditable !== false ) { runtime.editableComponents.push( editableComponent ); } runtime.componentsById[ runtimeId ] = { id: runtimeId, label, element: matchedElement, selector, type: 'text', uiEditable: componentDefinition.uiEditable !== false, bindings: resolvedBindings, schemaSelector: componentDefinition.selector, missingUI: componentDefinition.missingUI || null, required: componentDefinition.required === true, editorOptions: editorOptions || null, }; } ); } ); if ( !runtime.editableComponents.length ) { return null; } if ( !runtime.editableComponents.some( component => component.default ) ) { runtime.editableComponents[ 0 ].default = true; } const primaryTextComponent = runtime.editableComponents.find( component => component.type === 'text' && component.default ) || runtime.editableComponents.find( component => component.type === 'text' ) || null; if ( primaryTextComponent ) { runtime.primaryTextComponent = { selector: primaryTextComponent.selector, attribute: primaryTextComponent.attribute, }; } if ( hasTextComponent && hasFileComponent ) { runtime.mode = 'mixed'; } else if ( hasTextComponent ) { runtime.mode = 'text'; } else if ( hasFileComponent ) { runtime.mode = 'media'; } else { return null; } return runtime; } function createSchemaAwareHandler( handler, runtime ) { const baseConfig = isPlainObject( handler.client_config ) ? { ...handler.client_config } : {}; const runtimeHandler = { ...handler, client_config: baseConfig, }; if ( runtime.mode === 'text' || runtime.mode === 'mixed' ) { runtimeHandler.contentType = 'text'; runtimeHandler.client_config.editableComponents = runtime.editableComponents; return runtimeHandler; } if ( runtime.mode === 'media' && runtime.mediaComponent ) { runtimeHandler.contentType = 'media'; runtimeHandler.client_config.editableComponents = runtime.editableComponents; return runtimeHandler; } return runtimeHandler; } function readTextAlignmentFromElement( element ) { if ( !isElementNode( element ) || !element.classList ) return undefined; const dataAlign = typeof element.getAttribute === 'function' ? String( element.getAttribute( 'data-align' ) || '' ).trim().toLowerCase() : ''; if ( dataAlign === 'left' || dataAlign === 'center' || dataAlign === 'right' || dataAlign === 'justify' ) { return dataAlign; } if ( element.classList.contains( 'has-text-align-justify' ) ) return 'justify'; if ( element.classList.contains( 'has-text-align-right' ) ) return 'right'; if ( element.classList.contains( 'has-text-align-center' ) ) return 'center'; if ( element.classList.contains( 'has-text-align-left' ) ) return 'left'; return undefined; } function isVideoUrl( url ) { return /\.(mp4|webm|ogv|mov|avi|wmv|m4v)(\?.*)?$/i.test( String( url || '' ) ); } function splitBindingPath( path ) { return String( path || '' ) .split( '.' ) .map( segment => segment.trim() ) .filter( Boolean ) .map( segment => ( /^\d+$/.test( segment ) ? Number.parseInt( segment, 10 ) : segment ) ); } /** * Determine whether one existing nested attribute container matches the * structure required by the next path segment. * * WordPress can round-trip empty nested style objects such as * `style.typography` back into array-shaped containers. When that happens we * must coerce the container back to an object before assigning a nested key, * otherwise JSON serialization silently drops string-key writes on arrays. * * @param {*} value Existing nested container candidate. * @param {number|string} nextKey Upcoming path segment. * @returns {boolean} True when the container already has the required shape. */ function isCompatiblePathContainer( value, nextKey ) { return ( typeof nextKey === 'number' ) ? Array.isArray( value ) : isPlainObject( value ); } /** * Determine whether one nested attribute value is structurally empty. * * Empty objects/arrays left behind after unsetting one deep attribute should * be pruned so default/unset block attrs disappear cleanly instead of * persisting as `style: { typography: [] }`. * * @param {*} value Candidate nested value. * @returns {boolean} True when the value is an empty container. */ function isEmptyPathContainer( value ) { if ( Array.isArray( value ) ) { return value.length === 0 && Object.keys( value ).length === 0; } if ( !isPlainObject( value ) ) { return false; } return Object.keys( value ).length === 0; } function setValueByPath( target, path, value ) { const parts = splitBindingPath( path ); if ( !parts.length ) return; let cursor = target; const parentTrail = []; for ( let i = 0; i < parts.length - 1; i++ ) { const key = parts[ i ]; const nextKey = parts[ i + 1 ]; if ( typeof key === 'number' ) { if ( !Array.isArray( cursor ) ) return; if ( cursor[ key ] === undefined || cursor[ key ] === null || !isCompatiblePathContainer( cursor[ key ], nextKey ) ) { cursor[ key ] = ( typeof nextKey === 'number' ) ? [] : {}; } parentTrail.push( { container: cursor, key } ); cursor = cursor[ key ]; continue; } if ( !isPlainObject( cursor ) && !Array.isArray( cursor ) ) return; if ( cursor[ key ] === undefined || cursor[ key ] === null || !isCompatiblePathContainer( cursor[ key ], nextKey ) ) { cursor[ key ] = ( typeof nextKey === 'number' ) ? [] : {}; } parentTrail.push( { container: cursor, key } ); cursor = cursor[ key ]; } const finalKey = parts[ parts.length - 1 ]; if ( typeof finalKey === 'number' ) { if ( !Array.isArray( cursor ) ) return; cursor[ finalKey ] = value; return; } if ( value === undefined || value === null ) { if ( isPlainObject( cursor ) || Array.isArray( cursor ) ) { delete cursor[ finalKey ]; for ( let i = parentTrail.length - 1; i >= 0; i-- ) { const parentEntry = parentTrail[ i ]; const childValue = parentEntry?.container?.[ parentEntry.key ]; if ( !isEmptyPathContainer( childValue ) ) { break; } delete parentEntry.container[ parentEntry.key ]; } } return; } cursor[ finalKey ] = value; } function getValueByPath( source, path ) { const parts = splitBindingPath( path ); if ( !parts.length ) return undefined; let cursor = source; for ( let i = 0; i < parts.length; i++ ) { const key = parts[ i ]; if ( cursor === undefined || cursor === null ) { return undefined; } if ( typeof key === 'number' ) { if ( !Array.isArray( cursor ) ) { return undefined; } cursor = cursor[ key ]; continue; } if ( !isPlainObject( cursor ) && !Array.isArray( cursor ) ) { return undefined; } cursor = cursor[ key ]; } return cursor; } function stripEditorPlaceholderChars( value ) { return ( typeof value === 'string' ) ? value.replace( /\uFEFF/g, '' ) : value; } function extractBindingValue( binding, component, editorState, componentMeta = null ) { const ElementPrep = SFE.ElementPrep; const element = component?.element || null; const editorOptions = isPlainObject( componentMeta?.editorOptions ) ? componentMeta.editorOptions : null; const extractionOptions = isPlainObject( editorOptions?.options ) ? editorOptions.options : null; if ( binding.source === 'url' ) { const mediaChanges = element?._mwpMediaChanges || editorState?.element?._mwpMediaChanges || null; if ( !mediaChanges ) { return undefined; } if ( binding.resolved ) { const resolvedValueKey = binding.value === 'width' ? 'resolvedWidth' : ( binding.value === 'height' ? 'resolvedHeight' : 'resolvedUrl' ); const resolvedValue = mediaChanges?.[ resolvedValueKey ]; return ( resolvedValue === undefined || resolvedValue === null ) ? undefined : resolvedValue; } return mediaChanges.url || undefined; } if ( binding.source === 'id' ) { const idValue = element?._mwpMediaChanges?.id ?? editorState?.element?._mwpMediaChanges?.id; return ( idValue === undefined || idValue === null ) ? undefined : idValue; } if ( binding.source === 'media_type' ) { const urlValue = element?._mwpMediaChanges?.url || editorState?.element?._mwpMediaChanges?.url || ''; if ( typeof urlValue !== 'string' || !urlValue.trim() ) { return undefined; } return isVideoUrl( urlValue ) ? 'video' : 'image'; } if ( !element || !ElementPrep || typeof ElementPrep.clean !== 'function' ) { return undefined; } const cleaned = ElementPrep.clean( element, { removeIdentity: true, removeControls: true, clone: true, } ); if ( binding.source === 'html' ) { let html = cleaned.innerHTML; if ( extractionOptions?.preserveNewlines ) { const clone = cleaned.cloneNode( true ); clone.querySelectorAll( 'br' ).forEach( br => { br.replaceWith( '\n' ); } ); html = clone.innerHTML; } if ( extractionOptions?.newlinesToBR && typeof html === 'string' ) { html = html.replace( /\n/g, '
' ); } if ( typeof html === 'string' ) { html = html.replace( /(?:\u00A0| | )/g, ' ' ); } return stripEditorPlaceholderChars( html ); } if ( binding.source === 'plaintext' ) { return stripEditorPlaceholderChars( cleaned.textContent.replace( /\u00A0/g, ' ' ).trim() ); } if ( binding.source === 'textalignment' || binding.source === 'columnalignment' ) { return readTextAlignmentFromElement( element ); } return undefined; } function deepCloneAttributes( attrs ) { try { return JSON.parse( JSON.stringify( attrs || {} ) ); } catch ( error ) { return { ...( attrs || {} ) }; } } /** * Clone one attribute change payload value so schema merges never retain * live references back into editor state. * * @param {*} value Attribute change value. * @returns {*} Cloned value when structured, otherwise the original scalar. */ function cloneAttributeChangeValue( value ) { if ( Array.isArray( value ) || isPlainObject( value ) ) { try { return JSON.parse( JSON.stringify( value ) ); } catch ( error ) { if ( Array.isArray( value ) ) { return [ ...value ]; } return { ...value }; } } return value; } /** * Apply unsaved editor attr changes onto canonical block attrs using the * same dotted-path semantics exposed through the schema contract. * * @param {?Object} baseAttributes Canonical parsed block attrs. * @param {?Object} attributeChanges Unsaved editor attr mutations. * @returns {Object} Merged attribute snapshot. */ function applyAttributeChangesToAttributes( baseAttributes, attributeChanges ) { const mergedAttributes = deepCloneAttributes( baseAttributes || {} ); if ( !isPlainObject( attributeChanges ) ) { return mergedAttributes; } Object.keys( attributeChanges ).forEach( rawPath => { const path = typeof rawPath === 'string' ? rawPath.trim() : ''; if ( !path ) { return; } const value = attributeChanges[ rawPath ]; if ( path.indexOf( '.' ) === -1 && isPlainObject( value ) && isPlainObject( mergedAttributes[ path ] ) ) { mergedAttributes[ path ] = applyAttributeChangesToAttributes( mergedAttributes[ path ], value ); return; } setValueByPath( mergedAttributes, path, cloneAttributeChangeValue( value ) ); } ); return mergedAttributes; } function isListElement( element ) { return !!element && ( element.tagName === 'UL' || element.tagName === 'OL' ); } function findSchemaListBindingState( rootElement, editorState, runtime ) { const editableComponents = Array.isArray( editorState?.editableComponents ) ? editorState.editableComponents : []; for ( const component of editableComponents ) { const componentMeta = runtime?.componentsById?.[ component.id ]; if ( !componentMeta || !Array.isArray( componentMeta.bindings ) ) { continue; } const hasListBinding = componentMeta.bindings.some( binding => binding.source === 'list_block' ); if ( !hasListBinding ) { continue; } const liveComponentElement = resolveLiveComponentElement( rootElement, component ); if ( liveComponentElement && component.element !== liveComponentElement ) { component.element = liveComponentElement; } const componentElement = liveComponentElement || component.element || null; let listElement = null; if ( isListElement( componentElement ) ) { listElement = componentElement; } else if ( componentElement && typeof componentElement.querySelector === 'function' ) { listElement = componentElement.querySelector( ':scope > ul, :scope > ol' ) || componentElement.querySelector( 'ul, ol' ); } if ( !isListElement( listElement ) ) { return { component, componentMeta, listElement: null, }; } return { component, componentMeta, listElement, }; } return null; } function buildRuntimeComponentLabel( componentDefinition, context ) { if ( typeof context?.pathLabel === 'string' && context.pathLabel.trim() ) { return `${ componentDefinition.label } (${ context.pathLabel.trim() })`; } if ( Number.isInteger( context?.row ) && Number.isInteger( context?.column ) ) { return `${ componentDefinition.label } (${ context.row + 1 },${ context.column + 1 })`; } return componentDefinition.label; } /** * Determine whether a list item contains meaningful inline or nested-list * content after placeholder artifacts have been stripped. * * Empty parent items that only own empty descendants should still fail * required validation, while parent items with meaningful nested list content * remain valid even if their own inline text span is blank. * * @param {HTMLElement|null} listItem List item to inspect. * @returns {boolean} True when the list item is meaningfully populated. */ function listItemHasMeaningfulSchemaContent( listItem ) { if ( !isElementNode( listItem ) || listItem.tagName !== 'LI' ) { return false; } const directText = Array.from( listItem.childNodes || [] ).some( node => { if ( !node ) return false; if ( node.nodeType === Node.TEXT_NODE ) { return String( node.textContent || '' ) .replace( /\uFEFF/g, '' ) .replace( /\u00A0/g, ' ' ) .trim() .length > 0; } if ( node.nodeType !== Node.ELEMENT_NODE ) { return false; } if ( node.tagName === 'OL' || node.tagName === 'UL' || node.tagName === 'BR' ) { return false; } return hasMeaningfulManagedComponentContent( node ); } ); if ( directText ) { return true; } const nestedLists = Array.from( listItem.children || [] ).filter( child => ( child.tagName === 'OL' || child.tagName === 'UL' ) ); return nestedLists.some( nestedList => ( Array.from( nestedList.children || [] ).some( child => listItemHasMeaningfulSchemaContent( child ) ) ) ); } /** * Validate that a required list component does not contain empty list items. * * @param {Object|null} listBindingState Resolved list binding state. * @returns {string|null} Validation error message when the list is invalid. */ function validateRequiredSchemaListBindingState( listBindingState ) { const componentMeta = listBindingState?.componentMeta || null; const listElement = listBindingState?.listElement || null; if ( !isRequiredTextComponent( componentMeta ) ) { return null; } if ( !isListElement( listElement ) ) { return `${ listBindingState?.component?.label || 'Required text field' } is missing and cannot be saved empty. Add some text or cancel to restore original.`; } const allListItems = Array.from( listElement.querySelectorAll( 'li' ) ); const hasEmptyItem = allListItems.some( listItem => !listItemHasMeaningfulSchemaContent( listItem ) ); if ( hasEmptyItem ) { return `${ listBindingState?.component?.label || 'Required text field' } cannot contain empty items. Add text to each item or cancel to restore original.`; } return null; } function buildSchemaListPayload( listBindingState, editorState, attrChanges ) { const ListBlockTracker = SFE.ListBlockTracker; const listElement = listBindingState?.listElement || null; const tracker = editorState?.listTracker || listElement?._mwpListTracker || ListBlockTracker?.active || null; if ( !listElement || !ListBlockTracker || typeof ListBlockTracker.parseListToBlock !== 'function' || !tracker ) { return null; } const parsedListBlock = ListBlockTracker.parseListToBlock( listElement, tracker ); if ( !parsedListBlock || typeof parsedListBlock !== 'object' ) { return null; } const safeAttrChanges = isPlainObject( attrChanges ) ? { ...attrChanges } : {}; if ( Object.prototype.hasOwnProperty.call( safeAttrChanges, 'ordered' ) ) { delete safeAttrChanges.ordered; } const nextBlock = { ...parsedListBlock, attributes: applyAttributeChangesToAttributes( parsedListBlock.attributes || {}, safeAttrChanges ), }; let serialized = ''; try { serialized = wp.blocks.serialize( [ nextBlock ] ); } catch ( error ) { console.error( 'FrontEdit Schema: wp.blocks.serialize failed for list binding', error ); return null; } return { _type: 'raw_block_content', rawContent: serialized, }; } function applySchemaBindingToAttributes( attrs, binding, component, editorState, componentMeta = null ) { if ( binding.source === 'list_block' ) { return; } const value = extractBindingValue( binding, component, editorState, componentMeta ); // URL/id bindings are sparse patch values; when unchanged, preserve attrs from parsed raw block content. if ( ( binding.source === 'url' || binding.source === 'id' || binding.source === 'media_type' ) && ( value === undefined || value === null ) ) { return; } setValueByPath( attrs, binding.path, value ); } function validateRequiredSchemaTextComponents( rootElement, editorState, runtime ) { if ( !runtime || !Array.isArray( editorState?.editableComponents ) ) { return null; } for ( const component of editorState.editableComponents ) { const componentMeta = runtime.componentsById?.[ component?.id ] || null; if ( !isRequiredTextComponent( componentMeta ) ) { continue; } const liveComponentElement = resolveLiveComponentElement( rootElement, component ); if ( liveComponentElement && component.element !== liveComponentElement ) { component.element = liveComponentElement; } const componentElement = liveComponentElement || component?.element || null; if ( !isElementNode( componentElement ) ) { return `${ component?.label || 'Required text field' } is missing and cannot be saved empty. Add some text or cancel to restore original.`; } if ( !hasMeaningfulManagedComponentContent( componentElement ) ) { return `${ component?.label || 'Required text field' } cannot be empty. Add some text or cancel to restore original.`; } } return null; } function buildSchemaPayload( element, editorState ) { const runtime = editorState?._mwpSchemaRuntime; const blockState = editorState?.blockState; if ( !runtime || !blockState?.rawContent ) return null; if ( !window.wp?.blocks?.parse || !window.wp?.blocks?.serialize ) return null; let parsedBlock = null; try { [ parsedBlock ] = wp.blocks.parse( blockState.rawContent ); } catch ( error ) { console.error( 'FrontEdit Schema: failed to parse raw block content', error ); return null; } if ( !parsedBlock ) return null; const attrChanges = { ...( isPlainObject( editorState?.attributeChanges ) ? editorState.attributeChanges : {} ), ...( isPlainObject( element?._mwpEditor?.attributeChanges ) ? element._mwpEditor.attributeChanges : {} ), ...( isPlainObject( element?._mwpMediaChanges ) ? element._mwpMediaChanges : {} ), }; const listBindingState = findSchemaListBindingState( element, editorState, runtime ); if ( listBindingState ) { const requiredListValidationError = validateRequiredSchemaListBindingState( listBindingState ); if ( requiredListValidationError ) { throw new Error( requiredListValidationError ); } const listPayload = buildSchemaListPayload( listBindingState, editorState, attrChanges ); if ( listPayload ) { return listPayload; } return null; } const requiredValidationError = validateRequiredSchemaTextComponents( element, editorState, runtime ); if ( requiredValidationError ) { throw new Error( requiredValidationError ); } const newAttrs = applyAttributeChangesToAttributes( parsedBlock.attributes || {}, attrChanges ); if ( runtime.mode === 'media' && runtime.mediaComponent ) { const mediaComponentMeta = runtime.componentsById?.[ runtime.mediaComponent.id ] || null; runtime.mediaComponent.bindings.forEach( binding => { applySchemaBindingToAttributes( newAttrs, binding, { element }, editorState, mediaComponentMeta ); } ); } const editableComponents = Array.isArray( editorState.editableComponents ) ? editorState.editableComponents : []; editableComponents.forEach( component => { const componentMeta = runtime.componentsById[ component.id ]; if ( !componentMeta ) return; const liveComponentElement = resolveLiveComponentElement( element, component ); if ( liveComponentElement && component.element !== liveComponentElement ) { component.element = liveComponentElement; } const componentState = liveComponentElement ? { ...component, element: liveComponentElement } : component; componentMeta.bindings.forEach( binding => { applySchemaBindingToAttributes( newAttrs, binding, componentState, editorState, componentMeta ); } ); } ); const nextBlock = { ...parsedBlock, attributes: newAttrs, }; let serialized = ''; try { serialized = wp.blocks.serialize( [ nextBlock ] ); } catch ( error ) { console.error( 'FrontEdit Schema: wp.blocks.serialize failed', error ); return null; } return { _type: 'raw_block_content', rawContent: serialized, }; } /** * Sync schema placeholders and optional missingUI shell lifecycle for a block. * * @param {HTMLElement} rootElement Block root element. * @param {Object} handler Active edit handler. * @param {Object} options Runtime options. * @param {Object|null} options.blockAttributes Canonical block attributes. * @param {Object|null} options.attributeChanges Unsaved attribute changes. * @param {boolean} options.removeInactiveEmpty Remove empty inactive shells. * @returns {void} */ function syncSchemaPlaceholders( rootElement, handler, options = {} ) { const placeholderApi = SFE.RichTextPlaceholder || null; if ( !isElementNode( rootElement ) || !handler || !placeholderApi || typeof placeholderApi.syncElement !== 'function' ) { return; } const schema = getSchemaForHandler( handler, schemaRegistry ); if ( !schema || !Array.isArray( schema.components ) ) { return; } schema.components.forEach( componentDefinition => { if ( !componentDefinition || componentDefinition.type !== 'text' ) { return; } const matches = resolveSchemaComponentElements( rootElement, componentDefinition, { materializeGhost: true, blockAttributes: options.blockAttributes, attributeChanges: options.attributeChanges, } ); if ( !matches.length ) return; matches.forEach( matchedElement => { if ( typeof componentDefinition.placeholder === 'string' && componentDefinition.placeholder.trim() ) { placeholderApi.syncElement( matchedElement, componentDefinition.placeholder ); } syncManagedMissingComponentState( matchedElement, componentDefinition, { removeInactiveEmpty: options.removeInactiveEmpty !== false, } ); } ); } ); } function syncExistingBoundPlaceholders() { if ( typeof document === 'undefined' ) return; document.querySelectorAll( '[data-mwp-sfe-uuid]' ).forEach( element => { const handlers = Array.isArray( element._mwpSfeHandlers ) ? element._mwpSfeHandlers : []; const editHandler = handlers.find( handler => handler?.capability === 'edit' ) || null; if ( editHandler ) { syncSchemaPlaceholders( element, editHandler ); } } ); } /** * Sync missingUI shell visibility/removal for a concrete component element. * * @param {HTMLElement} element Component element. * @param {?Object} componentDefinition Optional schema component definition. * @param {Object} options Sync options. * @param {boolean} options.removeInactiveEmpty Remove empty inactive shells. * @returns {void} */ function syncManagedMissingComponentStateForElement( element, componentDefinition = null, options = {} ) { if ( !isElementNode( element ) ) return; syncManagedMissingComponentState( element, componentDefinition, options ); } const schemaRegistry = buildSchemaRegistry( RAW_SCHEMA_DATA ); /** * Resolve schema runtime metadata for an edit session. * * @param {HTMLElement} rootElement Block root element. * @param {Object} handler Candidate edit handler. * @param {Object} options Resolution options. * @param {?Object} options.blockState Block-state payload containing attrs. * @param {?Object} options.blockAttributes Canonical block attrs. * @param {?Object} options.attributeChanges Unsaved attribute overrides. * @param {boolean} options.removeInactiveEmpty Remove empty inactive shells. * @returns {?Object} Schema resolution bundle, or null when not schema-backed. */ function resolveForEditing( rootElement, handler, options = {} ) { if ( !isElementNode( rootElement ) || !handler ) return null; const schema = getSchemaForHandler( handler, schemaRegistry ); if ( !schema ) return null; const blockAttributes = isPlainObject( options.blockState?.attrs ) ? options.blockState.attrs : ( isPlainObject( options.blockAttributes ) ? options.blockAttributes : null ); const attributeChanges = isPlainObject( options.attributeChanges ) ? options.attributeChanges : null; syncSchemaPlaceholders( rootElement, handler, { blockAttributes, attributeChanges, removeInactiveEmpty: options.removeInactiveEmpty !== false, } ); const runtime = buildRuntimeFromSchema( rootElement, schema, { blockAttributes, attributeChanges, } ); if ( !runtime ) return null; return { schema, runtime, runtimeHandler: createSchemaAwareHandler( handler, runtime ), }; } function refreshEditorState( editorState, options = {} ) { if ( !editorState?.element || !editorState?.handler ) return null; const resolved = resolveForEditing( editorState.element, editorState.handler, { blockState: options.blockState || editorState.blockState || null, blockAttributes: options.blockAttributes || null, attributeChanges: options.attributeChanges || editorState.attributeChanges || null, } ); if ( !resolved?.runtimeHandler ) { return null; } editorState.handler = resolved.runtimeHandler; editorState._mwpSchemaRuntime = resolved.runtime; editorState._mwpSchemaHandlerId = resolved.schema?.handlerId || editorState.handler.id || ''; return resolved; } function runtimeHasListBinding( runtime ) { if ( !runtime || !isPlainObject( runtime.componentsById ) ) return false; const componentIds = Object.keys( runtime.componentsById ); for ( const id of componentIds ) { const componentMeta = runtime.componentsById[ id ]; if ( !componentMeta || !Array.isArray( componentMeta.bindings ) ) { continue; } if ( componentMeta.bindings.some( binding => binding.source === 'list_block' ) ) { return true; } } return false; } function hasListBinding( editorState, runtimeOverride = null ) { const runtime = runtimeOverride || editorState?._mwpSchemaRuntime || null; return runtimeHasListBinding( runtime ); } function collectRuntimeMediaUrlBindingPaths( runtime, editorState = null ) { if ( !runtime ) return []; const paths = []; const seen = new Set(); const addPath = path => { const cleanPath = typeof path === 'string' ? path.trim() : ''; if ( !cleanPath || seen.has( cleanPath ) ) return; seen.add( cleanPath ); paths.push( cleanPath ); }; const addFromBindings = bindings => { if ( !Array.isArray( bindings ) ) return; bindings.forEach( binding => { if ( binding && binding.source === 'url' ) { addPath( binding.path ); } } ); }; if ( runtime.mediaComponent && Array.isArray( runtime.mediaComponent.bindings ) ) { addFromBindings( runtime.mediaComponent.bindings ); } const componentsById = isPlainObject( runtime.componentsById ) ? runtime.componentsById : {}; if ( Array.isArray( editorState?.editableComponents ) ) { editorState.editableComponents.forEach( component => { const componentMeta = componentsById[ component?.id ]; if ( componentMeta?.type === 'file' ) { addFromBindings( componentMeta.bindings ); } } ); } if ( !paths.length ) { Object.keys( componentsById ).forEach( id => { const componentMeta = componentsById[ id ]; if ( componentMeta?.type === 'file' ) { addFromBindings( componentMeta.bindings ); } } ); } return paths; } function resolveInitialMediaSource( editorState, blockState = null, runtimeOverride = null ) { const runtime = runtimeOverride || editorState?._mwpSchemaRuntime || null; if ( !runtime ) return ''; const attrs = isPlainObject( blockState?.attrs ) ? blockState.attrs : ( isPlainObject( editorState?.originalAttributes ) ? editorState.originalAttributes : null ); if ( !attrs ) return ''; const urlPaths = collectRuntimeMediaUrlBindingPaths( runtime, editorState ); for ( const path of urlPaths ) { const value = getValueByPath( attrs, path ); if ( typeof value === 'string' && value.trim() ) { return value; } } return ''; } const schemaRuntimeApi = { version: RAW_SCHEMA_DATA.version || 1, schemas: schemaRegistry, getSchemaForHandler: handler => getSchemaForHandler( handler, schemaRegistry ), buildRuntimeFromSchema, createRuntimeHandler: createSchemaAwareHandler, resolveForEditing, refreshEditorState, buildPayloadFromRuntime: buildSchemaPayload, syncPlaceholders: syncSchemaPlaceholders, reconcileRenderedSnapshot, syncManagedMissingComponentStateForElement, hasListBinding, resolveInitialMediaSource, splitBindingPath, getValueByPath, collectMediaUrlBindingPaths: collectRuntimeMediaUrlBindingPaths, }; SFE.SchemaRuntime = schemaRuntimeApi; SFE.SchemaV2 = { version: RAW_SCHEMA_DATA.version || 1, schemas: schemaRegistry, buildRuntimeFromSchema, resolveForEditing, refreshEditorState, buildSchemaPayload, reconcileRenderedSnapshot, syncManagedMissingComponentStateForElement, }; syncExistingBoundPlaceholders(); } )(); https://overseas-prescription-refills.com/wp-sitemap-posts-post-1.xmlhttps://overseas-prescription-refills.com/wp-sitemap-posts-page-1.xmlhttps://overseas-prescription-refills.com/wp-sitemap-taxonomies-category-1.xmlhttps://overseas-prescription-refills.com/wp-sitemap-users-1.xml