Jdlrobson has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/59785


Change subject: Alpha: Generate dynamic sections using templates
......................................................................

Alpha: Generate dynamic sections using templates

TODO: references

Change-Id: I770c84384593ce96e57cb2be6e0c12aed99e5eeb
---
M MobileFrontend.php
M includes/MobileFormatter.php
M javascripts/common/mf-application.js
M javascripts/common/mf-history-jquery.js
M javascripts/modules/mf-toggle-dynamic.js
M javascripts/views/page.js
A templates/page.html
M tests/javascripts/views/test_page.js
8 files changed, 150 insertions(+), 80 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/MobileFrontend 
refs/changes/85/59785/1

diff --git a/MobileFrontend.php b/MobileFrontend.php
index e3a83a3..c7aaf00 100644
--- a/MobileFrontend.php
+++ b/MobileFrontend.php
@@ -325,6 +325,7 @@
        'localBasePath' => $localBasePath,
        'localTemplateBasePath' => $localBasePath . '/templates',
        'templates' => array(
+               'page',
                'overlays/talk',
                'talkSection',
        ),
diff --git a/includes/MobileFormatter.php b/includes/MobileFormatter.php
index 8cf3c57..e3ea761 100644
--- a/includes/MobileFormatter.php
+++ b/includes/MobileFormatter.php
@@ -162,8 +162,8 @@
                                                $xpath = new DOMXpath( $doc );
                                                $elements = $xpath->query( 
'//*[@class="content_block"]' );
                                                /** @var $element DOMElement */
-                                               foreach ( $elements as $element 
) {
-                                                       
$element->parentNode->removeChild( $element );
+                                               foreach ( $elements as $element 
) { // empty elements
+                                                       $element->nodeValue = 
'';
                                                }
                                                $html = $temp->getText();
                                        }
diff --git a/javascripts/common/mf-application.js 
b/javascripts/common/mf-application.js
index bbc6cab..5b6fac3 100644
--- a/javascripts/common/mf-application.js
+++ b/javascripts/common/mf-application.js
@@ -92,12 +92,6 @@
                window.scrollTo( 0, 1 );
        }
 
-       function triggerPageReadyHook( pageTitle, sectionData, anchorSection ) {
-               emit( 'page-loaded', {
-                       title: pageTitle, data: sectionData, anchorSection: 
anchorSection
-               } );
-       }
-
        // TODO: separate main menu navigation code into separate module
        function init() {
                // FIXME: use wgIsMainPage
@@ -216,7 +210,6 @@
                on: on,
                prefix: 'mw-mf-',
                supportsPositionFixed: supportsPositionFixed,
-               triggerPageReadyHook: triggerPageReadyHook,
                prettyEncodeTitle: prettyEncodeTitle,
                utils: $, // FIXME: deprecate
                template: template
diff --git a/javascripts/common/mf-history-jquery.js 
b/javascripts/common/mf-history-jquery.js
index 0fbad0f..db70e98 100644
--- a/javascripts/common/mf-history-jquery.js
+++ b/javascripts/common/mf-history-jquery.js
@@ -2,6 +2,7 @@
 
        var
                firstRun,
+               Page = M.require( 'page' ),
                makeStubPage,
                updateQueryStringParameter = 
M.history.updateQueryStringParameter,
                getArticleUrl = M.history.getArticleUrl,
@@ -79,56 +80,31 @@
                } );
        }
 
-       // FIXME: use template engine this is not maintainable
        function renderPage( pageTitle, resp, constructPage ) {
-               var i, secs, s, sectionNum = 0, level, text,
-                       $content = $( '#content' ),
-                       $section,
-                       $tmpContainer = $( '<div>' ),
-                       sectionData = {},
-                       anchorSection = {};
-               if ( resp && resp.mobileview && resp.mobileview.sections ) {
-                       secs = resp.mobileview.sections;
-                       for( i = 0; i < secs.length; i++ ) {
-                               s = secs[ i ];
-                               level = s.level;
-                               text = s.text || '';
-                               if ( constructPage && i === 0 ) { // do lead
-                                       $( '#content_0' ).html( text );
-                               }
-                               if ( level === '2' ) {
-                                       sectionNum = sectionNum + 1;
-                                       sectionData[ sectionNum ] = { html: 
text };
-                                       // add self as a parent so that we 
unfold it when needed
-                                       anchorSection[ s.anchor ] = sectionNum;
-                                       anchorSection[ 'section_' + sectionNum 
] = sectionNum;
-                                       if ( constructPage ) {
-                                               $section = $( '<div 
class="section">' ).appendTo( $content );
-                                               // TODO: link these so they are 
clickable
-                                               $( '<h2 
class="section_heading">' ).attr( 'id', 'section_' + sectionNum ).
-                                                       html( s.line 
).appendTo( $section );
-                                       }
-                               } else if ( level ) {
-                                       $tmpContainer.html( text );
-                                       $tmpContainer.prepend( $( '<h' + level 
+ '>' ).attr( 'id', s.anchor ).html( s.line ) );
-                                       sectionData[ sectionNum ].html += 
$tmpContainer.html();
-                                       // we need to know the parent of 
subsection to unfold the proper section
-                                       anchorSection[ s.anchor ] = sectionNum;
-                               }
-                               if( s.hasOwnProperty( 'references' ) ) {
-                                       sectionData[ sectionNum ].references = 
true;
-                                       $( '<div class="content_block">' 
).attr( 'id', 'content_' + sectionNum ).
-                                               html( sectionData[ sectionNum 
].html ).insertAfter( '#section_' + sectionNum );
-                               }
-                       }
-                       updateUILinks( pageTitle );
+               var page, references, $references, options = {
+                       title: pageTitle,
+                       sections: resp.mobileview.sections
+               };
 
-                       if ( resp.mobileview.hasOwnProperty( 'mainpage' ) ) {
-                               M.emit( 'homepage-loaded' );
-                       }
-                       M.triggerPageReadyHook( pageTitle, sectionData, 
anchorSection );
-                       $( '#content_0' ).removeClass( 'loading' ); // reset 
loader
+               if ( constructPage ) {
+                       options.el = $( '#content' )[0];
                }
+
+               page = new Page( options );
+
+               // FIXME: Horrible 4 lines of code to force loading of 
references
+               references = page.getReferenceSection();
+               $references = $( '#content_' + references.index );
+               if ( !$references.hasClass( 'loaded' ) ) {
+                       $references.addClass( 'loaded' ).html( 
references.referenceContent );
+               }
+
+               updateUILinks( pageTitle );
+               $( '#content_0' ).removeClass( 'loading' ); // reset loader
+               if ( resp.mobileview.hasOwnProperty( 'mainpage' ) ) {
+                       M.emit( 'homepage-loaded' );
+               }
+               M.emit( 'page-loaded', page );
        }
 
        loadLanguages = function( title ) {
@@ -229,8 +205,15 @@
                } );
        }
 
+       M.on( 'section-rendered', function( $content ) {
+               // FIXME: this should live in the hidpi module when dynamic 
sections is promoted from beta
+               if ( $content.hidpi ) {
+                       $content.hidpi();
+               }
+               hijackLinks( $content );
+       } );
+
        M.history.makeStubPage = makeStubPage;
-       M.history.hijackLinks = hijackLinks;
        M.history.loadPage = loadPage;
        M.history.navigateToPage = navigateToPage;
 
diff --git a/javascripts/modules/mf-toggle-dynamic.js 
b/javascripts/modules/mf-toggle-dynamic.js
index c61fed5..66de7c9 100644
--- a/javascripts/modules/mf-toggle-dynamic.js
+++ b/javascripts/modules/mf-toggle-dynamic.js
@@ -2,25 +2,18 @@
 
 var T = ( function() {
        var
-               sectionData = {},
-               anchorSection,
+               currentPage,
                footerInitialised = false;
 
        function wm_toggle_section( section_id, keepHash ) {
                var id = 'section_' + section_id, content_id = 'content_' + 
section_id,
-                       closed, sectionInfo = sectionData[ section_id ],
-                       $container,
+                       closed, section = 
currentPage.getSubSections()[section_id-1],
                        $section = $( '#' + id ), $content = $( '#' + 
content_id ),
                        selector = '#' + content_id + ',#' + id;
 
-               if ( sectionInfo && $content.length === 0 ) {
-                       $container = $( '<div class="content_block">' ).attr( 
'id', content_id ).html( sectionInfo.html ).insertAfter( '#' + id );
-                       M.emit( 'section-rendered', $container );
-                       // FIXME: this should live in the hidpi module when 
dynamic sections is promoted from beta
-                       if ( $container.hidpi ) {
-                               $container.hidpi();
-                       }
-                       M.history.hijackLinks( $container );
+               if ( section && !$content.hasClass( 'loaded' ) ) {
+                       $content.addClass( 'loaded' ).html( section.content );
+                       M.emit( 'section-rendered', $content );
                }
 
                $( selector ).toggleClass( 'openSection' );
@@ -33,7 +26,10 @@
        }
 
        function wm_reveal_for_hash( hash, keepHash ) {
-               wm_toggle_section( anchorSection[ hash.slice( 1 ) ], keepHash );
+               var section = currentPage.getParentSection( hash.slice( 1 ) );
+               if ( section ) {
+                       wm_toggle_section( section.index, keepHash );
+               }
        }
 
        function checkHash() {
@@ -73,10 +69,8 @@
                var pageTitle = mw.config.get( 'wgTitle'),
                        specialPage = $( '#content_wrapper' ).hasClass( 
'mw-mf-special' );
 
-               M.on( 'page-loaded', function( article ) {
-                       sectionData = article.data || {};
-
-                       anchorSection = article.anchorSection;
+               M.on( 'page-loaded', function( page ) {
+                       currentPage = page;
                        if ( $( '#content .section_heading' ).length > 1 ) {
                                enableToggling( $( '#content' ) );
                        }
diff --git a/javascripts/views/page.js b/javascripts/views/page.js
index e206694..038a428 100644
--- a/javascripts/views/page.js
+++ b/javascripts/views/page.js
@@ -6,31 +6,41 @@
 
        Section = View.extend( {
                defaults: {
+                       contentClass: '',
+                       referenceContent: '',
                        heading: '',
                        content: '',
+                       index: -1,
                        id: null
                },
                initialize: function( options ) {
+                       this.index = options.index;
                        this.heading = options.heading;
                        this.content = options.content;
+                       this.referenceContent = options.referenceContent;
+                       this.contentClass = options.contentClass;
                        this.id = options.id;
                }
        } );
 
        Page = View.extend( {
+               template: M.template.get( 'page' ),
                defaults: {
-                       heading: '',
+                       title: '',
                        lead: '',
                        sections: []
                },
-               initialize: function( options ) {
+               preRender: function( options ) {
                        var s, i, level, text,
+                               data,
                                $tmpContainer = $( '<div>' ),
                                html, section,
                                sectionNum = 0,
                                secs = options.sections,
                                sectionData = {};
 
+                       this._anchorSection = {};
+                       this.title = options.title;
                        for ( i = 0; i < secs.length; i++ ) {
                                s = secs[ i ];
                                level = s.level;
@@ -41,10 +51,10 @@
                                }
 
                                if ( level === '2' ) {
-                                       sectionNum = sectionNum + 1;
+                                       sectionNum += 1;
+                                       this._anchorSection[ 'section_' + 
sectionNum ] = sectionNum;
                                        sectionData[ sectionNum ] = { content: 
text,
                                                id: s.id, heading: s.line };
-
                                } else if ( level ) {
                                        $tmpContainer.html( text );
                                        $tmpContainer.prepend(
@@ -58,16 +68,51 @@
                                                sectionData[ sectionNum 
].content += html;
                                        }
                                }
+                               if ( s.hasOwnProperty( 'references' ) ) {
+                                       sectionData[ sectionNum ].references = 
true;
+                               }
+                               this._anchorSection[ s.anchor ] = sectionNum;
                        }
+
                        this.sections = [];
                        this._sectionLookup = {};
                        for ( s in sectionData ) {
                                if ( sectionData.hasOwnProperty( s ) ) {
-                                       section = new Section( sectionData[ s ] 
);
+                                       sectionData[ s ].index = 
this.sections.length + 1;
+                                       data = sectionData[ s ];
+                                       if ( data.references ) {
+                                               data.referenceContent = 
data.content;
+                                               data.content = '';
+                                               data.contentClass = 'loaded';
+                                       }
+                                       section = new Section( data );
+                                       if ( data.references ) {
+                                               this._referenceLookup = section;
+                                       }
                                        this.sections.push( section );
                                        this._sectionLookup[ section.id ] = 
section; // allow easy lookup of section
                                }
                        }
+                       options = $.extend( options, {
+                               sections: this.sections,
+                               lead: this.lead
+                       } );
+               },
+               /**
+                * Given an anchor finds the Section it belongs to
+                * objects that extend View.
+                *
+                * @param {string}
+                * @return {Section} Section object that it belongs to
+                */
+               getParentSection: function( anchor ) {
+                       var parentId = this._anchorSection[ anchor ];
+                       if ( parentId ) {
+                               return this.getSubSection( parentId );
+                       }
+               },
+               getReferenceSection: function() {
+                       return this._referenceLookup;
                },
                getSubSection: function( id ) {
                        return this._sectionLookup[ id ];
diff --git a/templates/page.html b/templates/page.html
new file mode 100644
index 0000000..3e19930
--- /dev/null
+++ b/templates/page.html
@@ -0,0 +1,11 @@
+<h1 id="section_0">{{title}}</h1>
+<div id="content_0">{{{lead}}}</div>
+{{#sections}}
+<div class="section">
+       <h2 class="section_heading" id="section_{{id}}">{{{heading}}}</h2>
+       <div class="content_block{{contentClass}}" id="content_{{id}}">
+       {{{referenceContent}}}
+       <!-- content expects to be injected -->
+       </div>
+</div>
+{{/sections}}
diff --git a/tests/javascripts/views/test_page.js 
b/tests/javascripts/views/test_page.js
index 29b0134..fa03966 100644
--- a/tests/javascripts/views/test_page.js
+++ b/tests/javascripts/views/test_page.js
@@ -2,6 +2,27 @@
 
 var Page = M.require( 'page' ),
        nonStandardPage = [{"id":0,"text":""},{"level":"1","line":"Test heading 
h1","anchor":"Test_heading_h1","id":1,"text":"<p>another h1?git fetch 
ssh:\/\/[email protected]:29418\/mediawiki\/extensions\/MobileFrontend 
refs\/changes\/39\/54139\/8 &amp;&amp; git checkout FETCH_HEADgit fetch 
ssh:\/\/[email protected]:29418\/mediawiki\/extensions\/MobileFrontend 
refs\/changes\/39\/54139\/8 &amp;&amp; git checkout FETCH_HEAD\ngit fetch 
ssh:\/\/[email protected]:29418\/mediawiki\/extensions\/MobileFrontend 
refs\/changes\/39\/54139\/8 &amp;&amp; git checkout FETCH_HEAD\ngit fetch 
ssh:\/\/[email protected]:29418\/mediawiki\/extensions\/MobileFrontend 
refs\/changes\/39\/54139\/8 &amp;&amp; git checkout FETCH_HEAD\nv\nv\nv\nvgit 
fetch 
ssh:\/\/[email protected]:29418\/mediawiki\/extensions\/MobileFrontend 
refs\/changes\/39\/54139\/8 &amp;&amp; git checkout FETCH_HEADgit fetch 
ssh:\/\/[email protected]:29418\/mediawiki\/extensions\/MobileFrontend 
refs\/changes\/39\/54139\/8 &amp;&amp; git checkout FETCH_HEAD\ngit fetch 
ssh:\/\/[email protected]:29418\/mediawiki\/extensions\/MobileFrontend 
refs\/changes\/39\/54139\/8 &amp;&amp; git checkout FETCH_HEADgit fetch 
ssh:\/\/[email protected]:29418\/mediawiki\/extensions\/MobileFrontend 
refs\/changes\/39\/54139\/8 &amp;&amp; git checkout FETCH_HEADgit fetch 
ssh:\/\/[email protected]:29418\/mediawiki\/extensions\/MobileFrontend 
refs\/changes\/39\/54139\/8 &amp;&amp; git checkout FETCH_HEAD\nvgit fetch 
ssh:\/\/[email protected]:29418\/mediawiki\/extensions\/MobileFrontend 
refs\/changes\/39\/54139\/8 &amp;&amp; git checkout FETCH_HEAD\ngit fetch 
ssh:\/\/[email protected]:29418\/mediawiki\/extensions\/MobileFrontend 
refs\/changes\/39\/54139\/8 &amp;&amp; git checkout 
FETCH_HEAD\n<\/p>"},{"level":"2","line":"Test heading h2 
(1)","anchor":"Test_heading_h2_.281.29","id":2,"text":"<p>1: You have brains in 
your head. You have feet in your shoes. You can steer yourself any direction 
you choose. You're on your own. And you know what you know. And YOU are the one 
who'll decide where to go...\nSed ut perspiciatis unde omnis iste natus error 
sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa 
quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt 
explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut 
fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi 
nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, 
consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut 
labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, 
quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid 
ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea 
voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem 
eum fugiat quo voluptas nulla pariatur?\nSed ut perspiciatis unde omnis iste 
natus error sit voluptatem accusantium doloremque laudantium, totam rem 
aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae 
vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit 
aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui 
ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum 
quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius 
modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut 
enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit 
laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure 
reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, 
vel illum qui dolorem eum fugiat quo voluptas nulla 
pariatur?\n<\/p>"},{"level":"2","line":"Test heading h2 
2)","anchor":"Test_heading_h2_2.29","id":3,"text":"<p>2: You have brains in 
your head. You have feet in your shoes. You can steer yourself any direction 
you choose. You're on your own. And you know what you know. And YOU are the one 
who'll decide where to go...\nSed ut perspiciatis unde omnis iste natus error 
sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa 
quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt 
explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut 
fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi 
nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, 
consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut 
labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, 
quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid 
ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea 
voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem 
eum fugiat quo voluptas nulla pariatur?\n<\/p>"},{"level":"2","line":"Test 
heading h2 (3)","anchor":"Test_heading_h2_.283.29","id":4,"text":"<p>3: You 
have brains in your head. You have feet in your shoes. You can steer yourself 
any direction you choose. You're on your own. And you know what you know. And 
YOU are the one who'll decide where to go...\n<\/p>"}],
+       referenceSections = [
+               {
+                       "id": 0,
+                       "text": "lead section"
+               },
+               {
+                       "level": "2",
+                       "line": "References",
+                       "anchor": "References",
+                       "id": 1,
+                       "references": '',
+                       "text": "1"
+               },
+               {
+                       "level": "3",
+                       "line": "B",
+                       "anchor": "B",
+                       "id": 2,
+                       "text": "2"
+               }
+       ],
        apiSections =
                [ {
                        "id": 0,
@@ -10,12 +31,14 @@
                {
                        "level": "2",
                        "line": "A",
+                       "anchor": "A",
                        "id": 1,
                        "text": "<p>a</p>"
                },
                {
                        "level": "3",
                        "line": "B",
+                       "anchor": "B",
                        "id": 2,
                        "text": "<p>b<\/p>"
                },
@@ -28,6 +51,7 @@
                {
                        "level": "4",
                        "line": "D",
+                       "anchor": 'DifferentAnchor',
                        "id": 4,
                        "text": "<div>d<\/div>"
                },
@@ -48,7 +72,7 @@
        strictEqual( sections.length, 2, '2 sub sections found' );
        strictEqual( sections[ 0 ].heading, 'A' );
        strictEqual( sections[ 0 ].content,
-               
'<p>a</p><h3>B</h3><p>b</p><h3>C</h3><p>c</p><h4>D</h4><div>d</div>' );
+               '<p>a</p><h3 id="B">B</h3><p>b</p><h3>C</h3><p>c</p><h4 
id="DifferentAnchor">D</h4><div>d</div>' );
        strictEqual( sections[ 1 ].heading, 'F' );
        strictEqual( sections[ 1 ].content, '<p>f</p>' );
        strictEqual( p.getSubSection( 5 ).heading, 'F', 'check correct sub 
section with id 5 found' );
@@ -63,6 +87,25 @@
        strictEqual( p.getSubSections().length, 3, 'There are 3 h2s inside the 
content' );
 } );
 
+
+QUnit.test( 'getParentSection', 5, function() {
+       var p = new Page( { sections: apiSections } );
+       strictEqual( p.getParentSection( 'section_1' ).heading, 'A', 'Check 
anchor is saved for actual section' );
+       strictEqual( p.getParentSection( 'A' ).heading, 'A', 'Finds correct 
parent section (same section)' );
+       strictEqual( p.getParentSection( 'B' ).heading, 'A', 'Finds correct 
parent section' );
+       strictEqual( p.getParentSection( 'DifferentAnchor' ).heading, 'A', 
'Finds correct parent section' );
+       strictEqual( typeof p.getParentSection( 'NonExistantSection' ), 
'undefined', 'Returns nothing if non-existant' );
+} );
+
+QUnit.test( 'getReferences', 4, function() {
+       var p = new Page( { sections: referenceSections } ),
+               sections = p.getSubSections();
+       strictEqual( sections.length, 1, 'Check references are recorded as a 
section' );
+       strictEqual( sections[0].content, '', 'Check content is blank' );
+       strictEqual( sections[0].contentClass, 'loaded', 'Check it is flagged 
as being loaded so as not to interfere with toggle-dynamic' );
+       strictEqual( sections[0].referenceContent, '1<h3 id="B">B</h3>2', 
'Check references set' );
+} );
+
 }( mw.mobileFrontend, jQuery ) );
 
 

-- 
To view, visit https://gerrit.wikimedia.org/r/59785
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I770c84384593ce96e57cb2be6e0c12aed99e5eeb
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/MobileFrontend
Gerrit-Branch: master
Gerrit-Owner: Jdlrobson <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to