-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathclass-settings.php
1082 lines (1018 loc) · 42.2 KB
/
class-settings.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?php
/**
* This file is part of PHP-Typography.
*
* Copyright 2014-2024 Peter Putzer.
* Copyright 2009-2011 KINGdesk, LLC.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ***
*
* @package mundschenk-at/php-typography
* @license http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace PHP_Typography;
use BadMethodCallException;
use OutOfRangeException;
use TypeError;
use PHP_Typography\Settings\Dash_Style;
use PHP_Typography\Settings\Dashes;
use PHP_Typography\Settings\Quote_Style;
use PHP_Typography\Settings\Quotes;
/**
* Store settings for the PHP_Typography class.
*
* @author Peter Putzer <[email protected]>
*
* @since 4.0.0
* @since 6.5.0 The protected property $no_break_narrow_space has been deprecated.
* @since 7.0.0 Deprecated properties and methods relating to $no_break_narrow_space have been removed.
* Most setter methods have been virtualized via `__call`. The class no longer allows array
* access.
*
* Removed properties:
* - `$remapped_characters`
* - `$unicode_mapping`
*
* Additional removed methods:
* - `apply_character_mapping`
* - `array_map_assoc` (previously deprecated)
* - custom_unit
* - dash_style
* - get_style
* - get_quote_style
* - jsonSerialize
* - offsetExists
* - offsetGet
* - offsetSet
* - offsetUnset
* - primary_quote_style
* - secondary_quote_style
* - update_unit_pattern
*
* General attributes:
* @property-read string[] $tags_to_ignore An array of tags to ignore.
* @property-read string[] $classes_to_ignore An array of HTML classes to ignore.
* @property-read string[] $ids_to_ignore An array of HTML IDs to ignore.
*
* Smart characters:
* @property-read bool $smart_quotes Whether typographic quotes are enabled.
* @property-read array{patterns: string[], replacements: string[]} $smart_quotes_exceptions The specific search & replace patterns for non-standard smart quotes.
* @property-read Quotes $primary_quote_style The primary (double) quote style.
* @property-read Quotes $secondary_quote_style The secondary (single) quote style.
* @property-read bool $smart_dashes Whether replacement of "a--a" with En Dash " -- " and "---" with Em Dash is enabled.
* @property-read Dashes $dash_style The dash style.
* @property-read bool $smart_ellipses Whether replacement of "..." with "…" is enabled.
* @property-read bool $smart_diacritics Whether replacement replacement "creme brulee" with "crème brûlée" is enabled.
* @property-read array{patterns: string[], replacements: string[]} $diacritic_combined The specific search & replace patterns for "smart diacritics" (combined from the diacritic language and any custom replacements).
* @property-read array{patterns: string[], replacements: string[]} $diacritic_words The search & replace patterns read from the diacritic language file.
* @property-read array{patterns: string[], replacements: string[]} $diacritic_custom_replacements The custom search & replace patterns for "smart diacritics".
* @property-read bool $smart_marks Whether replacement of (r) (c) (tm) (sm) (p) (R) (C) (TM) (SM) (P) with ® © ™ ℠ ℗ is enabled.
* @property-read bool $smart_math Whether proper mathematical symbols are enabled.
* @property-read bool $smart_exponents Whether replacement of 2^2 with 2<sup>2</sup> is enabled.
* @property-read bool $smart_fractions Whether replacement of 1/4 with <sup>1</sup>⁄<sub>4</sub> is enabled.
* @property-read bool $smart_ordinal_suffix Whether replacement of 1st with 1<sup>st</sup> is enabled.
* @property-read bool $smart_ordinal_suffix_match_roman_numerals Whether replacement of XXe with XX<sup>e</sup> is enabled.
* @property-read bool $smart_area_units Whether replacement of m2 with m³ and m3 with m³ is enabled.
*
* Smart spacing:
* @property-read bool $single_character_word_spacing Whether single character words are forced to the next line with the insertion of .
* @property-read bool $fraction_spacing Whether fraction spacing is enabled.
* @property-read bool $unit_spacing Whether units and values are kept together with the insertion of .
* @property-read string $custom_units A regex pattern for custom units (or the empty string).
* @property-read bool $numbered_abbreviation_spacing Whether numbered abbreviations like "ISO 9000" are kept together with the insertion of .
* @property-read bool $french_punctuation_spacing Whether extra whitespace before certain punction marks according to the French custom is enabled.
* @property-read bool $dash_spacing Whether wrapping of Em and En dashes are in thin spaces is enabled.
* @property-read bool $space_collapse Whether extra whitespace characters should be removed.
* @property-read bool $dewidow Whether widow handling is enabled.
* @property-read int $max_dewidow_length The maximum length of widows that will be protected.
* @property-read int $dewidow_word_number The maximum number of words considered for dewidowing.
* @property-read int $max_dewidow_pull The maximum length of pulled text to keep widows company.
* @property-read bool $wrap_hard_hyphens Whether wrapping at internal hard hyphens with the insertion of a zero-width-space is enabled.
* @property-read bool $wrap_urls Whether wrapping of URLs is enabled.
* @property-read int $min_after_url_wrap The minimum number of characters required after an URL wrapping point.
* @property-read bool $wrap_emails wrapping of email addresses is enabled.
*
* Characters styling:
* @property-read bool $style_ampersands Whether wrapping of ampersands in <span class="amp"> is enabled.
* @property-read bool $style_caps Whether wrapping caps in <span class="caps"> is enabled.
* @property-read bool $style_initial_quotes Whether wrapping of initial quotes in <span class="quo"> or <span class="dquo"> is enabled.
* @property-read array<string,int> $initial_quote_tags The inverted list of tags where initial quotes and guillemets should be styled (with lower-case tags as keys).
* @property-read bool $style_numbers Whether wrapping of numbers in <span class="numbers"> is enabled.
* @property-read bool $style_hanging_punctuation Whether wrapping of punctuation and wide characters in <span class="pull-*"> is enabled.
*
* Hyphenation:
* @property-read bool $hyphenation Whether hyphenation is enabled.
* @property-read string $hyphenation_language The hyphenation pattern language.
* @property-read int<2,max> $min_length_hyphenation The minimum length of a word that may be hyphenated.
* @property-read int<1,max> $min_before_hyphenation The minimum character requirement before a hyphenation point.
* @property-read int<1,max> $min_after_hyphenation The minimum character requirement after a hyphenation point.
* @property-read string[] $hyphenation_exceptions A list of custom hyphenations (hyphenation points marked by hard hyphens).
* @property-read bool $hyphenate_headings Whether hyphenation of titles and headings is enabled.
* @property-read bool $hyphenate_all_caps Whether hyphenation of words set completely in capital letters is enabled.
* @property-read bool $hyphenate_title_case Whether hyphenation of words starting with a capital letter is enabled.
* @property-read bool $hyphenate_compounds Whether hyphenation of compound words (e.g. "editor-in-chief") is enabled.
*
* Parser error handling:
* @property-read bool $ignore_parser_errors Whether lenient parser error handling (output "best guess" HTML) is enabled.
* @property-read ?callable $parser_errors_handler An optional handler for parser errors. The callable takes an array of error strings as its parameter.
*
* Post-processing:
* @property-read array<string,string> $unicode_character_mapping The Unicode character mapping (as some characters still have compatibility issues).
*
* Setters for general attributes:
* @method void set_classes_to_ignore( string[] $classes = ['vcard','noTypo'] ) Sets classes for which the typography of their children will be left untouched.
* @method void set_ids_to_ignore( string[] $ids = [] ) Sets IDs for which the typography of their children will be left untouched.
*
* Setters for smart characters:
* @method void set_smart_quotes( bool $on = true ) Enables/disables typographic quotes.
* @method void set_smart_dashes( bool $on = true ) Enables/disables replacement of "a--a" with En Dash " -- " and "---" with Em Dash.
* @method void set_smart_ellipses( bool $on = true ) Enables/disables replacement of "..." with "…".
* @method void set_smart_diacritics( bool $on = true ) Enables/disables replacement "creme brulee" with "crème brûlée".
* @method void set_smart_marks( bool $on = true ) Enables/disables replacement of (r) (c) (tm) (sm) (p) (R) (C) (TM) (SM) (P) with ® © ™ ℠ ℗.
* @method void set_smart_math( bool $on = true ) Enables/disables proper mathematical symbols.
* @method void set_smart_exponents( bool $on = true ) Enables/disables replacement of 2^2 with 2<sup>2</sup>.
* @method void set_smart_fractions( bool $on = true ) Enables/disables replacement of 1/4 with <sup>1</sup>⁄<sub>4</sub>.
* @method void set_smart_ordinal_suffix( bool $on = true ) Enables/disables replacement of 1st with 1<sup>st</sup>.
* @method void set_smart_ordinal_suffix_match_roman_numerals( bool $on = false ) Enables/disables replacement of XXe with XX<sup>e</sup>.
* @method void set_smart_area_units( bool $on = true ) Enables/disables replacement of m2 with m³ and m3 with m³.
*
* Setters for smart spacing:
* @method void set_single_character_word_spacing( bool $on = true ) Enables/disables forcing single character words to next line with the insertion of .
* @method void set_fraction_spacing( bool $on = true ) Enables/disables fraction spacing.
* @method void set_unit_spacing( bool $on = true ) Enables/disables keeping units and values together with the insertion of .
* @method void set_numbered_abbreviation_spacing( bool $on = true ) Enables/disables numbered abbreviations like "ISO 9000" together with the insertion of .
* @method void set_french_punctuation_spacing( bool $on = false ) Enables/disables extra whitespace before certain punction marks, as is the French custom.
* @method void set_dash_spacing( bool $on = true ) Enables/disables wrapping of Em and En dashes are in thin spaces.
* @method void set_space_collapse( bool $on = true ) Enables/disables removal of extra whitespace characters.
* @method void set_dewidow( bool $on = true ) Enables/disables widow handling.
* @method void set_max_dewidow_length( int $length = 5 ) Sets the maximum length of widows that will be protected. The length cannot be less than 2.
* @method void set_dewidow_word_number( int $number = 1 ) Sets the maximum number of words considered for dewidowing. Only 1, 2 and 3 are valid arguments.
* @method void set_max_dewidow_pull( int $length = 5 ) Sets the maximum length of pulled text to keep widows company. The length cannot be less than 2.
* @method void set_wrap_hard_hyphens( bool $on = true ) Enables/disables wrapping at internal hard hyphens with the insertion of a zero-width-space.
* @method void set_wrap_urls( bool $on = true ) Enables/disables wrapping of URLs.
* @method void set_min_after_url_wrap( int $length = 5 ) Sets the minimum character requirement after an URL wrapping point. The length cannot be less than 1.
* @method void set_wrap_emails( bool $on = true ) Enables/disables wrapping of email addresses.
*
* Setters for character styling:
* @method void set_style_ampersands( bool $on = true ) Enables/disables wrapping of ampersands in <span class="amp">.
* @method void set_style_caps( bool $on = true ) Enables/disables wrapping caps in <span class="caps">.
* @method void set_style_initial_quotes( bool $on = true ) Enables/disables wrapping of initial quotes in <span class="quo"> or <span class="dquo">.
* @method void set_style_numbers( bool $on = true ) Enables/disables wrapping of numbers in <span class="numbers">.
* @method void set_style_hanging_punctuation( bool $on = true ) Enables/disables wrapping of punctuation and wide characters in <span class="pull-*">.
*
* Setters for hyphenation:
* @method void set_hyphenation( bool $on = true ) Enables/disables hyphenation.
* @method void set_hyphenation_language( string $lang = 'en-US' ) Sets the hyphenation pattern language.
* @method void set_min_length_hyphenation( int $length = 5 ) Sets the minimum length of a word that may be hyphenated. The length cannot be less than 2.
* @method void set_min_before_hyphenation( int $length = 3 ) Sets the minimum character requirement before a hyphenation point. The length cannot be less than 1.
* @method void set_min_after_hyphenation( int $length = 2 ) Sets the minimum character requirement after a hyphenation point. The length cannot be less than 1.
* @method void set_hyphenate_headings( bool $on = true ) Enables/disables hyphenation of titles and headings.
* @method void set_hyphenate_all_caps( bool $on = true ) Enables/disables hyphenation of words set completely in capital letters.
* @method void set_hyphenate_title_case( bool $on = true ) Enables/disables hyphenation of words starting with a capital letter.
* @method void set_hyphenate_compounds( bool $on = true ) Enables/disables hyphenation of compound words (e.g. "editor-in-chief").
* @method void set_hyphenation_exceptions( string[] $exceptions = [] ) Sets custom word hyphenations. Takes an array of words with all hyphenation points marked with a hard hyphen.
*
* Setters for parser error handling:
* @method void set_ignore_parser_errors( bool $on = false ) Enable lenient parser error handling (HTML is "best guess" if enabled).
* @method void set_parser_errors_handler( callable $handler = null ) Sets an optional handler for parser errors. The callable takes an array of error strings as its parameter. Invalid callbacks will be silently ignored.
*
* @phpstan-type Property_Definition array{property:string, name:string, default?:mixed, verify?:callable-string}
*/
class Settings {
// General attributes.
const IGNORE_TAGS = 'ignoreTags';
const IGNORE_CLASSES = 'ignoreClasses';
const IGNORE_IDS = 'ignoreIDs';
// Smart characters.
const SMART_QUOTES = 'smartQuotes';
const SMART_QUOTES_EXCEPTIONS = 'smartQuotesExceptions';
const SMART_QUOTES_PRIMARY_STYLE = 'smartQuotesPrimaryStyle';
const SMART_QUOTES_SECONDARY_STYLE = 'smartQuotesSecondaryStyle';
const SMART_DASHES = 'smartDashes';
const SMART_DASHES_STYLE = 'smartDashesStyle';
const SMART_ELLIPSES = 'smartEllipses';
const SMART_DIACRITICS = 'smartDiacritics';
const DIACRITIC_LANGUAGE = 'diacriticLanguage'; // public for defaults only.
const DIACRITIC_WORDS = 'diacriticWords'; // public for testing.
const DIACRITIC_REPLACEMENT_DATA = 'diacriticReplacement';
const DIACRITIC_CUSTOM_REPLACEMENTS = 'diacriticCustomReplacements'; // public for testing.
const SMART_MARKS = 'smartMarks';
const SMART_MATH = 'smartMath';
const SMART_EXPONENTS = 'smartExponents';
const SMART_FRACTIONS = 'smartFractions';
const SMART_ORDINAL_SUFFIX = 'smartOrdinalSuffix';
const SMART_ORDINAL_SUFFIX_ROMAN_NUMERALS = 'smartOrdinalSuffixRomanNumerals';
const SMART_AREA_UNITS = 'smartAreaVolumeUnits';
// Smart spacing.
const SINGLE_CHARACTER_WORD_SPACING = 'singleCharacterWordSpacing';
const FRACTION_SPACING = 'fractionSpacing';
const UNIT_SPACING = 'unitSpacing';
const CUSTOM_UNITS = 'units';
const NUMBERED_ABBREVIATION_SPACING = 'numberedAbbreviationSpacing';
const FRENCH_PUNCTUATION_SPACING = 'frenchPunctuationSpacing';
const DASH_SPACING = 'dashSpacing';
const SPACE_COLLAPSE = 'spaceCollapse';
const DEWIDOW = 'dewidow';
const DEWIDOW_MAX_LENGTH = 'dewidowMaxLength';
const DEWIDOW_MAX_PULL = 'dewidowMaxPull';
const DEWIDOW_WORD_NUMBER = 'dewidowWordNumber';
const HYPHEN_HARD_WRAP = 'hyphenHardWrap';
const URL_WRAP = 'urlWrap';
const URL_MIN_AFTER_WRAP = 'urlMinAfterWrap';
const EMAIL_WRAP = 'emailWrap';
// Character styling.
const STYLE_AMPERSANDS = 'styleAmpersands';
const STYLE_CAPS = 'styleCaps';
const STYLE_INITIAL_QUOTES = 'styleInitialQuotes';
const INITIAL_QUOTE_TAGS = 'initialQuoteTags';
const STYLE_NUMBERS = 'styleNumbers';
const STYLE_HANGING_PUNCTUATION = 'styleHangingPunctuation';
// Hyphenation.
const HYPHENATION = 'hyphenation';
const HYPHENATION_LANGUAGE = 'hyphenLanguage';
const HYPHENATION_MIN_LENGTH = 'hyphenMinLength';
const HYPHENATION_MIN_BEFORE = 'hyphenMinBefore';
const HYPHENATION_MIN_AFTER = 'hyphenMinAfter';
const HYPHENATION_CUSTOM_EXCEPTIONS = 'hyphenationCustomExceptions';
const HYPHENATE_HEADINGS = 'hyphenateTitle';
const HYPHENATE_ALL_CAPS = 'hyphenateAllCaps';
const HYPHENATE_TITLE_CASE = 'hyphenateTitleCase';
const HYPHENATE_COMPOUNDS = 'hyphenateCompounds';
// Parser error handling.
const PARSER_ERRORS_IGNORE = 'parserErrorsIgnore';
const PARSER_ERRORS_HANDLER = 'parserErrorsHandler';
// Post-processing.
const UNICODE_CHARACTER_MAPPING = 'unicodeCharacterMapping';
/**
* A hashmap of settings for the various typographic options.
*
* @var array<string,mixed>
*/
protected $data = [];
/**
* Definitions of the properties that use a virtual setter function.
*
* @var array<Property_Definition>
*/
protected const VIRTUAL_PROPERTIES = [
[
'property' => self::PARSER_ERRORS_IGNORE,
'name' => 'ignore_parser_errors',
'default' => false,
'verify' => 'is_bool',
],
[
'property' => self::PARSER_ERRORS_HANDLER,
'name' => 'parser_errors_handler',
'default' => null,
'verify' => 'is_callable',
],
[
'property' => self::IGNORE_TAGS,
'name' => 'tags_to_ignore',
],
[
'property' => self::IGNORE_CLASSES,
'name' => 'classes_to_ignore',
'default' => [ 'vcard', 'noTypo' ],
'verify' => 'is_array',
],
[
'property' => self::IGNORE_IDS,
'name' => 'ids_to_ignore',
'default' => [],
'verify' => 'is_array',
],
[
'property' => self::SMART_QUOTES,
'name' => 'smart_quotes',
'default' => true,
'verify' => 'is_bool',
],
[
'property' => self::SMART_QUOTES_EXCEPTIONS,
'name' => 'smart_quotes_exceptions',
],
[
'property' => self::SMART_QUOTES_PRIMARY_STYLE,
'name' => 'primary_quote_style',
],
[
'property' => self::SMART_QUOTES_SECONDARY_STYLE,
'name' => 'secondary_quote_style',
],
[
'property' => self::SMART_DASHES,
'name' => 'smart_dashes',
'default' => true,
'verify' => 'is_bool',
],
[
'property' => self::SMART_DASHES_STYLE,
'name' => 'dash_style',
],
[
'property' => self::SMART_ELLIPSES,
'name' => 'smart_ellipses',
'default' => true,
'verify' => 'is_bool',
],
[
'property' => self::SMART_DIACRITICS,
'name' => 'smart_diacritics',
'default' => true,
'verify' => 'is_bool',
],
[
'property' => self::DIACRITIC_REPLACEMENT_DATA,
'name' => 'diacritic_combined',
],
[
'property' => self::DIACRITIC_WORDS,
'name' => 'diacritic_words',
],
[
'property' => self::DIACRITIC_CUSTOM_REPLACEMENTS,
'name' => 'diacritic_custom_replacements',
],
[
'property' => self::SMART_MARKS,
'name' => 'smart_marks',
'default' => true,
'verify' => 'is_bool',
],
[
'property' => self::SMART_MATH,
'name' => 'smart_math',
'default' => true,
'verify' => 'is_bool',
],
[
'property' => self::SMART_EXPONENTS,
'name' => 'smart_exponents',
'default' => true,
'verify' => 'is_bool',
],
[
'property' => self::SMART_FRACTIONS,
'name' => 'smart_fractions',
'default' => true,
'verify' => 'is_bool',
],
[
'property' => self::SMART_ORDINAL_SUFFIX,
'name' => 'smart_ordinal_suffix',
'default' => true,
'verify' => 'is_bool',
],
[
'property' => self::SMART_ORDINAL_SUFFIX_ROMAN_NUMERALS,
'name' => 'smart_ordinal_suffix_match_roman_numerals',
'default' => false,
'verify' => 'is_bool',
],
[
'property' => self::SMART_AREA_UNITS,
'name' => 'smart_area_units',
'default' => true,
'verify' => 'is_bool',
],
[
'property' => self::SINGLE_CHARACTER_WORD_SPACING,
'name' => 'single_character_word_spacing',
'default' => true,
'verify' => 'is_bool',
],
[
'property' => self::FRACTION_SPACING,
'name' => 'fraction_spacing',
'default' => true,
'verify' => 'is_bool',
],
[
'property' => self::UNIT_SPACING,
'name' => 'unit_spacing',
'default' => true,
'verify' => 'is_bool',
],
[
'property' => self::CUSTOM_UNITS,
'name' => 'custom_units',
],
[
'property' => self::NUMBERED_ABBREVIATION_SPACING,
'name' => 'numbered_abbreviation_spacing',
'default' => true,
'verify' => 'is_bool',
],
[
'property' => self::FRENCH_PUNCTUATION_SPACING,
'name' => 'french_punctuation_spacing',
'default' => false,
'verify' => 'is_bool',
],
[
'property' => self::DASH_SPACING,
'name' => 'dash_spacing',
'default' => true,
'verify' => 'is_bool',
],
[
'property' => self::SPACE_COLLAPSE,
'name' => 'space_collapse',
'default' => true,
'verify' => 'is_bool',
],
[
'property' => self::DEWIDOW,
'name' => 'dewidow',
'default' => true,
'verify' => 'is_bool',
],
[
'property' => self::DEWIDOW_MAX_LENGTH,
'name' => 'max_dewidow_length',
'default' => 5,
'verify' => 'is_int',
'min' => 2,
],
[
'property' => self::DEWIDOW_WORD_NUMBER,
'name' => 'dewidow_word_number',
'default' => 1,
'verify' => 'is_int',
'min' => 1,
'max' => 3,
],
[
'property' => self::DEWIDOW_MAX_PULL,
'name' => 'max_dewidow_pull',
'default' => 5,
'verify' => 'is_int',
'min' => 2,
],
[
'property' => self::HYPHEN_HARD_WRAP,
'name' => 'wrap_hard_hyphens',
'default' => true,
'verify' => 'is_bool',
],
[
'property' => self::URL_WRAP,
'name' => 'wrap_urls',
'default' => true,
'verify' => 'is_bool',
],
[
'property' => self::URL_MIN_AFTER_WRAP,
'name' => 'min_after_url_wrap',
'default' => 5,
'verify' => 'is_int',
'min' => 1,
],
[
'property' => self::EMAIL_WRAP,
'name' => 'wrap_emails',
'default' => true,
'verify' => 'is_bool',
],
[
'property' => self::STYLE_AMPERSANDS,
'name' => 'style_ampersands',
'default' => true,
'verify' => 'is_bool',
],
[
'property' => self::STYLE_CAPS,
'name' => 'style_caps',
'default' => true,
'verify' => 'is_bool',
],
[
'property' => self::STYLE_INITIAL_QUOTES,
'name' => 'style_initial_quotes',
'default' => true,
'verify' => 'is_bool',
],
[
'property' => self::INITIAL_QUOTE_TAGS,
'name' => 'initial_quote_tags',
],
[
'property' => self::STYLE_NUMBERS,
'name' => 'style_numbers',
'default' => true,
'verify' => 'is_bool',
],
[
'property' => self::STYLE_HANGING_PUNCTUATION,
'name' => 'style_hanging_punctuation',
'default' => true,
'verify' => 'is_bool',
],
[
'property' => self::HYPHENATION,
'name' => 'hyphenation',
'default' => true,
'verify' => 'is_bool',
],
[
'property' => self::HYPHENATION_LANGUAGE,
'name' => 'hyphenation_language',
'default' => 'en-US',
'verify' => 'is_string',
],
[
'property' => self::HYPHENATION_MIN_LENGTH,
'name' => 'min_length_hyphenation',
'default' => 5,
'verify' => 'is_int',
'min' => 2,
],
[
'property' => self::HYPHENATION_MIN_BEFORE,
'name' => 'min_before_hyphenation',
'default' => 3,
'verify' => 'is_int',
'min' => 1,
],
[
'property' => self::HYPHENATION_MIN_AFTER,
'name' => 'min_after_hyphenation',
'default' => 2,
'verify' => 'is_int',
'min' => 1,
],
[
'property' => self::HYPHENATION_CUSTOM_EXCEPTIONS,
'name' => 'hyphenation_exceptions',
'default' => [],
'verify' => 'is_array',
],
[
'property' => self::HYPHENATE_HEADINGS,
'name' => 'hyphenate_headings',
'default' => true,
'verify' => 'is_bool',
],
[
'property' => self::HYPHENATE_ALL_CAPS,
'name' => 'hyphenate_all_caps',
'default' => true,
'verify' => 'is_bool',
],
[
'property' => self::HYPHENATE_TITLE_CASE,
'name' => 'hyphenate_title_case',
'default' => true,
'verify' => 'is_bool',
],
[
'property' => self::HYPHENATE_COMPOUNDS,
'name' => 'hyphenate_compounds',
'default' => true,
'verify' => 'is_bool',
],
[
'property' => self::UNICODE_CHARACTER_MAPPING,
'name' => 'unicode_character_mapping',
],
];
/**
* An index of virtual method names to properties.
*
* @since 7.0.0
*
* @var array<string,array{property:string, name:string, default:mixed, verify:callable-string}>
*/
protected array $virtual_setters = [];
/**
* An index of virtual property names data array indices.
*
* @since 7.0.0
*
* @var array<string,string>
*/
protected array $virtual_properties = [];
/**
* Sets up a new Settings object.
*
* @since 6.5.0 A (partial) character mapping can be given to remap certain characters.
* @since 7.0.0 The object is no fully initialized again even when `$set_defaults` is `false`.
*
* @param bool $set_defaults Optional. If true, set default values for various properties. Default true.
* @param string[] $mapping Optional. Unicode characters to remap. The default maps the narrow no-break space to the normal NO-BREAK SPACE and the apostrophe to the RIGHT SINGLE QUOTATION MARK.
*/
public function __construct( bool $set_defaults = true, array $mapping = [ U::NO_BREAK_NARROW_SPACE => U::NO_BREAK_SPACE, U::APOSTROPHE => U::SINGLE_QUOTE_CLOSE ] ) { // phpcs:ignore WordPress.Arrays.ArrayDeclarationSpacing
// Set up virtualized set_* methods.
foreach ( self::VIRTUAL_PROPERTIES as $definition ) {
// Add virtual setter method if none is defined.
$setter = "set_{$definition['name']}";
if ( isset( $definition['verify'] ) && ! \method_exists( $this, $setter ) ) {
$this->virtual_setters[ $setter ] = $definition;
}
// Add virtual read-only properties.
$this->virtual_properties[ $definition['name'] ] = $definition['property'];
}
if ( $set_defaults ) {
$this->set_defaults();
} else {
$this->data[ self::CUSTOM_UNITS ] = '';
$null_quotes = Quote_Style::get_styled_quotes( Quote_Style::NONE );
$this->data[ self::SMART_QUOTES_PRIMARY_STYLE ] = $null_quotes;
$this->data[ self::SMART_QUOTES_SECONDARY_STYLE ] = $null_quotes;
$this->data[ self::SMART_DASHES_STYLE ] = Dash_Style::get_styled_dashes( Dash_Style::NONE );
}
// Merge default character mapping with given mapping.
$this->data[ self::UNICODE_CHARACTER_MAPPING ] = $mapping;
}
/**
* Provides virtual setter methods.
*
* @since 7.0.0
*
* @param string $name The method name.
* @param mixed[] $arguments The method arguments.
*
* @return mixed
*
* @throws BadMethodCallException Throws an exception if an invalid method is called.
* @throws TypeError Throws an error if a given argument is of an incorrect type.
* @throws OutOfRangeException Throws an exception if a given integer argument is out of bounds.
*/
public function __call( string $name, array $arguments ) {
if ( isset( $this->virtual_setters[ $name ] ) ) {
$def = $this->virtual_setters[ $name ];
$value = isset( $arguments[0] ) ? $arguments[0] : $def['default'];
// Check argument type.
if ( ! $def['verify']( $value ) ) {
throw new TypeError( "Argument for {$name} should be compatible with {$def['verify']}." );
}
// Check argument lower bounds.
if ( isset( $def['min'] ) && $value < $def['min'] ) {
throw new OutOfRangeException( "Argument for {$name} should not be less than {$def['min']}, {$value} given." );
}
// Check argument upper bounds.
if ( isset( $def['max'] ) && $value > $def['max'] ) {
throw new OutOfRangeException( "Argument for {$name} should be no more than {$def['max']}, {$value} given." );
}
$this->data[ $def['property'] ] = $value;
} else {
throw new BadMethodCallException( "Invalid method {$name} called." );
}
}
/**
* Provides access to named settings (object syntax).
*
* @param string $key The settings key.
*
* @return mixed
*/
public function &__get( $key ) {
if ( isset( $this->virtual_properties[ $key ] ) ) {
return $this->data[ $this->virtual_properties[ $key ] ];
}
return $this->data[ $key ];
}
/**
* Changes a named setting (object syntax).
*
* @param string $key The settings key.
* @param mixed $value The settings value.
*/
public function __set( $key, $value ): void {
$this->data[ $key ] = $value;
}
/**
* Checks if a named setting exists (object syntax).
*
* @param string $key The settings key.
*
* @return bool
*/
public function __isset( $key ) {
if ( isset( $this->virtual_properties[ $key ] ) ) {
return isset( $this->data[ $this->virtual_properties[ $key ] ] );
}
return isset( $this->data[ $key ] );
}
/**
* Unsets a named setting.
*
* @param string $key The settings key.
*/
public function __unset( $key ): void {
unset( $this->data[ $key ] );
}
/**
* Remaps a unicode character to another one.
*
* @since 6.5.0
*
* @param string $char The remapped character.
* @param string $new_char The character to actually use.
*/
public function remap_character( string $char, string $new_char ): void {
if ( $char !== $new_char ) {
$this->data[ self::UNICODE_CHARACTER_MAPPING ][ $char ] = $new_char;
} else {
unset( $this->data[ self::UNICODE_CHARACTER_MAPPING ][ $char ] );
}
}
/**
* (Re)set various options to their default values.
*/
public function set_defaults(): void {
// General attributes.
$this->set_tags_to_ignore();
$this->set_classes_to_ignore();
$this->set_ids_to_ignore();
// Smart characters.
$this->set_smart_quotes();
$this->set_smart_quotes_primary();
$this->set_smart_quotes_secondary();
$this->set_smart_quotes_exceptions();
$this->set_smart_dashes();
$this->set_smart_dashes_style();
$this->set_smart_ellipses();
$this->set_smart_diacritics();
$this->set_diacritic_language();
$this->set_diacritic_custom_replacements();
$this->set_smart_marks();
$this->set_smart_ordinal_suffix();
$this->set_smart_ordinal_suffix_match_roman_numerals();
$this->set_smart_math();
$this->set_smart_fractions();
$this->set_smart_exponents();
$this->set_smart_area_units();
// Smart spacing.
$this->set_single_character_word_spacing();
$this->set_fraction_spacing();
$this->set_unit_spacing();
$this->set_french_punctuation_spacing();
$this->set_units();
$this->set_dash_spacing();
$this->set_dewidow();
$this->set_max_dewidow_length();
$this->set_max_dewidow_pull();
$this->set_dewidow_word_number();
$this->set_wrap_hard_hyphens();
$this->set_wrap_urls();
$this->set_wrap_emails();
$this->set_min_after_url_wrap();
$this->set_space_collapse();
// Character styling.
$this->set_style_ampersands();
$this->set_style_caps();
$this->set_style_initial_quotes();
$this->set_style_numbers();
$this->set_style_hanging_punctuation();
$this->set_initial_quote_tags();
// Hyphenation.
$this->set_hyphenation();
$this->set_hyphenation_language();
$this->set_min_length_hyphenation();
$this->set_min_before_hyphenation();
$this->set_min_after_hyphenation();
$this->set_hyphenate_headings();
$this->set_hyphenate_all_caps();
$this->set_hyphenate_title_case();
$this->set_hyphenate_compounds();
$this->set_hyphenation_exceptions();
// Parser error handling.
$this->set_ignore_parser_errors();
}
/**
* Sets tags for which the typography of their children will be left untouched.
*
* @since 7.0.0 The parameter $tags can now only be passed as an array.
*
* @param string[] $tags An array of tag names.
*/
public function set_tags_to_ignore( array $tags = [ 'code', 'head', 'kbd', 'object', 'option', 'pre', 'samp', 'script', 'noscript', 'noembed', 'select', 'style', 'textarea', 'title', 'var', 'math' ] ): void {
// Ensure that we pass only lower-case tag names to XPath.
$tags = array_filter( array_map( 'strtolower', $tags ), 'ctype_alnum' );
$this->data[ self::IGNORE_TAGS ] = array_unique( array_merge( $tags, array_flip( DOM::inappropriate_tags() ) ) );
}
/**
* Sets the style for primary ('double') quotemarks.
*
* Allowed values for $style:
* "doubleCurled" => "“foo”",
* "doubleCurledReversed" => "”foo”",
* "doubleLow9" => "„foo”",
* "doubleLow9Reversed" => "„foo“",
* "singleCurled" => "‘foo’",
* "singleCurledReversed" => "’foo’",
* "singleLow9" => "‚foo’",
* "singleLow9Reversed" => "‚foo‘",
* "doubleGuillemetsFrench" => "« foo »",
* "doubleGuillemets" => "«foo»",
* "doubleGuillemetsReversed" => "»foo«",
* "singleGuillemets" => "‹foo›",
* "singleGuillemetsReversed" => "›foo‹",
* "cornerBrackets" => "「foo」",
* "whiteCornerBracket" => "『foo』"
*
* @param Quotes|string $style Optional. A Quotes instance or a quote style constant. Defaults to 'doubleCurled'.
*
* @throws \DomainException Thrown if $style constant is invalid.
*/
public function set_smart_quotes_primary( $style = Quote_Style::DOUBLE_CURLED ): void {
$this->data[ self::SMART_QUOTES_PRIMARY_STYLE ] = Quote_Style::get_styled_quotes( $style );
}
/**
* Sets the style for secondary ('single') quotemarks.
*
* Allowed values for $style:
* "doubleCurled" => "“foo”",
* "doubleCurledReversed" => "”foo”",
* "doubleLow9" => "„foo”",
* "doubleLow9Reversed" => "„foo“",
* "singleCurled" => "‘foo’",
* "singleCurledReversed" => "’foo’",
* "singleLow9" => "‚foo’",
* "singleLow9Reversed" => "‚foo‘",
* "doubleGuillemetsFrench" => "« foo »",
* "doubleGuillemets" => "«foo»",
* "doubleGuillemetsReversed" => "»foo«",
* "singleGuillemets" => "‹foo›",
* "singleGuillemetsReversed" => "›foo‹",
* "cornerBrackets" => "「foo」",
* "whiteCornerBracket" => "『foo』"
*
* @param Quotes|string $style Optional. A Quotes instance or a quote style constant. Defaults to 'singleCurled'.
*
* @throws \DomainException Thrown if $style constant is invalid.
*/
public function set_smart_quotes_secondary( $style = Quote_Style::SINGLE_CURLED ): void {
$this->data[ self::SMART_QUOTES_SECONDARY_STYLE ] = Quote_Style::get_styled_quotes( $style );
}
/**
* Sets the list of exceptional words for smart quotes replacement. Mainly,
* this is used for contractions beginning with an apostrophe.
*
* @param string[] $exceptions Optional. An array of replacements indexed by the ”non-smart" form.
* Default a list of English words beginning with an apostrophy.
*/
public function set_smart_quotes_exceptions( array $exceptions = [
"'tain't" => U::APOSTROPHE . 'tain' . U::APOSTROPHE . 't',
"'twere" => U::APOSTROPHE . 'twere',
"'twas" => U::APOSTROPHE . 'twas',
"'tis" => U::APOSTROPHE . 'tis',
"'til" => U::APOSTROPHE . 'til',
"'bout" => U::APOSTROPHE . 'bout',
"'nuff" => U::APOSTROPHE . 'nuff',
"'round" => U::APOSTROPHE . 'round',
"'cause" => U::APOSTROPHE . 'cause',
"'splainin" => U::APOSTROPHE . 'splainin',
"'em'" => U::APOSTROPHE . 'em',
] ): void {
$this->data[ self::SMART_QUOTES_EXCEPTIONS ] = [
'patterns' => \array_keys( $exceptions ),
'replacements' => \array_values( $exceptions ),
];
}
/**
* Sets the typographical conventions used by smart_dashes.
*
* Allowed values for $style:
* - "traditionalUS"
* - "international"
*
* @param string|Dashes $style Optional. Default Dash_Style::TRADITIONAL_US.
*
* @throws \DomainException Thrown if $style constant is invalid.
*/
public function set_smart_dashes_style( $style = Dash_Style::TRADITIONAL_US ): void {
$this->data[ self::SMART_DASHES_STYLE ] = Dash_Style::get_styled_dashes( $style );
}
/**
* Sets the language used for diacritics replacements.
*
* @param string $lang Has to correspond to a filename in 'diacritics'. Optional. Default 'en-US'.
*/
public function set_diacritic_language( string $lang = 'en-US' ): void {
if ( isset( $this->data[ self::DIACRITIC_LANGUAGE ] ) && $this->data[ self::DIACRITIC_LANGUAGE ] === $lang ) {
return;
}
$this->data[ self::DIACRITIC_LANGUAGE ] = $lang;
$language_file_name = __DIR__ . '/diacritics/' . $lang . '.json';
$diacritics = [];
if ( \file_exists( $language_file_name ) ) {
$diacritics = \json_decode( (string) \file_get_contents( $language_file_name ), true );
}
if ( ! empty( $diacritics['diacritic_words'] ) ) {
$this->data[ self::DIACRITIC_WORDS ] = $diacritics['diacritic_words'];
} else {
unset( $this->data[ self::DIACRITIC_WORDS ] );
}
$this->update_diacritics_replacement_arrays();
}
/**
* Sets up custom diacritics replacements.
*
* @since 7.0.0 The parameter $units can now only be passed as an array.
*
* @param array<string,string> $custom_replacements An array formatted [needle=>replacement, needle=>replacement...].
*/
public function set_diacritic_custom_replacements( array $custom_replacements = [] ): void {
$this->data[ self::DIACRITIC_CUSTOM_REPLACEMENTS ] = [];
foreach ( $custom_replacements as $key => $replacement ) {
$key = \strip_tags( \trim( $key ) );
$replacement = \strip_tags( \trim( $replacement ) );
if ( ! empty( $key ) && ! empty( $replacement ) ) {
$this->data[ self::DIACRITIC_CUSTOM_REPLACEMENTS ][ $key ] = $replacement;
}
}
$this->update_diacritics_replacement_arrays();
}
/**
* Update the pattern and replacement arrays in $settings['diacriticReplacement'].
*