| 1 | # See bottom of file for license and copyright information |
|---|
| 2 | package Foswiki::Plugins::WysiwygPlugin::Constants; |
|---|
| 3 | |
|---|
| 4 | use strict; |
|---|
| 5 | use warnings; |
|---|
| 6 | |
|---|
| 7 | use Encode; |
|---|
| 8 | |
|---|
| 9 | # HTML elements that are strictly block type, as defined by |
|---|
| 10 | # http://www.htmlhelp.com/reference/html40/block.html. |
|---|
| 11 | # Block type elements do not require |
|---|
| 12 | # <br /> to be generated for newlines on the boundary - see WC::isInline. |
|---|
| 13 | our %ALWAYS_BLOCK = map { $_ => 1 } |
|---|
| 14 | qw( ADDRESS BLOCKQUOTE CENTER DIR DIV DL FIELDSET FORM H1 H2 H3 H4 H5 H6 |
|---|
| 15 | HR ISINDEX MENU NOFRAMES NOSCRIPT OL P PRE TABLE UL ); |
|---|
| 16 | our $ALWAYS_BLOCK_S = join( '|', keys %ALWAYS_BLOCK ); |
|---|
| 17 | |
|---|
| 18 | # STARTWW should match Foswiki::Render, execpt need to include protected whitespace spans. |
|---|
| 19 | our $STARTWW = |
|---|
| 20 | qr/^|(?<=[ \t\n\(])|(?<=<p>)|(?<=nbsp;<\/span>)|(?<=160;<\/span>)/om; |
|---|
| 21 | our $ENDWW = qr/$|(?=[ \t\n\,\.\;\:\!\?\)])|(?=<\/p>)|(?=<span\b[^>]*> )/om; |
|---|
| 22 | our $PROTOCOL = qr/^(file|ftp|gopher|https?|irc|news|nntp|telnet|mailto):/; |
|---|
| 23 | |
|---|
| 24 | # Colours with colour settings in DefaultPreferences. |
|---|
| 25 | our @TML_COLOURS = ( |
|---|
| 26 | 'BLACK', 'MAROON', 'PURPLE', 'PINK', 'RED', 'ORANGE', |
|---|
| 27 | 'YELLOW', 'LIME', 'AQUA', 'AQUAMARINE', 'GREEN', 'OLIVE', |
|---|
| 28 | 'BROWN', 'NAVY', 'TEAL', 'BLUE', 'GRAY', 'SILVER', |
|---|
| 29 | 'WHITE', |
|---|
| 30 | ); |
|---|
| 31 | |
|---|
| 32 | # Map of possible colours back to TML %COLOUR%...%ENDCOLOR% |
|---|
| 33 | our %HTML2TML_COLOURMAP = ( |
|---|
| 34 | BLACK => 'BLACK', |
|---|
| 35 | '#000000' => 'BLACK', |
|---|
| 36 | MAROON => 'MAROON', |
|---|
| 37 | '#800000' => 'MAROON', |
|---|
| 38 | PURPLE => 'PURPLE', |
|---|
| 39 | '#800080' => 'PURPLE', |
|---|
| 40 | FUCHSIA => 'PINK', |
|---|
| 41 | '#FF00FF' => 'PINK', |
|---|
| 42 | RED => 'RED', |
|---|
| 43 | '#FF0000' => 'RED', |
|---|
| 44 | ORANGE => 'ORANGE', |
|---|
| 45 | '#FF6600' => 'ORANGE', |
|---|
| 46 | YELLOW => 'YELLOW', |
|---|
| 47 | '#FFFF00' => 'YELLOW', |
|---|
| 48 | LIME => 'LIME', |
|---|
| 49 | '#00FF00' => 'LIME', |
|---|
| 50 | AQUA => 'AQUA', |
|---|
| 51 | AQUAMARINE => 'AQUA', |
|---|
| 52 | '#00FFFF' => 'AQUA', |
|---|
| 53 | GREEN => 'GREEN', |
|---|
| 54 | '#008000' => 'GREEN', |
|---|
| 55 | OLIVE => 'OLIVE', |
|---|
| 56 | '#808000' => 'OLIVE', |
|---|
| 57 | BROWN => 'BROWN', |
|---|
| 58 | '#996633' => 'BROWN', |
|---|
| 59 | NAVY => 'NAVY', |
|---|
| 60 | '#000080' => 'NAVY', |
|---|
| 61 | TEAL => 'TEAL', |
|---|
| 62 | '#008080' => 'TEAL', |
|---|
| 63 | BLUE => 'BLUE', |
|---|
| 64 | '#0000FF' => 'BLUE', |
|---|
| 65 | GRAY => 'GRAY', |
|---|
| 66 | '#808080' => 'GRAY', |
|---|
| 67 | SILVER => 'SILVER', |
|---|
| 68 | '#C0C0C0' => 'SILVER', |
|---|
| 69 | WHITE => 'WHITE', |
|---|
| 70 | '#FFFFFF' => 'WHITE', |
|---|
| 71 | ); |
|---|
| 72 | |
|---|
| 73 | # Genuine HTML colors as follows: |
|---|
| 74 | # '#4682B4' => 'steelblue', |
|---|
| 75 | # '#041690' => 'royalblue', |
|---|
| 76 | # '#6495ED' => 'cornflowerblue', |
|---|
| 77 | # '#B0C4DE' => 'lightsteelblue', |
|---|
| 78 | # '#7B68EE' => 'mediumslateblue', |
|---|
| 79 | # '#6A5ACD' => 'slateblue', |
|---|
| 80 | # '#483D8B' => 'darkslateblue', |
|---|
| 81 | # '#191970' => 'midnightblue', |
|---|
| 82 | # '#000080' => 'navy', |
|---|
| 83 | # '#00008B' => 'darkblue', |
|---|
| 84 | # '#0000CD' => 'mediumblue', |
|---|
| 85 | # '#0000FF' => 'blue', |
|---|
| 86 | # '#1E90FF' => 'dodgerblue', |
|---|
| 87 | # '#00BFFF' => 'deepskyblue', |
|---|
| 88 | # '#87CEFA' => 'lightskyblue', |
|---|
| 89 | # '#87CEEB' => 'skyblue', |
|---|
| 90 | # '#ADD8E6' => 'lightblue', |
|---|
| 91 | # '#B0E0E6' => 'powderblue', |
|---|
| 92 | # '#F0FFFF' => 'azure', |
|---|
| 93 | # '#E0FFFF' => 'lightcyan', |
|---|
| 94 | # '#AFEEEE' => 'paleturquoise', |
|---|
| 95 | # '#48D1CC' => 'mediumturquoise', |
|---|
| 96 | # '#20B2AA' => 'lightseagreen', |
|---|
| 97 | # '#008B8B' => 'darkcyan', |
|---|
| 98 | # '#008080' => 'teal', |
|---|
| 99 | # '#5F9EA0' => 'cadetblue', |
|---|
| 100 | # '#00CED1' => 'darkturquoise', |
|---|
| 101 | # '#00FFFF' => 'aqua', |
|---|
| 102 | # '#00FFFF' => 'cyan', |
|---|
| 103 | # '#40E0D0' => 'turquoise', |
|---|
| 104 | # '#7FFFD4' => 'aquamarine', |
|---|
| 105 | # '#66CDAA' => 'mediumaquamarine', |
|---|
| 106 | # '#8FBC8F' => 'darkseagreen', |
|---|
| 107 | # '#3CB371' => 'mediumseagreen', |
|---|
| 108 | # '#2E8B57' => 'seagreen', |
|---|
| 109 | # '#006400' => 'darkgreen', |
|---|
| 110 | # '#008000' => 'green', |
|---|
| 111 | # '#228B22' => 'forestgreen', |
|---|
| 112 | # '#32CD32' => 'limegreen', |
|---|
| 113 | # '#00FF00' => 'lime', |
|---|
| 114 | # '#7FFF00' => 'chartreuse', |
|---|
| 115 | # '#7CFC00' => 'lawngreen', |
|---|
| 116 | # '#ADFF2F' => 'greenyellow', |
|---|
| 117 | # '#9ACD32' => 'yellowgreen', |
|---|
| 118 | # '#98FB98' => 'palegreen', |
|---|
| 119 | # '#90EE90' => 'lightgreen', |
|---|
| 120 | # '#00FF7F' => 'springgreen', |
|---|
| 121 | # '#00FA9A' => 'mediumspringgreen', |
|---|
| 122 | # '#556B2F' => 'darkolivegreen', |
|---|
| 123 | # '#6B8E23' => 'olivedrab', |
|---|
| 124 | # '#808000' => 'olive', |
|---|
| 125 | # '#BDB76B' => 'darkkhaki', |
|---|
| 126 | # '#B8860B' => 'darkgoldenrod', |
|---|
| 127 | # '#DAA520' => 'goldenrod', |
|---|
| 128 | # '#FFD700' => 'gold', |
|---|
| 129 | # '#FFFF00' => 'yellow', |
|---|
| 130 | # '#F0E68C' => 'khaki', |
|---|
| 131 | # '#EEE8AA' => 'palegoldenrod', |
|---|
| 132 | # '#FFEBCD' => 'blanchedalmond', |
|---|
| 133 | # '#FFE4B5' => 'moccasin', |
|---|
| 134 | # '#F5DEB3' => 'wheat', |
|---|
| 135 | # '#FFDEAD' => 'navajowhite', |
|---|
| 136 | # '#DEB887' => 'burlywood', |
|---|
| 137 | # '#D2B48C' => 'tan', |
|---|
| 138 | # '#BC8F8F' => 'rosybrown', |
|---|
| 139 | # '#A0522D' => 'sienna', |
|---|
| 140 | # '#8B4513' => 'saddlebrown', |
|---|
| 141 | # '#D2691E' => 'chocolate', |
|---|
| 142 | # '#CD853F' => 'peru', |
|---|
| 143 | # '#F4A460' => 'sandybrown', |
|---|
| 144 | # '#8B0000' => 'darkred', |
|---|
| 145 | # '#800000' => 'maroon', |
|---|
| 146 | # '#A52A2A' => 'brown', |
|---|
| 147 | # '#B22222' => 'firebrick', |
|---|
| 148 | # '#CD5C5C' => 'indianred', |
|---|
| 149 | # '#F08080' => 'lightcoral', |
|---|
| 150 | # '#FA8072' => 'salmon', |
|---|
| 151 | # '#E9967A' => 'darksalmon', |
|---|
| 152 | # '#FFA07A' => 'lightsalmon', |
|---|
| 153 | # '#FF7F50' => 'coral', |
|---|
| 154 | # '#FF6347' => 'tomato', |
|---|
| 155 | # '#FF8C00' => 'darkorange', |
|---|
| 156 | # '#FFA500' => 'orange', |
|---|
| 157 | # '#FF4500' => 'orangered', |
|---|
| 158 | # '#DC143C' => 'crimson', |
|---|
| 159 | # '#FF0000' => 'red', |
|---|
| 160 | # '#FF1493' => 'deeppink', |
|---|
| 161 | # '#FF00FF' => 'fuchsia', |
|---|
| 162 | # '#FF00FF' => 'magenta', |
|---|
| 163 | # '#FF69B4' => 'hotpink', |
|---|
| 164 | # '#FFB6C1' => 'lightpink', |
|---|
| 165 | # '#FFC0CB' => 'pink', |
|---|
| 166 | # '#DB7093' => 'palevioletred', |
|---|
| 167 | # '#C71585' => 'mediumvioletred', |
|---|
| 168 | # '#800080' => 'purple', |
|---|
| 169 | # '#8B008B' => 'darkmagenta', |
|---|
| 170 | # '#9370DB' => 'mediumpurple', |
|---|
| 171 | # '#8A2BE2' => 'blueviolet', |
|---|
| 172 | # '#4B0082' => 'indigo', |
|---|
| 173 | # '#9400D3' => 'darkviolet', |
|---|
| 174 | # '#9932CC' => 'darkorchid', |
|---|
| 175 | # '#BA55D3' => 'mediumorchid', |
|---|
| 176 | # '#DA70D6' => 'orchid', |
|---|
| 177 | # '#EE82EE' => 'violet', |
|---|
| 178 | # '#DDA0DD' => 'plum', |
|---|
| 179 | # '#D8BFD8' => 'thistle', |
|---|
| 180 | # '#E6E6FA' => 'lavender', |
|---|
| 181 | # '#F8F8FF' => 'ghostwhite', |
|---|
| 182 | # '#F0F8FF' => 'aliceblue', |
|---|
| 183 | # '#F5FFFA' => 'mintcream', |
|---|
| 184 | # '#F0FFF0' => 'honeydew', |
|---|
| 185 | # '#FAFAD2' => 'lightgoldenrodyellow', |
|---|
| 186 | # '#FFFACD' => 'lemonchiffon', |
|---|
| 187 | # '#FFF8DC' => 'cornsilk', |
|---|
| 188 | # '#FFFFE0' => 'lightyellow', |
|---|
| 189 | # '#FFFFF0' => 'ivory', |
|---|
| 190 | # '#FFFAF0' => 'floralwhite', |
|---|
| 191 | # '#FAF0E6' => 'linen', |
|---|
| 192 | # '#FDF5E6' => 'oldlace', |
|---|
| 193 | # '#FAEBD7' => 'antiquewhite', |
|---|
| 194 | # '#FFE4C4' => 'bisque', |
|---|
| 195 | # '#FFDAB9' => 'peachpuff', |
|---|
| 196 | # '#FFEFD5' => 'papayawhip', |
|---|
| 197 | # '#F5F5DC' => 'beige', |
|---|
| 198 | # '#FFF5EE' => 'seashell', |
|---|
| 199 | # '#FFF0F5' => 'lavenderblush', |
|---|
| 200 | # '#FFE4E1' => 'mistyrose', |
|---|
| 201 | # '#FFFAFA' => 'snow', |
|---|
| 202 | # '#FFFFFF' => 'white', |
|---|
| 203 | # '#F5F5F5' => 'whitesmoke', |
|---|
| 204 | # '#DCDCDC' => 'gainsboro', |
|---|
| 205 | # '#D3D3D3' => 'lightgrey', |
|---|
| 206 | |
|---|
| 207 | ############ Encodings ############### |
|---|
| 208 | |
|---|
| 209 | our $encoding; |
|---|
| 210 | |
|---|
| 211 | sub encoding { |
|---|
| 212 | unless ($encoding) { |
|---|
| 213 | $encoding = |
|---|
| 214 | Encode::resolve_alias( $Foswiki::cfg{Site}{CharSet} || 'iso-8859-1' ); |
|---|
| 215 | |
|---|
| 216 | $encoding = 'windows-1252' if $encoding =~ /^iso-8859-1$/i; |
|---|
| 217 | } |
|---|
| 218 | return $encoding; |
|---|
| 219 | } |
|---|
| 220 | |
|---|
| 221 | my $siteCharsetRepresentable; |
|---|
| 222 | |
|---|
| 223 | # Convert characters (unicode codepoints) that cannot be represented in |
|---|
| 224 | # the site charset to entities. Prefer named entities to numeric entities. |
|---|
| 225 | sub convertNotRepresentabletoEntity { |
|---|
| 226 | if ( encoding() =~ /^utf-?8/ ) { |
|---|
| 227 | |
|---|
| 228 | # UTF-8 can represent all characters, so no entities needed |
|---|
| 229 | } |
|---|
| 230 | else { |
|---|
| 231 | unless ($siteCharsetRepresentable) { |
|---|
| 232 | |
|---|
| 233 | # Produce a string of unicode characters that contains all of the |
|---|
| 234 | # characters representable in the site charset |
|---|
| 235 | $siteCharsetRepresentable = ''; |
|---|
| 236 | for my $code ( 0 .. 255 ) { |
|---|
| 237 | my $unicodeChar = |
|---|
| 238 | Encode::decode( encoding(), chr($code), Encode::FB_PERLQQ ); |
|---|
| 239 | if ( $unicodeChar =~ /^\\x/ ) { |
|---|
| 240 | |
|---|
| 241 | # code is not valid, so skip it |
|---|
| 242 | } |
|---|
| 243 | else { |
|---|
| 244 | |
|---|
| 245 | # Escape codes in the standard ASCII range, as necessary, |
|---|
| 246 | # to avoid special interpretation by perl |
|---|
| 247 | $unicodeChar = quotemeta($unicodeChar) |
|---|
| 248 | if ord($unicodeChar) <= 127; |
|---|
| 249 | |
|---|
| 250 | $siteCharsetRepresentable .= $unicodeChar; |
|---|
| 251 | } |
|---|
| 252 | } |
|---|
| 253 | } |
|---|
| 254 | |
|---|
| 255 | require HTML::Entities; |
|---|
| 256 | $_[0] = |
|---|
| 257 | HTML::Entities::encode_entities( $_[0], |
|---|
| 258 | "^$siteCharsetRepresentable" ); |
|---|
| 259 | |
|---|
| 260 | # All characters that cannot be represented in the site charset are now encoded as entities |
|---|
| 261 | # Named entities are used if available, otherwise numeric entities, |
|---|
| 262 | # because named entities produce more readable TML |
|---|
| 263 | } |
|---|
| 264 | } |
|---|
| 265 | |
|---|
| 266 | # Named entities that we want to convert back to characters, rather |
|---|
| 267 | # than leaving them as HTML entities. |
|---|
| 268 | our @safeEntities = qw( |
|---|
| 269 | euro iexcl cent pound curren yen brvbar sect |
|---|
| 270 | uml copy ordf laquo not shy reg macr |
|---|
| 271 | deg plusmn sup2 sup3 acute micro para middot |
|---|
| 272 | cedil sup1 ordm raquo frac14 frac12 frac34 iquest |
|---|
| 273 | Agrave Aacute Acirc Atilde Auml Aring AElig Ccedil |
|---|
| 274 | Egrave Eacute Ecirc Euml Igrave Iacute Icirc Iuml |
|---|
| 275 | ETH Ntilde Ograve Oacute Ocirc Otilde Ouml times |
|---|
| 276 | Oslash Ugrave Uacute Ucirc Uuml Yacute THORN szlig |
|---|
| 277 | agrave aacute acirc atilde auml aring aelig ccedil |
|---|
| 278 | egrave eacute ecirc euml igrave iacute icirc iuml |
|---|
| 279 | eth ntilde ograve oacute ocirc otilde ouml divide |
|---|
| 280 | oslash ugrave uacute ucirc uuml yacute thorn yuml |
|---|
| 281 | ); |
|---|
| 282 | |
|---|
| 283 | # Mapping from entity names to characters |
|---|
| 284 | our $safe_entities; |
|---|
| 285 | |
|---|
| 286 | # Get a hash that maps the safe entities values to unicode characters |
|---|
| 287 | sub safeEntities { |
|---|
| 288 | unless ($safe_entities) { |
|---|
| 289 | foreach my $entity (@safeEntities) { |
|---|
| 290 | |
|---|
| 291 | # Decode the entity name to unicode |
|---|
| 292 | my $unicode = HTML::Entities::decode_entities("&$entity;"); |
|---|
| 293 | |
|---|
| 294 | $safe_entities->{"$entity"} = $unicode; |
|---|
| 295 | } |
|---|
| 296 | } |
|---|
| 297 | return $safe_entities; |
|---|
| 298 | } |
|---|
| 299 | |
|---|
| 300 | # Debug |
|---|
| 301 | sub chCodes { |
|---|
| 302 | my $text = shift; |
|---|
| 303 | my $s = ""; |
|---|
| 304 | for ( my $i = 0 ; $i < length($text) ; $i++ ) { |
|---|
| 305 | my $ch = substr( $text, $i, 1 ); |
|---|
| 306 | if ( ord($ch) < 32 || ord($ch) > 127 ) { |
|---|
| 307 | $s = $s . '#' . ord($ch) . ';'; |
|---|
| 308 | } |
|---|
| 309 | else { |
|---|
| 310 | $s .= $ch; |
|---|
| 311 | } |
|---|
| 312 | } |
|---|
| 313 | return $s; |
|---|
| 314 | } |
|---|
| 315 | |
|---|
| 316 | # Allow the unit tests to force re-initialisation of |
|---|
| 317 | # %Foswiki::cfg-dependent cached data |
|---|
| 318 | sub reinitialiseForTesting { |
|---|
| 319 | undef $encoding; |
|---|
| 320 | undef $siteCharsetRepresentable; |
|---|
| 321 | } |
|---|
| 322 | |
|---|
| 323 | # Create shorter alias for other modules |
|---|
| 324 | no strict 'refs'; |
|---|
| 325 | *{'WC::'} = \*{'Foswiki::Plugins::WysiwygPlugin::Constants::'}; |
|---|
| 326 | |
|---|
| 327 | 1; |
|---|
| 328 | __END__ |
|---|
| 329 | Foswiki - The Free and Open Source Wiki, http://foswiki.org/ |
|---|
| 330 | |
|---|
| 331 | Copyright (C) 2008-2010 Foswiki Contributors. Foswiki Contributors |
|---|
| 332 | are listed in the AUTHORS file in the root of this distribution. |
|---|
| 333 | NOTE: Please extend that file, not this notice. |
|---|
| 334 | |
|---|
| 335 | This program is free software; you can redistribute it and/or |
|---|
| 336 | modify it under the terms of the GNU General Public License |
|---|
| 337 | as published by the Free Software Foundation; either version 2 |
|---|
| 338 | of the License, or (at your option) any later version. For |
|---|
| 339 | more details read LICENSE in the root of this distribution. |
|---|
| 340 | |
|---|
| 341 | This program is distributed in the hope that it will be useful, |
|---|
| 342 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 343 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|---|
| 344 | |
|---|
| 345 | As per the GPL, removal of this notice is prohibited. |
|---|