1<?php 2if(!defined('DOKU_INC')) die('meh.'); 3require_once DOKU_INC . 'inc/parser/lexer.php'; 4require_once DOKU_INC . 'inc/parser/handler.php'; 5 6 7/** 8 * Define various types of modes used by the parser - they are used to 9 * populate the list of modes another mode accepts 10 */ 11global $PARSER_MODES; 12$PARSER_MODES = array( 13 // containers are complex modes that can contain many other modes 14 // hr breaks the principle but they shouldn't be used in tables / lists 15 // so they are put here 16 'container' => array('listblock','table','quote','hr'), 17 18 // some mode are allowed inside the base mode only 19 'baseonly' => array('header'), 20 21 // modes for styling text -- footnote behaves similar to styling 22 'formatting' => array('strong', 'emphasis', 'underline', 'monospace', 23 'subscript', 'superscript', 'deleted', 'footnote'), 24 25 // modes where the token is simply replaced - they can not contain any 26 // other modes 27 'substition' => array('acronym','smiley','wordblock','entity', 28 'camelcaselink', 'internallink','media', 29 'externallink','linebreak','emaillink', 30 'windowssharelink','filelink','notoc', 31 'nocache','multiplyentity','quotes','rss'), 32 33 // modes which have a start and end token but inside which 34 // no other modes should be applied 35 'protected' => array('preformatted','code','file','php','html','htmlblock','phpblock'), 36 37 // inside this mode no wiki markup should be applied but lineendings 38 // and whitespace isn't preserved 39 'disabled' => array('unformatted'), 40 41 // used to mark paragraph boundaries 42 'paragraphs' => array('eol') 43); 44 45//------------------------------------------------------------------- 46 47/** 48* Sets up the Lexer with modes and points it to the Handler 49* For an intro to the Lexer see: wiki:parser 50*/ 51class Doku_Parser { 52 53 var $Handler; 54 55 var $Lexer; 56 57 var $modes = array(); 58 59 var $connected = false; 60 61 function addBaseMode(& $BaseMode) { 62 $this->modes['base'] = & $BaseMode; 63 if ( !$this->Lexer ) { 64 $this->Lexer = new Doku_Lexer($this->Handler,'base', true); 65 } 66 $this->modes['base']->Lexer = & $this->Lexer; 67 } 68 69 /** 70 * PHP preserves order of associative elements 71 * Mode sequence is important 72 */ 73 function addMode($name, & $Mode) { 74 if ( !isset($this->modes['base']) ) { 75 $this->addBaseMode(new Doku_Parser_Mode_base()); 76 } 77 $Mode->Lexer = & $this->Lexer; 78 $this->modes[$name] = & $Mode; 79 } 80 81 function connectModes() { 82 83 if ( $this->connected ) { 84 return; 85 } 86 87 foreach ( array_keys($this->modes) as $mode ) { 88 89 // Base isn't connected to anything 90 if ( $mode == 'base' ) { 91 continue; 92 } 93 94 $this->modes[$mode]->preConnect(); 95 96 foreach ( array_keys($this->modes) as $cm ) { 97 98 if ( $this->modes[$cm]->accepts($mode) ) { 99 $this->modes[$mode]->connectTo($cm); 100 } 101 102 } 103 104 $this->modes[$mode]->postConnect(); 105 } 106 107 $this->connected = true; 108 } 109 110 function parse($doc) { 111 if ( $this->Lexer ) { 112 $this->connectModes(); 113 // Normalize CRs and pad doc 114 $doc = "\n".str_replace("\r\n","\n",$doc)."\n"; 115 $this->Lexer->parse($doc); 116 $this->Handler->_finalize(); 117 return $this->Handler->calls; 118 } else { 119 return false; 120 } 121 } 122 123} 124 125//------------------------------------------------------------------- 126/** 127 * This class and all the subclasses below are 128 * used to reduce the effort required to register 129 * modes with the Lexer. For performance these 130 * could all be eliminated later perhaps, or 131 * the Parser could be serialized to a file once 132 * all modes are registered 133 * 134 * @author Harry Fuecks <hfuecks@gmail.com> 135*/ 136class Doku_Parser_Mode { 137 138 var $Lexer; 139 140 var $allowedModes = array(); 141 142 // returns a number used to determine in which order modes are added 143 function getSort() { 144 trigger_error('getSort() not implemented in '.get_class($this), E_USER_WARNING); 145 } 146 147 // Called before any calls to connectTo 148 function preConnect() {} 149 150 // Connects the mode 151 function connectTo($mode) {} 152 153 // Called after all calls to connectTo 154 function postConnect() {} 155 156 function accepts($mode) { 157 return in_array($mode, (array) $this->allowedModes ); 158 } 159 160} 161 162//------------------------------------------------------------------- 163class Doku_Parser_Mode_base extends Doku_Parser_Mode { 164 165 function Doku_Parser_Mode_base() { 166 global $PARSER_MODES; 167 168 $this->allowedModes = array_merge ( 169 $PARSER_MODES['container'], 170 $PARSER_MODES['baseonly'], 171 $PARSER_MODES['paragraphs'], 172 $PARSER_MODES['formatting'], 173 $PARSER_MODES['substition'], 174 $PARSER_MODES['protected'], 175 $PARSER_MODES['disabled'] 176 ); 177 } 178 179 function getSort() { 180 return 0; 181 } 182} 183 184//------------------------------------------------------------------- 185class Doku_Parser_Mode_footnote extends Doku_Parser_Mode { 186 187 function Doku_Parser_Mode_footnote() { 188 global $PARSER_MODES; 189 190 $this->allowedModes = array_merge ( 191 $PARSER_MODES['container'], 192 $PARSER_MODES['formatting'], 193 $PARSER_MODES['substition'], 194 $PARSER_MODES['protected'], 195 $PARSER_MODES['disabled'] 196 ); 197 198 unset($this->allowedModes[array_search('footnote', $this->allowedModes)]); 199 } 200 201 function connectTo($mode) { 202 $this->Lexer->addEntryPattern( 203 '\x28\x28(?=.*\x29\x29)',$mode,'footnote' 204 ); 205 } 206 207 function postConnect() { 208 $this->Lexer->addExitPattern( 209 '\x29\x29','footnote' 210 ); 211 } 212 213 function getSort() { 214 return 150; 215 } 216} 217 218//------------------------------------------------------------------- 219class Doku_Parser_Mode_header extends Doku_Parser_Mode { 220 221 function preConnect() { 222 //we're not picky about the closing ones, two are enough 223 $this->Lexer->addSpecialPattern( 224 '[ \t]*={2,}[^\n]+={2,}[ \t]*(?=\n)', 225 'base', 226 'header' 227 ); 228 } 229 230 function getSort() { 231 return 50; 232 } 233} 234 235//------------------------------------------------------------------- 236class Doku_Parser_Mode_notoc extends Doku_Parser_Mode { 237 238 function connectTo($mode) { 239 $this->Lexer->addSpecialPattern('~~NOTOC~~',$mode,'notoc'); 240 } 241 242 function getSort() { 243 return 30; 244 } 245} 246 247//------------------------------------------------------------------- 248class Doku_Parser_Mode_nocache extends Doku_Parser_Mode { 249 250 function connectTo($mode) { 251 $this->Lexer->addSpecialPattern('~~NOCACHE~~',$mode,'nocache'); 252 } 253 254 function getSort() { 255 return 40; 256 } 257} 258 259//------------------------------------------------------------------- 260class Doku_Parser_Mode_linebreak extends Doku_Parser_Mode { 261 262 function connectTo($mode) { 263 $this->Lexer->addSpecialPattern('\x5C{2}(?:[ \t]|(?=\n))',$mode,'linebreak'); 264 } 265 266 function getSort() { 267 return 140; 268 } 269} 270 271//------------------------------------------------------------------- 272class Doku_Parser_Mode_eol extends Doku_Parser_Mode { 273 274 function connectTo($mode) { 275 $badModes = array('listblock','table'); 276 if ( in_array($mode, $badModes) ) { 277 return; 278 } 279 // see FS#1652, pattern extended to swallow preceding whitespace to avoid issues with lines that only contain whitespace 280 $this->Lexer->addSpecialPattern('(?:^[ \t]*)?\n',$mode,'eol'); 281 } 282 283 function getSort() { 284 return 370; 285 } 286} 287 288//------------------------------------------------------------------- 289class Doku_Parser_Mode_hr extends Doku_Parser_Mode { 290 291 function connectTo($mode) { 292 $this->Lexer->addSpecialPattern('\n[ \t]*-{4,}[ \t]*(?=\n)',$mode,'hr'); 293 } 294 295 function getSort() { 296 return 160; 297 } 298} 299 300//------------------------------------------------------------------- 301class Doku_Parser_Mode_formatting extends Doku_Parser_Mode { 302 var $type; 303 304 var $formatting = array ( 305 'strong' => array ( 306 'entry'=>'\*\*(?=.*\*\*)', 307 'exit'=>'\*\*', 308 'sort'=>70 309 ), 310 311 'emphasis'=> array ( 312 'entry'=>'//(?=[^\x00]*[^:])', //hack for bugs #384 #763 #1468 313 'exit'=>'//', 314 'sort'=>80 315 ), 316 317 'underline'=> array ( 318 'entry'=>'__(?=.*__)', 319 'exit'=>'__', 320 'sort'=>90 321 ), 322 323 'monospace'=> array ( 324 'entry'=>'\x27\x27(?=.*\x27\x27)', 325 'exit'=>'\x27\x27', 326 'sort'=>100 327 ), 328 329 'subscript'=> array ( 330 'entry'=>'<sub>(?=.*</sub>)', 331 'exit'=>'</sub>', 332 'sort'=>110 333 ), 334 335 'superscript'=> array ( 336 'entry'=>'<sup>(?=.*</sup>)', 337 'exit'=>'</sup>', 338 'sort'=>120 339 ), 340 341 'deleted'=> array ( 342 'entry'=>'<del>(?=.*</del>)', 343 'exit'=>'</del>', 344 'sort'=>130 345 ), 346 ); 347 348 function Doku_Parser_Mode_formatting($type) { 349 global $PARSER_MODES; 350 351 if ( !array_key_exists($type, $this->formatting) ) { 352 trigger_error('Invalid formatting type '.$type, E_USER_WARNING); 353 } 354 355 $this->type = $type; 356 357 // formatting may contain other formatting but not it self 358 $modes = $PARSER_MODES['formatting']; 359 $key = array_search($type, $modes); 360 if ( is_int($key) ) { 361 unset($modes[$key]); 362 } 363 364 $this->allowedModes = array_merge ( 365 $modes, 366 $PARSER_MODES['substition'], 367 $PARSER_MODES['disabled'] 368 ); 369 } 370 371 function connectTo($mode) { 372 373 // Can't nest formatting in itself 374 if ( $mode == $this->type ) { 375 return; 376 } 377 378 $this->Lexer->addEntryPattern( 379 $this->formatting[$this->type]['entry'], 380 $mode, 381 $this->type 382 ); 383 } 384 385 function postConnect() { 386 387 $this->Lexer->addExitPattern( 388 $this->formatting[$this->type]['exit'], 389 $this->type 390 ); 391 392 } 393 394 function getSort() { 395 return $this->formatting[$this->type]['sort']; 396 } 397} 398 399//------------------------------------------------------------------- 400class Doku_Parser_Mode_listblock extends Doku_Parser_Mode { 401 402 function Doku_Parser_Mode_listblock() { 403 global $PARSER_MODES; 404 405 $this->allowedModes = array_merge ( 406 $PARSER_MODES['formatting'], 407 $PARSER_MODES['substition'], 408 $PARSER_MODES['disabled'], 409 $PARSER_MODES['protected'] #XXX new 410 ); 411 412 // $this->allowedModes[] = 'footnote'; 413 } 414 415 function connectTo($mode) { 416 $this->Lexer->addEntryPattern('[ \t]*\n {2,}[\-\*]',$mode,'listblock'); 417 $this->Lexer->addEntryPattern('[ \t]*\n\t{1,}[\-\*]',$mode,'listblock'); 418 419 $this->Lexer->addPattern('\n {2,}[\-\*]','listblock'); 420 $this->Lexer->addPattern('\n\t{1,}[\-\*]','listblock'); 421 422 } 423 424 function postConnect() { 425 $this->Lexer->addExitPattern('\n','listblock'); 426 } 427 428 function getSort() { 429 return 10; 430 } 431} 432 433//------------------------------------------------------------------- 434class Doku_Parser_Mode_table extends Doku_Parser_Mode { 435 436 function Doku_Parser_Mode_table() { 437 global $PARSER_MODES; 438 439 $this->allowedModes = array_merge ( 440 $PARSER_MODES['formatting'], 441 $PARSER_MODES['substition'], 442 $PARSER_MODES['disabled'], 443 $PARSER_MODES['protected'] 444 ); 445 } 446 447 function connectTo($mode) { 448 $this->Lexer->addEntryPattern('\n\^',$mode,'table'); 449 $this->Lexer->addEntryPattern('\n\|',$mode,'table'); 450 } 451 452 function postConnect() { 453 $this->Lexer->addPattern('\n\^','table'); 454 $this->Lexer->addPattern('\n\|','table'); 455 $this->Lexer->addPattern('[\t ]*:::[\t ]*(?=[\|\^])','table'); 456 $this->Lexer->addPattern('[\t ]+','table'); 457 $this->Lexer->addPattern('\^','table'); 458 $this->Lexer->addPattern('\|','table'); 459 $this->Lexer->addExitPattern('\n','table'); 460 } 461 462 function getSort() { 463 return 60; 464 } 465} 466 467//------------------------------------------------------------------- 468class Doku_Parser_Mode_unformatted extends Doku_Parser_Mode { 469 470 function connectTo($mode) { 471 $this->Lexer->addEntryPattern('<nowiki>(?=.*</nowiki>)',$mode,'unformatted'); 472 $this->Lexer->addEntryPattern('%%(?=.*%%)',$mode,'unformattedalt'); 473 } 474 475 function postConnect() { 476 $this->Lexer->addExitPattern('</nowiki>','unformatted'); 477 $this->Lexer->addExitPattern('%%','unformattedalt'); 478 $this->Lexer->mapHandler('unformattedalt','unformatted'); 479 } 480 481 function getSort() { 482 return 170; 483 } 484} 485 486//------------------------------------------------------------------- 487class Doku_Parser_Mode_php extends Doku_Parser_Mode { 488 489 function connectTo($mode) { 490 $this->Lexer->addEntryPattern('<php>(?=.*</php>)',$mode,'php'); 491 $this->Lexer->addEntryPattern('<PHP>(?=.*</PHP>)',$mode,'phpblock'); 492 } 493 494 function postConnect() { 495 $this->Lexer->addExitPattern('</php>','php'); 496 $this->Lexer->addExitPattern('</PHP>','phpblock'); 497 } 498 499 function getSort() { 500 return 180; 501 } 502} 503 504//------------------------------------------------------------------- 505class Doku_Parser_Mode_html extends Doku_Parser_Mode { 506 507 function connectTo($mode) { 508 $this->Lexer->addEntryPattern('<html>(?=.*</html>)',$mode,'html'); 509 $this->Lexer->addEntryPattern('<HTML>(?=.*</HTML>)',$mode,'htmlblock'); 510 } 511 512 function postConnect() { 513 $this->Lexer->addExitPattern('</html>','html'); 514 $this->Lexer->addExitPattern('</HTML>','htmlblock'); 515 } 516 517 function getSort() { 518 return 190; 519 } 520} 521 522//------------------------------------------------------------------- 523class Doku_Parser_Mode_preformatted extends Doku_Parser_Mode { 524 525 function connectTo($mode) { 526 // Has hard coded awareness of lists... 527 $this->Lexer->addEntryPattern('\n (?![\*\-])',$mode,'preformatted'); 528 $this->Lexer->addEntryPattern('\n\t(?![\*\-])',$mode,'preformatted'); 529 530 // How to effect a sub pattern with the Lexer! 531 $this->Lexer->addPattern('\n ','preformatted'); 532 $this->Lexer->addPattern('\n\t','preformatted'); 533 534 } 535 536 function postConnect() { 537 $this->Lexer->addExitPattern('\n','preformatted'); 538 } 539 540 function getSort() { 541 return 20; 542 } 543} 544 545//------------------------------------------------------------------- 546class Doku_Parser_Mode_code extends Doku_Parser_Mode { 547 548 function connectTo($mode) { 549 $this->Lexer->addEntryPattern('<code(?=.*</code>)',$mode,'code'); 550 } 551 552 function postConnect() { 553 $this->Lexer->addExitPattern('</code>','code'); 554 } 555 556 function getSort() { 557 return 200; 558 } 559} 560 561//------------------------------------------------------------------- 562class Doku_Parser_Mode_file extends Doku_Parser_Mode { 563 564 function connectTo($mode) { 565 $this->Lexer->addEntryPattern('<file(?=.*</file>)',$mode,'file'); 566 } 567 568 function postConnect() { 569 $this->Lexer->addExitPattern('</file>','file'); 570 } 571 572 function getSort() { 573 return 210; 574 } 575} 576 577//------------------------------------------------------------------- 578class Doku_Parser_Mode_quote extends Doku_Parser_Mode { 579 580 function Doku_Parser_Mode_quote() { 581 global $PARSER_MODES; 582 583 $this->allowedModes = array_merge ( 584 $PARSER_MODES['formatting'], 585 $PARSER_MODES['substition'], 586 $PARSER_MODES['disabled'], 587 $PARSER_MODES['protected'] #XXX new 588 ); 589 #$this->allowedModes[] = 'footnote'; 590 #$this->allowedModes[] = 'preformatted'; 591 #$this->allowedModes[] = 'unformatted'; 592 } 593 594 function connectTo($mode) { 595 $this->Lexer->addEntryPattern('\n>{1,}',$mode,'quote'); 596 } 597 598 function postConnect() { 599 $this->Lexer->addPattern('\n>{1,}','quote'); 600 $this->Lexer->addExitPattern('\n','quote'); 601 } 602 603 function getSort() { 604 return 220; 605 } 606} 607 608//------------------------------------------------------------------- 609class Doku_Parser_Mode_acronym extends Doku_Parser_Mode { 610 // A list 611 var $acronyms = array(); 612 var $pattern = ''; 613 614 function Doku_Parser_Mode_acronym($acronyms) { 615 usort($acronyms,array($this,'_compare')); 616 $this->acronyms = $acronyms; 617 } 618 619 function preConnect() { 620 if(!count($this->acronyms)) return; 621 622 $bound = '[\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]'; 623 $acronyms = array_map('Doku_Lexer_Escape',$this->acronyms); 624 $this->pattern = '(?<=^|'.$bound.')(?:'.join('|',$acronyms).')(?='.$bound.')'; 625 } 626 627 function connectTo($mode) { 628 if(!count($this->acronyms)) return; 629 630 if ( strlen($this->pattern) > 0 ) { 631 $this->Lexer->addSpecialPattern($this->pattern,$mode,'acronym'); 632 } 633 } 634 635 function getSort() { 636 return 240; 637 } 638 639 /** 640 * sort callback to order by string length descending 641 */ 642 function _compare($a,$b) { 643 $a_len = strlen($a); 644 $b_len = strlen($b); 645 if ($a_len > $b_len) { 646 return -1; 647 } else if ($a_len < $b_len) { 648 return 1; 649 } 650 651 return 0; 652 } 653} 654 655//------------------------------------------------------------------- 656class Doku_Parser_Mode_smiley extends Doku_Parser_Mode { 657 // A list 658 var $smileys = array(); 659 var $pattern = ''; 660 661 function Doku_Parser_Mode_smiley($smileys) { 662 $this->smileys = $smileys; 663 } 664 665 function preConnect() { 666 if(!count($this->smileys) || $this->pattern != '') return; 667 668 $sep = ''; 669 foreach ( $this->smileys as $smiley ) { 670 $this->pattern .= $sep.'(?<=\W|^)'.Doku_Lexer_Escape($smiley).'(?=\W|$)'; 671 $sep = '|'; 672 } 673 } 674 675 function connectTo($mode) { 676 if(!count($this->smileys)) return; 677 678 if ( strlen($this->pattern) > 0 ) { 679 $this->Lexer->addSpecialPattern($this->pattern,$mode,'smiley'); 680 } 681 } 682 683 function getSort() { 684 return 230; 685 } 686} 687 688//------------------------------------------------------------------- 689class Doku_Parser_Mode_wordblock extends Doku_Parser_Mode { 690 // A list 691 var $badwords = array(); 692 var $pattern = ''; 693 694 function Doku_Parser_Mode_wordblock($badwords) { 695 $this->badwords = $badwords; 696 } 697 698 function preConnect() { 699 700 if ( count($this->badwords) == 0 || $this->pattern != '') { 701 return; 702 } 703 704 $sep = ''; 705 foreach ( $this->badwords as $badword ) { 706 $this->pattern .= $sep.'(?<=\b)(?i)'.Doku_Lexer_Escape($badword).'(?-i)(?=\b)'; 707 $sep = '|'; 708 } 709 710 } 711 712 function connectTo($mode) { 713 if ( strlen($this->pattern) > 0 ) { 714 $this->Lexer->addSpecialPattern($this->pattern,$mode,'wordblock'); 715 } 716 } 717 718 function getSort() { 719 return 250; 720 } 721} 722 723//------------------------------------------------------------------- 724class Doku_Parser_Mode_entity extends Doku_Parser_Mode { 725 // A list 726 var $entities = array(); 727 var $pattern = ''; 728 729 function Doku_Parser_Mode_entity($entities) { 730 $this->entities = $entities; 731 } 732 733 function preConnect() { 734 if(!count($this->entities) || $this->pattern != '') return; 735 736 $sep = ''; 737 foreach ( $this->entities as $entity ) { 738 $this->pattern .= $sep.Doku_Lexer_Escape($entity); 739 $sep = '|'; 740 } 741 } 742 743 function connectTo($mode) { 744 if(!count($this->entities)) return; 745 746 if ( strlen($this->pattern) > 0 ) { 747 $this->Lexer->addSpecialPattern($this->pattern,$mode,'entity'); 748 } 749 } 750 751 function getSort() { 752 return 260; 753 } 754} 755 756//------------------------------------------------------------------- 757// Implements the 640x480 replacement 758class Doku_Parser_Mode_multiplyentity extends Doku_Parser_Mode { 759 760 function connectTo($mode) { 761 762 $this->Lexer->addSpecialPattern( 763 '(?<=\b)(?:[1-9]|\d{2,})[xX]\d+(?=\b)',$mode,'multiplyentity' 764 ); 765 766 } 767 768 function getSort() { 769 return 270; 770 } 771} 772 773//------------------------------------------------------------------- 774class Doku_Parser_Mode_quotes extends Doku_Parser_Mode { 775 776 function connectTo($mode) { 777 global $conf; 778 779 $ws = '\s/\#~:+=&%@\-\x28\x29\]\[{}><"\''; // whitespace 780 $punc = ';,\.?!'; 781 782 if($conf['typography'] == 2){ 783 $this->Lexer->addSpecialPattern( 784 "(?<=^|[$ws])'(?=[^$ws$punc])",$mode,'singlequoteopening' 785 ); 786 $this->Lexer->addSpecialPattern( 787 "(?<=^|[^$ws]|[$punc])'(?=$|[$ws$punc])",$mode,'singlequoteclosing' 788 ); 789 $this->Lexer->addSpecialPattern( 790 "(?<=^|[^$ws$punc])'(?=$|[^$ws$punc])",$mode,'apostrophe' 791 ); 792 } 793 794 $this->Lexer->addSpecialPattern( 795 "(?<=^|[$ws])\"(?=[^$ws$punc])",$mode,'doublequoteopening' 796 ); 797 $this->Lexer->addSpecialPattern( 798 "\"",$mode,'doublequoteclosing' 799 ); 800 801 802 } 803 804 function getSort() { 805 return 280; 806 } 807} 808 809//------------------------------------------------------------------- 810class Doku_Parser_Mode_camelcaselink extends Doku_Parser_Mode { 811 812 function connectTo($mode) { 813 $this->Lexer->addSpecialPattern( 814 '\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b',$mode,'camelcaselink' 815 ); 816 } 817 818 function getSort() { 819 return 290; 820 } 821} 822 823//------------------------------------------------------------------- 824class Doku_Parser_Mode_internallink extends Doku_Parser_Mode { 825 826 function connectTo($mode) { 827 // Word boundaries? 828 $this->Lexer->addSpecialPattern("\[\[.+?\]\]",$mode,'internallink'); 829 } 830 831 function getSort() { 832 return 300; 833 } 834} 835 836//------------------------------------------------------------------- 837class Doku_Parser_Mode_media extends Doku_Parser_Mode { 838 839 function connectTo($mode) { 840 // Word boundaries? 841 $this->Lexer->addSpecialPattern("\{\{[^\}]+\}\}",$mode,'media'); 842 } 843 844 function getSort() { 845 return 320; 846 } 847} 848 849//------------------------------------------------------------------- 850class Doku_Parser_Mode_rss extends Doku_Parser_Mode { 851 852 function connectTo($mode) { 853 $this->Lexer->addSpecialPattern("\{\{rss>[^\}]+\}\}",$mode,'rss'); 854 } 855 856 function getSort() { 857 return 310; 858 } 859} 860 861//------------------------------------------------------------------- 862class Doku_Parser_Mode_externallink extends Doku_Parser_Mode { 863 var $schemes = array(); 864 var $patterns = array(); 865 866 function preConnect() { 867 if(count($this->patterns)) return; 868 869 $ltrs = '\w'; 870 $gunk = '/\#~:.?+=&%@!\-'; 871 $punc = '.:?\-;,'; 872 $host = $ltrs.$punc; 873 $any = $ltrs.$gunk.$punc; 874 875 $this->schemes = getSchemes(); 876 foreach ( $this->schemes as $scheme ) { 877 $this->patterns[] = '\b(?i)'.$scheme.'(?-i)://['.$any.']+?(?=['.$punc.']*[^'.$any.'])'; 878 } 879 880 $this->patterns[] = '\b(?i)www?(?-i)\.['.$host.']+?\.['.$host.']+?['.$any.']+?(?=['.$punc.']*[^'.$any.'])'; 881 $this->patterns[] = '\b(?i)ftp?(?-i)\.['.$host.']+?\.['.$host.']+?['.$any.']+?(?=['.$punc.']*[^'.$any.'])'; 882 } 883 884 function connectTo($mode) { 885 886 foreach ( $this->patterns as $pattern ) { 887 $this->Lexer->addSpecialPattern($pattern,$mode,'externallink'); 888 } 889 } 890 891 function getSort() { 892 return 330; 893 } 894} 895 896//------------------------------------------------------------------- 897class Doku_Parser_Mode_filelink extends Doku_Parser_Mode { 898 899 var $pattern; 900 901 function preConnect() { 902 903 $ltrs = '\w'; 904 $gunk = '/\#~:.?+=&%@!\-'; 905 $punc = '.:?\-;,'; 906 $host = $ltrs.$punc; 907 $any = $ltrs.$gunk.$punc; 908 909 $this->pattern = '\b(?i)file(?-i)://['.$any.']+?['. 910 $punc.']*[^'.$any.']'; 911 } 912 913 function connectTo($mode) { 914 $this->Lexer->addSpecialPattern( 915 $this->pattern,$mode,'filelink'); 916 } 917 918 function getSort() { 919 return 360; 920 } 921} 922 923//------------------------------------------------------------------- 924class Doku_Parser_Mode_windowssharelink extends Doku_Parser_Mode { 925 926 var $pattern; 927 928 function preConnect() { 929 $this->pattern = "\\\\\\\\\w+?(?:\\\\[\w$]+)+"; 930 } 931 932 function connectTo($mode) { 933 $this->Lexer->addSpecialPattern( 934 $this->pattern,$mode,'windowssharelink'); 935 } 936 937 function getSort() { 938 return 350; 939 } 940} 941 942//------------------------------------------------------------------- 943class Doku_Parser_Mode_emaillink extends Doku_Parser_Mode { 944 945 function connectTo($mode) { 946 // pattern below is defined in inc/mail.php 947 $this->Lexer->addSpecialPattern('<'.PREG_PATTERN_VALID_EMAIL.'>',$mode,'emaillink'); 948 } 949 950 function getSort() { 951 return 340; 952 } 953} 954 955 956//Setup VIM: ex: et ts=4 enc=utf-8 : 957