'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("%s | ", $key, $value);
}
$str .= sprintf("%s
",$tmp);
}
$str.="
";
$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("",
$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(""
."
"
."
"
."
%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("%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("",
$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);
}
}