Skip to content

Commit 3090d8a

Browse files
authored
Merge pull request #32 from codex-editor/syntax-sugar
Syntax sugar
2 parents 0881681 + 947f1dc commit 3090d8a

File tree

4 files changed

+207
-0
lines changed

4 files changed

+207
-0
lines changed

EditorJS/BlockHandler.php

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ private function validate($rules, $blockData)
119119
}
120120

121121
$rule = $rules[$key];
122+
123+
$rule = $this->expandToolSettings($rule);
124+
122125
$elementType = $rule['type'];
123126

124127
/**
@@ -128,6 +131,9 @@ private function validate($rules, $blockData)
128131
if (!in_array($value, $rule['canBeOnly'])) {
129132
throw new EditorJSException("Option '$key' with value `$value` has invalid value. Check canBeOnly param.");
130133
}
134+
135+
// Do not perform additional elements validation in any case
136+
continue;
131137
}
132138

133139
/**
@@ -191,6 +197,7 @@ private function sanitize($rules, $blockData)
191197
$rule = $rules[$key];
192198
}
193199

200+
$rule = $this->expandToolSettings($rule);
194201
$elementType = $rule['type'];
195202

196203
/**
@@ -259,4 +266,48 @@ private function getDefaultPurifier()
259266

260267
return $sanitizer;
261268
}
269+
270+
/**
271+
* Check whether the array is associative or sequential
272+
*
273+
* @param array $arr – array to check
274+
*
275+
* @return bool – true if the array is associative
276+
*/
277+
private function isAssoc(array $arr)
278+
{
279+
if ([] === $arr) {
280+
return false;
281+
}
282+
283+
return array_keys($arr) !== range(0, count($arr) - 1);
284+
}
285+
286+
/**
287+
* Expand shortified tool settings
288+
*
289+
* @param $rule – tool settings
290+
*
291+
* @throws EditorJSException
292+
*
293+
* @return array – expanded tool settings
294+
*/
295+
private function expandToolSettings($rule)
296+
{
297+
if (is_string($rule)) {
298+
// 'blockName': 'string' – tool with string type and default settings
299+
$expandedRule = ["type" => $rule];
300+
} elseif (is_array($rule)) {
301+
if ($this->isAssoc($rule)) {
302+
$expandedRule = $rule;
303+
} else {
304+
// 'blockName': [] – tool with canBeOnly and default settings
305+
$expandedRule = ["type" => "string", "canBeOnly" => $rule];
306+
}
307+
} else {
308+
throw new EditorJSException("Cannot determine element type of the rule `$rule`.");
309+
}
310+
311+
return $expandedRule;
312+
}
262313
}

README.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,59 @@ Example:
131131
}
132132
```
133133

134+
### Short settings syntax
135+
136+
Some syntax sugar has been added.
137+
138+
Tool settings can be a `string`. It defines tool's type with default settings.
139+
```json
140+
"header": {
141+
"text": "string",
142+
"level": "int"
143+
}
144+
```
145+
146+
It evaluates to:
147+
```json
148+
"header": {
149+
"text": {
150+
"type": "string",
151+
"allowedTags": "",
152+
"required": true
153+
},
154+
"level": {
155+
"type": "int",
156+
"allowedTags": "",
157+
"required": true
158+
}
159+
}
160+
```
161+
162+
Tool settings can be an `array`. It defines set of allowed valus without sanitizing.
163+
```json
164+
"quote": {
165+
"alignment": ["left", "center"],
166+
"caption": "string"
167+
}
168+
```
169+
170+
It evaluates to:
171+
```json
172+
"quote": {
173+
"alignment": {
174+
"type": "string",
175+
"canBeOnly": ["left", "center"]
176+
},
177+
"caption": {
178+
"type": "string",
179+
"allowedTags": "",
180+
"required": true
181+
}
182+
}
183+
```
184+
185+
Another configuration example: [/tests/samples/syntax-sugar.json](/tests/samples/syntax-sugar.json)
186+
134187
### Nested tools
135188

136189
Tools can contain nested values. It is possible with the `array` type.

tests/SyntaxSugarTest.php

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?php
2+
3+
use EditorJS\EditorJS;
4+
use EditorJS\EditorJSException;
5+
6+
/**
7+
* Class SyntaxSugarTest
8+
*
9+
* Check simplified configuration structure
10+
*/
11+
class SyntaxSugarTest extends TestCase
12+
{
13+
const CONFIGURATION_FILE = TESTS_DIR . "/samples/syntax-sugar.json";
14+
15+
/**
16+
* Sample configuration
17+
*/
18+
public $configuration;
19+
20+
/**
21+
* Setup configuration
22+
*/
23+
public function setUp()
24+
{
25+
$this->configuration = file_get_contents(SyntaxSugarTest::CONFIGURATION_FILE);
26+
}
27+
28+
public function testShortTypeField()
29+
{
30+
$data = '{"blocks":[{"type":"header","data":{"text":"CodeX <b>Editor</b>", "level": 2}}]}';
31+
32+
$editor = new EditorJS($data, $this->configuration);
33+
$result = $editor->getBlocks();
34+
35+
$this->assertEquals('CodeX Editor', $result[0]['data']['text']);
36+
$this->assertEquals(2, $result[0]['data']['level']);
37+
}
38+
39+
public function testShortTypeFieldCanBeOnly()
40+
{
41+
$callable = function () {
42+
new EditorJS('{"blocks":[{"type":"header","data":{"text":"CodeX <b>Editor</b>", "level": 5}}]}',
43+
$this->configuration);
44+
};
45+
46+
$this->assertException($callable, EditorJSException::class, null, 'Option \'level\' with value `5` has invalid value. Check canBeOnly param.');
47+
}
48+
49+
public function testShortIntValid()
50+
{
51+
new EditorJS('{"blocks":[{"type":"subtitle","data":{"text": "string", "level": 1337}}]}', $this->configuration);
52+
}
53+
54+
public function testShortIntNotValid()
55+
{
56+
$callable = function () {
57+
new EditorJS('{"blocks":[{"type":"subtitle","data":{"text": "test", "level": "string"}}]}', $this->configuration);
58+
};
59+
60+
$this->assertException($callable, EditorJSException::class, null, 'Option \'level\' with value `string` must be integer');
61+
}
62+
63+
public function testInvalidType()
64+
{
65+
$callable = function () {
66+
$invalid_configuration = '{"tools": {"header": {"title": "invalid_type"}}}';
67+
new EditorJS('{"blocks":[{"type":"header","data":{"title": "test"}}]}', $invalid_configuration);
68+
};
69+
70+
$this->assertException($callable, EditorJSException::class, null, 'Unhandled type `invalid_type`');
71+
}
72+
73+
public function testMixedStructure()
74+
{
75+
$data = '{"time":1539180803359,"blocks":[{"type":"header","data":{"text":"<b>t</b><i>e</i><u>st</u>","level":2}}, {"type":"quote","data":{"text":"<b>t</b><i>e</i><u>st</u>","caption":"", "alignment":"left"}}]}';
76+
$editor = new EditorJS($data, $this->configuration);
77+
$result = $editor->getBlocks();
78+
79+
$this->assertEquals(2, count($result));
80+
$this->assertEquals('test', $result[0]['data']['text']);
81+
$this->assertEquals('<b>t</b><i>e</i>st', $result[1]['data']['text']);
82+
}
83+
}

tests/samples/syntax-sugar.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"tools": {
3+
"header": {
4+
"text": "string",
5+
"level": [2, 3, 4]
6+
},
7+
"subtitle": {
8+
"text": "string",
9+
"level": "int"
10+
},
11+
"quote": {
12+
"text": {
13+
"type": "string",
14+
"allowedTags": "i,b"
15+
},
16+
"caption": "string",
17+
"alignment": ["left", "center"]
18+
}
19+
}
20+
}

0 commit comments

Comments
 (0)