Index: trunk/extensions/MobileFrontend/tests/MobileFrontendTest.php |
— | — | @@ -26,6 +26,8 @@ |
27 | 27 | protected function tearDown() { |
28 | 28 | global $wgExtMobileFrontend; |
29 | 29 | unset( $wgExtMobileFrontend ); |
| 30 | + unset( $_SERVER[ 'HTTP_X_DEVICE' ] ); |
| 31 | + ExtMobileFrontend::$useFormat = null; |
30 | 32 | parent::tearDown(); |
31 | 33 | } |
32 | 34 | |
— | — | @@ -102,4 +104,203 @@ |
103 | 105 | $updateMobileUrlHost->invokeArgs( $wgExtMobileFrontend, array( &$parsedUrl ) ); |
104 | 106 | $this->assertEquals( "http://en.wikipedia.org/wiki/mobile/Gustavus_Airport", wfAssembleUrl( $parsedUrl ) ); |
105 | 107 | } |
| 108 | + |
| 109 | + /** |
| 110 | + * @dataProvider updateMobileUrlQueryStringProvider |
| 111 | + */ |
| 112 | + public function testUpdateMobileUrlQueryString( $assert, $useFormat ) { |
| 113 | + global $wgRequest, $wgExtMobileFrontend; |
| 114 | + |
| 115 | + $testMethod = ( $assert ) ? 'assertTrue' : 'assertFalse'; |
| 116 | + $url = 'http://en.wikipedia.org/wiki/Article/?something=bananas'; |
| 117 | + if ( !empty( $useFormat ) ) $url .= "&useformat=" . $useFormat; |
| 118 | + ExtMobileFrontend::$useFormat = $useFormat; |
| 119 | + |
| 120 | + $parsedUrl = wfParseUrl( $url ); |
| 121 | + |
| 122 | + $updateMobileUrlQueryString = self::getMethod( 'updateMobileUrlQueryString' ); |
| 123 | + $updateMobileUrlQueryString->invokeArgs( $wgExtMobileFrontend, array( &$parsedUrl) ); |
| 124 | + |
| 125 | + $targetUrl = wfAssembleUrl( $parsedUrl ); |
| 126 | + $this->$testMethod( $url == $targetUrl, $targetUrl ); |
| 127 | + } |
| 128 | + |
| 129 | + public function updateMobileUrlQueryStringProvider() { |
| 130 | + return array( |
| 131 | + array( true, 'mobile' ), |
| 132 | + array( true, 'mobile-wap' ), |
| 133 | + array( true, '' ), |
| 134 | + ); |
| 135 | + } |
| 136 | + |
| 137 | + /** |
| 138 | + * @dataProvider isMobileDeviceProvider |
| 139 | + */ |
| 140 | + public function testIsMobileDevice( $isDevice, $msg, $xDevice = null ) { |
| 141 | + global $wgReqeust, $wgExtMobileFrontend; |
| 142 | + $isMobileDevice = self::getMethod( 'isMobileDevice' ); |
| 143 | + |
| 144 | + $testMethod = ( $isDevice ) ? 'assertTrue' : 'assertFalse'; |
| 145 | + |
| 146 | + if ( !is_null( $xDevice )) { |
| 147 | + $_SERVER[ 'HTTP_X_DEVICE' ] = $xDevice; |
| 148 | + } |
| 149 | + |
| 150 | + $this->$testMethod( $isMobileDevice->invokeArgs( $wgExtMobileFrontend, array() ), $msg ); |
| 151 | + } |
| 152 | + |
| 153 | + public function isMobileDeviceProvider() { |
| 154 | + return array( |
| 155 | + array( false, 'Nothing set' ), |
| 156 | + array( true, 'HTTP_X_DEVICE = webkit', 'webkit' ), |
| 157 | + ); |
| 158 | + } |
| 159 | + |
| 160 | + /** |
| 161 | + * @dataProvider isFauxMobileDeviceProvider |
| 162 | + */ |
| 163 | + public function testIsFauxMobileDevice( $isFauxDevice, $msg, $useformat=null ) { |
| 164 | + global $wgRequest, $wgExtMobileFrontend; |
| 165 | + $isFauxMobileDevice = self::getMethod( 'isFauxMobileDevice' ); |
| 166 | + |
| 167 | + $testMethod = ( $isFauxDevice ) ? 'assertTrue' : 'assertFalse'; |
| 168 | + |
| 169 | + ExtMobileFrontend::$useFormat = $useformat; |
| 170 | + $this->$testMethod( $isFauxMobileDevice->invokeArgs( $wgExtMobileFrontend, array() ), $msg ); |
| 171 | + } |
| 172 | + |
| 173 | + public function isFauxMobileDeviceProvider() { |
| 174 | + return array( |
| 175 | + array( false, 'Nothing set' ), |
| 176 | + array( true, 'useformat=mobile', 'mobile' ), |
| 177 | + array( true, 'useformat=mobile-wap', 'mobile-wap' ), |
| 178 | + array( false, 'useformat=yourmom', 'yourmom' ), |
| 179 | + ); |
| 180 | + } |
| 181 | + |
| 182 | + /** |
| 183 | + * @dataProvider shouldDisplayMobileViewProvider |
| 184 | + */ |
| 185 | + public function testShouldDisplayMobileView( $shouldDisplay, $xDevice=null, $requestVal=array(), $msg=null ) { |
| 186 | + global $wgRequest, $wgExtMobileFrontend; |
| 187 | + $shouldDisplayMobileView = self::getMethod( 'shouldDisplayMobileView' ); |
| 188 | + |
| 189 | + $testMethod = ( $shouldDisplay ) ? 'assertTrue' : 'assertFalse'; |
| 190 | + |
| 191 | + if ( count( $requestVal )) { |
| 192 | + foreach ( $requestVal as $key => $val ) { |
| 193 | + if ( $key == 'useformat' ) { |
| 194 | + ExtMobileFrontend::$useFormat = $val; |
| 195 | + } else { |
| 196 | + $wgRequest->setVal( $key, $val ); |
| 197 | + } |
| 198 | + } |
| 199 | + } |
| 200 | + |
| 201 | + if ( !is_null( $xDevice )) { |
| 202 | + $_SERVER[ 'HTTP_X_DEVICE' ] = $xDevice; |
| 203 | + } |
| 204 | + |
| 205 | + $this->$testMethod( $shouldDisplayMobileView->invokeArgs( $wgExtMobileFrontend, array() ), $msg ); |
| 206 | + |
| 207 | + // clean up |
| 208 | + if ( count( $requestVal )) { |
| 209 | + foreach ( $requestVal as $key => $val ) { |
| 210 | + if ( $key == 'useformat' ) { |
| 211 | + continue; |
| 212 | + } else { |
| 213 | + $wgRequest->unsetVal( $key ); |
| 214 | + } |
| 215 | + } |
| 216 | + } |
| 217 | + } |
| 218 | + |
| 219 | + public function shouldDisplayMobileViewProvider() { |
| 220 | + return array( |
| 221 | + array( false, null, array() ), |
| 222 | + array( true, 'webkit', array() ), |
| 223 | + array( false, 'webkit', array( 'action' => 'edit' ) ), |
| 224 | + array( false, 'webkit', array( 'mobileaction' => 'view_normal_site' ) ), |
| 225 | + array( true, null, array( 'useformat' => 'mobile-wap' ) ), |
| 226 | + array( false, null, array( 'useformat' => 'mobile-wap', 'action' => 'edit' ) ), |
| 227 | + array( false, null, array( 'useformat' => 'mobile-wap', 'action' => 'history' ) ), |
| 228 | + array( false, null, array( 'useformat' => 'mobile-wap', 'mobileaction' => 'view_normal_site' ) ), |
| 229 | + array( true, null, array( 'useformat' => 'mobile' ) ), |
| 230 | + array( false, null, array( 'useformat' => 'mobile', 'action' => 'edit' ) ), |
| 231 | + array( false, null, array( 'useformat' => 'mobile', 'action' => 'history' ) ), |
| 232 | + array( false, null, array( 'useformat' => 'mobile', 'mobileaction' => 'view_normal_site' ) ), |
| 233 | + ); |
| 234 | + } |
| 235 | + |
| 236 | + /** |
| 237 | + * @dataProvider getXDeviceProvider |
| 238 | + */ |
| 239 | + public function testGetXDevice( $xDevice=null ) { |
| 240 | + global $wgExtMobileFrontend; |
| 241 | + if ( is_null( $xDevice ) ) { |
| 242 | + $assert = ''; |
| 243 | + if ( isset( $_SERVER[ 'HTTP_X_DEVICE' ] ) ) { |
| 244 | + unset( $_SERVER[ 'HTTP_X_DEVICE' ] ); |
| 245 | + } |
| 246 | + } else { |
| 247 | + $_SERVER[ 'HTTP_X_DEVICE' ] = $xDevice; |
| 248 | + $assert = $xDevice; |
| 249 | + } |
| 250 | + $this->assertEquals( $assert, $wgExtMobileFrontend->getXDevice() ); |
| 251 | + } |
| 252 | + |
| 253 | + public function getXDeviceProvider() { |
| 254 | + return array( |
| 255 | + array( 'webkit' ), |
| 256 | + array( null ), |
| 257 | + ); |
| 258 | + } |
| 259 | + |
| 260 | + /** |
| 261 | + * @dataProvider getMobileActionProvider |
| 262 | + */ |
| 263 | + public function testGetMobileAction( $mobileaction=null ) { |
| 264 | + global $wgRequest, $wgExtMobileFrontend; |
| 265 | + |
| 266 | + if ( is_null( $mobileaction )) { |
| 267 | + $assert = ''; |
| 268 | + $wgRequest->unsetVal( 'mobileaction' ); |
| 269 | + } else { |
| 270 | + $wgRequest->setVal( 'mobileaction', $mobileaction ); |
| 271 | + $assert = $mobileaction; |
| 272 | + } |
| 273 | + |
| 274 | + $this->assertEquals( $assert, $wgExtMobileFrontend->getMobileAction() ); |
| 275 | + } |
| 276 | + |
| 277 | + public function getMobileActionProvider() { |
| 278 | + return array( |
| 279 | + array( null ), |
| 280 | + array( 'view_normal_site' ), |
| 281 | + ); |
| 282 | + } |
| 283 | + |
| 284 | + /** |
| 285 | + * @dataProvider getActionProvider |
| 286 | + */ |
| 287 | + public function testGetAction( $action=null ) { |
| 288 | + global $wgRequest, $wgExtMobileFrontend; |
| 289 | + |
| 290 | + if ( is_null( $action )) { |
| 291 | + $assert = ''; |
| 292 | + $wgRequest->unsetVal( 'action' ); |
| 293 | + } else { |
| 294 | + $wgRequest->setVal( 'action', $action ); |
| 295 | + $assert = $action; |
| 296 | + } |
| 297 | + |
| 298 | + $this->assertEquals( $assert, $wgExtMobileFrontend->getAction() ); |
| 299 | + } |
| 300 | + |
| 301 | + public function getActionProvider() { |
| 302 | + return array( |
| 303 | + array( null ), |
| 304 | + array( 'edit' ), |
| 305 | + ); |
| 306 | + } |
106 | 307 | } |
Index: trunk/extensions/MobileFrontend/MobileFrontend.body.php |
— | — | @@ -43,6 +43,21 @@ |
44 | 44 | public static $logoutHtml; |
45 | 45 | public static $loginHtml; |
46 | 46 | public static $zeroRatedBanner; |
| 47 | + |
| 48 | + /** |
| 49 | + * @var string xDevice header information |
| 50 | + */ |
| 51 | + protected $xDevice; |
| 52 | + |
| 53 | + /** |
| 54 | + * @var string MediaWiki 'action' |
| 55 | + */ |
| 56 | + protected $action; |
| 57 | + |
| 58 | + /** |
| 59 | + * @var string |
| 60 | + */ |
| 61 | + protected $mobileAction; |
47 | 62 | |
48 | 63 | /** |
49 | 64 | * @var WmlContext |
— | — | @@ -127,8 +142,7 @@ |
128 | 143 | */ |
129 | 144 | public function testCanonicalRedirect( $request, $title, $output ) { |
130 | 145 | global $wgUsePathInfo; |
131 | | - $xDevice = isset( $_SERVER['HTTP_X_DEVICE'] ) ? $_SERVER['HTTP_X_DEVICE'] : ''; |
132 | | - if ( empty( $xDevice ) ) { |
| 146 | + if ( !$this->shouldDisplayMobileView() ) { |
133 | 147 | return true; // Let the redirect happen |
134 | 148 | } else { |
135 | 149 | if ( $title->getNamespace() == NS_SPECIAL ) { |
— | — | @@ -294,15 +308,14 @@ |
295 | 309 | */ |
296 | 310 | public function beforePageRedirect( $out, &$redirect, &$code ) { |
297 | 311 | wfProfileIn( __METHOD__ ); |
| 312 | + $shouldDisplayMobileView = $this->shouldDisplayMobileView(); |
298 | 313 | if ( $out->getTitle()->isSpecial( 'Userlogin' ) ) { |
299 | | - $xDevice = isset( $_SERVER['HTTP_X_DEVICE'] ) ? $_SERVER['HTTP_X_DEVICE'] : ''; |
300 | | - if ( $xDevice ) { |
| 314 | + if ( $shouldDisplayMobileView ) { |
301 | 315 | $forceHttps = true; |
302 | 316 | $redirect = $this->getMobileUrl( $redirect, $forceHttps ); |
303 | 317 | } |
304 | 318 | } else if ( $out->getTitle()->isSpecial( 'Randompage' ) ) { |
305 | | - $xDevice = isset( $_SERVER['HTTP_X_DEVICE'] ) ? $_SERVER['HTTP_X_DEVICE'] : ''; |
306 | | - if ( $xDevice ) { |
| 319 | + if ( $shouldDisplayMobileView ) { |
307 | 320 | $redirect = $this->getMobileUrl( $redirect ); |
308 | 321 | } |
309 | 322 | } |
— | — | @@ -325,22 +338,15 @@ |
326 | 339 | // Thus, globalized objects will not be available as expected in the function. |
327 | 340 | // This is stated to be intended behavior, as per the following: [http://bugs.php.net/bug.php?id=40104] |
328 | 341 | |
329 | | - $xDevice = isset( $_SERVER['HTTP_X_DEVICE'] ) ? $_SERVER['HTTP_X_DEVICE'] : ''; |
| 342 | + $xDevice = $this->getXDevice(); |
330 | 343 | self::$useFormat = $wgRequest->getText( 'useformat' ); |
331 | 344 | $this->wmlContext->setUseFormat( self::$useFormat ); |
332 | | - $mobileAction = $wgRequest->getText( 'mobileaction' ); |
333 | | - $action = $wgRequest->getText( 'action' ); |
| 345 | + $mobileAction = $this->getMobileAction(); |
334 | 346 | |
335 | | - if ( self::$useFormat !== 'mobile' && self::$useFormat !== 'mobile-wap' && |
336 | | - !$xDevice ) { |
| 347 | + if ( !$this->shouldDisplayMobileView() ) { |
337 | 348 | wfProfileOut( __METHOD__ ); |
338 | 349 | return true; |
339 | 350 | } |
340 | | - if ( $action === 'edit' || $action === 'history' || |
341 | | - $mobileAction === 'view_normal_site' ) { |
342 | | - wfProfileOut( __METHOD__ ); |
343 | | - return true; |
344 | | - } |
345 | 351 | |
346 | 352 | $userAgent = $_SERVER['HTTP_USER_AGENT']; |
347 | 353 | $acceptHeader = isset( $_SERVER["HTTP_ACCEPT"] ) ? $_SERVER["HTTP_ACCEPT"] : ''; |
— | — | @@ -1271,6 +1277,7 @@ |
1272 | 1278 | public function getMobileUrl( $url, $forceHttps = false ) { |
1273 | 1279 | $parsedUrl = wfParseUrl( $url ); |
1274 | 1280 | $this->updateMobileUrlHost( $parsedUrl ); |
| 1281 | + $this->updateMobileUrlQueryString( $parsedUrl ); |
1275 | 1282 | if ( $forceHttps ) { |
1276 | 1283 | $parsedUrl[ 'scheme' ] = 'https'; |
1277 | 1284 | } |
— | — | @@ -1342,6 +1349,20 @@ |
1343 | 1350 | $parsedUrl[ 'path' ] = $wgScriptPath . $templatePathSansToken . $pathSansScriptPath; |
1344 | 1351 | } |
1345 | 1352 | |
| 1353 | + protected function updateMobileUrlQueryString( &$parsedUrl ) { |
| 1354 | + if ( !$this->isFauxMobileDevice() ) { |
| 1355 | + return; |
| 1356 | + } |
| 1357 | + |
| 1358 | + if ( !isset( $parsedUrl[ 'query' ] )) { |
| 1359 | + $parsedUrl[ 'query' ] = 'useformat=' . urlencode( self::$useFormat ); |
| 1360 | + } else { |
| 1361 | + $query = wfCgiToArray( $parsedUrl[ 'query' ] ); |
| 1362 | + $query[ 'useformat' ] = urlencode( self::$useFormat ); |
| 1363 | + $parsedUrl[ 'query' ] = wfArrayToCgi( $query ); |
| 1364 | + } |
| 1365 | + } |
| 1366 | + |
1346 | 1367 | /** |
1347 | 1368 | * Parse mobile URL template into its host and path components. |
1348 | 1369 | * |
— | — | @@ -1377,6 +1398,67 @@ |
1378 | 1399 | } |
1379 | 1400 | } |
1380 | 1401 | |
| 1402 | + protected function isMobileDevice() { |
| 1403 | + $xDevice = $this->getXDevice(); |
| 1404 | + |
| 1405 | + if ( empty( $xDevice )) { |
| 1406 | + return false; |
| 1407 | + } |
| 1408 | + |
| 1409 | + return true; |
| 1410 | + } |
| 1411 | + |
| 1412 | + protected function isFauxMobileDevice() { |
| 1413 | + if ( self::$useFormat !== 'mobile' && self::$useFormat !== 'mobile-wap') { |
| 1414 | + return false; |
| 1415 | + } |
| 1416 | + |
| 1417 | + return true; |
| 1418 | + } |
| 1419 | + |
| 1420 | + protected function shouldDisplayMobileView() { |
| 1421 | + if ( !$this->isMobileDevice() && !$this->isFauxMobileDevice() ) { |
| 1422 | + return false; |
| 1423 | + } |
| 1424 | + |
| 1425 | + $action = $this->getAction(); |
| 1426 | + $mobileAction = $this->getMobileAction(); |
| 1427 | + |
| 1428 | + if ( $action === 'edit' || $action === 'history' || |
| 1429 | + $mobileAction === 'view_normal_site' ) { |
| 1430 | + return false; |
| 1431 | + } |
| 1432 | + |
| 1433 | + return true; |
| 1434 | + } |
| 1435 | + |
| 1436 | + public function getXDevice() { |
| 1437 | + if ( is_null( $this->xDevice ) ) { |
| 1438 | + $this->xDevice = isset( $_SERVER['HTTP_X_DEVICE'] ) ? |
| 1439 | + $_SERVER['HTTP_X_DEVICE'] : ''; |
| 1440 | + } |
| 1441 | + |
| 1442 | + return $this->xDevice; |
| 1443 | + } |
| 1444 | + |
| 1445 | + public function getMobileAction() { |
| 1446 | + global $wgRequest; |
| 1447 | + if ( is_null( $this->mobileAction )) { |
| 1448 | + $this->mobileAction = $wgRequest->getText( 'mobileaction' ); |
| 1449 | + } |
| 1450 | + |
| 1451 | + return $this->mobileAction; |
| 1452 | + } |
| 1453 | + |
| 1454 | + public function getAction() { |
| 1455 | + global $wgRequest; |
| 1456 | + if ( is_null( $this->action )) { |
| 1457 | + $this->action = $wgRequest->getText( 'action' ); |
| 1458 | + } |
| 1459 | + |
| 1460 | + return $this->action; |
| 1461 | + } |
| 1462 | + |
1381 | 1463 | public function getVersion() { |
1382 | 1464 | return __CLASS__ . ': $Id$'; |
1383 | 1465 | } |