From 7ea3d91a6f669c36879b6824b52a464f2ccd6902 Mon Sep 17 00:00:00 2001 From: Sabina Talipova Date: Wed, 17 Jan 2024 10:15:57 +1300 Subject: [PATCH] ENH Add Readonly field status --- client/dist/js/bundle.js | 2 +- client/dist/styles/bundle.css | 2 +- client/src/components/LinkField/LinkField.js | 4 ++ .../LinkField/tests/LinkField-test.js | 1 + .../src/components/LinkPicker/LinkPicker.js | 7 +-- .../src/components/LinkPicker/LinkPicker.scss | 2 +- .../components/LinkPicker/LinkPickerTitle.js | 6 ++- .../LinkPicker/tests/LinkPicker-test.js | 1 + .../LinkPicker/tests/LinkPickerTitle-test.js | 15 +++++++ client/src/entwine/LinkField.js | 1 + src/Controllers/LinkFieldController.php | 44 ++++++++++++++----- src/Form/LinkField.php | 16 +++---- src/Form/LinkField_Readonly.php | 27 ------------ src/Form/MultiLinkField.php | 15 ++++--- src/Form/MultiLinkField_Readonly.php | 27 ------------ 15 files changed, 82 insertions(+), 88 deletions(-) delete mode 100644 src/Form/LinkField_Readonly.php delete mode 100644 src/Form/MultiLinkField_Readonly.php diff --git a/client/dist/js/bundle.js b/client/dist/js/bundle.js index cc3d8f89..56c1d7c2 100644 --- a/client/dist/js/bundle.js +++ b/client/dist/js/bundle.js @@ -1 +1 @@ -!function(){"use strict";var e={274:function(e,t,n){var r,o=(r=n(521))&&r.__esModule?r:{default:r};document.addEventListener("DOMContentLoaded",(()=>{(0,o.default)()}))},521:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=u(n(648)),o=u(n(809)),i=u(n(852)),l=u(n(117)),a=u(n(606));function u(e){return e&&e.__esModule?e:{default:e}}var s=()=>{r.default.component.registerMany({LinkPicker:o.default,LinkField:i.default,"LinkModal.FormBuilderModal":l.default,"LinkModal.InsertMediaModal":a.default})};t.default=s},852:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.LinkFieldContext=t.Component=void 0;var r=b(n(363)),o=n(827),i=n(624),l=O(n(42)),a=O(n(809)),u=O(n(734)),s=O(n(264)),d=O(n(697)),c=b(n(123)),f=O(n(159)),p=O(n(510)),y=n(845),v=O(n(86)),_=O(n(754)),k=O(n(872)),m=O(n(902));function O(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)}function b(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={},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var i in e)if("default"!==i&&Object.prototype.hasOwnProperty.call(e,i)){var l=o?Object.getOwnPropertyDescriptor(e,i):null;l&&(l.get||l.set)?Object.defineProperty(r,i,l):r[i]=e[i]}return r.default=e,n&&n.set(e,r),r}const h=(0,r.createContext)(null);t.LinkFieldContext=h;const C="SilverStripe\\LinkField\\Controllers\\LinkFieldController",M=e=>{var t;let{value:n=null,onChange:o,types:i={},actions:l,isMulti:c=!1,canCreate:v,ownerID:O,ownerClass:g,ownerRelation:b}=e;const[M,R]=(0,r.useState)({}),[E,w]=(0,r.useState)(0),[j,D]=(0,r.useState)(!1);let L=n;Array.isArray(L)||("number"==typeof L&&0!=L&&(L=[L]),L||(L=[])),(0,r.useEffect)((()=>{if(!E&&L.length>0){D(!0);const e=[];for(const t of L)e.push(`itemIDs[]=${t}`);const t=`${p.default.getSection(C).form.linkForm.dataUrl}?${e.join("&")}`;f.default.get(t).then((e=>e.json())).then((e=>{R(e),D(!1)})).catch((()=>{l.toasts.error(_.default._t("LinkField.FAILED_TO_LOAD_LINKS","Failed to load links")),D(!1)}))}}),[E,n&&n.length]);const I=()=>{w(0)},P=e=>{w(0);const t=[...L];t.includes(e)||t.push(e),o(c?t:t[0]),l.toasts.success(_.default._t("LinkField.SAVE_SUCCESS","Saved link"))},S=e=>{var t;let n=(0,y.joinUrlPaths)(p.default.getSection(C).form.linkForm.deleteUrl,e.toString());const r=k.default.parse(n),i=m.default.parse(r.query);i.ownerID=O,i.ownerClass=g,i.ownerRelation=b,n=k.default.format({...r,search:m.default.stringify(i)});const a=(null===(t=M[e])||void 0===t?void 0:t.versionState)||"",u=["draft","modified","published"].includes(a),s=u?_.default._t("LinkField.ARCHIVE_SUCCESS","Archived link"):_.default._t("LinkField.DELETE_SUCCESS","Deleted link"),d=u?_.default._t("LinkField.ARCHIVE_ERROR","Failed to archive link"):_.default._t("LinkField.DELETE_ERROR","Failed to delete link");f.default.delete(n,{},{"X-SecurityID":p.default.get("SecurityID")}).then((()=>l.toasts.success(s))).catch((()=>l.toasts.error(d)));const v={...M};delete v[e],R(v),o(c?Object.keys(v):0)},F=0===O,q=!F&&(c||0===Object.keys(M).length),x=!F&&Boolean(E),T=_.default._t("LinkField.SAVE_RECORD_FIRST","Cannot add links until the record has been saved");return r.default.createElement(h.Provider,{value:{ownerID:O,ownerClass:g,ownerRelation:b,actions:l,loading:j}},r.default.createElement("div",{className:"link-field__container"},F&&r.default.createElement("div",{className:"link-field__save-record-first"},T),j&&!F&&r.default.createElement(s.default,{containerClass:"link-field__loading"}),q&&r.default.createElement(a.default,{onModalSuccess:P,onModalClosed:I,types:i,canCreate:v}),r.default.createElement("div",null," ",(()=>{const e=[];for(const d of L){var t,n,o,l,a,s;if(!M[d])continue;const c=i.hasOwnProperty(null===(t=M[d])||void 0===t?void 0:t.typeKey)?i[null===(n=M[d])||void 0===n?void 0:n.typeKey]:{};e.push(r.default.createElement(u.default,{key:d,id:d,title:null===(o=M[d])||void 0===o?void 0:o.Title,description:null===(l=M[d])||void 0===l?void 0:l.description,versionState:null===(a=M[d])||void 0===a?void 0:a.versionState,typeTitle:c.title||"",typeIcon:c.icon,onDelete:S,onClick:()=>{w(d)},canDelete:!(null===(s=M[d])||void 0===s||!s.canDelete),canCreate:v}))}return e})()," "),x&&r.default.createElement(d.default,{types:i,typeKey:null===(t=M[E])||void 0===t?void 0:t.typeKey,isOpen:Boolean(E),onSuccess:P,onClosed:I,linkID:E})))};t.Component=M,M.propTypes={value:v.default.oneOfType([v.default.arrayOf(v.default.number),v.default.number]),onChange:v.default.func.isRequired,types:v.default.object.isRequired,actions:v.default.object.isRequired,isMulti:v.default.bool,canCreate:v.default.bool.isRequired,ownerID:v.default.number.isRequired,ownerClass:v.default.string.isRequired,ownerRelation:v.default.string.isRequired};var R=(0,o.compose)(l.default,(0,i.connect)(null,(e=>({actions:{toasts:(0,o.bindActionCreators)(c,e)}}))))(M);t.default=R},606:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;s(n(754));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={},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var i in e)if("default"!==i&&Object.prototype.hasOwnProperty.call(e,i)){var l=o?Object.getOwnPropertyDescriptor(e,i):null;l&&(l.get||l.set)?Object.defineProperty(r,i,l):r[i]=e[i]}r.default=e,n&&n.set(e,r);return r}(n(363)),o=s(n(475)),i=n(624),l=s(n(686)),a=s(n(86));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)}function s(e){return e&&e.__esModule?e:{default:e}}function d(){return d=Object.assign?Object.assign.bind():function(e){for(var t=1;t{let{type:t,editing:n,data:i,actions:l,onSubmit:a,...u}=e;if(!t)return!1;(0,r.useEffect)((()=>{n?l.initModal():l.reset()}),[n]);const s=i?{ID:i.FileID,Description:i.Title,TargetBlank:!!i.OpenInNew}:{};return r.default.createElement(o.default,d({isOpen:n,type:"insert-link",title:!1,bodyClassName:"modal__dialog",className:"insert-link__dialog-wrapper--internal",fileAttributes:s,onInsert:e=>{let{ID:n,Description:r,TargetBlank:o}=e;return a({FileID:n,Title:r,OpenInNew:o,typeKey:t.key},"",(()=>{}))}},u))};c.propTypes={type:l.default.isRequired,editing:a.default.bool.isRequired,data:a.default.object.isRequired,actions:a.default.object.isRequired,onClick:a.default.func.isRequired};var f=(0,i.connect)((function(){return{}}),(function(e){return{actions:{initModal:()=>e({type:"INIT_FORM_SCHEMA_STACK",payload:{formSchema:{type:"insert-link",nextType:"admin"}}}),reset:()=>e({type:"RESET"})}}}))(c);t.default=f},117: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={},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var i in e)if("default"!==i&&Object.prototype.hasOwnProperty.call(e,i)){var l=o?Object.getOwnPropertyDescriptor(e,i):null;l&&(l.get||l.set)?Object.defineProperty(r,i,l):r[i]=e[i]}r.default=e,n&&n.set(e,r);return r}(n(363)),o=c(n(912)),i=n(852),l=c(n(872)),a=c(n(902)),u=c(n(510)),s=n(845),d=c(n(86));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)}const p=(e,t)=>{const{schemaUrl:n}=u.default.getSection("SilverStripe\\LinkField\\Controllers\\LinkFieldController").form.linkForm,o=l.default.parse(n),d=a.default.parse(o.query);d.typeKey=e;const{ownerID:c,ownerClass:f,ownerRelation:p}=(0,r.useContext)(i.LinkFieldContext);d.ownerID=c,d.ownerClass=f,d.ownerRelation=p;for(const e of["href","path","pathname"])o[e]=(0,s.joinUrlPaths)(o[e],t.toString());return l.default.format({...o,search:a.default.stringify(d)})},y=e=>{let{typeTitle:t,typeKey:n,linkID:l=0,isOpen:a,onSuccess:u,onClosed:s}=e;const{actions:d}=(0,r.useContext)(i.LinkFieldContext);if(!n)return!1;return r.default.createElement(o.default,{title:t,isOpen:a,schemaUrl:p(n,l),identifier:"Link.EditingLinkInfo",onSubmit:async(e,t,n)=>{let r=null;try{r=await n()}catch(e){return d.toasts.error(i18n._t("LinkField.FAILED_TO_SAVE_LINK","Failed to save link")),Promise.resolve()}if(!r.id.match(/\/schema\/linkfield\/([0-9]+)/)){const e=r.id.match(/\/linkForm\/([0-9]+)/),t=parseInt(e[1],10);u(t)}return Promise.resolve()},onClosed:s})};y.propTypes={typeTitle:d.default.string.isRequired,typeKey:d.default.string.isRequired,linkID:d.default.number,isOpen:d.default.bool.isRequired,onSuccess:d.default.func.isRequired,onClosed:d.default.func.isRequired};var v=y;t.default=v},809:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.Component=void 0;var r=d(n(754)),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={},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var i in e)if("default"!==i&&Object.prototype.hasOwnProperty.call(e,i)){var l=o?Object.getOwnPropertyDescriptor(e,i):null;l&&(l.get||l.set)?Object.defineProperty(r,i,l):r[i]=e[i]}r.default=e,n&&n.set(e,r);return r}(n(363)),i=d(n(86)),l=d(n(820)),a=d(n(97)),u=(d(n(686)),d(n(697)));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)}function d(e){return e&&e.__esModule?e:{default:e}}const c=e=>{let{types:t,onModalSuccess:n,onModalClosed:i,canCreate:s}=e;const[d,c]=(0,o.useState)(""),f=""!==d,p=(0,l.default)("link-picker","form-control"),y=Object.values(t);return s?o.default.createElement("div",{className:p},o.default.createElement(a.default,{types:y,onSelect:e=>{c(e)}}),f&&o.default.createElement(u.default,{types:t,typeKey:d,isOpen:f,onSuccess:e=>{c(""),n(e)},onClosed:()=>{"function"==typeof i&&i(),c("")}})):o.default.createElement("div",{className:p},o.default.createElement("div",{className:"link-picker__cannot-create"},r.default._t("LinkField.CANNOT_CREATE_LINK","Cannot create link")))};t.Component=c,c.propTypes={types:i.default.object.isRequired,onModalSuccess:i.default.func.isRequired,onModalClosed:i.default.func,canCreate:i.default.bool.isRequired};var f=c;t.default=f},97:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=d(n(754)),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={},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var i in e)if("default"!==i&&Object.prototype.hasOwnProperty.call(e,i)){var l=o?Object.getOwnPropertyDescriptor(e,i):null;l&&(l.get||l.set)?Object.defineProperty(r,i,l):r[i]=e[i]}r.default=e,n&&n.set(e,r);return r}(n(363)),i=d(n(86)),l=n(127),a=n(852),u=d(n(686));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)}function d(e){return e&&e.__esModule?e:{default:e}}const c=e=>{let{types:t,onSelect:n}=e;const[i,u]=(0,o.useState)(!1),{loading:s}=(0,o.useContext)(a.LinkFieldContext);return o.default.createElement(l.Dropdown,{disabled:s,isOpen:i,toggle:()=>u((e=>!e)),className:"link-picker__menu"},o.default.createElement(l.DropdownToggle,{className:"link-picker__menu-toggle font-icon-plus-1",caret:!0},r.default._t("LinkField.ADD_LINK","Add Link")),o.default.createElement(l.DropdownMenu,null,t.map((e=>{let{key:t,title:r,icon:i}=e;return o.default.createElement(l.DropdownItem,{key:t,onClick:()=>n(t)},o.default.createElement("span",{className:`link-picker__menu-icon ${i}`}),r)}))))};c.propTypes={types:i.default.arrayOf(u.default).isRequired,onSelect:i.default.func.isRequired};var f=c;t.default=f},734:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=d(n(820)),o=d(n(754)),i=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={},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var i in e)if("default"!==i&&Object.prototype.hasOwnProperty.call(e,i)){var l=o?Object.getOwnPropertyDescriptor(e,i):null;l&&(l.get||l.set)?Object.defineProperty(r,i,l):r[i]=e[i]}r.default=e,n&&n.set(e,r);return r}(n(363)),l=d(n(86)),a=n(127),u=n(852);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)}function d(e){return e&&e.__esModule?e:{default:e}}const c=e=>t=>{t.nativeEvent.stopImmediatePropagation(),t.preventDefault(),t.nativeEvent.preventDefault(),t.stopPropagation(),e&&e()},f=e=>{let{id:t,title:n,description:l,versionState:s,typeTitle:d,typeIcon:f,onDelete:p,onClick:y,canDelete:v,canCreate:_}=e;const{loading:k}=(0,i.useContext)(u.LinkFieldContext),m={"link-picker__link":!0,"form-control":!0,readonly:!_};s&&(m[` link-picker__link--${s}`]=!0);const O=(0,r.default)(m),g=["unversioned","unsaved"].includes(s)?o.default._t("LinkField.DELETE","Delete"):o.default._t("LinkField.ARCHIVE","Archive");return i.default.createElement("div",{className:O},i.default.createElement(a.Button,{disabled:k,className:`link-picker__button ${f}`,color:"secondary",onClick:c(y)},i.default.createElement("div",{className:"link-picker__link-detail"},i.default.createElement("div",{className:"link-picker__title"},i.default.createElement("span",{className:"link-picker__title-text"},n),(e=>{let t="",n="";if("draft"===e)t=o.default._t("LinkField.LINK_DRAFT_TITLE","Link has draft changes"),n=o.default._t("LinkField.LINK_DRAFT_LABEL","Draft");else{if("modified"!==e)return null;t=o.default._t("LinkField.LINK_MODIFIED_TITLE","Link has unpublished changes"),n=o.default._t("LinkField.LINK_MODIFIED_LABEL","Modified")}const l=(0,r.default)("badge",`status-${e}`);return i.default.createElement("span",{className:l,title:t},n)})(s)),i.default.createElement("small",{className:"link-picker__type"},d,": ",i.default.createElement("span",{className:"link-picker__url"},l)))),v&&_&&i.default.createElement(a.Button,{disabled:k,className:"link-picker__delete",color:"link",onClick:c((()=>p(t)))},g))};f.propTypes={id:l.default.number.isRequired,title:l.default.string,description:l.default.string,versionState:l.default.string,typeTitle:l.default.string.isRequired,typeIcon:l.default.string.isRequired,onDelete:l.default.func.isRequired,onClick:l.default.func.isRequired,canDelete:l.default.bool.isRequired,canCreate:l.default.bool.isRequired};var p=f;t.default=p},697:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=l(n(363)),o=n(648),i=l(n(86));function l(e){return e&&e.__esModule?e:{default:e}}const a=e=>{let{types:t,typeKey:n,linkID:i=0,isOpen:l,onSuccess:a,onClosed:u}=e;if(!n)return!1;const s=t.hasOwnProperty(n)?t[n]:{},d=s&&s.hasOwnProperty("handlerName")?s.handlerName:"FormBuilderModal",c=(0,o.loadComponent)(`LinkModal.${d}`);return r.default.createElement(c,{typeTitle:s.title||"",typeKey:n,linkID:i,isOpen:l,onSuccess:a,onClosed:u})};a.propTypes={types:i.default.object.isRequired,typeKey:i.default.string.isRequired,linkID:i.default.number,isOpen:i.default.bool.isRequired,onSuccess:i.default.func.isRequired,onClosed:i.default.func.isRequired};var u=a;t.default=u},41:function(e,t,n){var r=a(n(311)),o=a(n(363)),i=a(n(691)),l=n(648);function a(e){return e&&e.__esModule?e:{default:e}}function u(){return u=Object.assign?Object.assign.bind():function(e){for(var t=1;t{e(".js-injector-boot .entwine-linkfield").entwine({Component:null,Root:null,onmatch(){const e=this.closest(".cms-content").attr("id"),t=e?{context:e}:{},n=this.data("schema-component"),r=(0,l.loadComponent)(n,t);this.setComponent(r),this.setRoot(i.default.createRoot(this[0])),this._super(),this.refresh()},refresh(){const e=this.getProps();this.getInputField().val(e.value);const t=this.getComponent();this.getRoot().render(o.default.createElement(t,u({},e,{noHolder:!0})))},handleChange(e){this.getInputField().data("value",e),this.refresh()},getProps(){const e=this.getInputField();return{value:e.data("value"),ownerID:e.data("owner-id"),ownerClass:e.data("owner-class"),ownerRelation:e.data("owner-relation"),onChange:this.handleChange.bind(this),isMulti:this.data("is-multi")??!1,types:this.data("types")??{},canCreate:!!e.data("can-create")}},getInputField(){const t=this.data("field-id");return e(`#${t}`)},onunmatch(){const e=this.getRoot();e&&e.unmount()}})}))},686:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r,o=(r=n(86))&&r.__esModule?r:{default:r};var i=o.default.shape({key:o.default.string.isRequired,title:o.default.string.isRequired,icon:o.default.string.isRequired});t.default=i},159:function(e){e.exports=Backend},510:function(e){e.exports=Config},42:function(e){e.exports=FieldHolder},912:function(e){e.exports=FormBuilderModal},648:function(e){e.exports=Injector},475:function(e){e.exports=InsertMediaModal},264:function(e){e.exports=Loading},872:function(e){e.exports=NodeUrl},86:function(e){e.exports=PropTypes},363:function(e){e.exports=React},691:function(e){e.exports=ReactDomClient},624:function(e){e.exports=ReactRedux},127:function(e){e.exports=Reactstrap},827:function(e){e.exports=Redux},123:function(e){e.exports=ToastsActions},820:function(e){e.exports=classnames},754:function(e){e.exports=i18n},311:function(e){e.exports=jQuery},902:function(e){e.exports=qs},845:function(e){e.exports=ssUrlLib}},t={};function n(r){var o=t[r];if(void 0!==o)return o.exports;var i=t[r]={exports:{}};return e[r](i,i.exports,n),i.exports}n(274),n(41)}(); \ No newline at end of file +!function(){"use strict";var e={274:function(e,t,n){var r,o=(r=n(521))&&r.__esModule?r:{default:r};document.addEventListener("DOMContentLoaded",(()=>{(0,o.default)()}))},521:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=u(n(648)),o=u(n(809)),l=u(n(852)),a=u(n(117)),i=u(n(606));function u(e){return e&&e.__esModule?e:{default:e}}var d=()=>{r.default.component.registerMany({LinkPicker:o.default,LinkField:l.default,"LinkModal.FormBuilderModal":a.default,"LinkModal.InsertMediaModal":i.default})};t.default=d},852:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.LinkFieldContext=t.Component=void 0;var r=g(n(363)),o=n(827),l=n(624),a=O(n(42)),i=O(n(809)),u=O(n(734)),d=O(n(264)),s=O(n(697)),c=g(n(123)),f=O(n(159)),p=O(n(510)),y=n(845),v=O(n(86)),k=O(n(754)),_=O(n(872)),m=O(n(902));function O(e){return e&&e.__esModule?e:{default:e}}function b(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(b=function(e){return e?n:t})(e)}function g(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=b(t);if(n&&n.has(e))return n.get(e);var r={},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in e)if("default"!==l&&Object.prototype.hasOwnProperty.call(e,l)){var a=o?Object.getOwnPropertyDescriptor(e,l):null;a&&(a.get||a.set)?Object.defineProperty(r,l,a):r[l]=e[l]}return r.default=e,n&&n.set(e,r),r}const h=(0,r.createContext)(null);t.LinkFieldContext=h;const C="SilverStripe\\LinkField\\Controllers\\LinkFieldController",R=e=>{var t;let{value:n=null,onChange:o,types:l={},actions:a,isMulti:c=!1,canCreate:v,readonly:O,ownerID:b,ownerClass:g,ownerRelation:R}=e;const[M,E]=(0,r.useState)({}),[w,j]=(0,r.useState)(0),[D,L]=(0,r.useState)(!1);let I=n;Array.isArray(I)||("number"==typeof I&&0!=I&&(I=[I]),I||(I=[])),(0,r.useEffect)((()=>{if(!w&&I.length>0){L(!0);const e=[];for(const t of I)e.push(`itemIDs[]=${t}`);const t=`${p.default.getSection(C).form.linkForm.dataUrl}?${e.join("&")}`;f.default.get(t).then((e=>e.json())).then((e=>{E(e),L(!1)})).catch((()=>{a.toasts.error(k.default._t("LinkField.FAILED_TO_LOAD_LINKS","Failed to load links")),L(!1)}))}}),[w,n&&n.length]);const P=()=>{j(0)},S=e=>{j(0);const t=[...I];t.includes(e)||t.push(e),o(c?t:t[0]),a.toasts.success(k.default._t("LinkField.SAVE_SUCCESS","Saved link"))},F=e=>{var t;let n=(0,y.joinUrlPaths)(p.default.getSection(C).form.linkForm.deleteUrl,e.toString());const r=_.default.parse(n),l=m.default.parse(r.query);l.ownerID=b,l.ownerClass=g,l.ownerRelation=R,n=_.default.format({...r,search:m.default.stringify(l)});const i=(null===(t=M[e])||void 0===t?void 0:t.versionState)||"",u=["draft","modified","published"].includes(i),d=u?k.default._t("LinkField.ARCHIVE_SUCCESS","Archived link"):k.default._t("LinkField.DELETE_SUCCESS","Deleted link"),s=u?k.default._t("LinkField.ARCHIVE_ERROR","Failed to archive link"):k.default._t("LinkField.DELETE_ERROR","Failed to delete link");f.default.delete(n,{},{"X-SecurityID":p.default.get("SecurityID")}).then((()=>a.toasts.success(d))).catch((()=>a.toasts.error(s)));const v={...M};delete v[e],E(v),o(c?Object.keys(v):0)},q=0===b,x=!q&&(c||0===Object.keys(M).length),T=!q&&Boolean(w),N=k.default._t("LinkField.SAVE_RECORD_FIRST","Cannot add links until the record has been saved");return r.default.createElement(h.Provider,{value:{ownerID:b,ownerClass:g,ownerRelation:R,actions:a,loading:D}},r.default.createElement("div",{className:"link-field__container"},q&&r.default.createElement("div",{className:"link-field__save-record-first"},N),D&&!q&&r.default.createElement(d.default,{containerClass:"link-field__loading"}),x&&r.default.createElement(i.default,{onModalSuccess:S,onModalClosed:P,types:l,canCreate:v,readonly:O}),r.default.createElement("div",null," ",(()=>{const e=[];for(const s of I){var t,n,o,a,i,d;if(!M[s])continue;const c=l.hasOwnProperty(null===(t=M[s])||void 0===t?void 0:t.typeKey)?l[null===(n=M[s])||void 0===n?void 0:n.typeKey]:{};e.push(r.default.createElement(u.default,{key:s,id:s,title:null===(o=M[s])||void 0===o?void 0:o.Title,description:null===(a=M[s])||void 0===a?void 0:a.description,versionState:null===(i=M[s])||void 0===i?void 0:i.versionState,typeTitle:c.title||"",typeIcon:c.icon,onDelete:F,onClick:()=>{j(s)},canDelete:!(null===(d=M[s])||void 0===d||!d.canDelete),canCreate:v,readonly:O}))}return e})()," "),T&&r.default.createElement(s.default,{types:l,typeKey:null===(t=M[w])||void 0===t?void 0:t.typeKey,isOpen:Boolean(w),onSuccess:S,onClosed:P,linkID:w})))};t.Component=R,R.propTypes={value:v.default.oneOfType([v.default.arrayOf(v.default.number),v.default.number]),onChange:v.default.func.isRequired,types:v.default.object.isRequired,actions:v.default.object.isRequired,isMulti:v.default.bool,canCreate:v.default.bool.isRequired,readonly:v.default.bool.isRequired,ownerID:v.default.number.isRequired,ownerClass:v.default.string.isRequired,ownerRelation:v.default.string.isRequired};var M=(0,o.compose)(a.default,(0,l.connect)(null,(e=>({actions:{toasts:(0,o.bindActionCreators)(c,e)}}))))(R);t.default=M},606:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;d(n(754));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={},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in e)if("default"!==l&&Object.prototype.hasOwnProperty.call(e,l)){var a=o?Object.getOwnPropertyDescriptor(e,l):null;a&&(a.get||a.set)?Object.defineProperty(r,l,a):r[l]=e[l]}r.default=e,n&&n.set(e,r);return r}(n(363)),o=d(n(475)),l=n(624),a=d(n(686)),i=d(n(86));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)}function d(e){return e&&e.__esModule?e:{default:e}}function s(){return s=Object.assign?Object.assign.bind():function(e){for(var t=1;t{let{type:t,editing:n,data:l,actions:a,onSubmit:i,...u}=e;if(!t)return!1;(0,r.useEffect)((()=>{n?a.initModal():a.reset()}),[n]);const d=l?{ID:l.FileID,Description:l.Title,TargetBlank:!!l.OpenInNew}:{};return r.default.createElement(o.default,s({isOpen:n,type:"insert-link",title:!1,bodyClassName:"modal__dialog",className:"insert-link__dialog-wrapper--internal",fileAttributes:d,onInsert:e=>{let{ID:n,Description:r,TargetBlank:o}=e;return i({FileID:n,Title:r,OpenInNew:o,typeKey:t.key},"",(()=>{}))}},u))};c.propTypes={type:a.default.isRequired,editing:i.default.bool.isRequired,data:i.default.object.isRequired,actions:i.default.object.isRequired,onClick:i.default.func.isRequired};var f=(0,l.connect)((function(){return{}}),(function(e){return{actions:{initModal:()=>e({type:"INIT_FORM_SCHEMA_STACK",payload:{formSchema:{type:"insert-link",nextType:"admin"}}}),reset:()=>e({type:"RESET"})}}}))(c);t.default=f},117: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={},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in e)if("default"!==l&&Object.prototype.hasOwnProperty.call(e,l)){var a=o?Object.getOwnPropertyDescriptor(e,l):null;a&&(a.get||a.set)?Object.defineProperty(r,l,a):r[l]=e[l]}r.default=e,n&&n.set(e,r);return r}(n(363)),o=c(n(912)),l=n(852),a=c(n(872)),i=c(n(902)),u=c(n(510)),d=n(845),s=c(n(86));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)}const p=(e,t)=>{const{schemaUrl:n}=u.default.getSection("SilverStripe\\LinkField\\Controllers\\LinkFieldController").form.linkForm,o=a.default.parse(n),s=i.default.parse(o.query);s.typeKey=e;const{ownerID:c,ownerClass:f,ownerRelation:p}=(0,r.useContext)(l.LinkFieldContext);s.ownerID=c,s.ownerClass=f,s.ownerRelation=p;for(const e of["href","path","pathname"])o[e]=(0,d.joinUrlPaths)(o[e],t.toString());return a.default.format({...o,search:i.default.stringify(s)})},y=e=>{let{typeTitle:t,typeKey:n,linkID:a=0,isOpen:i,onSuccess:u,onClosed:d}=e;const{actions:s}=(0,r.useContext)(l.LinkFieldContext);if(!n)return!1;return r.default.createElement(o.default,{title:t,isOpen:i,schemaUrl:p(n,a),identifier:"Link.EditingLinkInfo",onSubmit:async(e,t,n)=>{let r=null;try{r=await n()}catch(e){return s.toasts.error(i18n._t("LinkField.FAILED_TO_SAVE_LINK","Failed to save link")),Promise.resolve()}if(!r.id.match(/\/schema\/linkfield\/([0-9]+)/)){const e=r.id.match(/\/linkForm\/([0-9]+)/),t=parseInt(e[1],10);u(t)}return Promise.resolve()},onClosed:d})};y.propTypes={typeTitle:s.default.string.isRequired,typeKey:s.default.string.isRequired,linkID:s.default.number,isOpen:s.default.bool.isRequired,onSuccess:s.default.func.isRequired,onClosed:s.default.func.isRequired};var v=y;t.default=v},809:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.Component=void 0;var r=s(n(754)),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={},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in e)if("default"!==l&&Object.prototype.hasOwnProperty.call(e,l)){var a=o?Object.getOwnPropertyDescriptor(e,l):null;a&&(a.get||a.set)?Object.defineProperty(r,l,a):r[l]=e[l]}r.default=e,n&&n.set(e,r);return r}(n(363)),l=s(n(86)),a=s(n(820)),i=s(n(97)),u=(s(n(686)),s(n(697)));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)}function s(e){return e&&e.__esModule?e:{default:e}}const c=e=>{let{types:t,onModalSuccess:n,onModalClosed:l,canCreate:d,readonly:s}=e;const[c,f]=(0,o.useState)(""),p=""!==c,y=(0,a.default)("link-picker","form-control"),v=Object.values(t);return!d||s?o.default.createElement("div",{className:y},o.default.createElement("div",{className:"link-picker__cannot-create"},r.default._t("LinkField.CANNOT_CREATE_LINK","Cannot create link"))):o.default.createElement("div",{className:y},o.default.createElement(i.default,{types:v,onSelect:e=>{f(e)}}),p&&o.default.createElement(u.default,{types:t,typeKey:c,isOpen:p,onSuccess:e=>{f(""),n(e)},onClosed:()=>{"function"==typeof l&&l(),f("")}}))};t.Component=c,c.propTypes={types:l.default.object.isRequired,onModalSuccess:l.default.func.isRequired,onModalClosed:l.default.func,canCreate:l.default.bool.isRequired,readonly:l.default.bool.isRequired};var f=c;t.default=f},97:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=s(n(754)),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={},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in e)if("default"!==l&&Object.prototype.hasOwnProperty.call(e,l)){var a=o?Object.getOwnPropertyDescriptor(e,l):null;a&&(a.get||a.set)?Object.defineProperty(r,l,a):r[l]=e[l]}r.default=e,n&&n.set(e,r);return r}(n(363)),l=s(n(86)),a=n(127),i=n(852),u=s(n(686));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)}function s(e){return e&&e.__esModule?e:{default:e}}const c=e=>{let{types:t,onSelect:n}=e;const[l,u]=(0,o.useState)(!1),{loading:d}=(0,o.useContext)(i.LinkFieldContext);return o.default.createElement(a.Dropdown,{disabled:d,isOpen:l,toggle:()=>u((e=>!e)),className:"link-picker__menu"},o.default.createElement(a.DropdownToggle,{className:"link-picker__menu-toggle font-icon-plus-1",caret:!0},r.default._t("LinkField.ADD_LINK","Add Link")),o.default.createElement(a.DropdownMenu,null,t.map((e=>{let{key:t,title:r,icon:l}=e;return o.default.createElement(a.DropdownItem,{key:t,onClick:()=>n(t)},o.default.createElement("span",{className:`link-picker__menu-icon ${l}`}),r)}))))};c.propTypes={types:l.default.arrayOf(u.default).isRequired,onSelect:l.default.func.isRequired};var f=c;t.default=f},734:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=s(n(820)),o=s(n(754)),l=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={},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in e)if("default"!==l&&Object.prototype.hasOwnProperty.call(e,l)){var a=o?Object.getOwnPropertyDescriptor(e,l):null;a&&(a.get||a.set)?Object.defineProperty(r,l,a):r[l]=e[l]}r.default=e,n&&n.set(e,r);return r}(n(363)),a=s(n(86)),i=n(127),u=n(852);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)}function s(e){return e&&e.__esModule?e:{default:e}}const c=e=>t=>{t.nativeEvent.stopImmediatePropagation(),t.preventDefault(),t.nativeEvent.preventDefault(),t.stopPropagation(),e&&e()},f=e=>{let{id:t,title:n,description:a,versionState:d,typeTitle:s,typeIcon:f,onDelete:p,onClick:y,canDelete:v,canCreate:k,readonly:_}=e;const{loading:m}=(0,l.useContext)(u.LinkFieldContext),O={"link-picker__link":!0,"form-control":!0,"link-picker__link--readonly":_||!k};d&&(O[` link-picker__link--${d}`]=!0);const b=(0,r.default)(O),g=["unversioned","unsaved"].includes(d)?o.default._t("LinkField.DELETE","Delete"):o.default._t("LinkField.ARCHIVE","Archive");return l.default.createElement("div",{className:b},l.default.createElement(i.Button,{disabled:m,className:`link-picker__button ${f}`,color:"secondary",onClick:c(y)},l.default.createElement("div",{className:"link-picker__link-detail"},l.default.createElement("div",{className:"link-picker__title"},l.default.createElement("span",{className:"link-picker__title-text"},n),(e=>{let t="",n="";if("draft"===e)t=o.default._t("LinkField.LINK_DRAFT_TITLE","Link has draft changes"),n=o.default._t("LinkField.LINK_DRAFT_LABEL","Draft");else{if("modified"!==e)return null;t=o.default._t("LinkField.LINK_MODIFIED_TITLE","Link has unpublished changes"),n=o.default._t("LinkField.LINK_MODIFIED_LABEL","Modified")}const a=(0,r.default)("badge",`status-${e}`);return l.default.createElement("span",{className:a,title:t},n)})(d)),l.default.createElement("small",{className:"link-picker__type"},s,": ",l.default.createElement("span",{className:"link-picker__url"},a)))),v&&!_&&l.default.createElement(i.Button,{disabled:m,className:"link-picker__delete",color:"link",onClick:c((()=>p(t)))},g))};f.propTypes={id:a.default.number.isRequired,title:a.default.string,description:a.default.string,versionState:a.default.string,typeTitle:a.default.string.isRequired,typeIcon:a.default.string.isRequired,onDelete:a.default.func.isRequired,onClick:a.default.func.isRequired,canDelete:a.default.bool.isRequired,canCreate:a.default.bool.isRequired,readonly:a.default.bool.isRequired};var p=f;t.default=p},697:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=a(n(363)),o=n(648),l=a(n(86));function a(e){return e&&e.__esModule?e:{default:e}}const i=e=>{let{types:t,typeKey:n,linkID:l=0,isOpen:a,onSuccess:i,onClosed:u}=e;if(!n)return!1;const d=t.hasOwnProperty(n)?t[n]:{},s=d&&d.hasOwnProperty("handlerName")?d.handlerName:"FormBuilderModal",c=(0,o.loadComponent)(`LinkModal.${s}`);return r.default.createElement(c,{typeTitle:d.title||"",typeKey:n,linkID:l,isOpen:a,onSuccess:i,onClosed:u})};i.propTypes={types:l.default.object.isRequired,typeKey:l.default.string.isRequired,linkID:l.default.number,isOpen:l.default.bool.isRequired,onSuccess:l.default.func.isRequired,onClosed:l.default.func.isRequired};var u=i;t.default=u},41:function(e,t,n){var r=i(n(311)),o=i(n(363)),l=i(n(691)),a=n(648);function i(e){return e&&e.__esModule?e:{default:e}}function u(){return u=Object.assign?Object.assign.bind():function(e){for(var t=1;t{e(".js-injector-boot .entwine-linkfield").entwine({Component:null,Root:null,onmatch(){const e=this.closest(".cms-content").attr("id"),t=e?{context:e}:{},n=this.data("schema-component"),r=(0,a.loadComponent)(n,t);this.setComponent(r),this.setRoot(l.default.createRoot(this[0])),this._super(),this.refresh()},refresh(){const e=this.getProps();this.getInputField().val(e.value);const t=this.getComponent();this.getRoot().render(o.default.createElement(t,u({},e,{noHolder:!0})))},handleChange(e){this.getInputField().data("value",e),this.refresh()},getProps(){const e=this.getInputField();return{value:e.data("value"),ownerID:e.data("owner-id"),ownerClass:e.data("owner-class"),ownerRelation:e.data("owner-relation"),onChange:this.handleChange.bind(this),isMulti:this.data("is-multi")??!1,types:this.data("types")??{},canCreate:!!e.data("can-create"),readonly:!!e.data("readonly")}},getInputField(){const t=this.data("field-id");return e(`#${t}`)},onunmatch(){const e=this.getRoot();e&&e.unmount()}})}))},686:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r,o=(r=n(86))&&r.__esModule?r:{default:r};var l=o.default.shape({key:o.default.string.isRequired,title:o.default.string.isRequired,icon:o.default.string.isRequired});t.default=l},159:function(e){e.exports=Backend},510:function(e){e.exports=Config},42:function(e){e.exports=FieldHolder},912:function(e){e.exports=FormBuilderModal},648:function(e){e.exports=Injector},475:function(e){e.exports=InsertMediaModal},264:function(e){e.exports=Loading},872:function(e){e.exports=NodeUrl},86:function(e){e.exports=PropTypes},363:function(e){e.exports=React},691:function(e){e.exports=ReactDomClient},624:function(e){e.exports=ReactRedux},127:function(e){e.exports=Reactstrap},827:function(e){e.exports=Redux},123:function(e){e.exports=ToastsActions},820:function(e){e.exports=classnames},754:function(e){e.exports=i18n},311:function(e){e.exports=jQuery},902:function(e){e.exports=qs},845:function(e){e.exports=ssUrlLib}},t={};function n(r){var o=t[r];if(void 0!==o)return o.exports;var l=t[r]={exports:{}};return e[r](l,l.exports,n),l.exports}n(274),n(41)}(); \ No newline at end of file diff --git a/client/dist/styles/bundle.css b/client/dist/styles/bundle.css index 062a87e5..d8007521 100644 --- a/client/dist/styles/bundle.css +++ b/client/dist/styles/bundle.css @@ -1 +1 @@ -.link-field__container{position:relative}.link-field__loading{position:absolute;top:0;left:0;width:100%;height:100%}.link-field__loading .cms-content-loading-overlay{position:relative}.link-field__save-record-first{padding-top:7px}.link-picker__link,.link-picker{display:flex;height:auto;width:100%;min-height:54px;background:#fff;padding:0}.link-picker{align-items:stretch;cursor:pointer;box-shadow:none}.link-picker:not(:last-child){margin-bottom:10px}.link-picker.font-icon-link::before{margin:.76925rem}.link-picker__cannot-create{cursor:default;flex-grow:1;padding:16px 13px}.link-picker__menu{flex-grow:1}.link-picker__menu-toggle{width:100%;height:100%;text-align:left}.link-picker__menu-toggle::before{padding:.76925rem}.link-picker__menu-icon{vertical-align:middle;padding-right:.7rem}.link-picker__link{align-items:center;text-align:left;margin-right:0;justify-content:space-between;position:relative}.link-picker__link:not(:last-child){border-bottom:0;border-bottom-left-radius:0;border-bottom-right-radius:0}.link-picker__link:not(:first-child){border-top:0;border-top-left-radius:0;border-top-right-radius:0}.link-picker__link:hover,.link-picker__link:focus{background:#eef0f4;text-decoration:none;color:inherit}.link-picker__link::before{top:29px;left:32px;content:" ";position:absolute;border:1px solid #cf3f00;border-radius:100%;bottom:6px;box-shadow:0 0 1px .5px #fff;display:block;height:8px;width:8px;z-index:1}.link-picker__link--draft::before{background-color:#ff7f22}.link-picker__link--modified::before{background-color:#fff7f0}.link-picker__link--unsaved::before,.link-picker__link--unversioned::before,.link-picker__link--published::before{display:none}.link-picker__link.readonly{background-color:#eef0f4}.link-picker__button{display:flex;align-items:center;flex-grow:1;height:100%;min-width:0;text-align:left;border:none;margin-right:0}.link-picker__button[class*=font-icon-]::before{position:absolute;font-size:1.231rem;padding:.76925rem;margin-right:6px;flex-grow:0}.link-picker__link-detail{flex-grow:1;width:100%;padding-left:3.5rem}.link-picker__delete{flex-grow:0}.link-picker__url{color:#0071c4}.link-picker__type,.link-picker__title-text{display:inline-block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.link-picker__title{display:flex;align-items:center;width:100%}.link-picker__title .badge{color:#cf3f00;background-color:#fff2ea;padding:2px 3px 2px 4px}.link-picker__title-text{min-width:0;margin-right:5px}.link-picker__type{width:100%} +.link-field__container{position:relative}.link-field__loading{position:absolute;top:0;left:0;width:100%;height:100%}.link-field__loading .cms-content-loading-overlay{position:relative}.link-field__save-record-first{padding-top:7px}.link-picker__link,.link-picker{display:flex;height:auto;width:100%;min-height:54px;background:#fff;padding:0}.link-picker{align-items:stretch;cursor:pointer;box-shadow:none}.link-picker:not(:last-child){margin-bottom:10px}.link-picker.font-icon-link::before{margin:.76925rem}.link-picker__cannot-create{cursor:default;flex-grow:1;padding:16px 13px}.link-picker__menu{flex-grow:1}.link-picker__menu-toggle{width:100%;height:100%;text-align:left}.link-picker__menu-toggle::before{padding:.76925rem}.link-picker__menu-icon{vertical-align:middle;padding-right:.7rem}.link-picker__link{align-items:center;text-align:left;margin-right:0;justify-content:space-between;position:relative}.link-picker__link:not(:last-child){border-bottom:0;border-bottom-left-radius:0;border-bottom-right-radius:0}.link-picker__link:not(:first-child){border-top:0;border-top-left-radius:0;border-top-right-radius:0}.link-picker__link:hover,.link-picker__link:focus{background:#eef0f4;text-decoration:none;color:inherit}.link-picker__link::before{top:29px;left:32px;content:" ";position:absolute;border:1px solid #cf3f00;border-radius:100%;bottom:6px;box-shadow:0 0 1px .5px #fff;display:block;height:8px;width:8px;z-index:1}.link-picker__link--draft::before{background-color:#ff7f22}.link-picker__link--modified::before{background-color:#fff7f0}.link-picker__link--unsaved::before,.link-picker__link--unversioned::before,.link-picker__link--published::before{display:none}.link-picker__link--readonly{background-color:#eef0f4}.link-picker__button{display:flex;align-items:center;flex-grow:1;height:100%;min-width:0;text-align:left;border:none;margin-right:0}.link-picker__button[class*=font-icon-]::before{position:absolute;font-size:1.231rem;padding:.76925rem;margin-right:6px;flex-grow:0}.link-picker__link-detail{flex-grow:1;width:100%;padding-left:3.5rem}.link-picker__delete{flex-grow:0}.link-picker__url{color:#0071c4}.link-picker__type,.link-picker__title-text{display:inline-block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.link-picker__title{display:flex;align-items:center;width:100%}.link-picker__title .badge{color:#cf3f00;background-color:#fff2ea;padding:2px 3px 2px 4px}.link-picker__title-text{min-width:0;margin-right:5px}.link-picker__type{width:100%} diff --git a/client/src/components/LinkField/LinkField.js b/client/src/components/LinkField/LinkField.js index cd8a7807..90bdcf53 100644 --- a/client/src/components/LinkField/LinkField.js +++ b/client/src/components/LinkField/LinkField.js @@ -39,6 +39,7 @@ const LinkField = ({ actions, isMulti = false, canCreate, + readonly, ownerID, ownerClass, ownerRelation, @@ -168,6 +169,7 @@ const LinkField = ({ onClick={() => { setEditingID(linkID); }} canDelete={data[linkID]?.canDelete ? true : false} canCreate={canCreate} + readonly={readonly} />); } return links; @@ -187,6 +189,7 @@ const LinkField = ({ onModalClosed={onModalClosed} types={types} canCreate={canCreate} + readonly={readonly} /> }
{ renderLinks() }
{ renderModal && { +const LinkPicker = ({ types, onModalSuccess, onModalClosed, canCreate, readonly }) => { const [typeKey, setTypeKey] = useState(''); /** @@ -42,7 +42,7 @@ const LinkPicker = ({ types, onModalSuccess, onModalClosed, canCreate }) => { const className = classnames('link-picker', 'form-control'); const typeArray = Object.values(types); - if (!canCreate) { + if (!canCreate || readonly) { return (
@@ -71,7 +71,8 @@ LinkPicker.propTypes = { types: PropTypes.object.isRequired, onModalSuccess: PropTypes.func.isRequired, onModalClosed: PropTypes.func, - canCreate: PropTypes.bool.isRequired + canCreate: PropTypes.bool.isRequired, + readonly: PropTypes.bool.isRequired, }; export {LinkPicker as Component}; diff --git a/client/src/components/LinkPicker/LinkPicker.scss b/client/src/components/LinkPicker/LinkPicker.scss index 76defd51..9211d689 100644 --- a/client/src/components/LinkPicker/LinkPicker.scss +++ b/client/src/components/LinkPicker/LinkPicker.scss @@ -106,7 +106,7 @@ display: none; } - &.readonly { + &--readonly { background-color: $gray-100; } } diff --git a/client/src/components/LinkPicker/LinkPickerTitle.js b/client/src/components/LinkPicker/LinkPickerTitle.js index 10ce1333..d92f0279 100644 --- a/client/src/components/LinkPicker/LinkPickerTitle.js +++ b/client/src/components/LinkPicker/LinkPickerTitle.js @@ -41,12 +41,13 @@ const LinkPickerTitle = ({ onClick, canDelete, canCreate, + readonly, }) => { const { loading } = useContext(LinkFieldContext); const classes = { 'link-picker__link': true, 'form-control': true, - 'readonly': !canCreate, + 'link-picker__link--readonly': readonly || !canCreate, }; if (versionState) { classes[` link-picker__link--${versionState}`] = true; @@ -68,7 +69,7 @@ const LinkPickerTitle = ({
- {(canDelete && canCreate) && + {(canDelete && !readonly) && }
@@ -85,6 +86,7 @@ LinkPickerTitle.propTypes = { onClick: PropTypes.func.isRequired, canDelete: PropTypes.bool.isRequired, canCreate: PropTypes.bool.isRequired, + readonly: PropTypes.bool.isRequired, }; export default LinkPickerTitle; diff --git a/client/src/components/LinkPicker/tests/LinkPicker-test.js b/client/src/components/LinkPicker/tests/LinkPicker-test.js index 213bc226..0f24dead 100644 --- a/client/src/components/LinkPicker/tests/LinkPicker-test.js +++ b/client/src/components/LinkPicker/tests/LinkPicker-test.js @@ -8,6 +8,7 @@ function makeProps(obj = {}) { return { types: { phone: { key: 'phone', title: 'Phone', icon: 'font-icon-phone' } }, canCreate: true, + readonly: false, onModalSuccess: () => {}, onModalClosed: () => {}, ...obj diff --git a/client/src/components/LinkPicker/tests/LinkPickerTitle-test.js b/client/src/components/LinkPicker/tests/LinkPickerTitle-test.js index e87df1c4..cc56ef7e 100644 --- a/client/src/components/LinkPicker/tests/LinkPickerTitle-test.js +++ b/client/src/components/LinkPicker/tests/LinkPickerTitle-test.js @@ -15,6 +15,7 @@ function makeProps(obj = {}) { typeIcon: 'font-icon-phone', canDelete: true, canCreate: true, + readonly: false, onDelete: () => {}, onClick: () => {}, ...obj @@ -86,3 +87,17 @@ test('LinkPickerTitle main button should not fire the onClick callback while loa fireEvent.click(container.querySelector('button.link-picker__button')); expect(mockOnClick).toHaveBeenCalledTimes(0); }); + +test('LinkPickerTitle render() should have readonly class if cannot edit', () => { + const { container } = render( + + ); + expect(container.querySelectorAll('.link-picker__link--readonly')).toHaveLength(1); +}); + +test('LinkPickerTitle render() should not have readonly class if can edit', () => { + const { container } = render( + + ); + expect(container.querySelectorAll('.link-picker__link--readonly')).toHaveLength(0); +}); diff --git a/client/src/entwine/LinkField.js b/client/src/entwine/LinkField.js index 6c59ec28..2c8f23e3 100644 --- a/client/src/entwine/LinkField.js +++ b/client/src/entwine/LinkField.js @@ -55,6 +55,7 @@ jQuery.entwine('ss', ($) => { isMulti: this.data('is-multi') ?? false, types: this.data('types') ?? {}, canCreate: inputField.data('can-create') ? true : false, + readonly: inputField.data('readonly') ? true : false, }; }, diff --git a/src/Controllers/LinkFieldController.php b/src/Controllers/LinkFieldController.php index f78f9f58..945bc7fb 100644 --- a/src/Controllers/LinkFieldController.php +++ b/src/Controllers/LinkFieldController.php @@ -310,7 +310,7 @@ private function createLinkForm(Link $link, string $operation): Form // Make readonly if fail can check if ($operation === 'create' && !$link->canCreate() || $operation === 'edit' && !$link->canEdit() - || $this->isReadOnlyField() && !$link->canEdit() + || $this->isReadOnlyField() ) { $form->makeReadonly(); } @@ -326,12 +326,10 @@ private function createLinkForm(Link $link, string $operation): Form */ private function isReadOnlyField(): bool { - $request = $this->getRequest(); - $ownerClass = $request->getVar('ownerClass') ?: $request->postVar('OwnerClass'); + $ownerClass = $this->getOwnerClassFromRequest(); $ownerRelation = $this->ownerRelationFromRequest(); - $isReadOnly = Injector::inst()->get($ownerClass)->getCMSFields()->dataFieldByName($ownerRelation)?->isReadonly(); - return $isReadOnly ?? false; + return (bool) Injector::inst()->get($ownerClass)->getCMSFields()->dataFieldByName($ownerRelation)?->isReadonly(); } /** @@ -416,20 +414,41 @@ private function typeKeyFromRequest(): string } /** - * Get the owner based on the query string params ownerID, ownerClass, ownerRelation - * OR the POST vars OwnerID, OwnerClass, OwnerRelation + * Get the owner class based on the query string param OwnerClass */ - private function ownerFromRequest(): DataObject + private function getOwnerClassFromRequest(): string { $request = $this->getRequest(); - $ownerID = (int) ($request->getVar('ownerID') ?: $request->postVar('OwnerID')); - if ($ownerID === 0) { - $this->jsonError(404, _t(__CLASS__ . '.INVALID_OWNER_ID', 'Invalid ownerID')); - } $ownerClass = $request->getVar('ownerClass') ?: $request->postVar('OwnerClass'); if (!is_a($ownerClass, DataObject::class, true)) { $this->jsonError(404, _t(__CLASS__ . '.INVALID_OWNER_CLASS', 'Invalid ownerClass')); } + + return $ownerClass; + } + + /** + * Get the owner ID based on the query string param OwnerID + */ + private function getOwnerIDFromRequest(): int + { + $request = $this->getRequest(); + $ownerID = (int) ($request->getVar('ownerID') ?: $request->postVar('OwnerID')); + if ($ownerID === 0) { + $this->jsonError(404, _t(__CLASS__ . '.INVALID_OWNER_ID', 'Invalid ownerID')); + } + + return $ownerID; + } + + /** + * Get the owner based on the query string params ownerID, ownerClass, ownerRelation + * OR the POST vars OwnerID, OwnerClass, OwnerRelation + */ + private function ownerFromRequest(): DataObject + { + $ownerID = $this->getOwnerIDFromRequest(); + $ownerClass = $this->getOwnerClassFromRequest(); $ownerRelation = $this->ownerRelationFromRequest(); /** @var DataObject $obj */ $obj = Injector::inst()->get($ownerClass); @@ -467,6 +486,7 @@ private function ownerRelationFromRequest(): string if (!$ownerRelation) { $this->jsonError(404, _t(__CLASS__ . '.INVALID_OWNER_RELATION', 'Invalid ownerRelation')); } + return $ownerRelation; } } diff --git a/src/Form/LinkField.php b/src/Form/LinkField.php index f9b2591d..823ef6ce 100644 --- a/src/Form/LinkField.php +++ b/src/Form/LinkField.php @@ -2,13 +2,10 @@ namespace SilverStripe\LinkField\Form; -use LogicException; use SilverStripe\Forms\FormField; use SilverStripe\LinkField\Models\Link; use SilverStripe\LinkField\Form\Traits\AllowedLinkClassesTrait; use SilverStripe\LinkField\Form\Traits\LinkFieldGetOwnerTrait; -use SilverStripe\ORM\DataObject; -use SilverStripe\ORM\DataObjectInterface; /** * Allows CMS users to edit a Link object. @@ -36,7 +33,8 @@ public function setValue($value, $data = null) public function getSchemaStateDefaults() { $data = parent::getSchemaStateDefaults(); - $data['canCreate'] = $this->getOwner()->canEdit() && !$this->isReadonly(); + $data['canCreate'] = $this->getOwner()->canEdit(); + $data['readonly'] = $this->isReadonly(); return $data; } @@ -44,7 +42,8 @@ protected function getDefaultAttributes(): array { $attributes = parent::getDefaultAttributes(); $attributes['data-value'] = $this->Value(); - $attributes['data-can-create'] = $this->getOwner()->canEdit() && !$this->isReadonly(); + $attributes['data-can-create'] = $this->getOwner()->canEdit(); + $attributes['data-readonly'] = $this->isReadonly(); $ownerFields = $this->getOwnerFields(); $attributes['data-owner-id'] = $ownerFields['ID']; $attributes['data-owner-class'] = $ownerFields['Class']; @@ -63,13 +62,14 @@ public function getSchemaDataDefaults() return $data; } - /** + /** * Changes this field to the readonly field. */ public function performReadonlyTransformation() { - $copy = $this->castedCopy(LinkField_Readonly::class); + $clone = $this->castedCopy($this); + $clone->setReadonly(true); - return $copy; + return $clone; } } diff --git a/src/Form/LinkField_Readonly.php b/src/Form/LinkField_Readonly.php deleted file mode 100644 index e41b2b91..00000000 --- a/src/Form/LinkField_Readonly.php +++ /dev/null @@ -1,27 +0,0 @@ -name, $this->title); - $field->setValue($this->Value()); - $field->setForm($this->form); - - // Store values to hidden field - $valueField = new HiddenField($this->name); - $valueField->setValue($this->Value()); - $valueField->setForm($this->form); - - return $field->Field() . $valueField->Field(); - } -} diff --git a/src/Form/MultiLinkField.php b/src/Form/MultiLinkField.php index a454fd14..a8540a81 100644 --- a/src/Form/MultiLinkField.php +++ b/src/Form/MultiLinkField.php @@ -53,7 +53,8 @@ public function getSchemaStateDefaults() { $data = parent::getSchemaStateDefaults(); $data['value'] = $this->getValueArray(); - $data['canCreate'] = $this->getOwner()->canEdit() && !$this->isReadonly(); + $data['canCreate'] = $this->getOwner()->canEdit(); + $data['readonly'] = $this->isReadonly(); return $data; } @@ -61,7 +62,8 @@ protected function getDefaultAttributes(): array { $attributes = parent::getDefaultAttributes(); $attributes['data-value'] = $this->getValueArray(); - $attributes['data-can-create'] = $this->getOwner()->canEdit() && !$this->isReadonly(); + $attributes['data-can-create'] = $this->getOwner()->canEdit(); + $attributes['data-readonly'] = $this->isReadonly(); $ownerFields = $this->getOwnerFields(); $attributes['data-owner-id'] = $ownerFields['ID']; $attributes['data-owner-class'] = $ownerFields['Class']; @@ -72,7 +74,7 @@ protected function getDefaultAttributes(): array /** * Extracts the value of this field, normalised as a non-associative array. */ - protected function getValueArray(): array + private function getValueArray(): array { return $this->convertValueToArray($this->Value()); } @@ -156,13 +158,14 @@ private function loadFrom(DataObject $record): void parent::setValue($value); } - /** + /** * Changes this field to the readonly field. */ public function performReadonlyTransformation() { - $copy = $this->castedCopy(MultiLinkField_Readonly::class); + $clone = $this->castedCopy($this); + $clone->setReadonly(true); - return $copy; + return $clone; } } diff --git a/src/Form/MultiLinkField_Readonly.php b/src/Form/MultiLinkField_Readonly.php deleted file mode 100644 index 4cc4768c..00000000 --- a/src/Form/MultiLinkField_Readonly.php +++ /dev/null @@ -1,27 +0,0 @@ -name, $this->title); - $field->setValue($this->getValueArray()); - $field->setForm($this->form); - - // Store values to hidden field - $valueField = new HiddenField($this->name); - $valueField->setValue($this->getValueArray()); - $valueField->setForm($this->form); - - return $field->Field() . $valueField->Field(); - } -}