[ Index ] |
|
Code source de b2evolution 2.1.0-beta |
1 <?php 2 /** 3 * This file implements Post handling functions. 4 * 5 * This file is part of the evoCore framework - {@link http://evocore.net/} 6 * See also {@link http://sourceforge.net/projects/evocms/}. 7 * 8 * @copyright (c)2003-2007 by Francois PLANQUE - {@link http://fplanque.net/} 9 * Parts of this file are copyright (c)2004-2006 by Daniel HAHLER - {@link http://thequod.de/contact}. 10 * 11 * {@internal License choice 12 * - If you have received this file as part of a package, please find the license.txt file in 13 * the same folder or the closest folder above for complete license terms. 14 * - If you have received this file individually (e-g: from http://evocms.cvs.sourceforge.net/) 15 * then you must choose one of the following licenses before using the file: 16 * - GNU General Public License 2 (GPL) - http://www.opensource.org/licenses/gpl-license.php 17 * - Mozilla Public License 1.1 (MPL) - http://www.opensource.org/licenses/mozilla1.1.php 18 * }} 19 * 20 * {@internal Open Source relicensing agreement: 21 * Daniel HAHLER grants Francois PLANQUE the right to license 22 * Daniel HAHLER's contributions to this file and the b2evolution project 23 * under any OSI approved OSS license (http://www.opensource.org/licenses/). 24 * }} 25 * 26 * @package evocore 27 * 28 * {@internal Below is a list of authors who have contributed to design/coding of this file: }} 29 * @author cafelog (team) 30 * @author blueyed: Daniel HAHLER. 31 * @author fplanque: Francois PLANQUE. 32 * @author tswicegood: Travis SWICEGOOD. 33 * @author vegarg: Vegar BERG GULDAL. 34 * 35 * @version $Id: _item.funcs.php,v 1.5 2007/09/23 18:57:15 fplanque Exp $ 36 */ 37 if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' ); 38 39 40 /** 41 * Prepare the MainList object for displaying skins. 42 * 43 * @param integer max # of posts on the page 44 */ 45 function init_MainList( $items_nb_limit ) 46 { 47 global $MainList; 48 global $Blog; 49 global $timestamp_min, $timestamp_max; 50 global $preview; 51 global $disp; 52 global $postIDlist, $postIDarray; 53 54 $MainList = new ItemList2( $Blog, $timestamp_min, $timestamp_max, $items_nb_limit ); // COPY (FUNC) 55 56 if( ! $preview ) 57 { 58 if( $disp == 'page' ) 59 { // Get pages: 60 $MainList->set_default_filters( array( 61 'types' => '1000', // pages 62 ) ); 63 } 64 // else: we are either in single or in page mode 65 66 // pre_dump( $MainList->default_filters ); 67 $MainList->load_from_Request( false ); 68 // pre_dump( $MainList->filters ); 69 // echo '<br/>'.( $MainList->is_filtered() ? 'filtered' : 'NOT filtered' ); 70 // $MainList->dump_active_filters(); 71 72 // Run the query: 73 $MainList->query(); 74 75 // Old style globals for category.funcs: 76 $postIDlist = $MainList->get_page_ID_list(); 77 $postIDarray = $MainList->get_page_ID_array(); 78 } 79 else 80 { // We want to preview a single post, we are going to fake a lot of things... 81 $MainList->preview_from_request(); 82 83 // Legacy for the category display 84 $cat_array = array(); 85 } 86 87 param( 'more', 'integer', 0, true ); 88 param( 'page', 'integer', 1, true ); // Post page to show 89 param( 'c', 'integer', 0, true ); // Display comments? 90 param( 'tb', 'integer', 0, true ); // Display trackbacks? 91 param( 'pb', 'integer', 0, true ); // Display pingbacks? 92 } 93 94 95 /** 96 * Validate URL title 97 * 98 * Using title as a source if url title is empty 99 * 100 * @todo Use configurable char as seperator (see tracker) 101 * @todo dh> Allow/Use more than 40 chars 102 * 103 * @param string url title to validate 104 * @param string real title to use as a source if $urltitle is empty (encoded in $evo_charset) 105 * @param integer ID of post 106 * @return string validated url title 107 */ 108 function urltitle_validate( $urltitle, $title, $post_ID = 0, $query_only = false, 109 $dbprefix = 'post_', $dbIDname = 'post_ID', $dbtable = 'T_items__item' ) 110 { 111 global $DB; 112 113 $urltitle = trim( $urltitle ); 114 115 if( empty( $urltitle ) ) 116 { 117 if( ! empty($title) ) 118 $urltitle = $title; 119 else 120 $urltitle = 'title'; 121 } 122 123 // echo 'starting with: '.$urltitle.'<br />'; 124 125 // Replace special chars/umlauts, if we can convert charsets: 126 load_funcs('locales/_charset.funcs.php'); 127 $urltitle = replace_special_chars($urltitle); 128 129 // Make everything lowercase 130 $urltitle = strtolower( $urltitle ); 131 132 // Normalize to 40 chars + a number 133 preg_match( '/^(.*?)((-|_)+([0-9]+))?$/', $urltitle, $matches ); 134 $urlbase = substr( $matches[1], 0, 40 ); 135 $urltitle = $urlbase; 136 if( ! empty( $matches[4] ) ) 137 { 138 $urltitle = $urlbase.'-'.$matches[4]; 139 } 140 141 142 // CHECK FOR UNIQUENESS: 143 // Find all occurrences of urltitle-number in the DB: 144 $sql = 'SELECT '.$dbprefix.'urltitle 145 FROM '.$dbtable.' 146 WHERE '.$dbprefix."urltitle REGEXP '^".$urlbase."(-[0-9]+)?$'"; 147 if( $post_ID ) 148 { // Ignore current post 149 $sql .= ' AND '.$dbIDname.' <> '.$post_ID; 150 } 151 $exact_match = false; 152 $highest_number = 0; 153 foreach( $DB->get_results( $sql, ARRAY_A ) as $row ) 154 { 155 $existing_urltitle = $row[$dbprefix.'urltitle']; 156 // echo "existing = $existing_urltitle <br />"; 157 if( $existing_urltitle == $urltitle ) 158 { // We have an exact match, we'll have to change the number. 159 $exact_match = true; 160 } 161 if( preg_match( '/-([0-9]+)$/', $existing_urltitle, $matches ) ) 162 { // This one has a number, we extract it: 163 $existing_number = (integer) $matches[1]; 164 if( $existing_number > $highest_number ) 165 { // This is the new high 166 $highest_number = $existing_number; 167 } 168 } 169 } 170 // echo "highest existing number = $highest_number <br />"; 171 172 if( $exact_match && !$query_only ) 173 { // We got an exact match, we need to change the number: 174 $urltitle = $urlbase.'-'.($highest_number + 1); 175 } 176 177 // echo "using = $urltitle <br />"; 178 179 return $urltitle; 180 } 181 182 183 /** 184 * if global $postdata was not set it will be 185 */ 186 function get_postdata($postid) 187 { 188 global $DB, $postdata, $show_statuses; 189 190 if( !empty($postdata) && $postdata['ID'] == $postid ) 191 { // We are asking for postdata of current post in memory! (we're in the b2 loop) 192 // Already in memory! This will be the case when generating permalink at display 193 // (but not when sending trackbacks!) 194 // echo "*** Accessing post data in memory! ***<br />\n"; 195 return($postdata); 196 } 197 198 // echo "*** Loading post data! ***<br>\n"; 199 // We have to load the post 200 $sql = 'SELECT post_ID, post_creator_user_ID, post_datestart, post_datemodified, post_status, post_content, post_title, 201 post_main_cat_ID, cat_blog_ID '; 202 $sql .= ', post_locale, post_url, post_wordcount, post_comment_status, post_views '; 203 $sql .= ' FROM T_items__item 204 INNER JOIN T_categories ON post_main_cat_ID = cat_ID 205 WHERE post_ID = '.$postid; 206 // Restrict to the statuses we want to show: 207 // echo $show_statuses; 208 // fplanque: 2004-04-04: this should not be needed here. (and is indeed problematic when we want to 209 // get a post before even knowning which blog it belongs to. We can think of putting a security check 210 // back into the Item class) 211 // $sql .= ' AND '.statuses_where_clause( $show_statuses ); 212 213 // echo $sql; 214 215 if( $myrow = $DB->get_row( $sql ) ) 216 { 217 $mypostdata = array ( 218 'ID' => $myrow->post_ID, 219 'Author_ID' => $myrow->post_creator_user_ID, 220 'Date' => $myrow->post_datestart, 221 'Status' => $myrow->post_status, 222 'Content' => $myrow->post_content, 223 'Title' => $myrow->post_title, 224 'Category' => $myrow->post_main_cat_ID, 225 'Locale' => $myrow->post_locale, 226 'Url' => $myrow->post_url, 227 'Wordcount' => $myrow->post_wordcount, 228 'views' => $myrow->post_views, 229 'comment_status' => $myrow->post_comment_status, 230 'Blog' => $myrow->cat_blog_ID, 231 ); 232 233 // Caching is particularly useful when displaying a single post and you call single_post_title several times 234 if( !isset( $postdata ) ) $postdata = $mypostdata; // Will save time, next time :) 235 236 return($mypostdata); 237 } 238 239 return false; 240 } 241 242 243 244 245 246 // @@@ These aren't template tags, do not edit them 247 248 249 /** 250 * Returns the number of the words in a string, sans HTML 251 * 252 * @param string 253 * @return integer 254 */ 255 function bpost_count_words($string) 256 { 257 $string = trim(strip_tags($string)); 258 if( function_exists( 'str_word_count' ) ) 259 { // PHP >= 4.3 260 return str_word_count($string); 261 } 262 263 /* In case str_word_count() doesn't exist (to accomodate PHP < 4.3). 264 (Code adapted from post by "brettNOSPAM at olwm dot NO_SPAM dot com" at 265 PHP documentation page for str_word_count(). A better implementation 266 probably exists.) 267 */ 268 if($string == '') 269 { 270 return 0; 271 } 272 273 $pattern = "/[^(\w|\d|\'|\"|\.|\!|\?|;|,|\\|\/|\-\-|:|\&|@)]+/"; 274 $string = preg_replace($pattern, " ", $string); 275 $string = count(explode(" ", $string)); 276 277 return $string; 278 } 279 280 281 /** 282 * Construct the where clause to limit retrieved posts on their status 283 * 284 * @param Array statuses of posts we want to get 285 */ 286 function statuses_where_clause( $show_statuses = '', $dbprefix = 'post_', $req_blog = NULL ) 287 { 288 global $current_User, $blog; 289 290 if( is_null($req_blog ) ) 291 { 292 global $blog; 293 $req_blog = $blog; 294 } 295 296 if( empty($show_statuses) ) 297 $show_statuses = array( 'published', 'protected', 'private' ); 298 299 $where = ' ( '; 300 $or = ''; 301 302 if( ($key = array_search( 'private', $show_statuses )) !== false ) 303 { // Special handling for Private status: 304 unset( $show_statuses[$key] ); 305 if( is_logged_in() ) 306 { // We need to be logged in to have a chance to see this: 307 $where .= $or.' ( '.$dbprefix."status = 'private' AND ".$dbprefix.'creator_user_ID = '.$current_User->ID.' ) '; 308 $or = ' OR '; 309 } 310 } 311 312 if( $key = array_search( 'protected', $show_statuses ) ) 313 { // Special handling for Protected status: 314 if( (!is_logged_in()) 315 || ($req_blog == 0) // No blog specified (ONgsb) 316 || (!$current_User->check_perm( 'blog_ismember', 1, false, $req_blog )) ) 317 { // we are not allowed to see this if we are not a member of the current blog: 318 unset( $show_statuses[$key] ); 319 } 320 } 321 322 // Remaining statuses: 323 $other_statuses = ''; 324 $sep = ''; 325 foreach( $show_statuses as $other_status ) 326 { 327 $other_statuses .= $sep.'\''.$other_status.'\''; 328 $sep = ','; 329 } 330 if( strlen( $other_statuses ) ) 331 { 332 $where .= $or.$dbprefix.'status IN ('. $other_statuses .') '; 333 } 334 335 $where .= ') '; 336 337 // echo $where; 338 return $where; 339 } 340 341 342 /** 343 * Allow recursive category selection. 344 * 345 * @todo Allow to use a dropdown (select) to switch between blogs ( CSS / JS onchange - no submit.. ) 346 * 347 * @param boolean 348 * @param boolean true: use form fields, false: display only 349 */ 350 function cat_select( $display_info = true, $form_fields = true ) 351 { 352 global $allow_cross_posting, $cache_categories, 353 $blog, $current_blog_ID, $current_User, $edited_Item, $cat_select_form_fields; 354 355 $r = '<div class="extracats"><div>'; 356 357 $cat_select_form_fields = $form_fields; 358 359 cat_load_cache(); // make sure the caches are loaded 360 361 $r .= '<table cellspacing="0" class="catselect">'; 362 $r .= cat_select_header(); 363 364 if( $allow_cross_posting >= 2 ) 365 { // If BLOG cross posting enabled, go through all blogs with cats: 366 /** 367 * @var BlogCache 368 */ 369 $BlogCache = & get_Cache('BlogCache'); 370 371 /** 372 * @var Blog 373 */ 374 for( $l_Blog = & $BlogCache->get_first(); !is_null($l_Blog); $l_Blog = & $BlogCache->get_next() ) 375 { // run recursively through the cats 376 if( ! blog_has_cats( $l_Blog->ID ) ) 377 continue; 378 379 if( ! $current_User->check_perm( 'blog_post_statuses', 'edit', false, $l_Blog->ID ) ) 380 continue; 381 382 $r .= '<tr class="group"><td colspan="3">'.$l_Blog->dget('name')."</td></tr>\n"; 383 $current_blog_ID = $l_Blog->ID; // Global needed in callbacks 384 $r .= cat_children( $cache_categories, $l_Blog->ID, NULL, 'cat_select_before_first', 385 'cat_select_before_each', 'cat_select_after_each', 'cat_select_after_last', 1 ); 386 } 387 } 388 else 389 { // BLOG Cross posting is disabled. Current blog only: 390 $current_blog_ID = $blog; 391 $r .= cat_children( $cache_categories, $current_blog_ID, NULL, 'cat_select_before_first', 392 'cat_select_before_each', 'cat_select_after_each', 'cat_select_after_last', 1 ); 393 394 } 395 396 $r .= '</table>'; 397 398 if( $current_User->check_perm( 'blog_cats', '', false, $blog ) ) 399 { 400 $r .= '<p class="extracatnote"><a href="admin.php?ctrl=chapters&action=new&blog='.$blog.'">'.T_('Add a new category').' »</a></p>'; 401 } 402 403 if( $display_info ) 404 { 405 $r .= '<p class="extracatnote">' 406 .T_('Select main category in target blog and optionally check additional categories') 407 .'</p>'; 408 409 $r .= '<p class="extracatnote">'; 410 if( $allow_cross_posting >= 3 ) 411 { 412 $r .= T_('Note: Moving posts across blogs is enabled. Use with caution.'); 413 } 414 elseif( $allow_cross_posting >= 2 ) 415 { 416 $r .= T_('Note: Cross posting among multiple blogs is enabled.'); 417 } 418 elseif( $allow_cross_posting ) 419 { 420 $r .= T_('Note: Cross posting among multiple blogs is currently disabled.'); 421 } 422 else 423 { 424 $r .= T_('Note: Cross posting among multiple categories is currently disabled.'); 425 } 426 $r .= '</p>'; 427 } 428 429 $r .= '</div></div>'; 430 431 return $r; 432 } 433 434 /** 435 * Header for {@link cat_select()} 436 */ 437 function cat_select_header() 438 { 439 global $current_blog_ID, $blog, $allow_cross_posting; 440 441 $r = '<thead><tr><th class="selector catsel_main">'.T_('Main').'</th>'; 442 if( $allow_cross_posting >= 1 ) 443 { // This is current blog or we allow moving posts accross blogs 444 $r .= '<th class="selector catsel_extra">'.T_('Extra').'</th>'; 445 } 446 $r .= '<th class="catsel_name">'.T_('Category').'</th></tr></thead>'; 447 return $r; 448 } 449 450 /** 451 * callback to start sublist 452 */ 453 function cat_select_before_first( $parent_cat_ID, $level ) 454 { // callback to start sublist 455 return ''; // "\n<ul>\n"; 456 } 457 458 /** 459 * callback to display sublist element 460 */ 461 function cat_select_before_each( $cat_ID, $level, $total_count ) 462 { // callback to display sublist element 463 global $current_blog_ID, $blog, $post_extracats, $edited_Item; 464 global $creating, $allow_cross_posting, $cat_select_level, $cat_select_form_fields; 465 $this_cat = get_the_category_by_ID( $cat_ID ); 466 $r = "\n".'<tr class="'.( $total_count%2 ? 'odd' : 'even' ).'">'; 467 468 // RADIO for main cat: 469 if( ($current_blog_ID == $blog) || ($allow_cross_posting > 2) ) 470 { // This is current blog or we allow moving posts accross blogs 471 if( $cat_select_form_fields ) 472 { // We want a form field: 473 $r .= '<td class="selector catsel_main"><input type="radio" name="post_category" class="checkbox" title="' 474 .T_('Select as MAIN category').'" value="'.$cat_ID.'"'; 475 if( $cat_ID == $edited_Item->main_cat_ID ) 476 { // main cat of the Item or set as default main cat above 477 $r .= ' checked="checked"'; 478 } 479 $r .= ' id="sel_maincat_'.$cat_ID.'"'; 480 $r .= ' onclick="check_extracat(this);" /></td>'; 481 } 482 else 483 { // We just want info: 484 $r .= '<td class="selector catsel_main">'.bullet( $cat_ID == $edited_Item->main_cat_ID ).'</td>'; 485 } 486 } 487 else 488 { // Don't allow to select this cat as a main cat 489 $r .= '<td class="selector catsel_main"> </td>'; 490 } 491 492 // CHECKBOX: 493 if( $allow_cross_posting ) 494 { // We allow cross posting, display checkbox: 495 if( $cat_select_form_fields ) 496 { // We want a form field: 497 $r .= '<td class="selector catsel_extra"><input type="checkbox" name="post_extracats[]" class="checkbox" title="' 498 .T_('Select as an additional category').'" value="'.$cat_ID.'"'; 499 // if( ($cat_ID == $edited_Item->main_cat_ID) || (in_array( $cat_ID, $post_extracats )) ) <--- We don't want to precheck the default cat because it will stay checked if we change the default main. On edit, the checkbox will always be in the array. 500 if( (in_array( $cat_ID, $post_extracats )) ) 501 { 502 $r .= ' checked="checked"'; 503 } 504 $r .= ' id="sel_extracat_'.$cat_ID.'"'; 505 $r .= ' /></td>'; 506 } 507 else 508 { // We just want info: 509 $r .= '<td class="selector catsel_main">'.bullet( ($cat_ID == $edited_Item->main_cat_ID) || (in_array( $cat_ID, $post_extracats )) ).'</td>'; 510 } 511 } 512 513 $r .= '<td class="catsel_name"><label' 514 .' for="'.( $allow_cross_posting 515 ? 'sel_extracat_'.$cat_ID 516 : 'sel_maincat_'.$cat_ID ).'"' 517 .' style="padding-left:'.($level-1).'em;">'.$this_cat['cat_name'].'</label>' 518 ."</td></tr>\n"; 519 520 return $r; 521 } 522 523 /** 524 * callback after each sublist element 525 */ 526 function cat_select_after_each( $cat_ID, $level ) 527 { // callback after each sublist element 528 return ''; 529 } 530 531 /** 532 * callback to end sublist 533 */ 534 function cat_select_after_last( $parent_cat_ID, $level ) 535 { // callback to end sublist 536 return ''; // "</ul>\n"; 537 } 538 539 540 /** 541 * Used by the items & the comments controllers 542 */ 543 function attach_browse_tabs() 544 { 545 global $AdminUI, $Blog, $current_User; 546 547 $AdminUI->add_menu_entries( 548 'items', 549 array( 550 'full' => array( 551 'text' => T_('Full posts'), 552 'href' => 'admin.php?ctrl=items&tab=full&filter=restore&blog='.$Blog->ID, 553 ), 554 'list' => array( 555 'text' => T_('Post list'), 556 'href' => 'admin.php?ctrl=items&tab=list&filter=restore&blog='.$Blog->ID, 557 ), 558 ) 559 ); 560 561 if( $Blog->get_setting( 'use_workflow' ) ) 562 { // We want to use workflow properties for this blog: 563 $AdminUI->add_menu_entries( 564 'items', 565 array( 566 'tracker' => array( 567 'text' => T_('Tracker'), 568 'href' => 'admin.php?ctrl=items&tab=tracker&filter=restore&blog='.$Blog->ID, 569 ), 570 ) 571 ); 572 } 573 574 if( $current_User->check_perm( 'blog_comments', 'edit', false, $Blog->ID ) ) 575 { 576 $AdminUI->add_menu_entries( 577 'items', 578 array( 579 'comments' => array( 580 'text' => T_('Comments'), 581 'href' => 'admin.php?ctrl=comments&blog='.$Blog->ID, 582 ), 583 ) 584 ); 585 } 586 } 587 588 589 590 /** 591 * Allow to select status/visibility 592 */ 593 function visibility_select( & $Form, $post_status ) 594 { 595 global $current_User, $Blog; 596 597 $sharing_options = array(); 598 599 if( $current_User->check_perm( 'blog_post!published', 'edit', false, $Blog->ID ) ) 600 $sharing_options[] = array( 'published', T_('Published (Public)') ); 601 602 if( $current_User->check_perm( 'blog_post!protected', 'edit', false, $Blog->ID ) ) 603 $sharing_options[] = array( 'protected', T_('Protected (Members only)') ); 604 605 if( $current_User->check_perm( 'blog_post!private', 'edit', false, $Blog->ID ) ) 606 $sharing_options[] = array( 'private', T_('Private (You only)') ); 607 608 if( $current_User->check_perm( 'blog_post!draft', 'edit', false, $Blog->ID ) ) 609 $sharing_options[] = array( 'draft', T_('Draft (Not published!)') ); 610 611 if( $current_User->check_perm( 'blog_post!deprecated', 'edit', false, $Blog->ID ) ) 612 $sharing_options[] = array( 'deprecated', T_('Deprecated (Not published!)') ); 613 614 if( $current_User->check_perm( 'blog_post!redirected', 'edit', false, $Blog->ID ) ) 615 $sharing_options[] = array( 'redirected', T_('Redirected') ); 616 617 $Form->radio( 'post_status', $post_status, $sharing_options, '', true ); 618 } 619 620 621 /* 622 * $Log: _item.funcs.php,v $ 623 * Revision 1.5 2007/09/23 18:57:15 fplanque 624 * filter handling fixes 625 * 626 * Revision 1.4 2007/09/07 20:11:18 fplanque 627 * Better category selector 628 * 629 * Revision 1.3 2007/09/03 20:01:53 blueyed 630 * Fixed "Add a new category »" link (blog param) 631 * 632 * Revision 1.2 2007/09/03 16:44:28 fplanque 633 * chicago admin skin 634 * 635 * Revision 1.1 2007/06/25 11:00:25 fplanque 636 * MODULES (refactored MVC) 637 * 638 * Revision 1.52 2007/05/28 01:33:22 fplanque 639 * permissions/fixes 640 * 641 * Revision 1.51 2007/05/14 02:43:05 fplanque 642 * Started renaming tables. There probably won't be a better time than 2.0. 643 * 644 * Revision 1.50 2007/05/13 20:44:11 fplanque 645 * url fix 646 * 647 * Revision 1.49 2007/05/09 01:01:32 fplanque 648 * permissions cleanup 649 * 650 * Revision 1.48 2007/05/07 18:03:28 fplanque 651 * cleaned up skin code a little 652 * 653 * Revision 1.47 2007/04/26 00:11:11 fplanque 654 * (c) 2007 655 * 656 * Revision 1.46 2007/03/26 14:21:30 fplanque 657 * better defaults for pages implementation 658 * 659 * Revision 1.45 2007/03/26 12:59:18 fplanque 660 * basic pages support 661 * 662 * Revision 1.44 2007/03/18 00:31:18 fplanque 663 * Delegated MainList init to skin *pages* which need it. 664 * 665 * Revision 1.43 2007/03/11 23:56:02 fplanque 666 * fixed some post editing oddities / variable cleanup (more could be done) 667 * 668 * Revision 1.42 2007/03/03 01:14:12 fplanque 669 * new methods for navigating through posts in single item display mode 670 * 671 * Revision 1.41 2007/02/12 15:42:40 fplanque 672 * public interface for looping over a cache 673 * 674 * Revision 1.40 2007/02/06 13:34:20 waltercruz 675 * Changing double quotes to single quotes 676 * 677 * Revision 1.39 2006/12/23 23:37:35 fplanque 678 * refactoring / Blog::get_default_cat_ID() 679 * 680 * Revision 1.38 2006/12/16 17:05:55 blueyed 681 * todo 682 * 683 * Revision 1.37 2006/12/15 23:31:21 fplanque 684 * reauthorized _ in urltitles. 685 * No breaking of legacy permalinks. 686 * - remains the default placeholder though. 687 * 688 * Revision 1.36 2006/12/12 23:23:30 fplanque 689 * finished post editing v2.0 690 * 691 * Revision 1.35 2006/12/12 02:53:56 fplanque 692 * Activated new item/comments controllers + new editing navigation 693 * Some things are unfinished yet. Other things may need more testing. 694 * 695 * Revision 1.34 2006/12/11 17:26:21 fplanque 696 * some cross-linking 697 * 698 * Revision 1.33 2006/12/04 21:20:27 blueyed 699 * Abstracted convert_special_charsets() out of urltitle_validate() 700 * 701 * Revision 1.32 2006/12/03 22:23:26 fplanque 702 * doc 703 * 704 * Revision 1.31 2006/11/24 18:27:24 blueyed 705 * Fixed link to b2evo CVS browsing interface in file docblocks 706 * 707 * Revision 1.30 2006/11/23 00:37:35 blueyed 708 * Added two more replacements in urltitle_validate and pass charset to htmlentities() 709 */ 710 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Thu Nov 29 23:58:50 2007 | par Balluche grâce à PHPXref 0.7 |
![]() |