Skip to content

Commit

Permalink
Update support for Silverstripe 5 (#55)
Browse files Browse the repository at this point in the history
Co-authored-by: Bernard Hamlin <[email protected]>
  • Loading branch information
chrispenny and blueo authored May 17, 2023
1 parent c4f33b3 commit 469ad24
Show file tree
Hide file tree
Showing 28 changed files with 6,063 additions and 10,175 deletions.
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
10
18
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,16 @@ This module provides a Link model and CMS interface for managing different types

Installation via composer.

### GraphQL v4 - Silverstripe 4
### Silverstripe 5

```sh
composer require silverstripe/linkfield
```

### GraphQL v4 - Silverstripe 4

`composer require silverstripe/linkfield:^2`

### GraphQL v3 - Silverstripe 4

```sh
Expand Down
6 changes: 6 additions & 0 deletions babel.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
]
}
2 changes: 1 addition & 1 deletion client/dist/js/bundle.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion client/dist/styles/bundle.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions client/src/bundles/bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
*/
// require('expose-loader?InsertMediaModal!containers/InsertMediaModal/InsertMediaModal');

require('boot');
require('entwine/JsonField.js');
import 'boot';
import 'entwine/JsonField';
55 changes: 31 additions & 24 deletions client/src/components/LinkField/LinkField.js
Original file line number Diff line number Diff line change
@@ -1,50 +1,58 @@
/* eslint-disable */
import i18n from 'i18n';
import React, { Component, Fragment, useState } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators, compose } from 'redux';
import { withApollo } from 'react-apollo';
import React, { Fragment, useState } from 'react';
import { compose } from 'redux';
import { inject, injectGraphql, loadComponent } from 'lib/Injector';
import fieldHolder from 'components/FieldHolder/FieldHolder';
import PropTypes from 'prop-types';

const LinkField = ({id, loading, Loading, data, LinkPicker, onChange, types, linkDescription, ...props}) => {
const LinkField = ({ id, loading, Loading, data, LinkPicker, onChange, types, linkDescription, ...props }) => {
if (loading) {
return <Loading />
return <Loading />;
}

const [editing, setEditing] = useState(false);
const [newTypeKey, setNewTypeKey] = useState('');

const onClear = (event) => {
typeof onChange === 'function' && onChange(event, { id, value: {}})
}
if (typeof onChange !== 'function') {
return;
}

onChange(event, { id, value: {} });
};

const { typeKey } = data;
const type = types[typeKey];
const modalType = newTypeKey ? types[newTypeKey] : type;

let title = data ? data.Title : '';

if (!title) {
title = data ? data.TitleRelField : '';
}

const linkProps = {
title: data ? data.Title : '',
link: type ? {type, title: data.Title, description: linkDescription} : undefined,
onEdit: () => {setEditing(true)},
title,
link: type ? { type, title, description: linkDescription } : undefined,
onEdit: () => { setEditing(true); },
onClear,
onSelect: (key) => {
setNewTypeKey(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 });
}

const onModalSubmit = (data, action, submitFn) => {
console.dir({data, action, submitFn, onChange});
const {SecurityID, action_insert, ...value} = data;
typeof onChange === 'function' && onChange(event, { id, value})
setEditing(false);
setNewTypeKey('');

return Promise.resolve();
}
};

const modalProps = {
type: modalType,
Expand All @@ -57,15 +65,15 @@ const LinkField = ({id, loading, Loading, data, LinkPicker, onChange, types, lin
};

const handlerName = modalType ? modalType.handlerName : 'FormBuilderModal';
const LinkModal = loadComponent(`LinkModal.${handlerName}`)
const LinkModal = loadComponent(`LinkModal.${handlerName}`);

return <Fragment>
<LinkPicker {...linkProps} />
<LinkModal {...modalProps} />
</Fragment>;
}
};

const stringifyData = (Component) => ( ({data, value, ...props}) => {
const stringifyData = (Component) => (({ data, value, ...props }) => {
let dataValue = value || data;
if (typeof dataValue === 'string') {
dataValue = JSON.parse(dataValue);
Expand All @@ -78,6 +86,5 @@ export default compose(
injectGraphql('readLinkTypes'),
stringifyData,
injectGraphql('readLinkDescription'),
withApollo,
fieldHolder
)(LinkField);
16 changes: 13 additions & 3 deletions client/src/components/LinkPicker/LinkPicker.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.link-picker {
display: flex;
height: 54px;
height: auto;
min-height: 54px;
background: white;
width: 100%;
align-items: stretch;
Expand All @@ -13,8 +14,7 @@
}

&__menu {
width: 100%;
height: 100%;
flex-grow: 1;
}

&__menu-toggle {
Expand All @@ -39,13 +39,23 @@
text-align: left;
border: none;
margin-right: 0;
justify-content: space-between;

&:hover, &:focus {
background: $gray-100;
text-decoration: none;
color: inherit;
}
}

&__button {
display: flex;
align-items: center;
flex-grow: 1;
height: 100%;
text-align: left;
border: none;
margin-right: 0;
&::before {
font-size: 1.231rem;
padding: .76925rem;
Expand Down
13 changes: 6 additions & 7 deletions client/src/components/LinkPicker/LinkPickerTitle.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
/* eslint-disable */
import i18n from 'i18n';
import React from 'react';
import { inject } from 'lib/Injector';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import LinkType from 'types/LinkType';
import {Button} from 'reactstrap';

const stopPropagation = (fn) => (e) => {
console.log('trying to stop propagation');
e.nativeEvent.stopImmediatePropagation();
e.preventDefault();
e.nativeEvent.preventDefault();
Expand All @@ -17,16 +14,18 @@ const stopPropagation = (fn) => (e) => {
}

const LinkPickerTitle = ({ title, type, description, onClear, onClick }) => (
<Button className="link-picker__link font-icon-link" color="secondary" onClick={stopPropagation(onClick)}>
<div className="link-picker__link-detail">
<div className="link-picker__link" >
<Button className="link-picker__button font-icon-link" color="secondary" onClick={stopPropagation(onClick)}>
<div className="link-picker__link-detail">
<div className="link-picker__title">{title}</div>
<small className="link-picker__type">
{type.title}:&nbsp;
<span className="link-picker__url">{description}</span>
</small>
</div>
</div>
</Button>
<Button className="link-picker__clear" color="link" onClick={stopPropagation(onClear)}>{i18n._t('Link.CLEAR', 'Clear')}</Button>
</Button>
</div>
);

LinkPickerTitle.propTypes = {
Expand Down
10 changes: 7 additions & 3 deletions client/src/entwine/JsonField.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
/* eslint-disable */
import jQuery from 'jquery';
import React from 'react';
import ReactDOM from 'react-dom';
import ReactDOM from 'react-dom/client';
import { loadComponent } from 'lib/Injector';

jQuery.entwine('ss', ($) => {
$('.js-injector-boot .entwine-jsonfield').entwine({

Component: null,
Root: null,

onmatch() {
const cmsContent = this.closest('.cms-content').attr('id');
Expand All @@ -20,14 +21,16 @@ jQuery.entwine('ss', ($) => {
const ReactField = loadComponent(schemaComponent, context);

this.setComponent(ReactField);
this.setRoot(ReactDOM.createRoot(this[0]))
this._super();
this.refresh();
},

refresh() {
const props = this.getProps();
const ReactField = this.getComponent();
ReactDOM.render(<ReactField {...props} noHolder/>, this[0]);
const Root = this.getRoot();
Root.render(<ReactField {...props} noHolder/>);
},

handleChange(event, {id, value}) {
Expand Down Expand Up @@ -57,7 +60,8 @@ jQuery.entwine('ss', ($) => {
* Remove the component when unmatching
*/
onunmatch() {
ReactDOM.unmountComponentAtNode(this[0]);
const Root = this.getRoot();
Root.unmount();
},
});
});
Empty file.
1 change: 0 additions & 1 deletion client/src/styles/bundle.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// Variables
@import "link-variables";
// See includePaths in webpack.config.js
@import "variables";

Expand Down
7 changes: 3 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@
"description": "Add advanced link functionality to Silverstripe.",
"type": "silverstripe-vendormodule",
"require": {
"php": "^7.4 || ^8",
"silverstripe/cms": "^4.11",
"silverstripe/graphql": "^4"
"php": "^8.1",
"silverstripe/cms": "^5"
},
"require-dev": {
"silverstripe/recipe-testing": "^2",
"silverstripe/recipe-testing": "^3",
"squizlabs/php_codesniffer": "^3"
},
"license": "BSD-3-Clause",
Expand Down
81 changes: 30 additions & 51 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
},
"author": "SilverStripe Ltd",
"engines": {
"node": "^10.x"
"node": "^18.x"
},
"scripts": {
"build": "yarn && yarn lint && yarn test && NODE_ENV=production webpack -p --bail --progress",
"build": "yarn && yarn lint && yarn test && rm -rf client/dist/* && NODE_ENV=production webpack --mode production --bail --progress",
"dev": "NODE_ENV=development webpack --progress",
"watch": "NODE_ENV=development webpack --watch --progress",
"css": "WEBPACK_CHILD=css npm run build",
Expand Down Expand Up @@ -48,58 +48,37 @@
}
},
"devDependencies": {
"@silverstripe/eslint-config": "0.0.5",
"@silverstripe/webpack-config": "^1.5.0",
"@storybook/addon-actions": "^3.4.11",
"@storybook/addons": "^3.4.11",
"@storybook/react": "^3.4.11",
"babel-jest": "^23.6.0",
"copy-webpack-plugin": "^4",
"jest-cli": "^23.6.0",
"webpack": "^2.6.1"
"@babel/runtime": "^7.20.0",
"@silverstripe/eslint-config": "^1.0.0-alpha6",
"@silverstripe/webpack-config": "^2.0.0-alpha9",
"babel-jest": "^29.2.2",
"jest-cli": "^29.2.2",
"jest-environment-jsdom": "^29.3.1",
"webpack": "^5.74.0",
"webpack-cli": "^5.0.0"
},
"dependencies": {
"apollo-client": "^2.4.2",
"apollo-link-batch-http": "^1.2.1",
"babel-core": "^6.26.3",
"babel-polyfill": "6.7.4",
"babel-runtime": "6.26.0",
"bootstrap": "^4.3.1",
"@apollo/client": "^3.7.1",
"bootstrap": "^4.6.2",
"core-js": "^3.26.0",
"classnames": "^2.2.5",
"deep-freeze-strict": "^1.1.1",
"dropzone": "^5.5.1",
"graphql": "^0.13.2",
"graphql-fragments": "^0.1.0",
"graphql-tag": "^2.8.0",
"griddle-react": "^0.8.2",
"jquery": "^3.1.1",
"merge": "^1.2.1",
"modernizr": "^3.5.0",
"popper.js": "^1.14.4",
"prop-types": "^15.6.2",
"qs": "^6.2.1",
"react": "^16.6.1",
"react-apollo": "^2.1.0",
"prop-types": "^15.8.1",
"qs": "^6.11.0",
"react": "^18.2.0",
"react-dnd": "^5.0.0",
"react-dnd-html5-backend": "^5.0.1",
"react-dom": "^16.6.1",
"react-redux": "^5.0.7",
"react-router-dom": "^4.4.0-beta.6",
"react-selectable": "^2.0.2",
"reactstrap": "^6.4.0",
"redux": "^4.0.0",
"redux-form": "^7.4.2",
"redux-logger": "^2.4.0",
"redux-thunk": "^1.0.3",
"webpack-sources": "^1.1.0"
"react-dom": "^18.2.0",
"react-redux": "^8.0.4",
"react-router": "^6.4.2",
"react-router-dom": "^6.4.2",
"react-select": "^5.5.8",
"reactstrap": "^8.9.0",
"redux": "^4.2.0",
"redux-form": "^8.3.8",
"redux-thunk": "^2.4.1",
"webpack-sources": "^3.2.3"
},
"babel": {
"presets": [
"env",
"react"
],
"plugins": [
"transform-object-rest-spread"
]
}
}
"browserslist": [
"defaults"
]
}
Loading

0 comments on commit 469ad24

Please sign in to comment.