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

