Index: trunk/extensions/MobileFrontend/MobileFormatter.php |
— | — | @@ -4,6 +4,8 @@ |
5 | 5 | * Converts HTML into a mobile-friendly version |
6 | 6 | */ |
7 | 7 | class MobileFormatter { |
| 8 | + const WML_SECTION_SEPARATOR = '***************************************************************************'; |
| 9 | + |
8 | 10 | /** |
9 | 11 | * @var DOMDocument |
10 | 12 | */ |
— | — | @@ -11,7 +13,23 @@ |
12 | 14 | protected $format; |
13 | 15 | protected $removeImages = false; |
14 | 16 | protected $idWhitelist = array(); |
| 17 | + |
15 | 18 | /** |
| 19 | + * @var Ttile |
| 20 | + */ |
| 21 | + protected $title; |
| 22 | + |
| 23 | + protected $enableJavaScript = false; |
| 24 | + protected $expandableSections = false; |
| 25 | + |
| 26 | + private $headings = 0; |
| 27 | + |
| 28 | + /** |
| 29 | + * @var WmlContext |
| 30 | + */ |
| 31 | + protected $wmlContext; |
| 32 | + |
| 33 | + /** |
16 | 34 | * Message cache, false if they should be loaded dynamically |
17 | 35 | * @var Array|bool |
18 | 36 | */ |
— | — | @@ -52,10 +70,15 @@ |
53 | 71 | |
54 | 72 | private $itemsToRemove = array(); |
55 | 73 | |
56 | | - public function __construct( $html, $format ) { |
| 74 | + public function __construct( $html, $title, $format, WmlContext $wmlContext = null ) { |
57 | 75 | wfProfileIn( __METHOD__ ); |
58 | 76 | |
| 77 | + $this->title = $title; |
59 | 78 | $this->format = $format; |
| 79 | + if ( !$wmlContext && $format == 'WML' ) { |
| 80 | + throw new MWException( __METHOD__ . '(): WML context not set' ); |
| 81 | + } |
| 82 | + $this->wmlContext = $wmlContext; |
60 | 83 | |
61 | 84 | $html = mb_convert_encoding( $html, 'HTML-ENTITIES', "UTF-8" ); |
62 | 85 | libxml_use_internal_errors( true ); |
— | — | @@ -89,6 +112,14 @@ |
90 | 113 | return $this->format; |
91 | 114 | } |
92 | 115 | |
| 116 | + public function enableJavaScript( $flag = true ) { |
| 117 | + $this->enableJavaScript = $flag; |
| 118 | + } |
| 119 | + |
| 120 | + public function enableExpandableSections( $flag = true ) { |
| 121 | + $this->expandableSections = $flag; |
| 122 | + } |
| 123 | + |
93 | 124 | /** |
94 | 125 | * Sets whether images should be removed from output |
95 | 126 | * @param bool $flag |
— | — | @@ -208,12 +239,202 @@ |
209 | 240 | wfProfileOut( __METHOD__ ); |
210 | 241 | } |
211 | 242 | |
212 | | - public function getText( $id = false ) { |
| 243 | + public function getText( $id = false, $prependHtml = '', $appendHtml = '' ) { |
| 244 | + wfProfileIn( __METHOD__ ); |
213 | 245 | $element = $id ? $this->doc->getElementById( $id ) : null; |
214 | | - return $this->doc->saveXML( $element, LIBXML_NOEMPTYTAG ); |
| 246 | + $html = $this->doc->saveXML( $element, LIBXML_NOEMPTYTAG ); |
| 247 | + |
| 248 | + switch ( $this->format ) { |
| 249 | + case 'XHTML': |
| 250 | + if ( $this->expandableSections && strlen( $html ) > 4000 ) { |
| 251 | + $html = $this->headingTransform( $html ); |
| 252 | + } |
| 253 | + break; |
| 254 | + case 'WML': |
| 255 | + $html = $this->headingTransform( $html ); |
| 256 | + // Content removal for WML rendering |
| 257 | + $elements = array( 'span', 'div', 'sup', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'sup', 'sub' ); |
| 258 | + foreach ( $elements as $element ) { |
| 259 | + $html = preg_replace( '#</?' . $element . '[^>]*>#is', '', $html ); |
| 260 | + } |
| 261 | + // Content wrapping |
| 262 | + $html = $this->createWMLCard( $html ); |
| 263 | + break; |
| 264 | + } |
| 265 | + |
| 266 | + wfProfileOut( __METHOD__ ); |
| 267 | + return $html; |
215 | 268 | } |
216 | 269 | |
217 | 270 | /** |
| 271 | + * @param $matches array |
| 272 | + * @return string |
| 273 | + */ |
| 274 | + private function headingTransformCallbackWML( $matches ) { |
| 275 | + wfProfileIn( __METHOD__ ); |
| 276 | + static $headings = 0; |
| 277 | + ++$headings; |
| 278 | + |
| 279 | + $base = self::WML_SECTION_SEPARATOR . |
| 280 | + "<h2 class='section_heading' id='section_{$headings}'>{$matches[2]}</h2>"; |
| 281 | + |
| 282 | + $this->headings = $headings; |
| 283 | + wfProfileOut( __METHOD__ ); |
| 284 | + return $base; |
| 285 | + } |
| 286 | + |
| 287 | + /** |
| 288 | + * @param $matches array |
| 289 | + * @return string |
| 290 | + */ |
| 291 | + private function headingTransformCallbackXHTML( $matches ) { |
| 292 | + wfProfileIn( __METHOD__ ); |
| 293 | + if ( isset( $matches[0] ) ) { |
| 294 | + preg_match( '/id="([^"]*)"/', $matches[0], $headlineMatches ); |
| 295 | + } |
| 296 | + |
| 297 | + $headlineId = ( isset( $headlineMatches[1] ) ) ? $headlineMatches[1] : ''; |
| 298 | + |
| 299 | + static $headings = 0; |
| 300 | + $show = $this->msg( 'mobile-frontend-show-button' ); |
| 301 | + $hide = $this->msg( 'mobile-frontend-hide-button' ); |
| 302 | + $backToTop = $this->msg( 'mobile-frontend-back-to-top-of-section' ); |
| 303 | + ++$headings; |
| 304 | + // Back to top link |
| 305 | + $base = Html::openElement( 'div', |
| 306 | + array( 'id' => 'anchor_' . intval( $headings - 1 ), |
| 307 | + 'class' => 'section_anchors', ) |
| 308 | + ) . |
| 309 | + Html::rawElement( 'a', |
| 310 | + array( 'href' => '#section_' . intval( $headings - 1 ), |
| 311 | + 'class' => 'back_to_top' ), |
| 312 | + '↑' . $backToTop ) . |
| 313 | + Html::closeElement( 'div' ); |
| 314 | + // generate the HTML we are going to inject |
| 315 | + $buttons = Html::element( 'button', |
| 316 | + array( 'class' => 'section_heading show', |
| 317 | + 'section_id' => $headings ), |
| 318 | + $show ) . |
| 319 | + Html::element( 'button', |
| 320 | + array( 'class' => 'section_heading hide', |
| 321 | + 'section_id' => $headings ), |
| 322 | + $hide ); |
| 323 | + if ( $this->expandableSections ) { |
| 324 | + $h2OnClick = 'javascript:wm_toggle_section(' . $headings . ');'; |
| 325 | + $base .= Html::openElement( 'h2', |
| 326 | + array( 'class' => 'section_heading', |
| 327 | + 'id' => 'section_' . $headings, |
| 328 | + 'onclick' => $h2OnClick ) ); |
| 329 | + } else { |
| 330 | + $base .= Html::openElement( 'h2', |
| 331 | + array( 'class' => 'section_heading', |
| 332 | + 'id' => 'section_' . $headings ) ); |
| 333 | + } |
| 334 | + $base .= $buttons . |
| 335 | + Html::rawElement( 'span', |
| 336 | + array( 'id' => $headlineId ), |
| 337 | + $matches[2] ) . |
| 338 | + Html::closeElement( 'h2' ) . |
| 339 | + Html::openElement( 'div', |
| 340 | + array( 'class' => 'content_block', |
| 341 | + 'id' => 'content_' . $headings ) ); |
| 342 | + |
| 343 | + if ( $headings > 1 ) { |
| 344 | + // Close it up here |
| 345 | + $base = Html::closeElement( 'div' ) . $base; |
| 346 | + } |
| 347 | + |
| 348 | + $this->headings = $headings; |
| 349 | + wfProfileOut( __METHOD__ ); |
| 350 | + return $base; |
| 351 | + } |
| 352 | + |
| 353 | + /** |
| 354 | + * @param $s string |
| 355 | + * @return string |
| 356 | + */ |
| 357 | + protected function createWMLCard( $s ) { |
| 358 | + wfProfileIn( __METHOD__ ); |
| 359 | + $segments = explode( self::WML_SECTION_SEPARATOR, $s ); |
| 360 | + $card = ''; |
| 361 | + $idx = 0; |
| 362 | + $requestedSegment = htmlspecialchars( $this->wmlContext->getRequestedSegment() ); |
| 363 | + $title = htmlspecialchars( $this->title->getText() ); |
| 364 | + $segmentText = $this->wmlContext->getOnlyThisSegment() |
| 365 | + ? str_replace( self::WML_SECTION_SEPARATOR, '', $s ) |
| 366 | + : $segments[$requestedSegment]; |
| 367 | + |
| 368 | + $card .= "<card id='s{$idx}' title='{$title}'><p>{$segmentText}</p>"; |
| 369 | + $idx = $requestedSegment + 1; |
| 370 | + $segmentsCount = $this->wmlContext->getOnlyThisSegment() |
| 371 | + ? $idx + 1 // @todo: when using from API we don't have the total section count |
| 372 | + : count( $segments ); |
| 373 | + $card .= "<p>" . $idx . "/" . $segmentsCount . "</p>"; |
| 374 | + |
| 375 | + $useFormatParam = ( $this->wmlContext->getUseFormat() ) |
| 376 | + ? '&useformat=' . $this->wmlContext->getUseFormat() |
| 377 | + : ''; |
| 378 | + |
| 379 | + // Title::getLocalUrl doesn't work at this point since PHP 5.1.x, all objects have their destructors called |
| 380 | + // before the output buffer callback function executes. |
| 381 | + // Thus, globalized objects will not be available as expected in the function. |
| 382 | + // This is stated to be intended behavior, as per the following: [http://bugs.php.net/bug.php?id=40104] |
| 383 | + $defaultQuery = wfCgiToArray( preg_replace( '/^.*?(\?|$)/', '', $this->wmlContext->getCurrentUrl() ) ); |
| 384 | + unset( $defaultQuery['seg'] ); |
| 385 | + unset( $defaultQuery['useformat'] ); |
| 386 | + |
| 387 | + $qs = wfArrayToCGI( $defaultQuery ); |
| 388 | + $delimiter = ( !empty( $qs ) ) ? '?' : ''; |
| 389 | + $basePageParts = wfParseUrl( $this->wmlContext->getCurrentUrl() ); |
| 390 | + $basePage = $basePageParts['scheme'] . $basePageParts['delimiter'] . $basePageParts['host'] . $basePageParts['path'] . $delimiter . $qs; |
| 391 | + $appendDelimiter = ( $delimiter === '?' ) ? '&' : '?'; |
| 392 | + |
| 393 | + if ( $idx < $segmentsCount ) { |
| 394 | + $card .= "<p><a href=\"{$basePage}{$appendDelimiter}seg={$idx}{$useFormatParam}\">" |
| 395 | + . $this->msg( 'mobile-frontend-wml-continue' ) . "</a></p>"; |
| 396 | + } |
| 397 | + |
| 398 | + if ( $idx > 1 ) { |
| 399 | + $back_idx = $requestedSegment - 1; |
| 400 | + $card .= "<p><a href=\"{$basePage}{$appendDelimiter}seg={$back_idx}{$useFormatParam}\">" |
| 401 | + . $this->msg( 'mobile-frontend-wml-back' ) . "</a></p>"; |
| 402 | + } |
| 403 | + |
| 404 | + $card .= '</card>'; |
| 405 | + wfProfileOut( __METHOD__ ); |
| 406 | + return $card; |
| 407 | + } |
| 408 | + |
| 409 | + /** |
| 410 | + * @param $s string |
| 411 | + * @return string |
| 412 | + */ |
| 413 | + protected function headingTransform( $s ) { |
| 414 | + wfProfileIn( __METHOD__ ); |
| 415 | + $callback = "headingTransformCallback{$this->format}"; |
| 416 | + |
| 417 | + // Closures are a PHP 5.3 feature. |
| 418 | + // MediaWiki currently requires PHP 5.2.3 or higher. |
| 419 | + // So, using old style for now. |
| 420 | + $s = preg_replace_callback( |
| 421 | + '/<h2(.*)<span class="mw-headline" [^>]*>(.+)<\/span>\w*<\/h2>/', |
| 422 | + array( $this, $callback ), |
| 423 | + $s |
| 424 | + ); |
| 425 | + |
| 426 | + // if we had any, make sure to close the whole thing! |
| 427 | + if ( $this->headings > 0 ) { |
| 428 | + $s = str_replace( |
| 429 | + '<div class="visualClear">', |
| 430 | + '</div><div class="visualClear">', |
| 431 | + $s |
| 432 | + ); |
| 433 | + } |
| 434 | + wfProfileOut( __METHOD__ ); |
| 435 | + return $s; |
| 436 | + } |
| 437 | + |
| 438 | + /** |
218 | 439 | * Returns interface message text |
219 | 440 | * @param string $key: Message key |
220 | 441 | * @return string |
Index: trunk/extensions/MobileFrontend/ApiParseExtender.php |
— | — | @@ -56,8 +56,19 @@ |
57 | 57 | $data = $module->getResultData(); |
58 | 58 | $params = $module->extractRequestParams(); |
59 | 59 | if ( isset( $data['parse']['text'] ) && isset( $params['mobileformat'] ) ) { |
| 60 | + $title = Title::newFromText( $data['parse']['title'] ); |
| 61 | + $context = new WmlContext(); |
| 62 | + $context->setCurrentUrl( $title->getCanonicalURL() ); |
| 63 | + $context->setRequestedSegment( isset( $params['section'] ) |
| 64 | + ? $params['section'] + 1 // Segment numbers start from 1 |
| 65 | + : 0 |
| 66 | + ); |
| 67 | + $context->setUseFormat( 'wml' ); // Force WML links just in case |
| 68 | + $context->setOnlyThisSegment( isset( $params['section'] ) ); |
60 | 69 | $mf = new MobileFormatter( '<body><div id="content">' . $data['parse']['text']['*'] . '</div></body>', |
61 | | - ExtMobileFrontend::parseContentFormat( $params['mobileformat'] ) |
| 70 | + $title, |
| 71 | + ExtMobileFrontend::parseContentFormat( $params['mobileformat'] ), |
| 72 | + $context |
62 | 73 | ); |
63 | 74 | $mf->filterContent(); |
64 | 75 | $data['parse']['text'] = $mf->getText( 'content' ); |
Index: trunk/extensions/MobileFrontend/MobileFrontend.body.php |
— | — | @@ -4,7 +4,6 @@ |
5 | 5 | const VERSION = '0.6.1'; |
6 | 6 | |
7 | 7 | public $contentFormat = ''; |
8 | | - public $WMLSectionSeparator = '***************************************************************************'; |
9 | 8 | |
10 | 9 | /** |
11 | 10 | * @var Title |
— | — | @@ -18,7 +17,6 @@ |
19 | 18 | public static $headings; |
20 | 19 | public static $mainPageUrl; |
21 | 20 | public static $randomPageUrl; |
22 | | - public static $requestedSegment; |
23 | 21 | public static $format; |
24 | 22 | public static $search; |
25 | 23 | public static $callback; |
— | — | @@ -47,6 +45,11 @@ |
48 | 46 | public static $loginHtml; |
49 | 47 | public static $zeroRatedBanner; |
50 | 48 | |
| 49 | + /** |
| 50 | + * @var WmlContext |
| 51 | + */ |
| 52 | + private $wmlContext; |
| 53 | + |
51 | 54 | public static $messageKeys = array( |
52 | 55 | 'mobile-frontend-show-button', |
53 | 56 | 'mobile-frontend-hide-button', |
— | — | @@ -95,6 +98,10 @@ |
96 | 99 | 'mobile-frontend-sopa-notice', |
97 | 100 | ); |
98 | 101 | |
| 102 | + public function __construct() { |
| 103 | + $this->wmlContext = new WmlContext(); |
| 104 | + } |
| 105 | + |
99 | 106 | /** |
100 | 107 | * Work out the site and language name from a database name |
101 | 108 | * @param $site string |
— | — | @@ -378,6 +385,7 @@ |
379 | 386 | |
380 | 387 | $xDevice = isset( $_SERVER['HTTP_X_DEVICE'] ) ? $_SERVER['HTTP_X_DEVICE'] : ''; |
381 | 388 | self::$useFormat = $wgRequest->getText( 'useformat' ); |
| 389 | + $this->wmlContext->setUseFormat( self::$useFormat ); |
382 | 390 | $mobileAction = $wgRequest->getText( 'mobileaction' ); |
383 | 391 | $action = $wgRequest->getText( 'action' ); |
384 | 392 | |
— | — | @@ -460,7 +468,7 @@ |
461 | 469 | |
462 | 470 | self::$format = $wgRequest->getText( 'format' ); |
463 | 471 | self::$callback = $wgRequest->getText( 'callback' ); |
464 | | - self::$requestedSegment = $wgRequest->getText( 'seg', 0 ); |
| 472 | + $this->wmlContext->setRequestedSegment( $wgRequest->getInt( 'seg', 0 ) ); |
465 | 473 | self::$search = $wgRequest->getText( 'search' ); |
466 | 474 | self::$searchField = $wgRequest->getText( 'search', '' ); |
467 | 475 | |
— | — | @@ -913,168 +921,7 @@ |
914 | 922 | } |
915 | 923 | |
916 | 924 | /** |
917 | | - * @param $matches array |
918 | | - * @return string |
919 | | - */ |
920 | | - private function headingTransformCallbackWML( $matches ) { |
921 | | - wfProfileIn( __METHOD__ ); |
922 | | - static $headings = 0; |
923 | | - ++$headings; |
924 | | - |
925 | | - $base = $this->WMLSectionSeparator . |
926 | | - "<h2 class='section_heading' id='section_{$headings}'>{$matches[2]}</h2>"; |
927 | | - |
928 | | - self::$headings = $headings; |
929 | | - wfProfileOut( __METHOD__ ); |
930 | | - return $base; |
931 | | - } |
932 | | - |
933 | | - /** |
934 | | - * @param $matches array |
935 | | - * @return string |
936 | | - */ |
937 | | - private function headingTransformCallbackXHTML( $matches ) { |
938 | | - wfProfileIn( __METHOD__ ); |
939 | | - if ( isset( $matches[0] ) ) { |
940 | | - preg_match( '/id="([^"]*)"/', $matches[0], $headlineMatches ); |
941 | | - } |
942 | | - |
943 | | - $headlineId = ( isset( $headlineMatches[1] ) ) ? $headlineMatches[1] : ''; |
944 | | - |
945 | | - static $headings = 0; |
946 | | - $show = self::$messages['mobile-frontend-show-button']; |
947 | | - $hide = self::$messages['mobile-frontend-hide-button']; |
948 | | - $backToTop = self::$messages['mobile-frontend-back-to-top-of-section']; |
949 | | - ++$headings; |
950 | | - // Back to top link |
951 | | - $base = Html::openElement( 'div', |
952 | | - array( 'id' => 'anchor_' . intval( $headings - 1 ), |
953 | | - 'class' => 'section_anchors', ) |
954 | | - ) . |
955 | | - Html::rawElement( 'a', |
956 | | - array( 'href' => '#section_' . intval( $headings - 1 ), |
957 | | - 'class' => 'back_to_top' ), |
958 | | - '↑' . $backToTop ) . |
959 | | - Html::closeElement( 'div' ); |
960 | | - // generate the HTML we are going to inject |
961 | | - $buttons = Html::element( 'button', |
962 | | - array( 'class' => 'section_heading show', |
963 | | - 'section_id' => $headings ), |
964 | | - $show ) . |
965 | | - Html::element( 'button', |
966 | | - array( 'class' => 'section_heading hide', |
967 | | - 'section_id' => $headings ), |
968 | | - $hide ); |
969 | | - if ( self::$device['supports_javascript'] ) { |
970 | | - $h2OnClick = 'javascript:wm_toggle_section(' . $headings . ');'; |
971 | | - $base .= Html::openElement( 'h2', |
972 | | - array( 'class' => 'section_heading', |
973 | | - 'id' => 'section_' . $headings, |
974 | | - 'onclick' => $h2OnClick ) ); |
975 | | - } else { |
976 | | - $base .= Html::openElement( 'h2', |
977 | | - array( 'class' => 'section_heading', |
978 | | - 'id' => 'section_' . $headings ) ); |
979 | | - } |
980 | | - $base .= $buttons . |
981 | | - Html::rawElement( 'span', |
982 | | - array( 'id' => $headlineId ), |
983 | | - $matches[2] ) . |
984 | | - Html::closeElement( 'h2' ) . |
985 | | - Html::openElement( 'div', |
986 | | - array( 'class' => 'content_block', |
987 | | - 'id' => 'content_' . $headings ) ); |
988 | | - |
989 | | - if ( $headings > 1 ) { |
990 | | - // Close it up here |
991 | | - $base = Html::closeElement( 'div' ) . $base; |
992 | | - } |
993 | | - |
994 | | - self::$headings = $headings; |
995 | | - wfProfileOut( __METHOD__ ); |
996 | | - return $base; |
997 | | - } |
998 | | - |
999 | | - /** |
1000 | | - * @param $s string |
1001 | | - * @return string |
1002 | | - */ |
1003 | | - public function headingTransform( $s ) { |
1004 | | - wfProfileIn( __METHOD__ ); |
1005 | | - $callback = 'headingTransformCallback'; |
1006 | | - $callback .= $this->contentFormat; |
1007 | | - |
1008 | | - // Closures are a PHP 5.3 feature. |
1009 | | - // MediaWiki currently requires PHP 5.2.3 or higher. |
1010 | | - // So, using old style for now. |
1011 | | - $s = preg_replace_callback( |
1012 | | - '/<h2(.*)<span class="mw-headline" [^>]*>(.+)<\/span>\w*<\/h2>/', |
1013 | | - array( $this, $callback ), |
1014 | | - $s |
1015 | | - ); |
1016 | | - |
1017 | | - // if we had any, make sure to close the whole thing! |
1018 | | - if ( isset( self::$headings ) && self::$headings > 0 ) { |
1019 | | - $s = str_replace( |
1020 | | - '<div class="visualClear">', |
1021 | | - '</div><div class="visualClear">', |
1022 | | - $s |
1023 | | - ); |
1024 | | - } |
1025 | | - wfProfileOut( __METHOD__ ); |
1026 | | - return $s; |
1027 | | - } |
1028 | | - |
1029 | | - /** |
1030 | | - * @param $s string |
1031 | | - * @return string |
1032 | | - */ |
1033 | | - private function createWMLCard( $s ) { |
1034 | | - wfProfileIn( __METHOD__ ); |
1035 | | - $segments = explode( $this->WMLSectionSeparator, $s ); |
1036 | | - $card = ''; |
1037 | | - $idx = 0; |
1038 | | - $requestedSegment = htmlspecialchars( self::$requestedSegment ); |
1039 | | - $title = htmlspecialchars( self::$title->getText() ); |
1040 | | - |
1041 | | - $card .= "<card id='s{$idx}' title='{$title}'><p>{$segments[$requestedSegment]}</p>"; |
1042 | | - $idx = $requestedSegment + 1; |
1043 | | - $segmentsCount = count( $segments ); |
1044 | | - $card .= "<p>" . $idx . "/" . $segmentsCount . "</p>"; |
1045 | | - |
1046 | | - $useFormatParam = ( isset( self::$useFormat ) ) ? '&' . 'useformat=' . self::$useFormat : ''; |
1047 | | - |
1048 | | - // Title::getLocalUrl doesn't work at this point since PHP 5.1.x, all objects have their destructors called |
1049 | | - // before the output buffer callback function executes. |
1050 | | - // Thus, globalized objects will not be available as expected in the function. |
1051 | | - // This is stated to be intended behavior, as per the following: [http://bugs.php.net/bug.php?id=40104] |
1052 | | - $mDefaultQuery = $_GET; |
1053 | | - unset( $mDefaultQuery['seg'] ); |
1054 | | - unset( $mDefaultQuery['useformat'] ); |
1055 | | - |
1056 | | - $qs = wfArrayToCGI( $mDefaultQuery ); |
1057 | | - $delimiter = ( !empty( $qs ) ) ? '?' : ''; |
1058 | | - $basePageParts = wfParseUrl( self::$currentURL ); |
1059 | | - $basePage = $basePageParts['scheme'] . $basePageParts['delimiter'] . $basePageParts['host'] . $basePageParts['path'] . $delimiter . $qs; |
1060 | | - $appendDelimiter = ( $delimiter === '?' ) ? '&' : '?'; |
1061 | | - |
1062 | | - if ( $idx < $segmentsCount ) { |
1063 | | - $card .= "<p><a href=\"{$basePage}{$appendDelimiter}seg={$idx}{$useFormatParam}\">" . self::$messages['mobile-frontend-wml-continue'] . "</a></p>"; |
1064 | | - } |
1065 | | - |
1066 | | - if ( $idx > 1 ) { |
1067 | | - $back_idx = $requestedSegment - 1; |
1068 | | - $card .= "<p><a href=\"{$basePage}{$appendDelimiter}seg={$back_idx}{$useFormatParam}\">" . self::$messages['mobile-frontend-wml-back'] . "</a></p>"; |
1069 | | - } |
1070 | | - |
1071 | | - $card .= '</card>'; |
1072 | | - wfProfileOut( __METHOD__ ); |
1073 | | - return $card; |
1074 | | - } |
1075 | | - |
1076 | | - /** |
1077 | 925 | * @param DOMDocument $mainPage |
1078 | | - * @return string |
1079 | 926 | */ |
1080 | 927 | public function DOMParseMainPage( DOMDocument $mainPage ) { |
1081 | 928 | wfProfileIn( __METHOD__ ); |
— | — | @@ -1122,9 +969,7 @@ |
1123 | 970 | } |
1124 | 971 | } |
1125 | 972 | |
1126 | | - $contentHtml = $mainPage->saveXML( $content, LIBXML_NOEMPTYTAG ); |
1127 | 973 | wfProfileOut( __METHOD__ ); |
1128 | | - return $contentHtml; |
1129 | 974 | } |
1130 | 975 | |
1131 | 976 | /** |
— | — | @@ -1219,8 +1064,9 @@ |
1220 | 1065 | global $wgScript; |
1221 | 1066 | wfProfileIn( __METHOD__ ); |
1222 | 1067 | |
1223 | | - $formatter = new MobileFormatter( $html, $this->contentFormat ); |
| 1068 | + $formatter = new MobileFormatter( $html, self::$title, $this->contentFormat, $this->wmlContext ); |
1224 | 1069 | $formatter->useMessages( self::$messages ); |
| 1070 | + $formatter->enableJavaScript( self::$device['supports_javascript'] ); |
1225 | 1071 | $doc = $formatter->getDoc(); |
1226 | 1072 | |
1227 | 1073 | $zeroRatedBannerElement = $doc->getElementById( 'zero-rated-banner' ); |
— | — | @@ -1290,35 +1136,27 @@ |
1291 | 1137 | } |
1292 | 1138 | |
1293 | 1139 | if ( self::$isMainPage ) { |
1294 | | - $contentHtml = $this->DOMParseMainPage( $doc ); |
1295 | | - } else { |
1296 | | - $content = $doc->getElementById( 'content' ); |
1297 | | - $contentHtml = $doc->saveXML( $content, LIBXML_NOEMPTYTAG ); |
| 1140 | + $this->DOMParseMainPage( $doc ); |
1298 | 1141 | } |
| 1142 | + $prepend = ''; |
| 1143 | + if ( $this->contentFormat == 'WML' ) { |
| 1144 | + // Wml for searching |
| 1145 | + $prepend = '<p><input emptyok="true" format="*M" type="text" name="search" value="" size="16" />' . |
| 1146 | + '<do type="accept" label="' . self::$messages['mobile-frontend-search-submit'] . '">' . |
| 1147 | + '<go href="' . $wgScript . '?title=Special%3ASearch&search=$(search)"></go></do></p>'; |
| 1148 | + } elseif ( $this->contentFormat == 'XHTML' |
| 1149 | + && self::$device['supports_javascript'] === true |
| 1150 | + && empty( self::$search ) && !self::$isMainPage ) |
| 1151 | + { |
| 1152 | + $formatter->enableExpandableSections(); |
| 1153 | + } |
| 1154 | + $contentHtml = $formatter->getText( 'content', $prepend ); |
1299 | 1155 | |
1300 | 1156 | $htmlTitle = htmlspecialchars( self::$htmlTitle ); |
1301 | 1157 | |
1302 | | - if ( strlen( $contentHtml ) > 4000 && $this->contentFormat == 'XHTML' |
1303 | | - && self::$device['supports_javascript'] === true |
1304 | | - && empty( self::$search ) && !self::$isMainPage ) { |
1305 | | - $contentHtml = $this->headingTransform( $contentHtml ); |
1306 | | - } elseif ( $this->contentFormat == 'WML' ) { |
| 1158 | + if ( $this->contentFormat == 'WML' ) { |
1307 | 1159 | header( 'Content-Type: text/vnd.wap.wml' ); |
1308 | | - $contentHtml = $this->headingTransform( $contentHtml ); |
1309 | 1160 | |
1310 | | - // Content removal for WML rendering |
1311 | | - $elements = array( 'span', 'div', 'sup', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'sup', 'sub' ); |
1312 | | - foreach ( $elements as $element ) { |
1313 | | - $contentHtml = preg_replace( '#</?' . $element . '[^>]*>#is', '', $contentHtml ); |
1314 | | - } |
1315 | | - |
1316 | | - // Wml for searching |
1317 | | - $searchWml = '<p><input emptyok="true" format="*M" type="text" name="search" value="" size="16" />' . |
1318 | | - '<do type="accept" label="' . self::$messages['mobile-frontend-search-submit'] . '">' . |
1319 | | - '<go href="' . $wgScript . '?title=Special%3ASearch&search=$(search)"></go></do></p>'; |
1320 | | - $contentHtml = $searchWml . $contentHtml; |
1321 | | - // Content wrapping |
1322 | | - $contentHtml = $this->createWMLCard( $contentHtml ); |
1323 | 1161 | $applicationWmlTemplate = new ApplicationWmlTemplate(); |
1324 | 1162 | $options = array( |
1325 | 1163 | 'mainPageUrl' => self::$mainPageUrl, |
Index: trunk/extensions/MobileFrontend/WmlContext.php |
— | — | @@ -0,0 +1,43 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Provides information for creation of WML cards |
| 6 | + */ |
| 7 | +class WmlContext { |
| 8 | + private $requestedSegment; |
| 9 | + private $useFormat; |
| 10 | + private $currentUrl; |
| 11 | + private $onlyThisSegment = false; |
| 12 | + |
| 13 | + public function getRequestedSegment() { |
| 14 | + return $this->requestedSegment; |
| 15 | + } |
| 16 | + |
| 17 | + public function setRequestedSegment( $value ) { |
| 18 | + $this->requestedSegment = $value; |
| 19 | + } |
| 20 | + |
| 21 | + public function getUseFormat() { |
| 22 | + return $this->useFormat; |
| 23 | + } |
| 24 | + |
| 25 | + public function setUseFormat( $value ) { |
| 26 | + $this->useFormat = $value; |
| 27 | + } |
| 28 | + |
| 29 | + public function getCurrentUrl() { |
| 30 | + return $this->currentUrl; |
| 31 | + } |
| 32 | + |
| 33 | + public function setCurrentUrl( $value ) { |
| 34 | + $this->currentUrl = $value; |
| 35 | + } |
| 36 | + |
| 37 | + public function getOnlyThisSegment() { |
| 38 | + return $this->onlyThisSegment; |
| 39 | + } |
| 40 | + |
| 41 | + public function setOnlyThisSegment( $value ) { |
| 42 | + $this->onlyThisSegment = $value; |
| 43 | + } |
| 44 | +} |
Property changes on: trunk/extensions/MobileFrontend/WmlContext.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 45 | + native |
Index: trunk/extensions/MobileFrontend/MobileFrontend.php |
— | — | @@ -48,6 +48,7 @@ |
49 | 49 | 'CssDetection' => 'CssDetection', |
50 | 50 | 'DeviceDetection' => 'DeviceDetection', |
51 | 51 | 'MobileFormatter' => 'MobileFormatter', |
| 52 | + 'WmlContext' => 'WmlContext', |
52 | 53 | |
53 | 54 | 'MobileFrontendTemplate' => 'templates/MobileFrontendTemplate', |
54 | 55 | 'ApplicationTemplate' => 'templates/ApplicationTemplate', |