mostly filebased Content Presentation System
No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

447 líneas
16KB

  1. <?php
  2. namespace Modules;
  3. class FilesInFolders {
  4. private $folder;
  5. public $content = array();
  6. public $extras = array();
  7. private $domains = array('default'=>'default');
  8. private $keyfiles = array();
  9. private $structs = array();
  10. private $EXT=array(
  11. 'txt'=>array( 'txt', 'text', 'md' ),
  12. 'pic'=>array( 'jpg', 'jpeg', 'png', 'svg' ),
  13. 'tpl'=>array( 'html', 'htm', 'tpl' ),
  14. 'csv'=>array( 'csv' )
  15. );
  16. public $config = array();
  17. private $state=array();
  18. function __construct($folder,$conf=array()) {
  19. $f3 = \Base::instance();
  20. if(is_dir($folder)) { // are we given a valid path?
  21. $this->folder = $folder;
  22. } else { // and if not?
  23. $this->folder = $f3->get('CONTENT')."./";
  24. }
  25. if(is_array($conf)) {
  26. foreach($conf as $key=>$value) {
  27. switch($key) {
  28. case 'content':
  29. if(is_array($value)) {
  30. foreach($value as $k=>$v) {
  31. $this->domains[$k] = $v;
  32. }
  33. }
  34. break;
  35. case 'keyfiles':
  36. if(is_array($value)) {
  37. foreach($value as $k=>$v) {
  38. $this->keyfiles[$k] = $v;
  39. }
  40. }
  41. break;
  42. }
  43. }
  44. }
  45. foreach($this->domains as $domain) {
  46. $this->content[$domain] = array();
  47. }
  48. foreach($this->keyfiles as $keys=>$d) {
  49. $this->extras[$keys] = "";
  50. }
  51. }
  52. /////////////////////////////
  53. // read folder into struct //
  54. /////////////////////////////
  55. function prepare_files() {
  56. foreach ($this->domains as $k=>$v) {
  57. foreach($this->EXT as $cat=>$endings) {
  58. $this->structs[$k][$cat]=array();
  59. }
  60. }
  61. $ls = scandir($this->folder);
  62. foreach ($ls as $k=>$f) {
  63. if (!strncmp($f,'.',1)) continue; // ignore hidden files
  64. $ex=explode(".", $f);
  65. $ext=strtolower(end($ex));
  66. if (array_key_exists($ex[0],$this->domains)) {
  67. $domain=$ex[0];
  68. $sort_key=1;
  69. } elseif (array_key_exists($ex[0], $this->keyfiles)) {
  70. if(in_array($ext,$this->EXT[$this->keyfiles[$ex[0]]['type']])) {
  71. $this->extras[$ex[0]]=$this->folder.$f;
  72. continue;
  73. }
  74. } else {
  75. $domain='default';
  76. $sort_key=0;
  77. }
  78. foreach ($this->EXT as $cat=>$endings) {
  79. if (in_array($ext, $endings)) {
  80. $this->structs[$domain][$cat][$ex[$sort_key]] = $this->folder.$f;
  81. }
  82. }
  83. }
  84. foreach($this->keyfiles as $key=>$param) {
  85. if(!$this->extras[$key]) {
  86. $this->extras[$key] = self::search_up(
  87. $key,
  88. array($this->folder,$param['until']),
  89. $this->EXT[$param['type']]);
  90. }
  91. }
  92. }
  93. ///////////////////////////////////////
  94. // prepare content as per the struct //
  95. ///////////////////////////////////////
  96. function fill_content() {
  97. $md = new \Parsedown();
  98. foreach($this->domains as $source=>$destination) {
  99. $this->state['current_domain'] = $source;
  100. foreach($this->structs[$source]['txt'] as $key=>$file) {
  101. $str = $this->read_textfile($file);
  102. $str = self::content_element_dispatcher($str);
  103. $str = $md->text($str);
  104. $str = sprintf("<div class='post'>%s</div>", $str);
  105. $this->content[$destination][$key] = sprintf(
  106. "<div class=\"item %s %s\">%s</div>",
  107. $page,
  108. $key,
  109. $str
  110. );
  111. }
  112. // var_dump($this->structs);
  113. foreach($this->structs[$source]['tpl'] as $key=>$file) {
  114. $str = file_get_contents($file);
  115. $str = \Template::instance()->render($file);
  116. $str = self::linkify($str);
  117. $this->content[$destination][$key] = sprintf(
  118. "<div class=\"item %s %s\">%s</div>",
  119. $page,
  120. $key,
  121. $str
  122. );
  123. }
  124. foreach($this->structs[$source]['pic'] as $key=>$file) {
  125. $this->content[$destination][$key] = sprintf(
  126. "<img class=\"direct\" src=\"/$file\" />"
  127. );
  128. }
  129. foreach($this->structs[$source]['csv'] as $key=>$file) {
  130. $csv = new \Modules\Ography($file,TRUE);
  131. $str="<table>";
  132. foreach($csv->entries as $entry) {
  133. $tmp="";
  134. foreach($entry as $key=>$value) {
  135. $tmp .= sprintf("<td class=\"%s\">%s</td>", $key, $value);
  136. }
  137. $str .= sprintf("<tr>%s</tr>",$tmp);
  138. }
  139. $str.="</table>";
  140. $this->content[$destination][$key] = $str;
  141. }
  142. }
  143. }
  144. //////////////////////
  145. // read config data //
  146. //////////////////////
  147. function read_config($domain=false) {
  148. foreach ($this->domains as $source=>$destination) {
  149. if (is_string($domain)) {
  150. if ($source != $domain) { continue; }
  151. } elseif (is_array($domain)) {
  152. if (!in_array($source,$domain)) { continue; }
  153. }
  154. foreach ($this->structs[$source]['txt'] as $key=>$file) {
  155. $this->read_textfile($file);
  156. }
  157. }
  158. return $this->config;
  159. }
  160. ////////////////
  161. // recursions //
  162. ////////////////
  163. function search_up($key,$paths,$ext) {
  164. $return = "";
  165. if(count($paths) == 2) {
  166. $current = $paths[0];
  167. $last_try = $paths[1];
  168. $ls=scandir($current);
  169. foreach($ls as $f) {
  170. if(!strncmp($f,'.',1)) continue; // ignore hidden files
  171. $ex=explode(".", $f);
  172. if(in_array(strtolower(end($ex)),$ext)) {
  173. if($ex[0]==$key) {
  174. $return = $current.$f;
  175. break;
  176. }
  177. }
  178. }
  179. }
  180. if ($return) {
  181. return $return;
  182. } elseif($current == $last_try) {
  183. return false;
  184. } else {
  185. $p = explode('/',$current);
  186. array_pop($p);
  187. array_pop($p);
  188. return self::search_up($key,array(implode("/",$p)."/",$last_try),$ext);
  189. }
  190. }
  191. ///////////////////////
  192. // Utility functions //
  193. ///////////////////////
  194. function read_textfile($file) {
  195. $str = file_get_contents($file);
  196. $str = self::linkify($str);
  197. $str = self::get_config_from_content($str);
  198. return $str;
  199. }
  200. function linkify($string) {
  201. $pattern = "/\s@(\w+)[=]([\w,]+)\s/";
  202. $count = 0;
  203. $new = preg_replace_callback
  204. ($pattern,
  205. function($m){
  206. $f3 = \Base::instance();
  207. return $f3->get('SITE_URL')
  208. .$f3->alias($m[1],self::$keyword."=".$m[2])
  209. ;},
  210. $string);
  211. return $new;
  212. }
  213. function get_config_from_content($string) {
  214. $f3 = \Base::instance();
  215. $f = 0;
  216. $pattern = "/#\+(\w+):\s?(.*)/";
  217. $f = preg_match_all($pattern, $string,$matches,PREG_PATTERN_ORDER);
  218. for ($i=0;$i<$f;$i++) {
  219. $string = str_replace($matches[0][$i],"",$string);
  220. $key = $matches[1][$i];
  221. $value = $matches[2][$i];
  222. if(!strncmp(trim($value),'@',1)) {
  223. //var_dump($f3->get('DATA'));
  224. if (array_key_exists($key,$f3->get('DATA'))) {
  225. $DATA = $f3->get('DATA.'.$key);
  226. $conf = array($DATA['type'],$DATA['dir']);
  227. $relation = new \Modules\TOC($conf,$f3->get('CONTENT'),substr($value,1));
  228. $relation->dispatch();
  229. $this->config[$key]=array_shift($relation->entries);
  230. } else {
  231. $this->config[$key]=$value;
  232. }
  233. } else {
  234. $this->config[$key]=$value;
  235. }
  236. }
  237. $pattern = "/§>\s*(\w+):(.*?)\R[\011\040]*\R/s";
  238. $f = preg_match_all($pattern, $string,$matches,PREG_PATTERN_ORDER);
  239. for ($i=0;$i<$f;$i++) {
  240. $string = str_replace($matches[0][$i],"",$string);
  241. $key = $matches[1][$i];
  242. $value = trim($matches[2][$i]);
  243. if (!strncmp($value,'@',1)) {
  244. # var_dump();
  245. if (array_key_exists($key,$f3->get('DATA'))) {
  246. $entries = explode("@",$value);
  247. array_shift($entries); // first entry is always empty
  248. $DATA = $f3->get('DATA.'.$key);
  249. $conf = array($DATA['type'],$DATA['dir']);
  250. $relation = new \Modules\TOC($conf,$f3->get('CONTENT'),$entries);
  251. $relation->dispatch();
  252. if(/*count($entries) >*/ 1) {
  253. $this->config[$key]= new CMultiple($relation->entries);
  254. } else {
  255. $this->config[$key]=array_shift($relation->entries);
  256. }
  257. } else {
  258. $this->config[$key]=$value;
  259. }
  260. } else {
  261. $this->config[$key]=$value;
  262. }
  263. }
  264. return $string;
  265. }
  266. function content_element_dispatcher($string) {
  267. $md = new \Parsedown();
  268. $f0 = 0;
  269. // find occorances of {| keyword |}
  270. $pattern = "/\{\|(.+?)\|\}/s";
  271. $f = preg_match_all($pattern, $string,$matches,PREG_PATTERN_ORDER);
  272. for ($i=0;$i<$f;$i++) {
  273. $body = preg_split("/\R/",trim($matches[1][$i]));
  274. $request = explode(":", trim(array_shift($body)));
  275. $new="";
  276. switch($request[0]) {
  277. case 'test':
  278. $new="seems to work";
  279. break;
  280. case 'path':
  281. $new="/".$this->folder;
  282. break;
  283. case 'space':
  284. $new=sprintf("<div style=\"height:%s;\"></div>",
  285. $request[1]
  286. );
  287. break;
  288. case 'small-text':
  289. if(count($body)) {
  290. $new=sprintf("<div class=\"f1\">%s</div>",
  291. implode("\n",$body)
  292. );
  293. } else {
  294. $new=sprintf("<span class=\"f1\">%s</span>",
  295. $request[1]
  296. );
  297. }
  298. break;
  299. case 'TOC':
  300. // throw away TOC part of request, we don't need it
  301. array_shift($request);
  302. $toc = new \Modules\TOC($request,$this->folder,$body);
  303. $toc->dispatch();
  304. $new=sprintf("<div class=\"TOC %s\">%s</div>",
  305. array_shift($request),
  306. $toc);
  307. break;
  308. case 'header':
  309. array_shift($request);
  310. $conf = array('path', $this->folder);
  311. $v = $this->read_config();
  312. switch (array_shift($request)) {
  313. case 'event':
  314. $el = new CEvent($v,$conf);
  315. $el->set_layout('archive');
  316. $new = $el;
  317. break;
  318. case 'concert':
  319. $el = new CConcert($v,$conf);
  320. $el->set_layout('header');
  321. $new = $el;
  322. break;
  323. }
  324. break;
  325. case 'image':
  326. $key=$request[1];
  327. $image="";
  328. if(!$key) {
  329. $new=self::warn("Content Module \"Image\" needs name of a file (without extension)");
  330. break;
  331. }
  332. foreach($this->structs as $domain=>$destination) {
  333. if(array_key_exists($key, $this->structs[$domain]['pic'])) {
  334. $image = $this->structs[$domain]['pic'][$key];
  335. unset($this->structs[$domain]['pic'][$key]);
  336. unset($this->content[$this->domains[$domain]][$key]);
  337. break;
  338. }
  339. }
  340. if ($image) {
  341. if( in_array($request[2],array('left','right'))) {
  342. $class = $request[2];
  343. } else {
  344. $class = 'left';
  345. }
  346. $img = new \Image($image);
  347. $ratio = ($img->width() >= $img->height())
  348. ? "landscape"
  349. : "portrait"
  350. ;
  351. $cached = new CachedImage($image);
  352. $new=sprintf("<div class='image-container %s'>"
  353. ."<div class=\"media %s\"><a href=\"/%s\" data-featherlight=\"image\"><img src=\"/%s\" /></a></div>"
  354. ."<img src=\"/%s\" style=\"display:none;\" />"
  355. ."<div class=\"caption\">%s</div>"
  356. ."</div>",
  357. $class,
  358. $ratio,
  359. $cached->get_src(1400),
  360. $cached->get_src(500),
  361. $cached->get_src(1400),
  362. $md->text(implode("\n",$body))
  363. );
  364. } else {
  365. $new=self::warn("image \"$key\" not found");
  366. }
  367. break;
  368. case 'youtube':
  369. if( in_array($request[2],array('left','right'))) {
  370. $class = $request[2];
  371. } else {
  372. $class = 'left';
  373. }
  374. $video=sprintf("<iframe width=\"700vw\" height=\"394vw\" class=\"ytvideo\" "
  375. ."src=\"https://www.youtube.com/embed/%s\"></iframe>",
  376. $request[1]);
  377. $thumbnail = sprintf("<div class=\"video-thumbnail\"><a href=\"%s\" data-featherlight=\"#%s\">"
  378. ."<img class=\"thumbnail\" src=\"https://img.youtube.com/vi/%s/mqdefault.jpg\" />"
  379. ."<img class=\"play-button\" src=\"%s\" />"
  380. ."</a></div><div class=\"lightbox\" id=\"%s\" >%s</div>",
  381. "https://www.youtube.com/watch?v=".$request[1],
  382. $request[1],
  383. $request[1],
  384. "/rsc/img/play-button.png",
  385. $request[1],
  386. $video
  387. );
  388. $new=sprintf("<div class='video-container %s'>"
  389. ."<div class=\"media\">%s</div>"
  390. ."<div class=\"caption\">%s</div>"
  391. ."</div>",
  392. $class,
  393. $thumbnail,
  394. $md->text(implode("\n",$body)));
  395. break;
  396. default:
  397. $new=self::warn("Content Module \"".$request[0]."\" unknown");
  398. break;
  399. }
  400. $string = str_replace($matches[0][$i],$new,$string);
  401. }
  402. return $string;
  403. }
  404. function warn($message) {
  405. return sprintf("<div class=\"warning\">%s</div>",$message);
  406. }
  407. }