]> lifelog.hopto.org Git - PerlCNFWEBServer.git/commitdiff
init
authorWill Budic <redacted>
Thu, 15 May 2025 08:22:04 +0000 (18:22 +1000)
committerWill Budic <redacted>
Thu, 15 May 2025 08:22:04 +0000 (18:22 +1000)
apps/PageHTMLPlugin.pm [new file with mode: 0755]
apps/PageletArticlePlugin.pm [new file with mode: 0755]
apps/PerlCNFWebServerBase.pm [new file with mode: 0644]
apps/app.cnf [new file with mode: 0644]
apps/app.html [new file with mode: 0644]
apps/app_defaults.cnf [new file with mode: 0644]
apps/index_markup.cgi [new file with mode: 0755]
apps/index_markup.cnf [new file with mode: 0644]
apps/index_markup.html [new file with mode: 0644]
apps/main.html [new file with mode: 0644]
apps/manifest.json [new file with mode: 0644]

diff --git a/apps/PageHTMLPlugin.pm b/apps/PageHTMLPlugin.pm
new file mode 100755 (executable)
index 0000000..d33d5e3
--- /dev/null
@@ -0,0 +1,201 @@
+
+package PageHTMLPlugin;
+use lib::relative '.';
+use PerlCNFWebServerBase;
+
+
+    
+our %TEMPLATES;
+
+sub new { bless {params=>{}}, shift }
+
+sub loadTemplate ($self, $parser, $path) {
+    if(-e $path){
+        if(not exists $TEMPLATES{$path}){
+            my $template = CNFGlobalFile -> new($path);
+            my %props =  %{$parser->collections()};
+                $TEMPLATES{$path}   = \$template;
+                $props{templates}  = \%TEMPLATES;
+                $self -> {content} = $template -> content();
+                $parser -> log("Loaded template: $path")
+        }else{
+            my $template = $TEMPLATES{$path};
+            if($$template -> changed()){
+                $self -> {content} = $$template -> content();
+                $parser -> log("Reloaded changed template: $path")
+            }else{
+                $self -> {content} = $$template -> {content};
+                $parser -> log("Using cached template: $path")
+            }
+        }
+        return 1
+    }else{
+        PageHTMLPluginException->throw(error=>"Template not found:$path", show_trace=>1)
+    }
+}
+
+###
+# If (cgi) parameters are set the Pagelet value has to be reprocessed.
+###
+sub setParameters ($self, $parser, $prp, $params){
+    if(defined $params){
+        my %parameters;
+        foreach (keys %$params){
+            $parameters{$_}    = $params->{$_}
+        }
+        $self -> {parameters} = %parameters;
+        process ($self, $parser, $prp)
+    }
+}
+
+sub resolvePropVal($parser, $property){
+    my $ref =  ref($property);
+    if($ref eq 'Pagelet'){
+        return $property->{html_body}
+    }
+    elsif($ref eq 'PropertyValueStyle'){
+        if(exists $property->{plugin}) {
+            my $plugin = $property->{plugin};
+                if(ref($$plugin) eq 'PageHTMLPlugin'){
+                return $$plugin -> {content} if exists $$plugin -> {content}
+                }
+                # What ever this is in the CNF repository as a plugin other than this.
+                # Convention is to store in value field.
+            return $$plugin -> {value}
+        }
+    }
+    return $parser->{$property} if exists $parser->{$property};
+    return $parser -> anon($property)
+}
+
+sub process ($self, $parser, $prp) { my ($config, $meta);
+    try{
+        my $app_tree =  'App';
+        my $property = $parser   -> property($prp);
+            $property = $prp if not $property;
+    if (exists $self -> {parameters}) {
+        $property = $property -> {cnf_property};
+        $app_tree = $self -> {parameters} -> {app} if $self -> {parameters} -> {app}
+    }
+    if (my $val = resolvePropVal($parser, $property)) {
+            $val = $$val if ref($val) eq 'SCALAR';
+        if ($config = $parser->anon($app_tree)) {
+            if ( $meta = $config->node('header/meta') ) {
+                foreach my $node (@{$meta->list()}) {
+                    if ( $node->{data} ) {
+                            $val = dataPropertyToHTMLParagraphs($parser->data()->{$node->{data}});
+                    }  else {                             
+                            $val = processNodeWithProperty($parser, $node, $val );
+                    }
+                }
+                my @template =  ($val =~ m/^(.*)\s*
+                <![-]+\s*PerlCNF\s*Template\s*Start\s*[-]+>*\s*
+                    (.*)
+                <\![-]+\s*PerlCNF\s*Template\s*End\s*[-]+>*\s*(.*)/mxsi);
+                $val = $template[1];
+                $parser->collections()->{$prp} = \Pagelet ->new({plugin => $self ,
+                                                            property => $prp,
+                                                            subroutine => 'process',
+                                                            cnf_property => $parser -> property($prp),
+                                                            html_head => \$template[0],
+                                                            html_body => \$val,
+                                                            html_foot => \$template[2],
+                                                            });
+                return 1;
+            }
+            else {die "Where is meta node in [$app_tree] property?"}
+        }
+        else {die "Where is the  [$app_tree]  property?"}
+    }
+    else {die "Unable to resolve CNF property -> $prp"}
+    }catch($e){
+        PageHTMLPluginException->throw(error=>$e, show_trace=>1)
+    }
+}
+
+sub processNodeWithProperty($parser, $node, $val) {
+    my ($tag,$rep);
+    my @nodes = $node->nodes();
+    if(@nodes){
+        foreach my $sub(@nodes){
+            my $bf;
+            foreach($sub->nodes()){
+                $bf .= "<".$_->name();
+                    foreach($_->attributes()){
+                        my @pair = @$_;
+                        $bf .= qq( $pair[0] = "$pair[1]");
+                    }
+                $bf .= ">\n";
+            }
+            $tag ='<\![-]+\s*<@<\s*' . $sub->name() . '\s*>@>\s*[-]+>';
+            if(!$bf){
+                $rep = qq([\$\$\$[ ). $sub->name() .' is UNDEFINED in subnodes! ]$$$]';
+                $val =~ s/$tag/$rep/xg if defined $rep;
+            }else{
+                $val =~ s/$tag/$bf/xg;
+            }
+        }
+        return $val;
+    }elsif($node->{property} ){
+        $rep = $node->{property}
+    }else{
+        $rep = $node->val()
+    }
+
+    $tag = '<\![-]+\s*<@<\s*' . $node -> {tag} . '\s*>@>\s*[-]+>';
+    if(!$rep){
+        $rep = '[$$$[ '. $node -> {tag} .' is UNDEFINED! ]$$$]';
+    }else{
+        my $ref = ref($rep);
+        if($ref eq 'SCALAR'){
+            $rep = $$rep
+        }elsif($ref eq 'PropertyValueStyle'){
+            my $value = $rep -> {value};
+            if(!$value){
+                $rep = ${$parser -> data() -> {$rep->{property}}}
+            }else{
+                $rep = $value;
+            }
+        }elsif($ref eq "Pagelet"){                   
+                $rep = $rep -> {html_body};
+        }elsif($ref ne ''){
+                $rep = $rep -> val()
+        }
+    }
+
+    $val = $$val if ref($val) eq 'SCALAR';
+    $rep =~ s/^\s*|\s*$//gs;
+    
+    $rep  = $node->{title} . $rep if $node->{title};
+    $rep  = $node->{head}  . $rep if $node->{head};
+    $rep .= $node->{foot}         if $node->{foot};
+
+    $val =~ s/$tag/$rep/xg;
+
+    return $val;
+}
+
+sub dataPropertyToHTMLParagraphs($data_struct) {
+    my $ret = "";
+    foreach my $record (@{$$data_struct->{data}}) {
+
+        my $p = qq(<div class = 'cnf_data_rec'>
+                <h2>@$record[1]</h2>
+                <p>@$record[2]</p>
+            </div>);
+        $ret .= $p ."\n";
+
+    }
+    return $ret;
+}
+
+
+
+
+1;
+=begin copyright
+Programed by  : Will Budić
+EContactHash  : 990MWWLWM8C2MI8K (https://github.com/wbudic/EContactHash.md)
+Source        : https://github.com/wbudic/LifeLog
+Open Source Code License -> https://github.com/wbudic/PerlCNF/blob/master/ISC_License.md
+=cut copyright
diff --git a/apps/PageletArticlePlugin.pm b/apps/PageletArticlePlugin.pm
new file mode 100755 (executable)
index 0000000..6576455
--- /dev/null
@@ -0,0 +1,106 @@
+package PageletArticlePlugin;
+use PluginBase;
+
+    sub new { bless {params=>{}}, shift }
+
+    sub resolvePropVal($parser, $property){
+        my $ref =  ref($property);
+        if($ref eq 'Pagelet'){
+           return $property->{html_body}
+        }
+        elsif($ref eq 'PropertyValueStyle'){
+           if(exists $property->{plugin}) {
+              my $plugin = $property->{plugin};
+                 if(ref($$plugin) eq 'PageHTMLPlugin'){
+                    return $$plugin -> {content} if exists $$plugin -> {content}
+                 }
+                 # What ever this is in the CNF repository as a plugin other than this.
+                 # Convention is to store in value field.
+              return $$plugin -> {value}
+           }
+        }
+        return $parser->{$property} if exists $parser->{$property};
+        return $parser -> anon($property)
+    }
+
+    sub publish ($self, $parser, $prp_name) {
+      my ($cnf_property, $buffer);
+      if($prp_name =~ m/(\w*)\*$/){
+         $prp_name = $1;
+         my @list = $parser->list($prp_name);
+         foreach my $ins(@list){
+                 $cnf_property = $parser -> anon($ins->{ele}.$ins->{aid});
+                 $buffer .= $self->publish_item ($parser, $cnf_property);
+         }
+      }else{
+         $cnf_property = resolvePropVal($parser, $prp_name);
+         $buffer = $self->publish_item ($parser, $cnf_property);
+      }
+      $parser->collections()->{$prp_name} = \ Pagelet -> new ({plugin => $self ,
+                                                   property => $prp_name,
+                                                   subroutine => 'process',
+                                                   cnf_property => $cnf_property,
+                                                   html_body => $buffer,
+                                                }) ;
+            return 1;
+    }
+
+    sub publish_item ($self, $parser, $item) {
+        try{
+            my $result;
+            my $ref = ref($item);
+            if($ref eq 'CNFNode'){
+               foreach my $node($item->nodes()){
+                    if($node ->name() eq 'article'){
+                       my $nd_img  = $node -> node('img');
+                       my $nd_txt  = $node -> node('text');                       
+                       if($nd_img ne CNFNode::EMPTY()){
+
+                        my $title =  $nd_img->{title};
+                        my $alt   =  $nd_img->{alt};
+                        if($alt){
+                           $alt = 'alt="'. $alt . '"'
+                        }else{
+                           $alt = 'alt'
+                        }
+                        $nd_txt  = $nd_txt ->val();
+                        my $nd_url  = $nd_img -> {url};
+                        my $nd_url_low  = $nd_img -> {url_high};
+                        my $nd_url_high = $nd_img -> {url_low};
+                        my $nd_siz  = $nd_img -> node('sizes');
+                        $nd_siz = "(min-width: 800px) 480px" if $nd_siz eq CNFNode::EMPTY();
+
+
+                        $result .= 
+qq(<div class="article">       
+       <div class="img">
+       <div class="title"> $title </div>
+            <img src="$nd_url"
+            srcset="$nd_url_low, $nd_url_high"
+            sizes="$nd_siz"
+            $alt>
+       </div>
+       <div class="text">
+                $nd_txt
+       </div>
+</div>)
+                       }
+                    }
+               }
+            }
+            $result =~ s/^\s*//gs;
+            return $result
+        }catch($e){
+            PageHTMLPluginException->throw(error=>$e, show_trace=>1)
+        }
+    }
+
+
+
+1;
+=begin copyright
+Programed by  : Will Budić
+EContactHash  : 990MWWLWM8C2MI8K (https://github.com/wbudic/EContactHash.md)
+Source        : https://github.com/wbudic/LifeLog
+Open Source Code License -> https://github.com/wbudic/PerlCNF/blob/master/ISC_License.md
+=cut copyright
diff --git a/apps/PerlCNFWebServerBase.pm b/apps/PerlCNFWebServerBase.pm
new file mode 100644 (file)
index 0000000..f0dd908
--- /dev/null
@@ -0,0 +1,44 @@
+package PerlCNFWebServerBase;
+use v5.36; #For younger Perl rebases change only here version, and bellow line 23. And brace for warnings in logs.
+use Syntax::Keyword::Try; no warnings qw(experimental::signatures);
+use feature qw(signatures);
+use Exception::Class ('PageHTMLPluginException');
+use Module::Load;
+                 autoload CNFGlobalFile;
+                 autoload CNFParser;
+
+package Pagelet {
+
+    sub new($class, $args){
+        return bless $args, $class;
+    }
+
+    sub val($self){
+        return $self -> {html_body} if exists $self -> {html_body}
+    }
+}
+
+
+sub import {
+  feature->import(':5.36');
+  feature->import('signatures');
+  warnings->import;
+  strict->import;  
+  Module::Load->import;
+  Syntax::Keyword::Try->import;  
+  Exception::Class->import('PageHTMLPluginException');
+  CNFGlobalFile->import;
+
+  my $caller = caller(0);
+  do {
+    no strict 'refs';
+    *{"$caller\:\:Pagelet"}  = *{Pagelet};
+    *{"$caller\:\:isTrue"}  = *{CNFParser::_isTrue};
+  };
+
+
+}
+
+
+
+1;
\ No newline at end of file
diff --git a/apps/app.cnf b/apps/app.cnf
new file mode 100644 (file)
index 0000000..993c91b
--- /dev/null
@@ -0,0 +1,285 @@
+!CNF3.3
+
+<<<CONST DEBUG=1>>>
+<<<INCLUDE  apps/app_defaults.cnf>>>
+<<property <VAR>
+    Please <@< meta_1   >@>, this line is a paragraph.
+    <@< dynamic_paragraphs >@>
+>>
+###
+# In CNF Nodes shorthand format assigned are all template substitutions here.
+# The geeky shortifes are faster then normal CNF node tags, and use less recursion.
+##
+<<App <TREE>__IN_SHORTIFE__  __PRIORITY_8__
+header __\
+<#<TEST_VALUE>#>
+meta __\
+    @@ __\
+        tag: page_title
+        Document Viewer App
+    __/
+    @@ __\
+        header __\
+            link __|
+                rel  = manifest
+                href = manifest.json
+                __~
+            __/
+            link __|
+                rel  = stylesheet
+                href = ../web_sources/root.css
+                __~
+            __/
+            link __|
+                rel  = stylesheet
+                href = ../web_sources/app.css
+                __~
+            __/
+        __/
+    __/
+    @@__\
+        tag: css_style
+        property: <*<MarkdownPlugin::CSS>*>
+    __/
+    @@__\
+        tag: css_style_articles
+        property: <*<ArticleSample_CSS>*>
+    __/
+    @@__\
+        tag : col_left
+        title: <span class="page_title"> Document Viewer App </span>
+        head: <dt class="page_title"><a href="/">Back To Main Page</a></dt><hr noshade/>
+        property: <*<MD1_headings>*>
+        foot: <hr noshade/>
+    __/
+    @@__\
+        tag : col_main
+        property: <*<MD1>*>
+    __/
+    @@__\
+        tag : col_right
+        <#< Test 2 >#>
+    __/
+__/
+>>
+
+<<PAGE_CONTENT <PLUGIN> __PRIORITY_7___
+  package     : PageHTMLPlugin
+  subroutine  : loadTemplate
+  property    : apps/app.html
+>>
+
+<< Processor <PLUGIN> __PRIORITY_9__
+  package     : PageHTMLPlugin
+  subroutine  : process
+  property    : PAGE_CONTENT
+>>
+
+<<<MD1
+# Main Heading
+
+    Introduction paragraph here.
+
+## First Chapter
+
+The story here, etc, goes on and on.
+If we have links CNF MarkupInstructions they macro translates this -> [$$$[ some_web_site_1 ]$$$]
+
+If not stays in macro format, like this -> [$$$[ This link doesn't exist ]$$$]
+
+## Second Chapter
+
+[$$$[MarkupInstructions]$$$]
+
+## Third Chapter
+
+[$$$[ArticleSample]$$$]
+
+>>>
+
+<< MarkupDocument <PLUGIN> __PRIORITY_6__
+   package      : MarkdownPlugin
+   subroutine   : convert
+   property     : MD1
+   instructions : MarkupInstructions
+>>
+
+<< MarkupInstructions <TREE> __PRIORITY_3_
+
+[links[
+    [some_web_site_1[
+       desc : desc_website_1_desc.html
+       url  : https://somewebsite.com
+    ]some_web_site_1]
+]links]
+[particulars[
+    <@@<
+        tag: ArticleSample
+    >@@>
+]particulars]
+<#<
+    This property holds further instructions on what actions and data is returned to client.
+    Including atomic descriptions and links that can be text rich and more informative.
+
+    So this whole script is both markup to render HTML and to prove configuration, to an web service app.
+    The page might render differently for other markup script processor if is read as an md file.
+
+### HTTP compression
+
+    HTTP compression is a capability that can be built into web servers and web clients to improve transfer speed and bandwidth utilization.[1]
+
+    HTTP data is compressed before it is sent from the server: compliant browsers will announce what methods are supported to the server before downloading the correct format; browsers that do not support compliant compression method will download uncompressed data. The most common compression schemes include gzip and Brotli; a full list of available schemes is maintained by the IANA.[2]
+
+        There are two different ways compression can be done in HTTP. At a lower level, a Transfer-Encoding header field may indicate the payload of an HTTP message is compressed. At a higher level, a Content-Encoding header field may indicate that a resource being transferred, cached, or otherwise referenced is compressed. Compression using Content-Encoding is more widely supported than Transfer-Encoding, and some browsers do not advertise support for Transfer-Encoding compression to avoid triggering bugs in servers.[3]
+
+>#>
+
+>>
+
+
+
+<<GenericInstructionHandler<INSTRUCTOR>PROPERTY>>
+<<ArticleSample_CSS <PROPERTY>
+
+
+
+.article{
+    display: grid;
+    grid-template-columns: .5fr 1fr;
+    column-gap: 1px;
+    border: 1px solid  rgb(133, 133, 233);
+    background-color: rgba(0, 0, 0, 0);
+    margin-bottom: 5px;
+}
+.img{
+    display: grid;
+    grid-template-columns: 1fr;
+    padding: 5px;
+    # border: solid black 1px;
+    min-width: min-content;
+
+    .title{
+      text-align: left;
+      font-kerning: auto;
+      font-weight: bolder;
+      font-size: x-large;
+      padding-bottom: 5px;
+    }
+    img{
+        max-width:380px;
+    }
+}
+.text{
+    font-size: 20px;
+    padding-top: 20px;
+    text-align: left;
+    p{
+       font-size: x-large;
+    }
+}
+
+@layer base {
+
+        @media (width > 599px) {
+
+                .content>*:nth-child(1) {
+                    flex: 1 2 0;
+                    margin-left: .2rem;
+                }
+
+                .content>*:nth-child(2) {
+                    flex: 0 1 80%;
+                    text-align: justify;
+                    display: inline-block;
+                    overflow: scroll;
+                    border-radius: 10px;
+                }
+
+                .content>*:nth-child(3) {
+                    flex: 1 2 0;
+                    margin-left: .2rem;
+                    display: none;
+                }
+        }
+
+
+
+        @media (width > 1440px) {
+
+                .content>*:nth-child(1) {
+                    flex: 1 2 .1%;
+                    margin-left: .5rem;
+                }
+                .content>*:nth-child(2) {
+                    flex: 0 1 90%;
+                    margin-left: .1rem;
+                }
+                .content>*:nth-child(3) {
+                    flex: 1 2 18%;
+                    margin-left: .5rem;
+                    display: none;
+                }
+        }
+
+    }
+
+>>
+
+
+<<ArticleSample$$ <TREE> __IN_SHORTIFE__   __PRIORITY_2__
+article __\
+                img __\
+                            title: Cat Deva
+                            alt: Cat Diva Artistic Image
+                            url:      images/cat_deva_2.jpeg
+                            url_high: images/cat_deva_2.jpeg 480w
+                            url_low:  images/cat_deva_2-240.jpeg 240w
+                            sizes: 380px
+
+                __/
+                text __\
+                        <p>This is a beautiful picture.</p> __~
+                __/
+__/
+>>
+<<ArticleSample$$ <TREE> __IN_SHORTIFE__  __PRIORITY_2__
+article __\
+                img __\
+                            title: Cica
+                            alt: Cica
+                            url:      images/cica_1.jpeg
+                            url_high: images/cica_1.jpeg 480w
+                            url_low:  images/cica_1_240x240.jpeg 240w
+                            sizes: 380px
+
+                __/
+                text __\
+                        <p>This is a beautiful picture two.</p> __~
+                __/
+__/
+>>
+
+
+<<ArticleSample$$ <TREE> __IN_SHORTIFE__ __PRIORITY_2__
+article __\
+                img __\
+                            title: Flowers In Spring
+                            alt: Flowers Picture
+                            url:      images/flowers_1.jpeg
+                            url_high: images/flowers_1.jpeg 480w
+                            url_low:  images/flowers_1_450x250.jpeg 450w
+                            sizes: 480px
+
+                __/
+                text __\
+                        <p>This is a beautiful picture three.</p> __~
+                __/
+__/
+>>
+
+<< ArticlePagelet <PLUGIN> __PRIORITY_5__
+   package      : PageletArticlePlugin
+   subroutine   : publish
+   property     : ArticleSample*
+>>
+
diff --git a/apps/app.html b/apps/app.html
new file mode 100644 (file)
index 0000000..e9b0a38
--- /dev/null
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">    
+    <meta name="description" content="">
+    <meta name="viewport" content="width=device-width, initial-scale=1">    
+    <!--<@<  header  >@>-->
+    <title><!--<@<  page_title  >@>--></title>
+</head>
+
+<body>
+<!--PerlCNF Template Start-->
+<style><!--<@< css_style   >@>--></style>
+<style><!--<@< css_style_articles   >@>--></style>
+<!-- img src="wsrc/images/Sun-Rotating.gif" -->
+<div class="content">
+    <div class="col" role="navigation">
+        <div class="toc"><strong>TOC</strong>&nbsp;&nbsp;
+            <span class="scrolling">
+                <!--<@< col_left   >@>-->
+            </span>
+        </div>
+    </div>
+    <div class="col_main" role="main">
+        <!--<@< col_main   >@>-->
+    </div>
+    <div class="col" role="contentinfo">
+        <!--<@< col_right   >@>-->
+    </div>
+</div>
+<!--PerlCNF Template End-->
+</body>
+</html>
\ No newline at end of file
diff --git a/apps/app_defaults.cnf b/apps/app_defaults.cnf
new file mode 100644 (file)
index 0000000..578d484
--- /dev/null
@@ -0,0 +1,5 @@
+!CNF3.3
+
+<<<CONST 
+APP_VERSION = 1.0 
+>>>
\ No newline at end of file
diff --git a/apps/index_markup.cgi b/apps/index_markup.cgi
new file mode 100755 (executable)
index 0000000..2e8376f
--- /dev/null
@@ -0,0 +1,113 @@
+#!/usr/bin/env perl
+#
+use v5.30;
+use strict;
+use warnings;
+use Exception::Class ('LifeLogException');
+use Syntax::Keyword::Try;
+##
+# We use dynamic perl compilations. The following ONLY HERE required to carp to browser on
+# system requirments or/and unexpected perl compiler errors.
+##
+use CGI::Carp qw(fatalsToBrowser set_message);
+
+BEGIN {
+   sub handle_errors {
+      my $err = shift;
+      say "<html><body><h2>Server Error</h2><pre>Error: $err</pre></body></html>";
+  }
+  set_message(\&handle_errors);
+}
+
+use lib "/home/will/dev_new/LifeLog/htdocs/cgi-bin/system/modules";
+#use lib "system/modules";
+require CNFParser; require CNFNode; require CNFDateTime;
+
+exit &HTMLPageBuilderFromCNF;
+
+sub HTMLPageBuilderFromCNF {
+
+    my $template = $0; $template =~ s/\.pl$|\.cgi$|\.perl/.html/g;
+    open( my $fh, "<:perlio", $template )
+      or LifeLogException->throw("Can't open $template: $!");
+    read $fh, my $content, -s $fh;
+    close $fh;
+    my $cnf  = CNFParser::_configure ({
+                      DO_ENABLED => 1, HAS_EXTENSIONS => 1, ANONS_ARE_PUBLIC => 1, DEBUG => 1,
+                      PAGE_CONTENT => \$content,
+                      PAGE_HEAD  => "<!--Not Defined-->",
+                      PAGE_FOOT  => "<!--Not Defined-->"
+                    },$0);
+    my $ptr = $cnf->data();
+    $ptr = $ptr->{'PAGE'};
+    say $$ptr if $ptr;
+    return 0
+}
+
+use feature qw(signatures); 
+package PageHTMLPlugin {
+    sub new { bless {}, shift }
+
+    sub resolvePropVal($parser,$prp){
+        return  exists $parser->{$prp} ? $parser->{$prp} : $parser -> anon($prp)
+    }
+
+    sub process {
+        my ( $class, $parser, $prp, $config, $meta ) = @_;
+        if ( my $val = resolvePropVal($parser ,$prp) ) {
+            if ( $config = $parser->anon('App') ) {
+                if ( $meta = $config->node('meta') ) {
+                    foreach my $node ( @{ $meta->list() } ) {
+                        if ( $node->{data} ) {
+                             $val = dataPropertyToHTMLParagraphs($parser->data()->{$node->{data}});
+                        }  else {
+                        # Notice DEBUG constance is not an app package required CNF default.
+                        # Not declaring it init of an instance of parser, the following will fail.
+                        # The{DEBUG=>1} is required, be set to 1 or 0.
+                             print $node->toScript() if $parser->{DEBUG};
+                             $val = processNodeWithProperty( $node, $val );
+                        }
+                        $parser->anon()->{$prp} = $val;
+                    }
+                    return 1;
+                }
+                else { die "Where is meta node in App property?" }
+            }
+            else { die "Where is App property?" }
+        }
+        else { die "Don't do that!" }
+    }
+    
+
+    sub processNodeWithProperty( $node, $val ) {
+        my $tag = '<@<\s*' . $node->{tag} . '\s*>@>';
+        my $rep = $node->{property} ? $node->{property} : $node->val();
+        $rep =~ s/^\s*|\s*$//gs;
+        $val =~ s/$tag/$rep/xg;
+        return $val;
+    }
+
+    sub dataPropertyToHTMLParagraphs($data_struct) {
+        my $ret = "";
+        foreach my $record (@{$$data_struct->{data}}) {
+
+            my $p = qq(<div class = 'cnf_data_rec'>
+    <h2>@$record[1]</h2>
+    <p>@$record[2]</p>
+</div>); 
+            $ret .= $p ."\n";
+
+        }
+        return $ret;
+    }
+}
+
+
+
+1;
+=begin copyright
+Programed by  : Will Budić
+EContactHash  : 990MWWLWM8C2MI8K (https://github.com/wbudic/EContactHash.md)
+Source        : https://github.com/wbudic/LifeLog
+Open Source Code License -> https://github.com/wbudic/PerlCNF/blob/master/ISC_License.md
+=cut copyright
diff --git a/apps/index_markup.cnf b/apps/index_markup.cnf
new file mode 100644 (file)
index 0000000..a8bc55d
--- /dev/null
@@ -0,0 +1,63 @@
+!CNF3.3
+
+<<property <VAR>
+    Please <@< meta_1   >@>, this line is a paragraph.
+
+    <@< dynamic_paragraphs >@>
+>>
+<<App <TREE>
+[meta[
+    <@@<
+        tag : col_left
+        <#< Dear Visitor >#>
+    >@@>
+    <@@<
+        tag : col_main
+        property: <*<Markup Document>*>
+    >@@>
+    <@@<
+        tag : col_right
+        <#< Test 2 >#>
+    >@@>
+]meta]
+>>
+<< Processor <PLUGIN>
+  package     : main::PageHTMLPlugin
+  subroutine  : process
+  property    : PAGE_CONTENT
+>>
+
+<<< Markup Document
+
+# Main Heading
+
+    Introduction paragraph here.
+
+## First Chapter
+
+The story hear, etc, on and on.
+If we have link CNF we macro as follow [$$$[ some_web_site_1 ]$$$]
+
+## Second Chapter
+>>>
+
+<< MarkupInstructions <TREE>
+
+[links[
+    [some_web_site_1[
+       provide : desc_website_1_desc.html
+            <#<https://somewebsite.com>#>
+    ]some_web_site_1]
+]links]
+
+<#<
+
+    This property holds further instructions on what actions and data is returned to client.
+    Including atomic descriptions and links that can be text rich and more informative.
+
+    So this whole script is both markup to render HTML and to prove configuration, to an web service app.
+    The page might render differently for other markup script processor if is read as an md file.
+
+>#>
+
+>>
\ No newline at end of file
diff --git a/apps/index_markup.html b/apps/index_markup.html
new file mode 100644 (file)
index 0000000..f94a722
--- /dev/null
@@ -0,0 +1,110 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <title></title>
+    <meta name="description" content="">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <link rel="stylesheet" href="wsrc/main.css">    
+</head>
+
+<body>
+    <style>
+        @font-face {
+            font-family: "LeagueMono";
+            src: url(wsrc/fonts/LeagueMono-VF.woff2);
+        }
+
+        @font-face {
+            font-family: "Lato";
+            src: url(wsrc/fonts/Lato/Lato-Regular.ttf);
+
+
+        }
+
+        body {
+            font-family: Lato;
+            display: flow-root;
+            padding: 0.5em;
+        }
+        p{
+            padding-bottom: .5em;
+        }
+
+
+        .content {
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            border: 2px dotted rgb(96 139 168);
+        }
+
+        .col {
+            border: 2px solid blue;
+            text-wrap: wrap;
+        }
+        .scrolling{
+            display: block;
+            height: 100%;
+            overflow-x: scroll !important;
+            text-wrap: wrap;
+            border: red;
+            width: 2em; 
+            margin-right: 1rem;         
+        }
+        .col_main {
+            
+            border: 2px solid blue;
+            min-width: 70%;          
+        }
+
+        .content>*:nth-child(1) {
+            flex: 1 2 10ch;
+            min-width: 10ch;
+            max-width: 150px;
+            margin-left: 5em;
+        }
+
+        .content>*:nth-child(2) {
+            flex: 0 2 85%;
+            padding: 2dvi;
+            text-align: justify;
+        }
+
+        .content>*:nth-child(3) {
+            flex: 1 2 10ch;
+            min-width: 10ch;
+            max-width: 150px;
+            margin-right: 5em;
+        }
+    </style>
+
+    <div class="content">
+
+        <div class="scrolling"><!--<@< col_left   >@>-->
+            
+                <ul>
+                    <li>Item One</li>
+                    <li>Item Two</li>
+                </ul>
+            
+        </div>
+        <div class="col_main"><!--<@< col_main   >@>-->
+            <p>
+            MaryLou wore the tiara with real pride.
+            There was something that made doing anything she didn't really want to do a bit easier when she wore it.
+            She really didn't care what those staring through the window were thinking as she vacuumed her
+            apartment.
+            <p>Bljat</p>
+            </p>
+        </div>
+        <div class="col"> <!--<@< col_right   >@>-->
+            Test Right
+        </div>
+    </div>
+
+</body>
+
+</html>
\ No newline at end of file
diff --git a/apps/main.html b/apps/main.html
new file mode 100644 (file)
index 0000000..2f2a4d8
--- /dev/null
@@ -0,0 +1,138 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="description" content="">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <title><!--<@<  page_title  >@>--></title>
+    <link rel="manifest" href="apps/manifest.json" />
+    <link rel="stylesheet" href="../web_sources/root.css" />
+    <link rel="stylesheet" href="../web_sources/app.css" />
+</head>
+
+
+<style>
+
+
+
+.col_section {
+    display: grid;    
+    border: solid salmon 1px;
+    border-radius: 10px;
+    overflow-block: scroll;
+
+    align-content:  start;
+    align-items:  start;
+    justify-items:  start;
+    text-align:  start;
+
+}
+
+.content>*:nth-child(1) {
+    flex: 1 2 10%;
+    margin-left: .5rem;
+}
+
+.content>*:nth-child(2) {
+    flex: 0 1 85%;    
+    text-align: justify;
+    display: inline-block;
+    overflow: scroll;
+    border-radius: 10px;
+}
+
+.content>*:nth-child(3) {
+    flex: 1 2 10%;
+    margin-left: .5rem;
+    /* display: none; */
+}
+
+</style>
+
+<body>
+    <!--PerlCNF Template Start-->
+    <div class="content">
+        <div class="col" role="navigation">
+            <div class="toc"><strong>TOC</strong>&nbsp;&nbsp;
+                <span class="scrolling">
+                    <!--<@< col_left   >@>-->
+                    PerlCNFWebServer
+                </span>
+            </div>
+        </div>
+        <div class="col_main" role="main">
+            <!--<@< col_main   >@>-->
+            <h1>Main</h1>
+            <p>Main paragraph sample text.</p>
+            <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.
+                Facilis perferendis eius fuga dignissimos tempore repellendus aliquid eligendi iste, esse a quidem cum
+                totam deserunt
+                harum accusantium modi similique officiis? Nemo?</p>
+            <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusamus repudiandae, saepe, veritatis eveniet repellat qui ipsa quas possimus iure quae illo! Tenetur libero error dicta non illo, sint porro nihil?</p>
+            <div class="col_section">
+                <h2>Test</h2>
+                <div>
+                    <h3>Lorem I</h3>
+                    <p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Iure, sint facere officia aliquid iste amet vel
+                        iusto nulla tenetur error porro modi voluptatum reprehenderit! Maiores quidem debitis ex consequuntur
+                        aspernatur?</p>
+                </div>
+
+                <div>
+                    <h3>Lorem II</h3>
+                    <p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Iure, sint facere officia aliquid iste amet vel
+                        iusto nulla tenetur error porro modi voluptatum reprehenderit! Maiores quidem debitis ex consequuntur
+                        aspernatur?</p>
+
+                    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Ab similique quisquam distinctio ut nemo
+                        culpa, esse fuga fugit eveniet sint, illum provident consequuntur expedita voluptate veritatis, tenetur quod
+                        delectus error?</p>
+                </div>
+
+                <div>
+                    <h3>Lorem III</h3>
+                    <p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Iure, sint facere officia aliquid iste amet vel
+                        iusto nulla tenetur error porro modi voluptatum reprehenderit! Maiores quidem debitis ex consequuntur
+                        aspernatur?</p>
+
+                    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Ab similique quisquam distinctio ut nemo
+                        culpa, esse fuga fugit eveniet sint, illum provident consequuntur expedita voluptate veritatis, tenetur quod
+                        delectus error?</p>
+                        <p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Fuga maiores eveniet quaerat maxime aspernatur mollitia
+                            modi itaque dolore quis nihil! Hic facilis eum laborum ipsam fugiat reiciendis sunt odio ratione?</p>
+                        <p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Fuga maiores eveniet quaerat maxime aspernatur mollitia
+                            modi itaque dolore quis nihil! Hic facilis eum laborum ipsam fugiat reiciendis sunt odio ratione?</p>
+                        <p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Fuga maiores eveniet quaerat maxime aspernatur mollitia
+                            modi itaque dolore quis nihil! Hic facilis eum laborum ipsam fugiat reiciendis sunt odio ratione?</p>
+                        <p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Fuga maiores eveniet quaerat maxime aspernatur mollitia
+                            modi itaque dolore quis nihil! Hic facilis eum laborum ipsam fugiat reiciendis sunt odio ratione?</p>
+
+                </div>
+            </div>
+
+            <div class="col_section">
+                <h2>Test</h2>
+                <div>
+                    <h3>Lorem II</h3>
+                    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Repellat vero accusantium at illo accusamus molestiae
+                        numquam eos optio odio quasi esse placeat eveniet, maxime deleniti vel earum mollitia rem quod?</p>
+                </div>
+            </div>
+                
+
+
+
+        </div>
+        
+        <div class="col" role="contentinfo">
+            <!--<@< col_right   >@>-->
+            <p>Right Column!</p>
+        </div>
+    </div>
+    <!--PerlCNF Template End-->
+  
+</body>
+
+</html>
\ No newline at end of file
diff --git a/apps/manifest.json b/apps/manifest.json
new file mode 100644 (file)
index 0000000..cc9af22
--- /dev/null
@@ -0,0 +1,21 @@
+{
+    "short_name": "PerlCNFWEB",
+    "name": "PerlCNFWEBServer App",
+    "icons": [
+      {
+        "src": "images/favicons/PerlCNFEagle_192x192.png",
+        "sizes": "192x192",
+        "type": "image/png"
+      },
+      {
+        "src": "images/favicons/PerlCNFEagle_512x512.png",
+        "sizes": "512x512",
+        "type": "image/png"
+      }
+    ],
+    "start_url": ".",
+    "display": "standalone",
+    "theme_color": "#000000",
+    "background_color": "#ffffff"
+  }
+  
\ No newline at end of file