ENHANCEMENT Using GridField for file selection in "insert image" dialog

API CHANGE Combined HTMLEditorField_Toolbar->FlashForm() and ImageForm() into new MediaForm() to handle both file types
This commit is contained in:
Ingo Schommer 2012-02-08 21:32:25 +01:00
parent 9f12c5a252
commit 3866f561f5
8 changed files with 115 additions and 120 deletions

View File

@ -210,8 +210,7 @@
closeRightPanel: function(){
if($('.cms-editor-dialogs').is(':visible')) {
$('.cms-editor-dialogs').hide();
$('#Form_EditorToolbarImageForm').hide();
$('#Form_EditorToolbarFlashForm').hide();
$('#Form_EditorToolbarMediaForm').hide();
$('#Form_EditorToolbarLinkForm').hide();
}
}

View File

@ -26,9 +26,8 @@
<% cached %>
<div id="cms-editor-dialogs">
<% control EditorToolbar %>
$ImageForm
$MediaForm
$LinkForm
$FlashForm
<% end_control %>
</div>
<% end_cached %>

View File

@ -230,15 +230,28 @@ class HtmlEditorField_Readonly extends ReadonlyField {
* @subpackage fields-formattedinput
*/
class HtmlEditorField_Toolbar extends RequestHandler {
static $allowed_actions = array(
'LinkForm',
'MediaForm',
'browse',
);
protected $controller, $name;
function __construct($controller, $name) {
parent::__construct();
Requirements::javascript(SAPPHIRE_DIR . "/thirdparty/jquery/jquery.js");
Requirements::javascript(THIRDPARTY_DIR . '/jquery-ui/jquery-ui.js');
Requirements::javascript(THIRDPARTY_DIR . '/jquery-entwine/dist/jquery.entwine-dist.js');
Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/javascript/ssui.core.js');
Requirements::javascript(SAPPHIRE_DIR . "/thirdparty/behaviour/behaviour.js");
Requirements::javascript(SAPPHIRE_DIR . "/javascript/tiny_mce_improvements.js");
Requirements::javascript(SAPPHIRE_DIR ."/thirdparty/jquery-form/jquery.form.js");
Requirements::javascript(SAPPHIRE_DIR ."/javascript/HtmlEditorField.js");
Requirements::css(THIRDPARTY_DIR . '/jquery-ui-themes/smoothness/jquery-ui.css');
$this->controller = $controller;
$this->name = $name;
@ -319,15 +332,30 @@ class HtmlEditorField_Toolbar extends RequestHandler {
/**
* Return a {@link Form} instance allowing a user to
* add images to the TinyMCE content editor.
* add images and flash objects to the TinyMCE content editor.
*
* @return Form
*/
function ImageForm() {
function MediaForm() {
if(!class_exists('ThumbnailStripField')) {
throw new Exception('ThumbnailStripField class required for HtmlEditorField->ImageForm()');
}
// TODO Handle through GridState within field - currently this state set too late to be useful here (during request handling)
$parentID = $this->controller->getRequest()->requestVar('ParentID');
$fileFieldConfig = GridFieldConfig::create();
$fileFieldConfig->addComponent(new GridFieldSortableHeader());
$fileFieldConfig->addComponent(new GridFieldFilter());
$fileFieldConfig->addComponent(new GridFieldDefaultColumns());
$fileFieldConfig->addComponent(new GridFieldPaginator(10));
$fileField = new GridField('Files', false, false, $fileFieldConfig);
$fileField->setList($this->getFiles($parentID));
$fileField->setAttribute('data-selectable', true);
$fileField->setAttribute('data-multiselect', true);
$numericLabelTmpl = '<span class="step-label"><span class="flyout">%d</span><span class="arrow"></span><strong class="title">%s</strong></span>';
$fields = new FieldList(
new LiteralField(
'Heading',
@ -335,32 +363,28 @@ class HtmlEditorField_Toolbar extends RequestHandler {
),
$contentComposite = new CompositeField(
new TreeDropdownField('FolderID', _t('HtmlEditorField.FOLDER', 'Folder'), 'Folder'),
new CompositeField(new FieldList(
new LiteralField('ShowUpload', '<p class="showUploadField"><a href="#">'. _t('HtmlEditorField.SHOWUPLOADFORM', 'Upload File') .'</a></p>'),
new FileField("Files[0]" , _t('AssetAdmin.CHOOSEFILE','Choose file: ')),
new LiteralField('Response', '<div id="UploadFormResponse"></div>'),
new HiddenField('UploadMode', 'Upload Mode', 'CMSEditor') // used as a hook for doUpload switching
)),
new TextField('getimagesSearch', _t('HtmlEditorField.SEARCHFILENAME', 'Search by file name')),
new ThumbnailStripField('FolderImages', 'FolderID', 'getimages'),
new TextField('AltText', _t('HtmlEditorField.IMAGEALTTEXT', 'Alternative text (alt) - shown if image cannot be displayed'), '', 80),
new TextField('ImageTitle', _t('HtmlEditorField.IMAGETITLE', 'Title text (tooltip) - for additional information about the image')),
new TextField('CaptionText', _t('HtmlEditorField.CAPTIONTEXT', 'Caption text')),
new DropdownField(
'CSSClass',
_t('HtmlEditorField.CSSCLASS', 'Alignment / style'),
array(
'left' => _t('HtmlEditorField.CSSCLASSLEFT', 'On the left, with text wrapping around.'),
'leftAlone' => _t('HtmlEditorField.CSSCLASSLEFTALONE', 'On the left, on its own.'),
'right' => _t('HtmlEditorField.CSSCLASSRIGHT', 'On the right, with text wrapping around.'),
'center' => _t('HtmlEditorField.CSSCLASSCENTER', 'Centered, on its own.'),
)
),
new FieldGroup(_t('HtmlEditorField.IMAGEDIMENSIONS', 'Dimensions'),
new TextField('Width', _t('HtmlEditorField.IMAGEWIDTHPX', 'Width'), 100),
new TextField('Height', " x " . _t('HtmlEditorField.IMAGEHEIGHTPX', 'Height'), 100)
)
new LiteralField('header1', '<h4 class="field">' . sprintf($numericLabelTmpl, '1', _t('HtmlEditorField.Find', 'Find')) . '</h4>'),
new TreeDropdownField('ParentID', _t('HtmlEditorField.FOLDER', 'Folder'), 'Folder'),
$fileField,
new LiteralField('header2', '<h4 class="field edit-details">' . sprintf($numericLabelTmpl, '2', _t('HtmlEditorField.EditDetails', 'Edit details')) . '</h4>')
// new TextField('AltText', _t('HtmlEditorField.IMAGEALTTEXT', 'Alternative text (alt) - shown if image cannot be displayed'), '', 80),
// new TextField('ImageTitle', _t('HtmlEditorField.IMAGETITLE', 'Title text (tooltip) - for additional information about the image')),
// new TextField('CaptionText', _t('HtmlEditorField.CAPTIONTEXT', 'Caption text')),
// new DropdownField(
// 'CSSClass',
// _t('HtmlEditorField.CSSCLASS', 'Alignment / style'),
// array(
// 'left' => _t('HtmlEditorField.CSSCLASSLEFT', 'On the left, with text wrapping around.'),
// 'leftAlone' => _t('HtmlEditorField.CSSCLASSLEFTALONE', 'On the left, on its own.'),
// 'right' => _t('HtmlEditorField.CSSCLASSRIGHT', 'On the right, with text wrapping around.'),
// 'center' => _t('HtmlEditorField.CSSCLASSCENTER', 'Centered, on its own.'),
// )
// ),
// new FieldGroup(_t('HtmlEditorField.IMAGEDIMENSIONS', 'Dimensions'),
// new TextField('Width', _t('HtmlEditorField.IMAGEWIDTHPX', 'Width'), 100),
// new TextField('Height', " x " . _t('HtmlEditorField.IMAGEHEIGHTPX', 'Height'), 100)
// )
)
);
@ -371,7 +395,7 @@ class HtmlEditorField_Toolbar extends RequestHandler {
$form = new Form(
$this->controller,
"{$this->name}/ImageForm",
"{$this->name}/MediaForm",
$fields,
$actions
);
@ -379,53 +403,35 @@ class HtmlEditorField_Toolbar extends RequestHandler {
$contentComposite->addExtraClass('content');
// Allow other people to extend the fields being added to the imageform
$this->extend('updateImageForm', $form);
$this->extend('updateMediaForm', $form);
$form->unsetValidator();
$form->disableSecurityToken();
$form->loadDataFrom($this);
$form->addExtraClass('htmleditorfield-form htmleditorfield-imageform cms-dialog-content');
$form->addExtraClass('htmleditorfield-form htmleditorfield-mediaform cms-dialog-content');
return $form;
}
function FlashForm() {
if(!class_exists('ThumbnailStripField')) {
throw new Exception('ThumbnailStripField class required for HtmlEditorField->FlashForm()');
}
public function browse($request) {
$form = new Form(
$this->controller,
"{$this->name}/FlashForm",
new FieldList(
new LiteralField(
'Heading',
sprintf('<h3>%s</h3>', _t('HtmlEditorField.FLASH', 'Flash'))
),
$contentComposite = new CompositeField(
new TreeDropdownField("FolderID", _t('HtmlEditorField.FOLDER'), "Folder"),
new TextField('getflashSearch', _t('HtmlEditorField.SEARCHFILENAME', 'Search by file name')),
new ThumbnailStripField("Flash", "FolderID", "getflash"),
new FieldGroup(_t('HtmlEditorField.IMAGEDIMENSIONS', "Dimensions"),
new TextField("Width", _t('HtmlEditorField.IMAGEWIDTHPX', "Width"), 100),
new TextField("Height", "x " . _t('HtmlEditorField.IMAGEHEIGHTPX', "Height"), 100)
)
)
),
new FieldList(
$insertAction = new FormAction("insertflash", _t('HtmlEditorField.BUTTONINSERTFLASH', 'Insert Flash'))
)
);
$insertAction->addExtraClass('ss-ui-action-constructive');
$contentComposite->addExtraClass('content');
}
/**
* @param Int
* @return DataList
*/
protected function getFiles($parentID = null) {
// TODO Use array('Filename:EndsWith' => $exts) once that's supported
$exts = array('jpg', 'gif', 'png', 'swf');
$wheres = array();
foreach($exts as $ext) $wheres[] = '"Filename" LIKE \'%.' . $ext . '\'';
$files = DataList::create('File')->where(implode(' OR ', $wheres));
$this->extend('updateFlashForm', $form);
// Limit by folder (if required)
if($parentID) $files->filter('ParentID', $parentID);
$form->unsetValidator();
$form->loadDataFrom($this);
$form->disableSecurityToken();
$form->addExtraClass('htmleditorfield-form htmleditorfield-flashform cms-dialog-content');
return $form;
return $files;
}
}

View File

@ -739,6 +739,7 @@ class GridField_Action extends FormAction {
// will strip it from the requests
'name' => 'action_gridFieldAlterAction'. '?' . http_build_query($actionData),
'tabindex' => $this->getTabIndex(),
'data-url' => $this->gridField->Link(),
);
if($this->isReadonly()) {

View File

@ -134,11 +134,4 @@
});
$('fieldset.ss-gridfield[data-multiselect] .ss-gridfield-item').entwine({
onclick: function() {
// this.siblings('selected');
this._super();
}
});
}(jQuery));

View File

@ -16,37 +16,22 @@
* On page refresh load the initial images (in root)
*/
if($("#FolderImages").length > 0 && $("body.CMSMain").length > 0) loadImages(false);
/**
* Show / Hide the Upload Form
*/
$("#Form_EditorToolbarImageForm .showUploadField a").click(function() {
if($(this).hasClass("showing")) {
$("#Form_EditorToolbarImageForm_Files-0").parents('.file').hide();
$(this).text(ss.i18n._t('HtmlEditorField.ShowUploadForm', 'Upload File')).removeClass("showing");
}
else {
$("#Form_EditorToolbarImageForm_Files-0").parents('.file').show();
$(this).text(ss.i18n._t('HtmlEditorField.HideUploadForm', 'Hide Upload Form')).addClass("showing");
}
return false;
}).show();
/**
* On folder change - lookup the new images
*/
$("#Form_EditorToolbarImageForm_Files-0").change(function() {
$(".cms-editor-dialogs #Form_EditorToolbarImageForm").ajaxForm({
$("#Form_EditorToolbarMediaForm_Files-0").change(function() {
$(".cms-editor-dialogs #Form_EditorToolbarMediaForm").ajaxForm({
url: 'admin/assets/UploadForm?action_doUpload=1',
iframe: true,
dataType: 'json',
beforeSubmit: function(data) {
$("#UploadFormResponse").text("Uploading File...").addClass("loading").show();
$("#Form_EditorToolbarImageForm_Files-0").parents('.file').hide();
$("#Form_EditorToolbarMediaForm_Files-0").parents('.file').hide();
},
success: function(data) {
$("#UploadFormResponse").text("").removeClass("loading");
$("#Form_EditorToolbarImageForm_Files-0").val("").parents('.file').show();
$("#Form_EditorToolbarMediaForm_Files-0").val("").parents('.file').show();
$("#FolderImages").html('<h2>'+ ss.i18n._t('HtmlEditorField.Loading', 'Loading') + '</h2>');
@ -59,13 +44,13 @@
* Loads images from getimages() to the thumbnail view. It's called on
*/
function loadImages(params) {
$.get('admin/EditorToolbar/ImageForm', {
$.get('admin/EditorToolbar/MediaForm', {
action_callfieldmethod: "1",
fieldName: "FolderImages",
ajax: "1",
methodName: "getimages",
folderID: $("#Form_EditorToolbarImageForm_FolderID").val(),
searchText: $("#Form_EditorToolbarImageForm_getimagesSearch").val(),
folderID: $("#Form_EditorToolbarMediaForm_ParentID").val(),
searchText: $("#Form_EditorToolbarMediaForm_getimagesSearch").val(),
cacheKillerDate: parseInt((new Date()).getTime()),
cacheKillerRand: parseInt(10000 * Math.random())
},
@ -480,5 +465,17 @@
return false;
}
});
$('form.htmleditorfield-mediaform').entwine({
});
$('form.htmleditorfield-mediaform #ParentID .TreeDropdownField').entwine({
onchange: function() {
var fileList = this.closest('form').find('fieldset.ss-gridfield');
fileList.setState('ParentID', this.getValue());
fileList.reload();
}
});
});
})(jQuery);

View File

@ -43,8 +43,8 @@ SideFormAction.prototype = {
}
}
ImageForm = Class.extend('ToolbarForm');
ImageForm.prototype = {
MediaForm = Class.extend('ToolbarForm');
MediaForm.prototype = {
initialize: function() {
var __form = this;
@ -153,8 +153,8 @@ ImageForm.prototype = {
try {
var imgTag = image.getElementsByTagName('img')[0];
this.selectedImageWidth = $('Form_EditorToolbarImageForm_Width').value = imgTag.className.match(/destwidth=([0-9.\-]+)([, ]|$)/) ? RegExp.$1 : null;
this.selectedImageHeight = $('Form_EditorToolbarImageForm_Height').value = imgTag.className.match(/destheight=([0-9.\-]+)([, ]|$)/) ? RegExp.$1 : null;
this.selectedImageWidth = $('Form_EditorToolbarMediaForm_Width').value = imgTag.className.match(/destwidth=([0-9.\-]+)([, ]|$)/) ? RegExp.$1 : null;
this.selectedImageHeight = $('Form_EditorToolbarMediaForm_Height').value = imgTag.className.match(/destheight=([0-9.\-]+)([, ]|$)/) ? RegExp.$1 : null;
} catch(er) {
}
},
@ -174,12 +174,12 @@ ImageThumbnail.prototype = {
},
onclick: function(e) {
$('Form_EditorToolbarImageForm').selectImage(this);
$('Form_EditorToolbarMediaForm').selectImage(this);
return false;
},
insert: function() {
var formObj = $('Form_EditorToolbarImageForm');
var formObj = $('Form_EditorToolbarMediaForm');
var altText = formObj.elements.AltText.value;
var titleText = formObj.elements.ImageTitle.value;
var cssClass = formObj.elements.CSSClass.value;
@ -193,8 +193,8 @@ ImageThumbnail.prototype = {
var data = {
'src' : relativeHref,
'alt' : altText,
'width' : $('Form_EditorToolbarImageForm_Width').value,
'height' : $('Form_EditorToolbarImageForm_Height').value,
'width' : $('Form_EditorToolbarMediaForm_Width').value,
'height' : $('Form_EditorToolbarMediaForm_Height').value,
'title' : titleText,
'class' : cssClass
};
@ -246,7 +246,7 @@ function reselectImage(transport) {
image = link.href.substring(0, quesmark);
if(image == selectedimage) {
link.className = 'selectedImage';
$('Form_EditorToolbarImageForm').selectedImage = link;
$('Form_EditorToolbarMediaForm').selectedImage = link;
break;
}
}
@ -328,9 +328,9 @@ FlashThumbnail.prototype = {
}
}
ImageForm.applyTo('#Form_EditorToolbarImageForm');
ImageThumbnail.applyTo('#Form_EditorToolbarImageForm div.thumbnailstrip a');
SideFormAction.applyTo('#Form_EditorToolbarImageForm .Actions input');
MediaForm.applyTo('#Form_EditorToolbarMediaForm');
ImageThumbnail.applyTo('#Form_EditorToolbarMediaForm div.thumbnailstrip a');
SideFormAction.applyTo('#Form_EditorToolbarMediaForm .Actions input');
FlashForm.applyTo('#Form_EditorToolbarFlashForm');
FlashThumbnail.applyTo('#Form_EditorToolbarFlashForm div.thumbnailstrip a');
@ -345,7 +345,7 @@ MCEImageResizer.prototype = {
//TinyMCE.prototype.addEvent(this, 'click', this._onclick);
},
_onclick: function() {
var form = $('Form_EditorToolbarImageForm');
var form = $('Form_EditorToolbarMediaForm');
if(form) {
form.elements.AltText.value = this.alt;
form.elements.ImageTitle.value = this.title;

View File

@ -10,7 +10,7 @@ class HtmlEditorFieldTest extends FunctionalTest {
public static $use_draft_site = true;
protected $requiredExtensions = array(
'HtmlEditorField_Toolbar' => array('HtmlEditorFieldTest_DummyImageFormFieldExtension')
'HtmlEditorField_Toolbar' => array('HtmlEditorFieldTest_DummyMediaFormFieldExtension')
);
protected $extraDataObjects = array('HtmlEditorFieldTest_Object');
@ -76,15 +76,15 @@ class HtmlEditorFieldTest extends FunctionalTest {
);
}
public function testExtendImageFormFields() {
public function testExtendMediaFormFields() {
if(class_exists('ThumbnailStripField')) {
$controller = new Controller();
$toolbar = new HtmlEditorField_Toolbar($controller, 'DummyToolbar');
$imageForm = $toolbar->ImageForm();
$this->assertTrue(HtmlEditorFieldTest_DummyImageFormFieldExtension::$update_called);
$this->assertEquals($imageForm->Fields(), HtmlEditorFieldTest_DummyImageFormFieldExtension::$fields);
$form = $toolbar->MediaForm();
$this->assertTrue(HtmlEditorFieldTest_DummyMediaFormFieldExtension::$update_called);
$this->assertEquals($form->Fields(), HtmlEditorFieldTest_DummyMediaFormFieldExtension::$fields);
} else {
$this->markTestSkipped('Test requires cms module (ThumbnailStripfield class)');
}
@ -96,7 +96,7 @@ class HtmlEditorFieldTest extends FunctionalTest {
* @package sapphire
* @subpackage tests
*/
class HtmlEditorFieldTest_DummyImageFormFieldExtension extends Extension implements TestOnly {
class HtmlEditorFieldTest_DummyMediaFormFieldExtension extends Extension implements TestOnly {
public static $fields = null;
public static $update_called = false;