From ad98e782e2bd9f6ba3e7c8dcc24288d48d4b4498 Mon Sep 17 00:00:00 2001 From: LarsDW223 Date: Mon, 5 Jun 2017 18:59:19 +0200 Subject: [PATCH 1/4] Added option to stop inclusion of page content at a certain point. This can be done by using the syntax tag '{{includestop}}' or by using the flag 'length'. E.g. if 'length=1000' is set, then only 1000 signs of a page will be included, counted is only cdata content. --- helper.php | 132 ++++++++++++++++++++++++++++++++++++++++++++++++ syntax/stop.php | 65 ++++++++++++++++++++++++ 2 files changed, 197 insertions(+) create mode 100644 syntax/stop.php diff --git a/helper.php b/helper.php index f693e9a..c7d5503 100644 --- a/helper.php +++ b/helper.php @@ -224,6 +224,9 @@ function get_flags($setflags) { case 'noreadmore': $flags['readmore'] = 0; break; + case 'length': + $flags['length'] = max(intval($value), 0); + break; } } // the include_content URL parameter overrides flags @@ -232,6 +235,131 @@ function get_flags($setflags) { return $flags; } + /** + * Shortens page instructions if it finds a 'includestop' + * or content is longer than $flags['length']. + */ + protected function _shorten_instructions(&$ins, $flags) { + // Cut off page content if required + $length = $flags['length']; + $stop = false; + $tr_closed = false; + $t_closed = false; + $li_closed = false; + $l_closed = false; + $max_entries = count($ins); + $sum = 0; + + for ($index = 0 ; $index < $max_entries ; $index++) { + $entry = &$ins[$index]; + switch ($entry[0]) { + case 'plugin': + if ($entry[1][0] == 'include_stop') { + $stop = true; + unset($ins[$index]); + } + break; + case 'cdata': + $entryLength = strlen($entry[1][0]); + if (!$stop && $sum+$entryLength > $length) { + if ($sum < $length) { + $max = $length - $sum; + $entry[1][0] = substr ($entry[1][0], 0, $max).'...'; + $sum = $length; + $stop = true; + } else { + unset($ins[$index]); + } + } else { + if ($stop) { + unset($ins[$index]); + } + } + $sum += $entryLength; + break; + case 'tablerow_close': + if ($stop) { + if ($t_closed || $tr_closed) { + unset ($ins[$index]); + } else { + $tr_closed = true; + } + } + break; + case 'table_close': + if ($stop) { + if ($t_closed) { + unset ($ins[$index]); + } else { + $t_closed = true; + } + } + break; + case 'table_open': + case 'tablerow_open': + case 'tablethead_open': + case 'tableheader_open': + if ($stop) { + unset ($ins[$index]); + } + break; + case 'tablethead_close': + case 'tableheader_close': + case 'tablecell_open': + case 'tablecell_close': + if ($t_closed || $tr_closed) { + unset ($ins[$index]); + } + break; + case 'listitem_close': + if ($stop) { + if ($l_closed || $li_closed) { + unset ($ins[$index]); + } else { + $li_closed = true; + } + } + break; + case 'listu_close': + case 'listo_close': + if ($stop) { + if ($l_closed) { + unset ($ins[$index]); + } else { + $l_closed = true; + } + } + break; + case 'listu_open': + case 'listo_open': + case 'listitem_open': + if ($stop) { + unset ($ins[$index]); + } + break; + case 'listcontent_open': + case 'listcontent_close': + if ($l_closed || $li_closed) { + unset ($ins[$index]); + } + break; + case 'section_close': + if ($stop) { + // Delete everything behind this point + for ($del = $index++ ; $del < $max_entries ; $del++) { + unset($ins[$del]); + } + // Leave switch and for loop! + break 2; + } + break; + } + } + + // Return if content was cut of or not + return $stop; + } + /** * Returns the converted instructions of a give page/section * @@ -278,6 +406,10 @@ function _get_instructions($page, $sect, $mode, $lvl, $flags, $root_id = null, $ $this->_convert_instructions($ins, $lvl, $page, $sect, $flags, $root_id, $included_pages); } + + if ($this->_shorten_instructions($ins, $flags) && $flags['readmore']) { + $ins[] = array('plugin', array('include_readmore', array($page))); + } return $ins; } diff --git a/syntax/stop.php b/syntax/stop.php new file mode 100644 index 0000000..eb26103 --- /dev/null +++ b/syntax/stop.php @@ -0,0 +1,65 @@ +Lexer->addSpecialPattern("{{includestop}}", $mode, 'plugin_include_stop'); + } + + /** + * Handle syntax matches + * + * @param string $match The current match + * @param int $state The match state + * @param int $pos The position of the match + * @param Doku_Handler $handler The hanlder object + * @return array The instructions of the plugin + */ + function handle($match, $state, $pos, Doku_Handler $handler) { + return true; + } + + /** + * Renders the include stop - dummy. + * 'includestop' is handled in helper_plugin_include::_shorten_instructions() + */ + function render($format, Doku_Renderer $renderer, $data) { + return true; + } +} +// vim:ts=4:sw=4:et: From f68c3724a59d0db7bdad723fc446ddd5f2fde4b6 Mon Sep 17 00:00:00 2001 From: LarsDW223 Date: Mon, 5 Jun 2017 20:51:35 +0200 Subject: [PATCH 2/4] Check if flag 'length' is set and ignore it if not. Fixes broken unit tests. --- helper.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/helper.php b/helper.php index c7d5503..b7b6132 100644 --- a/helper.php +++ b/helper.php @@ -241,7 +241,10 @@ function get_flags($setflags) { */ protected function _shorten_instructions(&$ins, $flags) { // Cut off page content if required - $length = $flags['length']; + $length = false; + if (!empty($flags['length'])) { + $length = $flags['length']; + } $stop = false; $tr_closed = false; $t_closed = false; @@ -261,7 +264,7 @@ protected function _shorten_instructions(&$ins, $flags) { break; case 'cdata': $entryLength = strlen($entry[1][0]); - if (!$stop && $sum+$entryLength > $length) { + if (!$stop && $length !== false && $sum+$entryLength > $length) { if ($sum < $length) { $max = $length - $sum; $entry[1][0] = substr ($entry[1][0], 0, $max).'...'; From 314291da98884cae496265294f75660451abaaa7 Mon Sep 17 00:00:00 2001 From: LarsDW223 Date: Mon, 5 Jun 2017 21:43:00 +0200 Subject: [PATCH 3/4] Added test cases for nested includes with cut off content using '{{includestop}}'. --- _test/nested_include.test.php | 41 ++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/_test/nested_include.test.php b/_test/nested_include.test.php index f577388..6321e6c 100644 --- a/_test/nested_include.test.php +++ b/_test/nested_include.test.php @@ -34,7 +34,23 @@ public function test_inner_to_outer() { $this->_validateContent($mainHTML, $secondHTML, $thirdHTML); } - private function _validateContent($mainHTML, $secondHTML, $thirdHTML) { + public function test_outer_to_inner_cut_off() { + $this->_createCutOffPages(); + $mainHTML = p_wiki_xhtml('test:plugin_include:nested:start'); + $secondHTML = p_wiki_xhtml('test:plugin_include:nested:second'); + $thirdHTML = p_wiki_xhtml('test:plugin_include:nested:third'); + $this->_validateContent($mainHTML, $secondHTML, $thirdHTML, true); + } + + public function test_inner_to_outer_cut_off() { + $this->_createCutOffPages(); + $thirdHTML = p_wiki_xhtml('test:plugin_include:nested:third'); + $secondHTML = p_wiki_xhtml('test:plugin_include:nested:second'); + $mainHTML = p_wiki_xhtml('test:plugin_include:nested:start'); + $this->_validateContent($mainHTML, $secondHTML, $thirdHTML, true); + } + + private function _validateContent($mainHTML, $secondHTML, $thirdHTML, $cutOff=false) { $this->assertTrue(strpos($mainHTML, 'Main Content') !== false, 'Main content contains "Main Content"'); $this->assertTrue($this->_matchHeader('1', 'Main Test Page', $mainHTML), 'Main page header is h1'); $this->assertTrue(strpos($mainHTML, 'Second Content') !== false, 'Main content contains "Second Content"'); @@ -47,6 +63,11 @@ private function _validateContent($mainHTML, $secondHTML, $thirdHTML) { $this->assertTrue($this->_matchHeader('2', 'Third Test Page', $secondHTML), 'Third page header on second page is h2'); $this->assertTrue(strpos($thirdHTML, 'Third Content') !== false, 'Third content contains "Third Content"'); $this->assertTrue($this->_matchHeader('1', 'Third Test Page', $thirdHTML), 'Third page header on third page is h1'); + if ($cutOff) { + $this->assertTrue(strpos($mainHTML, 'this-should-be-cut-off') === false, 'Main content contains "this-should-be-cut-off"'); + $this->assertTrue(strpos($mainHTML, 'this-should-be-included2') !== false, 'Main content does not contain "this-should-be-included2"'); + $this->assertTrue(strpos($mainHTML, 'this-should-be-included3') !== false, 'Main content does not contain "this-should-be-included3"'); + } } private function _matchHeader($level, $text, $html) { @@ -70,5 +91,23 @@ private function _createPages() { .'{{page>third}}'.DOKU_LF, 'setup for test'); } + + private function _createCutOffPages() { + saveWikiText('test:plugin_include:nested:start', + '====== Main Test Page ======'.DOKU_LF.DOKU_LF + .'Main Content'.rand().DOKU_LF.DOKU_LF + .'{{page>second}}'.DOKU_LF, + 'setup for test'); + saveWikiText('test:plugin_include:nested:second', + '====== Second Test Page ======'.DOKU_LF.DOKU_LF + .'Second Content'.rand().DOKU_LF.DOKU_LF + .'{{page>third}}this-should-be-included2{{includestop}} this-should-be-cut-off'.DOKU_LF, + 'setup for test'); + saveWikiText('test:plugin_include:nested:third', + '====== Third Test Page ======'.DOKU_LF.DOKU_LF + .'Third Content'.rand().DOKU_LF.DOKU_LF + .'{{page>third}}this-should-be-included3{{includestop}} this-should-be-cut-off'.DOKU_LF, + 'setup for test'); + } } From 09505cb3e5c28221a180b941a15eda1718464239 Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Sun, 15 Apr 2018 18:17:34 +0200 Subject: [PATCH 4/4] Add link test to cut-off test --- _test/nested_include.test.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_test/nested_include.test.php b/_test/nested_include.test.php index 6321e6c..9e411b6 100644 --- a/_test/nested_include.test.php +++ b/_test/nested_include.test.php @@ -101,12 +101,12 @@ private function _createCutOffPages() { saveWikiText('test:plugin_include:nested:second', '====== Second Test Page ======'.DOKU_LF.DOKU_LF .'Second Content'.rand().DOKU_LF.DOKU_LF - .'{{page>third}}this-should-be-included2{{includestop}} this-should-be-cut-off'.DOKU_LF, + .'{{page>third}}this-should-be-included2{{includestop}} this-should-be-cut-off [[this-should-be-cut-off]]'.DOKU_LF, 'setup for test'); saveWikiText('test:plugin_include:nested:third', '====== Third Test Page ======'.DOKU_LF.DOKU_LF .'Third Content'.rand().DOKU_LF.DOKU_LF - .'{{page>third}}this-should-be-included3{{includestop}} this-should-be-cut-off'.DOKU_LF, + .'{{page>third}}this-should-be-included3{{includestop}} this-should-be-cut-off [[this-should-be-cut-off]]'.DOKU_LF, 'setup for test'); } }