Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added option to stop inclusion of page content at a certain point. #210

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 40 additions & 1 deletion _test/nested_include.test.php
Original file line number Diff line number Diff line change
Expand Up @@ -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"');
Expand All @@ -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) {
Expand All @@ -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');
}
}

135 changes: 135 additions & 0 deletions helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -232,6 +235,134 @@ 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 = false;
if (!empty($flags['length'])) {
$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 && $length !== false && $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
*
Expand Down Expand Up @@ -278,6 +409,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;
}

Expand Down
65 changes: 65 additions & 0 deletions syntax/stop.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php
/**
* Include Plugin: displays a wiki page within another
* Usage:
* {{includestop}} stop including the current page at this point
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/

if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
require_once(DOKU_PLUGIN.'syntax.php');

/**
* All DokuWiki plugins to extend the parser/rendering mechanism
* need to inherit from this class
*/
class syntax_plugin_include_stop extends DokuWiki_Syntax_Plugin {

/**
* Get syntax plugin type.
*
* @return string The plugin type.
*/
function getType() { return 'formatting'; }

/**
* Get sort order of syntax plugin.
*
* @return int The sort order.
*/
function getSort() { return 303; }

/**
* Connect patterns/modes
*
* @param $mode mixed The current mode
*/
function connectTo($mode) {
$this->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: