Property changes on: trunk/extensions/SemanticForms/specials/SF_CreateClass.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 1 | + native |
Index: trunk/extensions/RT/RT_body.php |
— | — | @@ -1,415 +1,415 @@ |
2 | | -<?php
|
3 | | -
|
4 | | -class RT {
|
5 | | -
|
6 | | - /**
|
7 | | - * Register the hook with ParserFirstCallInit
|
8 | | - */
|
9 | | - public static function registerHook( &$parser ) {
|
10 | | - $parser->setHook( 'rt', array( 'RT::render' ) );
|
11 | | - return true;
|
12 | | - }
|
13 | | -
|
14 | | - // This is called to process <rt>...</rt> within a page
|
15 | | - public static function render( $input, $args = array(), $parser = null ) {
|
16 | | -
|
17 | | - global $wgRequestTracker_Cachepage, $wgRequestTracker_Active, $wgRequestTracker_DBconn,
|
18 | | - $wgRequestTracker_TIMEFORMAT_LASTUPDATED,
|
19 | | - $wgRequestTracker_TIMEFORMAT_LASTUPDATED2,
|
20 | | - $wgRequestTracker_TIMEFORMAT_CREATED,
|
21 | | - $wgRequestTracker_TIMEFORMAT_CREATED2,
|
22 | | - $wgRequestTracker_TIMEFORMAT_RESOLVED,
|
23 | | - $wgRequestTracker_TIMEFORMAT_RESOLVED2,
|
24 | | - $wgRequestTracker_TIMEFORMAT_NOW;
|
25 | | -
|
26 | | - wfLoadExtensionMessages( 'RT' );
|
27 | | -
|
28 | | - // Grab the number if one was given between the <tr> tags
|
29 | | - $ticketnum = 0;
|
30 | | - $matches = array();
|
31 | | - if ( preg_match( '/^\s*(\d+)\s*$/', $input, $matches ) ) {
|
32 | | - $ticketnum = $matches[0];
|
33 | | - }
|
34 | | -
|
35 | | - // Disable all caching unless told not to
|
36 | | - if ( !$wgRequestTracker_Cachepage ) {
|
37 | | - $parser->disableCache();
|
38 | | - }
|
39 | | -
|
40 | | - // Try and connect to the database if we are active
|
41 | | - if ( $wgRequestTracker_Active ) {
|
42 | | - global $wgUser;
|
43 | | - $dbh = pg_connect( $wgRequestTracker_DBconn );
|
44 | | - if ( $dbh == false ) {
|
45 | | - wfDebug( "DB connection error\n" );
|
46 | | - wfDebug( "Connection string: $wgRequestTracker_DBconn\n" );
|
47 | | - $wgRequestTracker_Active = 0;
|
48 | | - }
|
49 | | - $tz = $wgUser->getOption( 'timecorrection' );
|
50 | | - if ( $tz ) {
|
51 | | - $found = array();
|
52 | | - if ( preg_match ( '/((-?\d\d?):(\d\d))/', $tz, $found ) ) {
|
53 | | - if ( $found[3] === '00' ) {
|
54 | | - pg_query( "SET TIME ZONE $found[2]" );
|
55 | | - }
|
56 | | - else {
|
57 | | - print( "SET TIME ZONE INTERVAL '$found[1]' HOUR TO MINUTE" );
|
58 | | - }
|
59 | | - }
|
60 | | - }
|
61 | | - }
|
62 | | -
|
63 | | - // If we are not 'active', we leave right away, with minimal output
|
64 | | - if ( !$wgRequestTracker_Active ) {
|
65 | | - if ( $ticketnum ) {
|
66 | | - return "<span class='rt-ticket-inactive'>RT #$ticketnum</span>";
|
67 | | - }
|
68 | | - $msg = wfMsg( 'rt-inactive' );
|
69 | | - return "<table class='rt-table-inactive' border='1'><tr><td>$msg</td></tr></table>";
|
70 | | - }
|
71 | | -
|
72 | | - // Standard info we gather
|
73 | | - $TZ = "AT TIME ZONE 'GMT'";
|
74 | | - $ticketinfo = 't.id, t.subject, t.priority, INITCAP(t.status) AS status, q.name AS queue,'
|
75 | | - . ' COALESCE(u.realname, u.name) AS owner,'
|
76 | | - . ' u.name AS username,'
|
77 | | - . ' COALESCE(u2.realname, u2.name) AS creator,'
|
78 | | - . " TO_CHAR(t.lastupdated $TZ, '$wgRequestTracker_TIMEFORMAT_LASTUPDATED'::text) AS lastupdated,"
|
79 | | - . " TO_CHAR(t.lastupdated $TZ, '$wgRequestTracker_TIMEFORMAT_LASTUPDATED2'::text) AS lastupdated2,"
|
80 | | - . " TO_CHAR(now() $TZ, '$wgRequestTracker_TIMEFORMAT_NOW'::text) AS nowtime,"
|
81 | | - . " TO_CHAR(t.created $TZ, '$wgRequestTracker_TIMEFORMAT_CREATED'::text) AS created,"
|
82 | | - . " TO_CHAR(t.created $TZ, '$wgRequestTracker_TIMEFORMAT_CREATED2'::text) AS created2,"
|
83 | | - . " TO_CHAR(t.resolved $TZ, '$wgRequestTracker_TIMEFORMAT_RESOLVED'::text) AS resolved,"
|
84 | | - . " TO_CHAR(t.resolved $TZ, '$wgRequestTracker_TIMEFORMAT_RESOLVED2'::text) AS resolved2,"
|
85 | | - . " CASE WHEN (now() $TZ - t.created) <= '1 second'::interval THEN '1 second' ELSE"
|
86 | | - . " CASE WHEN (now() $TZ - t.created) <= '2 minute'::interval THEN EXTRACT(seconds FROM now() $TZ - t.created) || ' seconds' ELSE"
|
87 | | - . " CASE WHEN (now() $TZ - t.created) <= '2 hour'::interval THEN EXTRACT(minutes FROM now() $TZ - t.created) || ' minutes' ELSE"
|
88 | | - . " CASE WHEN (now() $TZ - t.created) <= '2 day'::interval THEN EXTRACT(hours FROM now() $TZ - t.created) || ' hours' ELSE"
|
89 | | - . " EXTRACT(days FROM now() $TZ - t.created) || ' days' END END END END AS age";
|
90 | | -
|
91 | | - // The standard query
|
92 | | - $ticketquery = "SELECT $ticketinfo FROM tickets t"
|
93 | | - . ' JOIN users u ON t.owner = u.id'
|
94 | | - . ' JOIN users u2 ON t.creator = u2.id'
|
95 | | - . ' JOIN queues q ON t.queue = q.id';
|
96 | | -
|
97 | | - // If just a single number, treat it as <rt>#</rt>
|
98 | | - if ( 1 === count( $args ) ) {
|
99 | | - if ( preg_match( '/^\d+$/', key( $args ) ) ) {
|
100 | | - $ticketnum = key( $args );
|
101 | | - }
|
102 | | - }
|
103 | | -
|
104 | | - // Look up a single ticket number
|
105 | | - if ( $ticketnum ) {
|
106 | | - $SQL = "$ticketquery AND t.id = $ticketnum";
|
107 | | - $res = pg_query( $dbh, $SQL );
|
108 | | - if ( !$res ) {
|
109 | | - die ( wfMsg( 'rt-badquery' ) );
|
110 | | - }
|
111 | | - $info = pg_fetch_array( $res );
|
112 | | - if ( !$info ) {
|
113 | | - return "<span class='rt-nosuchticket'>RT #$ticketnum</span>";
|
114 | | - }
|
115 | | - return self::fancyLink( $info, $args, $parser, 0 );
|
116 | | - }
|
117 | | -
|
118 | | - // Add in a LIMIT clause if l=xx was used
|
119 | | - $limit = '';
|
120 | | - if ( array_key_exists( 'l', $args ) ) {
|
121 | | - $limit = trim( $args['l'] );
|
122 | | - if ( !preg_match( '/^ *\d+ *$/', $limit ) ) {
|
123 | | - die ( wfMsg ( 'rt-badlimit', $limit ) );
|
124 | | - }
|
125 | | - $limit = " LIMIT $limit";
|
126 | | - }
|
127 | | -
|
128 | | - // Change the default ORDER BY clause if ob=xx was used
|
129 | | - $orderby = 'ORDER BY t.lastupdated DESC, t.id';
|
130 | | - $valid_orderby = array
|
131 | | - (
|
132 | | - 'id' => 't.id',
|
133 | | - 'subject' => 't.subject',
|
134 | | - 'priority' => 't.priority',
|
135 | | - 'status' => 't.status',
|
136 | | - 'queue' => 'q.name',
|
137 | | - 'owner' => 'COALESCE(u.realname, u.name)',
|
138 | | - 'creator' => 'COALESCE(u2.realname, u2.name)',
|
139 | | - 'lastupdated' => 't.lastupdated',
|
140 | | - 'created' => 't.created',
|
141 | | - 'resolved' => 't.resolved',
|
142 | | - );
|
143 | | - if ( array_key_exists( 'ob', $args ) ) {
|
144 | | - $orderby = 'ORDER BY';
|
145 | | - $orderbyargs = trim( strtolower( $args['ob'] ) );
|
146 | | - foreach ( preg_split( '/\s*,\s*/', $orderbyargs ) as $word ) {
|
147 | | - $oldlen = strlen( $word );
|
148 | | - $word = ltrim( $word, '!' );
|
149 | | - $mod = $oldlen !== strlen( $word ) ? ' DESC' : '';
|
150 | | - if ( !preg_match( '/^\w+$/', $word ) ) {
|
151 | | - die ( wfMsg ( 'rt-badorderby', $word ) );
|
152 | | - }
|
153 | | - if ( array_key_exists( $word, $valid_orderby ) ) {
|
154 | | - $word = $valid_orderby[$word];
|
155 | | - }
|
156 | | - else if ( !preg_match ( '/^\d+$/', $word ) ) {
|
157 | | - die ( wfMsg ( 'rt-badorderby', $word ) );
|
158 | | - }
|
159 | | - $orderby .= " $word$mod,";
|
160 | | - }
|
161 | | - $orderby = rtrim( $orderby, ',' );
|
162 | | - }
|
163 | | -
|
164 | | - // Determine what status to use. Default is new and open:
|
165 | | - $searchstatus = "AND t.status IN ('new','open')";
|
166 | | - $valid_status = array( 'new', 'open', 'resolved', 'deleted', 'stalled', 'rejected' );
|
167 | | - if ( array_key_exists( 's', $args ) ) {
|
168 | | - $statusargs = trim( strtolower( $args['s'] ) );
|
169 | | - if ( $statusargs === 'all' ) {
|
170 | | - $searchstatus = '';
|
171 | | - }
|
172 | | - else {
|
173 | | - $searchstatus = 'AND t.status IN (';
|
174 | | - foreach ( preg_split( '/\s*,\s*/', $statusargs ) as $word ) {
|
175 | | - if ( !in_array( $word, $valid_status ) ) {
|
176 | | - die ( wfMsg ( 'rt-badstatus', $word ) );
|
177 | | - }
|
178 | | - $searchstatus .= "'$word',";
|
179 | | - }
|
180 | | - $searchstatus = preg_replace( '/.$/', ')', $searchstatus );
|
181 | | - }
|
182 | | - }
|
183 | | -
|
184 | | - // See if we are limiting to one or more queues
|
185 | | - $searchq = '';
|
186 | | - if ( array_key_exists( 'q', $args ) ) {
|
187 | | - $qargs = trim( strtolower( $args['q'] ) );
|
188 | | - $searchq = 'AND LOWER(q.name) IN (';
|
189 | | - foreach ( preg_split( '/\s*,\s*/', $qargs ) as $word ) {
|
190 | | - $word = trim( $word );
|
191 | | - if ( !preg_match( '/^[\w \.-]+$/', $word ) ) {
|
192 | | - die ( wfMsg ( 'rt-badqueue', $word ) );
|
193 | | - }
|
194 | | - $searchq .= "'$word',";
|
195 | | - }
|
196 | | - $searchq = preg_replace( '/.$/', ')', $searchq );
|
197 | | - }
|
198 | | -
|
199 | | - // See if we are limiting to one or more owners
|
200 | | - $searchowner = '';
|
201 | | - if ( array_key_exists( 'o', $args ) ) {
|
202 | | - $oargs = trim( strtolower( $args['o'] ) );
|
203 | | - $searchowner = 'AND LOWER(u.name) IN (';
|
204 | | - foreach ( preg_split( '/\s*,\s*/', $oargs ) as $word ) {
|
205 | | - $word = trim( $word );
|
206 | | - if ( !preg_match( '/^[\w\@\.\-\:\/]+$/', $word ) ) {
|
207 | | - die ( wfMsg ( 'rt-badowner', $word ) );
|
208 | | - }
|
209 | | - $searchowner .= "'$word',";
|
210 | | - }
|
211 | | - $searchowner = preg_replace( '/.$/', ')', $searchowner );
|
212 | | - }
|
213 | | -
|
214 | | - // Build and run the final query
|
215 | | - $SQL = "$ticketquery $searchq $searchowner $searchstatus $orderby $limit";
|
216 | | - $res = pg_query( $dbh, $SQL );
|
217 | | - if ( !$res ) {
|
218 | | - die ( wfMsg( 'rt-badquery' ) );
|
219 | | - }
|
220 | | - $info = pg_fetch_all( $res );
|
221 | | - if ( !$info ) {
|
222 | | - $msg = wfMsg( 'rt-nomatches' );
|
223 | | - return "<table class='rt-table-empty' border='1'><tr><th>$msg</th><tr></table>";
|
224 | | - }
|
225 | | -
|
226 | | - // Figure out what columns to show
|
227 | | - // Anything specifically requested is shown
|
228 | | - // Everything else is either on or off by default, but can be overidden
|
229 | | - $output = '';
|
230 | | -
|
231 | | - // The queue: show by default unless searching a single queue
|
232 | | - $showqueue = 1;
|
233 | | - if ( array_key_exists( 'noqueue', $args )
|
234 | | - || ( $searchq
|
235 | | - && false === strpos( $searchq, ',' )
|
236 | | - && !array_key_exists( 'queue', $args ) ) ) {
|
237 | | - $showqueue = 0;
|
238 | | - }
|
239 | | -
|
240 | | - // The owner: show by default unless searching a single owner
|
241 | | - $showowner = 1;
|
242 | | - if ( array_key_exists( 'noowner', $args )
|
243 | | - || ( $searchowner
|
244 | | - && false === strpos( $searchowner, ',' )
|
245 | | - && !array_key_exists( 'owner', $args ) ) ) {
|
246 | | - $showowner = 0;
|
247 | | - }
|
248 | | -
|
249 | | - // The status: show by default unless searching a single status
|
250 | | - $showstatus = 1;
|
251 | | - if ( array_key_exists( 'nostatus', $args )
|
252 | | - || ( false === strpos( $searchstatus, ',' )
|
253 | | - && !array_key_exists( 'status', $args ) ) ) {
|
254 | | - $showstatus = 0;
|
255 | | - }
|
256 | | -
|
257 | | - // Things we always show unless told not to:
|
258 | | - $showsubject = ! array_key_exists( 'nosubject', $args );
|
259 | | - $showupdated = ! array_key_exists( 'noupdated', $args );
|
260 | | - $showticket = ! array_key_exists( 'noticket', $args );
|
261 | | -
|
262 | | - // Things we don't show unless asked to:
|
263 | | - $showpriority = array_key_exists( 'priority', $args );
|
264 | | - $showupdated2 = array_key_exists( 'updated2', $args );
|
265 | | - $showcreated = array_key_exists( 'created', $args );
|
266 | | - $showcreated2 = array_key_exists( 'created2', $args );
|
267 | | - $showresolved = array_key_exists( 'resolved', $args );
|
268 | | - $showresolved2 = array_key_exists( 'resolved2', $args );
|
269 | | - $showage = array_key_exists( 'age', $args );
|
270 | | -
|
271 | | - // Unless 'tablerows' has been set, output the table and header tags
|
272 | | - if ( !array_key_exists( 'tablerows', $args ) ) {
|
273 | | -
|
274 | | - $output = "<table class='rt-table' border='1'><tr>";
|
275 | | -
|
276 | | - if ( $showticket ) { $output .= '<th>Ticket</th>'; }
|
277 | | - if ( $showqueue ) { $output .= '<th>Queue</th>'; }
|
278 | | - if ( $showsubject ) { $output .= '<th>Subject</th>'; }
|
279 | | - if ( $showstatus ) { $output .= '<th>Status</th>'; }
|
280 | | - if ( $showpriority ) { $output .= '<th>Priority</th>'; }
|
281 | | - if ( $showowner ) { $output .= '<th>Owner</th>'; }
|
282 | | - if ( $showupdated ) { $output .= '<th>Last updated</th>'; }
|
283 | | - if ( $showupdated2 ) { $output .= '<th>Last updated</th>'; }
|
284 | | - if ( $showcreated ) { $output .= '<th>Created</th>'; }
|
285 | | - if ( $showcreated2 ) { $output .= '<th>Created</th>'; }
|
286 | | - if ( $showresolved ) { $output .= '<th>Resolved</th>'; }
|
287 | | - if ( $showresolved2 ) { $output .= '<th>Resolved</th>'; }
|
288 | | - if ( $showage ) { $output .= '<th>Age</th>'; }
|
289 | | -
|
290 | | - $output .= '</tr>';
|
291 | | - }
|
292 | | -
|
293 | | - foreach ( $info as $row ) {
|
294 | | -
|
295 | | - if ( $showticket ) {
|
296 | | - $id = self::fancyLink( $row, $args, $parser, 1 );
|
297 | | - $output .= "<td style='white-space: nowrap'>$id</td>";
|
298 | | - }
|
299 | | - if ( $showqueue ) { $output .= '<td>' . htmlspecialchars( $row['queue'] ) . '</td>'; }
|
300 | | - if ( $showsubject ) { $output .= '<td>' . htmlspecialchars( $row['subject'] ) . '</td>'; }
|
301 | | - if ( $showstatus ) { $output .= '<td>' . htmlspecialchars( $row['status'] ) . '</td>'; }
|
302 | | - if ( $showpriority ) { $output .= '<td>' . htmlspecialchars( $row['priority'] ) . '</td>'; }
|
303 | | - if ( $showowner ) { $output .= '<td>' . htmlspecialchars( $row['owner'] ) . '</td>'; }
|
304 | | - if ( $showupdated ) { $output .= '<td>' . $row['lastupdated'] . '</td>'; }
|
305 | | - if ( $showupdated2 ) { $output .= '<td>' . $row['lastupdated2'] . '</td>'; }
|
306 | | - if ( $showcreated ) { $output .= '<td>' . $row['created'] . '</td>'; }
|
307 | | - if ( $showcreated2 ) { $output .= '<td>' . $row['created2'] . '</td>'; }
|
308 | | - if ( $showresolved ) { $output .= '<td>' . $row['resolved'] . '</td>'; }
|
309 | | - if ( $showresolved2 ) { $output .= '<td>' . $row['resolved2'] . '</td>'; }
|
310 | | - if ( $showage ) { $output .= '<td>' . $row['age'] . '</td>'; }
|
311 | | - $output .= '<tr>';
|
312 | | - }
|
313 | | -
|
314 | | - if ( !array_key_exists( 'tablerows', $args ) ) {
|
315 | | - $output .= '</table>';
|
316 | | - }
|
317 | | -
|
318 | | - return $output;
|
319 | | - }
|
320 | | -
|
321 | | - private static function fancyLink( $row, $args, $parser, $istable ) {
|
322 | | -
|
323 | | - global $wgRequestTracker_URL, $wgRequestTracker_Formats, $wgRequestTracker_Useballoons;
|
324 | | -
|
325 | | - $ticketnum = $row['id'];
|
326 | | - $ret = "[$wgRequestTracker_URL=$ticketnum RT #$ticketnum]";
|
327 | | -
|
328 | | - # Check for any custom format args in the rt tag.
|
329 | | - # If any are found, use that and ignore any other args
|
330 | | - $foundformat = 0;
|
331 | | - foreach ( array_keys( $args ) as $val ) {
|
332 | | - if ( array_key_exists( $val, $wgRequestTracker_Formats ) ) {
|
333 | | - $format = $wgRequestTracker_Formats[$val];
|
334 | | - foreach ( array_keys( $row ) as $rev ) {
|
335 | | - $format = str_replace( "?$rev?", "$row[$rev]", $format );
|
336 | | - }
|
337 | | - $ret .= " $format";
|
338 | | - $foundformat = 1;
|
339 | | - break;
|
340 | | - }
|
341 | | - }
|
342 | | -
|
343 | | - # Process any column-based args to the rt tag
|
344 | | - if ( !$foundformat and !$istable ) {
|
345 | | - foreach ( array_keys( $args ) as $val ) {
|
346 | | - if ( array_key_exists( $val, $row ) ) {
|
347 | | - $format = $args[$val];
|
348 | | - if ( false === strpos( $format, '?' ) ) {
|
349 | | - $showname = $val === 'lastupdated' ? 'Last updated' : ucfirst( $val );
|
350 | | - $ret .= " $showname: $row[$val]";
|
351 | | - }
|
352 | | - else {
|
353 | | - $ret .= " " . str_replace( '?', $row[$val], $format );
|
354 | | - }
|
355 | | - }
|
356 | | - }
|
357 | | - }
|
358 | | -
|
359 | | - $ret = $parser->recursiveTagParse( $ret );
|
360 | | -
|
361 | | - // Not using balloons? Just return the current text
|
362 | | - if ( !$wgRequestTracker_Useballoons || array_key_exists( 'noballoon', $args ) ) {
|
363 | | - return "<span class='rt-ticket-noballoon'>$ret</span>";
|
364 | | - }
|
365 | | -
|
366 | | - $safesub = preg_replace( '/\"/', '\"', $row['subject'] );
|
367 | | - $safesub = preg_replace( '/\'/', "\'", $safesub );
|
368 | | - $safesub = htmlspecialchars( $safesub );
|
369 | | -
|
370 | | - $safeowner = $row['owner'];
|
371 | | - if ( $row['owner'] !== $row['username'] ) {
|
372 | | - $safeowner .= " ($row[username])";
|
373 | | - }
|
374 | | - $safeowner = preg_replace( '/\"/', '\"', $safeowner );
|
375 | | - $safeowner = preg_replace( '/\'/', "\'", $safeowner );
|
376 | | - $safeowner = htmlspecialchars( $safeowner );
|
377 | | -
|
378 | | - $safeq = preg_replace( '/\"/', '\"', $row['queue'] );
|
379 | | - $safeq = preg_replace( '/\'/', "\'", $safeq );
|
380 | | - $safeq = htmlspecialchars( $safeq );
|
381 | | -
|
382 | | - $text = "RT #<b>$ticketnum</b>";
|
383 | | - $text .= "<br />Status: <b>$row[status]</b>";
|
384 | | - $text .= "<br />Subject: <b>$safesub</b>";
|
385 | | - $text .= "<br />Owner: <b>$safeowner</b>";
|
386 | | - $text .= "<br />Queue: <b>$safeq</b>";
|
387 | | - $text .= "<br />Created: <b>$row[created]</b>";
|
388 | | - if ( $row['status'] === 'Resolved' ) {
|
389 | | - $text .= "<br />Resolved: <b>$row[resolved]</b>";
|
390 | | - }
|
391 | | - else {
|
392 | | - $text .= "<br />Last updated: <b>$row[lastupdated]</b>";
|
393 | | - }
|
394 | | -
|
395 | | - # Prepare some balloon-tek
|
396 | | - $link = isset( $args['link'] ) ? $args['link'] : '';
|
397 | | - $target = isset( $args['target'] ) ? $args['target'] : '';
|
398 | | - $sticky = isset( $args['sticky'] ) ? $args['sticky'] : '0';
|
399 | | - $width = isset( $args['width'] ) ? $args['width'] : '0';
|
400 | | -
|
401 | | - $event = isset( $args['click'] ) && $args['click'] && !$link ? 'onclick' : 'onmouseover';
|
402 | | - $event2 = '';
|
403 | | - $event = "$event=\"balloon.showTooltip(event,'${text}',${sticky},${width})\"";
|
404 | | -
|
405 | | - if ( preg_match( '/onclick/', $event ) && $args['hover'] ) {
|
406 | | - $event2 = " onmouseover=\"balloon.showTooltip(event,'" . $args['hover'] . "',0,${width})\"";
|
407 | | - }
|
408 | | -
|
409 | | - $has_style = isset( $args['style'] ) && $args['style'];
|
410 | | - $style = "style=\"" . ( $has_style ? $args['style'] . ";cursor:pointer\"" : "cursor:pointer\"" );
|
411 | | - $target = $target ? "target=${target}" : '';
|
412 | | - $output = "<span class='rt-ticket' ${event} ${event2} ${style}>$ret</span>";
|
413 | | -
|
414 | | - return $output;
|
415 | | - }
|
| 2 | +<?php |
| 3 | + |
| 4 | +class RT { |
| 5 | + |
| 6 | + /** |
| 7 | + * Register the hook with ParserFirstCallInit |
| 8 | + */ |
| 9 | + public static function registerHook( &$parser ) { |
| 10 | + $parser->setHook( 'rt', array( 'RT::render' ) ); |
| 11 | + return true; |
| 12 | + } |
| 13 | + |
| 14 | + // This is called to process <rt>...</rt> within a page |
| 15 | + public static function render( $input, $args = array(), $parser = null ) { |
| 16 | + |
| 17 | + global $wgRequestTracker_Cachepage, $wgRequestTracker_Active, $wgRequestTracker_DBconn, |
| 18 | + $wgRequestTracker_TIMEFORMAT_LASTUPDATED, |
| 19 | + $wgRequestTracker_TIMEFORMAT_LASTUPDATED2, |
| 20 | + $wgRequestTracker_TIMEFORMAT_CREATED, |
| 21 | + $wgRequestTracker_TIMEFORMAT_CREATED2, |
| 22 | + $wgRequestTracker_TIMEFORMAT_RESOLVED, |
| 23 | + $wgRequestTracker_TIMEFORMAT_RESOLVED2, |
| 24 | + $wgRequestTracker_TIMEFORMAT_NOW; |
| 25 | + |
| 26 | + wfLoadExtensionMessages( 'RT' ); |
| 27 | + |
| 28 | + // Grab the number if one was given between the <tr> tags |
| 29 | + $ticketnum = 0; |
| 30 | + $matches = array(); |
| 31 | + if ( preg_match( '/^\s*(\d+)\s*$/', $input, $matches ) ) { |
| 32 | + $ticketnum = $matches[0]; |
| 33 | + } |
| 34 | + |
| 35 | + // Disable all caching unless told not to |
| 36 | + if ( !$wgRequestTracker_Cachepage ) { |
| 37 | + $parser->disableCache(); |
| 38 | + } |
| 39 | + |
| 40 | + // Try and connect to the database if we are active |
| 41 | + if ( $wgRequestTracker_Active ) { |
| 42 | + global $wgUser; |
| 43 | + $dbh = pg_connect( $wgRequestTracker_DBconn ); |
| 44 | + if ( $dbh == false ) { |
| 45 | + wfDebug( "DB connection error\n" ); |
| 46 | + wfDebug( "Connection string: $wgRequestTracker_DBconn\n" ); |
| 47 | + $wgRequestTracker_Active = 0; |
| 48 | + } |
| 49 | + $tz = $wgUser->getOption( 'timecorrection' ); |
| 50 | + if ( $tz ) { |
| 51 | + $found = array(); |
| 52 | + if ( preg_match ( '/((-?\d\d?):(\d\d))/', $tz, $found ) ) { |
| 53 | + if ( $found[3] === '00' ) { |
| 54 | + pg_query( "SET TIME ZONE $found[2]" ); |
| 55 | + } |
| 56 | + else { |
| 57 | + print( "SET TIME ZONE INTERVAL '$found[1]' HOUR TO MINUTE" ); |
| 58 | + } |
| 59 | + } |
| 60 | + } |
| 61 | + } |
| 62 | + |
| 63 | + // If we are not 'active', we leave right away, with minimal output |
| 64 | + if ( !$wgRequestTracker_Active ) { |
| 65 | + if ( $ticketnum ) { |
| 66 | + return "<span class='rt-ticket-inactive'>RT #$ticketnum</span>"; |
| 67 | + } |
| 68 | + $msg = wfMsg( 'rt-inactive' ); |
| 69 | + return "<table class='rt-table-inactive' border='1'><tr><td>$msg</td></tr></table>"; |
| 70 | + } |
| 71 | + |
| 72 | + // Standard info we gather |
| 73 | + $TZ = "AT TIME ZONE 'GMT'"; |
| 74 | + $ticketinfo = 't.id, t.subject, t.priority, INITCAP(t.status) AS status, q.name AS queue,' |
| 75 | + . ' COALESCE(u.realname, u.name) AS owner,' |
| 76 | + . ' u.name AS username,' |
| 77 | + . ' COALESCE(u2.realname, u2.name) AS creator,' |
| 78 | + . " TO_CHAR(t.lastupdated $TZ, '$wgRequestTracker_TIMEFORMAT_LASTUPDATED'::text) AS lastupdated," |
| 79 | + . " TO_CHAR(t.lastupdated $TZ, '$wgRequestTracker_TIMEFORMAT_LASTUPDATED2'::text) AS lastupdated2," |
| 80 | + . " TO_CHAR(now() $TZ, '$wgRequestTracker_TIMEFORMAT_NOW'::text) AS nowtime," |
| 81 | + . " TO_CHAR(t.created $TZ, '$wgRequestTracker_TIMEFORMAT_CREATED'::text) AS created," |
| 82 | + . " TO_CHAR(t.created $TZ, '$wgRequestTracker_TIMEFORMAT_CREATED2'::text) AS created2," |
| 83 | + . " TO_CHAR(t.resolved $TZ, '$wgRequestTracker_TIMEFORMAT_RESOLVED'::text) AS resolved," |
| 84 | + . " TO_CHAR(t.resolved $TZ, '$wgRequestTracker_TIMEFORMAT_RESOLVED2'::text) AS resolved2," |
| 85 | + . " CASE WHEN (now() $TZ - t.created) <= '1 second'::interval THEN '1 second' ELSE" |
| 86 | + . " CASE WHEN (now() $TZ - t.created) <= '2 minute'::interval THEN EXTRACT(seconds FROM now() $TZ - t.created) || ' seconds' ELSE" |
| 87 | + . " CASE WHEN (now() $TZ - t.created) <= '2 hour'::interval THEN EXTRACT(minutes FROM now() $TZ - t.created) || ' minutes' ELSE" |
| 88 | + . " CASE WHEN (now() $TZ - t.created) <= '2 day'::interval THEN EXTRACT(hours FROM now() $TZ - t.created) || ' hours' ELSE" |
| 89 | + . " EXTRACT(days FROM now() $TZ - t.created) || ' days' END END END END AS age"; |
| 90 | + |
| 91 | + // The standard query |
| 92 | + $ticketquery = "SELECT $ticketinfo FROM tickets t" |
| 93 | + . ' JOIN users u ON t.owner = u.id' |
| 94 | + . ' JOIN users u2 ON t.creator = u2.id' |
| 95 | + . ' JOIN queues q ON t.queue = q.id'; |
| 96 | + |
| 97 | + // If just a single number, treat it as <rt>#</rt> |
| 98 | + if ( 1 === count( $args ) ) { |
| 99 | + if ( preg_match( '/^\d+$/', key( $args ) ) ) { |
| 100 | + $ticketnum = key( $args ); |
| 101 | + } |
| 102 | + } |
| 103 | + |
| 104 | + // Look up a single ticket number |
| 105 | + if ( $ticketnum ) { |
| 106 | + $SQL = "$ticketquery AND t.id = $ticketnum"; |
| 107 | + $res = pg_query( $dbh, $SQL ); |
| 108 | + if ( !$res ) { |
| 109 | + die ( wfMsg( 'rt-badquery' ) ); |
| 110 | + } |
| 111 | + $info = pg_fetch_array( $res ); |
| 112 | + if ( !$info ) { |
| 113 | + return "<span class='rt-nosuchticket'>RT #$ticketnum</span>"; |
| 114 | + } |
| 115 | + return self::fancyLink( $info, $args, $parser, 0 ); |
| 116 | + } |
| 117 | + |
| 118 | + // Add in a LIMIT clause if l=xx was used |
| 119 | + $limit = ''; |
| 120 | + if ( array_key_exists( 'l', $args ) ) { |
| 121 | + $limit = trim( $args['l'] ); |
| 122 | + if ( !preg_match( '/^ *\d+ *$/', $limit ) ) { |
| 123 | + die ( wfMsg ( 'rt-badlimit', $limit ) ); |
| 124 | + } |
| 125 | + $limit = " LIMIT $limit"; |
| 126 | + } |
| 127 | + |
| 128 | + // Change the default ORDER BY clause if ob=xx was used |
| 129 | + $orderby = 'ORDER BY t.lastupdated DESC, t.id'; |
| 130 | + $valid_orderby = array |
| 131 | + ( |
| 132 | + 'id' => 't.id', |
| 133 | + 'subject' => 't.subject', |
| 134 | + 'priority' => 't.priority', |
| 135 | + 'status' => 't.status', |
| 136 | + 'queue' => 'q.name', |
| 137 | + 'owner' => 'COALESCE(u.realname, u.name)', |
| 138 | + 'creator' => 'COALESCE(u2.realname, u2.name)', |
| 139 | + 'lastupdated' => 't.lastupdated', |
| 140 | + 'created' => 't.created', |
| 141 | + 'resolved' => 't.resolved', |
| 142 | + ); |
| 143 | + if ( array_key_exists( 'ob', $args ) ) { |
| 144 | + $orderby = 'ORDER BY'; |
| 145 | + $orderbyargs = trim( strtolower( $args['ob'] ) ); |
| 146 | + foreach ( preg_split( '/\s*,\s*/', $orderbyargs ) as $word ) { |
| 147 | + $oldlen = strlen( $word ); |
| 148 | + $word = ltrim( $word, '!' ); |
| 149 | + $mod = $oldlen !== strlen( $word ) ? ' DESC' : ''; |
| 150 | + if ( !preg_match( '/^\w+$/', $word ) ) { |
| 151 | + die ( wfMsg ( 'rt-badorderby', $word ) ); |
| 152 | + } |
| 153 | + if ( array_key_exists( $word, $valid_orderby ) ) { |
| 154 | + $word = $valid_orderby[$word]; |
| 155 | + } |
| 156 | + else if ( !preg_match ( '/^\d+$/', $word ) ) { |
| 157 | + die ( wfMsg ( 'rt-badorderby', $word ) ); |
| 158 | + } |
| 159 | + $orderby .= " $word$mod,"; |
| 160 | + } |
| 161 | + $orderby = rtrim( $orderby, ',' ); |
| 162 | + } |
| 163 | + |
| 164 | + // Determine what status to use. Default is new and open: |
| 165 | + $searchstatus = "AND t.status IN ('new','open')"; |
| 166 | + $valid_status = array( 'new', 'open', 'resolved', 'deleted', 'stalled', 'rejected' ); |
| 167 | + if ( array_key_exists( 's', $args ) ) { |
| 168 | + $statusargs = trim( strtolower( $args['s'] ) ); |
| 169 | + if ( $statusargs === 'all' ) { |
| 170 | + $searchstatus = ''; |
| 171 | + } |
| 172 | + else { |
| 173 | + $searchstatus = 'AND t.status IN ('; |
| 174 | + foreach ( preg_split( '/\s*,\s*/', $statusargs ) as $word ) { |
| 175 | + if ( !in_array( $word, $valid_status ) ) { |
| 176 | + die ( wfMsg ( 'rt-badstatus', $word ) ); |
| 177 | + } |
| 178 | + $searchstatus .= "'$word',"; |
| 179 | + } |
| 180 | + $searchstatus = preg_replace( '/.$/', ')', $searchstatus ); |
| 181 | + } |
| 182 | + } |
| 183 | + |
| 184 | + // See if we are limiting to one or more queues |
| 185 | + $searchq = ''; |
| 186 | + if ( array_key_exists( 'q', $args ) ) { |
| 187 | + $qargs = trim( strtolower( $args['q'] ) ); |
| 188 | + $searchq = 'AND LOWER(q.name) IN ('; |
| 189 | + foreach ( preg_split( '/\s*,\s*/', $qargs ) as $word ) { |
| 190 | + $word = trim( $word ); |
| 191 | + if ( !preg_match( '/^[\w \.-]+$/', $word ) ) { |
| 192 | + die ( wfMsg ( 'rt-badqueue', $word ) ); |
| 193 | + } |
| 194 | + $searchq .= "'$word',"; |
| 195 | + } |
| 196 | + $searchq = preg_replace( '/.$/', ')', $searchq ); |
| 197 | + } |
| 198 | + |
| 199 | + // See if we are limiting to one or more owners |
| 200 | + $searchowner = ''; |
| 201 | + if ( array_key_exists( 'o', $args ) ) { |
| 202 | + $oargs = trim( strtolower( $args['o'] ) ); |
| 203 | + $searchowner = 'AND LOWER(u.name) IN ('; |
| 204 | + foreach ( preg_split( '/\s*,\s*/', $oargs ) as $word ) { |
| 205 | + $word = trim( $word ); |
| 206 | + if ( !preg_match( '/^[\w\@\.\-\:\/]+$/', $word ) ) { |
| 207 | + die ( wfMsg ( 'rt-badowner', $word ) ); |
| 208 | + } |
| 209 | + $searchowner .= "'$word',"; |
| 210 | + } |
| 211 | + $searchowner = preg_replace( '/.$/', ')', $searchowner ); |
| 212 | + } |
| 213 | + |
| 214 | + // Build and run the final query |
| 215 | + $SQL = "$ticketquery $searchq $searchowner $searchstatus $orderby $limit"; |
| 216 | + $res = pg_query( $dbh, $SQL ); |
| 217 | + if ( !$res ) { |
| 218 | + die ( wfMsg( 'rt-badquery' ) ); |
| 219 | + } |
| 220 | + $info = pg_fetch_all( $res ); |
| 221 | + if ( !$info ) { |
| 222 | + $msg = wfMsg( 'rt-nomatches' ); |
| 223 | + return "<table class='rt-table-empty' border='1'><tr><th>$msg</th><tr></table>"; |
| 224 | + } |
| 225 | + |
| 226 | + // Figure out what columns to show |
| 227 | + // Anything specifically requested is shown |
| 228 | + // Everything else is either on or off by default, but can be overidden |
| 229 | + $output = ''; |
| 230 | + |
| 231 | + // The queue: show by default unless searching a single queue |
| 232 | + $showqueue = 1; |
| 233 | + if ( array_key_exists( 'noqueue', $args ) |
| 234 | + || ( $searchq |
| 235 | + && false === strpos( $searchq, ',' ) |
| 236 | + && !array_key_exists( 'queue', $args ) ) ) { |
| 237 | + $showqueue = 0; |
| 238 | + } |
| 239 | + |
| 240 | + // The owner: show by default unless searching a single owner |
| 241 | + $showowner = 1; |
| 242 | + if ( array_key_exists( 'noowner', $args ) |
| 243 | + || ( $searchowner |
| 244 | + && false === strpos( $searchowner, ',' ) |
| 245 | + && !array_key_exists( 'owner', $args ) ) ) { |
| 246 | + $showowner = 0; |
| 247 | + } |
| 248 | + |
| 249 | + // The status: show by default unless searching a single status |
| 250 | + $showstatus = 1; |
| 251 | + if ( array_key_exists( 'nostatus', $args ) |
| 252 | + || ( false === strpos( $searchstatus, ',' ) |
| 253 | + && !array_key_exists( 'status', $args ) ) ) { |
| 254 | + $showstatus = 0; |
| 255 | + } |
| 256 | + |
| 257 | + // Things we always show unless told not to: |
| 258 | + $showsubject = ! array_key_exists( 'nosubject', $args ); |
| 259 | + $showupdated = ! array_key_exists( 'noupdated', $args ); |
| 260 | + $showticket = ! array_key_exists( 'noticket', $args ); |
| 261 | + |
| 262 | + // Things we don't show unless asked to: |
| 263 | + $showpriority = array_key_exists( 'priority', $args ); |
| 264 | + $showupdated2 = array_key_exists( 'updated2', $args ); |
| 265 | + $showcreated = array_key_exists( 'created', $args ); |
| 266 | + $showcreated2 = array_key_exists( 'created2', $args ); |
| 267 | + $showresolved = array_key_exists( 'resolved', $args ); |
| 268 | + $showresolved2 = array_key_exists( 'resolved2', $args ); |
| 269 | + $showage = array_key_exists( 'age', $args ); |
| 270 | + |
| 271 | + // Unless 'tablerows' has been set, output the table and header tags |
| 272 | + if ( !array_key_exists( 'tablerows', $args ) ) { |
| 273 | + |
| 274 | + $output = "<table class='rt-table' border='1'><tr>"; |
| 275 | + |
| 276 | + if ( $showticket ) { $output .= '<th>Ticket</th>'; } |
| 277 | + if ( $showqueue ) { $output .= '<th>Queue</th>'; } |
| 278 | + if ( $showsubject ) { $output .= '<th>Subject</th>'; } |
| 279 | + if ( $showstatus ) { $output .= '<th>Status</th>'; } |
| 280 | + if ( $showpriority ) { $output .= '<th>Priority</th>'; } |
| 281 | + if ( $showowner ) { $output .= '<th>Owner</th>'; } |
| 282 | + if ( $showupdated ) { $output .= '<th>Last updated</th>'; } |
| 283 | + if ( $showupdated2 ) { $output .= '<th>Last updated</th>'; } |
| 284 | + if ( $showcreated ) { $output .= '<th>Created</th>'; } |
| 285 | + if ( $showcreated2 ) { $output .= '<th>Created</th>'; } |
| 286 | + if ( $showresolved ) { $output .= '<th>Resolved</th>'; } |
| 287 | + if ( $showresolved2 ) { $output .= '<th>Resolved</th>'; } |
| 288 | + if ( $showage ) { $output .= '<th>Age</th>'; } |
| 289 | + |
| 290 | + $output .= '</tr>'; |
| 291 | + } |
| 292 | + |
| 293 | + foreach ( $info as $row ) { |
| 294 | + |
| 295 | + if ( $showticket ) { |
| 296 | + $id = self::fancyLink( $row, $args, $parser, 1 ); |
| 297 | + $output .= "<td style='white-space: nowrap'>$id</td>"; |
| 298 | + } |
| 299 | + if ( $showqueue ) { $output .= '<td>' . htmlspecialchars( $row['queue'] ) . '</td>'; } |
| 300 | + if ( $showsubject ) { $output .= '<td>' . htmlspecialchars( $row['subject'] ) . '</td>'; } |
| 301 | + if ( $showstatus ) { $output .= '<td>' . htmlspecialchars( $row['status'] ) . '</td>'; } |
| 302 | + if ( $showpriority ) { $output .= '<td>' . htmlspecialchars( $row['priority'] ) . '</td>'; } |
| 303 | + if ( $showowner ) { $output .= '<td>' . htmlspecialchars( $row['owner'] ) . '</td>'; } |
| 304 | + if ( $showupdated ) { $output .= '<td>' . $row['lastupdated'] . '</td>'; } |
| 305 | + if ( $showupdated2 ) { $output .= '<td>' . $row['lastupdated2'] . '</td>'; } |
| 306 | + if ( $showcreated ) { $output .= '<td>' . $row['created'] . '</td>'; } |
| 307 | + if ( $showcreated2 ) { $output .= '<td>' . $row['created2'] . '</td>'; } |
| 308 | + if ( $showresolved ) { $output .= '<td>' . $row['resolved'] . '</td>'; } |
| 309 | + if ( $showresolved2 ) { $output .= '<td>' . $row['resolved2'] . '</td>'; } |
| 310 | + if ( $showage ) { $output .= '<td>' . $row['age'] . '</td>'; } |
| 311 | + $output .= '<tr>'; |
| 312 | + } |
| 313 | + |
| 314 | + if ( !array_key_exists( 'tablerows', $args ) ) { |
| 315 | + $output .= '</table>'; |
| 316 | + } |
| 317 | + |
| 318 | + return $output; |
| 319 | + } |
| 320 | + |
| 321 | + private static function fancyLink( $row, $args, $parser, $istable ) { |
| 322 | + |
| 323 | + global $wgRequestTracker_URL, $wgRequestTracker_Formats, $wgRequestTracker_Useballoons; |
| 324 | + |
| 325 | + $ticketnum = $row['id']; |
| 326 | + $ret = "[$wgRequestTracker_URL=$ticketnum RT #$ticketnum]"; |
| 327 | + |
| 328 | + # Check for any custom format args in the rt tag. |
| 329 | + # If any are found, use that and ignore any other args |
| 330 | + $foundformat = 0; |
| 331 | + foreach ( array_keys( $args ) as $val ) { |
| 332 | + if ( array_key_exists( $val, $wgRequestTracker_Formats ) ) { |
| 333 | + $format = $wgRequestTracker_Formats[$val]; |
| 334 | + foreach ( array_keys( $row ) as $rev ) { |
| 335 | + $format = str_replace( "?$rev?", "$row[$rev]", $format ); |
| 336 | + } |
| 337 | + $ret .= " $format"; |
| 338 | + $foundformat = 1; |
| 339 | + break; |
| 340 | + } |
| 341 | + } |
| 342 | + |
| 343 | + # Process any column-based args to the rt tag |
| 344 | + if ( !$foundformat and !$istable ) { |
| 345 | + foreach ( array_keys( $args ) as $val ) { |
| 346 | + if ( array_key_exists( $val, $row ) ) { |
| 347 | + $format = $args[$val]; |
| 348 | + if ( false === strpos( $format, '?' ) ) { |
| 349 | + $showname = $val === 'lastupdated' ? 'Last updated' : ucfirst( $val ); |
| 350 | + $ret .= " $showname: $row[$val]"; |
| 351 | + } |
| 352 | + else { |
| 353 | + $ret .= " " . str_replace( '?', $row[$val], $format ); |
| 354 | + } |
| 355 | + } |
| 356 | + } |
| 357 | + } |
| 358 | + |
| 359 | + $ret = $parser->recursiveTagParse( $ret ); |
| 360 | + |
| 361 | + // Not using balloons? Just return the current text |
| 362 | + if ( !$wgRequestTracker_Useballoons || array_key_exists( 'noballoon', $args ) ) { |
| 363 | + return "<span class='rt-ticket-noballoon'>$ret</span>"; |
| 364 | + } |
| 365 | + |
| 366 | + $safesub = preg_replace( '/\"/', '\"', $row['subject'] ); |
| 367 | + $safesub = preg_replace( '/\'/', "\'", $safesub ); |
| 368 | + $safesub = htmlspecialchars( $safesub ); |
| 369 | + |
| 370 | + $safeowner = $row['owner']; |
| 371 | + if ( $row['owner'] !== $row['username'] ) { |
| 372 | + $safeowner .= " ($row[username])"; |
| 373 | + } |
| 374 | + $safeowner = preg_replace( '/\"/', '\"', $safeowner ); |
| 375 | + $safeowner = preg_replace( '/\'/', "\'", $safeowner ); |
| 376 | + $safeowner = htmlspecialchars( $safeowner ); |
| 377 | + |
| 378 | + $safeq = preg_replace( '/\"/', '\"', $row['queue'] ); |
| 379 | + $safeq = preg_replace( '/\'/', "\'", $safeq ); |
| 380 | + $safeq = htmlspecialchars( $safeq ); |
| 381 | + |
| 382 | + $text = "RT #<b>$ticketnum</b>"; |
| 383 | + $text .= "<br />Status: <b>$row[status]</b>"; |
| 384 | + $text .= "<br />Subject: <b>$safesub</b>"; |
| 385 | + $text .= "<br />Owner: <b>$safeowner</b>"; |
| 386 | + $text .= "<br />Queue: <b>$safeq</b>"; |
| 387 | + $text .= "<br />Created: <b>$row[created]</b>"; |
| 388 | + if ( $row['status'] === 'Resolved' ) { |
| 389 | + $text .= "<br />Resolved: <b>$row[resolved]</b>"; |
| 390 | + } |
| 391 | + else { |
| 392 | + $text .= "<br />Last updated: <b>$row[lastupdated]</b>"; |
| 393 | + } |
| 394 | + |
| 395 | + # Prepare some balloon-tek |
| 396 | + $link = isset( $args['link'] ) ? $args['link'] : ''; |
| 397 | + $target = isset( $args['target'] ) ? $args['target'] : ''; |
| 398 | + $sticky = isset( $args['sticky'] ) ? $args['sticky'] : '0'; |
| 399 | + $width = isset( $args['width'] ) ? $args['width'] : '0'; |
| 400 | + |
| 401 | + $event = isset( $args['click'] ) && $args['click'] && !$link ? 'onclick' : 'onmouseover'; |
| 402 | + $event2 = ''; |
| 403 | + $event = "$event=\"balloon.showTooltip(event,'${text}',${sticky},${width})\""; |
| 404 | + |
| 405 | + if ( preg_match( '/onclick/', $event ) && $args['hover'] ) { |
| 406 | + $event2 = " onmouseover=\"balloon.showTooltip(event,'" . $args['hover'] . "',0,${width})\""; |
| 407 | + } |
| 408 | + |
| 409 | + $has_style = isset( $args['style'] ) && $args['style']; |
| 410 | + $style = "style=\"" . ( $has_style ? $args['style'] . ";cursor:pointer\"" : "cursor:pointer\"" ); |
| 411 | + $target = $target ? "target=${target}" : ''; |
| 412 | + $output = "<span class='rt-ticket' ${event} ${event2} ${style}>$ret</span>"; |
| 413 | + |
| 414 | + return $output; |
| 415 | + } |
416 | 416 | } |
\ No newline at end of file |
Property changes on: trunk/extensions/RT/RT_body.php |
___________________________________________________________________ |
Name: svn:eol-style |
417 | 417 | + native |
Property changes on: trunk/extensions/RT/README |
___________________________________________________________________ |
Name: svn:eol-style |
418 | 418 | + native |
Property changes on: trunk/extensions/MetavidWiki/skins/mv_embed/example_usage/sample_wikimedia_remote.smil.xml |
___________________________________________________________________ |
Name: svn:eol-style |
419 | 419 | + native |
Property changes on: trunk/extensions/Translate/ffs/OpenLayersJS.php |
___________________________________________________________________ |
Name: svn:eol-style |
420 | 420 | + native |
Index: trunk/extensions/DidYouMean/DidYouMean_body.php |
— | — | @@ -1,175 +1,175 @@ |
2 | | -<?php
|
3 | | -/**
|
4 | | - * Class definition for DidYouMean functions
|
5 | | - */
|
6 | | -class DidYouMean {
|
7 | | -
|
8 | | - # turn the array of titles into some wikitext we can add to an article
|
9 | | -
|
10 | | - public static function build_sees( $sees ) {
|
11 | | - global $wgDymUseSeeTemplate;
|
12 | | -
|
13 | | - if ( $wgDymUseSeeTemplate )
|
14 | | - return '{{see|' . implode('|', $sees) . '}}';
|
15 | | - else
|
16 | | - return '<div>\'\'See also:\'\' \'\'\'[[' . implode(']]\'\'\', \'\'\'[[', $sees) . ']]\'\'\'</div>';
|
17 | | - }
|
18 | | -
|
19 | | - # pass pageid = 0 to lookup by normtitle
|
20 | | - public static function lookup( $pageid, $title ) {
|
21 | | - wfDebug( 'HIPP: ' . __METHOD__ . "\n" );
|
22 | | -
|
23 | | - $sees = array();
|
24 | | -
|
25 | | - $dbr = wfGetDB( DB_SLAVE );
|
26 | | -
|
27 | | - if ( $dbr->tableExists( 'dympage' ) && $dbr->tableExists( 'dymnorm' ) ) {
|
28 | | - $normid = false;
|
29 | | -
|
30 | | - if ($pageid) {
|
31 | | - wfDebug( "HIPP: lookup by pageid: $pageid\n" );
|
32 | | - $normid = $dbr->selectField(
|
33 | | - array( 'page', 'dympage' ),
|
34 | | - 'dp_normid',
|
35 | | - array( 'page_id = dp_pageid', 'page_id' => $pageid )
|
36 | | - );
|
37 | | - } else {
|
38 | | - wfDebug( "HIPP: lookup by normtitle: " . wfDymNormalise($title) . "\n" );
|
39 | | - $normid = $dbr->selectField(
|
40 | | - 'dymnorm',
|
41 | | - 'dn_normid',
|
42 | | - array( 'dn_normtitle' => wfDymNormalise($title) )
|
43 | | - );
|
44 | | - }
|
45 | | -
|
46 | | - if ($normid) {
|
47 | | - $res = $dbr->select(
|
48 | | - /* FROM */ array( 'page', 'dympage' ),
|
49 | | - /* SELECT */ 'page_title',
|
50 | | - /* WHERE */ array( 'page_id = dp_pageid', 'dp_normid' => $normid )
|
51 | | - );
|
52 | | -
|
53 | | - $nr = $dbr->numRows( $res );
|
54 | | -
|
55 | | - if ($nr == 0) {
|
56 | | - wfDebug( "HIPP: DB New Miss\n" );
|
57 | | - } else {
|
58 | | - wfDebug( "HIPP: DB New Hit\n" );
|
59 | | -
|
60 | | - # accumulate the db results
|
61 | | - while( $o = $dbr->fetchObject( $res ) ) {
|
62 | | - $t2 = str_replace('_', ' ', $o->page_title);
|
63 | | - $dbo = $t2;
|
64 | | - if ($title != $t2) {
|
65 | | - array_push( $sees, $t2 );
|
66 | | - $dbo = '++ ' . $dbo;
|
67 | | - }
|
68 | | - else
|
69 | | - $dbo = ' (' . $dbo . ')';
|
70 | | - wfDebug( "HIPP: $dbo\n" );
|
71 | | - }
|
72 | | -
|
73 | | - $dbr->freeResult( $res );
|
74 | | - }
|
75 | | - }
|
76 | | - } else {
|
77 | | - wfDebug( "HIPP: No dympage or dymnorm table\n" );
|
78 | | - }
|
79 | | -
|
80 | | - return $sees;
|
81 | | - }
|
82 | | -
|
83 | | - public static function doInsert( $pageid , $title ) {
|
84 | | - wfDebug( 'HIPP: ' . __METHOD__ . " INSERT\n" );
|
85 | | - $dbw = wfGetDB( DB_MASTER );
|
86 | | -
|
87 | | - $norm = wfDymNormalise($title);
|
88 | | -
|
89 | | - # find or create normid for the new title
|
90 | | - $normid = $dbw->selectField( 'dymnorm', 'dn_normid', array( 'dn_normtitle' => $norm ) );
|
91 | | - if ($normid) {
|
92 | | - wfDebug( "HIPP: old: $title ->\t$norm = $normid\n" );
|
93 | | - } else {
|
94 | | - $nsvid = $dbw->nextSequenceValue( 'dymnorm_dn_normid_seq' );
|
95 | | - $dbw->insert( 'dymnorm', array( 'dn_normid' => $nsvid, 'dn_normtitle' => $norm ) );
|
96 | | - $normid = $dbw->insertId();
|
97 | | - wfDebug( "HIPP: NEW: $title ->\t$norm = $normid\n" );
|
98 | | - }
|
99 | | - $dbw->insert( 'dympage', array( 'dp_pageid' => $pageid, 'dp_normid' => $normid ) );
|
100 | | -
|
101 | | - # touch all pages which will now link here
|
102 | | - self::touchPages( "dp_normid=$normid" );
|
103 | | -
|
104 | | - }
|
105 | | -
|
106 | | - private static function touchPages( $condition ) {
|
107 | | - global $wgDBtype;
|
108 | | -
|
109 | | - $dbw = wfGetDB( DB_MASTER );
|
110 | | - $page = $dbw->tableName('page');
|
111 | | - $dpage = $dbw->tableName('dympage');
|
112 | | -
|
113 | | - $whereclause = "WHERE page_id = dp_pageid AND $condition";
|
114 | | - if ($wgDBtype == 'postgres') {
|
115 | | - $sql = "UPDATE $page SET page_touched=now() FROM $dpage $whereclause";
|
116 | | - } else {
|
117 | | - $sql = "UPDATE $page, $dpage SET page_touched = " .
|
118 | | - $dbw->addQuotes( $dbw->timestamp() ) .
|
119 | | - " $whereclause";
|
120 | | - }
|
121 | | -
|
122 | | - $dbw->query( $sql, __METHOD__ );
|
123 | | -
|
124 | | - }
|
125 | | -
|
126 | | - public static function doDelete( $pageid ) {
|
127 | | - wfDebug( 'HIPP: ' . __METHOD__ . " DELETE\n" );
|
128 | | - $dbw = wfGetDB( DB_MASTER );
|
129 | | -
|
130 | | - $normid = $dbw->selectField( 'dympage', 'dp_normid', array('dp_pageid' => $pageid) );
|
131 | | -
|
132 | | - $dbw->delete( 'dympage', array('dp_pageid' => $pageid) );
|
133 | | -
|
134 | | - $count = $dbw->selectField( 'dympage', 'COUNT(*)', array('dp_normid' => $normid) );
|
135 | | -
|
136 | | - if ($count == 0)
|
137 | | - $dbw->delete( 'dymnorm', array('dn_normid' => $normid) );
|
138 | | -
|
139 | | - # touch all pages which will now link here
|
140 | | - if( $normid ) {
|
141 | | - self::touchPages( "dp_normid=$normid" );
|
142 | | - }
|
143 | | - }
|
144 | | -
|
145 | | - public static function doUpdate( $pageid, $title ) {
|
146 | | - wfDebug( 'HIPP: ' . __METHOD__ . " MOVE\n" );
|
147 | | - $dbw = wfGetDB( DB_MASTER );
|
148 | | -
|
149 | | - $norm = wfDymNormalise($title);
|
150 | | -
|
151 | | - $normid = $dbw->selectField( 'dymnorm', 'dn_normid', array( 'dn_normtitle' => $norm ) );
|
152 | | - if ($normid) {
|
153 | | - wfDebug( "HIPP: old: $title ->\t$norm = $normid\n" );
|
154 | | - } else {
|
155 | | - $nsvid = $dbw->nextSequenceValue( 'dymnorm_dn_normid_seq' );
|
156 | | - $dbw->insert( 'dymnorm', array( 'dn_normid' => $nsvid, 'dn_normtitle' => $norm ) );
|
157 | | - $normid = $dbw->insertId();
|
158 | | - wfDebug( "HIPP: NEW: $title ->\t$norm = $normid\n" );
|
159 | | - }
|
160 | | -
|
161 | | - $oldnormid = $dbw->selectField( 'dympage', 'dp_normid', array('dp_pageid' => $pageid) );
|
162 | | -
|
163 | | - if ($oldnormid != $normid) {
|
164 | | - $dbw->update( 'dympage', array( 'dp_normid' => $normid ), array( 'dp_pageid' => $pageid ) );
|
165 | | -
|
166 | | - $count = $dbw->selectField( 'dympage', 'COUNT(*)', array('dp_normid' => $oldnormid) );
|
167 | | -
|
168 | | - if ($count == 0)
|
169 | | - $dbw->delete( 'dymnorm', array('dn_normid' => $oldnormid) );
|
170 | | -
|
171 | | - # touch all pages which linked to the old name or will link to the new one
|
172 | | - self::touchPages( "(dp_normid=$normid OR dp_normid=$oldnormid)" );
|
173 | | -
|
174 | | - }
|
175 | | - }
|
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Class definition for DidYouMean functions |
| 5 | + */ |
| 6 | +class DidYouMean { |
| 7 | + |
| 8 | + # turn the array of titles into some wikitext we can add to an article |
| 9 | + |
| 10 | + public static function build_sees( $sees ) { |
| 11 | + global $wgDymUseSeeTemplate; |
| 12 | + |
| 13 | + if ( $wgDymUseSeeTemplate ) |
| 14 | + return '{{see|' . implode('|', $sees) . '}}'; |
| 15 | + else |
| 16 | + return '<div>\'\'See also:\'\' \'\'\'[[' . implode(']]\'\'\', \'\'\'[[', $sees) . ']]\'\'\'</div>'; |
| 17 | + } |
| 18 | + |
| 19 | + # pass pageid = 0 to lookup by normtitle |
| 20 | + public static function lookup( $pageid, $title ) { |
| 21 | + wfDebug( 'HIPP: ' . __METHOD__ . "\n" ); |
| 22 | + |
| 23 | + $sees = array(); |
| 24 | + |
| 25 | + $dbr = wfGetDB( DB_SLAVE ); |
| 26 | + |
| 27 | + if ( $dbr->tableExists( 'dympage' ) && $dbr->tableExists( 'dymnorm' ) ) { |
| 28 | + $normid = false; |
| 29 | + |
| 30 | + if ($pageid) { |
| 31 | + wfDebug( "HIPP: lookup by pageid: $pageid\n" ); |
| 32 | + $normid = $dbr->selectField( |
| 33 | + array( 'page', 'dympage' ), |
| 34 | + 'dp_normid', |
| 35 | + array( 'page_id = dp_pageid', 'page_id' => $pageid ) |
| 36 | + ); |
| 37 | + } else { |
| 38 | + wfDebug( "HIPP: lookup by normtitle: " . wfDymNormalise($title) . "\n" ); |
| 39 | + $normid = $dbr->selectField( |
| 40 | + 'dymnorm', |
| 41 | + 'dn_normid', |
| 42 | + array( 'dn_normtitle' => wfDymNormalise($title) ) |
| 43 | + ); |
| 44 | + } |
| 45 | + |
| 46 | + if ($normid) { |
| 47 | + $res = $dbr->select( |
| 48 | + /* FROM */ array( 'page', 'dympage' ), |
| 49 | + /* SELECT */ 'page_title', |
| 50 | + /* WHERE */ array( 'page_id = dp_pageid', 'dp_normid' => $normid ) |
| 51 | + ); |
| 52 | + |
| 53 | + $nr = $dbr->numRows( $res ); |
| 54 | + |
| 55 | + if ($nr == 0) { |
| 56 | + wfDebug( "HIPP: DB New Miss\n" ); |
| 57 | + } else { |
| 58 | + wfDebug( "HIPP: DB New Hit\n" ); |
| 59 | + |
| 60 | + # accumulate the db results |
| 61 | + while( $o = $dbr->fetchObject( $res ) ) { |
| 62 | + $t2 = str_replace('_', ' ', $o->page_title); |
| 63 | + $dbo = $t2; |
| 64 | + if ($title != $t2) { |
| 65 | + array_push( $sees, $t2 ); |
| 66 | + $dbo = '++ ' . $dbo; |
| 67 | + } |
| 68 | + else |
| 69 | + $dbo = ' (' . $dbo . ')'; |
| 70 | + wfDebug( "HIPP: $dbo\n" ); |
| 71 | + } |
| 72 | + |
| 73 | + $dbr->freeResult( $res ); |
| 74 | + } |
| 75 | + } |
| 76 | + } else { |
| 77 | + wfDebug( "HIPP: No dympage or dymnorm table\n" ); |
| 78 | + } |
| 79 | + |
| 80 | + return $sees; |
| 81 | + } |
| 82 | + |
| 83 | + public static function doInsert( $pageid , $title ) { |
| 84 | + wfDebug( 'HIPP: ' . __METHOD__ . " INSERT\n" ); |
| 85 | + $dbw = wfGetDB( DB_MASTER ); |
| 86 | + |
| 87 | + $norm = wfDymNormalise($title); |
| 88 | + |
| 89 | + # find or create normid for the new title |
| 90 | + $normid = $dbw->selectField( 'dymnorm', 'dn_normid', array( 'dn_normtitle' => $norm ) ); |
| 91 | + if ($normid) { |
| 92 | + wfDebug( "HIPP: old: $title ->\t$norm = $normid\n" ); |
| 93 | + } else { |
| 94 | + $nsvid = $dbw->nextSequenceValue( 'dymnorm_dn_normid_seq' ); |
| 95 | + $dbw->insert( 'dymnorm', array( 'dn_normid' => $nsvid, 'dn_normtitle' => $norm ) ); |
| 96 | + $normid = $dbw->insertId(); |
| 97 | + wfDebug( "HIPP: NEW: $title ->\t$norm = $normid\n" ); |
| 98 | + } |
| 99 | + $dbw->insert( 'dympage', array( 'dp_pageid' => $pageid, 'dp_normid' => $normid ) ); |
| 100 | + |
| 101 | + # touch all pages which will now link here |
| 102 | + self::touchPages( "dp_normid=$normid" ); |
| 103 | + |
| 104 | + } |
| 105 | + |
| 106 | + private static function touchPages( $condition ) { |
| 107 | + global $wgDBtype; |
| 108 | + |
| 109 | + $dbw = wfGetDB( DB_MASTER ); |
| 110 | + $page = $dbw->tableName('page'); |
| 111 | + $dpage = $dbw->tableName('dympage'); |
| 112 | + |
| 113 | + $whereclause = "WHERE page_id = dp_pageid AND $condition"; |
| 114 | + if ($wgDBtype == 'postgres') { |
| 115 | + $sql = "UPDATE $page SET page_touched=now() FROM $dpage $whereclause"; |
| 116 | + } else { |
| 117 | + $sql = "UPDATE $page, $dpage SET page_touched = " . |
| 118 | + $dbw->addQuotes( $dbw->timestamp() ) . |
| 119 | + " $whereclause"; |
| 120 | + } |
| 121 | + |
| 122 | + $dbw->query( $sql, __METHOD__ ); |
| 123 | + |
| 124 | + } |
| 125 | + |
| 126 | + public static function doDelete( $pageid ) { |
| 127 | + wfDebug( 'HIPP: ' . __METHOD__ . " DELETE\n" ); |
| 128 | + $dbw = wfGetDB( DB_MASTER ); |
| 129 | + |
| 130 | + $normid = $dbw->selectField( 'dympage', 'dp_normid', array('dp_pageid' => $pageid) ); |
| 131 | + |
| 132 | + $dbw->delete( 'dympage', array('dp_pageid' => $pageid) ); |
| 133 | + |
| 134 | + $count = $dbw->selectField( 'dympage', 'COUNT(*)', array('dp_normid' => $normid) ); |
| 135 | + |
| 136 | + if ($count == 0) |
| 137 | + $dbw->delete( 'dymnorm', array('dn_normid' => $normid) ); |
| 138 | + |
| 139 | + # touch all pages which will now link here |
| 140 | + if( $normid ) { |
| 141 | + self::touchPages( "dp_normid=$normid" ); |
| 142 | + } |
| 143 | + } |
| 144 | + |
| 145 | + public static function doUpdate( $pageid, $title ) { |
| 146 | + wfDebug( 'HIPP: ' . __METHOD__ . " MOVE\n" ); |
| 147 | + $dbw = wfGetDB( DB_MASTER ); |
| 148 | + |
| 149 | + $norm = wfDymNormalise($title); |
| 150 | + |
| 151 | + $normid = $dbw->selectField( 'dymnorm', 'dn_normid', array( 'dn_normtitle' => $norm ) ); |
| 152 | + if ($normid) { |
| 153 | + wfDebug( "HIPP: old: $title ->\t$norm = $normid\n" ); |
| 154 | + } else { |
| 155 | + $nsvid = $dbw->nextSequenceValue( 'dymnorm_dn_normid_seq' ); |
| 156 | + $dbw->insert( 'dymnorm', array( 'dn_normid' => $nsvid, 'dn_normtitle' => $norm ) ); |
| 157 | + $normid = $dbw->insertId(); |
| 158 | + wfDebug( "HIPP: NEW: $title ->\t$norm = $normid\n" ); |
| 159 | + } |
| 160 | + |
| 161 | + $oldnormid = $dbw->selectField( 'dympage', 'dp_normid', array('dp_pageid' => $pageid) ); |
| 162 | + |
| 163 | + if ($oldnormid != $normid) { |
| 164 | + $dbw->update( 'dympage', array( 'dp_normid' => $normid ), array( 'dp_pageid' => $pageid ) ); |
| 165 | + |
| 166 | + $count = $dbw->selectField( 'dympage', 'COUNT(*)', array('dp_normid' => $oldnormid) ); |
| 167 | + |
| 168 | + if ($count == 0) |
| 169 | + $dbw->delete( 'dymnorm', array('dn_normid' => $oldnormid) ); |
| 170 | + |
| 171 | + # touch all pages which linked to the old name or will link to the new one |
| 172 | + self::touchPages( "(dp_normid=$normid OR dp_normid=$oldnormid)" ); |
| 173 | + |
| 174 | + } |
| 175 | + } |
176 | 176 | } |
\ No newline at end of file |
Property changes on: trunk/extensions/DidYouMean/DidYouMean_body.php |
___________________________________________________________________ |
Name: svn:eol-style |
177 | 177 | + native |
Index: trunk/extensions/DidYouMean/DidYouMean.hooks.php |
— | — | @@ -1,194 +1,194 @@ |
2 | | -<?php
|
3 | | -/**
|
4 | | - * All the hooks for DidYouMean
|
5 | | - */
|
6 | | -class DidYouMeanHooks {
|
7 | | -
|
8 | | - # TODO this is called even when editing a new page
|
9 | | - public static function articleNoArticleText( &$article, &$text ) {
|
10 | | - wfDebug( 'HIPP: ' . __METHOD__ . "\n" );
|
11 | | -
|
12 | | - $sees = DidYouMean::lookup( 0, $article->getTitle()->getText() );
|
13 | | -
|
14 | | - sort($sees);
|
15 | | -
|
16 | | - if (count($sees))
|
17 | | - $text = DidYouMean::build_sees($sees) . $text;
|
18 | | -
|
19 | | - return true;
|
20 | | - }
|
21 | | -
|
22 | | - # this is called when using the Go/Search box but it is not called when entering
|
23 | | - # a URL for a non-existing article
|
24 | | - public static function specialSearchNoResults( $term ) {
|
25 | | - wfDebug( 'HIPP: ' . __METHOD__ . "\n" );
|
26 | | -
|
27 | | - $sees = DidYouMean::lookup( 0, $term );
|
28 | | -
|
29 | | - sort($sees);
|
30 | | -
|
31 | | - if ( count($sees) ) {
|
32 | | - global $wgOut;
|
33 | | - $wgOut->addWikiText( DidYouMean::build_sees($sees) );
|
34 | | - }
|
35 | | - return true;
|
36 | | - }
|
37 | | -
|
38 | | - # this is called per chunk of wikitext, not per article
|
39 | | - public static function parserBeforeStrip( &$parser, &$text, &$stripState ) {
|
40 | | - #wfDebug( 'HIPP: ' . __METHOD__ . "\n" );
|
41 | | -
|
42 | | - # if revisionid is 0 this is not an article chunk
|
43 | | - if( isset( $parser->mDymFirstChunk ) || !$parser->getVariableValue('revisionid') || $parser->getVariableValue('namespace'))
|
44 | | - return true;
|
45 | | -
|
46 | | - $parser->mDymFirstChunk = 'done';
|
47 | | -
|
48 | | - $title = $parser->getTitle();
|
49 | | - $parser->mDymSees = DidYouMean::lookup( $title->getArticleID(), $title->getText() );
|
50 | | -
|
51 | | - if (preg_match( "/{{[sS]ee\|([^}]*)}}/", $text, $see )) {
|
52 | | - wfDebug( "HIPP: see Hit\n" );
|
53 | | - $hasTemplate = true;
|
54 | | - $sees = explode("|", $see[1]);
|
55 | | - } elseif (preg_match( "/{{[xX]see(\|[^}]*)}}/", $text, $see )) {
|
56 | | - wfDebug( "HIPP: xsee Hit\n" );
|
57 | | - $hasTemplate = true;
|
58 | | - preg_match_all( "/\|\[\[([^]|]*)(?:\|([^|]*))?\]\](?: \(([^)]*)\))?/", $see[1], $ma );
|
59 | | - $sees = $ma[1];
|
60 | | - } else {
|
61 | | - wfDebug( "HIPP: (x)see Miss\n" );
|
62 | | - # there's no {{see}} in this chunk of wikitext
|
63 | | - # if this is the 1st chunk of the article itself we can put an empty {{see}} there.
|
64 | | - $hasTemplate = false;
|
65 | | - $sees = array();
|
66 | | - }
|
67 | | -
|
68 | | - # normalize entities and urlencoding to pure utf-8
|
69 | | - foreach ($sees as &$value)
|
70 | | - $value = rawurldecode(html_entity_decode($value, ENT_QUOTES, 'UTF-8'));
|
71 | | -
|
72 | | - wfDebug( 'HIPP: Parser: ' . implode(', ', $sees) . "\n" );
|
73 | | - wfDebug( 'HIPP: DBase: ' . implode(', ', $parser->mDymSees) . "\n" );
|
74 | | -
|
75 | | - # add in the stuff from the database lookup
|
76 | | - $sees = array_unique(array_merge($sees, $parser->mDymSees));
|
77 | | - sort($sees);
|
78 | | -
|
79 | | - wfDebug( 'HIPP: Merged: ' . implode(', ', $sees) . "\n" );
|
80 | | -
|
81 | | - # TODO is it better to use $parser->insertStripItem() ?
|
82 | | -
|
83 | | - if (count($sees)) {
|
84 | | - if( !$hasTemplate ) {
|
85 | | - // We need to squish in a fresh copy of the template...
|
86 | | - $text = "{{see|}}\n" . $text;
|
87 | | - }
|
88 | | - $built_sees = DidYouMean::build_sees($sees);
|
89 | | - } else {
|
90 | | - $built_sees = '';
|
91 | | - }
|
92 | | -
|
93 | | - $text = preg_replace(
|
94 | | - '/{{[xX]?[sS]ee\|[^}]*}}/',
|
95 | | - #$built_sees . '<div style="text-decoration:line-through">$0</div>',
|
96 | | - $built_sees,
|
97 | | - $text );
|
98 | | -
|
99 | | - return true;
|
100 | | - }
|
101 | | -
|
102 | | - public static function articleDelete( $article, $user, $reason ) {
|
103 | | - if ($article->getTitle()->getNamespace() != 0 || $article->isRedirect() == true)
|
104 | | - return true;
|
105 | | -
|
106 | | - DidYouMean::doDelete( $article->getID() );
|
107 | | -
|
108 | | - return true;
|
109 | | - }
|
110 | | -
|
111 | | - public static function titleMoveComplete( &$title, &$nt, &$wgUser, &$pageid, &$redirid ) {
|
112 | | - $oldtitletext = $title->getText();
|
113 | | - $oldns = $title->getNamespace();
|
114 | | - $newtitletext = $nt->getText();
|
115 | | - $newns = $nt->getNamespace();
|
116 | | -
|
117 | | - wfDebug( 'HIPP: ' . __METHOD__ . "\n" );
|
118 | | -
|
119 | | - if ($oldns != 0 && $newns != 0)
|
120 | | - return true;
|
121 | | -
|
122 | | - # TODO we can't always check if we're moving a redirect because the old article's content
|
123 | | - # TODO has already been replaced with the redirect to the new title but a
|
124 | | - # TODO new title's content is still "noarticletext" at this point!
|
125 | | - #$a1 = new Article( $title );
|
126 | | - #$a2 = new Article( $nt );
|
127 | | - #wfDebug( "HIPP: getContent() for isRedirect()\n\tfrom <<<" . $a1->getContent() . ">>>\n\t to <<<" . $a2->getContent() . ">>>\n" );
|
128 | | - #if ($a1->isRedirect( $a->getContent() )) {
|
129 | | - # wfDebug( "HIPP: moving a redirect (?)\n" );
|
130 | | - # return true;
|
131 | | - #}
|
132 | | -
|
133 | | - if ($oldns == 0 && $newns == 0) {
|
134 | | - DidYouMean::doUpdate( $pageid, $newtitletext );
|
135 | | - } elseif ($oldns == 0) {
|
136 | | - DidYouMean::doDelete( $pageid );
|
137 | | - } elseif ($newns == 0) {
|
138 | | - DidYouMean::doInsert( $pageid, $newtitletext );
|
139 | | - }
|
140 | | -
|
141 | | - return true;
|
142 | | - }
|
143 | | -
|
144 | | - # called at action=edit. can detect if we're about to edit a redirect
|
145 | | - public static function alternateEdit( $editpage ) {
|
146 | | - global $wgParser;
|
147 | | -
|
148 | | - if ($editpage->mArticle->isRedirect())
|
149 | | - $wgParser->mDymRedirBeforeEdit = true;
|
150 | | -
|
151 | | - return 1;
|
152 | | - }
|
153 | | -
|
154 | | - # called at end of action=submit
|
155 | | - public static function articleSaveComplete( $article, $user, $text, $summary, $isminor, $dunno1, $dunno2, $flags ) {
|
156 | | - global $wgParser;
|
157 | | -
|
158 | | - if ($article->getTitle()->getNamespace() != 0)
|
159 | | - return true;
|
160 | | -
|
161 | | - if ($article->isRedirect($text)) {
|
162 | | - if (empty( $wgParser->mDymRedirBeforeEdit ) && !($flags & EDIT_NEW))
|
163 | | - DidYouMean::doDelete( $article->getID() );
|
164 | | - } else {
|
165 | | - if (!empty( $wgParser->mDymRedirBeforeEdit ) || $flags & EDIT_NEW)
|
166 | | - DidYouMean::doInsert( $article->getID(), $article->getTitle()->getText() );
|
167 | | - }
|
168 | | -
|
169 | | - $wgParser->mDymRedirBeforeEdit = false;
|
170 | | -
|
171 | | - return true;
|
172 | | - }
|
173 | | -
|
174 | | - public static function articleUndelete( &$title, &$create ) {
|
175 | | -
|
176 | | - if ($create == false || $title->getNamespace() != 0)
|
177 | | - return true;
|
178 | | -
|
179 | | - # TODO it's not possible to detect if the undeleted article is a redirect!
|
180 | | - #$artic1e = new Article( $title );
|
181 | | - #if ($article->isRedirect( $article->getContent() )) {
|
182 | | - # return true;
|
183 | | - #}
|
184 | | -
|
185 | | - DidYouMean::doInsert( $title->getArticleId(), $title->getText() );
|
186 | | -
|
187 | | - return true;
|
188 | | - }
|
189 | | -
|
190 | | - public static function parserTestTables( &$tables ) {
|
191 | | - $tables[] = 'dympage';
|
192 | | - $tables[] = 'dymnorm';
|
193 | | - return true;
|
194 | | - }
|
195 | | -}
|
| 2 | +<?php |
| 3 | +/** |
| 4 | + * All the hooks for DidYouMean |
| 5 | + */ |
| 6 | +class DidYouMeanHooks { |
| 7 | + |
| 8 | + # TODO this is called even when editing a new page |
| 9 | + public static function articleNoArticleText( &$article, &$text ) { |
| 10 | + wfDebug( 'HIPP: ' . __METHOD__ . "\n" ); |
| 11 | + |
| 12 | + $sees = DidYouMean::lookup( 0, $article->getTitle()->getText() ); |
| 13 | + |
| 14 | + sort($sees); |
| 15 | + |
| 16 | + if (count($sees)) |
| 17 | + $text = DidYouMean::build_sees($sees) . $text; |
| 18 | + |
| 19 | + return true; |
| 20 | + } |
| 21 | + |
| 22 | + # this is called when using the Go/Search box but it is not called when entering |
| 23 | + # a URL for a non-existing article |
| 24 | + public static function specialSearchNoResults( $term ) { |
| 25 | + wfDebug( 'HIPP: ' . __METHOD__ . "\n" ); |
| 26 | + |
| 27 | + $sees = DidYouMean::lookup( 0, $term ); |
| 28 | + |
| 29 | + sort($sees); |
| 30 | + |
| 31 | + if ( count($sees) ) { |
| 32 | + global $wgOut; |
| 33 | + $wgOut->addWikiText( DidYouMean::build_sees($sees) ); |
| 34 | + } |
| 35 | + return true; |
| 36 | + } |
| 37 | + |
| 38 | + # this is called per chunk of wikitext, not per article |
| 39 | + public static function parserBeforeStrip( &$parser, &$text, &$stripState ) { |
| 40 | + #wfDebug( 'HIPP: ' . __METHOD__ . "\n" ); |
| 41 | + |
| 42 | + # if revisionid is 0 this is not an article chunk |
| 43 | + if( isset( $parser->mDymFirstChunk ) || !$parser->getVariableValue('revisionid') || $parser->getVariableValue('namespace')) |
| 44 | + return true; |
| 45 | + |
| 46 | + $parser->mDymFirstChunk = 'done'; |
| 47 | + |
| 48 | + $title = $parser->getTitle(); |
| 49 | + $parser->mDymSees = DidYouMean::lookup( $title->getArticleID(), $title->getText() ); |
| 50 | + |
| 51 | + if (preg_match( "/{{[sS]ee\|([^}]*)}}/", $text, $see )) { |
| 52 | + wfDebug( "HIPP: see Hit\n" ); |
| 53 | + $hasTemplate = true; |
| 54 | + $sees = explode("|", $see[1]); |
| 55 | + } elseif (preg_match( "/{{[xX]see(\|[^}]*)}}/", $text, $see )) { |
| 56 | + wfDebug( "HIPP: xsee Hit\n" ); |
| 57 | + $hasTemplate = true; |
| 58 | + preg_match_all( "/\|\[\[([^]|]*)(?:\|([^|]*))?\]\](?: \(([^)]*)\))?/", $see[1], $ma ); |
| 59 | + $sees = $ma[1]; |
| 60 | + } else { |
| 61 | + wfDebug( "HIPP: (x)see Miss\n" ); |
| 62 | + # there's no {{see}} in this chunk of wikitext |
| 63 | + # if this is the 1st chunk of the article itself we can put an empty {{see}} there. |
| 64 | + $hasTemplate = false; |
| 65 | + $sees = array(); |
| 66 | + } |
| 67 | + |
| 68 | + # normalize entities and urlencoding to pure utf-8 |
| 69 | + foreach ($sees as &$value) |
| 70 | + $value = rawurldecode(html_entity_decode($value, ENT_QUOTES, 'UTF-8')); |
| 71 | + |
| 72 | + wfDebug( 'HIPP: Parser: ' . implode(', ', $sees) . "\n" ); |
| 73 | + wfDebug( 'HIPP: DBase: ' . implode(', ', $parser->mDymSees) . "\n" ); |
| 74 | + |
| 75 | + # add in the stuff from the database lookup |
| 76 | + $sees = array_unique(array_merge($sees, $parser->mDymSees)); |
| 77 | + sort($sees); |
| 78 | + |
| 79 | + wfDebug( 'HIPP: Merged: ' . implode(', ', $sees) . "\n" ); |
| 80 | + |
| 81 | + # TODO is it better to use $parser->insertStripItem() ? |
| 82 | + |
| 83 | + if (count($sees)) { |
| 84 | + if( !$hasTemplate ) { |
| 85 | + // We need to squish in a fresh copy of the template... |
| 86 | + $text = "{{see|}}\n" . $text; |
| 87 | + } |
| 88 | + $built_sees = DidYouMean::build_sees($sees); |
| 89 | + } else { |
| 90 | + $built_sees = ''; |
| 91 | + } |
| 92 | + |
| 93 | + $text = preg_replace( |
| 94 | + '/{{[xX]?[sS]ee\|[^}]*}}/', |
| 95 | + #$built_sees . '<div style="text-decoration:line-through">$0</div>', |
| 96 | + $built_sees, |
| 97 | + $text ); |
| 98 | + |
| 99 | + return true; |
| 100 | + } |
| 101 | + |
| 102 | + public static function articleDelete( $article, $user, $reason ) { |
| 103 | + if ($article->getTitle()->getNamespace() != 0 || $article->isRedirect() == true) |
| 104 | + return true; |
| 105 | + |
| 106 | + DidYouMean::doDelete( $article->getID() ); |
| 107 | + |
| 108 | + return true; |
| 109 | + } |
| 110 | + |
| 111 | + public static function titleMoveComplete( &$title, &$nt, &$wgUser, &$pageid, &$redirid ) { |
| 112 | + $oldtitletext = $title->getText(); |
| 113 | + $oldns = $title->getNamespace(); |
| 114 | + $newtitletext = $nt->getText(); |
| 115 | + $newns = $nt->getNamespace(); |
| 116 | + |
| 117 | + wfDebug( 'HIPP: ' . __METHOD__ . "\n" ); |
| 118 | + |
| 119 | + if ($oldns != 0 && $newns != 0) |
| 120 | + return true; |
| 121 | + |
| 122 | + # TODO we can't always check if we're moving a redirect because the old article's content |
| 123 | + # TODO has already been replaced with the redirect to the new title but a |
| 124 | + # TODO new title's content is still "noarticletext" at this point! |
| 125 | + #$a1 = new Article( $title ); |
| 126 | + #$a2 = new Article( $nt ); |
| 127 | + #wfDebug( "HIPP: getContent() for isRedirect()\n\tfrom <<<" . $a1->getContent() . ">>>\n\t to <<<" . $a2->getContent() . ">>>\n" ); |
| 128 | + #if ($a1->isRedirect( $a->getContent() )) { |
| 129 | + # wfDebug( "HIPP: moving a redirect (?)\n" ); |
| 130 | + # return true; |
| 131 | + #} |
| 132 | + |
| 133 | + if ($oldns == 0 && $newns == 0) { |
| 134 | + DidYouMean::doUpdate( $pageid, $newtitletext ); |
| 135 | + } elseif ($oldns == 0) { |
| 136 | + DidYouMean::doDelete( $pageid ); |
| 137 | + } elseif ($newns == 0) { |
| 138 | + DidYouMean::doInsert( $pageid, $newtitletext ); |
| 139 | + } |
| 140 | + |
| 141 | + return true; |
| 142 | + } |
| 143 | + |
| 144 | + # called at action=edit. can detect if we're about to edit a redirect |
| 145 | + public static function alternateEdit( $editpage ) { |
| 146 | + global $wgParser; |
| 147 | + |
| 148 | + if ($editpage->mArticle->isRedirect()) |
| 149 | + $wgParser->mDymRedirBeforeEdit = true; |
| 150 | + |
| 151 | + return 1; |
| 152 | + } |
| 153 | + |
| 154 | + # called at end of action=submit |
| 155 | + public static function articleSaveComplete( $article, $user, $text, $summary, $isminor, $dunno1, $dunno2, $flags ) { |
| 156 | + global $wgParser; |
| 157 | + |
| 158 | + if ($article->getTitle()->getNamespace() != 0) |
| 159 | + return true; |
| 160 | + |
| 161 | + if ($article->isRedirect($text)) { |
| 162 | + if (empty( $wgParser->mDymRedirBeforeEdit ) && !($flags & EDIT_NEW)) |
| 163 | + DidYouMean::doDelete( $article->getID() ); |
| 164 | + } else { |
| 165 | + if (!empty( $wgParser->mDymRedirBeforeEdit ) || $flags & EDIT_NEW) |
| 166 | + DidYouMean::doInsert( $article->getID(), $article->getTitle()->getText() ); |
| 167 | + } |
| 168 | + |
| 169 | + $wgParser->mDymRedirBeforeEdit = false; |
| 170 | + |
| 171 | + return true; |
| 172 | + } |
| 173 | + |
| 174 | + public static function articleUndelete( &$title, &$create ) { |
| 175 | + |
| 176 | + if ($create == false || $title->getNamespace() != 0) |
| 177 | + return true; |
| 178 | + |
| 179 | + # TODO it's not possible to detect if the undeleted article is a redirect! |
| 180 | + #$artic1e = new Article( $title ); |
| 181 | + #if ($article->isRedirect( $article->getContent() )) { |
| 182 | + # return true; |
| 183 | + #} |
| 184 | + |
| 185 | + DidYouMean::doInsert( $title->getArticleId(), $title->getText() ); |
| 186 | + |
| 187 | + return true; |
| 188 | + } |
| 189 | + |
| 190 | + public static function parserTestTables( &$tables ) { |
| 191 | + $tables[] = 'dympage'; |
| 192 | + $tables[] = 'dymnorm'; |
| 193 | + return true; |
| 194 | + } |
| 195 | +} |
Property changes on: trunk/extensions/DidYouMean/DidYouMean.hooks.php |
___________________________________________________________________ |
Name: svn:eol-style |
196 | 196 | + native |