Index: trunk/extensions/SemanticMediaWiki/includes/SMW_ParserExtensions.php |
— | — | @@ -274,10 +274,10 @@ |
275 | 275 | array_shift( $params ); // We already know the $parser ... |
276 | 276 | |
277 | 277 | // Use first parameter as concept (query) string. |
278 | | - $concept_input = str_replace( array( '>', '<' ), array( '>', '<' ), array_shift( $params ) ); |
| 278 | + $concept_input = str_replace( array( '>', '<' ), array( '>', '<' ), array_shift( $params ) ); |
279 | 279 | |
280 | 280 | // second parameter, if any, might be a description |
281 | | - $concept_docu = array_shift( $params ); |
| 281 | + $concept_docu = array_shift( $params ); |
282 | 282 | |
283 | 283 | // NOTE: the str_replace above is required in MediaWiki 1.11, but not in MediaWiki 1.14 |
284 | 284 | $query = SMWQueryProcessor::createQuery( $concept_input, array( 'limit' => 20, 'format' => 'list' ), SMWQueryProcessor::CONCEPT_DESC ); |
— | — | @@ -340,7 +340,7 @@ |
341 | 341 | $params = func_get_args(); |
342 | 342 | array_shift( $params ); // We already know the $parser ... |
343 | 343 | |
344 | | - foreach ( $params as $p ) |
| 344 | + foreach ( $params as $p ) { |
345 | 345 | if ( trim( $p ) != '' ) { |
346 | 346 | $parts = explode( '=', trim( $p ), 2 ); |
347 | 347 | |
— | — | @@ -351,143 +351,191 @@ |
352 | 352 | SMWParseData::addProperty( $property, $object, false, $parser, true ); |
353 | 353 | } |
354 | 354 | } |
355 | | - |
| 355 | + } |
| 356 | + |
356 | 357 | SMWOutputs::commitToParser( $parser ); // not obviously required, but let us be sure |
357 | 358 | return ''; |
358 | 359 | } |
359 | 360 | |
360 | | - /** |
361 | | - * Function for handling the {{\#set_recurring_event }} parser function. |
362 | | - * This is used for defining a set of date values for a page that |
363 | | - * represents a recurring event. |
364 | | - * Like with the #set function, all annotations happen silently. |
365 | | - * |
366 | | - * Usage: |
367 | | - * {{\#set_recurring_event: |
368 | | - * property = Has date |
369 | | - * | start = January 4, 2010 |
370 | | - * | end = June 7, 2010 |
371 | | - * | unit = week |
372 | | - * | period = 1 |
373 | | - * | include = March 16, 2010;March 23, 2010 |
374 | | - * | exclude = March 15, 2010;March 22, 2010 |
375 | | - * }} |
376 | | - * This sets a "Has date" value for every Monday within the specified |
377 | | - * six-month period, except for two Mondays which are excluded and |
378 | | - * two Tuesdays that are saved in their place. |
379 | | - * |
380 | | - * @param[in] &$parser Parser The current parser |
381 | | - * @return nothing |
382 | | - */ |
383 | | - static public function doSetRecurringEvent( &$parser ) { |
384 | | - $params = func_get_args(); |
385 | | - array_shift( $params ); // we already know the $parser ... |
386 | | - // initialize variables |
387 | | - $property_name = $start_date = $end_date = $unit = $period = null; |
388 | | - $included_dates = array(); |
389 | | - $excluded_dates_jd = array(); |
390 | | - // set values from the parameters |
391 | | - foreach ( $params as $p ) { |
392 | | - if ( trim( $p ) != "" ) { |
393 | | - $parts = explode( "=", trim( $p ) ); |
394 | | - if ( count( $parts ) == 2 ) { |
395 | | - list( $arg, $value ) = $parts; |
396 | | - if ( $arg === 'property' ) { |
397 | | - $property_name = $value; |
398 | | - } elseif ( $arg === 'start' ) { |
399 | | - $start_date = SMWDataValueFactory::newTypeIDValue( '_dat', $value ); |
400 | | - } elseif ( $arg === 'end' ) { |
401 | | - $end_date = SMWDataValueFactory::newTypeIDValue( '_dat', $value ); |
402 | | - } elseif ( $arg === 'unit' ) { |
403 | | - $unit = $value; |
404 | | - } elseif ( $arg === 'period' ) { |
405 | | - $period = (int)$value; |
406 | | - } elseif ( $arg === 'include' ) { |
407 | | - $included_dates = explode( ';', $value ); |
408 | | - } elseif ( $arg === 'exclude' ) { |
409 | | - $excluded_dates = explode( ';', $value ); |
410 | | - foreach ( $excluded_dates as $date_str ) { |
411 | | - $date = SMWDataValueFactory::newTypeIDValue( '_dat', $date_str ); |
412 | | - $excluded_dates_jd[] = $date->getValueKey(); |
413 | | - } |
414 | | - } |
415 | | - } |
416 | | - } |
417 | | - } |
418 | | - // we need at least a property and start date - if either one |
419 | | - // is null, exit here |
420 | | - if ( is_null( $property_name ) || is_null( $start_date ) ) |
421 | | - return; |
422 | | - |
423 | | - // if the period is null, or outside of normal bounds, set it to 1 |
424 | | - if ( is_null( $period ) || $period < 1 || $period > 500 ) |
425 | | - $period = 1; |
426 | | - // get the Julian day value for both the start and end date |
427 | | - $start_date_jd = $start_date->getValueKey(); |
428 | | - if ( ! is_null( $end_date ) ) |
429 | | - $end_date_jd = $end_date->getValueKey(); |
430 | | - $cur_date = $start_date; |
431 | | - $cur_date_jd = $start_date->getValueKey(); |
432 | | - $i = 0; |
433 | | - $reached_end_date = false; |
434 | | - do { |
435 | | - $i++; |
436 | | - $exclude_date = ( in_array( $cur_date_jd, $excluded_dates_jd ) ); |
437 | | - if ( ! $exclude_date ) { |
438 | | - $cur_date_str = $cur_date->getLongWikiText(); |
439 | | - SMWParseData::addProperty( $property_name, $cur_date_str, false, $parser, true ); |
440 | | - } |
441 | | - // now get the next date |
442 | | - // handling is different depending on whether it's |
443 | | - // month/year or week/day, since the latter is a |
444 | | - // set number of days while the former isn't |
445 | | - if ( $unit === 'year' || $unit == 'month' ) { |
446 | | - $cur_year = $cur_date->getYear(); |
447 | | - $cur_month = $cur_date->getMonth(); |
448 | | - $cur_day = $cur_date->getDay(); |
449 | | - $cur_time = $cur_date->getTimeString(); |
450 | | - if ( $unit == 'year' ) { |
451 | | - $cur_year += $period; |
452 | | - } else { // $unit === 'month' |
453 | | - $cur_month += $period; |
454 | | - $cur_year += (int)( ( $cur_month - 1 ) / 12 ); |
455 | | - $cur_month %= 12; |
456 | | - $display_month = ( $cur_month == 0 ) ? 12 : $cur_month; |
457 | | - } |
458 | | - $date_str = "$cur_year-$display_month-$cur_day $cur_time"; |
459 | | - $cur_date = SMWDataValueFactory::newTypeIDValue( '_dat', $date_str ); |
460 | | - $cur_date_jd = $cur_date->getValueKey(); |
461 | | - } elseif($unit == 'dayofweekinmonth') { |
462 | | - // e.g., "3rd Monday of every month" |
463 | | - $check_month = $cur_date->getMonth(); |
464 | | - $cur_date_jd += 28 * $period; |
465 | | - $cur_date = SMWDataValueFactory::newTypeIDValue('_dat', $cur_date_jd); |
466 | | - if ($cur_date->getMonth() != (($check_month + $period) % 12 )){ |
467 | | - $cur_date_jd += 7; // add another week |
468 | | - $cur_date = SMWDataValueFactory::newTypeIDValue('_dat', $cur_date_jd); |
| 361 | + /** |
| 362 | + * Function for handling the {{\#set_recurring_event }} parser function. |
| 363 | + * This is used for defining a set of date values for a page that |
| 364 | + * represents a recurring event. |
| 365 | + * Like with the #set function, all annotations happen silently. |
| 366 | + * |
| 367 | + * Usage: |
| 368 | + * {{\#set_recurring_event: |
| 369 | + * property = Has date |
| 370 | + * | start = January 4, 2010 |
| 371 | + * | end = June 7, 2010 |
| 372 | + * | unit = week |
| 373 | + * | period = 1 |
| 374 | + * | include = March 16, 2010;March 23, 2010 |
| 375 | + * | exclude = March 15, 2010;March 22, 2010 |
| 376 | + * }} |
| 377 | + * This sets a "Has date" value for every Monday within the specified |
| 378 | + * six-month period, except for two Mondays which are excluded and |
| 379 | + * two Tuesdays that are saved in their place. |
| 380 | + * |
| 381 | + * There's also a 'week number' parameter, which is only valid when |
| 382 | + * the 'unit' parameter is set to 'month'. This one dictates that the |
| 383 | + * event should always happen on the n-th week of each month, instead |
| 384 | + * of a specific numbered date. Negative values for 'week number' |
| 385 | + * indicate the n-th last week of a month instead. |
| 386 | + * |
| 387 | + * @param[in] &$parser Parser The current parser |
| 388 | + * @return nothing |
| 389 | + */ |
| 390 | + static public function doSetRecurringEvent( &$parser ) { |
| 391 | + $params = func_get_args(); |
| 392 | + array_shift( $params ); // We already know the $parser ... |
| 393 | + |
| 394 | + // Initialize variables |
| 395 | + $property_name = $start_date = $end_date = $unit = $period = $week_num = null; |
| 396 | + $included_dates = array(); |
| 397 | + $excluded_dates_jd = array(); |
| 398 | + // Set values from the parameters |
| 399 | + foreach ( $params as $p ) { |
| 400 | + if ( trim( $p ) != '' ) { |
| 401 | + $parts = explode( '=', trim( $p ) ); |
| 402 | + if ( count( $parts ) == 2 ) { |
| 403 | + list( $arg, $value ) = $parts; |
| 404 | + if ( $arg === 'property' ) { |
| 405 | + $property_name = $value; |
| 406 | + } elseif ( $arg === 'start' ) { |
| 407 | + $start_date = SMWDataValueFactory::newTypeIDValue( '_dat', $value ); |
| 408 | + } elseif ( $arg === 'end' ) { |
| 409 | + $end_date = SMWDataValueFactory::newTypeIDValue( '_dat', $value ); |
| 410 | + } elseif ( $arg === 'unit' ) { |
| 411 | + $unit = $value; |
| 412 | + } elseif ( $arg === 'period' ) { |
| 413 | + $period = (int)$value; |
| 414 | + } elseif ( $arg === 'week number' ) { |
| 415 | + $week_num = (int)$value; |
| 416 | + } elseif ( $arg === 'include' ) { |
| 417 | + $included_dates = explode( ';', $value ); |
| 418 | + } elseif ( $arg === 'exclude' ) { |
| 419 | + $excluded_dates = explode( ';', $value ); |
| 420 | + foreach ( $excluded_dates as $date_str ) { |
| 421 | + $date = SMWDataValueFactory::newTypeIDValue( '_dat', $date_str ); |
| 422 | + $excluded_dates_jd[] = $date->getValueKey(); |
| 423 | + } |
| 424 | + } |
469 | 425 | } |
470 | | - } else { // $unit == 'day' or 'week' |
471 | | - // assume 'day' if it's none of the above |
472 | | - $cur_date_jd += ( $unit === 'week' ) ? 7 * $period : $period; |
473 | | - $cur_date = SMWDataValueFactory::newTypeIDValue( '_dat', $cur_date_jd ); |
474 | | - } |
| 426 | + } |
| 427 | + } |
| 428 | + // We need at least a property and start date - if either one |
| 429 | + // is null, exit here |
| 430 | + if ( is_null( $property_name ) || is_null( $start_date ) ) |
| 431 | + return; |
475 | 432 | |
476 | | - // should we stop? |
477 | | - if ( is_null( $end_date ) ) { |
478 | | - global $smwgDefaultNumRecurringEvents; |
479 | | - $reached_end_date = $i > $smwgDefaultNumRecurringEvents; |
480 | | - } else { |
481 | | - global $smwgMaxNumRecurringEvents; |
482 | | - $reached_end_date = ( $cur_date_jd > $end_date_jd ) || ( $i > $smwgMaxNumRecurringEvents ); |
483 | | - } |
484 | | - } while ( ! $reached_end_date ); |
| 433 | + // If the period is null, or outside of normal bounds, set it to 1 |
| 434 | + if ( is_null( $period ) || $period < 1 || $period > 500 ) |
| 435 | + $period = 1; |
485 | 436 | |
486 | | - // handle the 'include' dates as well |
487 | | - foreach ( $included_dates as $date_str ) |
488 | | - SMWParseData::addProperty( $property_name, $date_str, false, $parser, true ); |
489 | | - SMWOutputs::commitToParser( $parser ); // not obviously required, but let us be sure |
490 | | - } |
| 437 | + // Handle 'week number', but only if it's of unit 'month' |
| 438 | + if ( $unit == 'month' && ! is_null( $week_num ) ) { |
| 439 | + $unit = 'dayofweekinmonth'; |
| 440 | + if ( $week_num < -4 || $week_num > 5 || $week_num == 0 ) { |
| 441 | + $week_num = null; |
| 442 | + } |
| 443 | + } |
| 444 | + if ( $unit == 'dayofweekinmonth' && is_null( $week_num ) ) |
| 445 | + $week_num = ceil($start_date->getDay() / 7); |
491 | 446 | |
| 447 | + // Get the Julian day value for both the start and end date |
| 448 | + $start_date_jd = $start_date->getValueKey(); |
| 449 | + if ( ! is_null( $end_date ) ) |
| 450 | + $end_date_jd = $end_date->getValueKey(); |
| 451 | + $cur_date = $start_date; |
| 452 | + $cur_date_jd = $start_date->getValueKey(); |
| 453 | + $i = 0; |
| 454 | + $reached_end_date = false; |
| 455 | + do { |
| 456 | + $i++; |
| 457 | + $exclude_date = ( in_array( $cur_date_jd, $excluded_dates_jd ) ); |
| 458 | + if ( ! $exclude_date ) { |
| 459 | + $cur_date_str = $cur_date->getLongWikiText(); |
| 460 | + SMWParseData::addProperty( $property_name, $cur_date_str, false, $parser, true ); |
| 461 | + } |
| 462 | + // now get the next date |
| 463 | + // handling is different depending on whether it's |
| 464 | + // month/year or week/day, since the latter is a |
| 465 | + // set number of days while the former isn't |
| 466 | + if ( $unit === 'year' || $unit == 'month' ) { |
| 467 | + $cur_year = $cur_date->getYear(); |
| 468 | + $cur_month = $cur_date->getMonth(); |
| 469 | + $cur_day = $cur_date->getDay(); |
| 470 | + $cur_time = $cur_date->getTimeString(); |
| 471 | + if ( $unit == 'year' ) { |
| 472 | + $cur_year += $period; |
| 473 | + $display_month = $cur_month; |
| 474 | + } else { // $unit === 'month' |
| 475 | + $cur_month += $period; |
| 476 | + $cur_year += (int)( ( $cur_month - 1 ) / 12 ); |
| 477 | + $cur_month %= 12; |
| 478 | + $display_month = ( $cur_month == 0 ) ? 12 : $cur_month; |
| 479 | + } |
| 480 | + $date_str = "$cur_year-$display_month-$cur_day $cur_time"; |
| 481 | + $cur_date = SMWDataValueFactory::newTypeIDValue( '_dat', $date_str ); |
| 482 | + $cur_date_jd = $cur_date->getValueKey(); |
| 483 | + } elseif ( $unit == 'dayofweekinmonth' ) { |
| 484 | + // e.g., "3rd Monday of every month" |
| 485 | + $prev_month = $cur_date->getMonth(); |
| 486 | + $prev_year = $cur_date->getYear(); |
| 487 | + $new_month = ( $prev_month + $period ) % 12; |
| 488 | + if ( $new_month == 0 ) $new_month = 12; |
| 489 | + $new_year = $prev_year + floor( ( $prev_month + $period - 1 ) / 12 ); |
| 490 | + $cur_date_jd += ( 28 * $period ) - 7; |
| 491 | + // we're sometime before the actual date now - |
| 492 | + // keep incrementing by a week, until we get |
| 493 | + // there |
| 494 | + do { |
| 495 | + $cur_date_jd += 7; |
| 496 | + $cur_date = SMWDataValueFactory::newTypeIDValue('_dat', $cur_date_jd); |
| 497 | + $right_month = ($cur_date->getMonth() == $new_month); |
| 498 | + if ( $week_num < 0 ) { |
| 499 | + $next_week_jd = $cur_date_jd; |
| 500 | + do { |
| 501 | + $next_week_jd += 7; |
| 502 | + $next_week_date = SMWDataValueFactory::newTypeIDValue( '_dat', $next_week_jd ); |
| 503 | + $right_week = ($next_week_date->getMonth() != $new_month) || ($next_week_date->getYear() != $new_year); |
| 504 | + } while ( ! $right_week ); |
| 505 | + $cur_date_jd = $next_week_jd + ( 7 * $week_num ); |
| 506 | + $cur_date = SMWDataValueFactory::newTypeIDValue( '_dat', $cur_date_jd ); |
| 507 | + } else { |
| 508 | + $cur_week_num = ceil( $cur_date->getDay() / 7 ); |
| 509 | + $right_week = ( $cur_week_num == $week_num ); |
| 510 | + if ($week_num == 5 && ( $cur_date->getMonth() % 12 == ( $new_month + 1 ) % 12 ) ) { |
| 511 | + $cur_date_jd -= 7; |
| 512 | + $cur_date = SMWDataValueFactory::newTypeIDValue( '_dat', $cur_date_jd ); |
| 513 | + $right_month = $right_week = true; |
| 514 | + } |
| 515 | + } |
| 516 | + } while (! $right_month || ! $right_week); |
| 517 | + } else { // $unit == 'day' or 'week' |
| 518 | + // assume 'day' if it's none of the above |
| 519 | + $cur_date_jd += ( $unit === 'week' ) ? 7 * $period : $period; |
| 520 | + $cur_date = SMWDataValueFactory::newTypeIDValue( '_dat', $cur_date_jd ); |
| 521 | + } |
| 522 | + |
| 523 | + // should we stop? |
| 524 | + if ( is_null( $end_date ) ) { |
| 525 | + global $smwgDefaultNumRecurringEvents; |
| 526 | + $reached_end_date = $i > $smwgDefaultNumRecurringEvents; |
| 527 | + } else { |
| 528 | + global $smwgMaxNumRecurringEvents; |
| 529 | + $reached_end_date = ( $cur_date_jd > $end_date_jd ) || ( $i > $smwgMaxNumRecurringEvents ); |
| 530 | + } |
| 531 | + } while ( ! $reached_end_date ); |
| 532 | + |
| 533 | + // handle the 'include' dates as well |
| 534 | + foreach ( $included_dates as $date_str ) |
| 535 | + SMWParseData::addProperty( $property_name, $date_str, false, $parser, true ); |
| 536 | + |
| 537 | + SMWOutputs::commitToParser( $parser ); // not obviously required, but let us be sure |
| 538 | + } |
| 539 | + |
492 | 540 | /** |
493 | 541 | * Function for handling the {{\#declare }} parser function. It is used for declaring template parameters |
494 | 542 | * that should automagically be annotated when the template is used. |