diff --git a/.gitignore b/.gitignore index 52c6233..24fcb0d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,9 @@ +# General +.DS_Store +.AppleDouble +.LSOverride + transifexAuth.json **/css/bourbon -**/.sass-cache \ No newline at end of file +**/.sass-cache +node_modules/ \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..50920fc --- /dev/null +++ b/LICENSE @@ -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. diff --git a/README.md b/README.md index 3c0c7e6..357c168 100644 --- a/README.md +++ b/README.md @@ -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) diff --git a/bulkManager/code/BulkAction/DeleteHandler.php b/bulkManager/code/BulkAction/DeleteHandler.php deleted file mode 100644 index 4453ccc..0000000 --- a/bulkManager/code/BulkAction/DeleteHandler.php +++ /dev/null @@ -1,57 +0,0 @@ - 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; - } -} diff --git a/bulkManager/code/BulkAction/Handler.php b/bulkManager/code/BulkAction/Handler.php deleted file mode 100644 index f68a82e..0000000 --- a/bulkManager/code/BulkAction/Handler.php +++ /dev/null @@ -1,148 +0,0 @@ -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; - } - } -} diff --git a/bulkManager/code/BulkAction/UnlinkHandler.php b/bulkManager/code/BulkAction/UnlinkHandler.php deleted file mode 100644 index 48fc3b6..0000000 --- a/bulkManager/code/BulkAction/UnlinkHandler.php +++ /dev/null @@ -1,53 +0,0 @@ - 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; - } -} diff --git a/bulkManager/css/GridFieldBulkEditingForm.css b/bulkManager/css/GridFieldBulkEditingForm.css deleted file mode 100644 index cfdea76..0000000 --- a/bulkManager/css/GridFieldBulkEditingForm.css +++ /dev/null @@ -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 */ diff --git a/bulkManager/css/GridFieldBulkEditingForm.css.map b/bulkManager/css/GridFieldBulkEditingForm.css.map deleted file mode 100644 index 3410ecf..0000000 --- a/bulkManager/css/GridFieldBulkEditingForm.css.map +++ /dev/null @@ -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" -} \ No newline at end of file diff --git a/bulkManager/css/GridFieldBulkManager.css b/bulkManager/css/GridFieldBulkManager.css deleted file mode 100644 index 005c515..0000000 --- a/bulkManager/css/GridFieldBulkManager.css +++ /dev/null @@ -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 */ diff --git a/bulkManager/css/GridFieldBulkManager.css.map b/bulkManager/css/GridFieldBulkManager.css.map deleted file mode 100644 index 6bb71bf..0000000 --- a/bulkManager/css/GridFieldBulkManager.css.map +++ /dev/null @@ -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" -} \ No newline at end of file diff --git a/bulkManager/screenshots/GridFieldBulkEditingTools_00_Upload-and-Edit-buttons.png b/bulkManager/screenshots/GridFieldBulkEditingTools_00_Upload-and-Edit-buttons.png deleted file mode 100644 index 5cba552..0000000 Binary files a/bulkManager/screenshots/GridFieldBulkEditingTools_00_Upload-and-Edit-buttons.png and /dev/null differ diff --git a/bulkUpload/css/GridFieldBulkUpload.css b/bulkUpload/css/GridFieldBulkUpload.css deleted file mode 100644 index fdb7916..0000000 --- a/bulkUpload/css/GridFieldBulkUpload.css +++ /dev/null @@ -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; } diff --git a/bulkUpload/screenshots/GridFieldBulkEditingTools_01_Uploading.png b/bulkUpload/screenshots/GridFieldBulkEditingTools_01_Uploading.png deleted file mode 100644 index 80ae423..0000000 Binary files a/bulkUpload/screenshots/GridFieldBulkEditingTools_01_Uploading.png and /dev/null differ diff --git a/bulkUpload/screenshots/GridFieldBulkEditingTools_02_Bulk-Edit.png b/bulkUpload/screenshots/GridFieldBulkEditingTools_02_Bulk-Edit.png deleted file mode 100644 index 36f81d5..0000000 Binary files a/bulkUpload/screenshots/GridFieldBulkEditingTools_02_Bulk-Edit.png and /dev/null differ diff --git a/bulkUpload/screenshots/GridFieldBulkEditingTools_02_Uploads-Field-Editing.png b/bulkUpload/screenshots/GridFieldBulkEditingTools_02_Uploads-Field-Editing.png deleted file mode 100644 index ac66aee..0000000 Binary files a/bulkUpload/screenshots/GridFieldBulkEditingTools_02_Uploads-Field-Editing.png and /dev/null differ diff --git a/client/dist/js/bulkTools.js b/client/dist/js/bulkTools.js new file mode 100644 index 0000000..49b064a --- /dev/null +++ b/client/dist/js/bulkTools.js @@ -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);io&&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('')}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+n0?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)}]); \ No newline at end of file diff --git a/client/dist/js/bulkTools.js.map b/client/dist/js/bulkTools.js.map new file mode 100644 index 0000000..3851079 --- /dev/null +++ b/client/dist/js/bulkTools.js.map @@ -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('\"\"');\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":""} \ No newline at end of file diff --git a/client/dist/styles/bulkTools.css b/client/dist/styles/bulkTools.css new file mode 100644 index 0000000..21d4c1a --- /dev/null +++ b/client/dist/styles/bulkTools.css @@ -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} \ No newline at end of file diff --git a/client/dist/styles/bulkTools.css.map b/client/dist/styles/bulkTools.css.map new file mode 100644 index 0000000..2ebdf82 --- /dev/null +++ b/client/dist/styles/bulkTools.css.map @@ -0,0 +1 @@ +{"version":3,"sources":[],"names":[],"mappings":"","file":"styles/bulkTools.css","sourceRoot":""} \ No newline at end of file diff --git a/client/dist/styles/bundle.css b/client/dist/styles/bundle.css new file mode 100644 index 0000000..e146e77 --- /dev/null +++ b/client/dist/styles/bundle.css @@ -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 + +/***/ }) +/******/ ]); \ No newline at end of file diff --git a/client/dist/styles/bundle.css.map b/client/dist/styles/bundle.css.map new file mode 100644 index 0000000..df77551 --- /dev/null +++ b/client/dist/styles/bundle.css.map @@ -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":""} \ No newline at end of file diff --git a/lang/js/cs.js b/client/lang/cs.js similarity index 100% rename from lang/js/cs.js rename to client/lang/cs.js diff --git a/lang/js/de.js b/client/lang/de.js similarity index 100% rename from lang/js/de.js rename to client/lang/de.js diff --git a/lang/js/en.js b/client/lang/en.js similarity index 100% rename from lang/js/en.js rename to client/lang/en.js diff --git a/lang/js/fi.js b/client/lang/fi.js similarity index 100% rename from lang/js/fi.js rename to client/lang/fi.js diff --git a/lang/js/fr.js b/client/lang/fr.js similarity index 100% rename from lang/js/fr.js rename to client/lang/fr.js diff --git a/lang/js/it.js b/client/lang/it.js similarity index 100% rename from lang/js/it.js rename to client/lang/it.js diff --git a/lang/js/nl.js b/client/lang/nl.js similarity index 100% rename from lang/js/nl.js rename to client/lang/nl.js diff --git a/lang/js/pl.js b/client/lang/pl.js similarity index 100% rename from lang/js/pl.js rename to client/lang/pl.js diff --git a/lang/js/sk.js b/client/lang/sk.js similarity index 100% rename from lang/js/sk.js rename to client/lang/sk.js diff --git a/bulkManager/javascript/GridFieldBulkManager.js b/client/src/js/manager.js similarity index 86% rename from bulkManager/javascript/GridFieldBulkManager.js rename to client/src/js/manager.js index edf16e3..3d38944 100644 --- a/bulkManager/javascript/GridFieldBulkManager.js +++ b/client/src/js/manager.js @@ -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(''); + } } 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, diff --git a/bulkManager/javascript/GridFieldBulkEditingForm.js b/client/src/js/managerBulkEditingForm.js similarity index 100% rename from bulkManager/javascript/GridFieldBulkEditingForm.js rename to client/src/js/managerBulkEditingForm.js diff --git a/bulkUpload/javascript/GridFieldBulkUpload.js b/client/src/js/uploader.js similarity index 59% rename from bulkUpload/javascript/GridFieldBulkUpload.js rename to client/src/js/uploader.js index 3bc91c6..9561c05 100644 --- a/bulkUpload/javascript/GridFieldBulkUpload.js +++ b/client/src/js/uploader.js @@ -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 diff --git a/lang/js/src/en.json b/client/src/lang/en.json similarity index 100% rename from lang/js/src/en.json rename to client/src/lang/en.json diff --git a/bulkManager/css/GridFieldBulkManager.scss b/client/src/styles/manager.scss similarity index 78% rename from bulkManager/css/GridFieldBulkManager.scss rename to client/src/styles/manager.scss index f5d5dc5..c7a1b52 100644 --- a/bulkManager/css/GridFieldBulkManager.scss +++ b/client/src/styles/manager.scss @@ -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; - } + }*/ } } diff --git a/bulkManager/css/GridFieldBulkEditingForm.scss b/client/src/styles/managerBulkEditingForm.scss similarity index 100% rename from bulkManager/css/GridFieldBulkEditingForm.scss rename to client/src/styles/managerBulkEditingForm.scss diff --git a/bulkUpload/css/GridFieldBulkUpload.scss b/client/src/styles/uploader.scss similarity index 97% rename from bulkUpload/css/GridFieldBulkUpload.scss rename to client/src/styles/uploader.scss index ecb28f9..942da68 100644 --- a/bulkUpload/css/GridFieldBulkUpload.scss +++ b/client/src/styles/uploader.scss @@ -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; } diff --git a/composer.json b/composer.json index a366cb0..a41c2a1 100644 --- a/composer.json +++ b/composer.json @@ -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/" } } } diff --git a/bulkManager/BULK_MANAGER.md b/docs/en/BULK_MANAGER.md similarity index 58% rename from bulkManager/BULK_MANAGER.md rename to docs/en/BULK_MANAGER.md index 061e939..3838016 100644 --- a/bulkManager/BULK_MANAGER.md +++ b/docs/en/BULK_MANAGER.md @@ -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. diff --git a/bulkUpload/BULK_UPLOAD.md b/docs/en/BULK_UPLOAD.md similarity index 100% rename from bulkUpload/BULK_UPLOAD.md rename to docs/en/BULK_UPLOAD.md diff --git a/images/spinner.gif b/images/spinner.gif deleted file mode 100644 index e705856..0000000 Binary files a/images/spinner.gif and /dev/null differ diff --git a/package.json b/package.json new file mode 100644 index 0000000..e787f9d --- /dev/null +++ b/package.json @@ -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" + } +} diff --git a/screenshots/bulkAction.jpg b/screenshots/bulkAction.jpg deleted file mode 100644 index cc4457b..0000000 Binary files a/screenshots/bulkAction.jpg and /dev/null differ diff --git a/screenshots/bulkEdit.jpg b/screenshots/bulkEdit.jpg deleted file mode 100644 index c6daa4b..0000000 Binary files a/screenshots/bulkEdit.jpg and /dev/null differ diff --git a/screenshots/bulkUpload.jpg b/screenshots/bulkUpload.jpg deleted file mode 100644 index b6a588a..0000000 Binary files a/screenshots/bulkUpload.jpg and /dev/null differ diff --git a/screenshots/preview.png b/screenshots/preview.png deleted file mode 100644 index 6266c65..0000000 Binary files a/screenshots/preview.png and /dev/null differ diff --git a/src/BulkManager/BulkAction/DeleteHandler.php b/src/BulkManager/BulkAction/DeleteHandler.php new file mode 100644 index 0000000..f08eddc --- /dev/null +++ b/src/BulkManager/BulkAction/DeleteHandler.php @@ -0,0 +1,112 @@ + 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; + } +} diff --git a/bulkManager/code/BulkAction/EditHandler.php b/src/BulkManager/BulkAction/EditHandler.php similarity index 87% rename from bulkManager/code/BulkAction/EditHandler.php rename to src/BulkManager/BulkAction/EditHandler.php index cb8898c..613f2df 100644 --- a/bulkManager/code/BulkAction/EditHandler.php +++ b/src/BulkManager/BulkAction/EditHandler.php @@ -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( diff --git a/src/BulkManager/BulkAction/Handler.php b/src/BulkManager/BulkAction/Handler.php new file mode 100644 index 0000000..c3cb6d2 --- /dev/null +++ b/src/BulkManager/BulkAction/Handler.php @@ -0,0 +1,329 @@ +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; + } + } +} diff --git a/src/BulkManager/BulkAction/UnlinkHandler.php b/src/BulkManager/BulkAction/UnlinkHandler.php new file mode 100644 index 0000000..2a2c8e5 --- /dev/null +++ b/src/BulkManager/BulkAction/UnlinkHandler.php @@ -0,0 +1,108 @@ + 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; + } +} diff --git a/bulkManager/code/BulkManager.php b/src/BulkManager/BulkManager.php similarity index 61% rename from bulkManager/code/BulkManager.php rename to src/BulkManager/BulkManager.php index 39344d6..5137e97 100644 --- a/bulkManager/code/BulkManager.php +++ b/src/BulkManager/BulkManager.php @@ -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); } } diff --git a/bulkUpload/code/BulkUploadField.php b/src/BulkUploader/BulkUploadField.php similarity index 100% rename from bulkUpload/code/BulkUploadField.php rename to src/BulkUploader/BulkUploadField.php diff --git a/bulkUpload/code/BulkUploader.php b/src/BulkUploader/BulkUploader.php similarity index 82% rename from bulkUpload/code/BulkUploader.php rename to src/BulkUploader/BulkUploader.php index 47514ee..6f2ada2 100644 --- a/bulkUpload/code/BulkUploader.php +++ b/src/BulkUploader/BulkUploader.php @@ -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'), diff --git a/bulkUpload/code/BulkUploaderRequest.php b/src/BulkUploader/BulkUploaderRequest.php similarity index 100% rename from bulkUpload/code/BulkUploaderRequest.php rename to src/BulkUploader/BulkUploaderRequest.php diff --git a/bulkUpload/code/GridFieldBulkImageUpload.php b/src/BulkUploader/GridFieldBulkImageUpload.php similarity index 100% rename from bulkUpload/code/GridFieldBulkImageUpload.php rename to src/BulkUploader/GridFieldBulkImageUpload.php diff --git a/bulkManager/templates/BulkManagerButtons.ss b/templates/Colymba/BulkManager/BulkManagerButtons.ss similarity index 83% rename from bulkManager/templates/BulkManagerButtons.ss rename to templates/Colymba/BulkManager/BulkManagerButtons.ss index ac8f897..3ef1588 100644 --- a/bulkManager/templates/BulkManagerButtons.ss +++ b/templates/Colymba/BulkManager/BulkManagerButtons.ss @@ -8,8 +8,8 @@ $Menu + class="doBulkActionButton btn btn-outline-secondary $Button.Classes"> + <% if $Button.Icon %><% end_if %> $Button.Label