00001 <?php
00007 namespace Habari;
00008
00015 class Format
00016 {
00017 private static $formatters = null;
00018
00024 public static function apply( $format, $onwhat )
00025 {
00026 if ( self::$formatters == null ) {
00027 self::load_all();
00028 }
00029
00030 $priority = 8;
00031 if(preg_match('#^(.+)_(\d+)$#', $onwhat, $matches)) {
00032 $priority = intval($matches[2]);
00033 $onwhat = $matches[1];
00034 }
00035
00036 $method = false;
00037 if (is_callable($format)) {
00038 $method = $format;
00039 }
00040 else {
00041 foreach ( self::$formatters as $formatobj ) {
00042 if ( method_exists( $formatobj, $format ) ) {
00043 $method = array($formatobj, $format);
00044 break;
00045 }
00046 }
00047 }
00048
00049 if($method) {
00050 $args = func_get_args();
00051 $args = array_slice($args, 2);
00052 $lambda = function() use ($args, $method) {
00053 $filterargs = func_get_args();
00054 $filterargs = array_slice($filterargs, 0, 1);
00055 foreach($args as $arg) {
00056 $filterargs[] = $arg;
00057 }
00058 return call_user_func_array($method, $filterargs);
00059 };
00060 Plugins::register( $lambda, 'filter', $onwhat, $priority );
00061 }
00062 }
00063
00069 public static function apply_with_hook_params( $format, $onwhat )
00070 {
00071 if ( self::$formatters == null ) {
00072 self::load_all();
00073 }
00074
00075 $priority = 8;
00076 if(preg_match('#^(.+)_(\d+)$#', $onwhat, $matches)) {
00077 $priority = intval($matches[2]);
00078 $onwhat = $matches[1];
00079 }
00080
00081 $method = false;
00082 if (is_callable($format)) {
00083 $method = $format;
00084 }
00085 else {
00086 foreach ( self::$formatters as $formatobj ) {
00087 if ( method_exists( $formatobj, $format ) ) {
00088 $method = array($formatobj, $format);
00089 break;
00090 }
00091 }
00092 }
00093
00094 if($method) {
00095 $args = func_get_args();
00096 $args = array_slice($args, 2);
00097 $lambda = function() use ($args, $method) {
00098 $filterargs = func_get_args();
00099
00100 foreach($args as $arg) {
00101 $filterargs[] = $arg;
00102 }
00103 return call_user_func_array($method, $filterargs);
00104 };
00105 Plugins::register( $lambda, 'filter', $onwhat );
00106 }
00107 }
00108
00116 public static function by_index( $index )
00117 {
00118 return self::$formatters[$index];
00119 }
00120
00125 public static function load_all()
00126 {
00127 self::$formatters = array();
00128 $classes = get_declared_classes();
00129 foreach ( $classes as $class ) {
00130 if ( $class == __CLASS__ || get_parent_class( $class ) == __CLASS__ ) {
00131 self::$formatters[] = new $class();
00132 }
00133 }
00134 self::$formatters = array_merge( self::$formatters, Plugins::get_by_interface( 'FormatPlugin' ) );
00135 self::$formatters = array_reverse( self::$formatters, true );
00136 }
00137
00153 public static function autop( $value )
00154 {
00155 $value = str_replace( "\r\n", "\n", $value );
00156 $value = trim( $value );
00157 $ht = new HtmlTokenizer( $value, false );
00158 $set = $ht->parse();
00159 $value = '';
00160
00161
00162 $no_auto_p = array(
00163 'pre','code','ul','h1','h2','h3','h4','h5','h6',
00164 'object','applet','embed',
00165 'table','ul','ol','li','i','b','em','strong','script', 'dl', 'dt', 'dd'
00166 );
00167
00168 $block_elements = array(
00169 'address','blockquote','center','dir','div','dl','fieldset','form',
00170 'h1','h2','h3','h4','h5','h6','hr','isindex','menu','noframes',
00171 'object','applet','embed',
00172 'noscript','ol','p','pre','table','ul','figure','figcaption'
00173 );
00174
00175 $token = $set->current();
00176
00177
00178 if ( $token === false ) {
00179 return $value;
00180 }
00181
00182 $open_p = false;
00183 do {
00184
00185 if ( $open_p ) {
00186 if ( ( $token['type'] == HTMLTokenizer::NODE_TYPE_ELEMENT_EMPTY || $token['type'] == HTMLTokenizer::NODE_TYPE_ELEMENT_OPEN || $token['type'] == HTMLTokenizer::NODE_TYPE_ELEMENT_CLOSE ) && in_array( strtolower( $token['name'] ), $block_elements ) ) {
00187 if ( strtolower( $token['name'] ) != 'p' || $token['type'] != HTMLTokenizer::NODE_TYPE_ELEMENT_CLOSE ) {
00188 $value .= '</p>';
00189 }
00190 $open_p = false;
00191 }
00192 }
00193
00194 if ( ( $token['type'] == HTMLTokenizer::NODE_TYPE_ELEMENT_OPEN || $token['type'] == HTMLTokenizer::NODE_TYPE_ELEMENT_EMPTY ) && !in_array( strtolower( $token['name'] ), $block_elements ) && !$open_p ) {
00195
00196 $value .= '<p>';
00197 $open_p = true;
00198 }
00199
00200
00201 if ( $token['type'] == HTMLTokenizer::NODE_TYPE_ELEMENT_OPEN && in_array( strtolower( $token['name'] ), $no_auto_p ) ) {
00202 $nested_token = $token;
00203 do {
00204 $value .= HtmlTokenSet::token_to_string( $nested_token, false );
00205 if (
00206 ( $nested_token['type'] == HTMLTokenizer::NODE_TYPE_ELEMENT_CLOSE
00207 && strtolower( $nested_token['name'] ) == strtolower( $token['name'] ) )
00208 ) {
00209 break;
00210 }
00211 } while ( $nested_token = $set->next() );
00212 continue;
00213 }
00214
00215
00216 if ( $token['type'] != HTMLTokenizer::NODE_TYPE_TEXT ) {
00217 $value .= HtmlTokenSet::token_to_string( $token, true );
00218
00219 if ( strtolower( $token['name'] ) == 'p' && $token['type'] == HTMLTokenizer::NODE_TYPE_ELEMENT_OPEN ) {
00220 $open_p = true;
00221 }
00222 continue;
00223 }
00224
00225
00226 $local_value = $token['value'];
00227 if ( MultiByte::strlen( $local_value ) ) {
00228 if ( !$open_p ) {
00229 $local_value = '<p>' . ltrim( $local_value );
00230 $open_p = true;
00231 }
00232
00233 $local_value = preg_replace( '/\s*(\n\s*){2,}/u', "</p><p>", $local_value );
00234 $local_value = str_replace( "\n", "<br>", $local_value );
00235 }
00236 $value .= $local_value;
00237 } while ( $token = $set->next() );
00238
00239 $value = preg_replace( '#\s*<p></p>\s*#u', '', $value );
00240 $value = preg_replace( '/<p><!--(.*?)--><\/p>/', "<!--\\1-->", $value );
00241 if ( $open_p ) {
00242 $value .= '</p>';
00243 }
00244
00245 return $value;
00246 }
00247
00256 public static function and_list( $array, $between = ', ', $between_last = null )
00257 {
00258 if ( ! is_array( $array ) ) {
00259 $array = array( $array );
00260 }
00261
00262 if ( $between_last === null ) {
00263
00264 $between_last = _t( ' and ' );
00265 }
00266
00267 $last = array_pop( $array );
00268 $out = implode( $between, $array );
00269 $out .= ($out == '') ? $last : $between_last . $last;
00270 return $out;
00271 }
00272
00283 public static function tag_and_list( $terms, $between = ', ', $between_last = null, $sort_alphabetical = false )
00284 {
00285 $array = array();
00286 if ( !$terms instanceof Terms ) {
00287 $terms = new Terms( $terms );
00288 }
00289
00290 foreach ( $terms as $term ) {
00291 $array[$term->term] = $term->term_display;
00292 }
00293
00294 if ( $sort_alphabetical ) {
00295 ksort( $array );
00296 }
00297
00298 if ( $between_last === null ) {
00299
00300 $between_last = _t( ' and ' );
00301 }
00302
00303 $fn = function($a, $b) {
00304 return "<a href=\"" . URL::get("display_entries_by_tag", array( "tag" => $b) ) . "\" rel=\"tag\">" . $a . "</a>";
00305 };
00306 $array = array_map( $fn, $array, array_keys( $array ) );
00307 $last = array_pop( $array );
00308 $out = implode( $between, $array );
00309 $out .= ( $out == '' ) ? $last : $between_last . $last;
00310 return $out;
00311
00312 }
00313
00326 public static function format_date( $date, $format )
00327 {
00328 if ( !( $date instanceOf DateTime ) ) {
00329 $date = DateTime::create( $date );
00330 }
00331 return $date->text_format( $format );
00332 }
00333
00341 public static function nice_date( $date, $dateformat = 'F j, Y' )
00342 {
00343 if ( !( $date instanceOf DateTime ) ) {
00344 $date = DateTime::create( $date );
00345 }
00346 return $date->format( $dateformat );
00347 }
00348
00356 public static function nice_time( $date, $dateformat = 'H:i:s' )
00357 {
00358 if ( !( $date instanceOf DateTime ) ) {
00359 $date = DateTime::create( $date );
00360 }
00361 return $date->format( $dateformat );
00362 }
00363
00371 public static function summarize( $text, $count = 100, $max_paragraphs = 1 )
00372 {
00373 $ellipsis = '…';
00374
00375 $showmore = false;
00376
00377 $ht = new HtmlTokenizer($text, false);
00378 $set = $ht->parse();
00379
00380 $stack = array();
00381 $para = 0;
00382 $token = $set->current();
00383 $summary = new HTMLTokenSet();
00384 $set->rewind();
00385 $remaining_words = $count;
00386
00387 $bail = false;
00388 for ( $token = $set->current(); $set->valid(); $token = $set->next() ) {
00389 if ( !$bail && $token['type'] == HTMLTokenizer::NODE_TYPE_ELEMENT_OPEN ) {
00390 $stack[] = $token;
00391 }
00392 if ( !$bail ) {
00393 switch ( $token['type'] ) {
00394 case HTMLTokenizer::NODE_TYPE_TEXT:
00395 $words = preg_split( '/(\\s+)/u', $token['value'], -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY );
00396
00397 $words = array_slice( $words, 0, $remaining_words * 2 );
00398 $remaining_words -= count( $words ) / 2;
00399 $token['value'] = implode( '', $words );
00400 if ( $remaining_words <= 0 ) {
00401 $token['value'] .= $ellipsis;
00402 $summary[] = $token;
00403 $bail = true;
00404 }
00405 else {
00406 $summary[] = $token;
00407 }
00408 break;
00409 case HTMLTokenizer::NODE_TYPE_ELEMENT_CLOSE;
00410
00411 break;
00412 default:
00413 $summary[] = $token;
00414 break;
00415 }
00416 }
00417 if ( $token['type'] == HTMLTokenizer::NODE_TYPE_ELEMENT_CLOSE ) {
00418 if(count($stack) > 0 && in_array($token['name'], Utils::array_map_field($stack, 'name'))) {
00419 do {
00420 $end = array_pop( $stack );
00421 $end['type'] = HTMLTokenizer::NODE_TYPE_ELEMENT_CLOSE;
00422 $end['attrs'] = null;
00423 $end['value'] = null;
00424 $summary[] = $end;
00425 } while ( ( $bail || $end['name'] != $token['name'] ) && count( $stack ) > 0 );
00426 }
00427 else {
00428 $end['name'] = $token['name'];
00429 $end['type'] = HTMLTokenizer::NODE_TYPE_ELEMENT_CLOSE;
00430 $end['attrs'] = null;
00431 $end['value'] = null;
00432 }
00433 if ( count( $stack ) == 0 ) {
00434 $para++;
00435 }
00436 if ( $bail || $para >= $max_paragraphs ) {
00437 break;
00438 }
00439 }
00440 }
00441
00442 return (string) $summary;
00443 }
00444
00459 public static function more( $content, $post, $properties = array() )
00460 {
00461
00462 if ( $post->slug == Controller::get_var( 'slug' ) ) {
00463 return $content;
00464 }
00465 elseif ( is_string( $properties ) ) {
00466 $args = func_get_args();
00467 $more_text = $properties;
00468 $max_words = ( isset( $args[3] ) ? $args[3] : null );
00469 $max_paragraphs = ( isset( $args[4] ) ? $args[4] : null );
00470 $inside_last = ( isset( $args[5] ) ? $args[5] : true );
00471 $paramstring = "";
00472 }
00473 else {
00474 $paramstring = "";
00475 $paramarray = Utils::get_params( $properties );
00476
00477 $more_text = ( isset( $paramarray['more_text'] ) ? $paramarray['more_text'] : 'Read More' );
00478 $max_words = ( isset( $paramarray['max_words'] ) ? $paramarray['max_words'] : null );
00479 $max_paragraphs = ( isset( $paramarray['max_paragraphs'] ) ? $paramarray['max_paragraphs'] : null );
00480 $inside_last = ( isset( $paramarray['inside_last'] ) ? $paramarray['inside_last'] : true );
00481
00482 if ( isset( $paramarray['title:before'] ) || isset( $paramarray['title'] ) || isset( $paramarray['title:after'] ) ) {
00483 $paramstring .= 'title="';
00484
00485 if ( isset( $paramarray['title:before'] ) ) {
00486 $paramstring .= $paramarray['title:before'];
00487 }
00488 if ( isset( $paramarray['title'] ) ) {
00489 $paramstring .= $post->title;
00490 }
00491 if ( isset( $paramarray['title:after'] ) ) {
00492 $paramstring .= $paramarray['title:after'];
00493 }
00494 $paramstring .= '" ';
00495 }
00496 if ( isset( $paramarray['class'] ) ) {
00497 $paramstring .= 'class="' . $paramarray['class'] . '" ';
00498 }
00499
00500 }
00501
00502 $link_text = '<a ' . $paramstring . ' href="' . $post->permalink . '">' . $more_text . '</a>';
00503
00504
00505 if ( $inside_last ) {
00506 $link_text = ' ' . $link_text;
00507 }
00508
00509
00510 $matches = preg_split( '/<!--\s*more\s*-->/isu', $content, 2, PREG_SPLIT_NO_EMPTY );
00511 if ( count( $matches ) > 1 ) {
00512 $summary = reset( $matches );
00513 }
00514 else {
00515
00516 $max_words = empty( $max_words ) ? 9999999 : intval( $max_words );
00517 $max_paragraphs = empty( $max_paragraphs ) ? 9999999 : intval( $max_paragraphs );
00518 $summary = Format::summarize( $content, $max_words, $max_paragraphs );
00519 }
00520
00521
00522 if ( MultiByte::strlen( $summary ) >= MultiByte::strlen( $content ) ) {
00523 return $content;
00524 }
00525 else {
00526
00527 if ( strlen( $more_text ) ) {
00528
00529
00530
00531 $ht = new HTMLTokenizer( $summary );
00532 $summary_set = $ht->parse();
00533
00534
00535 $ht = new HTMLTokenizer( $link_text );
00536 $link_set = $ht->parse();
00537
00538
00539 $end = $summary_set->end();
00540
00541 $key = $summary_set->key();
00542
00543
00544 if ( $inside_last == false ) {
00545 $key++;
00546 }
00547
00548
00549 $summary_set->insert( $link_set, $key );
00550
00551
00552 return (string)$summary_set;
00553 }
00554 else {
00555
00556 return $summary;
00557 }
00558
00559 }
00560
00561 return $content;
00562
00563 }
00564
00572 public static function html_messages( $notices, $errors )
00573 {
00574 $output = '';
00575 if ( count( $errors ) ) {
00576 $output.= '<ul class="messages error">';
00577 foreach ( $errors as $error ) {
00578 $output.= '<li>' . $error . '</li>';
00579 }
00580 $output.= '</ul>';
00581 }
00582 if ( count( $notices ) ) {
00583 $output.= '<ul class="messages success">';
00584 foreach ( $notices as $notice ) {
00585 $output.= '<li>' . $notice . '</li>';
00586 }
00587 $output.= '</ul>';
00588 }
00589
00590 return $output;
00591 }
00592
00600 public static function humane_messages( $notices, $errors )
00601 {
00602 $output = '';
00603 if ( count( $errors ) ) {
00604 foreach ( $errors as $error ) {
00605 $error = addslashes( $error );
00606 $output .= "human_msg.display_msg(\"{$error}\");";
00607 }
00608 }
00609 if ( count( $notices ) ) {
00610 foreach ( $notices as $notice ) {
00611 $notice = addslashes( $notice );
00612 $output .= "human_msg.display_msg(\"{$notice}\");";
00613 }
00614 }
00615
00616 return $output;
00617 }
00618
00626 public static function json_messages( $notices, $errors )
00627 {
00628 $messages = array_merge( $errors, $notices );
00629 return json_encode( $messages );
00630 }
00631
00642 public static function term_tree( $terms, $tree_name, $config = array() )
00643 {
00644 $defaults = array(
00645 'treestart' => '<ol %s>',
00646 'treeattr' => array('class' => 'tree', 'id' => Utils::slugify('tree_' . $tree_name)),
00647 'treeend' => '</ol>',
00648 'liststart' => '<ol %s>',
00649 'listattr' => array(),
00650 'listend' => '</ol>',
00651 'itemstart' => '<li %s>',
00652 'itemattr' => array('class' => 'treeitem'),
00653 'itemend' => '</li>',
00654 'wrapper' => '<div>%s</div>',
00655 'linkcallback' => null,
00656 'itemcallback' => null,
00657 'listcallback' => null,
00658 );
00659 $config = array_merge($defaults, $config);
00660
00661 $out = sprintf($config['treestart'], Utils::html_attr($config['treeattr']));
00662 $stack = array();
00663 $tree_name = Utils::slugify($tree_name);
00664
00665 if ( !$terms instanceof Terms ) {
00666 $terms = new Terms( $terms );
00667 }
00668
00669 foreach ( $terms as $term ) {
00670 if(count($stack)) {
00671 if($term->mptt_left - end($stack)->mptt_left == 1) {
00672 if(isset($config['listcallback'])) {
00673 $config = call_user_func($config['listcallback'], $term, $config);
00674 }
00675 $out .= sprintf($config['liststart'], Utils::html_attr($config['listattr']));
00676 }
00677 while(count($stack) && $term->mptt_left > end($stack)->mptt_right) {
00678 $out .= $config['listend'] . $config['itemend'] . "\n";
00679 array_pop($stack);
00680 }
00681 }
00682
00683 $config['itemattr']['id'] = $tree_name . '_' . $term->id;
00684 if(isset($config['itemcallback'])) {
00685 $config = call_user_func($config['itemcallback'], $term, $config);
00686 }
00687 $out .= sprintf($config['itemstart'], Utils::html_attr($config['itemattr']));
00688 if(isset($config['linkcallback'])) {
00689 $display = call_user_func($config['linkcallback'], $term, $config);
00690 }
00691 else {
00692 $display = $term->term_display;
00693 }
00694 $out .= sprintf( $config['wrapper'], $display );
00695 if($term->mptt_right - $term->mptt_left > 1) {
00696 $stack[] = $term;
00697 }
00698 else {
00699 $out .= $config['itemend'] ."\n";
00700 }
00701 }
00702 while(count($stack)) {
00703 $out .= $config['listend'] . $config['itemend'] . "\n";
00704 array_pop($stack);
00705 }
00706
00707 $out .= $config['treeend'];
00708 return $out;
00709 }
00710 }
00711 ?>