'default'); private $keyfiles = array(); public $structs = array(); private $EXT=array( 'txt'=>array( 'txt', 'text', 'md' ), 'pic'=>array( 'jpg', 'jpeg', 'png', 'svg' ), 'tpl'=>array( 'html', 'htm', 'tpl' ), 'csv'=>array( 'csv' ) ); public $config = array(); private $state=array(); function __construct($folder,$conf=array()) { $f3 = \Base::instance(); if(is_dir($folder)) { // are we given a valid path? $this->folder = $folder; } else { // and if not? $this->folder = $f3->get('CONTENT')."./"; } if(is_array($conf)) { foreach($conf as $key=>$value) { switch($key) { case 'content': if(is_array($value)) { foreach($value as $k=>$v) { $this->domains[$k] = $v; } } break; case 'keyfiles': if(is_array($value)) { foreach($value as $k=>$v) { $this->keyfiles[$k] = $v; } } break; } } } foreach($this->domains as $domain) { $this->content[$domain] = array(); } foreach($this->keyfiles as $keys=>$d) { $this->extras[$keys] = ""; } } ///////////////////////////// // read folder into struct // ///////////////////////////// function prepare_files() { foreach ($this->domains as $k=>$v) { foreach($this->EXT as $cat=>$endings) { $this->structs[$k][$cat]=array(); } } $ls = scandir($this->folder); foreach ($ls as $k=>$f) { if (!strncmp($f,'.',1)) continue; // ignore hidden files $ex=explode(".", $f); $ext=strtolower(end($ex)); if (array_key_exists($ex[0],$this->domains)) { $domain_key=$ex[0]; $sort_key=1; } elseif (array_key_exists($ex[0], $this->keyfiles)) { if(in_array($ext,$this->EXT[$this->keyfiles[$ex[0]]['type']])) { $this->extras[$ex[0]]=$this->folder.$f; continue; } $domain_key='default'; $sort_key=0; } else { $domain_key='default'; $sort_key=0; } foreach ($this->EXT as $cat=>$endings) { if (in_array($ext, $endings)) { $this->structs[$domain_key][$cat][$ex[$sort_key]] = $this->folder.$f; break; } } } foreach($this->keyfiles as $key=>$param) { if(!$this->extras[$key]) { $this->extras[$key] = self::search_up( $key, array($this->folder,$param['until']), $this->EXT[$param['type']] ); } if($this->extras[$key]) { if ($param['type'] == 'txt') { $this->read_textfile($this->extras[$key]); } } } } /////////////////////////////////////// // prepare content as per the struct // /////////////////////////////////////// function fill_content() { $md = new \Parsedown(); foreach($this->domains as $domain_key=>$domain) { $this->state['current_domain'] = $domain_key; foreach($this->structs[$domain_key]['txt'] as $key=>$file) { $str = $this->read_textfile($file); $str = self::content_element_dispatcher($str); $str = $md->text($str); $str = sprintf("
%s
", $str); $this->content[$domain][$key] = sprintf( "
%s
", $page, $key, $str ); } foreach($this->structs[$domain_key]['tpl'] as $key=>$file) { $str = file_get_contents($file); $str = \Template::instance()->render($file); $str = self::linkify($str); $this->content[$domain][$key] = sprintf( "
%s
", $page, $key, $str ); } if (false) { // TODO: make this configurable in main.cfg foreach($this->structs[$domain_key]['pic'] as $key=>$file) { $this->content[$domain][$key] = sprintf( "" ); } } foreach($this->structs[$domain_key]['csv'] as $key=>$file) { $csv = new \Modules\Ography($file,TRUE); $str=""; foreach($csv->entries as $entry) { $tmp=""; foreach($entry as $key=>$value) { $tmp .= sprintf("", $key, $value); } $str .= sprintf("%s",$tmp); } $str.="
%s
"; $this->content[$domain][$key] = $str; } } } ////////////////////// // read config data // ////////////////////// function read_config($domain=false) { foreach ($this->domains as $source=>$destination) { if (is_string($domain)) { if ($source != $domain) { continue; } } elseif (is_array($domain)) { if (!in_array($source,$domain)) { continue; } } foreach ($this->structs[$source]['txt'] as $key=>$file) { $this->read_textfile($file); } } return $this->config; } //////////////// // recursions // //////////////// function search_up($key,$paths,$ext) { $return = ""; if(count($paths) == 2) { $current = $paths[0]; $last_try = $paths[1]; $ls=scandir($current); foreach($ls as $f) { if(!strncmp($f,'.',1)) continue; // ignore hidden files $ex=explode(".", $f); if(in_array(strtolower(end($ex)),$ext)) { if($ex[0]==$key) { $return = $current.$f; break; } } } } if ($return) { return $return; } elseif($current == $last_try) { return false; } else { $p = explode('/',$current); array_pop($p); array_pop($p); return self::search_up($key,array(implode("/",$p)."/",$last_try),$ext); } } /////////////////////// // Utility functions // /////////////////////// function read_textfile($file) { $str = file_get_contents($file); $str = self::linkify($str); $str = self::strip_comments($str); $str = self::get_config_from_content($str); return $str; } function strip_comments($str) { $single_line_comments = "/(^;.*\R)/m"; $str = preg_replace($single_line_comments,"",$str); $multi_line_comments = "/\/\*.*?\*\//s"; $str = preg_replace($multi_line_comments,"",$str); return $str; } function linkify($string) { $pattern = "/\s@(\w+)[=]([\w,]+)\s/"; $count = 0; $new = preg_replace_callback ($pattern, function($m){ $f3 = \Base::instance(); return $f3->get('SITE_URL') .$f3->alias($m[1],self::$keyword."=".$m[2]) ;}, $string); return $new; } function get_config_from_content($string) { $f3 = \Base::instance(); $f = 0; $pattern = "/#\+(\w+):\s?(.*)/"; $f = preg_match_all($pattern, $string,$matches,PREG_PATTERN_ORDER); for ($i=0;$i<$f;$i++) { $string = str_replace($matches[0][$i],"",$string); $key = $matches[1][$i]; $value = $matches[2][$i]; if(strtolower($value) == "false") { $value = FALSE; } if(!strncmp(trim($value),'@',1)) { //var_dump($f3->get('DATA')); if (array_key_exists($key,$f3->get('DATA'))) { $DATA = $f3->get('DATA.'.$key); $conf = array($DATA['type'],$DATA['dir']); $relation = new \Modules\TOC($conf,$f3->get('CONTENT'),substr($value,1)); $relation->dispatch(); $this->config[$key]=array_shift($relation->entries); } else { $this->config[$key]=$value; } } else { $this->config[$key]=$value; } } $pattern = "/§>\s*(\w+):(.*?)\R[\011\040]*\R/s"; $f = preg_match_all($pattern, $string,$matches,PREG_PATTERN_ORDER); for ($i=0;$i<$f;$i++) { $string = str_replace($matches[0][$i],"",$string); $key = $matches[1][$i]; $value = trim($matches[2][$i]); if(strtolower($value) == "false") { $value = FALSE; } if (!strncmp($value,'@',1)) { # var_dump(); if (array_key_exists($key,$f3->get('DATA'))) { $entries = explode("@",$value); array_shift($entries); // first entry is always empty $DATA = $f3->get('DATA.'.$key); $conf = array($DATA['type'],$DATA['dir']); $relation = new \Modules\TOC($conf,$f3->get('CONTENT'),$entries); $relation->dispatch(); if(/*count($entries) >*/ 1) { $this->config[$key]= new CMultiple($relation->entries); } else { $this->config[$key]=array_shift($relation->entries); } } else { $this->config[$key]=$value; } } else { $this->config[$key]=$value; } } return $string; } function content_element_dispatcher($string) { $f3 = \Base::instance(); $md = new \Parsedown(); $f0 = 0; // find occorances of {| keyword |} $pattern = "/\{\|(.+?)\|\}/s"; $f = preg_match_all($pattern, $string,$matches,PREG_PATTERN_ORDER); for ($i=0;$i<$f;$i++) { $body = preg_split("/\R/",trim($matches[1][$i])); $request = explode(":", trim(array_shift($body))); $new=""; switch($request[0]) { case 'test': $new="seems to work"; break; case ';': $new=""; break; case 'path': $new="/".$this->folder; break; case 'space': $new=sprintf("
", $request[1] ); break; case 'small-text': if(count($body)) { $new=sprintf("
%s
", implode("\n",$body) ); } else { $new=sprintf("%s", $request[1] ); } break; case 'TOC': // throw away TOC part of request, we don't need it array_shift($request); $toc = new \Modules\TOC($request,$this->folder,$body); $toc->dispatch(); $new=sprintf("
%s
", array_shift($request), $toc); break; case 'box': array_shift($request); //get rid of identifier $type = array_shift($request); $pics = explode(":",array_shift($body)); $pic = $pics[0]; $pic_hover = count($pics) > 1 ? $pics[1] : $pic; $cap1 = array_shift($body); $cap2 = array_shift($body); $cap1_hover = array_shift($body); $cap2_hover = array_shift($body); $pic = new CachedImage($this->folder.$pic); $pic_hover = new CachedImage($this->folder.$pic_hover); switch($type) { case 'download': $file = "/".$this->folder.implode(":",$request); $link='href="'.$file.'" download '; break; case 'lightbox': $body = implode("\n",$body); if (count($request) >= 2) { $body=str_replace([$request[0],$request[1]],["{|","|}"],$body); $body=$this->content_element_dispatcher($body); } $hash=md5($body); $add=sprintf('
%s
', $hash, $md->text($body)); $link='href="#" data-featherlight="#'.$hash.'" '; break; case 'internal': $dest=implode(":",$request); $link=sprintf('href="%s" ',$f3->get('SITE_URL')."/".$dest); break; case 'external': $dest=implode(":",$request); $link=sprintf('href="%s" target="_blank"',$dest); break; default: $link='href="#"'; break; } $new=sprintf("
%s
%s
%s
%s
%s
", $link, $pic->get_src(400), $pic_hover->get_src(400), $cap1,$cap2, $cap1_hover,$cap2_hover, $add ); break; case 'calendar': array_shift($request); $conf = array('path', $this->folder); $v = $this->read_config(); $cal = new \Modules\CCalendar($v,$conf); $new=sprintf("
%s
", $cal); break; case 'header': array_shift($request); $conf = array('path', $this->folder); $v = $this->read_config(); switch (array_shift($request)) { case 'event': $el = new CEvent($v,$conf); $el->set_layout('archive'); $new = $el; break; case 'concert': $el = new CConcert($v,$conf); $el->set_layout('header'); $new = $el; break; } break; case 'image': $key=$request[1]; $image=""; if(!$key) { $new=self::warn("Content Module \"Image\" needs name of a file (without extension)"); break; } foreach($this->structs as $domain=>$destination) { if(array_key_exists($key, $this->structs[$domain]['pic'])) { $image = $this->structs[$domain]['pic'][$key]; unset($this->structs[$domain]['pic'][$key]); unset($this->content[$this->domains[$domain]][$key]); break; } } if ($image) { if( in_array($request[2],array('left','right','full'))) { $class = $request[2]; } else { $class = 'left'; } $img = new \Image($image); $ratio = ($img->width() >= $img->height()) ? "landscape" : "portrait" ; $cached = new CachedImage($image); foreach ($body as $k=>$line) { if (strpos($line,"©") !== FALSE || strpos($line,"©") !== FALSE) { $body[$k] = sprintf("%s",$line); } } $new=sprintf("
" ."
\"user
" ."\"user" ."
%s
" ."
", $class, $ratio, $cached->get_src(1400), $cached->get_src(500), $cached->get_src(1400), $md->text(implode("\n",$body)) ); } else { $new=self::warn("image \"$key\" not found"); } break; case 'devide': $new = "
"; $contents = explode($request[1],implode("\n",$body)); $counter=0; foreach($contents as $part) { $counter++; if (count($request) >= 4) { $part=str_replace([$request[2],$request[3]],["{|","|}"],$part); $part=$this->content_element_dispatcher($part); } $new .= sprintf("
%s
", $md->text($part) ); } $new.="
"; break; case 'page': array_shift($request); $target = array_shift($request); $class = array_shift($request); $folder = $this->folder.$target."/"; $f = new \Modules\FilesInFolders($folder); $f->prepare_files(); $f->fill_content(); $new = sprintf('
%s
', $class, implode("\n",$f->content['default'])); break; case 'youtube': $vid=array_shift($request); $pos= array_shift($request); if( in_array($pos,array('left','right','full'))) { $class = $pos; } else { $class = 'left'; } $video=sprintf("", $vid); $thumbnail = sprintf("
" ."\"video-preview\"/" ."\"play-button\"" ."
%s
", "https://www.youtube.com/watch?v=".$vid, $vid, $vid, "/rsc/img/play-button.png", $vid, $video ); foreach ($body as $k=>$line) { if (strpos($line,"©") !== FALSE || strpos($line,"©") !== FALSE) { $body[$k] = sprintf("%s",$line); } } $new=sprintf("
" ."
%s
" ."
%s
" ."
", $class, $thumbnail, $md->text(implode("\n",$body))); break; default: $new=self::warn("Content Module \"".$request[0]."\" unknown"); break; } $string = str_replace($matches[0][$i],$new,$string); } return $string; } function warn($message) { return sprintf("
%s
",$message); } }