Enhancement: SilverStripe 4 compatibility (#137)

* Basic SS4 compat: Implemented namespacing, updated some Image manipulations, readmes, composer configuration

* Add bootstrap form styles to the bulk manager

* API Rename classes to be less confusing with the namespaces
This commit is contained in:
Robbie Averill 2017-01-26 01:27:11 +13:00 committed by Thierry François
parent 0e6f2e6efb
commit 7221897f27
25 changed files with 520 additions and 325 deletions

10
.upgrade.yml Normal file
View File

@ -0,0 +1,10 @@
mappings:
GridFieldBulkActionDeleteHandler: Colymba\BulkManager\BulkAction\DeleteHandler
GridFieldBulkActionEditHandler: Colymba\BulkManager\BulkAction\EditHandler
GridFieldBulkActionHandler: Colymba\BulkManager\BulkAction\Handler
GridFieldBulkActionUnlinkHandler: Colymba\BulkManager\BulkAction\UnlinkHandler
GridFieldBulkManager: Colymba\BulkManager\BulkManager
BulkUploadField: Colymba\BulkUpload\BulkUploadField
GridFieldBulkImageUpload: Colymba\BulkUpload\GridFieldBulkImageUpload
GridFieldBulkUpload: Colymba\BulkUpload\BulkUploader
GridFieldBulkUpload_Request: Colymba\BulkUpload\BulkUploadRequest

View File

@ -5,7 +5,7 @@ GridField Bulk Editing Tools
[![Latest Unstable Version](https://poser.pugx.org/colymba/gridfield-bulk-editing-tools/v/unstable.svg)](https://github.com/colymba/GridFieldBulkEditingTools/tree/master) [![Latest Unstable Version](https://poser.pugx.org/colymba/gridfield-bulk-editing-tools/v/unstable.svg)](https://github.com/colymba/GridFieldBulkEditingTools/tree/master)
[![License](https://poser.pugx.org/colymba/gridfield-bulk-editing-tools/license.svg)](#license-bsd-simplified) [![License](https://poser.pugx.org/colymba/gridfield-bulk-editing-tools/license.svg)](#license-bsd-simplified)
Set of SilverStripe 3 GridField components to facilitate bulk file upload & record editing. Set of SilverStripe 4 GridField components to facilitate bulk file upload & record editing.
![preview](screenshots/preview.png) ![preview](screenshots/preview.png)
@ -16,37 +16,47 @@ Set of SilverStripe 3 GridField components to facilitate bulk file upload & reco
[More screenshots here.](screenshots) [More screenshots here.](screenshots)
## Requirements ## Requirements
* SilverStripe 3.1 (version master / 2.+ / 1.+) * SilverStripe 4.0 (version master / 3.+)
* SilverStripe 3.1 (version 2.+ / 1.+)
* Silverstripe 3.0 (version [0.5](https://github.com/colymba/GridFieldBulkEditingTools/tree/0.5)) * Silverstripe 3.0 (version [0.5](https://github.com/colymba/GridFieldBulkEditingTools/tree/0.5))
## Installation ## Installation
### Composer ### Composer
* `composer require "colymba/gridfield-bulk-editing-tools:*"` * `composer require colymba/gridfield-bulk-editing-tools`
### Manual ### Manual
* Download and copy module in SilverStripe root directory * Download and copy module in SilverStripe root directory
## 3.0.0 deprecations
The 3.x versions of this module require SilverStripe 4.x+, and PHP 5.5 or above:
* Namespaces are implemented, and some class names have changed (see `.upgrade.yml` for mapping)
## 2.0.0 deprecations ## 2.0.0 deprecations
Major depractions in latest 2.0.0 release: Major deprections in latest 2.0.0 release:
* The `GridFieldBulkImageUpload` has been renamed to `GridFieldBulkUpload`. * The `GridFieldBulkImageUpload` has been renamed to `GridFieldBulkUpload`.
* `onBulkImageUpload` callback has been renamed to `onBulkUpload` * `onBulkImageUpload` callback has been renamed to `onBulkUpload`
## Bulk Upload ## Bulk Upload
Upload multiple images or files at once into DataObjects. Perfect for galleries and the like. Upload multiple images or files at once into DataObjects. Perfect for galleries and the like.
$config->addComponent(new GridFieldBulkUpload()); ```php
$config->addComponent(new \Colymba\BulkUpload\BulkUploader());
```
See [BULK_UPLOAD.md](bulkUpload/BULK_UPLOAD.md) for detailed configuration. See [BULK_UPLOAD.md](bulkUpload/BULK_UPLOAD.md) for detailed configuration.
## Bulk Manager ## Bulk Manager
Perform actions on multiple records straight from the GridField Perform actions on multiple records straight from the GridField
$config->addComponent(new GridFieldBulkManager()); ```php
$config->addComponent(new \Colymba\BulkManager\BulkManager());
```
See [BULK_MANAGER.md](bulkManager/BULK_MANAGER.md) for detailed configuration. See [BULK_MANAGER.md](bulkManager/BULK_MANAGER.md) for detailed configuration.
## Interdependencies ## Interdependencies
The `GridFieldBulkUpload` component makes use of `GridFieldBulkManager` to allow quick editing of the newly uploaded files. Although not nescessary for the component to work, adding `GridFieldBulkManager` too to your `GridFieldConfig` will give you this advantage. The `BulkUploader` component makes use of `BulkManager` to allow quick editing of the newly uploaded files. Although not nescessary for the component to work, adding `Colymba\BulkManager\BulkManager` too to your `GridFieldConfig` will give you this advantage.
#### @TODO #### @TODO
* Add individual actions for each upload (update + cancel) * Add individual actions for each upload (update + cancel)

View File

@ -3,6 +3,6 @@
if (!defined('BULKEDITTOOLS_PATH')) { if (!defined('BULKEDITTOOLS_PATH')) {
$folder = rtrim(basename(dirname(__FILE__))); $folder = rtrim(basename(dirname(__FILE__)));
define('BULKEDITTOOLS_PATH', $folder); define('BULKEDITTOOLS_PATH', $folder);
define('BULKEDITTOOLS_UPLOAD_PATH', $folder.'/bulkUpload'); define('BULKEDITTOOLS_UPLOAD_PATH', $folder . '/bulkUpload');
define('BULKEDITTOOLS_MANAGER_PATH', $folder.'/bulkManager'); define('BULKEDITTOOLS_MANAGER_PATH', $folder . '/bulkManager');
} }

View File

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
# Phing build script
# phing installation
sudo pear channel-discover pear.phing.info
sudo pear install phing/phing
sudo pear install pear/VersionControl_Git-0.4.4
-->
<project name="gridfield-bulk-editing-tools" default="transifex" phingVersion="2.7.0">
<taskdef name="buildTransifexTranslations" classname="tasks.BuildTransifexTranslations" />
<target name="transifex" description="Fetches Transifex translations and build lang files.">
<echo msg="Building translations..." />
<buildTransifexTranslations
txproject="gridfieldbulkeditingtools"
/>
</target>
</project>

View File

@ -4,12 +4,16 @@ Perform actions on multiple records straight from the GridField. Comes with *unl
## Usage ## Usage
Simply add component to your `GridFieldConfig` Simply add component to your `GridFieldConfig`
$config->addComponent(new GridFieldBulkManager()); ```php
$config->addComponent(new \Colymba\BulkManager\BulkManager());
```
## Configuration ## Configuration
The component's options can be configurated individually or in bulk through the 'config' functions like this: The component's options can be configurated individually or in bulk through the 'config' functions like this:
$config->getComponentByType('GridFieldBulkManager')->setConfig($reference, $value); ```php
$config->getComponentByType('Colymba\\BulkManager\\BulkManager')->setConfig($reference, $value);
```
### $config overview ### $config overview
The available configuration options are: The available configuration options are:
@ -21,16 +25,20 @@ You can remove or add individual action or replace them all via `addBulkAction()
### Adding a custom action ### Adding a custom action
To add a custom bulk action to the list use: To add a custom bulk action to the list use:
$config->getComponentByType('GridFieldBulkManager')->addBulkAction('actionName', 'Dropdown label', 'ActionHandlerClassName', $frontEndConfig) ```php
$config
->getComponentByType('Colymba\\BulkManager\\BulkManager')
->addBulkAction('actionName', 'Dropdown label', 'ActionHandlerClassName', $frontEndConfig)
```
You can omit the handler's class name and the front-end config array, those will default to: You can omit the handler's class name and the front-end config array, those will default to:
* `'GridFieldBulkAction'.ucfirst($name).'Handler'` * `'GridFieldBulkAction'.ucfirst($name).'Handler'`
* `$config = array( 'isAjax' => true, 'icon' => 'accept', 'isDestructive' => false )` * `$config = array( 'isAjax' => true, 'icon' => 'accept', 'isDestructive' => false )`
#### Custom action handler #### Custom action handler
When creating your own bulk action `RequestHandler`, you should extend `GridFieldBulkActionHandler` which will expose 2 usefull functions `getRecordIDList()` and `getRecords()` returning either an array with the selected records IDs or a `DataList` of the selected records. When creating your own bulk action `RequestHandler`, you should extend `Colymba\BulkManager\BulkAction\Handler` which will expose 2 useful functions `getRecordIDList()` and `getRecords()` returning either an array with the selected records IDs or a `DataList` of the selected records.
Make sure to define your `$allowed_actions` and `$url_handlers` on your custom bulk action handler. See `GridFieldBulkActionEditHandler`, `GridFieldBulkActionDeleteHandler` and `GridFieldBulkActionUnlinkHandler` for examples. Make sure to define your `$allowed_actions` and `$url_handlers` on your custom bulk action handler. See `Handler`, `DeleteHandler` and `UnlinkHandler` for examples.
#### Front-end config #### Front-end config
The last `addBulkAction()` parameter lets you pass an array with configuration options for the UI/UX: The last `addBulkAction()` parameter lets you pass an array with configuration options for the UI/UX:

View File

@ -1,10 +1,18 @@
<?php <?php
namespace Colymba\BulkManager\BulkAction;
use Colymba\BulkManager\BulkAction\Handler;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Core\Convert;
/** /**
* Bulk action handler for deleting records. * Bulk action handler for deleting records.
* *
* @author colymba * @author colymba
*/ */
class GridFieldBulkActionDeleteHandler extends GridFieldBulkActionHandler class DeleteHandler extends Handler
{ {
/** /**
* RequestHandler allowed actions. * RequestHandler allowed actions.
@ -25,11 +33,11 @@ class GridFieldBulkActionDeleteHandler extends GridFieldBulkActionHandler
/** /**
* Delete the selected records passed from the delete bulk action. * Delete the selected records passed from the delete bulk action.
* *
* @param SS_HTTPRequest $request * @param HTTPRequest $request
* *
* @return SS_HTTPResponse List of deleted records ID * @return HTTPResponse List of deleted records ID
*/ */
public function delete(SS_HTTPRequest $request) public function delete(HTTPRequest $request)
{ {
$ids = array(); $ids = array();
@ -38,7 +46,7 @@ class GridFieldBulkActionDeleteHandler extends GridFieldBulkActionHandler
$record->delete(); $record->delete();
} }
$response = new SS_HTTPResponse(Convert::raw2json(array( $response = new HTTPResponse(Convert::raw2json(array(
'done' => true, 'done' => true,
'records' => $ids, 'records' => $ids,
))); )));

View File

@ -1,10 +1,25 @@
<?php <?php
namespace Colymba\BulkManager\BulkAction;
use Colymba\BulkManager\BulkAction\Handler;
use SilverStripe\Control\Controller;
use SilverStripe\Core\Convert;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\Form;
use SilverStripe\Forms\FormAction;
use SilverStripe\Forms\LiteralField;
use SilverStripe\Forms\ToggleCompositeField;
use SilverStripe\ORM\DataObject;
use SilverStripe\View\Requirements;
/** /**
* Bulk action handler for editing records. * Bulk action handler for editing records.
* *
* @author colymba * @author colymba
*/ */
class GridFieldBulkActionEditHandler extends GridFieldBulkActionHandler class EditHandler extends Handler
{ {
/** /**
* RequestHandler allowed actions. * RequestHandler allowed actions.
@ -58,7 +73,7 @@ class GridFieldBulkActionEditHandler extends GridFieldBulkActionHandler
$actions->push( $actions->push(
FormAction::create('doSave', _t('GRIDFIELD_BULKMANAGER_EDIT_HANDLER.SAVE_BTN_LABEL', 'Save all')) FormAction::create('doSave', _t('GRIDFIELD_BULKMANAGER_EDIT_HANDLER.SAVE_BTN_LABEL', 'Save all'))
->setAttribute('id', 'bulkEditingSaveBtn') ->setAttribute('id', 'bulkEditingSaveBtn')
->addExtraClass('ss-ui-action-constructive') ->addExtraClass('btn btn-success')
->setAttribute('data-icon', 'accept') ->setAttribute('data-icon', 'accept')
->setUseButtonTag(true) ->setUseButtonTag(true)
); );
@ -66,7 +81,7 @@ class GridFieldBulkActionEditHandler extends GridFieldBulkActionHandler
$actions->push( $actions->push(
FormAction::create('Cancel', _t('GRIDFIELD_BULKMANAGER_EDIT_HANDLER.CANCEL_BTN_LABEL', 'Cancel')) FormAction::create('Cancel', _t('GRIDFIELD_BULKMANAGER_EDIT_HANDLER.CANCEL_BTN_LABEL', 'Cancel'))
->setAttribute('id', 'bulkEditingUpdateCancelBtn') ->setAttribute('id', 'bulkEditingUpdateCancelBtn')
->addExtraClass('ss-ui-action-destructive cms-panel-link') ->addExtraClass('btn btn-danger cms-panel-link')
->setAttribute('data-icon', 'decline') ->setAttribute('data-icon', 'decline')
->setAttribute('href', $one_level_up->Link) ->setAttribute('href', $one_level_up->Link)
->setUseButtonTag(true) ->setUseButtonTag(true)
@ -83,7 +98,8 @@ class GridFieldBulkActionEditHandler extends GridFieldBulkActionHandler
$titleModelClass = (($editingCount > 1) ? $singleton->i18n_plural_name() : $singleton->i18n_singular_name()); $titleModelClass = (($editingCount > 1) ? $singleton->i18n_plural_name() : $singleton->i18n_singular_name());
//some cosmetics //some cosmetics
$headerText = _t('GRIDFIELD_BULKMANAGER_EDIT_HANDLER.HEADER_TEXT', $headerText = _t(
'GRIDFIELD_BULKMANAGER_EDIT_HANDLER.HEADER_TEXT',
'Editing {count} {class}', 'Editing {count} {class}',
array( array(
'count' => $editingCount, 'count' => $editingCount,
@ -96,7 +112,10 @@ class GridFieldBulkActionEditHandler extends GridFieldBulkActionHandler
); );
$recordsFieldList->push($header); $recordsFieldList->push($header);
$toggle = LiteralField::create('bulkEditToggle', '<span id="bulkEditToggle">'._t('GRIDFIELD_BULKMANAGER_EDIT_HANDLER.TOGGLE_ALL_LINK', 'Show/Hide all').'</span>'); $toggle = LiteralField::create(
'bulkEditToggle',
'<span id="bulkEditToggle">' . _t('GRIDFIELD_BULKMANAGER_EDIT_HANDLER.TOGGLE_ALL_LINK', 'Show/Hide all') . '</span>'
);
$recordsFieldList->push($toggle); $recordsFieldList->push($toggle);
//fetch fields for each record and push to fieldList //fetch fields for each record and push to fieldList
@ -105,7 +124,7 @@ class GridFieldBulkActionEditHandler extends GridFieldBulkActionHandler
$recordEditingFields = $this->getRecordEditingFields($record); $recordEditingFields = $this->getRecordEditingFields($record);
$toggleField = ToggleCompositeField::create( $toggleField = ToggleCompositeField::create(
'RecordFields_'.$id, 'RecordFields_' . $id,
$record->getTitle(), $record->getTitle(),
$recordEditingFields $recordEditingFields
) )
@ -192,7 +211,8 @@ class GridFieldBulkActionEditHandler extends GridFieldBulkActionHandler
private function getRecordEditingFields(DataObject $record) private function getRecordEditingFields(DataObject $record)
{ {
$tempForm = Form::create( $tempForm = Form::create(
$this, 'TempEditForm', $this,
'TempEditForm',
$record->getCMSFields(), $record->getCMSFields(),
FieldList::create() FieldList::create()
); );
@ -210,7 +230,7 @@ class GridFieldBulkActionEditHandler extends GridFieldBulkActionHandler
* based on component's config * based on component's config
* and escape each field with unique name. * and escape each field with unique name.
* *
* See {@link GridFieldBulkManager} component for filtering config. * See {@link BulkManager} component for filtering config.
* *
* @param FieldList $fields Record's CMS Fields * @param FieldList $fields Record's CMS Fields
* @param int $id Record's ID, used fir unique name * @param int $id Record's ID, used fir unique name
@ -252,7 +272,7 @@ class GridFieldBulkActionEditHandler extends GridFieldBulkActionHandler
*/ */
protected function escapeFieldName($recordID, $name) protected function escapeFieldName($recordID, $name)
{ {
return 'record_'.$recordID.'_'.$name; return 'record_' . $recordID . '_' . $name;
} }
/** /**
@ -285,21 +305,24 @@ class GridFieldBulkActionEditHandler extends GridFieldBulkActionHandler
public function index() public function index()
{ {
$form = $this->bulkEditForm(); $form = $this->bulkEditForm();
$form->setTemplate('LeftAndMain_EditForm'); $form->setTemplate([
'type' => 'Includes',
'SilverStripe\\Admin\\LeftAndMain_EditForm',
]);
$form->addExtraClass('center cms-content'); $form->addExtraClass('center cms-content');
$form->setAttribute('data-pjax-fragment', 'CurrentForm Content'); $form->setAttribute('data-pjax-fragment', 'CurrentForm Content');
Requirements::javascript(BULKEDITTOOLS_MANAGER_PATH.'/javascript/GridFieldBulkEditingForm.js'); Requirements::javascript(BULKEDITTOOLS_MANAGER_PATH . '/javascript/GridFieldBulkEditingForm.js');
Requirements::css(BULKEDITTOOLS_MANAGER_PATH.'/css/GridFieldBulkEditingForm.css'); Requirements::css(BULKEDITTOOLS_MANAGER_PATH . '/css/GridFieldBulkEditingForm.css');
Requirements::add_i18n_javascript(BULKEDITTOOLS_PATH.'/lang/js'); Requirements::add_i18n_javascript(BULKEDITTOOLS_PATH . '/lang/js');
if ($this->request->isAjax()) { if ($this->request->isAjax()) {
$response = new SS_HTTPResponse( $response = new HTTPResponse(
Convert::raw2json(array('Content' => $form->forAjaxTemplate()->getValue())) Convert::raw2json(array('Content' => $form->forAjaxTemplate()->getValue()))
); );
$response->addHeader('X-Pjax', 'Content'); $response->addHeader('X-Pjax', 'Content');
$response->addHeader('Content-Type', 'text/json'); $response->addHeader('Content-Type', 'text/json');
$response->addHeader('X-Title', 'SilverStripe - Bulk '.$this->gridField->list->dataClass.' Editing'); $response->addHeader('X-Title', 'SilverStripe - Bulk ' . $this->gridField->list->dataClass . ' Editing');
return $response; return $response;
} else { } else {
@ -340,7 +363,8 @@ class GridFieldBulkActionEditHandler extends GridFieldBulkActionHandler
foreach ($formsData as $recordID => $recordData) { foreach ($formsData as $recordID => $recordData) {
$record = DataObject::get_by_id($className, $recordID); $record = DataObject::get_by_id($className, $recordID);
$recordForm = Form::create( $recordForm = Form::create(
$this, 'RecordForm', $this,
'RecordForm',
$record->getCMSFields(), $record->getCMSFields(),
FieldList::create() FieldList::create()
); );
@ -358,7 +382,8 @@ class GridFieldBulkActionEditHandler extends GridFieldBulkActionHandler
//compose form message //compose form message
$messageModelClass = (($done > 1) ? $singleton->i18n_plural_name() : $singleton->i18n_singular_name()); $messageModelClass = (($done > 1) ? $singleton->i18n_plural_name() : $singleton->i18n_singular_name());
$message = _t('GRIDFIELD_BULKMANAGER_EDIT_HANDLER.SAVE_RESULT_TEXT', $message = _t(
'GRIDFIELD_BULKMANAGER_EDIT_HANDLER.SAVE_RESULT_TEXT',
'{count} {class} saved successfully.', '{count} {class} saved successfully.',
array( array(
'count' => $done, 'count' => $done,
@ -368,7 +393,7 @@ class GridFieldBulkActionEditHandler extends GridFieldBulkActionHandler
$form->sessionMessage($message, 'good'); $form->sessionMessage($message, 'good');
//return back to form //return back to form
return Controller::curr()->redirect($this->Link('?records[]='.implode('&records[]=', $ids))); return Controller::curr()->redirect($this->Link('?records[]=' . implode('&records[]=', $ids)));
//return Controller::curr()->redirect($form->Backlink); //returns to gridField //return Controller::curr()->redirect($form->Backlink); //returns to gridField
} }
} }

View File

@ -1,4 +1,14 @@
<?php <?php
namespace Colymba\BulkManager\BulkAction;
use SilverStripe\Control\Controller;
use SilverStripe\Control\RequestHandler;
use SilverStripe\Forms\GridField\GridFieldDetailForm;
use SilverStripe\Forms\GridField\GridFieldDetailForm_ItemRequest;
use SilverStripe\ORM\DataList;
use SilverStripe\View\ArrayData;
/** /**
* Base class to extend for all custom bulk action handlers * Base class to extend for all custom bulk action handlers
* Gives access to the GridField, Component and Controller * Gives access to the GridField, Component and Controller
@ -6,7 +16,7 @@
* *
* @author colymba * @author colymba
*/ */
class GridFieldBulkActionHandler extends RequestHandler class Handler extends RequestHandler
{ {
/** /**
* Related GridField instance. * Related GridField instance.
@ -30,7 +40,7 @@ class GridFieldBulkActionHandler extends RequestHandler
protected $controller; protected $controller;
/** /**
* @param GridFIeld $gridField * @param GridField $gridField
* @param GridField_URLHandler $component * @param GridField_URLHandler $component
* @param Controller $controller * @param Controller $controller
*/ */

View File

@ -1,10 +1,18 @@
<?php <?php
namespace Colymba\BulkManager\BulkAction;
use Colymba\BulkManager\BulkAction\Handler;
use SilverStripe\Core\Convert;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse;
/** /**
* Bulk action handler for unlinking records. * Bulk action handler for unlinking records.
* *
* @author colymba * @author colymba
*/ */
class GridFieldBulkActionUnlinkHandler extends GridFieldBulkActionHandler class UnlinkHandler extends Handler
{ {
/** /**
* RequestHandler allowed actions. * RequestHandler allowed actions.
@ -25,16 +33,16 @@ class GridFieldBulkActionUnlinkHandler extends GridFieldBulkActionHandler
/** /**
* Unlink the selected records passed from the unlink bulk action. * Unlink the selected records passed from the unlink bulk action.
* *
* @param SS_HTTPRequest $request * @param HTTPRequest $request
* *
* @return SS_HTTPResponse List of affected records ID * @return HTTPResponse List of affected records ID
*/ */
public function unLink(SS_HTTPRequest $request) public function unLink(HTTPRequest $request)
{ {
$ids = $this->getRecordIDList(); $ids = $this->getRecordIDList();
$this->gridField->list->removeMany($ids); $this->gridField->list->removeMany($ids);
$response = new SS_HTTPResponse(Convert::raw2json(array( $response = new HTTPResponse(Convert::raw2json(array(
'done' => true, 'done' => true,
'records' => $ids, 'records' => $ids,
))); )));

View File

@ -1,10 +1,25 @@
<?php <?php
namespace Colymba\BulkManager;
use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Forms\CheckboxField;
use SilverStripe\Forms\DropdownField;
use SilverStripe\Forms\GridField\GridField_HTMLProvider;
use SilverStripe\Forms\GridField\GridField_ColumnProvider;
use SilverStripe\Forms\GridField\GridField_URLHandler;
use SilverStripe\ORM\DataModel;
use SilverStripe\View\ArrayData;
use SilverStripe\View\Requirements;
/** /**
* GridField component for editing attached models in bulk. * GridField component for editing attached models in bulk.
* *
* @author colymba * @author colymba
*/ */
class GridFieldBulkManager implements GridField_HTMLProvider, GridField_ColumnProvider, GridField_URLHandler class BulkManager implements GridField_HTMLProvider, GridField_ColumnProvider, GridField_URLHandler
{ {
/** /**
* component configuration. * component configuration.
@ -35,7 +50,7 @@ class GridFieldBulkManager implements GridField_HTMLProvider, GridField_ColumnPr
$this->config['actions'] = array( $this->config['actions'] = array(
'bulkEdit' => array( 'bulkEdit' => array(
'label' => _t('GRIDFIELD_BULK_MANAGER.EDIT_SELECT_LABEL', 'Edit'), 'label' => _t('GRIDFIELD_BULK_MANAGER.EDIT_SELECT_LABEL', 'Edit'),
'handler' => 'GridFieldBulkActionEditHandler', 'handler' => 'Colymba\\BulkManager\\BulkAction\\EditHandler',
'config' => array( 'config' => array(
'isAjax' => false, 'isAjax' => false,
'icon' => 'pencil', 'icon' => 'pencil',
@ -44,7 +59,7 @@ class GridFieldBulkManager implements GridField_HTMLProvider, GridField_ColumnPr
), ),
'unLink' => array( 'unLink' => array(
'label' => _t('GRIDFIELD_BULK_MANAGER.UNLINK_SELECT_LABEL', 'UnLink'), 'label' => _t('GRIDFIELD_BULK_MANAGER.UNLINK_SELECT_LABEL', 'UnLink'),
'handler' => 'GridFieldBulkActionUnlinkHandler', 'handler' => 'Colymba\\BulkManager\\BulkAction\\UnlinkHandler',
'config' => array( 'config' => array(
'isAjax' => true, 'isAjax' => true,
'icon' => 'chain--minus', 'icon' => 'chain--minus',
@ -53,13 +68,13 @@ class GridFieldBulkManager implements GridField_HTMLProvider, GridField_ColumnPr
), ),
'delete' => array( 'delete' => array(
'label' => _t('GRIDFIELD_BULK_MANAGER.DELETE_SELECT_LABEL', 'Delete'), 'label' => _t('GRIDFIELD_BULK_MANAGER.DELETE_SELECT_LABEL', 'Delete'),
'handler' => 'GridFieldBulkActionDeleteHandler', 'handler' => 'Colymba\\BulkManager\\BulkAction\\DeleteHandler',
'config' => array( 'config' => array(
'isAjax' => true, 'isAjax' => true,
'icon' => 'decline', 'icon' => 'decline',
'isDestructive' => true, 'isDestructive' => true,
), ),
), )
); );
} }
} }
@ -132,7 +147,7 @@ class GridFieldBulkManager implements GridField_HTMLProvider, GridField_ColumnPr
} }
if (!$handler) { if (!$handler) {
$handler = 'GridFieldBulkAction'.ucfirst($name).'Handler'; $handler = 'Colymba\\BulkManager\\BulkAction\\' . ucfirst($name) . 'Handler';
} }
if (!ClassInfo::exists($handler)) { if (!ClassInfo::exists($handler)) {
@ -216,7 +231,7 @@ class GridFieldBulkManager implements GridField_HTMLProvider, GridField_ColumnPr
*/ */
public function getColumnContent($gridField, $record, $columnName) public function getColumnContent($gridField, $record, $columnName)
{ {
$cb = CheckboxField::create('bulkSelect_'.$record->ID) $cb = CheckboxField::create('bulkSelect_' . $record->ID)
->addExtraClass('bulkSelect no-change-track') ->addExtraClass('bulkSelect no-change-track')
->setAttribute('data-record', $record->ID); ->setAttribute('data-record', $record->ID);
@ -263,9 +278,9 @@ class GridFieldBulkManager implements GridField_HTMLProvider, GridField_ColumnPr
*/ */
public function getHTMLFragments($gridField) public function getHTMLFragments($gridField)
{ {
Requirements::css(BULKEDITTOOLS_MANAGER_PATH.'/css/GridFieldBulkManager.css'); Requirements::css(BULKEDITTOOLS_MANAGER_PATH . '/css/GridFieldBulkManager.css');
Requirements::javascript(BULKEDITTOOLS_MANAGER_PATH.'/javascript/GridFieldBulkManager.js'); Requirements::javascript(BULKEDITTOOLS_MANAGER_PATH . '/javascript/GridFieldBulkManager.js');
Requirements::add_i18n_javascript(BULKEDITTOOLS_PATH.'/lang/js'); Requirements::add_i18n_javascript(BULKEDITTOOLS_PATH . '/lang/js');
if (!count($this->config['actions'])) { if (!count($this->config['actions'])) {
user_error('Trying to use GridFieldBulkManager without any bulk action.', E_USER_ERROR); user_error('Trying to use GridFieldBulkManager without any bulk action.', E_USER_ERROR);
@ -284,16 +299,16 @@ class GridFieldBulkManager implements GridField_HTMLProvider, GridField_ColumnPr
$dropDownActionsList = DropdownField::create('bulkActionName', '') $dropDownActionsList = DropdownField::create('bulkActionName', '')
->setSource($actionsListSource) ->setSource($actionsListSource)
->setAttribute('class', 'bulkActionName no-change-track') ->addExtraClass('bulkActionName no-change-track no-chosen')
->setAttribute('id', ''); ->setAttribute('id', '');
$templateData = array( $templateData = array(
'Menu' => $dropDownActionsList->FieldHolder(), 'Menu' => $dropDownActionsList,
'Button' => array( 'Button' => array(
'Label' => _t('GRIDFIELD_BULK_MANAGER.ACTION_BTN_LABEL', 'Go'), 'Label' => _t('GRIDFIELD_BULK_MANAGER.ACTION_BTN_LABEL', 'Go'),
'DataURL' => $gridField->Link('bulkAction'), 'DataURL' => $gridField->Link('bulkAction'),
'Icon' => $this->config['actions'][$firstAction]['config']['icon'], 'Icon' => $this->config['actions'][$firstAction]['config']['icon'],
'DataConfig' => htmlspecialchars(json_encode($actionsConfig), ENT_QUOTES, 'UTF-8'), 'DataConfig' => json_encode($actionsConfig),
), ),
'Select' => array( 'Select' => array(
'Label' => _t('GRIDFIELD_BULK_MANAGER.SELECT_ALL_LABEL', 'Select all'), 'Label' => _t('GRIDFIELD_BULK_MANAGER.SELECT_ALL_LABEL', 'Select all'),
@ -335,13 +350,13 @@ class GridFieldBulkManager implements GridField_HTMLProvider, GridField_ColumnPr
* but have more specific path defined * but have more specific path defined
* *
* @param GridField $gridField * @param GridField $gridField
* @param SS_HTTPRequest $request * @param HTTPRequest $request
* *
* @return mixed * @return mixed
*/ */
public function handleBulkAction($gridField, $request) public function handleBulkAction($gridField, $request)
{ {
$controller = $gridField->getForm()->Controller(); $controller = $gridField->getForm()->getController();
foreach ($this->config['actions'] as $name => $data) { foreach ($this->config['actions'] as $name => $data) {
$handlerClass = $data['handler']; $handlerClass = $data['handler'];
@ -359,6 +374,6 @@ class GridFieldBulkManager implements GridField_HTMLProvider, GridField_ColumnPr
} }
} }
user_error('Unable to find matching bulk action handler for '.$request->remaining().'.', E_USER_ERROR); user_error('Unable to find matching bulk action handler for ' . $request->remaining() . '.', E_USER_ERROR);
} }
} }

View File

@ -31,12 +31,14 @@
text-shadow: none; } text-shadow: none; }
.bulkEditingFieldHolder.updated .ui-accordion-header { .bulkEditingFieldHolder.updated .ui-accordion-header {
background-color: #a4ca3a; background-color: #a4ca3a;
background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #a4ca3a), color-stop(100%, #59781d)); background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #a4ca3a), color-stop(100%, #59781D));
background-image: -webkit-linear-gradient(top, #a4ca3a 0%, #59781d 100%); background-image: -webkit-linear-gradient(top, #a4ca3a 0%, #59781D 100%);
background-image: -moz-linear-gradient(top, #a4ca3a 0%, #59781d 100%); background-image: -moz-linear-gradient(top, #a4ca3a 0%, #59781D 100%);
background-image: -o-linear-gradient(top, #a4ca3a 0%, #59781d 100%); background-image: -o-linear-gradient(top, #a4ca3a 0%, #59781D 100%);
background-image: -ms-linear-gradient(top, #a4ca3a 0%, #59781d 100%); background-image: -ms-linear-gradient(top, #a4ca3a 0%, #59781D 100%);
background-image: linear-gradient(top, #a4ca3a 0%, #59781d 100%); } background-image: linear-gradient(top, #a4ca3a 0%, #59781D 100%); }
.bulkEditingFieldHolder.updated .ui-accordion-header a { .bulkEditingFieldHolder.updated .ui-accordion-header a {
color: #fff; color: #fff;
text-shadow: none; } text-shadow: none; }
/*# sourceMappingURL=GridFieldBulkEditingForm.css.map */

View File

@ -0,0 +1,7 @@
{
"version": 3,
"mappings": "AACA,eACA;EACC,KAAK,EAAE,IAAI;EACX,KAAK,EAAE,GAAG;EAEV,MAAM,EAAE,aAAa;EAErB,SAAS,EAAE,IAAI;EACf,WAAW,EAAE,IAAI;;AAGlB,eACA;EACC,KAAK,EAAE,KAAK;EACZ,KAAK,EAAE,KAAK;EACZ,KAAK,EAAE,GAAG;EAEV,MAAM,EAAE,aAAa;EAErB,eAAe,EAAE,SAAS;EAC1B,UAAU,EAAE,KAAK;EACjB,MAAM,EAAE,OAAO;;AAGhB,uBACA;EACC,QAAQ,EAAE,QAAQ;EAClB,KAAK,EAAE,IAAI;EACX,KAAK,EAAE,IAAI;EAEX,sDACA;IACC,gBAAgB,EAAE,OAAO;IAEzB,gBAAgB,EAAE,8FAA8F;IAChH,gBAAgB,EAAE,sDAAsD;IACxE,gBAAgB,EAAE,mDAAmD;IACrE,gBAAgB,EAAE,iDAAiD;IACnE,gBAAgB,EAAE,kDAAkD;IACpE,gBAAgB,EAAE,8CAA8C;IAEhE,wDACA;MACC,KAAK,EAAE,IAAI;MACX,WAAW,EAAE,IAAI;EAInB,oDACA;IACC,gBAAgB,EAAE,OAAO;IAEzB,gBAAgB,EAAE,8FAA8F;IAChH,gBAAgB,EAAE,sDAAsD;IACxE,gBAAgB,EAAE,mDAAmD;IACrE,gBAAgB,EAAE,iDAAiD;IACnE,gBAAgB,EAAE,kDAAkD;IACpE,gBAAgB,EAAE,8CAA8C;IAEhE,sDACA;MACC,KAAK,EAAE,IAAI;MACX,WAAW,EAAE,IAAI",
"sources": ["GridFieldBulkEditingForm.scss"],
"names": [],
"file": "GridFieldBulkEditingForm.css"
}

View File

@ -1,10 +1,12 @@
.cms table.ss-gridfield-table tr.bulkManagerOptions th.bulkmanagerselect { .cms table.grid-field__table tr.bulkManagerOptions th.bulkmanagerheading {
padding-left: 40px; }
.cms table.grid-field__table tr.bulkManagerOptions th.bulkmanagerselect {
text-align: center; } text-align: center; }
.cms table.ss-gridfield-table tr.bulkManagerOptions th.bulkmanagerselect input { .cms table.grid-field__table tr.bulkManagerOptions th.bulkmanagerselect input {
margin-left: 0; } margin-left: 0; }
.cms table.ss-gridfield-table tr.bulkManagerOptions .title { .cms table.grid-field__table tr.bulkManagerOptions .title {
margin: 0 0 2px 2px; } margin: 0 0 2px 2px; }
.cms table.ss-gridfield-table tr.bulkManagerOptions .dropdown { .cms table.grid-field__table tr.bulkManagerOptions .dropdown {
display: inline-block; display: inline-block;
border: none; border: none;
box-shadow: none; box-shadow: none;
@ -12,17 +14,17 @@
margin: 0; margin: 0;
color: #000; color: #000;
vertical-align: top; } vertical-align: top; }
.cms table.ss-gridfield-table tr.bulkManagerOptions .doBulkActionButton .ui-button-text { .cms table.grid-field__table tr.bulkManagerOptions .doBulkActionButton .ui-button-text {
padding: 6px 0 5px 2.1em; } padding: 6px 0 5px 2.1em; }
.cms table.ss-gridfield-table tr.bulkManagerOptions .doBulkActionButton .ui-button-text .ui-button-text { .cms table.grid-field__table tr.bulkManagerOptions .doBulkActionButton .ui-button-text .ui-button-text {
padding: 0; } padding: 0; }
.cms table.ss-gridfield-table tr.bulkManagerOptions .doBulkActionButton .loading .ui-icon { .cms table.grid-field__table tr.bulkManagerOptions .doBulkActionButton .loading .ui-icon {
background: transparent url(../../framework/images/network-save.gif) no-repeat 0 0; } background: transparent url(../../framework/images/network-save.gif) no-repeat 0 0; }
.cms table.ss-gridfield-table tbody .col-bulkSelect { .cms table.grid-field__table tbody .col-bulkSelect {
width: 25px; width: 25px;
padding: 0 10px; padding: 0 10px;
text-align: center; } text-align: center; }
.cms table.ss-gridfield-table tbody td a.tempDisabledEditLink { .cms table.grid-field__table tbody td a.tempDisabledEditLink {
background: url("../../framework/admin/images/btn-icon/document--pencil.png") no-repeat 2px 0px; background: url("../../framework/admin/images/btn-icon/document--pencil.png") no-repeat 2px 0px;
display: inline-block; display: inline-block;
width: 20px; width: 20px;
@ -32,3 +34,5 @@
vertical-align: middle; vertical-align: middle;
background-position: 2px 0px; background-position: 2px 0px;
background-repeat: no-repeat no-repeat; } background-repeat: no-repeat no-repeat; }
/*# sourceMappingURL=GridFieldBulkManager.css.map */

View File

@ -0,0 +1,7 @@
{
"version": 3,
"mappings": "AAII,wEAAsB;EAClB,YAAY,EAAE,IAAI;AAGtB,uEACA;EACE,UAAU,EAAE,MAAM;EAElB,6EACA;IACE,WAAW,EAAE,CAAC;AAIlB,yDACA;EACE,MAAM,EAAE,WAAW;AAGrB,4DACA;EACE,OAAO,EAAE,YAAY;EACrB,MAAM,EAAE,IAAI;EACZ,UAAU,EAAE,IAAI;EAEhB,OAAO,EAAE,CAAC;EACV,MAAM,EAAE,CAAC;EAET,KAAK,EAAE,IAAI;EACX,cAAc,EAAE,GAAG;AAKnB,sFACA;EACE,OAAO,EAAE,eAAe;EAExB,sGACA;IACE,OAAO,EAAE,CAAC;AAId,wFACA;EACE,UAAU,EAAE,sEAAsE;AAOtF,kDACA;EACE,KAAK,EAAE,IAAI;EACX,OAAO,EAAE,MAAM;EACf,UAAU,EAAE,MAAM;AAGpB,4DACA;EACE,UAAU,EAAE,mFAAmF;EAC/F,OAAO,EAAE,YAAY;EACrB,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,IAAI;EACZ,WAAW,EAAE,QAAQ;EACrB,QAAQ,EAAE,MAAM;EAChB,cAAc,EAAE,MAAM;EACtB,mBAAmB,EAAE,OAAO;EAC5B,iBAAiB,EAAE,mBAAmB",
"sources": ["GridFieldBulkManager.scss"],
"names": [],
"file": "GridFieldBulkManager.css"
}

View File

@ -1,7 +1,11 @@
.cms table.ss-gridfield-table .cms table.grid-field__table
{ {
tr.bulkManagerOptions tr.bulkManagerOptions
{ {
th.bulkmanagerheading {
padding-left: 40px;
}
th.bulkmanagerselect th.bulkmanagerselect
{ {
text-align: center; text-align: center;

View File

@ -69,7 +69,7 @@
onunmatch: function(){ onunmatch: function(){
}, },
onclick: function(e) { onclick: function(e) {
$(this).parents('.ss-gridfield-table').find('input.bulkSelectAll').prop('checked', ''); $(this).parents('.grid-field__table').find('input.bulkSelectAll').prop('checked', '');
} }
}); });
@ -85,14 +85,14 @@
onclick: function() onclick: function()
{ {
var state = $(this).prop('checked'); var state = $(this).prop('checked');
$(this).parents('.ss-gridfield-table') $(this).parents('.grid-field__table')
.find('td.col-bulkSelect input') .find('td.col-bulkSelect input')
.prop('checked', state) .prop('checked', state)
.trigger('change'); .trigger('change');
}, },
getSelectRecordsID: function() getSelectRecordsID: function()
{ {
return $(this).parents('.ss-gridfield-table') return $(this).parents('.grid-field__table')
.find('td.col-bulkSelect input:checked') .find('td.col-bulkSelect input:checked')
.map(function() { .map(function() {
return parseInt( $(this).data('record') ) return parseInt( $(this).data('record') )

View File

@ -1,15 +1,25 @@
<tr class="bulkManagerOptions"> <tr class="bulkManagerOptions">
<th class="main bulkmanagerheading" colspan="$Colspan"> <th class="main bulkmanagerheading" colspan="$Colspan">
<div class="row">
<p class="title"><% _t('GRIDFIELD_BULK_MANAGER.COMPONENT_TITLE', 'Modify one or more entry at a time.') %></p> <p class="title"><% _t('GRIDFIELD_BULK_MANAGER.COMPONENT_TITLE', 'Modify one or more entry at a time.') %></p>
</div>
<div class="row">
<div class="form-inline">
$Menu $Menu
<a data-url="$Button.DataURL" data-config="$Button.DataConfig" class="doBulkActionButton ss-ui-button" data-icon="$Button.Icon"> <a data-url="$Button.DataURL"
data-config="$Button.DataConfig"
class="doBulkActionButton btn btn-primary"
data-icon="$Button.Icon">
$Button.Label $Button.Label
</a> </a>
<label class="form-check-label">
</th> <input class="no-change-track bulkSelectAll form-check-input"
<th class="main bulkmanagerselect"> type="checkbox"
<input class="no-change-track bulkSelectAll" type="checkbox" title="$Select.Label" name="toggleSelectAll" /> title="$Select.Label"
name="toggleSelectAll" />
<% _t('GRIDFIELD_BULK_MANAGER.SELECT_ALL_LABEL', '$Select.Label') %>
</label>
</div>
</div>
</th> </th>
</tr> </tr>

View File

@ -4,20 +4,26 @@ A component for uploading images and/or files in bulk into `DataObject` managed
## Usage 1 ## Usage 1
Simplest usage, add the component to your `GridFieldConfig` as below. The component will find the first `Image` or `File` has_one relation to use on the managed `DataObject`. Simplest usage, add the component to your `GridFieldConfig` as below. The component will find the first `Image` or `File` has_one relation to use on the managed `DataObject`.
$config->addComponent(new GridFieldBulkUpload()); ```php
$config->addComponent(new \Colymba\BulkUpload\BulkUploader());
```
## Usage 2 ## Usage 2
You can specify which `Image` or `File` field to use and a specific `DataObject` class name to use. You can specify which `Image` or `File` field to use and a specific `DataObject` class name to use.
$fileRelationName (string, optional): The name of the `Image` or `File` has_one field to use (If your relation is set has 'MyImage' => 'Image', the parameter should be 'MyImage') $fileRelationName (string, optional): The name of the `Image` or `File` has_one field to use (If your relation is set has 'MyImage' => 'Image', the parameter should be 'MyImage')
$recordClassName (string, optional): The class name of the `DataObject` to create (Usefull if for example your `GridField` holds `DataObject`s of different classes, like when used with the `GridFieldAddNewMultiClass` component.) $recordClassName (string, optional): The class name of the `DataObject` to create (Usefull if for example your `GridField` holds `DataObject`s of different classes, like when used with the `GridFieldAddNewMultiClass` component.)
$config->addComponent(new GridFieldBulkUpload($fileRelationName, $recordClassName)); ```php
$config->addComponent(new \Colymba\BulkUpload\BulkUploader($fileRelationName, $recordClassName));
```
## Configuration ## Configuration
### Component configuration ### Component configuration
The component's option can be configurated through the `setConfig` functions like this: The component's option can be configurated through the `setConfig` functions like this:
$config->getComponentByType('GridFieldBulkUpload')->setConfig($reference, $value); ```php
$config->getComponentByType('Colymba\\BulkUpload\\BulkUploader')->setConfig($reference, $value);
```
The available configuration options are: The available configuration options are:
* 'fileRelationName' : sets the name of the `Image` or `File` has_one field to use (i.e. 'MyImage') * 'fileRelationName' : sets the name of the `Image` or `File` has_one field to use (i.e. 'MyImage')
@ -30,12 +36,14 @@ The underlying `UploadField` can be configured via a set of APIs:
For example, to set the upload folder, which is set by calling `setFolderName` on the `UploadField`, and setting the upload method as sequential, you would use the following: For example, to set the upload folder, which is set by calling `setFolderName` on the `UploadField`, and setting the upload method as sequential, you would use the following:
$config->getComponentByType('GridFieldBulkUpload') ```php
$config->getComponentByType('Colymba\\BulkUpload\\BulkUploader')
->setUfSetup('setFolderName', 'myFolder') ->setUfSetup('setFolderName', 'myFolder')
->setUfConfig('sequentialUploads', true); ->setUfConfig('sequentialUploads', true);
```
Please see the [`UploadField` api](http://api.silverstripe.org/master/class-UploadField.html) and the [`Upload` api](http://api.silverstripe.org/master/class-Upload.html) for more info. Please see the [`UploadField` api](http://api.silverstripe.org/master/class-UploadField.html) and the [`Upload` api](http://api.silverstripe.org/master/class-Upload.html) for more info.
## Bulk Editing ## Bulk Editing
To get a quick edit shortcut to all the newly upload files, please also add the `GridFieldBulkManager` component to your `GridFieldConfig`. To get a quick edit shortcut to all the newly upload files, please also add the `Colymba\BulkManager\BulkManager` component to your `GridFieldConfig`.

View File

@ -1,4 +1,10 @@
<?php <?php
namespace Colymba\BulkUpload;
use SilverStripe\Control\Controller;
use SilverStripe\Forms\UploadField;
/** /**
* Custom UploadField used to override Link() * Custom UploadField used to override Link()
* and redirect UploadField action properly through the GridField. * and redirect UploadField action properly through the GridField.
@ -7,13 +13,25 @@
*/ */
class BulkUploadField extends UploadField class BulkUploadField extends UploadField
{ {
/**
* @var GridField
*/
protected $gridfield; protected $gridfield;
public function __construct($gridfield, $parent, $folderName = null) { /**
* @param GridField $gridfield
* @param string $parent
* @param string $folderName
*/
public function __construct($gridfield, $parent, $folderName = null)
{
$this->gridfield = $gridfield; $this->gridfield = $gridfield;
parent::__construct($parent, $folderName); parent::__construct($parent, $folderName);
} }
/**
* {@inheritDoc}
*/
public function Link($action = null) public function Link($action = null)
{ {
return Controller::join_links($this->gridfield->Link(), 'bulkupload/', $action); return Controller::join_links($this->gridfield->Link(), 'bulkupload/', $action);

View File

@ -1,10 +1,24 @@
<?php <?php
namespace Colymba\BulkUpload;
use Colymba\BulkUpload\BulkUploaderRequest;
use SilverStripe\Core\Config\Config;
use SilverStripe\Dev\Deprecation;
use SilverStripe\Forms\FormAction;
use SilverStripe\Forms\GridField\GridField_HTMLProvider;
use SilverStripe\Forms\GridField\GridField_URLHandler;
use SilverStripe\ORM\DataModel;
use SilverStripe\ORM\DataObject;
use SilverStripe\View\ArrayData;
use SilverStripe\View\Requirements;
/** /**
* GridField component for uploading images in bulk. * GridField component for uploading images in bulk.
* *
* @author colymba * @author colymba
*/ */
class GridFieldBulkUpload implements GridField_HTMLProvider, GridField_URLHandler class BulkUploader implements GridField_HTMLProvider, GridField_URLHandler
{ {
/** /**
* Component configuration. * Component configuration.
@ -24,7 +38,7 @@ class GridFieldBulkUpload implements GridField_HTMLProvider, GridField_URLHandle
* These options are passed on directly to the UploadField * These options are passed on directly to the UploadField
* via {@link UploadField::setConfig()} api. * via {@link UploadField::setConfig()} api.
* *
* Defaults are: * * Defaults are:
* 'sequentialUploads' => false : process uploads 1 after the other rather than all at once * 'sequentialUploads' => false : process uploads 1 after the other rather than all at once
* 'canAttachExisting' => true : displays "From files" button in the UploadField * 'canAttachExisting' => true : displays "From files" button in the UploadField
* 'canPreviewFolder' => true : displays the upload location in the UploadField * 'canPreviewFolder' => true : displays the upload location in the UploadField
@ -67,6 +81,7 @@ class GridFieldBulkUpload implements GridField_HTMLProvider, GridField_URLHandle
* Component constructor. * Component constructor.
* *
* @param string $fileRelationName * @param string $fileRelationName
* @param string $recordClassName
*/ */
public function __construct($fileRelationName = null, $recordClassName = null) public function __construct($fileRelationName = null, $recordClassName = null)
{ {
@ -92,7 +107,7 @@ class GridFieldBulkUpload implements GridField_HTMLProvider, GridField_URLHandle
public function setConfig($reference, $value) public function setConfig($reference, $value)
{ {
if (in_array($reference, array('folderName', 'maxFileSize', 'sequentialUploads', 'canAttachExisting', 'canPreviewFolder'))) { if (in_array($reference, array('folderName', 'maxFileSize', 'sequentialUploads', 'canAttachExisting', 'canPreviewFolder'))) {
Deprecation::notice('2.1.0', "GridFieldBulkUpload 'setConfig()' doesn't support '$reference' anymore. Please use 'setUfConfig()', 'setUfSetup()' or 'setUfValidatorSetup()' instead."); Deprecation::notice('2.1.0', "BulkUploader 'setConfig()' doesn't support '$reference' anymore. Please use 'setUfConfig()', 'setUfSetup()' or 'setUfValidatorSetup()' instead.");
if ($reference === 'folderName') { if ($reference === 'folderName') {
$this->setUfSetup('setFolderName', $value); $this->setUfSetup('setFolderName', $value);
@ -228,6 +243,7 @@ class GridFieldBulkUpload implements GridField_HTMLProvider, GridField_URLHandle
* Get the first has_one Image/File relation from the GridField managed DataObject * Get the first has_one Image/File relation from the GridField managed DataObject
* i.e. 'MyImage' => 'Image' will return 'MyImage'. * i.e. 'MyImage' => 'Image' will return 'MyImage'.
* *
* @param GridField $gridField
* @return string Name of the $has_one relation * @return string Name of the $has_one relation
*/ */
public function getDefaultFileRelationName($gridField) public function getDefaultFileRelationName($gridField)
@ -237,7 +253,10 @@ class GridFieldBulkUpload implements GridField_HTMLProvider, GridField_URLHandle
$imageField = null; $imageField = null;
foreach ($hasOneFields as $field => $type) { foreach ($hasOneFields as $field => $type) {
if ($type === 'Image' || $type === 'File' || is_subclass_of($type, 'File')) { if ($type === 'SilverStripe\\Assets\\Image'
|| $type === 'SilverStripe\\Assets\\File'
|| is_subclass_of($type, 'SilverStripe\\Assets\\File')
) {
$imageField = $field; $imageField = $field;
break; break;
} }
@ -250,6 +269,7 @@ class GridFieldBulkUpload implements GridField_HTMLProvider, GridField_URLHandle
* Returns the name of the Image/File field name from the managed record * Returns the name of the Image/File field name from the managed record
* Either as set in the component config or the default one. * Either as set in the component config or the default one.
* *
* @param GridField $gridField
* @return string * @return string
*/ */
public function getFileRelationName($gridField) public function getFileRelationName($gridField)
@ -264,6 +284,7 @@ class GridFieldBulkUpload implements GridField_HTMLProvider, GridField_URLHandle
* i.e. 'MyImage' => 'Image' will return 'Image' * i.e. 'MyImage' => 'Image' will return 'Image'
* i.e. 'MyImage' => 'File' will return 'File'. * i.e. 'MyImage' => 'File' will return 'File'.
* *
* @param GridField $gridField
* @return string file relation className * @return string file relation className
*/ */
public function getFileRelationClassName($gridField) public function getFileRelationClassName($gridField)
@ -275,7 +296,7 @@ class GridFieldBulkUpload implements GridField_HTMLProvider, GridField_URLHandle
if ($fieldName) { if ($fieldName) {
return $hasOneFields[$fieldName]; return $hasOneFields[$fieldName];
} else { } else {
return 'File'; return 'SilverStripe\\Assets\\File';
} }
} }
@ -299,7 +320,7 @@ class GridFieldBulkUpload implements GridField_HTMLProvider, GridField_URLHandle
->setRecord(DataObject::create()) // avoid UploadField to get auto-config from the Page (e.g fix allowedMaxFileNumber) ->setRecord(DataObject::create()) // avoid UploadField to get auto-config from the Page (e.g fix allowedMaxFileNumber)
->setTemplate('GridFieldBulkUploadField') ->setTemplate('BulkUploadField')
->setDownloadTemplateName('colymba-bulkuploaddownloadtemplate') ->setDownloadTemplateName('colymba-bulkuploaddownloadtemplate')
->setConfig('url', $gridField->Link('bulkupload/upload')) ->setConfig('url', $gridField->Link('bulkupload/upload'))
@ -345,7 +366,7 @@ class GridFieldBulkUpload implements GridField_HTMLProvider, GridField_URLHandle
} }
// check BulkManager exists // check BulkManager exists
$bulkManager = $gridField->getConfig()->getComponentsByType('GridFieldBulkManager'); $bulkManager = $gridField->getConfig()->getComponentsByType('Colymba\\BulkManager\\BulkManager');
// upload management buttons // upload management buttons
$finishButton = FormAction::create('Finish', _t('GRIDFIELD_BULK_UPLOAD.FINISH_BTN_LABEL', 'Finish')) $finishButton = FormAction::create('Finish', _t('GRIDFIELD_BULK_UPLOAD.FINISH_BTN_LABEL', 'Finish'))
@ -393,13 +414,13 @@ class GridFieldBulkUpload implements GridField_HTMLProvider, GridField_URLHandle
'UploadField' => $uploadField->Field(), // call ->Field() to get requirements in right order 'UploadField' => $uploadField->Field(), // call ->Field() to get requirements in right order
)); ));
Requirements::css(BULKEDITTOOLS_UPLOAD_PATH.'/css/GridFieldBulkUpload.css'); Requirements::css(BULKEDITTOOLS_UPLOAD_PATH . '/css/GridFieldBulkUpload.css');
Requirements::javascript(BULKEDITTOOLS_UPLOAD_PATH.'/javascript/GridFieldBulkUpload.js'); Requirements::javascript(BULKEDITTOOLS_UPLOAD_PATH . '/javascript/GridFieldBulkUpload.js');
Requirements::javascript(BULKEDITTOOLS_UPLOAD_PATH.'/javascript/GridFieldBulkUpload_downloadtemplate.js'); Requirements::javascript(BULKEDITTOOLS_UPLOAD_PATH . '/javascript/GridFieldBulkUpload_downloadtemplate.js');
Requirements::add_i18n_javascript(BULKEDITTOOLS_PATH.'/lang/js'); Requirements::add_i18n_javascript(BULKEDITTOOLS_PATH . '/lang/js');
return array( return array(
'header' => $data->renderWith('GridFieldBulkUpload'), 'header' => $data->renderWith('Colymba\\BulkUpload\\BulkUploader'),
); );
} }
@ -425,14 +446,14 @@ class GridFieldBulkUpload implements GridField_HTMLProvider, GridField_URLHandle
* Pass control over to the RequestHandler. * Pass control over to the RequestHandler.
* *
* @param GridField $gridField * @param GridField $gridField
* @param SS_HTTPRequest $request * @param HTTPRequest $request
* *
* @return mixed * @return mixed
*/ */
public function handleBulkUpload($gridField, $request) public function handleBulkUpload($gridField, $request)
{ {
$controller = $gridField->getForm()->Controller(); $controller = $gridField->getForm()->getController();
$handler = new GridFieldBulkUpload_Request($gridField, $this, $controller); $handler = new BulkUploaderRequest($gridField, $this, $controller);
return $handler->handleRequest($request, DataModel::inst()); return $handler->handleRequest($request, DataModel::inst());
} }

View File

@ -1,10 +1,23 @@
<?php <?php
namespace Colymba\BulkUpload;
use SilverStripe\Assets\Image;
use SilverStripe\Core\Convert;
use SilverStripe\Core\Object;
use SilverStripe\Control\Controller;
use SilverStripe\Control\RequestHandler;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Dev\Deprecation;
use SilverStripe\ORM\DataObject;
/** /**
* Handles request from the GridFieldBulkUpload component. * Handles request from the GridFieldBulkUpload component.
* *
* @author colymba * @author colymba
*/ */
class GridFieldBulkUpload_Request extends RequestHandler class BulkUploaderRequest extends RequestHandler
{ {
/** /**
* Gridfield instance. * Gridfield instance.
@ -16,7 +29,7 @@ class GridFieldBulkUpload_Request extends RequestHandler
/** /**
* Bulk upload component. * Bulk upload component.
* *
* @var GridFieldBulkUpload * @var BulkUploader
*/ */
protected $component; protected $component;
@ -48,7 +61,7 @@ class GridFieldBulkUpload_Request extends RequestHandler
/** /**
* Handler's constructor. * Handler's constructor.
* *
* @param GridFIeld $gridField * @param GridField $gridField
* @param GridField_URLHandler $component * @param GridField_URLHandler $component
* @param Controller $controller * @param Controller $controller
*/ */
@ -76,11 +89,11 @@ class GridFieldBulkUpload_Request extends RequestHandler
* adds record to GrifField relation list * adds record to GrifField relation list
* and return image/file data and record edit form. * and return image/file data and record edit form.
* *
* @param SS_HTTPRequest $request * @param HTTPRequest $request
* *
* @return string json * @return string json
*/ */
public function upload(SS_HTTPRequest $request) public function upload(HTTPRequest $request)
{ {
//create record //create record
$recordClass = $this->component->getRecordClassName($this->gridField); $recordClass = $this->component->getRecordClassName($this->gridField);
@ -114,7 +127,7 @@ class GridFieldBulkUpload_Request extends RequestHandler
// JS Template Data // JS Template Data
$responseData = $this->newRecordJSTemplateData($record, $uploadResponse); $responseData = $this->newRecordJSTemplateData($record, $uploadResponse);
$response = new SS_HTTPResponse(Convert::raw2json(array($responseData))); $response = new HTTPResponse(Convert::raw2json(array($responseData)));
$this->contentTypeNegotiation($response); $this->contentTypeNegotiation($response);
return $response; return $response;
@ -133,16 +146,19 @@ class GridFieldBulkUpload_Request extends RequestHandler
{ {
// fetch uploadedFile record and sort out previewURL // fetch uploadedFile record and sort out previewURL
// update $uploadResponse datas in case changes happened onAfterWrite() // update $uploadResponse datas in case changes happened onAfterWrite()
$uploadedFile = DataObject::get_by_id($this->component->getFileRelationClassName($this->gridField), $uploadResponse['id']); $uploadedFile = DataObject::get_by_id(
$this->component->getFileRelationClassName($this->gridField),
$uploadResponse['id']
);
if ($uploadedFile) { if ($uploadedFile) {
$uploadResponse['name'] = $uploadedFile->Name; $uploadResponse['name'] = $uploadedFile->Name;
$uploadResponse['url'] = $uploadedFile->getURL(); $uploadResponse['url'] = $uploadedFile->getURL();
if ($uploadedFile instanceof Image) { if ($uploadedFile instanceof Image) {
$uploadResponse['thumbnail_url'] = $uploadedFile->CroppedImage(30, 30)->getURL(); $uploadResponse['thumbnail_url'] = $uploadedFile->Fill(30, 30)->getURL();
} else { } else {
$uploadResponse['thumbnail_url'] = $uploadedFile->Icon(); $uploadResponse['thumbnail_url'] = $uploadedFile->IconTag();
} }
// check if our new record has a Title, if not create one automatically // check if our new record has a Title, if not create one automatically
@ -173,8 +189,10 @@ class GridFieldBulkUpload_Request extends RequestHandler
* Used by select dialog. * Used by select dialog.
* *
* @link UploadField->getRelationAutosetClass() * @link UploadField->getRelationAutosetClass()
* @param string $default
* @return string
*/ */
public function getRelationAutosetClass($default = 'File') public function getRelationAutosetClass($default = 'SilverStripe\\Assets\\File')
{ {
$uploadField = $this->getUploadField(); $uploadField = $this->getUploadField();
@ -186,6 +204,7 @@ class GridFieldBulkUpload_Request extends RequestHandler
* Used by select dialog. * Used by select dialog.
* *
* @link UploadField->getAllowedMaxFileNumber() * @link UploadField->getAllowedMaxFileNumber()
* @return int|null
*/ */
public function getAllowedMaxFileNumber() public function getAllowedMaxFileNumber()
{ {
@ -198,11 +217,11 @@ class GridFieldBulkUpload_Request extends RequestHandler
* Retrieve Files to be attached * Retrieve Files to be attached
* and generated DataObjects for each one. * and generated DataObjects for each one.
* *
* @param SS_HTTPRequest $request * @param HTTPRequest $request
* *
* @return SS_HTTPResponse * @return HTTPResponse
*/ */
public function attach(SS_HTTPRequest $request) public function attach(HTTPRequest $request)
{ {
$uploadField = $this->getUploadField(); $uploadField = $this->getUploadField();
$attachResponses = $uploadField->attach($request); $attachResponses = $uploadField->attach($request);
@ -231,7 +250,7 @@ class GridFieldBulkUpload_Request extends RequestHandler
array_push($return, $responseData); array_push($return, $responseData);
} }
$response = new SS_HTTPResponse(Convert::raw2json($return)); $response = new HTTPResponse(Convert::raw2json($return));
$this->contentTypeNegotiation($response); $this->contentTypeNegotiation($response);
return $response; return $response;
@ -242,7 +261,7 @@ class GridFieldBulkUpload_Request extends RequestHandler
* *
* @link UploadField->select() * @link UploadField->select()
*/ */
public function select(SS_HTTPRequest $request) public function select(HTTPRequest $request)
{ {
$uploadField = $this->getUploadField(); $uploadField = $this->getUploadField();
@ -256,7 +275,7 @@ class GridFieldBulkUpload_Request extends RequestHandler
* *
* @link UploadField->fileexists() * @link UploadField->fileexists()
*/ */
public function fileexists(SS_HTTPRequest $request) public function fileexists(HTTPRequest $request)
{ {
$uploadField = $this->getUploadField(); $uploadField = $this->getUploadField();
@ -278,11 +297,15 @@ class GridFieldBulkUpload_Request extends RequestHandler
* e.g. IE needs text/plain for iframe transport * e.g. IE needs text/plain for iframe transport
* https://github.com/blueimp/jQuery-File-Upload/issues/1795. * https://github.com/blueimp/jQuery-File-Upload/issues/1795.
* *
* @param SS_HTTPResponse $response HTTP Response to set content-type on * @param HTTPResponse $response HTTP Response to set content-type on
*/ */
protected function contentTypeNegotiation(&$response) protected function contentTypeNegotiation(&$response)
{ {
if (isset($_SERVER['HTTP_ACCEPT']) && ((strpos($_SERVER['HTTP_ACCEPT'], 'application/json') !== false) || $_SERVER['HTTP_ACCEPT'] === '*/*')) { if (isset($_SERVER['HTTP_ACCEPT'])
&& ((strpos($_SERVER['HTTP_ACCEPT'], 'application/json') !== false)
|| $_SERVER['HTTP_ACCEPT'] === '*/*'
)
) {
$response->addHeader('Content-Type', 'application/json'); $response->addHeader('Content-Type', 'application/json');
} else { } else {
$response->addHeader('Content-Type', 'text/plain'); $response->addHeader('Content-Type', 'text/plain');

View File

@ -1,24 +1,33 @@
<?php <?php
namespace Colymba\BulkUpload;
use Colymba\BulkUpload\BulkUploader;
use SilverStripe\Dev\Deprecation;
/** /**
* Legacy GridFieldBulkImageUpload component. * Legacy GridFieldBulkImageUpload component.
* *
* @deprecated 2.0 "GridFieldBulkImageUpload" is deprecated, use {@link GridFieldBulkUpload} class instead. * @deprecated 2.0 "GridFieldBulkImageUpload" is deprecated, use {@link BulkUploader} class instead.
* *
* @author colymba * @author colymba
*/ */
class GridFieldBulkImageUpload extends GridFieldBulkUpload class GridFieldBulkImageUpload extends BulkUploader
{ {
/** /**
* Component constructor. * Component constructor.
* *
* @deprecated 2.0 "GridFieldBulkImageUpload" is deprecated, use {@link GridFieldBulkUpload} class instead. * @deprecated 2.0 "GridFieldBulkImageUpload" is deprecated, use {@link BulkUploader} class instead.
* *
* @param string $fileRelationName * @param string $fileRelationName
*/ */
public function __construct($fileRelationName = null) public function __construct($fileRelationName = null)
{ {
Deprecation::notice('2.0', '"GridFieldBulkImageUpload" is deprecated, use "GridFieldBulkUpload" class instead.'); Deprecation::notice(
'2.0',
'"GridFieldBulkImageUpload" is deprecated, use "BulkUploader" class instead.'
);
return new GridFieldBulkUpload($fileRelationName); return new BulkUploader($fileRelationName);
} }
} }

View File

@ -5,18 +5,28 @@
"homepage": "https://github.com/colymba/GridFieldBulkEditingTools", "homepage": "https://github.com/colymba/GridFieldBulkEditingTools",
"keywords": ["silverstripe", "bulk upload", "image upload", "gridfield bulk upload"], "keywords": ["silverstripe", "bulk upload", "image upload", "gridfield bulk upload"],
"license": "BSD Simplified", "license": "BSD Simplified",
"authors": [{ "authors": [
{
"name": "Thierry Francois", "name": "Thierry Francois",
"homepage": "http://colymba.com" "homepage": "http://colymba.com"
},{ },
{
"name": "GitHub contributors", "name": "GitHub contributors",
"homepage": "https://github.com/colymba/GridFieldBulkEditingTools/contributors" "homepage": "https://github.com/colymba/GridFieldBulkEditingTools/contributors"
}], }
"repositories": [{ ],
"type": "vcs",
"url": "git@github.com:colymba/GridFieldBulkEditingTools.git"
}],
"require": { "require": {
"silverstripe/framework": ">=3.1" "silverstripe/framework": "^4.0@dev"
},
"extra": {
"branch-alias": {
"dev-master": "3.x-dev"
}
},
"autoload": {
"psr-4": {
"Colymba\\BulkManager\\": "bulkManager/code/",
"Colymba\\BulkUpload\\": "bulkUpload/code/"
}
} }
} }