Source for file typography_functions.php

Documentation is available at typography_functions.php

  1. <?php
  2. /**
  3.  * CodeIgniter
  4.  *
  5.  * An open source application development framework for PHP 4.3.2 or newer
  6.  *
  7.  * @package        CodeIgniter
  8.  * @subpackage     Helpers
  9.  * @author        ExpressionEngine Dev Team
  10.  * @copyright    Copyright (c) 2006, EllisLab, Inc.
  11.  * @license        http://codeigniter.com/user_guide/license.html
  12.  * @link        http://codeigniter.com
  13.  * @since        Version 1.0
  14.  * @filesource
  15.  */
  16.  
  17. // ------------------------------------------------------------------------
  18.  
  19. /**
  20.  * CodeIgniter Typography Helpers
  21.  *
  22.  * @author        ExpressionEngine Dev Team
  23.  * @link        http://codeigniter.com/user_guide/helpers/typography_helper.html
  24.  */
  25.  
  26. // ------------------------------------------------------------------------
  27.  
  28. if (function_exists('nl2br_except_pre')) {
  29.     /**
  30.      * Convert newlines to HTML line breaks except within PRE tags
  31.      *
  32.      * @access    public
  33.      * @param    string 
  34.      * @return    string 
  35.      */    
  36.     function nl2br_except_pre($str)
  37.     {
  38.         $ex explode("pre>",$str);
  39.         $ct count($ex);
  40.     
  41.         $newstr "";
  42.         for ($i 0$i $ct$i++)
  43.         {
  44.             if (($i 2== 0)
  45.             {
  46.                 $newstr .= nl2br($ex[$i]);
  47.             }
  48.             else
  49.             {
  50.                 $newstr .= $ex[$i];
  51.             }
  52.         
  53.             if ($ct != $i)
  54.                 $newstr .= "pre>";
  55.         }
  56.     
  57.         return $newstr;
  58.     }
  59. }
  60.     
  61. // ------------------------------------------------------------------------
  62.  
  63. if (function_exists('auto_typography')) {
  64.     /**
  65.      * Auto Typography Wrapper Function
  66.      *
  67.      *
  68.      * @access    public
  69.      * @param    string 
  70.      * @return    string 
  71.      */
  72.     function auto_typography($str)
  73.     {
  74.         $TYPE new Auto_typography();
  75.         return $TYPE->convert($str);
  76.     }
  77. }
  78.     
  79. // ------------------------------------------------------------------------
  80.  
  81. /**
  82.  * Auto Typography Class
  83.  *
  84.  *
  85.  * @package     CodeIgniter
  86.  * @category    Helpers
  87.  * @author        ExpressionEngine Dev Team
  88.  * @link        http://codeigniter.com/user_guide/helpers/
  89.  */
  90. class Auto_typography {
  91.  
  92.     // Block level elements that should not be wrapped inside <p> tags
  93.     public $block_elements = 'div|blockquote|pre|code|h\d|script|ol|ul';
  94.     
  95.     // Elements that should not have <p> and <br /> tags within them.
  96.     public $skip_elements    = 'pre|ol|ul';
  97.     
  98.     // Tags we want the parser to completely ignore when splitting the string.
  99.     public $ignore_elements = 'a|b|i|em|strong|span|img|li';    
  100.  
  101.  
  102.     /**
  103.      * Main Processing Function
  104.      *
  105.      */
  106.     function convert($str)
  107.     {
  108.         if ($str == '')
  109.         {
  110.             return '';
  111.         }
  112.         
  113.         $str ' '.$str.' ';
  114.         
  115.         // Standardize Newlines to make matching easier
  116.         $str preg_replace("/(\r\n|\r)/""\n"$str);
  117.         
  118.         /*
  119.          * Reduce line breaks
  120.          *
  121.          * If there are more than two consecutive line
  122.          * breaks we'll compress them down to a maximum
  123.          * of two since there's no benefit to more.
  124.          *
  125.          */
  126.         $str preg_replace("/\n\n+/""\n\n"$str);
  127.  
  128.         /*
  129.          * Convert quotes within tags to temporary marker
  130.          *
  131.          * We don't want quotes converted within
  132.          * tags so we'll temporarily convert them to
  133.          * {@DQ} and {@SQ}
  134.          *
  135.          */            
  136.         if (preg_match_all("#\<.+?>#si"$str$matches))
  137.         {
  138.             for ($i 0$i count($matches['0'])$i++)
  139.             {
  140.                 $str str_replace($matches['0'][$i],
  141.                                     str_replace(array("'",'"')array('{@SQ}''{@DQ}')$matches['0'][$i]),
  142.                                     $str);
  143.             }
  144.         }
  145.     
  146.  
  147.         /*
  148.          * Add closing/opening paragraph tags before/after "block" elements
  149.          *
  150.          * Since block elements (like <blockquotes>, <pre>, etc.) do not get
  151.          * wrapped in paragraph tags we will add a closing </p> tag just before
  152.          * each block element starts and an opening <p> tag right after the block element
  153.          * ends.  Later on we'll do some further clean up.
  154.          *
  155.          */
  156.         $str preg_replace("#(<)(".$this->block_elements.")(.*?>)#""</p>\\1\\2\\3"$str);
  157.         $str preg_replace("#(</)(".$this->block_elements.")(.*?>)#""\\1\\2\\3<p>"$str);
  158.     
  159.         /*
  160.          * Convert "ignore" tags to temporary marker
  161.          *
  162.          * The parser splits out the string at every tag
  163.          * it encounters.  Certain inline tags, like image
  164.          * tags, links, span tags, etc. will be adversely
  165.          * affected if they are split out so we'll convert
  166.          * the opening < temporarily to: {@TAG}
  167.          *
  168.          */        
  169.         $str preg_replace("#<(/*)(".$this->ignore_elements.")#i""{@TAG}\\1\\2"$str);    
  170.         
  171.         /*
  172.          * Split the string at every tag
  173.          *
  174.          * This creates an array with this prototype:
  175.          *
  176.          *    [array]
  177.          *    {
  178.          *        [0] = <opening tag>
  179.          *        [1] = Content contained between the tags
  180.          *        [2] = <closing tag>
  181.          *        Etc...
  182.          *    }
  183.          *
  184.          */            
  185.         $chunks preg_split('/(<(?:[^<>]+(?:"[^"]*"|\'[^\']*\')?)+>)/'$str-1PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);
  186.         
  187.         /*
  188.          * Build our finalized string
  189.          *
  190.          * We'll cycle through the array, skipping tags,
  191.          * and processing the contained text
  192.          *
  193.          */            
  194.         $str '';
  195.         $process TRUE;
  196.         foreach ($chunks as $chunk)
  197.         {
  198.             /*
  199.              * Are we dealing with a tag?
  200.              *
  201.              * If so, we'll skip the processing for this cycle.
  202.              * Well also set the "process" flag which allows us
  203.              * to skip <pre> tags and a few other things.
  204.              *
  205.              */
  206.             if (preg_match("#<(/*)(".$this->block_elements.").*?\>#"$chunk$match))
  207.             {
  208.                 if (preg_match("#".$this->skip_elements."#"$match['2']))
  209.                 {
  210.                     $process =  ($match['1'== '/'TRUE FALSE;        
  211.                 }
  212.         
  213.                 $str .= $chunk;
  214.                 continue;
  215.             }
  216.         
  217.             if ($process == FALSE)
  218.             {
  219.                 $str .= $chunk;
  220.                 continue;
  221.             }
  222.             
  223.             //  Convert Newlines into <p> and <br /> tags
  224.             $str .= $this->format_newlines($chunk);
  225.         }
  226.  
  227.         // FINAL CLEAN UP
  228.         // IMPORTANT:  DO NOT ALTER THE ORDER OF THE ITEMS BELOW!
  229.         
  230.         /*
  231.          * Clean up paragraph tags before/after "block" elements
  232.          *
  233.          * Earlier we added <p></p> tags before/after block level elements.
  234.          * Then, we added paragraph tags around double line breaks.  This
  235.          * potentially created incorrectly formatted paragraphs so we'll
  236.          * clean it up here.
  237.          *
  238.          */
  239.         $str preg_replace("#<p>({@TAG}.*?)(".$this->block_elements.")(.*?>)#""\\1\\2\\3"$str);
  240.         $str preg_replace("#({@TAG}/.*?)(".$this->block_elements.")(.*?>)</p>#""\\1\\2\\3"$str);
  241.  
  242.         // Convert Quotes and other characters
  243.         $str $this->format_characters($str);
  244.         
  245.         // Fix an artifact that happens during the paragraph replacement
  246.         $str preg_replace('#(<p>\n*</p>)#'''$str);
  247.  
  248.         // If the user submitted their own paragraph tags with class data
  249.         // in them we will retain them instead of using our tags.
  250.         $str preg_replace('#(<p.*?>)<p>#'"\\1"$str);
  251.  
  252.         // Final clean up
  253.         $str str_replace(
  254.                             array(
  255.                                     '</p></p>',
  256.                                     '</p><p>',
  257.                                     '<p> ',
  258.                                     ' </p>',
  259.                                     '{@TAG}',
  260.                                     '{@DQ}',
  261.                                     '{@SQ}',
  262.                                     '<p></p>'
  263.                                 ),
  264.                             array(
  265.                                     '</p>',
  266.                                     '<p>',
  267.                                     '<p>',
  268.                                     '</p>',
  269.                                     '<',
  270.                                     '"',
  271.                                     "'",
  272.                                     ''
  273.                                 ),
  274.                             $str
  275.                         );
  276.         
  277.         return $str;
  278.     }
  279.     
  280.     // --------------------------------------------------------------------
  281.  
  282.     /**
  283.      * Format Characters
  284.      *
  285.      * This function mainly converts double and single quotes
  286.      * to entities, but since these are directional, it does
  287.      * it based on some rules.  It also converts em-dashes
  288.      * and a couple other things.
  289.      */
  290.     function format_characters($str)
  291.     {    
  292.         $table array(
  293.                         ' "'        => " &#8220;",
  294.                         '" '        => "&#8221; ",
  295.                         " '"        => " &#8216;",
  296.                         "' "        => "&#8217; ",
  297.                         
  298.                         '>"'        => ">&#8220;",
  299.                         '"<'        => "&#8221;<",
  300.                         ">'"        => ">&#8216;",
  301.                         "'<"        => "&#8217;<",
  302.  
  303.                         "\"."        => "&#8221;.",
  304.                         "\","        => "&#8221;,",
  305.                         "\";"        => "&#8221;;",
  306.                         "\":"        => "&#8221;:",
  307.                         "\"!"        => "&#8221;!",
  308.                         "\"?"        => "&#8221;?",
  309.                         
  310.                         ".  "        => ".&nbsp; ",
  311.                         "?  "        => "?&nbsp; ",
  312.                         "!  "        => "!&nbsp; ",
  313.                         ":  "        => ":&nbsp; ",
  314.                     );
  315.  
  316.         // These deal with quotes within quotes, like:  "'hi here'"
  317.         $start 0;
  318.         $space array("\n""\t"" ");
  319.         
  320.         while(TRUE)
  321.         {
  322.             $current strpos(substr($str$start)"\"'");
  323.             
  324.             if ($current === FALSEbreak;
  325.             
  326.             $one_before substr($str$start+$current-11);
  327.             $one_after substr($str$start+$current+21);
  328.             
  329.             if in_array($one_after$spaceTRUE&& $one_after != "<")
  330.             {
  331.                 $str str_replace(    $one_before."\"'".$one_after,
  332.                                     $one_before."&#8220;&#8216;".$one_after,
  333.                                     $str);
  334.             }
  335.             elseif in_array($one_before$spaceTRUE&& (in_array($one_after$spaceTRUEOR $one_after == '<'))
  336.             {
  337.                 $str str_replace(    $one_before."\"'".$one_after,
  338.                                     $one_before."&#8221;&#8217;".$one_after,
  339.                                     $str);
  340.             }
  341.             
  342.             $start $start+$current+2;
  343.         }
  344.         
  345.         $start 0;
  346.         
  347.         while(TRUE)
  348.         {
  349.             $current strpos(substr($str$start)"'\"");
  350.             
  351.             if ($current === FALSEbreak;
  352.             
  353.             $one_before substr($str$start+$current-11);
  354.             $one_after substr($str$start+$current+21);
  355.             
  356.             if in_array($one_before$spaceTRUE&& in_array($one_after$spaceTRUE&& $one_after != "<")
  357.             {
  358.                 $str str_replace(    $one_before."'\"".$one_after,
  359.                                     $one_before."&#8216;&#8220;".$one_after,
  360.                                     $str);
  361.             }
  362.             elseif in_array($one_before$spaceTRUE&& $one_before != ">")
  363.             {
  364.                 $str str_replace(    $one_before."'\"".$one_after,
  365.                                     $one_before."&#8217;&#8221;".$one_after,
  366.                                     $str);
  367.             }
  368.             
  369.             $start $start+$current+2;
  370.         }
  371.         
  372.         // Are there quotes within a word, as in:  ("something")
  373.         if (preg_match_all("/(.)\"(\S+?)\"(.)/"$str$matches))
  374.         {
  375.             for ($i=0$s=sizeof($matches['0'])$i $s++$i)
  376.             {
  377.                 if in_array($matches['1'][$i]$spaceTRUE&& in_array($matches['3'][$i]$spaceTRUE))
  378.                 {
  379.                     $str str_replace(    $matches['0'][$i],
  380.                                         $matches['1'][$i]."&#8220;".$matches['2'][$i]."&#8221;".$matches['3'][$i],
  381.                                         $str);
  382.                 }
  383.             }
  384.         }
  385.         
  386.         if (preg_match_all("/(.)\'(\S+?)\'(.)/"$str$matches))
  387.         {
  388.             for ($i=0$s=sizeof($matches['0'])$i $s++$i)
  389.             {
  390.                 if in_array($matches['1'][$i]$spaceTRUE&& in_array($matches['3'][$i]$spaceTRUE))
  391.                 {
  392.                     $str str_replace(    $matches['0'][$i],
  393.                                         $matches['1'][$i]."&#8216;".$matches['2'][$i]."&#8217;".$matches['3'][$i],
  394.                                         $str);
  395.                 }
  396.             }
  397.         }
  398.         
  399.         // How about one apostrophe, as in Rick's
  400.         $start 0;
  401.         
  402.         while(TRUE)
  403.         {
  404.             $current strpos(substr($str$start)"'");
  405.             
  406.             if ($current === FALSEbreak;
  407.             
  408.             $one_before substr($str$start+$current-11);
  409.             $one_after substr($str$start+$current+11);
  410.             
  411.             if in_array($one_before$spaceTRUE&& in_array($one_after$spaceTRUE))
  412.             {
  413.                 $str str_replace(    $one_before."'".$one_after,
  414.                                     $one_before."&#8217;".$one_after,
  415.                                     $str);
  416.             }
  417.             
  418.             $start $start+$current+2;
  419.         }
  420.  
  421.         // Em-dashes
  422.         $start 0;
  423.         while(TRUE)
  424.         {
  425.             $current strpos(substr($str$start)"--");
  426.             
  427.             if ($current === FALSEbreak;
  428.             
  429.             $one_before substr($str$start+$current-11);
  430.             $one_after substr($str$start+$current+21);
  431.             $two_before substr($str$start+$current-21);
  432.             $two_after substr($str$start+$current+31);
  433.             
  434.             if (( in_array($one_before$spaceTRUE&& in_array($one_after$spaceTRUE))
  435.                 OR
  436.                 in_array($two_before$spaceTRUE&& in_array($two_after$spaceTRUE&& $one_before == ' ' && $one_after == ' ')
  437.                 )
  438.             {
  439.                 $str str_replace(    $two_before.$one_before."--".$one_after.$two_after,
  440.                                     $two_before.trim($one_before)."&#8212;".trim($one_after).$two_after,
  441.                                     $str);
  442.             }
  443.             
  444.             $start $start+$current+2;
  445.         }
  446.         
  447.         // Ellipsis
  448.         $str preg_replace("#(\w)\.\.\.(\s|<br />|</p>)#""\\1&#8230;\\2"$str);
  449.         $str preg_replace("#(\s|<br />|</p>)\.\.\.(\w)#""\\1&#8230;\\2"$str);
  450.         
  451.         // Run the translation array we defined above        
  452.         $str str_replace(array_keys($table)array_values($table)$str);
  453.         
  454.         // If there are any stray double quotes we'll catch them here
  455.         
  456.         $start 0;
  457.         
  458.         while(TRUE)
  459.         {
  460.             $current strpos(substr($str$start)'"');
  461.             
  462.             if ($current === FALSEbreak;
  463.             
  464.             $one_before substr($str$start+$current-11);
  465.             $one_after substr($str$start+$current+11);
  466.             
  467.             if in_array($one_after$spaceTRUE))
  468.             {
  469.                 $str str_replace(    $one_before.'"'.$one_after,
  470.                                     $one_before."&#8220;".$one_after,
  471.                                     $str);
  472.             }
  473.             elseifin_array($one_before$spaceTRUE))
  474.             {
  475.                 $str str_replace(    $one_before."'".$one_after,
  476.                                     $one_before."&#8221;".$one_after,
  477.                                     $str);
  478.             }
  479.             
  480.             $start $start+$current+2;
  481.         }
  482.         
  483.         $start 0;
  484.         
  485.         while(TRUE)
  486.         {
  487.             $current strpos(substr($str$start)"'");
  488.             
  489.             if ($current === FALSEbreak;
  490.             
  491.             $one_before substr($str$start+$current-11);
  492.             $one_after substr($str$start+$current+11);
  493.             
  494.             if in_array($one_after$spaceTRUE))
  495.             {
  496.                 $str str_replace(    $one_before."'".$one_after,
  497.                                     $one_before."&#8216;".$one_after,
  498.                                     $str);
  499.             }
  500.             elseifin_array($one_before$spaceTRUE))
  501.             {
  502.                 $str str_replace(    $one_before."'".$one_after,
  503.                                     $one_before."&#8217;".$one_after,
  504.                                     $str);
  505.             }
  506.             
  507.             $start $start+$current+2;
  508.         }
  509.         
  510.         return $str;
  511.     }
  512.     
  513.     // --------------------------------------------------------------------
  514.  
  515.     /**
  516.      * Format Newlines
  517.      *
  518.      * Converts newline characters into either <p> tags or <br />
  519.      *
  520.      */    
  521.     function format_newlines($str)
  522.     {
  523.         if ($str == '')
  524.         {
  525.             return $str;
  526.         }
  527.  
  528.         if (strpos($str"\n"=== FALSE)
  529.         {
  530.             return '<p>'.$str.'</p>';
  531.         }
  532.             
  533.         $str str_replace("\n\n""</p>\n\n<p>"$str);
  534.         $str preg_replace("/([^\n])(\n)([^\n])/""\\1<br />\\2\\3"$str);
  535.         
  536.         return '<p>'.$str.'</p>';
  537.     }    
  538. }
  539.  
  540.  
  541. ?>

Documentation generated on Tue, 22 Nov 2011 13:29:01 -0200 by phpDocumentor 1.4.3