forked from silverstripe/silverstripe-linkfield
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
NEW LinkFieldController to handle FormSchema
- Loading branch information
1 parent
f0a3b25
commit 40722cb
Showing
26 changed files
with
1,818 additions
and
240 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,5 +5,4 @@ | |
|
||
// Avoid creating global variables | ||
call_user_func(function () { | ||
|
||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,90 +1,170 @@ | ||
import React, { Fragment, useState } from 'react'; | ||
import { compose } from 'redux'; | ||
import React, { useState, useEffect } from 'react'; | ||
import { bindActionCreators, compose } from 'redux'; | ||
import { connect } from 'react-redux'; | ||
import { inject, injectGraphql, loadComponent } from 'lib/Injector'; | ||
import fieldHolder from 'components/FieldHolder/FieldHolder'; | ||
import * as toastsActions from 'state/toasts/ToastsActions'; | ||
import backend from 'lib/Backend'; | ||
import Config from 'lib/Config'; | ||
|
||
const LinkField = ({ id, loading, Loading, data, LinkPicker, onChange, types, linkDescription, ...props }) => { | ||
if (loading) { | ||
return <Loading />; | ||
} | ||
const LinkField = ({ loading, Loading, data, LinkPicker, onChange, types, actions, ...props}) => { | ||
|
||
const [editing, setEditing] = useState(false); | ||
const [newTypeKey, setNewTypeKey] = useState(''); | ||
const [typeKey, setTypeKey] = useState(data.typeKey || ''); | ||
const [linkID, setLinkID] = useState(data.ID || 0); | ||
const [linkData, setLinkData] = useState({}); | ||
|
||
const onClear = (event) => { | ||
if (typeof onChange !== 'function') { | ||
return; | ||
// deleteUrl is set via LeftAndMainExtension.php | ||
const endpoint = `${section.form.DynamicLink.deleteUrl}/${linkID}`; | ||
backend.delete(endpoint) | ||
.then(() => { | ||
actions.toasts.success('Deleted link'); | ||
}) | ||
.catch(() => { | ||
actions.toasts.error('Failed to delete link'); | ||
}); | ||
|
||
setLinkID(0); | ||
setTypeKey(''); | ||
if (typeof onChange === 'function') { | ||
onChange(event, {}); | ||
} | ||
|
||
onChange(event, { id, value: {} }); | ||
}; | ||
|
||
const onModalSubmit = async (modalData, action, submitFn) => { | ||
const { | ||
SecurityID, | ||
action_submit: actionSubmit, | ||
...data | ||
} = modalData; | ||
|
||
// get id from formSchema | ||
let id = 0; | ||
const formSchema = await submitFn(); | ||
// formSchema will be undefined for FileLink which uses asset-admin graphql when using InsertMediaModal rather than FormBuilderModal | ||
if (typeof formSchema !== 'undefined') { | ||
// onsuccess formSchema.id | ||
let match = formSchema.id.match(/\/linkForm\/[a-z\-]+\/([0-9]+)$/); | ||
if (match) { | ||
id = parseInt(match[1]); | ||
} | ||
// onfailure formSchema.id | ||
match = formSchema.id.match(/\/schema\/linkfield\/[a-z\-]+\/([0-9]+)$/); | ||
if (match) { | ||
id = parseInt(match[1]); | ||
} | ||
} | ||
|
||
// update parent JsonField data id - this is required to update the underlying <input form field> | ||
// so that the Page (or other parent DataObject) gets the Link relation ID set | ||
if (typeof onChange === 'function') { | ||
data.ID = id; | ||
onChange(null, data); | ||
} | ||
|
||
// update component state | ||
setLinkID(id); | ||
setEditing(false); | ||
// setTypeKey(''); | ||
|
||
// trigger success toast | ||
actions.toasts.success('Saved link'); | ||
|
||
return Promise.resolve(); | ||
}; | ||
|
||
const { typeKey } = data; | ||
const type = types[typeKey]; | ||
const modalType = newTypeKey ? types[newTypeKey] : type; | ||
const section = Config.getSection('SilverStripe\\Admin\\LeftAndMain'); | ||
// const typeKey = data.typeKey; | ||
// const type = types[typeKey] || {}; | ||
// const linkType = newTypeKey ? types[newTypeKey] : type; | ||
// const handlerName = modalType ? modalType.handlerName : 'FormBuilderModal'; | ||
const handlerName = 'FormBuilderModal'; | ||
const LinkModal = loadComponent(`LinkModal.${handlerName}`); | ||
|
||
let title = data ? data.Title : ''; | ||
// jsonFieldData is the initial value of the field passed from JsonField | ||
// linkData is XHR'd in from the endpoint afterwards | ||
const hasLinkData = Object.keys(linkData).length > 0; | ||
const theData = hasLinkData ? linkData : data; | ||
const title = theData.Title || theData.TitleRelField || ''; | ||
|
||
if (!title) { | ||
title = data ? data.TitleRelField : ''; | ||
} | ||
const type = types.hasOwnProperty(typeKey) ? types[typeKey] : {}; | ||
|
||
const linkProps = { | ||
const pickerProps = { | ||
title, | ||
link: type ? { type, title, description: linkDescription } : undefined, | ||
onEdit: () => { setEditing(true); }, | ||
description: theData.description, | ||
typeTitle: type.title || '', | ||
onEdit: () => { | ||
setEditing(true); | ||
}, | ||
onClear, | ||
onSelect: (key) => { | ||
setNewTypeKey(key); | ||
setTypeKey(key); | ||
setEditing(true); | ||
}, | ||
types: Object.values(types) | ||
}; | ||
|
||
const onModalSubmit = (modalData, action, submitFn) => { | ||
const { SecurityID, action_insert: actionInsert, ...value } = modalData; | ||
|
||
if (typeof onChange === 'function') { | ||
onChange(event, { id, value }); | ||
} | ||
|
||
setEditing(false); | ||
setNewTypeKey(''); | ||
|
||
return Promise.resolve(); | ||
}; | ||
|
||
const modalProps = { | ||
type: modalType, | ||
// type: modalType, | ||
typeTitle: type.title || '', | ||
typeKey, | ||
editing, | ||
onSubmit: onModalSubmit, | ||
onClosed: () => { | ||
setEditing(false); | ||
}, | ||
data | ||
linkID, | ||
data: theData | ||
}; | ||
|
||
const handlerName = modalType ? modalType.handlerName : 'FormBuilderModal'; | ||
const LinkModal = loadComponent(`LinkModal.${handlerName}`); | ||
// read data from endpoint and update component state | ||
useEffect(() => { | ||
if (!editing && linkID) { | ||
const endpoint = `${section.form.DynamicLink.dataUrl}/${linkID}`; | ||
backend.get(endpoint) | ||
.then(response => response.json()) | ||
.then(responseJson => { | ||
setLinkData(responseJson); | ||
}); | ||
} | ||
}, [editing, linkID]); | ||
|
||
if (loading) { | ||
return <Loading />; | ||
} | ||
|
||
return <Fragment> | ||
<LinkPicker {...linkProps} /> | ||
<LinkModal {...modalProps} /> | ||
</Fragment>; | ||
return <> | ||
<LinkPicker {...pickerProps} /> | ||
<LinkModal {...modalProps} /> | ||
</>; | ||
}; | ||
|
||
const stringifyData = (Component) => (({ data, value, ...props }) => { | ||
const stringifyData = (Component) => (({ value, data, ...props }) => { | ||
let dataValue = value || data; | ||
if (typeof dataValue === 'string') { | ||
dataValue = JSON.parse(dataValue); | ||
} | ||
return <Component dataStr={JSON.stringify(dataValue)} {...props} data={dataValue} />; | ||
return <Component | ||
// dataStr={JSON.stringify(dataValue)} | ||
{...props} | ||
data={dataValue} | ||
/>; | ||
}); | ||
|
||
const mapDispatchToProps = (dispatch) => { | ||
return { | ||
actions: { | ||
toasts: bindActionCreators(toastsActions, dispatch), | ||
}, | ||
}; | ||
} | ||
|
||
export default compose( | ||
inject(['LinkPicker', 'Loading']), | ||
injectGraphql('readLinkTypes'), | ||
stringifyData, | ||
injectGraphql('readLinkDescription'), | ||
fieldHolder | ||
stringifyData, // get rid of this? | ||
// injectGraphql('readLinkDescription'), | ||
fieldHolder, | ||
connect(null, mapDispatchToProps) | ||
)(LinkField); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.