diff --git a/application/asset/js/admin.js b/application/asset/js/admin.js index 9977d52670..98d06ecac1 100644 --- a/application/asset/js/admin.js +++ b/application/asset/js/admin.js @@ -392,7 +392,7 @@ var Omeka = { $('.select-all').change(function() { if (this.checked) { - $('.batch-edit td input[type=checkbox]').prop('checked', true); + $('.batch-edit td input[type=checkbox]:not(:disabled)').prop('checked', true); } else { $('.batch-edit td input[type=checkbox]:checked').prop('checked', false); } diff --git a/application/config/module.config.php b/application/config/module.config.php index 402effb686..f554bf0174 100644 --- a/application/config/module.config.php +++ b/application/config/module.config.php @@ -442,6 +442,7 @@ ], 'factories' => [ 'Omeka\Form\ResourceForm' => Service\Form\ResourceFormFactory::class, + 'Omeka\Form\ResourceBatchUpdateForm' => Service\Form\ResourceBatchUpdateFormFactory::class, 'Omeka\Form\UserForm' => Service\Form\UserFormFactory::class, 'Omeka\Form\SettingForm' => Service\Form\SettingFormFactory::class, 'Omeka\Form\ModuleStateChangeForm' => Service\Form\ModuleStateChangeFormFactory::class, diff --git a/application/src/Api/Adapter/MediaAdapter.php b/application/src/Api/Adapter/MediaAdapter.php index ba3eaf5de2..a7cc635884 100644 --- a/application/src/Api/Adapter/MediaAdapter.php +++ b/application/src/Api/Adapter/MediaAdapter.php @@ -182,4 +182,16 @@ public function hydrateOwner(Request $request, EntityInterface $entity) $entity->setOwner($entity->getItem()->getOwner()); } } + + public function preprocessBatchUpdate(array $data, Request $request) + { + $rawData = $request->getContent(); + $data = parent::preprocessBatchUpdate($data, $request); + + if (array_key_exists('o:lang', $rawData)) { + $data['o:lang'] = $rawData['o:lang']; + } + + return $data; + } } diff --git a/application/src/Controller/Admin/ItemController.php b/application/src/Controller/Admin/ItemController.php index e7ec9e2fc4..51c8ede8ed 100644 --- a/application/src/Controller/Admin/ItemController.php +++ b/application/src/Controller/Admin/ItemController.php @@ -277,21 +277,20 @@ public function batchEditAction() } $form = $this->getForm(ResourceBatchUpdateForm::class, ['resource_type' => 'item']); + $form->setAttribute('id', 'batch-edit-item'); if ($this->params()->fromPost('batch_update')) { $data = $this->params()->fromPost(); $form->setData($data); if ($form->isValid()) { - list($dataRemove, $dataAppend) = $this->preprocessBatchUpdateData($data); + $data = $form->preprocessData(); - $this->api($form)->batchUpdate('items', $resourceIds, $dataRemove, [ - 'continueOnError' => true, - 'collectionAction' => 'remove', - ]); - $this->api($form)->batchUpdate('items', $resourceIds, $dataAppend, [ - 'continueOnError' => true, - 'collectionAction' => 'append', - ]); + foreach ($data as $collectionAction => $properties) { + $this->api($form)->batchUpdate('items', $resourceIds, $properties, [ + 'continueOnError' => true, + 'collectionAction' => $collectionAction, + ]); + } $this->messenger()->addSuccess('Items successfully edited'); // @translate return $this->redirect()->toRoute(null, ['action' => 'browse'], true); @@ -324,18 +323,20 @@ public function batchEditAllAction() $count = $this->api()->search('items', ['limit' => 0] + $query)->getTotalResults(); $form = $this->getForm(ResourceBatchUpdateForm::class, ['resource_type' => 'item']); + $form->setAttribute('id', 'batch-edit-item'); if ($this->params()->fromPost('batch_update')) { $data = $this->params()->fromPost(); $form->setData($data); if ($form->isValid()) { - list($dataRemove, $dataAppend) = $this->preprocessBatchUpdateData($data); + $data = $form->preprocessData(); $job = $this->jobDispatcher()->dispatch('Omeka\Job\BatchUpdate', [ 'resource' => 'items', 'query' => $query, - 'data_remove' => $dataRemove, - 'data_append' => $dataAppend, + 'data' => isset($data['replace']) ? $data['replace'] : [], + 'data_remove' => isset($data['remove']) ? $data['remove'] : [], + 'data_append' => isset($data['append']) ? $data['append'] : [], ]); $this->messenger()->addSuccess('Editing items. This may take a while.'); // @translate @@ -354,71 +355,6 @@ public function batchEditAllAction() return $view; } - /** - * Preprocess batch update data. - * - * Batch update data contains instructions on what to update. It needs to be - * preprocessed before it's sent to the API. - * - * @param array $data - * @return array An array containing the collectionAction=remove data as the - * first element and the collectionAction=append data as the second. - */ - protected function preprocessBatchUpdateData(array $data) - { - $dataRemove = []; - $dataAppend = []; - - // Set the data to change and data to remove. - if (in_array($data['is_public'], ['0', '1'])) { - $dataRemove['o:is_public'] = $data['is_public']; - } - if (-1 == $data['resource_template']) { - $dataRemove['o:resource_template'] = ['o:id' => null]; - } elseif (is_numeric($data['resource_template'])) { - $dataRemove['o:resource_template'] = ['o:id' => $data['resource_template']]; - } - if (-1 == $data['resource_class']) { - $dataRemove['o:resource_class'] = ['o:id' => null]; - } elseif (is_numeric($data['resource_class'])) { - $dataRemove['o:resource_class'] = ['o:id' => $data['resource_class']]; - } - if (isset($data['remove_from_item_set'])) { - $dataRemove['o:item_set'] = $data['remove_from_item_set']; - } - if (isset($data['clear_property_values'])) { - $dataRemove['clear_property_values'] = $data['clear_property_values']; - } - - // Set the data to append. - if (isset($data['value'])) { - foreach ($data['value'] as $value) { - $valueObj = [ - 'property_id' => $value['property_id'], - 'type' => $value['type'], - ]; - switch ($value['type']) { - case 'uri': - $valueObj['@id'] = $value['id']; - $valueObj['o:label'] = $value['label']; - break; - case 'resource': - $valueObj['value_resource_id'] = $value['value_resource_id']; - break; - case 'literal': - default: - $valueObj['@value'] = $value['value']; - } - $dataAppend[$value['property_id']][] = $valueObj; - } - } - if (isset($data['add_to_item_set'])) { - $dataAppend['o:item_set'] = array_unique($data['add_to_item_set']); - } - - return [$dataRemove, $dataAppend]; - } - protected function getMediaForms() { $mediaHelper = $this->viewHelpers()->get('media'); diff --git a/application/src/Controller/Admin/ItemSetController.php b/application/src/Controller/Admin/ItemSetController.php index 1a19cd2484..1b2c6b67cd 100644 --- a/application/src/Controller/Admin/ItemSetController.php +++ b/application/src/Controller/Admin/ItemSetController.php @@ -248,22 +248,21 @@ public function batchEditAction() $resources[] = $this->api()->read('item_sets', $resourceId)->getContent(); } - $form = $this->getForm(ResourceBatchUpdateForm::class); + $form = $this->getForm(ResourceBatchUpdateForm::class, ['resource_type' => 'itemSet']); + $form->setAttribute('id', 'batch-edit-item-set'); if ($this->params()->fromPost('batch_update')) { $data = $this->params()->fromPost(); $form->setData($data); if ($form->isValid()) { - list($dataRemove, $dataAppend) = $this->preprocessBatchUpdateData($data); + $data = $form->preprocessData(); - $this->api($form)->batchUpdate('item_sets', $resourceIds, $dataRemove, [ - 'continueOnError' => true, - 'collectionAction' => 'remove', - ]); - $this->api($form)->batchUpdate('item_sets', $resourceIds, $dataAppend, [ - 'continueOnError' => true, - 'collectionAction' => 'append', - ]); + foreach ($data as $collectionAction => $properties) { + $this->api($form)->batchUpdate('item_sets', $resourceIds, $properties, [ + 'continueOnError' => true, + 'collectionAction' => $collectionAction, + ]); + } $this->messenger()->addSuccess('Item sets successfully edited'); // @translate return $this->redirect()->toRoute(null, ['action' => 'browse'], true); @@ -295,19 +294,21 @@ public function batchEditAllAction() $query['offset'], $query['sort_by'], $query['sort_order']); $count = $this->api()->search('item_sets', ['limit' => 0] + $query)->getTotalResults(); - $form = $this->getForm(ResourceBatchUpdateForm::class); + $form = $this->getForm(ResourceBatchUpdateForm::class, ['resource_type' => 'itemSet']); + $form->setAttribute('id', 'batch-edit-item-set'); if ($this->params()->fromPost('batch_update')) { $data = $this->params()->fromPost(); $form->setData($data); if ($form->isValid()) { - list($dataRemove, $dataAppend) = $this->preprocessBatchUpdateData($data); + $data = $form->preprocessData(); $job = $this->jobDispatcher()->dispatch('Omeka\Job\BatchUpdate', [ 'resource' => 'item_sets', 'query' => $query, - 'data_remove' => $dataRemove, - 'data_append' => $dataAppend, + 'data' => isset($data['replace']) ? $data['replace'] : [], + 'data_remove' => isset($data['remove']) ? $data['remove'] : [], + 'data_append' => isset($data['append']) ? $data['append'] : [], ]); $this->messenger()->addSuccess('Editing item sets. This may take a while.'); // @translate @@ -325,66 +326,4 @@ public function batchEditAllAction() $view->setVariable('count', $count); return $view; } - - /** - * Preprocess batch update data. - * - * Batch update data contains instructions on what to update. It needs to be - * preprocessed before it's sent to the API. - * - * @param array $data - * @return array An array containing the collectionAction=remove data as the - * first element and the collectionAction=append data as the second. - */ - protected function preprocessBatchUpdateData(array $data) - { - $dataRemove = []; - $dataAppend = []; - - // Set the data to change and data to remove. - if (in_array($data['is_public'], ['0', '1'])) { - $dataRemove['o:is_public'] = $data['is_public']; - } - if (in_array($data['is_open'], ['0', '1'])) { - $dataRemove['o:is_open'] = $data['is_open']; - } - if (-1 == $data['resource_template']) { - $dataRemove['o:resource_template'] = ['o:id' => null]; - } elseif (is_numeric($data['resource_template'])) { - $dataRemove['o:resource_template'] = ['o:id' => $data['resource_template']]; - } - if (-1 == $data['resource_class']) { - $dataRemove['o:resource_class'] = ['o:id' => null]; - } elseif (is_numeric($data['resource_class'])) { - $dataRemove['o:resource_class'] = ['o:id' => $data['resource_class']]; - } - if (isset($data['clear_property_values'])) { - $dataRemove['clear_property_values'] = $data['clear_property_values']; - } - - // Set the data to append. - if (isset($data['value'])) { - foreach ($data['value'] as $value) { - $valueObj = [ - 'property_id' => $value['property_id'], - 'type' => $value['type'], - ]; - switch ($value['type']) { - case 'uri': - $valueObj['@id'] = $value['id']; - $valueObj['o:label'] = $value['label']; - break; - case 'resource': - $valueObj['value_resource_id'] = $value['value_resource_id']; - break; - case 'literal': - default: - $valueObj['@value'] = $value['value']; - } - $dataAppend[$value['property_id']][] = $valueObj; - } - } - - return [$dataRemove, $dataAppend]; - } } diff --git a/application/src/Controller/Admin/MediaController.php b/application/src/Controller/Admin/MediaController.php index 391cf620f1..c9329e36cf 100644 --- a/application/src/Controller/Admin/MediaController.php +++ b/application/src/Controller/Admin/MediaController.php @@ -3,9 +3,9 @@ use Omeka\Form\ConfirmForm; use Omeka\Form\ResourceForm; +use Omeka\Form\ResourceBatchUpdateForm; use Zend\Mvc\Controller\AbstractActionController; use Zend\View\Model\ViewModel; -use Zend\Form\Form; class MediaController extends AbstractActionController { @@ -22,10 +22,23 @@ public function browseAction() $response = $this->api()->search('media', $this->params()->fromQuery()); $this->paginator($response->getTotalResults(), $this->params()->fromQuery('page')); + $formDeleteSelected = $this->getForm(ConfirmForm::class); + $formDeleteSelected->setAttribute('action', $this->url()->fromRoute(null, ['action' => 'batch-delete'], true)); + $formDeleteSelected->setButtonLabel('Confirm Delete'); // @translate + $formDeleteSelected->setAttribute('id', 'confirm-delete-selected'); + + $formDeleteAll = $this->getForm(ConfirmForm::class); + $formDeleteAll->setAttribute('action', $this->url()->fromRoute(null, ['action' => 'batch-delete-all'], true)); + $formDeleteAll->setButtonLabel('Confirm Delete'); // @translate + $formDeleteAll->setAttribute('id', 'confirm-delete-all'); + $formDeleteAll->get('submit')->setAttribute('disabled', true); + $view = new ViewModel; $medias = $response->getContent(); $view->setVariable('medias', $medias); $view->setVariable('resources', $medias); + $view->setVariable('formDeleteSelected', $formDeleteSelected); + $view->setVariable('formDeleteAll', $formDeleteAll); return $view; } @@ -132,4 +145,153 @@ public function sidebarSelectAction() $view->setTerminal(true); return $view; } + + public function batchDeleteAction() + { + if (!$this->getRequest()->isPost()) { + return $this->redirect()->toRoute(null, ['action' => 'browse'], true); + } + + $resourceIds = $this->params()->fromPost('resource_ids', []); + if (!$resourceIds) { + $this->messenger()->addError('You must select at least one media to batch delete.'); // @translate + return $this->redirect()->toRoute(null, ['action' => 'browse'], true); + } + + $form = $this->getForm(ConfirmForm::class); + $form->setData($this->getRequest()->getPost()); + if ($form->isValid()) { + $response = $this->api($form)->batchDelete('media', $resourceIds, [], ['continueOnError' => true]); + if ($response) { + $this->messenger()->addSuccess('Medias successfully deleted'); // @translate + } + } else { + $this->messenger()->addFormErrors($form); + } + return $this->redirect()->toRoute(null, ['action' => 'browse'], true); + } + + public function batchDeleteAllAction() + { + if (!$this->getRequest()->isPost()) { + return $this->redirect()->toRoute(null, ['action' => 'browse'], true); + } + + // Derive the query, removing limiting and sorting params. + $query = json_decode($this->params()->fromPost('query', []), true); + unset($query['submit'], $query['page'], $query['per_page'], $query['limit'], + $query['offset'], $query['sort_by'], $query['sort_order']); + + $form = $this->getForm(ConfirmForm::class); + $form->setData($this->getRequest()->getPost()); + if ($form->isValid()) { + $job = $this->jobDispatcher()->dispatch('Omeka\Job\BatchDelete', [ + 'resource' => 'media', + 'query' => $query, + ]); + $this->messenger()->addSuccess('Deleting medias. This may take a while.'); // @translate + } else { + $this->messenger()->addFormErrors($form); + } + return $this->redirect()->toRoute(null, ['action' => 'browse'], true); + } + + /** + * Batch update selected medias. + */ + public function batchEditAction() + { + if (!$this->getRequest()->isPost()) { + return $this->redirect()->toRoute(null, ['action' => 'browse'], true); + } + + $resourceIds = $this->params()->fromPost('resource_ids', []); + if (!$resourceIds) { + $this->messenger()->addError('You must select at least one media to batch edit.'); // @translate + return $this->redirect()->toRoute(null, ['action' => 'browse'], true); + } + + $resources = []; + foreach ($resourceIds as $resourceId) { + $resources[] = $this->api()->read('media', $resourceId)->getContent(); + } + + $form = $this->getForm(ResourceBatchUpdateForm::class, ['resource_type' => 'media']); + $form->setAttribute('id', 'batch-edit-media'); + if ($this->params()->fromPost('batch_update')) { + $data = $this->params()->fromPost(); + $form->setData($data); + + if ($form->isValid()) { + $data = $form->preprocessData(); + + foreach ($data as $collectionAction => $properties) { + $this->api($form)->batchUpdate('media', $resourceIds, $properties, [ + 'continueOnError' => true, + 'collectionAction' => $collectionAction, + ]); + } + + $this->messenger()->addSuccess('Medias successfully edited'); // @translate + return $this->redirect()->toRoute(null, ['action' => 'browse'], true); + } else { + $this->messenger()->addFormErrors($form); + } + } + + $view = new ViewModel; + $view->setVariable('form', $form); + $view->setVariable('resources', $resources); + $view->setVariable('query', []); + $view->setVariable('count', null); + return $view; + } + + /** + * Batch update all medias returned from a query. + */ + public function batchEditAllAction() + { + if (!$this->getRequest()->isPost()) { + return $this->redirect()->toRoute(null, ['action' => 'browse'], true); + } + + // Derive the query, removing limiting and sorting params. + $query = json_decode($this->params()->fromPost('query', []), true); + unset($query['submit'], $query['page'], $query['per_page'], $query['limit'], + $query['offset'], $query['sort_by'], $query['sort_order']); + $count = $this->api()->search('media', ['limit' => 0] + $query)->getTotalResults(); + + $form = $this->getForm(ResourceBatchUpdateForm::class, ['resource_type' => 'media']); + $form->setAttribute('id', 'batch-edit-media'); + if ($this->params()->fromPost('batch_update')) { + $data = $this->params()->fromPost(); + $form->setData($data); + + if ($form->isValid()) { + $data = $form->preprocessData(); + + $job = $this->jobDispatcher()->dispatch('Omeka\Job\BatchUpdate', [ + 'resource' => 'media', + 'query' => $query, + 'data' => isset($data['replace']) ? $data['replace'] : [], + 'data_remove' => isset($data['remove']) ? $data['remove'] : [], + 'data_append' => isset($data['append']) ? $data['append'] : [], + ]); + + $this->messenger()->addSuccess('Editing medias. This may take a while.'); // @translate + return $this->redirect()->toRoute(null, ['action' => 'browse'], true); + } else { + $this->messenger()->addFormErrors($form); + } + } + + $view = new ViewModel; + $view->setTemplate('omeka/admin/media/batch-edit.phtml'); + $view->setVariable('form', $form); + $view->setVariable('resources', []); + $view->setVariable('query', $query); + $view->setVariable('count', $count); + return $view; + } } diff --git a/application/src/Form/ResourceBatchUpdateForm.php b/application/src/Form/ResourceBatchUpdateForm.php index de1c5b92c1..fa2b58dfcb 100644 --- a/application/src/Form/ResourceBatchUpdateForm.php +++ b/application/src/Form/ResourceBatchUpdateForm.php @@ -1,11 +1,335 @@ getUrlHelper(); + + $resourceType = $this->getOption('resource_type'); + + $this->add([ + 'name' => 'is_public', + 'type' => Element\Radio::class, + 'options' => [ + 'label' => 'Set visibility', // @translate + 'value_options' => [ + '1' => 'Public', // @translate + '0' => 'Not public', // @translate + '' => '[No change]', // @translate + ], + ], + 'attributes' => [ + 'value' => '', + ], + ]); + + if ($resourceType === 'itemSet') { + $this->add([ + 'name' => 'is_open', + 'type' => Element\Radio::class, + 'options' => [ + 'label' => 'Set openness', // @translate + 'value_options' => [ + '1' => 'Open', // @translate + '0' => 'Not open', // @translate + '' => '[No change]', // @translate + ], + ], + 'attributes' => [ + 'value' => '', + ], + ]); + } + + $this->add([ + 'name' => 'resource_template', + 'type' => ResourceSelect::class, + 'attributes' => [ + 'id' => 'resource-template-select', + 'class' => 'chosen-select', + 'data-placeholder' => 'Select a template', // @translate + 'data-api-base-url' => $urlHelper('api/default', ['resource' => 'resource_templates']), + ], + 'options' => [ + 'label' => 'Set template', // @translate + 'empty_option' => '[No change]', // @translate + 'prepend_value_options' => ['-1' => '[Unset template]'], // @translate + 'resource_value_options' => [ + 'resource' => 'resource_templates', + 'query' => [], + 'option_text_callback' => function ($resourceTemplate) { + return $resourceTemplate->label(); + }, + ], + ], + ]); + + $this->add([ + 'name' => 'resource_class', + 'type' => ResourceClassSelect::class, + 'attributes' => [ + 'id' => 'resource-class-select', + 'class' => 'chosen-select', + 'data-placeholder' => 'Select a class', // @translate + ], + 'options' => [ + 'label' => 'Set class', // @translate + 'prepend_value_options' => ['-1' => '[Unset class]'], // @translate + 'empty_option' => '[No change]', // @translate + ], + ]); + + switch ($resourceType) { + case 'item': + $this->add([ + 'name' => 'add_to_item_set', + 'type' => ItemSetSelect::class, + 'attributes' => [ + 'id' => 'add-to-item-sets', + 'class' => 'chosen-select', + 'multiple' => true, + 'data-placeholder' => 'Select item sets', // @translate + ], + 'options' => [ + 'label' => 'Add to item sets', // @translate + ], + ]); + + $this->add([ + 'name' => 'remove_from_item_set', + 'type' => ItemSetSelect::class, + 'attributes' => [ + 'id' => 'remove-from-item-sets', + 'class' => 'chosen-select', + 'multiple' => true, + 'data-placeholder' => 'Select item sets', // @translate + ], + 'options' => [ + 'label' => 'Remove from item sets', // @translate + ], + ]); + break; + + case 'media': + $this->add([ + 'name' => 'clear_language', + 'type' => Element\Checkbox::class, + 'options' => [ + 'label' => 'Clear language', // @transalte + ], + ]); + + $this->add([ + 'name' => 'language', + 'type' => Element\Text::class, + 'attributes' => [ + 'class' => 'value-language active', + ], + 'options' => [ + 'label' => 'Set language', // @transalte + ], + ]); + break; + } + + $this->add([ + 'name' => 'clear_property_values', + 'type' => PropertySelect::class, + 'attributes' => [ + 'id' => 'remove-property-values', + 'class' => 'chosen-select', + 'multiple' => true, + 'data-placeholder' => 'Select properties', // @translate + ], + 'options' => [ + 'label' => 'Clear property values', // @translate + ], + ]); + + // This hidden element manages the elements "value" added in the view. + $this->add([ + 'name' => 'value', + 'type' => Element\Hidden::class, + 'attributes' => [ + 'value' => '', + ], + ]); + + $addEvent = new Event('form.add_elements', $this); + $this->getEventManager()->triggerEvent($addEvent); + + $inputFilter = $this->getInputFilter(); + $inputFilter->add([ + 'name' => 'is_public', + 'required' => false, + ]); + $inputFilter->add([ + 'name' => 'is_open', + 'required' => false, + ]); + $inputFilter->add([ + 'name' => 'resource_template', + 'required' => false, + ]); + $inputFilter->add([ + 'name' => 'resource_class', + 'required' => false, + ]); + $inputFilter->add([ + 'name' => 'add_to_item_set', + 'required' => false, + ]); + $inputFilter->add([ + 'name' => 'remove_from_item_set', + 'required' => false, + ]); + $inputFilter->add([ + 'name' => 'clear_property_values', + 'required' => false, + ]); + $inputFilter->add([ + 'name' => 'value', + 'required' => false, + ]); + + $filterEvent = new Event('form.add_input_filters', $this, ['inputFilter' => $inputFilter]); + $this->getEventManager()->triggerEvent($filterEvent); + } + + /** + * @param Url $urlHelper + */ + public function setUrlHelper(Url $urlHelper) + { + $this->urlHelper = $urlHelper; + } + + /** + * @return Url + */ + public function getUrlHelper() + { + return $this->urlHelper; + } + + /** + * Preprocess data to get data to replace, to remove and to append. + * + * Batch update data contains instructions on what to update. It needs to be + * preprocessed before it's sent to the API. The elements are udpated by + * entity according to the attribute "data-collection-action", that can be + * "replace" (default), "remove" or "append". + * + * @todo Use standard validationGroup and filters. + * + * @return array Associative array of data to replace, to remove and to + * append. + */ + public function preprocessData() + { + $data = $this->getData(); + $preData = [ + 'replace' => null, + 'remove' => null, + 'append' => null, + ]; + + // Set the data to change and data to remove. + if (array_key_exists('is_public', $data) && in_array($data['is_public'], ['0', '1'])) { + $preData['remove']['o:is_public'] = $data['is_public']; + } + if (array_key_exists('is_open', $data) && in_array($data['is_open'], ['0', '1'])) { + $preData['remove']['o:is_open'] = $data['is_open']; + } + if (-1 == $data['resource_template']) { + $preData['remove']['o:resource_template'] = ['o:id' => null]; + } elseif (is_numeric($data['resource_template'])) { + $preData['remove']['o:resource_template'] = ['o:id' => $data['resource_template']]; + } + if (-1 == $data['resource_class']) { + $preData['remove']['o:resource_class'] = ['o:id' => null]; + } elseif (is_numeric($data['resource_class'])) { + $preData['remove']['o:resource_class'] = ['o:id' => $data['resource_class']]; + } + if (isset($data['remove_from_item_set'])) { + $preData['remove']['o:item_set'] = $data['remove_from_item_set']; + } + if (isset($data['clear_property_values'])) { + $preData['remove']['clear_property_values'] = $data['clear_property_values']; + } + if (!empty($data['clear_language'])) { + $preData['remove']['o:lang'] = null; + } + if (!empty($data['language'])) { + $preData['remove']['o:lang'] = $data['language']; + } + + // Set the data to append. + if (!empty($data['value'])) { + foreach ($data['value'] as $value) { + $valueObj = [ + 'property_id' => $value['property_id'], + 'type' => $value['type'], + ]; + switch ($value['type']) { + case 'uri': + $valueObj['@id'] = $value['id']; + $valueObj['o:label'] = $value['label']; + break; + case 'resource': + $valueObj['value_resource_id'] = $value['value_resource_id']; + break; + case 'literal': + default: + $valueObj['@value'] = $value['value']; + } + $preData['append'][$value['property_id']][] = $valueObj; + } + } + if (isset($data['add_to_item_set'])) { + $preData['append']['o:item_set'] = array_unique($data['add_to_item_set']); + } + + // Set remaining elements according to attribute data-collection-action. + $processeds = [ + 'is_public', 'is_open', 'resource_template', 'resource_class', + 'remove_from_item_set', 'add_to_item_set', + 'clear_property_values', 'value', + 'clear_language', 'language', + 'csrf', 'id', 'o:id', + ]; + + foreach ($data as $key => $value) { + if (is_numeric($key) || in_array($key, $processeds) + || is_null($value) || $value === '' + ) { + continue; + } + $collectionAction = $this->has($key) + ? $this->get($key)->getAttribute('data-collection-action') + : 'replace'; + $preData[$collectionAction][$key] = $value; + } + + return array_filter($preData); } } diff --git a/application/src/Media/Ingester/Html.php b/application/src/Media/Ingester/Html.php index 8098eb9a9e..dd1ddebd9d 100644 --- a/application/src/Media/Ingester/Html.php +++ b/application/src/Media/Ingester/Html.php @@ -64,9 +64,11 @@ public function ingest(Media $media, Request $request, ErrorStore $errorStore) public function update(Media $media, Request $request, ErrorStore $errorStore) { $data = $request->getContent(); - $html = $data['o:media']['__index__']['html']; - $html = $this->purifier->purify($html); - $media->setData(['html' => $html]); + if (isset($data['o:media']['__index__']['html'])) { + $html = $data['o:media']['__index__']['html']; + $html = $this->purifier->purify($html); + $media->setData(['html' => $html]); + } } /** diff --git a/application/src/Service/Form/ResourceBatchUpdateFormFactory.php b/application/src/Service/Form/ResourceBatchUpdateFormFactory.php new file mode 100644 index 0000000000..528bad87ca --- /dev/null +++ b/application/src/Service/Form/ResourceBatchUpdateFormFactory.php @@ -0,0 +1,17 @@ +setUrlHelper($services->get('ViewHelperManager')->get('Url')); + $form->setEventManager($services->get('EventManager')); + return $form; + } +} diff --git a/application/view/common/property-form-batch-edit.phtml b/application/view/common/property-form-batch-edit.phtml new file mode 100644 index 0000000000..57d0fbf0d1 --- /dev/null +++ b/application/view/common/property-form-batch-edit.phtml @@ -0,0 +1,82 @@ +plugin('escapeHtml'); + +$selectProperty = $this->propertySelect([ + 'name' => 'value[__INDEX__][property_id]', + 'options' => ['empty_option' => $this->translate('Select property')], +]); +$templateLiteral = ' +
+
+ +
+
+ ' . $selectProperty . ' + + + +
+
'; +$templateResource = ' +
+
+ +
+
+ ' . $selectProperty . ' + + + +
+
'; +$templateUri = ' +
+
+ +
+
+ ' . $selectProperty . ' + + + + +
+
'; +?> +
+
+ + + +
+ diff --git a/application/view/omeka/admin/item-set/batch-edit.phtml b/application/view/omeka/admin/item-set/batch-edit.phtml index 6d88f22c32..44e0c13948 100644 --- a/application/view/omeka/admin/item-set/batch-edit.phtml +++ b/application/view/omeka/admin/item-set/batch-edit.phtml @@ -1,53 +1,11 @@ pageTitle($this->translate('Batch edit item sets')); - -$selectPropertyToClear = $this->propertySelect([ - 'name' => 'clear_property_values[]', - 'options' => ['empty_option' => 'Select property'], -]); - -$selectProperty = $this->propertySelect([ - 'name' => 'value[__INDEX__][property_id]', - 'options' => ['empty_option' => $this->translate('Select property')], -]); -$templateLiteral = ' -
-
- -
-
- ' . $selectProperty . ' - - - -
-
'; -$templateResource = ' -
-
- -
-
- ' . $selectProperty . ' - - - -
-
'; -$templateUri = ' -
-
- -
-
- ' . $selectProperty . ' - - - - -
-
'; +$form->prepare(); +$this->htmlElement('body')->appendAttribute('class', 'batch-edit item-sets'); +$escape = $this->plugin('escapeHtml'); ?> +pageTitle($this->translate('Batch edit item sets')); ?> + +trigger('view.batch_edit.before'); ?> form()->openTag($form); ?> @@ -60,94 +18,9 @@ $templateUri = ' -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- resourceSelect([ - 'name' => 'resource_template', - 'options' => [ - 'empty_option' => $this->translate('[No change]'), - 'prepend_value_options' => ['-1' => $this->translate('[Unset template]')], - 'resource_value_options' => [ - 'resource' => 'resource_templates', - 'option_text_callback' => function ($resourceTemplate) { - return $resourceTemplate->label(); - }, - ], - ], - ]); ?> -
-
- -
-
- -
-
- resourceClassSelect([ - 'name' => 'resource_class', - 'options' => [ - 'empty_option' => $this->translate('[No change]'), - 'prepend_value_options' => ['-1' => $this->translate('[Unset class]')], - ], - ]); ?> -
-
- -
-
- -
-
-
- - -
- -
-
- -
-
- - - -
- -formRow($form->get('resourcebatchupdateform_csrf')); ?> -form()->closeTag();; ?> +formCollection($form, false); ?> +partial('common/property-form-batch-edit.phtml', ['resourceType' => 'item_sets']); ?> +form()->closeTag(); ?> - +trigger('view.batch_edit.after'); ?> diff --git a/application/view/omeka/admin/item/batch-edit.phtml b/application/view/omeka/admin/item/batch-edit.phtml index 9130836839..8550a5a563 100644 --- a/application/view/omeka/admin/item/batch-edit.phtml +++ b/application/view/omeka/admin/item/batch-edit.phtml @@ -1,63 +1,11 @@ pageTitle($this->translate('Batch edit items')); - -$selectItemSetToAdd = $this->itemSetSelect([ - 'name' => 'add_to_item_set[]', - 'options' => ['empty_option' => 'Select item set'], -]); - -$selectItemSetToRemove = $this->itemSetSelect([ - 'name' => 'remove_from_item_set[]', - 'options' => ['empty_option' => 'Select item set'], -]); - -$selectPropertyToClear = $this->propertySelect([ - 'name' => 'clear_property_values[]', - 'options' => ['empty_option' => 'Select property'], -]); - -$selectProperty = $this->propertySelect([ - 'name' => 'value[__INDEX__][property_id]', - 'options' => ['empty_option' => $this->translate('Select property')], -]); -$templateLiteral = ' -
-
- -
-
- ' . $selectProperty . ' - - - -
-
'; -$templateResource = ' -
-
- -
-
- ' . $selectProperty . ' - - - -
-
'; -$templateUri = ' -
-
- -
-
- ' . $selectProperty . ' - - - - -
-
'; +$form->prepare(); +$this->htmlElement('body')->appendAttribute('class', 'batch-edit items'); +$escape = $this->plugin('escapeHtml'); ?> +pageTitle($this->translate('Batch edit items')); ?> + +trigger('view.batch_edit.before'); ?> form()->openTag($form); ?> @@ -70,107 +18,9 @@ $templateUri = ' -
-
- -
-
- -
-
- -
-
- -
-
- resourceSelect([ - 'name' => 'resource_template', - 'options' => [ - 'empty_option' => $this->translate('[No change]'), - 'prepend_value_options' => ['-1' => $this->translate('[Unset template]')], - 'resource_value_options' => [ - 'resource' => 'resource_templates', - 'option_text_callback' => function ($resourceTemplate) { - return $resourceTemplate->label(); - }, - ], - ], - ]); ?> -
-
- -
-
- -
-
- resourceClassSelect([ - 'name' => 'resource_class', - 'options' => [ - 'empty_option' => $this->translate('[No change]'), - 'prepend_value_options' => ['-1' => $this->translate('[Unset class]')], - ], - ]); ?> -
-
- -
-
- -
-
-
- - -
- -
-
- -
-
- -
-
-
- - -
- -
-
- -
-
- -
-
-
- - -
- -
-
- -
-
- - - -
- -formRow($form->get('resourcebatchupdateform_csrf')); ?> -form()->closeTag();; ?> +formCollection($form, false); ?> +partial('common/property-form-batch-edit.phtml', ['resourceType' => 'item_sets']); ?> +form()->closeTag(); ?> - +trigger('view.batch_edit.after'); ?> diff --git a/application/view/omeka/admin/media/batch-edit.phtml b/application/view/omeka/admin/media/batch-edit.phtml new file mode 100644 index 0000000000..62fb546836 --- /dev/null +++ b/application/view/omeka/admin/media/batch-edit.phtml @@ -0,0 +1,41 @@ +prepare(); +$this->htmlElement('body')->appendAttribute('class', 'batch-edit media'); +$escape = $this->plugin('escapeHtml'); +$this->headStyle()->appendStyle('.inputs input.value-language.active[type="text"] { background-color: #fff; padding: 0 5px; display: inherit; }'); +$this->headScript()->appendFile($this->assetUrl('js/resource-form.js', 'Omeka')); +?> +pageTitle($this->translate('Batch edit medias')); ?> + +trigger('view.batch_edit.before'); ?> + +form()->openTag($form); ?> + + + + + + +
+ +
+ +formCollection($form, false); ?> +partial('common/property-form-batch-edit.phtml', ['resourceType' => 'media']); ?> +form()->closeTag(); ?> + + + +trigger('view.batch_edit.after'); ?> diff --git a/application/view/omeka/admin/media/browse.phtml b/application/view/omeka/admin/media/browse.phtml index e1a2ea1d56..24023c9ca3 100644 --- a/application/view/omeka/admin/media/browse.phtml +++ b/application/view/omeka/admin/media/browse.phtml @@ -1,5 +1,7 @@ htmlElement('body')->appendAttribute('class', 'media browse'); +$userIsAllowedBatchUpdate = $this->userIsAllowed('Omeka\Api\Adapter\MediaAdapter', 'batch_update'); +$userIsAllowedBatchDelete = $this->userIsAllowed('Omeka\Api\Adapter\MediaAdapter', 'batch_delete'); $escape = $this->plugin('escapeHtml'); $sortHeadings = [ [ @@ -32,11 +34,45 @@ $sortHeadings = [ trigger('view.browse.before'); ?> - - + + + +
+ +
+ + + + + + + + translate('Go'); ?> + translate('Go'); ?> + +
+
+ + +
- + @@ -44,6 +80,8 @@ $sortHeadings = [ + userIsAllowed('update'); ?> + userIsAllowed('delete'); ?> owner()) { $ownerText = $this->hyperlink( @@ -58,45 +96,54 @@ $sortHeadings = [ $ownerText = $this->translate('[no owner]'); } ?> - - + - - - - +
  • hyperlink('', '#', [ + 'data-sidebar-selector' => '#sidebar', + 'data-sidebar-content-url' => $media->url('show-details'), + 'class' => 'o-icon-more sidebar-content', + 'title' => $this->translate('Details'), + ]); ?>
  • + + + + + + -
    translate('Title'); ?> + + + + translate('Title'); ?> + translate('Class'); ?> translate('Owner'); ?> translate('Created'); ?>
    - linkPretty(); ?> - isPublic()): ?> - +
    + + disabled="disabled"> + + linkPretty(); ?> + isPublic()): ?> + + +
      + +
    • link('', 'edit', [ + 'class' => 'o-icon-edit', + 'title' => $this->translate('Edit'), + ]); ?>
    • + + +
    • hyperlink('', '#', [ + 'data-sidebar-selector' => '#sidebar', + 'data-sidebar-content-url' => $media->url('delete-confirm'), + 'class' => 'o-icon-delete sidebar-content', + 'title' => $this->translate('Delete'), + ]); ?>
    • -
        -
      • link('', 'edit', [ - 'class' => 'o-icon-edit', - 'title' => $this->translate('Edit'), - ]); ?>
      • - userIsAllowed('delete')): ?> -
      • hyperlink('', '#', [ - 'data-sidebar-content-url' => $media->url('delete-confirm'), - 'class' => 'o-icon-delete sidebar-content', - 'title' => $this->translate('Delete'), - ]); ?>
      • - -
      • hyperlink('', '#', [ - 'data-sidebar-content-url' => $media->url('show-details'), - 'class' => 'o-icon-more sidebar-content', - 'title' => $this->translate('Details'), - ]); ?>
      • -
      -
    displayResourceClassLabel()); ?>i18n()->dateFormat($media->created())); ?>
    translate($media->displayResourceClassLabel())); ?>i18n()->dateFormat($media->created())); ?>
    + + + trigger('view.browse.after'); ?>
    pagination(); ?>
    -