ENHANCEMENT Converted AssetAdmin and AssetTableField javascript to jquery-concrete

MINOR Moved AssetAdmin->movemarked() logic to AssetTableField

git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/trunk@92829 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
Ingo Schommer 2009-11-21 03:20:11 +00:00
parent 1581d93df6
commit c467c926fd
7 changed files with 176 additions and 305 deletions

View File

@ -38,15 +38,10 @@ class AssetAdmin extends LeftAndMain {
static $allowed_actions = array(
'doAdd',
'AddForm',
'deletemarked',
'DeleteItemsForm',
'deleteUnusedThumbnails',
'doUpload',
'getfile',
'getsubtree',
'movemarked',
'save',
'savefile',
'uploadiframe',
'UploadForm',
'deleteUnusedThumbnails' => 'ADMIN',
@ -324,74 +319,7 @@ HTML;
return $form;
}
/**
* Perform the "move marked" action.
* Called and returns in same way as 'save' function
*/
public function movemarked($urlParams, $form) {
if($_REQUEST['DestFolderID'] && (is_numeric($_REQUEST['DestFolderID']) || ($_REQUEST['DestFolderID']) == 'root')) {
$destFolderID = ($_REQUEST['DestFolderID'] == 'root') ? 0 : $_REQUEST['DestFolderID'];
$fileList = "'" . ereg_replace(' *, *',"','",trim(addslashes($_REQUEST['FileIDs']))) . "'";
$numFiles = 0;
if($fileList != "''") {
$files = DataObject::get("File", "\"File\".\"ID\" IN ($fileList)");
if($files) {
foreach($files as $file) {
if($file instanceof Image) {
$file->deleteFormattedImages();
}
$file->ParentID = $destFolderID;
$file->write();
$numFiles++;
}
} else {
user_error("No files in $fileList could be found!", E_USER_ERROR);
}
}
$message = sprintf(_t('AssetAdmin.MOVEDX','Moved %s files'),$numFiles);
FormResponse::status_message($message, "good");
FormResponse::add("$('Form_EditForm_Files').refresh();");
return FormResponse::respond();
}
}
/**
* Returns the content to be placed in Form_SubForm when editing a file.
* Called using ajax.
*/
public function getfile() {
SSViewer::setOption('rewriteHashlinks', false);
// bdc: only try to return something if user clicked on an object
if (is_object($this->getSubForm($this->urlParams['ID']))) {
return $this->getSubForm($this->urlParams['ID'])->formHtmlContent();
}
else return null;
}
/**
* Action handler for the save button on the file subform.
* Saves the file
*/
public function savefile($data, $form) {
$record = DataObject::get_by_id("File", $data['ID']);
$form->saveInto($record);
$record->write();
$title = Convert::raw2js($record->Title);
$name = Convert::raw2js($record->Name);
$saved = sprintf(_t('AssetAdmin.SAVEDFILE','Saved file %s'),"#$data[ID]");
echo <<<JS
statusMessage('$saved');
$('record-$data[ID]').getElementsByTagName('td')[1].innerHTML = "$title";
$('record-$data[ID]').getElementsByTagName('td')[2].innerHTML = "$name";
JS;
}
/**
* Return the entire site tree as a nested UL.
* @return string HTML for site tree

View File

@ -225,21 +225,27 @@ class AssetTableField extends ComplexTableField {
* @return string HTML for search form
*/
function SearchForm() {
$searchFields = new FieldGroup(
new TextField('FileSearch', _t('MemberTableField.SEARCH', 'Search'), $this->searchingFor),
new HiddenField("ctf[ID]", '', $this->ID),
new HiddenField('FileFieldName', '', $this->name)
);
$actionFields = new LiteralField(
'FileFilterButton',
'<input type="submit" class="action" name="FileFilterButton" value="' . _t('MemberTableField.FILTER', 'Filter') . '" id="FileFilterButton"/>'
);
$fieldContainer = new FieldGroup(
$searchFields,
$actionFields
new FieldGroup(
new TextField(
'FileSearch',
_t('MemberTableField.SEARCH', 'Search'),
$this->searchingFor
)
),
new FieldGroup(
$btnFilter = new InlineFormAction(
'FileFilterButton',
_t('MemberTableField.FILTER', 'Filter')
),
$btnClear = new InlineFormAction(
'FileFilterClearButton',
_t('AssetTableField.CLEAR', 'Clear')
)
)
);
$btnFilter->includeDefaultJS(false);
$btnClear->includeDefaultJS(false);
return $fieldContainer->FieldHolder();
}
@ -300,8 +306,39 @@ class AssetTableField extends ComplexTableField {
$brokenPageList
)
);
}
public function movemarked($request) {
$fileIDs = $request->requestVar($this->Name());
$folderId = $request->requestVar('DestFolderID');
$numFiles = 0;
return $response->output();
if($folderId && (is_numeric($folderId) || ($folderId) == 'root')) {
if($folderId == 'root') $folderId = 0;
if($fileIDs && count($fileIDs)) {
$files = DataObject::get(
"File",
sprintf("\"File\".\"ID\" IN (%s)", Convert::raw2sql(implode(',', $fileIDs)))
);
if($files) {
foreach($files as $file) {
$file->ParentID = $folderId;
$file->write();
$numFiles++;
}
}
}
$response = $this->form->Controller()->getResponse();
$response->addHeader(
'X-Status',
sprintf(
sprintf(_t('AssetAdmin.MOVEDX','Moved %s files'),$numFiles),
$numFiles
)
);
}
}
}

View File

@ -75,7 +75,8 @@ ul.tree span.a {
cursor: pointer;
}
.filefolderhover span.a,
ul.tree span.a.over {
ul.tree span.a.over,
ul.tree .over > span.a {
background-color: #FFFFBB !important;
/* these push the highlight out to the left of the window */
margin-left: -100px;

View File

@ -1,118 +1,76 @@
// SubsDraggable adapted from http://dev.rubyonrails.org/ticket/5771
// extentions for scriptaculous dragdrop.js
Object.extend(Class, {
superrise: function(obj, names){
names.each( function(n){ obj['super_' + n] = obj[n] } )
return obj;
}
})
// Draggable that allows substitution of draggable element
var SubsDraggable = Class.create();
SubsDraggable.prototype = Object.extend({}, Draggable.prototype);
Class.superrise(SubsDraggable.prototype, ['initialize', 'startDrag', 'finishDrag'])
Object.extend( SubsDraggable.prototype , {
initialize: function(event) {
this.super_initialize.apply(this, arguments);
if( typeof(this.options.dragelement) == 'undefined' ) this.options.dragelement = false;
},
startDrag: function(event) {
if( this.options.dragelement ) {
this._originalElement = this.element;
// Get the id of the file being dragged
var beingDraggedId = this.element.id.replace('drag-Files-','');
this.element = this.options.dragelement(this.element);
Position.absolutize(this.element);
Position.clone(this._originalElement, this.element);
// Add # files being moved message
this.element.className = 'dragfile DraggedHandle';
// We are at least moving the 1 file being dragged
var numMoved = 1;
var i, checkboxes = $('Form_EditForm').elements['Files[]'];
if(!checkboxes) checkboxes = [];
if(!checkboxes.length) checkboxes = [ checkboxes ];
for(i=0;i<checkboxes.length;i++) {
// Total up the other files that are checked
if(checkboxes[i].checked && checkboxes[i].value != beingDraggedId) {
numMoved++;
(function($) {
$.concrete('ss', function($){
$('.AssetTableField.dragdrop').concrete({
onmatch: function() {
var self = this;
$('#sitetree li').each(function() {
$(this).droppable({
greedy: true,
hoverClass: 'over', // same hover effect as normal tree
drop: function(e, ui) {self.drop(e, ui);}
});
});
this._super();
},
/**
* Take selected files and move them to a folder target in the tree.
*/
drop: function(e, ui) {
var self = this;
if(e.target.id.match(/-([^-]+)$/)) {
var folderId = RegExp.$1;
$.post(
this.attr('href') + '/movemarked',
this.parents('form').serialize() + '&DestFolderID=' + folderId,
function(data, status) {
self.refresh();
}
)
}
}
numFilesIndicator = document.createElement('span');
numFilesIndicator.innerHTML = 'Moving ' + numMoved + ' files';
numFilesIndicator.className = 'NumFilesIndicator';
this.element.appendChild(numFilesIndicator);
}
this.super_startDrag(event);
},
finishDrag: function(event, success) {
this.super_finishDrag(event, success);
if(this.options.dragelement){
Element.remove(this.element);
this.element = this._originalElement;
this._originalElement = null;
}
}
})
// gets element that should be dragged instead of original element
// returned element should be added to DOM tree, and will be deleted by dragdrop library
function getDragElement(element){
var el = element.cloneNode(true);
el.id = '';
document.body.appendChild(el);
return el;
}
// Set up DRAG handle
DragFileItem = Class.create();
DragFileItem.prototype = {
initialize: function() {
if (this.id)
{
this.draggable = new SubsDraggable(this.id, {revert:true,ghosting:false,dragelement:getDragElement});
}
},
destroy: function() {
this.draggable = null;
}
}
DragFileItem.applyTo('#Form_EditForm_Files tr td.dragfile');
// Set up folder drop target
DropFileItem = Class.create();
DropFileItem.prototype = {
initialize: function() {
// Get this.recordID from the last "-" separated chunk of the id HTML attribute
// eg: <li id="treenode-6"> would give a recordID of 6
if(this.id && this.id.match(/-([^-]+)$/))
this.recordID = RegExp.$1;
this.droppable = Droppables.add(this.id, {accept:'dragfile', hoverclass:'filefolderhover',
onDrop:function(droppedElement) {
// Get this.recordID from the last "-" separated chunk of the id HTML attribute
// eg: <li id="treenode-6"> would give a recordID of 6
if(this.element.id && this.element.id.match(/-([^-]+)$/))
this.recordID = RegExp.$1;
$('Form_EditForm').elements['DestFolderID'].value = this.recordID;
// Add the dropped file to the list of files to move
var list = droppedElement.getElementsByTagName('img')[0].id.replace('drag-img-Files-','');
var i, checkboxes = $('Form_EditForm').elements['Files[]'];
if(!checkboxes) checkboxes = [];
if(!checkboxes.length) checkboxes = [ checkboxes ];
// Add each checked file to the list of ones to move
for(i=0;i<checkboxes.length;i++) {
if(checkboxes[i].checked) list += (list?',':'') + checkboxes[i].value;
}
$('Form_EditForm_FileIDs').value = list;
$('Form_EditForm').save(false, null, 'movemarked')
},
/**
* Get the IDs of all selected files in the table.
* Used for drag'n'drop.
*
* @return Array
*/
getSelected: function() {
return this.find(':input[name=Files\[\]]:checked').map(function() {
return $(this).val();
});
}
});
},
destroy: function() {
this.droppable = null;
this.recordID = null;
}
}
DropFileItem.applyTo('#sitetree li');
$('.AssetTableField .dragfile').concrete({
onmatch: function() {
var self = this;
var container = this.parents('.AssetTableField');
this.draggable({
zIndex: 4000,
//stack: {group: '.ui-layout-west'},
appendTo: 'body',
helper: function() {
return $(
'<div class="NumFilesIndicator">' +
ss.i18n.sprintf(ss.i18n._t('AssetTableField.MOVING'),container.getSelected().length) +
'</div>'
);
}
});
this._super();
},
/**
* Automatically select the checkbox in the same table row
* to signify that this element is moved, and hint that
* all checkboxed elements will be moved along with it.
*/
onmousedown: function(e) {
this.siblings('.markingcheckbox').find(':input').attr('checked', 'checked');
}
});
});
}(jQuery));

View File

@ -1,6 +1,51 @@
(function($) {
$.concrete('ss', function($){
$('.AssetTableField').concrete({
onmatch: function() {
var self = this;
// search button
this.find('input#FileFilterButton').click(function(e) {
var btn = $(this);
$(this).addClass('loading');
self.refresh(function() {btn.removeClass('loading');});
return false;
});
// clear button
this.find('input#FileFilterClearButton').click(function(e) {
self.find('input#FileSearch').val('');
self.find('input#FileFilterButton').click();
return false;
});
// search field
this.find('input#FileSearch').keypress(function(e) {
if(e.keyCode == $.ui.keyCode.ENTER) {
self.find('input#FileFilterButton').click();
}
});
this._super();
},
refresh: function(callback) {
var self = this;
this.load(
this.attr('href'),
this.find(':input').serialize(),
function(response, status, xmlhttp) {
Behaviour.apply(self[0], true);
if(callback) callback.apply(arguments);
}
);
}
});
/**
* Checkboxes used to batch delete files
*/
$('.AssetTableField :checkbox').concrete({
onchange: function() {
var container = this.parents('.AssetTableField');
@ -33,110 +78,11 @@
this.parents('form').serialize(),
function(data, status) {
self.removeClass('loading');
container[0].refresh();
container.refresh();
}
);
return false;
}
});
});
}(jQuery));
AssetTableField = Class.create();
AssetTableField.applyTo('#Form_EditForm_Files');
AssetTableField.prototype = {
initialize: function() {
Behaviour.register({
'#Form_EditForm div.FileFilter input' : {
onkeypress : this.prepareSearch.bind(this)
},
'#Form_EditForm' : {
changeDetection_fieldsToIgnore : {
'ctf[start]' : true,
'ctf[ID]' : true,
'FileFilterButton' : true,
'FileFieldName' : true,
'FileSearch' : true,
'Files[]' : true
}
}
});
},
// prevent submission of wrong form-button (FileFilterButton)
prepareSearch: function(e) {
// IE6 doesnt send an event-object with onkeypress
var event = (e) ? e : window.event;
var keyCode = (event.keyCode) ? event.keyCode : event.which;
if(keyCode == Event.KEY_RETURN) {
var el = Event.element(event);
$('FileFilterButton').onclick(event);
Event.stop(event);
return false;
}
}
}
FileFilterButton = Class.create();
FileFilterButton.applyTo('#FileFilterButton');
FileFilterButton.prototype = {
initialize: function() {
this.inputFields = new Array();
var childNodes = this.parentNode.parentNode.getElementsByTagName('input');
for( var index = 0; index < childNodes.length; index++ ) {
if( childNodes[index].tagName ) {
childNodes[index].resetChanged = function() { return false; }
childNodes[index].isChanged = function() { return false; }
this.inputFields.push( childNodes[index] );
}
}
childNodes = this.parentNode.getElementsByTagName('select');
for( var index = 0; index < childNodes.length; index++ ) {
if( childNodes[index].tagName ) {
childNodes[index].resetChanged = function() { return false; }
childNodes[index].field_changed = function() { return false; }
this.inputFields.push( childNodes[index] );
}
}
},
isChanged: function() {
return false;
},
onclick: function(e) {
if(!$('ctf-ID') || !$('FileFieldName')) {
return false;
}
try {
var form = Event.findElement(e, 'form');
var fieldName = $('FileFieldName').value;
// build url
var updateURL = form.action + '/field/' + fieldName + '?';
for(var index = 0; index < this.inputFields.length; index++) {
if(this.inputFields[index].tagName) {
updateURL += '&' + this.inputFields[index].name + '=' + encodeURIComponent(this.inputFields[index].value);
}
}
updateURL += ($('SecurityID') ? '&SecurityID=' + $('SecurityID').value : '');
// update the field
var field = form.getElementsByClassName('AssetTableField')[0];
field.setAttribute('href', updateURL);
field.refresh();
} catch(er) {
errorMessage('Error searching');
}
return false;
}
}
}(jQuery));

View File

@ -29,6 +29,7 @@ if(typeof(ss) == 'undefined' || typeof(ss.i18n) == 'undefined') {
'CMSMAIN.ALERTCLASSNAME': 'The page type will be updated after the page is saved',
'CMSMAIN.URLSEGMENTVALIDATION': 'URLs can only be made up of letters, digits and hyphens.',
'AssetAdmin.BATCHACTIONSDELETECONFIRM': "Do you really want to delete %s folders?",
'AssetTableField.REALLYDELETE': 'Do you really want to delete the marked files?'
'AssetTableField.REALLYDELETE': 'Do you really want to delete the marked files?',
'AssetTableField.MOVING': 'Moving %s file(s)'
});
}

View File

@ -1,4 +1,4 @@
<div id="$id" class="$CSSClasses $extraClass field" href="$CurrentLink">
<div id="$id" class="$CSSClasses $extraClass field dragdrop" href="$CurrentLink">
<div class="FileFilter filterBox">
$SearchForm
</div>