diff --git a/_config.php b/_config.php new file mode 100644 index 0000000..b3d9bbc --- /dev/null +++ b/_config.php @@ -0,0 +1 @@ +imageFieldName = $imageField; + + if ( !is_array($editableFields) ) $editableFields = array($editableFields); + $this->recordEditableFields = $editableFields; + } + + public function setRecordImageField($field) + { + $this->imageFieldName = $field; + } + + public function setRecordEditableFields($fields) + { + $this->recordEditableFields = $fields; + } + + public function getRecordImageField() + { + return $this->imageFieldName; + } + + public function getRecordEditableFields() + { + return $this->recordEditableFields; + } + + /** + * + * @param GridField $gridField + * @return Array + */ + public function getHTMLFragments($gridField) { + + $data = new ArrayData(array( + 'NewLink' => $gridField->Link('bulkimageupload'), + 'ButtonName' => 'Bulk Upload' + )); + + return array( + 'toolbar-header-right' => $data->renderWith('GridFieldAddNewbutton') + ); + } + + /** + * + * @param GridField $gridField + * @return Array + */ + public function getURLHandlers($gridField) { + return array( + 'bulkimageupload' => 'handleBulkUpload' + ); + } + + /** + * + * @param type $gridField + * @param type $request + * @return type + */ + public function handleBulkUpload($gridField, $request) + { + $controller = $gridField->getForm()->Controller(); + $handler = new GridFieldBulkImageUpload_Request($gridField, $this, $controller); + + return $handler->handleRequest($request, DataModel::inst()); + } +} \ No newline at end of file diff --git a/code/GridFieldBulkImageUpload_Request.php b/code/GridFieldBulkImageUpload_Request.php new file mode 100644 index 0000000..7266742 --- /dev/null +++ b/code/GridFieldBulkImageUpload_Request.php @@ -0,0 +1,349 @@ + '$Action' + ); + + /** + * + * @param GridFIeld $gridField + * @param GridField_URLHandler $component + * @param Controller $controller + */ + public function __construct($gridField, $component, $controller) { + $this->gridField = $gridField; + $this->component = $component; + $this->controller = $controller; + $this->createdRecords = array(); + parent::__construct(); + } + + /** + * Returns the URL for this RequestHandler + * @param String $action + * @return String + */ + public function Link($action = null) { + return Controller::join_links($this->gridField->Link(), 'bulkimageupload', $action); + } + + /** + * Default and main action that returns the upload form etc... + * @param SS_HTTPRequest $request + * @return String Form HTML ??? + */ + public function index(SS_HTTPRequest $request) + { + Requirements::javascript(FRAMEWORK_DIR . '/javascript/AssetUploadField.js'); + Requirements::css(FRAMEWORK_DIR . '/css/AssetUploadField.css'); + + Requirements::javascript('GridFieldBulkImageUpload/javascript/GridFieldBulkImageUpload_downloadtemplate.js'); + Requirements::javascript('GridFieldBulkImageUpload/javascript/GridFieldBulkImageUpload.js'); + Requirements::css('GridFieldBulkImageUpload/css/GridFieldBulkImageUpload.css'); + + + $actions = new FieldList(); + /* + $actions->push(FormAction::create('update', 'Finish') + ->setUseButtonTag(true)->addExtraClass('ss-ui-action-constructive')->addExtraClass('bulkImageUploadUpdateBtn')->setAttribute('data-icon', 'accept')); + */ + + + $html = " + Link('update')."\" href=\"#\"> + Save All + "; + $actions->push(new LiteralField('savebutton', $html)); + + $crumbs = $this->Breadcrumbs(); + if($crumbs && $crumbs->count()>=2){ + $one_level_up = $crumbs->offsetGet($crumbs->count()-2); + + $html = " + Link('update')."\" href=\"".$one_level_up->Link."\"> + Save All & Finish + "; + $actions->push(new LiteralField('finishbutton', $html)); + + $html = " + Link('cancel')."\" href=\"#\"> + Cancel & Delete All + "; + $actions->push(new LiteralField('cancelbutton', $html)); + } + + + $uploadField = UploadField::create('BulkImageUploadField', ''); + $uploadField->setConfig('previewMaxWidth', 40); + $uploadField->setConfig('previewMaxHeight', 30); + + $uploadField->addExtraClass('ss-assetuploadfield'); + $uploadField->removeExtraClass('ss-uploadfield'); + + $uploadField->setTemplate('AssetUploadField'); + $uploadField->setConfig('downloadTemplateName','GridFieldBulkImageUpload_downloadtemplate'); + + + $uploadField->setConfig('url', $this->Link('upload')); + + $uploadField->setFolderName(ASSETS_DIR); + + + $form = new Form( + $this, + 'bulkImageUploadForm', + new FieldList( + $uploadField + ), + $actions + ); + + $form->setTemplate('LeftAndMain_EditForm'); + $form->addExtraClass('center cms-edit-form'); + $form->setAttribute('data-pjax-fragment', 'CurrentForm Content'); + + if($crumbs && $crumbs->count()>=2){ + $form->Backlink = $one_level_up->Link; + } + + $response = new SS_HTTPResponse(Convert::raw2json(array('Content' => $form->forTemplate()))); + $response->addHeader('Content-Type', 'text/json'); + $response->addHeader('X-Title', 'SilverStripe - Bulk '.$this->gridField->list->dataClass.' Image Upload'); + return $response; + } + + + public function upload(SS_HTTPRequest $request) + { + $recordClass = $this->gridField->list->dataClass; + $recordForeignKey = $this->gridField->list->foreignKey; + $recordForeignID = $this->gridField->list->foreignID; + + $record = Object::create($recordClass); + $record->setField($recordForeignKey, $recordForeignID); + $record->write(); + + $upload = new Upload(); + $tmpfile = $request->postVar('BulkImageUploadField'); + + // Check if the file has been uploaded into the temporary storage. + if (!$tmpfile) { + $return = array('error' => _t('UploadField.FIELDNOTSET', 'File information not found')); + } else { + $return = array( + 'name' => $tmpfile['name'], + 'size' => $tmpfile['size'], + 'type' => $tmpfile['type'], + 'error' => $tmpfile['error'] + ); + /* + $record->setField($this->component->getLabelFieldName(), $tmpfile['name']); + $record->write(); + */ + } + + // Process the uploaded file + if (!$return['error']) { + $fileObject = Object::create('Image'); + + // Get the uploaded file into a new file object. + try { + $upload->loadIntoFile($tmpfile, $fileObject, 'Uploads/bulk'); + } catch (Exception $e) { + // we shouldn't get an error here, but just in case + $return['error'] = $e->getMessage(); + } + + if (!$return['error']) { + if ($upload->isError()) { + $return['error'] = implode(' '.PHP_EOL, $upload->getErrors()); + } else { + $file = $upload->getFile(); + + // Attach the file to the related record. + $record->setField($this->component->getRecordImageField(), $file->ID); + $record->write(); + + // Collect all output data. + $return = array_merge($return, array( + 'id' => $file->ID, + 'name' => $file->getTitle() . '.' . $file->getExtension(), + 'url' => $file->getURL(), + 'preview_url' => $file->setHeight(55)->Link(), + 'thumbnail_url' => $file->SetRatioSize(40,30)->getURL(), + 'size' => $file->getAbsoluteSize(), + //'buttons' => $file->UploadFieldFileButtons, + 'record' => array( + 'ID' => $record->ID, + 'fields' => $this->component->getRecordEditableFields() + ) + )); + } + } + } + + array_push($this->createdRecords, $record->ID); + + $response = new SS_HTTPResponse(Convert::raw2json(array($return))); + $response->addHeader('Content-Type', 'text/plain'); + return $response; + } + + /** + * Update a record with the newly edited fields + * + * @param SS_HTTPRequest $request + * @return String + */ + public function update(SS_HTTPRequest $request) + { + $data = $request->requestVars(); + $recordID = false; + $recordFields = array(); + + foreach( $data as $key => $val) + { + if ( stripos($key, 'record_') !== false ) + { + if ( $key == 'record_ID' ) + { + $recordID = $val; + }else{ + $recordFields[str_ireplace('record_', '', $key)] = $val; + } + } + } + + $recordClass = $this->gridField->list->dataClass; + $record = DataObject::get_by_id($recordClass, $recordID); + + foreach($recordFields as $field => $value) + { + $record->setField($field, $value); + } + + $record->write(); + + return '{done:1,recordID:'.$recordID.'}'; + } + + /** + * + * @param SS_HTTPRequest $request + * @return String JSON + */ + public function cancel(SS_HTTPRequest $request) + { + $data = $this->getParsedPostData($request->requestVars()); + $return = array(); + + $recordClass = $this->gridField->list->dataClass; + $record = DataObject::get_by_id($recordClass, $data['ID']); + $imageField = $this->component->getRecordImageField(); + + $imageID = $record->$imageField; + $image = DataObject::get_by_id('Image', $imageID); + + $return[$data['ID']]['imageID'] = $imageID; + $return[$data['ID']]['deletedDataObject'] = DataObject::delete_by_id($recordClass, $data['ID']); + + $return[$data['ID']]['deletedFormattedImages'] = $image->deleteFormattedImages(); + $return[$data['ID']]['deletedImageFile'] = unlink( Director::getAbsFile($image->getRelativePath()) ); + + + $response = new SS_HTTPResponse(Convert::raw2json($return)); + $response->addHeader('Content-Type', 'text/plain'); + return $response; + } + + /** + * + * @param array $data + * @return array + */ + public function getParsedPostData(array $data) + { + $return = array(); + $fields = array(); + + foreach( $data as $key => $val) + { + if ( stripos($key, 'record_') !== false ) + { + if ( $key == 'record_ID' ) + { + $return['ID'] = $val; + }else{ + $fields[str_ireplace('record_', '', $key)] = $val; + } + } + } + + $return['fields'] = $fields; + + return $return; + } + + /** + * Traverse up nested requests until we reach the first that's not a GridFieldBulkImageUpload_Request. + * 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 GridFieldBulkImageUpload_Request) { + $c = $c->getController(); + } + return $c; + } + */ + + /** + * CMS-specific functionality: Passes through navigation breadcrumbs + * to the template, and includes the currently edited record (if any). + * see {@link LeftAndMain->Breadcrumbs()} for details. + * + * @param boolean $unlinked + * @return ArrayData + */ + function Breadcrumbs($unlinked = false) { + if(!$this->controller->hasMethod('Breadcrumbs')) return; + + $items = $this->controller->Breadcrumbs($unlinked); + $items->push(new ArrayData(array( + 'Title' => 'Bulk Upload', + 'Link' => false + ))); + return $items; + } +} \ No newline at end of file diff --git a/css/GridFieldBulkImageUpload.css b/css/GridFieldBulkImageUpload.css new file mode 100644 index 0000000..fd146b1 --- /dev/null +++ b/css/GridFieldBulkImageUpload.css @@ -0,0 +1,31 @@ +.ss-assetuploadfield .ss-uploadfield-files .ss-uploadfield-item-editform +{ + position: relative; + height: auto; + display: block; +} + +li.ss-uploadfield-item .ss-uploadfield-item-editform +{ + padding: 10px; +} + +li.ss-uploadfield-item.template-download .imgPreview +{ + position: absolute; + top: 10px; + right: 10px; +} + +#BulkImageUploadField .ss-uploadfield-item-info.updated +{ + 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%); +} + diff --git a/javascript/GridFieldBulkImageUpload.js b/javascript/GridFieldBulkImageUpload.js new file mode 100644 index 0000000..d182add --- /dev/null +++ b/javascript/GridFieldBulkImageUpload.js @@ -0,0 +1,158 @@ +(function($) { + + $.entwine('ss', function($) { + + // start SS overhides + + $('div.ss-upload .ss-uploadfield-item-edit, div.ss-upload .ss-uploadfield-item-name').entwine({ + onclick: function(e){ + this.closest('.ss-uploadfield-item').find('.ss-uploadfield-item-editform').toggleEditForm(); + } + }); + + $('div.ss-upload .fileOverview .ss-uploadfield-item-edit-all').entwine({ + onmatch: function(){ + if( !$(this).hasClass('opened') ){ + $(this).addClass('opened'); + } + }, + onunmatch: function(){ + + }, + onclick: function(e) { + if($(this).hasClass('opened')){ + $('.ss-uploadfield-files .ss-uploadfield-item-editform').hide(); + $(this).removeClass('opened'); + }else{ + $('.ss-uploadfield-files .ss-uploadfield-item-editform').show(); + $(this).addClass('opened'); + } + } + }); + + $('div.ss-upload .ss-uploadfield-item-editform').entwine({ + toggleEditForm: function() { + if( this.css('display') == 'none' ) { + this.show(); + }else{ + this.hide(); + } + } + }); + + // end SS overhides + // start add-on behaviours + + $.entwine('colymba', function($) { + + $('.bulkImageUploadUpdateForm input.text, .bulkImageUploadUpdateForm input.checkbox, .bulkImageUploadUpdateForm select, .bulkImageUploadUpdateForm textarea').entwine({ + onchange: function(){ + var form = this.closest('.bulkImageUploadUpdateForm'); + if ( !$(form).hasClass('hasUpdate') ) { + $(form).addClass('hasUpdate'); + } + $('a#bulkImageUploadUpdateFinishBtn').addClass('dirty'); + } + }); + + $('#bulkImageUploadUpdateBtn').entwine({ + onmatch: function(){ + $(this).data('completedForms', 0); + }, + onunmatch: function(){ + }, + onclick: function(e){ + + var formsWithUpadtes = $('form.bulkImageUploadUpdateForm.hasUpdate'); + $(this).data('formsToUpdate', $(formsWithUpadtes).length); + var url = $(this).data('url'); + var cacheBuster = new Date().getTime(); + + $(formsWithUpadtes).each(function(){ + var data = $(this).serialize(); + $.ajax({ + url: url + '?cacheBuster=' + cacheBuster, + data: data, + type: "POST", + context: $(this) + }).done(function() { + + var btn = $('a#bulkImageUploadUpdateBtn'); + var totalForms = parseInt( $(btn).data('formsToUpdate') ); + var counter = parseInt( $(btn).data('completedForms') ); + counter = counter + 1; + $(btn).data('completedForms', counter); + + $(this).removeClass('hasUpdate'); + $(this).parents('li').find('.ss-uploadfield-item-status').html('Updated'); + $(this).parents('li').find('.ss-uploadfield-item-info').addClass('updated'); + + var formHolder = $(this).parents('li').find('.ss-uploadfield-item-editform'); + console.log(formHolder); + try{$(formHolder).toggleEditForm();}catch(e){} + //$(this).parents('li').find('.ss-uploadfield-item-editform').entwine('ss').toggleEditForm(); + //this.closest('.ss-uploadfield-item').find('.ss-uploadfield-item-editform').toggleEditForm(); + + $(this).removeClass('hasUpdate'); + + if ( counter == totalForms ) { + $('#bulkImageUploadUpdateFinishBtn').removeClass('dirty'); + if ( $(this).hasClass('doFinish') ) { + $('#bulkImageUploadUpdateFinishBtn').clcik(); + } + } + + }); + }) + + e.preventDefault(); + } + }); + + $('#bulkImageUploadUpdateFinishBtn').entwine({ + onclick: function(e){ + if ( $(this).hasClass('dirty') ) { + $('#bulkImageUploadUpdateBtn').addClass('doFinish'); + $('#bulkImageUploadUpdateBtn').click(); + e.stopImmediatePropagation(); + } + } + }); + + $('#bulkImageUploadUpdateCancelBtn').entwine({ + onclick: function(e){ + + var url = $(this).data('url'); + var cacheBuster = new Date().getTime(); + + $('form.bulkImageUploadUpdateForm').each(function(){ + var data = $(this).serialize(); + + $.ajax({ + url: url + '?cacheBuster=' + cacheBuster, + data: data, + type: "POST", + context: $(this) + }).done(function() { + + $(this).parents('li.ss-uploadfield-item').empty().remove(); + + if ( $('li.ss-uploadfield-item').lenght == 0 ) { + $('.ss-uploadfield-editandorganize').css('display', 'none'); + $('#Form_bulkImageUploadForm').removeClass('loading'); + } + + }); + }); + + e.stopImmediatePropagation(); + e.preventDefault(); + } + }); + + // + + }); + }); + +}(jQuery)); \ No newline at end of file diff --git a/javascript/GridFieldBulkImageUpload_downloadtemplate.js b/javascript/GridFieldBulkImageUpload_downloadtemplate.js new file mode 100644 index 0000000..55cf6a5 --- /dev/null +++ b/javascript/GridFieldBulkImageUpload_downloadtemplate.js @@ -0,0 +1,45 @@ +window.tmpl.cache['GridFieldBulkImageUpload_downloadtemplate'] = tmpl( + '{% for (var i=0, files=o.files, l=files.length, file=files[0]; i' + + '
' + + '' + + '
' + + '
' + + '' + + '{% if (file.error) { %}' + + '
' + + '
' + + '
' + + '{% } %}' + + '
' + + '{% if (!file.error) { %}' + + '
'+ + '
'+ + ''+ + ''+ + + '{% for (var j=0; j' + + '' + + '
' + + '' + + '
' + + '
' + + + '{% } %}' + + + ''+ + '' + + '{% } %}' + + '' + + '{% } %}' +); \ No newline at end of file