From 30a2a3d7677c5fad67285c3a46005bcd612d5e62 Mon Sep 17 00:00:00 2001 From: Nicola Fontana Date: Sun, 19 Mar 2017 13:02:50 +0100 Subject: [PATCH 01/26] Doc fix: the default augmenter is now setId() In the 1.2 branch the default algorithm of the HTML augmenter is to set the id on the destination element, not to add anchors. --- docs/en/usage.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/en/usage.md b/docs/en/usage.md index 68add8d..22e4b9d 100644 --- a/docs/en/usage.md +++ b/docs/en/usage.md @@ -34,16 +34,16 @@ name in the `content_field` property of a YAML config file, e.g.: The *$Autotoc* tag will automatically become available in the above controllers. -By default the HTML is augmented with anchors (`` elements with the -_id_ attribute but without _href_) prepended to the destination -elements. See `Tocifier::prependAnchor` for the exact implementation. +By default the HTML is augmented by setting the _id_ attribute directly on the +destination element (see `Tocifier::setId` for the exact implementation). Any +preexisting _id_ will be overwritten. -This is kept mainly for backward compatibility. A better approach would -be to directly set the id of the destination element. If you want to -enable this behavior, just change the augment callback to -`Tocifier::setId` by adding the following to your YAML config: +The old behavior instead was to inject anchors (`` elements with the _id_ +attribute but without _href_) just before the destination element. It is still +possible to enable it by changing the augment callback to +`Tocifier::prependAnchor`. Just add the following to your YAML config: Tocifier: - augment_callback: [ Tocifier, setId ] + augment_callback: [ Tocifier, prependAnchor ] You can leverage this option to enable your own callbacks too. From 09443ea4281ccdc78ffb3b930731271f2da5d43d Mon Sep 17 00:00:00 2001 From: Nicola Fontana Date: Tue, 19 Dec 2017 14:55:45 +0100 Subject: [PATCH 02/26] Update copyright in LICENSE.md --- LICENSE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE.md b/LICENSE.md index 34c64e6..08a367b 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,4 +1,4 @@ -_Copyright © 2013-2016, Nicola Fontana _ +_Copyright © 2013-2017, Nicola Fontana _ _All rights reserved._ Redistribution and use in source and binary forms, with or without modification, From 40f867698c5a39172eec6d50defdb9b5cf6db094 Mon Sep 17 00:00:00 2001 From: Nicola Fontana Date: Tue, 19 Dec 2017 23:32:54 +0100 Subject: [PATCH 03/26] Initial porting to SilverStripe 4 --- composer.json | 24 ++++++++++++++++-------- {code => src}/Autotoc.php | 19 +++++++++++++------ {code => src}/Tocifier.php | 0 3 files changed, 29 insertions(+), 14 deletions(-) rename {code => src}/Autotoc.php (92%) rename {code => src}/Tocifier.php (100%) diff --git a/composer.json b/composer.json index 560378c..fd40784 100644 --- a/composer.json +++ b/composer.json @@ -1,10 +1,17 @@ { - "name": "entidi/silverstripe-autotoc", + "name": "entidi/autotoc", + "type": "silverstripe-vendormodule", "description": "Dynamically generate the table of contents from $Content", - "type": "silverstripe-module", "homepage": "http://silverstripe.entidi.com/", - "keywords": ["silverstripe", "contents", "toc", "autotoc", "index", "summary"], "license": "BSD-2-Clause", + "keywords": [ + "silverstripe", + "contents", + "toc", + "autotoc", + "index", + "table of contents" + ], "authors": [ { "name": "Nicola Fontana", @@ -18,14 +25,15 @@ "source": "http://dev.entidi.com/p/silverstripe-autotoc/source/tree/master/" }, "require": { - "php": ">=5.3.6", - "silverstripe/framework": "~3.0" + "silverstripe/framework": "~4.0" }, - "require-dev": { - "phpunit/PHPUnit": "~3.7" + "autoload": { + "psr-4": { + "eNTiDi\\Autotoc\\": "src/", + "eNTiDi\\Autotoc\\Tests\\": "tests/" + } }, "extra": { - "installer-name": "autotoc", "screenshots": [ "http://silverstripe.entidi.com/assets/autotoc.jpeg" ] diff --git a/code/Autotoc.php b/src/Autotoc.php similarity index 92% rename from code/Autotoc.php rename to src/Autotoc.php index cd8c815..07b6692 100644 --- a/code/Autotoc.php +++ b/src/Autotoc.php @@ -1,6 +1,13 @@ $node['id'], 'Title' => $node['title'] - )); + ]); if (isset($node['children'])) { $data->setField('Children', self::_convertChildren($node['children'])); @@ -29,7 +36,7 @@ private static function _convertNode($node) private static function _convertChildren($children) { - $list = new ArrayList; + $list = ArrayList::create(); foreach ($children as $child) { $list->push(self::_convertNode($child)); @@ -127,9 +134,9 @@ public function getAutotoc() return ''; } - return new ArrayData(array( + return ArrayData::create([ 'Children' => self::_convertChildren($toc) - )); + ]); } /** * @return string diff --git a/code/Tocifier.php b/src/Tocifier.php similarity index 100% rename from code/Tocifier.php rename to src/Tocifier.php From 2a9feb7d6906074bc6c228edb74e4b4da07b4559 Mon Sep 17 00:00:00 2001 From: Nicola Fontana Date: Wed, 20 Dec 2017 00:13:18 +0100 Subject: [PATCH 04/26] Update codebase for PHP 7 --- src/Tocifier.php | 6 ++++++ tests/Bootstrap.php | 15 --------------- tests/TocifierTest.php | 7 ++++++- 3 files changed, 12 insertions(+), 16 deletions(-) delete mode 100644 tests/Bootstrap.php diff --git a/src/Tocifier.php b/src/Tocifier.php index 3a20a9e..bc50d8a 100644 --- a/src/Tocifier.php +++ b/src/Tocifier.php @@ -1,5 +1,11 @@ setAugmentCallback(array('Tocifier', 'setId')); + $tocifier->setAugmentCallback(array('\eNTiDi\Autotoc\Tocifier', 'setId')); $this->assertEquals($tocifier->getHtml(), ''); $this->assertTrue($tocifier->process()); $this->assertStringEqualsFile(__DIR__ . '/html2', $tocifier->getHtml()); From 71ddc5521676f60ced6db5971239e3e8ac379a56 Mon Sep 17 00:00:00 2001 From: Nicola Fontana Date: Wed, 20 Dec 2017 01:07:50 +0100 Subject: [PATCH 05/26] Fix Travis issue on old supported PHP --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8771685..264ef28 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,8 +5,6 @@ sudo: false language: php php: - - 5.3 - - 5.4 - 5.5 - 5.6 - 7.0 @@ -33,4 +31,4 @@ before_script: - composer install script: - - vendor/bin/phpunit autotoc/tests + - vendor/bin/phpunit vendor/entidi/autotoc/tests From 9ebe50cf181db935791fa61a80acd925f89dcfa1 Mon Sep 17 00:00:00 2001 From: Nicola Fontana Date: Wed, 20 Dec 2017 08:56:51 +0100 Subject: [PATCH 06/26] Update travis infrastructure for SS4 --- .travis.yml | 30 ++---------------------------- composer.json | 6 +++++- phpunit.xml.dist | 5 +++++ 3 files changed, 12 insertions(+), 29 deletions(-) create mode 100644 phpunit.xml.dist diff --git a/.travis.yml b/.travis.yml index 264ef28..c001903 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,34 +1,8 @@ -# See https://github.com/silverstripe-labs/silverstripe-travis-support for setup details - -sudo: false - language: php - php: - - 5.5 - 5.6 - 7.0 -env: - - DB=MYSQL CORE_RELEASE=3.2 - -matrix: - include: - - php: 5.6 - env: DB=MYSQL CORE_RELEASE=3 - - php: 5.6 - env: DB=MYSQL CORE_RELEASE=3.1 - - php: 5.6 - env: DB=PGSQL CORE_RELEASE=3.2 - allow_failures: - - php: 7.0 - before_script: - - composer self-update || true - - git clone git://github.com/silverstripe-labs/silverstripe-travis-support.git ~/travis-support - - php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss - - cd ~/builds/ss - - composer install - -script: - - vendor/bin/phpunit vendor/entidi/autotoc/tests + - composer validate + - composer update diff --git a/composer.json b/composer.json index fd40784..ee24d1d 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,11 @@ "source": "http://dev.entidi.com/p/silverstripe-autotoc/source/tree/master/" }, "require": { - "silverstripe/framework": "~4.0" + "silverstripe/framework": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7", + "silverstripe/recipe-core": "^1.0" }, "autoload": { "psr-4": { diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..1dac3c4 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,5 @@ + + + tests + + From 02dba2855dd123368358f14e592bafd69200ed40 Mon Sep 17 00:00:00 2001 From: Nicola Fontana Date: Wed, 20 Dec 2017 09:54:42 +0100 Subject: [PATCH 07/26] Fix path in scrutinizer YAML --- .scrutinizer.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.scrutinizer.yml b/.scrutinizer.yml index d1ebd80..b69d934 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -66,4 +66,6 @@ checks: argument_type_checks: true filter: - paths: [code/*, tests/*] + paths: + - src/* + - tests/* From 75aac40387bf28fb851da1e6829b82cc3dddabb5 Mon Sep 17 00:00:00 2001 From: Nicola Fontana Date: Wed, 20 Dec 2017 10:33:45 +0100 Subject: [PATCH 08/26] Set minimum-stability to dev Check if lowering the minimum-stability resolves the scrutinizer block: https://scrutinizer-ci.com/g/ntd/silverstripe-autotoc/inspections?branchReference=dev --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index ee24d1d..123fda7 100644 --- a/composer.json +++ b/composer.json @@ -31,6 +31,7 @@ "phpunit/phpunit": "^5.7", "silverstripe/recipe-core": "^1.0" }, + "minimum-stability": "dev", "autoload": { "psr-4": { "eNTiDi\\Autotoc\\": "src/", From c0349ffed89f51e66a2ecfeffe9e8454b0f5169c Mon Sep 17 00:00:00 2001 From: Nicola Fontana Date: Wed, 20 Dec 2017 12:26:08 +0100 Subject: [PATCH 09/26] Update composer and scrutinizer according to mainline --- .scrutinizer.yml | 62 +----------------------------------------------- composer.json | 5 ++-- 2 files changed, 4 insertions(+), 63 deletions(-) diff --git a/.scrutinizer.yml b/.scrutinizer.yml index b69d934..a1473ef 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -2,68 +2,8 @@ inherit: true checks: php: - verify_property_names: true - verify_argument_usable_as_reference: true - verify_access_scope_valid: true - useless_calls: true - use_statement_alias_conflict: true - variable_existence: true - unused_variables: true - unused_properties: true - unused_parameters: true - unused_methods: true - unreachable_code: true - too_many_arguments: true - sql_injection_vulnerabilities: true - simplify_boolean_return: true - side_effects_or_types: true - security_vulnerabilities: true - return_doc_comments: true - return_doc_comment_if_not_inferrable: true - require_scope_for_properties: true - require_scope_for_methods: true - require_php_tag_first: true - psr2_switch_declaration: true - psr2_class_declaration: true - property_assignments: true - prefer_while_loop_over_for_loop: true - precedence_mistakes: true - precedence_in_conditions: true - phpunit_assertions: true - php5_style_constructor: true - parse_doc_comments: true - parameter_non_unique: true - parameter_doc_comments: true - param_doc_comment_if_not_inferrable: true - optional_parameters_at_the_end: true - one_class_per_file: true - no_unnecessary_if: true - no_trailing_whitespace: true - no_property_on_interface: true - no_non_implemented_abstract_methods: true - no_error_suppression: true - no_duplicate_arguments: true - no_commented_out_code: true - newline_at_end_of_file: true - missing_arguments: true - method_calls_on_non_object: true - instanceof_class_exists: true - foreach_traversable: true - fix_line_ending: true - fix_doc_comments: true - duplication: true - deprecated_code_usage: true - deadlock_detection_in_loops: true code_rating: true - closure_use_not_conflicting: true - catch_class_exists: true - blank_line_after_namespace_declaration: false - avoid_multiple_statements_on_same_line: true - avoid_duplicate_types: true - avoid_conflicting_incrementers: true - avoid_closing_tag: true - assignment_of_null_return: true - argument_type_checks: true + duplication: true filter: paths: diff --git a/composer.json b/composer.json index 123fda7..c26cdfe 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,6 @@ "phpunit/phpunit": "^5.7", "silverstripe/recipe-core": "^1.0" }, - "minimum-stability": "dev", "autoload": { "psr-4": { "eNTiDi\\Autotoc\\": "src/", @@ -45,5 +44,7 @@ }, "suggest": { "entidi/silverstrap": "A theme that supports silverstripe-autotoc out of the box" - } + }, + "minimum-stability": "dev", + "prefer-stable": true } From e7bc91abae1453a6106f015329aecde284ab0182 Mon Sep 17 00:00:00 2001 From: Nicola Fontana Date: Wed, 20 Dec 2017 12:37:52 +0100 Subject: [PATCH 10/26] Add support for PHP CodeSniffer --- composer.json | 13 ++++++++++++- phpcs.xml.dist | 12 ++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 phpcs.xml.dist diff --git a/composer.json b/composer.json index c26cdfe..5978425 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,8 @@ }, "require-dev": { "phpunit/phpunit": "^5.7", - "silverstripe/recipe-core": "^1.0" + "silverstripe/recipe-core": "^1.0", + "squizlabs/php_codesniffer": "^3.0" }, "autoload": { "psr-4": { @@ -40,6 +41,16 @@ "extra": { "screenshots": [ "http://silverstripe.entidi.com/assets/autotoc.jpeg" + ], + "project-files-installed": [ + ".htaccess", + "index.php", + "install-frameworkmissing.html", + "install.php", + "mysite/.htaccess", + "mysite/_config.php", + "mysite/_config/mysite.yml", + "web.config" ] }, "suggest": { diff --git a/phpcs.xml.dist b/phpcs.xml.dist new file mode 100644 index 0000000..0bf5738 --- /dev/null +++ b/phpcs.xml.dist @@ -0,0 +1,12 @@ + + + CodeSniffer ruleset for SilverStripe coding conventions. + + + + + + + + + From 3d9ed8c3c30b99cbdcedafdb9442f0d28f41e698 Mon Sep 17 00:00:00 2001 From: Nicola Fontana Date: Wed, 20 Dec 2017 12:43:05 +0100 Subject: [PATCH 11/26] Fix issue highlighted by phpcs --- src/{Autotoc.php => AutotocExtension.php} | 34 ++++++------ src/Tocifier.php | 67 +++++++++++------------ 2 files changed, 50 insertions(+), 51 deletions(-) rename src/{Autotoc.php => AutotocExtension.php} (79%) diff --git a/src/Autotoc.php b/src/AutotocExtension.php similarity index 79% rename from src/Autotoc.php rename to src/AutotocExtension.php index 07b6692..462c934 100644 --- a/src/Autotoc.php +++ b/src/AutotocExtension.php @@ -20,7 +20,7 @@ class AutotocExtension extends Extension private $_tocifier; - private static function _convertNode($node) + private static function convertNode($node) { $data = ArrayData::create([ 'Id' => $node['id'], @@ -28,18 +28,18 @@ private static function _convertNode($node) ]); if (isset($node['children'])) { - $data->setField('Children', self::_convertChildren($node['children'])); + $data->setField('Children', self::convertChildren($node['children'])); } return $data; } - private static function _convertChildren($children) + private static function convertChildren($children) { $list = ArrayList::create(); foreach ($children as $child) { - $list->push(self::_convertNode($child)); + $list->push(self::convertNode($child)); } return $list; @@ -49,7 +49,7 @@ private static function _convertChildren($children) * Get the field name to be used as content. * @return string */ - private function _contentField() + private function contentField() { $field = $this->owner->config()->get('content_field'); return $field ? $field : 'Content'; @@ -72,16 +72,16 @@ public function setOwner($owner, $base_class = null) parent::setOwner($owner, $base_class); if ($owner) { - $tocifier = $this->_getTocifier(); - $content = $tocifier ? $tocifier->getHtml() : $this->_getHtml(); - $owner->setField($this->_contentField(), $content); + $tocifier = $this->getTocifier(); + $content = $tocifier ? $tocifier->getHtml() : $this->getHtml(); + $owner->setField($this->contentField(), $content); } } /** * @return string */ - private function _getHtml() + private function getHtml() { $c = $this->owner; $model = $c->customisedObject ? $c->customisedObject : $c->data(); @@ -89,7 +89,7 @@ private function _getHtml() return null; } - $field = $this->_contentField(); + $field = $this->contentField(); if (! $model->hasField($field)) { return null; } @@ -106,25 +106,25 @@ private function _getHtml() * * @return Tocifier|false */ - private function _getTocifier() + private function getTocifier() { - if (is_null($this->_tocifier)) { - $tocifier = new Tocifier($this->_getHtml()); + if (is_null($this->tocifier)) { + $tocifier = new Tocifier($this->getHtml()); // TODO: not sure this is the best approach... maybe I // should look to $this->owner->dataRecord before $config = Config::inst()->get(__CLASS__, 'augment_callback'); // Take only the first two, because SilverStripe merges // arrays with the same key instead of overwriting them $tocifier->setAugmentCallback(array_slice($config, 0, 2)); - $this->_tocifier = $tocifier->process() ? $tocifier : false; + $this->tocifier = $tocifier->process() ? $tocifier : false; } - return $this->_tocifier; + return $this->tocifier; } public function getAutotoc() { - $tocifier = $this->_getTocifier(); + $tocifier = $this->getTocifier(); if (! $tocifier) { return null; } @@ -135,7 +135,7 @@ public function getAutotoc() } return ArrayData::create([ - 'Children' => self::_convertChildren($toc) + 'Children' => self::convertChildren($toc) ]); } /** diff --git a/src/Tocifier.php b/src/Tocifier.php index bc50d8a..1b687a6 100644 --- a/src/Tocifier.php +++ b/src/Tocifier.php @@ -16,19 +16,19 @@ class Tocifier public static $prefix = 'TOC-'; // The original HTML - private $_raw_html = ''; + private $raw_html = ''; - // $_raw_html augmented for proper navigation - private $_html = ''; + // $raw_html augmented for proper navigation + private $html = ''; // The most recently generated TOC tree. - private $_tree; + private $tree; // Array of references to the potential parents - private $_dangling = array(); + private $dangling = array(); // Callback for augmenting a single DOMElement - private $_augment_callback; + private $augment_callback; /** @@ -37,11 +37,11 @@ class Tocifier * @param int $level The requested nesting level. * @return array */ - private function &_getParent($level) + private function &getParent($level) { while (--$level >= 0) { - if (isset($this->_dangling[$level])) { - return $this->_dangling[$level]; + if (isset($this->dangling[$level])) { + return $this->dangling[$level]; } } // This should never be reached @@ -54,7 +54,7 @@ private function &_getParent($level) * @param DOMElement $tag The DOM element to inspect. * @return string */ - private function _getPlainText(DOMElement $tag) + private function getPlainText(DOMElement $tag) { // Work on a copy $clone = $tag->cloneNode(true); @@ -75,7 +75,7 @@ private function _getPlainText(DOMElement $tag) * @param int $level The nesting level of the node * @return array */ - private function &_newNode($id, $text, $level) + private function &newNode($id, $text, $level) { $node = array( 'id' => $id, @@ -83,14 +83,14 @@ private function &_newNode($id, $text, $level) ); // Clear the trailing dangling parents after level, if any - end($this->_dangling); - $last = key($this->_dangling); + end($this->dangling); + $last = key($this->dangling); for ($n = $level+1; $n <= $last; ++$n) { - unset($this->_dangling[$n]); + unset($this->dangling[$n]); } // Consider this node a potential dangling parent - $this->_dangling[$level] = & $node; + $this->dangling[$level] = & $node; return $node; } @@ -100,34 +100,33 @@ private function &_newNode($id, $text, $level) * * @param DOMDocument $doc The document to process. */ - private function _processDocument($doc) + private function processDocument($doc) { - $this->_tree = & $this->_newNode(self::$prefix, '', 0); + $this->tree = & $this->newNode(self::$prefix, '', 0); $n = 1; $xpath = new DOMXPath($doc); $query = '//*[translate(name(), "123456", "......") = "h."][not(@data-hide-from-toc)]'; foreach ($xpath->query($query) as $h) { - $text = $this->_getPlainText($h); + $text = $this->getPlainText($h); $level = (int) substr($h->tagName, 1); $id = self::$prefix.$n; ++$n; // Build the tree - $parent = & $this->_getParent($level); - $node = & $this->_newNode($id, $text, $level); + $parent = & $this->getParent($level); + $node = & $this->newNode($id, $text, $level); if (!isset($parent['children'])) { $parent['children'] = array(); } $parent['children'][] = & $node; - call_user_func($this->_augment_callback, $doc, $h, $id); + call_user_func($this->augment_callback, $doc, $h, $id); } $body = $doc->getElementsByTagName('body')->item(0); - $this->_html = str_replace(array("\n", ''), '', - $doc->saveHTML($body)); + $this->html = str_replace(array("\n", ''), '', $doc->saveHTML($body)); } /** @@ -136,12 +135,12 @@ private function _processDocument($doc) * @param array $node The TOC node to dump * @param string $indent Indentation string. */ - private function _dumpBranch($node, $indent = '') + private function dumpBranch($node, $indent = '') { echo $indent.$node['title']."\n"; if (isset($node['children'])) { foreach ($node['children'] as &$child) { - $this->_dumpBranch($child, "$indent\t"); + $this->dumpBranch($child, "$indent\t"); } } } @@ -165,7 +164,7 @@ private function _dumpBranch($node, $indent = '') */ public function __construct($html) { - $this->_raw_html = $html; + $this->raw_html = $html; // Default augmenting method (kept for backward compatibility) $this->setAugmentCallback(array(__CLASS__, 'prependAnchor')); } @@ -188,7 +187,7 @@ public function __construct($html) */ public function setAugmentCallback($callback) { - $this->_augment_callback = $callback; + $this->augment_callback = $callback; } /** @@ -202,15 +201,15 @@ public function setAugmentCallback($callback) */ public function process() { - // Check if $this->_raw_html is valid - if (!is_string($this->_raw_html) || empty($this->_raw_html)) { + // Check if $this->raw_html is valid + if (!is_string($this->raw_html) || empty($this->raw_html)) { return false; } // DOMDocument sucks ass (welcome to PHP, you poor shit). I // really don't understand why it is so difficult for loadHTML() // to read a chunk of text in UTF-8... - $html = mb_convert_encoding($this->_raw_html, 'HTML-ENTITIES', 'UTF-8'); + $html = mb_convert_encoding($this->raw_html, 'HTML-ENTITIES', 'UTF-8'); // Parse the HTML into a DOMDocument tree $doc = new DOMDocument(); @@ -219,7 +218,7 @@ public function process() } // Process the doc - $this->_processDocument($doc); + $this->processDocument($doc); return true; } @@ -262,7 +261,7 @@ public function process() */ public function getTOC() { - return isset($this->_tree['children']) ? $this->_tree['children'] : array(); + return isset($this->tree['children']) ? $this->tree['children'] : array(); } /** @@ -276,7 +275,7 @@ public function getTOC() */ public function getHtml() { - return $this->_html; + return $this->html; } /** @@ -284,7 +283,7 @@ public function getHtml() */ public function dumpTOC() { - $this->_dumpBranch($this->_tree); + $this->dumpBranch($this->tree); } /** From 7b4096faaaf3f9a6cef286a123b2a3e91ef1c064 Mon Sep 17 00:00:00 2001 From: Nicola Fontana Date: Wed, 20 Dec 2017 14:06:41 +0100 Subject: [PATCH 12/26] Restore old package name Renaming a package in packagist is not straigthforward: https://github.com/composer/packagist/issues/225 Keep the old name until a better approach is implemented. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 5978425..320dc99 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "entidi/autotoc", + "name": "entidi/silverstripe-autotoc", "type": "silverstripe-vendormodule", "description": "Dynamically generate the table of contents from $Content", "homepage": "http://silverstripe.entidi.com/", From 6fd6dc4f409c36ec1926e0a3eddb53936ae1c0f9 Mon Sep 17 00:00:00 2001 From: Nicola Fontana Date: Wed, 20 Dec 2017 14:28:16 +0100 Subject: [PATCH 13/26] Strip project-files-installed from composer.json --- composer.json | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/composer.json b/composer.json index 320dc99..c505229 100644 --- a/composer.json +++ b/composer.json @@ -41,16 +41,6 @@ "extra": { "screenshots": [ "http://silverstripe.entidi.com/assets/autotoc.jpeg" - ], - "project-files-installed": [ - ".htaccess", - "index.php", - "install-frameworkmissing.html", - "install.php", - "mysite/.htaccess", - "mysite/_config.php", - "mysite/_config/mysite.yml", - "web.config" ] }, "suggest": { From 72daf19bc2b8371214efb13b9c708067e734a144 Mon Sep 17 00:00:00 2001 From: Nicola Fontana Date: Wed, 20 Dec 2017 14:36:14 +0100 Subject: [PATCH 14/26] Remove silverstripe recipe from composer The recipe seems to be not required for testing and forcibly modifies composer.json on every update (see commit 6fd6dc4f409c). --- composer.json | 1 - 1 file changed, 1 deletion(-) diff --git a/composer.json b/composer.json index c505229..ee99423 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,6 @@ }, "require-dev": { "phpunit/phpunit": "^5.7", - "silverstripe/recipe-core": "^1.0", "squizlabs/php_codesniffer": "^3.0" }, "autoload": { From f6bd25841fb22430b4c3b35517740cdffab190cf Mon Sep 17 00:00:00 2001 From: Nicola Fontana Date: Wed, 20 Dec 2017 22:09:28 +0100 Subject: [PATCH 15/26] Fix YAML configuration I got a circular dependency error. On silverstripe-framework#6700 [1], kinglozzer suggested to remove before/after blocks from `mysite/_config.yml` but I am still getting the same error, so I suppose I need to remove those blocks from other YAML too. [1] https://github.com/silverstripe/silverstripe-framework/issues/6700 --- _config/autotoc.yml | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/_config/autotoc.yml b/_config/autotoc.yml index f7cf13b..bad7329 100644 --- a/_config/autotoc.yml +++ b/_config/autotoc.yml @@ -1,14 +1,12 @@ --- Name: autotoc -After: - - framework --- -Autotoc: - augment_callback: [ Tocifier, SetId ] +eNTiDi\Autotoc\AutotocExtension: + augment_callback: [ Tocifier, SetId ] --- Only: - classexists: ContentController + classexists: SilverStripe\CMS\Controllers\ContentController --- -ContentController: - extensions: - - 'Autotoc' +SilverStripe\CMS\Controllers\ContentController: + extensions: + - eNTiDi\Autotoc\AutotocExtension From f20638794dc13f481dda243a86f0648ab7320191 Mon Sep 17 00:00:00 2001 From: Nicola Fontana Date: Thu, 21 Dec 2017 00:22:17 +0100 Subject: [PATCH 16/26] Fix minor bugs in AutotocExtension --- src/AutotocExtension.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/AutotocExtension.php b/src/AutotocExtension.php index 462c934..424d37a 100644 --- a/src/AutotocExtension.php +++ b/src/AutotocExtension.php @@ -2,7 +2,8 @@ namespace eNTiDi\Autotoc; -use eNTiDi\Autotoc; +use eNTiDi\Autotoc\Tocifier; +use SilverStripe\Core\Config\Config; use SilverStripe\Core\Extension; use SilverStripe\ORM\ArrayList; use SilverStripe\View\ArrayData; @@ -17,7 +18,7 @@ class AutotocExtension extends Extension */ private static $augment_callback; - private $_tocifier; + private $tocifier; private static function convertNode($node) From a0a809cc8035e4b6f2bb7b08445541e15bc17b82 Mon Sep 17 00:00:00 2001 From: Nicola Fontana Date: Thu, 21 Dec 2017 17:19:00 +0100 Subject: [PATCH 17/26] Add missing namespace to default augment callback --- _config/autotoc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_config/autotoc.yml b/_config/autotoc.yml index bad7329..d938183 100644 --- a/_config/autotoc.yml +++ b/_config/autotoc.yml @@ -2,7 +2,7 @@ Name: autotoc --- eNTiDi\Autotoc\AutotocExtension: - augment_callback: [ Tocifier, SetId ] + augment_callback: [ eNTiDi\Autotoc\Tocifier, SetId ] --- Only: classexists: SilverStripe\CMS\Controllers\ContentController From 94378c699b4c44dde3f2064616f49ab31d3c7caf Mon Sep 17 00:00:00 2001 From: Nicola Fontana Date: Thu, 21 Dec 2017 17:43:11 +0100 Subject: [PATCH 18/26] Use the injector for instantiating the Tocifier --- src/AutotocExtension.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/AutotocExtension.php b/src/AutotocExtension.php index 424d37a..6798767 100644 --- a/src/AutotocExtension.php +++ b/src/AutotocExtension.php @@ -2,9 +2,9 @@ namespace eNTiDi\Autotoc; -use eNTiDi\Autotoc\Tocifier; use SilverStripe\Core\Config\Config; use SilverStripe\Core\Extension; +use SilverStripe\Core\Injector\Injector; use SilverStripe\ORM\ArrayList; use SilverStripe\View\ArrayData; @@ -23,7 +23,7 @@ class AutotocExtension extends Extension private static function convertNode($node) { - $data = ArrayData::create([ + $data = new ArrayData([ 'Id' => $node['id'], 'Title' => $node['title'] ]); @@ -37,7 +37,7 @@ private static function convertNode($node) private static function convertChildren($children) { - $list = ArrayList::create(); + $list = new ArrayList(); foreach ($children as $child) { $list->push(self::convertNode($child)); @@ -110,7 +110,7 @@ private function getHtml() private function getTocifier() { if (is_null($this->tocifier)) { - $tocifier = new Tocifier($this->getHtml()); + $tocifier = Injector::inst()->create('Tocifier'); // TODO: not sure this is the best approach... maybe I // should look to $this->owner->dataRecord before $config = Config::inst()->get(__CLASS__, 'augment_callback'); @@ -135,7 +135,7 @@ public function getAutotoc() return ''; } - return ArrayData::create([ + return new ArrayData([ 'Children' => self::convertChildren($toc) ]); } From b2314120e104a262f7fc2d431ed8d9fb23aae6c1 Mon Sep 17 00:00:00 2001 From: Nicola Fontana Date: Thu, 21 Dec 2017 19:03:44 +0100 Subject: [PATCH 19/26] Fix Tocifier instantiation call --- src/AutotocExtension.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/AutotocExtension.php b/src/AutotocExtension.php index 6798767..ba64e5f 100644 --- a/src/AutotocExtension.php +++ b/src/AutotocExtension.php @@ -110,7 +110,10 @@ private function getHtml() private function getTocifier() { if (is_null($this->tocifier)) { - $tocifier = Injector::inst()->create('Tocifier'); + $tocifier = Injector::inst()->create( + 'eNTiDi\Autotoc\Tocifier', + $this->getHtml() + ); // TODO: not sure this is the best approach... maybe I // should look to $this->owner->dataRecord before $config = Config::inst()->get(__CLASS__, 'augment_callback'); From ce1f91c36c41c22623bc92bcbc67808c506a13fd Mon Sep 17 00:00:00 2001 From: Nicola Fontana Date: Fri, 29 Dec 2017 00:47:59 +0100 Subject: [PATCH 20/26] Major refactoring for SS4 --- CONTRIBUTING.md | 7 +- README.md | 17 +--- _config/autotoc.yml | 6 +- docs/en/format.md | 8 +- docs/en/usage.md | 56 ++++++++--- src/Autotoc.php | 212 +++++++++++++++++++++++++++++++++++++++ src/AutotocExtension.php | 152 ---------------------------- src/Hacks.php | 37 +++++++ src/Tocifier.php | 5 +- tests/AutotocTest.php | 125 +++++++++++++++++++++++ tests/TestObject.php | 14 +++ tests/TocifierTest.php | 15 +-- 12 files changed, 457 insertions(+), 197 deletions(-) create mode 100644 src/Autotoc.php delete mode 100644 src/AutotocExtension.php create mode 100644 src/Hacks.php create mode 100644 tests/AutotocTest.php create mode 100644 tests/TestObject.php diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7fd5973..eae82ea 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,6 +4,7 @@ Any open source product is only as good as the community behind it. You can participate by sharing code, ideas, or simply helping others. No matter what your skill level is, every contribution counts. -The main development happens into the `dev` branch, so pull requests are -expected to be done against `dev`. Anyway the project is so small that -contributions in master will not be surely rejected. +The main developement is done in `dev`: that is merged into `master` when +considered stable enough. When this happens, an appropriate release is tagged. +`dev` and `master` branches are compatibles with SilverStripe 4. For +SilverStripe 3 you should take a look at the `ss3` branch. diff --git a/README.md b/README.md index d3d012c..83823eb 100644 --- a/README.md +++ b/README.md @@ -11,28 +11,19 @@ page or, more generally, from any HTML field. Installation ------------ -If you use [composer](https://getcomposer.org/), you could just run the -following command: - composer require entidi/silverstripe-autotoc -To manually install it you should unpack or copy `silverstripe-autotoc` -into your SilverStripe root directory, rename it to `autotoc` and do a -`?flush`. +Manual installation is probably possible but not really tested. This module can be used without the CMS. Testing ------- -Part of this project (the _Tocifier_ class) is intentionally decoupled -from SilverStripe so it can be tested without pulling in all the -framework. - -From the module root directory you can trigger the testing by calling -`phpunit` (that must be previously installed on your system): +Basically it boils down to the following commands: - phpunit --bootstrap tests/Bootstrap.php tests/ + composer update + vendor/bin/phpunit Other documentation ------------------- diff --git a/_config/autotoc.yml b/_config/autotoc.yml index d938183..2241a5d 100644 --- a/_config/autotoc.yml +++ b/_config/autotoc.yml @@ -1,12 +1,12 @@ --- Name: autotoc --- -eNTiDi\Autotoc\AutotocExtension: - augment_callback: [ eNTiDi\Autotoc\Tocifier, SetId ] +eNTiDi\Autotoc\Autotoc: + augment_callback: eNTiDi\Autotoc\Tocifier::SetId --- Only: classexists: SilverStripe\CMS\Controllers\ContentController --- SilverStripe\CMS\Controllers\ContentController: extensions: - - eNTiDi\Autotoc\AutotocExtension + - eNTiDi\Autotoc\Autotoc diff --git a/docs/en/format.md b/docs/en/format.md index 8e721e1..92ae0b6 100644 --- a/docs/en/format.md +++ b/docs/en/format.md @@ -8,7 +8,7 @@ pseudocode: = ArrayList( ) = ArrayData( $Id, $Title [, $Children <- ] ) -In a more SilverStripe template way, this can be seen as: +In a more SilverStripe way, this can be seen as: $Autotoc $Children[] @@ -16,9 +16,9 @@ In a more SilverStripe template way, this can be seen as: $Title $Children[] -The `Autotoc.ss` and `AutotocItem.ss` show a way to represent the whole -table of content tree in a recursive way. The format used there is -intentionally compatible with the +`Autotoc.ss` and `AutotocItem.ss` show a way to render the whole table of +contents by leveraging mutual recursion between two templates. The format used +there is intentionally compatible with the [Bootstrap navlist](http://getbootstrap.com/components/#nav) component, so it can be used and it will be properly handled by the [Silverstrap](http://dev.entidi.com/p/silverstrap/) theme. diff --git a/docs/en/usage.md b/docs/en/usage.md index 22e4b9d..bec2eaa 100644 --- a/docs/en/usage.md +++ b/docs/en/usage.md @@ -1,19 +1,24 @@ Usage ----- -`silverstripe-autotoc` is basically a [SilverStripe 3](http://www.silverstripe.org/) +`silverstripe-autotoc` is basically a [SilverStripe 4](http://www.silverstripe.org/) module that extends a controller (if the CMS is present the -[ContentController](http://api.silverstripe.org/3.0/class-ContentController.html) +[ContentController](http://api.silverstripe.org/4/SilverStripe/CMS/Controllers/ContentController.html) will be extended out of the box) to provide: * the *$Autotoc* tag, containing the table of contents dynamically - created from the content of the current page. The tree is provided as + generated from the content of the current page. The tree is provided as a mixture of - [ArrayData](http://api.silverstripe.org/3.0/class-ArrayData.html) and - [ArrayList](http://api.silverstripe.org/3.0/class-ArrayList.html), - ready to be consumed by templates. -* the override of the subject field (i.e. *$Content* by default) that - will be augmented to add proper destinations for the links. + [ArrayData](http://api.silverstripe.org/4/SilverStripe/View/ArrayData.html) and + [ArrayList](http://api.silverstripe.org/4/SilverStripe/ORM/ArrayList.html), + ready to be consumed by templates; +* the *$ContentField* tag, containing the HTML content properly augmented with + the destinations of the TOC links; +* the *$OriginalContentField* tag, for accessing the original (non-augmented) + content field; +* an automatic override of the value of the content field (*$Content* by + default): accessing that field will automatically return the augmented HTML. + Use *$OriginalContentField* to access the non-augmented content, if needed. You will need to modify your templates for embedding the *$Autotoc* tag (see [AutoTOC format](format.md) for the gory details) or directly @@ -21,8 +26,11 @@ include the sample template, e.g.: <% include Autotoc %> +Specifying the content field +---------------------------- + If you want to tocify a field different from *Content*, set the desired -name in the `content_field` property of a YAML config file, e.g.: +name in the `content_field` property, e.g.: ContentController: content_field: 'Content' # Bogus: this is the default @@ -34,6 +42,9 @@ name in the `content_field` property of a YAML config file, e.g.: The *$Autotoc* tag will automatically become available in the above controllers. +Augmenting algorithm +-------------------- + By default the HTML is augmented by setting the _id_ attribute directly on the destination element (see `Tocifier::setId` for the exact implementation). Any preexisting _id_ will be overwritten. @@ -43,7 +54,28 @@ attribute but without _href_) just before the destination element. It is still possible to enable it by changing the augment callback to `Tocifier::prependAnchor`. Just add the following to your YAML config: - Tocifier: - augment_callback: [ Tocifier, prependAnchor ] + eNTiDi\Autotoc\Autotoc: + augment_callback: eNTiDi\Autotoc\Tocifier::prependAnchor + +You can leverage this option to run your own callbacks too, e.g.: + + eNTiDi\Autotoc\Autotoc: + augment_callback: 'Page::defaultCallback' + Page: + augment_callback: 'Page::specificCallback' + +The callback receives three arguments: the main +[DOMDocument](http://php.net/manual/en/class.domdocument.php) instance, the +[DOMElement](http://php.net/manual/en/class.domelement.php) to augment and a +string with the ID the element must refer to. + +Excluding items from the TOC +---------------------------- + +If for some reasons you **do not** want to include some sections in the TOC, +just specify the `data-hide-from-toc` attribute, e.g.: -You can leverage this option to enable your own callbacks too. +

First section

+

Second section

+

This section will be skipped

+

Last section

diff --git a/src/Autotoc.php b/src/Autotoc.php new file mode 100644 index 0000000..5f6cab5 --- /dev/null +++ b/src/Autotoc.php @@ -0,0 +1,212 @@ + $node['id'], + 'Title' => $node['title'] + ]); + + if (isset($node['children'])) { + $data->setField('Children', self::convertChildren($node['children'])); + } + + return $data; + } + + private static function convertChildren($children) + { + $list = new ArrayList(); + + foreach ($children as $child) { + $list->push(self::convertNode($child)); + } + + return $list; + } + + /** + * Get the field name to be used as content. + * @return string + */ + private function contentField() + { + $field = $this->owner->config()->get('content_field'); + return $field ? $field : 'Content'; + } + + /** + * Provide content_field customization on a class basis. + * + * Override the default setOwner() method so, when valorized, I can + * enhance the (possibly custom) content field with anchors. I did + * not find a better way to override a field other than directly + * substituting it with setField(). + * + * @param Object $owner + */ + public function setOwner($owner) + { + parent::setOwner($owner); + if ($owner) { + Hacks::addCallbackMethodToInstance( + $owner, + 'getContent', + function () use ($owner) { + return $owner->getContentField(); + } + ); + } + } + + /** + * Return the internal Tocifier instance bound to $owner. + * + * If not present, try to create and execute a new one. On failure + * (e.g. because of malformed content) no further attempts will be + * made. + * + * @param DataObject $owner + * @return Tocifier|false|null + */ + private static function getTocifier($owner) + { + if (!$owner) { + $tocifier = null; + } elseif (isset(self::$tocifiers[$owner])) { + $tocifier = self::$tocifiers[$owner]; + } else { + $tocifier = Injector::inst()->create( + 'eNTiDi\Autotoc\Tocifier', + $owner->getOriginalContentField() + ); + $callback = $owner->config()->get('augment_callback'); + if (empty($callback)) { + $callback = Config::inst()->get(self::class, 'augment_callback'); + } + $tocifier->setAugmentCallback(explode('::', $callback)); + if (! $tocifier->process()) { + $tocifier = false; + } + self::$tocifiers[$owner] = $tocifier; + } + + return $tocifier; + } + + /** + * Clear the internal Autotoc cache. + * + * The TOC is usually cached the first time you call (directly or + * indirectly) getAutotoc() or getContentField(). This method allows + * to clear the internal cache to force a recomputation. + */ + public function clearAutotoc() + { + unset(self::$tocifiers[$this->owner]); + } + + /** + * Get the automatically generated table of contents. + * @return ArrayData|null + */ + public function getAutotoc() + { + $tocifier = self::getTocifier($this->owner); + if (! $tocifier) { + return null; + } + + $toc = $tocifier->getTOC(); + if (empty($toc)) { + return null; + } + + return new ArrayData([ + 'Children' => self::convertChildren($toc) + ]); + } + + /** + * Get the non-augmented content field. + * @return string + */ + public function getOriginalContentField() + { + $model = $this->owner->getCustomisedObj(); + if (! $model) { + $model = $this->owner->data(); + } + if (! $model) { + return null; + } + + $field = $this->contentField(); + if (! $model->hasField($field)) { + return null; + } + + return $model->getField($field); + return $model->obj($field)->forTemplate(); + } + + /** + * Get the augmented content field. + * @return string + */ + public function getContentField() + { + $tocifier = self::getTocifier($this->owner); + if (!$tocifier) { + return $this->getOriginalContentField(); + } + + return $tocifier->getHTML(); + } + + /** + * I don't remember what the hell is this... + * @return string + */ + public function getBodyAutotoc() + { + return ' data-spy="scroll" data-target=".toc"'; + } +} diff --git a/src/AutotocExtension.php b/src/AutotocExtension.php deleted file mode 100644 index ba64e5f..0000000 --- a/src/AutotocExtension.php +++ /dev/null @@ -1,152 +0,0 @@ - $node['id'], - 'Title' => $node['title'] - ]); - - if (isset($node['children'])) { - $data->setField('Children', self::convertChildren($node['children'])); - } - - return $data; - } - - private static function convertChildren($children) - { - $list = new ArrayList(); - - foreach ($children as $child) { - $list->push(self::convertNode($child)); - } - - return $list; - } - - /** - * Get the field name to be used as content. - * @return string - */ - private function contentField() - { - $field = $this->owner->config()->get('content_field'); - return $field ? $field : 'Content'; - } - - /** - * Provide content_field customization on a class basis. - * - * Override the default setOwner() method so, when valorized, I can - * enhance the (possibly custom) content field with anchors. I did - * not find a better way to override a field other than directly - * substituting it with setField(). - * - * @param Object $owner The owner instance - * @param string|null $base_class The name of the base class this - * extension is applied to - */ - public function setOwner($owner, $base_class = null) - { - parent::setOwner($owner, $base_class); - - if ($owner) { - $tocifier = $this->getTocifier(); - $content = $tocifier ? $tocifier->getHtml() : $this->getHtml(); - $owner->setField($this->contentField(), $content); - } - } - - /** - * @return string - */ - private function getHtml() - { - $c = $this->owner; - $model = $c->customisedObject ? $c->customisedObject : $c->data(); - if (! $model) { - return null; - } - - $field = $this->contentField(); - if (! $model->hasField($field)) { - return null; - } - - return $model->obj($field)->forTemplate(); - } - - /** - * Return the internal Tocifier instance bound to this Autotoc. - * - * If not preset, try to create and execute a new one. On failure - * (e.g. because of malformed content) no further attempts will be - * made. - * - * @return Tocifier|false - */ - private function getTocifier() - { - if (is_null($this->tocifier)) { - $tocifier = Injector::inst()->create( - 'eNTiDi\Autotoc\Tocifier', - $this->getHtml() - ); - // TODO: not sure this is the best approach... maybe I - // should look to $this->owner->dataRecord before - $config = Config::inst()->get(__CLASS__, 'augment_callback'); - // Take only the first two, because SilverStripe merges - // arrays with the same key instead of overwriting them - $tocifier->setAugmentCallback(array_slice($config, 0, 2)); - $this->tocifier = $tocifier->process() ? $tocifier : false; - } - - return $this->tocifier; - } - - public function getAutotoc() - { - $tocifier = $this->getTocifier(); - if (! $tocifier) { - return null; - } - - $toc = $tocifier->getTOC(); - if (empty($toc)) { - return ''; - } - - return new ArrayData([ - 'Children' => self::convertChildren($toc) - ]); - } - /** - * @return string - */ - public function getBodyAutotoc() - { - return ' data-spy="scroll" data-target=".toc"'; - } -} diff --git a/src/Hacks.php b/src/Hacks.php new file mode 100644 index 0000000..37802c3 --- /dev/null +++ b/src/Hacks.php @@ -0,0 +1,37 @@ +hasMethod('UnexistentMethod'); + self::$extra_methods[get_class($instance)][strtolower($method)] = [ + 'wrap' => $wrap, + 'method' => $method, + ]; + } + + public static function addCallbackMethodToInstance($instance, $method, $callback) + { + // hasMethod() trigger the population of $extra_methods + $instance->hasMethod('UnexistentMethod'); + self::$extra_methods[get_class($instance)][strtolower($method)] = [ + 'callback' => $callback, + ]; + } +} diff --git a/src/Tocifier.php b/src/Tocifier.php index 1b687a6..35bd770 100644 --- a/src/Tocifier.php +++ b/src/Tocifier.php @@ -126,7 +126,7 @@ private function processDocument($doc) } $body = $doc->getElementsByTagName('body')->item(0); - $this->html = str_replace(array("\n", ''), '', $doc->saveHTML($body)); + $this->html = str_replace(array("\n", '', ''), '', $doc->saveHTML($body)); } /** @@ -165,8 +165,7 @@ private function dumpBranch($node, $indent = '') public function __construct($html) { $this->raw_html = $html; - // Default augmenting method (kept for backward compatibility) - $this->setAugmentCallback(array(__CLASS__, 'prependAnchor')); + $this->setAugmentCallback(array(static::class, 'setId')); } /** diff --git a/tests/AutotocTest.php b/tests/AutotocTest.php new file mode 100644 index 0000000..b107dfe --- /dev/null +++ b/tests/AutotocTest.php @@ -0,0 +1,125 @@ +Content = ''; + $obj->Test2 = ''; + return $obj; + } + private function populatedTestObject() + { + $obj = new TestObject; + $obj->Content = file_get_contents(__DIR__ . '/test1'); + $obj->Test2 = file_get_contents(__DIR__ . '/test2'); + return $obj; + } + + public function testBodyAutotoc() + { + $obj = new TestObject; + $this->assertEquals(' data-spy="scroll" data-target=".toc"', $obj->getBodyAutotoc()); + } + + public function testContentField() + { + $obj = new TestObject; + $obj->Content = '

Content

'; + $obj->Test2 = '

Test2

'; + + // Check the default content field is Content + $this->assertEquals('

Content

', $obj->OriginalContentField); + + // Try to change the content field + $obj->config()->update('content_field', 'Test2'); + $this->assertEquals('

Test2

', $obj->OriginalContentField); + + // Change it again + $obj->config()->update('content_field', 'Unexistent'); + $this->assertEquals('', $obj->OriginalContentField); + + // Restore original value + $obj->config()->update('content_field', 'Content'); + } + + public function testGetAutotoc() + { + $obj = new TestObject; + $toc = $obj->getAutotoc(); + $this->assertNull($toc); + + $obj->Content = file_get_contents(__DIR__ . '/test1'); + $obj->Test2 = file_get_contents(__DIR__ . '/test2'); + + // Old TOC should still be cached + $toc = $obj->getAutotoc(); + $this->assertNull($toc); + + $obj->clearAutotoc(); + + $toc = $obj->getAutotoc(); + $this->assertTrue($toc instanceof ArrayData); + $this->assertEquals(5, $toc->Children->count()); + $this->assertStringEqualsFile(__DIR__ . '/test1', $obj->OriginalContentField); + $this->assertStringEqualsFile(__DIR__ . '/html2', $obj->ContentField); + $this->assertStringEqualsFile(__DIR__ . '/html2', $obj->Content); + + // Change the content field + $obj->config()->update('content_field', 'Test2'); + $obj->clearAutotoc(); + + $toc = $obj->getAutotoc(); + $this->assertNull($toc); + $this->assertStringEqualsFile(__DIR__ . '/test2', $obj->OriginalContentField); + $this->assertStringEqualsFile(__DIR__ . '/test2', $obj->ContentField); + } + + public function testAugmentCallback() + { + $obj = new TestObject; + $obj->Content = file_get_contents(__DIR__ . '/test1'); + $obj->Test2 = file_get_contents(__DIR__ . '/test2'); + + // Change the augmenter at class level + Config::inst()->update( + get_class($obj), + 'augment_callback', + 'eNTiDi\Autotoc\Tocifier::prependAnchor' + ); + $obj->clearAutotoc(); + + $toc = $obj->getAutotoc(); + $this->assertEquals(5, $toc->Children->count()); + $this->assertStringEqualsFile(__DIR__ . '/html1', $obj->Content); + + // Change the augmenter at install level: should have higher + // precedence + $obj->config()->update( + 'augment_callback', + 'eNTiDi\Autotoc\Tocifier::setId' + ); + $obj->clearAutotoc(); + + $toc = $obj->getAutotoc(); + $this->assertEquals(5, $toc->Children->count()); + $this->assertStringEqualsFile(__DIR__ . '/html2', $obj->Content); + } +} diff --git a/tests/TestObject.php b/tests/TestObject.php new file mode 100644 index 0000000..1d52bf5 --- /dev/null +++ b/tests/TestObject.php @@ -0,0 +1,14 @@ + 'HTMLText', + 'Test2' => 'HTMLText', + ]; +} diff --git a/tests/TocifierTest.php b/tests/TocifierTest.php index 2ed1b69..3039107 100644 --- a/tests/TocifierTest.php +++ b/tests/TocifierTest.php @@ -28,18 +28,19 @@ public function testProcess() public function testPrependAnchor() { $tocifier = new Tocifier(file_get_contents(__DIR__ . '/test1')); - $this->assertEquals($tocifier->getHtml(), ''); - $this->assertTrue($tocifier->process()); + $this->assertEquals('', $tocifier->getHtml()); - // The default augmenting method should already be prependAnchor + $tocifier->setAugmentCallback(array('\eNTiDi\Autotoc\Tocifier', 'prependAnchor')); + $this->assertTrue($tocifier->process()); $this->assertStringEqualsFile(__DIR__ . '/html1', $tocifier->getHtml()); } public function testSetId() { $tocifier = new Tocifier(file_get_contents(__DIR__ . '/test1')); - $tocifier->setAugmentCallback(array('\eNTiDi\Autotoc\Tocifier', 'setId')); - $this->assertEquals($tocifier->getHtml(), ''); + $this->assertEquals('', $tocifier->getHtml()); + + // The default augmenting method should already be setId $this->assertTrue($tocifier->process()); $this->assertStringEqualsFile(__DIR__ . '/html2', $tocifier->getHtml()); } @@ -47,7 +48,7 @@ public function testSetId() public function testTOC() { $tocifier = new Tocifier(file_get_contents(__DIR__ . '/test1')); - $this->assertEquals($tocifier->getTOC(), array()); + $this->assertEquals(array(), $tocifier->getTOC()); $this->assertTrue($tocifier->process()); $this->assertNotNull($tocifier->getTOC()); @@ -60,7 +61,7 @@ public function testTOC() public function testDataHideFromTOC() { $tocifier = new Tocifier(file_get_contents(__DIR__ . '/test2')); - $this->assertEquals($tocifier->getHtml(), ''); + $this->assertEquals('', $tocifier->getHtml()); $this->assertTrue($tocifier->process()); // Check the augmented HTML is equal to the original one From b038d0a020dabef8859666c866becb16457bc280 Mon Sep 17 00:00:00 2001 From: Nicola Fontana Date: Fri, 29 Dec 2017 00:49:17 +0100 Subject: [PATCH 21/26] Move templates in namespaced directories --- templates/{Includes => eNTiDi/Autotoc}/Autotoc.ss | 0 templates/{Includes => eNTiDi/Autotoc}/AutotocItem.ss | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename templates/{Includes => eNTiDi/Autotoc}/Autotoc.ss (100%) rename templates/{Includes => eNTiDi/Autotoc}/AutotocItem.ss (100%) diff --git a/templates/Includes/Autotoc.ss b/templates/eNTiDi/Autotoc/Autotoc.ss similarity index 100% rename from templates/Includes/Autotoc.ss rename to templates/eNTiDi/Autotoc/Autotoc.ss diff --git a/templates/Includes/AutotocItem.ss b/templates/eNTiDi/Autotoc/AutotocItem.ss similarity index 100% rename from templates/Includes/AutotocItem.ss rename to templates/eNTiDi/Autotoc/AutotocItem.ss From b57e3f1743d472fc27fc6f15041555a3ae137763 Mon Sep 17 00:00:00 2001 From: Nicola Fontana Date: Fri, 29 Dec 2017 00:59:42 +0100 Subject: [PATCH 22/26] Improve README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 83823eb..e4be8d4 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ silverstripe-autotoc Automatically generate the table of contents from the *Content* of a page or, more generally, from any HTML field. +This module can be used without the CMS. + Installation ------------ @@ -15,8 +17,6 @@ Installation Manual installation is probably possible but not really tested. -This module can be used without the CMS. - Testing ------- From 4d7cbf61a27b6ecd5cb920717c38f92bb3b92e14 Mon Sep 17 00:00:00 2001 From: Nicola Fontana Date: Fri, 29 Dec 2017 10:11:55 +0100 Subject: [PATCH 23/26] Update gitattributes --- .gitattributes | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.gitattributes b/.gitattributes index 556e2c7..e92dc19 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,7 @@ -/docs export-ignore -/tests export-ignore -/.travis.yml export-ignore +docs/ export-ignore +tests/ export-ignore +*.dist +.editorconfig export-ignore +.gitattributes export-ignore +.scrutinizer.yml export-ignore +.travis.yml export-ignore From d3fb711af265cfbcb38cd9e557e5b7cfa94eeb43 Mon Sep 17 00:00:00 2001 From: Nicola Fontana Date: Fri, 29 Dec 2017 10:12:11 +0100 Subject: [PATCH 24/26] Add link to standard code of conduct --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e4be8d4..0825312 100644 --- a/README.md +++ b/README.md @@ -29,8 +29,9 @@ Other documentation ------------------- * [Usage](docs/en/usage.md) -* [AutoTOC format](docs/en/format.md) +* [Autotoc format](docs/en/format.md) * [Contributing](CONTRIBUTING.md) +* [Code of Conduct](https://docs.silverstripe.org/en/contributing/code_of_conduct) * [BSD license](LICENSE.md) * [ChangeLog](CHANGELOG.md) * [Support](docs/en/support.md) From 15636962fa8a59891458bbefb457748229a8cd8c Mon Sep 17 00:00:00 2001 From: Nicola Fontana Date: Fri, 29 Dec 2017 10:18:44 +0100 Subject: [PATCH 25/26] Use short hashes in docs --- CHANGELOG.md | 74 ++++++++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 86e7669..ed8c20c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,68 +7,68 @@ of this ChangeLog is autogenerated by the following command: git log \ --no-merges \ --date=format:'%Y-%m-%d' \ - --pretty=format:'* %cd %H %s' \ + --pretty=format:'* %cd %h %s' \ $(git ls-remote -t .|tail -1|cut -f1).. ### 1.2.0 (2016-08-03) -* 2016-08-04 e8eaecdef76f7af315ab0678508133db1a6ac1d6 Change default anchor method to setId +* 2016-08-04 e8eaecd Change default anchor method to setId ### 1.1.3 (2016-08-03) -* 2016-07-22 1ec20086c0e0b1eae290d3fb801f4e45712c71ed Allow customization of augmenting method +* 2016-07-22 1ec2008 Allow customization of augmenting method ### 1.1.2 (2016-05-26) -* 2016-05-26 cd1e45c82ceef1ace0e781b95e3102ca06b12cab Add CHANGELOG.md -* 2016-05-26 1bf8d5c77870d4530fc90517052c3525facc5dc7 Exclude docs from gitattributes -* 2016-05-26 d164ca96bce0068e9e0eb933fa6eaeea5a6bdf74 Correct documentation link -* 2016-05-26 2ecbf535ff5621a9b8c3252c44c1b505fc042c8b Reorganize documentation -* 2016-05-06 2bc6fca0b3dc03604d7e81fe5ef15714a3d31442 Trying to improve Scrutinizr ranking +* 2016-05-26 cd1e45c Add CHANGELOG.md +* 2016-05-26 1bf8d5c Exclude docs from gitattributes +* 2016-05-26 d164ca9 Correct documentation link +* 2016-05-26 2ecbf53 Reorganize documentation +* 2016-05-06 2bc6fca Trying to improve Scrutinizr ranking ### 1.1.1 (2016-05-06) -* 2016-05-06 2afe181dac53417957eabcb3f7b87e7be4420a0d Remove some redundancy from XPath expression -* 2016-05-06 4ba8f02c2d8577ded81bbfe040195b3be7ad3c71 Add tests for data-hide-from-toc -* 2016-05-06 b39695adc0a1bd547d5c0423ddd64dd54bbf10a2 Avoid bogus \n when augmenting the HTML -* 2016-05-06 e296a3dbe580730d1c21076e9c55e43822e2d3bb Added standard Scrutinizer config -* 2016-05-06 1d2c7d2b347dd1360f8fa0bd5ff28785641c457c Allow easy testing from CLI -* 2016-05-06 1bd030b1ce5c1824c858107c09de273fcecc54e5 Added minimum PHP version requirement. -* 2016-05-03 a71b0b9bf77370c8f514332430dd75a3f0b0fbde Added `data-hide-from-toc` attribute to ToC query. -* 2016-02-09 b6d81addeca6ffc35c7c802573fd3b49b6c0c70c Update copyright for 2016 -* 2016-02-08 28d52d41bc978c434011278008831ad72bdcdec4 Add Scrutinizer badge to README.md -* 2016-01-16 0ca6cee029dff02784f8398afd045b64ee5b30db Added standard .gitattributes file +* 2016-05-06 2afe181 Remove some redundancy from XPath expression +* 2016-05-06 4ba8f02 Add tests for data-hide-from-toc +* 2016-05-06 b39695a Avoid bogus \n when augmenting the HTML +* 2016-05-06 e296a3d Added standard Scrutinizer config +* 2016-05-06 1d2c7d2 Allow easy testing from CLI +* 2016-05-06 1bd030b Added minimum PHP version requirement. +* 2016-05-03 a71b0b9 Added `data-hide-from-toc` attribute to ToC query. +* 2016-02-09 b6d81ad Update copyright for 2016 +* 2016-02-08 28d52d4 Add Scrutinizer badge to README.md +* 2016-01-16 0ca6cee Added standard .gitattributes file ### 1.1.0 (2016-01-09) -* 2016-01-09 341eab334463753b73885fb883724ca8bc395dac Add TravisCI badge in README.md -* 2016-01-09 2218f7f071d645aec0a2dabb225f4a5cd0303986 Correct README.md typo -* 2016-01-09 f48cfcaf3d9686c71a5069935e10c9c057e064d7 Add Packagist stable version badge to README.md -* 2016-01-09 3c97621145fe6f4eda973d8a9022643b908f8c0e Improve README.md -* 2016-01-09 824fe2f791eedd652280fb94d5de43f4707eff5c Improve tests interoperability -* 2016-01-08 91f231c8ccc91282f902e30b96803e9d045168af Tocify custom field instead of Content -* 2016-01-08 e986d312841d0903596d7f376861fa661ed53c6d Empty lines after class are not needed in PSR-2 mode -* 2016-01-08 ad7896938d0810116db00648454e7de1b00b00f7 Enhance composer.json -* 2016-01-08 8ddd4459b69519e4f824658e58bfaa417d5d7537 Use YAML for configuration -* 2016-01-01 d5a78a5b094db5d27f4fbadc086c27ba8d9b8f54 Converted to PSR-2 -* 2016-01-01 f06546b9387424d32f0274ad841c6920fff9a4f6 Added standard Travis config -* 2015-12-17 279fa104456e0e68ded252d245d5b84456d51d74 Added standard .editorconfig file +* 2016-01-09 341eab3 Add TravisCI badge in README.md +* 2016-01-09 2218f7f Correct README.md typo +* 2016-01-09 f48cfca Add Packagist stable version badge to README.md +* 2016-01-09 3c97621 Improve README.md +* 2016-01-09 824fe2f Improve tests interoperability +* 2016-01-08 91f231c Tocify custom field instead of Content +* 2016-01-08 e986d31 Empty lines after class are not needed in PSR-2 mode +* 2016-01-08 ad78969 Enhance composer.json +* 2016-01-08 8ddd445 Use YAML for configuration +* 2016-01-01 d5a78a5 Converted to PSR-2 +* 2016-01-01 f06546b Added standard Travis config +* 2015-12-17 279fa10 Added standard .editorconfig file ### 1.0.3 (2014-02-20) -* 2014-02-20 e3a45766fa4e217378b4b2b90ab2da52beebe38e Do not handle $Content if does not exist -* 2014-01-18 4a98c25c40fbad4b0bf40963da543d148f130136 Improve composer.json compatibility -* 2014-01-06 1768739e46d796eaa52138e8689214df587b98e0 Revert "Use a less verbose package name" -* 2014-01-06 9a950978f04cfae7a72f6e7de4f4dca89b1d607a Use a less verbose package name +* 2014-02-20 e3a4576 Do not handle $Content if does not exist +* 2014-01-18 4a98c25 Improve composer.json compatibility +* 2014-01-06 1768739 Revert "Use a less verbose package name" +* 2014-01-06 9a95097 Use a less verbose package name ### 1.0.2 (2013-12-23) -* 2013-12-23 64f22e881d6036adfe1e4a6f9ea6c323d986d8fa Use proper license in composer.json -* 2013-12-23 f7ce9f35beda9c7460976bfda08c599abafd2d6b Add missing comma to composer.json +* 2013-12-23 64f22e8 Use proper license in composer.json +* 2013-12-23 f7ce9f3 Add missing comma to composer.json ### 1.0.1 (2013-12-23) -* 2013-12-23 e3719f095606eeb34f4fc01a4522b6cefb2217f6 Cite silverstrap as compatible theme in composer +* 2013-12-23 e3719f0 Cite silverstrap as compatible theme in composer ### 1.0.0 (2013-12-23) From d9bc20cf872a26aa87f50d12fb332fa624e6707e Mon Sep 17 00:00:00 2001 From: Nicola Fontana Date: Fri, 29 Dec 2017 10:20:18 +0100 Subject: [PATCH 26/26] Update CHANGELOG --- CHANGELOG.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed8c20c..a473ec2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,35 @@ of this ChangeLog is autogenerated by the following command: --pretty=format:'* %cd %h %s' \ $(git ls-remote -t .|tail -1|cut -f1).. +### 2.0.0 (2017-12-29) + +* 2017-12-29 1563696 Use short hashes in docs +* 2017-12-29 d3fb711 Add link to standard code of conduct +* 2017-12-29 4d7cbf6 Update gitattributes +* 2017-12-29 b57e3f1 Improve README +* 2017-12-29 b038d0a Move templates in namespaced directories +* 2017-12-29 ce1f91c Major refactoring for SS4 +* 2017-12-21 b231412 Fix Tocifier instantiation call +* 2017-12-21 94378c6 Use the injector for instantiating the Tocifier +* 2017-12-21 a0a809c Add missing namespace to default augment callback +* 2017-12-21 f206387 Fix minor bugs in AutotocExtension +* 2017-12-20 f6bd258 Fix YAML configuration +* 2017-12-20 72daf19 Remove silverstripe recipe from composer +* 2017-12-20 6fd6dc4 Strip project-files-installed from composer.json +* 2017-12-20 7b4096f Restore old package name +* 2017-12-20 3d9ed8c Fix issue highlighted by phpcs +* 2017-12-20 e7bc91a Add support for PHP CodeSniffer +* 2017-12-20 c0349ff Update composer and scrutinizer according to mainline +* 2017-12-20 75aac40 Set minimum-stability to dev +* 2017-12-20 02dba28 Fix path in scrutinizer YAML +* 2017-12-20 9ebe50c Update travis infrastructure for SS4 +* 2017-12-20 71ddc55 Fix Travis issue on old supported PHP +* 2017-12-20 2a9feb7 Update codebase for PHP 7 +* 2017-12-19 40f8676 Initial porting to SilverStripe 4 +* 2017-12-19 09443ea Update copyright in LICENSE.md +* 2017-03-19 30a2a3d Doc fix: the default augmenter is now setId() +* 2016-08-04 5bc2a28 Scrutinizer Auto-Fixes + ### 1.2.0 (2016-08-03) * 2016-08-04 e8eaecd Change default anchor method to setId