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