mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
API Remove legacy HTMLEditor classes
This commit is contained in:
parent
36e3a43bdb
commit
e7d87add9f
@ -352,7 +352,7 @@ mappings:
|
||||
HTMLEditorConfig: SilverStripe\Forms\HTMLEditor\HTMLEditorConfig
|
||||
HTMLEditorField: SilverStripe\Forms\HTMLEditor\HTMLEditorField
|
||||
HTMLEditorField_Readonly: SilverStripe\Forms\HTMLEditor\HTMLEditorField_Readonly
|
||||
HTMLEditorField_Toolbar: SilverStripe\Forms\HTMLEditor\HTMLEditorField_Toolbar
|
||||
HTMLEditorField_Toolbar: SilverStripe\Admin\ModalController\HTMLEditorField_Toolbar
|
||||
HTMLEditorField_Embed: SilverStripe\Forms\HTMLEditor\HTMLEditorField_Embed
|
||||
HTMLEditorField_File: SilverStripe\Forms\HTMLEditor\HTMLEditorField_File
|
||||
HTMLEditorField_Flash: SilverStripe\Forms\HTMLEditor\HTMLEditorField_Flash
|
||||
|
@ -261,19 +261,11 @@ of the CMS you have to take care of instantiate yourself:
|
||||
:::php
|
||||
// File: mysite/code/MyController.php
|
||||
class MyObjectController extends Controller {
|
||||
public function EditorToolbar() {
|
||||
return HtmlEditorField_Toolbar::create($this, "EditorToolbar");
|
||||
public function Modals() {
|
||||
return ModalController::create($this, "Modals");
|
||||
}
|
||||
}
|
||||
|
||||
:::ss
|
||||
// File: mysite/templates/MyController.ss
|
||||
$Form
|
||||
<% with $EditorToolbar %>
|
||||
$MediaForm
|
||||
$LinkForm
|
||||
<% end_with %>
|
||||
|
||||
Note: The dialogs rely on CMS-access, e.g. for uploading and browsing files,
|
||||
so this is considered advanced usage of the field.
|
||||
|
||||
|
@ -1309,6 +1309,8 @@ After (`mysite/_config/config.yml`):
|
||||
* `getsubtree()` -> moved to `CMSMain`
|
||||
* `updatetreenodes()` -> moved to `CMSMain`
|
||||
* `savetreenodes()` -> moved to `CMSMain`
|
||||
* `EditorToolbar()` method renamed to `Modals()` and now returns a `ModalController` handler
|
||||
instance rather than a `HTMLEditorField_Toolbar`
|
||||
* Some `Director` API have been removed.
|
||||
* $dev_servers
|
||||
* $test_servers
|
||||
@ -1857,6 +1859,12 @@ New `TimeField` methods replace `getConfig()` / `setConfig()`
|
||||
* `setOption`
|
||||
* Removed `MemberDatetimeOptionsetField` (no replacement)
|
||||
* Removed `DateField_View_JQuery` (replaced with native HTML5 support in `DateField`)
|
||||
* The following HTMLEditorField_* classes have been removed:
|
||||
* `HTMLEditorField_Toolbar` (replaced With `ModalController` in admin module)
|
||||
* `HTMLEditorField_Embed` (replaced with `EmbedResource` in asset-admin module)
|
||||
* `HTMLEditorField_File`
|
||||
* `HTMLEditorField_Flash`
|
||||
* `HTMLEditorField_Image`
|
||||
|
||||
### <a name="overview-i18n"></a>i18n API
|
||||
|
||||
|
@ -1,167 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\Forms\HTMLEditor;
|
||||
|
||||
use Embed\Adapters\Adapter;
|
||||
use SilverStripe\Assets\File;
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Control\HTTPResponse_Exception;
|
||||
use SilverStripe\Forms\FieldList;
|
||||
use SilverStripe\Forms\TextField;
|
||||
use Embed\Adapters\AdapterInterface;
|
||||
use Embed\Embed;
|
||||
|
||||
/**
|
||||
* Encapsulation of an embed tag, linking to an external media source.
|
||||
*
|
||||
* @see Embed
|
||||
*/
|
||||
class HTMLEditorField_Embed extends HTMLEditorField_File
|
||||
{
|
||||
|
||||
private static $casting = array(
|
||||
'Type' => 'Varchar',
|
||||
'Info' => 'Varchar'
|
||||
);
|
||||
|
||||
/**
|
||||
* Embed result
|
||||
*
|
||||
* @var Adapter
|
||||
*/
|
||||
protected $embed;
|
||||
|
||||
public function __construct($url, File $file = null)
|
||||
{
|
||||
parent::__construct($url, $file);
|
||||
$this->embed = Embed::create($url);
|
||||
if (!$this->embed) {
|
||||
$controller = Controller::curr();
|
||||
$response = $controller->getResponse();
|
||||
$response->addHeader(
|
||||
'X-Status',
|
||||
rawurlencode(_t(
|
||||
'SilverStripe\\Forms\\HTMLEditor\\HTMLEditorField.URLNOTANOEMBEDRESOURCE',
|
||||
"The URL '{url}' could not be turned into a media resource.",
|
||||
"The given URL is not a valid Oembed resource; the embed element couldn't be created.",
|
||||
array('url' => $url)
|
||||
))
|
||||
);
|
||||
$response->setStatusCode(404);
|
||||
|
||||
throw new HTTPResponse_Exception($response);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file-edit fields for this filed
|
||||
*
|
||||
* @return FieldList
|
||||
*/
|
||||
public function getFields()
|
||||
{
|
||||
$fields = parent::getFields();
|
||||
if ($this->getType() === 'photo') {
|
||||
$fields->insertBefore('CaptionText', new TextField(
|
||||
'AltText',
|
||||
_t('SilverStripe\\Forms\\HTMLEditor\\HTMLEditorField.IMAGEALTTEXT', 'Alternative text (alt) - shown if image can\'t be displayed'),
|
||||
$this->Title,
|
||||
80
|
||||
));
|
||||
$fields->insertBefore('CaptionText', new TextField(
|
||||
'Title',
|
||||
_t('SilverStripe\\Forms\\HTMLEditor\\HTMLEditorField.IMAGETITLE', 'Title text (tooltip) - for additional information about the image')
|
||||
));
|
||||
}
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get width of this Embed
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getWidth()
|
||||
{
|
||||
return $this->embed->getWidth() ?: 100;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get height of this Embed
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getHeight()
|
||||
{
|
||||
return $this->embed->getHeight() ?: 100;
|
||||
}
|
||||
|
||||
public function getPreviewURL()
|
||||
{
|
||||
// Use thumbnail url
|
||||
if ($this->embed->image) {
|
||||
return $this->embed->image;
|
||||
}
|
||||
|
||||
// Use direct image type
|
||||
if ($this->getType() == 'photo' && !empty($this->embed->url)) {
|
||||
return $this->embed->url;
|
||||
}
|
||||
|
||||
// Default media
|
||||
return FRAMEWORK_ADMIN_DIR . '/client/dist/images/src/default_media.png';
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
if ($this->embed->title) {
|
||||
return $this->embed->title;
|
||||
} else {
|
||||
return parent::getName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Embed type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return $this->embed->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filetype
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFileType()
|
||||
{
|
||||
return $this->getType()
|
||||
?: parent::getFileType();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AdapterInterface
|
||||
*/
|
||||
public function getEmbed()
|
||||
{
|
||||
return $this->embed;
|
||||
}
|
||||
|
||||
public function appCategory()
|
||||
{
|
||||
return 'embed';
|
||||
}
|
||||
|
||||
/**
|
||||
* Info for this Embed
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getInfo()
|
||||
{
|
||||
return $this->embed->info;
|
||||
}
|
||||
}
|
@ -1,402 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\Forms\HTMLEditor;
|
||||
|
||||
use SilverStripe\Assets\File;
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Core\Convert;
|
||||
use SilverStripe\Forms\CompositeField;
|
||||
use SilverStripe\Forms\DateField_Disabled;
|
||||
use SilverStripe\Forms\DropdownField;
|
||||
use SilverStripe\Forms\FieldGroup;
|
||||
use SilverStripe\Forms\FieldList;
|
||||
use SilverStripe\Forms\HiddenField;
|
||||
use SilverStripe\Forms\HTMLReadonlyField;
|
||||
use SilverStripe\Forms\LiteralField;
|
||||
use SilverStripe\Forms\ReadonlyField;
|
||||
use SilverStripe\Forms\TextField;
|
||||
use SilverStripe\View\ViewableData;
|
||||
|
||||
/**
|
||||
* Encapsulation of a file which can either be a remote URL
|
||||
* or a {@link File} on the local filesystem, exhibiting common properties
|
||||
* such as file name or the URL.
|
||||
*
|
||||
* @todo Remove once core has support for remote files
|
||||
*/
|
||||
abstract class HTMLEditorField_File extends ViewableData
|
||||
{
|
||||
|
||||
/**
|
||||
* Default insertion width for Images and Media
|
||||
*
|
||||
* @config
|
||||
* @var int
|
||||
*/
|
||||
private static $insert_width = 600;
|
||||
|
||||
/**
|
||||
* Default insert height for images and media
|
||||
*
|
||||
* @config
|
||||
* @var int
|
||||
*/
|
||||
private static $insert_height = 360;
|
||||
|
||||
/**
|
||||
* Max width for insert-media preview.
|
||||
*
|
||||
* Matches CSS rule for .cms-file-info-preview
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private static $media_preview_width = 176;
|
||||
|
||||
/**
|
||||
* Max height for insert-media preview.
|
||||
*
|
||||
* Matches CSS rule for .cms-file-info-preview
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private static $media_preview_height = 128;
|
||||
|
||||
private static $casting = array(
|
||||
'URL' => 'Varchar',
|
||||
'Name' => 'Varchar'
|
||||
);
|
||||
|
||||
/**
|
||||
* Absolute URL to asset
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $url;
|
||||
|
||||
/**
|
||||
* File dataobject (if available)
|
||||
*
|
||||
* @var File
|
||||
*/
|
||||
protected $file;
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @param File $file
|
||||
*/
|
||||
public function __construct($url, File $file = null)
|
||||
{
|
||||
$this->url = $url;
|
||||
$this->file = $file;
|
||||
$this->failover = $file;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return FieldList
|
||||
*/
|
||||
public function getFields()
|
||||
{
|
||||
$fields = new FieldList(
|
||||
CompositeField::create(
|
||||
CompositeField::create(LiteralField::create("ImageFull", $this->getPreview()))
|
||||
->setName("FilePreviewImage")
|
||||
->addExtraClass('cms-file-info-preview'),
|
||||
CompositeField::create($this->getDetailFields())
|
||||
->setName("FilePreviewData")
|
||||
->addExtraClass('cms-file-info-data')
|
||||
)
|
||||
->setName("FilePreview")
|
||||
->addExtraClass('cms-file-info'),
|
||||
TextField::create('CaptionText', _t('SilverStripe\\Forms\\HTMLEditor\\HTMLEditorField.CAPTIONTEXT', 'Caption text')),
|
||||
DropdownField::create(
|
||||
'CSSClass',
|
||||
_t('SilverStripe\\Forms\\HTMLEditor\\HTMLEditorField.CSSCLASS', 'Alignment / style'),
|
||||
array(
|
||||
'leftAlone' => _t('SilverStripe\\Forms\\HTMLEditor\\HTMLEditorField.CSSCLASSLEFTALONE', 'On the left, on its own.'),
|
||||
'center' => _t('SilverStripe\\Forms\\HTMLEditor\\HTMLEditorField.CSSCLASSCENTER', 'Centered, on its own.'),
|
||||
'left' => _t('SilverStripe\\Forms\\HTMLEditor\\HTMLEditorField.CSSCLASSLEFT', 'On the left, with text wrapping around.'),
|
||||
'right' => _t('SilverStripe\\Forms\\HTMLEditor\\HTMLEditorField.CSSCLASSRIGHT', 'On the right, with text wrapping around.')
|
||||
),
|
||||
HtmlEditorField::config()->uninherited('media_alignment')
|
||||
),
|
||||
FieldGroup::create(
|
||||
_t('SilverStripe\\Forms\\HTMLEditor\\HTMLEditorField.IMAGEDIMENSIONS', 'Dimensions'),
|
||||
TextField::create(
|
||||
'Width',
|
||||
_t('SilverStripe\\Forms\\HTMLEditor\\HTMLEditorField.IMAGEWIDTHPX', 'Width'),
|
||||
$this->getInsertWidth()
|
||||
)->setMaxLength(5),
|
||||
TextField::create(
|
||||
'Height',
|
||||
" x " . _t('SilverStripe\\Forms\\HTMLEditor\\HTMLEditorField.IMAGEHEIGHTPX', 'Height'),
|
||||
$this->getInsertHeight()
|
||||
)->setMaxLength(5)
|
||||
)->addExtraClass('dimensions last'),
|
||||
HiddenField::create('URL', false, $this->getURL()),
|
||||
HiddenField::create('FileID', false, $this->getFileID())
|
||||
);
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of fields for previewing this records details
|
||||
*
|
||||
* @return FieldList
|
||||
*/
|
||||
protected function getDetailFields()
|
||||
{
|
||||
$fields = new FieldList(
|
||||
ReadonlyField::create("FileType", _t(__CLASS__.'.TYPE', 'File type'), $this->getFileType()),
|
||||
HTMLReadonlyField::create(
|
||||
'ClickableURL',
|
||||
_t(__CLASS__.'.URL', 'URL'),
|
||||
$this->getExternalLink()
|
||||
)
|
||||
);
|
||||
// Get file size
|
||||
if ($this->getSize()) {
|
||||
$fields->insertAfter(
|
||||
'FileType',
|
||||
ReadonlyField::create("Size", _t(__CLASS__.'.SIZE', 'File size'), $this->getSize())
|
||||
);
|
||||
}
|
||||
// Get modified details of local record
|
||||
if ($this->getFile()) {
|
||||
$fields->push(new DateField_Disabled(
|
||||
"Created",
|
||||
_t(__CLASS__.'.CREATED', 'First uploaded'),
|
||||
$this->getFile()->Created
|
||||
));
|
||||
$fields->push(new DateField_Disabled(
|
||||
"LastEdited",
|
||||
_t(__CLASS__.'.LASTEDIT', 'Last changed'),
|
||||
$this->getFile()->LastEdited
|
||||
));
|
||||
}
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file DataObject
|
||||
*
|
||||
* Might not be set (for remote files)
|
||||
*
|
||||
* @return File
|
||||
*/
|
||||
public function getFile()
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file ID
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getFileID()
|
||||
{
|
||||
if ($file = $this->getFile()) {
|
||||
return $file->ID;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get absolute URL
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getURL()
|
||||
{
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get basename
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->file
|
||||
? $this->file->Name
|
||||
: preg_replace('/\?.*/', '', basename($this->url));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get descriptive file type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFileType()
|
||||
{
|
||||
return File::get_file_type($this->getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file size (if known) as string
|
||||
*
|
||||
* @return string|false String value, or false if doesn't exist
|
||||
*/
|
||||
public function getSize()
|
||||
{
|
||||
if ($this->file) {
|
||||
return $this->file->getSize();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML content for preview
|
||||
*
|
||||
* @return string HTML
|
||||
*/
|
||||
public function getPreview()
|
||||
{
|
||||
$preview = $this->extend('getPreview');
|
||||
if ($preview) {
|
||||
return $preview;
|
||||
}
|
||||
|
||||
// Generate tag from preview
|
||||
$thumbnailURL = Convert::raw2att(
|
||||
Controller::join_links($this->getPreviewURL(), "?r=" . rand(1, 100000))
|
||||
);
|
||||
$fileName = Convert::raw2att($this->Name);
|
||||
return sprintf(
|
||||
"<img id='thumbnailImage' class='thumbnail-preview' src='%s' alt='%s' />\n",
|
||||
$thumbnailURL,
|
||||
$fileName
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML Content for external link
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getExternalLink()
|
||||
{
|
||||
$title = $this->file
|
||||
? $this->file->getTitle()
|
||||
: $this->getName();
|
||||
return sprintf(
|
||||
'<a href="%1$s" title="%2$s" target="_blank" rel="external" class="file-url">%1$s</a>',
|
||||
Convert::raw2att($this->url),
|
||||
Convert::raw2att($title)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate thumbnail url
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPreviewURL()
|
||||
{
|
||||
// Get preview from file
|
||||
if ($this->file) {
|
||||
return $this->getFilePreviewURL();
|
||||
}
|
||||
|
||||
// Generate default icon html
|
||||
return File::get_icon_for_extension($this->getExtension());
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate thumbnail URL from file dataobject (if available)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getFilePreviewURL()
|
||||
{
|
||||
// Get preview from file
|
||||
if ($this->file) {
|
||||
$width = HTMLEditorField_File::config()->media_preview_width;
|
||||
$height = HTMLEditorField_File::config()->media_preview_height;
|
||||
return $this->file->ThumbnailURL($width, $height);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file extension
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getExtension()
|
||||
{
|
||||
$extension = File::get_file_extension($this->getName());
|
||||
return strtolower($extension);
|
||||
}
|
||||
|
||||
/**
|
||||
* Category name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function appCategory()
|
||||
{
|
||||
if ($this->file) {
|
||||
return $this->file->appCategory();
|
||||
} else {
|
||||
return File::get_app_category($this->getExtension());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get height of this item
|
||||
*/
|
||||
public function getHeight()
|
||||
{
|
||||
if ($this->file) {
|
||||
$height = $this->file->getHeight();
|
||||
if ($height) {
|
||||
return $height;
|
||||
}
|
||||
}
|
||||
return HTMLEditorField_File::config()->insert_height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get width of this item
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getWidth()
|
||||
{
|
||||
if ($this->file) {
|
||||
$width = $this->file->getWidth();
|
||||
if ($width) {
|
||||
return $width;
|
||||
}
|
||||
}
|
||||
return HTMLEditorField_File::config()->insert_width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide an initial width for inserted media, restricted based on $embed_width
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getInsertWidth()
|
||||
{
|
||||
$width = $this->getWidth();
|
||||
$maxWidth = HTMLEditorField_File::config()->insert_width;
|
||||
return ($width <= $maxWidth) ? $width : $maxWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide an initial height for inserted media, scaled proportionally to the initial width
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getInsertHeight()
|
||||
{
|
||||
$width = $this->getWidth();
|
||||
$height = $this->getHeight();
|
||||
$maxWidth = HTMLEditorField_File::config()->insert_width;
|
||||
return ($width <= $maxWidth) ? $height : round($height * ($maxWidth / $width));
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\Forms\HTMLEditor;
|
||||
|
||||
/**
|
||||
* Generate flash file embed
|
||||
*/
|
||||
class HTMLEditorField_Flash extends HTMLEditorField_File
|
||||
{
|
||||
|
||||
public function getFields()
|
||||
{
|
||||
$fields = parent::getFields();
|
||||
$fields->removeByName('CaptionText', true);
|
||||
return $fields;
|
||||
}
|
||||
}
|
@ -1,213 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\Forms\HTMLEditor;
|
||||
|
||||
use SilverStripe\Assets\File;
|
||||
use SilverStripe\Forms\ReadonlyField;
|
||||
use SilverStripe\Forms\TextField;
|
||||
|
||||
/**
|
||||
* Encapsulation of an image tag, linking to an image either internal or external to the site.
|
||||
*/
|
||||
class HTMLEditorField_Image extends HTMLEditorField_File
|
||||
{
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $width;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $height;
|
||||
|
||||
/**
|
||||
* File size details
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $size;
|
||||
|
||||
public function __construct($url, File $file = null)
|
||||
{
|
||||
parent::__construct($url, $file);
|
||||
|
||||
if ($file) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get size of remote file
|
||||
$size = @filesize($url);
|
||||
if ($size) {
|
||||
$this->size = $size;
|
||||
}
|
||||
|
||||
// Get dimensions of remote file
|
||||
$info = @getimagesize($url);
|
||||
if ($info) {
|
||||
$this->width = $info[0];
|
||||
$this->height = $info[1];
|
||||
}
|
||||
}
|
||||
|
||||
public function getFields()
|
||||
{
|
||||
$fields = parent::getFields();
|
||||
|
||||
// Alt text
|
||||
$fields->insertBefore(
|
||||
'CaptionText',
|
||||
TextField::create(
|
||||
'AltText',
|
||||
_t('SilverStripe\\Forms\\HTMLEditor\\HTMLEditorField.IMAGEALT', 'Alternative text (alt)'),
|
||||
$this->Title,
|
||||
80
|
||||
)->setDescription(
|
||||
_t('SilverStripe\\Forms\\HTMLEditor\\HTMLEditorField.IMAGEALTTEXTDESC', 'Shown to screen readers or if image can\'t be displayed')
|
||||
)
|
||||
);
|
||||
|
||||
// Tooltip
|
||||
$fields->insertAfter(
|
||||
'AltText',
|
||||
TextField::create(
|
||||
'Title',
|
||||
_t('SilverStripe\\Forms\\HTMLEditor\\HTMLEditorField.IMAGETITLETEXT', 'Title text (tooltip)')
|
||||
)->setDescription(
|
||||
_t('SilverStripe\\Forms\\HTMLEditor\\HTMLEditorField.IMAGETITLETEXTDESC', 'For additional information about the image')
|
||||
)
|
||||
);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
protected function getDetailFields()
|
||||
{
|
||||
$fields = parent::getDetailFields();
|
||||
$width = $this->getOriginalWidth();
|
||||
$height = $this->getOriginalHeight();
|
||||
|
||||
// Show dimensions of original
|
||||
if ($width && $height) {
|
||||
$fields->insertAfter(
|
||||
'ClickableURL',
|
||||
ReadonlyField::create(
|
||||
"OriginalWidth",
|
||||
_t(__CLASS__.'.WIDTH', 'Width'),
|
||||
$width
|
||||
)
|
||||
);
|
||||
$fields->insertAfter(
|
||||
'OriginalWidth',
|
||||
ReadonlyField::create(
|
||||
"OriginalHeight",
|
||||
_t(__CLASS__.'.HEIGHT', 'Height'),
|
||||
$height
|
||||
)
|
||||
);
|
||||
}
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get width of original, if known
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getOriginalWidth()
|
||||
{
|
||||
if ($this->width) {
|
||||
return $this->width;
|
||||
}
|
||||
if ($this->file) {
|
||||
$width = $this->file->getWidth();
|
||||
if ($width) {
|
||||
return $width;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get height of original, if known
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getOriginalHeight()
|
||||
{
|
||||
if ($this->height) {
|
||||
return $this->height;
|
||||
}
|
||||
|
||||
if ($this->file) {
|
||||
$height = $this->file->getHeight();
|
||||
if ($height) {
|
||||
return $height;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getWidth()
|
||||
{
|
||||
if ($this->width) {
|
||||
return $this->width;
|
||||
}
|
||||
return parent::getWidth();
|
||||
}
|
||||
|
||||
public function getHeight()
|
||||
{
|
||||
if ($this->height) {
|
||||
return $this->height;
|
||||
}
|
||||
return parent::getHeight();
|
||||
}
|
||||
|
||||
public function getSize()
|
||||
{
|
||||
if ($this->size) {
|
||||
return File::format_size($this->size);
|
||||
}
|
||||
return parent::getSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide an initial width for inserted image, restricted based on $embed_width
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getInsertWidth()
|
||||
{
|
||||
$width = $this->getWidth();
|
||||
$maxWidth = HTMLEditorField_Image::config()->insert_width;
|
||||
return $width <= $maxWidth
|
||||
? $width
|
||||
: $maxWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide an initial height for inserted image, scaled proportionally to the initial width
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getInsertHeight()
|
||||
{
|
||||
$width = $this->getWidth();
|
||||
$height = $this->getHeight();
|
||||
$maxWidth = HTMLEditorField_Image::config()->insert_width;
|
||||
return ($width <= $maxWidth) ? $height : round($height * ($maxWidth / $width));
|
||||
}
|
||||
|
||||
public function getPreviewURL()
|
||||
{
|
||||
// Get preview from file
|
||||
if ($this->file) {
|
||||
return $this->getFilePreviewURL();
|
||||
}
|
||||
|
||||
// Embed image directly
|
||||
return $this->url;
|
||||
}
|
||||
}
|
@ -1,495 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\Forms\HTMLEditor;
|
||||
|
||||
use SilverStripe\Admin\Forms\EditorExternalLinkFormFactory;
|
||||
use SilverStripe\Admin\Forms\EditorEmailLinkFormFactory;
|
||||
use SilverStripe\Assets\File;
|
||||
use SilverStripe\CMS\Model\SiteTree;
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Control\RequestHandler;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Control\HTTPResponse_Exception;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Forms\CheckboxField;
|
||||
use SilverStripe\Forms\CompositeField;
|
||||
use SilverStripe\Forms\EmailField;
|
||||
use SilverStripe\Forms\FieldList;
|
||||
use SilverStripe\Forms\Form;
|
||||
use SilverStripe\Forms\HiddenField;
|
||||
use SilverStripe\Forms\LiteralField;
|
||||
use SilverStripe\Forms\OptionsetField;
|
||||
use SilverStripe\Forms\TextField;
|
||||
use SilverStripe\Forms\TreeDropdownField;
|
||||
use SilverStripe\ORM\DataList;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\View\SSViewer;
|
||||
|
||||
/**
|
||||
* Toolbar shared by all instances of {@link HTMLEditorField}, to avoid too much markup duplication.
|
||||
* Needs to be inserted manually into the template in order to function - see {@link LeftAndMain->EditorToolbar()}.
|
||||
*/
|
||||
class HTMLEditorField_Toolbar extends RequestHandler
|
||||
{
|
||||
|
||||
private static $allowed_actions = array(
|
||||
'LinkForm',
|
||||
'EditorExternalLink',
|
||||
'EditorEmailLink',
|
||||
'viewfile',
|
||||
'getanchors'
|
||||
);
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTemplateViewFile()
|
||||
{
|
||||
return SSViewer::get_templates_by_class(static::class, '_viewfile', __CLASS__);
|
||||
}
|
||||
|
||||
/**
|
||||
* @var Controller
|
||||
*/
|
||||
protected $controller;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
public function __construct($controller, $name)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->controller = $controller;
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
public function forTemplate()
|
||||
{
|
||||
return sprintf(
|
||||
'<div id="cms-editor-dialogs" data-url-linkform="%s"></div>',
|
||||
Controller::join_links($this->controller->Link(), $this->name, 'LinkForm', 'forTemplate')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the SiteTree for display in the dropdown
|
||||
*
|
||||
* @param string $sourceObject
|
||||
* @param string $labelField
|
||||
* @param string $search
|
||||
* @return DataList
|
||||
*/
|
||||
public function siteTreeSearchCallback($sourceObject, $labelField, $search)
|
||||
{
|
||||
return DataObject::get($sourceObject)->filterAny(array(
|
||||
'MenuTitle:PartialMatch' => $search,
|
||||
'Title:PartialMatch' => $search
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link Form} instance allowing a user to
|
||||
* add links in the TinyMCE content editor.
|
||||
*
|
||||
* @skipUpgrade
|
||||
* @return Form
|
||||
*/
|
||||
public function LinkForm()
|
||||
{
|
||||
$siteTree = TreeDropdownField::create(
|
||||
'internal',
|
||||
_t(__CLASS__.'.PAGE', "Page"),
|
||||
SiteTree::class,
|
||||
'ID',
|
||||
'MenuTitle',
|
||||
true
|
||||
);
|
||||
// mimic the SiteTree::getMenuTitle(), which is bypassed when the search is performed
|
||||
$siteTree->setSearchFunction(array($this, 'siteTreeSearchCallback'));
|
||||
|
||||
$numericLabelTmpl = '<span class="step-label"><span class="flyout">Step %d.</span>'
|
||||
. '<span class="title">%s</span></span>';
|
||||
|
||||
$form = new Form(
|
||||
$this->controller,
|
||||
"{$this->name}/LinkForm",
|
||||
new FieldList(
|
||||
$headerWrap = new CompositeField(
|
||||
new LiteralField(
|
||||
'Heading',
|
||||
sprintf(
|
||||
'<h3 class="htmleditorfield-linkform-heading insert">%s</h3>',
|
||||
_t(__CLASS__.'.LINK', 'Insert Link')
|
||||
)
|
||||
)
|
||||
),
|
||||
$contentComposite = new CompositeField(
|
||||
OptionsetField::create(
|
||||
'LinkType',
|
||||
DBField::create_field(
|
||||
'HTMLFragment',
|
||||
sprintf($numericLabelTmpl, '1', _t(__CLASS__.'.LINKTO', 'Link type'))
|
||||
),
|
||||
array(
|
||||
'internal' => _t(__CLASS__.'.LINKINTERNAL', 'Link to a page on this site'),
|
||||
'external' => _t(__CLASS__.'.LINKEXTERNAL', 'Link to another website'),
|
||||
'anchor' => _t(__CLASS__.'.LINKANCHOR', 'Link to an anchor on this page'),
|
||||
'email' => _t(__CLASS__.'.LINKEMAIL', 'Link to an email address'),
|
||||
'file' => _t(__CLASS__.'.LINKFILE', 'Link to download a file'),
|
||||
),
|
||||
'internal'
|
||||
),
|
||||
LiteralField::create(
|
||||
'Step2',
|
||||
'<div class="step2">'
|
||||
. sprintf($numericLabelTmpl, '2', _t(__CLASS__.'.LINKDETAILS', 'Link details')) . '</div>'
|
||||
),
|
||||
$siteTree,
|
||||
TextField::create('external', _t(__CLASS__.'.URL', 'URL'), 'http://'),
|
||||
EmailField::create('email', _t(__CLASS__.'.EMAIL', 'Email address')),
|
||||
$fileField = TreeDropdownField::create(
|
||||
'file',
|
||||
_t(__CLASS__.'.FILE', 'File'),
|
||||
File::class,
|
||||
'ID',
|
||||
'Name'
|
||||
),
|
||||
TextField::create('Anchor', _t(__CLASS__.'.ANCHORVALUE', 'Anchor')),
|
||||
TextField::create('Subject', _t(__CLASS__.'.SUBJECT', 'Email subject')),
|
||||
TextField::create('Description', _t(__CLASS__.'.LINKDESCR', 'Link description')),
|
||||
CheckboxField::create(
|
||||
'TargetBlank',
|
||||
_t(__CLASS__.'.LINKOPENNEWWIN', 'Open link in a new window?')
|
||||
),
|
||||
HiddenField::create('Locale', null, $this->controller->Locale)
|
||||
)
|
||||
),
|
||||
new FieldList()
|
||||
);
|
||||
|
||||
$headerWrap->setName('HeaderWrap');
|
||||
$headerWrap->addExtraClass('CompositeField composite cms-content-header form-group--no-label ');
|
||||
$contentComposite->setName('ContentBody');
|
||||
$contentComposite->addExtraClass('ss-insert-link content');
|
||||
|
||||
$form->unsetValidator();
|
||||
$form->loadDataFrom($this);
|
||||
$form->addExtraClass('htmleditorfield-form htmleditorfield-linkform cms-linkform-content');
|
||||
|
||||
$this->extend('updateLinkForm', $form);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and returns the external link form
|
||||
*
|
||||
* @return null|Form
|
||||
*/
|
||||
public function EditorExternalLink($id = null)
|
||||
{
|
||||
/** @var EditorExternalLinkFormFactory $factory */
|
||||
$factory = Injector::inst()->get(EditorExternalLinkFormFactory::class);
|
||||
if ($factory) {
|
||||
return $factory->getForm($this->controller, "{$this->name}/EditorExternalLink");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and returns the external link form
|
||||
*
|
||||
* @return null|Form
|
||||
*/
|
||||
public function EditorEmailLink($id = null)
|
||||
{
|
||||
/** @var EditorEmailLinkFormFactory $factory */
|
||||
$factory = Injector::inst()->get(EditorEmailLinkFormFactory::class);
|
||||
|
||||
if ($factory) {
|
||||
return $factory->getForm($this->controller, "{$this->name}/EditorEmailLink");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the folder ID to filter files by for the "from cms" tab
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function getAttachParentID()
|
||||
{
|
||||
$parentID = $this->controller->getRequest()->requestVar('ParentID');
|
||||
$this->extend('updateAttachParentID', $parentID);
|
||||
return $parentID;
|
||||
}
|
||||
|
||||
/**
|
||||
* List of allowed schemes (no wildcard, all lower case) or empty to allow all schemes
|
||||
*
|
||||
* @config
|
||||
* @var array
|
||||
*/
|
||||
private static $fileurl_scheme_whitelist = array('http', 'https');
|
||||
|
||||
/**
|
||||
* List of allowed domains (no wildcard, all lower case) or empty to allow all domains
|
||||
*
|
||||
* @config
|
||||
* @var array
|
||||
*/
|
||||
private static $fileurl_domain_whitelist = array();
|
||||
|
||||
/**
|
||||
* Find local File dataobject given ID
|
||||
*
|
||||
* @param int $id
|
||||
* @return array
|
||||
*/
|
||||
protected function viewfile_getLocalFileByID($id)
|
||||
{
|
||||
/** @var File $file */
|
||||
$file = DataObject::get_by_id(File::class, $id);
|
||||
if ($file && $file->canView()) {
|
||||
return array($file, $file->getURL());
|
||||
}
|
||||
return [null, null];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get remote File given url
|
||||
*
|
||||
* @param string $fileUrl Absolute URL
|
||||
* @return array
|
||||
* @throws HTTPResponse_Exception
|
||||
*/
|
||||
protected function viewfile_getRemoteFileByURL($fileUrl)
|
||||
{
|
||||
if (!Director::is_absolute_url($fileUrl)) {
|
||||
throw $this->getErrorFor(_t(
|
||||
"SilverStripe\\Forms\\HTMLEditor\\HTMLEditorField_Toolbar.ERROR_ABSOLUTE",
|
||||
"Only absolute urls can be embedded"
|
||||
));
|
||||
}
|
||||
$scheme = strtolower(parse_url($fileUrl, PHP_URL_SCHEME));
|
||||
$allowed_schemes = self::config()->get('fileurl_scheme_whitelist');
|
||||
if (!$scheme || ($allowed_schemes && !in_array($scheme, $allowed_schemes))) {
|
||||
throw $this->getErrorFor(_t(
|
||||
"SilverStripe\\Forms\\HTMLEditor\\HTMLEditorField_Toolbar.ERROR_SCHEME",
|
||||
"This file scheme is not included in the whitelist"
|
||||
));
|
||||
}
|
||||
$domain = strtolower(parse_url($fileUrl, PHP_URL_HOST));
|
||||
$allowed_domains = self::config()->get('fileurl_domain_whitelist');
|
||||
if (!$domain || ($allowed_domains && !in_array($domain, $allowed_domains))) {
|
||||
throw $this->getErrorFor(_t(
|
||||
"SilverStripe\\Forms\\HTMLEditor\\HTMLEditorField_Toolbar.ERROR_HOSTNAME",
|
||||
"This file hostname is not included in the whitelist"
|
||||
));
|
||||
}
|
||||
return [null, $fileUrl];
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare error for the front end
|
||||
*
|
||||
* @param string $message
|
||||
* @param int $code
|
||||
* @return HTTPResponse_Exception
|
||||
*/
|
||||
protected function getErrorFor($message, $code = 400)
|
||||
{
|
||||
$exception = new HTTPResponse_Exception($message, $code);
|
||||
$exception->getResponse()->addHeader('X-Status', $message);
|
||||
return $exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* View of a single file, either on the filesystem or on the web.
|
||||
*
|
||||
* @throws HTTPResponse_Exception
|
||||
* @param HTTPRequest $request
|
||||
* @return string
|
||||
*/
|
||||
public function viewfile($request)
|
||||
{
|
||||
$file = null;
|
||||
$url = null;
|
||||
// Get file and url by request method
|
||||
if ($fileUrl = $request->getVar('FileURL')) {
|
||||
// Get remote url
|
||||
list($file, $url) = $this->viewfile_getRemoteFileByURL($fileUrl);
|
||||
} elseif ($id = $request->getVar('ID')) {
|
||||
// Or we could have been passed an ID directly
|
||||
list($file, $url) = $this->viewfile_getLocalFileByID($id);
|
||||
} else {
|
||||
// Or we could have been passed nothing, in which case panic
|
||||
throw $this->getErrorFor(_t(
|
||||
"SilverStripe\\Forms\\HTMLEditor\\HTMLEditorField_Toolbar.ERROR_ID",
|
||||
'Need either "ID" or "FileURL" parameter to identify the file'
|
||||
));
|
||||
}
|
||||
|
||||
// Validate file exists
|
||||
if (!$url) {
|
||||
throw $this->getErrorFor(_t(
|
||||
"SilverStripe\\Forms\\HTMLEditor\\HTMLEditorField_Toolbar.ERROR_NOTFOUND",
|
||||
'Unable to find file to view'
|
||||
));
|
||||
}
|
||||
|
||||
// Instantiate file wrapper and get fields based on its type
|
||||
// Check if appCategory is an image and exists on the local system, otherwise use Embed to reference a
|
||||
// remote image
|
||||
$fileCategory = $this->getFileCategory($url, $file);
|
||||
switch ($fileCategory) {
|
||||
case 'image':
|
||||
case 'image/supported':
|
||||
$fileWrapper = new HTMLEditorField_Image($url, $file);
|
||||
break;
|
||||
case 'flash':
|
||||
$fileWrapper = new HTMLEditorField_Flash($url, $file);
|
||||
break;
|
||||
default:
|
||||
// Only remote files can be linked via o-embed
|
||||
// {@see HTMLEditorField_Toolbar::getAllowedExtensions())
|
||||
if ($file) {
|
||||
throw $this->getErrorFor(_t(
|
||||
"SilverStripe\\Forms\\HTMLEditor\\HTMLEditorField_Toolbar.ERROR_OEMBED_REMOTE",
|
||||
"Embed is only compatible with remote files"
|
||||
));
|
||||
}
|
||||
|
||||
// Other files should fallback to embed
|
||||
$fileWrapper = new HTMLEditorField_Embed($url, $file);
|
||||
break;
|
||||
}
|
||||
|
||||
// Render fields and return
|
||||
$fields = $this->getFieldsForFile($url, $fileWrapper);
|
||||
return $fileWrapper->customise(array(
|
||||
'Fields' => $fields,
|
||||
))->renderWith($this->getTemplateViewFile());
|
||||
}
|
||||
|
||||
/**
|
||||
* Guess file category from either a file or url
|
||||
*
|
||||
* @param string $url
|
||||
* @param File $file
|
||||
* @return string
|
||||
*/
|
||||
protected function getFileCategory($url, $file)
|
||||
{
|
||||
if ($file) {
|
||||
return $file->appCategory();
|
||||
}
|
||||
if ($url) {
|
||||
return File::get_app_category(File::get_file_extension($url));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all anchors available on the given page.
|
||||
*
|
||||
* @return array
|
||||
* @throws HTTPResponse_Exception
|
||||
*/
|
||||
public function getanchors()
|
||||
{
|
||||
$id = (int)$this->getRequest()->getVar('PageID');
|
||||
$anchors = array();
|
||||
|
||||
if (($page = SiteTree::get()->byID($id)) && !empty($page)) {
|
||||
if (!$page->canView()) {
|
||||
throw new HTTPResponse_Exception(
|
||||
_t(
|
||||
'SilverStripe\\Forms\\HTMLEditor\\HTMLEditorField.ANCHORSCANNOTACCESSPAGE',
|
||||
'You are not permitted to access the content of the target page.'
|
||||
),
|
||||
403
|
||||
);
|
||||
}
|
||||
|
||||
// Parse the shortcodes so [img id=x] doesn't end up as anchor x
|
||||
$htmlValue = $page->obj('Content')->forTemplate();
|
||||
|
||||
// Similar to the regex found in HTMLEditorField.js / getAnchors method.
|
||||
if (preg_match_all(
|
||||
"/\\s+(name|id)\\s*=\\s*([\"'])([^\\2\\s>]*?)\\2|\\s+(name|id)\\s*=\\s*([^\"']+)[\\s +>]/im",
|
||||
$htmlValue,
|
||||
$matches
|
||||
)) {
|
||||
$anchors = array_values(array_unique(array_filter(
|
||||
array_merge($matches[3], $matches[5])
|
||||
)));
|
||||
}
|
||||
} else {
|
||||
throw new HTTPResponse_Exception(
|
||||
_t('SilverStripe\\Forms\\HTMLEditor\\HTMLEditorField.ANCHORSPAGENOTFOUND', 'Target page not found.'),
|
||||
404
|
||||
);
|
||||
}
|
||||
|
||||
return json_encode($anchors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to {@link File->getCMSFields()}, but only returns fields
|
||||
* for manipulating the instance of the file as inserted into the HTML content,
|
||||
* not the "master record" in the database - hence there's no form or saving logic.
|
||||
*
|
||||
* @param string $url Abolute URL to asset
|
||||
* @param HTMLEditorField_File $file Asset wrapper
|
||||
* @return FieldList
|
||||
*/
|
||||
protected function getFieldsForFile($url, HTMLEditorField_File $file)
|
||||
{
|
||||
$fields = $this->extend('getFieldsForFile', $url, $file);
|
||||
if (!$fields) {
|
||||
$fields = $file->getFields();
|
||||
$file->extend('updateFields', $fields);
|
||||
}
|
||||
$this->extend('updateFieldsForFile', $fields, $url, $file);
|
||||
return $fields;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets files filtered by a given parent with the allowed extensions
|
||||
*
|
||||
* @param int $parentID
|
||||
* @return DataList
|
||||
*/
|
||||
protected function getFiles($parentID = null)
|
||||
{
|
||||
$exts = $this->getAllowedExtensions();
|
||||
$dotExts = array_map(function ($ext) {
|
||||
return ".{$ext}";
|
||||
}, $exts);
|
||||
$files = File::get()->filter('Name:EndsWith', $dotExts);
|
||||
|
||||
// Limit by folder (if required)
|
||||
if ($parentID) {
|
||||
$files = $files->filter('ParentID', $parentID);
|
||||
}
|
||||
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array All extensions which can be handled by the different views.
|
||||
*/
|
||||
protected function getAllowedExtensions()
|
||||
{
|
||||
$exts = array('jpg', 'gif', 'png', 'swf', 'jpeg');
|
||||
$this->extend('updateAllowedExtensions', $exts);
|
||||
return $exts;
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ namespace SilverStripe\Forms\Schema;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Core\Injector\Injectable;
|
||||
use SilverStripe\Forms\CompositeField;
|
||||
use SilverStripe\Forms\Form;
|
||||
use SilverStripe\Forms\FormField;
|
||||
@ -16,6 +17,8 @@ use SilverStripe\ORM\ValidationResult;
|
||||
*/
|
||||
class FormSchema
|
||||
{
|
||||
use Injectable;
|
||||
|
||||
/**
|
||||
* Request the schema part
|
||||
*/
|
||||
|
@ -2,40 +2,27 @@
|
||||
|
||||
namespace SilverStripe\Forms\Tests\HTMLEditor;
|
||||
|
||||
use Page;
|
||||
use SilverStripe\Assets\File;
|
||||
use SilverStripe\Assets\FileNameFilter;
|
||||
use SilverStripe\Assets\Filesystem;
|
||||
use SilverStripe\Assets\Folder;
|
||||
use SilverStripe\Assets\Image;
|
||||
use SilverStripe\Assets\Tests\Storage\AssetStoreTest\TestAssetStore;
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\Dev\CSSContentParser;
|
||||
use SilverStripe\Dev\FunctionalTest;
|
||||
use SilverStripe\Forms\HTMLEditor\HTMLEditorField;
|
||||
use SilverStripe\Forms\HTMLEditor\HTMLEditorField_Toolbar;
|
||||
use SilverStripe\Forms\HTMLEditor\HTMLEditorField_Image;
|
||||
use SilverStripe\Forms\HTMLReadonlyField;
|
||||
use SilverStripe\Forms\Tests\HTMLEditor\HTMLEditorFieldTest\DummyMediaFormFieldExtension;
|
||||
use SilverStripe\Forms\Tests\HTMLEditor\HTMLEditorFieldTest\TestObject;
|
||||
use SilverStripe\ORM\FieldType\DBHTMLText;
|
||||
use SilverStripe\Forms\HTMLEditor\TinyMCEConfig;
|
||||
|
||||
class HTMLEditorFieldTest extends FunctionalTest
|
||||
{
|
||||
|
||||
protected static $fixture_file = 'HTMLEditorFieldTest.yml';
|
||||
|
||||
protected static $use_draft_site = true;
|
||||
|
||||
protected static $required_extensions= array(
|
||||
HTMLEditorField_Toolbar::class => array(
|
||||
DummyMediaFormFieldExtension::class,
|
||||
),
|
||||
);
|
||||
|
||||
protected static $extra_dataobjects = [
|
||||
TestObject::class,
|
||||
];
|
||||
@ -48,16 +35,16 @@ class HTMLEditorFieldTest extends FunctionalTest
|
||||
TestAssetStore::activate('HTMLEditorFieldTest');
|
||||
|
||||
// Set the File Name Filter replacements so files have the expected names
|
||||
Config::inst()->update(
|
||||
Config::modify()->set(
|
||||
FileNameFilter::class,
|
||||
'default_replacements',
|
||||
array(
|
||||
'/\s/' => '-', // remove whitespace
|
||||
'/_/' => '-', // underscores to dashes
|
||||
'/[^A-Za-z0-9+.\-]+/' => '', // remove non-ASCII chars, only allow alphanumeric plus dash and dot
|
||||
'/[\-]{2,}/' => '-', // remove duplicate dashes
|
||||
'/^[\.\-_]+/' => '', // Remove all leading dots, dashes or underscores
|
||||
)
|
||||
[
|
||||
'/\s/' => '-', // remove whitespace
|
||||
'/_/' => '-', // underscores to dashes
|
||||
'/[^A-Za-z0-9+.\-]+/' => '', // remove non-ASCII chars, only allow alphanumeric plus dash and dot
|
||||
'/[\-]{2,}/' => '-', // remove duplicate dashes
|
||||
'/^[\.\-_]+/' => '', // Remove all leading dots, dashes or underscores
|
||||
]
|
||||
);
|
||||
|
||||
// Create a test files for each of the fixture references
|
||||
@ -175,73 +162,6 @@ class HTMLEditorFieldTest extends FunctionalTest
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetAnchors()
|
||||
{
|
||||
if (!class_exists('Page')) {
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
$linkedPage = new Page();
|
||||
$linkedPage->Title = 'Dummy';
|
||||
$linkedPage->write();
|
||||
|
||||
$html = <<<EOS
|
||||
<div name="foo"></div>
|
||||
<div name='bar'></div>
|
||||
<div id="baz"></div>
|
||||
[sitetree_link id="{$linkedPage->ID}"]
|
||||
<div id='bam'></div>
|
||||
<div id = "baz"></div>
|
||||
<div id = ""></div>
|
||||
<div id="some'id"></div>
|
||||
<div id=bar></div>
|
||||
EOS
|
||||
;
|
||||
$expected = array(
|
||||
'foo',
|
||||
'bar',
|
||||
'baz',
|
||||
'bam',
|
||||
"some'id",
|
||||
);
|
||||
$page = new Page();
|
||||
$page->Title = 'Test';
|
||||
$page->Content = $html;
|
||||
$page->write();
|
||||
$this->useDraftSite(true);
|
||||
|
||||
$request = new HTTPRequest(
|
||||
'GET',
|
||||
'/',
|
||||
array(
|
||||
'PageID' => $page->ID,
|
||||
)
|
||||
);
|
||||
|
||||
$toolBar = new HTMLEditorField_Toolbar(new Controller(), 'test');
|
||||
$toolBar->setRequest($request);
|
||||
|
||||
$results = json_decode($toolBar->getanchors(), true);
|
||||
$this->assertEquals($expected, $results);
|
||||
}
|
||||
|
||||
public function testHTMLEditorFieldFileLocal()
|
||||
{
|
||||
$file = new HTMLEditorField_Image('http://domain.com/folder/my_image.jpg?foo=bar');
|
||||
$this->assertEquals('http://domain.com/folder/my_image.jpg?foo=bar', $file->URL);
|
||||
$this->assertEquals('my_image.jpg', $file->Name);
|
||||
$this->assertEquals('jpg', $file->Extension);
|
||||
// TODO Can't easily test remote file dimensions
|
||||
}
|
||||
|
||||
public function testHTMLEditorFieldFileRemote()
|
||||
{
|
||||
$fileFixture = new File(array('Name' => 'my_local_image.jpg', 'Filename' => 'folder/my_local_image.jpg'));
|
||||
$file = new HTMLEditorField_Image('http://localdomain.com/folder/my_local_image.jpg', $fileFixture);
|
||||
$this->assertEquals('http://localdomain.com/folder/my_local_image.jpg', $file->URL);
|
||||
$this->assertEquals('my_local_image.jpg', $file->Name);
|
||||
$this->assertEquals('jpg', $file->Extension);
|
||||
}
|
||||
|
||||
public function testReadonlyField()
|
||||
{
|
||||
$editor = new HTMLEditorField('Content');
|
||||
@ -252,13 +172,9 @@ EOS
|
||||
$fileID
|
||||
)
|
||||
);
|
||||
/**
|
||||
* @var HTMLReadonlyField $readonly
|
||||
*/
|
||||
/** @var HTMLReadonlyField $readonly */
|
||||
$readonly = $editor->performReadonlyTransformation();
|
||||
/**
|
||||
* @var DBHTMLText $readonlyContent
|
||||
*/
|
||||
/** @var DBHTMLText $readonlyContent */
|
||||
$readonlyContent = $readonly->Field();
|
||||
|
||||
$this->assertEquals(
|
||||
@ -276,9 +192,7 @@ EOS
|
||||
// Test with include input tag
|
||||
$readonly = $editor->performReadonlyTransformation()
|
||||
->setIncludeHiddenField(true);
|
||||
/**
|
||||
* @var DBHTMLText $readonlyContent
|
||||
*/
|
||||
/** @var DBHTMLText $readonlyContent */
|
||||
$readonlyContent = $readonly->Field();
|
||||
$this->assertEquals(
|
||||
<<<EOS
|
||||
|
@ -1,22 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\Forms\Tests\HTMLEditor\HTMLEditorFieldTest;
|
||||
|
||||
use SilverStripe\Core\Extension;
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\Forms\Form;
|
||||
|
||||
class DummyMediaFormFieldExtension extends Extension implements TestOnly
|
||||
{
|
||||
public static $fields = null;
|
||||
public static $update_called = false;
|
||||
|
||||
/**
|
||||
* @param Form $form
|
||||
*/
|
||||
public function updateImageForm($form)
|
||||
{
|
||||
self::$update_called = true;
|
||||
self::$fields = $form->Fields();
|
||||
}
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\Forms\Tests\HTMLEditor;
|
||||
|
||||
use SilverStripe;
|
||||
use SilverStripe\Assets\File;
|
||||
use SilverStripe\Assets\Image;
|
||||
use SilverStripe\Assets\Tests\Storage\AssetStoreTest\TestAssetStore;
|
||||
use SilverStripe\Control\HTTPResponse_Exception;
|
||||
use SilverStripe\Dev\SapphireTest;
|
||||
use SilverStripe\Forms\HTMLEditor\HTMLEditorField_Toolbar;
|
||||
use SilverStripe\Forms\Tests\HTMLEditor\HTMLEditorFieldToolbarTest\Toolbar;
|
||||
|
||||
class HTMLEditorFieldToolbarTest extends SapphireTest
|
||||
{
|
||||
|
||||
protected static $fixture_file = 'HTMLEditorFieldToolbarTest.yml';
|
||||
|
||||
/**
|
||||
* @return Toolbar
|
||||
*/
|
||||
protected function getToolbar()
|
||||
{
|
||||
return new Toolbar(null, '/');
|
||||
}
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
HTMLEditorField_Toolbar::config()->set('fileurl_scheme_whitelist', array('http'));
|
||||
HTMLEditorField_Toolbar::config()->set('fileurl_domain_whitelist', array('example.com'));
|
||||
|
||||
// Filesystem mock
|
||||
TestAssetStore::activate(__CLASS__);
|
||||
|
||||
// Load up files
|
||||
/** @var File $file1 */
|
||||
$file1 = $this->objFromFixture(File::class, 'example_file');
|
||||
$file1->setFromString(str_repeat('x', 1000), $file1->Name);
|
||||
$file1->write();
|
||||
|
||||
/** @var Image $image1 */
|
||||
$image1 = $this->objFromFixture(Image::class, 'example_image');
|
||||
$image1->setFromLocalFile(
|
||||
__DIR__ . '/HTMLEditorFieldTest/images/example.jpg',
|
||||
'folder/subfolder/example.jpg'
|
||||
);
|
||||
$image1->write();
|
||||
}
|
||||
|
||||
public function testValidLocalReference()
|
||||
{
|
||||
/** @var File $exampleFile */
|
||||
$exampleFile = $this->objFromFixture(File::class, 'example_file');
|
||||
$expectedUrl = $exampleFile->AbsoluteLink();
|
||||
HTMLEditorField_Toolbar::config()->set(
|
||||
'fileurl_domain_whitelist',
|
||||
[
|
||||
'example.com',
|
||||
strtolower(parse_url($expectedUrl, PHP_URL_HOST))
|
||||
]
|
||||
);
|
||||
|
||||
list(, $url) = $this->getToolbar()->viewfile_getRemoteFileByURL($exampleFile->AbsoluteLink());
|
||||
$this->assertEquals($expectedUrl, $url);
|
||||
}
|
||||
|
||||
public function testValidScheme()
|
||||
{
|
||||
list(, $url) = $this->getToolbar()->viewfile_getRemoteFileByURL('http://example.com/test.pdf');
|
||||
$this->assertEquals($url, 'http://example.com/test.pdf');
|
||||
}
|
||||
|
||||
public function testInvalidScheme()
|
||||
{
|
||||
$this->setExpectedException(HTTPResponse_Exception::class);
|
||||
$this->getToolbar()->viewfile_getRemoteFileByURL('nosuchscheme://example.com/test.pdf');
|
||||
}
|
||||
|
||||
public function testValidDomain()
|
||||
{
|
||||
list(, $url) = $this->getToolbar()->viewfile_getRemoteFileByURL('http://example.com/test.pdf');
|
||||
$this->assertEquals($url, 'http://example.com/test.pdf');
|
||||
}
|
||||
|
||||
public function testInvalidDomain()
|
||||
{
|
||||
$this->setExpectedException(HTTPResponse_Exception::class);
|
||||
$this->getToolbar()->viewfile_getRemoteFileByURL('http://evil.com/test.pdf');
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
SilverStripe\Assets\Folder:
|
||||
folder1:
|
||||
Name: folder
|
||||
Title: folder
|
||||
folder2:
|
||||
Name: subfolder
|
||||
Title: subfolder
|
||||
Parent: =>SilverStripe\Assets\Folder.folder1
|
||||
|
||||
SilverStripe\Assets\File:
|
||||
example_file:
|
||||
Name: example.pdf
|
||||
Parent: =>SilverStripe\Assets\Folder.folder2
|
||||
|
||||
SilverStripe\Assets\Image:
|
||||
example_image:
|
||||
Name: HTMLEditorFieldTest_example.jpg
|
||||
Parent: =>SilverStripe\Assets\Folder.folder2
|
@ -1,18 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\Forms\Tests\HTMLEditor\HTMLEditorFieldToolbarTest;
|
||||
|
||||
use SilverStripe\Forms\HTMLEditor\HTMLEditorField_Toolbar;
|
||||
|
||||
class Toolbar extends HTMLEditorField_Toolbar
|
||||
{
|
||||
public function viewfile_getLocalFileByID($id)
|
||||
{
|
||||
return parent::viewfile_getLocalFileByID($id);
|
||||
}
|
||||
|
||||
public function viewfile_getRemoteFileByURL($fileUrl)
|
||||
{
|
||||
return parent::viewfile_getRemoteFileByURL($fileUrl);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user