Since there was already a lengthy discussion on the first draft of this patch let's start by looking at a diff between this version and the original (annotated with footnotes this time!):
1 | |
2 | |
3 | |
4 | class mp_wp_content_processing { |
5 | const MP_WP_FOOTNOTES_OPEN = " (("; |
6 | const MP_WP_FOOTNOTES_CLOSE = "))"; |
7 | - const MP_WP_CODEBLOCK_OPEN = "[["; |
8 | - const MP_WP_CODEBLOCK_CLOSE = "/]]"; |
9 | + const MP_WP_CODEBLOCK_OPEN = "\[[0-9]\[";1 |
10 | + const MP_WP_CODEBLOCK_CLOSE = "]]"; |
11 | |
12 | var $options; |
13 | |
14 | |
15 | 'backlink'=>'↩', |
16 | 'post_backlink'=>']', |
17 | 'pre_identifier'=>'', |
18 | - 'list_style_type'=>'lower-roman', |
19 | + 'list_style_type'=>'decimal',2 |
20 | 'list_style_symbol'=>'†', |
21 | 'post_identifier'=>'', |
22 | 'pre_footnotes'=>'', |
23 | |
24 | // Regex extraction of all codeblocks (or return if there are none) |
25 | if ( |
26 | !preg_match_all( |
27 | - "/(".preg_quote(self::MP_WP_CODEBLOCK_OPEN).")(.*)(".preg_quote(self::MP_WP_CODEBLOCK_CLOSE, '/').")/Us", |
28 | + "/(".self::MP_WP_CODEBLOCK_OPEN.")(.*)(".preg_quote(self::MP_WP_CODEBLOCK_CLOSE, '/').")/Us",3 |
29 | $data, |
30 | $codeblocks, |
31 | PREG_SET_ORDER |
32 | |
33 | } |
34 | |
35 | for ($i = 0; $i < count($codeblocks); $i++) { |
36 | - $codeblocks[$i]['snippet'] = $this->format_snippet($codeblocks[$i][2], $i+1); |
37 | + $codeblocks[$i]['snippet'] = $this->format_snippet($codeblocks[$i][2], substr($codeblocks[$i][1], 1, 1), $i+1);4 |
38 | } |
39 | |
40 | foreach ($codeblocks as $key => $value) { |
41 | |
42 | return $data; |
43 | } |
44 | |
45 | - function format_snippet($snippet, $snippet_number) { |
46 | - $formatted_snippet = htmlspecialchars($snippet);5 |
47 | - $code_lines = explode("\r\n", $formatted_snippet); |
48 | - |
49 | + function format_snippet($snippet, $syntax_index, $snippet_number) { |
50 | + $highlighting_functions = array( |
51 | + 'highlight_as_plain_text', |
52 | + 'highlight_as_diff' |
53 | + ); |
54 | + |
55 | + if (is_null($highlighting_functions[$syntax_index])) { |
56 | + $syntax_index = 0; |
57 | + } |
58 | + |
59 | + $code_lines = explode("\r\n", $snippet); |
60 | + |
61 | foreach ($code_lines as $idx => $line) { |
62 | $line_number = sprintf('S%d-L%d', $snippet_number, $idx+1); |
63 | $line_link = sprintf('<a href="#%s" name="%s">%d</a>', $line_number, $line_number, $idx+1); |
64 | $line_open = sprintf('<tr><td class="line-number-column">%s</td><td class="content-column">', $line_link); |
65 | $line_close = '</td></tr>'; |
66 | - |
67 | - if (substr($line, 0, 5) == 'diff ') { |
68 | - $code_lines[$idx] = sprintf('%s<span class="line-filename">%s</span>%s', $line_open, $line, $line_close); |
69 | - } elseif (substr($line, 0, 4) == '--- ' || substr($line, 0, 4) == '+++ ' || substr($line, 0, 3) == '@@ ') { |
70 | - $code_lines[$idx] = sprintf('%s<span class="line-meta">%s</span>%s', $line_open, $line, $line_close); |
71 | - } elseif (substr($line, 0, 1) == '-') { |
72 | - $code_lines[$idx] = sprintf('%s<span class="line-removed">%s</span>%s', $line_open, $line, $line_close); |
73 | - } elseif (substr($line, 0, 1) == '+') { |
74 | - $code_lines[$idx] = sprintf('%s<span class="line-added">%s</span>%s', $line_open, $line, $line_close); |
75 | - } else { |
76 | - $code_lines[$idx] = sprintf('%s<span class="line-default">%s</span>%s', $line_open, $line, $line_close); |
77 | - } |
78 | + |
79 | + $code_lines[$idx] = $this->$highlighting_functions[$syntax_index]($line_open, $line, $line_close); |
80 | } |
81 | |
82 | $formatted_snippet = implode("\n", $code_lines); |
83 | |
84 | $formatted_snippet = sprintf( |
85 | '%s%s%s', |
86 | - '<pre class="mp-wp-codeblock"><table cellpadding="0" cellspacing="0"><tbody>', |
87 | + '<div class="mp-wp-codeblock"><table cellpadding="0" cellspacing="0"><tbody>',6 |
88 | $formatted_snippet, |
89 | - '</tbody></table></pre>' |
90 | + '</tbody></table></div>' |
91 | ); |
92 | |
93 | return $formatted_snippet; |
94 | } |
95 | |
96 | + function highlight_as_plain_text($line_open, $line, $line_close) { |
97 | + return sprintf('%s<span class="line-default">%s</span>%s', $line_open, $line, $line_close); |
98 | + } |
99 | + |
100 | + function highlight_as_diff($line_open, $line, $line_close) { |
101 | + if (substr($line, 0, 5) == 'diff ') { |
102 | + $highlighted_line = sprintf('%s<span class="line-filename">%s</span>%s', $line_open, $line, $line_close); |
103 | + } elseif (substr($line, 0, 4) == '--- ' || substr($line, 0, 4) == '+++ ' || substr($line, 0, 3) == '@@ ') { |
104 | + $highlighted_line = sprintf('%s<span class="line-meta">%s</span>%s', $line_open, $line, $line_close); |
105 | + } elseif (substr($line, 0, 1) == '-') { |
106 | + $highlighted_line = sprintf('%s<span class="line-removed">%s</span>%s', $line_open, $line, $line_close); |
107 | + } elseif (substr($line, 0, 1) == '+') { |
108 | + $highlighted_line = sprintf('%s<span class="line-added">%s</span>%s', $line_open, $line, $line_close); |
109 | + } else { |
110 | + $highlighted_line = sprintf('%s<span class="line-default">%s</span>%s', $line_open, $line, $line_close); |
111 | + } |
112 | + |
113 | + return $highlighted_line; |
114 | + } |
115 | + |
116 | /** |
117 | * Searches the text and extracts footnotes. |
118 | * Adds the identifier links and creats footnotes list. |
119 | |
120 | // Check for and setup the starting number |
121 | $start_number = (preg_match("|<!\-\-startnum=(\d+)\-\->|",$data,$start_number_array)==1) ? $start_number_array[1] : 1; |
122 | |
123 | - // Remove codeblocks from content to be parsed for footnotes |
124 | - $data_sans_codeblocks = preg_replace("/(<pre class=\"mp-wp-codeblock\">)(.*)(<\/pre>)/Us", '', $data); |
125 | - |
126 | - // Regex extraction of all footnotes from non-codeblock content (or return if there are none) |
127 | - if (!preg_match_all("/(".preg_quote(self::MP_WP_FOOTNOTES_OPEN)."|<footnote>)(.*)(".preg_quote(self::MP_WP_FOOTNOTES_CLOSE)."|<\/footnote>)/Us", $data_sans_codeblocks, $identifiers, PREG_SET_ORDER)) { |
128 | + // Regex extraction of all footnotes (or return if there are none) |
129 | + if (!preg_match_all("/(".preg_quote(self::MP_WP_FOOTNOTES_OPEN)."|<footnote>)(.*)(".preg_quote(self::MP_WP_FOOTNOTES_CLOSE)."|<\/footnote>)/Us", $data, $identifiers, PREG_SET_ORDER)) { |
130 | return $data; |
131 | } |
132 | |
133 | |
134 | ?> |
135 | <style type="text/css"> |
136 | ol.footnotes { font-size: 0.8em; color: #666666; } |
137 | - pre.mp-wp-codeblock { background: none; color: #333; border: 1px solid #ddd; padding: 0; } |
138 | - td.line-number-column { background: #f5f6f7; text-align: right; } |
139 | + a.footnote-link, |
140 | + td.line-number-column {7 |
141 | + -moz-user-select: none; |
142 | + -webkit-user-select: none; |
143 | + user-select: none; |
144 | + } |
145 | + div.mp-wp-codeblock { |
146 | + background: none; |
147 | + font-family: monospace; |
148 | + color: #333; |
149 | + border: 1px solid #ddd; |
150 | + padding: 0; |
151 | + overflow: auto; |
152 | + } |
153 | + td.line-number-column { background: #f5f6f7; text-align: right; vertical-align: top; } |
154 | td.line-number-column a { color: #555; padding: 0 5px; } |
155 | - td.content-column { padding-left: 10px; } |
156 | + td.content-column { |
157 | + padding-left: 10px; |
158 | + white-space: pre-wrap; |
159 | + tab-size: 4; |
160 | + -moz-tab-size: 4; |
161 | + max-width: 670px; /* adjust as necessary to fit your blog's viewport */ |
162 | + } |
163 | span.line-filename { font-weight: bold; } |
164 | - span.line-meta { color: #999; } |
165 | + span.line-meta { color: #999; word-wrap: break-word; }8 |
166 | span.line-added { color: green; } |
167 | span.line-removed { color:red; } |
168 | |
169 |
I think I hit on all the grievances raised during the original draft review. Overall I'm happy with the outcome and happy that I got to learn something about how to use sed
and regular expressions for quick file manipulation. Next up for me will be adding proper server-side selection to the main mp-wp tree, if no one else has gotten to it first.
The updated patch in its entirety, in the form of file links and an embed in this post, why not:
mp-wp_add-embedded-vpatch-formatting.vpatch
mp-wp_add-embedded-vpatch-formatting.vpatch.billymg.sig
1 | diff -uNr a/mp-wp/manifest b/mp-wp/manifest |
2 | |
3 | |
4 | |
5 | 569483 mp-wp_remove-tinymce-and-other-crud billymg Remove tinymce, most of the importers, the self-update feature, and the google gears and press-this plugins |
6 | 602064 mp-wp_apply-htmlspecialchars-to-post-edit-content billymg Run post content through htmlspecialchars() before loading into the post edit UI |
7 | 605926 mp-wp_comments_filtering diana_coman Recent comments widget should show only people's comments (no track/pingbacks); theme default changed to show trackbacks/pingbacks as last/at the bottom in an article's comments list. |
8 | +624366 mp-wp_add-embedded-vpatch-formatting billymg Add the ability to embed vpatches within article content. Embedded vpatch blocks will be formatted with diff syntax highlighting and anchored line numbers |
9 | diff -uNr a/mp-wp/wp-content/plugins/footnotes.php b/mp-wp/wp-content/plugins/footnotes.php |
10 | |
11 | |
12 | |
13 | <?php |
14 | /* |
15 | -Plugin Name: WP-Footnotes |
16 | -Plugin URI: http://www.elvery.net/drzax/more-things/wordpress-footnotes-plugin/ |
17 | -Version: 4.2 |
18 | -Description: Allows a user to easily add footnotes to a post. |
19 | -Author: Simon Elvery |
20 | -Author URI: http://www.elvery.net/drzax/ |
21 | +Plugin Name: MP-WP-Content-Processing |
22 | +Plugin URI: http://billymg.com/category/mp-wp/ |
23 | +Description: Allows for the custom processing of article content. Currently supports footnotes and embedded vpatch snippets. |
24 | +Author: billymg |
25 | +Author URI: http://billymg.com |
26 | */ |
27 | |
28 | -/* |
29 | - * This file is part of WP-Footnotes a plugin for Word Press |
30 | - * Copyright (C) 2007 Simon Elvery |
31 | - * |
32 | - * This program is free software; you can redistribute it and/or |
33 | - * modify it under the terms of the GNU General Public License |
34 | - * as published by the Free Software Foundation; either version 2 |
35 | - * of the License, or (at your option) any later version. |
36 | - * |
37 | - * This program is distributed in the hope that it will be useful, |
38 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
39 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
40 | - * GNU General Public License for more details. |
41 | - * |
42 | - * You should have received a copy of the GNU General Public License |
43 | - * along with this program; if not, write to the Free Software |
44 | - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
45 | - */ |
46 | - |
47 | -// Some important constants |
48 | -define('WP_FOOTNOTES_OPEN', " (("); //You can change this if you really have to, but I wouldn't recommend it. |
49 | -define('WP_FOOTNOTES_CLOSE', "))"); //Same with this one. |
50 | -define('WP_FOOTNOTES_VERSION', '4.2'); |
51 | - |
52 | // Instantiate the class |
53 | -$swas_wp_footnotes = new swas_wp_footnotes(); |
54 | +$mp_wp_content_processing = new mp_wp_content_processing(); |
55 | |
56 | // Encapsulate in a class |
57 | -class swas_wp_footnotes { |
58 | - var $current_options; |
59 | - var $default_options; |
60 | +class mp_wp_content_processing { |
61 | + const MP_WP_FOOTNOTES_OPEN = " (("; |
62 | + const MP_WP_FOOTNOTES_CLOSE = "))"; |
63 | + const MP_WP_CODEBLOCK_OPEN = "\[[0-9]\["; |
64 | + const MP_WP_CODEBLOCK_CLOSE = "]]"; |
65 | + |
66 | + var $options; |
67 | |
68 | /** |
69 | * Constructor. |
70 | */ |
71 | - function swas_wp_footnotes() { |
72 | + function mp_wp_content_processing() { |
73 | // Define the implemented option styles |
74 | $this->styles = array( |
75 | 'decimal' => '1,2...10', |
76 | |
77 | ); |
78 | |
79 | // Define default options |
80 | - $this->default_options = array('superscript'=>true, |
81 | + $this->options = array('superscript'=>true, |
82 | 'pre_backlink'=>' [', |
83 | 'backlink'=>'↩', |
84 | 'post_backlink'=>']', |
85 | |
86 | 'post_identifier'=>'', |
87 | 'pre_footnotes'=>'', |
88 | 'post_footnotes'=>'', |
89 | - 'style_rules'=>'ol.footnotes{font-size:0.8em; color:#666666;}', |
90 | 'no_display_home'=>false, |
91 | 'no_display_archive'=>false, |
92 | 'no_display_date'=>false, |
93 | |
94 | 'no_display_search'=>false, |
95 | 'no_display_feed'=>false, |
96 | 'combine_identical_notes'=>false, |
97 | - 'priority'=>11, |
98 | - 'version'=>WP_FOOTNOTES_VERSION); |
99 | + 'codeblocks_priority'=>9, // highest value that comes before wpautop filter |
100 | + 'footnotes_priority'=>11); |
101 | |
102 | - // Get the current settings or setup some defaults if needed |
103 | - if (!$this->current_options = get_option('swas_footnote_options')){ |
104 | - $this->current_options = $this->default_options; |
105 | - update_option('swas_footnote_options', $this->current_options); |
106 | - } else { |
107 | - // Set any unset options |
108 | - if ($this->current_options['version'] != WP_FOOTNOTES_VERSION) { |
109 | - foreach ($this->default_options as $key => $value) { |
110 | - if (!isset($this->current_options[$key])) { |
111 | - $this->current_options[$key] = $value; |
112 | - } |
113 | - } |
114 | - $this->current_options['version'] = WP_FOOTNOTES_VERSION; |
115 | - update_option('swas_footnote_options', $this->current_options); |
116 | - } |
117 | + // Hook me up |
118 | + add_action('the_content', array($this, 'process_codeblocks'), $this->options['codeblocks_priority']); |
119 | + add_action('the_content', array($this, 'process_footnotes'), $this->options['footnotes_priority']); |
120 | + add_action('wp_head', array($this, 'insert_styles')); |
121 | + } |
122 | + |
123 | + /** |
124 | + * Searches the text and apply markup to codeblocks. |
125 | + * Adds line number links and diff syntax highlighting. |
126 | + * @param $data string The content of the post. |
127 | + * @return string The new content with formatted codeblocks. |
128 | + */ |
129 | + function process_codeblocks($data) { |
130 | + global $post; |
131 | + |
132 | + // Regex extraction of all codeblocks (or return if there are none) |
133 | + if ( |
134 | + !preg_match_all( |
135 | + "/(".self::MP_WP_CODEBLOCK_OPEN.")(.*)(".preg_quote(self::MP_WP_CODEBLOCK_CLOSE, '/').")/Us", |
136 | + $data, |
137 | + $codeblocks, |
138 | + PREG_SET_ORDER |
139 | + ) |
140 | + ) { |
141 | + return $data; |
142 | } |
143 | |
144 | -/* |
145 | - if (!empty($_POST['save_options'])){ |
146 | - $footnotes_options['superscript'] = (array_key_exists('superscript', $_POST)) ? true : false; |
147 | - $footnotes_options['pre_backlink'] = $_POST['pre_backlink']; |
148 | - $footnotes_options['backlink'] = $_POST['backlink']; |
149 | - $footnotes_options['post_backlink'] = $_POST['post_backlink']; |
150 | - $footnotes_options['pre_identifier'] = $_POST['pre_identifier']; |
151 | - $footnotes_options['list_style_type'] = $_POST['list_style_type']; |
152 | - $footnotes_options['post_identifier'] = $_POST['post_identifier']; |
153 | - $footnotes_options['list_style_symbol'] = $_POST['list_style_symbol']; |
154 | - $footnotes_options['pre_footnotes'] = stripslashes($_POST['pre_footnotes']); |
155 | - $footnotes_options['post_footnotes'] = stripslashes($_POST['post_footnotes']); |
156 | - $footnotes_options['style_rules'] = stripslashes($_POST['style_rules']); |
157 | - $footnotes_options['no_display_home'] = (array_key_exists('no_display_home', $_POST)) ? true : false; |
158 | - $footnotes_options['no_display_archive'] = (array_key_exists('no_display_archive', $_POST)) ? true : false; |
159 | - $footnotes_options['no_display_date'] = (array_key_exists('no_display_date', $_POST)) ? true : false; |
160 | - $footnotes_options['no_display_category'] = (array_key_exists('no_display_category', $_POST)) ? true : false; |
161 | - $footnotes_options['no_display_search'] = (array_key_exists('no_display_search', $_POST)) ? true : false; |
162 | - $footnotes_options['no_display_feed'] = (array_key_exists('no_display_feed', $_POST)) ? true : false; |
163 | - $footnotes_options['combine_identical_notes'] = (array_key_exists('combine_identical_notes', $_POST)) ? true : false; |
164 | - $footnotes_options['priority'] = $_POST['priority']; |
165 | - update_option('swas_footnote_options', $footnotes_options); |
166 | - }elseif(!empty($_POST['reset_options'])){ |
167 | - update_option('swas_footnote_options', ''); |
168 | - update_option('swas_footnote_options', $this->default_options); |
169 | + for ($i = 0; $i < count($codeblocks); $i++) { |
170 | + $codeblocks[$i]['snippet'] = $this->format_snippet($codeblocks[$i][2], substr($codeblocks[$i][1], 1, 1), $i+1); |
171 | } |
172 | -*/ |
173 | |
174 | - // Hook me up |
175 | - add_action('the_content', array($this, 'process'), $this->current_options['priority']); |
176 | - add_action('admin_menu', array($this, 'add_options_page')); // Insert the Admin panel. |
177 | - add_action('wp_head', array($this, 'insert_styles')); |
178 | + foreach ($codeblocks as $key => $value) { |
179 | + $data = substr_replace($data, $value['snippet'], strpos($data,$value[0]),strlen($value[0])); |
180 | + } |
181 | + |
182 | + return $data; |
183 | + } |
184 | + |
185 | + function format_snippet($snippet, $syntax_index, $snippet_number) { |
186 | + $highlighting_functions = array( |
187 | + 'highlight_as_plain_text', |
188 | + 'highlight_as_diff' |
189 | + ); |
190 | + |
191 | + if (is_null($highlighting_functions[$syntax_index])) { |
192 | + $syntax_index = 0; |
193 | + } |
194 | + |
195 | + $code_lines = explode("\r\n", $snippet); |
196 | + |
197 | + foreach ($code_lines as $idx => $line) { |
198 | + $line_number = sprintf('S%d-L%d', $snippet_number, $idx+1); |
199 | + $line_link = sprintf('<a href="#%s" name="%s">%d</a>', $line_number, $line_number, $idx+1); |
200 | + $line_open = sprintf('<tr><td class="line-number-column">%s</td><td class="content-column">', $line_link); |
201 | + $line_close = '</td></tr>'; |
202 | + |
203 | + $code_lines[$idx] = $this->$highlighting_functions[$syntax_index]($line_open, $line, $line_close); |
204 | + } |
205 | + |
206 | + $formatted_snippet = implode("\n", $code_lines); |
207 | + |
208 | + $formatted_snippet = sprintf( |
209 | + '%s%s%s', |
210 | + '<div class="mp-wp-codeblock"><table cellpadding="0" cellspacing="0"><tbody>', |
211 | + $formatted_snippet, |
212 | + '</tbody></table></div>' |
213 | + ); |
214 | + |
215 | + return $formatted_snippet; |
216 | + } |
217 | + |
218 | + function highlight_as_plain_text($line_open, $line, $line_close) { |
219 | + return sprintf('%s<span class="line-default">%s</span>%s', $line_open, $line, $line_close); |
220 | + } |
221 | + |
222 | + function highlight_as_diff($line_open, $line, $line_close) { |
223 | + if (substr($line, 0, 5) == 'diff ') { |
224 | + $highlighted_line = sprintf('%s<span class="line-filename">%s</span>%s', $line_open, $line, $line_close); |
225 | + } elseif (substr($line, 0, 4) == '--- ' || substr($line, 0, 4) == '+++ ' || substr($line, 0, 3) == '@@ ') { |
226 | + $highlighted_line = sprintf('%s<span class="line-meta">%s</span>%s', $line_open, $line, $line_close); |
227 | + } elseif (substr($line, 0, 1) == '-') { |
228 | + $highlighted_line = sprintf('%s<span class="line-removed">%s</span>%s', $line_open, $line, $line_close); |
229 | + } elseif (substr($line, 0, 1) == '+') { |
230 | + $highlighted_line = sprintf('%s<span class="line-added">%s</span>%s', $line_open, $line, $line_close); |
231 | + } else { |
232 | + $highlighted_line = sprintf('%s<span class="line-default">%s</span>%s', $line_open, $line, $line_close); |
233 | + } |
234 | + |
235 | + return $highlighted_line; |
236 | } |
237 | |
238 | /** |
239 | |
240 | * @param $data string The content of the post. |
241 | * @return string The new content with footnotes generated. |
242 | */ |
243 | - function process($data) { |
244 | + function process_footnotes($data) { |
245 | global $post; |
246 | |
247 | // Check for and setup the starting number |
248 | $start_number = (preg_match("|<!\-\-startnum=(\d+)\-\->|",$data,$start_number_array)==1) ? $start_number_array[1] : 1; |
249 | |
250 | // Regex extraction of all footnotes (or return if there are none) |
251 | - if (!preg_match_all("/(".preg_quote(WP_FOOTNOTES_OPEN)."|<footnote>)(.*)(".preg_quote(WP_FOOTNOTES_CLOSE)."|<\/footnote>)/Us", $data, $identifiers, PREG_SET_ORDER)) { |
252 | + if (!preg_match_all("/(".preg_quote(self::MP_WP_FOOTNOTES_OPEN)."|<footnote>)(.*)(".preg_quote(self::MP_WP_FOOTNOTES_CLOSE)."|<\/footnote>)/Us", $data, $identifiers, PREG_SET_ORDER)) { |
253 | return $data; |
254 | } |
255 | |
256 | // Check whether we are displaying them or not |
257 | $display = true; |
258 | - if ($this->current_options['no_display_home'] && is_home()) $display = false; |
259 | - if ($this->current_options['no_display_archive'] && is_archive()) $display = false; |
260 | - if ($this->current_options['no_display_date'] && is_date()) $display = false; |
261 | - if ($this->current_options['no_display_category'] && is_category()) $display = false; |
262 | - if ($this->current_options['no_display_search'] && is_search()) $display = false; |
263 | - if ($this->current_options['no_display_feed'] && is_feed()) $display = false; |
264 | + if ($this->options['no_display_home'] && is_home()) $display = false; |
265 | + if ($this->options['no_display_archive'] && is_archive()) $display = false; |
266 | + if ($this->options['no_display_date'] && is_date()) $display = false; |
267 | + if ($this->options['no_display_category'] && is_category()) $display = false; |
268 | + if ($this->options['no_display_search'] && is_search()) $display = false; |
269 | + if ($this->options['no_display_feed'] && is_feed()) $display = false; |
270 | |
271 | $footnotes = array(); |
272 | |
273 | |
274 | if ( array_key_exists(get_post_meta($post->ID, 'footnote_style', true), $this->styles) ) { |
275 | $style = get_post_meta($post->ID, 'footnote_style', true); |
276 | } else { |
277 | - $style = $this->current_options['list_style_type']; |
278 | + $style = $this->options['list_style_type']; |
279 | } |
280 | |
281 | // Create 'em |
282 | |
283 | |
284 | |
285 | // if we're combining identical notes check if we've already got one like this & record keys |
286 | - if ($this->current_options['combine_identical_notes']){ |
287 | + if ($this->options['combine_identical_notes']){ |
288 | for ($j=0; $j<count($footnotes); $j++){ |
289 | if ($footnotes[$j]['text'] == $identifiers[$i]['text']){ |
290 | $identifiers[$i]['use_footnote'] = $j; |
291 | |
292 | $id_id = "identifier_".$key."_".$post->ID; |
293 | $id_num = ($style == 'decimal') ? $value['use_footnote']+$start_number : $this->convert_num($value['use_footnote']+$start_number, $style, count($footnotes)); |
294 | $id_href = ( ($use_full_link) ? get_permalink($post->ID) : '' ) . "#footnote_".$value['use_footnote']."_".$post->ID; |
295 | - |
296 | -// $id_title = str_replace('"', """, htmlentities(strip_tags($value['text']), ENT_QUOTES, 'UTF-8')); |
297 | - |
298 | $id_title = str_replace('"', '`', strip_tags($value['text'])); |
299 | - $id_replace = $this->current_options['pre_identifier'].'<a href="'.$id_href.'" id="'.$id_id.'" class="footnote-link footnote-identifier-link" title="'.$id_title.'">'.$id_num.'</a>'.$this->current_options['post_identifier']; |
300 | - if ($this->current_options['superscript']) $id_replace = '<sup>'.$id_replace.'</sup>'; |
301 | + $id_replace = $this->options['pre_identifier'].'<a href="'.$id_href.'" id="'.$id_id.'" class="footnote-link footnote-identifier-link" title="'.$id_title.'">'.$id_num.'</a>'.$this->options['post_identifier']; |
302 | + if ($this->options['superscript']) $id_replace = '<sup>'.$id_replace.'</sup>'; |
303 | if ($display) $data = substr_replace($data, $id_replace, strpos($data,$value[0]),strlen($value[0])); |
304 | else $data = substr_replace($data, '', strpos($data,$value[0]),strlen($value[0])); |
305 | } |
306 | |
307 | // Display footnotes |
308 | if ($display) { |
309 | $start = ($start_number != 1) ? 'start="'.$start_number.'" ' : ''; |
310 | - $data = $data.$this->current_options['pre_footnotes']; |
311 | + $data = $data.$this->options['pre_footnotes']; |
312 | |
313 | $data = $data . '<ol '.$start.'class="footnotes">'; |
314 | foreach ($footnotes as $key => $value) { |
315 | $data = $data.'<li id="footnote_'.$key.'_'.$post->ID.'" class="footnote"'; |
316 | if ($style == 'symbol') { |
317 | $data = $data . ' style="list-style-type:none;"'; |
318 | - } elseif($style != $this->current_options['list_style_type']) { |
319 | + } elseif($style != $this->options['list_style_type']) { |
320 | $data = $data . ' style="list-style-type:' . $style . ';"'; |
321 | } |
322 | $data = $data . '>'; |
323 | |
324 | $data = $data.$value['text']; |
325 | if (!is_feed()){ |
326 | foreach($value['identifiers'] as $identifier){ |
327 | - $data = $data.$this->current_options['pre_backlink'].'<a href="'.( ($use_full_link) ? get_permalink($post->ID) : '' ).'#identifier_'.$identifier.'_'.$post->ID.'" class="footnote-link footnote-back-link">'.$this->current_options['backlink'].'</a>'.$this->current_options['post_backlink']; |
328 | + $data = $data.$this->options['pre_backlink'].'<a href="'.( ($use_full_link) ? get_permalink($post->ID) : '' ).'#identifier_'.$identifier.'_'.$post->ID.'" class="footnote-link footnote-back-link">'.$this->options['backlink'].'</a>'.$this->options['post_backlink']; |
329 | } |
330 | } |
331 | $data = $data . '</li>'; |
332 | } |
333 | - $data = $data . '</ol>' . $this->current_options['post_footnotes']; |
334 | + $data = $data . '</ol>' . $this->options['post_footnotes']; |
335 | } |
336 | return $data; |
337 | } |
338 | |
339 | - /** |
340 | - * Really insert the options page. |
341 | - */ |
342 | - function footnotes_options_page() { |
343 | - $this->current_options = get_option('swas_footnote_options'); |
344 | - foreach ($this->current_options as $key=>$setting) { |
345 | - $new_setting[$key] = htmlentities($setting); |
346 | - } |
347 | - $this->current_options = $new_setting; |
348 | - unset($new_setting); |
349 | - include (dirname(__FILE__) . '/options.php'); |
350 | - } |
351 | - |
352 | - /** |
353 | - * Insert the options page into the admin area. |
354 | - */ |
355 | - function add_options_page() { |
356 | - // Add a new menu under Options: |
357 | - add_options_page('Footnotes', 'Footnotes', 8, __FILE__, array($this, 'footnotes_options_page')); |
358 | - } |
359 | - |
360 | - function upgrade_post($data){ |
361 | - $data = str_replace('<footnote>',WP_FOOTNOTES_OPEN,$data); |
362 | - $data = str_replace('</footnote>',WP_FOOTNOTES_CLOSE,$data); |
363 | - return $data; |
364 | - } |
365 | - |
366 | - function insert_styles(){ |
367 | + function insert_styles() { |
368 | ?> |
369 | <style type="text/css"> |
370 | - <?php if ($this->current_options['list_style_type'] != 'symbol'): ?> |
371 | - ol.footnotes li {list-style-type:<?php echo $this->current_options['list_style_type']; ?>;} |
372 | + ol.footnotes { font-size: 0.8em; color: #666666; } |
373 | + a.footnote-link, |
374 | + td.line-number-column { |
375 | + -moz-user-select: none; |
376 | + -webkit-user-select: none; |
377 | + user-select: none; |
378 | + } |
379 | + div.mp-wp-codeblock { |
380 | + background: none; |
381 | + font-family: monospace; |
382 | + color: #333; |
383 | + border: 1px solid #ddd; |
384 | + padding: 0; |
385 | + overflow: auto; |
386 | + } |
387 | + td.line-number-column { background: #f5f6f7; text-align: right; vertical-align: top; } |
388 | + td.line-number-column a { color: #555; padding: 0 5px; } |
389 | + td.content-column { |
390 | + padding-left: 10px; |
391 | + white-space: pre-wrap; |
392 | + tab-size: 4; |
393 | + -moz-tab-size: 4; |
394 | + max-width: 670px; /* adjust as necessary to fit your blog's viewport */ |
395 | + } |
396 | + span.line-filename { font-weight: bold; } |
397 | + span.line-meta { color: #999; word-wrap: break-word; } |
398 | + span.line-added { color: green; } |
399 | + span.line-removed { color:red; } |
400 | + |
401 | + <?php if ($this->options['list_style_type'] != 'symbol'): ?> |
402 | + ol.footnotes li { list-style-type: <?php echo $this->options['list_style_type']; ?>; } |
403 | <?php endif; ?> |
404 | - <?php echo $this->current_options['style_rules'];?> |
405 | + |
406 | </style> |
407 | <?php |
408 | } |
409 | |
410 | |
411 | - function convert_num ($num, $style, $total){ |
412 | + function convert_num ($num, $style, $total) { |
413 | switch ($style) { |
414 | case 'decimal-leading-zero' : |
415 | $width = max(2, strlen($total)); |
416 | |
417 | case 'symbol' : |
418 | $sym = ''; |
419 | for ($i = 0; $i<$num; $i++) { |
420 | - $sym .= $this->current_options['list_style_symbol']; |
421 | + $sym .= $this->options['list_style_symbol']; |
422 | } |
423 | return $sym; |
424 | } |
425 | |
426 | * @param string $case Upper or lower case. |
427 | * @return string The roman numeral |
428 | */ |
429 | - function roman($num, $case= 'upper'){ |
430 | + function roman($num, $case= 'upper') { |
431 | $num = (int) $num; |
432 | $conversion = array('M'=>1000, 'CM'=>900, 'D'=>500, 'CD'=>400, 'C'=>100, 'XC'=>90, 'L'=>50, 'XL'=>40, 'X'=>10, 'IX'=>9, 'V'=>5, 'IV'=>4, 'I'=>1); |
433 | $roman = ''; |
434 | |
435 | return ($case == 'lower') ? strtolower($roman) : $roman; |
436 | } |
437 | |
438 | - function alpha($num, $case='upper'){ |
439 | + function alpha($num, $case='upper') { |
440 | $j = 1; |
441 | for ($i = 'A'; $i <= 'ZZ'; $i++){ |
442 | if ($j == $num){ |
443 |
- This is now a regex pattern to include an encoded syntax index. The current patch supports plain text/no highlighting (0) and linux
diff -u
(1). [↩] - I reverted this change to the default footnote marker style back to its original. I personally like the roman numerals though so that's what billymg.com is using now. Feel free to set it how you like using this variable. [↩]
- The open tag no longer needs to be escaped now that it's a regex pattern. [↩]
- Pass the new syntax index to
format_snippet()
so it knows how to highlight the codeblock. [↩] - Upon jfw's suggestion, I decided to not run the codeblock content through
htmlspecialchars()
. The idea being that the operator can escape their code with a simple line ofsed
before pasting into mp-wp. This way of thinking also opened up the possibility of including footnotes within codeblocks, since the '((' can be pre-escaped in the sed -> mp-wp workflow.This was all I needed for this article:
cat [FILE] | sed 's/&/\&/g; s/</\</g; s/>/\>/g; s/"/\"/g; s/'"'"'/\'/g; s/((/\(\(/g; s/))/\)\)/g; s/\[([0-9])\[/\[$1\[/g; s/]]/\]\]/g' > [FILE_ESCAPED]
[↩] - I changed this to a plain
div
because thepre
tag wrapped around the other markup (which is probably a misuse of thepre
tag in any case) would cause extra newlines to be added when copy/pasting from the snippet into a text file. [↩] - This little bit of CSS avoids selecting footnote markers and line numbers when copy/pasting text from a codeblock. Go ahead, try it out. [↩]
- In other jfw-was-right, this change and the
white-space: pre-wrap;
above were added to eliminate the unseemly horizontal scrolling present in the initial draft. [↩]
Looks quite good! I'll add it to the list to give it a spin sooner rather than later.
Looking good!
> i. This is now a regex pattern to include an encoded syntax index.
Do you mean for this to allow only one digit? You could use \[([0-9]+)\[ so the parens capture the number portion (then there's surely a preg function to get at it).
> ii. ... Feel free to set it how you like using this variable.
This nonetheless comes at the cost of having to fork the v-tree. It occurred to me this one might warrant a global setting in wp-config.php, since it really seems to be a matter of taste/theme.
> v. ... This was all I needed for this article:
The closing characters don't generally need escaping, since they have special meaning only after the corresponding opening one (and footnotes-within-footnotes wouldn't work anyway AFAIK). Single/double quotes only need it in the context of an attribute (i.e. <a href="evil-user-input-here">). So my current filter is:
> vi. I changed this to a plain div because the pre tag wrapped around the other markup (which is probably a misuse of the pre tag in any case) would cause extra newlines to be added when copy/pasting from the snippet into a text file.
I don't quite follow, but how does this handle multiple sequential spaces (as might be significant e.g. in a regexp even if one fully adopts MP's space-indent ban)?
> vii. This little bit of CSS avoids selecting footnote markers and line numbers when copy/pasting text from a codeblock. Go ahead, try it out.
That's very shiny!
> Do you mean for this to allow only one digit? You could use \[([0-9]+)\[ so the parens capture the number portion (then there's surely a preg function to get at it).
I meant for it to only be 0-9 as I think adding support for eight more languages will take quite some time. I'm grabbing the matched index from the array that
preg_match_all
populates (#S1-L37), which currently depends on it being a single-digit number (though it could be updated to grab any length between[[
).> This nonetheless comes at the cost of having to fork the v-tree. It occurred to me this one might warrant a global setting in wp-config.php, since it really seems to be a matter of taste/theme.
I could see that, perhaps the entire options can be set in wp-config.php? See also my comment on your recent article.
> So my current filter is: [...]
This is a nice simplification, thanks!
> I don't quite follow, but how does this handle multiple sequential spaces [...] ?
e.g. previously with the
pre
tag wrapped around thetable
, copying:and pasting it would yield:
Multiple sequential spaces are handled as you would want/expect them to be (i.e. maintained). The
pre
tag was superfluous because oftd.content-column { white-space: pre-wrap; }
in the CSS.> I think adding support for eight more languages will take quite some time.
Seems more likely that someone would do a whole bunch at once rather than a trickle, and also to be encouraged to reduce churn and chance of conflicts in the "address space" (hey, it wasn't my idea to use numbers instead of language names).
I think the regexing is easier than you've made it on yourself. Why not un-indirect the MP_WP_CODEBLOCK_OPEN which isn't meaningfully customizable anyway, and shrink the first set of parens to include just the number (as I showed)? Then no need for substr and you get multi-digits for free.
> Why not un-indirect the MP_WP_CODEBLOCK_OPEN which isn't meaningfully customizable anyway, and shrink the first set of parens to include just the number (as I showed)? Then no need for substr and you get multi-digits for free.
That's a good point, i'll update the patch accordingly. And per our other thread on your article i'll ping others in #o about what options people would like to see customizable.
[...] below for the updated embeddable codeblocks patch. This is the third iteration after the first two discussions. This patch also now contains the server-side select mechanism, including the updates [...]
[...] . The characters in http://billymg.com/2020/04/updated-patch-code-embed-plugin-for-mp-wp/ didn't work. Consequently the codeblock in my [...]