|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* Evgeny Muravjev Typograph, http://mdash.ru |
|
4
|
|
|
* Version: 3.0 Gold Master |
|
5
|
|
|
* Release Date: September 28, 2013 |
|
6
|
|
|
* Authors: Evgeny Muravjev & Alexander Drutsa |
|
7
|
|
|
*/ |
|
8
|
|
|
|
|
9
|
|
|
namespace EMT; |
|
10
|
|
|
|
|
11
|
|
|
/** |
|
12
|
|
|
* Class EMTypograph |
|
13
|
|
|
* @package EMT |
|
14
|
|
|
*/ |
|
15
|
|
|
class EMTypograph extends AbstractTypograph |
|
16
|
|
|
{ |
|
17
|
|
|
public $trets = array( |
|
18
|
|
|
'\EMT\Tret\Quote', |
|
19
|
|
|
'\EMT\Tret\Dash', |
|
20
|
|
|
'\EMT\Tret\Symbol', |
|
21
|
|
|
'\EMT\Tret\Punctmark', |
|
22
|
|
|
'\EMT\Tret\Number', |
|
23
|
|
|
'\EMT\Tret\Space', |
|
24
|
|
|
'\EMT\Tret\Abbr', |
|
25
|
|
|
'\EMT\Tret\Nobr', |
|
26
|
|
|
'\EMT\Tret\Date', |
|
27
|
|
|
'\EMT\Tret\OptAlign', |
|
28
|
|
|
'\EMT\Tret\Etc', |
|
29
|
|
|
'\EMT\Tret\Text' |
|
30
|
|
|
); |
|
31
|
|
|
|
|
32
|
|
|
protected $group_list = array( |
|
33
|
|
|
'Quote' => true, |
|
34
|
|
|
'Dash' => true, |
|
35
|
|
|
'Nobr' => true, |
|
36
|
|
|
'Symbol' => true, |
|
37
|
|
|
'Punctmark' => true, |
|
38
|
|
|
'Number' => true, |
|
39
|
|
|
'Date' => true, |
|
40
|
|
|
'Space' => true, |
|
41
|
|
|
'Abbr' => true, |
|
42
|
|
|
'OptAlign' => true, |
|
43
|
|
|
'Text' => true, |
|
44
|
|
|
'Etc' => true, |
|
45
|
|
|
); |
|
46
|
|
|
protected $all_options = array( |
|
47
|
|
|
|
|
48
|
|
|
'Quote.quotes' => array( 'description' => 'Расстановка «кавычек-елочек» первого уровня', 'selector' => "Quote.*quote" ), |
|
49
|
|
|
'Quote.quotation' => array( 'description' => 'Внутренние кавычки-лапки', 'selector' => "Quote", 'setting' => 'no_bdquotes', 'reversed' => true ), |
|
50
|
|
|
|
|
51
|
|
|
'Dash.to_libo_nibud' => 'direct', |
|
52
|
|
|
'Dash.iz_za_pod' => 'direct', |
|
53
|
|
|
'Dash.ka_de_kas' => 'direct', |
|
54
|
|
|
|
|
55
|
|
|
'Nobr.super_nbsp' => 'direct', |
|
56
|
|
|
'Nobr.nbsp_in_the_end' => 'direct', |
|
57
|
|
|
'Nobr.phone_builder' => 'direct', |
|
58
|
|
|
'Nobr.ip_address' => 'direct', |
|
59
|
|
|
'Nobr.spaces_nobr_in_surname_abbr' => 'direct', |
|
60
|
|
|
'Nobr.nbsp_celcius' => 'direct', |
|
61
|
|
|
'Nobr.hyphen_nowrap_in_small_words' => 'direct', |
|
62
|
|
|
'Nobr.hyphen_nowrap' => 'direct', |
|
63
|
|
|
'Nobr.nowrap' => array('description' => 'Nobr (по умолчанию) & nowrap', 'disabled' => true, 'selector' => '*', 'setting' => 'nowrap' ), |
|
64
|
|
|
|
|
65
|
|
|
'Symbol.tm_replace' => 'direct', |
|
66
|
|
|
'Symbol.r_sign_replace' => 'direct', |
|
67
|
|
|
'Symbol.copy_replace' => 'direct', |
|
68
|
|
|
'Symbol.apostrophe' => 'direct', |
|
69
|
|
|
'Symbol.degree_f' => 'direct', |
|
70
|
|
|
'Symbol.arrows_symbols' => 'direct', |
|
71
|
|
|
'Symbol.no_inches' => array( 'description' => 'Расстановка дюйма после числа', 'selector' => "Quote", 'setting' => 'no_inches', 'reversed' => true ), |
|
72
|
|
|
|
|
73
|
|
|
'Punctmark.auto_comma' => 'direct', |
|
74
|
|
|
'Punctmark.hellip' => 'direct', |
|
75
|
|
|
'Punctmark.fix_pmarks' => 'direct', |
|
76
|
|
|
'Punctmark.fix_excl_quest_marks' => 'direct', |
|
77
|
|
|
'Punctmark.dot_on_end' => 'direct', |
|
78
|
|
|
|
|
79
|
|
|
'Number.minus_between_nums' => 'direct', |
|
80
|
|
|
'Number.minus_in_numbers_range' => 'direct', |
|
81
|
|
|
'Number.auto_times_x' => 'direct', |
|
82
|
|
|
'Number.simple_fraction' => 'direct', |
|
83
|
|
|
'Number.math_chars' => 'direct', |
|
84
|
|
|
//'Number.split_number_to_triads' => 'direct', |
|
85
|
|
|
'Number.thinsp_between_number_triads' => 'direct', |
|
86
|
|
|
'Number.thinsp_between_no_and_number' => 'direct', |
|
87
|
|
|
'Number.thinsp_between_sect_and_number' => 'direct', |
|
88
|
|
|
|
|
89
|
|
|
'Date.years' => 'direct', |
|
90
|
|
|
'Date.mdash_month_interval' => 'direct', |
|
91
|
|
|
'Date.nbsp_and_dash_month_interval' => 'direct', |
|
92
|
|
|
'Date.nobr_year_in_date' => 'direct', |
|
93
|
|
|
|
|
94
|
|
|
'Space.many_spaces_to_one' => 'direct', |
|
95
|
|
|
'Space.clear_percent' => 'direct', |
|
96
|
|
|
'Space.clear_before_after_punct' => array( 'description' => 'Удаление пробелов перед и после знаков препинания в предложении', 'selector' => 'Space.remove_space_before_punctuationmarks'), |
|
97
|
|
|
'Space.autospace_after' => array( 'description' => 'Расстановка пробелов после знаков препинания', 'selector' => 'Space.autospace_after_*'), |
|
98
|
|
|
'Space.bracket_fix' => array( 'description' => 'Удаление пробелов внутри скобок, а также расстановка пробела перед скобками', |
|
99
|
|
|
'selector' => array('Space.nbsp_before_open_quote', 'Punctmark.fix_brackets')), |
|
100
|
|
|
|
|
101
|
|
|
'Abbr.nbsp_money_abbr' => 'direct', |
|
102
|
|
|
'Abbr.nobr_vtch_itd_itp' => 'direct', |
|
103
|
|
|
'Abbr.nobr_sm_im' => 'direct', |
|
104
|
|
|
'Abbr.nobr_acronym' => 'direct', |
|
105
|
|
|
'Abbr.nobr_locations' => 'direct', |
|
106
|
|
|
'Abbr.nobr_abbreviation' => 'direct', |
|
107
|
|
|
'Abbr.ps_pps' => 'direct', |
|
108
|
|
|
'Abbr.nbsp_org_abbr' => 'direct', |
|
109
|
|
|
'Abbr.nobr_gost' => 'direct', |
|
110
|
|
|
'Abbr.nobr_before_unit_volt' => 'direct', |
|
111
|
|
|
'Abbr.nbsp_before_unit' => 'direct', |
|
112
|
|
|
|
|
113
|
|
|
'OptAlign.all' => array( 'description' => 'Inline стили или CSS', 'hide' => true, 'selector' => 'OptAlign.*'), |
|
114
|
|
|
'OptAlign.oa_oquote' => 'direct', |
|
115
|
|
|
'OptAlign.oa_obracket_coma' => 'direct', |
|
116
|
|
|
'OptAlign.oa_oquote_extra' => 'direct', |
|
117
|
|
|
'OptAlign.layout' => array( 'description' => 'Inline стили или CSS' ), |
|
118
|
|
|
|
|
119
|
|
|
'Text.paragraphs' => 'direct', |
|
120
|
|
|
'Text.auto_links' => 'direct', |
|
121
|
|
|
'Text.email' => 'direct', |
|
122
|
|
|
'Text.breakline' => 'direct', |
|
123
|
|
|
'Text.no_repeat_words' => 'direct', |
|
124
|
|
|
|
|
125
|
|
|
//'Etc.no_nbsp_in_nobr' => 'direct', |
|
126
|
|
|
'Etc.unicode_convert' => array('description' => 'Преобразовывать html-сущности в юникод', 'selector' => '*', 'setting' => 'dounicode' , 'disabled' => true), |
|
127
|
|
|
|
|
128
|
|
|
); |
|
129
|
|
|
|
|
130
|
|
|
/** |
|
131
|
|
|
* Получить список имеющихся опций |
|
132
|
|
|
* |
|
133
|
|
|
* @return array |
|
134
|
|
|
* all - полный список |
|
135
|
|
|
* group - сгруппрованный по группам |
|
136
|
|
|
*/ |
|
137
|
|
|
public function get_options_list() |
|
138
|
|
|
{ |
|
139
|
|
|
$arr['all'] = array(); |
|
|
|
|
|
|
140
|
|
|
$bygroup = array(); |
|
141
|
|
|
foreach ($this->all_options as $opt => $op) { |
|
142
|
|
|
$arr['all'][$opt] = $this->get_option_info($opt); |
|
143
|
|
|
$x = explode(".",$opt); |
|
144
|
|
|
$bygroup[$x[0]][] = $opt; |
|
145
|
|
|
} |
|
146
|
|
|
$arr['group'] = array(); |
|
147
|
|
|
foreach ($this->group_list as $group => $ginfo) { |
|
148
|
|
|
if ($ginfo === true) { |
|
149
|
|
|
$tret = $this->get_tret($group); |
|
150
|
|
|
if($tret) $info['title'] = $tret->title; else $info['title'] = "Не определено"; |
|
|
|
|
|
|
151
|
|
|
} else { |
|
152
|
|
|
$info = $ginfo; |
|
153
|
|
|
} |
|
154
|
|
|
$info['name'] = $group; |
|
|
|
|
|
|
155
|
|
|
$info['options'] = array(); |
|
156
|
|
|
if(is_array($bygroup[$group])) foreach($bygroup[$group] as $opt) $info['options'][] = $opt; |
|
157
|
|
|
$arr['group'][] = $info; |
|
158
|
|
|
} |
|
159
|
|
|
|
|
160
|
|
|
return $arr; |
|
161
|
|
|
} |
|
162
|
|
|
|
|
163
|
|
|
/** |
|
164
|
|
|
* Получить информацию о настройке |
|
165
|
|
|
* |
|
166
|
|
|
* @param string $key |
|
167
|
|
|
* @return array|false |
|
168
|
|
|
*/ |
|
169
|
|
|
protected function get_option_info($key) |
|
170
|
|
|
{ |
|
171
|
|
|
if (!isset($this->all_options[$key])) { |
|
172
|
|
|
return false; |
|
173
|
|
|
} |
|
174
|
|
|
|
|
175
|
|
|
if (is_array($this->all_options[$key])) { |
|
176
|
|
|
return $this->all_options[$key]; |
|
177
|
|
|
} |
|
178
|
|
|
|
|
179
|
|
|
if (($this->all_options[$key] == "direct") || ($this->all_options[$key] == "reverse")) { |
|
180
|
|
|
$pa = explode(".", $key); |
|
181
|
|
|
$tret_pattern = $pa[0]; |
|
182
|
|
|
$tret = $this->get_tret($tret_pattern); |
|
183
|
|
|
|
|
184
|
|
|
if (!$tret) { |
|
185
|
|
|
return false; |
|
186
|
|
|
} |
|
187
|
|
|
|
|
188
|
|
|
if (!isset($tret->rules[$pa[1]])) { |
|
189
|
|
|
return false; |
|
190
|
|
|
} |
|
191
|
|
|
$array = $tret->rules[$pa[1]]; |
|
192
|
|
|
$array['way'] = $this->all_options[$key]; |
|
193
|
|
|
|
|
194
|
|
|
return $array; |
|
195
|
|
|
} |
|
196
|
|
|
|
|
197
|
|
|
return false; |
|
198
|
|
|
} |
|
199
|
|
|
|
|
200
|
|
|
/** |
|
201
|
|
|
* Установка одной метанастройки |
|
202
|
|
|
* |
|
203
|
|
|
* @param string $name |
|
204
|
|
|
* @param mixed $value |
|
205
|
|
|
*/ |
|
206
|
|
|
public function do_setup($name, $value) |
|
207
|
|
|
{ |
|
208
|
|
|
if (!isset($this->all_options[$name])) { |
|
209
|
|
|
return; |
|
210
|
|
|
} |
|
211
|
|
|
|
|
212
|
|
|
// эта настрока связана с правилом ядра |
|
213
|
|
|
if (is_string($this->all_options[$name])) { |
|
214
|
|
|
$this->set($name, "active", $value ); |
|
215
|
|
|
|
|
216
|
|
|
return ; |
|
217
|
|
|
} |
|
218
|
|
|
if (is_array($this->all_options[$name])) { |
|
219
|
|
|
if (isset($this->all_options[$name]['selector'])) { |
|
220
|
|
|
$settingname = "active"; |
|
221
|
|
|
if(isset($this->all_options[$name]['setting'])) $settingname = $this->all_options[$name]['setting']; |
|
222
|
|
|
$this->set($this->all_options[$name]['selector'], $settingname, $value); |
|
223
|
|
|
} |
|
224
|
|
|
} |
|
225
|
|
|
|
|
226
|
|
|
if ($name == "OptAlign.layout") { |
|
227
|
|
|
if($value == "style") $this->set_tag_layout(Util::LAYOUT_STYLE); |
|
228
|
|
|
if($value == "class") $this->set_tag_layout(Util::LAYOUT_CLASS); |
|
229
|
|
|
} |
|
230
|
|
|
|
|
231
|
|
|
} |
|
232
|
|
|
|
|
233
|
|
|
/** |
|
234
|
|
|
* Запустить типограф со стандартными параметрами |
|
235
|
|
|
* |
|
236
|
|
|
* @param string $text |
|
237
|
|
|
* @param array $options |
|
238
|
|
|
* @return string |
|
239
|
|
|
*/ |
|
240
|
|
|
public static function fast_apply($text, $options = null) |
|
241
|
|
|
{ |
|
242
|
|
|
$obj = new self(); |
|
243
|
|
|
|
|
244
|
|
|
if (is_array($options)) { |
|
245
|
|
|
$obj->setup($options); |
|
246
|
|
|
} |
|
247
|
|
|
|
|
248
|
|
|
$obj->set_text($text); |
|
249
|
|
|
|
|
250
|
|
|
return $obj->apply(); |
|
251
|
|
|
} |
|
252
|
|
|
|
|
253
|
|
|
/** |
|
254
|
|
|
* @param string $text |
|
255
|
|
|
* @return string |
|
256
|
|
|
*/ |
|
257
|
|
|
public function process($text) |
|
258
|
|
|
{ |
|
259
|
|
|
$this->set_text($text); |
|
260
|
|
|
return $this->apply(); |
|
261
|
|
|
} |
|
262
|
|
|
} |
|
263
|
|
|
|
Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.
Let’s take a look at an example:
As you can see in this example, the array
$myArrayis initialized the first time when the foreach loop is entered. You can also see that the value of thebarkey is only written conditionally; thus, its value might result from a previous iteration.This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.