|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace SilverStripe\Forms\Tests\HTMLEditor; |
|
4
|
|
|
|
|
5
|
|
|
use SilverStripe\Assets\File; |
|
6
|
|
|
use SilverStripe\Assets\FileNameFilter; |
|
7
|
|
|
use SilverStripe\Assets\Filesystem; |
|
8
|
|
|
use SilverStripe\Assets\Folder; |
|
9
|
|
|
use SilverStripe\Assets\Image; |
|
10
|
|
|
use SilverStripe\Assets\Tests\Storage\AssetStoreTest\TestAssetStore; |
|
11
|
|
|
use SilverStripe\Core\Config\Config; |
|
12
|
|
|
use SilverStripe\Dev\CSSContentParser; |
|
13
|
|
|
use SilverStripe\Dev\FunctionalTest; |
|
14
|
|
|
use SilverStripe\Forms\HTMLEditor\HTMLEditorField; |
|
15
|
|
|
use SilverStripe\Forms\HTMLReadonlyField; |
|
16
|
|
|
use SilverStripe\Forms\Tests\HTMLEditor\HTMLEditorFieldTest\TestObject; |
|
17
|
|
|
use SilverStripe\ORM\FieldType\DBHTMLText; |
|
18
|
|
|
use SilverStripe\Forms\HTMLEditor\TinyMCEConfig; |
|
19
|
|
|
|
|
20
|
|
|
class HTMLEditorFieldTest extends FunctionalTest |
|
21
|
|
|
{ |
|
22
|
|
|
protected static $fixture_file = 'HTMLEditorFieldTest.yml'; |
|
23
|
|
|
|
|
24
|
|
|
protected static $use_draft_site = true; |
|
25
|
|
|
|
|
26
|
|
|
protected static $extra_dataobjects = [ |
|
27
|
|
|
TestObject::class, |
|
28
|
|
|
]; |
|
29
|
|
|
|
|
30
|
|
|
protected function setUp() |
|
31
|
|
|
{ |
|
32
|
|
|
parent::setUp(); |
|
33
|
|
|
|
|
34
|
|
|
// Set backend root to /HTMLEditorFieldTest |
|
35
|
|
|
TestAssetStore::activate('HTMLEditorFieldTest'); |
|
36
|
|
|
|
|
37
|
|
|
// Set the File Name Filter replacements so files have the expected names |
|
38
|
|
|
Config::modify()->set( |
|
39
|
|
|
FileNameFilter::class, |
|
40
|
|
|
'default_replacements', |
|
41
|
|
|
[ |
|
42
|
|
|
'/\s/' => '-', // remove whitespace |
|
43
|
|
|
'/_/' => '-', // underscores to dashes |
|
44
|
|
|
'/[^A-Za-z0-9+.\-]+/' => '', // remove non-ASCII chars, only allow alphanumeric plus dash and dot |
|
45
|
|
|
'/[\-]{2,}/' => '-', // remove duplicate dashes |
|
46
|
|
|
'/^[\.\-_]+/' => '', // Remove all leading dots, dashes or underscores |
|
47
|
|
|
] |
|
48
|
|
|
); |
|
49
|
|
|
|
|
50
|
|
|
// Create a test files for each of the fixture references |
|
51
|
|
|
$files = File::get()->exclude('ClassName', Folder::class); |
|
52
|
|
|
foreach ($files as $file) { |
|
53
|
|
|
$fromPath = __DIR__ . '/HTMLEditorFieldTest/images/' . $file->Name; |
|
54
|
|
|
$destPath = TestAssetStore::getLocalPath($file); // Only correct for test asset store |
|
55
|
|
|
Filesystem::makeFolder(dirname($destPath)); |
|
56
|
|
|
copy($fromPath, $destPath); |
|
57
|
|
|
} |
|
58
|
|
|
} |
|
59
|
|
|
|
|
60
|
|
|
protected function tearDown() |
|
61
|
|
|
{ |
|
62
|
|
|
TestAssetStore::reset(); |
|
63
|
|
|
parent::tearDown(); |
|
64
|
|
|
} |
|
65
|
|
|
|
|
66
|
|
|
public function testCasting() |
|
67
|
|
|
{ |
|
68
|
|
|
// Shim TinyMCE so silverstripe/admin doesn't have to be installed |
|
69
|
|
|
TinyMCEConfig::config()->set('base_dir', 'test'); |
|
70
|
|
|
HtmlEditorField::config()->set('use_gzip', false); |
|
71
|
|
|
|
|
72
|
|
|
// Test special characters |
|
73
|
|
|
$inputText = "These are some unicodes: ä, ö, & ü"; |
|
74
|
|
|
$field = new HTMLEditorField("Test", "Test"); |
|
75
|
|
|
$field->setValue($inputText); |
|
76
|
|
|
$this->assertContains('These are some unicodes: ä, ö, & ü', $field->Field()); |
|
77
|
|
|
// Test shortcodes |
|
78
|
|
|
$inputText = "Shortcode: [file_link id=4]"; |
|
79
|
|
|
$field = new HTMLEditorField("Test", "Test"); |
|
80
|
|
|
$field->setValue($inputText); |
|
81
|
|
|
$this->assertContains('Shortcode: [file_link id=4]', $field->Field()); |
|
82
|
|
|
} |
|
83
|
|
|
|
|
84
|
|
|
public function testBasicSaving() |
|
85
|
|
|
{ |
|
86
|
|
|
$obj = new TestObject(); |
|
87
|
|
|
$editor = new HTMLEditorField('Content'); |
|
88
|
|
|
|
|
89
|
|
|
$editor->setValue('<p class="foo">Simple Content</p>'); |
|
90
|
|
|
$editor->saveInto($obj); |
|
91
|
|
|
$this->assertEquals('<p class="foo">Simple Content</p>', $obj->Content, 'Attributes are preserved.'); |
|
92
|
|
|
|
|
93
|
|
|
$editor->setValue('<p>Unclosed Tag'); |
|
94
|
|
|
$editor->saveInto($obj); |
|
95
|
|
|
$this->assertEquals('<p>Unclosed Tag</p>', $obj->Content, 'Unclosed tags are closed.'); |
|
96
|
|
|
} |
|
97
|
|
|
|
|
98
|
|
|
public function testNullSaving() |
|
99
|
|
|
{ |
|
100
|
|
|
$obj = new TestObject(); |
|
101
|
|
|
$editor = new HTMLEditorField('Content'); |
|
102
|
|
|
|
|
103
|
|
|
$editor->setValue(null); |
|
104
|
|
|
$editor->saveInto($obj); |
|
105
|
|
|
$this->assertEquals('', $obj->Content, "Doesn't choke on empty/null values."); |
|
106
|
|
|
} |
|
107
|
|
|
|
|
108
|
|
|
public function testResizedImageInsertion() |
|
109
|
|
|
{ |
|
110
|
|
|
$obj = new TestObject(); |
|
111
|
|
|
$editor = new HTMLEditorField('Content'); |
|
112
|
|
|
|
|
113
|
|
|
$fileID = $this->idFromFixture(Image::class, 'example_image'); |
|
114
|
|
|
$editor->setValue( |
|
115
|
|
|
sprintf( |
|
116
|
|
|
'[image src="assets/example.jpg" width="10" height="20" id="%d"]', |
|
117
|
|
|
$fileID |
|
118
|
|
|
) |
|
119
|
|
|
); |
|
120
|
|
|
$editor->saveInto($obj); |
|
121
|
|
|
|
|
122
|
|
|
$parser = new CSSContentParser($obj->dbObject('Content')->forTemplate()); |
|
123
|
|
|
$xml = $parser->getByXpath('//img'); |
|
124
|
|
|
$this->assertEquals( |
|
125
|
|
|
'example', |
|
126
|
|
|
(string)$xml[0]['alt'], |
|
127
|
|
|
'Alt tags are added by default based on filename' |
|
128
|
|
|
); |
|
129
|
|
|
$this->assertEquals('', (string)$xml[0]['title'], 'Title tags are added by default.'); |
|
130
|
|
|
$this->assertEquals(10, (int)$xml[0]['width'], 'Width tag of resized image is set.'); |
|
131
|
|
|
$this->assertEquals(20, (int)$xml[0]['height'], 'Height tag of resized image is set.'); |
|
132
|
|
|
|
|
133
|
|
|
$neededFilename |
|
134
|
|
|
= '/assets/HTMLEditorFieldTest/f5c7c2f814/example__ResizedImageWyIxMCIsIjIwIl0.jpg'; |
|
135
|
|
|
|
|
136
|
|
|
$this->assertEquals($neededFilename, (string)$xml[0]['src'], 'Correct URL of resized image is set.'); |
|
137
|
|
|
$this->assertTrue(file_exists(BASE_PATH.DIRECTORY_SEPARATOR.$neededFilename), 'File for resized image exists'); |
|
138
|
|
|
$this->assertEquals(false, $obj->HasBrokenFile, 'Referenced image file exists.'); |
|
139
|
|
|
} |
|
140
|
|
|
|
|
141
|
|
View Code Duplication |
public function testMultiLineSaving() |
|
|
|
|
|
|
142
|
|
|
{ |
|
143
|
|
|
$obj = $this->objFromFixture(TestObject::class, 'home'); |
|
144
|
|
|
$editor = new HTMLEditorField('Content'); |
|
145
|
|
|
$editor->setValue('<p>First Paragraph</p><p>Second Paragraph</p>'); |
|
146
|
|
|
$editor->saveInto($obj); |
|
|
|
|
|
|
147
|
|
|
$this->assertEquals('<p>First Paragraph</p><p>Second Paragraph</p>', $obj->Content); |
|
148
|
|
|
} |
|
149
|
|
|
|
|
150
|
|
View Code Duplication |
public function testSavingLinksWithoutHref() |
|
|
|
|
|
|
151
|
|
|
{ |
|
152
|
|
|
$obj = $this->objFromFixture(TestObject::class, 'home'); |
|
153
|
|
|
$editor = new HTMLEditorField('Content'); |
|
154
|
|
|
|
|
155
|
|
|
$editor->setValue('<p><a name="example-anchor"></a></p>'); |
|
156
|
|
|
$editor->saveInto($obj); |
|
|
|
|
|
|
157
|
|
|
|
|
158
|
|
|
$this->assertEquals( |
|
159
|
|
|
'<p><a name="example-anchor"></a></p>', |
|
160
|
|
|
$obj->Content, |
|
161
|
|
|
'Saving a link without a href attribute works' |
|
162
|
|
|
); |
|
163
|
|
|
} |
|
164
|
|
|
|
|
165
|
|
|
public function testReadonlyField() |
|
166
|
|
|
{ |
|
167
|
|
|
$editor = new HTMLEditorField('Content'); |
|
168
|
|
|
$fileID = $this->idFromFixture(Image::class, 'example_image'); |
|
169
|
|
|
$editor->setValue( |
|
170
|
|
|
sprintf( |
|
171
|
|
|
'[image src="assets/example.jpg" width="10" height="20" id="%d"]', |
|
172
|
|
|
$fileID |
|
173
|
|
|
) |
|
174
|
|
|
); |
|
175
|
|
|
/** @var HTMLReadonlyField $readonly */ |
|
176
|
|
|
$readonly = $editor->performReadonlyTransformation(); |
|
177
|
|
|
/** @var DBHTMLText $readonlyContent */ |
|
178
|
|
|
$readonlyContent = $readonly->Field(); |
|
179
|
|
|
|
|
180
|
|
|
$this->assertEquals( |
|
181
|
|
|
<<<EOS |
|
182
|
|
|
<span class="readonly typography" id="Content"> |
|
183
|
|
|
<img src="/assets/HTMLEditorFieldTest/f5c7c2f814/example__ResizedImageWyIxMCIsIjIwIl0.jpg" alt="example" width="10" height="20"> |
|
184
|
|
|
</span> |
|
185
|
|
|
|
|
186
|
|
|
|
|
187
|
|
|
EOS |
|
188
|
|
|
, |
|
189
|
|
|
$readonlyContent->getValue() |
|
190
|
|
|
); |
|
191
|
|
|
|
|
192
|
|
|
// Test with include input tag |
|
193
|
|
|
$readonly = $editor->performReadonlyTransformation() |
|
194
|
|
|
->setIncludeHiddenField(true); |
|
195
|
|
|
/** @var DBHTMLText $readonlyContent */ |
|
196
|
|
|
$readonlyContent = $readonly->Field(); |
|
197
|
|
|
$this->assertEquals( |
|
198
|
|
|
<<<EOS |
|
199
|
|
|
<span class="readonly typography" id="Content"> |
|
200
|
|
|
<img src="/assets/HTMLEditorFieldTest/f5c7c2f814/example__ResizedImageWyIxMCIsIjIwIl0.jpg" alt="example" width="10" height="20"> |
|
201
|
|
|
</span> |
|
202
|
|
|
|
|
203
|
|
|
<input type="hidden" name="Content" value="[image src="/assets/HTMLEditorFieldTest/f5c7c2f814/example.jpg" width="10" height="20" id="{$fileID}"]" /> |
|
204
|
|
|
|
|
205
|
|
|
|
|
206
|
|
|
EOS |
|
207
|
|
|
, |
|
208
|
|
|
$readonlyContent->getValue() |
|
209
|
|
|
); |
|
210
|
|
|
} |
|
211
|
|
|
} |
|
212
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.