mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 12:05:37 +00:00
ENHANCEMENT ajshort: Major refactoring of FileIFrameField and ImageField to use the new URL handler. Access control to the field is now controlled by the form, and ImageField now uses a codebase much more aligned with FileIFrameField.
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@77012 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
parent
104470006e
commit
8d4e1dd6e0
@ -466,336 +466,3 @@ class Image_Cached extends Image {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploader support for the uploading anything which is a File or subclass of File, eg Image.
|
||||
* Is connected to the URL routing "/image" through sapphire/_config.php,
|
||||
* and used by all iframe-based upload-fields in the CMS.
|
||||
*
|
||||
* Used by {@link FileIFrameField}, {@link ImageField}.
|
||||
*
|
||||
* @todo Refactor to using FileIFrameField and ImageField as a controller for the upload,
|
||||
* rather than something totally disconnected from the original Form and FormField
|
||||
* context. Without the original context its impossible to control permissions etc.
|
||||
*
|
||||
* @package sapphire
|
||||
* @subpackage filesystem
|
||||
*/
|
||||
class Image_Uploader extends Controller {
|
||||
static $url_handlers = array(
|
||||
'$Action!/$Class!/$ID!/$Field!/$FormName!' => '$FormName',
|
||||
'$Action/$Class/$ID/$Field' => 'handleAction',
|
||||
);
|
||||
|
||||
static $allowed_actions = array(
|
||||
'iframe' => 'CMS_ACCESS_CMSMain',
|
||||
'flush' => 'CMS_ACCESS_CMSMain',
|
||||
'save' => 'CMS_ACCESS_CMSMain',
|
||||
'delete' => 'CMS_ACCESS_CMSMain',
|
||||
'EditImageForm' => 'CMS_ACCESS_CMSMain',
|
||||
'DeleteImageForm' => 'CMS_ACCESS_CMSMain'
|
||||
);
|
||||
|
||||
function init() {
|
||||
// set language
|
||||
$member = Member::currentUser();
|
||||
if(!empty($member->Locale)) {
|
||||
i18n::set_locale($member->Locale);
|
||||
}
|
||||
|
||||
// set reading lang
|
||||
if(singleton('SiteTree')->hasExtension('Translatable') && !Director::is_ajax()) {
|
||||
Translatable::choose_site_locale(array_keys(Translatable::get_existing_content_languages('SiteTree')));
|
||||
}
|
||||
|
||||
parent::init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the css is loaded for the iframe.
|
||||
*/
|
||||
function iframe() {
|
||||
if(!Permission::check('CMS_ACCESS_CMSMain')) Security::permissionFailure($this);
|
||||
|
||||
Requirements::css(CMS_DIR . "/css/Image_iframe.css");
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Image object attached to this class.
|
||||
* @var Image
|
||||
*/
|
||||
protected $imageObj;
|
||||
|
||||
/**
|
||||
* Associated parent object.
|
||||
* @var DataObject
|
||||
*/
|
||||
protected $linkedObj;
|
||||
|
||||
/**
|
||||
* Finds the associated parent object from the urlParams.
|
||||
* @return DataObject
|
||||
*/
|
||||
function linkedObj() {
|
||||
if(!$this->linkedObj) {
|
||||
$this->linkedObj = DataObject::get_by_id($this->urlParams['Class'], $this->urlParams['ID']);
|
||||
if(!$this->linkedObj) {
|
||||
user_error("Data object '{$this->urlParams['Class']}.{$this->urlParams['ID']}' couldn't be found", E_USER_ERROR);
|
||||
}
|
||||
}
|
||||
return $this->linkedObj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Image object attached to this class.
|
||||
* @return Image
|
||||
*/
|
||||
function Image() {
|
||||
if(!$this->imageObj) {
|
||||
$funcName = $this->urlParams['Field'];
|
||||
$linked = $this->linkedObj();
|
||||
$this->imageObj = $linked->obj($funcName);
|
||||
if(!$this->imageObj) {$this->imageObj = new Image(null);}
|
||||
}
|
||||
|
||||
return $this->imageObj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the file attachment is an image.
|
||||
* Otherwise, it's a file.
|
||||
* @return boolean
|
||||
*/
|
||||
function IsImage() {
|
||||
$className = $this->Image()->class;
|
||||
return $className == "Image" || is_subclass_of($className, "Image");
|
||||
}
|
||||
|
||||
function UseSimpleForm() {
|
||||
if(!$this->useSimpleForm) {
|
||||
$this->useSimpleForm = false;
|
||||
}
|
||||
return $this->useSimpleForm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a link to this uploader.
|
||||
* @return string
|
||||
*/
|
||||
function Link($action = null) {
|
||||
return $this->RelativeLink($action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the relative link to this uploader.
|
||||
* @return string
|
||||
*/
|
||||
function RelativeLink($action = null) {
|
||||
if(!$action) {
|
||||
$action = "index";
|
||||
}
|
||||
return "images/$action/{$this->urlParams['Class']}/{$this->urlParams['ID']}/{$this->urlParams['Field']}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Form to show the current image and allow you to upload another one.
|
||||
* @return Form
|
||||
*/
|
||||
function EditImageForm() {
|
||||
$isImage = $this->IsImage();
|
||||
$type = $isImage ? _t('Controller.IMAGE', "Image") : _t('Controller.FILE', "File");
|
||||
if($this->Image()->ID) {
|
||||
$title = sprintf(
|
||||
_t('ImageUploader.REPLACE', "Replace %s", PR_MEDIUM, 'Replace file/image'),
|
||||
$type
|
||||
);
|
||||
$fromYourPC = _t('ImageUploader.ONEFROMCOMPUTER', "With one from your computer");
|
||||
$fromTheDB = _t('ImageUplaoder.ONEFROMFILESTORE', "With one from the file store");
|
||||
} else {
|
||||
$title = sprintf(
|
||||
_t('ImageUploader.ATTACH', "Attach %s", PR_MEDIUM, 'Attach image/file'),
|
||||
$type
|
||||
);
|
||||
$fromYourPC = _t('ImageUploader.FROMCOMPUTER', "From your computer");
|
||||
$fromTheDB = _t('ImageUploader.FROMFILESTORE', "From the file store");
|
||||
}
|
||||
return new Form(
|
||||
$this,
|
||||
'EditImageForm',
|
||||
new FieldSet(
|
||||
new HiddenField("Class", null, $this->urlParams['Class']),
|
||||
new HiddenField("ID", null, $this->urlParams['ID']),
|
||||
new HiddenField("Field", null, $this->urlParams['Field']),
|
||||
new HeaderField('EditImageHeader',$title),
|
||||
new SelectionGroup("ImageSource", array(
|
||||
"new//$fromYourPC" => new FieldGroup("",
|
||||
new FileField("Upload","")
|
||||
),
|
||||
"existing//$fromTheDB" => new FieldGroup("",
|
||||
new TreeDropdownField("ExistingFile", "","File")
|
||||
)
|
||||
))
|
||||
),
|
||||
new FieldSet(
|
||||
new FormAction("save",$title)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple version of the upload form.
|
||||
* @returns string
|
||||
*/
|
||||
function EditImageSimpleForm() {
|
||||
$isImage = $this->IsImage();
|
||||
$type = $isImage ? _t('Controller.IMAGE') : _t('Controller.FILE');
|
||||
if($this->Image()->ID) {
|
||||
$title = sprintf(
|
||||
_t('ImageUploader.REPLACE'),
|
||||
$type
|
||||
);
|
||||
$fromYourPC = _t('ImageUploader.ONEFROMCOMPUTER');
|
||||
} else {
|
||||
$title = sprintf(
|
||||
_t('ImageUploader.ATTACH'),
|
||||
$type
|
||||
);
|
||||
$fromTheDB = _t('ImageUploader.ONEFROMFILESTORE');
|
||||
}
|
||||
|
||||
return new Form($this, 'EditImageSimpleForm', new FieldSet(
|
||||
new HiddenField("Class", null, $this->urlParams['Class']),
|
||||
new HiddenField("ID", null, $this->urlParams['ID']),
|
||||
new HiddenField("Field", null, $this->urlParams['Field']),
|
||||
new FileField("Upload","")
|
||||
),
|
||||
new FieldSet(
|
||||
new FormAction("save",$title)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* A form to delete this image.
|
||||
* @return string
|
||||
*/
|
||||
function DeleteImageForm() {
|
||||
if($this->Image()->ID) {
|
||||
$isImage = $this->IsImage();
|
||||
$type = $isImage ? _t('Controller.IMAGE') : _t('Controller.FILE');
|
||||
$title = sprintf(
|
||||
_t('ImageUploader.DELETE', 'Delete %s', PR_MEDIUM, 'Delete file/image'),
|
||||
$type
|
||||
);
|
||||
$form = new Form(
|
||||
$this,
|
||||
'DeleteImageForm',
|
||||
new FieldSet(
|
||||
new HiddenField("Class", null, $this->urlParams['Class']),
|
||||
new HiddenField("ID", null, $this->urlParams['ID']),
|
||||
new HiddenField("Field", null, $this->urlParams['Field'])
|
||||
),
|
||||
new FieldSet(
|
||||
$deleteAction = new ConfirmedFormAction(
|
||||
"delete",
|
||||
$title,
|
||||
sprintf(_t('ImageUploader.REALLYDELETE', "Do you really want to remove this %s?"), $type)
|
||||
)
|
||||
)
|
||||
);
|
||||
$deleteAction->addExtraClass('delete');
|
||||
|
||||
return $form;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the data in this form.
|
||||
*/
|
||||
function save($data, $form) {
|
||||
if($data['ImageSource'] != 'existing' && $data['Upload']['size'] == 0) {
|
||||
// No image has been uploaded
|
||||
Director::redirectBack();
|
||||
return;
|
||||
}
|
||||
$owner = DataObject::get_by_id($data['Class'], $data['ID']);
|
||||
$fieldName = $data['Field'] . 'ID';
|
||||
|
||||
if($data['ImageSource'] == 'existing') {
|
||||
if(!$data['ExistingFile']) {
|
||||
// No image has been selected
|
||||
Director::redirectBack();
|
||||
return;
|
||||
}
|
||||
|
||||
$owner->$fieldName = $data['ExistingFile'];
|
||||
|
||||
// Edit the class name, if applicable
|
||||
$existingFile = DataObject::get_by_id("File", $data['ExistingFile']);
|
||||
$desiredClass = $owner->has_one($data['Field']);
|
||||
|
||||
// Unless specifically asked, we don't want the user to be able
|
||||
// to select a folder
|
||||
if(is_a($existingFile, 'Folder') && $desiredClass != 'Folder') {
|
||||
Director::redirectBack();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!is_a($existingFile, $desiredClass)) {
|
||||
$existingFile->ClassName = $desiredClass;
|
||||
$existingFile->write();
|
||||
}
|
||||
} else {
|
||||
// TODO We need to replace this with a way to get the type of a field
|
||||
$imageClass = $owner->has_one($data['Field']);
|
||||
|
||||
// If we can't find the relationship, assume its an Image.
|
||||
if( !$imageClass) $imageClass = 'Image';
|
||||
|
||||
// Assuming its a decendant of File
|
||||
$image = new $imageClass();
|
||||
$image->loadUploaded($data['Upload']);
|
||||
$owner->$fieldName = $image->ID;
|
||||
|
||||
// store the owner id with the uploaded image
|
||||
$member = Member::currentUser();
|
||||
$image->OwnerID = $member->ID;
|
||||
$image->write();
|
||||
}
|
||||
|
||||
$owner->write();
|
||||
Director::redirectBack();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the image referenced by this form.
|
||||
*/
|
||||
function delete($data, $form) {
|
||||
$owner = DataObject::get_by_id( $data[ 'Class' ], $data[ 'ID' ] );
|
||||
$fieldName = $data[ 'Field' ] . 'ID';
|
||||
$owner->$fieldName = 0;
|
||||
$owner->write();
|
||||
Director::redirect($this->Link('iframe'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush all of the generated images.
|
||||
*/
|
||||
function flush() {
|
||||
if(!Permission::check('ADMIN')) Security::permissionFailure($this);
|
||||
|
||||
$images = DataObject::get("Image","");
|
||||
$numItems = 0;
|
||||
$num = 0;
|
||||
|
||||
foreach($images as $image) {
|
||||
$numDeleted = $image->deleteFormattedImages();
|
||||
if($numDeleted) {
|
||||
$numItems++;
|
||||
}
|
||||
$num += $numDeleted;
|
||||
}
|
||||
echo $num . ' formatted images from ' . $numItems . ' items flushed';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
167
css/FileIFrameField.css
Normal file
167
css/FileIFrameField.css
Normal file
@ -0,0 +1,167 @@
|
||||
@import url("typography.css");
|
||||
|
||||
html,body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border-style: none;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
form {
|
||||
margin: 0; padding: 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
font-size: 1.4em;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selection Groups
|
||||
*/
|
||||
.SelectionGroup {
|
||||
padding: 0;
|
||||
margin: 10px 0 0 0;
|
||||
}
|
||||
.SelectionGroup li {
|
||||
list-style-type: none;
|
||||
margin: 0 0 4px;
|
||||
}
|
||||
.SelectionGroup li label {
|
||||
font-size: 11px;
|
||||
}
|
||||
.SelectionGroup li input.selector {
|
||||
width: 20px;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
|
||||
.SelectionGroup li div.field {
|
||||
display: none;
|
||||
}
|
||||
.SelectionGroup li.selected div.field {
|
||||
display: block;
|
||||
margin-left: 30px;
|
||||
margin-bottom: 1em;
|
||||
margin-top: 4px;
|
||||
}
|
||||
.mainblock .SelectionGroup li.selected div.field {
|
||||
margin-left: 27px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.SelectionGroup li.selected label.selector {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* TreeDropdownField stying
|
||||
*/
|
||||
.SelectionGroup div.TreeDropdownField {
|
||||
width: 241px;
|
||||
padding: 0;
|
||||
}
|
||||
html>body div.TreeDropdownField {
|
||||
position:relative;
|
||||
}
|
||||
|
||||
.SelectionGroup div.TreeDropdownField span.items {
|
||||
display: block;
|
||||
height: 100%;
|
||||
border: 1px #7f9db9 solid;
|
||||
cursor: pointer;
|
||||
width: 214px;
|
||||
float: left;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.SelectionGroup div.TreeDropdownField div.tree_holder {
|
||||
clear: left;
|
||||
cursor: default;
|
||||
border: 1px black solid;
|
||||
margin: 0;
|
||||
height: 180px;
|
||||
overflow: auto;
|
||||
background-color: white;
|
||||
/**
|
||||
* HACK IE6, see http://www.hedgerwow.com/360/bugs/css-select-free.html
|
||||
*/
|
||||
position:absolute;
|
||||
z-index:10;
|
||||
width:238px;/*must have for any value*/
|
||||
}
|
||||
|
||||
html>body div.TreeDropdownField div.tree_holder {
|
||||
top: 20px;
|
||||
left: 0px;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* HACK IE6, see http://www.hedgerwow.com/360/bugs/css-select-free.html
|
||||
*/
|
||||
.SelectionGroup div.TreeDropdownField div.tree_holder iframe {
|
||||
display:none;/* IE5*/
|
||||
display/**/:block;/* IE5*/
|
||||
position:absolute;
|
||||
top:0;
|
||||
left:0;
|
||||
z-index:-1;
|
||||
filter:mask();
|
||||
width:180px; /*must have for any big value*/
|
||||
height:200px/*must have for any big value*/;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
div.TreeDropdownField a.editLink {
|
||||
border-width: 1px 1px 1px 0;
|
||||
background: url(../../sapphire/images/TreeDropdownField_button.gif) left top no-repeat;
|
||||
width: 19px;
|
||||
height: 21px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
float: left;
|
||||
clear: right;
|
||||
z-index: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* added block/width so tree values don't disappear in ie7 */
|
||||
.SelectionGroup div.TreeDropdownField ul.tree li {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.Actions {
|
||||
text-align: right;
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
bottom: 5px;
|
||||
}
|
||||
|
||||
.mainblock {
|
||||
float: left;
|
||||
border: 1px #CCC solid;
|
||||
padding: 5px;
|
||||
margin-right: 5px;
|
||||
height: 140px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.mainblock.editform {
|
||||
width: 290px;
|
||||
}
|
||||
|
||||
.mainblock form fieldset {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.mainblock form div.Actions input {
|
||||
font-size: 11px;
|
||||
}
|
44
filesystem/FlushGeneratedImagesTask.php
Normal file
44
filesystem/FlushGeneratedImagesTask.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
/**
|
||||
* Remove all cached/generated images that have been created as the result of a manipulation method being called on a
|
||||
* {@link Image} object
|
||||
*
|
||||
* @package sapphire
|
||||
* @subpackage filesystem
|
||||
*/
|
||||
class FlushGeneratedImagesTask extends BuildTask {
|
||||
|
||||
protected $title = 'Flush Generated Images Task';
|
||||
|
||||
protected $description = 'Remove all cached/generated images created as the result of an image manipulation';
|
||||
|
||||
/**
|
||||
* Check that the user has appropriate permissions to execute this task
|
||||
*/
|
||||
public function init() {
|
||||
if(!Director::is_cli() && !Director::isDev() && !Permission::check('ADMIN')) {
|
||||
Security::permissionFailure();
|
||||
}
|
||||
|
||||
parent::init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually clear out all the images
|
||||
*/
|
||||
public function run($request) {
|
||||
$processedImages = 0;
|
||||
$removedItems = 0;
|
||||
|
||||
if($images = DataObject::get('Image')) foreach($images as $image) {
|
||||
if($deleted = $image->deleteFormattedImages()) {
|
||||
$removedItems += $deleted;
|
||||
}
|
||||
|
||||
$processedImages++;
|
||||
}
|
||||
|
||||
echo "Removed $removedItems generated images from $processedImages Image objects stored in the Database.";
|
||||
}
|
||||
|
||||
}
|
@ -1,35 +1,228 @@
|
||||
<?php
|
||||
/**
|
||||
* A field that will upload files to a page for use within the CMS through an iframe.
|
||||
* If you want to upload files without an iframe, use {@link FileField}.
|
||||
* A field that allows you to attach a file to a DataObject without submitting the form it is part of, through the use
|
||||
* of an iframe.
|
||||
*
|
||||
* If all you need is a simple file upload, it is reccomended you use {@link FileField}
|
||||
*
|
||||
* @used Image_Upload
|
||||
*
|
||||
* @package forms
|
||||
* @subpackage fields-files
|
||||
*/
|
||||
class FileIFrameField extends FileField {
|
||||
|
||||
public function Field() {
|
||||
$data = $this->form->getRecord();
|
||||
|
||||
if($data && $data->ID && is_numeric($data->ID)) {
|
||||
$idxField = $this->name . 'ID';
|
||||
$hiddenField = "<input type=\"hidden\" id=\"" . $this->id() . "\" name=\"$idxField\" value=\"" . $this->attrValue() . "\" />";
|
||||
|
||||
$parentClass = $data->class;
|
||||
|
||||
$parentID = $data->ID;
|
||||
$parentField = $this->name;
|
||||
$iframe = "<iframe name=\"{$this->name}_iframe\" src=\"images/iframe/$parentClass/$parentID/$parentField\" style=\"height: 152px; width: 600px; border-style: none;\"></iframe>";
|
||||
public static $allowed_actions = array (
|
||||
'iframe',
|
||||
'EditFileForm',
|
||||
'DeleteFileForm'
|
||||
);
|
||||
|
||||
return $iframe . $hiddenField;
|
||||
|
||||
} else {
|
||||
$this->value = _t('FileIFrameField.NOTEADDFILES', 'You can add files once you have saved for the first time.');
|
||||
return FormField::Field();
|
||||
}
|
||||
/**
|
||||
* @see FileField::__construct()
|
||||
*/
|
||||
public function __construct($name, $title = null, $value = null, $form = null, $rightTitle = null, $folderName = null) {
|
||||
Requirements::css(THIRDPARTY_DIR . '/jquery/themes/default/ui.all.css');
|
||||
|
||||
Requirements::add_i18n_javascript(SAPPHIRE_DIR . '/javascript/lang');
|
||||
Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery.js');
|
||||
Requirements::javascript(THIRDPARTY_DIR . '/jquery/ui/ui.core.js');
|
||||
Requirements::javascript(THIRDPARTY_DIR . '/jquery/ui/ui.dialog.js');
|
||||
|
||||
parent::__construct($name, $title, $value, $form, $rightTitle, $folderName);
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function Field() {
|
||||
if($this->form->getRecord() && $this->form->getRecord()->exists()) {
|
||||
return $this->createTag (
|
||||
'iframe',
|
||||
array (
|
||||
'name' => $this->Name() . '_iframe',
|
||||
'src' => Controller::join_links($this->Link(), 'iframe'),
|
||||
'style' => 'height: 152px; width: 100%; border: none;'
|
||||
)
|
||||
) . $this->createTag (
|
||||
'input',
|
||||
array (
|
||||
'type' => 'hidden',
|
||||
'id' => $this->ID(),
|
||||
'name' => $this->Name() . 'ID',
|
||||
'value' => $this->attrValue()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$this->setValue(sprintf(_t (
|
||||
'FileIFrameField.ATTACHONCESAVED', '%ss can be attached once you have saved the record for the first time.'
|
||||
), $this->FileTypeName()));
|
||||
|
||||
return FormField::field();
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to retreive a File object that has already been attached to this forms data record
|
||||
*
|
||||
* @return File|null
|
||||
*/
|
||||
public function AttachedFile() {
|
||||
return $this->form->getRecord()->has_one($this->Name()) ? $this->form->getRecord()->{$this->Name()}() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function iframe() {
|
||||
// clear the requirements added by any parent controllers
|
||||
Requirements::clear();
|
||||
Requirements::add_i18n_javascript('sapphire/javascript/lang');
|
||||
Requirements::javascript('jsparty/jquery/jquery.js');
|
||||
Requirements::javascript('sapphire/javascript/FileIFrameField.js');
|
||||
|
||||
Requirements::css('cms/css/typography.css');
|
||||
Requirements::css('sapphire/css/FileIFrameField.css');
|
||||
|
||||
return $this->renderWith('FileIFrameField');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Form
|
||||
*/
|
||||
public function EditFileForm() {
|
||||
$uploadFile = _t('FileIFrameField.FROMCOMPUTER', 'From your Computer');
|
||||
$selectFile = _t('FileIFrameField.FROMFILESTORE', 'From the File Store');
|
||||
|
||||
if($this->AttachedFile() && $this->AttachedFile()->ID) {
|
||||
$title = sprintf(_t('FileIFrameField.REPLACE', 'Replace %s'), $this->FileTypeName());
|
||||
} else {
|
||||
$title = sprintf(_t('FileIFrameField.ATTACH', 'Attach %s'), $this->FileTypeName());
|
||||
}
|
||||
|
||||
$fileSources = array();
|
||||
|
||||
if(singleton('File')->canCreate()) {
|
||||
$fileSources["new//$uploadFile"] = new FileField('Upload', '');
|
||||
}
|
||||
|
||||
$fileSources["existing//$selectFile"] = new TreeDropdownField('ExistingFile', '', 'File');
|
||||
|
||||
return new Form (
|
||||
$this,
|
||||
'EditFileForm',
|
||||
new FieldSet (
|
||||
new HeaderField('EditFileHeader', $title),
|
||||
new SelectionGroup('FileSource', $fileSources)
|
||||
),
|
||||
new FieldSet (
|
||||
new FormAction('save', $title)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function save($data, $form) {
|
||||
// check the user has entered all the required information
|
||||
if (
|
||||
!isset($data['FileSource'])
|
||||
|| ($data['FileSource'] == 'new' && (!isset($_FILES['Upload']) || !$_FILES['Upload']))
|
||||
|| ($data['FileSource'] == 'existing' && (!isset($data['ExistingFile']) || !$data['ExistingFile']))
|
||||
) {
|
||||
Director::redirectBack();
|
||||
return;
|
||||
}
|
||||
|
||||
if($this->form->getRecord()->has_one($this->Name())) {
|
||||
$desiredClass = $this->form->getRecord()->has_one($this->Name());
|
||||
} else {
|
||||
$desiredClass = 'File';
|
||||
}
|
||||
|
||||
// upload a new file
|
||||
if($data['FileSource'] == 'new') {
|
||||
$fileObject = Object::create($desiredClass);
|
||||
|
||||
$this->upload->setAllowedExtensions($this->allowedExtensions);
|
||||
$this->upload->setAllowedMaxFileSize($this->allowedMaxFileSize);
|
||||
|
||||
$this->upload->loadIntoFile($_FILES['Upload'], $fileObject, $this->folderName);
|
||||
|
||||
if($this->upload->isError()) {
|
||||
Director::redirectBack();
|
||||
return;
|
||||
}
|
||||
|
||||
$this->form->getRecord()->{$this->Name() . 'ID'} = $fileObject->ID;
|
||||
|
||||
$fileObject->OwnerID = (Member::currentUser() ? Member::currentUser()->ID : 0);
|
||||
$fileObject->write();
|
||||
}
|
||||
|
||||
// attach an existing image from the assets store
|
||||
if($data['FileSource'] == 'existing') {
|
||||
$fileObject = DataObject::get_by_id('File', $data['ExistingFile']);
|
||||
|
||||
// dont allow the user to attach a folder by default
|
||||
if(!$fileObject || ($fileObject instanceof Folder && $desiredClass != 'Folder')) {
|
||||
Director::redirectBack();
|
||||
return;
|
||||
}
|
||||
|
||||
$this->form->getRecord()->{$this->Name() . 'ID'} = $fileObject->ID;
|
||||
|
||||
if(!$fileObject instanceof $desiredClass) {
|
||||
$fileObject->ClassName = $desiredClass;
|
||||
$fileObject->write();
|
||||
}
|
||||
}
|
||||
|
||||
$this->form->getRecord()->write();
|
||||
Director::redirectBack();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Form
|
||||
*/
|
||||
public function DeleteFileForm() {
|
||||
$form = new Form (
|
||||
$this,
|
||||
'DeleteFileForm',
|
||||
new FieldSet (
|
||||
new HiddenField('DeleteFile', null, false)
|
||||
),
|
||||
new FieldSet (
|
||||
$deleteButton = new FormAction (
|
||||
'delete', sprintf(_t('FileIFrameField.DELETE', 'Delete %s'), $this->FileTypeName())
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$deleteButton->addExtraClass('delete');
|
||||
return $form;
|
||||
}
|
||||
|
||||
public function delete($data, $form) {
|
||||
// delete the actual file, or just un-attach it?
|
||||
if(isset($data['DeleteFile']) && $data['DeleteFile']) {
|
||||
$file = DataObject::get_by_id('File', $this->form->getRecord()->{$this->Name() . 'ID'});
|
||||
|
||||
if($file) {
|
||||
$file->delete();
|
||||
}
|
||||
}
|
||||
|
||||
// then un-attach file from this record
|
||||
$this->form->getRecord()->{$this->Name() . 'ID'} = 0;
|
||||
$this->form->getRecord()->write();
|
||||
|
||||
Director::redirectBack();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type of file this field is used to attach (e.g. File, Image)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function FileTypeName() {
|
||||
return _t('FileIFrameField.FILE', 'File');
|
||||
}
|
||||
|
||||
}
|
@ -1,62 +1,25 @@
|
||||
<?php
|
||||
/**
|
||||
* A field that will upload attached images within the CMS through an iframe.
|
||||
* If you want to upload images without iframes, see {@link SimpleImageField}.
|
||||
* A field that allows you to attach an image to a record from within a iframe - designed for use in AJAX forms where it
|
||||
* is not possible to use {@link SimpleImageField}.
|
||||
*
|
||||
* @uses Image_Upload
|
||||
*
|
||||
* @package forms
|
||||
* @subpackage fields-files
|
||||
*/
|
||||
class ImageField extends FileField {
|
||||
|
||||
public function Field($id = null) {
|
||||
$data = $this->form->getRecord();
|
||||
|
||||
if($id && is_numeric($id)) {
|
||||
$parentID = $id;
|
||||
} elseif($data) {
|
||||
$parentID = $data->ID;
|
||||
} else {
|
||||
$parentID = null;
|
||||
}
|
||||
|
||||
if($data && $parentID && is_numeric($parentID)) {
|
||||
$idxField = $this->name . 'ID';
|
||||
$hiddenField = "<input class=\"hidden\" type=\"hidden\" id=\"" .
|
||||
$this->id() . "\" name=\"$idxField\" value=\"" . $this->attrValue() . "\" />";
|
||||
|
||||
$parentClass = $data->class;
|
||||
$parentField = $this->name;
|
||||
|
||||
$iframe = "<iframe name=\"{$this->name}_iframe\" src=\"images/iframe/$parentClass/$parentID/$parentField\" style=\"height: 152px; width: 525px; border: none;\" frameborder=\"0\"></iframe>";
|
||||
|
||||
return $iframe . $hiddenField;
|
||||
} else {
|
||||
$this->value = _t('ImageField.NOTEADDIMAGES', 'You can add images once you have saved for the first time.');
|
||||
return FormField::Field();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function saveInto($record) {
|
||||
$data = $this->form->getRecord();
|
||||
// if the record was written for the first time (has an arbitrary "new"-ID),
|
||||
// update the imagefield to enable uploading
|
||||
if($record->ID && $data && substr($data->ID, 0, 3) == 'new') {
|
||||
FormResponse::update_dom_id($this->id(), $this->Field($record->ID));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ImageField extends FileIFrameField {
|
||||
|
||||
/**
|
||||
* Returns a readonly version of this field
|
||||
* @return SimpleImageField_Disabled
|
||||
*/
|
||||
function performReadonlyTransformation() {
|
||||
$field = new SimpleImageField_Disabled($this->name, $this->title, $this->value);
|
||||
$field->setForm($this->form);
|
||||
return $field;
|
||||
public function performReadonlyTransformation() {
|
||||
return new SimpleImageField_Disabled($this->name, $this->title, $this->value, $this->form);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function FileTypeName() {
|
||||
return _t('ImageField.IMAGE', 'Image');
|
||||
}
|
||||
|
||||
}
|
47
javascript/FileIFrameField.js
Normal file
47
javascript/FileIFrameField.js
Normal file
@ -0,0 +1,47 @@
|
||||
(function($) {
|
||||
|
||||
$('#Form_DeleteFileForm_action_delete').click(function(e) {
|
||||
var deleteMessage = ss.i18n._t('FILEIFRAMEFIELD.CONFIRMDELETE', 'Are you sure you want to delete this file?');
|
||||
|
||||
if(typeof(parent.jQuery.fn.dialog) != 'undefined') {
|
||||
var buttons = {};
|
||||
var $dialog = undefined;
|
||||
var $deleteForm = $('#Form_DeleteFileForm');
|
||||
var $deleteFile = $('#Form_DeleteFileForm_DeleteFile');
|
||||
|
||||
buttons[ss.i18n._t('FILEIFRAMEFIELD.DELETEFILE', 'Delete File')] = function() {
|
||||
$deleteFile.attr('value', 'true');
|
||||
$deleteForm.submit();
|
||||
|
||||
$dialog.dialog('close');
|
||||
};
|
||||
|
||||
buttons[ss.i18n._t('FILEIFRAMEFIELD.UNATTACHFILE', 'Un-Attach File')] = function() {
|
||||
$deleteForm.submit();
|
||||
$dialog.dialog('close');
|
||||
};
|
||||
|
||||
buttons[ss.i18n._t('CANCEL', 'Cancel')] = function() {
|
||||
$dialog.dialog('close');
|
||||
};
|
||||
|
||||
$dialog = parent.jQuery('<p><span class="ui-icon ui-icon-alert">' + deleteMessage + '</span></p>').dialog({
|
||||
bgiframe: true,
|
||||
resizable: false,
|
||||
modal: true,
|
||||
height: 140,
|
||||
overlay: {
|
||||
backgroundColor: '#000',
|
||||
opacity: 0.5
|
||||
},
|
||||
title: ss.i18n._t('FILEIFRAMEFIELD.DELETEIMAGE', 'Delete Image'),
|
||||
buttons: buttons
|
||||
});
|
||||
|
||||
e.preventDefault();
|
||||
} else if(!confirm(deleteMessage)) {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery);
|
25
templates/FileIFrameField.ss
Normal file
25
templates/FileIFrameField.ss
Normal file
@ -0,0 +1,25 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" >
|
||||
<head>
|
||||
<% base_tag %>
|
||||
|
||||
<title><% _t('TITLE', 'Image Uploading Iframe') %></title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="mainblock editform">
|
||||
$EditFileForm
|
||||
</div>
|
||||
|
||||
<% if AttachedFile.ID %>
|
||||
<div class="mainblock">
|
||||
$AttachedFile.CMSThumbnail
|
||||
|
||||
<% if DeleteFileForm %>
|
||||
$DeleteFileForm
|
||||
<% end_if %>
|
||||
</div>
|
||||
<% end_if %>
|
||||
</body>
|
||||
|
||||
</html>
|
Loading…
x
Reference in New Issue
Block a user