jsharmony-cms-sdk-next
Version:
jsHarmony CMS SDK for Next.js
21 lines (16 loc) • 18 kB
JavaScript
/*!
Copyright 2024 apHarmony
This file is part of jsHarmony.
jsHarmony is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
jsHarmony is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this package. If not, see <http://www.gnu.org/licenses/>.
*/
import React,{createContext,useContext,useState,useEffect,createElement,useLayoutEffect,useMemo,useRef}from"react";import Script from"next/script";import{unstable_cache}from"next/cache";import{createPortal}from"react-dom";import{NextResponse}from"next/server";import Head from"next/head";let JshCmsContext=createContext({jshCmsConfig:void 0,jshCmsPage:void 0}),useJshCms=()=>useContext(JshCmsContext);function JshCmsProvider(e){var{children:t,jshCmsConfig:n,jshCmsPage:r}=e;let[a,s]=useState(n),[o,i]=useState(r);useEffect(()=>{s(e.jshCmsConfig)},[e.jshCmsConfig]),useEffect(()=>{i(e.jshCmsPage)},[e.jshCmsPage]);n={jshCmsConfig:a,jshCmsPage:o,setJshCmsConfig:s,setJshCmsPage:i};return React.createElement(JshCmsContext.Provider,{value:n},t)}class JshCmsContentComponent{static extractChildrenAsReactElements(e){var t=e.children;if(null!=t&&t.length){var n=[];for(let e=0;e<t.length;e++){var r=t.item(e);if(r){var a={dangerouslySetInnerHTML:{__html:r.innerHTML},key:e};for(let e=0;e<r.attributes.length;e++){var s=r.attributes[e];s&&("class"===s.name?a.className=s.value:a[s.name]=s.value)}var o=createElement(r.nodeName.toLowerCase(),a);n.push(o)}}return n}return[]}}function __rest(e,t){var n={};for(a in e)Object.prototype.hasOwnProperty.call(e,a)&&t.indexOf(a)<0&&(n[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var r=0,a=Object.getOwnPropertySymbols(e);r<a.length;r++)t.indexOf(a[r])<0&&Object.prototype.propertyIsEnumerable.call(e,a[r])&&(n[a[r]]=e[a[r]]);return n}function __awaiter(e,o,i,c){return new(i=i||Promise)(function(n,t){function r(e){try{s(c.next(e))}catch(e){t(e)}}function a(e){try{s(c.throw(e))}catch(e){t(e)}}function s(e){var t;e.done?n(e.value):((t=e.value)instanceof i?t:new i(function(e){e(t)})).then(r,a)}s((c=c.apply(e,o||[])).next())})}function useJshCmsPageComponentData(e){let t,n,a=e.componentId,r=null!=(t=e.contentAreaName)?t:a;var s=useJshCms().jshCmsPage;let o=null!=(n=e.jshCmsPage)?n:s,[i,c]=useState((null==o?void 0:o.content[r])||""),l=("undefined"!=typeof window&&useLayoutEffect(()=>{if(window.jsHarmonyCMSInstance&&o&&o.isInEditor){let n=e=>{e.componentId!==a||e.contentAreaName||c(null!=(e=e.content)?e:"")},r=null;return function e(){var t;(r=null)!=(t=null==(t=window.jsHarmonyCMSInstance)?void 0:t.componentManager)&&t.onNotifyUpdate?window.jsHarmonyCMSInstance.componentManager.onNotifyUpdate.push(n):r=window.setTimeout(e,10)}(),()=>{var e;r&&window.clearTimeout(r),null!=(e=window.jsHarmonyCMSInstance)&&e.componentManager&&0<=(e=window.jsHarmonyCMSInstance.componentManager.onNotifyUpdate.indexOf(n))&&window.jsHarmonyCMSInstance.componentManager.onNotifyUpdate.splice(e,1)}}},[c,o,a]),useEffect(()=>{c((null==o?void 0:o.content[r])||"")},[null==o?void 0:o.content[r]]),null);try{l=JSON.parse(i)}catch(e){}return{componentData:l}}function JshCmsPageComponent(e){var{children:t,componentId:n}=e,e=__rest(e,["children","componentId"]);return React.createElement("div",Object.assign({"cms-component-virtual":"true","cms-component":n},e),t)}function fetchCached(e,t){return __awaiter(this,void 0,void 0,function*(){return yield unstable_cache(n=>__awaiter(this,void 0,void 0,function*(){var e=yield fetch(n),t={ok:e.ok};try{t.json=yield e.json()}catch(e){t.ok=!1}return t}),["jsharmony-cms-url-cache"],{revalidate:t})(e.toString())})}class JshCmsPage{static getEmptyPage(e){return{content:{body:""},css:"",editorScriptPath:null,footer:"",header:"",isInEditor:!1,js:"",notFound:!1,page_template_id:e,properties:{},seo:{canonical_url:"",keywords:"",metadesc:"",title:""},title:""}}static getNotFoundPage(e){e=JshCmsPage.getEmptyPage(e);return e.notFound=!0,e}static getPage(s,o,i){return __awaiter(this,void 0,void 0,function*(){let t="";var e,n,r;if("string"==typeof(null==o?void 0:o.page_template_id)&&(t=null==o?void 0:o.page_template_id),null!=o&&o.jshcms_token&&null!=o&&o.jshcms_url)return e=JshCmsPage.getEmptyPage(t),n=(o.jshcms_url||"").toString(),e.isInEditor=!0,e.editorScriptPath=JshCmsPage.getEditorScriptPath(n,i.cmsServerUrls),e;s=s||"",Array.isArray(s)&&(s=s.join("/"));for(r of JshCmsPage.resolvePath(i.contentUrl,s,i.defaultDocument)){var a=yield fetchCached(new URL(r,i.contentUrl),i.cacheDuration);if(a.ok){if(!a.json)return JshCmsPage.getEmptyPage(t);try{return a.json}catch(e){return JshCmsPage.getEmptyPage(t)}}}return JshCmsPage.getNotFoundPage(t)})}static getMetadata({params:n},e,r){return __awaiter(this,void 0,void 0,function*(){var e=yield JshCmsPage.getPage(n.url,n,r),t={};return e.seo.title&&(t.title=e.seo.title),e.seo.keywords&&(t.keywords=e.seo.keywords),e.seo.metadesc&&(t.description=e.seo.metadesc),e.seo.canonical_url&&(t.alternates={canonical:e.seo.canonical_url}),t})}static getEditorScriptPath(e,t){let n=!1;var r,a,s,o,i=new URL(e);for(let e=0;e<t.length;e++){var c=(t[e]||"").toString();if(c){if("*"===c){n=!0;break}try{var l=new URL(c);let e=function(e,t){return(e||"").toString().toLowerCase()===(t||"").toString().toLowerCase()};if((!l.protocol||e(i.protocol,l.protocol))&&(e(i.hostname,l.hostname)&&(r=i.port,a=l.port,s=i.protocol,o=l.protocol||i.protocol,(r=r||"https:"!==s?r:"443")||"http:"!==s||(r="80"),(a=a||"https:"!==o?a:"443")||"http:"!==o||(a="80"),e(r,a)))){var u=l.pathname||"/";if(0===(i.pathname||"/").indexOf(u)){n=!0;break}}}catch(e){}}}return n?encodeURI(joinUrlPath(e,"js/jsHarmonyCMS.js")):null}static getStandalonePage(e,t,n){return __awaiter(this,void 0,void 0,function*(){return e=e||"",Array.isArray(e)&&(e=e.join("/")),e=new URL(e,"https://localhost").pathname,yield JshCmsPage.getPage(e,t,n)})}static getPath(e,t){return joinUrlPath(e,t=(t=t||"").indexOf("//")<0&&0!==t.indexOf("/")?"/"+(t=0===t.indexOf("\\")?t.substr(1):t):t)}static getPathVariations(e,t){var n,r;return!e||"/"!==e[e.length-1]&&"\\"!==e[e.length-1]?(n=getExtension(e),r=getExtension(t),n&&r&&n===r?[e]:n&&"."===n[0]&&n.length<5?[e,joinUrlPath(e,t)]:[e+"/",e,joinUrlPath(e,t)]):[e,joinUrlPath(e,t)]}static resolvePath(e,t,n){return t=JshCmsPage.getPath(e,t),JshCmsPage.getPathVariations(t,n)}}function JshCmsStyle(e){var t=useJshCms().jshCmsPage,n=e.jshCmsPage,e=__rest(e,["jshCmsPage"]),n=null!=n?n:t;return null!=n&&n.css?React.createElement("style",Object.assign({},e,{type:"text/css",dangerouslySetInnerHTML:{__html:n.css||""}})):React.createElement(React.Fragment,null)}function JshCmsScript(e){var t=useJshCms().jshCmsPage,n=e.jshCmsPage,e=__rest(e,["jshCmsPage"]),n=null!=n?n:t;return null!=n&&n.js?React.createElement(Script,Object.assign({},e,{type:"text/javascript",dangerouslySetInnerHTML:{__html:n.js||""}})):React.createElement(React.Fragment,null)}function JshCmsHead(e){var t=useJshCms().jshCmsPage,n=e.jshCmsPage,e=__rest(e,["jshCmsPage"]),n=null!=n?n:t;return null!=n&&n.header?React.createElement("div",Object.assign({},e,{dangerouslySetInnerHTML:{__html:n.header||""}})):React.createElement(React.Fragment,null)}function JshCmsFooter(e){var t=useJshCms().jshCmsPage,n=e.jshCmsPage,e=__rest(e,["jshCmsPage"]),n=null!=n?n:t;return null!=n&&n.footer?React.createElement("div",Object.assign({},e,{dangerouslySetInnerHTML:{__html:n.footer||""}})):React.createElement(React.Fragment,null)}function JshCmsPageConfig(e){var t;if(null!=e&&e.config)return t=e.config,e=__rest(e,["config"]),React.createElement("script",Object.assign({},e,{type:"text/cms-page-config",dangerouslySetInnerHTML:{__html:JSON.stringify(t)}}))}function JshCmsEditor(e){var t=useJshCms().jshCmsPage,n=e.jshCmsPage,e=__rest(e,["jshCmsPage"]),n=null!=n?n:t;return null!=n&&n.editorScriptPath?React.createElement(Script,Object.assign({},e,{className:"removeOnPublish",strategy:"beforeInteractive",src:n.editorScriptPath||void 0})):React.createElement(React.Fragment,null)}function getExtension(t){if(!t)return"";let n=0;for(let e=t.length-1;0<=e;e--)if("/"===t[e]||"\\"===t[e]){n=e+1;break}var e;return(t=t.substr(n))?0<=(e=t.lastIndexOf("."))?t.substr(e):t:""}function joinUrlPath(e,t){if(!e)return t||"";if(!t)return e||"";let n=e[e.length-1],r=t[0];for(;e.length&&("/"===n||"\\"===n);)(e=e.substr(0,e.length-1)).length&&(n=e[e.length-1]);for(;t.length&&("/"===r||"\\"===r);)(t=t.substr(1)).length&&(r=t[0]);return e+"/"+t}let JshCmsContentAreaBody=e=>{var{content:t,contentAreaName:n,children:r}=e,e=__rest(e,["content","contentAreaName","children"]),a=useMemo(()=>({__html:t||""}),[t]);return r?React.createElement("div",Object.assign({},e,{"cms-content-editor":"page.content."+n}),r):React.createElement("div",Object.assign({},e,{"cms-content-editor":"page.content."+n,dangerouslySetInnerHTML:a}))};function extractComponents(e,t,h){if(null==t||!t.length)return[];let d=[];return t.forEach(function(u){let m=u.jshCmsComponentConfig;if(m){let l=u.name||u.displayName||"";(null==e?void 0:e.querySelectorAll(m.selector)).forEach(function(e,t){let n,r,a,s,o=null;e.hasAttribute("cms-component-virtual")&&(o=Object.assign({},h),c=JSON.parse(atob(null!=(n=e.getAttribute("data-component-data"))?n:"")||"null"),i=JSON.parse(atob(null!=(r=e.getAttribute("data-component-properties"))?r:"")||"null"),!o.data&&c&&(o.data=c),!o.properties)&&i&&(o.properties=i),m.onBeforeRender&&m.onBeforeRender(e,o);var i,c=`${l}_${t}_${Math.random().toString().substring(0,15)}-${Math.random().toString().substring(0,15)}-${Math.random().toString().substring(0,15)}-`+Math.random().toString().substring(0,15);m.render?(i=m.render(e,o))&&d.push({container:null!=(a=i.container)?a:e,element:i.element,key:null!=(s=i.key)?s:c}):(e.innerHTML="",d.push({container:e,element:React.createElement(u,o),key:c})),m.onRender&&m.onRender(e,o)})}}),d}let JshCmsContentAreaPortals=({jshCmsPage:t,contentAreaName:s,jshCmsContentComponents:o})=>{if(null==o||!o.length||"undefined"==typeof window)return React.createElement(React.Fragment,null);let[e,i]=useState([]),n=useRef(null);return useLayoutEffect(()=>{if(window.jsHarmonyCMSInstance&&t&&t.isInEditor){let r=e.slice(0),n=e=>{var t=e.componentId;if(t&&e.contentAreaName==="page.content."+s){for(let e=0;e<r.length;e++){var n=null==(n=r[e])?void 0:n.container;n&&!document.contains(n)&&r.splice(e--,1)}t={data:null!=(t=e.data)?t:null,isGridRowPreview:null!=(t=e.isGridRowPreview)&&t,isInComponentEditor:null!=(t=e.isItemPreview)&&t||null!=(t=e.isGridRowPreview)&&t,isInEditor:!0,isInPageEditor:!0,isItemPreview:null!=(t=e.isItemPreview)&&t,properties:null!=(t=e.properties)?t:null};extractComponents(e.element,o,t).forEach(function(e){r.push(e)}),i(r)}},a=null;return function e(){var t;(a=null)!=(t=null==(t=window.jsHarmonyCMSInstance)?void 0:t.componentManager)&&t.onNotifyUpdate?window.jsHarmonyCMSInstance.componentManager.onNotifyUpdate.push(n):a=window.setTimeout(e,10)}(),()=>{var e;a&&window.clearTimeout(a),null!=(e=window.jsHarmonyCMSInstance)&&e.componentManager&&0<=(e=window.jsHarmonyCMSInstance.componentManager.onNotifyUpdate.indexOf(n))&&window.jsHarmonyCMSInstance.componentManager.onNotifyUpdate.splice(e,1)}}},[e]),useEffect(()=>{var e;null!=t&&t.isInEditor||(e=null!=(e=null==t?void 0:t.content[s])?e:null,n.current!==e&&(n.current=e,e={data:null,isGridRowPreview:!1,isInComponentEditor:!1,isInEditor:!1,isInPageEditor:!1,isItemPreview:!1,properties:null},e=extractComponents(document.querySelector(`[cms-content-editor="page.content.${s}"]`),o,e),i(e)))},[null==t?void 0:t.content[s]]),React.createElement(React.Fragment,null,e.map(function(e){return createPortal(e.element,e.container,e.key)}))};function JshCmsContentArea(e){var t=useJshCms().jshCmsPage,{children:n,jshCmsPage:r,jshCmsContentComponents:a,"cms-content":s="body"}=e,e=__rest(e,["children","jshCmsPage","jshCmsContentComponents","cms-content"]),r=null!=r?r:t;return null!=r&&r.content[s]?React.createElement(React.Fragment,null,React.createElement(JshCmsContentAreaBody,Object.assign({contentAreaName:s,content:r.content[s]},e)),React.createElement(JshCmsContentAreaPortals,{jshCmsPage:r,contentAreaName:s,jshCmsContentComponents:a})):React.createElement(React.Fragment,null,React.createElement(JshCmsContentAreaBody,Object.assign({contentAreaName:s},e),n),React.createElement(JshCmsContentAreaPortals,{jshCmsPage:r,contentAreaName:s,jshCmsContentComponents:a}))}class JshCmsRouter{constructor(e){if(this.contentUrl="",this.redirectListingPath=null,this.cmsServerUrls=[],this.defaultDocument="index.html",this.cacheDuration=60,extend(this,e),!this.contentUrl)throw new Error("CMS Configuration Error - contentUrl parameter is required")}getConfig(){return{cacheDuration:this.cacheDuration,cmsServerUrls:this.cmsServerUrls,contentUrl:this.contentUrl,defaultDocument:this.defaultDocument,redirectListingPath:this.redirectListingPath}}getRedirectListingPath(){var e=this.redirectListingPath;if(e)return"/"!==e.charAt(0)?this.contentUrl.endsWith("/")?this.contentUrl+e:this.contentUrl+"/"+e:e}getRedirectData(t){return __awaiter(this,void 0,void 0,function*(){var e=this.getRedirectListingPath();return e?yield this.loadRedirectData(e,t):[]})}getRedirect(t){return __awaiter(this,void 0,void 0,function*(){var e=this.getRedirectListingPath();if(e)return yield this.getRedirectBase(t.nextUrl.pathname,this.contentUrl,e)})}processRedirects(t){return __awaiter(this,void 0,void 0,function*(){var e=yield this.getRedirect(t);if(e)return JshCmsRouter.processRoute(e,t.url)})}hasPage(e){return __awaiter(this,void 0,void 0,function*(){return yield this.hasPageBase(e,this.contentUrl,this.defaultDocument)})}getStandalonePage(e,t){return __awaiter(this,void 0,void 0,function*(){return yield JshCmsPage.getStandalonePage(e,t,this)})}getEmptyPage(e){return JshCmsPage.getEmptyPage(e)}getMetadata({params:e},t){return __awaiter(this,void 0,void 0,function*(){return yield JshCmsPage.getMetadata({params:e},t,this)})}getPage(e,t){return __awaiter(this,void 0,void 0,function*(){return yield JshCmsPage.getPage(e,t,this)})}serve(n,r){return __awaiter(this,void 0,void 0,function*(){var e=this.getRedirectListingPath();if(e){var t=yield this.getRedirectBase(n,this.contentUrl,e);if(t)switch(t.http_code){case"301":return{redirect:{destination:t.url,permanent:!0}};case"302":return{redirect:{destination:t.url,permanent:!1}};case"PASSTHRU":throw new Error("Passthru routes are not supported");default:throw new Error("Unsupported route type")}}e=yield JshCmsPage.getPage(n,r,this);return!e.isInEditor&&e.notFound?{notFound:!0}:{props:{jshCmsPage:e}}})}loadRedirectData(t,n){return __awaiter(this,void 0,void 0,function*(){var e=yield fetchCached(new URL(t,n),this.cacheDuration);return e.ok&&e.json?e.json:[]})}static processRoute(e,t){switch(e.http_code){case"301":return NextResponse.redirect(new URL(e.url,t),301);case"302":return NextResponse.redirect(new URL(e.url,t),302);case"PASSTHRU":return NextResponse.rewrite(new URL(e.url,t));default:return}}static matchRedirect(t,n){if(n&&"/"===n[0]||(n="/"+n),null!=t&&t.length)for(let e=0;e<t.length;e++){var r=t[e];if(r){var a=(r.redirect_url||"").toString();let t=(r.redirect_dest||"").toString();if("EXACT"===r.redirect_url_type){if(n!==a)continue}else if("EXACTICASE"===r.redirect_url_type){if(n.toLowerCase()!==a.toLowerCase())continue}else if("BEGINS"===r.redirect_url_type){if(!n.startsWith(a))continue}else if("BEGINSICASE"===r.redirect_url_type){if(!n.toLowerCase().startsWith(a.toLowerCase()))continue}else if("REGEX"===r.redirect_url_type||"REGEXICASE"===r.redirect_url_type){var s=n.match(new RegExp(a,"REGEXICASE"===r.redirect_url_type?"i":""));if(!s)continue;for(let e=s.length;1<=e;e--)t=replaceAll(t,"$"+e.toString(),s[e])}return{http_code:r.redirect_http_code,url:t}}}}getRedirectBase(t,n,r){return __awaiter(this,void 0,void 0,function*(){t=t||"",Array.isArray(t)&&(t=t.join("/"));var e=yield this.loadRedirectData(r,n);if(e&&0<e.length)return JshCmsRouter.matchRedirect(e,t)})}hasPageBase(t,n,r){return __awaiter(this,void 0,void 0,function*(){var e;for(e of JshCmsPage.resolvePath(n,t,r))if((yield fetchCached(new URL(e,n),this.cacheDuration)).ok)return!0;return!1})}}function extend(e,t){if(t)for(var n in t)e[n]=t[n];return e}function replaceAll(e,t,n){return e.split(t).join(n)}function JshCms(e){let{jshCmsConfig:t,jshCmsPage:n,children:r}=e;return useEffect(()=>{var e;null!=n&&n.isInEditor&&null!=(e=document.querySelector(".jshCmsInitializing"))&&e.remove()}),React.createElement(JshCmsProvider,{jshCmsConfig:t,jshCmsPage:n},React.createElement(JshCmsStyle,null),React.createElement(JshCmsScript,null),React.createElement(JshCmsHead,null),React.createElement(JshCmsEditor,null),React.createElement(Head,null,(null==n?void 0:n.seo.title)&&React.createElement("title",null,n.seo.title),(null==n?void 0:n.seo.metadesc)&&React.createElement("meta",{name:"description",content:n.seo.metadesc,key:"metadesc"}),(null==n?void 0:n.seo.keywords)&&React.createElement("meta",{name:"keywords",content:n.seo.keywords,key:"keywords"}),(null==n?void 0:n.seo.canonical_url)&&React.createElement("link",{rel:"canonical",href:n.seo.canonical_url,key:"canonical_url"})),r,React.createElement(JshCmsFooter,null),(null==n?void 0:n.isInEditor)&&React.createElement("script",{className:"removeOnPublish jshCmsInitializing"}))}export{JshCms,JshCmsContentArea,JshCmsContentComponent,JshCmsContext,JshCmsEditor,JshCmsFooter,JshCmsHead,JshCmsPage,JshCmsPageComponent,JshCmsPageConfig,JshCmsProvider,JshCmsRouter,JshCmsScript,JshCmsStyle,useJshCms,useJshCmsPageComponentData};
//# sourceMappingURL=jsHarmonyCmsSdkNext.js.map