diff --git a/CHANGELOG.md b/CHANGELOG.md
index ab811de..a1a6f5d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,13 @@
Full changelog for PHP Quill Renderer
+## v3.17.1 - 2019-03-xx
+
+* Fixed [#117](https://github.com/deanblackborough/php-quill-renderer/issues/117), compound
+deltas not aware of the fact that they can also be links.
+* Fixed [#109](https://github.com/deanblackborough/php-quill-renderer/issues/109) again as it
+appears I did not fix it correctly before.
+
## v3.17.0 - 2019-03-04
* Handle custom color attribute in a better way, assign to style attribute if sensible,
diff --git a/README.md b/README.md
index 320585c..8557415 100644
--- a/README.md
+++ b/README.md
@@ -159,10 +159,11 @@ for use under the MIT License (MIT).
* [raphaelsaunier](https://github.com/raphaelsaunier) [Issue #87] - Newlines proceeding inserts ignored, bug location.
* [Basil](https://github.com/nadar) [Issue #101] - Newline only inserts being ignored by parser.
* [Lee Hesselden](https://github.com/on2) [PR #104] - Color delta to allowing spans with a style:color="#xxx" definition. (Feature will be extended by [Issue #106])
-* [Alex](https://github.com/AlexFence) [PR112] - Custom attributes assigned to style attribute if sensible.
-* [davidraijmakers](https://github.com/davidraijmakers) [#Issue #108] - Children not supported with headers.
-* [philippkuehn](https://github.com/philippkuehn) [#Issue #109] - Multiple list output incorrect and paragraphs not being closed.
+* [Alex](https://github.com/AlexFence) [PR #112] - Custom attributes assigned to style attribute if sensible.
+* [davidraijmakers](https://github.com/davidraijmakers) [Issue #108] - Children not supported with headers.
+* [philippkuehn](https://github.com/philippkuehn) [Issue #109] - Multiple list output incorrect and paragraphs not being closed.
+* [mechanicalgux](https://github.com/mechanicalgux) [Issue #117] - Compound deltas don't know that they can be links.
## Coding standard credit
-* [Lode Claassen](https://github.com/lode) [PR#113] - Incorrect case in keyword.
+* [Lode Claassen](https://github.com/lode) [PR #113] - Incorrect case in keyword.
diff --git a/Tests/Api/BugTest.php b/Tests/Api/BugTest.php
index f3cbb9f..2823a3b 100644
--- a/Tests/Api/BugTest.php
+++ b/Tests/Api/BugTest.php
@@ -156,8 +156,8 @@ final class BugTest extends \PHPUnit\Framework\TestCase
"attributes": {
"bold": true,
"link": "https://scrumpy.io"
- },
- "insert": "link"
+ },
+ "insert": "link"
},
{
"attributes": {
@@ -179,6 +179,77 @@ final class BugTest extends \PHPUnit\Framework\TestCase
}
]
}';
+ private $delta_bug_117_links_deltas_with_attributes = '
+ {
+ "ops":[
+ {
+ "insert":"The "
+ },
+ {
+ "attributes":{
+ "italic":true,
+ "link":"https://www.google.com"
+ },
+ "insert":"quick"
+ },
+ {
+ "insert":" brown fox "
+ },
+ {
+ "attributes":{
+ "bold":true,
+ "link":"https://www.google.com"
+ },
+ "insert":"jumps"
+ },
+ {
+ "insert":" over t"
+ },
+ {
+ "attributes":{
+ "link":"https://www.google.com"
+ },
+ "insert":"he "
+ },
+ {
+ "attributes":{
+ "italic":true,
+ "bold":true,
+ "link":"https://www.google.com"
+ },
+ "insert":"lazy"
+ },
+ {
+ "attributes":{
+ "link":"https://www.google.com"
+ },
+ "insert":" do"
+ },
+ {
+ "insert":"g... "
+ },
+ {
+ "attributes":{
+ "italic":true,
+ "link":"https://www.amazon.com"
+ },
+ "insert":"Space"
+ },
+ {
+ "insert":" "
+ },
+ {
+ "attributes":{
+ "bold":true,
+ "link":"https://www.yahoo.com"
+ },
+ "insert":"removed"
+ },
+ {
+ "insert":".\n"
+ }
+ ]
+ }';
private $expected_bug_external_3 = '
Lorem ipsum
@@ -190,7 +261,7 @@ final class BugTest extends \PHPUnit\Framework\TestCase
';
private $expected_bug_108_link_within_header = 'This is a header, it has a link within it.
';
private $expected_bug_108_link_end_of_header = 'This is a header, with a link at the end
';
- private $expected_bug_109_list_outout_incorrect = 'Headline 1
+ private $expected_bug_109_list_output_incorrect = 'Headline 1
Some text. Bold Text. Italic Text. Bold and italic Text. Here is a Link.
@@ -202,11 +273,14 @@ final class BugTest extends \PHPUnit\Framework\TestCase
- unordered list item
-- unordered list item with linklink
+- unordered list item with link
- unordered list item
Some Text.
+
';
+ private $expected_bug_117_links_deltas_with_attributes = 'The quick brown fox jumps over the lazy dog... Spaceremoved.
+
';
/**
@@ -303,9 +377,34 @@ public function testIncorrectListOutput()
}
$this->assertEquals(
- $this->expected_bug_109_list_outout_incorrect,
+ $this->expected_bug_109_list_output_incorrect,
trim($result),
__METHOD__ . ' list output incorrect'
);
}
+
+ /**
+ * Links with attributes not being created correctly
+ * Bug report https://github.com/deanblackborough/php-quill-renderer/issues/117
+ *
+ * @return void
+ * @throws \Exception
+ */
+ public function testLinkDeltasWithAdditionalAttributes()
+ {
+ $result = null;
+
+ try {
+ $quill = new QuillRender($this->delta_bug_117_links_deltas_with_attributes);
+ $result = $quill->render();
+ } catch (\Exception $e) {
+ $this->fail(__METHOD__ . 'failure, ' . $e->getMessage());
+ }
+
+ $this->assertEquals(
+ $this->expected_bug_117_links_deltas_with_attributes,
+ trim($result),
+ __METHOD__ . ' link output incorrect'
+ );
+ }
}
diff --git a/composer.lock b/composer.lock
index feb412b..e8f1335 100644
--- a/composer.lock
+++ b/composer.lock
@@ -1,10 +1,9 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
- "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "hash": "92ae46b1f7e9eaf7fc0c09542abe9a03",
"content-hash": "c885cd3cce2d83e57036969840f27f13",
"packages": [],
"packages-dev": [
@@ -60,7 +59,7 @@
"constructor",
"instantiate"
],
- "time": "2017-07-22 11:58:36"
+ "time": "2017-07-22T11:58:36+00:00"
},
{
"name": "guzzlehttp/guzzle",
@@ -125,7 +124,7 @@
"rest",
"web service"
],
- "time": "2018-04-22 15:46:56"
+ "time": "2018-04-22T15:46:56+00:00"
},
{
"name": "guzzlehttp/promises",
@@ -176,7 +175,7 @@
"keywords": [
"promise"
],
- "time": "2016-12-20 10:07:11"
+ "time": "2016-12-20T10:07:11+00:00"
},
{
"name": "guzzlehttp/psr7",
@@ -243,7 +242,7 @@
"uri",
"url"
],
- "time": "2018-12-04 20:46:45"
+ "time": "2018-12-04T20:46:45+00:00"
},
{
"name": "myclabs/deep-copy",
@@ -291,7 +290,7 @@
"object",
"object graph"
],
- "time": "2018-06-11 23:09:50"
+ "time": "2018-06-11T23:09:50+00:00"
},
{
"name": "phar-io/manifest",
@@ -346,7 +345,7 @@
}
],
"description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
- "time": "2018-07-08 19:23:20"
+ "time": "2018-07-08T19:23:20+00:00"
},
{
"name": "phar-io/version",
@@ -393,7 +392,7 @@
}
],
"description": "Library for handling version information and constraints",
- "time": "2018-07-08 19:19:57"
+ "time": "2018-07-08T19:19:57+00:00"
},
{
"name": "php-coveralls/php-coveralls",
@@ -476,7 +475,7 @@
"github",
"test"
],
- "time": "2018-05-22 23:11:08"
+ "time": "2018-05-22T23:11:08+00:00"
},
{
"name": "phpdocumentor/reflection-common",
@@ -530,7 +529,7 @@
"reflection",
"static analysis"
],
- "time": "2017-09-11 18:02:19"
+ "time": "2017-09-11T18:02:19+00:00"
},
{
"name": "phpdocumentor/reflection-docblock",
@@ -581,7 +580,7 @@
}
],
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
- "time": "2017-11-30 07:14:17"
+ "time": "2017-11-30T07:14:17+00:00"
},
{
"name": "phpdocumentor/type-resolver",
@@ -628,7 +627,7 @@
"email": "me@mikevanriel.com"
}
],
- "time": "2017-07-14 14:27:02"
+ "time": "2017-07-14T14:27:02+00:00"
},
{
"name": "phpspec/prophecy",
@@ -691,7 +690,7 @@
"spy",
"stub"
],
- "time": "2018-08-05 17:53:17"
+ "time": "2018-08-05T17:53:17+00:00"
},
{
"name": "phpunit/php-code-coverage",
@@ -754,7 +753,7 @@
"testing",
"xunit"
],
- "time": "2018-10-31 16:06:48"
+ "time": "2018-10-31T16:06:48+00:00"
},
{
"name": "phpunit/php-file-iterator",
@@ -804,7 +803,7 @@
"filesystem",
"iterator"
],
- "time": "2018-09-13 20:33:42"
+ "time": "2018-09-13T20:33:42+00:00"
},
{
"name": "phpunit/php-text-template",
@@ -845,7 +844,7 @@
"keywords": [
"template"
],
- "time": "2015-06-21 13:50:34"
+ "time": "2015-06-21T13:50:34+00:00"
},
{
"name": "phpunit/php-timer",
@@ -894,7 +893,7 @@
"keywords": [
"timer"
],
- "time": "2019-02-20 10:12:59"
+ "time": "2019-02-20T10:12:59+00:00"
},
{
"name": "phpunit/php-token-stream",
@@ -943,7 +942,7 @@
"keywords": [
"tokenizer"
],
- "time": "2018-10-30 05:52:18"
+ "time": "2018-10-30T05:52:18+00:00"
},
{
"name": "phpunit/phpunit",
@@ -1027,7 +1026,7 @@
"testing",
"xunit"
],
- "time": "2019-02-18 09:24:50"
+ "time": "2019-02-18T09:24:50+00:00"
},
{
"name": "psr/http-message",
@@ -1077,7 +1076,7 @@
"request",
"response"
],
- "time": "2016-08-06 14:39:51"
+ "time": "2016-08-06T14:39:51+00:00"
},
{
"name": "psr/log",
@@ -1124,7 +1123,7 @@
"psr",
"psr-3"
],
- "time": "2018-11-20 15:27:04"
+ "time": "2018-11-20T15:27:04+00:00"
},
{
"name": "ralouphie/getallheaders",
@@ -1164,7 +1163,7 @@
}
],
"description": "A polyfill for getallheaders.",
- "time": "2016-02-11 07:05:27"
+ "time": "2016-02-11T07:05:27+00:00"
},
{
"name": "sebastian/code-unit-reverse-lookup",
@@ -1209,7 +1208,7 @@
],
"description": "Looks up which function or method a line of code belongs to",
"homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
- "time": "2017-03-04 06:30:41"
+ "time": "2017-03-04T06:30:41+00:00"
},
{
"name": "sebastian/comparator",
@@ -1273,7 +1272,7 @@
"compare",
"equality"
],
- "time": "2018-07-12 15:12:46"
+ "time": "2018-07-12T15:12:46+00:00"
},
{
"name": "sebastian/diff",
@@ -1329,7 +1328,7 @@
"unidiff",
"unified diff"
],
- "time": "2019-02-04 06:01:07"
+ "time": "2019-02-04T06:01:07+00:00"
},
{
"name": "sebastian/environment",
@@ -1382,7 +1381,7 @@
"environment",
"hhvm"
],
- "time": "2019-02-01 05:27:49"
+ "time": "2019-02-01T05:27:49+00:00"
},
{
"name": "sebastian/exporter",
@@ -1449,7 +1448,7 @@
"export",
"exporter"
],
- "time": "2017-04-03 13:19:02"
+ "time": "2017-04-03T13:19:02+00:00"
},
{
"name": "sebastian/global-state",
@@ -1500,7 +1499,7 @@
"keywords": [
"global state"
],
- "time": "2017-04-27 15:39:26"
+ "time": "2017-04-27T15:39:26+00:00"
},
{
"name": "sebastian/object-enumerator",
@@ -1547,7 +1546,7 @@
],
"description": "Traverses array structures and object graphs to enumerate all referenced objects",
"homepage": "https://github.com/sebastianbergmann/object-enumerator/",
- "time": "2017-08-03 12:35:26"
+ "time": "2017-08-03T12:35:26+00:00"
},
{
"name": "sebastian/object-reflector",
@@ -1592,7 +1591,7 @@
],
"description": "Allows reflection of object attributes, including inherited and non-public ones",
"homepage": "https://github.com/sebastianbergmann/object-reflector/",
- "time": "2017-03-29 09:07:27"
+ "time": "2017-03-29T09:07:27+00:00"
},
{
"name": "sebastian/recursion-context",
@@ -1645,7 +1644,7 @@
],
"description": "Provides functionality to recursively process PHP variables",
"homepage": "http://www.github.com/sebastianbergmann/recursion-context",
- "time": "2017-03-03 06:23:57"
+ "time": "2017-03-03T06:23:57+00:00"
},
{
"name": "sebastian/resource-operations",
@@ -1687,7 +1686,7 @@
],
"description": "Provides a list of PHP built-in functions that operate on resources",
"homepage": "https://www.github.com/sebastianbergmann/resource-operations",
- "time": "2018-10-04 04:07:39"
+ "time": "2018-10-04T04:07:39+00:00"
},
{
"name": "sebastian/version",
@@ -1730,20 +1729,20 @@
],
"description": "Library that helps with managing the version number of Git-hosted PHP projects",
"homepage": "https://github.com/sebastianbergmann/version",
- "time": "2016-10-03 07:35:21"
+ "time": "2016-10-03T07:35:21+00:00"
},
{
"name": "symfony/config",
- "version": "v4.2.3",
+ "version": "v4.2.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/config.git",
- "reference": "25a2e7abe0d97e70282537292e3df45cf6da7b98"
+ "reference": "7f70d79c7a24a94f8e98abb988049403a53d7b31"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/config/zipball/25a2e7abe0d97e70282537292e3df45cf6da7b98",
- "reference": "25a2e7abe0d97e70282537292e3df45cf6da7b98",
+ "url": "https://api.github.com/repos/symfony/config/zipball/7f70d79c7a24a94f8e98abb988049403a53d7b31",
+ "reference": "7f70d79c7a24a94f8e98abb988049403a53d7b31",
"shasum": ""
},
"require": {
@@ -1793,20 +1792,20 @@
],
"description": "Symfony Config Component",
"homepage": "https://symfony.com",
- "time": "2019-01-30 11:44:30"
+ "time": "2019-02-23T15:17:42+00:00"
},
{
"name": "symfony/console",
- "version": "v4.2.3",
+ "version": "v4.2.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "1f0ad51dfde4da8a6070f06adc58b4e37cbb37a4"
+ "reference": "9dc2299a016497f9ee620be94524e6c0af0280a9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/1f0ad51dfde4da8a6070f06adc58b4e37cbb37a4",
- "reference": "1f0ad51dfde4da8a6070f06adc58b4e37cbb37a4",
+ "url": "https://api.github.com/repos/symfony/console/zipball/9dc2299a016497f9ee620be94524e6c0af0280a9",
+ "reference": "9dc2299a016497f9ee620be94524e6c0af0280a9",
"shasum": ""
},
"require": {
@@ -1865,7 +1864,7 @@
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
- "time": "2019-01-25 14:35:16"
+ "time": "2019-02-23T15:17:42+00:00"
},
{
"name": "symfony/contracts",
@@ -1933,20 +1932,20 @@
"interoperability",
"standards"
],
- "time": "2018-12-05 08:06:11"
+ "time": "2018-12-05T08:06:11+00:00"
},
{
"name": "symfony/filesystem",
- "version": "v4.2.3",
+ "version": "v4.2.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
- "reference": "7c16ebc2629827d4ec915a52ac809768d060a4ee"
+ "reference": "e16b9e471703b2c60b95f14d31c1239f68f11601"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/filesystem/zipball/7c16ebc2629827d4ec915a52ac809768d060a4ee",
- "reference": "7c16ebc2629827d4ec915a52ac809768d060a4ee",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/e16b9e471703b2c60b95f14d31c1239f68f11601",
+ "reference": "e16b9e471703b2c60b95f14d31c1239f68f11601",
"shasum": ""
},
"require": {
@@ -1983,7 +1982,7 @@
],
"description": "Symfony Filesystem Component",
"homepage": "https://symfony.com",
- "time": "2019-01-16 20:35:37"
+ "time": "2019-02-07T11:40:08+00:00"
},
{
"name": "symfony/polyfill-ctype",
@@ -2041,7 +2040,7 @@
"polyfill",
"portable"
],
- "time": "2018-08-06 14:22:27"
+ "time": "2018-08-06T14:22:27+00:00"
},
{
"name": "symfony/polyfill-mbstring",
@@ -2100,11 +2099,11 @@
"portable",
"shim"
],
- "time": "2018-09-21 13:07:52"
+ "time": "2018-09-21T13:07:52+00:00"
},
{
"name": "symfony/stopwatch",
- "version": "v4.2.3",
+ "version": "v4.2.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/stopwatch.git",
@@ -2150,20 +2149,20 @@
],
"description": "Symfony Stopwatch Component",
"homepage": "https://symfony.com",
- "time": "2019-01-16 20:31:39"
+ "time": "2019-01-16T20:31:39+00:00"
},
{
"name": "symfony/yaml",
- "version": "v4.2.3",
+ "version": "v4.2.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
- "reference": "d461670ee145092b7e2a56c1da7118f19cadadb0"
+ "reference": "761fa560a937fd7686e5274ff89dcfa87a5047df"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/yaml/zipball/d461670ee145092b7e2a56c1da7118f19cadadb0",
- "reference": "d461670ee145092b7e2a56c1da7118f19cadadb0",
+ "url": "https://api.github.com/repos/symfony/yaml/zipball/761fa560a937fd7686e5274ff89dcfa87a5047df",
+ "reference": "761fa560a937fd7686e5274ff89dcfa87a5047df",
"shasum": ""
},
"require": {
@@ -2209,7 +2208,7 @@
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
- "time": "2019-01-16 20:35:37"
+ "time": "2019-02-23T15:17:42+00:00"
},
{
"name": "theseer/tokenizer",
@@ -2249,7 +2248,7 @@
}
],
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
- "time": "2017-04-07 12:08:54"
+ "time": "2017-04-07T12:08:54+00:00"
},
{
"name": "webmozart/assert",
@@ -2300,7 +2299,7 @@
"check",
"validate"
],
- "time": "2018-12-25 11:19:39"
+ "time": "2018-12-25T11:19:39+00:00"
}
],
"aliases": [],
diff --git a/src/Delta/Html/Compound.php b/src/Delta/Html/Compound.php
index 3f91e1a..bc53ee4 100644
--- a/src/Delta/Html/Compound.php
+++ b/src/Delta/Html/Compound.php
@@ -30,6 +30,16 @@ class Compound extends Delta
*/
private $html;
+ /**
+ * @var boolean Contains a link attribute
+ */
+ private $isLink = false;
+
+ /**
+ * @var string The link
+ */
+ private $link = null;
+
/**
* Set the insert for the compound delta insert
*
@@ -88,7 +98,12 @@ private function tags(): void
*/
public function setAttribute($attribute, $value): Compound
{
- $this->attributes[$attribute] = $value;
+ if ($attribute !== 'link') {
+ $this->attributes[$attribute] = $value;
+ } else {
+ $this->isLink = true;
+ $this->link = $value;
+ }
return $this;
}
@@ -102,6 +117,10 @@ public function render(): string
{
$this->tags();
+ if ($this->isLink === true) {
+ $this->html .= "link}\">";
+ }
+
$element_attributes = '';
foreach ($this->element_attributes as $attribute => $value) {
if ($attribute == "color") {
@@ -125,6 +144,28 @@ public function render(): string
$this->html .= "{$tag}>";
}
+ if ($this->isLink === true) {
+ $this->html .= '';
+ }
+
return $this->html;
}
+
+ /**
+ * Override the method to include the link in the attributes array if
+ * necessary as it will have be striped
+ *
+ * @return array
+ */
+ public function getAttributes(): array
+ {
+ if ($this->isLink === false) {
+ return $this->attributes;
+ } else {
+ return array_merge(
+ ['link' => $this->link],
+ $this->attributes
+ );
+ }
+ }
}
diff --git a/src/Parser/Html.php b/src/Parser/Html.php
index 11bc4e3..700e348 100644
--- a/src/Parser/Html.php
+++ b/src/Parser/Html.php
@@ -73,18 +73,20 @@ public function attributeList(array $quill)
array('ordered', 'bullet')
) === true
) {
- $insert = $this->deltas[count($this->deltas) - 1]->getInsert();
- $attributes = $this->deltas[count($this->deltas) - 1]->getAttributes();
+ $previous_index = count($this->deltas) - 1;
- unset($this->deltas[count($this->deltas) - 1]);
+ $insert = $this->deltas[$previous_index]->getInsert();
+ $attributes = $this->deltas[$previous_index]->getAttributes();
+
+ unset($this->deltas[$previous_index]);
if (count($attributes) === 0) {
$this->deltas[] = new ListItem($insert, $quill['attributes']);
} else {
$delta = new ListItem("", $quill['attributes']);
- foreach ($attributes as $attribute_name => $value) {
- switch ($attribute_name) {
+ if (count($attributes) === 1) {
+ switch(key($attributes)) {
case Options::ATTRIBUTE_BOLD:
$delta->addChild(new Bold($insert));
break;
@@ -121,7 +123,15 @@ public function attributeList(array $quill)
default:
break;
}
+ } else {
+ $childDelta = new Compound($insert);
+ foreach ($attributes as $attribute => $value) {
+ $childDelta->setAttribute($attribute, $value);
+ }
+
+ $delta->addChild($childDelta);
}
+
$this->deltas[] = $delta;
}