From 7dace895114e2d17ccea85460ef6003368c22a7a Mon Sep 17 00:00:00 2001 From: Steve Boyd Date: Sat, 3 Aug 2024 00:31:02 +1200 Subject: [PATCH] API Remove GraphQL --- _config/graphql.yml | 10 - _graphql/config.yml | 5 - _graphql/models.yml | 41 - _graphql/mutations.yml | 9 - _graphql/scalars.yml | 4 - client/dist/js/bundle.js | 3185 ++++++++++++++++- client/dist/styles/bundle.css | 493 ++- client/src/boot/registerTransforms.js | 47 +- .../ElementActions/ArchiveAction.js | 35 +- .../ElementActions/DuplicateAction.js | 29 +- .../ElementActions/UnpublishAction.js | 87 +- .../tests/ArchiveAction-test.js | 140 +- .../tests/DuplicateAction-test.js | 44 +- .../tests/PublishAction-test.js | 99 +- .../ElementActions/tests/SaveAction-test.js | 97 +- .../tests/UnpublishAction-test.js | 100 +- .../ElementEditor/AddElementPopover.js | 33 +- .../src/components/ElementEditor/Element.js | 47 +- .../components/ElementEditor/ElementEditor.js | 121 +- .../components/ElementEditor/ElementList.js | 59 +- .../ElementEditor/tests/Element-test.js | 105 +- .../ElementEditor/tests/ElementEditor-test.js | 27 +- .../ElementEditor/tests/ElementList-test.js | 12 +- client/src/legacy/ElementEditor/entwine.js | 9 +- client/src/state/editor/addElementMutation.js | 42 - .../src/state/editor/archiveBlockMutation.js | 36 - .../state/editor/duplicateBlockMutation.js | 38 - .../src/state/editor/publishBlockMutation.js | 9 - .../state/editor/readBlocksForAreaQuery.js | 65 - client/src/state/editor/sortBlockMutation.js | 92 - .../state/editor/unpublishBlockMutation.js | 45 - client/src/state/history/readOneBlockQuery.js | 96 - .../history/revertToBlockVersionMutation.js | 43 - .../history/revertToBlockVersionRequest.js | 26 + client/src/types/elementTypeType.js | 2 +- composer.json | 1 - package.json | 5 +- src/Controllers/ElementalAreaController.php | 278 +- src/GraphQL/Resolvers/Resolver.php | 197 - src/Models/BaseElement.php | 38 +- src/ORM/FieldType/DBObjectType.php | 21 - src/Services/ElementTypeRegistry.php | 5 +- src/Services/ReorderElements.php | 6 - .../GraphQL/AddElementToAreaMutationTest.php | 95 - .../GraphQL/AddElementToAreaMutationTest.yml | 2 - .../GraphQL/DuplicateElementMutationTest.php | 72 - tests/GraphQL/FakeResolveInfo.php | 28 - .../GraphQL/SortBlockMutationCreatorTest.php | 64 - .../GraphQL/SortBlockMutationCreatorTest.yml | 13 - tests/Reports/ElementsInUseReportTest.php | 21 - yarn.lock | 143 +- 51 files changed, 4559 insertions(+), 1762 deletions(-) delete mode 100644 _config/graphql.yml delete mode 100644 _graphql/config.yml delete mode 100644 _graphql/models.yml delete mode 100644 _graphql/mutations.yml delete mode 100644 _graphql/scalars.yml delete mode 100644 client/src/state/editor/addElementMutation.js delete mode 100644 client/src/state/editor/archiveBlockMutation.js delete mode 100644 client/src/state/editor/duplicateBlockMutation.js delete mode 100644 client/src/state/editor/publishBlockMutation.js delete mode 100644 client/src/state/editor/readBlocksForAreaQuery.js delete mode 100644 client/src/state/editor/sortBlockMutation.js delete mode 100644 client/src/state/editor/unpublishBlockMutation.js delete mode 100644 client/src/state/history/readOneBlockQuery.js delete mode 100644 client/src/state/history/revertToBlockVersionMutation.js create mode 100644 client/src/state/history/revertToBlockVersionRequest.js delete mode 100644 src/GraphQL/Resolvers/Resolver.php delete mode 100644 src/ORM/FieldType/DBObjectType.php delete mode 100644 tests/GraphQL/AddElementToAreaMutationTest.php delete mode 100644 tests/GraphQL/AddElementToAreaMutationTest.yml delete mode 100644 tests/GraphQL/DuplicateElementMutationTest.php delete mode 100644 tests/GraphQL/FakeResolveInfo.php delete mode 100644 tests/GraphQL/SortBlockMutationCreatorTest.php delete mode 100644 tests/GraphQL/SortBlockMutationCreatorTest.yml diff --git a/_config/graphql.yml b/_config/graphql.yml deleted file mode 100644 index 13b2b076..00000000 --- a/_config/graphql.yml +++ /dev/null @@ -1,10 +0,0 @@ ---- -Name: elemental-graphql -Only: - classexists: 'SilverStripe\GraphQL\Schema\Schema' ---- -SilverStripe\GraphQL\Schema\Schema: - schemas: - admin: - src: - elemental: 'dnadesign/silverstripe-elemental: _graphql' diff --git a/_graphql/config.yml b/_graphql/config.yml deleted file mode 100644 index 08e7c7be..00000000 --- a/_graphql/config.yml +++ /dev/null @@ -1,5 +0,0 @@ -resolvers: - - 'DNADesign\Elemental\GraphQL\Resolvers\Resolver' -typeMapping: - DNADesign\Elemental\Models\BaseElement: Block - DNADesign\Elemental\Models\ElementalArea: ElementalArea diff --git a/_graphql/models.yml b/_graphql/models.yml deleted file mode 100644 index 77e585aa..00000000 --- a/_graphql/models.yml +++ /dev/null @@ -1,41 +0,0 @@ -# Expose common static fields for the ElementEditor component to use for preview summaries -DNADesign\Elemental\Models\BaseElement: - fields: - id: true - lastEdited: true - absoluteLink: String - title: true - showTitle: true - sort: true - blockSchema: ObjectType - obsoleteClassName: String - isPublished: Boolean - isLiveVersion: Boolean - canCreate: Boolean - canPublish: Boolean - canUnpublish: Boolean - canDelete: Boolean - operations: - copyToStage: true - readOne: true - delete: true - publish: true - unpublish: true -# Expose access to Elements via Page -> ElementalArea -> Elements (see resolver) -DNADesign\Elemental\Models\ElementalArea: - fields: - id: true - elements: - plugins: - paginateList: false - operations: - readOne: true - -# Basic member information is required for history views -SilverStripe\Security\Member: - fields: - id: true - firstName: true - surname: true - operations: - readOne: true diff --git a/_graphql/mutations.yml b/_graphql/mutations.yml deleted file mode 100644 index 48ecba4d..00000000 --- a/_graphql/mutations.yml +++ /dev/null @@ -1,9 +0,0 @@ -'addElementToArea(className: String!, elementalAreaID: ID!, afterElementID: ID)': - model: DNADesign\Elemental\Models\BaseElement - description: Adds an Element to an ElementalArea, optionally after another Element -'duplicateBlock(id: ID!)': - model: DNADesign\Elemental\Models\BaseElement - description: Duplicate an Element in this ElementalArea -'sortBlock(id: ID!, afterBlockID: ID!)': - model: DNADesign\Elemental\Models\BaseElement - description: Changes the sort position of an element diff --git a/_graphql/scalars.yml b/_graphql/scalars.yml deleted file mode 100644 index 1bffd517..00000000 --- a/_graphql/scalars.yml +++ /dev/null @@ -1,4 +0,0 @@ -ObjectType: - serialiser: [DNADesign\Elemental\GraphQL\Resolvers\Resolver, 'serialiseObjectType'] - literalParser: [DNADesign\Elemental\GraphQL\Resolvers\Resolver, 'parseLiteralObjectType'] - valueParser: [DNADesign\Elemental\GraphQL\Resolvers\Resolver, 'parseValueObjectType'] diff --git a/client/dist/js/bundle.js b/client/dist/js/bundle.js index df1b50b3..ce1b338e 100644 --- a/client/dist/js/bundle.js +++ b/client/dist/js/bundle.js @@ -1,109 +1,3092 @@ -!function(){"use strict";var e={2038:function(e,t,n){var r=a(n(4121)),o=a(n(1240));function a(e){return e&&e.__esModule?e:{default:e}}window.document.addEventListener("DOMContentLoaded",(()=>{(0,r.default)(),(0,o.default)()}))},4121:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=v(n(5207)),o=v(n(584)),a=v(n(7105)),l=v(n(6721)),i=v(n(2512)),s=v(n(5563)),d=v(n(5297)),u=v(n(7651)),c=v(n(1305)),f=v(n(7660)),p=v(n(7333)),m=v(n(2382)),g=v(n(8953)),h=v(n(1950)),b=v(n(6573));function v(e){return e&&e.__esModule?e:{default:e}}t.default=()=>{r.default.component.registerMany({ElementEditor:l.default,ElementToolbar:s.default,ElementAddNewButton:d.default,ElementList:i.default,Element:o.default,ElementActions:a.default,ElementHeader:u.default,ElementContent:c.default,ElementSummary:f.default,ElementInlineEditForm:p.default,AddElementPopover:m.default,HoverBar:g.default,DragPositionIndicator:h.default,TextCheckboxGroupField:b.default})}},1240:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=m(n(5207)),o=m(n(5071)),a=m(n(2977)),l=m(n(8633)),i=m(n(3521)),s=m(n(6283)),d=m(n(4)),u=m(n(9283)),c=m(n(8501)),f=m(n(2221)),p=m(n(5904));function m(e){return e&&e.__esModule?e:{default:e}}t.default=()=>{r.default.transform("elemental-fieldgroup",(e=>{e.component("FieldGroup.HistoryViewer.VersionDetail",a.default,"HistoricElement")}),{after:"field-holders"}),r.default.transform("elements-history",(e=>{e.component("HistoryViewer.Form_ItemEditForm",o.default,"ElementHistoryViewer")})),r.default.transform("blocks-history-revert",(e=>{e.component("HistoryViewerToolbar.VersionedAdmin.HistoryViewer.Element.HistoryViewerVersionDetail",l.default,"BlockRevertMutation")})),r.default.transform("cms-element-editor",(e=>{e.component("ElementList",i.default,"PageElements")})),r.default.transform("cms-element-adder",(e=>{e.component("AddElementPopover",s.default,"ElementAddButton")})),r.default.transform("element-actions",(e=>{e.component("ElementActions",c.default,"ElementActionsWithSave"),e.component("ElementActions",f.default,"ElementActionsWithPublish"),e.component("ElementActions",p.default,"ElementActionsWithUnpublish"),e.component("ElementActions",u.default,"ElementActionsWithDuplicate"),e.component("ElementActions",d.default,"ElementActionsWithArchive")}))}},26:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=s(n(1594)),o=s(n(6935)),a=s(n(6923)),l=n(3556),i=n(9791);function s(e){return e&&e.__esModule?e:{default:e}}const d=e=>{const{className:t,title:n,label:o}=e,i={className:(0,a.default)(t,"dropdown-item"),...e};return r.default.createElement(l.DropdownItem,i,o||n)};d.propTypes={disabled:o.default.bool,className:o.default.string,onClick:o.default.func,title:o.default.string,name:o.default.string,type:i.elementTypeType,active:o.default.bool,label:o.default.string},d.defaultProps={disabled:!1};t.default=d},4:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.Component=void 0;var r=s(n(1594)),o=n(9367),a=s(n(26)),l=s(n(1429)),i=s(n(5815));function s(e){return e&&e.__esModule?e:{default:e}}const d=e=>t=>{const n=void 0!==t.element.canDelete&&!t.element.canDelete,o=i.default._t("ElementArchiveAction.ARCHIVE","Archive"),l={label:o,title:n?i.default._t("ElementArchiveAction.ARCHIVE_PERMISSION_DENY","Archive, insufficient permissions"):o,disabled:n,className:"element-editor__actions-archive",onClick:e=>{e.stopPropagation();const{element:{id:n},isPublished:r,actions:{handleArchiveBlock:o}}=t;let a=i.default._t("ElementArchiveAction.CONFIRM_DELETE","Are you sure you want to send this block to the archive?");r&&(a=i.default._t("ElementArchiveAction.CONFIRM_DELETE_AND_UNPUBLISH","Warning: This block will be unpublished before being sent to the archive. Are you sure you want to proceed?")),o&&window.confirm(a)&&o(n).then((()=>{const e=window.jQuery(".cms-preview");e&&"function"==typeof e.entwine&&e.entwine("ss.preview")._loadUrl(e.find("iframe").attr("src"))}))},toggle:t.toggle};return r.default.createElement(e,t,t.children,r.default.createElement(a.default,l))};t.Component=d;t.default=(0,o.compose)(l.default,d)},9283:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.Component=void 0;var r=s(n(1594)),o=n(9367),a=s(n(26)),l=s(n(9324)),i=s(n(5815));function s(e){return e&&e.__esModule?e:{default:e}}const d=e=>t=>{if(t.type.broken)return r.default.createElement(e,t);const n=void 0!==t.element.canCreate&&!t.element.canCreate,o=i.default._t("ElementArchiveAction.DUPLICATE","Duplicate"),l={label:o,title:n?i.default._t("ElementArchiveAction.DUPLICATE_PERMISSION_DENY","Duplicate, insufficient permissions"):o,disabled:n,className:"element-editor__actions-duplicate",onClick:e=>{e.stopPropagation();const{element:{id:n},actions:{handleDuplicateBlock:r}}=t;r&&r(n).then((()=>{const e=window.jQuery(".cms-preview");e.entwine("ss.preview")._loadUrl(e.find("iframe").attr("src"))}))},toggle:t.toggle};return r.default.createElement(e,t,t.children,r.default.createElement(a.default,l))};t.Component=d;t.default=(0,o.compose)(l.default,d)},2221:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.Component=void 0;var r=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=s(t);if(n&&n.has(e))return n.get(e);var r={__proto__:null},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&{}.hasOwnProperty.call(e,a)){var l=o?Object.getOwnPropertyDescriptor(e,a):null;l&&(l.get||l.set)?Object.defineProperty(r,a,l):r[a]=e[a]}return r.default=e,n&&n.set(e,r),r}(n(1594)),o=i(n(26)),a=i(n(5815)),l=n(584);function i(e){return e&&e.__esModule?e:{default:e}}function s(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(s=function(e){return e?n:t})(e)}const d=e=>t=>{const{formDirty:n,onPublishButtonClick:i}=(0,r.useContext)(l.ElementContext),{element:s}=t,d=void 0!==t.element.canPublish&&!t.element.canPublish,u=a.default._t("ElementArchiveAction.PUBLISH","Publish"),c={label:u,title:d?a.default._t("ElementArchiveAction.PUBLISH_PERMISSION_DENY","Publish, insufficient permissions"):u,disabled:d,className:"element-editor__actions-publish",onClick:e=>{e.stopPropagation(),i()},toggle:t.toggle};return t.type.broken?r.default.createElement(e,t):r.default.createElement(e,t,t.children,(n||!s.isLiveVersion)&&r.default.createElement(o.default,c))};t.Component=d;t.default=d},8501:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.Component=void 0;var r=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=s(t);if(n&&n.has(e))return n.get(e);var r={__proto__:null},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&{}.hasOwnProperty.call(e,a)){var l=o?Object.getOwnPropertyDescriptor(e,a):null;l&&(l.get||l.set)?Object.defineProperty(r,a,l):r[a]=e[a]}return r.default=e,n&&n.set(e,r),r}(n(1594)),o=i(n(26)),a=i(n(5815)),l=n(584);function i(e){return e&&e.__esModule?e:{default:e}}function s(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(s=function(e){return e?n:t})(e)}const d=e=>t=>{const{onSaveButtonClick:n,formDirty:i}=(0,r.useContext)(l.ElementContext),s={title:a.default._t("ElementSaveAction.SAVE","Save"),className:"element-editor__actions-save",onClick:e=>{e.stopPropagation(),n()},toggle:t.toggle};return!t.expandable||t.type.broken?r.default.createElement(e,t):r.default.createElement(e,t,t.children,i&&r.default.createElement(o.default,s))};t.Component=d;t.default=d},5904:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.Component=void 0;var r=s(n(1594)),o=n(9367),a=s(n(26)),l=s(n(2393)),i=s(n(5815));function s(e){return e&&e.__esModule?e:{default:e}}const d=e=>t=>{if(t.type.broken)return r.default.createElement(e,t);const{element:n,type:o,actions:{handleUnpublishBlock:l}}=t,s=void 0!==t.element.canUnpublish&&!t.element.canUnpublish,d=i.default._t("ElementArchiveAction.UNPUBLISH","Unpublish"),u={label:d,title:s?i.default._t("ElementArchiveAction.UNPUBLISH_PERMISSION_DENY","Unpublish, insufficient permissions"):d,disabled:s,className:"element-editor__actions-unpublish",onClick:e=>{e.stopPropagation();const{jQuery:t}=window,r=i.default.inject(i.default._t("ElementHeader.NOTITLE","Untitled {type} block"),{type:o.title});l&&l(n.id).then((()=>{const e=t(".cms-preview");e.entwine("ss.preview")._loadUrl(e.find("iframe").attr("src")),t.noticeAdd({text:i.default.inject(i.default._t("ElementUnpublishAction.SUCCESS_NOTIFICATION","Removed '{title}' from the published page"),{title:n.title||r}),stay:!1,type:"success"})})).catch((()=>{t.noticeAdd({text:i.default.inject(i.default._t("ElementUnpublishAction.ERROR_NOTIFICATION","Error unpublishing '{title}'"),{title:n.title||r}),stay:!1,type:"error"})}))},toggle:t.toggle};return r.default.createElement(e,t,t.children,n.isPublished&&r.default.createElement(a.default,u))};t.Component=d;t.default=(0,o.compose)(l.default,d)},2382:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=u(t);if(n&&n.has(e))return n.get(e);var r={__proto__:null},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&{}.hasOwnProperty.call(e,a)){var l=o?Object.getOwnPropertyDescriptor(e,a):null;l&&(l.get||l.set)?Object.defineProperty(r,a,l):r[a]=e[a]}return r.default=e,n&&n.set(e,r),r}(n(1594)),o=d(n(6935)),a=d(n(6923)),l=n(5207),i=n(9791),s=d(n(5815));function d(e){return e&&e.__esModule?e:{default:e}}function u(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(u=function(e){return e?n:t})(e)}class c extends r.Component{constructor(e){super(e),this.handleToggle=this.handleToggle.bind(this)}getElementButtonClickHandler(e){return t=>{const{actions:{handleAddElementToArea:n},insertAfterElement:r}=this.props;t.preventDefault(),n(e.class,r).then((()=>{const e=window.jQuery(".cms-preview");e.entwine("ss.preview")._loadUrl(e.find("iframe").attr("src"))})),this.handleToggle()}}handleToggle(){const{toggle:e}=this.props;e()}render(){const{PopoverOptionSetComponent:e,elementTypes:t,container:n,extraClass:o,isOpen:l,placement:i,target:d}=this.props,u=(0,a.default)("element-editor-add-element",o),c=t.map((e=>({content:e.title,key:e.name,className:(0,a.default)(e.icon,"btn--icon-xl","element-editor-add-element__button"),onClick:this.getElementButtonClickHandler(e)})));return r.default.createElement(e,{buttons:c,searchPlaceholder:s.default._t("ElementAddElementPopover.SEARCH_BLOCKS","Search blocks"),extraClass:u,container:n,isOpen:l,placement:i,target:d,toggle:this.handleToggle})}}c.propTypes={container:o.default.oneOfType([o.default.string,o.default.func,o.default.object]),elementTypes:o.default.arrayOf(i.elementTypeType).isRequired,extraClass:o.default.oneOfType([o.default.string,o.default.array,o.default.object]),isOpen:o.default.bool.isRequired,placement:o.default.string,target:o.default.oneOfType([o.default.string,o.default.func,o.default.object]).isRequired,toggle:o.default.func.isRequired,areaId:o.default.number.isRequired,insertAfterElement:o.default.oneOfType([o.default.number,o.default.string])};t.default=(0,l.inject)(["PopoverOptionSet"],(e=>({PopoverOptionSetComponent:e})),(()=>"ElementEditor"))(c)},5297:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.Component=void 0;var r=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=u(t);if(n&&n.has(e))return n.get(e);var r={__proto__:null},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&{}.hasOwnProperty.call(e,a)){var l=o?Object.getOwnPropertyDescriptor(e,a):null;l&&(l.get||l.set)?Object.defineProperty(r,a,l):r[a]=e[a]}return r.default=e,n&&n.set(e,r),r}(n(1594)),o=d(n(6935)),a=n(3556),l=d(n(5815)),i=n(9791),s=n(5207);function d(e){return e&&e.__esModule?e:{default:e}}function u(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(u=function(e){return e?n:t})(e)}class c extends r.Component{constructor(e){super(e),this.toggle=this.toggle.bind(this),this.state={popoverOpen:!1}}toggle(){this.setState((e=>({popoverOpen:!e.popoverOpen})))}render(){const{AddElementPopoverComponent:e,elementTypes:t,areaId:n}=this.props,o={id:`ElementalArea${n}_AddButton`,color:"primary",onClick:this.toggle,className:"font-icon-plus"};return r.default.createElement("div",null,r.default.createElement(a.Button,o,l.default._t("ElementAddNewButton.ADD_BLOCK","Add block")),r.default.createElement(e,{placement:"bottom-start",target:o.id,isOpen:this.state.popoverOpen,elementTypes:t,toggle:this.toggle,areaId:n,insertAfterElement:0}))}}t.Component=c,c.defaultProps={},c.propTypes={elementTypes:o.default.arrayOf(i.elementTypeType).isRequired,areaId:o.default.number.isRequired};t.default=(0,s.inject)(["AddElementPopover"],(e=>({AddElementPopoverComponent:e})),(()=>"ElementEditor.ElementList.AddNewButton"))(c)},1305:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.Component=void 0;var r,o=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=s(t);if(n&&n.has(e))return n.get(e);var r={__proto__:null},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&{}.hasOwnProperty.call(e,a)){var l=o?Object.getOwnPropertyDescriptor(e,a):null;l&&(l.get||l.set)?Object.defineProperty(r,a,l):r[a]=e[a]}return r.default=e,n&&n.set(e,r),r}(n(1594)),a=(r=n(6935))&&r.__esModule?r:{default:r},l=n(5207),i=n(9367);function s(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(s=function(e){return e?n:t})(e)}class d extends o.PureComponent{render(){const{id:e,fileUrl:t,fileTitle:n,content:r,previewExpanded:a,InlineEditFormComponent:l,SummaryComponent:i,activeTab:s,onFormInit:d,handleLoadingError:u,formDirty:c,broken:f,onFormSchemaSubmitResponse:p,ensureFormRendered:m,formHasRendered:g}=this.props,h=!a&&(m||g),b={"element-editor-editform--collapsed":!a,"element-editor-editform--rendered-not-visible":h};return o.default.createElement("div",{className:"element-editor-content"},!a&&o.default.createElement(i,{content:r,fileUrl:t,fileTitle:n,broken:f}),(a||m||g)&&o.default.createElement(l,{extraClass:b,onClick:e=>e.stopPropagation(),elementId:e,activeTab:s,onFormInit:d,handleLoadingError:u,onFormSchemaSubmitResponse:p,notVisible:h}),c&&o.default.createElement("input",{type:"hidden",name:"change-tracker",className:"element-form-dirty-state",value:"1"}))}}t.Component=d,d.propTypes={id:a.default.string,content:a.default.string,fileUrl:a.default.string,fileTitle:a.default.string,previewExpanded:a.default.bool,SummaryComponent:a.default.elementType,InlineEditFormComponent:a.default.elementType,handleLoadingError:a.default.func,broken:a.default.bool,onFormSchemaSubmitResponse:a.default.func,onFormInit:a.default.func,ensureFormRendered:a.default.bool,formHasRendered:a.default.bool,formDirty:a.default.object},d.defaultProps={};t.default=(0,i.compose)((0,l.inject)(["ElementSummary","ElementInlineEditForm"],((e,t)=>({SummaryComponent:e,InlineEditFormComponent:t})),(()=>"ElementEditor.ElementList.Element")))(d)},1950:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=o(t);if(n&&n.has(e))return n.get(e);var r={__proto__:null},a=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in e)if("default"!==l&&{}.hasOwnProperty.call(e,l)){var i=a?Object.getOwnPropertyDescriptor(e,l):null;i&&(i.get||i.set)?Object.defineProperty(r,l,i):r[l]=e[l]}return r.default=e,n&&n.set(e,r),r}(n(1594));function o(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(o=function(e){return e?n:t})(e)}class a extends r.PureComponent{render(){return r.default.createElement("div",{className:"elemental-editor-drag-indicator"},r.default.createElement("div",{className:"elemental-editor-drag-indicator__ball"}))}}t.default=a},584:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.ElementContext=t.Component=void 0;var r=I(n(1594)),o=n(8695),a=D(n(6935)),l=n(455),i=n(9791),s=n(9367),d=n(5207),u=D(n(5815)),c=D(n(6923)),f=n(9040),p=n(5381),m=n(2153),g=n(7785),h=n(4242),b=n(3521),v=I(n(5034)),y=n(1820),_=n(8724),E=n(9306),O=I(n(8918)),T=n(9077);function D(e){return e&&e.__esModule?e:{default:e}}function k(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(k=function(e){return e?n:t})(e)}function I(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=k(t);if(n&&n.has(e))return n.get(e);var r={__proto__:null},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&{}.hasOwnProperty.call(e,a)){var l=o?Object.getOwnPropertyDescriptor(e,a):null;l&&(l.get||l.set)?Object.defineProperty(r,a,l):r[a]=e[a]}return r.default=e,n&&n.set(e,r),r}const C=t.ElementContext=(0,r.createContext)(null),P=e=>{const[t,n]=(0,r.useState)(!1),[a,l]=(0,r.useState)(""),[i,s]=(0,r.useState)(!1),[d,f]=(0,r.useState)(e.element.title),[p,m]=(0,r.useState)(!1),[g,v]=(0,r.useState)(!1),[y,E]=(0,r.useState)(!1),[O,T]=(0,r.useState)(!1),[D,k]=(0,r.useState)(!1),[I,P]=(0,r.useState)(!1),[S,w]=(0,r.useState)(!1),[j,A]=(0,r.useState)(!1),[M]=(0,o.useMutation)(h.publishBlockMutation);(0,r.useEffect)((()=>{void 0!==e.formDirty&&!j&&A(!0)}),[e.formDirty]),(0,r.useEffect)((()=>{e.onChangeHasUnsavedChanges(j)}),[j]),(0,r.useEffect)((()=>{e.saveElement&&j&&!g&&v(!0)}),[e.saveElement,j,e.increment]),(0,r.useEffect)((()=>{e.connectDragPreview&&e.connectDragPreview((0,_.getEmptyImage)(),{captureDraggingState:!0})}),[]),(0,r.useEffect)((()=>{p&&I&&(m(!1),j?(e.submitForm(),T(!0)):E(!0))}),[p,I]),(0,r.useEffect)((()=>{S&&(w(!1),e.dispatchAddFormChanged())}),[S]);const R=()=>u.default.inject(u.default._t("ElementHeader.NOTITLE","Untitled {type} block"),{type:e.type.title}),N=()=>window.ss.apolloClient.queryManager.refetchQueries({include:[{query:b.query,variables:{id:e.areaId}}]}),B=t=>{(t=>{const n=d||R();if(t){const t=u.default.inject(u.default._t("ElementPublishAction.ERROR_NOTIFICATION","Error publishing '{title}'"),{title:n});e.actions.toasts.error(t)}else{const t=u.default.inject(u.default._t("ElementPublishAction.SUCCESS_NOTIFICATION","Published '{title}' successfully"),{title:n});e.actions.toasts.success(t)}})(t),E(!1),T(!1),Promise.all(N()).then((()=>{setTimeout((()=>e.dispatchRemoveFormChanged()),250)}))};(0,r.useEffect)((()=>{I&&g&&(e.submitForm(),v(!1))}),[I,g]),(0,r.useEffect)((()=>{I&&y&&M({variables:{blockId:e.element.id}}).then((()=>B(!1))).catch((()=>B(!0)))}),[I,y]);const x=t=>{const{tabSetName:n,onActivateTab:r}=e;if(a||l(t),t||a)r(n,t||a);else{r(n,"Main")}},q=r=>{const{type:o,link:a}=e;o.broken||("button"!==r.target.type?!o.inlineEditable||i?window.location=a:n(!t):r.stopPropagation())},{element:L,type:F,areaId:$,HeaderComponent:U,ContentComponent:H,link:W,activeTab:V,connectDragSource:Q,connectDropTarget:K,isDragging:G,isOver:Y,onDragEnd:J,formDirty:X}=e;if(!L.id)return null;const z=(0,c.default)("element-editor__element",{"element-editor__element--broken":F.broken,"element-editor__element--expandable":F.inlineEditable&&!F.broken,"element-editor__element--dragging":G,"element-editor__element--dragged-over":Y},(()=>{const{element:t}=e,n="element-editor__element";return t.isPublished?t.isPublished&&!t.isLiveVersion?`${n}--modified`:`${n}--published`:`${n}--draft`})()),Z={formDirty:X,onPublishButtonClick:()=>{m(!0),k(!0)},onSaveButtonClick:()=>{k(!0),v(!0)}},ee=K(r.default.createElement("div",{className:z,onClick:q,onKeyUp:e=>{const{nodeName:t}=e.target;" "!==e.key&&"Enter"!==e.key||["input","textarea"].includes(t.toLowerCase())||q(e)},role:"button",tabIndex:0,title:(e=>e.broken?u.default._t("ElementalElement.ARCHIVE_BROKEN","Archive this block"):u.default.inject(u.default._t("ElementalElement.TITLE","Edit this {type} block"),{type:e.title}))(F),key:L.id},r.default.createElement(C.Provider,{value:Z},r.default.createElement(U,{element:L,type:F,areaId:$,expandable:F.inlineEditable,link:W,previewExpanded:t,handleEditTabsClick:t=>{const{activeTab:r}=e;t===r||i||(n(!0),x(t))},activeTab:V,disableTooltip:G,onDragEnd:J}),r.default.createElement(H,{id:L.id,fileUrl:L.blockSchema.fileURL,fileTitle:L.blockSchema.fileTitle,content:((e,t)=>t.broken?e.title?u.default.inject(u.default._t("ElementalElement.BROKEN_DESCRIPTION_TITLE",'This block had the title "{title}". It is broken and will not display on the front-end. You can archive it to remove it from this elemental area.'),{title:e.title}):u.default._t("ElementalElement.BROKEN_DESCRIPTION","This block is broken and will not display on the front-end. You can archive it to remove it from this elemental area."):e.blockSchema.content)(L,F),previewExpanded:t&&!G,ensureFormRendered:D,formHasRendered:I,activeTab:V,handleLoadingError:()=>{s(!0)},broken:F.broken,onFormSchemaSubmitResponse:(t,r)=>{if(t.id.match(/\/schema\/elemental-area\/([0-9]+)/))return e.type.inlineEditable&&n(!0),w(!0),O&&T(!1),void e.onAfterSubmitResponse(!1);A(!1),f(r),O&&(T(!1),E(!0)),y||O||(t=>{const n=t||R(),r=u.default.inject(u.default._t("ElementSaveAction.SUCCESS_NOTIFICATION","Saved '{title}' successfully"),{title:n});e.actions.toasts.success(r)})(r),N(),e.onAfterSubmitResponse(!0)},onFormInit:()=>(e=>{x(e),P(!0)})(V)}))));return t?ee:Q(ee)};t.Component=P,P.propTypes={element:l.elementType,type:i.elementTypeType.isRequired,areaId:a.default.number.isRequired,link:a.default.string.isRequired,activeTab:a.default.string,tabSetName:a.default.string,onActivateTab:a.default.func,connectDragSource:a.default.func.isRequired,connectDragPreview:a.default.func.isRequired,connectDropTarget:a.default.func.isRequired,isDragging:a.default.bool.isRequired,isOver:a.default.bool.isRequired,onDragOver:a.default.func,onDragEnd:a.default.func,onDragStart:a.default.func,saveElement:a.default.bool.isRequired,onBeforeSubmitForm:a.default.func.isRequired,onAfterSubmitResponse:a.default.func.isRequired,increment:a.default.number.isRequired},P.defaultProps={element:null};const S={drop(e,t,n){const{element:r}=e;return{target:r.id,dropSpot:(0,E.isOverTop)(t,n)?"top":"bottom"}},hover(e,t,n){const{element:r,onDragOver:o}=e;o&&o(r,(0,E.isOverTop)(t,n))}};t.default=(0,s.compose)((0,y.DropTarget)("element",S,((e,t)=>({connectDropTarget:e.dropTarget(),isOver:t.isOver()}))),(0,y.DragSource)("element",E.elementDragSource,((e,t)=>({connectDragSource:e.dragSource(),connectDragPreview:e.dragPreview(),isDragging:t.isDragging()}))),(0,f.connect)((function(e,t){const n=t.element.id,r=(0,m.loadElementFormStateName)(n),o=(0,g.loadElementSchemaValue)("schemaUrl",n),a=e.form&&e.form.formSchemas[o]&&e.form.formSchemas[o].schema&&e.form.formSchemas[o].schema.fields.find((e=>"Tabs"===e.component)),l=a&&a.id,i=`element.${r}__${l}`,s=e.unsavedForms.find((e=>e.name===`element.${r}`));return{tabSetName:l,activeTab:e.tabs&&e.tabs.fields&&e.tabs.fields[i]&&e.tabs.fields[i].activeTab,formDirty:s}}),(function(e,t){const n=(0,m.loadElementFormStateName)(t.element.id);return{onActivateTab(t,r){e(v.activateTab(`element.${n}__${t}`,r))},submitForm(){t.onBeforeSubmitForm(t.element.id),e((0,p.submit)(`element.${n}`))},dispatchAddFormChanged(){e((0,T.addFormChanged)(`element.${n}`))},dispatchRemoveFormChanged(){e((0,T.removeFormChanged)(`element.${n}`))},actions:{toasts:(0,s.bindActionCreators)(O,e)}}})),(0,d.inject)(["ElementHeader","ElementContent"],((e,t)=>({HeaderComponent:e,ContentComponent:t})),(()=>"ElementEditor.ElementList.Element")))(P)},7105:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.Component=void 0;var r=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=f(t);if(n&&n.has(e))return n.get(e);var r={__proto__:null},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&{}.hasOwnProperty.call(e,a)){var l=o?Object.getOwnPropertyDescriptor(e,a):null;l&&(l.get||l.set)?Object.defineProperty(r,a,l):r[a]=e[a]}return r.default=e,n&&n.set(e,r),r}(n(1594)),o=c(n(6935)),a=n(9367),l=n(3556),i=n(5207),s=n(455),d=n(9791),u=c(n(26));function c(e){return e&&e.__esModule?e:{default:e}}function f(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(f=function(e){return e?n:t})(e)}class p extends r.Component{constructor(e){super(e),this.handleEditTabsClick=this.handleEditTabsClick.bind(this)}handleEditTabsClick(e){const{handleEditTabsClick:t}=this.props;t(e.target.name)}renderEditTabs(){const{editTabs:e,activeTab:t,type:n,expandable:o}=this.props;return!n.broken&&o&&e&&e.length?e.map((e=>{let{name:o,title:a}=e;return r.default.createElement(u.default,{key:o,name:o,title:a,type:n,onClick:this.handleEditTabsClick,active:o===t})})):null}renderDivider(){const{children:e,editTabs:t,expandable:n}=this.props;return n&&t&&t.length&&0!==r.default.Children.count(e)?r.default.createElement(l.DropdownItem,{divider:!0,role:"separator"}):null}render(){const{children:e,id:t,ActionMenuComponent:n}=this.props;return r.default.createElement(n,{id:`element-editor-actions-${t}`,className:"element-editor-header__actions-dropdown",dropdownMenuProps:{right:!0},dropdownToggleClassNames:["element-editor-header__actions-toggle","btn","btn-sm","btn--no-text","font-icon-dot-3"]},this.renderEditTabs(),this.renderDivider(),e)}}t.Component=p,p.propTypes={element:s.elementType,type:d.elementTypeType.isRequired,areaId:o.default.number.isRequired,activeTab:o.default.string,editTabs:o.default.arrayOf(o.default.shape({title:o.default.string,name:o.default.string})),handleEditTabsClick:o.default.func.isRequired,expandable:o.default.bool},p.defaultProps={editTabs:[],expandable:!0};t.default=(0,a.compose)((0,i.inject)(["ActionMenu"],(e=>({ActionMenuComponent:e})),(()=>"ElementEditor.ElementList.Element")))(p)},920:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=c(t);if(n&&n.has(e))return n.get(e);var r={__proto__:null},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&{}.hasOwnProperty.call(e,a)){var l=o?Object.getOwnPropertyDescriptor(e,a):null;l&&(l.get||l.set)?Object.defineProperty(r,a,l):r[a]=e[a]}return r.default=e,n&&n.set(e,r),r}(n(1594)),o=u(n(6935)),a=u(n(7651)),l=n(1820),i=n(455),s=n(9791),d=n(1135);function u(e){return e&&e.__esModule?e:{default:e}}function c(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(c=function(e){return e?n:t})(e)}class f extends r.Component{render(){const{isDragging:e,element:t,elementTypes:n,currentOffset:o}=this.props;if(!e||!o)return null;const{x:l,y:i}=o,s=`translate(${l}px, ${i}px)`,u={transform:s,WebkitTransform:s},c=(0,d.getElementTypeConfig)(t,n);return r.default.createElement("div",{className:"element-editor-drag-preview",style:u},r.default.createElement(a.default,{element:t,type:c,simple:!0}))}}f.propTypes={element:i.elementType,elementTypes:o.default.arrayOf(s.elementTypeType),isDragging:o.default.bool,currentOffset:o.default.shape({x:o.default.number.isRequired,y:o.default.number.isRequired})};t.default=(0,l.DragLayer)((e=>({element:e.getItem(),currentOffset:e.getSourceClientOffset(),isDragging:e.isDragging()})))(f)},6721:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.Component=void 0;var r=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=p(t);if(n&&n.has(e))return n.get(e);var r={__proto__:null},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&{}.hasOwnProperty.call(e,a)){var l=o?Object.getOwnPropertyDescriptor(e,a):null;l&&(l.get||l.set)?Object.defineProperty(r,a,l):r[a]=e[a]}return r.default=e,n&&n.set(e,r),r}(n(1594)),o=f(n(6935)),a=n(5207),l=n(9367),i=n(9791),s=n(1820),d=f(n(3695)),u=f(n(920)),c=f(n(5799));function f(e){return e&&e.__esModule?e:{default:e}}function p(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(p=function(e){return e?n:t})(e)}class m extends r.PureComponent{constructor(e){super(e),this.state={dragTargetElementId:null,dragSpot:null},this.handleDragOver=this.handleDragOver.bind(this),this.handleDragEnd=this.handleDragEnd.bind(this)}handleDragOver(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;const n=!!e&&e.id;this.setState({dragTargetElementId:n,dragSpot:!1===t?"bottom":"top"})}handleDragEnd(e,t){const{actions:{handleSortBlock:n},areaId:r}=this.props;n(e,t,r).then((()=>{const e=window.jQuery(".cms-preview");e.entwine("ss.preview")._loadUrl(e.find("iframe").attr("src"))})),this.setState({dragTargetElementId:null,dragSpot:null})}render(){const{ToolbarComponent:e,ListComponent:t,areaId:n,elementTypes:o,isDraggingOver:a,connectDropTarget:l,allowedElements:i,sharedObject:s}=this.props,{dragTargetElementId:d,dragSpot:c}=this.state,f=i.map((e=>o.find((t=>t.class===e))));return l(r.default.createElement("div",{className:"element-editor"},r.default.createElement(e,{elementTypes:f,areaId:n,onDragOver:this.handleDragOver}),r.default.createElement(t,{allowedElementTypes:f,elementTypes:o,areaId:n,onDragOver:this.handleDragOver,onDragStart:this.handleDragStart,onDragEnd:this.handleDragEnd,dragSpot:c,isDraggingOver:a,dragTargetElementId:d,sharedObject:s}),r.default.createElement(u.default,{elementTypes:o})))}}t.Component=m,m.propTypes={elementTypes:o.default.arrayOf(i.elementTypeType).isRequired,allowedElements:o.default.arrayOf(o.default.string).isRequired,areaId:o.default.number.isRequired,actions:o.default.shape({handleSortBlock:o.default.func})};t.default=(0,l.compose)(c.default,(0,s.DropTarget)("element",{},((e,t)=>({connectDropTarget:e.dropTarget(),isDraggingOver:t.isOver()}))),(0,a.inject)(["ElementToolbar","ElementList"],((e,t)=>({ToolbarComponent:e,ListComponent:t})),(()=>"ElementEditor")),d.default)(m)},2512:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.Component=void 0;var r=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=g(t);if(n&&n.has(e))return n.get(e);var r={__proto__:null},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&{}.hasOwnProperty.call(e,a)){var l=o?Object.getOwnPropertyDescriptor(e,a):null;l&&(l.get||l.set)?Object.defineProperty(r,a,l):r[a]=e[a]}return r.default=e,n&&n.set(e,r),r}(n(1594)),o=m(n(6935)),a=n(455),l=n(9791),i=n(9367),s=n(5207),d=m(n(6923)),u=m(n(5815)),c=n(1820),f=n(9306),p=n(1135);function m(e){return e&&e.__esModule?e:{default:e}}function g(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(g=function(e){return e?n:t})(e)}class h extends r.Component{constructor(e){super(e),this.resetState=this.resetState.bind(this),this.handleBeforeSubmitForm=this.handleBeforeSubmitForm.bind(this),this.handleAfterSubmitResponse=this.handleAfterSubmitResponse.bind(this),this.state={saveAllElements:!1,increment:0,hasUnsavedChangesBlockIDs:{},validBlockIDs:{}},this.props.sharedObject.setState=this.setState.bind(this)}componentDidUpdate(e,t){if(this.props.blocks===e.blocks){if(this.state.saveAllElements){const e=this.props.blocks.map((e=>parseInt(e.id,10))).filter((e=>this.state.hasUnsavedChangesBlockIDs[e]));if(e.every((e=>null!==this.state.validBlockIDs[e]))){const n=e.every((e=>this.state.validBlockIDs[e])),r={success:n,reason:n?"":"invalid"};this.props.sharedObject.entwineResolve(r),this.resetState(t,n),this.setState({saveAllElements:!1})}}}else this.resetState(t,!1)}resetState(e,t){const n={},r={};(this.props.blocks||[]).forEach((o=>{const a=parseInt(o.id,10);t?n[a]=!1:e.hasUnsavedChangesBlockIDs.hasOwnProperty(a)?n[a]=e.hasUnsavedChangesBlockIDs[a]:n[a]=!1,r[a]=null})),this.setState({hasUnsavedChangesBlockIDs:n,validBlockIDs:r})}handleChangeHasUnsavedChanges(e,t){this.setState((n=>({hasUnsavedChangesBlockIDs:{...n.hasUnsavedChangesBlockIDs,[e]:t}})))}handleBeforeSubmitForm(e){this.setState((t=>({validBlockIDs:{...t.validBlockIDs,[e]:null}})))}handleAfterSubmitResponse(e,t){this.setState((n=>({hasUnsavedChangesBlockIDs:{...n.hasUnsavedChangesBlockIDs,[e]:!t},validBlockIDs:{...n.validBlockIDs,[e]:t}})))}getDragIndicatorIndex(){const{dragTargetElementId:e,draggedItem:t,blocks:n,dragSpot:r}=this.props;return(0,f.getDragIndicatorIndex)(n.map((e=>e.id)),e,t&&t.id,r)}renderBlocks(){const{ElementComponent:e,HoverBarComponent:t,DragIndicatorComponent:n,blocks:o,allowedElementTypes:a,elementTypes:l,areaId:i,onDragEnd:s,onDragOver:d,onDragStart:c,isDraggingOver:f}=this.props;if(!o)return null;if(o&&!o.length)return r.default.createElement("div",null,u.default._t("ElementList.ADD_BLOCKS","Add blocks to place your content"));let m=o.map((n=>{const o=this.state.saveAllElements&&this.state.hasUnsavedChangesBlockIDs[n.id]&&null===this.state.validBlockIDs[n.id];return r.default.createElement("div",{key:n.id},r.default.createElement(e,{element:n,areaId:i,type:(0,p.getElementTypeConfig)(n,l),link:n.blockSchema.actions.edit,onDragOver:d,onDragEnd:s,onDragStart:c,saveElement:o,onChangeHasUnsavedChanges:e=>this.handleChangeHasUnsavedChanges(n.id,e),onBeforeSubmitForm:()=>this.handleBeforeSubmitForm(n.id),onAfterSubmitResponse:e=>this.handleAfterSubmitResponse(n.id,e),increment:this.state.increment}),f||r.default.createElement(t,{key:`create-after-${n.id}`,areaId:i,elementId:n.id,elementTypes:a}))}));f||(m=[r.default.createElement(t,{key:0,areaId:i,elementId:0,elementTypes:a})].concat(m));const g=this.getDragIndicatorIndex();return f&&null!==g&&m.splice(g,0,r.default.createElement(n,{key:"DropIndicator"})),m}renderLoading(){const{loading:e,LoadingComponent:t}=this.props;return e?r.default.createElement(t,null):null}render(){const{blocks:e}=this.props,t=(0,d.default)("elemental-editor-list",{"elemental-editor-list--empty":!e||!e.length});return this.props.connectDropTarget(r.default.createElement("div",{className:t},this.renderLoading(),this.renderBlocks()))}}t.Component=h,h.propTypes={blocks:o.default.arrayOf(a.elementType),elementTypes:o.default.arrayOf(l.elementTypeType).isRequired,allowedElementTypes:o.default.arrayOf(l.elementTypeType).isRequired,loading:o.default.bool,areaId:o.default.number.isRequired,dragTargetElementId:o.default.oneOfType([o.default.string,o.default.bool]),onDragOver:o.default.func,onDragStart:o.default.func,onDragEnd:o.default.func,sharedObject:o.default.object.isRequired},h.defaultProps={blocks:[],loading:!1,sharedObject:{entwineResolve:()=>{},setState:null}};const b={drop(e,t){const{blocks:n}=e,r=t.getDropResult();if(!r)return{};const o=(0,f.getDragIndicatorIndex)(n.map((e=>e.id)),r.target,t.getItem(),r.dropSpot),a=n[o-1]?n[o-1].id:"0";return{...r,dropAfterID:a}}};t.default=(0,i.compose)((0,c.DropTarget)("element",b,((e,t)=>({connectDropTarget:e.dropTarget(),draggedItem:t.getItem()}))),(0,s.inject)(["Element","Loading","HoverBar","DragPositionIndicator"],((e,t,n,r)=>({ElementComponent:e,LoadingComponent:t,HoverBarComponent:n,DragIndicatorComponent:r})),(()=>"ElementEditor.ElementList")))(h)},7651:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.Component=void 0;var r=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=h(t);if(n&&n.has(e))return n.get(e);var r={__proto__:null},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&{}.hasOwnProperty.call(e,a)){var l=o?Object.getOwnPropertyDescriptor(e,a):null;l&&(l.get||l.set)?Object.defineProperty(r,a,l):r[a]=e[a]}return r.default=e,n&&n.set(e,r),r}(n(1594)),o=g(n(6935)),a=n(3556),l=n(455),i=n(9791),s=n(9367),d=n(5207),u=g(n(5815)),c=g(n(6923)),f=n(1820),p=n(9306),m=n(8724);function g(e){return e&&e.__esModule?e:{default:e}}function h(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(h=function(e){return e?n:t})(e)}class b extends r.Component{constructor(e){super(e),this.toggle=this.toggle.bind(this),this.state={tooltipOpen:!1}}componentDidMount(){const{connectDragPreview:e}=this.props;e&&e((0,m.getEmptyImage)(),{captureDraggingState:!0})}componentDidUpdate(){const{tooltipOpen:e}=this.state,{disableTooltip:t}=this.props;e&&t&&this.setState({tooltipOpen:!1})}getBlockTitle(e,t){return t.broken?u.default.inject(u.default._t("ElementHeader.BROKEN","This element is of obsolete type {type}."),{type:t.obsoleteClassName}):e.title?e.title:u.default.inject(u.default._t("ElementHeader.NOTITLE","Untitled {type} block"),{type:t.title})}toggle(){this.setState((e=>({tooltipOpen:!e.tooltipOpen})))}renderVersionedStateMessage(){const{element:{isLiveVersion:e,isPublished:t}}=this.props;if(t&&e)return null;let n="";const o=["element-editor-header__version-state"];return t?e||(n=u.default._t("ElementHeader.STATE_MODIFIED","Item has unpublished changes"),o.push("element-editor-header__version-state--modified")):(n=u.default._t("ElementHeader.STATE_DRAFT","Item has not been published yet"),o.push("element-editor-header__version-state--draft")),r.default.createElement("span",{className:(0,c.default)(o),title:n})}renderStatusBadge(){const{element:{isLiveVersion:e,isPublished:t}}=this.props;if(t&&e)return null;let n="",o="";const a=["badge"];return t?e||(n=u.default._t("ElementHeader.BADGE_MODIFIED","Modified"),o=u.default._t("ElementHeader.STATE_MODIFIED","Item has unpublished changes"),a.push("status-modified")):(n=u.default._t("ElementHeader.BADGE_DRAFT","Draft"),o=u.default._t("ElementHeader.STATE_DRAFT","Item has not been published yet"),a.push("status-addedtodraft")),r.default.createElement("span",{className:(0,c.default)(a),title:o},n)}render(){const{connectDragSource:e,element:t,type:n,areaId:o,previewExpanded:l,simple:i,disableTooltip:s,activeTab:d,expandable:f,ElementActionsComponent:p,handleEditTabsClick:m}=this.props,g=this.getBlockTitle(t,n),h=(0,c.default)({"element-editor-header__title":!0,"element-editor-header__title--none":!t.title}),b=u.default._t("ElementHeader.EXPAND","Show editable fields"),v=(0,c.default)("element-editor-header",{"element-editor-header--simple":i}),y=(0,c.default)("element-editor-header__icon-container",{"element-editor-header__icon-container--broken":n.broken}),_=(0,c.default)("element-editor-header__expand",{"font-icon-right-open-big":!f,"font-icon-up-open-big":f&&l,"font-icon-down-open-big":f&&!l}),E=`element-icon-${t.id}`,O=r.default.createElement("div",{className:v},r.default.createElement("div",{className:"element-editor-header__drag-handle"},r.default.createElement("i",{className:"font-icon-drag-handle"})),r.default.createElement("div",{className:"element-editor-header__info"},r.default.createElement("div",{className:y},r.default.createElement("i",{className:n.icon,id:E}),this.renderVersionedStateMessage(),!n.broken&&!i&&r.default.createElement(a.Tooltip,{placement:"top",isOpen:this.state.tooltipOpen&&!s,target:E,toggle:this.toggle},n.title)),r.default.createElement("h3",{className:h},g),this.renderStatusBadge()),!i&&r.default.createElement("div",{className:"element-editor-header__actions"},r.default.createElement("div",{role:"none",onClick:e=>e.stopPropagation()},r.default.createElement(p,{element:t,type:n,areaId:o,activeTab:d,editTabs:n.editTabs,handleEditTabsClick:m,expandable:f})),!n.broken&&r.default.createElement("i",{className:_,title:b})));return l?e(O):O}}t.Component=b,b.propTypes={element:l.elementType.isRequired,type:i.elementTypeType.isRequired,areaId:o.default.number,activeTab:o.default.string,simple:o.default.bool,ElementActionsComponent:o.default.elementType,previewExpanded:o.default.bool,disableTooltip:o.default.bool,connectDragSource:o.default.func.isRequired,connectDragPreview:o.default.func.isRequired,onDragEnd:o.default.func},b.defaultProps={expandable:!0};t.default=(0,s.compose)((0,f.DragSource)("element",p.elementDragSource,(e=>({connectDragSource:e.dragSource(),connectDragPreview:e.dragPreview()}))),(0,d.inject)(["ElementActions"],(e=>({ElementActionsComponent:e})),(()=>"ElementEditor.ElementList.Element")))(b)},8953:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.Component=void 0;var r=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=d(t);if(n&&n.has(e))return n.get(e);var r={__proto__:null},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&{}.hasOwnProperty.call(e,a)){var l=o?Object.getOwnPropertyDescriptor(e,a):null;l&&(l.get||l.set)?Object.defineProperty(r,a,l):r[a]=e[a]}return r.default=e,n&&n.set(e,r),r}(n(1594)),o=s(n(6935)),a=n(5207),l=n(9791),i=s(n(5815));function s(e){return e&&e.__esModule?e:{default:e}}function d(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(d=function(e){return e?n:t})(e)}const u=(0,s(n(7577)).default)("element-editor__hover-bar");function c(e){let{AddElementPopoverComponent:t,elementTypes:n,elementId:o,areaId:a,popoverOpen:l,onToggle:s}=e;const d=`${u("-line")} font-icon-plus-circled`,c=i.default._t("ElementAddNewButton.ADD_BLOCK","Add block"),f={className:u("-area",{"-area--focus":l}),onClick:s,"aria-label":c,title:c,id:`AddBlockHoverBarArea_${a}_${o}`};return r.default.createElement("div",{className:u(""),id:`AddBlockHoverBar_${a}_${o}`},r.default.createElement("button",f,r.default.createElement("span",{className:u("-area-inner")},r.default.createElement("span",{className:d}))),r.default.createElement(t,{placement:"bottom",target:`AddBlockHoverBarArea_${a}_${o}`,isOpen:l,elementTypes:n,toggle:s,container:`#AddBlockHoverBar_${a}_${o}`,areaId:a,insertAfterElement:o}))}class f extends r.Component{constructor(e){super(e),this.toggle=this.toggle.bind(this),this.state={popoverOpen:!1}}toggle(){this.setState((e=>({popoverOpen:!e.popoverOpen})))}render(){const e={...this.state,...this.props,onToggle:this.toggle};return r.default.createElement(c,e)}}t.Component=f,f.propTypes={elementTypes:o.default.arrayOf(l.elementTypeType).isRequired,elementId:o.default.oneOfType([o.default.string,o.default.number]).isRequired,areaId:o.default.oneOfType([o.default.number,o.default.string]).isRequired};t.default=(0,a.inject)(["AddElementPopover"],(e=>({AddElementPopoverComponent:e})),(()=>"ElementEditor.ElementList.HoverBar"))(f)},7333:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=f(t);if(n&&n.has(e))return n.get(e);var r={__proto__:null},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&{}.hasOwnProperty.call(e,a)){var l=o?Object.getOwnPropertyDescriptor(e,a):null;l&&(l.get||l.set)?Object.defineProperty(r,a,l):r[a]=e[a]}return r.default=e,n&&n.set(e,r),r}(n(1594)),o=c(n(6935)),a=c(n(6923)),l=c(n(55)),i=n(7785),s=c(n(5815)),d=n(2153),u=n(9040);function c(e){return e&&e.__esModule?e:{default:e}}function f(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(f=function(e){return e?n:t})(e)}function p(){return p=Object.assign?Object.assign.bind():function(e){for(var t=1;t{t.match(/PageElements_[0-9]+_Title/)&&(r=e[t])})),n().then((e=>this.props.onFormSchemaSubmitResponse(e,r)))}render(){const{elementId:e,extraClass:t,onClick:n,onFormInit:o,formHasState:s,notVisible:d}=this.props,{loadingError:u}=this.state,c=(0,a.default)("element-editor-editform",t),f={formTag:"form",schemaUrl:(0,i.loadElementSchemaValue)("schemaUrl",e),identifier:"element",refetchSchemaOnMount:!s,onLoadingError:this.handleLoadingError,onSubmit:this.handleSubmit};u&&(f.loading=!1),"function"==typeof o&&(f.onReduxFormInit=o);const m={};return d&&(m["aria-hidden"]="true"),r.default.createElement("div",p({className:c,onClick:n,role:"presentation"},m),r.default.createElement(l.default,f))}}m.propTypes={extraClass:o.default.oneOfType([o.default.string,o.default.object]),onClick:o.default.func,elementId:o.default.string,handleLoadingError:o.default.func,onFormSchemaSubmitResponse:o.default.func,notVisible:o.default.bool};t.default=(0,u.connect)((function(e,t){const n=(0,d.loadElementFormStateName)(t.elementId);return{formHasState:e.form.formState&&e.form.formState.element&&!!e.form.formState.element[n]}}))(m)},7660:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=s(t);if(n&&n.has(e))return n.get(e);var r={__proto__:null},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&{}.hasOwnProperty.call(e,a)){var l=o?Object.getOwnPropertyDescriptor(e,a):null;l&&(l.get||l.set)?Object.defineProperty(r,a,l):r[a]=e[a]}return r.default=e,n&&n.set(e,r),r}(n(1594)),o=i(n(6935)),a=i(n(6923)),l=i(n(5815));function i(e){return e&&e.__esModule?e:{default:e}}function s(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(s=function(e){return e?n:t})(e)}class d extends r.PureComponent{render(){const{fileUrl:e,fileTitle:t,content:n,broken:o}=this.props,i=l.default._t("ElementSummary.NO_PREVIEW","No preview available"),s=(0,a.default)("element-editor-summary__content",{"element-editor-summary__content--broken":o});return r.default.createElement("div",{className:"element-editor-summary"},e&&r.default.createElement("img",{className:"element-editor-summary__thumbnail-image",src:e,alt:t}),(n||!e)&&r.default.createElement("p",{className:s},n||i))}}d.defaultProps={},d.propTypes={content:o.default.string,fileUrl:o.default.string,fileTitle:o.default.string,broken:o.default.bool};t.default=d},5563:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r,o=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=d(t);if(n&&n.has(e))return n.get(e);var r={__proto__:null},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&{}.hasOwnProperty.call(e,a)){var l=o?Object.getOwnPropertyDescriptor(e,a):null;l&&(l.get||l.set)?Object.defineProperty(r,a,l):r[a]=e[a]}return r.default=e,n&&n.set(e,r),r}(n(1594)),a=(r=n(6935))&&r.__esModule?r:{default:r},l=n(5207),i=n(9791),s=n(1820);function d(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(d=function(e){return e?n:t})(e)}class u extends o.PureComponent{render(){const{AddNewButtonComponent:e,elementTypes:t,areaId:n,connectDropTarget:r}=this.props;return r(o.default.createElement("div",{className:"element-editor__toolbar"},o.default.createElement(e,{elementTypes:t,areaId:n})))}}u.defaultProps={},u.propTypes={elementTypes:a.default.arrayOf(i.elementTypeType).isRequired,areaId:a.default.number.isRequired,AddNewButtonComponent:a.default.elementType.isRequired,connectDropTarget:a.default.func.isRequired,onDragOver:a.default.func,onDragDrop:a.default.func};const c={hover(e){const{onDragOver:t}=e;t&&t()}};t.default=(0,s.DropTarget)("element",c,(e=>({connectDropTarget:e.dropTarget()})))((0,l.inject)(["ElementAddNewButton"],(e=>({AddNewButtonComponent:e})),(()=>"ElementEditor.ElementToolbar"))(u))},2977:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=l(n(1594)),o=l(n(5815)),a=l(n(6923));function l(e){return e&&e.__esModule?e:{default:e}}t.default=e=>class extends e{getClassName(){const e=[super.getClassName()];return this.props.data.ElementID&&e.unshift("elemental-area__element--historic-inner"),(0,a.default)(e)}render(){const e=this.getLegend(),t=this.props.data.tag||"div",n=this.getClassName(),{data:a}=this.props;return a.ElementID?r.default.createElement(t,{className:n},e,r.default.createElement("div",{className:"elemental-preview elemental-preview--historic"},a.ElementEditLink&&r.default.createElement("a",{className:"elemental-preview__link",href:a.ElementEditLink},r.default.createElement("span",{className:"elemental-preview__link-text"},o.default._t("HistoricElementView.VIEW_BLOCK_HISTORY","Block history")),r.default.createElement("i",{className:"font-icon-angle-right btn--icon-lg elemental-preview__link-caret"})),r.default.createElement("div",{className:"elemental-preview__icon"},r.default.createElement("i",{className:a.ElementIcon})),r.default.createElement("div",{className:"elemental-preview__detail"},r.default.createElement("h3",null,a.ElementTitle," ",r.default.createElement("small",null,a.ElementType)))),this.props.children):super.render()}}},6573:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=l(n(1594)),o=n(3556),a=l(n(2623));function l(e){return e&&e.__esModule?e:{default:e}}t.default=(0,a.default)((e=>{const{children:t}=e,n=r.default.Children.toArray(r.default.Children.map(t,((t,n)=>{const o={};return 0===n?(o.id=e.id,o.title=null):1===n&&(o.noHolder=!0),r.default.cloneElement(t,o)})));return e.readOnly?r.default.createElement("div",{className:"text-checkbox-group-field--read-only"},n):1===n.length?n[0]:r.default.createElement(o.InputGroup,{className:"text-checkbox-group-field"},n[0],r.default.createElement(o.InputGroupAddon,{addonType:"append"},r.default.createElement(o.InputGroupText,null,n[1])))}))},51:function(e,t,n){var r=d(n(1669)),o=d(n(1594)),a=n(5145),l=n(5207),i=n(1135),s=n(5381);function d(e){return e&&e.__esModule?e:{default:e}}const u=()=>{window.ss.apolloClient.resetStore(),setTimeout((()=>{const{store:e}=window.ss;e&&e.dispatch((0,s.destroy)(...Object.keys(e.getState().form.formState.element||{}).map((e=>`element.${e}`))))}),0)};r.default.entwine("ss",(e=>{e(".js-injector-boot .element-editor__container").entwine({ReactRoot:null,AreaIDsSharedObject:{},Increment:0,onmatch(){const e=(0,l.loadComponent)("ElementEditor",{}),t=this.data("schema"),n=(0,i.getConfig)().elementTypes,r=t["elemental-area-id"],s=this.getAreaIDsSharedObject();s.hasOwnProperty(r)||(s[r]={entwineResolve:null,setState:null});const d={areaId:r,allowedElements:t["allowed-elements"],elementTypes:n,sharedObject:s[r]};let u=this.getReactRoot();u||(u=(0,a.createRoot)(this[0]),this.setReactRoot(u)),u.render(o.default.createElement(e,d))},onunmatch(){e(".cms-edit-form").data("hasValidationErrors")||u(),this.unmountComponent()},unmountComponent(){const e=this.getReactRoot();e&&(e.unmount(),this.setReactRoot(null))},"from .cms-edit-form":{onbeforesubmitform(e,t){if(!t)return;let n;const r=new Promise((e=>{n=e}));t.promises.push(r),t.onAjaxSuccessCallbacks.push(this.unmountComponent.bind(this));const o=this.data("schema")["elemental-area-id"],a=this.getAreaIDsSharedObject()[o],l=this.getIncrement()+1;this.setIncrement(l),a.entwineResolve=n,a.setState({saveAllElements:!0,increment:l})},onaftersubmitform(t,n){const r=JSON.parse(n.xhr.responseText).ValidationResult;JSON.parse(r.replace(/<\/?script[^>]*?>/g,"")).isValid?(e(".cms-edit-form").data("hasValidationErrors",!1),u()):e(".cms-edit-form").data("hasValidationErrors",!0)}}}),e(".js-injector-boot .element-editor__container .element-form-dirty-state").entwine({onmatch(){e(".cms-edit-form").trigger("change")},onunmatch(){e(".cms-edit-form").trigger("change")}}),e(".cms-edit-form").entwine({getChangeTrackerOptions(){const t=void 0===this.entwineData("ChangeTrackerOptions");let n=this._super();return t&&(n=e.extend({},n),n.ignoreFieldSelector+=", .elementalarea :input:not(.element-form-dirty-state)",this.setChangeTrackerOptions(n)),n}})}))},9306:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.isOverTop=t.getDragIndicatorIndex=t.elementDragSource=void 0;var r=n(4518);t.isOverTop=(e,t)=>{const n=e.getClientOffset(),o=(0,r.findDOMNode)(t).getBoundingClientRect();return n.y{if(null===t||!n)return null;let o=t?e.findIndex((e=>e===t)):0;const a=e.findIndex((e=>e===n));return"bottom"===r&&(o+=1),a===o||a+1===o?null:o};t.elementDragSource={beginDrag(e){return e.element},endDrag(e,t){const{onDragEnd:n}=e,r=t.getDropResult();if(!n||!r||!r.dropAfterID)return;const o=t.getItem().id,{dropAfterID:a}=r;o!==a&&n(o,a)}}},7577:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r,o=(r=n(6923))&&r.__esModule?r:{default:r};t.default=e=>function(){const t=t=>`${e}${t}`;for(var n=arguments.length,r=new Array(n),a=0;a!(!e&&""!==e)&&("object"==typeof e?Array.isArray(e)?e.map(t):Object.entries(e).reduce(((e,n)=>{let[r,o]=n;return Object.assign({},e,{[t(r)]:o})}),{}):t(e))));return(0,o.default)(...l)}},6283:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.mutation=t.default=t.config=void 0;var r,o=n(708),a=(r=n(7284))&&r.__esModule?r:{default:r},l=n(3521);const i=t.mutation=a.default` -mutation AddElementToArea($className: String!, $elementalAreaID: ID!, $afterElementID: ID) { - addElementToArea( - className: $className, - elementalAreaID: $elementalAreaID, - afterElementID: $afterElementID - ) { - id - } -} -`,s=t.config={props:e=>{let{mutate:t,ownProps:{actions:n,areaId:r}}=e;return{actions:{...n,handleAddElementToArea:(e,n)=>t({variables:{className:e,elementalAreaID:r,afterElementID:n}})}}},options:e=>{let{areaId:t}=e;return{refetchQueries:[{query:l.query,variables:l.config.options({areaId:t}).variables}]}}};t.default=(0,o.graphql)(i,s)},1429:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.mutation=t.default=t.config=void 0;var r,o=n(708),a=(r=n(7284))&&r.__esModule?r:{default:r},l=n(3521);const i=t.mutation=a.default` -mutation ArchiveBlock($blockId: ID!) { - deleteBlocks(ids: [$blockId]) -} -`,s=t.config={props:e=>{let{mutate:t,ownProps:{actions:n}}=e;return{actions:{...n,handleArchiveBlock:e=>t({variables:{blockId:e}})}}},options:e=>{let{areaId:t}=e;return{refetchQueries:[{query:l.query,variables:l.config.options({areaId:t}).variables}]}}};t.default=(0,o.graphql)(i,s)},9324:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.mutation=t.default=t.config=void 0;var r,o=n(708),a=(r=n(7284))&&r.__esModule?r:{default:r},l=n(3521);const i=t.mutation=a.default` -mutation DuplicateBlock($blockId: ID!) { - duplicateBlock(id: $blockId) { - id - } -} -`,s=t.config={props:e=>{let{mutate:t,ownProps:{actions:n}}=e;return{actions:{...n,handleDuplicateBlock:e=>t({variables:{blockId:e}})}}},options:e=>{let{areaId:t}=e;return{refetchQueries:[{query:l.query,variables:l.config.options({areaId:t}).variables}]}}};t.default=(0,o.graphql)(i,s)},1135:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.getElementTypeConfig=t.getConfig=void 0;var r,o=(r=n(6177))&&r.__esModule?r:{default:r};const a=()=>o.default.getSection("DNADesign\\Elemental\\Controllers\\ElementalAreaController");t.getConfig=a;t.getElementTypeConfig=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;const n=e.blockSchema.typeName;let r=(Array.isArray(t)?t:a().elementTypes).find((e=>e.class===n||e.name===n));return e.obsoleteClassName&&(r=Object.assign({obsoleteClassName:e.obsoleteClassName},r),Object.preventExtensions(r)),r}},2153:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.loadElementFormStateName=void 0;var r,o=(r=n(6177))&&r.__esModule?r:{default:r};t.loadElementFormStateName=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;const t=o.default.getSection("DNADesign\\Elemental\\Controllers\\ElementalAreaController").form.elementForm.formNameTemplate;return e?t.replace("{id}",e):t}},7785:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.loadElementSchemaValue=void 0;var r,o=(r=n(6177))&&r.__esModule?r:{default:r};t.loadElementSchemaValue=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;const n=o.default.getSection("DNADesign\\Elemental\\Controllers\\ElementalAreaController").form.elementForm[e]||"";return t?`${n}/${t}`:n}},4242:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.publishBlockMutation=void 0;var r,o=(r=n(7284))&&r.__esModule?r:{default:r};t.publishBlockMutation=o.default` -mutation PublishBlock($blockId:ID!) { - publishBlock(id: $blockId) { - id - } -} -`},3521:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.query=t.default=t.config=void 0;var r,o=n(708),a=(r=n(7284))&&r.__esModule?r:{default:r};const l=t.query=a.default` -query ReadBlocksForArea($id:ID!) { - readOneElementalArea(filter: { id: { eq: $id } }, versioning: { - mode: DRAFT - }){ - elements { - id +/******/ (function() { // webpackBootstrap +/******/ "use strict"; +/******/ var __webpack_modules__ = ({ + +/***/ "./client/src/boot/index.js": +/*!**********************************!*\ + !*** ./client/src/boot/index.js ***! + \**********************************/ +/***/ (function(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { + + + +var _registerComponents = _interopRequireDefault(__webpack_require__(/*! boot/registerComponents */ "./client/src/boot/registerComponents.js")); +var _registerTransforms = _interopRequireDefault(__webpack_require__(/*! boot/registerTransforms */ "./client/src/boot/registerTransforms.js")); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +window.document.addEventListener('DOMContentLoaded', () => { + (0, _registerComponents.default)(); + (0, _registerTransforms.default)(); +}); + +/***/ }), + +/***/ "./client/src/boot/registerComponents.js": +/*!***********************************************!*\ + !*** ./client/src/boot/registerComponents.js ***! + \***********************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = void 0; +var _Injector = _interopRequireDefault(__webpack_require__(/*! lib/Injector */ "lib/Injector")); +var _Element = _interopRequireDefault(__webpack_require__(/*! components/ElementEditor/Element */ "./client/src/components/ElementEditor/Element.js")); +var _ElementActions = _interopRequireDefault(__webpack_require__(/*! components/ElementEditor/ElementActions */ "./client/src/components/ElementEditor/ElementActions.js")); +var _ElementEditor = _interopRequireDefault(__webpack_require__(/*! components/ElementEditor/ElementEditor */ "./client/src/components/ElementEditor/ElementEditor.js")); +var _ElementList = _interopRequireDefault(__webpack_require__(/*! components/ElementEditor/ElementList */ "./client/src/components/ElementEditor/ElementList.js")); +var _Toolbar = _interopRequireDefault(__webpack_require__(/*! components/ElementEditor/Toolbar */ "./client/src/components/ElementEditor/Toolbar.js")); +var _AddNewButton = _interopRequireDefault(__webpack_require__(/*! components/ElementEditor/AddNewButton */ "./client/src/components/ElementEditor/AddNewButton.js")); +var _Header = _interopRequireDefault(__webpack_require__(/*! components/ElementEditor/Header */ "./client/src/components/ElementEditor/Header.js")); +var _Content = _interopRequireDefault(__webpack_require__(/*! components/ElementEditor/Content */ "./client/src/components/ElementEditor/Content.js")); +var _Summary = _interopRequireDefault(__webpack_require__(/*! components/ElementEditor/Summary */ "./client/src/components/ElementEditor/Summary.js")); +var _InlineEditForm = _interopRequireDefault(__webpack_require__(/*! components/ElementEditor/InlineEditForm */ "./client/src/components/ElementEditor/InlineEditForm.js")); +var _AddElementPopover = _interopRequireDefault(__webpack_require__(/*! components/ElementEditor/AddElementPopover */ "./client/src/components/ElementEditor/AddElementPopover.js")); +var _HoverBar = _interopRequireDefault(__webpack_require__(/*! components/ElementEditor/HoverBar */ "./client/src/components/ElementEditor/HoverBar.js")); +var _DragPositionIndicator = _interopRequireDefault(__webpack_require__(/*! components/ElementEditor/DragPositionIndicator */ "./client/src/components/ElementEditor/DragPositionIndicator.js")); +var _TextCheckboxGroupField = _interopRequireDefault(__webpack_require__(/*! components/TextCheckboxGroupField/TextCheckboxGroupField */ "./client/src/components/TextCheckboxGroupField/TextCheckboxGroupField.js")); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +var _default = () => { + _Injector.default.component.registerMany({ + ElementEditor: _ElementEditor.default, + ElementToolbar: _Toolbar.default, + ElementAddNewButton: _AddNewButton.default, + ElementList: _ElementList.default, + Element: _Element.default, + ElementActions: _ElementActions.default, + ElementHeader: _Header.default, + ElementContent: _Content.default, + ElementSummary: _Summary.default, + ElementInlineEditForm: _InlineEditForm.default, + AddElementPopover: _AddElementPopover.default, + HoverBar: _HoverBar.default, + DragPositionIndicator: _DragPositionIndicator.default, + TextCheckboxGroupField: _TextCheckboxGroupField.default + }); +}; +exports["default"] = _default; + +/***/ }), + +/***/ "./client/src/boot/registerTransforms.js": +/*!***********************************************!*\ + !*** ./client/src/boot/registerTransforms.js ***! + \***********************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = void 0; +var _Injector = _interopRequireDefault(__webpack_require__(/*! lib/Injector */ "lib/Injector")); +var _HistoricElementView = _interopRequireDefault(__webpack_require__(/*! components/HistoricElementView/HistoricElementView */ "./client/src/components/HistoricElementView/HistoricElementView.js")); +var _revertToBlockVersionRequest = _interopRequireDefault(__webpack_require__(/*! state/history/revertToBlockVersionRequest */ "./client/src/state/history/revertToBlockVersionRequest.js")); +var _ArchiveAction = _interopRequireDefault(__webpack_require__(/*! components/ElementActions/ArchiveAction */ "./client/src/components/ElementActions/ArchiveAction.js")); +var _DuplicateAction = _interopRequireDefault(__webpack_require__(/*! components/ElementActions/DuplicateAction */ "./client/src/components/ElementActions/DuplicateAction.js")); +var _SaveAction = _interopRequireDefault(__webpack_require__(/*! components/ElementActions/SaveAction */ "./client/src/components/ElementActions/SaveAction.js")); +var _PublishAction = _interopRequireDefault(__webpack_require__(/*! components/ElementActions/PublishAction */ "./client/src/components/ElementActions/PublishAction.js")); +var _UnpublishAction = _interopRequireDefault(__webpack_require__(/*! components/ElementActions/UnpublishAction */ "./client/src/components/ElementActions/UnpublishAction.js")); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +var _default = () => { + _Injector.default.transform('elemental-fieldgroup', updater => { + updater.component('FieldGroup.HistoryViewer.VersionDetail', _HistoricElementView.default, 'HistoricElement'); + }, { + after: 'field-holders' + }); + _Injector.default.transform('blocks-history-revert', updater => { + updater.component('HistoryViewerToolbar.VersionedAdmin.HistoryViewer.Element.HistoryViewerVersionDetail', _revertToBlockVersionRequest.default, 'BlockRevertRequest'); + }); + _Injector.default.transform('element-actions', updater => { + updater.component('ElementActions', _SaveAction.default, 'ElementActionsWithSave'); + updater.component('ElementActions', _PublishAction.default, 'ElementActionsWithPublish'); + updater.component('ElementActions', _UnpublishAction.default, 'ElementActionsWithUnpublish'); + updater.component('ElementActions', _DuplicateAction.default, 'ElementActionsWithDuplicate'); + updater.component('ElementActions', _ArchiveAction.default, 'ElementActionsWithArchive'); + }); +}; +exports["default"] = _default; + +/***/ }), + +/***/ "./client/src/components/ElementActions/AbstractAction.js": +/*!****************************************************************!*\ + !*** ./client/src/components/ElementActions/AbstractAction.js ***! + \****************************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = void 0; +var _react = _interopRequireDefault(__webpack_require__(/*! react */ "react")); +var _propTypes = _interopRequireDefault(__webpack_require__(/*! prop-types */ "prop-types")); +var _classnames = _interopRequireDefault(__webpack_require__(/*! classnames */ "classnames")); +var _reactstrap = __webpack_require__(/*! reactstrap */ "reactstrap"); +var _elementTypeType = __webpack_require__(/*! types/elementTypeType */ "./client/src/types/elementTypeType.js"); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +const AbstractAction = props => { + const { + className, + title, + label + } = props; + const itemProps = { + className: (0, _classnames.default)(className, 'dropdown-item'), + ...props + }; + return _react.default.createElement(_reactstrap.DropdownItem, itemProps, label || title); +}; +AbstractAction.propTypes = { + disabled: _propTypes.default.bool, + className: _propTypes.default.string, + onClick: _propTypes.default.func, + title: _propTypes.default.string, + name: _propTypes.default.string, + type: _elementTypeType.elementTypeType, + active: _propTypes.default.bool, + label: _propTypes.default.string +}; +AbstractAction.defaultProps = { + disabled: false +}; +var _default = exports["default"] = AbstractAction; + +/***/ }), + +/***/ "./client/src/components/ElementActions/ArchiveAction.js": +/*!***************************************************************!*\ + !*** ./client/src/components/ElementActions/ArchiveAction.js ***! + \***************************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = exports.Component = void 0; +var _react = _interopRequireWildcard(__webpack_require__(/*! react */ "react")); +var _AbstractAction = _interopRequireDefault(__webpack_require__(/*! components/ElementActions/AbstractAction */ "./client/src/components/ElementActions/AbstractAction.js")); +var _i18n = _interopRequireDefault(__webpack_require__(/*! i18n */ "i18n")); +var _ElementEditor = __webpack_require__(/*! components/ElementEditor/ElementEditor */ "./client/src/components/ElementEditor/ElementEditor.js"); +var _Backend = _interopRequireDefault(__webpack_require__(/*! lib/Backend */ "lib/Backend")); +var _Config = _interopRequireDefault(__webpack_require__(/*! lib/Config */ "lib/Config")); +var _elementConfig = __webpack_require__(/*! state/editor/elementConfig */ "./client/src/state/editor/elementConfig.js"); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } +function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } +const ArchiveAction = MenuComponent => props => { + const { + fetchElements + } = (0, _react.useContext)(_ElementEditor.ElementEditorContext); + const handleClick = event => { + event.stopPropagation(); + const isPublished = props.element.isPublished; + let archiveMessage = _i18n.default._t('ElementArchiveAction.CONFIRM_DELETE', 'Are you sure you want to send this block to the archive?'); + if (isPublished) { + archiveMessage = _i18n.default._t('ElementArchiveAction.CONFIRM_DELETE_AND_UNPUBLISH', 'Warning: This block will be unpublished before being sent to the archive. Are you sure you want to proceed?'); + } + if (!window.confirm(archiveMessage)) { + return; + } + const id = props.element.id; + const url = `${(0, _elementConfig.getConfig)().controllerLink.replace(/\/$/, '')}/api/archive`; + _Backend.default.post(url, { + ID: id + }, { + SecurityID: _Config.default.get('SecurityID') + }).then(() => fetchElements()); + }; + const disabled = props.element.canDelete !== undefined && !props.element.canDelete; + const label = _i18n.default._t('ElementArchiveAction.ARCHIVE', 'Archive'); + const title = disabled ? _i18n.default._t('ElementArchiveAction.ARCHIVE_PERMISSION_DENY', 'Archive, insufficient permissions') : label; + const newProps = { + label, + title, + disabled, + className: 'element-editor__actions-archive', + onClick: handleClick, + toggle: props.toggle + }; + return _react.default.createElement(MenuComponent, props, props.children, _react.default.createElement(_AbstractAction.default, newProps)); +}; +exports.Component = ArchiveAction; +var _default = exports["default"] = ArchiveAction; + +/***/ }), + +/***/ "./client/src/components/ElementActions/DuplicateAction.js": +/*!*****************************************************************!*\ + !*** ./client/src/components/ElementActions/DuplicateAction.js ***! + \*****************************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = exports.Component = void 0; +var _react = _interopRequireWildcard(__webpack_require__(/*! react */ "react")); +var _AbstractAction = _interopRequireDefault(__webpack_require__(/*! components/ElementActions/AbstractAction */ "./client/src/components/ElementActions/AbstractAction.js")); +var _i18n = _interopRequireDefault(__webpack_require__(/*! i18n */ "i18n")); +var _ElementEditor = __webpack_require__(/*! components/ElementEditor/ElementEditor */ "./client/src/components/ElementEditor/ElementEditor.js"); +var _Backend = _interopRequireDefault(__webpack_require__(/*! lib/Backend */ "lib/Backend")); +var _Config = _interopRequireDefault(__webpack_require__(/*! lib/Config */ "lib/Config")); +var _elementConfig = __webpack_require__(/*! state/editor/elementConfig */ "./client/src/state/editor/elementConfig.js"); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } +function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } +const DuplicateAction = MenuComponent => props => { + const { + fetchElements + } = (0, _react.useContext)(_ElementEditor.ElementEditorContext); + if (props.type.broken) { + return _react.default.createElement(MenuComponent, props); + } + const handleClick = event => { + event.stopPropagation(); + const id = props.element.id; + const url = `${(0, _elementConfig.getConfig)().controllerLink.replace(/\/$/, '')}/api/duplicate`; + _Backend.default.post(url, { + ID: id + }, { + SecurityID: _Config.default.get('SecurityID') + }).then(() => fetchElements()); + }; + const disabled = props.element.canCreate !== undefined && !props.element.canCreate; + const label = _i18n.default._t('ElementArchiveAction.DUPLICATE', 'Duplicate'); + const title = disabled ? _i18n.default._t('ElementArchiveAction.DUPLICATE_PERMISSION_DENY', 'Duplicate, insufficient permissions') : label; + const newProps = { + label, + title, + disabled, + className: 'element-editor__actions-duplicate', + onClick: handleClick, + toggle: props.toggle + }; + return _react.default.createElement(MenuComponent, props, props.children, _react.default.createElement(_AbstractAction.default, newProps)); +}; +exports.Component = DuplicateAction; +var _default = exports["default"] = DuplicateAction; + +/***/ }), + +/***/ "./client/src/components/ElementActions/PublishAction.js": +/*!***************************************************************!*\ + !*** ./client/src/components/ElementActions/PublishAction.js ***! + \***************************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = exports.Component = void 0; +var _react = _interopRequireWildcard(__webpack_require__(/*! react */ "react")); +var _AbstractAction = _interopRequireDefault(__webpack_require__(/*! components/ElementActions/AbstractAction */ "./client/src/components/ElementActions/AbstractAction.js")); +var _i18n = _interopRequireDefault(__webpack_require__(/*! i18n */ "i18n")); +var _Element = __webpack_require__(/*! components/ElementEditor/Element */ "./client/src/components/ElementEditor/Element.js"); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } +function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } +const PublishAction = MenuComponent => props => { + const { + formDirty, + onPublishButtonClick + } = (0, _react.useContext)(_Element.ElementContext); + const { + element + } = props; + const handleClick = event => { + event.stopPropagation(); + onPublishButtonClick(); + }; + const disabled = props.element.canPublish !== undefined && !props.element.canPublish; + const label = _i18n.default._t('ElementArchiveAction.PUBLISH', 'Publish'); + const title = disabled ? _i18n.default._t('ElementArchiveAction.PUBLISH_PERMISSION_DENY', 'Publish, insufficient permissions') : label; + const newProps = { + label, + title, + disabled, + className: 'element-editor__actions-publish', + onClick: handleClick, + toggle: props.toggle + }; + if (props.type.broken) { + return _react.default.createElement(MenuComponent, props); + } + return _react.default.createElement(MenuComponent, props, props.children, (formDirty || !element.isLiveVersion) && _react.default.createElement(_AbstractAction.default, newProps)); +}; +exports.Component = PublishAction; +var _default = exports["default"] = PublishAction; + +/***/ }), + +/***/ "./client/src/components/ElementActions/SaveAction.js": +/*!************************************************************!*\ + !*** ./client/src/components/ElementActions/SaveAction.js ***! + \************************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = exports.Component = void 0; +var _react = _interopRequireWildcard(__webpack_require__(/*! react */ "react")); +var _AbstractAction = _interopRequireDefault(__webpack_require__(/*! components/ElementActions/AbstractAction */ "./client/src/components/ElementActions/AbstractAction.js")); +var _i18n = _interopRequireDefault(__webpack_require__(/*! i18n */ "i18n")); +var _Element = __webpack_require__(/*! components/ElementEditor/Element */ "./client/src/components/ElementEditor/Element.js"); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } +function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } +const SaveAction = MenuComponent => props => { + const { + onSaveButtonClick, + formDirty + } = (0, _react.useContext)(_Element.ElementContext); + const handleClick = event => { + event.stopPropagation(); + onSaveButtonClick(); + }; + const newProps = { + title: _i18n.default._t('ElementSaveAction.SAVE', 'Save'), + className: 'element-editor__actions-save', + onClick: handleClick, + toggle: props.toggle + }; + if (!props.expandable || props.type.broken) { + return _react.default.createElement(MenuComponent, props); + } + return _react.default.createElement(MenuComponent, props, props.children, formDirty && _react.default.createElement(_AbstractAction.default, newProps)); +}; +exports.Component = SaveAction; +var _default = exports["default"] = SaveAction; + +/***/ }), + +/***/ "./client/src/components/ElementActions/UnpublishAction.js": +/*!*****************************************************************!*\ + !*** ./client/src/components/ElementActions/UnpublishAction.js ***! + \*****************************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = exports.Component = void 0; +var _react = _interopRequireWildcard(__webpack_require__(/*! react */ "react")); +var _AbstractAction = _interopRequireDefault(__webpack_require__(/*! components/ElementActions/AbstractAction */ "./client/src/components/ElementActions/AbstractAction.js")); +var _i18n = _interopRequireDefault(__webpack_require__(/*! i18n */ "i18n")); +var _Backend = _interopRequireDefault(__webpack_require__(/*! lib/Backend */ "lib/Backend")); +var _ElementEditor = __webpack_require__(/*! components/ElementEditor/ElementEditor */ "./client/src/components/ElementEditor/ElementEditor.js"); +var _Config = _interopRequireDefault(__webpack_require__(/*! lib/Config */ "lib/Config")); +var _elementConfig = __webpack_require__(/*! state/editor/elementConfig */ "./client/src/state/editor/elementConfig.js"); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } +function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } +const UnpublishAction = MenuComponent => props => { + const { + fetchElements + } = (0, _react.useContext)(_ElementEditor.ElementEditorContext); + if (props.type.broken) { + return _react.default.createElement(MenuComponent, props); + } + const reportUnpublicationStatus = (type, title, success) => { + const noTitle = _i18n.default.inject(_i18n.default._t('ElementHeader.NOTITLE', 'Untitled {type} block'), { + type + }); + const successMessage = _i18n.default.inject(_i18n.default._t('ElementUnpublishAction.SUCCESS_NOTIFICATION', 'Removed \'{title}\' from the published page'), { + title: title || noTitle + }); + const errorMessage = _i18n.default.inject(_i18n.default._t('ElementUnpublishAction.ERROR_NOTIFICATION', 'Error unpublishing \'{title}\''), { + title: title || noTitle + }); + window.jQuery.noticeAdd({ + text: success ? successMessage : errorMessage, + stay: false, + type: success ? 'success' : 'error' + }); + }; + const unpublishElement = () => { + const id = props.element.id; + const url = `${(0, _elementConfig.getConfig)().controllerLink.replace(/\/$/, '')}/api/unpublish`; + return _Backend.default.post(url, { + ID: id + }, { + SecurityID: _Config.default.get('SecurityID') + }).then(() => fetchElements()); + }; + const { + element, + type + } = props; + const handleClick = event => { + event.stopPropagation(); + unpublishElement().then(() => reportUnpublicationStatus(type.title, element.title, true)).catch(() => reportUnpublicationStatus(type.title, element.title, false)); + }; + const disabled = props.element.canUnpublish !== undefined && !props.element.canUnpublish; + const label = _i18n.default._t('ElementArchiveAction.UNPUBLISH', 'Unpublish'); + const title = disabled ? _i18n.default._t('ElementArchiveAction.UNPUBLISH_PERMISSION_DENY', 'Unpublish, insufficient permissions') : label; + const newProps = { + label, + title, + disabled, + className: 'element-editor__actions-unpublish', + onClick: handleClick, + toggle: props.toggle + }; + return _react.default.createElement(MenuComponent, props, props.children, element.isPublished && _react.default.createElement(_AbstractAction.default, newProps)); +}; +exports.Component = UnpublishAction; +var _default = exports["default"] = UnpublishAction; + +/***/ }), + +/***/ "./client/src/components/ElementEditor/AddElementPopover.js": +/*!******************************************************************!*\ + !*** ./client/src/components/ElementEditor/AddElementPopover.js ***! + \******************************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = void 0; +var _react = _interopRequireWildcard(__webpack_require__(/*! react */ "react")); +var _propTypes = _interopRequireDefault(__webpack_require__(/*! prop-types */ "prop-types")); +var _classnames = _interopRequireDefault(__webpack_require__(/*! classnames */ "classnames")); +var _Injector = __webpack_require__(/*! lib/Injector */ "lib/Injector"); +var _elementTypeType = __webpack_require__(/*! types/elementTypeType */ "./client/src/types/elementTypeType.js"); +var _i18n = _interopRequireDefault(__webpack_require__(/*! i18n */ "i18n")); +var _Backend = _interopRequireDefault(__webpack_require__(/*! lib/Backend */ "lib/Backend")); +var _Config = _interopRequireDefault(__webpack_require__(/*! lib/Config */ "lib/Config")); +var _ElementEditor = __webpack_require__(/*! components/ElementEditor/ElementEditor */ "./client/src/components/ElementEditor/ElementEditor.js"); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } +function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } +class AddElementPopover extends _react.Component { + constructor(props) { + super(props); + this.handleToggle = this.handleToggle.bind(this); + AddElementPopover.contextType = _ElementEditor.ElementEditorContext; + } + getElementButtonClickHandler(elementType) { + return event => { + event.preventDefault(); + _Backend.default.post('/admin/elemental-area/api/add/', { + elementClass: elementType.class, + elementalAreaID: this.props.areaId, + insertAfterElementID: this.props.insertAfterElement + }, { + SecurityID: _Config.default.get('SecurityID') + }).then(() => { + const { + fetchElements + } = this.context; + return fetchElements(); + }).then(() => { + const preview = window.jQuery('.cms-preview'); + preview.entwine('ss.preview')._loadUrl(preview.find('iframe').attr('src')); + }); + this.handleToggle(); + }; + } + handleToggle() { + const { + toggle + } = this.props; + toggle(); + } + render() { + const { + PopoverOptionSetComponent, + elementTypes, + container, + extraClass, + isOpen, + placement, + target + } = this.props; + const popoverClassNames = (0, _classnames.default)('element-editor-add-element', extraClass); + const buttons = elementTypes.map(elementType => ({ + content: elementType.title, + key: elementType.name, + className: (0, _classnames.default)(elementType.icon, 'btn--icon-xl', 'element-editor-add-element__button'), + onClick: this.getElementButtonClickHandler(elementType) + })); + return _react.default.createElement(PopoverOptionSetComponent, { + buttons: buttons, + searchPlaceholder: _i18n.default._t('ElementAddElementPopover.SEARCH_BLOCKS', 'Search blocks'), + extraClass: popoverClassNames, + container: container, + isOpen: isOpen, + placement: placement, + target: target, + toggle: this.handleToggle + }); + } +} +AddElementPopover.propTypes = { + container: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.func, _propTypes.default.object]), + elementTypes: _propTypes.default.arrayOf(_elementTypeType.elementTypeType).isRequired, + extraClass: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.array, _propTypes.default.object]), + isOpen: _propTypes.default.bool.isRequired, + placement: _propTypes.default.string, + target: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.func, _propTypes.default.object]).isRequired, + toggle: _propTypes.default.func.isRequired, + areaId: _propTypes.default.number.isRequired, + insertAfterElement: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]) +}; +var _default = exports["default"] = (0, _Injector.inject)(['PopoverOptionSet'], PopoverOptionSetComponent => ({ + PopoverOptionSetComponent +}), () => 'ElementEditor')(AddElementPopover); + +/***/ }), + +/***/ "./client/src/components/ElementEditor/AddNewButton.js": +/*!*************************************************************!*\ + !*** ./client/src/components/ElementEditor/AddNewButton.js ***! + \*************************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = exports.Component = void 0; +var _react = _interopRequireWildcard(__webpack_require__(/*! react */ "react")); +var _propTypes = _interopRequireDefault(__webpack_require__(/*! prop-types */ "prop-types")); +var _reactstrap = __webpack_require__(/*! reactstrap */ "reactstrap"); +var _i18n = _interopRequireDefault(__webpack_require__(/*! i18n */ "i18n")); +var _elementTypeType = __webpack_require__(/*! types/elementTypeType */ "./client/src/types/elementTypeType.js"); +var _Injector = __webpack_require__(/*! lib/Injector */ "lib/Injector"); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } +function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } +class AddNewButton extends _react.Component { + constructor(props) { + super(props); + this.toggle = this.toggle.bind(this); + this.state = { + popoverOpen: false + }; + } + toggle() { + this.setState(prevState => ({ + popoverOpen: !prevState.popoverOpen + })); + } + render() { + const { + AddElementPopoverComponent, + elementTypes, + areaId + } = this.props; + const buttonAttributes = { + id: `ElementalArea${areaId}_AddButton`, + color: 'primary', + onClick: this.toggle, + className: 'font-icon-plus' + }; + return _react.default.createElement("div", null, _react.default.createElement(_reactstrap.Button, buttonAttributes, _i18n.default._t('ElementAddNewButton.ADD_BLOCK', 'Add block')), _react.default.createElement(AddElementPopoverComponent, { + placement: "bottom-start", + target: buttonAttributes.id, + isOpen: this.state.popoverOpen, + elementTypes: elementTypes, + toggle: this.toggle, + areaId: areaId, + insertAfterElement: 0 + })); + } +} +exports.Component = AddNewButton; +AddNewButton.defaultProps = {}; +AddNewButton.propTypes = { + elementTypes: _propTypes.default.arrayOf(_elementTypeType.elementTypeType).isRequired, + areaId: _propTypes.default.number.isRequired +}; +var _default = exports["default"] = (0, _Injector.inject)(['AddElementPopover'], AddElementPopoverComponent => ({ + AddElementPopoverComponent +}), () => 'ElementEditor.ElementList.AddNewButton')(AddNewButton); + +/***/ }), + +/***/ "./client/src/components/ElementEditor/Content.js": +/*!********************************************************!*\ + !*** ./client/src/components/ElementEditor/Content.js ***! + \********************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = exports.Component = void 0; +var _react = _interopRequireWildcard(__webpack_require__(/*! react */ "react")); +var _propTypes = _interopRequireDefault(__webpack_require__(/*! prop-types */ "prop-types")); +var _Injector = __webpack_require__(/*! lib/Injector */ "lib/Injector"); +var _redux = __webpack_require__(/*! redux */ "redux"); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } +function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } +class Content extends _react.PureComponent { + render() { + const { + id, + fileUrl, + fileTitle, + content, + previewExpanded, + InlineEditFormComponent, + SummaryComponent, + activeTab, + onFormInit, + handleLoadingError, + formDirty, + broken, + onFormSchemaSubmitResponse, + ensureFormRendered, + formHasRendered + } = this.props; + const notVisible = !previewExpanded && (ensureFormRendered || formHasRendered); + const extraClass = { + 'element-editor-editform--collapsed': !previewExpanded, + 'element-editor-editform--rendered-not-visible': notVisible + }; + return _react.default.createElement("div", { + className: "element-editor-content" + }, !previewExpanded && _react.default.createElement(SummaryComponent, { + content: content, + fileUrl: fileUrl, + fileTitle: fileTitle, + broken: broken + }), (previewExpanded || ensureFormRendered || formHasRendered) && _react.default.createElement(InlineEditFormComponent, { + extraClass: extraClass, + onClick: event => event.stopPropagation(), + elementId: id, + activeTab: activeTab, + onFormInit: onFormInit, + handleLoadingError: handleLoadingError, + onFormSchemaSubmitResponse: onFormSchemaSubmitResponse, + notVisible: notVisible + }), formDirty && _react.default.createElement("input", { + type: "hidden", + name: "change-tracker", + className: "element-form-dirty-state", + value: "1" + })); + } +} +exports.Component = Content; +Content.propTypes = { + id: _propTypes.default.string, + content: _propTypes.default.string, + fileUrl: _propTypes.default.string, + fileTitle: _propTypes.default.string, + previewExpanded: _propTypes.default.bool, + SummaryComponent: _propTypes.default.elementType, + InlineEditFormComponent: _propTypes.default.elementType, + handleLoadingError: _propTypes.default.func, + broken: _propTypes.default.bool, + onFormSchemaSubmitResponse: _propTypes.default.func, + onFormInit: _propTypes.default.func, + ensureFormRendered: _propTypes.default.bool, + formHasRendered: _propTypes.default.bool, + formDirty: _propTypes.default.object +}; +Content.defaultProps = {}; +var _default = exports["default"] = (0, _redux.compose)((0, _Injector.inject)(['ElementSummary', 'ElementInlineEditForm'], (SummaryComponent, InlineEditFormComponent) => ({ + SummaryComponent, + InlineEditFormComponent +}), () => 'ElementEditor.ElementList.Element'))(Content); + +/***/ }), + +/***/ "./client/src/components/ElementEditor/DragPositionIndicator.js": +/*!**********************************************************************!*\ + !*** ./client/src/components/ElementEditor/DragPositionIndicator.js ***! + \**********************************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = void 0; +var _react = _interopRequireWildcard(__webpack_require__(/*! react */ "react")); +function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } +function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } +class DragPositionIndicator extends _react.PureComponent { + render() { + return _react.default.createElement("div", { + className: "elemental-editor-drag-indicator" + }, _react.default.createElement("div", { + className: "elemental-editor-drag-indicator__ball" + })); + } +} +var _default = exports["default"] = DragPositionIndicator; + +/***/ }), + +/***/ "./client/src/components/ElementEditor/Element.js": +/*!********************************************************!*\ + !*** ./client/src/components/ElementEditor/Element.js ***! + \********************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = exports.ElementContext = exports.Component = void 0; +var _react = _interopRequireWildcard(__webpack_require__(/*! react */ "react")); +var _propTypes = _interopRequireDefault(__webpack_require__(/*! prop-types */ "prop-types")); +var _elementType = __webpack_require__(/*! types/elementType */ "./client/src/types/elementType.js"); +var _elementTypeType = __webpack_require__(/*! types/elementTypeType */ "./client/src/types/elementTypeType.js"); +var _redux = __webpack_require__(/*! redux */ "redux"); +var _Injector = __webpack_require__(/*! lib/Injector */ "lib/Injector"); +var _i18n = _interopRequireDefault(__webpack_require__(/*! i18n */ "i18n")); +var _classnames = _interopRequireDefault(__webpack_require__(/*! classnames */ "classnames")); +var _reactRedux = __webpack_require__(/*! react-redux */ "react-redux"); +var _reduxForm = __webpack_require__(/*! redux-form */ "redux-form"); +var _loadElementFormStateName = __webpack_require__(/*! state/editor/loadElementFormStateName */ "./client/src/state/editor/loadElementFormStateName.js"); +var _loadElementSchemaValue = __webpack_require__(/*! state/editor/loadElementSchemaValue */ "./client/src/state/editor/loadElementSchemaValue.js"); +var TabsActions = _interopRequireWildcard(__webpack_require__(/*! state/tabs/TabsActions */ "state/tabs/TabsActions")); +var _reactDnd = __webpack_require__(/*! react-dnd */ "react-dnd"); +var _reactDndHtml5Backend = __webpack_require__(/*! react-dnd-html5-backend */ "react-dnd-html5-backend"); +var _dragHelpers = __webpack_require__(/*! lib/dragHelpers */ "./client/src/lib/dragHelpers.js"); +var toastsActions = _interopRequireWildcard(__webpack_require__(/*! state/toasts/ToastsActions */ "state/toasts/ToastsActions")); +var _UnsavedFormsActions = __webpack_require__(/*! state/unsavedForms/UnsavedFormsActions */ "state/unsavedForms/UnsavedFormsActions"); +var _ElementEditor = __webpack_require__(/*! components/ElementEditor/ElementEditor */ "./client/src/components/ElementEditor/ElementEditor.js"); +var _elementConfig = __webpack_require__(/*! state/editor/elementConfig */ "./client/src/state/editor/elementConfig.js"); +var _Backend = _interopRequireDefault(__webpack_require__(/*! lib/Backend */ "lib/Backend")); +var _Config = _interopRequireDefault(__webpack_require__(/*! lib/Config */ "lib/Config")); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } +function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } +const ElementContext = exports.ElementContext = (0, _react.createContext)(null); +const Element = props => { + const [previewExpanded, setPreviewExpanded] = (0, _react.useState)(false); + const [initialTab, setInitialTab] = (0, _react.useState)(''); + const [loadingError, setLoadingError] = (0, _react.useState)(false); + const [newTitle, setNewTitle] = (0, _react.useState)(props.element.title); + const [justClickedPublishButton, setJustClickedPublishButton] = (0, _react.useState)(false); + const [doSaveElement, setDoSaveElement] = (0, _react.useState)(false); + const [doPublishElement, setDoPublishElement] = (0, _react.useState)(false); + const [doPublishElementAfterSave, setDoPublishElementAfterSave] = (0, _react.useState)(false); + const [ensureFormRendered, setEnsureFormRendered] = (0, _react.useState)(false); + const [formHasRendered, setFormHasRendered] = (0, _react.useState)(false); + const [doDispatchAddFormChanged, setDoDispatchAddFormChanged] = (0, _react.useState)(false); + const [hasUnsavedChanges, setHasUnsavedChanges] = (0, _react.useState)(false); + const { + fetchElements + } = (0, _react.useContext)(_ElementEditor.ElementEditorContext); + (0, _react.useEffect)(() => { + const formDirty = typeof props.formDirty !== 'undefined'; + if (formDirty && !hasUnsavedChanges) { + setHasUnsavedChanges(true); + } + }, [props.formDirty]); + (0, _react.useEffect)(() => { + props.onChangeHasUnsavedChanges(hasUnsavedChanges); + }, [hasUnsavedChanges]); + (0, _react.useEffect)(() => { + if (props.saveElement && hasUnsavedChanges && !doSaveElement) { + setDoSaveElement(true); + } + }, [props.saveElement, hasUnsavedChanges, props.increment]); + (0, _react.useEffect)(() => { + if (props.connectDragPreview) { + props.connectDragPreview((0, _reactDndHtml5Backend.getEmptyImage)(), { + captureDraggingState: true + }); + } + }, []); + (0, _react.useEffect)(() => { + if (justClickedPublishButton && formHasRendered) { + setJustClickedPublishButton(false); + if (hasUnsavedChanges) { + props.submitForm(); + setDoPublishElementAfterSave(true); + } else { + setDoPublishElement(true); + } + } + }, [justClickedPublishButton, formHasRendered]); + (0, _react.useEffect)(() => { + if (doDispatchAddFormChanged) { + setDoDispatchAddFormChanged(false); + props.dispatchAddFormChanged(); + } + }, [doDispatchAddFormChanged]); + const getNoTitle = () => _i18n.default.inject(_i18n.default._t('ElementHeader.NOTITLE', 'Untitled {type} block'), { + type: props.type.title + }); + const showSavedElementToast = elementTitle => { + const title = elementTitle || getNoTitle(); + const message = _i18n.default.inject(_i18n.default._t('ElementSaveAction.SUCCESS_NOTIFICATION', 'Saved \'{title}\' successfully'), { title - blockSchema - obsoleteClassName - isLiveVersion - isPublished - version - canCreate - canPublish - canUnpublish - canDelete - } - } -} -`,i=t.config={options(e){let{areaId:t}=e;return{variables:{id:t}}},props(e){let{data:{error:t,readOneElementalArea:n,loading:r}}=e,o=null;n&&(o=n.elements);return{loading:r||!o,blocks:o,graphQLErrors:t&&t.graphQLErrors&&t.graphQLErrors.map((e=>e.message))}}};t.default=(0,o.graphql)(l,i)},3695:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.mutation=t.default=t.config=void 0;var r,o=n(708),a=(r=n(7284))&&r.__esModule?r:{default:r},l=n(3521);const i=t.mutation=a.default` -mutation SortBlockMutation($blockId:ID!, $afterBlockId:ID!) { - sortBlock( - id: $blockId - afterBlockID: $afterBlockId - ) { - id - isLiveVersion - isPublished - } -} -`,s=t.config={props:e=>{let{mutate:t,ownProps:{actions:n}}=e;return{actions:{...n,handleSortBlock:(e,n,r)=>t({variables:{blockId:e,afterBlockId:n},optimisticResponse:{sortBlock:{id:e,isLiveVersion:!1,isPublished:!1,__typename:"Block"}},update:(t,o)=>{let{data:{sortBlock:a}}=o;const i=l.config.options({areaId:r}).variables,s=t.readQuery({query:l.query,variables:i}),d=JSON.parse(JSON.stringify(s));let u=d.readOneElementalArea.elements;const c=u.findIndex((t=>t.id===e)),f=u[c];if(Object.entries(a).forEach((e=>{let[t,n]=e;"__typename"!==t&&(f[t]=n)})),u.splice(c,1),"0"===n)u.unshift(f);else{let e=u.findIndex((e=>e.id===n));-1===e&&(e=c-1);const t=u.slice(e+1);u=u.slice(0,e+1),u.push(f),u=u.concat(t)}d.readOneElementalArea.elements=u,t.writeQuery({query:l.query,data:d,variables:i})}})}}}};t.default=(0,o.graphql)(i,s)},2393:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.mutation=t.default=t.config=void 0;var r,o=n(708),a=(r=n(7284))&&r.__esModule?r:{default:r},l=n(3521);const i=t.mutation=a.default` -mutation UnpublishBlock($blockId:ID!) { - unpublishBlock( - id: $blockId - ) { - id - } -} -`,s=t.config={props:e=>{let{mutate:t,ownProps:{actions:n}}=e;return{actions:{...n,handleUnpublishBlock:(e,n,r,o)=>t({variables:{blockId:e,fromStage:n,toStage:r,fromVersion:o}})}}},options:e=>{let{areaId:t}=e;return{refetchQueries:[{query:l.query,variables:l.config.options({areaId:t}).variables}]}}};t.default=(0,o.graphql)(i,s)},5071:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.query=t.default=t.config=void 0;var r,o=n(708),a=(r=n(7284))&&r.__esModule?r:{default:r};const l=t.query=a.default` -query ReadHistoryViewerBlock ($block_id: ID!, $limit: Int!, $offset: Int!) { - readOneBlock( - versioning: { - mode: LATEST + }); + props.actions.toasts.success(message); + }; + const showPublishedElementToast = wasError => { + const title = newTitle || getNoTitle(); + if (wasError) { + const message = _i18n.default.inject(_i18n.default._t('ElementPublishAction.ERROR_NOTIFICATION', 'Error publishing \'{title}\''), { + title + }); + props.actions.toasts.error(message); + } else { + const message = _i18n.default.inject(_i18n.default._t('ElementPublishAction.SUCCESS_NOTIFICATION', 'Published \'{title}\' successfully'), { + title + }); + props.actions.toasts.success(message); + } + }; + const handleAfterPublish = wasError => { + showPublishedElementToast(wasError); + setDoPublishElement(false); + setDoPublishElementAfterSave(false); + fetchElements().then(() => { + setTimeout(() => props.dispatchRemoveFormChanged(), 250); + }); + }; + (0, _react.useEffect)(() => { + if (formHasRendered && doSaveElement) { + props.submitForm(); + setDoSaveElement(false); + } + }, [formHasRendered, doSaveElement]); + (0, _react.useEffect)(() => { + if (formHasRendered && doPublishElement) { + const url = `${(0, _elementConfig.getConfig)().controllerLink.replace(/\/$/, '')}/api/publish`; + _Backend.default.post(url, { + ID: props.element.id + }, { + SecurityID: _Config.default.get('SecurityID') + }).then(() => handleAfterPublish(false)).catch(() => handleAfterPublish(true)); + } + }, [formHasRendered, doPublishElement]); + const getVersionedStateClassName = () => { + const { + element + } = props; + const baseClassName = 'element-editor__element'; + if (!element.isPublished) { + return `${baseClassName}--draft`; + } + if (element.isPublished && !element.isLiveVersion) { + return `${baseClassName}--modified`; + } + return `${baseClassName}--published`; + }; + const getLinkTitle = type => { + if (type.broken) { + return _i18n.default._t('ElementalElement.ARCHIVE_BROKEN', 'Archive this block'); + } + return _i18n.default.inject(_i18n.default._t('ElementalElement.TITLE', 'Edit this {type} block'), { + type: type.title + }); + }; + const getSummary = (element, type) => { + if (type.broken) { + return element.title ? _i18n.default.inject(_i18n.default._t('ElementalElement.BROKEN_DESCRIPTION_TITLE', 'This block had the title "{title}". It is broken and will not display on the front-end. You can archive it to remove it from this elemental area.'), { + title: element.title + }) : _i18n.default._t('ElementalElement.BROKEN_DESCRIPTION', 'This block is broken and will not display on the front-end. You can archive it to remove it from this elemental area.'); + } + return element.blockSchema.content; + }; + const handleLoadingError = () => { + setLoadingError(true); + }; + const updateFormTab = activeTab => { + const { + tabSetName, + onActivateTab + } = props; + if (!initialTab) { + setInitialTab(activeTab); + } + if (activeTab || initialTab) { + onActivateTab(tabSetName, activeTab || initialTab); + } else { + const defaultFirstTab = 'Main'; + onActivateTab(tabSetName, defaultFirstTab); + } + }; + const handleTabClick = toBeActiveTab => { + const { + activeTab + } = props; + if (toBeActiveTab !== activeTab && !loadingError) { + setPreviewExpanded(true); + updateFormTab(toBeActiveTab); + } + }; + const handleExpand = event => { + const { + type, + link + } = props; + if (type.broken) { + return; + } + if (event.target.type === 'button') { + event.stopPropagation(); + return; + } + if (type.inlineEditable && !loadingError) { + setPreviewExpanded(!previewExpanded); + return; + } + window.location = link; + }; + const handleKeyUp = event => { + const { + nodeName + } = event.target; + if ((event.key === ' ' || event.key === 'Enter') && !['input', 'textarea'].includes(nodeName.toLowerCase())) { + handleExpand(event); + } + }; + const handleSaveButtonClick = () => { + setEnsureFormRendered(true); + setDoSaveElement(true); + }; + const handlePublishButtonClick = () => { + setJustClickedPublishButton(true); + setEnsureFormRendered(true); + }; + const handleFormInit = activeTab => { + updateFormTab(activeTab); + setFormHasRendered(true); + }; + const handleFormSchemaSubmitResponse = (formSchema, title) => { + const hasValidationErrors = formSchema.id.match(/\/schema\/elemental-area\/([0-9]+)/); + if (hasValidationErrors) { + if (props.type.inlineEditable) { + setPreviewExpanded(true); + } + setDoDispatchAddFormChanged(true); + if (doPublishElementAfterSave) { + setDoPublishElementAfterSave(false); + } + props.onAfterSubmitResponse(false); + return; + } + setHasUnsavedChanges(false); + setNewTitle(title); + if (doPublishElementAfterSave) { + setDoPublishElementAfterSave(false); + setDoPublishElement(true); + } + if (!doPublishElement && !doPublishElementAfterSave) { + showSavedElementToast(title); + } + props.onAfterSubmitResponse(true); + fetchElements(); + }; + const { + element, + type, + areaId, + HeaderComponent, + ContentComponent, + link, + activeTab, + connectDragSource, + connectDropTarget, + isDragging, + isOver, + onDragEnd, + formDirty + } = props; + if (!element.id) { + return null; + } + const elementClassNames = (0, _classnames.default)('element-editor__element', { + 'element-editor__element--broken': type.broken, + 'element-editor__element--expandable': type.inlineEditable && !type.broken, + 'element-editor__element--dragging': isDragging, + 'element-editor__element--dragged-over': isOver + }, getVersionedStateClassName()); + const providerValue = { + formDirty, + onPublishButtonClick: handlePublishButtonClick, + onSaveButtonClick: handleSaveButtonClick + }; + const content = connectDropTarget(_react.default.createElement("div", { + className: elementClassNames, + onClick: handleExpand, + onKeyUp: handleKeyUp, + role: "button", + tabIndex: 0, + title: getLinkTitle(type), + key: element.id + }, _react.default.createElement(ElementContext.Provider, { + value: providerValue + }, _react.default.createElement(HeaderComponent, { + element: element, + type: type, + areaId: areaId, + expandable: type.inlineEditable, + link: link, + previewExpanded: previewExpanded, + handleEditTabsClick: handleTabClick, + activeTab: activeTab, + disableTooltip: isDragging, + onDragEnd: onDragEnd + }), _react.default.createElement(ContentComponent, { + id: element.id, + fileUrl: element.blockSchema.fileURL, + fileTitle: element.blockSchema.fileTitle, + content: getSummary(element, type), + previewExpanded: previewExpanded && !isDragging, + ensureFormRendered: ensureFormRendered, + formHasRendered: formHasRendered, + activeTab: activeTab, + handleLoadingError: handleLoadingError, + broken: type.broken, + onFormSchemaSubmitResponse: handleFormSchemaSubmitResponse, + onFormInit: () => handleFormInit(activeTab) + })))); + if (!previewExpanded) { + return connectDragSource(content); + } + return content; +}; +exports.Component = Element; +function mapStateToProps(state, ownProps) { + const elementId = ownProps.element.id; + const elementName = (0, _loadElementFormStateName.loadElementFormStateName)(elementId); + const elementFormSchema = (0, _loadElementSchemaValue.loadElementSchemaValue)('schemaUrl', elementId); + const filterFieldsForTabs = field => field.component === 'Tabs'; + const tabSet = state.form && state.form.formSchemas[elementFormSchema] && state.form.formSchemas[elementFormSchema].schema && state.form.formSchemas[elementFormSchema].schema.fields.find(filterFieldsForTabs); + const tabSetName = tabSet && tabSet.id; + const uniqueFieldId = `element.${elementName}__${tabSetName}`; + const formDirty = state.unsavedForms.find(unsaved => unsaved.name === `element.${elementName}`); + const activeTab = state.tabs && state.tabs.fields && state.tabs.fields[uniqueFieldId] && state.tabs.fields[uniqueFieldId].activeTab; + return { + tabSetName, + activeTab, + formDirty + }; +} +function mapDispatchToProps(dispatch, ownProps) { + const elementName = (0, _loadElementFormStateName.loadElementFormStateName)(ownProps.element.id); + return { + onActivateTab(tabSetName, activeTabName) { + dispatch(TabsActions.activateTab(`element.${elementName}__${tabSetName}`, activeTabName)); }, - filter: { id: { eq: $block_id } } - ) { - id - versions (limit: $limit, offset: $offset, sort: { version: DESC }) { - pageInfo { - totalCount - } - nodes { - version - absoluteLink - author { - firstName - surname - } - publisher { - firstName - surname - } - published - liveVersion - latestDraftVersion - lastEdited + submitForm() { + ownProps.onBeforeSubmitForm(ownProps.element.id); + dispatch((0, _reduxForm.submit)(`element.${elementName}`)); + }, + dispatchAddFormChanged() { + dispatch((0, _UnsavedFormsActions.addFormChanged)(`element.${elementName}`)); + }, + dispatchRemoveFormChanged() { + dispatch((0, _UnsavedFormsActions.removeFormChanged)(`element.${elementName}`)); + }, + actions: { + toasts: (0, _redux.bindActionCreators)(toastsActions, dispatch) + } + }; +} +Element.propTypes = { + element: _elementType.elementType, + type: _elementTypeType.elementTypeType.isRequired, + areaId: _propTypes.default.number.isRequired, + link: _propTypes.default.string.isRequired, + activeTab: _propTypes.default.string, + tabSetName: _propTypes.default.string, + onActivateTab: _propTypes.default.func, + connectDragSource: _propTypes.default.func.isRequired, + connectDragPreview: _propTypes.default.func.isRequired, + connectDropTarget: _propTypes.default.func.isRequired, + isDragging: _propTypes.default.bool.isRequired, + isOver: _propTypes.default.bool.isRequired, + onDragOver: _propTypes.default.func, + onDragEnd: _propTypes.default.func, + onDragStart: _propTypes.default.func, + saveElement: _propTypes.default.bool.isRequired, + onBeforeSubmitForm: _propTypes.default.func.isRequired, + onAfterSubmitResponse: _propTypes.default.func.isRequired, + increment: _propTypes.default.number.isRequired +}; +Element.defaultProps = { + element: null +}; +const elementTarget = { + drop(props, monitor, component) { + const { + element + } = props; + return { + target: element.id, + dropSpot: (0, _dragHelpers.isOverTop)(monitor, component) ? 'top' : 'bottom' + }; + }, + hover(props, monitor, component) { + const { + element, + onDragOver + } = props; + if (onDragOver) { + onDragOver(element, (0, _dragHelpers.isOverTop)(monitor, component)); + } + } +}; +var _default = exports["default"] = (0, _redux.compose)((0, _reactDnd.DropTarget)('element', elementTarget, (connector, monitor) => ({ + connectDropTarget: connector.dropTarget(), + isOver: monitor.isOver() +})), (0, _reactDnd.DragSource)('element', _dragHelpers.elementDragSource, (connector, monitor) => ({ + connectDragSource: connector.dragSource(), + connectDragPreview: connector.dragPreview(), + isDragging: monitor.isDragging() +})), (0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps), (0, _Injector.inject)(['ElementHeader', 'ElementContent'], (HeaderComponent, ContentComponent) => ({ + HeaderComponent, + ContentComponent +}), () => 'ElementEditor.ElementList.Element'))(Element); + +/***/ }), + +/***/ "./client/src/components/ElementEditor/ElementActions.js": +/*!***************************************************************!*\ + !*** ./client/src/components/ElementEditor/ElementActions.js ***! + \***************************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = exports.Component = void 0; +var _react = _interopRequireWildcard(__webpack_require__(/*! react */ "react")); +var _propTypes = _interopRequireDefault(__webpack_require__(/*! prop-types */ "prop-types")); +var _redux = __webpack_require__(/*! redux */ "redux"); +var _reactstrap = __webpack_require__(/*! reactstrap */ "reactstrap"); +var _Injector = __webpack_require__(/*! lib/Injector */ "lib/Injector"); +var _elementType = __webpack_require__(/*! types/elementType */ "./client/src/types/elementType.js"); +var _elementTypeType = __webpack_require__(/*! types/elementTypeType */ "./client/src/types/elementTypeType.js"); +var _AbstractAction = _interopRequireDefault(__webpack_require__(/*! components/ElementActions/AbstractAction */ "./client/src/components/ElementActions/AbstractAction.js")); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } +function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } +class ElementActions extends _react.Component { + constructor(props) { + super(props); + this.handleEditTabsClick = this.handleEditTabsClick.bind(this); + } + handleEditTabsClick(event) { + const { + handleEditTabsClick + } = this.props; + handleEditTabsClick(event.target.name); + } + renderEditTabs() { + const { + editTabs, + activeTab, + type, + expandable + } = this.props; + if (type.broken || !expandable || !editTabs || !editTabs.length) { + return null; + } + return editTabs.map(_ref => { + let { + name, + title + } = _ref; + return _react.default.createElement(_AbstractAction.default, { + key: name, + name: name, + title: title, + type: type, + onClick: this.handleEditTabsClick, + active: name === activeTab + }); + }); + } + renderDivider() { + const { + children, + editTabs, + expandable + } = this.props; + if (!expandable || !editTabs || !editTabs.length || _react.default.Children.count(children) === 0) { + return null; + } + return _react.default.createElement(_reactstrap.DropdownItem, { + divider: true, + role: "separator" + }); + } + render() { + const { + children, + id, + ActionMenuComponent + } = this.props; + const dropdownToggleClassNames = ['element-editor-header__actions-toggle', 'btn', 'btn-sm', 'btn--no-text', 'font-icon-dot-3']; + return _react.default.createElement(ActionMenuComponent, { + id: `element-editor-actions-${id}`, + className: "element-editor-header__actions-dropdown", + dropdownMenuProps: { + right: true + }, + dropdownToggleClassNames: dropdownToggleClassNames + }, this.renderEditTabs(), this.renderDivider(), children); + } +} +exports.Component = ElementActions; +ElementActions.propTypes = { + element: _elementType.elementType, + type: _elementTypeType.elementTypeType.isRequired, + areaId: _propTypes.default.number.isRequired, + activeTab: _propTypes.default.string, + editTabs: _propTypes.default.arrayOf(_propTypes.default.shape({ + title: _propTypes.default.string, + name: _propTypes.default.string + })), + handleEditTabsClick: _propTypes.default.func.isRequired, + expandable: _propTypes.default.bool +}; +ElementActions.defaultProps = { + editTabs: [], + expandable: true +}; +var _default = exports["default"] = (0, _redux.compose)((0, _Injector.inject)(['ActionMenu'], ActionMenuComponent => ({ + ActionMenuComponent +}), () => 'ElementEditor.ElementList.Element'))(ElementActions); + +/***/ }), + +/***/ "./client/src/components/ElementEditor/ElementDragPreview.js": +/*!*******************************************************************!*\ + !*** ./client/src/components/ElementEditor/ElementDragPreview.js ***! + \*******************************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = void 0; +var _react = _interopRequireWildcard(__webpack_require__(/*! react */ "react")); +var _propTypes = _interopRequireDefault(__webpack_require__(/*! prop-types */ "prop-types")); +var _Header = _interopRequireDefault(__webpack_require__(/*! components/ElementEditor/Header */ "./client/src/components/ElementEditor/Header.js")); +var _reactDnd = __webpack_require__(/*! react-dnd */ "react-dnd"); +var _elementType = __webpack_require__(/*! types/elementType */ "./client/src/types/elementType.js"); +var _elementTypeType = __webpack_require__(/*! types/elementTypeType */ "./client/src/types/elementTypeType.js"); +var _elementConfig = __webpack_require__(/*! state/editor/elementConfig */ "./client/src/state/editor/elementConfig.js"); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } +function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } +class ElementDragPreview extends _react.Component { + render() { + const { + isDragging, + element, + elementTypes, + currentOffset + } = this.props; + if (!isDragging || !currentOffset) { + return null; + } + const { + x, + y + } = currentOffset; + const transform = `translate(${x}px, ${y}px)`; + const style = { + transform, + WebkitTransform: transform + }; + const type = (0, _elementConfig.getElementTypeConfig)(element, elementTypes); + return _react.default.createElement("div", { + className: "element-editor-drag-preview", + style: style + }, _react.default.createElement(_Header.default, { + element: element, + type: type, + simple: true + })); + } +} +ElementDragPreview.propTypes = { + element: _elementType.elementType, + elementTypes: _propTypes.default.arrayOf(_elementTypeType.elementTypeType), + isDragging: _propTypes.default.bool, + currentOffset: _propTypes.default.shape({ + x: _propTypes.default.number.isRequired, + y: _propTypes.default.number.isRequired + }) +}; +var _default = exports["default"] = (0, _reactDnd.DragLayer)(monitor => ({ + element: monitor.getItem(), + currentOffset: monitor.getSourceClientOffset(), + isDragging: monitor.isDragging() +}))(ElementDragPreview); + +/***/ }), + +/***/ "./client/src/components/ElementEditor/ElementEditor.js": +/*!**************************************************************!*\ + !*** ./client/src/components/ElementEditor/ElementEditor.js ***! + \**************************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = exports.ElementEditorContext = exports.Component = void 0; +var _react = _interopRequireWildcard(__webpack_require__(/*! react */ "react")); +var _propTypes = _interopRequireDefault(__webpack_require__(/*! prop-types */ "prop-types")); +var _Injector = __webpack_require__(/*! lib/Injector */ "lib/Injector"); +var _redux = __webpack_require__(/*! redux */ "redux"); +var _elementTypeType = __webpack_require__(/*! types/elementTypeType */ "./client/src/types/elementTypeType.js"); +var _reactDnd = __webpack_require__(/*! react-dnd */ "react-dnd"); +var _ElementDragPreview = _interopRequireDefault(__webpack_require__(/*! components/ElementEditor/ElementDragPreview */ "./client/src/components/ElementEditor/ElementDragPreview.js")); +var _withDragDropContext = _interopRequireDefault(__webpack_require__(/*! lib/withDragDropContext */ "lib/withDragDropContext")); +var _Backend = _interopRequireDefault(__webpack_require__(/*! lib/Backend */ "lib/Backend")); +var _Config = _interopRequireDefault(__webpack_require__(/*! lib/Config */ "lib/Config")); +var _elementConfig = __webpack_require__(/*! state/editor/elementConfig */ "./client/src/state/editor/elementConfig.js"); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } +function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } +const ElementEditorContext = exports.ElementEditorContext = (0, _react.createContext)(null); +class ElementEditor extends _react.PureComponent { + constructor(props) { + super(props); + this.state = { + dragTargetElementId: null, + dragSpot: null, + elements: null, + isLoading: true + }; + this.handleDragOver = this.handleDragOver.bind(this); + this.handleDragEnd = this.handleDragEnd.bind(this); + this.fetchElements = this.fetchElements.bind(this); + } + handleDragOver() { + let element = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; + let isOverTop = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + const id = element ? element.id : false; + this.setState({ + dragTargetElementId: id, + dragSpot: isOverTop === false ? 'bottom' : 'top' + }); + } + handleDragEnd(sourceId, afterId) { + const url = `${(0, _elementConfig.getConfig)().controllerLink.replace(/\/$/, '')}/api/sort`; + _Backend.default.post(url, { + ID: sourceId, + afterBlockID: afterId + }, { + SecurityID: _Config.default.get('SecurityID') + }).then(() => this.fetchElements()); + this.setState({ + dragTargetElementId: null, + dragSpot: null + }); + } + fetchElements() { + let doSetLoadingState = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; + if (doSetLoadingState) { + this.setState(prevState => ({ + ...prevState, + isLoading: true + })); + } + const url = `${(0, _elementConfig.getConfig)().controllerLink.replace(/\/$/, '')}/api/readElements/${this.props.areaId}`; + return _Backend.default.get(url, { + SecurityID: _Config.default.get('SecurityID') + }).then(response => response.json()).then(responseJson => { + this.setState(prevState => ({ + ...prevState, + elements: responseJson, + isLoading: false + })); + const preview = window.jQuery('.cms-preview'); + if (preview) { + preview.entwine('ss.preview')._loadUrl(preview.find('iframe').attr('src')); + } + }); + } + render() { + const { + ToolbarComponent, + ListComponent, + areaId, + elementTypes, + isDraggingOver, + connectDropTarget, + allowedElements, + sharedObject, + isLoading + } = this.props; + const { + dragTargetElementId, + dragSpot, + elements + } = this.state; + if (elements === null) { + this.fetchElements(false); + return null; + } + const allowedElementTypes = allowedElements.map(className => elementTypes.find(type => type.class === className)); + const providerValue = { + fetchElements: this.fetchElements + }; + return connectDropTarget(_react.default.createElement("div", { + className: "element-editor" + }, _react.default.createElement(ElementEditorContext.Provider, { + value: providerValue + }, _react.default.createElement(ToolbarComponent, { + elementTypes: allowedElementTypes, + areaId: areaId, + onDragOver: this.handleDragOver + }), _react.default.createElement(ListComponent, { + allowedElementTypes: allowedElementTypes, + elementTypes: elementTypes, + areaId: areaId, + onDragOver: this.handleDragOver, + onDragStart: this.handleDragStart, + onDragEnd: this.handleDragEnd, + dragSpot: dragSpot, + isDraggingOver: isDraggingOver, + dragTargetElementId: dragTargetElementId, + sharedObject: sharedObject, + elements: elements, + isLoading: isLoading + }), _react.default.createElement(_ElementDragPreview.default, { + elementTypes: elementTypes + })))); + } +} +exports.Component = ElementEditor; +ElementEditor.propTypes = { + elementTypes: _propTypes.default.arrayOf(_elementTypeType.elementTypeType).isRequired, + allowedElements: _propTypes.default.arrayOf(_propTypes.default.string).isRequired, + areaId: _propTypes.default.number.isRequired, + actions: _propTypes.default.shape({ + handleSortBlock: _propTypes.default.func + }) +}; +const params = [_withDragDropContext.default, (0, _reactDnd.DropTarget)('element', {}, (connector, monitor) => ({ + connectDropTarget: connector.dropTarget(), + isDraggingOver: monitor.isOver() +})), (0, _Injector.inject)(['ElementToolbar', 'ElementList'], (ToolbarComponent, ListComponent) => ({ + ToolbarComponent, + ListComponent +}), () => 'ElementEditor')]; +var _default = exports["default"] = (0, _redux.compose)(...params)(ElementEditor); + +/***/ }), + +/***/ "./client/src/components/ElementEditor/ElementList.js": +/*!************************************************************!*\ + !*** ./client/src/components/ElementEditor/ElementList.js ***! + \************************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = exports.Component = void 0; +var _react = _interopRequireWildcard(__webpack_require__(/*! react */ "react")); +var _propTypes = _interopRequireDefault(__webpack_require__(/*! prop-types */ "prop-types")); +var _elementType = __webpack_require__(/*! types/elementType */ "./client/src/types/elementType.js"); +var _elementTypeType = __webpack_require__(/*! types/elementTypeType */ "./client/src/types/elementTypeType.js"); +var _redux = __webpack_require__(/*! redux */ "redux"); +var _Injector = __webpack_require__(/*! lib/Injector */ "lib/Injector"); +var _classnames = _interopRequireDefault(__webpack_require__(/*! classnames */ "classnames")); +var _i18n = _interopRequireDefault(__webpack_require__(/*! i18n */ "i18n")); +var _reactDnd = __webpack_require__(/*! react-dnd */ "react-dnd"); +var _dragHelpers = __webpack_require__(/*! lib/dragHelpers */ "./client/src/lib/dragHelpers.js"); +var _elementConfig = __webpack_require__(/*! state/editor/elementConfig */ "./client/src/state/editor/elementConfig.js"); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } +function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } +class ElementList extends _react.Component { + constructor(props) { + super(props); + this.resetState = this.resetState.bind(this); + this.handleBeforeSubmitForm = this.handleBeforeSubmitForm.bind(this); + this.handleAfterSubmitResponse = this.handleAfterSubmitResponse.bind(this); + this.state = { + saveAllElements: false, + increment: 0, + hasUnsavedChangesBlockIDs: {}, + validBlockIDs: {} + }; + this.props.sharedObject.setState = this.setState.bind(this); + } + componentDidUpdate(prevProps, prevState) { + if (!this.props.elements) { + return; + } + if (this.props.elements !== prevProps.elements) { + this.resetState(prevState, false); + return; + } + if (this.state.saveAllElements) { + const unsavedChangesBlockIDs = this.props.elements.map(block => parseInt(block.id, 10)).filter(blockID => this.state.hasUnsavedChangesBlockIDs[blockID]); + const allValidated = unsavedChangesBlockIDs.every(blockID => this.state.validBlockIDs[blockID] !== null); + if (allValidated) { + const allValid = unsavedChangesBlockIDs.every(blockID => this.state.validBlockIDs[blockID]); + const result = { + success: allValid, + reason: allValid ? '' : 'invalid' + }; + this.props.sharedObject.entwineResolve(result); + this.resetState(prevState, allValid); + this.setState({ + saveAllElements: false + }); + } + } + } + resetState(prevState, resetHasUnsavedChangesBlockIDs) { + const hasUnsavedChangesBlockIDs = {}; + const validBlockIDs = {}; + const elements = this.props.elements || []; + elements.forEach(element => { + const blockID = parseInt(element.id, 10); + if (resetHasUnsavedChangesBlockIDs) { + hasUnsavedChangesBlockIDs[blockID] = false; + } else if (prevState.hasUnsavedChangesBlockIDs.hasOwnProperty(blockID)) { + hasUnsavedChangesBlockIDs[blockID] = prevState.hasUnsavedChangesBlockIDs[blockID]; + } else { + hasUnsavedChangesBlockIDs[blockID] = false; + } + validBlockIDs[blockID] = null; + }); + this.setState({ + hasUnsavedChangesBlockIDs, + validBlockIDs + }); + } + handleChangeHasUnsavedChanges(elementID, hasUnsavedChanges) { + this.setState(prevState => ({ + hasUnsavedChangesBlockIDs: { + ...prevState.hasUnsavedChangesBlockIDs, + [elementID]: hasUnsavedChanges + } + })); + } + handleBeforeSubmitForm(elementID) { + this.setState(prevState => ({ + validBlockIDs: { + ...prevState.validBlockIDs, + [elementID]: null } + })); + } + handleAfterSubmitResponse(elementID, valid) { + this.setState(prevState => ({ + hasUnsavedChangesBlockIDs: { + ...prevState.hasUnsavedChangesBlockIDs, + [elementID]: !valid + }, + validBlockIDs: { + ...prevState.validBlockIDs, + [elementID]: valid + } + })); + } + getDragIndicatorIndex() { + const { + dragTargetElementId, + draggedItem, + elements, + dragSpot + } = this.props; + return (0, _dragHelpers.getDragIndicatorIndex)(elements.map(element => element.id), dragTargetElementId, draggedItem && draggedItem.id, dragSpot); + } + renderBlocks() { + const { + ElementComponent, + HoverBarComponent, + DragIndicatorComponent, + elements, + allowedElementTypes, + elementTypes, + areaId, + onDragEnd, + onDragOver, + onDragStart, + isDraggingOver + } = this.props; + if (elements.length === 0) { + return _react.default.createElement("div", null, _i18n.default._t('ElementList.ADD_BLOCKS', 'Add blocks to place your content')); + } + let output = elements.map(element => { + const saveElement = this.state.saveAllElements && this.state.hasUnsavedChangesBlockIDs[element.id] && this.state.validBlockIDs[element.id] === null; + return _react.default.createElement("div", { + key: element.id + }, _react.default.createElement(ElementComponent, { + element: element, + areaId: areaId, + type: (0, _elementConfig.getElementTypeConfig)(element, elementTypes), + link: element.blockSchema.actions.edit, + onDragOver: onDragOver, + onDragEnd: onDragEnd, + onDragStart: onDragStart, + saveElement: saveElement, + onChangeHasUnsavedChanges: hasUnsavedChanges => this.handleChangeHasUnsavedChanges(element.id, hasUnsavedChanges), + onBeforeSubmitForm: () => this.handleBeforeSubmitForm(element.id), + onAfterSubmitResponse: valid => this.handleAfterSubmitResponse(element.id, valid), + increment: this.state.increment + }), isDraggingOver || _react.default.createElement(HoverBarComponent, { + key: `create-after-${element.id}`, + areaId: areaId, + elementId: element.id, + elementTypes: allowedElementTypes + })); + }); + if (!isDraggingOver) { + output = [_react.default.createElement(HoverBarComponent, { + key: 0, + areaId: areaId, + elementId: 0, + elementTypes: allowedElementTypes + })].concat(output); + } + const dragIndicatorIndex = this.getDragIndicatorIndex(); + if (isDraggingOver && dragIndicatorIndex !== null) { + output.splice(dragIndicatorIndex, 0, _react.default.createElement(DragIndicatorComponent, { + key: "DropIndicator" + })); + } + return output; + } + renderLoading() { + const { + isLoading, + LoadingComponent + } = this.props; + if (isLoading) { + return _react.default.createElement(LoadingComponent, null); + } + return null; + } + render() { + const { + elements + } = this.props; + const listClassNames = (0, _classnames.default)('elemental-editor-list', { + 'elemental-editor-list--empty': !elements || !elements.length + }); + return this.props.connectDropTarget(_react.default.createElement("div", { + className: listClassNames + }, this.renderLoading(), this.renderBlocks())); + } +} +exports.Component = ElementList; +ElementList.propTypes = { + elements: _propTypes.default.arrayOf(_elementType.elementType).isRequired, + elementTypes: _propTypes.default.arrayOf(_elementTypeType.elementTypeType).isRequired, + allowedElementTypes: _propTypes.default.arrayOf(_elementTypeType.elementTypeType).isRequired, + areaId: _propTypes.default.number.isRequired, + dragTargetElementId: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.bool]), + onDragOver: _propTypes.default.func, + onDragStart: _propTypes.default.func, + onDragEnd: _propTypes.default.func, + sharedObject: _propTypes.default.object.isRequired +}; +ElementList.defaultProps = { + sharedObject: { + entwineResolve: () => {}, + setState: null + }, + elements: [], + isLoading: false +}; +const elementListTarget = { + drop(props, monitor) { + const { + elements + } = props; + const elementTargetDropResult = monitor.getDropResult(); + if (!elementTargetDropResult) { + return {}; + } + const dropIndex = (0, _dragHelpers.getDragIndicatorIndex)(elements.map(element => element.id), elementTargetDropResult.target, monitor.getItem(), elementTargetDropResult.dropSpot); + const dropAfterID = elements[dropIndex - 1] ? elements[dropIndex - 1].id : '0'; + return { + ...elementTargetDropResult, + dropAfterID + }; + } +}; +var _default = exports["default"] = (0, _redux.compose)((0, _reactDnd.DropTarget)('element', elementListTarget, (connector, monitor) => ({ + connectDropTarget: connector.dropTarget(), + draggedItem: monitor.getItem() +})), (0, _Injector.inject)(['Element', 'Loading', 'HoverBar', 'DragPositionIndicator'], (ElementComponent, LoadingComponent, HoverBarComponent, DragIndicatorComponent) => ({ + ElementComponent, + LoadingComponent, + HoverBarComponent, + DragIndicatorComponent +}), () => 'ElementEditor.ElementList'))(ElementList); + +/***/ }), + +/***/ "./client/src/components/ElementEditor/Header.js": +/*!*******************************************************!*\ + !*** ./client/src/components/ElementEditor/Header.js ***! + \*******************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = exports.Component = void 0; +var _react = _interopRequireWildcard(__webpack_require__(/*! react */ "react")); +var _propTypes = _interopRequireDefault(__webpack_require__(/*! prop-types */ "prop-types")); +var _reactstrap = __webpack_require__(/*! reactstrap */ "reactstrap"); +var _elementType = __webpack_require__(/*! types/elementType */ "./client/src/types/elementType.js"); +var _elementTypeType = __webpack_require__(/*! types/elementTypeType */ "./client/src/types/elementTypeType.js"); +var _redux = __webpack_require__(/*! redux */ "redux"); +var _Injector = __webpack_require__(/*! lib/Injector */ "lib/Injector"); +var _i18n = _interopRequireDefault(__webpack_require__(/*! i18n */ "i18n")); +var _classnames = _interopRequireDefault(__webpack_require__(/*! classnames */ "classnames")); +var _reactDnd = __webpack_require__(/*! react-dnd */ "react-dnd"); +var _dragHelpers = __webpack_require__(/*! lib/dragHelpers */ "./client/src/lib/dragHelpers.js"); +var _reactDndHtml5Backend = __webpack_require__(/*! react-dnd-html5-backend */ "react-dnd-html5-backend"); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } +function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } +class Header extends _react.Component { + constructor(props) { + super(props); + this.toggle = this.toggle.bind(this); + this.state = { + tooltipOpen: false + }; + } + componentDidMount() { + const { + connectDragPreview + } = this.props; + if (connectDragPreview) { + connectDragPreview((0, _reactDndHtml5Backend.getEmptyImage)(), { + captureDraggingState: true + }); + } + } + componentDidUpdate() { + const { + tooltipOpen + } = this.state; + const { + disableTooltip + } = this.props; + if (tooltipOpen && disableTooltip) { + this.setState({ + tooltipOpen: false + }); + } + } + getBlockTitle(element, type) { + if (type.broken) { + return _i18n.default.inject(_i18n.default._t('ElementHeader.BROKEN', 'This element is of obsolete type {type}.'), { + type: type.obsoleteClassName + }); + } + if (element.title) { + return element.title; + } + return _i18n.default.inject(_i18n.default._t('ElementHeader.NOTITLE', 'Untitled {type} block'), { + type: type.title + }); + } + toggle() { + this.setState(prevState => ({ + tooltipOpen: !prevState.tooltipOpen + })); + } + renderVersionedStateMessage() { + const { + element: { + isLiveVersion, + isPublished + } + } = this.props; + if (isPublished && isLiveVersion) { + return null; + } + let versionStateButtonTitle = ''; + const stateClassNames = ['element-editor-header__version-state']; + if (!isPublished) { + versionStateButtonTitle = _i18n.default._t('ElementHeader.STATE_DRAFT', 'Item has not been published yet'); + stateClassNames.push('element-editor-header__version-state--draft'); + } else if (!isLiveVersion) { + versionStateButtonTitle = _i18n.default._t('ElementHeader.STATE_MODIFIED', 'Item has unpublished changes'); + stateClassNames.push('element-editor-header__version-state--modified'); + } + return _react.default.createElement("span", { + className: (0, _classnames.default)(stateClassNames), + title: versionStateButtonTitle + }); + } + renderStatusBadge() { + const { + element: { + isLiveVersion, + isPublished + } + } = this.props; + if (isPublished && isLiveVersion) { + return null; + } + let versionStateTitle = ''; + let versionStateButtonTitle = ''; + const stateClassNames = ['badge']; + if (!isPublished) { + versionStateTitle = _i18n.default._t('ElementHeader.BADGE_DRAFT', 'Draft'); + versionStateButtonTitle = _i18n.default._t('ElementHeader.STATE_DRAFT', 'Item has not been published yet'); + stateClassNames.push('status-addedtodraft'); + } else if (!isLiveVersion) { + versionStateTitle = _i18n.default._t('ElementHeader.BADGE_MODIFIED', 'Modified'); + versionStateButtonTitle = _i18n.default._t('ElementHeader.STATE_MODIFIED', 'Item has unpublished changes'); + stateClassNames.push('status-modified'); + } + return _react.default.createElement("span", { + className: (0, _classnames.default)(stateClassNames), + title: versionStateButtonTitle + }, versionStateTitle); + } + render() { + const { + connectDragSource, + element, + type, + areaId, + previewExpanded, + simple, + disableTooltip, + activeTab, + expandable, + ElementActionsComponent, + handleEditTabsClick + } = this.props; + const title = this.getBlockTitle(element, type); + const titleClasses = (0, _classnames.default)({ + 'element-editor-header__title': true, + 'element-editor-header__title--none': !element.title + }); + const expandTitle = _i18n.default._t('ElementHeader.EXPAND', 'Show editable fields'); + const containerClasses = (0, _classnames.default)('element-editor-header', { + 'element-editor-header--simple': simple + }); + const iconContainerClasses = (0, _classnames.default)('element-editor-header__icon-container', { + 'element-editor-header__icon-container--broken': type.broken + }); + const expandCaretClasses = (0, _classnames.default)('element-editor-header__expand', { + 'font-icon-right-open-big': !expandable, + 'font-icon-up-open-big': expandable && previewExpanded, + 'font-icon-down-open-big': expandable && !previewExpanded + }); + const blockIconId = `element-icon-${element.id}`; + const content = _react.default.createElement("div", { + className: containerClasses + }, _react.default.createElement("div", { + className: "element-editor-header__drag-handle" + }, _react.default.createElement("i", { + className: "font-icon-drag-handle" + })), _react.default.createElement("div", { + className: "element-editor-header__info" + }, _react.default.createElement("div", { + className: iconContainerClasses + }, _react.default.createElement("i", { + className: type.icon, + id: blockIconId + }), this.renderVersionedStateMessage(), !type.broken && !simple && _react.default.createElement(_reactstrap.Tooltip, { + placement: "top", + isOpen: this.state.tooltipOpen && !disableTooltip, + target: blockIconId, + toggle: this.toggle + }, type.title)), _react.default.createElement("h3", { + className: titleClasses + }, title), this.renderStatusBadge()), !simple && _react.default.createElement("div", { + className: "element-editor-header__actions" + }, _react.default.createElement("div", { + role: "none", + onClick: event => event.stopPropagation() + }, _react.default.createElement(ElementActionsComponent, { + element: element, + type: type, + areaId: areaId, + activeTab: activeTab, + editTabs: type.editTabs, + handleEditTabsClick: handleEditTabsClick, + expandable: expandable + })), !type.broken && _react.default.createElement("i", { + className: expandCaretClasses, + title: expandTitle + }))); + if (previewExpanded) { + return connectDragSource(content); + } + return content; + } +} +exports.Component = Header; +Header.propTypes = { + element: _elementType.elementType.isRequired, + type: _elementTypeType.elementTypeType.isRequired, + areaId: _propTypes.default.number, + activeTab: _propTypes.default.string, + simple: _propTypes.default.bool, + ElementActionsComponent: _propTypes.default.elementType, + previewExpanded: _propTypes.default.bool, + disableTooltip: _propTypes.default.bool, + connectDragSource: _propTypes.default.func.isRequired, + connectDragPreview: _propTypes.default.func.isRequired, + onDragEnd: _propTypes.default.func +}; +Header.defaultProps = { + expandable: true +}; +var _default = exports["default"] = (0, _redux.compose)((0, _reactDnd.DragSource)('element', _dragHelpers.elementDragSource, connector => ({ + connectDragSource: connector.dragSource(), + connectDragPreview: connector.dragPreview() +})), (0, _Injector.inject)(['ElementActions'], ElementActionsComponent => ({ + ElementActionsComponent +}), () => 'ElementEditor.ElementList.Element'))(Header); + +/***/ }), + +/***/ "./client/src/components/ElementEditor/HoverBar.js": +/*!*********************************************************!*\ + !*** ./client/src/components/ElementEditor/HoverBar.js ***! + \*********************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = exports.Component = void 0; +var _react = _interopRequireWildcard(__webpack_require__(/*! react */ "react")); +var _propTypes = _interopRequireDefault(__webpack_require__(/*! prop-types */ "prop-types")); +var _Injector = __webpack_require__(/*! lib/Injector */ "lib/Injector"); +var _elementTypeType = __webpack_require__(/*! types/elementTypeType */ "./client/src/types/elementTypeType.js"); +var _i18n = _interopRequireDefault(__webpack_require__(/*! i18n */ "i18n")); +var _prefixClassNames = _interopRequireDefault(__webpack_require__(/*! ../../lib/prefixClassNames */ "./client/src/lib/prefixClassNames.js")); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } +function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } +const classNames = (0, _prefixClassNames.default)('element-editor__hover-bar'); +function StatelessHoverBar(_ref) { + let { + AddElementPopoverComponent, + elementTypes, + elementId, + areaId, + popoverOpen, + onToggle + } = _ref; + const lineClasses = `${classNames('-line')} font-icon-plus-circled`; + const label = _i18n.default._t('ElementAddNewButton.ADD_BLOCK', 'Add block'); + const btnProps = { + className: classNames('-area', { + '-area--focus': popoverOpen + }), + onClick: onToggle, + 'aria-label': label, + title: label, + id: `AddBlockHoverBarArea_${areaId}_${elementId}` + }; + return _react.default.createElement("div", { + className: classNames(''), + id: `AddBlockHoverBar_${areaId}_${elementId}` + }, _react.default.createElement("button", btnProps, _react.default.createElement("span", { + className: classNames('-area-inner') + }, _react.default.createElement("span", { + className: lineClasses + }))), _react.default.createElement(AddElementPopoverComponent, { + placement: "bottom", + target: `AddBlockHoverBarArea_${areaId}_${elementId}`, + isOpen: popoverOpen, + elementTypes: elementTypes, + toggle: onToggle, + container: `#AddBlockHoverBar_${areaId}_${elementId}`, + areaId: areaId, + insertAfterElement: elementId + })); +} +class HoverBar extends _react.Component { + constructor(props) { + super(props); + this.toggle = this.toggle.bind(this); + this.state = { + popoverOpen: false + }; + } + toggle() { + this.setState(prevState => ({ + popoverOpen: !prevState.popoverOpen + })); + } + render() { + const props = { + ...this.state, + ...this.props, + onToggle: this.toggle + }; + return _react.default.createElement(StatelessHoverBar, props); + } +} +exports.Component = HoverBar; +HoverBar.propTypes = { + elementTypes: _propTypes.default.arrayOf(_elementTypeType.elementTypeType).isRequired, + elementId: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.number]).isRequired, + areaId: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]).isRequired +}; +var _default = exports["default"] = (0, _Injector.inject)(['AddElementPopover'], AddElementPopoverComponent => ({ + AddElementPopoverComponent +}), () => 'ElementEditor.ElementList.HoverBar')(HoverBar); + +/***/ }), + +/***/ "./client/src/components/ElementEditor/InlineEditForm.js": +/*!***************************************************************!*\ + !*** ./client/src/components/ElementEditor/InlineEditForm.js ***! + \***************************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = void 0; +var _react = _interopRequireWildcard(__webpack_require__(/*! react */ "react")); +var _propTypes = _interopRequireDefault(__webpack_require__(/*! prop-types */ "prop-types")); +var _classnames = _interopRequireDefault(__webpack_require__(/*! classnames */ "classnames")); +var _FormBuilderLoader = _interopRequireDefault(__webpack_require__(/*! containers/FormBuilderLoader/FormBuilderLoader */ "containers/FormBuilderLoader/FormBuilderLoader")); +var _loadElementSchemaValue = __webpack_require__(/*! state/editor/loadElementSchemaValue */ "./client/src/state/editor/loadElementSchemaValue.js"); +var _i18n = _interopRequireDefault(__webpack_require__(/*! i18n */ "i18n")); +var _loadElementFormStateName = __webpack_require__(/*! state/editor/loadElementFormStateName */ "./client/src/state/editor/loadElementFormStateName.js"); +var _reactRedux = __webpack_require__(/*! react-redux */ "react-redux"); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } +function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } +function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } +class InlineEditForm extends _react.PureComponent { + constructor(props) { + super(props); + this.handleLoadingError = this.handleLoadingError.bind(this); + this.handleSubmit = this.handleSubmit.bind(this); + this.state = { + loadingError: null + }; + } + handleLoadingError() { + const { + jQuery: $ + } = window; + const { + handleLoadingError + } = this.props; + this.setState({ + loadingError: true + }); + $.noticeAdd({ + text: _i18n.default.inject(_i18n.default._t('ElementEditForm.ERROR_NOTIFICATION', 'Error displaying the edit form for this block')), + stay: true, + type: 'notice' + }); + handleLoadingError(); + } + handleSubmit(data, action, submitFn) { + let title = ''; + Object.keys(data).forEach(key => { + if (key.match(/PageElements_[0-9]+_Title/)) { + title = data[key]; + } + }); + return submitFn().then(formSchema => this.props.onFormSchemaSubmitResponse(formSchema, title)); + } + render() { + const { + elementId, + extraClass, + onClick, + onFormInit, + formHasState, + notVisible + } = this.props; + const { + loadingError + } = this.state; + const classNames = (0, _classnames.default)('element-editor-editform', extraClass); + const schemaUrl = (0, _loadElementSchemaValue.loadElementSchemaValue)('schemaUrl', elementId); + const formTag = 'form'; + const formProps = { + formTag, + schemaUrl, + identifier: 'element', + refetchSchemaOnMount: !formHasState, + onLoadingError: this.handleLoadingError, + onSubmit: this.handleSubmit + }; + if (loadingError) { + formProps.loading = false; } + if (typeof onFormInit === 'function') { + formProps.onReduxFormInit = onFormInit; + } + const extraAttrs = {}; + if (notVisible) { + extraAttrs['aria-hidden'] = 'true'; + } + return _react.default.createElement("div", _extends({ + className: classNames, + onClick: onClick, + role: "presentation" + }, extraAttrs), _react.default.createElement(_FormBuilderLoader.default, formProps)); + } +} +InlineEditForm.propTypes = { + extraClass: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.object]), + onClick: _propTypes.default.func, + elementId: _propTypes.default.string, + handleLoadingError: _propTypes.default.func, + onFormSchemaSubmitResponse: _propTypes.default.func, + notVisible: _propTypes.default.bool +}; +function mapStateToProps(state, ownProps) { + const formName = (0, _loadElementFormStateName.loadElementFormStateName)(ownProps.elementId); + return { + formHasState: state.form.formState && state.form.formState.element && !!state.form.formState.element[formName] + }; +} +var _default = exports["default"] = (0, _reactRedux.connect)(mapStateToProps)(InlineEditForm); + +/***/ }), + +/***/ "./client/src/components/ElementEditor/Summary.js": +/*!********************************************************!*\ + !*** ./client/src/components/ElementEditor/Summary.js ***! + \********************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = void 0; +var _react = _interopRequireWildcard(__webpack_require__(/*! react */ "react")); +var _propTypes = _interopRequireDefault(__webpack_require__(/*! prop-types */ "prop-types")); +var _classnames = _interopRequireDefault(__webpack_require__(/*! classnames */ "classnames")); +var _i18n = _interopRequireDefault(__webpack_require__(/*! i18n */ "i18n")); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } +function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } +class Summary extends _react.PureComponent { + render() { + const { + fileUrl, + fileTitle, + content, + broken + } = this.props; + const noContent = _i18n.default._t('ElementSummary.NO_PREVIEW', 'No preview available'); + const summaryClassNames = (0, _classnames.default)('element-editor-summary__content', { + 'element-editor-summary__content--broken': broken + }); + return _react.default.createElement("div", { + className: "element-editor-summary" + }, fileUrl && _react.default.createElement("img", { + className: "element-editor-summary__thumbnail-image", + src: fileUrl, + alt: fileTitle + }), (content || !fileUrl) && _react.default.createElement("p", { + className: summaryClassNames + }, content || noContent)); } } -`,i=t.config={options(e){let{recordId:t,limit:n,page:r}=e;return{variables:{limit:n,offset:((r||1)-1)*n,block_id:t}}},props(e){let{data:{error:t,refetch:n,readOneBlock:r,loading:o},ownProps:{actions:a={versions:{}},limit:l,recordId:i}}=e;const s=r||null;return{loading:o||!s,versions:s,graphQLErrors:t&&t.graphQLErrors&&t.graphQLErrors.map((e=>e.message)),actions:{...a,versions:{...s,goToPage(e){n({offset:((e||1)-1)*l,limit:l,block_id:i})}}}}}};t.default=(0,o.graphql)(l,i)},8633:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.mutation=t.default=t.config=void 0;var r,o=n(708),a=(r=n(7284))&&r.__esModule?r:{default:r};const l=t.mutation=a.default` -mutation revertBlockToVersion($id:ID!, $fromStage:VersionedStage!, $toStage:VersionedStage!, $fromVersion:Int!) { - copyBlockToStage(input: { - id: $id - fromVersion: $fromVersion - fromStage: $fromStage - toStage: $toStage - }) { - id +Summary.defaultProps = {}; +Summary.propTypes = { + content: _propTypes.default.string, + fileUrl: _propTypes.default.string, + fileTitle: _propTypes.default.string, + broken: _propTypes.default.bool +}; +var _default = exports["default"] = Summary; + +/***/ }), + +/***/ "./client/src/components/ElementEditor/Toolbar.js": +/*!********************************************************!*\ + !*** ./client/src/components/ElementEditor/Toolbar.js ***! + \********************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = void 0; +var _react = _interopRequireWildcard(__webpack_require__(/*! react */ "react")); +var _propTypes = _interopRequireDefault(__webpack_require__(/*! prop-types */ "prop-types")); +var _Injector = __webpack_require__(/*! lib/Injector */ "lib/Injector"); +var _elementTypeType = __webpack_require__(/*! types/elementTypeType */ "./client/src/types/elementTypeType.js"); +var _reactDnd = __webpack_require__(/*! react-dnd */ "react-dnd"); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } +function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } +class Toolbar extends _react.PureComponent { + render() { + const { + AddNewButtonComponent, + elementTypes, + areaId, + connectDropTarget + } = this.props; + return connectDropTarget(_react.default.createElement("div", { + className: "element-editor__toolbar" + }, _react.default.createElement(AddNewButtonComponent, { + elementTypes: elementTypes, + areaId: areaId + }))); } } -`,i=t.config={props:e=>{let{mutate:t,ownProps:{actions:n}}=e;return{actions:{...n,revertToVersion:(e,n,r,o)=>t({variables:{id:e,fromVersion:n,fromStage:r,toStage:o}})}}},options:{refetchQueries:["ReadHistoryViewerBlock"]}};t.default=(0,o.graphql)(l,i)},455:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.elementType=void 0;var r,o=(r=n(6935))&&r.__esModule?r:{default:r};t.elementType=o.default.shape({id:o.default.string.isRequired,title:o.default.string,blockSchema:o.default.object,inlineEditable:o.default.bool,published:o.default.bool,liveVersion:o.default.bool,version:o.default.number})},9791:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.elementTypeType=void 0;var r,o=(r=n(6935))&&r.__esModule?r:{default:r};t.elementTypeType=o.default.shape({name:o.default.string,title:o.default.string,icon:o.default.string,inlineEditable:o.default.bool,editTabs:o.default.arrayOf(o.default.shape({title:o.default.string,name:o.default.string})),config:o.default.object})},8695:function(e){e.exports=ApolloClient},708:function(e){e.exports=ApolloClientReactHoc},6177:function(e){e.exports=Config},2623:function(e){e.exports=FieldHolder},55:function(e){e.exports=FormBuilderLoader},7284:function(e){e.exports=GraphQLTag},5207:function(e){e.exports=Injector},6935:function(e){e.exports=PropTypes},1594:function(e){e.exports=React},1820:function(e){e.exports=ReactDND},8724:function(e){e.exports=ReactDNDHtml5Backend},4518:function(e){e.exports=ReactDom},5145:function(e){e.exports=ReactDomClient},9040:function(e){e.exports=ReactRedux},3556:function(e){e.exports=Reactstrap},9367:function(e){e.exports=Redux},5381:function(e){e.exports=ReduxForm},5034:function(e){e.exports=TabsActions},8918:function(e){e.exports=ToastsActions},9077:function(e){e.exports=UnsavedFormsActions},6923:function(e){e.exports=classnames},5815:function(e){e.exports=i18n},1669:function(e){e.exports=jQuery},5799:function(e){e.exports=withDragDropContext}},t={};function n(r){var o=t[r];if(void 0!==o)return o.exports;var a=t[r]={exports:{}};return e[r](a,a.exports,n),a.exports}n(51),n(2038)}(); \ No newline at end of file +Toolbar.defaultProps = {}; +Toolbar.propTypes = { + elementTypes: _propTypes.default.arrayOf(_elementTypeType.elementTypeType).isRequired, + areaId: _propTypes.default.number.isRequired, + AddNewButtonComponent: _propTypes.default.elementType.isRequired, + connectDropTarget: _propTypes.default.func.isRequired, + onDragOver: _propTypes.default.func, + onDragDrop: _propTypes.default.func +}; +const toolbarTarget = { + hover(props) { + const { + onDragOver + } = props; + if (onDragOver) { + onDragOver(); + } + } +}; +var _default = exports["default"] = (0, _reactDnd.DropTarget)('element', toolbarTarget, connect => ({ + connectDropTarget: connect.dropTarget() +}))((0, _Injector.inject)(['ElementAddNewButton'], AddNewButtonComponent => ({ + AddNewButtonComponent +}), () => 'ElementEditor.ElementToolbar')(Toolbar)); + +/***/ }), + +/***/ "./client/src/components/HistoricElementView/HistoricElementView.js": +/*!**************************************************************************!*\ + !*** ./client/src/components/HistoricElementView/HistoricElementView.js ***! + \**************************************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = void 0; +var _react = _interopRequireDefault(__webpack_require__(/*! react */ "react")); +var _i18n = _interopRequireDefault(__webpack_require__(/*! i18n */ "i18n")); +var _classnames = _interopRequireDefault(__webpack_require__(/*! classnames */ "classnames")); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +const ElementalAreaHistoryFactory = FieldGroup => class HistoricElementView extends FieldGroup { + getClassName() { + const classlist = [super.getClassName()]; + if (this.props.data.ElementID) { + classlist.unshift('elemental-area__element--historic-inner'); + } + return (0, _classnames.default)(classlist); + } + render() { + const legend = this.getLegend(); + const Tag = this.props.data.tag || 'div'; + const classNames = this.getClassName(); + const { + data + } = this.props; + if (!data.ElementID) { + return super.render(); + } + return _react.default.createElement(Tag, { + className: classNames + }, legend, _react.default.createElement("div", { + className: "elemental-preview elemental-preview--historic" + }, data.ElementEditLink && _react.default.createElement("a", { + className: "elemental-preview__link", + href: data.ElementEditLink + }, _react.default.createElement("span", { + className: "elemental-preview__link-text" + }, _i18n.default._t('HistoricElementView.VIEW_BLOCK_HISTORY', 'Block history')), _react.default.createElement("i", { + className: "font-icon-angle-right btn--icon-lg elemental-preview__link-caret" + })), _react.default.createElement("div", { + className: "elemental-preview__icon" + }, _react.default.createElement("i", { + className: data.ElementIcon + })), _react.default.createElement("div", { + className: "elemental-preview__detail" + }, _react.default.createElement("h3", null, data.ElementTitle, " ", _react.default.createElement("small", null, data.ElementType)))), this.props.children); + } +}; +var _default = exports["default"] = ElementalAreaHistoryFactory; + +/***/ }), + +/***/ "./client/src/components/TextCheckboxGroupField/TextCheckboxGroupField.js": +/*!********************************************************************************!*\ + !*** ./client/src/components/TextCheckboxGroupField/TextCheckboxGroupField.js ***! + \********************************************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = void 0; +var _react = _interopRequireDefault(__webpack_require__(/*! react */ "react")); +var _reactstrap = __webpack_require__(/*! reactstrap */ "reactstrap"); +var _FieldHolder = _interopRequireDefault(__webpack_require__(/*! components/FieldHolder/FieldHolder */ "components/FieldHolder/FieldHolder")); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +const TextCheckboxGroupField = props => { + const { + children + } = props; + const childrenWithProps = _react.default.Children.toArray(_react.default.Children.map(children, (child, index) => { + const additionalProps = {}; + if (index === 0) { + additionalProps.id = props.id; + additionalProps.title = null; + } else if (index === 1) { + additionalProps.noHolder = true; + } + return _react.default.cloneElement(child, additionalProps); + })); + if (props.readOnly) { + return _react.default.createElement("div", { + className: "text-checkbox-group-field--read-only" + }, childrenWithProps); + } + if (childrenWithProps.length === 1) { + return childrenWithProps[0]; + } + return _react.default.createElement(_reactstrap.InputGroup, { + className: "text-checkbox-group-field" + }, childrenWithProps[0], _react.default.createElement(_reactstrap.InputGroupAddon, { + addonType: "append" + }, _react.default.createElement(_reactstrap.InputGroupText, null, childrenWithProps[1]))); +}; +var _default = exports["default"] = (0, _FieldHolder.default)(TextCheckboxGroupField); + +/***/ }), + +/***/ "./client/src/legacy/ElementEditor/entwine.js": +/*!****************************************************!*\ + !*** ./client/src/legacy/ElementEditor/entwine.js ***! + \****************************************************/ +/***/ (function(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { + + + +var _jquery = _interopRequireDefault(__webpack_require__(/*! jquery */ "jquery")); +var _react = _interopRequireDefault(__webpack_require__(/*! react */ "react")); +var _client = __webpack_require__(/*! react-dom/client */ "react-dom/client"); +var _Injector = __webpack_require__(/*! lib/Injector */ "lib/Injector"); +var _elementConfig = __webpack_require__(/*! state/editor/elementConfig */ "./client/src/state/editor/elementConfig.js"); +var _reduxForm = __webpack_require__(/*! redux-form */ "redux-form"); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +const resetStores = () => { + setTimeout(() => { + const { + store + } = window.ss; + if (!store) { + return; + } + store.dispatch((0, _reduxForm.destroy)(...Object.keys(store.getState().form.formState.element || {}).map(name => `element.${name}`))); + }, 0); +}; +_jquery.default.entwine('ss', $ => { + $('.js-injector-boot .element-editor__container').entwine({ + ReactRoot: null, + AreaIDsSharedObject: {}, + Increment: 0, + onmatch() { + const context = {}; + const ElementEditorComponent = (0, _Injector.loadComponent)('ElementEditor', context); + const schemaData = this.data('schema'); + const elementTypes = (0, _elementConfig.getConfig)().elementTypes; + const areaID = schemaData['elemental-area-id']; + const areaIDsSharedObject = this.getAreaIDsSharedObject(); + if (!areaIDsSharedObject.hasOwnProperty(areaID)) { + areaIDsSharedObject[areaID] = { + entwineResolve: null, + setState: null + }; + } + const props = { + areaId: areaID, + allowedElements: schemaData['allowed-elements'], + elementTypes, + sharedObject: areaIDsSharedObject[areaID] + }; + let root = this.getReactRoot(); + if (!root) { + root = (0, _client.createRoot)(this[0]); + this.setReactRoot(root); + } + root.render(_react.default.createElement(ElementEditorComponent, props)); + }, + onunmatch() { + if (!$('.cms-edit-form').data('hasValidationErrors')) { + resetStores(); + } + this.unmountComponent(); + }, + unmountComponent() { + const root = this.getReactRoot(); + if (root) { + root.unmount(); + this.setReactRoot(null); + } + }, + 'from .cms-edit-form': { + onbeforesubmitform(event, data) { + if (!data) { + return; + } + let entwineResolve; + const entwinePromise = new Promise(resolve => { + entwineResolve = resolve; + }); + data.promises.push(entwinePromise); + data.onAjaxSuccessCallbacks.push(this.unmountComponent.bind(this)); + const areaID = this.data('schema')['elemental-area-id']; + const areaIDsSharedObject = this.getAreaIDsSharedObject(); + const sharedObject = areaIDsSharedObject[areaID]; + const increment = this.getIncrement() + 1; + this.setIncrement(increment); + sharedObject.entwineResolve = entwineResolve; + sharedObject.setState({ + saveAllElements: true, + increment + }); + }, + onaftersubmitform(event, data) { + const validationResultPjax = JSON.parse(data.xhr.responseText).ValidationResult; + const validationResult = JSON.parse(validationResultPjax.replace(/<\/?script[^>]*?>/g, '')); + if (validationResult.isValid) { + $('.cms-edit-form').data('hasValidationErrors', false); + resetStores(); + } else { + $('.cms-edit-form').data('hasValidationErrors', true); + } + } + } + }); + $('.js-injector-boot .element-editor__container .element-form-dirty-state').entwine({ + onmatch() { + $('.cms-edit-form').trigger('change'); + }, + onunmatch() { + $('.cms-edit-form').trigger('change'); + } + }); + $('.cms-edit-form').entwine({ + getChangeTrackerOptions() { + const isDefault = this.entwineData('ChangeTrackerOptions') === undefined; + let opts = this._super(); + if (isDefault) { + opts = $.extend({}, opts); + opts.ignoreFieldSelector += ', .elementalarea :input:not(.element-form-dirty-state)'; + this.setChangeTrackerOptions(opts); + } + return opts; + } + }); +}); + +/***/ }), + +/***/ "./client/src/lib/dragHelpers.js": +/*!***************************************!*\ + !*** ./client/src/lib/dragHelpers.js ***! + \***************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.isOverTop = exports.getDragIndicatorIndex = exports.elementDragSource = void 0; +var _reactDom = __webpack_require__(/*! react-dom */ "react-dom"); +const isOverTop = (monitor, component) => { + const clientOffset = monitor.getClientOffset(); + const componentRect = (0, _reactDom.findDOMNode)(component).getBoundingClientRect(); + return clientOffset.y < componentRect.y + componentRect.height / 2; +}; +exports.isOverTop = isOverTop; +const getDragIndicatorIndex = (items, dragTarget, draggedItem, dragSpot) => { + if (dragTarget === null || !draggedItem) { + return null; + } + let targetIndex = dragTarget ? items.findIndex(element => element === dragTarget) : 0; + const sourceIndex = items.findIndex(item => item === draggedItem); + if (dragSpot === 'bottom') { + targetIndex += 1; + } + if (sourceIndex === targetIndex || sourceIndex + 1 === targetIndex) { + return null; + } + return targetIndex; +}; +exports.getDragIndicatorIndex = getDragIndicatorIndex; +const elementDragSource = exports.elementDragSource = { + beginDrag(props) { + return props.element; + }, + endDrag(props, monitor) { + const { + onDragEnd + } = props; + const dropResult = monitor.getDropResult(); + if (!onDragEnd || !dropResult || !dropResult.dropAfterID) { + return; + } + const itemID = monitor.getItem().id; + const { + dropAfterID + } = dropResult; + if (itemID !== dropAfterID) { + onDragEnd(itemID, dropAfterID); + } + } +}; + +/***/ }), + +/***/ "./client/src/lib/prefixClassNames.js": +/*!********************************************!*\ + !*** ./client/src/lib/prefixClassNames.js ***! + \********************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = void 0; +var _classnames = _interopRequireDefault(__webpack_require__(/*! classnames */ "classnames")); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +const prefixClassNames = cssPrefix => function () { + const prefix = str => `${cssPrefix}${str}`; + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + const prefixArgs = args.map(arg => { + if (!arg && arg !== '') { + return false; + } + if (typeof arg === 'object') { + return Array.isArray(arg) ? arg.map(prefix) : Object.entries(arg).reduce((accumulator, _ref) => { + let [key, value] = _ref; + return Object.assign({}, accumulator, { + [prefix(key)]: value + }); + }, {}); + } + return prefix(arg); + }); + return (0, _classnames.default)(...prefixArgs); +}; +var _default = exports["default"] = prefixClassNames; + +/***/ }), + +/***/ "./client/src/state/editor/elementConfig.js": +/*!**************************************************!*\ + !*** ./client/src/state/editor/elementConfig.js ***! + \**************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.getElementTypeConfig = exports.getConfig = void 0; +var _Config = _interopRequireDefault(__webpack_require__(/*! lib/Config */ "lib/Config")); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +const getConfig = () => _Config.default.getSection('DNADesign\\Elemental\\Controllers\\ElementalAreaController'); +exports.getConfig = getConfig; +const getElementTypeConfig = function (element) { + let typeConfig = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + const elementType = element.blockSchema.typeName; + const types = Array.isArray(typeConfig) ? typeConfig : getConfig().elementTypes; + let type = types.find(value => value.class === elementType || value.name === elementType); + if (element.obsoleteClassName) { + type = Object.assign({ + obsoleteClassName: element.obsoleteClassName + }, type); + Object.preventExtensions(type); + } + return type; +}; +exports.getElementTypeConfig = getElementTypeConfig; + +/***/ }), + +/***/ "./client/src/state/editor/loadElementFormStateName.js": +/*!*************************************************************!*\ + !*** ./client/src/state/editor/loadElementFormStateName.js ***! + \*************************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.loadElementFormStateName = void 0; +var _Config = _interopRequireDefault(__webpack_require__(/*! lib/Config */ "lib/Config")); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +const loadElementFormStateName = function () { + let elementId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; + const sectionKey = 'DNADesign\\Elemental\\Controllers\\ElementalAreaController'; + const section = _Config.default.getSection(sectionKey); + const formNameTemplate = section.form.elementForm.formNameTemplate; + if (elementId) { + return formNameTemplate.replace('{id}', elementId); + } + return formNameTemplate; +}; +exports.loadElementFormStateName = loadElementFormStateName; + +/***/ }), + +/***/ "./client/src/state/editor/loadElementSchemaValue.js": +/*!***********************************************************!*\ + !*** ./client/src/state/editor/loadElementSchemaValue.js ***! + \***********************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.loadElementSchemaValue = void 0; +var _Config = _interopRequireDefault(__webpack_require__(/*! lib/Config */ "lib/Config")); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +const loadElementSchemaValue = function (key) { + let elementId = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + const sectionKey = 'DNADesign\\Elemental\\Controllers\\ElementalAreaController'; + const section = _Config.default.getSection(sectionKey); + const schemaValue = section.form.elementForm[key] || ''; + if (elementId) { + return `${schemaValue}/${elementId}`; + } + return schemaValue; +}; +exports.loadElementSchemaValue = loadElementSchemaValue; + +/***/ }), + +/***/ "./client/src/state/history/revertToBlockVersionRequest.js": +/*!*****************************************************************!*\ + !*** ./client/src/state/history/revertToBlockVersionRequest.js ***! + \*****************************************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = void 0; +var _react = _interopRequireDefault(__webpack_require__(/*! react */ "react")); +var _Backend = _interopRequireDefault(__webpack_require__(/*! lib/Backend */ "lib/Backend")); +var _elementConfig = __webpack_require__(/*! state/editor/elementConfig */ "./client/src/state/editor/elementConfig.js"); +var _Config = _interopRequireDefault(__webpack_require__(/*! lib/Config */ "lib/Config")); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +const revertToBlockVersionRequest = HistoryViewerVersionDetailComponent => props => { + const newProps = { + ...props + }; + if (!newProps.hasOwnProperty('actions')) { + newProps.actions = {}; + } + newProps.actions.revertToVersion = (id, fromVersion, fromStage, toStage) => { + const url = `${(0, _elementConfig.getConfig)().controllerLink.replace(/\/$/, '')}/api/revert`; + return _Backend.default.post(url, { + ID: id, + fromVersion, + fromStage, + toStage + }, { + SecurityID: _Config.default.get('SecurityID') + }); + }; + return _react.default.createElement(HistoryViewerVersionDetailComponent, newProps); +}; +var _default = exports["default"] = revertToBlockVersionRequest; + +/***/ }), + +/***/ "./client/src/types/elementType.js": +/*!*****************************************!*\ + !*** ./client/src/types/elementType.js ***! + \*****************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.elementType = void 0; +var _propTypes = _interopRequireDefault(__webpack_require__(/*! prop-types */ "prop-types")); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +const elementType = exports.elementType = _propTypes.default.shape({ + id: _propTypes.default.string.isRequired, + title: _propTypes.default.string, + blockSchema: _propTypes.default.object, + inlineEditable: _propTypes.default.bool, + published: _propTypes.default.bool, + liveVersion: _propTypes.default.bool, + version: _propTypes.default.number +}); + +/***/ }), + +/***/ "./client/src/types/elementTypeType.js": +/*!*********************************************!*\ + !*** ./client/src/types/elementTypeType.js ***! + \*********************************************/ +/***/ (function(__unused_webpack_module, exports, __webpack_require__) { + + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.elementTypeType = void 0; +var _propTypes = _interopRequireDefault(__webpack_require__(/*! prop-types */ "prop-types")); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +const elementTypeType = exports.elementTypeType = _propTypes.default.shape({ + name: _propTypes.default.string, + title: _propTypes.default.string, + icon: _propTypes.default.string, + inlineEditable: _propTypes.default.bool, + editTabs: _propTypes.default.arrayOf(_propTypes.default.shape({ + title: _propTypes.default.string, + name: _propTypes.default.string + })), + config: _propTypes.default.object +}); + +/***/ }), + +/***/ "lib/Backend": +/*!**************************!*\ + !*** external "Backend" ***! + \**************************/ +/***/ (function(module) { + +module.exports = Backend; + +/***/ }), + +/***/ "lib/Config": +/*!*************************!*\ + !*** external "Config" ***! + \*************************/ +/***/ (function(module) { + +module.exports = Config; + +/***/ }), + +/***/ "components/FieldHolder/FieldHolder": +/*!******************************!*\ + !*** external "FieldHolder" ***! + \******************************/ +/***/ (function(module) { + +module.exports = FieldHolder; + +/***/ }), + +/***/ "containers/FormBuilderLoader/FormBuilderLoader": +/*!************************************!*\ + !*** external "FormBuilderLoader" ***! + \************************************/ +/***/ (function(module) { + +module.exports = FormBuilderLoader; + +/***/ }), + +/***/ "lib/Injector": +/*!***************************!*\ + !*** external "Injector" ***! + \***************************/ +/***/ (function(module) { + +module.exports = Injector; + +/***/ }), + +/***/ "prop-types": +/*!****************************!*\ + !*** external "PropTypes" ***! + \****************************/ +/***/ (function(module) { + +module.exports = PropTypes; + +/***/ }), + +/***/ "react": +/*!************************!*\ + !*** external "React" ***! + \************************/ +/***/ (function(module) { + +module.exports = React; + +/***/ }), + +/***/ "react-dnd": +/*!***************************!*\ + !*** external "ReactDND" ***! + \***************************/ +/***/ (function(module) { + +module.exports = ReactDND; + +/***/ }), + +/***/ "react-dnd-html5-backend": +/*!***************************************!*\ + !*** external "ReactDNDHtml5Backend" ***! + \***************************************/ +/***/ (function(module) { + +module.exports = ReactDNDHtml5Backend; + +/***/ }), + +/***/ "react-dom": +/*!***************************!*\ + !*** external "ReactDom" ***! + \***************************/ +/***/ (function(module) { + +module.exports = ReactDom; + +/***/ }), + +/***/ "react-dom/client": +/*!*********************************!*\ + !*** external "ReactDomClient" ***! + \*********************************/ +/***/ (function(module) { + +module.exports = ReactDomClient; + +/***/ }), + +/***/ "react-redux": +/*!*****************************!*\ + !*** external "ReactRedux" ***! + \*****************************/ +/***/ (function(module) { + +module.exports = ReactRedux; + +/***/ }), + +/***/ "reactstrap": +/*!*****************************!*\ + !*** external "Reactstrap" ***! + \*****************************/ +/***/ (function(module) { + +module.exports = Reactstrap; + +/***/ }), + +/***/ "redux": +/*!************************!*\ + !*** external "Redux" ***! + \************************/ +/***/ (function(module) { + +module.exports = Redux; + +/***/ }), + +/***/ "redux-form": +/*!****************************!*\ + !*** external "ReduxForm" ***! + \****************************/ +/***/ (function(module) { + +module.exports = ReduxForm; + +/***/ }), + +/***/ "state/tabs/TabsActions": +/*!******************************!*\ + !*** external "TabsActions" ***! + \******************************/ +/***/ (function(module) { + +module.exports = TabsActions; + +/***/ }), + +/***/ "state/toasts/ToastsActions": +/*!********************************!*\ + !*** external "ToastsActions" ***! + \********************************/ +/***/ (function(module) { + +module.exports = ToastsActions; + +/***/ }), + +/***/ "state/unsavedForms/UnsavedFormsActions": +/*!**************************************!*\ + !*** external "UnsavedFormsActions" ***! + \**************************************/ +/***/ (function(module) { + +module.exports = UnsavedFormsActions; + +/***/ }), + +/***/ "classnames": +/*!*****************************!*\ + !*** external "classnames" ***! + \*****************************/ +/***/ (function(module) { + +module.exports = classnames; + +/***/ }), + +/***/ "i18n": +/*!***********************!*\ + !*** external "i18n" ***! + \***********************/ +/***/ (function(module) { + +module.exports = i18n; + +/***/ }), + +/***/ "jquery": +/*!*************************!*\ + !*** external "jQuery" ***! + \*************************/ +/***/ (function(module) { + +module.exports = jQuery; + +/***/ }), + +/***/ "lib/withDragDropContext": +/*!**************************************!*\ + !*** external "withDragDropContext" ***! + \**************************************/ +/***/ (function(module) { + +module.exports = withDragDropContext; + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. +!function() { +/*!**************************************!*\ + !*** ./client/src/bundles/bundle.js ***! + \**************************************/ + + +__webpack_require__(/*! legacy/ElementEditor/entwine */ "./client/src/legacy/ElementEditor/entwine.js"); +__webpack_require__(/*! boot */ "./client/src/boot/index.js"); +}(); +/******/ })() +; +//# sourceMappingURL=bundle.js.map \ No newline at end of file diff --git a/client/dist/styles/bundle.css b/client/dist/styles/bundle.css index 3102b087..8c1bda69 100644 --- a/client/dist/styles/bundle.css +++ b/client/dist/styles/bundle.css @@ -1 +1,492 @@ -.elemental-edit{display:flex;color:inherit}.elemental-edit:hover,.elemental-edit:focus{text-decoration:none;color:inherit}.elemental-editor .col-EditorPreview{padding-left:0}.elemental-preview__detail{display:inline-block;margin-left:.76925rem;margin-top:1px}.elemental-preview__detail h3{font-weight:400;line-height:26px;margin:0;-webkit-font-smoothing:antialiased}.elemental-preview__detail p{align-items:center;display:flex;margin-bottom:0;margin-top:6px}.elemental-preview__detail small{color:#566b8d;font-size:13px}.elemental-preview__thumbnail-image{margin-right:.76925rem}.elemental-preview__thumbnail-image img{border-radius:.192rem}.elemental-preview__thumbnail-image--placeholder{border-radius:0;height:36px;margin-left:-4px}.elemental-preview__icon{color:#566b8d;display:inline-block;flex-direction:row;font-size:2.3rem;width:28px;vertical-align:top;margin-top:-1px}.ss-gridfield-orderable.elemental-editor .col-reorder .handle{opacity:.5;padding:22px 0 0}.ss-gridfield-orderable.elemental-editor .col-reorder .handle .icon{font-size:1.3em}.elemental-editor .ss-gridfield-item:hover .handle{opacity:1}.elemental-editor .grid-field__table{margin-bottom:12px}@media(max-width: 991.98px){.elemental-editor .grid-field__table .col-EditorPreview{display:table-cell}}.elemental-report__grid-field .element-editor-header__version-state{bottom:9px;left:14px}.element-editor .form-group:nth-child(1n){display:block}@media(min-width: 992px){.element-editor .form-group:nth-child(1n) .form__field-label,.element-editor .form-group:nth-child(1n) .form__field-holder{flex:0 0 83.33333333%;max-width:83.33333333%;margin-left:0}}.elemental-block__history-tab{margin-top:-1.5385rem}.cms-edit-form .fieldgroup.elemental-area__element--historic{margin-left:0;margin-right:0}.cms-edit-form .fieldgroup.elemental-area__element--historic.form-group{border-top:1px solid #dbe0e9}.cms-edit-form .fieldgroup.elemental-area__element--historic .form__field-holder{flex:0 0 100%;max-width:100%}.elemental-preview{line-height:20px}.elemental-preview--historic{margin-bottom:1rem}.elemental-preview__link{float:right;margin-top:4px}.elemental-preview__link:hover{text-decoration:none}.elemental-preview__link:hover .elemental-preview__link-text{text-decoration:underline}.elemental-preview__link-caret{display:block;float:right;margin-top:-2px;margin-left:2px}div.elemental-area__element--historic.elemental-area__element--historic-inner{background:rgba(0,0,0,0);border:0;padding-left:0;padding-right:0;padding-top:1.5385rem}.elemental-area--read-only{border-bottom:1px solid #dbe0e9;margin:2.30775rem -1.5385rem}.history-viewer__version-detail fieldset{overflow:visible}.elemental-report__grid-field .ss-gridfield-item td:first-child{width:1px}.elemental-report__grid-field .col-Icon{font-size:1.5rem}.elemental-report__grid-field .element-item--draft,.elemental-report__grid-field .element-item--modified{bottom:8px;left:14px;height:6px;width:6px}.textcheckboxgroup .input-group-append .form-check-input{margin-left:0;position:relative}.element-editor .action-menu .dropdown-item.disabled{font-style:italic;pointer-events:initial;cursor:not-allowed;color:#6f84a7}.elemental-editor__add-new-block-control{width:20rem}.elemental-editor__add-new-block-control a{line-height:1.85em}.element-editor__element{border-bottom:1px solid #dbe0e9;color:inherit;cursor:pointer;min-height:8rem;padding:.9231rem 1.5385rem 1.8462rem}.element-editor__element:focus,.element-editor__element:hover{box-shadow:0 2px 5px 0 rgba(0,0,0,.1),0 2px 10px 0 rgba(0,0,0,.1);outline-width:0}.element-editor__element:hover .element-editor-header__drag-handle{display:block}.element-editor__element--broken{cursor:default}.element-editor__element--dragging{opacity:.3;cursor:grabbing}.elemental-editor-list{background-color:#fff;border-top:1px solid #dbe0e9;margin-left:-1.5385rem;margin-right:-1.5385rem;min-height:calc(8rem + 1px);position:relative;margin-bottom:1.5385rem}.elemental-editor-list--empty{border-bottom:1px solid #dbe0e9;display:flex;align-items:center;justify-content:center}.element-editor-editform{margin-top:.76925rem;cursor:auto;margin-bottom:-1rem}.element-editor-editform .mce-tinymce{box-sizing:border-box}.element-editor-editform__form{width:100%}.element-editor-editform .element-editor-editform__form .form-group .form__field-holder{flex:1 0 100%;max-width:900px}.element-editor-editform--rendered-not-visible{position:absolute;top:-9999px;left:-9999px}.element-editor-editform .btn--hidden{display:none}.element-editor-editform .text-checkbox-group-field{align-items:flex-start}.element-editor-editform .text-checkbox-group-field .form-group{margin-bottom:0;flex:auto}.element-editor-header{display:flex;align-items:center;justify-content:space-between}.element-editor-header__title{font-size:15px;font-weight:400;margin:0 0 0 .76925rem;-webkit-font-smoothing:antialiased;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.element-editor-header__title--none{font-style:italic;color:#6f84a7}.element-editor-header__info,.element-editor-header__actions{align-items:center;display:flex;flex-grow:1}.element-editor-header__info{max-width:calc(100% - 60px)}.element-editor-header__info .badge{color:#cf3f00;background-color:#fff7f0;padding:2px 3px 2px 4px;margin-left:.5rem}.element-editor-header__actions{justify-content:flex-end}.element-editor-header__actions-toggle{padding-top:3px;padding-bottom:3px}.element-editor-header__icon-container{margin-left:-2px;color:#566b8d;font-size:2.154rem;height:28px;line-height:1.5rem}.element-editor-header__icon-container--broken{color:#da273b}.element-editor-header__expand{font-size:1.1rem;margin-left:3px;width:unset}.element-editor-header__version-state{border:1px solid #cf3f00;border-radius:100%;bottom:6px;box-shadow:0 0 1px .5px #fff;display:block;height:8px;left:22px;position:relative;width:8px;z-index:1}.element-editor-header__version-state--draft{background-color:#ff7f22}.element-editor-header__version-state--modified{background-color:#fff7f0}.element-editor-header__drag-handle{display:none;position:absolute;left:5px;cursor:grab}.element-editor-header--simple .element-editor-header__drag-handle{display:block}.element-editor-header--simple .element-editor-header__info{width:460px}.element-editor-header .dropdown-item.active{cursor:default}.element-editor-summary{display:flex;margin-top:.9231rem;margin-left:36px;align-items:center;min-height:2em}.element-editor-summary__thumbnail-image{border-radius:.1536rem;height:36px;margin:-.6154rem .9231rem -.6154rem 0}.element-editor-summary__content{color:#566b8d;line-height:1.3;margin-bottom:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.element-editor-summary__content--broken{overflow:visible;white-space:normal}.element-editor__toolbar{margin-bottom:1rem}.element-editor__hover-bar{height:0;display:flex;width:100%;position:relative;align-items:center}.element-editor__hover-bar-area{background-color:rgba(0,0,0,0);min-height:1.8462rem;width:100%;margin:0;padding:0;border:0;outline:none;transition:all ease .2s;position:relative}.element-editor__hover-bar-area:hover,.element-editor__hover-bar-area:focus,.element-editor__hover-bar-area--focus{outline:none}.element-editor__hover-bar-area:hover .element-editor__hover-bar-area-inner,.element-editor__hover-bar-area:focus .element-editor__hover-bar-area-inner,.element-editor__hover-bar-area--focus .element-editor__hover-bar-area-inner{margin:0 20px}.element-editor__hover-bar-area:hover .element-editor__hover-bar-line,.element-editor__hover-bar-area:focus .element-editor__hover-bar-line,.element-editor__hover-bar-area--focus .element-editor__hover-bar-line{opacity:1;border-radius:5px;max-height:5px}.element-editor__hover-bar-area:hover .element-editor__hover-bar-line:before,.element-editor__hover-bar-area:focus .element-editor__hover-bar-line:before,.element-editor__hover-bar-area--focus .element-editor__hover-bar-line:before{transform:translateY(calc(3px - 50%)) scale(1)}.element-editor__hover-bar-area-inner{margin:0;display:block;position:relative;transition:all ease .2s}.element-editor__hover-bar-line{background-color:#005ae1;transition:all ease .2s;opacity:0;align-self:center;width:100%;border:0;position:absolute;display:flex;justify-content:flex-end;padding:0;top:50%;transform:translateY(-66%);max-height:0;border-radius:0}.element-editor__hover-bar-line:before{font-size:1.5rem;background-image:radial-gradient(#fff 50%, transparent 50%);position:relative;z-index:2;margin-right:50%;right:-0.5em;display:block;height:1em;transform:translateY(calc(-1px - 50%)) scale(0);transition:all ease .2s;color:#005ae1}.elemental-editor-drag-indicator{height:3px;margin:-2px 0 -1px;background-color:#29abe2}.elemental-editor-drag-indicator__ball{position:relative;height:7px;width:7px;top:-2px;left:-3px;border-radius:3.5px;background-color:#29abe2}.element-editor--dragging{cursor:grabbing}.element-editor-drag-preview{top:0;left:0;position:fixed;pointer-events:none;z-index:100;background-color:#fff;border:1px solid #ced5e1;padding:.9231rem 1.5385rem;box-shadow:0 2px 5px 0 rgba(0,0,0,.1),0 2px 10px 0 rgba(0,0,0,.1)}.text-checkbox-group-field .form-check{display:inline;padding-left:0;margin-bottom:0}.text-checkbox-group-field--read-only{display:flex}.text-checkbox-group-field--read-only :first-child{flex:1}.text-checkbox-group-field--read-only .show-title{font-style:italic} +/*!*****************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ + !*** css ./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[0].use[1]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[0].use[2]!./node_modules/resolve-url-loader/index.js??ruleSet[1].rules[0].use[3]!./node_modules/sass-loader/dist/cjs.js??ruleSet[1].rules[0].use[4]!./client/src/styles/bundle.scss ***! + \*****************************************************************************************************************************************************************************************************************************************************************************************************************************/ +.elemental-edit { + display: flex; + color: inherit; +} +.elemental-edit:hover, .elemental-edit:focus { + text-decoration: none; + color: inherit; +} + +.elemental-editor .col-EditorPreview { + padding-left: 0; +} + +.elemental-preview__detail { + display: inline-block; + margin-left: 0.76925rem; + margin-top: 1px; +} +.elemental-preview__detail h3 { + font-weight: 400; + line-height: 26px; + margin: 0; + -webkit-font-smoothing: antialiased; +} +.elemental-preview__detail p { + align-items: center; + display: flex; + margin-bottom: 0; + margin-top: 6px; +} +.elemental-preview__detail small { + color: #566b8d; + font-size: 13px; +} + +.elemental-preview__thumbnail-image { + margin-right: 0.76925rem; +} +.elemental-preview__thumbnail-image img { + border-radius: 0.192rem; +} + +.elemental-preview__thumbnail-image--placeholder { + border-radius: 0; + height: 36px; + margin-left: -4px; +} + +.elemental-preview__icon { + color: #566b8d; + display: inline-block; + flex-direction: row; + font-size: 2.3rem; + width: 28px; + vertical-align: top; + margin-top: -1px; +} + +.ss-gridfield-orderable.elemental-editor .col-reorder .handle { + opacity: 0.5; + padding: 22px 0 0; +} +.ss-gridfield-orderable.elemental-editor .col-reorder .handle .icon { + font-size: 1.3em; +} + +.elemental-editor .ss-gridfield-item:hover .handle { + opacity: 1; +} +.elemental-editor .grid-field__table { + margin-bottom: 12px; +} +@media (max-width: 991.98px) { + .elemental-editor .grid-field__table .col-EditorPreview { + display: table-cell; + } +} + +.elemental-report__grid-field .element-editor-header__version-state { + bottom: 9px; + left: 14px; +} + +.element-editor .form-group:nth-child(1n) { + display: block; +} +@media (min-width: 992px) { + .element-editor .form-group:nth-child(1n) .form__field-label, + .element-editor .form-group:nth-child(1n) .form__field-holder { + flex: 0 0 83.33333333%; + max-width: 83.33333333%; + margin-left: 0; + } +} + +.elemental-block__history-tab { + margin-top: -1.5385rem; +} + +.cms-edit-form .fieldgroup.elemental-area__element--historic { + margin-left: 0; + margin-right: 0; +} +.cms-edit-form .fieldgroup.elemental-area__element--historic.form-group { + border-top: 1px solid #dbe0e9; +} +.cms-edit-form .fieldgroup.elemental-area__element--historic .form__field-holder { + flex: 0 0 100%; + max-width: 100%; +} + +.elemental-preview { + line-height: 20px; +} + +.elemental-preview--historic { + margin-bottom: 1rem; +} + +.elemental-preview__link { + float: right; + margin-top: 4px; +} +.elemental-preview__link:hover { + text-decoration: none; +} +.elemental-preview__link:hover .elemental-preview__link-text { + text-decoration: underline; +} +.elemental-preview__link-caret { + display: block; + float: right; + margin-top: -2px; + margin-left: 2px; +} + +div.elemental-area__element--historic.elemental-area__element--historic-inner { + background: transparent; + border: 0; + padding-left: 0; + padding-right: 0; + padding-top: 1.5385rem; +} + +.elemental-area--read-only { + border-bottom: 1px solid #dbe0e9; + margin: 2.30775rem -1.5385rem; +} + +.history-viewer__version-detail fieldset { + overflow: visible; +} + +.elemental-report__grid-field .ss-gridfield-item td:first-child { + width: 1px; +} + +.elemental-report__grid-field .col-Icon { + font-size: 1.5rem; +} + +.elemental-report__grid-field .element-item--draft, +.elemental-report__grid-field .element-item--modified { + bottom: 8px; + left: 14px; + height: 6px; + width: 6px; +} + +.textcheckboxgroup .input-group-append .form-check-input { + margin-left: 0; + position: relative; +} + +.element-editor .action-menu .dropdown-item.disabled { + font-style: italic; + pointer-events: initial; + cursor: not-allowed; + color: #6f84a7; +} + +.elemental-editor__add-new-block-control { + width: 20rem; +} +.elemental-editor__add-new-block-control a { + line-height: 1.85em; +} + +.element-editor__element { + border-bottom: 1px solid #dbe0e9; + color: inherit; + cursor: pointer; + min-height: 8rem; + padding: 0.9231rem 1.5385rem 1.8462rem; +} +.element-editor__element:focus, .element-editor__element:hover { + box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.1), 0 2px 10px 0 rgba(0, 0, 0, 0.1); + outline-width: 0; +} +.element-editor__element:hover .element-editor-header__drag-handle { + display: block; +} +.element-editor__element--broken { + cursor: default; +} +.element-editor__element--dragging { + opacity: 0.3; + cursor: grabbing; +} + +.elemental-editor-list { + background-color: #fff; + border-top: 1px solid #dbe0e9; + margin-left: -1.5385rem; + margin-right: -1.5385rem; + min-height: calc(8rem + 1px); + position: relative; + margin-bottom: 1.5385rem; +} +.elemental-editor-list--empty { + border-bottom: 1px solid #dbe0e9; + display: flex; + align-items: center; + justify-content: center; +} + +.element-editor-editform { + margin-top: 0.76925rem; + cursor: auto; + margin-bottom: -1rem; +} +.element-editor-editform .mce-tinymce { + box-sizing: border-box; +} +.element-editor-editform__form { + width: 100%; +} +.element-editor-editform .element-editor-editform__form .form-group .form__field-holder { + flex: 1 0 100%; + max-width: 900px; +} +.element-editor-editform--rendered-not-visible { + position: absolute; + top: -9999px; + left: -9999px; +} +.element-editor-editform .btn--hidden { + display: none; +} +.element-editor-editform .text-checkbox-group-field { + align-items: flex-start; +} +.element-editor-editform .text-checkbox-group-field .form-group { + margin-bottom: 0; + flex: auto; +} + +.element-editor-header { + display: flex; + align-items: center; + justify-content: space-between; +} +.element-editor-header__title { + font-size: 15px; + font-weight: 400; + margin: 0 0 0 0.76925rem; + -webkit-font-smoothing: antialiased; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.element-editor-header__title--none { + font-style: italic; + color: #6f84a7; +} +.element-editor-header__info, .element-editor-header__actions { + align-items: center; + display: flex; + flex-grow: 1; +} +.element-editor-header__info { + max-width: calc(100% - 60px); +} +.element-editor-header__info .badge { + color: #cf3f00; + background-color: #fff7f0; + padding: 2px 3px 2px 4px; + margin-left: 0.5rem; +} +.element-editor-header__actions { + justify-content: flex-end; +} +.element-editor-header__actions-toggle { + padding-top: 3px; + padding-bottom: 3px; +} +.element-editor-header__icon-container { + margin-left: -2px; + color: #566b8d; + font-size: 2.154rem; + height: 28px; + line-height: 1.5rem; +} +.element-editor-header__icon-container--broken { + color: #da273b; +} +.element-editor-header__expand { + font-size: 1.1rem; + margin-left: 3px; + width: unset; +} +.element-editor-header__version-state { + border: 1px solid #cf3f00; + border-radius: 100%; + bottom: 6px; + box-shadow: 0 0 1px 0.5px #fff; + display: block; + height: 8px; + left: 22px; + position: relative; + width: 8px; + z-index: 1; +} +.element-editor-header__version-state--draft { + background-color: #ff7f22; +} +.element-editor-header__version-state--modified { + background-color: #fff7f0; +} +.element-editor-header__drag-handle { + display: none; + position: absolute; + left: 5px; + cursor: grab; +} +.element-editor-header--simple .element-editor-header__drag-handle { + display: block; +} +.element-editor-header--simple .element-editor-header__info { + width: 460px; +} +.element-editor-header .dropdown-item.active { + cursor: default; +} + +.element-editor-summary { + display: flex; + margin-top: 0.9231rem; + margin-left: 36px; + align-items: center; + min-height: 2em; +} +.element-editor-summary__thumbnail-image { + border-radius: 0.1536rem; + height: 36px; + margin: -0.6154rem 0.9231rem -0.6154rem 0; +} +.element-editor-summary__content { + color: #566b8d; + line-height: 1.3; + margin-bottom: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.element-editor-summary__content--broken { + overflow: visible; + white-space: normal; +} + +.element-editor__toolbar { + margin-bottom: 1rem; +} + +.element-editor__hover-bar { + height: 0; + display: flex; + width: 100%; + position: relative; + align-items: center; +} +.element-editor__hover-bar-area { + background-color: transparent; + min-height: 1.8462rem; + width: 100%; + margin: 0; + padding: 0; + border: 0; + outline: none; + transition: all ease 0.2s; + position: relative; +} +.element-editor__hover-bar-area:hover, .element-editor__hover-bar-area:focus, .element-editor__hover-bar-area--focus { + outline: none; +} +.element-editor__hover-bar-area:hover .element-editor__hover-bar-area-inner, .element-editor__hover-bar-area:focus .element-editor__hover-bar-area-inner, .element-editor__hover-bar-area--focus .element-editor__hover-bar-area-inner { + margin: 0 20px; +} +.element-editor__hover-bar-area:hover .element-editor__hover-bar-line, .element-editor__hover-bar-area:focus .element-editor__hover-bar-line, .element-editor__hover-bar-area--focus .element-editor__hover-bar-line { + opacity: 1; + border-radius: 5px; + max-height: 5px; +} +.element-editor__hover-bar-area:hover .element-editor__hover-bar-line:before, .element-editor__hover-bar-area:focus .element-editor__hover-bar-line:before, .element-editor__hover-bar-area--focus .element-editor__hover-bar-line:before { + transform: translateY(calc(3px - 50%)) scale(1); +} +.element-editor__hover-bar-area-inner { + margin: 0; + display: block; + position: relative; + transition: all ease 0.2s; +} +.element-editor__hover-bar-line { + background-color: #005ae1; + transition: all ease 0.2s; + opacity: 0; + align-self: center; + width: 100%; + border: 0; + position: absolute; + display: flex; + justify-content: flex-end; + padding: 0; + top: 50%; + transform: translateY(-66%); + max-height: 0; + border-radius: 0; +} +.element-editor__hover-bar-line:before { + font-size: 1.5rem; + background-image: radial-gradient(#fff 50%, transparent 50%); + position: relative; + z-index: 2; + margin-right: 50%; + right: -0.5em; + display: block; + height: 1em; + transform: translateY(calc(-1px - 50%)) scale(0); + transition: all ease 0.2s; + color: #005ae1; +} + +.elemental-editor-drag-indicator { + height: 3px; + margin: -2px 0 -1px; + background-color: #29abe2; +} +.elemental-editor-drag-indicator__ball { + position: relative; + height: 7px; + width: 7px; + top: -2px; + left: -3px; + border-radius: 3.5px; + background-color: #29abe2; +} + +.element-editor--dragging { + cursor: grabbing; +} + +.element-editor-drag-preview { + top: 0; + left: 0; + position: fixed; + pointer-events: none; + z-index: 100; + background-color: #fff; + border: 1px solid #ced5e1; + padding: 0.9231rem 1.5385rem; + box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.1), 0 2px 10px 0 rgba(0, 0, 0, 0.1); +} + +.text-checkbox-group-field .form-check { + display: inline; + padding-left: 0; + margin-bottom: 0; +} +.text-checkbox-group-field--read-only { + display: flex; +} +.text-checkbox-group-field--read-only :first-child { + flex: 1; +} +.text-checkbox-group-field--read-only .show-title { + font-style: italic; +} + +/*# sourceMappingURL=bundle.css.map*/ \ No newline at end of file diff --git a/client/src/boot/registerTransforms.js b/client/src/boot/registerTransforms.js index 75cfd145..8fd98f43 100644 --- a/client/src/boot/registerTransforms.js +++ b/client/src/boot/registerTransforms.js @@ -1,9 +1,6 @@ import Injector from 'lib/Injector'; -import readOneBlockQuery from 'state/history/readOneBlockQuery'; import HistoricElementViewFactory from 'components/HistoricElementView/HistoricElementView'; -import revertToBlockVersionMutation from 'state/history/revertToBlockVersionMutation'; -import readBlocksForAreaQuery from 'state/editor/readBlocksForAreaQuery'; -import addElementToArea from 'state/editor/addElementMutation'; +import revertToBlockVersionRequest from 'state/history/revertToBlockVersionRequest'; import ArchiveAction from 'components/ElementActions/ArchiveAction'; import DuplicateAction from 'components/ElementActions/DuplicateAction'; import SaveAction from 'components/ElementActions/SaveAction'; @@ -25,50 +22,14 @@ export default () => { } ); - Injector.transform( - 'elements-history', - (updater) => { - // Add content block history to the HistoryViewer - updater.component( - 'HistoryViewer.Form_ItemEditForm', - readOneBlockQuery, - 'ElementHistoryViewer' - ); - } - ); - Injector.transform( 'blocks-history-revert', (updater) => { - // Add block element revert GraphQL mutation to the HistoryViewerToolbar + // Add revertToVersion() to props.actions on HistoryViewerToolbar updater.component( 'HistoryViewerToolbar.VersionedAdmin.HistoryViewer.Element.HistoryViewerVersionDetail', - revertToBlockVersionMutation, - 'BlockRevertMutation' - ); - } - ); - - Injector.transform( - 'cms-element-editor', - (updater) => { - // Add GraphQL query for reading elements on a page for the ElementEditor - updater.component( - 'ElementList', - readBlocksForAreaQuery, - 'PageElements' - ); - } - ); - - Injector.transform( - 'cms-element-adder', - (updater) => { - // Add GraphQL query for adding elements to an ElementEditor (ElementalArea) - updater.component( - 'AddElementPopover', - addElementToArea, - 'ElementAddButton' + revertToBlockVersionRequest, + 'BlockRevertRequest' ); } ); diff --git a/client/src/components/ElementActions/ArchiveAction.js b/client/src/components/ElementActions/ArchiveAction.js index 101198a7..a7fc6580 100644 --- a/client/src/components/ElementActions/ArchiveAction.js +++ b/client/src/components/ElementActions/ArchiveAction.js @@ -1,40 +1,43 @@ /* global window */ -import React from 'react'; -import { compose } from 'redux'; +import React, { useContext } from 'react'; import AbstractAction from 'components/ElementActions/AbstractAction'; -import archiveBlockMutation from 'state/editor/archiveBlockMutation'; import i18n from 'i18n'; +import { ElementEditorContext } from 'components/ElementEditor/ElementEditor'; +import backend from 'lib/Backend'; +import Config from 'lib/Config'; +import { getConfig } from 'state/editor/elementConfig'; /** * Adds the elemental menu action to archive a block of any state */ const ArchiveAction = (MenuComponent) => (props) => { + const { fetchElements } = useContext(ElementEditorContext); + const handleClick = (event) => { event.stopPropagation(); - - const { element: { id }, isPublished, actions: { handleArchiveBlock } } = props; - + const isPublished = props.element.isPublished; let archiveMessage = i18n._t( 'ElementArchiveAction.CONFIRM_DELETE', 'Are you sure you want to send this block to the archive?' ); - if (isPublished) { archiveMessage = i18n._t( 'ElementArchiveAction.CONFIRM_DELETE_AND_UNPUBLISH', 'Warning: This block will be unpublished before being sent to the archive. Are you sure you want to proceed?' ); } - // eslint-disable-next-line no-alert - if (handleArchiveBlock && window.confirm(archiveMessage)) { - handleArchiveBlock(id).then(() => { - const preview = window.jQuery('.cms-preview'); - if (preview && typeof preview.entwine === 'function') { - preview.entwine('ss.preview')._loadUrl(preview.find('iframe').attr('src')); - } - }); + if (!window.confirm(archiveMessage)) { + return; } + const id = props.element.id; + const url = `${getConfig().controllerLink.replace(/\/$/, '')}/api/archive`; + backend.post(url, { + ID: id, + }, { + SecurityID: Config.get('SecurityID') + }) + .then(() => fetchElements()); }; const disabled = props.element.canDelete !== undefined && !props.element.canDelete; @@ -61,4 +64,4 @@ const ArchiveAction = (MenuComponent) => (props) => { export { ArchiveAction as Component }; -export default compose(archiveBlockMutation, ArchiveAction); +export default ArchiveAction; diff --git a/client/src/components/ElementActions/DuplicateAction.js b/client/src/components/ElementActions/DuplicateAction.js index f1996aab..60dc7d9f 100644 --- a/client/src/components/ElementActions/DuplicateAction.js +++ b/client/src/components/ElementActions/DuplicateAction.js @@ -1,14 +1,18 @@ /* global window */ -import React from 'react'; -import { compose } from 'redux'; +import React, { useContext } from 'react'; import AbstractAction from 'components/ElementActions/AbstractAction'; -import duplicateBlockMutation from 'state/editor/duplicateBlockMutation'; import i18n from 'i18n'; +import { ElementEditorContext } from 'components/ElementEditor/ElementEditor'; +import backend from 'lib/Backend'; +import Config from 'lib/Config'; +import { getConfig } from 'state/editor/elementConfig'; /** * Adds the elemental menu action to duplicate a block */ const DuplicateAction = (MenuComponent) => (props) => { + const { fetchElements } = useContext(ElementEditorContext); + if (props.type.broken) { // Don't allow this action for a broken element. return ( @@ -18,15 +22,14 @@ const DuplicateAction = (MenuComponent) => (props) => { const handleClick = (event) => { event.stopPropagation(); - - const { element: { id }, actions: { handleDuplicateBlock } } = props; - - if (handleDuplicateBlock) { - handleDuplicateBlock(id).then(() => { - const preview = window.jQuery('.cms-preview'); - preview.entwine('ss.preview')._loadUrl(preview.find('iframe').attr('src')); - }); - } + const id = props.element.id; + const url = `${getConfig().controllerLink.replace(/\/$/, '')}/api/duplicate`; + backend.post(url, { + ID: id, + }, { + SecurityID: Config.get('SecurityID') + }) + .then(() => fetchElements()); }; const disabled = props.element.canCreate !== undefined && !props.element.canCreate; @@ -53,4 +56,4 @@ const DuplicateAction = (MenuComponent) => (props) => { export { DuplicateAction as Component }; -export default compose(duplicateBlockMutation, DuplicateAction); +export default DuplicateAction; diff --git a/client/src/components/ElementActions/UnpublishAction.js b/client/src/components/ElementActions/UnpublishAction.js index a8bc506d..d3e20cdd 100644 --- a/client/src/components/ElementActions/UnpublishAction.js +++ b/client/src/components/ElementActions/UnpublishAction.js @@ -1,14 +1,18 @@ /* global window */ -import React from 'react'; -import { compose } from 'redux'; +import React, { useContext } from 'react'; import AbstractAction from 'components/ElementActions/AbstractAction'; -import unpublishBlockMutation from 'state/editor/unpublishBlockMutation'; import i18n from 'i18n'; +import backend from 'lib/Backend'; +import { ElementEditorContext } from 'components/ElementEditor/ElementEditor'; +import Config from 'lib/Config'; +import { getConfig } from 'state/editor/elementConfig'; /** * Adds the elemental menu action to unpublish a published block */ const UnpublishAction = (MenuComponent) => (props) => { + const { fetchElements } = useContext(ElementEditorContext); + if (props.type.broken) { // Don't allow this action for a broken element. return ( @@ -16,51 +20,44 @@ const UnpublishAction = (MenuComponent) => (props) => { ); } - const { element, type, actions: { handleUnpublishBlock } } = props; - - const handleClick = (event) => { - event.stopPropagation(); - const { jQuery: $ } = window; + const reportUnpublicationStatus = (type, title, success) => { const noTitle = i18n.inject( - i18n._t( - 'ElementHeader.NOTITLE', - 'Untitled {type} block' - ), - { type: type.title } + i18n._t('ElementHeader.NOTITLE', 'Untitled {type} block'), + { type } + ); + const successMessage = i18n.inject( + i18n._t('ElementUnpublishAction.SUCCESS_NOTIFICATION', 'Removed \'{title}\' from the published page'), + { title: title || noTitle } + ); + const errorMessage = i18n.inject( + i18n._t('ElementUnpublishAction.ERROR_NOTIFICATION', 'Error unpublishing \'{title}\''), + { title: title || noTitle } ); + window.jQuery.noticeAdd({ + text: success ? successMessage : errorMessage, + stay: false, + type: success ? 'success' : 'error', + }); + }; + + const unpublishElement = () => { + const id = props.element.id; + const url = `${getConfig().controllerLink.replace(/\/$/, '')}/api/unpublish`; + return backend.post(url, { + ID: id, + }, { + SecurityID: Config.get('SecurityID') + }) + .then(() => fetchElements()); + }; - if (handleUnpublishBlock) { - handleUnpublishBlock(element.id) - .then(() => { - const preview = $('.cms-preview'); - preview.entwine('ss.preview')._loadUrl(preview.find('iframe').attr('src')); + const { element, type } = props; - $.noticeAdd({ - text: i18n.inject( - i18n._t( - 'ElementUnpublishAction.SUCCESS_NOTIFICATION', - 'Removed \'{title}\' from the published page' - ), - { title: element.title || noTitle } - ), - stay: false, - type: 'success' - }); - }) - .catch(() => { - $.noticeAdd({ - text: i18n.inject( - i18n._t( - 'ElementUnpublishAction.ERROR_NOTIFICATION', - 'Error unpublishing \'{title}\'' - ), - { title: element.title || noTitle } - ), - stay: false, - type: 'error' - }); - }); - } + const handleClick = (event) => { + event.stopPropagation(); + unpublishElement() + .then(() => reportUnpublicationStatus(type.title, element.title, true)) + .catch(() => reportUnpublicationStatus(type.title, element.title, false)); }; const disabled = props.element.canUnpublish !== undefined && !props.element.canUnpublish; @@ -87,4 +84,4 @@ const UnpublishAction = (MenuComponent) => (props) => { export { UnpublishAction as Component }; -export default compose(unpublishBlockMutation, UnpublishAction); +export default UnpublishAction; diff --git a/client/src/components/ElementActions/tests/ArchiveAction-test.js b/client/src/components/ElementActions/tests/ArchiveAction-test.js index bd21978d..44336f0c 100644 --- a/client/src/components/ElementActions/tests/ArchiveAction-test.js +++ b/client/src/components/ElementActions/tests/ArchiveAction-test.js @@ -4,6 +4,26 @@ import React from 'react'; import { render, fireEvent } from '@testing-library/react'; import { Component as ArchiveAction } from '../ArchiveAction'; +import { ElementEditorContext } from '../../ElementEditor/ElementEditor'; + +let resolveMockPostRequest; + +jest.mock('lib/Backend', () => ({ + post: () => new Promise((resolve) => { + resolveMockPostRequest = resolve; + }) +})); + +const sectionConfigKey = 'DNADesign\\Elemental\\Controllers\\ElementalAreaController'; +window.ss.config = { + SecurityID: 1234567890, + sections: [ + { + name: sectionConfigKey, + controllerLink: 'my/test/endpoint', + }, + ], +}; const WrappedComponent = (props) =>
{props.children}
; const ActionComponent = ArchiveAction(WrappedComponent); @@ -16,9 +36,7 @@ function makeProps(obj = {}) { element: { id: 123, isPublished: true, - blockSchema: { type: 'Test' } }, - isPublished: true, actions: { handleArchiveBlock: () => {} }, @@ -27,44 +45,70 @@ function makeProps(obj = {}) { }; } +function makeProviderProps(obj = {}) { + return { + value: { + fetchElements: () => {}, + ...obj, + } + }; +} + test('ArchiveAction renders the title and class', () => { - const { container } = render(); + const { container } = render( + + + + ); expect(container.querySelector('button.element-editor__actions-archive').textContent).toBe('Archive'); }); -test('ArchiveAction does not archive when declining the confirmation', () => { +test('ArchiveAction does not archive when declining the confirmation', async () => { + resolveMockPostRequest = 'lorem ipsum'; global.confirm = () => false; - const mockMutation = jest.fn(() => new Promise((resolve) => { resolve(); })); - const { container } = render(); + const { container } = render( + + + + ); fireEvent.click(container.querySelector('button.element-editor__actions-archive')); - expect(mockMutation).not.toHaveBeenCalled(); + // mock backend post method was never called, therefore resolveMockPostRequest value unchanged + expect(resolveMockPostRequest).toBe('lorem ipsum'); }); -test('ArchiveAction archives when accepting the confirmation', () => { +test('ArchiveAction archives when accepting the confirmation', async () => { global.confirm = () => true; - const mockMutation = jest.fn(() => new Promise((resolve) => { resolve(); })); - const { container } = render(); + let resolvePromise; + const myPromise = new Promise((resolve) => { + resolvePromise = resolve; + }); + const fetchElements = jest.fn(() => { + resolvePromise(); + }); + const { container } = render( + + + + ); fireEvent.click(container.querySelector('button.element-editor__actions-archive')); - expect(mockMutation).toHaveBeenCalled(); + resolveMockPostRequest(); + await Promise.all([myPromise]); + expect(fetchElements).toHaveBeenCalled(); }); test('ArchiveAction indicates that the block will be sent to archive when it is unpublished', () => { const mockConfirm = jest.fn(); global.confirm = mockConfirm; - const { container } = render(); + const { container } = render( + + + + ); fireEvent.click(container.querySelector('button.element-editor__actions-archive')); expect(mockConfirm).toHaveBeenCalledWith('Are you sure you want to send this block to the archive?'); }); @@ -72,30 +116,44 @@ test('ArchiveAction indicates that the block will be sent to archive when it is test('ArchiveAction indicates that the block will be sent to archive when it is published', () => { const mockConfirm = jest.fn(); global.confirm = mockConfirm; - const { container } = render(); + const { container } = render( + + + + ); fireEvent.click(container.querySelector('button.element-editor__actions-archive')); expect(mockConfirm).toHaveBeenCalledWith('Warning: This block will be unpublished before being sent to the archive. Are you sure you want to proceed?'); }); test('ArchiveAction is disabled when user doesn\'t have correct permissions', () => { - const { container } = render(); + const { container } = render( + + + + ); expect(container.querySelector('button.element-editor__actions-archive').disabled).toBe(true); }); test('ArchiveAction renders a button even when block is broken', () => { - const { container } = render(); + const { container } = render( + + + + ); expect(container.querySelectorAll('button.element-editor__actions-archive')).toHaveLength(1); }); diff --git a/client/src/components/ElementActions/tests/DuplicateAction-test.js b/client/src/components/ElementActions/tests/DuplicateAction-test.js index 4ec0f761..56b75960 100644 --- a/client/src/components/ElementActions/tests/DuplicateAction-test.js +++ b/client/src/components/ElementActions/tests/DuplicateAction-test.js @@ -4,6 +4,7 @@ import React from 'react'; import { render } from '@testing-library/react'; import { Component as DuplicateAction } from '../DuplicateAction'; +import { ElementEditorContext } from '../../ElementEditor/ElementEditor'; const WrappedComponent = (props) =>
{props.children}
; const ActionComponent = DuplicateAction(WrappedComponent); @@ -27,30 +28,49 @@ function makeProps(obj = {}) { }; } +function makeProviderProps(obj = {}) { + return { + value: { + fetchElements: () => {}, + ...obj, + } + }; +} + test('DuplicateAction renders a button', () => { - const { container } = render(); + const { container } = render( + + + + ); expect(container.querySelectorAll('button.element-editor__actions-duplicate')).toHaveLength(1); }); test('DuplicateAction is disabled when user doesn\'t have correct permissions', () => { const { container } = render( - + + + ); expect(container.querySelector('button.element-editor__actions-duplicate').disabled).toBe(true); }); test('DuplicateAction does not render a button when block is broken', () => { const { container } = render( - + + + ); expect(container.querySelectorAll('button.element-editor__actions-duplicate')).toHaveLength(0); }); diff --git a/client/src/components/ElementActions/tests/PublishAction-test.js b/client/src/components/ElementActions/tests/PublishAction-test.js index 47b0b3bd..1bf0fa4e 100644 --- a/client/src/components/ElementActions/tests/PublishAction-test.js +++ b/client/src/components/ElementActions/tests/PublishAction-test.js @@ -3,6 +3,7 @@ import React from 'react'; import { fireEvent, render } from '@testing-library/react'; import { Component as PublishAction } from '../PublishAction'; +import { ElementEditorContext } from '../../ElementEditor/ElementEditor'; import { ElementContext } from '../../ElementEditor/Element'; window.jQuery = { @@ -28,61 +29,85 @@ function makeProps(obj = {}) { }; } -function makeProviderValue(obj = {}) { +function makeElementEditorProviderProps(obj = {}) { return { - doPublishElement: false, - formHasRendered: false, - onAfterPublish: () => {}, - onPublishButtonClick: () => {}, - ...obj, + value: { + fetchElements: () => {}, + ...obj, + } + }; +} + +function makeElementProviderProps(obj = {}) { + return { + value: { + doPublishElement: false, + formHasRendered: false, + onAfterPublish: () => {}, + onPublishButtonClick: () => {}, + ...obj, + } }; } const WrappedComponent = (props) =>
{props.children}
; const ActionComponent = PublishAction(WrappedComponent); -const ProvidedActionComponent = (props) => ( - - - -); test('PublishAction renders the title and class', () => { - const { container } = render(); + const { container } = render( + + + + + + ); expect(container.querySelector('button.element-editor__actions-publish').textContent).toBe('Publish'); }); test('PublishAction returns null when is the live version', () => { const { container } = render( - + + + + + ); expect(container.querySelector('button.element-editor__actions-publish')).toBe(null); }); test('PublishAction is disabled when user doesn\'t have correct permissions', () => { const { container } = render( - + + + + + ); expect(container.querySelector('button.element-editor__actions-publish').disabled).toBe(true); }); test('PublishAction does not render a button when block is broken', () => { const { container } = render( - + + + + + ); expect(container.querySelectorAll('button.element-editor__actions-publish')).toHaveLength(0); }); @@ -90,12 +115,14 @@ test('PublishAction does not render a button when block is broken', () => { test('Clicking button calls onPublishButtonClick', () => { const onPublishButtonClick = jest.fn(); const { container } = render( - - - + + + + + ); fireEvent.click(container.querySelector('button.element-editor__actions-publish')); expect(onPublishButtonClick).toHaveBeenCalled(); diff --git a/client/src/components/ElementActions/tests/SaveAction-test.js b/client/src/components/ElementActions/tests/SaveAction-test.js index 528c0b73..89257293 100644 --- a/client/src/components/ElementActions/tests/SaveAction-test.js +++ b/client/src/components/ElementActions/tests/SaveAction-test.js @@ -4,6 +4,7 @@ import React from 'react'; import { fireEvent, render } from '@testing-library/react'; import { Component as SaveAction } from '../SaveAction'; +import { ElementEditorContext } from '../../ElementEditor/ElementEditor'; import { ElementContext } from '../../ElementEditor/Element'; function makeProps(obj = {}) { @@ -26,61 +27,83 @@ function makeProps(obj = {}) { }; } -function makeProviderValue(obj = {}) { +function makeElementEditorProviderProps(obj = {}) { return { - formHasRendered: false, - onAfterSave: () => {}, - doSaveElement: false, - onSaveButtonClick: () => {}, - submitForm: () => {}, - formDirty: true, - ...obj, + value: { + fetchElements: () => {}, + ...obj, + } + }; +} + +function makeElementProviderProps(obj = {}) { + return { + value: { + formHasRendered: false, + onAfterSave: () => {}, + doSaveElement: false, + onSaveButtonClick: () => {}, + submitForm: () => {}, + formDirty: true, + ...obj, + } }; } const WrappedComponent = (props) =>
{props.children}
; const ActionComponent = SaveAction(WrappedComponent); -const ProvidedActionComponent = (props) => ( - - - -); + test('SaveAction does not render a button when block is expandable and not formDirty', () => { const { container } = render( - - - + + + + + ); expect(container.querySelectorAll('button.element-editor__actions-save')).toHaveLength(0); }); + test('SaveAction renders a button when block is expandable and formDirty', () => { const { container } = render( - + + + + + ); expect(container.querySelectorAll('button.element-editor__actions-save')).toHaveLength(1); }); test('SaveAction does not render a button when block is not expandable', () => { const { container } = render( - + + + + + ); expect(container.querySelectorAll('button.element-editor__actions-save')).toHaveLength(0); }); test('SaveAction does not render a button when block is broken', () => { const { container } = render( - + + + + + ); expect(container.querySelectorAll('button.element-editor__actions-save')).toHaveLength(0); }); @@ -88,12 +111,14 @@ test('SaveAction does not render a button when block is broken', () => { test('Clicking button calls onSaveButtonClick', () => { const onSaveButtonClick = jest.fn(); const { container } = render( - - - + + + + + ); fireEvent.click(container.querySelector('button.element-editor__actions-save')); expect(onSaveButtonClick).toHaveBeenCalled(); diff --git a/client/src/components/ElementActions/tests/UnpublishAction-test.js b/client/src/components/ElementActions/tests/UnpublishAction-test.js index edd3dcac..49a95576 100644 --- a/client/src/components/ElementActions/tests/UnpublishAction-test.js +++ b/client/src/components/ElementActions/tests/UnpublishAction-test.js @@ -4,11 +4,31 @@ import React from 'react'; import { fireEvent, render } from '@testing-library/react'; import { Component as UnpublishAction } from '../UnpublishAction'; +import { ElementEditorContext } from '../../ElementEditor/ElementEditor'; window.jQuery = { noticeAdd: jest.fn() }; +let resolveMockPostRequest; + +jest.mock('lib/Backend', () => ({ + post: () => new Promise((resolve) => { + resolveMockPostRequest = resolve; + }) +})); + +const sectionConfigKey = 'DNADesign\\Elemental\\Controllers\\ElementalAreaController'; +window.ss.config = { + SecurityID: 1234567890, + sections: [ + { + name: sectionConfigKey, + controllerLink: 'my/test/endpoint', + }, + ], +}; + function makeProps(obj = {}) { return { title: 'My unpublish action', @@ -26,63 +46,85 @@ function makeProps(obj = {}) { }; } +function makeProviderProps(obj = {}) { + return { + value: { + fetchElements: () => {}, + ...obj, + } + }; +} + const WrappedComponent = (props) =>
{props.children}
; const ActionComponent = UnpublishAction(WrappedComponent); test('UnpublishAction renders the title and class', () => { const { container } = render( - + + + ); expect(container.querySelector('button.element-editor__actions-unpublish').textContent).toBe('Unpublish'); }); test('UnpublishAction returns null when is not published', () => { const { container } = render( - + + + ); expect(container.querySelectorAll('button')).toHaveLength(0); }); -test('UnpublishAction calls the unpublish mutation', () => { - const mockMutation = jest.fn(() => new Promise((resolve) => { resolve(); })); +test('UnpublishAction calls unpublish endpoint and fetchElements', async () => { + let resolvePromise; + const myPromise = new Promise((resolve) => { + resolvePromise = resolve; + }); + const fetchElements = jest.fn(() => { + resolvePromise(); + }); const { container } = render( - + + + ); fireEvent.click(container.querySelector('button.element-editor__actions-unpublish')); - expect(mockMutation).toHaveBeenCalledWith(123); + resolveMockPostRequest(); + await Promise.all([myPromise]); + expect(fetchElements).toHaveBeenCalled(); }); test('UnpublishAction is disabled when user doesn\'t have correct permissions', () => { const { container } = render( - + + + ); expect(container.querySelector('button.element-editor__actions-unpublish').disabled).toBe(true); }); test('UnpublishAction does not render a button when block is broken', () => { const { container } = render( - + + + ); expect(container.querySelectorAll('button.element-editor__actions-unpublish')).toHaveLength(0); }); diff --git a/client/src/components/ElementEditor/AddElementPopover.js b/client/src/components/ElementEditor/AddElementPopover.js index cb6cb312..9fe70842 100644 --- a/client/src/components/ElementEditor/AddElementPopover.js +++ b/client/src/components/ElementEditor/AddElementPopover.js @@ -6,6 +6,9 @@ import classNames from 'classnames'; import { inject } from 'lib/Injector'; import { elementTypeType } from 'types/elementTypeType'; import i18n from 'i18n'; +import backend from 'lib/Backend'; +import Config from 'lib/Config'; +import { ElementEditorContext } from 'components/ElementEditor/ElementEditor'; /** * The AddElementPopover component used in the context of an ElementEditor shows the @@ -16,27 +19,33 @@ class AddElementPopover extends Component { super(props); this.handleToggle = this.handleToggle.bind(this); + AddElementPopover.contextType = ElementEditorContext; } /** - * click handler that preserves the details of what was clicked - * @param {object} elementType in the shape of types/elmementTypeType - * @returns {function} + * #rpc + * - call add element to area endpoint (areaID, elementType, insertAfterElementID) + * - then call read blocks from area endpoint (areaID) + * - also then update the preview via jquery/entwine */ getElementButtonClickHandler(elementType) { return (event) => { - const { - actions: { handleAddElementToArea }, - insertAfterElement - } = this.props; - event.preventDefault(); - handleAddElementToArea(elementType.class, insertAfterElement).then( - () => { + backend.post('/admin/elemental-area/api/add/', { + elementClass: elementType.class, + elementalAreaID: this.props.areaId, + insertAfterElementID: this.props.insertAfterElement, + }, { + SecurityID: Config.get('SecurityID') + }) + .then(() => { + const { fetchElements } = this.context; + return fetchElements(); + }) + .then(() => { const preview = window.jQuery('.cms-preview'); preview.entwine('ss.preview')._loadUrl(preview.find('iframe').attr('src')); - } - ); + }); this.handleToggle(); }; } diff --git a/client/src/components/ElementEditor/Element.js b/client/src/components/ElementEditor/Element.js index ee7f5f33..3195e81d 100644 --- a/client/src/components/ElementEditor/Element.js +++ b/client/src/components/ElementEditor/Element.js @@ -1,7 +1,6 @@ /* global window */ -import React, { useState, useEffect, createContext } from 'react'; -import { useMutation } from '@apollo/client'; +import React, { useState, useEffect, useContext, createContext } from 'react'; import PropTypes from 'prop-types'; import { elementType } from 'types/elementType'; import { elementTypeType } from 'types/elementTypeType'; @@ -13,14 +12,16 @@ import { connect } from 'react-redux'; import { submit } from 'redux-form'; import { loadElementFormStateName } from 'state/editor/loadElementFormStateName'; import { loadElementSchemaValue } from 'state/editor/loadElementSchemaValue'; -import { publishBlockMutation } from 'state/editor/publishBlockMutation'; -import { query as readBlocksForAreaQuery } from 'state/editor/readBlocksForAreaQuery'; import * as TabsActions from 'state/tabs/TabsActions'; import { DragSource, DropTarget } from 'react-dnd'; import { getEmptyImage } from 'react-dnd-html5-backend'; import { elementDragSource, isOverTop } from 'lib/dragHelpers'; import * as toastsActions from 'state/toasts/ToastsActions'; import { addFormChanged, removeFormChanged } from 'state/unsavedForms/UnsavedFormsActions'; +import { ElementEditorContext } from 'components/ElementEditor/ElementEditor'; +import { getConfig } from 'state/editor/elementConfig'; +import backend from 'lib/Backend'; +import Config from 'lib/Config'; export const ElementContext = createContext(null); @@ -41,7 +42,7 @@ const Element = (props) => { const [formHasRendered, setFormHasRendered] = useState(false); const [doDispatchAddFormChanged, setDoDispatchAddFormChanged] = useState(false); const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false); - const [publishBlock] = useMutation(publishBlockMutation); + const { fetchElements } = useContext(ElementEditorContext); useEffect(() => { // Note that formDirty from redux can be set to undefined after failed validation @@ -128,29 +129,20 @@ const Element = (props) => { } }; - // This will trigger a graphql request that will cause this - // element to re-render including any updated title and versioned badge - const refetchElementalArea = () => window.ss.apolloClient.queryManager.refetchQueries({ - include: [{ - query: readBlocksForAreaQuery, - variables: { id: props.areaId } - }] - }); - const handleAfterPublish = (wasError) => { showPublishedElementToast(wasError); setDoPublishElement(false); setDoPublishElementAfterSave(false); - // Ensure that formDirty becomes falsey after publishing - // We need to call at a later render rather than straight away or redux-form may override this - // and set the form state to dirty under certain conditions - // setTimeout is a hackish way to do this, though I'm not sure how else we can do this - // The core issue is that redux-form will detect changes when a form is hydrated for the first - // time under certain conditions, specifically during a behat test when trying to publish a closed - // block when presumably the apollo cache is empty (or something like that). This happens late and - // there are no hooks/callbacks available after this happens the input onchange handlers are fired - Promise.all(refetchElementalArea()) + fetchElements() .then(() => { + // Ensure that formDirty becomes falsey after publishing + // We need to call at a later render rather than straight away or redux-form may override this + // and set the form state to dirty under certain conditions + // setTimeout is a hackish way to do this, though I'm not sure how else we can do this + // The core issue is that redux-form will detect changes when a form is hydrated for the first + // time under certain conditions, specifically during a behat test when trying to publish a closed + // block when presumably the old apollo cache was empty (or something like that). This happens late and + // there are no hooks/callbacks available after this happens the input onchange handlers are fired setTimeout(() => props.dispatchRemoveFormChanged(), 250); }); }; @@ -166,7 +158,12 @@ const Element = (props) => { // Publish action useEffect(() => { if (formHasRendered && doPublishElement) { - publishBlock({ variables: { blockId: props.element.id } }) + const url = `${getConfig().controllerLink.replace(/\/$/, '')}/api/publish`; + backend.post(url, { + ID: props.element.id, + }, { + SecurityID: Config.get('SecurityID') + }) .then(() => handleAfterPublish(false)) .catch(() => handleAfterPublish(true)); } @@ -354,8 +351,8 @@ const Element = (props) => { if (!doPublishElement && !doPublishElementAfterSave) { showSavedElementToast(title); } - refetchElementalArea(); props.onAfterSubmitResponse(true); + fetchElements(); }; const { diff --git a/client/src/components/ElementEditor/ElementEditor.js b/client/src/components/ElementEditor/ElementEditor.js index 99a7cb5f..29f89435 100644 --- a/client/src/components/ElementEditor/ElementEditor.js +++ b/client/src/components/ElementEditor/ElementEditor.js @@ -1,13 +1,17 @@ /* global window */ -import React, { PureComponent } from 'react'; +import React, { PureComponent, createContext } from 'react'; import PropTypes from 'prop-types'; import { inject } from 'lib/Injector'; import { compose } from 'redux'; import { elementTypeType } from 'types/elementTypeType'; import { DropTarget } from 'react-dnd'; -import sortBlockMutation from 'state/editor/sortBlockMutation'; import ElementDragPreview from 'components/ElementEditor/ElementDragPreview'; import withDragDropContext from 'lib/withDragDropContext'; +import backend from 'lib/Backend'; +import Config from 'lib/Config'; +import { getConfig } from 'state/editor/elementConfig'; + +export const ElementEditorContext = createContext(null); /** * The ElementEditor is used in the CMS to manage a list or nested lists of @@ -20,10 +24,13 @@ class ElementEditor extends PureComponent { this.state = { dragTargetElementId: null, dragSpot: null, + elements: null, + isLoading: true, }; this.handleDragOver = this.handleDragOver.bind(this); this.handleDragEnd = this.handleDragEnd.bind(this); + this.fetchElements = this.fetchElements.bind(this); } /** @@ -47,18 +54,18 @@ class ElementEditor extends PureComponent { /** * Hook for ReactDND triggered when a drag source is dropped onto a drag target. * - * This will fire the GraphQL mutation for sorting and reset any state updates - * * @param sourceId * @param afterId */ handleDragEnd(sourceId, afterId) { - const { actions: { handleSortBlock }, areaId } = this.props; - - handleSortBlock(sourceId, afterId, areaId).then(() => { - const preview = window.jQuery('.cms-preview'); - preview.entwine('ss.preview')._loadUrl(preview.find('iframe').attr('src')); - }); + const url = `${getConfig().controllerLink.replace(/\/$/, '')}/api/sort`; + backend.post(url, { + ID: sourceId, + afterBlockID: afterId, + }, { + SecurityID: Config.get('SecurityID') + }) + .then(() => this.fetchElements()); this.setState({ dragTargetElementId: null, @@ -66,6 +73,35 @@ class ElementEditor extends PureComponent { }); } + /** + * Make an API call to readAll elements endpoint (areaID) + */ + fetchElements(doSetLoadingState = true) { + if (doSetLoadingState) { + this.setState(prevState => ({ + ...prevState, + isLoading: true, + })); + } + const url = `${getConfig().controllerLink.replace(/\/$/, '')}/api/readElements/${this.props.areaId}`; + return backend.get(url, { + SecurityID: Config.get('SecurityID') + }) + .then(response => response.json()) + .then(responseJson => { + this.setState(prevState => ({ + ...prevState, + elements: responseJson, + isLoading: false, + })); + // refresh preview + const preview = window.jQuery('.cms-preview'); + if (preview) { + preview.entwine('ss.preview')._loadUrl(preview.find('iframe').attr('src')); + } + }); + } + render() { const { ToolbarComponent, @@ -76,34 +112,51 @@ class ElementEditor extends PureComponent { connectDropTarget, allowedElements, sharedObject, + isLoading, } = this.props; - const { dragTargetElementId, dragSpot } = this.state; + const { dragTargetElementId, dragSpot, elements } = this.state; + + if (elements === null) { + this.fetchElements(false); + return null; + } // Map the allowed elements because we want to retain the sort order provided by that array. const allowedElementTypes = allowedElements.map(className => elementTypes.find(type => type.class === className) ); + // Need to convert this to a functional component in order to resolve the following eslint warning: + // warning The 'providerValue' object (at line 124) passed as the value prop to the Context provider (at line 127) changes every render. To fix this consider wrapping it in a useMemo hook + // eslint-disable-next-line react/jsx-no-constructed-context-values + const providerValue = { + fetchElements: this.fetchElements, + }; + return connectDropTarget(
- - - + + + + +
); } @@ -119,7 +172,8 @@ ElementEditor.propTypes = { }; export { ElementEditor as Component }; -export default compose( + +const params = [ withDragDropContext, DropTarget('element', {}, (connector, monitor) => ({ connectDropTarget: connector.dropTarget(), @@ -132,6 +186,7 @@ export default compose( ListComponent, }), () => 'ElementEditor' - ), - sortBlockMutation -)(ElementEditor); + ) +]; + +export default compose(...params)(ElementEditor); diff --git a/client/src/components/ElementEditor/ElementList.js b/client/src/components/ElementEditor/ElementList.js index 8ee7adb4..9704f564 100644 --- a/client/src/components/ElementEditor/ElementList.js +++ b/client/src/components/ElementEditor/ElementList.js @@ -30,15 +30,19 @@ class ElementList extends Component { } componentDidUpdate(prevProps, prevState) { - // Scenario: blocks props just changed after a graphql query response updated it - if (this.props.blocks !== prevProps.blocks) { + // Don't do anything if elements have not yet been recieved from xhr request + if (!this.props.elements) { + return; + } + // Scenario: elements props just changed after an xhr response updated it + if (this.props.elements !== prevProps.elements) { this.resetState(prevState, false); return; } // Scenario Saving all elements and state has just updated because of a formSchema response from // an inline save - see Element.js handleFormSchemaSubmitResponse() if (this.state.saveAllElements) { - const unsavedChangesBlockIDs = this.props.blocks + const unsavedChangesBlockIDs = this.props.elements .map(block => parseInt(block.id, 10)) .filter(blockID => this.state.hasUnsavedChangesBlockIDs[blockID]); const allValidated = unsavedChangesBlockIDs.every(blockID => this.state.validBlockIDs[blockID] !== null); @@ -64,9 +68,9 @@ class ElementList extends Component { // - true: saved, valid // - false: attempted save, invalid const validBlockIDs = {}; - const blocks = this.props.blocks || []; - blocks.forEach(block => { - const blockID = parseInt(block.id, 10); + const elements = this.props.elements || []; + elements.forEach(element => { + const blockID = parseInt(element.id, 10); if (resetHasUnsavedChangesBlockIDs) { hasUnsavedChangesBlockIDs[blockID] = false; } else if (prevState.hasUnsavedChangesBlockIDs.hasOwnProperty(blockID)) { @@ -111,9 +115,9 @@ class ElementList extends Component { } getDragIndicatorIndex() { - const { dragTargetElementId, draggedItem, blocks, dragSpot } = this.props; + const { dragTargetElementId, draggedItem, elements, dragSpot } = this.props; return getDragIndicatorIndex( - blocks.map(element => element.id), + elements.map(element => element.id), dragTargetElementId, draggedItem && draggedItem.id, dragSpot @@ -122,15 +126,14 @@ class ElementList extends Component { /** * Renders a list of Element components, each with an elementType object - * of data mapped into it. The data is provided by a GraphQL HOC registered - * in registerTransforms.js. + * of data mapped into it. */ renderBlocks() { const { ElementComponent, HoverBarComponent, DragIndicatorComponent, - blocks, + elements, allowedElementTypes, elementTypes, areaId, @@ -140,16 +143,11 @@ class ElementList extends Component { isDraggingOver, } = this.props; - // Blocks can be either null or an empty array - if (!blocks) { - return null; - } - - if (blocks && !blocks.length) { + if (elements.length === 0) { return
{i18n._t('ElementList.ADD_BLOCKS', 'Add blocks to place your content')}
; } - let output = blocks.map(element => { + let output = elements.map(element => { const saveElement = this.state.saveAllElements && this.state.hasUnsavedChangesBlockIDs[element.id] && this.state.validBlockIDs[element.id] === null; @@ -203,19 +201,23 @@ class ElementList extends Component { * @returns {LoadingComponent|null} */ renderLoading() { - const { loading, LoadingComponent } = this.props; + const { + isLoading, + LoadingComponent + } = this.props; - if (loading) { + if (isLoading) { return ; } return null; } render() { - const { blocks } = this.props; + const { elements } = this.props; + const listClassNames = classNames( 'elemental-editor-list', - { 'elemental-editor-list--empty': !blocks || !blocks.length } + { 'elemental-editor-list--empty': !elements || !elements.length } ); return this.props.connectDropTarget( @@ -228,10 +230,9 @@ class ElementList extends Component { } ElementList.propTypes = { - blocks: PropTypes.arrayOf(elementType), + elements: PropTypes.arrayOf(elementType).isRequired, elementTypes: PropTypes.arrayOf(elementTypeType).isRequired, allowedElementTypes: PropTypes.arrayOf(elementTypeType).isRequired, - loading: PropTypes.bool, areaId: PropTypes.number.isRequired, dragTargetElementId: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), onDragOver: PropTypes.func, @@ -241,19 +242,19 @@ ElementList.propTypes = { }; ElementList.defaultProps = { - blocks: [], - loading: false, sharedObject: { entwineResolve: () => {}, setState: null, }, + elements: [], + isLoading: false, }; export { ElementList as Component }; const elementListTarget = { drop(props, monitor) { - const { blocks } = props; + const { elements } = props; const elementTargetDropResult = monitor.getDropResult(); if (!elementTargetDropResult) { @@ -261,12 +262,12 @@ const elementListTarget = { } const dropIndex = getDragIndicatorIndex( - blocks.map(element => element.id), + elements.map(element => element.id), elementTargetDropResult.target, monitor.getItem(), elementTargetDropResult.dropSpot, ); - const dropAfterID = blocks[dropIndex - 1] ? blocks[dropIndex - 1].id : '0'; + const dropAfterID = elements[dropIndex - 1] ? elements[dropIndex - 1].id : '0'; return { ...elementTargetDropResult, diff --git a/client/src/components/ElementEditor/tests/Element-test.js b/client/src/components/ElementEditor/tests/Element-test.js index ba564b0b..7f6de2d5 100644 --- a/client/src/components/ElementEditor/tests/Element-test.js +++ b/client/src/components/ElementEditor/tests/Element-test.js @@ -2,9 +2,9 @@ /* global jest, test, describe, it, expect */ import React from 'react'; -import { ApolloClient, ApolloProvider, InMemoryCache } from '@apollo/client'; import { render } from '@testing-library/react'; import { Component as Element } from '../Element'; +import { ElementEditorContext } from '../ElementEditor'; function makeProps(obj = {}) { return { @@ -45,81 +45,98 @@ function makeProps(obj = {}) { }; } +function makeProviderProps(obj = {}) { + return { + value: { + fetchElements: () => {}, + ...obj, + } + }; +} + test('Element should render the HeaderComponent and the ContentComponent', () => { - const client = new ApolloClient({ cache: new InMemoryCache() }); - const { container } = render(); + const { container } = render( + + + + ); expect(container.querySelectorAll('.element-editor__element .test-header')).toHaveLength(1); expect(container.querySelectorAll('.element-editor__element .test-content')).toHaveLength(1); }); test('Element should not render at all if no ID is given', () => { - const client = new ApolloClient({ cache: new InMemoryCache() }); const { container } = render( - + + + ); expect(container.querySelectorAll('.element-editor__element')).toHaveLength(0); }); test('Element should render even if the element is broken', () => { - const client = new ApolloClient({ cache: new InMemoryCache() }); const { container } = render( - + + + ); expect(container.querySelectorAll('.element-editor__element .test-header')).toHaveLength(1); expect(container.querySelectorAll('.element-editor__element .test-content')).toHaveLength(1); }); test('Element getVersionedStateClassName() should identify draft elements', () => { - const client = new ApolloClient({ cache: new InMemoryCache() }); const { container } = render( - + + + ); expect(container.querySelector('.element-editor__element').classList.contains('element-editor__element--draft')).toBe(true); }); test('Element getVersionedStateClassName() should identify modified elements', () => { - const client = new ApolloClient({ cache: new InMemoryCache() }); const { container } = render( - + + + ); expect(container.querySelectorAll('.element-editor__element--modified')).toHaveLength(1); }); test('Element getVersionedStateClassName() should identify published elements', () => { - const client = new ApolloClient({ cache: new InMemoryCache() }); const { container } = render( - + + + ); expect(container.querySelectorAll('.element-editor__element--published')).toHaveLength(1); }); diff --git a/client/src/components/ElementEditor/tests/ElementEditor-test.js b/client/src/components/ElementEditor/tests/ElementEditor-test.js index 39f9213b..93045074 100644 --- a/client/src/components/ElementEditor/tests/ElementEditor-test.js +++ b/client/src/components/ElementEditor/tests/ElementEditor-test.js @@ -5,6 +5,24 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import { Component as ElementEditor } from '../ElementEditor'; +jest.mock('lib/Backend', () => ({ + get: () => Promise.resolve({ json: () => [] }), +})); + +const sectionConfigKey = 'DNADesign\\Elemental\\Controllers\\ElementalAreaController'; +window.ss.config = { + SecurityID: 1234567890, + sections: [ + { + name: sectionConfigKey, + controllerLink: 'my/test/endpoint', + }, + ], +}; + +const jQuery = jest.fn(); +window.jQuery = jQuery; + function makeProps(obj = {}) { return { ToolbarComponent: ({ elementTypes }) =>
type.class).join(',')} />, @@ -53,28 +71,31 @@ function makeProps(obj = {}) { }; } -test('ElementEditor should render ElementList and Toolbar', () => { +test('ElementEditor should render ElementList and Toolbar', async () => { const { container } = render(); + await screen.findByTestId('test-toolbar'); expect(container.querySelectorAll('.test-list')).toHaveLength(1); expect(container.querySelectorAll('[data-testid="test-toolbar"]')).toHaveLength(1); }); -test('ElementEditor should filter all element types by those allowed for this editor', () => { +test('ElementEditor should filter all element types by those allowed for this editor', async () => { render( ); + await screen.findByTestId('test-toolbar'); expect(screen.getByTestId('test-toolbar').getAttribute('data-elementtypes')).toBe('Test\\Class\\Aye'); }); -test('ElementEditor should retain the order specified by the allowed elements config', () => { +test('ElementEditor should retain the order specified by the allowed elements config', async () => { render( ); + await screen.findByTestId('test-toolbar'); expect(screen.getByTestId('test-toolbar').getAttribute('data-elementtypes')).toBe('Test\\Class\\Bee,Test\\Class\\TestElement'); }); diff --git a/client/src/components/ElementEditor/tests/ElementList-test.js b/client/src/components/ElementEditor/tests/ElementList-test.js index 94628c8d..186cc298 100644 --- a/client/src/components/ElementEditor/tests/ElementList-test.js +++ b/client/src/components/ElementEditor/tests/ElementList-test.js @@ -17,7 +17,7 @@ const elementTypes = [ function makeProps(obj = {}) { return { key: '1', - blocks: [ + elements: [ { id: '1', title: 'Title', @@ -53,7 +53,7 @@ function makeProps(obj = {}) { }; } -test('ElementList renders elements when blocks are provided as props', () => { +test('ElementList renders elements when elements are provided as props', () => { const { container } = render(); expect(container.querySelectorAll('.test-element')).toHaveLength(2); expect(container.querySelectorAll('.test-loading')).toHaveLength(0); @@ -63,8 +63,8 @@ test('ElementList renders a loading component', () => { const { container } = render( ); @@ -76,8 +76,8 @@ test('ElementList renders a placeholder message when no elements are provided as const { container } = render( ); diff --git a/client/src/legacy/ElementEditor/entwine.js b/client/src/legacy/ElementEditor/entwine.js index 68fd4024..91123572 100644 --- a/client/src/legacy/ElementEditor/entwine.js +++ b/client/src/legacy/ElementEditor/entwine.js @@ -9,14 +9,9 @@ import { getConfig } from 'state/editor/elementConfig'; import { destroy } from 'redux-form'; /** - * Reset the Apollo and Redux stores holding data relating to elemental inline edit forms + * Reset the Redux store holding data relating to elemental inline edit forms */ const resetStores = () => { - // After page level saves we need to reload all the blocks from the server. We can remove - // this if we can figure out a way to optimistically update the apollo cache. See: - // https://github.com/dnadesign/silverstripe-elemental/pull/439#issuecomment-428773370 - window.ss.apolloClient.resetStore(); - // Defer playing with redux store setTimeout(() => { // After the page submit we want to destroy the form values so it's reloaded. We can't @@ -133,7 +128,7 @@ jQuery.entwine('ss', ($) => { const validationResultPjax = JSON.parse(data.xhr.responseText).ValidationResult; const validationResult = JSON.parse(validationResultPjax.replace(/<\/?script[^>]*?>/g, '')); - // Reset redux store if form is succesfully submitted so apollo to refetches element data + // Reset redux store if form is succesfully submitted // Do not reset if there are any validation errors because we want redux to hydrate the // form, rather than then refetching which will return a value from the database. // Instead the user should still see any modfied value they just entered. diff --git a/client/src/state/editor/addElementMutation.js b/client/src/state/editor/addElementMutation.js deleted file mode 100644 index e61223fc..00000000 --- a/client/src/state/editor/addElementMutation.js +++ /dev/null @@ -1,42 +0,0 @@ -import { graphql } from '@apollo/client/react/hoc'; -import gql from 'graphql-tag'; -import { query as readBlocksQuery, config as readBlocksConfig } from './readBlocksForAreaQuery'; - -// GraphQL query for deleting a specific block -const mutation = gql` -mutation AddElementToArea($className: String!, $elementalAreaID: ID!, $afterElementID: ID) { - addElementToArea( - className: $className, - elementalAreaID: $elementalAreaID, - afterElementID: $afterElementID - ) { - id - } -} -`; - -const config = { - props: ({ mutate, ownProps: { actions, areaId } }) => { - const handleAddElementToArea = (className, afterElementID) => mutate({ - variables: { className, elementalAreaID: areaId, afterElementID }, - }); - - return { - actions: { - ...actions, - handleAddElementToArea, - }, - }; - }, - options: ({ areaId }) => ({ - // Refetch versions after mutation is completed - refetchQueries: [{ - query: readBlocksQuery, - variables: readBlocksConfig.options({ areaId }).variables - }] - }) -}; - -export { mutation, config }; - -export default graphql(mutation, config); diff --git a/client/src/state/editor/archiveBlockMutation.js b/client/src/state/editor/archiveBlockMutation.js deleted file mode 100644 index 2b12fb39..00000000 --- a/client/src/state/editor/archiveBlockMutation.js +++ /dev/null @@ -1,36 +0,0 @@ -import { graphql } from '@apollo/client/react/hoc'; -import gql from 'graphql-tag'; -import { config as readBlocksConfig, query as readBlocksQuery } from './readBlocksForAreaQuery'; - -// GraphQL query for deleting a specific block -const mutation = gql` -mutation ArchiveBlock($blockId: ID!) { - deleteBlocks(ids: [$blockId]) -} -`; - -const config = { - props: ({ mutate, ownProps: { actions } }) => { - const handleArchiveBlock = (blockId) => mutate({ - variables: { blockId }, - }); - - return { - actions: { - ...actions, - handleArchiveBlock, - }, - }; - }, - options: ({ areaId }) => ({ - // Refetch versions after mutation is completed - refetchQueries: [{ - query: readBlocksQuery, - variables: readBlocksConfig.options({ areaId }).variables - }] - }), -}; - -export { mutation, config }; - -export default graphql(mutation, config); diff --git a/client/src/state/editor/duplicateBlockMutation.js b/client/src/state/editor/duplicateBlockMutation.js deleted file mode 100644 index 5e36496a..00000000 --- a/client/src/state/editor/duplicateBlockMutation.js +++ /dev/null @@ -1,38 +0,0 @@ -import { graphql } from '@apollo/client/react/hoc'; -import gql from 'graphql-tag'; -import { config as readBlocksConfig, query as readBlocksQuery } from './readBlocksForAreaQuery'; - -// GraphQL query for duplicating a specific block -const mutation = gql` -mutation DuplicateBlock($blockId: ID!) { - duplicateBlock(id: $blockId) { - id - } -} -`; - -const config = { - props: ({ mutate, ownProps: { actions } }) => { - const handleDuplicateBlock = (blockId) => mutate({ - variables: { blockId }, - }); - - return { - actions: { - ...actions, - handleDuplicateBlock, - }, - }; - }, - options: ({ areaId }) => ({ - // Refetch versions after mutation is completed - refetchQueries: [{ - query: readBlocksQuery, - variables: readBlocksConfig.options({ areaId }).variables - }] - }), -}; - -export { mutation, config }; - -export default graphql(mutation, config); diff --git a/client/src/state/editor/publishBlockMutation.js b/client/src/state/editor/publishBlockMutation.js deleted file mode 100644 index 9f54f2e8..00000000 --- a/client/src/state/editor/publishBlockMutation.js +++ /dev/null @@ -1,9 +0,0 @@ -import gql from 'graphql-tag'; - -export const publishBlockMutation = gql` -mutation PublishBlock($blockId:ID!) { - publishBlock(id: $blockId) { - id - } -} -`; diff --git a/client/src/state/editor/readBlocksForAreaQuery.js b/client/src/state/editor/readBlocksForAreaQuery.js deleted file mode 100644 index 9b9488c3..00000000 --- a/client/src/state/editor/readBlocksForAreaQuery.js +++ /dev/null @@ -1,65 +0,0 @@ -import { graphql } from '@apollo/client/react/hoc'; -import gql from 'graphql-tag'; - -// GraphQL query for retrieving the current state of elements for an area. The results of the query -// must be set to the "blocks" prop on the component that this HOC is applied to for binding -// implementation. -const query = gql` -query ReadBlocksForArea($id:ID!) { - readOneElementalArea(filter: { id: { eq: $id } }, versioning: { - mode: DRAFT - }){ - elements { - id - title - blockSchema - obsoleteClassName - isLiveVersion - isPublished - version - canCreate - canPublish - canUnpublish - canDelete - } - } -} -`; - -const config = { - options({ areaId }) { - return { - variables: { - id: areaId, - } - }; - }, - props( - { - data: { - error, - readOneElementalArea, - loading: networkLoading, - }, - } - ) { - let blocks = null; - if (readOneElementalArea) { - // Remove the GraphQL pagination keys - blocks = readOneElementalArea.elements; - } - - const errors = error && error.graphQLErrors && - error.graphQLErrors.map((graphQLError) => graphQLError.message); - - return { - loading: networkLoading || !blocks, - blocks, - graphQLErrors: errors, - }; - }, -}; - -export { query, config }; - -export default graphql(query, config); diff --git a/client/src/state/editor/sortBlockMutation.js b/client/src/state/editor/sortBlockMutation.js deleted file mode 100644 index 71dedc0b..00000000 --- a/client/src/state/editor/sortBlockMutation.js +++ /dev/null @@ -1,92 +0,0 @@ -import { graphql } from '@apollo/client/react/hoc'; -import gql from 'graphql-tag'; -import { query as readBlocksQuery, config as readBlocksConfig } from './readBlocksForAreaQuery'; - -// GraphQL query for changing the sort order of blocks -const mutation = gql` -mutation SortBlockMutation($blockId:ID!, $afterBlockId:ID!) { - sortBlock( - id: $blockId - afterBlockID: $afterBlockId - ) { - id - isLiveVersion - isPublished - } -} -`; - -const config = { - props: ({ mutate, ownProps: { actions } }) => { - const handleSortBlock = (blockId, afterBlockId, areaId) => mutate({ - variables: { - blockId, - afterBlockId, - }, - optimisticResponse: { - sortBlock: { - id: blockId, - isLiveVersion: false, - isPublished: false, - __typename: 'Block', - }, - }, - update: (store, { data: { sortBlock: updatedElementData } }) => { - const variables = readBlocksConfig.options({ areaId }).variables; - const cachedData = store.readQuery({ query: readBlocksQuery, variables }); - - // Query returns a deeply nested object. Explicit reconstruction via spreads is too verbose. - // This is an alternative, relatively efficient way to deep clone - const newData = JSON.parse(JSON.stringify(cachedData)); - let blocks = newData.readOneElementalArea.elements; - // Find the block we reordered - const movedBlockIndex = blocks.findIndex(block => block.id === blockId); - // Keep it - const movedBlock = blocks[movedBlockIndex]; - // Update the moved block with the new details returned in the GraphQL response - Object.entries(updatedElementData).forEach(([key, value]) => { - // Skip the type name as this is always returned but should never change - if (key === '__typename') { - return; - } - - movedBlock[key] = value; - }); - // Remove the moved block - blocks.splice(movedBlockIndex, 1); - // If the target is 0, it's moving to the start - if (afterBlockId === '0') { - blocks.unshift(movedBlock); - } else { - // Else, find the block we inserted after - let targetBlockIndex = blocks.findIndex(block => block.id === afterBlockId); - - // If we can't find the block, it must be the one we're trying to move - put it back! - if (targetBlockIndex === -1) { - targetBlockIndex = movedBlockIndex - 1; - } - - // Add it back after the target - const end = blocks.slice(targetBlockIndex + 1); - blocks = blocks.slice(0, targetBlockIndex + 1); - blocks.push(movedBlock); - blocks = blocks.concat(end); - } - - // Add it back to the full result - newData.readOneElementalArea.elements = blocks; - store.writeQuery({ query: readBlocksQuery, data: newData, variables }); - }, - }); - return { - actions: { - ...actions, - handleSortBlock, - }, - }; - }, -}; - -export { mutation, config }; - -export default graphql(mutation, config); diff --git a/client/src/state/editor/unpublishBlockMutation.js b/client/src/state/editor/unpublishBlockMutation.js deleted file mode 100644 index 261bcb1f..00000000 --- a/client/src/state/editor/unpublishBlockMutation.js +++ /dev/null @@ -1,45 +0,0 @@ -import { graphql } from '@apollo/client/react/hoc'; -import gql from 'graphql-tag'; -import { config as readBlocksConfig, query as readBlocksQuery } from './readBlocksForAreaQuery'; - -// GraphQL query for unpublishing a specific block -const mutation = gql` -mutation UnpublishBlock($blockId:ID!) { - unpublishBlock( - id: $blockId - ) { - id - } -} -`; - -const config = { - props: ({ mutate, ownProps: { actions } }) => { - const handleUnpublishBlock = (blockId, fromStage, toStage, fromVersion) => mutate({ - variables: { - blockId, - fromStage, - toStage, - fromVersion - }, - }); - - return { - actions: { - ...actions, - handleUnpublishBlock, - }, - }; - }, - options: ({ areaId }) => ({ - // Refetch versions after mutation is completed - refetchQueries: [{ - query: readBlocksQuery, - variables: readBlocksConfig.options({ areaId }).variables - }] - }), -}; - -export { mutation, config }; - -export default graphql(mutation, config); diff --git a/client/src/state/history/readOneBlockQuery.js b/client/src/state/history/readOneBlockQuery.js deleted file mode 100644 index af211a61..00000000 --- a/client/src/state/history/readOneBlockQuery.js +++ /dev/null @@ -1,96 +0,0 @@ -import { graphql } from '@apollo/client/react/hoc'; -import gql from 'graphql-tag'; - -// GraphQL query for retrieving the version history of a specific block. The results of -// the query must be set to the "versions" prop on the component that this HOC is -// applied to for binding implementation. -const query = gql` -query ReadHistoryViewerBlock ($block_id: ID!, $limit: Int!, $offset: Int!) { - readOneBlock( - versioning: { - mode: LATEST - }, - filter: { id: { eq: $block_id } } - ) { - id - versions (limit: $limit, offset: $offset, sort: { version: DESC }) { - pageInfo { - totalCount - } - nodes { - version - absoluteLink - author { - firstName - surname - } - publisher { - firstName - surname - } - published - liveVersion - latestDraftVersion - lastEdited - } - } - } -} -`; - -const config = { - options({ recordId, limit, page }) { - return { - variables: { - limit, - offset: ((page || 1) - 1) * limit, - block_id: recordId, - } - }; - }, - props( - { - data: { - error, - refetch, - readOneBlock, - loading: networkLoading, - }, - ownProps: { - actions = { - versions: {} - }, - limit, - recordId, - }, - } - ) { - const versions = readOneBlock || null; - - const errors = error && error.graphQLErrors && - error.graphQLErrors.map((graphQLError) => graphQLError.message); - - return { - loading: networkLoading || !versions, - versions, - graphQLErrors: errors, - actions: { - ...actions, - versions: { - ...versions, - goToPage(page) { - refetch({ - offset: ((page || 1) - 1) * limit, - limit, - block_id: recordId, - }); - } - }, - }, - }; - }, -}; - -export { query, config }; - -export default graphql(query, config); diff --git a/client/src/state/history/revertToBlockVersionMutation.js b/client/src/state/history/revertToBlockVersionMutation.js deleted file mode 100644 index ef2de656..00000000 --- a/client/src/state/history/revertToBlockVersionMutation.js +++ /dev/null @@ -1,43 +0,0 @@ -import { graphql } from '@apollo/client/react/hoc'; -import gql from 'graphql-tag'; - -const mutation = gql` -mutation revertBlockToVersion($id:ID!, $fromStage:VersionedStage!, $toStage:VersionedStage!, $fromVersion:Int!) { - copyBlockToStage(input: { - id: $id - fromVersion: $fromVersion - fromStage: $fromStage - toStage: $toStage - }) { - id - } -} -`; - -const config = { - props: ({ mutate, ownProps: { actions } }) => { - const revertToVersion = (id, fromVersion, fromStage, toStage) => mutate({ - variables: { - id, - fromVersion, - fromStage, - toStage, - }, - }); - - return { - actions: { - ...actions, - revertToVersion, - }, - }; - }, - options: { - // Refetch versions after mutation is completed - refetchQueries: ['ReadHistoryViewerBlock'] - } -}; - -export { mutation, config }; - -export default graphql(mutation, config); diff --git a/client/src/state/history/revertToBlockVersionRequest.js b/client/src/state/history/revertToBlockVersionRequest.js new file mode 100644 index 00000000..c100ef59 --- /dev/null +++ b/client/src/state/history/revertToBlockVersionRequest.js @@ -0,0 +1,26 @@ +import React from 'react'; +import backend from 'lib/Backend'; +import { getConfig } from 'state/editor/elementConfig'; +import Config from 'lib/Config'; + +// TODO: See if it's viable to move this out of 'state' and 'registerTransforms' +const revertToBlockVersionRequest = (HistoryViewerVersionDetailComponent) => (props) => { + const newProps = { ...props }; + if (!newProps.hasOwnProperty('actions')) { + newProps.actions = {}; + } + newProps.actions.revertToVersion = (id, fromVersion, fromStage, toStage) => { + const url = `${getConfig().controllerLink.replace(/\/$/, '')}/api/revert`; + return backend.post(url, { + ID: id, + fromVersion, + fromStage, + toStage + }, { + SecurityID: Config.get('SecurityID') + }); + }; + return ; +}; + +export default revertToBlockVersionRequest; diff --git a/client/src/types/elementTypeType.js b/client/src/types/elementTypeType.js index fcc28308..e80dc1a9 100644 --- a/client/src/types/elementTypeType.js +++ b/client/src/types/elementTypeType.js @@ -2,7 +2,7 @@ import PropTypes from 'prop-types'; // Describes the structure of an element type: const elementTypeType = PropTypes.shape({ - // The GraphQL typeName of the element + // The typeName of the element name: PropTypes.string, // The "name" of the type (eg. "Content") title: PropTypes.string, diff --git a/composer.json b/composer.json index 1d469bfe..1359a63a 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,6 @@ "silverstripe/admin": "^3", "silverstripe/versioned": "^3", "silverstripe/versioned-admin": "^3", - "silverstripe/graphql": "^6", "symbiote/silverstripe-gridfieldextensions": "^5", "silverstripe/vendor-plugin": "^2" }, diff --git a/package.json b/package.json index 8ea978eb..23ff4148 100644 --- a/package.json +++ b/package.json @@ -33,12 +33,9 @@ }, "homepage": "https://github.com/dnadesign/silverstripe-elemental#readme", "dependencies": { - "@apollo/client": "^3.7.1", "@popperjs/core": "^2.11.6", "bootstrap": "^4.6.2", "classnames": "^2.3.2", - "graphql": "^16.8.1", - "graphql-tag": "^2.12.6", "prop-types": "^15.8.1", "react": "^18.2.0", "react-dnd": "^5.0.0", @@ -51,7 +48,7 @@ }, "devDependencies": { "@silverstripe/eslint-config": "^1.3.0", - "@silverstripe/webpack-config": "^2.1.0", + "@silverstripe/webpack-config": "^3.0.0-alpha1", "@testing-library/react": "^14.0.0", "babel-jest": "^29.2.2", "jest-cli": "^29.2.2", diff --git a/src/Controllers/ElementalAreaController.php b/src/Controllers/ElementalAreaController.php index 9cad61e9..bcd2557f 100644 --- a/src/Controllers/ElementalAreaController.php +++ b/src/Controllers/ElementalAreaController.php @@ -15,6 +15,13 @@ use SilverStripe\Forms\FormAction; use SilverStripe\Forms\FieldList; use SilverStripe\Control\Controller; +use InvalidArgumentException; +use DNADesign\Elemental\Models\ElementalArea; +use DNADesign\Elemental\Services\ReorderElements; +use SilverStripe\Control\Director; +use SilverStripe\Versioned\Versioned; +use Exception; +use SilverStripe\Control\HTTPRequest; /** * Controller for "ElementalArea" - handles loading and saving of in-line edit forms in an elemental area in admin @@ -29,16 +36,248 @@ class ElementalAreaController extends CMSMain private static $url_handlers = [ 'elementForm/$ItemID' => 'elementForm', - 'POST api/saveForm/$ID' => 'apiSaveForm', '$FormName/field/$FieldName' => 'formAction', + 'GET api/readElements/$elementalAreaID!' => 'apiReadElements', + 'POST api/add' => 'apiAdd', + 'POST api/archive' => 'apiArchive', + 'POST api/duplicate' => 'apiDuplicate', + 'POST api/publish' => 'apiPublish', + 'POST api/revert' => 'apiRevert', + 'POST api/saveForm/$ID' => 'apiSaveForm', + 'POST api/sort' => 'apiSort', + 'POST api/unpublish' => 'apiUnpublish', ]; private static $allowed_actions = [ 'elementForm', - 'apiSaveForm', 'formAction', + 'apiReadElements', + 'apiAdd', + 'apiArchive', + 'apiDuplicate', + 'apiPublish', + 'apiRevert', + 'apiSaveForm', + 'apiSort', + 'apiUnpublish', ]; + public function apiAdd(HTTPRequest $request): HTTPResponse + { + $this->checkJsonCsrfToken($request); + $postData = json_decode($request->getBody(), true); + $elementClass = $postData['elementClass']; + $elementalAreaID = $postData['elementalAreaID']; + $afterElementID = $postData['insertAfterElementID'] ?? null; + // validate post vars + if (!is_subclass_of($elementClass, BaseElement::class)) { + throw new InvalidArgumentException("$elementClass is not a subclass of " . BaseElement::class); + } + $elementalArea = ElementalArea::get()->byID($elementalAreaID); + if (!$elementalArea) { + throw new InvalidArgumentException("Invalid ElementalAreaID: $elementalAreaID"); + } + // permission checks + if (!$elementalArea->canEdit()) { + throw new InvalidArgumentException("The current user has insufficient permission to edit ElementalAreas"); + } + /** @var BaseElement $newElement */ + $newElement = Injector::inst()->create($elementClass); + if (!$newElement->canEdit()) { + throw new InvalidArgumentException( + 'The current user has insufficient permission to edit Elements' + ); + } + // Assign the parent ID directly rather than via HasManyList to prevent multiple writes. + // See BaseElement::$has_one for the "Parent" naming. + $newElement->ParentID = $elementalArea->ID; + // Ensure that a sort order is assigned - see BaseElement::ensureSortSet() + $newElement->ensureSortSet(); + if ($afterElementID !== null) { + /** @var ReorderElements $reorderer */ + $reorderer = Injector::inst()->create(ReorderElements::class, $newElement); + $reorderer->reorder($afterElementID); // also writes the element + } else { + $newElement->write(); + } + $response = $this->getResponse(); + $response->setStatusCode(201); + return $response; + } + + public function apiArchive(HTTPRequest $request): HTTPResponse + { + $this->checkJsonCsrfToken($request); + $id = $this->getPostData()['ID'] ?? ''; + $element = BaseElement::get()->byID($id); + if (!$element) { + $this->jsonError(400, "Element with ID $id does not exist"); + } + if (!$element->canDelete()) { + $this->jsonError(403, "Unable to delete element with ID $id"); + } + $element->doArchive(); + return $this->jsonSuccess(204); + } + + public function apiDuplicate(HTTPRequest $request): HTTPResponse + { + $this->checkJsonCsrfToken($request); + $id = $this->getPostData()['ID'] ?? ''; + $element = BaseElement::get()->byID($id); + if (!$element) { + $this->jsonError(400, "Element with ID $id does not exist"); + } + // check can edit the elemental area + $areaID = $element->ParentID; + $area = ElementalArea::get()->byID($areaID); + if (!$area) { + $this->jsonError(400, "Invalid ParentID on BaseElement $id"); + } + if (!$area->canEdit()) { + $this->jsonError(403, "Unable to edit element with ID $id"); + } + try { + // clone element + $clone = $element->duplicate(false); + $clone->Title = $this->getNewTitle($clone->Title ?? ''); + $clone->Sort = 0; // must be zeroed for reorder to work + $area->Elements()->add($clone); + // reorder + $reorderer = Injector::inst()->create(ReorderElements::class, $clone); + $reorderer->reorder($id); + return $this->jsonSuccess(204); + } catch (Exception) { + $this->jsonError(500, "Something went wrong when duplicating element with ID $id"); + } + } + + public function apiPublish(HTTPRequest $request): HTTPResponse + { + $this->checkJsonCsrfToken($request); + $id = $this->getPostData()['ID'] ?? ''; + $element = BaseElement::get()->byID($id); + if (!$element) { + $this->jsonError(400, "Element with ID $id does not exist"); + } + if (!$element->canPublish()) { + $this->jsonError(403, "Unable to publish element with ID $id"); + } + $element->publishRecursive(); + return $this->jsonSuccess(204); + } + + public function apiReadElements(HTTPRequest $request): HTTPResponse + { + $this->checkJsonCsrfToken($request); + $request = $this->getRequest(); + $elementalAreaID = $request->param('elementalAreaID'); + $elementalArea = ElementalArea::get()->byID($elementalAreaID); + if (!$elementalArea) { + $this->jsonError(404); + } + if (!$elementalArea->canView()) { + $this->jsonError(403); + } + $data = []; + foreach ($elementalArea->Elements() as $element) { + if (!$element->canView()) { + continue; + } + $data[] = [ + 'id' => (string) $element->ID, + 'title' => $element->Title, + 'blockSchema' => $element->getBlockSchema(), + 'obsoleteClassName' => $element->getObsoleteClassName(), + 'version' => $element->Version, + 'isPublished' => $element->isPublished(), + 'isLiveVersion' => $element->isLiveVersion(), + 'canDelete' => $element->canDelete(), + 'canPublish' => $element->canPublish(), + 'canUnpublish' => $element->canUnpublish(), + 'canCreate' => $element->canCreate(), + ]; + } + return $this->jsonSuccess(200, $data); + } + + public function apiRevert(HTTPRequest $request): HTTPResponse + { + $this->checkJsonCsrfToken($request); + $postData = $this->getPostData(); + $id = $postData['ID'] ?? ''; + $fromVersion = (int) $postData['fromVersion'] ?? 0; + $fromStage = ucfirst(strtolower($postData['fromStage'])) ?? ''; + if ($fromStage === 'Draft') { + $fromStage = 'Stage'; + } + $toStage = ucfirst(strtolower($postData['toStage'])) ?? ''; + if ($toStage === 'Draft') { + $toStage = 'Stage'; + } + if (!in_array($fromStage, ['', Versioned::DRAFT, Versioned::LIVE]) + || !in_array($toStage, [Versioned::DRAFT, Versioned::LIVE]) + ) { + $this->jsonError(400, 'Invalid request'); + } + $dataClass = BaseElement::class; + $record = null; + $from = null; + // todo: elemental revert will probably only ever use one of these, so remove the other one + if ($fromVersion) { + $record = Versioned::get_version($dataClass, $id, $fromVersion); + $from = $fromVersion; + } elseif ($fromStage) { + $record = Versioned::get_by_stage($dataClass, $fromVersion)->byID($id); + $from = $fromStage; + } else { + $this->jsonError(400, 'You must provide either a fromStage or fromVersion argument'); + } + if (!$record) { + $this->jsonError(400, "Record $id not found"); + } + $can = $toStage === Versioned::LIVE ? $record->canPublish(): $record->canEdit(); + if (!$can) { + $this->jsonError(403, "Copying element from $from to $toStage is not allowed"); + } + /** @var DataObject|Versioned $record */ + $record->copyVersionToStage($from, $toStage); + return $this->jsonSuccess(201); + } + + public function apiSort(HTTPRequest $request): HTTPResponse + { + $this->checkJsonCsrfToken($request); + $postData = $this->getPostData(); + $id = $postData['ID'] ?? 0; + $afterBlockID = $postData['afterBlockID'] ?? 0; + $element = BaseElement::get()->byID($id); + if (!$element) { + $this->jsonError(404); + } + if (!$element->canEdit()) { + $this->jsonError(403); + } + $reorderingService = Injector::inst()->create(ReorderElements::class, $element); + $reorderingService->reorder($afterBlockID); + return $this->jsonSuccess(204); + } + + public function apiUnpublish(HTTPRequest $request): HTTPResponse + { + $this->checkJsonCsrfToken($request); + $id = $this->getPostData()['ID'] ?? ''; + $element = BaseElement::get()->byID($id); + if (!$element) { + $this->jsonError(400, "Element with ID $id does not exist"); + } + if (!$element->canUnpublish()) { + $this->jsonError(403, "Unable to publish element with ID $id"); + } + $element->doUnpublish(); + return $this->jsonSuccess(204); + } + public function getClientConfig() { $clientConfig = parent::getClientConfig(); @@ -46,6 +285,8 @@ public function getClientConfig() 'schemaUrl' => $this->Link('schema/elementForm'), 'formNameTemplate' => sprintf(static::FORM_NAME_TEMPLATE, '{id}'), ]; + $clientConfig['controllerLink'] = $this->Link(); + // Configuration that is available per element type $clientConfig['elementTypes'] = ElementTypeRegistry::generate()->getDefinitions(); return $clientConfig; @@ -60,7 +301,6 @@ public function getClientConfig() public function elementForm(): Form { $id = $this->getRequest()->param('ItemID'); - // Note that new elements are added via graphql, so only using this endpoint for editing existing $element = BaseElement::get()->byID($id); if (!$element) { $this->jsonError(404); @@ -89,7 +329,7 @@ public function save(array $data, Form $form): HTTPResponse { $request = $this->getRequest(); - // Check security token for non-view operation + // Check security token for non-view operation - note token is pased in POST body, not headers if (!SecurityToken::inst()->checkRequest($request)) { $this->jsonError(400); } @@ -158,6 +398,36 @@ public static function removeNamespacesFromFields(array $data, $elementID) return $output; } + private function getNewTitle(string $title = ''): ?string + { + $hasCopyPattern = '/^.*(\scopy($|\s[0-9]+$))/'; + $hasNumPattern = '/^.*(\s[0-9]+$)/'; + $parts = []; + // does $title end with 'copy' (ignoring numbers for now)? + if (preg_match($hasCopyPattern ?? '', $title ?? '', $parts)) { + $copy = $parts[1]; + // does $title end with numbers? + if (preg_match($hasNumPattern ?? '', $copy ?? '', $parts)) { + $num = trim($parts[1] ?? ''); + $len = strlen($num ?? ''); + $inc = (int)$num + 1; + return substr($title ?? '', 0, -$len) . "$inc"; + } else { + return $title . ' 2'; + } + } else { + return $title . ' copy'; + } + } + + // TODO: upgrade to AssesAdmin:: get-post-data + private function getPostData() + { + $request = $this->getRequest(); + $postData = json_decode($request->getBody(), true); + return $postData; + } + /** * Create a form for a given element */ diff --git a/src/GraphQL/Resolvers/Resolver.php b/src/GraphQL/Resolvers/Resolver.php deleted file mode 100644 index 2d1315e7..00000000 --- a/src/GraphQL/Resolvers/Resolver.php +++ /dev/null @@ -1,197 +0,0 @@ -value; - } - - /** - * @param $obj - * @param array $args - * @param array $context - * @param ResolveInfo $info - * @return BaseElement - * @throws ValidationException - * @throws InvalidArgumentException - */ - public static function resolveAddElementToArea( - $obj, - array $args, - array $context, - ResolveInfo $info - ): BaseElement { - $elementClass = $args['className']; - $elementalAreaID = $args['elementalAreaID']; - $afterElementID = $args['afterElementID'] ?? null; - - if (!is_subclass_of($elementClass, BaseElement::class)) { - throw new InvalidArgumentException("$elementClass is not a subclass of " . BaseElement::class); - } - - $elementalArea = ElementalArea::get()->byID($elementalAreaID); - - if (!$elementalArea) { - throw new InvalidArgumentException("Invalid ElementalAreaID: $elementalAreaID"); - } - - $member = UserContextProvider::get($context); - if (!$elementalArea->canEdit($member)) { - throw new InvalidArgumentException("The current user has insufficient permission to edit ElementalAreas"); - } - - /** @var BaseElement $newElement */ - $newElement = Injector::inst()->create($elementClass); - - $member = UserContextProvider::get($context); - if (!$newElement->canEdit($member)) { - throw new InvalidArgumentException( - 'The current user has insufficient permission to edit Elements' - ); - } - - // Assign the parent ID directly rather than via HasManyList to prevent multiple writes. - // See BaseElement::$has_one for the "Parent" naming. - $newElement->ParentID = $elementalArea->ID; - // Ensure that a sort order is assigned - $newElement->ensureSortSet(); - - if ($afterElementID !== null) { - /** @var ReorderElements $reorderer */ - $reorderer = Injector::inst()->create(ReorderElements::class, $newElement, true); - $reorderer->reorder($afterElementID); // also writes the element - } else { - $newElement->write(skipValidation: true); - } - - return $newElement; - } - - /** - * @param $object - * @param array $args - * @param $context - * @param ResolveInfo $info - * @return BaseElement - * @throws ValidationException - */ - public static function resolveDuplicateBlock($object, array $args, $context, ResolveInfo $info) - { - // load element to clone - $elementID = $args['id']; - $element = BaseElement::get_by_id($elementID); - if (!$element) { - throw new InvalidArgumentException("Invalid BaseElementID: $elementID"); - } - - // check can edit the elemental area - $areaID = $element->ParentID; - $area = ElementalArea::get_by_id($areaID); - if (!$area) { - throw new InvalidArgumentException("Invalid ParentID on BaseElement: $elementID"); - } - $member = UserContextProvider::get($context); - if (!$area->canEdit($member)) { - throw new InvalidArgumentException( - "The current user has insufficient permission to edit ElementalArea: $areaID" - ); - } - - try { - // clone element - $clone = $element->duplicate(false); - $clone->Title = static::newTitle($clone->Title ?? ''); - $clone->Sort = 0; // must be zeroed for reorder to work - $area->Elements()->add($clone); - - // reorder - $reorderer = Injector::inst()->create(ReorderElements::class, $clone); - $reorderer->reorder($elementID); - - return $clone; - } catch (Exception $e) { - throw new Exception("Something went wrong when duplicating element: $elementID"); - } - } - - public static function newTitle(string $title = ''): ?string - { - $hasCopyPattern = '/^.*(\scopy($|\s[0-9]+$))/'; - $hasNumPattern = '/^.*(\s[0-9]+$)/'; - $parts = []; - - // does $title end with 'copy' (ignoring numbers for now)? - if (preg_match($hasCopyPattern ?? '', $title ?? '', $parts)) { - $copy = $parts[1]; - // does $title end with numbers? - if (preg_match($hasNumPattern ?? '', $copy ?? '', $parts)) { - $num = trim($parts[1] ?? ''); - $len = strlen($num ?? ''); - $inc = (int)$num + 1; - return substr($title ?? '', 0, -$len) . "$inc"; - } else { - return $title . ' 2'; - } - } else { - return $title . ' copy'; - } - } - - public static function resolveSortBlock($object, array $args, $context, ResolveInfo $info) - { - $element = BaseElement::get()->byID($args['id']); - - if (!$element) { - throw new InvalidArgumentException(sprintf( - '%s#%s not found', - BaseElement::class, - $args['ID'] - )); - } - $member = UserContextProvider::get($context); - if (!$element->canEdit($member)) { - throw new InvalidArgumentException( - 'Changing the sort order of blocks is not allowed for the current user' - ); - } - - $reorderingService = Injector::inst()->create(ReorderElements::class, $element); - return $reorderingService->reorder($args['afterBlockID']); - } -} diff --git a/src/Models/BaseElement.php b/src/Models/BaseElement.php index 16513727..22ed7431 100644 --- a/src/Models/BaseElement.php +++ b/src/Models/BaseElement.php @@ -4,7 +4,6 @@ use DNADesign\Elemental\Controllers\ElementController; use DNADesign\Elemental\Forms\TextCheckboxGroupField; -use DNADesign\Elemental\ORM\FieldType\DBObjectType; use DNADesign\Elemental\TopPage\DataExtension; use Exception; use SilverStripe\CMS\Controllers\CMSPageEditController; @@ -18,8 +17,6 @@ use SilverStripe\Forms\HiddenField; use SilverStripe\Forms\NumericField; use SilverStripe\Forms\TextField; -use SilverStripe\GraphQL\Scaffolding\StaticSchema; -use SilverStripe\GraphQL\Schema\Exception\SchemaBuilderException; use SilverStripe\ORM\DataObject; use SilverStripe\ORM\FieldType\DBBoolean; use SilverStripe\ORM\FieldType\DBField; @@ -34,7 +31,6 @@ use SilverStripe\View\Requirements; use SilverStripe\ORM\CMSPreviewable; use SilverStripe\Core\Config\Config; -use SilverStripe\ORM\DataObjectSchema; use SilverStripe\ORM\ValidationResult; /** @@ -94,7 +90,6 @@ class BaseElement extends DataObject implements CMSPreviewable ]; private static $casting = [ - 'BlockSchema' => DBObjectType::class, 'IsLiveVersion' => DBBoolean::class, 'IsPublished' => DBBoolean::class, 'canCreate' => DBBoolean::class, @@ -1049,7 +1044,7 @@ public function getMimeType() /** * This can be overridden on child elements to create a summary for display in GridFields. * The react Summary component takes `content` (html) and/or `fileUrl` & `fileTitle` (image) props, - * which have to be added to the graphql output in `provideBlockSchema()`. + * which have to be added to the output in `provideBlockSchema()`. * * @return string */ @@ -1069,28 +1064,13 @@ public static function getBlockConfig() return []; } - /** - * The block actions is an associative array available for providing data to the client side to be used to describe - * actions that may be performed. This is available as a plain "ObjectType" in the GraphQL schema. - * - * By default the only action is "edit" which is simply the URL where the block may be edited. - * - * To modify the actions, either use the extension point or overload the `provideBlockSchema` method. - * - * @internal This API may change in future. Treat this as a `final` method. - * @return array - */ - public function getBlockSchema() + public function getBlockSchema(): array { - $blockSchema = $this->provideBlockSchema(); - - $this->extend('updateBlockSchema', $blockSchema); - - return $blockSchema; + return $this->provideBlockSchema(); } /** - * Provide block schema data, which will be serialised and sent via GraphQL to the editor client. + * Provide block schema data which will be sent to the editor client. * * Overload this method in child element classes to augment, or use the extension point on `getBlockSchema` * to update it from an `Extension`. @@ -1102,7 +1082,7 @@ public function getBlockSchema() protected function provideBlockSchema() { return [ - 'typeName' => static::getGraphQLTypeName(), + 'typeName' => str_replace('\\', '_', get_class($this)), 'actions' => [ 'edit' => $this->getEditLink(), ], @@ -1110,7 +1090,7 @@ protected function provideBlockSchema() ]; } - /** + /** * Generate markup for element type icons suitable for use in GridFields. * * @return null|DBHTMLText @@ -1274,12 +1254,8 @@ public function EvenOdd() /** * @return string */ - public static function getGraphQLTypeName(): string + public static function getTypeName(): string { - // For GraphQL 3, use the static schema type name - except for BaseElement for which this is inconsistent. - if (class_exists(StaticSchema::class) && static::class !== BaseElement::class) { - return StaticSchema::inst()->typeNameForDataObject(static::class); - } return str_replace('\\', '_', static::class); } } diff --git a/src/ORM/FieldType/DBObjectType.php b/src/ORM/FieldType/DBObjectType.php deleted file mode 100644 index f91710ed..00000000 --- a/src/ORM/FieldType/DBObjectType.php +++ /dev/null @@ -1,21 +0,0 @@ -getType('ObjectType'); - } -} diff --git a/src/Services/ElementTypeRegistry.php b/src/Services/ElementTypeRegistry.php index 61be6e3a..dec1587e 100644 --- a/src/Services/ElementTypeRegistry.php +++ b/src/Services/ElementTypeRegistry.php @@ -48,11 +48,10 @@ public function registerElement($elementClass) } // Get the GraphQL type name - $typeName = $singleton->getGraphQLTypeName(); $this->elementTypes[] = [ 'icon' => $singleton::config()->get('icon'), - 'name' => $typeName, + 'name' => $singleton->getTypeName(), 'class' => $elementClass, 'title' => $singleton->getType(), 'inlineEditable' => $singleton->inlineEditable(), @@ -70,7 +69,7 @@ private function registerBrokenElement() $singleton = singleton(BaseElement::class); $this->elementTypes[] = [ 'icon' => 'font-icon-block', - 'name' => $singleton->getGraphQLTypeName(), + 'name' => $singleton->getTypeName(), 'class' => BaseElement::class, 'title' => '', 'inlineEditable' => false, diff --git a/src/Services/ReorderElements.php b/src/Services/ReorderElements.php index 936587e0..dda76dc6 100644 --- a/src/Services/ReorderElements.php +++ b/src/Services/ReorderElements.php @@ -98,13 +98,7 @@ public function reorder($elementToBeAfterID = 0) // for each element that is affected by this reordering. $baseTableName = Convert::raw2sql(DataObject::getSchema()->tableName(BaseElement::class)); - // Update both the draft and live versions of the records $tableNames = [$baseTableName]; - if (BaseElement::has_extension(Versioned::class)) { - /** @var BaseElement&Versioned $element */ - $tableNames[] = $element->stageTable($baseTableName, Versioned::LIVE); - } - foreach ($tableNames as $tableName) { $tableName = sprintf('"%s"', $tableName); diff --git a/tests/GraphQL/AddElementToAreaMutationTest.php b/tests/GraphQL/AddElementToAreaMutationTest.php deleted file mode 100644 index 5504074d..00000000 --- a/tests/GraphQL/AddElementToAreaMutationTest.php +++ /dev/null @@ -1,95 +0,0 @@ -markTestSkipped('Skipped GraphQL 4 test ' . __CLASS__); - } - } - - public function testAddingBlocksInOrder() - { - $className = TestElement::class; - $areaID = $this->objFromFixture(ElementalArea::class, 'one')->ID; - - $one = $this->runMutation($className, $areaID)->ID; - $this->assertIdsInOrder([$one], 'The first element is added'); - - $two = $this->runMutation($className, $areaID, $one)->ID; - $this->assertIdsInOrder([$one, $two], 'The second element is added after the first'); - - $three = $this->runMutation($className, $areaID, $one)->ID; - $this->assertIdsInOrder([$one, $three, $two], 'The third element is added after the first'); - - $four = $this->runMutation($className, $areaID)->ID; - $this->assertIdsInOrder( - [$one, $three, $two, $four], - 'The fourth element is added last, when no after ID parameter is given' - ); - - $five = $this->runMutation($className, $areaID, 0)->ID; - $this->assertIdsInOrder([$five, $one, $three, $two, $four], 'The fifth element is added first, after ID 0'); - } - - public function testBadElementalArea() - { - $this->expectException(InvalidArgumentException::class); - $areaID = $this->objFromFixture(ElementalArea::class, 'one')->ID; - $this->runMutation(TestElement::class, $areaID + 1); - } - - public function testOrderingByWrongElementalArea() - { - $this->expectException(InvalidArgumentException::class); - $firstArea = ElementalArea::get()->first(); - $elementInFirstArea = TestElement::create(); - $firstArea->Elements()->add($elementInFirstArea); - - ElementalArea::create()->write(); - $this->runMutation(TestElement::class, 2, $elementInFirstArea->ID); - } - - protected function assertIdsInOrder($ids, $message = null) - { - $actualIDs = TestElement::get()->sort('Sort')->map()->keys(); - // Ideally this should be assertSame, but sometimes the database - // returns IDs as strings instead of integers (e.g. "1" instead of 1). - $this->assertEquals($ids, $actualIDs, $message); - } - - protected function runMutation($className, $elementalAreaID, $afterElementId = null) - { - $context = ['currentUser' => Security::getCurrentUser()]; - $resolveInfo = new FakeResolveInfo(); - - $args = [ - 'className' => $className, - 'elementalAreaID' => $elementalAreaID, - ]; - - if (!is_null($afterElementId)) { - $args['afterElementID'] = $afterElementId; - } - - return Resolver::resolveAddElementToArea(null, $args, $context, $resolveInfo); - } -} diff --git a/tests/GraphQL/AddElementToAreaMutationTest.yml b/tests/GraphQL/AddElementToAreaMutationTest.yml deleted file mode 100644 index 4f099556..00000000 --- a/tests/GraphQL/AddElementToAreaMutationTest.yml +++ /dev/null @@ -1,2 +0,0 @@ -DNADesign\Elemental\Models\ElementalArea: - one: \ No newline at end of file diff --git a/tests/GraphQL/DuplicateElementMutationTest.php b/tests/GraphQL/DuplicateElementMutationTest.php deleted file mode 100644 index 66a94b2d..00000000 --- a/tests/GraphQL/DuplicateElementMutationTest.php +++ /dev/null @@ -1,72 +0,0 @@ -markTestSkipped('Skipped GraphQL 4 test ' . __CLASS__); - } - } - - public function testResolvePermissions() - { - $cannotEditClass = new class extends BaseElement { - public function canEdit($member = null) - { - return false; - } - public function canCreate($member = null, $context = []) - { - return true; - } - }; - - $cannotCreateClass = new class extends BaseElement { - public function canEdit($member = null) - { - return true; - } - public function canCreate($member = null, $context = []) - { - return false; - } - }; - - $area = new ElementalArea(); - $area->write(); - - $testCases = [ - [$cannotEditClass, 'edit'], - [$cannotCreateClass, 'create'], - ]; - - foreach ($testCases as $data) { - [$class, $operation] = $data; - - $element = new $class(); - $element->ParentID = $area->ID; - $element->write(); - $mutation = new DuplicateElementMutation(); - $object = null; - $args = ['id' => $element->ID]; - $context = ['currentUser' => Security::getCurrentUser()]; - $resolveInfo = new FakeResolveInfo(); - - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessageRegExp("#insufficient permission to {$operation}#"); - $mutation->resolve($object, $args, $context, $resolveInfo); - } - } -} diff --git a/tests/GraphQL/FakeResolveInfo.php b/tests/GraphQL/FakeResolveInfo.php deleted file mode 100644 index 8618ace6..00000000 --- a/tests/GraphQL/FakeResolveInfo.php +++ /dev/null @@ -1,28 +0,0 @@ - 'fake', 'type' => Type::string()]), - new \ArrayObject(), - new ObjectType(['name' => 'fake']), - [], - new Schema([]), - [], - '', - new OperationDefinitionNode([]), - [] - ); - } -} diff --git a/tests/GraphQL/SortBlockMutationCreatorTest.php b/tests/GraphQL/SortBlockMutationCreatorTest.php deleted file mode 100644 index 8c50499c..00000000 --- a/tests/GraphQL/SortBlockMutationCreatorTest.php +++ /dev/null @@ -1,64 +0,0 @@ -markTestSkipped('Skipped GraphQL 4 test ' . __CLASS__); - } - } - - /** - * Reorders blocks by compounding each result into the next test (rather than isolated sorting tests) - */ - public function testSortBlock() - { - $this->runMutation(1, 3); - $this->assertIdsInOrder([2, 3, 1, 4]); - - $this->runMutation(4, 2); - $this->assertIdsInOrder([2, 4, 3, 1]); - - $this->runMutation(1, 0); - $this->assertIdsInOrder([1, 2, 4, 3]); - - $this->runMutation(3, 2); - $this->assertIdsInOrder([1, 2, 3, 4]); - } - - protected function assertIdsInOrder($ids) - { - $actualIDs = TestElement::get()->sort('Sort')->map()->keys(); - - $this->assertSame($ids, $actualIDs); - } - - protected function runMutation($id, $afterBlockId) - { - $member = Security::getCurrentUser(); - - $context = ['currentUser' => $member]; - $resolveInfo = new FakeResolveInfo(); - - Resolver::resolveSortBlock(null, [ - 'id' => $id, - 'afterBlockID' => $afterBlockId, - ], $context, $resolveInfo); - } -} diff --git a/tests/GraphQL/SortBlockMutationCreatorTest.yml b/tests/GraphQL/SortBlockMutationCreatorTest.yml deleted file mode 100644 index d54cb617..00000000 --- a/tests/GraphQL/SortBlockMutationCreatorTest.yml +++ /dev/null @@ -1,13 +0,0 @@ -DNADesign\Elemental\Tests\Src\TestElement: - element1: - ID: 1 - Sort: 1 - element2: - ID: 2 - Sort: 2 - element3: - ID: 3 - Sort: 3 - element4: - ID: 4 - Sort: 4 diff --git a/tests/Reports/ElementsInUseReportTest.php b/tests/Reports/ElementsInUseReportTest.php index 2f22432e..4b8871ff 100644 --- a/tests/Reports/ElementsInUseReportTest.php +++ b/tests/Reports/ElementsInUseReportTest.php @@ -9,7 +9,6 @@ use DNADesign\Elemental\Tests\Src\TestElement; use DNADesign\Elemental\Tests\Src\TestPage; use SilverStripe\Dev\FunctionalTest; -use SilverStripe\GraphQL\Tests\Schema\NaiveSchemaBuilder; use SilverStripe\ORM\DataList; class ElementsInUseReportTest extends FunctionalTest @@ -27,26 +26,6 @@ class ElementsInUseReportTest extends FunctionalTest TestPage::class, ]; - protected function setUp(): void - { - parent::setUp(); - - // GraphQL 4 only - if (class_exists(NaiveSchemaBuilder::class)) { - NaiveSchemaBuilder::activate(); - } - } - - protected function tearDown(): void - { - parent::tearDown(); - - // GraphQL 4 only - if (class_exists(NaiveSchemaBuilder::class)) { - NaiveSchemaBuilder::deactivate(); - } - } - public function testReportShowsElementsInUse() { $this->logInWithPermission('ADMIN'); diff --git a/yarn.lock b/yarn.lock index 8ac31e84..5e290f44 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15,26 +15,6 @@ "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.24" -"@apollo/client@^3.7.1": - version "3.9.9" - resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.9.9.tgz#38f983a1ad24e2687abfced0a9c1c3bef8d32616" - integrity sha512-/sMecU/M0WK9knrguts1lSLV8xFKzIgOMVb4mi6MOxgJXjliDB8PvOtmXhTqh2cVMMR4TzXgOnb+af/690zlQw== - dependencies: - "@graphql-typed-document-node/core" "^3.1.1" - "@wry/caches" "^1.0.0" - "@wry/equality" "^0.5.6" - "@wry/trie" "^0.5.0" - graphql-tag "^2.12.6" - hoist-non-react-statics "^3.3.2" - optimism "^0.18.0" - prop-types "^15.7.2" - rehackt "0.0.6" - response-iterator "^0.2.6" - symbol-observable "^4.0.0" - ts-invariant "^0.10.3" - tslib "^2.3.0" - zen-observable-ts "^1.2.5" - "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.23.5", "@babel/code-frame@^7.24.1", "@babel/code-frame@^7.24.2": version "7.24.2" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.2.tgz#718b4b19841809a58b29b68cde80bc5e1aa6d9ae" @@ -1110,11 +1090,6 @@ resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== -"@graphql-typed-document-node/core@^3.1.1": - version "3.2.0" - resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861" - integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ== - "@humanwhocodes/config-array@^0.11.14": version "0.11.14" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" @@ -1622,10 +1597,10 @@ stylelint-config-standard "^36.0.0" stylelint-scss "^6.2.1" -"@silverstripe/webpack-config@^2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@silverstripe/webpack-config/-/webpack-config-2.1.0.tgz#9d6409498126db766299fa40f209f618515932a4" - integrity sha512-8rE2K3AXkIP6crDTBXdHz/3hiNVp2XpINkWGDBKzvMS6sGRcVTluPs12BdOXYo1aUZEeqDk9QYOLLGGgZxnOdw== +"@silverstripe/webpack-config@^3.0.0-alpha1": + version "3.0.0-alpha1" + resolved "https://registry.yarnpkg.com/@silverstripe/webpack-config/-/webpack-config-3.0.0-alpha1.tgz#9576b8b1deac92ea96636e149b051b513ce14ab6" + integrity sha512-xBsiewBVAUIGdshWSs8ChAg4JXNNpHMwBLhjhYJCPFKe2HpNx3OqFEIqjR9YgSbCVSxkNh4x5yvYklu6+k+YpA== dependencies: "@babel/core" "^7.19.6" "@babel/preset-env" "^7.19.4" @@ -2007,41 +1982,6 @@ resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-2.0.5.tgz#325db42395cd49fe6c14057f9a900e427df8810e" integrity sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ== -"@wry/caches@^1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@wry/caches/-/caches-1.0.1.tgz#8641fd3b6e09230b86ce8b93558d44cf1ece7e52" - integrity sha512-bXuaUNLVVkD20wcGBWRyo7j9N3TxePEWFZj2Y+r9OoUzfqmavM84+mFykRicNsBqatba5JLay1t48wxaXaWnlA== - dependencies: - tslib "^2.3.0" - -"@wry/context@^0.7.0": - version "0.7.4" - resolved "https://registry.yarnpkg.com/@wry/context/-/context-0.7.4.tgz#e32d750fa075955c4ab2cfb8c48095e1d42d5990" - integrity sha512-jmT7Sb4ZQWI5iyu3lobQxICu2nC/vbUhP0vIdd6tHC9PTfenmRmuIFqktc6GH9cgi+ZHnsLWPvfSvc4DrYmKiQ== - dependencies: - tslib "^2.3.0" - -"@wry/equality@^0.5.6": - version "0.5.7" - resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.5.7.tgz#72ec1a73760943d439d56b7b1e9985aec5d497bb" - integrity sha512-BRFORjsTuQv5gxcXsuDXx6oGRhuVsEGwZy6LOzRRfgu+eSfxbhUQ9L9YtSEIuIjY/o7g3iWFjrc5eSY1GXP2Dw== - dependencies: - tslib "^2.3.0" - -"@wry/trie@^0.4.3": - version "0.4.3" - resolved "https://registry.yarnpkg.com/@wry/trie/-/trie-0.4.3.tgz#077d52c22365871bf3ffcbab8e95cb8bc5689af4" - integrity sha512-I6bHwH0fSf6RqQcnnXLJKhkSXG45MFral3GxPaY4uAl0LYDZM+YDVDAiU9bYwjTuysy1S0IeecWtmq1SZA3M1w== - dependencies: - tslib "^2.3.0" - -"@wry/trie@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@wry/trie/-/trie-0.5.0.tgz#11e783f3a53f6e4cd1d42d2d1323f5bc3fa99c94" - integrity sha512-FNoYzHawTMk/6KMQoEG5O4PuioX19UbwdQKF44yw0nLfOypfQdjtfZzo/UIJWAJ23sNIFbD1Ug9lbaDGMwbqQA== - dependencies: - tslib "^2.3.0" - "@xtuc/ieee754@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" @@ -2673,9 +2613,9 @@ camelcase@^6.2.0: integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== caniuse-lite@^1.0.30001565: - version "1.0.30001636" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001636.tgz#b15f52d2bdb95fad32c2f53c0b68032b85188a78" - integrity sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg== + version "1.0.30001642" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001642.tgz#6aa6610eb24067c246d30c57f055a9d0a7f8d05f" + integrity sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA== caniuse-lite@^1.0.30001587, caniuse-lite@^1.0.30001599: version "1.0.30001603" @@ -3306,9 +3246,9 @@ duplexer@^0.1.2: integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== electron-to-chromium@^1.4.601: - version "1.4.810" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.810.tgz#7dee01b090b9e048e6db752f7b30921790230654" - integrity sha512-Kaxhu4T7SJGpRQx99tq216gCq2nMxJo+uuT6uzz9l8TVN2stL7M06MIIXAtr9jsrLs2Glflgf2vMQRepxawOdQ== + version "1.4.828" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.828.tgz#a1ee8cd8847448b2898d3f2d9db02113f9c5b35c" + integrity sha512-QOIJiWpQJDHAVO4P58pwb133Cwee0nbvy/MV1CwzZVGpkH1RX33N3vsaWRCpR6bF63AAq366neZrRTu7Qlsbbw== electron-to-chromium@^1.4.668: version "1.4.722" @@ -4196,18 +4136,6 @@ graphemer@^1.4.0: resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== -graphql-tag@^2.12.6: - version "2.12.6" - resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.6.tgz#d441a569c1d2537ef10ca3d1633b48725329b5f1" - integrity sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg== - dependencies: - tslib "^2.1.0" - -graphql@^16.8.1: - version "16.8.1" - resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.8.1.tgz#1930a965bef1170603702acdb68aedd3f3cf6f07" - integrity sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw== - gud@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0" @@ -6266,16 +6194,6 @@ opener@^1.5.2: resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A== -optimism@^0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/optimism/-/optimism-0.18.0.tgz#e7bb38b24715f3fdad8a9a7fc18e999144bbfa63" - integrity sha512-tGn8+REwLRNFnb9WmcY5IfpOqeX2kpaYJ1s6Ae3mn12AeydLkR3j+jSCmVQFoXqU8D41PAJ1RG1rCRNWmNZVmQ== - dependencies: - "@wry/caches" "^1.0.0" - "@wry/context" "^0.7.0" - "@wry/trie" "^0.4.3" - tslib "^2.3.0" - optionator@^0.9.3: version "0.9.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" @@ -6651,7 +6569,7 @@ promzard@^0.3.0: dependencies: read "1" -prop-types@^15.5.8, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: +prop-types@^15.5.8, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -6972,11 +6890,6 @@ regjsparser@^0.9.1: dependencies: jsesc "~0.5.0" -rehackt@0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/rehackt/-/rehackt-0.0.6.tgz#7a0a2247f2295e7548915417e44fbbf03bf004f4" - integrity sha512-l3WEzkt4ntlEc/IB3/mF6SRgNHA6zfQR7BlGOgBTOmx7IJJXojDASav+NsgXHFjHn+6RmwqsGPFgZpabWpeOdw== - require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -7053,11 +6966,6 @@ resolve@^2.0.0-next.5: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -response-iterator@^0.2.6: - version "0.2.6" - resolved "https://registry.yarnpkg.com/response-iterator/-/response-iterator-0.2.6.tgz#249005fb14d2e4eeb478a3f735a28fd8b4c9f3da" - integrity sha512-pVzEEzrsg23Sh053rmDUvLSkGXluZio0qu8VT6ukrYuvtjVfCbDZH9d6PGXb8HZfzdNZt8feXv/jvUzlhRgLnw== - retry@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" @@ -7635,11 +7543,6 @@ symbol-observable@^1.0.4: resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== -symbol-observable@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-4.0.0.tgz#5b425f192279e87f2f9b937ac8540d1984b39205" - integrity sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ== - symbol-tree@^3.2.4: version "3.2.4" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" @@ -7757,13 +7660,6 @@ treeverse@^2.0.0: resolved "https://registry.yarnpkg.com/treeverse/-/treeverse-2.0.0.tgz#036dcef04bc3fd79a9b79a68d4da03e882d8a9ca" integrity sha512-N5gJCkLu1aXccpOTtqV6ddSEi6ZmGkh3hjmbu1IjcavJK4qyOVQmi0myQKM7z5jVGmD68SJoliaVrMmVObhj6A== -ts-invariant@^0.10.3: - version "0.10.3" - resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.10.3.tgz#3e048ff96e91459ffca01304dbc7f61c1f642f6c" - integrity sha512-uivwYcQaxAucv1CzRp2n/QdYPo4ILf9VXgH19zEIjFx2EJufV16P0JtJVpYHy89DItG6Kwj2oIUjrcK5au+4tQ== - dependencies: - tslib "^2.1.0" - tsconfig-paths@^3.15.0: version "3.15.0" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" @@ -7774,11 +7670,6 @@ tsconfig-paths@^3.15.0: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@^2.1.0, tslib@^2.3.0: - version "2.6.2" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" - integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== - type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" @@ -8344,15 +8235,3 @@ yocto-queue@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.0.0.tgz#7f816433fb2cbc511ec8bf7d263c3b58a1a3c251" integrity sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g== - -zen-observable-ts@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-1.2.5.tgz#6c6d9ea3d3a842812c6e9519209365a122ba8b58" - integrity sha512-QZWQekv6iB72Naeake9hS1KxHlotfRpe+WGNbNx5/ta+R3DNjVO2bswf63gXlWDcs+EMd7XY8HfVQyP1X6T4Zg== - dependencies: - zen-observable "0.8.15" - -zen-observable@0.8.15: - version "0.8.15" - resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15" - integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==