Merge branch '3.0'

This commit is contained in:
Thierry François 2018-02-24 12:07:57 +02:00
commit 8bf9b620b0
58 changed files with 966 additions and 832 deletions

8
.gitignore vendored
View File

@ -1,3 +1,9 @@
# General
.DS_Store
.AppleDouble
.LSOverride
transifexAuth.json
**/css/bourbon
**/.sass-cache
**/.sass-cache
node_modules/

29
LICENSE Normal file
View File

@ -0,0 +1,29 @@
BSD 3-Clause License
Copyright (c) 2018, Thierry François (colymba)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -3,7 +3,7 @@ GridField Bulk Editing Tools
[![Latest Stable Version](https://poser.pugx.org/colymba/gridfield-bulk-editing-tools/v/stable.svg)](https://github.com/colymba/GridFieldBulkEditingTools/releases)
[![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-and-copyright)
Set of SilverStripe 4 GridField components to facilitate bulk file upload & record editing.
@ -16,7 +16,7 @@ Set of SilverStripe 4 GridField components to facilitate bulk file upload & reco
[More screenshots here.](screenshots)
## Requirements
* SilverStripe 4.0 (version master / 3.+)
* SilverStripe 4.0 (3.+)
* SilverStripe 3.1 (version 2.+ / 1.+)
* Silverstripe 3.0 (version [0.5](https://github.com/colymba/GridFieldBulkEditingTools/tree/0.5))
@ -44,7 +44,7 @@ Upload multiple images or files at once into DataObjects. Perfect for galleries
$config->addComponent(new \Colymba\BulkUpload\BulkUploader());
```
See [BULK_UPLOAD.md](bulkUpload/BULK_UPLOAD.md) for detailed configuration.
See [BULK_UPLOAD.md](docs/en/BULK_UPLOAD.md) for detailed configuration.
## Bulk Manager
Perform actions on multiple records straight from the GridField
@ -53,14 +53,11 @@ Perform actions on multiple records straight from the GridField
$config->addComponent(new \Colymba\BulkManager\BulkManager());
```
See [BULK_MANAGER.md](bulkManager/BULK_MANAGER.md) for detailed configuration.
See [BULK_MANAGER.md](docs/en//BULK_MANAGER.md) for detailed configuration.
## Interdependencies
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)
* Handle and display errors better for: creation, update, cancel
## Translations
@ -68,16 +65,6 @@ Translations of the natural language strings are managed through a third party t
Please use [https://www.transifex.com/projects/p/gridfieldbulkeditingtools/](https://www.transifex.com/projects/p/gridfieldbulkeditingtools/) to contribute translations, rather than sending pull requests with YAML/JS files.
## License (BSD Simplified)
## License and Copyright
Copyright (c) 2013, Thierry Francois (colymba)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of Thierry Francois, colymba nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[BSD 3-clause license](LICENSE)

View File

@ -1,57 +0,0 @@
<?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 DeleteHandler extends Handler
{
/**
* RequestHandler allowed actions.
*
* @var array
*/
private static $allowed_actions = array('delete');
/**
* RequestHandler url => action map.
*
* @var array
*/
private static $url_handlers = array(
'delete' => 'delete',
);
/**
* Delete the selected records passed from the delete bulk action.
*
* @param HTTPRequest $request
*
* @return HTTPResponse List of deleted records ID
*/
public function delete(HTTPRequest $request)
{
$ids = array();
foreach ($this->getRecords() as $record) {
array_push($ids, $record->ID);
$record->delete();
}
$response = new HTTPResponse(Convert::raw2json(array(
'done' => true,
'records' => $ids,
)));
$response->addHeader('Content-Type', 'text/json');
return $response;
}
}

View File

@ -1,148 +0,0 @@
<?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
* and implements useful functions like {@link getRecordIDList()} and {@link getRecords()}.
*
* @author colymba
*/
class Handler extends RequestHandler
{
/**
* Related GridField instance.
*
* @var GridField
*/
protected $gridField;
/**
* GridFieldBulkManager instance.
*
* @var GridFieldBulkManager
*/
protected $component;
/**
* Current controller instance.
*
* @var Controller
*/
protected $controller;
/**
* @param GridField $gridField
* @param GridField_URLHandler $component
* @param Controller $controller
*/
public function __construct($gridField, $component, $controller)
{
$this->gridField = $gridField;
$this->component = $component;
$this->controller = $controller;
parent::__construct();
}
/**
* Returns the URL for this RequestHandler.
*
* @author SilverStripe
*
* @see GridFieldDetailForm_ItemRequest
*
* @param string $action
*
* @return string
*/
public function Link($action = null)
{
return Controller::join_links($this->gridField->Link(), 'bulkAction', $action);
}
/**
* Traverse up nested requests until we reach the first that's not a GridFieldDetailForm or GridFieldDetailForm_ItemRequest.
* The opposite of {@link Controller::curr()}, required because
* Controller::$controller_stack is not directly accessible.
*
* @return Controller
*/
protected function getToplevelController()
{
$c = $this->controller;
while ($c && ($c instanceof GridFieldDetailForm_ItemRequest || $c instanceof GridFieldDetailForm)) {
$c = $c->getController();
}
return $c;
}
/**
* Edited version of the GridFieldEditForm function
* adds the 'Bulk Upload' at the end of the crums.
*
* CMS-specific functionality: Passes through navigation breadcrumbs
* to the template, and includes the currently edited record (if any).
* see {@link LeftAndMain->Breadcrumbs()} for details.
*
* @author SilverStripe original Breadcrumbs() method
*
* @see GridFieldDetailForm_ItemRequest
*
* @param bool $unlinked
*
* @return ArrayData
*/
public function Breadcrumbs($unlinked = false)
{
if (!$this->controller->hasMethod('Breadcrumbs')) {
return;
}
$items = $this->controller->Breadcrumbs($unlinked);
$items->push(new ArrayData(array(
'Title' => 'Bulk Editing',
'Link' => false,
)));
return $items;
}
/**
* Returns the list of record IDs selected in the front-end.
*
* @return array List of IDs
*/
public function getRecordIDList()
{
$vars = $this->request->requestVars();
return $vars['records'];
}
/**
* Returns a DataList of the records selected in the front-end.
*
* @return DataList List of records
*/
public function getRecords()
{
$ids = $this->getRecordIDList();
if ($ids) {
$class = $this->gridField->list->dataClass;
return DataList::create($class)->byIDs($ids);
} else {
return false;
}
}
}

View File

@ -1,53 +0,0 @@
<?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 UnlinkHandler extends Handler
{
/**
* RequestHandler allowed actions.
*
* @var array
*/
private static $allowed_actions = array('unLink');
/**
* RequestHandler url => action map.
*
* @var array
*/
private static $url_handlers = array(
'unLink' => 'unLink',
);
/**
* Unlink the selected records passed from the unlink bulk action.
*
* @param HTTPRequest $request
*
* @return HTTPResponse List of affected records ID
*/
public function unLink(HTTPRequest $request)
{
$ids = $this->getRecordIDList();
$this->gridField->list->removeMany($ids);
$response = new HTTPResponse(Convert::raw2json(array(
'done' => true,
'records' => $ids,
)));
$response->addHeader('Content-Type', 'text/json');
return $response;
}
}

View File

@ -1,44 +0,0 @@
#bulkEditHeader {
float: left;
width: 70%;
margin: 40px 0 20px 0;
font-size: 30px;
font-weight: bold; }
#bulkEditToggle {
float: right;
clear: right;
width: 25%;
margin: 40px 0 20px 0;
text-decoration: underline;
text-align: right;
cursor: pointer; }
.bulkEditingFieldHolder {
position: relative;
float: left;
width: 100%; }
.bulkEditingFieldHolder.hasUpdate .ui-accordion-header {
background-color: #f2ba11;
background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #f2ba11), color-stop(100%, #df6e00));
background-image: -webkit-linear-gradient(top, #f2ba11 0%, #df6e00 100%);
background-image: -moz-linear-gradient(top, #f2ba11 0%, #df6e00 100%);
background-image: -o-linear-gradient(top, #f2ba11 0%, #df6e00 100%);
background-image: -ms-linear-gradient(top, #f2ba11 0%, #df6e00 100%);
background-image: linear-gradient(top, #f2ba11 0%, #df6e00 100%); }
.bulkEditingFieldHolder.hasUpdate .ui-accordion-header a {
color: #fff;
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%); }
.bulkEditingFieldHolder.updated .ui-accordion-header a {
color: #fff;
text-shadow: none; }
/*# sourceMappingURL=GridFieldBulkEditingForm.css.map */

View File

@ -1,7 +0,0 @@
{
"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,37 +0,0 @@
.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.grid-field__table tr.bulkManagerOptions th.bulkmanagerselect input {
margin-left: 0; }
.cms table.grid-field__table tr.bulkManagerOptions .title {
margin: 0 0 2px 2px; }
.cms table.grid-field__table tr.bulkManagerOptions .dropdown {
display: inline-block;
border: none;
box-shadow: none;
padding: 0;
margin: 0;
color: #000;
vertical-align: top; }
.cms table.grid-field__table tr.bulkManagerOptions .doBulkActionButton .ui-button-text {
padding: 6px 0 5px 2.1em; }
.cms table.grid-field__table tr.bulkManagerOptions .doBulkActionButton .ui-button-text .ui-button-text {
padding: 0; }
.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.grid-field__table tbody .col-bulkSelect {
width: 25px;
text-align: center; }
.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;
height: 20px;
text-indent: 119988px;
overflow: hidden;
vertical-align: middle;
background-position: 2px 0px;
background-repeat: no-repeat no-repeat; }
/*# sourceMappingURL=GridFieldBulkManager.css.map */

View File

@ -1,7 +0,0 @@
{
"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"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

View File

@ -1,153 +0,0 @@
.bulkUpload {
padding: 0 !important;
border-bottom: 1px solid rgba(0, 0, 0, 0.1); }
.bulkUpload:hover {
background-color: #444546; }
.bulkUpload .component {
padding: 0 !important;
color: #fff;
background: #98aab6;
border-top: 1px solid #a4b4bf;
border-left: 1px solid #a4b4bf;
border-bottom: 1px solid rgba(0, 0, 0, 0.1); }
.bulkUpload .component div.ss-uploadfield {
position: relative;
float: left;
clear: both;
width: 100%; }
.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files {
float: left;
clear: both;
width: 100%; }
.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item {
position: relative;
float: left;
clear: both;
overflow: hidden;
width: 98%;
padding: 5px 1% 5px 1%;
border: none;
border-top: 1px solid rgba(0, 0, 0, 0.1);
background-color: #eceff1; }
.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item:nth-child(2n-1) {
background-color: #e6eaed; }
.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item .ss-uploadfield-item-preview {
width: 30px;
height: 30px;
line-height: 38px; }
.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item .ss-uploadfield-item-info {
height: 30px;
margin-left: 40px;
line-height: 30px; }
.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item .ss-uploadfield-item-info .ss-uploadfield-item-name {
position: absolute;
top: 0;
left: 50px;
width: 100%;
height: 100%;
line-height: 40px; }
.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item .ss-uploadfield-item-info .ss-uploadfield-item-name .name {
color: #343434; }
.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item .ss-uploadfield-item-info .ss-uploadfield-item-name .size {
font-weight: normal; }
.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item .ss-uploadfield-item-info .ss-uploadfield-item-name .ss-uploadfield-item-status {
float: left;
width: auto;
padding: 0 0 0 5px;
text-align: left;
max-width: none; }
.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item .ss-uploadfield-item-info .ss-uploadfield-item-name .ss-uploadfield-item-status.ui-state-warning-text {
color: #f29500; }
.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item .ss-uploadfield-item-info .ss-uploadfield-item-name .ss-uploadfield-item-status.ui-state-success-text {
color: #298530; }
.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item .ss-uploadfield-item-info .ss-uploadfield-item-actions {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 30px;
margin: 0;
padding: 5px 0 5px 0; }
.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item .ss-uploadfield-item-info .ss-uploadfield-item-actions .ss-uploadfield-item-progress {
left: 50px;
right: 35px;
margin-top: 8px; }
.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item .ss-uploadfield-item-info .ss-uploadfield-item-actions button {
margin: 0 10px 0 0; }
.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item .ss-uploadfield-item-info .ss-uploadfield-item-actions button .ui-button-text {
padding-top: 4px;
padding-bottom: 3px; }
.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item .ss-uploadfield-item-info .ss-uploadfield-item-actions .ss-uploadfield-item-cancel {
position: relative;
top: 7px;
right: auto;
float: right; }
.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item .ss-uploadfield-item-info .ss-uploadfield-item-actions .ss-uploadfield-item-cancel button {
background: none; }
.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item .ss-uploadfield-item-info .ss-uploadfield-item-actions .ss-uploadfield-item-overwrite {
position: relative;
float: right;
margin-top: 2px; }
.bulkUpload .component div.ss-uploadfield .ss-uploadfield-addfile {
float: left;
clear: both;
width: 98%;
padding: 1%; }
.bulkUpload .component div.ss-uploadfield .ss-uploadfield-addfile.borderTop {
border: none; }
.bulkUpload .component div.ss-uploadfield .ss-uploadfield-addfile .ss-uploadfield-item-preview.ss-uploadfield-dropzone {
float: right;
width: 35%;
height: 43px;
margin: 0;
line-height: 43px;
color: #eee;
background-color: #8898a3;
border: 2px dashed #73818a;
box-shadow: #73818a 0 0 10px 0 inset; }
.bulkUpload .component div.ss-uploadfield .ss-uploadfield-addfile .ss-uploadfield-item-preview.ss-uploadfield-dropzone.hover {
color: #444546;
background-color: #eee; }
.bulkUpload .component div.ss-uploadfield .ss-uploadfield-addfile .ss-uploadfield-item-info {
float: left;
width: 60%;
margin: 0; }
.bulkUpload .component div.ss-uploadfield .ss-uploadfield-addfile .ss-uploadfield-item-info .ss-uploadfield-item-name {
height: auto;
margin-bottom: 5px !important; }
.bulkUpload .component div.ss-uploadfield .ss-uploadfield-addfile .ss-uploadfield-item-info .ss-uploadfield-item-name small {
font-weight: normal !important; }
.bulkUpload .component div.ss-uploadfield .ss-uploadfield-addfile .ss-uploadfield-item-info .ss-ui-button .ui-button-text .ui-button-text {
padding: 0px; }
.bulkUpload .component div.ss-uploadfield .ss-uploadfield-addfile .ss-uploadfield-item-info .ss-uploadfield-fromcomputer {
margin-bottom: 0; }
.bulkUpload .component div.ss-uploadfield .ss-uploadfield-addfile .ss-uploadfield-item-info .ss-uploadfield-fromfiles {
margin-bottom: 0;
padding: .5px; }
.bulkUpload .component div.ss-uploadfield .colymba-bulkupload-buttons {
display: none;
float: left;
width: 98%;
padding: 6px 1% 6px 1%;
background-color: #8898a3; }
.bulkUpload .component div.ss-uploadfield .colymba-bulkupload-buttons button {
float: left;
margin: 0 6px 0 0; }
.bulkUpload .component div.ss-uploadfield .colymba-bulkupload-buttons button .ui-button-text .ui-button-text {
padding: 0; }
.bulkUpload .component div.ss-uploadfield .colymba-bulkupload-buttons button.bulkUploadEditButton, .bulkUpload .component div.ss-uploadfield .colymba-bulkupload-buttons button.bulkUploadClearErrorButton {
float: right;
margin: 0 0 0 6px; }
.bulkUpload .component div.ss-uploadfield .colymba-bulkupload-buttons .colymba-bulkupload-info {
float: left;
margin: 0 6px 0 6px;
line-height: 28px;
height: 28px;
color: #ffffff;
background-image: url(../../images/spinner.gif);
background-position: 0 -50px;
background-repeat: no-repeat;
overflow: hidden; }
.bulkUpload .component div.ss-uploadfield .colymba-bulkupload-buttons.loading .colymba-bulkupload-info {
padding-left: 20px;
background-position: 0 5px; }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

1
client/dist/js/bulkTools.js vendored Normal file
View File

@ -0,0 +1 @@
!function(t){function e(i){if(n[i])return n[i].exports;var a=n[i]={i:i,l:!1,exports:{}};return t[i].call(a.exports,a,a.exports,e),a.l=!0,a.exports}var n={};e.m=t,e.c=n,e.d=function(t,n,i){e.o(t,n)||Object.defineProperty(t,n,{configurable:!1,enumerable:!0,get:i})},e.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(n,"a",n),n},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s=0)}([function(t,e,n){n(1),n(2),t.exports=n(3)},function(t,e){!function(t){t.entwine("ss",function(t){t.entwine("colymba",function(t){t(".bulkManagerOptions").entwine({onmatch:function(){var e=this.parents("thead"),n=e.find("tr"),i=[".filter-header",".sortable-header"],a=e.find(i.join(",")),s=n.index(this),o=n.length-1;a.each(function(t,e){var i=n.index(e);i<o&&(o=i)}),s>o&&n.eq(o).insertAfter(t(this))},onunmatch:function(){}}),t("td.col-bulkSelect").entwine({onmatch:function(){},onunmatch:function(){},onmouseover:function(){t(this).parents(".ss-gridfield-item").find(".edit-link").removeClass("edit-link").addClass("tempDisabledEditLink")},onmouseout:function(){t(this).parents(".ss-gridfield-item").find(".tempDisabledEditLink").addClass("edit-link").removeClass("tempDisabledEditLink")},onclick:function(e){var n=t(e.target).find("input");t(n).prop("checked")?t(n).prop("checked",!1):t(n).prop("checked",!0)}}),t("td.col-bulkSelect input").entwine({onmatch:function(){},onunmatch:function(){},onclick:function(e){t(this).parents(".grid-field__table").find("input.bulkSelectAll").prop("checked","")}}),t("input.bulkSelectAll").entwine({onmatch:function(){},onunmatch:function(){},onclick:function(){var e=t(this).prop("checked");t(this).parents(".grid-field__table").find("td.col-bulkSelect input").prop("checked",e).trigger("change")},getSelectRecordsID:function(){return t(this).parents(".grid-field__table").find("td.col-bulkSelect input:checked").map(function(){return parseInt(t(this).data("record"))}).get()}}),t("select.bulkActionName").entwine({onmatch:function(){},onunmatch:function(){},onchange:function(e){var n=t(this).val(),i=t(this).parents(".bulkManagerOptions"),a=i.find(".doBulkActionButton"),s=a.data("config");if(t.each(s,function(t,e){t!=n&&a.removeClass(e.buttonClasses)}),a.addClass(s[n].buttonClasses).addClass("btn-outline-secondary"),s[n].icon){var o=a.find("img");o.length?o.attr("src",s[n].icon):a.prepend('<img src="'+s[n].icon+'" alt="" />')}else a.find("img").remove();s[n].destructive?a.addClass("btn-outline-danger"):a.removeClass("btn-outline-danger")}}),t(".doBulkActionButton").entwine({onmatch:function(){},onunmatch:function(){},getActionURL:function(t,e){var n=(new Date).getTime();return e=e.split("?"),t=t?"/"+t:"",e=e[1]?e[0]+t+"?"+e[1]+"&cacheBuster="+n:e[0]+t+"?cacheBuster="+n},onclick:function(e){var n=t(this).parents(".bulkManagerOptions"),i=n.find("select.bulkActionName").val(),a=t(this).parents(".bulkManagerOptions").find("input.bulkSelectAll:first").getSelectRecordsID();this.doBulkAction(i,a)},doBulkAction:function(e,n,i,a){var s=t(this).parents(".bulkManagerOptions"),o=s.find("a.doBulkActionButton"),d=o.data("config"),l=this.getActionURL(e,t(this).data("url")),r={records:n};if(n.length<=0)return void alert(ss.i18n._t("GRIDFIELD_BULK_MANAGER.BULKACTION_EMPTY_SELECT"));if(d[e].destructive&&!confirm(ss.i18n._t("GRIDFIELD_BULK_MANAGER.CONFIRM_DESTRUCTIVE_ACTION")))return i&&a&&i.call(a,!1),!1;if(o.addClass("loading"),d[e].xhr)t.ajax({url:l,data:r,type:"POST",context:t(this)}).done(function(e,n,s){o.removeClass("loading"),i&&a?i.call(a,e):t(this).parents(".ss-gridfield").entwine(".").entwine("ss").reload()});else{l=l+"&"+("records[]="+n.join("&records[]=")),window.location.href=l}}})})})}(jQuery)},function(t,e){!function(t){t.entwine("colymba",function(t){t("#bulkEditToggle").entwine({onmatch:function(){},onunmatch:function(){},onclick:function(e){var n=this.parents("form").find(".ss-toggle .ui-accordion-header"),i=this.data("state");i=i&&"close"!==i?"close":"open",n.each(function(){var e=t(this);"open"!==i||e.hasClass("ui-state-active")||e.click(),"close"===i&&e.hasClass("ui-state-active")&&e.click()}),this.data("state",i)}}),t(".bulkEditingFieldHolder").entwine({onmatch:function(){},onunmatch:function(){},onchange:function(){this.removeClass("updated"),this.hasClass("hasUpdate")||this.addClass("hasUpdate")}})})}(jQuery)},function(t,e){!function(t){t.entwine("ss",function(t){t.entwine("colymba",function(t){t(".bulkUploader").entwine({onmatch:function(){var t=this.parents("thead").find("tr"),e=this.clone();t.index(this)>1&&(e.insertAfter(t.eq(0)),this.remove())},onunmatch:function(){}}),t("ul.ss-uploadfield-files").entwine({onmatch:function(){},onunmatch:function(){},trackProgress:function(){var t=this.find("li.ss-uploadfield-item"),e=t.length,n=t.filter(".done"),i=n.length,a=t.not(n).find(".ui-state-warning-text,.ui-state-error-text"),s=a.length;this.parents(".ss-uploadfield").find(".colymba-bulkupload-buttons").refresh(e,i,s)}}),t("li.ss-uploadfield-item").entwine({onmatch:function(){this.parents("ul.ss-uploadfield-files").trackProgress()},onunmatch:function(){t("ul.ss-uploadfield-files").trackProgress()}}),t("li.ss-uploadfield-item .ui-state-warning-text,li.ss-uploadfield-item .ui-state-error-text").entwine({onmatch:function(){this.parents("ul.ss-uploadfield-files").trackProgress()},onunmatch:function(){t("ul.ss-uploadfield-files").trackProgress()}}),t(".colymba-bulkupload-buttons").entwine({onmatch:function(){},onunmatch:function(){},refresh:function(t,e,n){var i=this.find(".colymba-bulkupload-info"),a=this.find(".bulkUploadEditButton"),s=this.find(".bulkUploadCancelButton"),o=this.find(".bulkUploadFinishButton"),d=this.find(".bulkUploadClearErrorButton");t>0?(this.css({display:"block"}),i.html(ss.i18n.sprintf(ss.i18n._t("GRIDFIELD_BULK_UPLOAD.PROGRESS_INFO"),t,e,n)),s.removeClass("ui-state-disabled ssui-button-disabled").attr("aria-disabled","false").removeAttr("disabled"),e+n<t?this.hasClass("loading")||(this.addClass("loading"),o.addClass("ui-state-disabled ssui-button-disabled").attr("aria-disabled","true").attr("disabled","disabled")):(this.removeClass("loading"),o.removeClass("ui-state-disabled ssui-button-disabled").attr("aria-disabled","false").removeAttr("disabled")),t===e?a.removeClass("ui-state-disabled ssui-button-disabled").attr("aria-disabled","false").removeAttr("disabled"):a.addClass("ui-state-disabled ssui-button-disabled").attr("aria-disabled","true").attr("disabled","true"),n>0?d.removeClass("ui-state-disabled ssui-button-disabled").attr("aria-disabled","false").removeAttr("disabled"):d.addClass("ui-state-disabled ssui-button-disabled").attr("aria-disabled","true").attr("disabled","true")):(this.css({display:"none"}).removeClass("loading"),a.addClass("ui-state-disabled ssui-button-disabled").attr("aria-disabled","true").attr("disabled","true"),s.addClass("ui-state-disabled ssui-button-disabled").attr("aria-disabled","true").attr("disabled","true"),o.addClass("ui-state-disabled ssui-button-disabled").attr("aria-disabled","true").attr("disabled","true"),d.addClass("ui-state-disabled ssui-button-disabled").attr("aria-disabled","true").attr("disabled","true"))}}),t(".bulkUploadClearErrorButton:not(.ui-state-disabled)").entwine({onmatch:function(){this.removeClass("action")},onunmatch:function(){},onclick:function(e){var n=this.parents(".bulkUpload"),i=n.find("li.ss-uploadfield-item .ui-state-warning-text,li.ss-uploadfield-item .ui-state-error-text").parents("li");t(i.get().reverse()).each(function(e,n){t(this).remove()})}}),t(".bulkUploadCancelButton:not(.ui-state-disabled)").entwine({onmatch:function(){this.removeClass("action")},onunmatch:function(){},onclick:function(){var e,n=this.parents(".bulkUpload"),i=n.find("li.ss-uploadfield-item"),a=i.filter("[data-recordid]"),s=i.not(a),o=n.parents(".ss-gridfield-table").find(".doBulkActionButton");s.each(function(e,n){t(this).remove()}),o.length>0&&(e=a.map(function(){return parseInt(t(this).data("recordid"))}).get(),this.addClass("loading"),o.doBulkAction("delete",e,this.cancelCallback,this))},cancelCallback:function(e){var n,i=this.parents(".bulkUpload"),a=i.find("li.ss-uploadfield-item");e&&(n=e.records,a.each(function(e,i){var a=t(this),s=parseInt(a.data("recordid"));-1!==n.indexOf(s)&&a.remove()}),t(this).parents(".ss-gridfield").entwine(".").entwine("ss").reload()),this.removeClass("loading")}}),t(".bulkUploadFinishButton:not(.ui-state-disabled)").entwine({onmatch:function(){this.removeClass("action")},onunmatch:function(){},onclick:function(){var e=this.parents(".bulkUpload"),n=e.find("li.ss-uploadfield-item");this.addClass("loading"),n.each(function(e,n){t(this).remove()}),t(this).parents(".ss-gridfield").entwine(".").entwine("ss").reload(),this.removeClass("loading")}}),t(".bulkUploadEditButton:not(.ui-state-disabled)").entwine({onmatch:function(){this.removeClass("action")},onunmatch:function(){},onclick:function(){var e,n=this.parents(".bulkUpload"),i=n.find("li.ss-uploadfield-item"),a=i.filter("[data-recordid]"),s=n.parents(".ss-gridfield-table").find(".doBulkActionButton");s.length>0&&(this.addClass("loading"),e=a.map(function(){return parseInt(t(this).data("recordid"))}).get(),s.doBulkAction("bulkedit",e))}})})})}(jQuery)}]);

1
client/dist/js/bulkTools.js.map vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"sources":["webpack:///webpack/bootstrap 4815efe042c2a898f146","webpack:///./client/src/js/manager.js","webpack:///./client/src/js/managerBulkEditingForm.js","webpack:///./client/src/js/uploader.js"],"names":[],"mappings":";AAAA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;AAEA;AACA;;;;;;;;;;;;;;;;AC7DA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;;AAEX;AACA;AACA;AACA;AACA,SAAS;AACT;AACA,OAAO;;;AAGP;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;;;AAGJ;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA;AACA;AACA,IAAI;;;AAGJ;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB;AAChB;AACA;AACA,MAAM;;;AAGN;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;;;AAGA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,IAAI;;;AAGJ;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,KAAK;;AAEL;AACA;AACA;AACA;;AAEA;AACA;AACA,yBAAyB;AACzB;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,IAAI;;;AAGJ,GAAG;AACH,EAAE;AACF,CAAC;;;;;;;ACnQD;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,2BAA2B;AAC3B,6BAA6B;AAC7B;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,W;AACA,SAAS;;AAET;AACA;AACA,KAAK;;;AAGL;AACA;AACA;AACA;AACA;AACA,2BAA2B;AAC3B,6BAA6B;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL,GAAG;AACH,CAAC,U;;;;;;AC7DD,c;AACA;;;AAGA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,W;AACA,SAAS;AACT;AACA,OAAO;;;AAGP;AACA;AACA;AACA;AACA,6BAA6B;AAC7B,+BAA+B;AAC/B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,OAAO;;;AAGP;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,SAAS;AACT,OAAO;;AAEP;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,SAAS;AACT,OAAO;;;AAGP;AACA;AACA;AACA;AACA,6BAA6B;AAC7B,+BAA+B;AAC/B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,sBAAsB,iBAAiB;;AAEvC;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,e;AACA;AACA;AACA;AACA;AACA,a;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAsB,gBAAgB;AACtC;AACA;AACA;AACA;AACA,W;AACA;AACA,OAAO;;;AAGP;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT,+BAA+B;AAC/B;AACA;AACA;AACA;AACA;;AAEA,mE;AACA;AACA,WAAW;AACX;AACA,OAAO;;;AAGP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT,+BAA+B;AAC/B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW;;AAEX;AACA;AACA,iD;AACA;AACA,aAAa;;AAEb;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,aAAa;;AAEb;AACA;;AAEA;AACA;AACA,OAAO;;;AAGP;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT,+BAA+B;AAC/B;AACA,S;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW;;AAEX;;AAEA;AACA;AACA,OAAO;;AAEP;AACA;AACA;AACA,SAAS;AACT,+BAA+B;AAC/B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA,iD;AACA;AACA,aAAa;;AAEb;AACA;AACA;AACA,OAAO;;AAEP,GAAG,EAAE;;AAEL,EAAE,EAAE;AACJ,CAAC,U","file":"js/bulkTools.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 4815efe042c2a898f146","(function($) {\n\t$.entwine('ss', function($) {\n\n\t\t$.entwine('colymba', function($) {\n\n\t\t\t/**\n * Makes sure the component is above the headers\n */\n $('.bulkManagerOptions').entwine({\n onmatch: function(){\n var $parent = this.parents('thead'),\n \t\t$tr = $parent.find('tr'),\n\n \t\ttargets = ['.filter-header', '.sortable-header'],\n \t\t$target = $parent.find(targets.join(',')),\n\n index = $tr.index(this),\n newIndex = $tr.length - 1\n ;\n\n $target.each(function(index, Element){\n \tvar idx = $tr.index(Element);\n \tif ( idx < newIndex )\n \t{\n \t\tnewIndex = idx;\n \t}\n });\n\n if ( index > newIndex )\n {\n $tr.eq(newIndex).insertAfter($(this));\n }\n },\n onunmatch: function(){}\n });\n\n\n\t\t /**\n\t\t * Bulkselect table cell behaviours\n\t\t */\n\t\t\t$('td.col-bulkSelect').entwine({\n\t\t\t\tonmatch: function(){\n\t\t\t\t},\n\t\t\t\tonunmatch: function(){\n\t\t\t\t},\n\t\t\t\tonmouseover: function(){\n\t\t\t\t\t//disable default row click behaviour -> avoid navigation to edit form when clicking the checkbox\n\t $(this).parents('.ss-gridfield-item').find('.edit-link').removeClass('edit-link').addClass('tempDisabledEditLink');\n\t\t\t\t},\n\t\t\t\tonmouseout: function(){\n\t\t\t\t\t//re-enable default row click behaviour\n\t\t\t\t\t$(this).parents('.ss-gridfield-item').find('.tempDisabledEditLink').addClass('edit-link').removeClass('tempDisabledEditLink');\n\t\t\t\t},\n\t\t\t\tonclick: function(e) {\n\t\t\t\t\t//check/uncheck checkbox when clicking cell\n\t\t\t\t\tvar cb = $(e.target).find('input');\n\t\t\t\t\tif ( !$(cb).prop('checked') ) $(cb).prop('checked', true);\n\t\t\t\t\telse $(cb).prop('checked', false);\n\t\t\t\t}\n\t\t\t});\n\n\n\t\t\t/**\n\t\t\t * Individual select checkbox behaviour\n\t\t\t */\n\t\t\t$('td.col-bulkSelect input').entwine({\n\t\t\t\tonmatch: function(){\n\t\t\t\t},\n\t\t\t\tonunmatch: function(){\n\t\t\t\t},\n\t\t\t\tonclick: function(e) {\n\t\t\t\t\t$(this).parents('.grid-field__table').find('input.bulkSelectAll').prop('checked', '');\n\t\t\t\t}\n\t\t\t});\n\n\n\t\t\t/**\n\t\t\t * Bulkselect checkbox behaviours\n\t\t\t */\n\t $('input.bulkSelectAll').entwine({\n\t onmatch: function(){\n\t\t\t\t},\n\t\t\t\tonunmatch: function(){\n\t\t\t\t},\n\t onclick: function()\n\t {\n\t var state = $(this).prop('checked');\n\t $(this).parents('.grid-field__table')\n\t \t\t\t .find('td.col-bulkSelect input')\n\t \t\t\t .prop('checked', state)\n\t \t\t\t .trigger('change');\n\t },\n\t getSelectRecordsID: function()\n\t {\n\t \treturn $(this).parents('.grid-field__table')\n\t\t\t\t\t \t\t\t\t.find('td.col-bulkSelect input:checked')\n\t\t\t\t\t \t\t\t\t.map(function() {\n\t\t\t\t\t \t\t\t\t\treturn parseInt( $(this).data('record') )\n\t\t\t\t\t \t\t\t\t})\n\t\t\t\t\t\t\t\t\t\t\t .get();\n\t }\n\t });\n\n\n\t /**\n\t * Bulk action dropdown behaviours\n\t */\n\t\t\t$('select.bulkActionName').entwine({\n\t\t\t\tonmatch: function(){\n\t\t\t\t},\n\t\t\t\tonunmatch: function(){\n\t\t\t\t},\n\t\t\t\tonchange: function(e)\n\t\t\t\t{\n\t\t\t\t\tvar value = $(this).val(),\n\t\t\t\t\t\t$parent = $(this).parents('.bulkManagerOptions'),\n\t\t\t\t\t\t$btn = $parent.find('.doBulkActionButton'),\n\t\t\t\t\t\tconfig = $btn.data('config');\n\n\t\t\t\t\t$.each( config, function( configKey, configData )\n\t\t\t\t\t{\n\t\t\t\t\t\tif ( configKey != value )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$btn.removeClass(configData['buttonClasses']);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\t$btn.addClass(config[value]['buttonClasses']).addClass('btn-outline-secondary');\n\n\n\t\t\t\t\tif ( config[value]['icon'] )\n\t\t\t\t\t{\n\t\t\t\t\t\tvar $img = $btn.find('img');\n\n\t\t\t\t\t\tif ($img.length)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$img.attr('src', config[value]['icon']);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse{\n\t\t\t\t\t\t\t$btn.prepend('<img src=\"'+config[value]['icon']+'\" alt=\"\" />');\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse{\n\t\t\t\t\t\t$btn.find('img').remove();\n\t\t\t\t\t}\n\n\n\t\t\t\t\tif ( config[value]['destructive'] )\n\t\t\t\t\t{\n\t\t\t\t\t\t$btn.addClass('btn-outline-danger');\n\t\t\t\t\t}\n\t\t\t\t\telse{\n\t\t\t\t\t\t$btn.removeClass('btn-outline-danger');\n\t\t\t\t\t}\n\n\t\t\t\t}\n\t\t\t});\n\n\n\t\t\t/**\n\t\t\t * bulk action button behaviours\n\t\t\t */\n\t\t\t$('.doBulkActionButton').entwine({\n\t\t\t\tonmatch: function(){\n\t\t\t\t},\n\t\t\t\tonunmatch: function(){\n\t\t\t\t},\n\t\t\t\tgetActionURL: function(action, url)\n\t\t\t\t{\n\t\t\t\t\tvar cacheBuster = new Date().getTime();\n\t\t\t\t\turl = url.split('?');\n\n\t\t\t\t\tif ( action )\n\t\t\t\t\t{\n\t\t\t\t\t\taction = '/' + action;\n\t\t\t\t\t}\n\t\t\t\t\telse{\n\t\t\t\t\t\taction = '';\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( url[1] )\n\t\t\t\t\t{\n\t\t\t\t\t\turl = url[0] + action + '?' + url[1] + '&' + 'cacheBuster=' + cacheBuster;\n\t\t\t\t\t}\n\t\t\t\t\telse{\n\t\t\t\t\t\turl = url[0] + action + '?' + 'cacheBuster=' + cacheBuster;\n\t\t\t\t\t}\n\t\t\t\t\treturn url;\n\t\t\t\t},\n\t\t\t\tonclick: function(e)\n\t\t\t\t{\n var $parent = $(this).parents('.bulkManagerOptions'),\n action = $parent.find('select.bulkActionName').val(),\n ids = $(this).parents('.bulkManagerOptions').find('input.bulkSelectAll:first').getSelectRecordsID()\n\t\t\t\t\t\t\t;\n\n\t\t\t\t\tthis.doBulkAction(action, ids);\n\t\t\t\t},\n\n\t\t\t\tdoBulkAction: function(action, ids, callbackFunction, callbackContext)\n\t\t\t\t{\n var $parent = $(this).parents('.bulkManagerOptions'),\n $btn = $parent.find('a.doBulkActionButton'),\n\n config = $btn.data('config'),\n url = this.getActionURL(action, $(this).data('url')),\n data = { records: ids }\n\t\t\t\t\t\t\t;\n\n\t\t\t\t\tif ( ids.length <= 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\talert( ss.i18n._t('GRIDFIELD_BULK_MANAGER.BULKACTION_EMPTY_SELECT') );\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t//if ( $btn.hasClass('ss-ui-action-destructive') )\n\t\t\t\t\tif ( config[action]['destructive'] )\n\t\t\t\t\t{\n\t\t\t\t\t\tif( !confirm(ss.i18n._t('GRIDFIELD_BULK_MANAGER.CONFIRM_DESTRUCTIVE_ACTION')) )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ( callbackFunction && callbackContext )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcallbackFunction.call(callbackContext, false);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t$btn.addClass('loading');\n\n\t\t\t\t\tif ( config[action]['xhr'] )\n\t\t\t\t\t{\n\t\t\t\t\t\t$.ajax({\n\t\t\t\t\t\t\turl: url,\n\t\t\t\t\t\t\tdata: data,\n\t\t\t\t\t\t\ttype: \"POST\",\n\t\t\t\t\t\t\tcontext: $(this)\n\t\t\t\t\t\t}).done(function(data, textStatus, jqXHR) {\n\t $btn.removeClass('loading');\n\t if ( callbackFunction && callbackContext )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcallbackFunction.call(callbackContext, data);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse{\n\t\t\t\t\t\t\t\t$(this).parents('.ss-gridfield').entwine('.').entwine('ss').reload();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\telse{\n\t\t\t\t\t\tvar records = 'records[]='+ids.join('&records[]=');\n\t\t\t\t\t\turl = url + '&' + records;\n\n\t\t\t\t\t\twindow.location.href = url;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\n\t\t});\n\t});\n}(jQuery));\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./client/src/js/manager.js\n// module id = 1\n// module chunks = 0","(function($) {\n $.entwine('colymba', function($) {\n\n /**\n * Toggle all accordion forms\n * open or closed\n */\n $('#bulkEditToggle') .entwine({\n onmatch: function(){},\n onunmatch: function(){},\n onclick: function(e)\n {\n var toggleFields = this.parents('form').find('.ss-toggle .ui-accordion-header'),\n state = this.data('state')\n ;\n\n if ( !state || state === 'close' )\n {\n state = 'open';\n }\n else {\n state = 'close';\n }\n\n toggleFields.each(function()\n {\n var $this = $(this);\n \n if ( state === 'open' && !$this.hasClass('ui-state-active') )\n {\n $this.click();\n }\n\n if ( state === 'close' && $this.hasClass('ui-state-active') )\n {\n $this.click();\n } \n });\n\n this.data('state', state);\n }\n });\n \n \n /**\n * Contains each rocrds editing fields,\n * tracks changes and updates...\n */\n $('.bulkEditingFieldHolder').entwine({\n onmatch: function(){},\n onunmatch: function(){},\n onchange: function(){\n this.removeClass('updated');\n if ( !this.hasClass('hasUpdate') )\n {\n this.addClass('hasUpdate');\n }\n }\n });\n \n });\n}(jQuery));\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./client/src/js/managerBulkEditingForm.js\n// module id = 2\n// module chunks = 0","(function($) {\t\n\t$.entwine('ss', function($) {\n\t\t\n\n\t\t$.entwine('colymba', function($) {\n\n /**\n * Makes sure the component is at the top :)\n */\n $('.bulkUploader').entwine({\n onmatch: function(){\n var $tr = this.parents('thead').find('tr'),\n $component = this.clone(),\n index = $tr.index(this)\n ;\n if ( index > 1 )\n {\n $component.insertAfter($tr.eq(0));\n this.remove();\n } \n },\n onunmatch: function(){}\n });\n\n\n /**\n * Track upload progress...\n */ \n $('ul.ss-uploadfield-files').entwine({\n onmatch: function(){},\n onunmatch: function(){},\n trackProgress: function()\n {\n var $li = this.find('li.ss-uploadfield-item'),\n total = $li.length,\n $done = $li.filter('.done'),\n done = $done.length,\n $errors = $li.not($done).find('.ui-state-warning-text,.ui-state-error-text'),\n errors = $errors.length\n ;\n \n this.parents('.ss-uploadfield').find('.colymba-bulkupload-buttons').refresh(total, done, errors);\n }\n });\n\n\n /**\n * Track new and canceled updloads\n */\n $('li.ss-uploadfield-item').entwine({\n onmatch: function(){\n this.parents('ul.ss-uploadfield-files').trackProgress();\n },\n onunmatch: function(){\n $('ul.ss-uploadfield-files').trackProgress();\n },\n });\n\n /**\n * Track updload warning/errors\n */\n $('li.ss-uploadfield-item .ui-state-warning-text,li.ss-uploadfield-item .ui-state-error-text').entwine({\n onmatch: function(){\n this.parents('ul.ss-uploadfield-files').trackProgress();\n },\n onunmatch: function(){\n $('ul.ss-uploadfield-files').trackProgress();\n },\n });\n\n\n /**\n * Update buttons state and progress info...\n */ \n $('.colymba-bulkupload-buttons').entwine({\n onmatch: function(){},\n onunmatch: function(){},\n refresh: function(total, done, error)\n {\n var $info = this.find('.colymba-bulkupload-info'),\n $editBtn = this.find('.bulkUploadEditButton'),\n $cancelBtn = this.find('.bulkUploadCancelButton'),\n $finishBtn = this.find('.bulkUploadFinishButton'),\n $clearErrorBtn = this.find('.bulkUploadClearErrorButton')\n ;\n\n if ( total > 0 )\n {\n this.css({display: 'block'});\n\n $info.html(ss.i18n.sprintf(\n ss.i18n._t('GRIDFIELD_BULK_UPLOAD.PROGRESS_INFO'),\n total,\n done,\n error\n ));\n\n $cancelBtn.removeClass('ui-state-disabled ssui-button-disabled').attr('aria-disabled', 'false').removeAttr('disabled');\n\n //if there are still uploads going\n if ( (done + error) < total )\n {\n if ( !this.hasClass('loading') )\n {\n this.addClass('loading');\n $finishBtn.addClass('ui-state-disabled ssui-button-disabled').attr('aria-disabled', 'true').attr('disabled', 'disabled');\n } \n }\n else{\n this.removeClass('loading');\n $finishBtn.removeClass('ui-state-disabled ssui-button-disabled').attr('aria-disabled', 'false').removeAttr('disabled');\n } \n\n //if all done and OK, enable edit\n if ( total === done )\n {\n $editBtn.removeClass('ui-state-disabled ssui-button-disabled').attr('aria-disabled', 'false').removeAttr('disabled');\n }\n else{\n $editBtn.addClass('ui-state-disabled ssui-button-disabled').attr('aria-disabled', 'true').attr('disabled', 'true');\n }\n\n //toggle clear error button\n if ( error > 0 )\n {\n $clearErrorBtn.removeClass('ui-state-disabled ssui-button-disabled').attr('aria-disabled', 'false').removeAttr('disabled');\n }\n else{\n $clearErrorBtn.addClass('ui-state-disabled ssui-button-disabled').attr('aria-disabled', 'true').attr('disabled', 'true');\n }\n }\n else{\n //if not uploading, reset + hide\n this.css({display: 'none'}).removeClass('loading');\n $editBtn.addClass('ui-state-disabled ssui-button-disabled').attr('aria-disabled', 'true').attr('disabled', 'true');\n $cancelBtn.addClass('ui-state-disabled ssui-button-disabled').attr('aria-disabled', 'true').attr('disabled', 'true');\n $finishBtn.addClass('ui-state-disabled ssui-button-disabled').attr('aria-disabled', 'true').attr('disabled', 'true');\n $clearErrorBtn.addClass('ui-state-disabled ssui-button-disabled').attr('aria-disabled', 'true').attr('disabled', 'true');\n } \n }\n });\n\n\n /**\n * Clears all updloads with warning or error\n */\n $('.bulkUploadClearErrorButton:not(.ui-state-disabled)').entwine({\n onmatch: function(){\n this.removeClass('action');\n },\n onunmatch: function(){},\n onclick: function(e)\n {\n var $bulkUpload = this.parents('.bulkUpload'),\n $errors = $bulkUpload.find('li.ss-uploadfield-item .ui-state-warning-text,li.ss-uploadfield-item .ui-state-error-text').parents('li')\n ;\n\n $($errors.get().reverse()).each(function(index, Element){ \n $(this).remove();\n });\n }\n });\n\n\n /**\n * Cancel all uploads\n * Clear the ones with warnings/error and delete dataObjects from the successful ones\n */\n $('.bulkUploadCancelButton:not(.ui-state-disabled)').entwine({\n onmatch: function(){\n this.removeClass('action');\n },\n onunmatch: function(){},\n onclick: function()\n {\n var $bulkUpload = this.parents('.bulkUpload'),\n $li = $bulkUpload.find('li.ss-uploadfield-item'),\n $records = $li.filter('[data-recordid]'),\n $other = $li.not($records),\n $doBulkActionButton = $bulkUpload.parents('.ss-gridfield-table').find('.doBulkActionButton'), \n recordsID\n ;\n\n $other.each(function(index, Element){\n // skip in progress \n $(this).remove();\n });\n\n if ( $doBulkActionButton.length > 0 )\n {\n recordsID = $records.map(function() { \n return parseInt( $(this).data('recordid') )\n }).get();\n\n this.addClass('loading');\n $doBulkActionButton.doBulkAction('delete', recordsID, this.cancelCallback, this);\n }\n },\n cancelCallback: function(data)\n {\n var $bulkUpload = this.parents('.bulkUpload'),\n $li = $bulkUpload.find('li.ss-uploadfield-item'),\n ids\n ;\n\n if ( data )\n {\n ids = data.records;\n\n $li.each(function(index, Element){\n var $this = $(this),\n recordID = parseInt( $this.data('recordid') )\n ;\n\n if ( ids.indexOf(recordID) !== -1 )\n {\n $this.remove();\n }\n });\n\n $(this).parents('.ss-gridfield').entwine('.').entwine('ss').reload();\n }\n\n this.removeClass('loading');\n }\n });\n\n \n /**\n * Clear all the warning/error/finished uploads\n */\n $('.bulkUploadFinishButton:not(.ui-state-disabled)').entwine({\n onmatch: function(){\n this.removeClass('action');\n },\n onunmatch: function(){},\n onclick: function()\n { \n var $bulkUpload = this.parents('.bulkUpload'),\n $li = $bulkUpload.find('li.ss-uploadfield-item')\n ;\n\n this.addClass('loading');\n $li.each(function(index, Element){\n // skip in progress \n $(this).remove();\n });\n\n $(this).parents('.ss-gridfield').entwine('.').entwine('ss').reload();\n \n this.removeClass('loading');\n }\n });\n\n $('.bulkUploadEditButton:not(.ui-state-disabled)').entwine({\n onmatch: function(){\n this.removeClass('action');\n },\n onunmatch: function(){},\n onclick: function()\n {\n var $bulkUpload = this.parents('.bulkUpload'),\n $li = $bulkUpload.find('li.ss-uploadfield-item'),\n $records = $li.filter('[data-recordid]'), \n recordsID,\n $doBulkActionButton = $bulkUpload.parents('.ss-gridfield-table').find('.doBulkActionButton')\n ;\n\n if ( $doBulkActionButton.length > 0 )\n {\n this.addClass('loading');\n\n recordsID = $records.map(function() { \n return parseInt( $(this).data('recordid') )\n }).get();\n\n $doBulkActionButton.doBulkAction('bulkedit', recordsID);\n }\n }\n });\n\n\t\t}); // colymba namespace\n\n\t}); // ss namespace\n}(jQuery));\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./client/src/js/uploader.js\n// module id = 3\n// module chunks = 0"],"sourceRoot":""}

1
client/dist/styles/bulkTools.css vendored Normal file
View File

@ -0,0 +1 @@
.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.grid-field__table tr.bulkManagerOptions th.bulkmanagerselect input{margin-left:0}.cms table.grid-field__table tr.bulkManagerOptions .title{margin:0 0 2px 2px}.cms table.grid-field__table tr.bulkManagerOptions .dropdown{display:inline-block;border:none;box-shadow:none;padding:0;margin:0;color:#000;vertical-align:top}.cms table.grid-field__table tr.bulkManagerOptions .doBulkActionButton img{height:20px}.cms table.grid-field__table tbody .col-bulkSelect{width:25px;text-align:center}#bulkEditHeader{float:left;width:70%;margin:40px 0 20px;font-size:30px;font-weight:700}#bulkEditToggle{float:right;clear:right;width:25%;margin:40px 0 20px;text-decoration:underline;text-align:right;cursor:pointer}.bulkEditingFieldHolder{position:relative;float:left;width:100%}.bulkEditingFieldHolder.hasUpdate .ui-accordion-header{background-color:#f2ba11;background-image:-webkit-gradient(linear,50% 0,50% 100%,color-stop(0,#f2ba11),color-stop(100%,#df6e00));background-image:-webkit-linear-gradient(top,#f2ba11,#df6e00);background-image:-moz-linear-gradient(top,#f2ba11 0,#df6e00 100%);background-image:-o-linear-gradient(top,#f2ba11 0,#df6e00 100%);background-image:-ms-linear-gradient(top,#f2ba11 0,#df6e00 100%);background-image:linear-gradient(top,#f2ba11,#df6e00)}.bulkEditingFieldHolder.hasUpdate .ui-accordion-header a{color:#fff;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,#59781d);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,#59781d)}.bulkEditingFieldHolder.updated .ui-accordion-header a{color:#fff;text-shadow:none}.bulkUpload{padding:0!important;border-bottom:1px solid rgba(0,0,0,.1)}.bulkUpload:hover{background-color:#444546}.bulkUpload .component{padding:0!important;color:#fff;background:#98aab6;border-top:1px solid #a4b4bf;border-left:1px solid #a4b4bf;border-bottom:1px solid rgba(0,0,0,.1)}.bulkUpload .component div.ss-uploadfield{position:relative;float:left;clear:both;width:100%}.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files{float:left;clear:both;width:100%}.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item{position:relative;float:left;clear:both;overflow:hidden;width:98%;padding:5px 1%;border:none;border-top:1px solid rgba(0,0,0,.1);background-color:#eceff1}.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item:nth-child(2n-1){background-color:#e6eaed}.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item .ss-uploadfield-item-preview{width:30px;height:30px;line-height:38px}.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item .ss-uploadfield-item-info{height:30px;margin-left:40px;line-height:30px}.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item .ss-uploadfield-item-info .ss-uploadfield-item-name{position:absolute;top:0;left:50px;width:100%;height:100%;line-height:40px}.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item .ss-uploadfield-item-info .ss-uploadfield-item-name .name{color:#343434}.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item .ss-uploadfield-item-info .ss-uploadfield-item-name .size{font-weight:400}.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item .ss-uploadfield-item-info .ss-uploadfield-item-name .ss-uploadfield-item-status{float:left;width:auto;padding:0 0 0 5px;text-align:left;max-width:none}.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item .ss-uploadfield-item-info .ss-uploadfield-item-name .ss-uploadfield-item-status.ui-state-warning-text{color:#f29500}.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item .ss-uploadfield-item-info .ss-uploadfield-item-name .ss-uploadfield-item-status.ui-state-success-text{color:#298530}.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item .ss-uploadfield-item-info .ss-uploadfield-item-actions{position:absolute;top:0;left:0;width:100%;height:30px;margin:0;padding:5px 0}.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item .ss-uploadfield-item-info .ss-uploadfield-item-actions .ss-uploadfield-item-progress{left:50px;right:35px;margin-top:8px}.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item .ss-uploadfield-item-info .ss-uploadfield-item-actions button{margin:0 10px 0 0}.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item .ss-uploadfield-item-info .ss-uploadfield-item-actions button .ui-button-text{padding-top:4px;padding-bottom:3px}.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item .ss-uploadfield-item-info .ss-uploadfield-item-actions .ss-uploadfield-item-cancel{position:relative;top:7px;right:auto;float:right}.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item .ss-uploadfield-item-info .ss-uploadfield-item-actions .ss-uploadfield-item-cancel button{background:none}.bulkUpload .component div.ss-uploadfield .ss-uploadfield-files .ss-uploadfield-item .ss-uploadfield-item-info .ss-uploadfield-item-actions .ss-uploadfield-item-overwrite{position:relative;float:right;margin-top:2px}.bulkUpload .component div.ss-uploadfield .ss-uploadfield-addfile{float:left;clear:both;width:98%;padding:1%}.bulkUpload .component div.ss-uploadfield .ss-uploadfield-addfile.borderTop{border:none}.bulkUpload .component div.ss-uploadfield .ss-uploadfield-addfile .ss-uploadfield-item-preview.ss-uploadfield-dropzone{float:right;width:35%;height:43px;margin:0;line-height:43px;color:#eee;background-color:#8898a3;border:2px dashed #73818a;box-shadow:inset 0 0 10px 0 #73818a}.bulkUpload .component div.ss-uploadfield .ss-uploadfield-addfile .ss-uploadfield-item-preview.ss-uploadfield-dropzone.hover{color:#444546;background-color:#eee}.bulkUpload .component div.ss-uploadfield .ss-uploadfield-addfile .ss-uploadfield-item-info{float:left;width:60%;margin:0}.bulkUpload .component div.ss-uploadfield .ss-uploadfield-addfile .ss-uploadfield-item-info .ss-uploadfield-item-name{height:auto;margin-bottom:5px!important}.bulkUpload .component div.ss-uploadfield .ss-uploadfield-addfile .ss-uploadfield-item-info .ss-uploadfield-item-name small{font-weight:400!important}.bulkUpload .component div.ss-uploadfield .ss-uploadfield-addfile .ss-uploadfield-item-info .ss-ui-button .ui-button-text .ui-button-text{padding:0}.bulkUpload .component div.ss-uploadfield .ss-uploadfield-addfile .ss-uploadfield-item-info .ss-uploadfield-fromcomputer{margin-bottom:0}.bulkUpload .component div.ss-uploadfield .ss-uploadfield-addfile .ss-uploadfield-item-info .ss-uploadfield-fromfiles{margin-bottom:0;padding:.5px}.bulkUpload .component div.ss-uploadfield .colymba-bulkupload-buttons{display:none;float:left;width:98%;padding:6px 1%;background-color:#8898a3}.bulkUpload .component div.ss-uploadfield .colymba-bulkupload-buttons button{float:left;margin:0 6px 0 0}.bulkUpload .component div.ss-uploadfield .colymba-bulkupload-buttons button .ui-button-text .ui-button-text{padding:0}.bulkUpload .component div.ss-uploadfield .colymba-bulkupload-buttons button.bulkUploadClearErrorButton,.bulkUpload .component div.ss-uploadfield .colymba-bulkupload-buttons button.bulkUploadEditButton{float:right;margin:0 0 0 6px}.bulkUpload .component div.ss-uploadfield .colymba-bulkupload-buttons .colymba-bulkupload-info{float:left;margin:0 6px;line-height:28px;height:28px;color:#fff;overflow:hidden}.bulkUpload .component div.ss-uploadfield .colymba-bulkupload-buttons.loading .colymba-bulkupload-info{padding-left:20px;background-position:0 5px}

1
client/dist/styles/bulkTools.css.map vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"sources":[],"names":[],"mappings":"","file":"styles/bulkTools.css","sourceRoot":""}

94
client/dist/styles/bundle.css vendored Normal file
View File

@ -0,0 +1,94 @@
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
__webpack_require__(1);
__webpack_require__(2);
module.exports = __webpack_require__(3);
/***/ }),
/* 1 */
/***/ (function(module, exports) {
// removed by extract-text-webpack-plugin
/***/ }),
/* 2 */
/***/ (function(module, exports) {
// removed by extract-text-webpack-plugin
/***/ }),
/* 3 */
/***/ (function(module, exports) {
// removed by extract-text-webpack-plugin
/***/ })
/******/ ]);

1
client/dist/styles/bundle.css.map vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"sources":["webpack:///webpack/bootstrap c1e0c772c911cc70bc24","webpack:///./client/src/styles/manager.scss","webpack:///./client/src/styles/managerBulkEditingForm.scss","webpack:///./client/src/styles/uploader.scss"],"names":[],"mappings":";AAAA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;AAEA;AACA;;;;;;;;;;;;;;;;AC7DA,yC;;;;;;ACAA,yC;;;;;;ACAA,yC","file":"styles/bundle.css","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap c1e0c772c911cc70bc24","// removed by extract-text-webpack-plugin\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./client/src/styles/manager.scss\n// module id = 1\n// module chunks = 0","// removed by extract-text-webpack-plugin\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./client/src/styles/managerBulkEditingForm.scss\n// module id = 2\n// module chunks = 0","// removed by extract-text-webpack-plugin\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./client/src/styles/uploader.scss\n// module id = 3\n// module chunks = 0"],"sourceRoot":""}

View File

@ -112,29 +112,44 @@
},
onchange: function(e)
{
var value = $(this).val(),
$parent = $(this).parents('.bulkManagerOptions'),
$btn = $parent.find('.doBulkActionButton'),
config = $btn.data('config'),
$icon = $parent.find('.doBulkActionButton .ui-icon')
;
var value = $(this).val(),
$parent = $(this).parents('.bulkManagerOptions'),
$btn = $parent.find('.doBulkActionButton'),
config = $btn.data('config');
$.each( config, function( configKey, configData )
{
if ( configKey != value )
{
$icon.removeClass('btn-icon-'+configData['icon']);
$btn.removeClass(configData['buttonClasses']);
}
});
$icon.addClass('btn-icon-'+config[value]['icon']);
$btn.addClass(config[value]['buttonClasses']).addClass('btn-outline-secondary');
if ( config[value]['isDestructive'] )
if ( config[value]['icon'] )
{
$btn.addClass('ss-ui-action-destructive');
var $img = $btn.find('img');
if ($img.length)
{
$img.attr('src', config[value]['icon']);
}
else{
$btn.prepend('<img src="'+config[value]['icon']+'" alt="" />');
}
}
else{
$btn.removeClass('ss-ui-action-destructive');
$btn.find('img').remove();
}
if ( config[value]['destructive'] )
{
$btn.addClass('btn-outline-danger');
}
else{
$btn.removeClass('btn-outline-danger');
}
}
@ -198,7 +213,7 @@
}
//if ( $btn.hasClass('ss-ui-action-destructive') )
if ( config[action]['isDestructive'] )
if ( config[action]['destructive'] )
{
if( !confirm(ss.i18n._t('GRIDFIELD_BULK_MANAGER.CONFIRM_DESTRUCTIVE_ACTION')) )
{
@ -212,7 +227,7 @@
$btn.addClass('loading');
if ( config[action]['isAjax'] )
if ( config[action]['xhr'] )
{
$.ajax({
url: url,

View File

@ -78,8 +78,6 @@
refresh: function(total, done, error)
{
var $info = this.find('.colymba-bulkupload-info'),
$editBtn = this.find('.bulkUploadEditButton'),
$cancelBtn = this.find('.bulkUploadCancelButton'),
$finishBtn = this.find('.bulkUploadFinishButton'),
$clearErrorBtn = this.find('.bulkUploadClearErrorButton')
;
@ -95,8 +93,6 @@
error
));
$cancelBtn.removeClass('ui-state-disabled ssui-button-disabled').attr('aria-disabled', 'false').removeAttr('disabled');
//if there are still uploads going
if ( (done + error) < total )
{
@ -109,15 +105,6 @@
else{
this.removeClass('loading');
$finishBtn.removeClass('ui-state-disabled ssui-button-disabled').attr('aria-disabled', 'false').removeAttr('disabled');
}
//if all done and OK, enable edit
if ( total === done )
{
$editBtn.removeClass('ui-state-disabled ssui-button-disabled').attr('aria-disabled', 'false').removeAttr('disabled');
}
else{
$editBtn.addClass('ui-state-disabled ssui-button-disabled').attr('aria-disabled', 'true').attr('disabled', 'true');
}
//toggle clear error button
@ -132,8 +119,6 @@
else{
//if not uploading, reset + hide
this.css({display: 'none'}).removeClass('loading');
$editBtn.addClass('ui-state-disabled ssui-button-disabled').attr('aria-disabled', 'true').attr('disabled', 'true');
$cancelBtn.addClass('ui-state-disabled ssui-button-disabled').attr('aria-disabled', 'true').attr('disabled', 'true');
$finishBtn.addClass('ui-state-disabled ssui-button-disabled').attr('aria-disabled', 'true').attr('disabled', 'true');
$clearErrorBtn.addClass('ui-state-disabled ssui-button-disabled').attr('aria-disabled', 'true').attr('disabled', 'true');
}
@ -161,70 +146,6 @@
}
});
/**
* Cancel all uploads
* Clear the ones with warnings/error and delete dataObjects from the successful ones
*/
$('.bulkUploadCancelButton:not(.ui-state-disabled)').entwine({
onmatch: function(){
this.removeClass('action');
},
onunmatch: function(){},
onclick: function()
{
var $bulkUpload = this.parents('.bulkUpload'),
$li = $bulkUpload.find('li.ss-uploadfield-item'),
$records = $li.filter('[data-recordid]'),
$other = $li.not($records),
$doBulkActionButton = $bulkUpload.parents('.ss-gridfield-table').find('.doBulkActionButton'),
recordsID
;
$other.each(function(index, Element){
// skip in progress
$(this).remove();
});
if ( $doBulkActionButton.length > 0 )
{
recordsID = $records.map(function() {
return parseInt( $(this).data('recordid') )
}).get();
this.addClass('loading');
$doBulkActionButton.doBulkAction('delete', recordsID, this.cancelCallback, this);
}
},
cancelCallback: function(data)
{
var $bulkUpload = this.parents('.bulkUpload'),
$li = $bulkUpload.find('li.ss-uploadfield-item'),
ids
;
if ( data )
{
ids = data.records;
$li.each(function(index, Element){
var $this = $(this),
recordID = parseInt( $this.data('recordid') )
;
if ( ids.indexOf(recordID) !== -1 )
{
$this.remove();
}
});
$(this).parents('.ss-gridfield').entwine('.').entwine('ss').reload();
}
this.removeClass('loading');
}
});
/**
* Clear all the warning/error/finished uploads
@ -252,33 +173,6 @@
}
});
$('.bulkUploadEditButton:not(.ui-state-disabled)').entwine({
onmatch: function(){
this.removeClass('action');
},
onunmatch: function(){},
onclick: function()
{
var $bulkUpload = this.parents('.bulkUpload'),
$li = $bulkUpload.find('li.ss-uploadfield-item'),
$records = $li.filter('[data-recordid]'),
recordsID,
$doBulkActionButton = $bulkUpload.parents('.ss-gridfield-table').find('.doBulkActionButton')
;
if ( $doBulkActionButton.length > 0 )
{
this.addClass('loading');
recordsID = $records.map(function() {
return parseInt( $(this).data('recordid') )
}).get();
$doBulkActionButton.doBulkAction('bulkedit', recordsID);
}
}
});
}); // colymba namespace
}); // ss namespace

View File

@ -36,19 +36,9 @@
.doBulkActionButton
{
.ui-button-text
img
{
padding: 6px 0 5px 2.1em; //3px 0 2px 1.05em; //
.ui-button-text
{
padding: 0;
}
}
.loading .ui-icon
{
background: transparent url(../../framework/images/network-save.gif) no-repeat 0 0;
height: 20px;
}
}
}// .bulkManagerOptions
@ -60,7 +50,7 @@
width: 25px;
text-align: center;
}
/*
td a.tempDisabledEditLink
{
background: url('../../framework/admin/images/btn-icon/document--pencil.png') no-repeat 2px 0px;
@ -72,6 +62,6 @@
vertical-align: middle;
background-position: 2px 0px;
background-repeat: no-repeat no-repeat;
}
}*/
}
}

View File

@ -1,5 +1,3 @@
@import 'bourbon/bourbon';
.bulkUpload
{
padding: 0 !important;
@ -284,9 +282,9 @@
height: 28px;
color: #ffffff;
background-image: url(../../images/spinner.gif);
/*background-image: url(../../images/spinner.gif);
background-position: 0 -50px;
background-repeat: no-repeat;
background-repeat: no-repeat;*/
overflow: hidden;
}

View File

@ -1,10 +1,10 @@
{
"name": "colymba/gridfield-bulk-editing-tools",
"type": "silverstripe-module",
"description": "SilverStripe GridField component to upload images and edit records in bulk",
"type": "silverstripe-vendormodule",
"description": "SilverStripe GridField component to upload images/files and edit records in bulk",
"homepage": "https://github.com/colymba/GridFieldBulkEditingTools",
"keywords": ["silverstripe", "bulk upload", "image upload", "gridfield bulk upload"],
"license": "BSD Simplified",
"license": "BSD-3-Clause",
"authors": [
{
"name": "Thierry Francois",
@ -16,18 +16,22 @@
}
],
"require": {
"silverstripe/framework": "^4.0@dev",
"silverstripe/asset-admin": "^1.0@dev"
"silverstripe/framework": "^4.0",
"silverstripe/asset-admin": "^1.0"
},
"extra": {
"branch-alias": {
"dev-master": "3.x-dev"
}
},
"expose": [
"client/dist",
"client/lang"
]
},
"autoload": {
"psr-4": {
"Colymba\\BulkManager\\": "bulkManager/code/",
"Colymba\\BulkUpload\\": "bulkUpload/code/"
"Colymba\\BulkManager\\": "src/BulkManager/",
"Colymba\\BulkUpload\\": "src/BulkUploader/"
}
}
}

View File

@ -28,20 +28,13 @@ To add a custom bulk action to the list use:
```php
$config
->getComponentByType('Colymba\\BulkManager\\BulkManager')
->addBulkAction('actionName', 'Dropdown label', 'ActionHandlerClassName', $frontEndConfig)
->addBulkAction('Namespace\\ClassName')
```
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 `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 `Handler`, `DeleteHandler` and `UnlinkHandler` for examples.
Make sure to define the handler's `$url_segment`, from which the handler will be called and its relating `$allowed_actions` and `$url_handlers`. 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:
* `isAjax`: if true the action will be called via XHR request otherwise the browser will be redirected to the action's URL
* `icon`: lets you define which icon to use on the button when the action is selected (SilverStripe button icon name only)
* `isDestructive`: if true, a confirmation dialog will be shown before the action is processed
Bulk action handler's front-end configuration is set via class properties `label`, `icon`, `buttonClasses`, `xhr` and `destructive`. See `Handler`, `DeleteHandler` and `UnlinkHandler` for reference and examples.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

37
package.json Normal file
View File

@ -0,0 +1,37 @@
{
"name": "colymba-gridfield-bulk-editing-tools",
"version": "3.0.0",
"description": "Bulk upload and record editing for SilverStripe CMS",
"engines": {
"node": "^6.x"
},
"scripts": {
"build": "NODE_ENV=production webpack -p --bail --progress",
"watch": "NODE_ENV=development webpack --watch --progress"
},
"repository": {
"type": "git",
"url": "git://github.com/tractorcow/silverstripe-fluent.git"
},
"keywords": [
"bulk",
"manager",
"upload",
"silverstripe"
],
"author": "Thierry Francois",
"license": "BSD-3-Clause",
"bugs": {
"url": "https://github.com/colymba/GridFieldBulkEditingTools/issues"
},
"homepage": "https://github.com/colymba/GridFieldBulkEditingTools",
"dependencies": {},
"devDependencies": {
"node-sass": "^4.7.2",
"sass-loader": "^6.0",
"css-loader": "^0.28",
"style-loader": "^0.19",
"extract-text-webpack-plugin": "^3.0",
"webpack": "^3.10.0"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 177 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 KiB

View File

@ -0,0 +1,112 @@
<?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 DeleteHandler extends Handler
{
/**
* URL segment used to call this handler
* If none given, @BulkManager will fallback to the Unqualified class name
*
* @var string
*/
private static $url_segment = 'delete';
/**
* RequestHandler allowed actions.
*
* @var array
*/
private static $allowed_actions = array('delete');
/**
* RequestHandler url => action map.
*
* @var array
*/
private static $url_handlers = array(
'' => 'delete',
);
/**
* Front-end label for this handler's action
*
* @var string
*/
protected $label = 'Delete';
/**
* Front-end icon path for this handler's action.
*
* @var string
*/
protected $icon = '';
/**
* Extra classes to add to the bulk action button for this handler
* Can also be used to set the button font-icon e.g. font-icon-trash
*
* @var string
*/
protected $buttonClasses = 'font-icon-trash';
/**
* Whether this handler should be called via an XHR from the front-end
*
* @var boolean
*/
protected $xhr = true;
/**
* Set to true is this handler will destroy any data.
* A warning and confirmation will be shown on the front-end.
*
* @var boolean
*/
protected $destructive = true;
/**
* Return i18n localized front-end label
*
* @return array
*/
public function getI18nLabel()
{
return _t('GRIDFIELD_BULK_MANAGER.DELETE_SELECT_LABEL', $this->getLabel());
}
/**
* Delete the selected records passed from the delete bulk action.
*
* @param HTTPRequest $request
*
* @return HTTPResponse List of deleted records ID
*/
public function delete(HTTPRequest $request)
{
$ids = array();
foreach ($this->getRecords() as $record) {
array_push($ids, $record->ID);
$record->delete();
}
$response = new HTTPResponse(Convert::raw2json(array(
'done' => true,
'records' => $ids,
)));
$response->addHeader('Content-Type', 'text/json');
return $response;
}
}

View File

@ -21,6 +21,14 @@ use SilverStripe\View\Requirements;
*/
class EditHandler extends Handler
{
/**
* URL segment used to call this handler
* If none given, @BulkManager will fallback to the Unqualified class name
*
* @var string
*/
private static $url_segment = 'edit';
/**
* RequestHandler allowed actions.
*
@ -38,11 +46,58 @@ class EditHandler extends Handler
* @var array
*/
private static $url_handlers = array(
'bulkEdit/bulkEditForm' => 'bulkEditForm',
'bulkEdit/recordEditForm' => 'recordEditForm',
'bulkEdit' => 'index',
'bulkEditForm' => 'bulkEditForm',
'recordEditForm' => 'recordEditForm',
'' => 'index',
);
/**
* Front-end label for this handler's action
*
* @var string
*/
protected $label = 'Edit';
/**
* Front-end icon path for this handler's action.
*
* @var string
*/
protected $icon = '';
/**
* Extra classes to add to the bulk action button for this handler
* Can also be used to set the button font-icon e.g. font-icon-trash
*
* @var string
*/
protected $buttonClasses = 'font-icon-edit';
/**
* Whether this handler should be called via an XHR from the front-end
*
* @var boolean
*/
protected $xhr = false;
/**
* Set to true is this handler will destroy any data.
* A warning and confirmation will be shown on the front-end.
*
* @var boolean
*/
protected $destructive = false;
/**
* Return i18n localized front-end label
*
* @return array
*/
public function getI18nLabel()
{
return _t('GRIDFIELD_BULK_MANAGER.EDIT_SELECT_LABEL', $this->getLabel());
}
/**
* Return URL to this RequestHandler.
*
@ -52,7 +107,7 @@ class EditHandler extends Handler
*/
public function Link($action = null)
{
return Controller::join_links(parent::Link(), 'bulkEdit', $action);
return Controller::join_links(parent::Link(), $this->stat('url_segment'), $action);
}
/**
@ -312,9 +367,9 @@ class EditHandler extends Handler
$form->addExtraClass('center cms-content');
$form->setAttribute('data-pjax-fragment', 'CurrentForm Content');
Requirements::javascript(BULKEDITTOOLS_MANAGER_PATH . '/javascript/GridFieldBulkEditingForm.js');
Requirements::css(BULKEDITTOOLS_MANAGER_PATH . '/css/GridFieldBulkEditingForm.css');
Requirements::add_i18n_javascript(BULKEDITTOOLS_PATH . '/lang/js');
Requirements::javascript('colymba/gridfield-bulk-editing-tools:client/dist/js/bulkTools.js');
Requirements::css('colymba/gridfield-bulk-editing-tools:client/dist/styles/bulkTools.css');
Requirements::add_i18n_javascript('colymba/gridfield-bulk-editing-tools:lang');
if ($this->request->isAjax()) {
$response = new HTTPResponse(

View File

@ -0,0 +1,329 @@
<?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
* and implements useful functions like {@link getRecordIDList()} and {@link getRecords()}.
*
* @author colymba
*/
class Handler extends RequestHandler
{
/**
* URL segment used to call this handler
* If none given, @BulkManager will fallback to the Unqualified class name
*
* @var string
*/
private static $url_segment = null;
/**
* Related GridField instance.
*
* @var GridField
*/
protected $gridField;
/**
* GridFieldBulkManager instance.
*
* @var GridFieldBulkManager
*/
protected $component;
/**
* Current controller instance.
*
* @var Controller
*/
protected $controller;
/**
* Front-end label for this handler's action
*
* @var string
*/
protected $label = 'Action';
/**
* Front-end icon path for this handler's action.
*
* @var string
*/
protected $icon = '';
/**
* Extra classes to add to the bulk action button for this handler
* Can also be used to set the button font-icon e.g. font-icon-trash
*
* @var string
*/
protected $buttonClasses = '';
/**
* Whether this handler should be called via an XHR from the front-end
*
* @var boolean
*/
protected $xhr = true;
/**
* Set to true is this handler will destroy any data.
* A warning and confirmation will be shown on the front-end.
*
* @var boolean
*/
protected $destructive = false;
/**
* @param GridField $gridField
* @param GridField_URLHandler $component
* @param Controller $controller
*/
public function __construct($gridField = null, $component = null, $controller = null)
{
$this->gridField = $gridField;
$this->component = $component;
$this->controller = $controller;
parent::__construct();
}
/**
* Return front-end configuration
*
* @return array
*/
public function getConfig()
{
$config = array(
'label' => $this->getI18nLabel(),
'icon' => $this->getIcon(),
'buttonClasses' => $this->getButtonClasses(),
'xhr' => $this->getXhr(),
'destructive' => $this->getDestructive()
);
return $config;
}
/**
* Set if hanlder performs destructive actions
*
* @param boolean destructive If true, a warning will be shown on the front-end
* @return RequestHandler
*/
public function setDestructive($destructive)
{
$this->destructive = $destructive;
return $this;
}
/**
* True if the hanlder performs destructive actions
*
* @return boolean
*/
public function getDestructive()
{
return $this->destructive;
}
/**
* Set if handler is called via XHR
*
* @param boolean xhr If true the handler will be called via an XHR from front-end
* @return RequestHandler
*/
public function setXhr($xhr)
{
$this->xhr = $xhr;
return $this;
}
/**
* True if handler is called via XHR
*
* @return boolean
*/
public function getXhr()
{
return $this->xhr;
}
/**
* Set front-end buttonClasses
*
* @return RequestHandler
*/
public function setButtonClasses($buttonClasses)
{
$this->buttonClasses = $buttonClasses;
return $this;
}
/**
* Return front-end buttonClasses
*
* @return string
*/
public function getButtonClasses()
{
return $this->buttonClasses;
}
/**
* Set front-end icon
*
* @return RequestHandler
*/
public function setIcon($icon)
{
$this->icon = $icon;
return $this;
}
/**
* Return front-end icon
*
* @return string
*/
public function getIcon()
{
return $this->icon;
}
/**
* Set front-end label
*
* @return RequestHandler
*/
public function setLabel($label)
{
$this->label = $label;
return $this;
}
/**
* Return front-end label
*
* @return string
*/
public function getLabel()
{
return $this->label;
}
/**
* Return i18n localized front-end label
*
* @return array
*/
public function getI18nLabel()
{
return _t('GRIDFIELD_BULK_MANAGER.HANDLER_LABEL', $this->getLabel());
}
/**
* Returns the URL for this RequestHandler.
*
* @author SilverStripe
*
* @see GridFieldDetailForm_ItemRequest
*
* @param string $action
*
* @return string
*/
public function Link($action = null)
{
return Controller::join_links($this->gridField->Link(), 'bulkAction', $action);
}
/**
* Traverse up nested requests until we reach the first that's not a GridFieldDetailForm or GridFieldDetailForm_ItemRequest.
* The opposite of {@link Controller::curr()}, required because
* Controller::$controller_stack is not directly accessible.
*
* @return Controller
*/
protected function getToplevelController()
{
$c = $this->controller;
while ($c && ($c instanceof GridFieldDetailForm_ItemRequest || $c instanceof GridFieldDetailForm)) {
$c = $c->getController();
}
return $c;
}
/**
* Edited version of the GridFieldEditForm function
* adds the 'Bulk Upload' at the end of the crums.
*
* CMS-specific functionality: Passes through navigation breadcrumbs
* to the template, and includes the currently edited record (if any).
* see {@link LeftAndMain->Breadcrumbs()} for details.
*
* @author SilverStripe original Breadcrumbs() method
*
* @see GridFieldDetailForm_ItemRequest
*
* @param bool $unlinked
*
* @return ArrayData
*/
public function Breadcrumbs($unlinked = false)
{
if (!$this->controller->hasMethod('Breadcrumbs')) {
return;
}
$items = $this->controller->Breadcrumbs($unlinked);
$items->push(new ArrayData(array(
'Title' => 'Bulk Editing',
'Link' => false,
)));
return $items;
}
/**
* Returns the list of record IDs selected in the front-end.
*
* @return array List of IDs
*/
public function getRecordIDList()
{
$vars = $this->request->requestVars();
return $vars['records'];
}
/**
* Returns a DataList of the records selected in the front-end.
*
* @return DataList List of records
*/
public function getRecords()
{
$ids = $this->getRecordIDList();
if ($ids) {
$class = $this->gridField->list->dataClass;
return DataList::create($class)->byIDs($ids);
} else {
return false;
}
}
}

View File

@ -0,0 +1,108 @@
<?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 UnlinkHandler extends Handler
{
/**
* URL segment used to call this handler
* If none given, @BulkManager will fallback to the Unqualified class name
*
* @var string
*/
private static $url_segment = 'unlink';
/**
* RequestHandler allowed actions.
*
* @var array
*/
private static $allowed_actions = array('unLink');
/**
* RequestHandler url => action map.
*
* @var array
*/
private static $url_handlers = array(
'' => 'unLink',
);
/**
* Front-end label for this handler's action
*
* @var string
*/
protected $label = 'Unlink';
/**
* Front-end icon path for this handler's action.
*
* @var string
*/
protected $icon = '';
/**
* Extra classes to add to the bulk action button for this handler
* Can also be used to set the button font-icon e.g. font-icon-trash
*
* @var string
*/
protected $buttonClasses = 'font-icon-link-broken';
/**
* Whether this handler should be called via an XHR from the front-end
*
* @var boolean
*/
protected $xhr = true;
/**
* Set to true is this handler will destroy any data.
* A warning and confirmation will be shown on the front-end.
*
* @var boolean
*/
protected $destructive = false;
/**
* Return i18n localized front-end label
*
* @return array
*/
public function getI18nLabel()
{
return _t('GRIDFIELD_BULK_MANAGER.UNLINK_SELECT_LABEL', $this->getLabel());
}
/**
* Unlink the selected records passed from the unlink bulk action.
*
* @param HTTPRequest $request
*
* @return HTTPResponse List of affected records ID
*/
public function unLink(HTTPRequest $request)
{
$ids = $this->getRecordIDList();
$this->gridField->list->removeMany($ids);
$response = new HTTPResponse(Convert::raw2json(array(
'done' => true,
'records' => $ids,
)));
$response->addHeader('Content-Type', 'text/json');
return $response;
}
}

View File

@ -2,6 +2,7 @@
namespace Colymba\BulkManager;
use ReflectionClass;
use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Injector\Injector;
@ -24,7 +25,7 @@ class BulkManager implements GridField_HTMLProvider, GridField_ColumnProvider, G
* component configuration.
*
* 'editableFields' => fields editable on the Model
* 'actions' => maps of action name and configuration
* 'actions' => maps of action URL and Handler Class
*
* @var array
*/
@ -46,35 +47,9 @@ class BulkManager implements GridField_HTMLProvider, GridField_ColumnProvider, G
}
if ($defaultActions) {
$this->config['actions'] = array(
'bulkEdit' => array(
'label' => _t('GRIDFIELD_BULK_MANAGER.EDIT_SELECT_LABEL', 'Edit'),
'handler' => 'Colymba\\BulkManager\\BulkAction\\EditHandler',
'config' => array(
'isAjax' => false,
'icon' => 'pencil',
'isDestructive' => false,
),
),
'unLink' => array(
'label' => _t('GRIDFIELD_BULK_MANAGER.UNLINK_SELECT_LABEL', 'UnLink'),
'handler' => 'Colymba\\BulkManager\\BulkAction\\UnlinkHandler',
'config' => array(
'isAjax' => true,
'icon' => 'chain--minus',
'isDestructive' => false,
),
),
'delete' => array(
'label' => _t('GRIDFIELD_BULK_MANAGER.DELETE_SELECT_LABEL', 'Delete'),
'handler' => 'Colymba\\BulkManager\\BulkAction\\DeleteHandler',
'config' => array(
'isAjax' => true,
'icon' => 'decline',
'isDestructive' => true,
),
)
);
$this->addBulkAction('Colymba\\BulkManager\\BulkAction\\EditHandler')
->addBulkAction('Colymba\\BulkManager\\BulkAction\\UnlinkHandler')
->addBulkAction('Colymba\\BulkManager\\BulkAction\\DeleteHandler');
}
}
@ -125,49 +100,28 @@ class BulkManager implements GridField_HTMLProvider, GridField_ColumnProvider, G
/**
* Lets you add custom bulk actions to the bulk manager interface.
* Exisiting handler will be replaced
*
* @todo add config options for front-end: isAjax, icon
*
* @param string $name Bulk action's name. Used by RequestHandler.
* @param string $label Dropdown menu action's label. Default to ucfirst($name).
* @param string $handler RequestHandler class name for this action. Default to 'GridFieldBulkAction'.ucfirst($name).'Handler'
* @param array $config Front-end configuration array( 'isAjax' => true, 'icon' => 'accept', 'isDestructive' => false )
* @param string $hanlderClassName RequestHandler class name for this action.
* @param string $action Specific RequestHandler action to be called.
*
* @return GridFieldBulkManager Current GridFieldBulkManager instance
*/
public function addBulkAction($name, $label = null, $handler = null, $config = null)
public function addBulkAction($hanlderClassName, $action = null)
{
if (array_key_exists($name, $this->config['actions'])) {
user_error("Bulk action '$name' already exists.", E_USER_ERROR);
if (!$hanlderClassName || !ClassInfo::exists($hanlderClassName)) {
user_error("Bulk action handler not found: $handler", E_USER_ERROR);
}
if (!$label) {
$label = ucfirst($name);
$handler = Injector::inst()->get($hanlderClassName);
$urlSegment = $handler->config()->get('url_segment');
if (!$urlSegment)
{
$rc = new ReflectionClass($hanlderClassName);
$urlSegment = $rc->getShortName();
}
if (!$handler) {
$handler = 'Colymba\\BulkManager\\BulkAction\\' . ucfirst($name) . 'Handler';
}
if (!ClassInfo::exists($handler)) {
user_error("Bulk action handler for $name not found: $handler", E_USER_ERROR);
}
if ($config && !is_array($config)) {
user_error('Bulk action front-end config should be an array of key => value pairs.', E_USER_ERROR);
} else {
$config = array(
'isAjax' => isset($config['isAjax']) ? $config['isAjax'] : true,
'icon' => isset($config['icon']) ? $config['icon'] : 'accept',
'isDestructive' => isset($config['isDestructive']) ? $config['isDestructive'] : false,
);
}
$this->config['actions'][$name] = array(
'label' => $label,
'handler' => $handler,
'config' => $config,
);
$this->config['actions'][$urlSegment] = $hanlderClassName;
return $this;
}
@ -175,19 +129,27 @@ class BulkManager implements GridField_HTMLProvider, GridField_ColumnProvider, G
/**
* Removes a bulk actions from the bulk manager interface.
*
* @param string $name Bulk action's name
* @param string $hanlderClassName RequestHandler class name of the action to remove.
* @param string $urlSegment URL segment of the action to remove.
*
* @return GridFieldBulkManager Current GridFieldBulkManager instance
*/
public function removeBulkAction($name)
public function removeBulkAction($hanlderClassName = null, $urlSegment = null)
{
if (!array_key_exists($name, $this->config['actions'])) {
user_error("Bulk action '$name' doesn't exists.", E_USER_ERROR);
if (!$hanlderClassName && !$urlSegment) {
user_error("Provide either a class name or URL segment", E_USER_ERROR);
}
unset($this->config['actions'][$name]);
foreach ($this->config['actions'] as $url => $class)
{
if ($hanlderClassName === $class || $urlSegment === $url)
{
unset($this->config['actions'][$url]);
return $this;
}
}
return $this;
user_error("Bulk action '$hanlderClassName' or '$urlSegment' doesn't exists.", E_USER_ERROR);
}
/* **********************************************************************
@ -277,9 +239,9 @@ class BulkManager implements GridField_HTMLProvider, GridField_ColumnProvider, G
*/
public function getHTMLFragments($gridField)
{
Requirements::css(BULKEDITTOOLS_MANAGER_PATH . '/css/GridFieldBulkManager.css');
Requirements::javascript(BULKEDITTOOLS_MANAGER_PATH . '/javascript/GridFieldBulkManager.js');
Requirements::add_i18n_javascript(BULKEDITTOOLS_PATH . '/lang/js');
Requirements::javascript('colymba/gridfield-bulk-editing-tools:client/dist/js/bulkTools.js');
Requirements::css('colymba/gridfield-bulk-editing-tools:client/dist/styles/bulkTools.css');
Requirements::add_i18n_javascript('colymba/gridfield-bulk-editing-tools:lang');
if (!count($this->config['actions'])) {
user_error('Trying to use GridFieldBulkManager without any bulk action.', E_USER_ERROR);
@ -288,25 +250,32 @@ class BulkManager implements GridField_HTMLProvider, GridField_ColumnProvider, G
$actionsListSource = array();
$actionsConfig = array();
foreach ($this->config['actions'] as $action => $actionData) {
$actionsListSource[$action] = $actionData['label'];
$actionsConfig[$action] = $actionData['config'];
}
foreach ($this->config['actions'] as $urlSegment => $hanlderClassName) {
$handler = Injector::inst()->get($hanlderClassName);
$handlerConfig = $handler->getConfig();
reset($this->config['actions']);
$firstAction = key($this->config['actions']);
$actionsListSource[$urlSegment] = $handlerConfig['label'];
$actionsConfig[$urlSegment] = $handlerConfig;
}
$dropDownActionsList = DropdownField::create('bulkActionName', '')
->setSource($actionsListSource)
->addExtraClass('bulkActionName no-change-track no-chosen')
->setAttribute('id', '');
reset($actionsListSource);
$firstAction = key($actionsListSource);
$buttonClasses = $actionsConfig[$firstAction]['buttonClasses'];
$buttonClasses .= ($actionsConfig[$firstAction]['destructive'] ? ' btn-outline-danger' : '');
$templateData = array(
'Menu' => $dropDownActionsList,
'Button' => array(
'Label' => _t('GRIDFIELD_BULK_MANAGER.ACTION_BTN_LABEL', 'Go'),
'DataURL' => $gridField->Link('bulkAction'),
'Icon' => $this->config['actions'][$firstAction]['config']['icon'],
'Icon' => $actionsConfig[$firstAction]['icon'],
'Classes' => $buttonClasses,
'DataConfig' => json_encode($actionsConfig),
),
'Select' => array(
@ -318,7 +287,7 @@ class BulkManager implements GridField_HTMLProvider, GridField_ColumnProvider, G
$templateData = new ArrayData($templateData);
return array(
'header' => $templateData->renderWith('BulkManagerButtons'),
'header' => $templateData->renderWith('Colymba\\BulkManager\\BulkManagerButtons'),
);
}
@ -356,23 +325,16 @@ class BulkManager implements GridField_HTMLProvider, GridField_ColumnProvider, G
public function handleBulkAction($gridField, $request)
{
$controller = $gridField->getForm()->getController();
$actionUrlSegment = $request->shift();
$handlerClass = $this->config['actions'][$actionUrlSegment];
foreach ($this->config['actions'] as $name => $data) {
$handlerClass = $data['handler'];
$urlHandlers = Config::inst()->get($handlerClass, 'url_handlers', Config::UNINHERITED);
if ($urlHandlers) {
foreach ($urlHandlers as $rule => $action) {
if ($request->match($rule, false)) {
//print_r('matched ' . $handlerClass . ' to ' . $rule);
$handler = Injector::inst()->create($handlerClass, $gridField, $this, $controller);
return $handler->handleRequest($request);
}
}
}
$handler = Injector::inst()->create($handlerClass, $gridField, $this, $controller);
if ($handler)
{
return $handler->handleRequest($request);
}
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 ' . $actionUrlSegment . ' URL segment.', E_USER_ERROR);
}
}

View File

@ -3,6 +3,8 @@
namespace Colymba\BulkUpload;
use Colymba\BulkUpload\BulkUploaderRequest;
use Colymba\BulkUpload\BulkUploadField;
use SilverStripe\Core\Config\Config;
use SilverStripe\Dev\Deprecation;
use SilverStripe\Forms\FormAction;
@ -105,17 +107,7 @@ class BulkUploader implements GridField_HTMLProvider, GridField_URLHandler
*/
public function setConfig($reference, $value)
{
if (in_array($reference, array('folderName', 'maxFileSize', 'sequentialUploads', 'canAttachExisting', 'canPreviewFolder'))) {
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);
} elseif ($reference === 'maxFileSize') {
$this->setUfValidatorSetup('setAllowedMaxFileSize', $value);
} else {
$this->setUfConfig($reference, $value);
}
} elseif (!array_key_exists($reference, $this->config)) {
if (!array_key_exists($reference, $this->config)) {
user_error("Unknown option reference: $reference", E_USER_ERROR);
}
@ -377,10 +369,7 @@ class BulkUploader implements GridField_HTMLProvider, GridField_URLHandler
if (!singleton($gridField->getModelClass())->canEdit()) {
return array();
}
// check BulkManager exists
$bulkManager = $gridField->getConfig()->getComponentsByType('Colymba\\BulkManager\\BulkManager');
// upload management buttons
$finishButton = FormAction::create('Finish', _t('GRIDFIELD_BULK_UPLOAD.FINISH_BTN_LABEL', 'Finish'))
->addExtraClass('bulkUploadFinishButton')
@ -392,44 +381,19 @@ class BulkUploader implements GridField_HTMLProvider, GridField_URLHandler
->setAttribute('data-icon', 'arrow-circle-double')
->setUseButtonTag(true);
if (count($bulkManager)) {
$cancelButton = FormAction::create('Cancel', _t('GRIDFIELD_BULK_UPLOAD.CANCEL_BTN_LABEL', 'Cancel'))
->addExtraClass('bulkUploadCancelButton ss-ui-action-destructive')
->setAttribute('data-icon', 'decline')
->setAttribute('data-url', $gridField->Link('bulkupload/cancel'))
->setUseButtonTag(true);
$bulkManager_config = $bulkManager->first()->getConfig();
$bulkManager_actions = $bulkManager_config['actions'];
if (array_key_exists('bulkedit', $bulkManager_actions)) {
$editAllButton = FormAction::create('EditAll', _t('GRIDFIELD_BULK_UPLOAD.EDIT_ALL_BTN_LABEL', 'Edit all'))
->addExtraClass('bulkUploadEditButton')
->setAttribute('data-icon', 'pencil')
->setAttribute('data-url', $gridField->Link('bulkupload/edit'))
->setUseButtonTag(true);
} else {
$editAllButton = '';
}
} else {
$cancelButton = '';
$editAllButton = '';
}
// get uploadField + inject extra buttons
// get uploadField
$uploadField = $this->bulkUploadField($gridField);
$uploadField->FinishButton = $finishButton;
$uploadField->CancelButton = $cancelButton;
$uploadField->EditAllButton = $editAllButton;
$uploadField->ClearErrorButton = $clearErrorButton;
$data = ArrayData::create(array(
'Finish' => $finishButton,
'ClearErrors' => $clearErrorButton,
'Colspan' => (count($gridField->getColumns())),
'UploadField' => $uploadField->Field() // call ->Field() to get requirements in right order
));
Requirements::css(BULKEDITTOOLS_UPLOAD_PATH . '/css/GridFieldBulkUpload.css');
Requirements::javascript(BULKEDITTOOLS_UPLOAD_PATH . '/javascript/GridFieldBulkUpload.js');
Requirements::add_i18n_javascript(BULKEDITTOOLS_PATH . '/lang/js');
Requirements::javascript('colymba/gridfield-bulk-editing-tools:client/dist/js/bulkTools.js');
Requirements::css('colymba/gridfield-bulk-editing-tools:client/dist/styles/bulkTools.css');
Requirements::add_i18n_javascript('colymba/gridfield-bulk-editing-tools:lang');
return array(
'header' => $data->renderWith('Colymba\\BulkUpload\\BulkUploader'),

View File

@ -8,8 +8,8 @@
$Menu
<a data-url="$Button.DataURL"
data-config="$Button.DataConfig"
class="doBulkActionButton btn btn-primary"
data-icon="$Button.Icon">
class="doBulkActionButton btn btn-outline-secondary $Button.Classes">
<% if $Button.Icon %><img src="$Button.Icon" alt="" /><% end_if %>
$Button.Label
</a>
<label class="form-check-label">

View File

@ -1,5 +1,7 @@
<tr class="bulkUploader">
<th class="" colspan="$Colspan">
$UploadField
$Finish
$ClearErrors
</th>
</tr>

56
webpack.config.js Normal file
View File

@ -0,0 +1,56 @@
const path = require('path');
const PATHS = {
ROOT: path.resolve(),
SRC: path.resolve('client/src'),
DIST: path.resolve('client/dist'),
};
const ENV = process.env.NODE_ENV;
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const extractSASS = new ExtractTextPlugin({ filename: 'styles/bulkTools.css' });
const config = [
{
name: 'js',
entry: [
`${PATHS.SRC}/js/manager.js`,
`${PATHS.SRC}/js/managerBulkEditingForm.js`,
`${PATHS.SRC}/js/uploader.js`
],
output: {
path: PATHS.DIST,
filename: 'js/bulkTools.js'
},
devtool: (ENV !== 'production') ? 'source-map' : ''
},{
name: 'scss',
entry: [
`${PATHS.SRC}/styles/manager.scss`,
`${PATHS.SRC}/styles/managerBulkEditingForm.scss`,
`${PATHS.SRC}/styles/uploader.scss`
],
output: {
path: PATHS.DIST,
filename: 'styles/bundle.css'
},
devtool: (ENV !== 'production') ? 'source-map' : '',
module: {
rules: [{
test: /\.scss$/,
use: extractSASS.extract({
fallback: 'style-loader',
use: [ 'css-loader', 'sass-loader' ]
})
}]
},
plugins: [
extractSASS
]
}
];
module.exports = config;