schulle4u / yellow-extensions-schulle4u

My experimental extensions for Datenstrom Yellow.
GNU General Public License v2.0
15 stars 4 forks source link

Render CSV input as Markdown? #4

Closed JetGum closed 4 years ago

JetGum commented 5 years ago

Hi! With the help of your plugin, I grab data from a CSV file, create a table & output HTML in Yellow. This works fine, although I would like to be able to have HTML (or Markdown) links (or other markup) in the CSV to be displayed correctly on the frontend.

Example: "Modell","Gewicht","Preis","URL" "Product 1","12 kg","123,45 €",":fa-location-arrow: "<a href=""https://www.amazon.de\"">Amazon""

This renders as it is. So I cannot seem to make MD or HTML-Links in my CSV display in the output.

Any hint greatly appreciated!

Carsten

PS: As a sidenote, I adapted your csv.php to grab csv header values ($headerName) and use them as data-label in . Had to do this becauce data-labels work nicely for table layout in mobile devices, where colums stacked as rows on small screens.

schulle4u commented 5 years ago

Hello Carsten,

thanks for your feedback. Yellow has a safeMode setting to prevent HTML and Javascript code from being parsed in pages. I can use this setting in the CSV extension as well. If safeMode is set to 0 (default value), HTML code within CSV columns will be parsed. Would this solve your problem?
I'm not sure if it is actually possible to parse Markdown in CSV files, will investigate this further.

Steffen

schulle4u commented 5 years ago

The extension now uses the safeMode setting as described above. You can download a fresh copy from the master branch. HTML parsing should now work as expected, please let me know if still something isn't working. To update your modified copy, change line 57 of system/extensions/csv.php:

$output .= "<td>".($this->yellow->system->get("safeMode") ? htmlspecialchars($value) : $value)."</td>\n";

I'll release it to the software update channel later this day.

Steffen

JetGum commented 5 years ago

Works like a charm! Links in CSV are now parsed correctly in HTML and shown as links. I can also add other markup like fa-icons etc. Great, thx!

Carsten

FYI: Below please find my adjusted code for data-label inclusion in , just to have nice responsive tables with thead on small screens. I'm a newbie with PHP so I used some snippets I found on the net. Maybe the code can be more elegant (or faster?) but it seems to work for my purposes:

<?php
// CSV extension, https://github.com/schulle4u/yellow-extensions-schulle4u/tree/master/csv
// Copyright (c) 2019 Steffen Schultz
// This file may be used and distributed under the terms of the public license.

class YellowCsv {
    const VERSION = "0.8.5";
    const TYPE = "feature";
    public $yellow;         //access to API

    // Handle initialisation
    public function onLoad($yellow) {
        $this->yellow = $yellow;
        $this->yellow->system->setDefault("csvDir", "media/downloads/");
        $this->yellow->system->setDefault("csvDelimiter", ";");
        $this->yellow->system->setDefault("csvFirstRowHeader", "1");
        $this->yellow->system->setDefault("csvFilter", "1");
    }

    // Handle page content of shortcut
    public function onParseContentShortcut($page, $name, $text, $type) {
        $output = null;

        if ($name=="csv" && ($type=="block" || $type=="inline")) {
            list($file, $delimiter, $class) = $this->yellow->toolbox->getTextArgs($text);
            if (empty($delimiter)) $delimiter = $this->yellow->system->get("csvDelimiter");
            $delimiter = strreplaceu("\\t", "\t", $delimiter);
            if (empty($class)) $class = htmlspecialchars($name);
            $firstRowHeader = $this->yellow->system->get("csvFirstRowHeader");
         $output = "<div id=\"".htmlspecialchars($name)."\">\n";

            // get CSV
            $row = 0;

            // added to get header values
            $headerValues  = array();
            $counter = 0;

            $dir = $this->yellow->system->get("csvDir");
            if ($handle = @fopen($dir.$file, "r")) {
                // Prepare Table
                if ($this->yellow->system->get("csvFilter")) $output .= "<p><input type=\"search\" class=\"light-table-filter\" data-table=\"".htmlspecialchars($class)."\" placeholder=\"Filter\"></p>\n";

                $output .= "<table class=\"".htmlspecialchars($class)."\">\n";

                // loop
                while (($data = fgetcsv($handle, "1000", $delimiter)) !== false) {

                // BEGIN to grab the header values on first iteration
                    if ($counter == 0) {
              // store them in an array
              $headerValues = $data;
              // increment counter
              $counter++;                  
            }      
                $col    = count($data);
                // grab CSV header END    

                    $num = count($data);
                    if (($row == 0) && $firstRowHeader) {
                        $output .= "<thead><tr>\n";
                    } else {
                        $output .= "<tr>\n";
                    }
                    for ($c=0; $c < $num; $c++) {

                        // grab column name here
                        $headerName = $headerValues[$c]; 
                        $cell   = $data[$c];
                        $colnum = $c + 1;                

                        if (strempty($data[$c])) {
                            $value = "";
                        } else {
                            $value = $data[$c];
                        }
                        if (($row == 0) && $firstRowHeader) {
                            $output .= "<th>".htmlspecialchars($value)."</th>\n";
                        } else {
                             $output .= "<td data-label=\"$headerName\">".($this->yellow->system->get("safeMode") ? htmlspecialchars($value) : $value)."</td>\n"; 
                        }
                    }
                    if (($row == 0) && $firstRowHeader) {
                        $output .= "</tr></thead><tbody>\n";
                    } else {
                        $output .= "</tr>\n";
                    }
                    $row++;

                }

                $output .= "</tbody></table>\n";
                fclose($handle);
            } else {
                $this->yellow->page->error(500, "File '$file' does not exist!");
            }
            $output .= "</div>\n";
        }
        return $output;
    }
    // Handle page extra data
    public function onParsePageExtra($page, $name) {
        $output = null;
        if ($name=="header") {
            $extensionLocation = $this->yellow->system->get("serverBase").$this->yellow->system->get("extensionLocation");
            $output .= "<script type=\"text/javascript\" defeheadr=\"defer\" src=\"{$extensionLocation}csv.js\"></script>\n";
        }
        return $output;
    }

}
schulle4u commented 5 years ago

Thanks for sharing, I've edited your comment to display the code correctly.

I'm not a designer and therefore can't say much about responsive tables, but there seem to exist several more or less painful methods to make tables responsive. This also depends on the type of table. According Yellow's philosophy I prefer pure CSS tricks like this one suggested at W3Schools. Horizontal scrolling might not be the best solution, but probably achieves better rendering results for large data tables. I'll keep an eye on this topic.

Steffen