WikiPage.class.php 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. <?php
  2. /**
  3. * Define a page.
  4. * @author Valentin CARRUESCO
  5. * @category Plugin
  6. * @license copyright
  7. */
  8. class WikiPage extends Entity{
  9. public $id,$label,$content,$state,$path,$category,$slug,$sort = 0;
  10. const PUBLISHED = 'published';
  11. const DRAFT = 'draft';
  12. protected $TABLE_NAME = 'wiki_page';
  13. public $links = array(
  14. 'category' => 'WikiCategory'
  15. );
  16. public $fields =
  17. array(
  18. 'id' => 'key',
  19. 'label' => 'string',
  20. 'state' => 'string',
  21. 'category' => 'int',
  22. 'slug' => 'string',
  23. 'sort' => 'int',
  24. 'path' => 'string'
  25. );
  26. public static function defaultContent(){
  27. $default = 'Mon contenu ici...';
  28. $defaultFile = File::dir().'wiki'.SLASH.'default.md';
  29. if(file_exists($defaultFile)) $default = file_get_contents($defaultFile);
  30. return $default;
  31. }
  32. public static function workspace(){
  33. return File::dir().'wiki'.SLASH.'pages';
  34. }
  35. public static function uploads(){
  36. return File::dir().'wiki'.SLASH.'uploads';
  37. }
  38. public static function path_from_label($label){
  39. return preg_replace('|[\?\\\/\*\:\|\<\>]|i', '-',$label);
  40. }
  41. public function author(){
  42. return User::byLogin($this->creator, false)->fullName();
  43. }
  44. public function created(){
  45. return relative_time($this->created);
  46. }
  47. public function updater(){
  48. return User::byLogin($this->updater, false)->fullName();
  49. }
  50. public function updated(){
  51. return relative_time($this->updated);
  52. }
  53. public function html(){
  54. $markdown = new WikiPageParsedown();
  55. $markdown->setBreaksEnabled(true);
  56. return $markdown->text($this->content);
  57. }
  58. public function content(){
  59. $this->content = file_get_contents(self::workspace().SLASH.wiki_os_encode($this->path));
  60. }
  61. }
  62. require_once(__DIR__.SLASH.'lib'.SLASH.'Parsedown.php');
  63. //Etend la classe parsedown pour y ajouter des features (ex:le souligné (__texte souligné__))
  64. class WikiPageParsedown extends Parsedown{
  65. protected function paragraph($Line)
  66. {
  67. if (substr($Line['text'], -1) === '#')
  68. {
  69. $closed = true;
  70. $Line['text'] = substr($Line['text'], 0, -1);
  71. }
  72. $Block = parent::paragraph($Line);
  73. if (isset($closed))
  74. {
  75. $Block['closed'] = true;
  76. }
  77. return $Block;
  78. }
  79. protected function paragraphContinue($Line, array $Block)
  80. {
  81. if (isset($Block['closed']))
  82. {
  83. return;
  84. }
  85. if (isset($Block['interrupted']))
  86. {
  87. $Block['element']['handler']['argument'] .= ' '.str_repeat("\n ", $Block['interrupted']);
  88. unset($Block['interrupted']);
  89. }
  90. if (substr($Line['text'], -1) === '#')
  91. {
  92. $Block['closed'] = true;
  93. $Line['text'] = substr($Line['text'], 0, -1);
  94. }
  95. $Block['element']['handler']['argument'] .= "\n".$Line['text'];
  96. return $Block;
  97. }
  98. protected function blockCode($Line, $Block = null)
  99. {
  100. if (isset($Block) and $Block['type'] === 'Paragraph' and ! isset($Block['interrupted']))
  101. {
  102. return;
  103. }
  104. if ($Line['indent'] >= 4)
  105. {
  106. $text = substr($Line['body'], 4);
  107. $Block = array(
  108. 'element' => array(
  109. 'name' => 'pre',
  110. 'element' => array(
  111. 'name' => 'code',
  112. 'attributes' => array('class' => "block-code"),
  113. 'text' => $text,
  114. ),
  115. ),
  116. );
  117. return $Block;
  118. }
  119. }
  120. protected function blockQuote($Line)
  121. {
  122. if (preg_match('/^>[ ]?+(.*+)/', $Line['text'], $matches))
  123. {
  124. $Block = array(
  125. 'element' => array(
  126. 'name' => 'blockquote',
  127. 'attributes' => array('class' => "blockquote"),
  128. 'handler' => array(
  129. 'function' => 'linesElements',
  130. 'argument' => (array) $matches[1],
  131. 'destination' => 'elements',
  132. )
  133. ),
  134. );
  135. return $Block;
  136. }
  137. }
  138. protected function blockTable($Line, array $Block = null)
  139. {
  140. if ( ! isset($Block) or $Block['type'] !== 'Paragraph' or isset($Block['interrupted']))
  141. {
  142. return;
  143. }
  144. if (
  145. strpos($Block['element']['handler']['argument'], '|') === false
  146. and strpos($Line['text'], '|') === false
  147. and strpos($Line['text'], ':') === false
  148. or strpos($Block['element']['handler']['argument'], "\n") !== false
  149. ) {
  150. return;
  151. }
  152. if (chop($Line['text'], ' -:|') !== '')
  153. {
  154. return;
  155. }
  156. $alignments = array();
  157. $divider = $Line['text'];
  158. $divider = trim($divider);
  159. $divider = trim($divider, '|');
  160. $dividerCells = explode('|', $divider);
  161. foreach ($dividerCells as $dividerCell)
  162. {
  163. $dividerCell = trim($dividerCell);
  164. if ($dividerCell === '')
  165. {
  166. return;
  167. }
  168. $alignment = null;
  169. if ($dividerCell[0] === ':')
  170. {
  171. $alignment = 'left';
  172. }
  173. if (substr($dividerCell, - 1) === ':')
  174. {
  175. $alignment = $alignment === 'left' ? 'center' : 'right';
  176. }
  177. $alignments []= $alignment;
  178. }
  179. # ~
  180. $HeaderElements = array();
  181. $header = $Block['element']['handler']['argument'];
  182. $header = trim($header);
  183. $header = trim($header, '|');
  184. $headerCells = explode('|', $header);
  185. if (count($headerCells) !== count($alignments))
  186. {
  187. return;
  188. }
  189. foreach ($headerCells as $index => $headerCell)
  190. {
  191. $headerCell = trim($headerCell);
  192. $HeaderElement = array(
  193. 'name' => 'th',
  194. 'handler' => array(
  195. 'function' => 'lineElements',
  196. 'argument' => $headerCell,
  197. 'destination' => 'elements',
  198. )
  199. );
  200. if (isset($alignments[$index]))
  201. {
  202. $alignment = $alignments[$index];
  203. $HeaderElement['attributes'] = array(
  204. 'style' => "text-align: $alignment;"
  205. );
  206. }
  207. $HeaderElements []= $HeaderElement;
  208. }
  209. # ~
  210. $Block = array(
  211. 'alignments' => $alignments,
  212. 'identified' => true,
  213. 'element' => array(
  214. 'name' => 'table',
  215. 'attributes' => array('class' => "table"), /* + sys1 */
  216. 'elements' => array(),
  217. ),
  218. );
  219. $Block['element']['elements'] []= array(
  220. 'name' => 'thead',
  221. );
  222. $Block['element']['elements'] []= array(
  223. 'name' => 'tbody',
  224. 'elements' => array(),
  225. );
  226. $Block['element']['elements'][0]['elements'] []= array(
  227. 'name' => 'tr',
  228. 'elements' => $HeaderElements,
  229. );
  230. return $Block;
  231. }
  232. protected function blockFencedCode($Line)
  233. {
  234. $marker = $Line['text'][0];
  235. $openerLength = strspn($Line['text'], $marker);
  236. if ($openerLength < 3)
  237. {
  238. return;
  239. }
  240. $infostring = trim(substr($Line['text'], $openerLength), "\t ");
  241. if (strpos($infostring, '`') !== false)
  242. {
  243. return;
  244. }
  245. $Element = array(
  246. 'name' => 'code',
  247. 'attributes' => array('class' => "block-code"),
  248. 'text' => '',
  249. );
  250. if ($infostring !== '')
  251. {
  252. $Element['attributes'] = array('class' => "language-$infostring");
  253. }
  254. $Block = array(
  255. 'char' => $marker,
  256. 'openerLength' => $openerLength,
  257. 'element' => array(
  258. 'name' => 'pre',
  259. 'element' => $Element,
  260. ),
  261. );
  262. return $Block;
  263. }
  264. protected function inlineCode($Excerpt)
  265. {
  266. $marker = $Excerpt['text'][0];
  267. if (preg_match('/^(['.$marker.']++)[ ]*+(.+?)[ ]*+(?<!['.$marker.'])\1(?!'.$marker.')/s', $Excerpt['text'], $matches))
  268. {
  269. $text = $matches[2];
  270. $text = preg_replace('/[ ]*+\n/', ' ', $text);
  271. return array(
  272. 'extent' => strlen($matches[0]),
  273. 'element' => array(
  274. 'name' => 'code',
  275. 'attributes' => array('class' => "inline-code"),
  276. 'text' => $text,
  277. ),
  278. );
  279. }
  280. }
  281. protected function inlineEmphasis($Excerpt)
  282. {
  283. if ( ! isset($Excerpt['text'][1]))
  284. {
  285. return;
  286. }
  287. $marker = $Excerpt['text'][0];
  288. if(preg_match('/^__([^__]*)__/us', $Excerpt['text'], $matches)){
  289. $emphasis = 'u';
  290. }else if ($Excerpt['text'][1] === $marker and preg_match($this->StrongRegex[$marker], $Excerpt['text'], $matches))
  291. {
  292. $emphasis = 'strong';
  293. }
  294. elseif (preg_match($this->EmRegex[$marker], $Excerpt['text'], $matches))
  295. {
  296. $emphasis = 'em';
  297. }
  298. else
  299. {
  300. return;
  301. }
  302. return array(
  303. 'extent' => strlen($matches[0]),
  304. 'element' => array(
  305. 'name' => $emphasis,
  306. 'attributes' => array(
  307. 'class' => 'emphasis-underscore' ,
  308. ),
  309. 'handler' => array(
  310. 'function' => 'lineElements',
  311. 'argument' => $matches[1],
  312. 'destination' => 'elements',
  313. )
  314. ),
  315. );
  316. }
  317. }
  318. ?>