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)
[![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)
@ -16,37 +16,47 @@ Set of SilverStripe 3 GridField components to facilitate bulk file upload & reco
[More screenshots here.](screenshots)
## 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))
## Installation
### Composer
* `composer require "colymba/gridfield-bulk-editing-tools:*"`
* `composer require colymba/gridfield-bulk-editing-tools`
### Manual
* 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
Major depractions in latest 2.0.0 release:
Major deprections in latest 2.0.0 release:
* The `GridFieldBulkImageUpload` has been renamed to `GridFieldBulkUpload`.
* `onBulkImageUpload` callback has been renamed to `onBulkUpload`
## Bulk Upload
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.
## Bulk Manager
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.
## 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
* Add individual actions for each upload (update + cancel)

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
Simply add component to your `GridFieldConfig`
$config->addComponent(new GridFieldBulkManager());
```php
$config->addComponent(new \Colymba\BulkManager\BulkManager());
```
## Configuration
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
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
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:
* `'GridFieldBulkAction'.ucfirst($name).'Handler'`
* `$config = array( 'isAjax' => true, 'icon' => 'accept', 'isDestructive' => false )`
#### 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
The last `addBulkAction()` parameter lets you pass an array with configuration options for the UI/UX:

View File

@ -1,10 +1,18 @@
<?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.
*
* @author colymba
*/
class GridFieldBulkActionDeleteHandler extends GridFieldBulkActionHandler
class DeleteHandler extends Handler
{
/**
* RequestHandler allowed actions.
@ -25,11 +33,11 @@ class GridFieldBulkActionDeleteHandler extends GridFieldBulkActionHandler
/**
* 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();
@ -38,7 +46,7 @@ class GridFieldBulkActionDeleteHandler extends GridFieldBulkActionHandler
$record->delete();
}
$response = new SS_HTTPResponse(Convert::raw2json(array(
$response = new HTTPResponse(Convert::raw2json(array(
'done' => true,
'records' => $ids,
)));

View File

@ -1,10 +1,25 @@
<?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.
*
* @author colymba
*/
class GridFieldBulkActionEditHandler extends GridFieldBulkActionHandler
class EditHandler extends Handler
{
/**
* RequestHandler allowed actions.
@ -58,7 +73,7 @@ class GridFieldBulkActionEditHandler extends GridFieldBulkActionHandler
$actions->push(
FormAction::create('doSave', _t('GRIDFIELD_BULKMANAGER_EDIT_HANDLER.SAVE_BTN_LABEL', 'Save all'))
->setAttribute('id', 'bulkEditingSaveBtn')
->addExtraClass('ss-ui-action-constructive')
->addExtraClass('btn btn-success')
->setAttribute('data-icon', 'accept')
->setUseButtonTag(true)
);
@ -66,7 +81,7 @@ class GridFieldBulkActionEditHandler extends GridFieldBulkActionHandler
$actions->push(
FormAction::create('Cancel', _t('GRIDFIELD_BULKMANAGER_EDIT_HANDLER.CANCEL_BTN_LABEL', 'Cancel'))
->setAttribute('id', 'bulkEditingUpdateCancelBtn')
->addExtraClass('ss-ui-action-destructive cms-panel-link')
->addExtraClass('btn btn-danger cms-panel-link')
->setAttribute('data-icon', 'decline')
->setAttribute('href', $one_level_up->Link)
->setUseButtonTag(true)
@ -83,7 +98,8 @@ class GridFieldBulkActionEditHandler extends GridFieldBulkActionHandler
$titleModelClass = (($editingCount > 1) ? $singleton->i18n_plural_name() : $singleton->i18n_singular_name());
//some cosmetics
$headerText = _t('GRIDFIELD_BULKMANAGER_EDIT_HANDLER.HEADER_TEXT',
$headerText = _t(
'GRIDFIELD_BULKMANAGER_EDIT_HANDLER.HEADER_TEXT',
'Editing {count} {class}',
array(
'count' => $editingCount,
@ -96,7 +112,10 @@ class GridFieldBulkActionEditHandler extends GridFieldBulkActionHandler
);
$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);
//fetch fields for each record and push to fieldList
@ -192,7 +211,8 @@ class GridFieldBulkActionEditHandler extends GridFieldBulkActionHandler
private function getRecordEditingFields(DataObject $record)
{
$tempForm = Form::create(
$this, 'TempEditForm',
$this,
'TempEditForm',
$record->getCMSFields(),
FieldList::create()
);
@ -210,7 +230,7 @@ class GridFieldBulkActionEditHandler extends GridFieldBulkActionHandler
* based on component's config
* 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 int $id Record's ID, used fir unique name
@ -285,7 +305,10 @@ class GridFieldBulkActionEditHandler extends GridFieldBulkActionHandler
public function index()
{
$form = $this->bulkEditForm();
$form->setTemplate('LeftAndMain_EditForm');
$form->setTemplate([
'type' => 'Includes',
'SilverStripe\\Admin\\LeftAndMain_EditForm',
]);
$form->addExtraClass('center cms-content');
$form->setAttribute('data-pjax-fragment', 'CurrentForm Content');
@ -294,7 +317,7 @@ class GridFieldBulkActionEditHandler extends GridFieldBulkActionHandler
Requirements::add_i18n_javascript(BULKEDITTOOLS_PATH . '/lang/js');
if ($this->request->isAjax()) {
$response = new SS_HTTPResponse(
$response = new HTTPResponse(
Convert::raw2json(array('Content' => $form->forAjaxTemplate()->getValue()))
);
$response->addHeader('X-Pjax', 'Content');
@ -340,7 +363,8 @@ class GridFieldBulkActionEditHandler extends GridFieldBulkActionHandler
foreach ($formsData as $recordID => $recordData) {
$record = DataObject::get_by_id($className, $recordID);
$recordForm = Form::create(
$this, 'RecordForm',
$this,
'RecordForm',
$record->getCMSFields(),
FieldList::create()
);
@ -358,7 +382,8 @@ class GridFieldBulkActionEditHandler extends GridFieldBulkActionHandler
//compose form message
$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.',
array(
'count' => $done,

View File

@ -1,4 +1,14 @@
<?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
* Gives access to the GridField, Component and Controller
@ -6,7 +16,7 @@
*
* @author colymba
*/
class GridFieldBulkActionHandler extends RequestHandler
class Handler extends RequestHandler
{
/**
* Related GridField instance.
@ -30,7 +40,7 @@ class GridFieldBulkActionHandler extends RequestHandler
protected $controller;
/**
* @param GridFIeld $gridField
* @param GridField $gridField
* @param GridField_URLHandler $component
* @param Controller $controller
*/

View File

@ -1,10 +1,18 @@
<?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.
*
* @author colymba
*/
class GridFieldBulkActionUnlinkHandler extends GridFieldBulkActionHandler
class UnlinkHandler extends Handler
{
/**
* RequestHandler allowed actions.
@ -25,16 +33,16 @@ class GridFieldBulkActionUnlinkHandler extends GridFieldBulkActionHandler
/**
* 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();
$this->gridField->list->removeMany($ids);
$response = new SS_HTTPResponse(Convert::raw2json(array(
$response = new HTTPResponse(Convert::raw2json(array(
'done' => true,
'records' => $ids,
)));

View File

@ -1,10 +1,25 @@
<?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.
*
* @author colymba
*/
class GridFieldBulkManager implements GridField_HTMLProvider, GridField_ColumnProvider, GridField_URLHandler
class BulkManager implements GridField_HTMLProvider, GridField_ColumnProvider, GridField_URLHandler
{
/**
* component configuration.
@ -35,7 +50,7 @@ class GridFieldBulkManager implements GridField_HTMLProvider, GridField_ColumnPr
$this->config['actions'] = array(
'bulkEdit' => array(
'label' => _t('GRIDFIELD_BULK_MANAGER.EDIT_SELECT_LABEL', 'Edit'),
'handler' => 'GridFieldBulkActionEditHandler',
'handler' => 'Colymba\\BulkManager\\BulkAction\\EditHandler',
'config' => array(
'isAjax' => false,
'icon' => 'pencil',
@ -44,7 +59,7 @@ class GridFieldBulkManager implements GridField_HTMLProvider, GridField_ColumnPr
),
'unLink' => array(
'label' => _t('GRIDFIELD_BULK_MANAGER.UNLINK_SELECT_LABEL', 'UnLink'),
'handler' => 'GridFieldBulkActionUnlinkHandler',
'handler' => 'Colymba\\BulkManager\\BulkAction\\UnlinkHandler',
'config' => array(
'isAjax' => true,
'icon' => 'chain--minus',
@ -53,13 +68,13 @@ class GridFieldBulkManager implements GridField_HTMLProvider, GridField_ColumnPr
),
'delete' => array(
'label' => _t('GRIDFIELD_BULK_MANAGER.DELETE_SELECT_LABEL', 'Delete'),
'handler' => 'GridFieldBulkActionDeleteHandler',
'handler' => 'Colymba\\BulkManager\\BulkAction\\DeleteHandler',
'config' => array(
'isAjax' => true,
'icon' => 'decline',
'isDestructive' => true,
),
),
)
);
}
}
@ -132,7 +147,7 @@ class GridFieldBulkManager implements GridField_HTMLProvider, GridField_ColumnPr
}
if (!$handler) {
$handler = 'GridFieldBulkAction'.ucfirst($name).'Handler';
$handler = 'Colymba\\BulkManager\\BulkAction\\' . ucfirst($name) . 'Handler';
}
if (!ClassInfo::exists($handler)) {
@ -284,16 +299,16 @@ class GridFieldBulkManager implements GridField_HTMLProvider, GridField_ColumnPr
$dropDownActionsList = DropdownField::create('bulkActionName', '')
->setSource($actionsListSource)
->setAttribute('class', 'bulkActionName no-change-track')
->addExtraClass('bulkActionName no-change-track no-chosen')
->setAttribute('id', '');
$templateData = array(
'Menu' => $dropDownActionsList->FieldHolder(),
'Menu' => $dropDownActionsList,
'Button' => array(
'Label' => _t('GRIDFIELD_BULK_MANAGER.ACTION_BTN_LABEL', 'Go'),
'DataURL' => $gridField->Link('bulkAction'),
'Icon' => $this->config['actions'][$firstAction]['config']['icon'],
'DataConfig' => htmlspecialchars(json_encode($actionsConfig), ENT_QUOTES, 'UTF-8'),
'DataConfig' => json_encode($actionsConfig),
),
'Select' => array(
'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
*
* @param GridField $gridField
* @param SS_HTTPRequest $request
* @param HTTPRequest $request
*
* @return mixed
*/
public function handleBulkAction($gridField, $request)
{
$controller = $gridField->getForm()->Controller();
$controller = $gridField->getForm()->getController();
foreach ($this->config['actions'] as $name => $data) {
$handlerClass = $data['handler'];

View File

@ -31,12 +31,14 @@
text-shadow: none; }
.bulkEditingFieldHolder.updated .ui-accordion-header {
background-color: #a4ca3a;
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: -moz-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: linear-gradient(top, #a4ca3a 0%, #59781d 100%); }
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: -moz-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: linear-gradient(top, #a4ca3a 0%, #59781D 100%); }
.bulkEditingFieldHolder.updated .ui-accordion-header a {
color: #fff;
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; }
.cms table.ss-gridfield-table tr.bulkManagerOptions th.bulkmanagerselect input {
.cms table.grid-field__table tr.bulkManagerOptions th.bulkmanagerselect input {
margin-left: 0; }
.cms table.ss-gridfield-table tr.bulkManagerOptions .title {
.cms table.grid-field__table tr.bulkManagerOptions .title {
margin: 0 0 2px 2px; }
.cms table.ss-gridfield-table tr.bulkManagerOptions .dropdown {
.cms table.grid-field__table tr.bulkManagerOptions .dropdown {
display: inline-block;
border: none;
box-shadow: none;
@ -12,17 +14,17 @@
margin: 0;
color: #000;
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; }
.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; }
.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; }
.cms table.ss-gridfield-table tbody .col-bulkSelect {
.cms table.grid-field__table tbody .col-bulkSelect {
width: 25px;
padding: 0 10px;
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;
display: inline-block;
width: 20px;
@ -32,3 +34,5 @@
vertical-align: middle;
background-position: 2px 0px;
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
{
th.bulkmanagerheading {
padding-left: 40px;
}
th.bulkmanagerselect
{
text-align: center;

View File

@ -69,7 +69,7 @@
onunmatch: function(){
},
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()
{
var state = $(this).prop('checked');
$(this).parents('.ss-gridfield-table')
$(this).parents('.grid-field__table')
.find('td.col-bulkSelect input')
.prop('checked', state)
.trigger('change');
},
getSelectRecordsID: function()
{
return $(this).parents('.ss-gridfield-table')
return $(this).parents('.grid-field__table')
.find('td.col-bulkSelect input:checked')
.map(function() {
return parseInt( $(this).data('record') )

View File

@ -1,15 +1,25 @@
<tr class="bulkManagerOptions">
<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>
</div>
<div class="row">
<div class="form-inline">
$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
</a>
</th>
<th class="main bulkmanagerselect">
<input class="no-change-track bulkSelectAll" type="checkbox" title="$Select.Label" name="toggleSelectAll" />
<label class="form-check-label">
<input class="no-change-track bulkSelectAll form-check-input"
type="checkbox"
title="$Select.Label"
name="toggleSelectAll" />
<% _t('GRIDFIELD_BULK_MANAGER.SELECT_ALL_LABEL', '$Select.Label') %>
</label>
</div>
</div>
</th>
</tr>

View File

@ -4,20 +4,26 @@ A component for uploading images and/or files in bulk into `DataObject` managed
## 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`.
$config->addComponent(new GridFieldBulkUpload());
```php
$config->addComponent(new \Colymba\BulkUpload\BulkUploader());
```
## Usage 2
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')
$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
### Component configuration
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:
* '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:
$config->getComponentByType('GridFieldBulkUpload')
```php
$config->getComponentByType('Colymba\\BulkUpload\\BulkUploader')
->setUfSetup('setFolderName', 'myFolder')
->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.
## 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
namespace Colymba\BulkUpload;
use SilverStripe\Control\Controller;
use SilverStripe\Forms\UploadField;
/**
* Custom UploadField used to override Link()
* and redirect UploadField action properly through the GridField.
@ -7,13 +13,25 @@
*/
class BulkUploadField extends UploadField
{
/**
* @var 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;
parent::__construct($parent, $folderName);
}
/**
* {@inheritDoc}
*/
public function Link($action = null)
{
return Controller::join_links($this->gridfield->Link(), 'bulkupload/', $action);

View File

@ -1,10 +1,24 @@
<?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.
*
* @author colymba
*/
class GridFieldBulkUpload implements GridField_HTMLProvider, GridField_URLHandler
class BulkUploader implements GridField_HTMLProvider, GridField_URLHandler
{
/**
* Component configuration.
@ -24,7 +38,7 @@ class GridFieldBulkUpload implements GridField_HTMLProvider, GridField_URLHandle
* These options are passed on directly to the UploadField
* via {@link UploadField::setConfig()} api.
*
* Defaults are: *
* Defaults are:
* 'sequentialUploads' => false : process uploads 1 after the other rather than all at once
* 'canAttachExisting' => true : displays "From files" button 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.
*
* @param string $fileRelationName
* @param string $recordClassName
*/
public function __construct($fileRelationName = null, $recordClassName = null)
{
@ -92,7 +107,7 @@ class GridFieldBulkUpload implements GridField_HTMLProvider, GridField_URLHandle
public function setConfig($reference, $value)
{
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') {
$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
* i.e. 'MyImage' => 'Image' will return 'MyImage'.
*
* @param GridField $gridField
* @return string Name of the $has_one relation
*/
public function getDefaultFileRelationName($gridField)
@ -237,7 +253,10 @@ class GridFieldBulkUpload implements GridField_HTMLProvider, GridField_URLHandle
$imageField = null;
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;
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
* Either as set in the component config or the default one.
*
* @param GridField $gridField
* @return string
*/
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' => 'File' will return 'File'.
*
* @param GridField $gridField
* @return string file relation className
*/
public function getFileRelationClassName($gridField)
@ -275,7 +296,7 @@ class GridFieldBulkUpload implements GridField_HTMLProvider, GridField_URLHandle
if ($fieldName) {
return $hasOneFields[$fieldName];
} 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)
->setTemplate('GridFieldBulkUploadField')
->setTemplate('BulkUploadField')
->setDownloadTemplateName('colymba-bulkuploaddownloadtemplate')
->setConfig('url', $gridField->Link('bulkupload/upload'))
@ -345,7 +366,7 @@ class GridFieldBulkUpload implements GridField_HTMLProvider, GridField_URLHandle
}
// check BulkManager exists
$bulkManager = $gridField->getConfig()->getComponentsByType('GridFieldBulkManager');
$bulkManager = $gridField->getConfig()->getComponentsByType('Colymba\\BulkManager\\BulkManager');
// upload management buttons
$finishButton = FormAction::create('Finish', _t('GRIDFIELD_BULK_UPLOAD.FINISH_BTN_LABEL', 'Finish'))
@ -399,7 +420,7 @@ class GridFieldBulkUpload implements GridField_HTMLProvider, GridField_URLHandle
Requirements::add_i18n_javascript(BULKEDITTOOLS_PATH . '/lang/js');
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.
*
* @param GridField $gridField
* @param SS_HTTPRequest $request
* @param HTTPRequest $request
*
* @return mixed
*/
public function handleBulkUpload($gridField, $request)
{
$controller = $gridField->getForm()->Controller();
$handler = new GridFieldBulkUpload_Request($gridField, $this, $controller);
$controller = $gridField->getForm()->getController();
$handler = new BulkUploaderRequest($gridField, $this, $controller);
return $handler->handleRequest($request, DataModel::inst());
}

View File

@ -1,10 +1,23 @@
<?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.
*
* @author colymba
*/
class GridFieldBulkUpload_Request extends RequestHandler
class BulkUploaderRequest extends RequestHandler
{
/**
* Gridfield instance.
@ -16,7 +29,7 @@ class GridFieldBulkUpload_Request extends RequestHandler
/**
* Bulk upload component.
*
* @var GridFieldBulkUpload
* @var BulkUploader
*/
protected $component;
@ -48,7 +61,7 @@ class GridFieldBulkUpload_Request extends RequestHandler
/**
* Handler's constructor.
*
* @param GridFIeld $gridField
* @param GridField $gridField
* @param GridField_URLHandler $component
* @param Controller $controller
*/
@ -76,11 +89,11 @@ class GridFieldBulkUpload_Request extends RequestHandler
* adds record to GrifField relation list
* and return image/file data and record edit form.
*
* @param SS_HTTPRequest $request
* @param HTTPRequest $request
*
* @return string json
*/
public function upload(SS_HTTPRequest $request)
public function upload(HTTPRequest $request)
{
//create record
$recordClass = $this->component->getRecordClassName($this->gridField);
@ -114,7 +127,7 @@ class GridFieldBulkUpload_Request extends RequestHandler
// JS Template Data
$responseData = $this->newRecordJSTemplateData($record, $uploadResponse);
$response = new SS_HTTPResponse(Convert::raw2json(array($responseData)));
$response = new HTTPResponse(Convert::raw2json(array($responseData)));
$this->contentTypeNegotiation($response);
return $response;
@ -133,16 +146,19 @@ class GridFieldBulkUpload_Request extends RequestHandler
{
// fetch uploadedFile record and sort out previewURL
// 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) {
$uploadResponse['name'] = $uploadedFile->Name;
$uploadResponse['url'] = $uploadedFile->getURL();
if ($uploadedFile instanceof Image) {
$uploadResponse['thumbnail_url'] = $uploadedFile->CroppedImage(30, 30)->getURL();
$uploadResponse['thumbnail_url'] = $uploadedFile->Fill(30, 30)->getURL();
} else {
$uploadResponse['thumbnail_url'] = $uploadedFile->Icon();
$uploadResponse['thumbnail_url'] = $uploadedFile->IconTag();
}
// 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.
*
* @link UploadField->getRelationAutosetClass()
* @param string $default
* @return string
*/
public function getRelationAutosetClass($default = 'File')
public function getRelationAutosetClass($default = 'SilverStripe\\Assets\\File')
{
$uploadField = $this->getUploadField();
@ -186,6 +204,7 @@ class GridFieldBulkUpload_Request extends RequestHandler
* Used by select dialog.
*
* @link UploadField->getAllowedMaxFileNumber()
* @return int|null
*/
public function getAllowedMaxFileNumber()
{
@ -198,11 +217,11 @@ class GridFieldBulkUpload_Request extends RequestHandler
* Retrieve Files to be attached
* 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();
$attachResponses = $uploadField->attach($request);
@ -231,7 +250,7 @@ class GridFieldBulkUpload_Request extends RequestHandler
array_push($return, $responseData);
}
$response = new SS_HTTPResponse(Convert::raw2json($return));
$response = new HTTPResponse(Convert::raw2json($return));
$this->contentTypeNegotiation($response);
return $response;
@ -242,7 +261,7 @@ class GridFieldBulkUpload_Request extends RequestHandler
*
* @link UploadField->select()
*/
public function select(SS_HTTPRequest $request)
public function select(HTTPRequest $request)
{
$uploadField = $this->getUploadField();
@ -256,7 +275,7 @@ class GridFieldBulkUpload_Request extends RequestHandler
*
* @link UploadField->fileexists()
*/
public function fileexists(SS_HTTPRequest $request)
public function fileexists(HTTPRequest $request)
{
$uploadField = $this->getUploadField();
@ -278,11 +297,15 @@ class GridFieldBulkUpload_Request extends RequestHandler
* e.g. IE needs text/plain for iframe transport
* 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)
{
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');
} else {
$response->addHeader('Content-Type', 'text/plain');

View File

@ -1,24 +1,33 @@
<?php
namespace Colymba\BulkUpload;
use Colymba\BulkUpload\BulkUploader;
use SilverStripe\Dev\Deprecation;
/**
* 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
*/
class GridFieldBulkImageUpload extends GridFieldBulkUpload
class GridFieldBulkImageUpload extends BulkUploader
{
/**
* 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
*/
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",
"keywords": ["silverstripe", "bulk upload", "image upload", "gridfield bulk upload"],
"license": "BSD Simplified",
"authors": [{
"authors": [
{
"name": "Thierry Francois",
"homepage": "http://colymba.com"
},{
},
{
"name": "GitHub contributors",
"homepage": "https://github.com/colymba/GridFieldBulkEditingTools/contributors"
}],
"repositories": [{
"type": "vcs",
"url": "git@github.com:colymba/GridFieldBulkEditingTools.git"
}],
}
],
"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/"
}
}
}