The NL2BR Plugin acts a little strange between the introduction and extended part of an article. In the general template for the extended view, both parts are in separate <div> containers, so it is not possible to continue the extended part in the last line of the introduction, if you don't want a break there.
Then, the plugin removes one newline at the end of the data, so you have to add three newlines to get a big break between both article parts. In the article overview, that doesn't look good because you've then the break between the introduction and the "continue reading ..." line.
Is anybody here who knows the code of this plugin inside out and can work on a fix? Otherwise, i have to try that myself. The best solution would be to change the general template for the extended view that both article parts would be inside <span> containers, but only one shared <div> container, so the extended parts continues in the same line if you do nothing (no newlines at all). The main problem seems, that the plugin cannot know if an extension is following and with <p> tags, you have to change the tag of the introduction to add a margin on the bottom of the introduction if there are newlines at the beginning of the extended part. The other way round is not better, because then it should have a margin when an extension follows and no when a "continue reading" is following. I have to work that out if nobody else does ...
NL2BR and extended article
Re: NL2BR and extended article
I don't really get what is the issue here. Can you give an example what you would want to do here? Also, can you please provide a URL to the blog so that we can have a look at what we're dealing with here?stephanbrunker wrote:In the general template for the extended view, both parts are in separate <div> containers, so it is not possible to continue the extended part in the last line of the introduction, if you don't want a break there.
You're not actually supposed to use newlines for visual styles, that's what CSS is for. That being said, it is kind of hard to apply CSS to text generated using NL2BR since NL2BR doesn't really structure text. But either way, if you want vertical space between entry and extended entry, but not in the article list, you should to that by giving the extended entry's wrapper div margin-top using CSS.stephanbrunker wrote:Then, the plugin removes one newline at the end of the data, so you have to add three newlines to get a big break between both article parts.
stephanbrunker wrote:The best solution would be to change the general template for the extended view that both article parts would be inside <span> containers, but only one shared <div> container, so the extended parts continues in the same line if you do nothing (no newlines at all).]/quote]
You can do that using CSS as well, by the way. A div container has display: block; per default, changing that do display: inline-block; for these two wrapper divs should give you the same result.
That being said, I don't see a need for a "fix" here, just a very, very special use case in a rarely used plugin. (I'll admit I'm not a fan of NL2BR since it kind of promotes bad markup, though.)
YL
-
- Regular
- Posts: 23
- Joined: Sat Nov 25, 2017 12:08 am
Re: NL2BR and extended article
Okay, if there is another way to get what I want instead of the NL2BR (was it in the standard setup?), i don't say no. Basically, I want my paragraphs in <p> containers and a markup to do that in the editor. But if possible, that i have not to define explicit every paragraph.
The problem in pictures:
I don't want a break in the article listing: But then you also don't have one in the extended view, except of the CRLF with the new <div> even if you have two newlines in the editor:
The problem in pictures:
I don't want a break in the article listing: But then you also don't have one in the extended view, except of the CRLF with the new <div> even if you have two newlines in the editor:
Last edited by stephanbrunker on Sat Nov 25, 2017 6:32 pm, edited 2 times in total.
-
- Regular
- Posts: 23
- Joined: Sat Nov 25, 2017 12:08 am
Re: NL2BR and extended article
And that is the html output if you use NL2BR to generate <p> tags:
Any other plugins to generate paragraphs easily like writing this post in the forum? <p></p> will work, but it is not really positive to a fluid writing.
And as I wrote, the class "break" for the first part of the body is just wrong, because it does that break anyway because of the </div>. There sould be a class "whiteline", but only if an <div ... extended> is following.
there is always that newline coming with the <div ... id="extended"> for the extended part of the content. Any other plugins to generate paragraphs easily like writing this post in the forum? <p></p> will work, but it is not really positive to a fluid writing.
And as I wrote, the class "break" for the first part of the body is just wrong, because it does that break anyway because of the </div>. There sould be a class "whiteline", but only if an <div ... extended> is following.
-
- Regular
- Posts: 23
- Joined: Sat Nov 25, 2017 12:08 am
Re: NL2BR and extended article
I worked it out:
I created a pull request on Github and now i'm very curious if it is going to be accepted or not. Normally nobody wants me to fix something
I changed only the nl to <p> part. The body part has now always the <p class="break"> as last one, e.g. has no margin at the bottom, so you can change that globally with the CSS if you want, equally for extended and not extended articles. If you put a newline at the end of the body or at the beginning of the extended part, a margin is added at the first paragraph of the extended part with the classes "newlinetopbottom" or "newlinetop" . The only thing what wasn't possible is to continue the extended part in the same line because that would be incompatible with caching, because at compiletime the plugin cannot know if the extended part is following or not and for that, you'd have to add the closing </p> dynamically. I created a pull request on Github and now i'm very curious if it is going to be accepted or not. Normally nobody wants me to fix something
Re: NL2BR and extended article
Option A: Keep using NL2BR (I'm not a fan of it), but switch it to use the NL2P option. That does just that – basically, instead of inserting <br> elements where you create line breaks, it creates the proper <p> elements.stephanbrunker wrote:Okay, if there is another way to get what I want instead of the NL2BR (was it in the standard setup?), i don't say no. Basically, I want my paragraphs in <p> containers and a markup to do that in the editor.
Option B: Switch to the Markdown plugin instead. (Offers more possibilities.)
Option C: (not sure if you ruled that out before) Use the WYSIWYG editor. (In that case, disable NL2BR for entries and extended entries, but keep it – or use Markdown instead – for comments.)
As I stated before, line breaks and converting them to either <br> or <p> is not really the proper way to implement this anymore.stephanbrunker wrote:I don't want a break in the article listing:
If I was to put into words what you're trying to do, I'd say: "Have a clearly visibly margin between entry and extended entry if both are visible." That only happens if the div with the id="extended" is emitted (which is single entry view), so I'd give that container a top margin using CSS:
Code: Select all
#extended {
margin-top: 1em;
}
Personally, I don't think a plugin like this should need configuring, it should "just work", which is why I always suggest using the Markdown plugin instead. However, Markdown is not quite as intuitive (because it offers more flexibility).
Just know that if your PR is not accepted, it might just be because no one really sees the need for this fix which, as far as I can tell, is tailored to your very specific needs. It is definitely not because we "don't want you to fix something". On the contrary, we welcome every contribution to s9y – we just have to decide what is actually worth putting in the core.
YL
-
- Regular
- Posts: 23
- Joined: Sat Nov 25, 2017 12:08 am
Re: NL2BR and extended article
So, I spent some time with that plugin and improved it to "does simply work". I didn't count the hours ...
Basically, i left the nl2br untouched and upgraded the nl2p version to something which is universally usable. Means: if you write simple text, it formats the article with paragraphs, depending on your newlines. That did it before ... more or less. But now, it also can digest any html input, and that according to the specifications. So, out of:
it generates this output:
The CSS would be accordingly with margin on top,bottom, both or none(=break).
If you want to test it, i put the core into a short demonstration of the html coding:
http://s521456705.online.de/webspace/testnl2br.php
I also rejuvenated the isolation tag feature, this was not working with nl2p (contrary to the description), in the demonstrator it is <nl>, in the plugin it gets the tags from the config.
This extended version makes paragraphs only where they are allowed, simply put. You can even make the Tags in Uppercase, or insert white spaces ... It is open to discussion if it should automatically delete the last nl in the article / extended article or push that newline from article to extended, but the core is the formatting of plain text seasoned with html tags.
I've not put it into a second Pull Request yet, because it's too late and I have to tidy up the code a bit.
So, it does what it should better than before, it extends the functionality of something existing without breaking the previous functionality and i'm really tired if nobody appreciates that. Because there is simply no reason why it shouldn't be integrated in the core and that happened too often to me in the past, so that I even wrote a post about that: http://www.intjblog.de/index.php?/archi ... Hilfe.html
Oh, and because the plugin now splits the text into content and html tags and keeps a stack of the active tags, it wouldn't be that much work to automatically fix overlappings, like a <p> inside a <em>. According to the specs, the paragraph closes the inline element, and now it is easily possible to close the inline element before and open it again on the new paragraph. Not implemented yet, but the structure now allows that. If somebody wants that. I think that not everyone wants to use a full-fledged WYSIWYG-Editor and the standard interface uses html tags and you need simply something to make your paragraphs, because I don't want to write all the <p> tags by hand.
But the preliminary version is like this:
Basically, i left the nl2br untouched and upgraded the nl2p version to something which is universally usable. Means: if you write simple text, it formats the article with paragraphs, depending on your newlines. That did it before ... more or less. But now, it also can digest any html input, and that according to the specifications. So, out of:
Code: Select all
this is some text
next line
<div>
<ol>
<li>first point
<li>second point
no paragraphs allowed in ol
</ol>
</div>
some text
with break
Code: Select all
<p_class="wl_bottom">this is some text</p>
<p_class="wl_bottom">next line</p>
<div>
<ol>
<li>first point
<li>second point
no paragraphs allowed in ol
</ol>
</div>
<p class="wl_top">some text</p>
<p class="break">with break</p>
If you want to test it, i put the core into a short demonstration of the html coding:
http://s521456705.online.de/webspace/testnl2br.php
I also rejuvenated the isolation tag feature, this was not working with nl2p (contrary to the description), in the demonstrator it is <nl>, in the plugin it gets the tags from the config.
This extended version makes paragraphs only where they are allowed, simply put. You can even make the Tags in Uppercase, or insert white spaces ... It is open to discussion if it should automatically delete the last nl in the article / extended article or push that newline from article to extended, but the core is the formatting of plain text seasoned with html tags.
I've not put it into a second Pull Request yet, because it's too late and I have to tidy up the code a bit.
So, it does what it should better than before, it extends the functionality of something existing without breaking the previous functionality and i'm really tired if nobody appreciates that. Because there is simply no reason why it shouldn't be integrated in the core and that happened too often to me in the past, so that I even wrote a post about that: http://www.intjblog.de/index.php?/archi ... Hilfe.html
Oh, and because the plugin now splits the text into content and html tags and keeps a stack of the active tags, it wouldn't be that much work to automatically fix overlappings, like a <p> inside a <em>. According to the specs, the paragraph closes the inline element, and now it is easily possible to close the inline element before and open it again on the new paragraph. Not implemented yet, but the structure now allows that. If somebody wants that. I think that not everyone wants to use a full-fledged WYSIWYG-Editor and the standard interface uses html tags and you need simply something to make your paragraphs, because I don't want to write all the <p> tags by hand.
But the preliminary version is like this:
Code: Select all
// following w3.org, these elements close p elements automatically:
var $block_elements = array('table','ul','ol','pre', 'dl',
'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
'menu', 'section',
'address', 'article', 'aside', 'fieldset', 'footer',
'form', 'header', 'hgroup', 'hr', 'main', 'nav', 'p'
);
var $nested_block_elements = array('div','table','blockquote');
/* paragraphs aren't allowed in these inline elements -> p closes these elements:
* var $inline_elements = array('b', 'big', 'i', 'small', 'tt', 'abbr',
'acronym', 'cite', 'code', 'dfn', 'em', 'kbd', 'strong',
'samp', 'var', 'a', 'bdo', 'br', 'map', 'object',
'q', 'script', 'span', 'sub', 'sup', 'button',
'label', 'select', 'textarea'
); */
var $allowed_p_parents = array('blockquote', 'td', 'div', 'article', 'aside', 'dd',
'details', 'dl', 'dt', 'footer', 'header', 'summary'
);
/** Make sure that all the tags are in lowercase
* @param string text
* @return text
*/
function tag_tolower($textstring)
{
$text = str_split($textstring);
$tag = false;
for ($i = 0; $i < count($text); $i++)
{
if ($text[$i] == '<' ) { $tag = true; }
elseif ($tag && ($text[$i] == ' ' || $text[$i] == '>') )
{ $tag = false; }
elseif ($tag)
{ $text[$i] = strtolower($text[$i]); }
}
return implode($text);
}
/**
* remove spaces in end tags
* @param string text
* @return text
*/
function trim_end_tags($textstring)
{
$text = str_split($textstring);
$endtag = false;
for ($i = 1; $i < count($text); $i++)
{
if ($text[$i] == '/' && $text[$i-1] == '<' )
{ $endtag = true; }
elseif ($endtag && $text[$i] == ' ' )
{ $text[$i] = ''; }
elseif ($endtag && $text[$i] == '>')
{ $endtag = false; }
}
return implode($text);
}
/**
* Insert <p class="whiteline" at paragraphs ending with two newlines
* Insert <p class="break" at paragraphs ending with one or no nl
* Insert <p class="whitelinetop" at the first paragraph if starting with a nl
* Insert <p class="whitelinetopbottom" if the first paragraph is ending with two newlines
* @param string text
* @param boolean complex operations (not necessary when text is flat)
* @return string
*/
function nl2p($textstring)
{
//check for empty content
if (empty(trim($textstring))) { return $textstring; }
//check for whiteline on start and end
$startnl = ( strspn($textstring,"\n") ) ? true : false;
$endnl = ( strspn($textstring,"\n",-1 ) ) ? true : false;
$whiteline = $endnl;
//trim whitespaces and line breaks
$textstring = trim($textstring);
if (empty($textstring)) { return $textstring; }
$p_top = '<p class="wl_top">';
$p_bottom = '<p_class="wl_bottom">';
$p_top_bottom = '<p_class="wl_top_bottom">';
$p = '<p class="break">';
$end_p = '</p>';
// check for newlines in text block
if ($startnl || $endnl || strpos($textstring,"\n") )
{
//split into array
$text = str_split($textstring);
$i = count($text) - 1;
//main operation: convert \n to p, dependent of the context
//crawling from end to start
while ($i > 0) {
//search next /n enclosing text, starting at $i-1
$i = $this->next_nl_block($i, $text);
if ($i == 0) { //no newlines left
break;
} elseif ($whiteline) {
$text[$i] = "</p>" . $p_bottom;
} else {
$text[$i] = "</p>" . $p;
}
//look ahead for next paragraph class
if ($text[$i-1] == "\n") {
$whiteline = true;
$text[$i-1] = '';
$i--;
} else {
$whiteline = false;
}
}
//implode
$textstring = implode($text);
//get type of first paragraph
if ($whiteline && $startnl) {
$textstring = $p_top_bottom . $textstring . $end_p;
} elseif ($startnl) {
$textstring = $p_top . $textstring . $end_p;
} elseif ($whiteline) {
$textstring = $p_bottom . $textstring . $end_p;
} else {
$textstring = $p . $textstring . $end_p;
}
//format output
if ($startnl) { $textstring = "\n" . $textstring; }
$textstring = str_replace('</p>',"</p>\n",$textstring);
}
return $textstring;
}
/**
* Find next newline separated by text from current position
* @param int start
* $param array text
*/
function next_nl_block($i, $text)
{
$skipped = false;
for ($i--; $i>0; $i-- ) {
if (!$skipped){
//see if you skipped over a non-newline (heading to the next block)
if (strpos($text[$i], "\n") === false) {
$skipped = true;
}
} else if (strpos($text[$i], "\n") !== false) {
break;
}
}
return $i;
}
/** explode textstring into array of substrings
* array element can be tag or content
* @param text
* $return array of tags and contents
*/
function explode_along_tags($text)
{
$startpos = 0;
$endpos = 0;
$textarray = array();
do
{
//find tag start
$endpos = strpos($text,'<',$startpos);
if ($endpos === false)
{
//no more tags, copy remainder to array
$endpos = strlen($text);
if ($endpos - $startpos > 0)
{ $textarray[] = substr($text,$startpos,$endpos - $startpos); }
return $textarray;
}
elseif (($endpos - $startpos) > 0)
{
//copy preliminary text to array
$textarray[] = substr($text,$startpos,$endpos - $startpos);
}
$startpos = $endpos;
//find tag end
$endpos = strpos($text,'>',$startpos);
if ($endpos === false) { return false; }
elseif (($endpos - $startpos) > 1)
{
//copy tag to array
$textarray[] = substr($text,$startpos,$endpos - $startpos + 1);
$startpos = $endpos + 1;
}
else { return false; }
} while (1);
return false;
}
function extract_tag($text)
{
if ($text[0] != "<") { return false; }
$n = strcspn($text," >");
return ltrim(substr($text,0,$n),"</");
}
function is_starttag($text) { return ($text[1] == "/") ? false : true; }
/*
* handles tagged content, apply nl2p if tag allows it
* works also for ommitted closing tags
* @param: text
* return string
*/
function tagged_nl2p($text)
{
//join config isolation tags into block elements
//if (!empty($isolate)) { $block_elements = array_merge($block_elements,$isolate); }
//explode string into array of tags and contents
$textarray = $this->explode_along_tags($text);
$content = "";
$start = 0;
$tagstack = array();
$isolation_flag = false;
for ($i=0; $i < count($textarray); $i++)
{
//delete isolation tags from other arrays
if ($this->isolationtags)
{
$this->block_elements = array_diff($this->block_elements,$this->isolationtags);
$this->allowed_p_parents = array_diff($this->allowed_p_parents,$this->isolationtags);
$this->nested_block_elements = array_diff($this->nested_block_elements,$this->isolationtags);
}
//get tag or false if none
$tag = $this->extract_tag($textarray[$i]);
//new blocktag - e.g. <table>
if ($tag && $this->is_starttag($textarray[$i])
&& (in_array($tag, $this->block_elements) || in_array($tag, $this->nested_block_elements) ))
{
//merge previous content, apply nl2p if needed and concatenate
if (!$isolation_flag && empty($tagstack) )
{
$content .= $this->nl2p(implode(array_slice($textarray,$start,$i-$start)));
} elseif (!$isolation_flag && in_array($tagstack[0], $this->allowed_p_parents) )
{
$content .= $textarray[$start]
. $this->nl2p(implode(array_slice($textarray,$start+1,$i-$start-1)));
} else
{
$content .= implode(array_slice($textarray,$start,$i-$start));
}
// clear stack of block elements and insert
if (in_array($tag, $this->block_elements) )
{
$tagstack = array_diff($tagstack, $this->block_elements);
}
array_unshift($tagstack, $tag);
$start = $i;
}
//new tag which can contain paragraphs and can be inside a blocktag - e.g. <td>
elseif ($tag && $this->is_starttag($textarray[$i]) && in_array($tag, $this->allowed_p_parents))
{
//merge previous content, apply nl2p if needed and concatenate
if (!$isolation_flag && empty($tagstack) )
{
$content .= $this->nl2p(implode(array_slice($textarray,$start,$i-$start)));
} elseif (!$isolation_flag && in_array($tagstack[0], $this->allowed_p_parents) )
{
$content .= $textarray[$start]
. $this->nl2p(implode(array_slice($textarray,$start+1,$i-$start-1)));
} else
{
$content .= implode(array_slice($textarray,$start,$i-$start));
}
//insert tag into the stack
array_unshift($tagstack, $tag);
$start = $i;
}
//isolation tag
elseif($tag && $this->is_starttag($textarray[$i]) && in_array($tag, $this->isolationtags) )
{
//merge previous content, apply nl2p if needed and concatenate
if (!$isolation_flag && empty($tagstack) )
{
$content .= $this->nl2p(implode(array_slice($textarray,$start,$i-$start)));
} elseif (!$isolation_flag && in_array($tagstack[0], $this->allowed_p_parents) )
{
$content .= $textarray[$start]
. $this->nl2p(implode(array_slice($textarray,$start+1,$i-$start-1)));
} else
{
$content .= implode(array_slice($textarray,$start,$i-$start));
}
$isolation_flag = true;
$start = $i+1;
}
//closing isolation tag
elseif($tag && !$this->is_starttag($textarray[$i]) && in_array($tag, $this->isolationtags) )
{
if ($isolation_flag)
{
//content, no nl2p
$content .= implode(array_slice($textarray,$start,$i-$start-1));
$isolation_flag = false;
$start = $i+1;
}
}
//closing blocktag or p parent - e.g. </table> or </td>
elseif($tag && !$this->is_starttag($textarray[$i]) && $tag == $tagstack[0])
{
//concatenate the start tag
$content .= $textarray[$start];
//content, apply nl2p if needed
if (!$isolation_flag && in_array($tagstack[0], $this->allowed_p_parents) )
{
$content .= $this->nl2p(implode(array_slice($textarray,$start+1,$i-$start-1)));
} else
{
$content .= implode(array_slice($textarray,$start+1,$i-$start-1));
}
//closing tag
if ($i != $start) { $content .= $textarray[$i]; }
$start = $i+1;
array_shift($tagstack);
}
}
//merge remainder
if (!$isolation_flag && empty($tagstack) )
{
$content .= $this->nl2p(implode(array_slice($textarray,$start,$i-$start)));
} elseif (!$isolation_flag && in_array($tagstack[0], $this->allowed_p_parents) )
{
$content .= $textarray[$start]
. $this->nl2p(implode(array_slice($textarray,$start,$i-$start-1)));
} else
{
$content .= implode(array_slice($textarray,$start,$i-$start-1));
}
return $content;
}
Re: NL2BR and extended article
I have to admit that it's too late for me today as well to follow (and understand) you explanations, but be assured that we appreciate your effort and are looking forward to a PR.stephanbrunker wrote:I've not put it into a second Pull Request yet, because it's too late and I have to tidy up the code a bit.
YL
-
- Regular
- Posts: 23
- Joined: Sat Nov 25, 2017 12:08 am
Re: NL2BR and extended article
A short update: I'm still working on the code for the new nl2p. But to make it right, its slightly complicated. On my blog, I've it running now and so far I exterminated all the bugs which showed up. The last one was replacing < and > with < > automatically if they are not part of an html tag.
Basically, it should do:
That means: You can either just type your text in and nl2p set your paragraphs. Or you can code that text in html at will and it still sets the paragraphs for you.
I've updated the test site too to the latest version, so you can try some content against it.
Basically, it should do:
- split the text into parts defined by the blocktags or nestable block elements (div, table, blockquote)
- get isolation tags from config
- apply nl2p to these parts if the parent element allows it and its not isolated
- inside the block elements, the inline elements (like i,b, ...) are continued over newlines. If a newline appears, the element is closed, the paragraph closed, a new one created and the inline element retrieved.
That means: You can either just type your text in and nl2p set your paragraphs. Or you can code that text in html at will and it still sets the paragraphs for you.
I've updated the test site too to the latest version, so you can try some content against it.