First stub of the asset location hierarchy editor feature.
This commit is contained in:
parent
51562201ee
commit
771c753518
|
@ -32,6 +32,7 @@
|
|||
"drupal/geofield": "^1.22",
|
||||
"drupal/gin": "3.0-alpha34",
|
||||
"drupal/inline_entity_form": "^1.0@RC",
|
||||
"drupal/inspire_tree": "^1.0",
|
||||
"drupal/jsonapi_extras": "^3.15",
|
||||
"drupal/jsonapi_schema": "^1.0@beta",
|
||||
"drupal/log": "2.x-dev",
|
||||
|
|
|
@ -8,4 +8,5 @@ dependencies:
|
|||
- drupal:user
|
||||
- drupal:views
|
||||
- entity:entity
|
||||
- inspire_tree:inspire_tree
|
||||
- state_machine:state_machine
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
reorder:
|
||||
version: 1.x
|
||||
js:
|
||||
js/asset_reorder.js: {}
|
||||
dependencies:
|
||||
- core/drupal.message
|
||||
- core/jquery
|
||||
- inspire_tree/inspire_tree
|
||||
- inspire_tree/inspire_tree_dom
|
|
@ -2,3 +2,8 @@ entity.asset.collection:
|
|||
route_name: entity.asset.collection
|
||||
title: 'Assets'
|
||||
base_route: system.admin_content
|
||||
entity.asset.locations:
|
||||
route_name: entity.asset.locations
|
||||
title: 'Locations'
|
||||
base_route: entity.asset.canonical
|
||||
weight: 100
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
asset.locations:
|
||||
path: '/asset-locations'
|
||||
defaults:
|
||||
_title: 'Locations'
|
||||
_controller: '\Drupal\asset\Controller\AssetReorderController::build'
|
||||
requirements:
|
||||
_permission: 'administer assets'
|
||||
|
||||
|
||||
entity.asset.locations:
|
||||
path: '/asset/{asset}/locations'
|
||||
defaults:
|
||||
_title: 'Locations'
|
||||
_controller: '\Drupal\asset\Controller\AssetReorderController::build'
|
||||
requirements:
|
||||
_entity_access: 'asset.edit'
|
||||
_module_dependencies: 'asset'
|
||||
asset: \d+
|
||||
options:
|
||||
parameters:
|
||||
asset:
|
||||
type: entity:asset
|
|
@ -0,0 +1,173 @@
|
|||
/**
|
||||
* @file
|
||||
* Integration with inspire tree.
|
||||
*/
|
||||
|
||||
(function ($, Drupal, settings) {
|
||||
|
||||
"use strict";
|
||||
|
||||
// @TODO drag and drop validate if exist.
|
||||
// @TODO validate circular references.
|
||||
|
||||
Drupal.behaviors.asset_reorder = {
|
||||
attach: function (context, settings) {
|
||||
var tree = new InspireTree({
|
||||
data: settings.asset_tree,
|
||||
});
|
||||
new InspireTreeDOM(tree, {
|
||||
target: '.asset-tree',
|
||||
dragAndDrop: true
|
||||
});
|
||||
|
||||
var changes = {};
|
||||
|
||||
tree.on('node.drop', function(event, source, target, index) {
|
||||
var destination = (target === null) ? settings.asset_parent : target.uuid;
|
||||
if (!changes.hasOwnProperty(source.id)) {
|
||||
if (source.original_parent !== destination) {
|
||||
changes[source.id] = {
|
||||
'uuid': source.uuid,
|
||||
'original_parent': source.original_parent,
|
||||
'original_type': source.original_type,
|
||||
'destination': destination,
|
||||
'type': (target === null) ? settings.asset_parent_type : target.type,
|
||||
};
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (changes[source.id].original_parent !== destination) {
|
||||
changes[source.id].destination = destination;
|
||||
}
|
||||
else {
|
||||
delete changes[source.id];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('.asset-tree-reset').on('click', function(event) {
|
||||
event.preventDefault();
|
||||
// Reset the changes so nothing is pushed accidentally.
|
||||
changes = {};
|
||||
// Reset the tree to the original status.
|
||||
tree.reload();
|
||||
});
|
||||
|
||||
$('.asset-tree-save').on('click', function(event) {
|
||||
event.preventDefault();
|
||||
var entries = Object.entries(changes);
|
||||
if (entries.length > 0) {
|
||||
var token = '';
|
||||
$.ajax({
|
||||
async: false,
|
||||
url: Drupal.url('session/token'),
|
||||
success(data) {
|
||||
if (data) {
|
||||
token = data;
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
var messages = new Drupal.Message();
|
||||
for (var [treeUuid, item] of entries) {
|
||||
if (item.destination === '' && item.original_parent !== '') {
|
||||
var deleteItem = {
|
||||
'data': [
|
||||
{
|
||||
'type': 'asset--' + item.original_type,
|
||||
'id': item.original_parent,
|
||||
}
|
||||
]
|
||||
};
|
||||
$.ajax({
|
||||
type: 'DELETE',
|
||||
cache: false,
|
||||
headers: {
|
||||
'X-CSRF-Token': token,
|
||||
},
|
||||
url: '/api/asset/' + item.original_type + '/' + item.uuid + '/relationships/parent',
|
||||
data: JSON.stringify(deleteItem),
|
||||
contentType: 'application/vnd.api+json',
|
||||
success: function success(data) {
|
||||
messages.clear();
|
||||
messages.add(Drupal.t('Assets have been saved'), { type: 'status' });
|
||||
delete changes.treeUuid
|
||||
},
|
||||
error: function error(xmlhttp) {
|
||||
var e = new Drupal.AjaxError(xmlhttp);
|
||||
messages.clear();
|
||||
messages.add(e.message, { type: 'error' });
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
var patch = {
|
||||
'data': [
|
||||
{
|
||||
'type': 'asset--' + item.type,
|
||||
'id': item.destination,
|
||||
}
|
||||
]
|
||||
};
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
cache: false,
|
||||
headers: {
|
||||
'X-CSRF-Token': token,
|
||||
},
|
||||
url: '/api/asset/' + item.type + '/' + item.uuid + '/relationships/parent',
|
||||
data: JSON.stringify(patch),
|
||||
contentType: 'application/vnd.api+json',
|
||||
success: function success(data) {
|
||||
if (item.original_parent !== settings.asset_parent) {
|
||||
var deleteItem = {
|
||||
'data': [
|
||||
{
|
||||
'type': 'asset--' + item.original_type,
|
||||
'id': item.original_parent,
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
$.ajax({
|
||||
type: 'DELETE',
|
||||
cache: false,
|
||||
headers: {
|
||||
'X-CSRF-Token': token,
|
||||
},
|
||||
url: '/api/asset/' + item.original_type + '/' + item.uuid + '/relationships/parent',
|
||||
data: JSON.stringify(deleteItem),
|
||||
contentType: 'application/vnd.api+json',
|
||||
success: function success(data) {
|
||||
messages.clear();
|
||||
messages.add(Drupal.t('Assets have been saved'), { type: 'status' });
|
||||
delete changes.treeUuid
|
||||
},
|
||||
error: function error(xmlhttp) {
|
||||
var e = new Drupal.AjaxError(xmlhttp);
|
||||
messages.clear();
|
||||
messages.add(e.message, { type: 'error' });
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
messages.clear();
|
||||
messages.add(Drupal.t('Assets have been saved'), { type: 'status' });
|
||||
}
|
||||
},
|
||||
error: function error(xmlhttp) {
|
||||
var e = new Drupal.AjaxError(xmlhttp);
|
||||
messages.clear();
|
||||
messages.add(e.message, { type: 'error' });
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
})(jQuery, Drupal, drupalSettings);
|
|
@ -0,0 +1,125 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\asset\Controller;
|
||||
|
||||
use Drupal\asset\Entity\AssetInterface;
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Returns responses for asset drag and drop routes.
|
||||
*/
|
||||
class AssetReorderController extends ControllerBase {
|
||||
|
||||
/**
|
||||
* The entity type manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* The controller constructor.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||
* The entity type manager.
|
||||
*/
|
||||
public function __construct(EntityTypeManagerInterface $entity_type_manager) {
|
||||
$this->entityTypeManager = $entity_type_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('entity_type.manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the response.
|
||||
*/
|
||||
public function build(AssetInterface $asset = NULL) {
|
||||
$build['content'] = [
|
||||
'#type' => 'html_tag',
|
||||
'#tag' => 'div',
|
||||
'#attributes' => [
|
||||
'class' => [
|
||||
'asset-tree',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$build['save'] = [
|
||||
'#type' => 'link',
|
||||
'#title' => $this->t('Save'),
|
||||
'#url' => Url::fromRoute('<none>'),
|
||||
'#attributes' => [
|
||||
'class' => [
|
||||
'asset-tree-save',
|
||||
'button',
|
||||
'button--primary',
|
||||
],
|
||||
],
|
||||
];
|
||||
$build['reset'] = [
|
||||
'#type' => 'link',
|
||||
'#title' => $this->t('Reset'),
|
||||
'#url' => Url::fromRoute('<none>'),
|
||||
'#attributes' => [
|
||||
'class' => [
|
||||
'asset-tree-reset',
|
||||
'button',
|
||||
'button--danger',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$build['#attached']['library'][] = 'asset/reorder';
|
||||
$build['#attached']['drupalSettings']['asset_tree'] = $this->buildTree($asset);
|
||||
$build['#attached']['drupalSettings']['asset_parent'] = !empty($asset) ? $asset->uuid() : '';
|
||||
$build['#attached']['drupalSettings']['asset_parent_type'] = !empty($asset) ? $asset->bundle() : '';
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Drupal\asset\Entity\AssetInterface|null $asset
|
||||
*
|
||||
* @return array
|
||||
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
|
||||
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
|
||||
*/
|
||||
protected function buildTree(AssetInterface $asset = NULL) {
|
||||
$storage = $this->entityTypeManager->getStorage('asset');
|
||||
$query = $storage->getQuery();
|
||||
if ($asset) {
|
||||
$query->condition('parent', $asset->id());
|
||||
}
|
||||
else {
|
||||
$query->condition('parent', NULL, 'IS NULL');
|
||||
}
|
||||
$query->sort('name');
|
||||
|
||||
$asset_ids = $query->execute();
|
||||
/** @var \Drupal\asset\Entity\AssetInterface $children */
|
||||
$children = $storage->loadMultiple($asset_ids);
|
||||
$tree = [];
|
||||
foreach ($children as $child) {
|
||||
$element = [
|
||||
'uuid' => $child->uuid(),
|
||||
'text' => $child->label(),
|
||||
'children' => $this->buildTree($child),
|
||||
'type' => $child->bundle(),
|
||||
];
|
||||
$element['original_parent'] = $asset ? $asset->uuid() : '';
|
||||
$element['original_type'] = $asset ? $asset->bundle() : '';
|
||||
$tree[] = $element;
|
||||
}
|
||||
|
||||
return $tree;
|
||||
}
|
||||
|
||||
}
|
|
@ -74,6 +74,7 @@ use Drupal\user\EntityOwnerTrait;
|
|||
* "delete-form" = "/asset/{asset}/delete",
|
||||
* "delete-multiple-form" = "/asset/delete",
|
||||
* "edit-form" = "/asset/{asset}/edit",
|
||||
* "locations" = "/asset/{asset}/locations",
|
||||
* "revision" = "/asset/{asset}/revisions/{asset_revision}/view",
|
||||
* "revision-revert-form" = "/asset/{asset}/revisions/{asset_revision}/revert",
|
||||
* "version-history" = "/asset/{asset}/revisions",
|
||||
|
|
Loading…
Reference in New Issue