Index: trunk/extensions/MobileFrontend/tests/MobileFrontendTest.php |
— | — | @@ -1,10 +1,11 @@ |
2 | 2 | <?php |
3 | 3 | |
4 | 4 | class ExtMobileFrontendTest extends MediaWikiTestCase { |
5 | | - |
6 | 5 | /** |
7 | 6 | * PHP 5.3.2 introduces the ReflectionMethod::setAccessible() method to allow the invocation of |
8 | 7 | * protected and private methods directly through the Reflection API |
| 8 | + * |
| 9 | + * @param $name string |
9 | 10 | */ |
10 | 11 | protected static function getMethod( $name ) { |
11 | 12 | $class = new ReflectionClass( 'ExtMobileFrontend' ); |
— | — | @@ -15,32 +16,34 @@ |
16 | 17 | |
17 | 18 | protected function setUp() { |
18 | 19 | parent::setUp(); |
19 | | - $this->wgExtMobileFrontend = new ExtMobileFrontend(); |
| 20 | + global $wgExtMobileFrontend; |
| 21 | + $wgExtMobileFrontend = new ExtMobileFrontend(); |
20 | 22 | } |
21 | 23 | |
22 | 24 | protected function tearDown() { |
23 | | - unset( $this->wgExtMobileFrontend ); |
| 25 | + global $wgExtMobileFrontend; |
| 26 | + unset( $wgExtMobileFrontend ); |
24 | 27 | parent::tearDown(); |
25 | 28 | } |
26 | 29 | |
27 | 30 | public function testGetBaseDomain() { |
| 31 | + global $wgExtMobileFrontend; |
28 | 32 | $getBaseDomain = self::getMethod( 'getBaseDomain' ); |
29 | | - $wgExtMobileFrontend = new ExtMobileFrontend(); |
30 | 33 | $_SERVER['HTTP_HOST'] = 'en.wikipedia.org'; |
31 | 34 | $this->assertEquals( '.wikipedia.org', $getBaseDomain->invokeArgs( $wgExtMobileFrontend, array() ) ); |
32 | 35 | } |
33 | 36 | |
34 | 37 | public function testGetRelativeURL() { |
| 38 | + global $wgExtMobileFrontend; |
35 | 39 | $getRelativeURL = self::getMethod( 'getRelativeURL' ); |
36 | | - $wgExtMobileFrontend = new ExtMobileFrontend(); |
37 | 40 | $url = 'http://en.wikipedia.org/wiki/Positional_astronomy'; |
38 | 41 | $this->assertEquals( '/wiki/Positional_astronomy', $getRelativeURL->invokeArgs( $wgExtMobileFrontend, array( $url ) ) ); |
39 | 42 | } |
40 | 43 | |
41 | 44 | public function testDisableCaching() { |
42 | | - global $wgRequest; |
| 45 | + global $wgRequest, $wgExtMobileFrontend; |
43 | 46 | $disableCaching = self::getMethod( 'disableCaching' ); |
44 | | - $wgExtMobileFrontend = new ExtMobileFrontend(); |
| 47 | + |
45 | 48 | $_SERVER['HTTP_VIA'] = '.wikimedia.org:3128'; |
46 | 49 | $disableCaching->invokeArgs( $wgExtMobileFrontend, array() ); |
47 | 50 | $this->assertEquals( 'no-cache, must-revalidate', $wgRequest->response()->getheader( 'Cache-Control' ) ); |
— | — | @@ -49,9 +52,8 @@ |
50 | 53 | } |
51 | 54 | |
52 | 55 | public function testSendXDeviceVaryHeader() { |
53 | | - global $wgRequest; |
| 56 | + global $wgRequest, $wgExtMobileFrontend; |
54 | 57 | $sendXDeviceVaryHeader = self::getMethod( 'sendXDeviceVaryHeader' ); |
55 | | - $wgExtMobileFrontend = new ExtMobileFrontend(); |
56 | 58 | $_SERVER['HTTP_X_DEVICE'] = 'device'; |
57 | 59 | $sendXDeviceVaryHeader->invokeArgs( $wgExtMobileFrontend, array() ); |
58 | 60 | $this->assertEquals( $_SERVER['HTTP_X_DEVICE'], $wgRequest->response()->getheader( 'X-Device' ) ); |
Index: trunk/extensions/MobileFrontend/DeviceDetection.php |
— | — | @@ -249,11 +249,18 @@ |
250 | 250 | return $formats; |
251 | 251 | } |
252 | 252 | |
| 253 | + /** |
| 254 | + * @param $formatName |
| 255 | + * @return array |
| 256 | + */ |
253 | 257 | public function format( $formatName ) { |
254 | 258 | $format = $this->availableFormats(); |
255 | 259 | return ( isset( $format[$formatName] ) ) ? $format[$formatName] : array(); |
256 | 260 | } |
257 | 261 | |
| 262 | + /** |
| 263 | + * @return string |
| 264 | + */ |
258 | 265 | public function testFormatName() { |
259 | 266 | $testResults = ''; |
260 | 267 | |
Index: trunk/extensions/MobileFrontend/MobileFrontend.php |
— | — | @@ -72,12 +72,15 @@ |
73 | 73 | * Make the classes stripped from page content configurable. Each item will |
74 | 74 | * be stripped from the page. See $itemsToRemove for more info |
75 | 75 | */ |
76 | | -$wgMFRemovableClasses = array( |
77 | | -); |
| 76 | +$wgMFRemovableClasses = array(); |
78 | 77 | |
79 | 78 | # Unit tests |
80 | 79 | $wgHooks['UnitTestsList'][] = 'efExtMobileFrontendUnitTests'; |
81 | 80 | |
| 81 | +/** |
| 82 | + * @param $files array |
| 83 | + * @return bool |
| 84 | + */ |
82 | 85 | function efExtMobileFrontendUnitTests( &$files ) { |
83 | 86 | $files[] = dirname( __FILE__ ) . '/tests/MobileFrontendTest.php'; |
84 | 87 | return true; |
— | — | @@ -89,8 +92,7 @@ |
90 | 93 | /** |
91 | 94 | * @var DOMDocument |
92 | 95 | */ |
93 | | - private $doc; |
94 | | - private $mainPage; |
| 96 | + private $doc, $mainPage; |
95 | 97 | |
96 | 98 | public static $messages = array(); |
97 | 99 | |
— | — | @@ -200,6 +202,13 @@ |
201 | 203 | '.nomobile', |
202 | 204 | ); |
203 | 205 | |
| 206 | + /** |
| 207 | + * @param $request WebRequest |
| 208 | + * @param $title Title |
| 209 | + * @param $output OutputPage |
| 210 | + * @return bool |
| 211 | + * @throws HttpError |
| 212 | + */ |
204 | 213 | public function testCanonicalRedirect( $request, $title, $output ) { |
205 | 214 | global $wgUsePathInfo, $wgMobileDomain; |
206 | 215 | $xDevice = isset( $_SERVER['HTTP_X_DEVICE'] ) ? $_SERVER['HTTP_X_DEVICE'] : ''; |
— | — | @@ -251,6 +260,11 @@ |
252 | 261 | } |
253 | 262 | } |
254 | 263 | |
| 264 | + /** |
| 265 | + * @param $obj Article |
| 266 | + * @param $tpl |
| 267 | + * @return bool |
| 268 | + */ |
255 | 269 | public function addMobileFooter( &$obj, &$tpl ) { |
256 | 270 | global $wgRequest; |
257 | 271 | wfProfileIn( __METHOD__ ); |
— | — | @@ -269,7 +283,12 @@ |
270 | 284 | wfProfileOut( __METHOD__ ); |
271 | 285 | return true; |
272 | 286 | } |
273 | | - |
| 287 | + |
| 288 | + /** |
| 289 | + * @param $url string |
| 290 | + * @param $field string |
| 291 | + * @return string |
| 292 | + */ |
274 | 293 | private function removeQueryStringParameter( $url, $field ) { |
275 | 294 | $url = preg_replace( '/(.*)(\?|&)' . $field . '=[^&]+?(&)(.*)/i', '$1$2$4', $url . '&' ); |
276 | 295 | $url = substr( $url, 0, -1 ); |
— | — | @@ -344,6 +363,7 @@ |
345 | 364 | |
346 | 365 | $key = wfMemcKey( 'mobile', 'ua', $uAmd5 ); |
347 | 366 | |
| 367 | + $props = null; |
348 | 368 | try { |
349 | 369 | $props = $wgMemc->get( $key ); |
350 | 370 | if ( ! $props ) { |
— | — | @@ -465,28 +485,22 @@ |
466 | 486 | exit(); |
467 | 487 | } |
468 | 488 | |
469 | | - if ( $mobileAction == 'disable_mobile_site' ) { |
470 | | - if ( $this->contentFormat == 'XHTML' ) { |
471 | | - echo $this->renderDisableMobileSiteXHTML(); |
472 | | - wfProfileOut( __METHOD__ ); |
473 | | - exit(); |
474 | | - } |
| 489 | + if ( $mobileAction == 'disable_mobile_site' && $this->contentFormat == 'XHTML' ) { |
| 490 | + echo $this->renderDisableMobileSiteXHTML(); |
| 491 | + wfProfileOut( __METHOD__ ); |
| 492 | + exit(); |
475 | 493 | } |
476 | 494 | |
477 | | - if ( $mobileAction == 'opt_in_mobile_site' ) { |
478 | | - if ( $this->contentFormat == 'XHTML' ) { |
479 | | - echo $this->renderOptInMobileSiteXHTML(); |
480 | | - wfProfileOut( __METHOD__ ); |
481 | | - exit(); |
482 | | - } |
| 495 | + if ( $mobileAction == 'opt_in_mobile_site' && $this->contentFormat == 'XHTML' ) { |
| 496 | + echo $this->renderOptInMobileSiteXHTML(); |
| 497 | + wfProfileOut( __METHOD__ ); |
| 498 | + exit(); |
483 | 499 | } |
484 | 500 | |
485 | | - if ( $mobileAction == 'opt_out_mobile_site' ) { |
486 | | - if ( $this->contentFormat == 'XHTML' ) { |
487 | | - echo $this->renderOptOutMobileSiteXHTML(); |
488 | | - wfProfileOut( __METHOD__ ); |
489 | | - exit(); |
490 | | - } |
| 501 | + if ( $mobileAction == 'opt_out_mobile_site' && $this->contentFormat == 'XHTML' ) { |
| 502 | + echo $this->renderOptOutMobileSiteXHTML(); |
| 503 | + wfProfileOut( __METHOD__ ); |
| 504 | + exit(); |
491 | 505 | } |
492 | 506 | |
493 | 507 | if ( $mobileAction == 'opt_in_cookie' ) { |
— | — | @@ -502,7 +516,7 @@ |
503 | 517 | |
504 | 518 | // WURFL documentation: http://wurfl.sourceforge.net/help_doc.php |
505 | 519 | // Determine the kind of markup |
506 | | - if ( is_array( $props ) && $props['preferred_markup'] ) { |
| 520 | + if ( is_array( $props ) && isset( $props['preferred_markup'] ) && $props['preferred_markup'] ) { |
507 | 521 | // wfDebug( __METHOD__ . ": preferred markup for this device: " . $props['preferred_markup'] ); |
508 | 522 | // xhtml/html: html_web_3_2, html_web_4_0 |
509 | 523 | // xthml basic/xhtmlmp (wap 2.0): html_wi_w3_xhtmlbasic html_wi_oma_xhtmlmp_1_0 |
— | — | @@ -538,6 +552,9 @@ |
539 | 553 | return true; |
540 | 554 | } |
541 | 555 | |
| 556 | + /** |
| 557 | + * @param $value string |
| 558 | + */ |
542 | 559 | private function setOptInOutCookie( $value ) { |
543 | 560 | global $wgCookieDomain, $wgRequest; |
544 | 561 | wfProfileIn( __METHOD__ ); |
— | — | @@ -548,6 +565,9 @@ |
549 | 566 | wfProfileOut( __METHOD__ ); |
550 | 567 | } |
551 | 568 | |
| 569 | + /** |
| 570 | + * @return string |
| 571 | + */ |
552 | 572 | private function getBaseDomain() { |
553 | 573 | wfProfileIn( __METHOD__ ); |
554 | 574 | // Validates value as IP address |
— | — | @@ -557,12 +577,15 @@ |
558 | 578 | // Although some browsers will accept cookies without the initial ., » RFC 2109 requires it to be included. |
559 | 579 | wfProfileOut( __METHOD__ ); |
560 | 580 | return '.' . $domainParts[1] . '.' . $domainParts[0]; |
561 | | - } else { |
562 | | - wfProfileOut( __METHOD__ ); |
563 | | - return $_SERVER['HTTP_HOST']; |
564 | 581 | } |
| 582 | + wfProfileOut( __METHOD__ ); |
| 583 | + return $_SERVER['HTTP_HOST']; |
565 | 584 | } |
566 | 585 | |
| 586 | + /** |
| 587 | + * @param $url string |
| 588 | + * @return string |
| 589 | + */ |
567 | 590 | private function getRelativeURL( $url ) { |
568 | 591 | wfProfileIn( __METHOD__ ); |
569 | 592 | $parsedUrl = parse_url( $url ); |
— | — | @@ -572,10 +595,9 @@ |
573 | 596 | $baseUrl = $parsedUrl['scheme'] . '://' . $parsedUrl['host']; |
574 | 597 | $baseUrl = str_replace( $baseUrl, '', $url ); |
575 | 598 | return $baseUrl; |
576 | | - } else { |
577 | | - wfProfileOut( __METHOD__ ); |
578 | | - return $url; |
579 | 599 | } |
| 600 | + wfProfileOut( __METHOD__ ); |
| 601 | + return $url; |
580 | 602 | } |
581 | 603 | |
582 | 604 | private function disableCaching() { |
— | — | @@ -600,6 +622,9 @@ |
601 | 623 | wfProfileOut( __METHOD__ ); |
602 | 624 | } |
603 | 625 | |
| 626 | + /** |
| 627 | + * @return string |
| 628 | + */ |
604 | 629 | private function renderLeaveFeedbackXHTML() { |
605 | 630 | global $wgRequest, $wgUser; |
606 | 631 | wfProfileIn( __METHOD__ ); |
— | — | @@ -628,6 +653,9 @@ |
629 | 654 | return ''; |
630 | 655 | } |
631 | 656 | |
| 657 | + /** |
| 658 | + * @return string |
| 659 | + */ |
632 | 660 | private function renderOptInMobileSiteXHTML() { |
633 | 661 | wfProfileIn( __METHOD__ ); |
634 | 662 | if ( $this->contentFormat == 'XHTML' ) { |
— | — | @@ -649,6 +677,9 @@ |
650 | 678 | return ''; |
651 | 679 | } |
652 | 680 | |
| 681 | + /** |
| 682 | + * @return string |
| 683 | + */ |
653 | 684 | private function renderOptOutMobileSiteXHTML() { |
654 | 685 | wfProfileIn( __METHOD__ ); |
655 | 686 | if ( $this->contentFormat == 'XHTML' ) { |
— | — | @@ -670,6 +701,9 @@ |
671 | 702 | return ''; |
672 | 703 | } |
673 | 704 | |
| 705 | + /** |
| 706 | + * @return string |
| 707 | + */ |
674 | 708 | private function renderDisableMobileSiteXHTML() { |
675 | 709 | wfProfileIn( __METHOD__ ); |
676 | 710 | if ( $this->contentFormat == 'XHTML' ) { |
— | — | @@ -692,6 +726,10 @@ |
693 | 727 | return ''; |
694 | 728 | } |
695 | 729 | |
| 730 | + /** |
| 731 | + * @param $matches array |
| 732 | + * @return string |
| 733 | + */ |
696 | 734 | private function headingTransformCallbackWML( $matches ) { |
697 | 735 | wfProfileIn( __METHOD__ ); |
698 | 736 | static $headings = 0; |
— | — | @@ -705,6 +743,10 @@ |
706 | 744 | return $base; |
707 | 745 | } |
708 | 746 | |
| 747 | + /** |
| 748 | + * @param $matches array |
| 749 | + * @return string |
| 750 | + */ |
709 | 751 | private function headingTransformCallbackXHTML( $matches ) { |
710 | 752 | wfProfileIn( __METHOD__ ); |
711 | 753 | if ( isset( $matches[0] ) ) { |
— | — | @@ -720,13 +762,13 @@ |
721 | 763 | ++$headings; |
722 | 764 | // Back to top link |
723 | 765 | $base = Html::openElement( 'div', |
724 | | - array( 'id' => 'anchor_' . intval( $headings - 1 ), |
725 | | - 'class' => 'section_anchors', ) |
| 766 | + array( 'id' => 'anchor_' . intval( $headings - 1 ), |
| 767 | + 'class' => 'section_anchors', ) |
726 | 768 | ) . |
727 | 769 | Html::rawElement( 'a', |
728 | 770 | array( 'href' => '#section_' . intval( $headings - 1 ), |
729 | 771 | 'class' => 'back_to_top' ), |
730 | | - '↑' . $backToTop ) . |
| 772 | + '↑' . $backToTop ) . |
731 | 773 | Html::closeElement( 'div' ); |
732 | 774 | // generate the HTML we are going to inject |
733 | 775 | $buttons = Html::element( 'button', |
— | — | @@ -789,8 +831,11 @@ |
790 | 832 | return $s; |
791 | 833 | } |
792 | 834 | |
| 835 | + /** |
| 836 | + * @param $s string |
| 837 | + * @return string |
| 838 | + */ |
793 | 839 | private function createWMLCard( $s ) { |
794 | | - global $wgRequest; |
795 | 840 | wfProfileIn( __METHOD__ ); |
796 | 841 | $segments = explode( $this->WMLSectionSeperator, $s ); |
797 | 842 | $card = ''; |
— | — | @@ -833,6 +878,9 @@ |
834 | 879 | return $card; |
835 | 880 | } |
836 | 881 | |
| 882 | + /** |
| 883 | + * @return array |
| 884 | + */ |
837 | 885 | private function parseItemsToRemove() { |
838 | 886 | global $wgMFRemovableClasses; |
839 | 887 | wfProfileIn( __METHOD__ ); |
— | — | @@ -851,6 +899,9 @@ |
852 | 900 | return $itemToRemoveRecords; |
853 | 901 | } |
854 | 902 | |
| 903 | + /** |
| 904 | + * @param $html string |
| 905 | + */ |
855 | 906 | public function DOMParseMainPage( $html ) { |
856 | 907 | wfProfileIn( __METHOD__ ); |
857 | 908 | $html = mb_convert_encoding( $html, 'HTML-ENTITIES', "UTF-8" ); |
— | — | @@ -907,8 +958,12 @@ |
908 | 959 | return $contentHtml; |
909 | 960 | } |
910 | 961 | |
| 962 | + /** |
| 963 | + * @param $html string |
| 964 | + * @return string |
| 965 | + */ |
911 | 966 | public function DOMParse( $html ) { |
912 | | - global $wgSitename, $wgScript; |
| 967 | + global $wgScript; |
913 | 968 | wfProfileIn( __METHOD__ ); |
914 | 969 | $html = mb_convert_encoding( $html, 'HTML-ENTITIES', "UTF-8" ); |
915 | 970 | libxml_use_internal_errors( true ); |
— | — | @@ -958,7 +1013,7 @@ |
959 | 1014 | foreach ( $itemToRemoveRecords['ID'] as $itemToRemove ) { |
960 | 1015 | $itemToRemoveNode = $this->doc->getElementById( $itemToRemove ); |
961 | 1016 | if ( $itemToRemoveNode ) { |
962 | | - $removedItemToRemove = $itemToRemoveNode->parentNode->removeChild( $itemToRemoveNode ); |
| 1017 | + $itemToRemoveNode->parentNode->removeChild( $itemToRemoveNode ); |
963 | 1018 | } |
964 | 1019 | } |
965 | 1020 | |
— | — | @@ -968,7 +1023,7 @@ |
969 | 1024 | $elements = $xpath->query( '//*[@class="' . $classToRemove . '"]' ); |
970 | 1025 | |
971 | 1026 | foreach ( $elements as $element ) { |
972 | | - $removedElement = $element->parentNode->removeChild( $element ); |
| 1027 | + $element->parentNode->removeChild( $element ); |
973 | 1028 | } |
974 | 1029 | } |
975 | 1030 | |
— | — | @@ -1008,9 +1063,6 @@ |
1009 | 1064 | $contentHtml = $this->DOMParseMainPage( $contentHtml ); |
1010 | 1065 | } |
1011 | 1066 | |
1012 | | - $title = htmlspecialchars( self::$title->getText() ); |
1013 | | - $htmlTitle = htmlspecialchars( self::$htmlTitle ); |
1014 | | - |
1015 | 1067 | if ( strlen( $contentHtml ) > 4000 && $this->contentFormat == 'XHTML' |
1016 | 1068 | && self::$device['supports_javascript'] === true |
1017 | 1069 | && empty( self::$search ) && !self::$isMainPage ) { |