soo_plugin_display Page 2 of 2 «
soo_plugin_display Source code
1 : //---------------------------------------------------------------------//
2 : // soo_plugin_pref compatibility //
3 : //---------------------------------------------------------------------//
4 :
5 :
6 : global $soo_plugin_display_prefs;
7 :
8 : @require_plugin('soo_plugin_pref'); // optional
9 : add_privs('plugin_prefs.soo_plugin_display','1,2');
10 : add_privs('plugin_lifecycle.soo_plugin_display','1,2');
11 : register_callback('soo_plugin_display_prefs', 'plugin_prefs.soo_plugin_display');
12 : register_callback('soo_plugin_display_prefs', 'plugin_lifecycle.soo_plugin_display');
13 :
14 : // load prefs if soo_plugin_pref enabled, else load defaults
15 : $soo_plugin_display_prefs = function_exists('soo_plugin_pref_vals') ?
16 : soo_plugin_pref_vals('soo_plugin_display') : array();
17 : foreach ( soo_plugin_display_defaults() as $name => $arr )
18 : // just in case prefs/defaults do not match;
19 : // might happen if plugin upgraded while soo_plugin_pref disabled
20 : if ( ! array_key_exists($name, $soo_plugin_display_prefs) )
21 : $soo_plugin_display_prefs[$name] = $arr['val'];
22 :
23 : // callback for plugin_prefs/plugin_lifecycle events
24 : function soo_plugin_display_prefs( $event, $step ) {
25 : if ( function_exists('soo_plugin_pref') )
26 : return soo_plugin_pref($event, $step, soo_plugin_display_defaults());
27 :
28 : // message to install soo_plugin_pref
29 : if ( substr($event, 0, 12) == 'plugin_prefs' ) {
30 : $plugin = substr($event, 13);
31 : $message = '<p><br /><strong>' . gTxt('edit') . " $plugin " .
32 : gTxt('edit_preferences') . ':</strong><br />' . gTxt('install_plugin') .
33 : ' <a href="http://ipsedixit.net/txp/92/soo_plugin_pref">soo_plugin_pref</a></p>';
34 : pagetop(gTxt('edit_preferences') . " › $plugin", $message);
35 : }
36 : }
37 :
38 : function soo_plugin_display_defaults( ) {
39 : return array(
40 : 'default_form' => array(
41 : 'val' => '',
42 : 'html' => 'text_input',
43 : 'text' => 'Default output form for <b>soo_plugin_display</b> tag',
44 : ),
45 : 'strip_style' => array(
46 : 'val' => 0,
47 : 'html' => 'yesnoradio',
48 : 'text' => 'Remove leading <style> element from Help text?',
49 : ),
50 : 'strip_title' => array(
51 : 'val' => 0,
52 : 'html' => 'yesnoradio',
53 : 'text' => 'Remove first <h1> element from Help text?',
54 : ),
55 : 'size_format' => array(
56 : 'val' => '{size} KB',
57 : 'html' => 'text_input',
58 : 'text' => 'Default format string for <b>soo_plugin_size</b>',
59 : ),
60 : 'highlight' => array(
61 : 'val' => 1,
62 : 'html' => 'yesnoradio',
63 : 'text' => 'Add syntax highlighting to <b>soo_plugin_code</b>?',
64 : ),
65 : 'show_line_numbers' => array(
66 : 'val' => ':',
67 : 'html' => 'text_input',
68 : 'text' => 'Text to append to line numbers (leave blank to hide numbers)',
69 : ),
70 : 'tab_stop' => array(
71 : 'val' => 4,
72 : 'html' => 'text_input',
73 : 'text' => 'Spaces per tab in plugin code',
74 : ),
75 : );
76 : }
77 :
78 : //---------------------------------------------------------------------//
79 : // Tags //
80 : //---------------------------------------------------------------------//
81 :
82 : // tag to select plugin(s) for display
83 : // can be used as single w/form or container
84 : // for plugin lists code and help are not retrieved
85 : function soo_plugin_display( $atts, $thing = '' ) {
86 : global $soo_plugin_display, $soo_plugin_display_prefs;
87 : extract(lAtts(array(
88 : 'name' => '',
89 : 'prefix' => '',
90 : 'form' => $soo_plugin_display_prefs['default_form'],
91 : 'show_inactive' => 0,
92 : 'sort' => 'name asc',
93 : 'wraptag' => '',
94 : 'break' => '',
95 : 'class' => '',
96 : 'html_id' => '',
97 : ), $atts));
98 :
99 : $columns = 'author, author_uri, version, description, name, ' .
100 : 'round(char_length(code)/1024, 1) as size' . ( $name ? ', help, code' : '' );
101 :
102 : if ( $name or $prefix )
103 : $where = ( $name ? "name = '$name'" : "name like '$prefix%'" )
104 : . ( ( $show_inactive or $name ) ? '' : ' and status = 1' );
105 : else
106 : $where = $show_inactive ? 1 : 'status = 1';
107 : $where .= " order by $sort";
108 :
109 : if ( ! $data = safe_rows($columns, 'txp_plugin', $where) )
110 : return;
111 :
112 : foreach ( $data as $r ) {
113 : $soo_plugin_display = $r;
114 : $out[] = $thing ? parse($thing) : parse_form($form);
115 : }
116 :
117 : if ( isset($out) )
118 : return doWrap($out, $wraptag, $break, $class, '', '', '', $html_id);
119 : }
120 :
121 : // basic output tags: display field direct from database
122 : function soo_plugin_author_uri( ) { return _soo_plugin_field('author_uri'); }
123 : function soo_plugin_version( ) { return _soo_plugin_field('version'); }
124 : function soo_plugin_description( ) { return _soo_plugin_field('description'); }
125 :
126 : // as above, but with option to make output a link to author's website
127 : function soo_plugin_author( $atts ) { return _soo_plugin_field('author_uri', $atts); }
128 : function soo_plugin_name( $atts ) { return _soo_plugin_field('name', $atts); }
129 :
130 : // display plugin help, with options to remove leading style and/or h1 elements,
131 : // and option to restrict display to named section
132 : function soo_plugin_help( $atts ) {
133 : global $soo_plugin_display_prefs;
134 : extract(lAtts(array(
135 : 'strip_style' => $soo_plugin_display_prefs['strip_style'],
136 : 'strip_title' => $soo_plugin_display_prefs['strip_title'],
137 : 'section_id' => '', // HTML id for header element to display
138 : 'h_plus' => 0, // transpose header levels by this amount
139 : ), $atts));
140 : $help = _soo_plugin_field('help');
141 :
142 : // remove leading <style> element
143 : if ( $strip_style and preg_match('/^<style/', $help) )
144 : $help = preg_replace('/^[\s\S]+?<\/style>([\s\S]+)$/', '$1', $help);
145 :
146 : // remove leading <h1> element
147 : if ( $strip_title )
148 : $help = preg_replace('/^([\s\S]+?)<h1[\s\S]+?<\/h1>([\s\S]+)$/', '$1$2', $help);
149 :
150 : // display from named header element to next header with same or lower h-level
151 : if ( $section_id ) {
152 : $pattern = "/^([\s\S]+)<h(\d)([^>]+id=['\"]$section_id('|\").+?>[\s\S]+)$/";
153 : if ( preg_match($pattern, $help, $match) ) {
154 : list( , , $h_num, $remainder) = $match;
155 : $help = '';
156 : $pattern = '/^([\s\S]+?)<h(\d)([\s\S]+)$/';
157 : $remainder = "<h$h_num$remainder";
158 : while ( preg_match($pattern, $remainder, $match) ) {
159 : list( , $keep, $next_h, $remainder) = $match;
160 : $help .= $keep;
161 : $remainder = "<h$next_h$remainder";
162 : if ( $h_num >= $next_h )
163 : $remainder = '';
164 : }
165 : if ( ! $help )
166 : $help = $remainder;
167 : }
168 : }
169 :
170 : // transpose HTML header levels.
171 : if ( $h_plus ) {
172 : for ( $i = 1; $i <= 6; $i++ ) {
173 : $j = $i + $h_plus;
174 : if ( $j < 1 ) $j = 1;
175 : if ( $j > 6 ) $j = 6;
176 : $old_tag[] = "<h$i";
177 : $old_tag[] = "</h$i";
178 : $new_tag[] = "<h$j";
179 : $new_tag[] = "</h$j";
180 : }
181 : $help = str_replace($old_tag, $new_tag, $help);
182 : }
183 :
184 : return $help;
185 : }
186 :
187 : // display installed code size in KB
188 : function soo_plugin_size( $atts ) {
189 : global $soo_plugin_display_prefs;
190 : extract(lAtts(array(
191 : 'format' => $soo_plugin_display_prefs['size_format'],
192 : ), $atts));
193 : $size = _soo_plugin_field('size');
194 : return str_replace('{size}', $size, $format);
195 : }
196 :
197 : // display plugin source code
198 : // code highlighting with named classes for styling
199 : // various options for line numbering
200 : // display full source or named function, class, or method
201 : function soo_plugin_code( $atts ) {
202 : global $soo_plugin_display_prefs;
203 : extract(lAtts(array(
204 : 'highlight' => $soo_plugin_display_prefs['highlight'],
205 : 'show_line_numbers' => $soo_plugin_display_prefs['show_line_numbers'],
206 : 'reindex_lines' => 0,
207 : 'tab_stop' => $soo_plugin_display_prefs['tab_stop'],
208 : 'function' => '',
209 : 'php_class' => '',
210 : 'class' => 'soo_plugin_code',
211 : 'html_id' => '',
212 : ), $atts));
213 :
214 : $raw_code = trim(_soo_plugin_field('code'));
215 : $match_index = 2;
216 : $safety_check = true;
217 :
218 : // find named method: assumes end brace one tab in from start of line
219 : if ( $php_class and $function ) {
220 : $pattern = '/([\s\S]*(abstract|)\s*class\s+'
221 : . $php_class . '\s+.*?\{[\s\S]+?)(\t(public|private|protected)?\s*function\s+'
222 : . $function . '\s*\([\s\S]+?\n\t}.*)[\s\S]*/';
223 : $match_index ++;
224 : }
225 :
226 : // find named function: assumes end brace at start of line
227 : elseif ( $function )
228 : $pattern = '/([\s\S]*)((public|private|protected)?\s*function\s+'
229 : . $function . '\s*\([\s\S]+?\n}.*)/';
230 :
231 : // find named class: assumes end brace at start of line
232 : elseif ( $php_class )
233 : $pattern = '/([\s\S]*?)((abstract|)\s*class\s+'
234 : . $php_class . '\s+.*?\{[\s\S]+?\n}.*)[\s\S]*/';
235 :
236 : else
237 : $safety_check = false;
238 :
239 : // safety check is because the preg_match() can take a long time if there is no match
240 : if ( $safety_check ) {
241 : if ( $function and ! preg_match("/$function\s*\(/", $raw_code) )
242 : return;
243 : if ( $php_class and ! preg_match("/class\s*$php_class\s+/", $raw_code) )
244 : return;
245 : }
246 :
247 : if ( isset($pattern) ) {
248 : if ( ! preg_match($pattern, $raw_code, $match) ) return;
249 : $raw_code = $match[$match_index];
250 : // if not reindexing, find starting line number in full source code
251 : $start_line = $reindex_lines ?
252 : $reindex_lines : count(explode(n, $match[1]));
253 : }
254 :
255 : // convert tabs to spaces, retaining tab stop alignment
256 : foreach ( explode(n, $raw_code) as $line ) {
257 : $bucket = array();
258 : foreach ( str_split($line) as $char )
259 : if ( $char == t ) {
260 : $add = $tab_stop - fmod(count($bucket), $tab_stop);
261 : while ( $add ) {
262 : $bucket[] = ' ';
263 : $add --;
264 : }
265 : }
266 : else
267 : $bucket[] = $char;
268 : $lines[] = implode('', $bucket);
269 : }
270 :
271 : if ( ! $highlight )
272 : return implode(n, array_map('htmlspecialchars', $lines));
273 :
274 : $find = array(sp, br, '<code>', '</code>');
275 : $replace = array(' ', n, '', '');
276 : // names of code highlight types from ini_get()
277 : // highlight_string() output style attributes will be replaced by named classes
278 : foreach ( array('bg', 'comment', 'default', 'html', 'keyword', 'string') as $k ) {
279 : $find[] = 'style="color: ' . ini_get("highlight.$k") . '"';
280 : $replace[] = "class=\"php_$k\"";
281 : }
282 :
283 : $start_line = 1;
284 :
285 : // run highlight_string(), clean up
286 : $h_s = highlight_string("<?php\n" . implode(n, $lines) . "\n?>", true);
287 : $lines = str_replace($find, $replace, explode(br, $h_s));
288 : array_shift($lines);
289 : $lines[0] = '<span class="php_html">' . $lines[0];
290 : array_pop($lines);
291 : $lines[count($lines)-1] .= '</span>';
292 :
293 : // add line numbers
294 : $total_lines = $start_line + count($lines) - 1;
295 : foreach ( $lines as $i => $line ) {
296 : if ( $show_line_numbers ) {
297 : $i += $start_line;
298 : $line = "<span class=\"php_comment\">$i $show_line_numbers</span> $line";
299 : if ( $i < 1000 and $total_lines > 999 ) $line = sp . $line;
300 : if ( $i < 100 and $total_lines > 99 ) $line = sp . $line;
301 : if ( $i < 10 ) $line = sp . $line;
302 : }
303 : $code[] = $line;
304 : }
305 :
306 : $tag_atts = ( $class ? " class=\"$class\"" : '' ) . ( $html_id ? " id=\"$html_id\"" : '' );
307 :
308 : return "<pre$tag_atts><code$tag_atts>" . implode(n, $code) . '</code></pre>';
309 : }
310 :
311 : //---------------------------------------------------------------------//
312 : // Support Functions //
313 : //---------------------------------------------------------------------//
314 :
315 : function _soo_plugin_field( $field, $atts = null ) {
316 : if ( is_array($atts) )
317 : extract(lAtts(array(
318 : 'link' => 1,
319 : ), $atts));
320 : global $soo_plugin_display;
321 : $author_uri = $soo_plugin_display['author_uri'];
322 : if ( isset($soo_plugin_display[$field]) ) {
323 : $out = $soo_plugin_display[$field];
324 : return ( ! empty($link) and $author_uri ) ? href($out, $author_uri) : $out;
325 : }
326 : }








