/[drupal]/contributions/modules/typogrify/typogrify.class.php
ViewVC logotype

Contents of /contributions/modules/typogrify/typogrify.class.php

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.4 - (show annotations) (download) (as text)
Sat May 30 12:55:19 2009 UTC (5 months, 4 weeks ago) by mikl
Branch: MAIN
CVS Tags: DRUPAL-7--1-0-ALPHA1, DRUPAL-7--1-0-BETA1, HEAD
Changes since 1.3: +3 -1 lines
File MIME type: text/x-php
Merged changes from DRUPAL6--1.
1 <?php
2 // $Id: typogrify.class.php,v 1.2.2.4 2009/04/28 16:01:52 mikl Exp $
3
4 /**
5 * @file typogrify.class.php
6 * Defines a class for providing different typographical tweaks to HTML
7 */
8 class Typogrify {
9 /**
10 * Enable custom styling of ampersands.
11 *
12 * Wraps apersands in html with '<span class="amp">', so they can be
13 * styled with CSS. Ampersands are also normalized to '&amp;. Requires
14 * ampersands to have whitespace or an '&nbsp;' on both sides.
15 *
16 * It won't mess up & that are already wrapped, in entities or URLs
17 * @param string
18 * @return string
19 */
20 public static function amp($text) {
21 $amp_finder = "/(\s|&nbsp;)(&|&amp;|&\#38;|&#038;)(\s|&nbsp;)/";
22 return preg_replace($amp_finder, '\\1<span class="amp">&amp;</span>\\3', $text);
23 }
24
25 /**
26 * Puts a &thinsp; before and after an &ndash or &mdash;
27 *
28 * Dashes may have whitespace or an ``&nbsp;`` on both sides
29 * @param string
30 * @return string
31 */
32 public static function dash($text) {
33 $dash_finder = "/(\s|&nbsp;|&thinsp;)*(&mdash;|&ndash;|&#x2013;|&#8211;|&#x2014;|&#8212;)(\s|&nbsp;|&thinsp;)*/";
34 return preg_replace($dash_finder, '&thinsp;\\2&thinsp;', $text);
35 }
36
37 /**
38 * Helper method for caps method - used for preg_replace_callback
39 */
40 public static function _cap_wrapper($matchobj) {
41 if (!empty($matchobj[2])) {
42 return sprintf('<span class="caps">%s</span>', $matchobj[2]);
43 }
44 else {
45 $mthree = $matchobj[3];
46 if (($mthree{strlen($mthree)-1}) == " ") {
47 $caps = substr($mthree, 0, -1);
48 $tail = ' ';
49 }
50 else {
51 $caps = $mthree;
52 $tail = '';
53 }
54 return sprintf('<span class="caps">%s</span>%s', $caps, $tail);
55 }
56 }
57
58 /**
59 * Stylable capitals
60 *
61 * Wraps multiple capital letters in ``<span class="caps">``
62 * so they can be styled with CSS.
63 *
64 * Uses the smartypants tokenizer to not screw with HTML or with tags it shouldn't.
65 */
66 public static function caps($text) {
67 // If _TokenizeHTML from Smartypants is not present, don't do anything.
68 if (!function_exists('_TokenizeHTML')) {
69 return $text;
70 }
71
72 $tokens = _TokenizeHTML($text);
73 $result = array();
74 $in_skipped_tag = false;
75
76 $cap_finder = "/(
77 (\b[A-Z\d]* # Group 2: Any amount of caps and digits
78 [A-Z]\d*[A-Z] # A cap string much at least include two caps (but they can have digits between them)
79 [A-Z\d]*\b) # Any amount of caps and digits
80 | (\b[A-Z]+\.\s? # OR: Group 3: Some caps, followed by a '.' and an optional space
81 (?:[A-Z]+\.\s?)+) # Followed by the same thing at least once more
82 (?:\s|\b|$))/x";
83
84 $tags_to_skip_regex = "/<(\/)?(?:pre|code|kbd|script|math)[^>]*>/i";
85
86 foreach ($tokens as $token) {
87 if ( $token[0] == "tag" ) {
88 // Don't mess with tags.
89 $result[] = $token[1];
90 $close_match = preg_match($tags_to_skip_regex, $token[1]);
91 if ($close_match) {
92 $in_skipped_tag = true;
93 }
94 else {
95 $in_skipped_tag = false;
96 }
97 }
98 else {
99 if ( $in_skipped_tag ) {
100 $result[] = $token[1];
101 }
102 else {
103 $result[] = preg_replace_callback($cap_finder, array('Typogrify', '_cap_wrapper'), $token[1]);
104 }
105 }
106 }
107 return join("", $result);
108 }
109
110 /**
111 * Helper method for initial_quotes method - used for preg_replace_callback
112 */
113 public static function _quote_wrapper($matchobj) {
114 if (!empty($matchobj[7])) {
115 $classname = "dquo";
116 $quote = $matchobj[7];
117 }
118 else {
119 $classname = "quo";
120 $quote = $matchobj[8];
121 }
122 return sprintf('%s<span class="%s">%s</span>', $matchobj[1], $classname, $quote);
123 }
124
125 /**
126 * initial_quotes
127 *
128 * Wraps initial quotes in ``class="dquo"`` for double quotes or
129 * ``class="quo"`` for single quotes. Works in these block tags ``(h1-h6, p, li)``
130 * and also accounts for potential opening inline elements ``a, em, strong, span, b, i``
131 * Optionally choose to apply quote span tags to Gullemets as well.
132 */
133 public static function initial_quotes($text, $do_guillemets = false) {
134 $quote_finder = "/((<(p|h[1-6]|li)[^>]*>|^) # start with an opening p, h1-6, li or the start of the string
135 \s* # optional white space!
136 (<(a|em|span|strong|i|b)[^>]*>\s*)*) # optional opening inline tags, with more optional white space for each.
137 ((\"|&ldquo;|&\#8220;)|('|&lsquo;|&\#8216;)) # Find me a quote! (only need to find the left quotes and the primes)
138 # double quotes are in group 7, singles in group 8
139 /ix";
140
141 if ($do_guillemets) {
142 $quote_finder = "/((<(p|h[1-6]|li)[^>]*>|^) # start with an opening p, h1-6, li or the start of the string
143 \s* # optional white space!
144 (<(a|em|span|strong|i|b)[^>]*>\s*)*) # optional opening inline tags, with more optional white space for each.
145 ((\"|&ldquo;|&\#8220;|\xAE|&\#171;|&laquo;)|('|&lsquo;|&\#8216;)) # Find me a quote! (only need to find the left quotes and the primes) - also look for guillemets (>> and << characters))
146 # double quotes are in group 7, singles in group 8
147 /ix";
148 }
149 return preg_replace_callback($quote_finder, array('Typogrify', '_quote_wrapper'), $text);
150 }
151
152 /**
153 * widont
154 *
155 * Replaces the space between the last two words in a string with ``&nbsp;``
156 * Works in these block tags ``(h1-h6, p, li)`` and also accounts for
157 * potential closing inline elements ``a, em, strong, span, b, i``
158 *
159 * Empty HTMLs shouldn't error
160 */
161 public static function widont($text) {
162 // This regex is a beast, tread lightly
163 $widont_finder = "/(\s+) # the space to replace
164 ([^<>\s]+ # must be flollowed by non-tag non-space characters
165 \s* # optional white space!
166 (<\/(a|em|span|strong|i|b)[^>]*>\s*)* # optional closing inline tags with optional white space after each
167 ((<\/(p|h[1-6]|li|dt|dd)>)|$)) # end with a closing p, h1-6, li or the end of the string
168 /x";
169 return preg_replace($widont_finder, '&nbsp;$2', $text);
170 }
171
172 /**
173 * typogrify
174 *
175 * The super typography filter.
176 * Applies the following filters: widont, smartypants, caps, amp, initial_quotes
177 * Optionally choose to apply quote span tags to Gullemets as well.
178 */
179 public static function filter($text, $do_guillemets=FALSE) {
180 $text = Typogrify::amp($text);
181 $text = Typogrify::widont($text);
182 $text = SmartyPants($text);
183 $text = Typogrify::caps($text);
184 $text = Typogrify::initial_quotes($text, $do_guillemets);
185 $text = Typogrify::dash($text);
186 return $text;
187 }
188 }
189

  ViewVC Help
Powered by ViewVC 1.1.2