diff --git a/client/dist/js/bundle.js b/client/dist/js/bundle.js index 44fd5d6a..14770334 100644 --- a/client/dist/js/bundle.js +++ b/client/dist/js/bundle.js @@ -539,7 +539,7 @@ var _i18n = __webpack_require__(2); var _i18n2 = _interopRequireDefault(_i18n); -var _Backend = __webpack_require__(13); +var _Backend = __webpack_require__(12); var _Backend2 = _interopRequireDefault(_Backend); @@ -708,7 +708,7 @@ var _AbstractAction = __webpack_require__("./client/src/components/ElementAction var _AbstractAction2 = _interopRequireDefault(_AbstractAction); -var _Backend = __webpack_require__(13); +var _Backend = __webpack_require__(12); var _Backend2 = _interopRequireDefault(_Backend); @@ -949,6 +949,10 @@ var _i18n = __webpack_require__(2); var _i18n2 = _interopRequireDefault(_i18n); +var _Backend = __webpack_require__(12); + +var _Backend2 = _interopRequireDefault(_Backend); + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } @@ -981,7 +985,6 @@ var AddElementPopover = function (_Component) { event.preventDefault(); - handleAddElementToArea(elementType.class, insertAfterElement).then(function () { var preview = window.jQuery('.cms-preview'); preview.entwine('ss.preview')._loadUrl(preview.find('iframe').attr('src')); @@ -991,7 +994,22 @@ var AddElementPopover = function (_Component) { } }, { key: 'getElementButtonClickHandler', - value: function getElementButtonClickHandler(elementType) {} + value: function getElementButtonClickHandler(elementType) { + var _this3 = this; + + return function (event) { + event.preventDefault(); + _Backend2.default.post('/admin/elemental-area/add/', { + elementClass: elementType.class, + elementalAreaID: _this3.props.areaId, + insertAfterElementID: _this3.props.insertAfterElement + }).then(function () {}).then(function () { + var preview = window.jQuery('.cms-preview'); + preview.entwine('ss.preview')._loadUrl(preview.find('iframe').attr('src')); + }); + _this3.handleToggle(); + }; + } }, { key: 'handleToggle', value: function handleToggle() { @@ -1003,7 +1021,7 @@ var AddElementPopover = function (_Component) { }, { key: 'render', value: function render() { - var _this3 = this; + var _this4 = this; var _props2 = this.props, PopoverOptionSetComponent = _props2.PopoverOptionSetComponent, @@ -1017,14 +1035,14 @@ var AddElementPopover = function (_Component) { var popoverClassNames = (0, _classnames2.default)('element-editor-add-element', extraClass); - var globalUseGraphQL = true; + var globalUseGraphQL = false; var buttons = elementTypes.map(function (elementType) { return { content: elementType.title, key: elementType.name, className: (0, _classnames2.default)(elementType.icon, 'btn--icon-xl', 'element-editor-add-element__button'), - onClick: globalUseGraphQL ? _this3.getGraphQLElementButtonClickHandler(elementType) : _this3.getElementButtonClickHandler(elementType) + onClick: globalUseGraphQL ? _this4.getGraphQLElementButtonClickHandler(elementType) : _this4.getElementButtonClickHandler(elementType) }; }); @@ -3912,7 +3930,7 @@ Object.defineProperty(exports, "__esModule", { }); exports.getElementTypeConfig = exports.getConfig = undefined; -var _Config = __webpack_require__(12); +var _Config = __webpack_require__(13); var _Config2 = _interopRequireDefault(_Config); @@ -3951,7 +3969,7 @@ Object.defineProperty(exports, "__esModule", { }); exports.loadElementFormStateName = undefined; -var _Config = __webpack_require__(12); +var _Config = __webpack_require__(13); var _Config2 = _interopRequireDefault(_Config); @@ -3983,7 +4001,7 @@ Object.defineProperty(exports, "__esModule", { }); exports.loadElementSchemaValue = undefined; -var _Config = __webpack_require__(12); +var _Config = __webpack_require__(13); var _Config2 = _interopRequireDefault(_Config); @@ -4561,14 +4579,14 @@ module.exports = ReduxForm; /***/ 12: /***/ (function(module, exports) { -module.exports = Config; +module.exports = Backend; /***/ }), /***/ 13: /***/ (function(module, exports) { -module.exports = Backend; +module.exports = Config; /***/ }), diff --git a/client/src/components/ElementEditor/AddElementPopover.js b/client/src/components/ElementEditor/AddElementPopover.js index 39e1cdd0..72121353 100644 --- a/client/src/components/ElementEditor/AddElementPopover.js +++ b/client/src/components/ElementEditor/AddElementPopover.js @@ -6,6 +6,7 @@ import classNames from 'classnames'; import { inject } from 'lib/Injector'; import { elementTypeType } from 'types/elementTypeType'; import i18n from 'i18n'; +import backend from 'lib/Backend'; /** * The AddElementPopover component used in the context of an ElementEditor shows the @@ -27,13 +28,13 @@ class AddElementPopover extends Component { */ getGraphQLElementButtonClickHandler(elementType) { return (event) => { + // handleAddElementToArea comes from addElementMutation.js const { actions: { handleAddElementToArea }, insertAfterElement } = this.props; event.preventDefault(); - // TODO This should probably use the GraphQL element type name (element.__typeName) handleAddElementToArea(elementType.class, insertAfterElement).then( () => { const preview = window.jQuery('.cms-preview'); @@ -51,7 +52,22 @@ class AddElementPopover extends Component { * - also then update the preview via jquery/entwine */ getElementButtonClickHandler(elementType) { - // todo + return (event) => { + event.preventDefault(); + backend.post(`/admin/elemental-area/add/`,{ + elementClass: elementType.class, + elementalAreaID: this.props.areaId, + insertAfterElementID: this.props.insertAfterElement, + }) + .then(() => { + // todo call read blocks from area endpoint (areaID) + }) + .then(() => { + const preview = window.jQuery('.cms-preview'); + preview.entwine('ss.preview')._loadUrl(preview.find('iframe').attr('src')); + }); + this.handleToggle(); + }; } /** @@ -78,7 +94,7 @@ class AddElementPopover extends Component { extraClass ); - const globalUseGraphQL = true; + const globalUseGraphQL = false; const buttons = elementTypes.map((elementType) => ({ content: elementType.title, diff --git a/src/Controllers/ElementalAreaController.php b/src/Controllers/ElementalAreaController.php index 283b6b89..1e350970 100644 --- a/src/Controllers/ElementalAreaController.php +++ b/src/Controllers/ElementalAreaController.php @@ -15,6 +15,10 @@ use SilverStripe\Core\Injector\Injector; use SilverStripe\Forms\Form; use SilverStripe\Security\SecurityToken; +use InvalidArgumentException; +use DNADesign\Elemental\Models\ElementalArea; +use SilverStripe\GraphQL\QueryHandler\UserContextProvider; +use DNADesign\Elemental\Services\ReorderElements; /** * Controller for "ElementalArea" - handles loading and saving of in-line edit forms in an elemental area in admin @@ -31,6 +35,8 @@ class ElementalAreaController extends CMSMain // API access points with structured data 'POST api/saveForm/$ID' => 'apiSaveForm', '$FormName/field/$FieldName' => 'formAction', + // + 'POST add' => 'add', ]; private static $allowed_actions = [ @@ -38,8 +44,63 @@ class ElementalAreaController extends CMSMain 'schema', 'apiSaveForm', 'formAction', + //a + 'add', ]; + // === + + // Resolver.php resolveAddElementToArea() + public function add() + { + $request = $this->getRequest(); + $postVars = json_decode($request->getBody(), true); + $elementClass = $postVars['elementClass']; + $elementalAreaID = $postVars['elementalAreaID']; + $afterElementID = $postVars['afterElementID'] ?? 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::onBeforeWrite() + $newElement->onBeforeWrite(); + + 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 $newElement; + } + + // === + public function getClientConfig() { $clientConfig = parent::getClientConfig();