0

On our website we have got a simple BB-Code based editor to create our posts. To be able to create basic grids I added a new tag which is a simple wrapper with display:grid and grid-template-columns: repeat(2, 1fr).

So the input looks something like this:

[easy-columns]
[box]
Text box 1
[/box]
[box]
Text box 2
[/box]
[/easy-columns]

And the output would look like this:

<div class="easy-columns">
  <div class="box">Text box 1</div>
  <br />
  <div class="box">Text box 2</div>
</div>

My problem comes with the line breaks which let the grid collapse.

Solution 1: So my first attempt was simply to set display: none to the br elements inside the wrapper. But I am not sure if this is working in all browsers. (I would prefer this very simple solution)

Solution 2: And my second attempt was to use php domdocument to remove all br children from the div with the class easy-columns.

Is my css solution working or just a working 'bug' in my testing environment? Or should i go with domdocument?

.easy-columns {
  gap: 2em;
  align-items: stretch;
  display: grid;
  grid-auto-flow: row;
  grid-template-columns: repeat(2, 1fr);
  justify-items: stretch;
  margin-bottom: 2em;
  max-width: 100%;
  overflow: hidden;
  position: relative;
  width: 100%;
}

.css-approach>br {
  display: none;
}

.box {
  background-color: grey;
  color: white;
  display: inline-block;
  padding: 2em;
  position: relative;
  text-align: left;
}
[easy-columns]<br /> [box]
<br /> Text box 1<br /> [/box]
<br /> [box]
<br /> Text box 2<br /> [/box]
<br /> [/easy-columns]
<br />
<br />
<hr />
<br />
<br />
<div class="easy-columns">
  <div class="box">
    Text box 1
  </div>
  <br />
  <div class="box">
    Text box 2
  </div>
</div>
<div class="easy-columns css-approach">
  <div class="box">
    Text box 1
  </div>
  <br />
  <div class="box">
    Text box 2
  </div>
  <div class="box">
    Text box 1
  </div>
  <br />
  <div class="box">
    Text box 2
  </div>
</div>
TylerH
  • 20,799
  • 66
  • 75
  • 101
  • 2
    IMHO `display:none` should be working with all browsers supporting grid. But actually those `br`s should not present at the output at all. Check if you can configure your bb-to-html library not to generate them. And btw in this case (if was forced) i'd cut off `br`s with regexps, domdocument seems to be an overkill. – Jared Jun 26 '23 at 15:58

1 Answers1

0

Thanks for the answer. It took me a while but I think I have a good solution now. I ended up using domdocument and try to explain how and why.

First here is my bb-to-html function:

bbToHtml($bb){
 $elements = array(
  array("\[h1\]\s*(.*?)\s*\[\/h1\]\s{0,2}", 
        "<h2 class=\"bb-headline\">\\1</h2>", 
        ""),
  array("\[img\-p\=([^\"]*\.(?:png|jpe?g|gif))\]\s{0,1}?", 
        "<div class=\"bb-img-wrapper portrait hover-fx-trigger\"><img src=\"gallery/articles/main/\\1\" /></div>",
     "Ui"),
  array("\[box\-simple\]\s*(.*?)\s*\[\/box\-simple\]\s{0,1}",
        "<div class=\"box-simple\">\\1</div>",
        "")
 );

 // Replacing
 foreach ($elements as $replace) {
  $modifier = "is";
  // Additional modifiers
  if(array_key_exists(2, $replace) and !empty($replace[2])){
   $modifier = $replace[2];
  }
   $bb = preg_replace("#" . $replace[0] . "#{$modifier}", $replace[1], $bb);
  }

  $bb = addInfos($bb);
  $bb = nl2br($bb);

 return $bb;
}

As I am just replacing images without any additional informations I am calling the function addInfos().

Looks like this:

function addInfos($bb){
 // Step 1
 $dom = new DOMDocument();
 $dom->preserveWhiteSpace = false;

 $internalErrors = libxml_use_internal_errors(true);
 $dom->loadHTML(mb_convert_encoding($bb, "HTML-ENTITIES", "UTF-8"), LIBXML_HTML_NODEFDTD);
 libxml_use_internal_errors($internalErrors);

 // Step 2
 $divs = $dom->getElementsByTagName("div");

 // Step 3
 foreach ($divs as $div) {

  $class = $div->getAttribute("class");
  $children = $div->childNodes;

  switch (true) {
   // Step 4
   case strpos($class, "hover-fx-trigger") !== false:
    if(property_exists($firstchild, "tagName") and $firstchild->tagName == "img"){
     $childclass = $firstchild->getAttribute("class");
     $src = $firstchild->getAttribute("src");
     $style = $firstchild->getAttribute("style");
     $width = $firstchild->getAttribute("width");

     // creating the new html......

     $newdom = new DOMDocument();
     $newdom->loadHTML($newhtml, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
     $import = $dom->importNode($newdom->documentElement, true);
     $firstchild->parentNode->replaceChild($import, $firstchild);
    }
    break;

   // Step 5
   case strpos($class, "easy-columns") !== false:
    $easychildren = $div->childNodes;

     for ($i = $easychildren->length; --$i >= 0; ) {
      $easychild = $easychildren->item($i);
       if($easychild->nodeType === 3){
        $easychild = $easychildren->item($i);
        $easychild->parentNode->removeChild($easychild);
       }
     }
   break;
  }

 // Step 6
 $bb = substr($dom->saveHTML(), 12, -15);

 // Step 7
 $bb = str_replace(
          array("<p>", "</p>"),
          array("", ""),
          $bb
         );

 return $bb;

}

Step 1: creating new dom objeckt

Step 2: looking for divs

Step 3: looping through divs

Step 4: The first case looks for a specific class(hover-fx-trigger) . If the first child is an image, it extracts all attributes which I need to create the new html the image gets replaced. E.g. the src to find it in the database.

Step 5: The actual Problem with the linebreaks. First i get all child nodes. Then I loop through and removing all children with nodeType = 3 (DOMText). As it is a grid I just can use divs inside easy-columns.

Step 6: Saving the new html. DOMDocument adds body and html tags which I remove with substr($dom->saveHTML(), 12, -15).

Step 7: DOMDocument also wraps all DOMText nodes in a paragraph which I also do not need have to remove.

I use this functions to create html files which I include then.

For more infos just ask. Open for improvement!