Merge "Remove not used private member variable mParserWarnings from OutputPage"
[mediawiki.git] / resources / src / mediawiki / page / image-pagination.js
bloba097b1796f9cb3d3054c33579fe51ebc38da6675
1 /*!
2  * Implement AJAX navigation for multi-page images so the user may browse without a full page reload.
3  */
4 ( function ( mw, $ ) {
5         /*jshint latedef:false */
6         var jqXhr, $multipageimage, $spinner,
7                 cache = {},
8                 cacheOrder = [];
10         /* Fetch the next page, caching up to 10 last-loaded pages.
11          * @param {string} url
12          * @return {jQuery.Promise}
13          */
14         function fetchPageData( url ) {
15                 if ( jqXhr && jqXhr.abort ) {
16                         // Prevent race conditions and piling up pending requests
17                         jqXhr.abort();
18                 }
19                 jqXhr = undefined;
21                 // Try the cache
22                 if ( cache[ url ] ) {
23                         // Update access freshness
24                         cacheOrder.splice( $.inArray( url, cacheOrder ), 1 );
25                         cacheOrder.push( url );
26                         return $.Deferred().resolve( cache[ url ] ).promise();
27                 }
29                 // TODO Don't fetch the entire page. Ideally we'd only fetch the content portion or the data
30                 // (thumbnail urls) and update the interface manually.
31                 jqXhr = $.ajax( url ).then( function ( data ) {
32                         return $( data ).find( 'table.multipageimage' ).contents();
33                 } );
35                 // Handle cache updates
36                 jqXhr.done( function ( $contents ) {
37                         jqXhr = undefined;
39                         // Cache the newly loaded page
40                         cache[ url ] = $contents;
41                         cacheOrder.push( url );
43                         // Remove the oldest entry if we're over the limit
44                         if ( cacheOrder.length > 10 ) {
45                                 delete cache[ cacheOrder[ 0 ] ];
46                                 cacheOrder = cacheOrder.slice( 1 );
47                         }
48                 } );
50                 return jqXhr.promise();
51         }
53         /* Fetch the next page and use jQuery to swap the table.multipageimage contents.
54          * @param {string} url
55          * @param {boolean} [hist=false] Whether this is a load triggered by history navigation (if
56          *   true, this function won't push a new history state, for the browser did so already).
57          */
58         function switchPage( url, hist ) {
59                 var $tr, promise;
61                 // Start fetching data (might be cached)
62                 promise = fetchPageData( url );
64                 // Add a new spinner if one doesn't already exist and the data is not already ready
65                 if ( !$spinner && promise.state() !== 'resolved' ) {
66                         $tr = $multipageimage.find( 'tr' );
67                         $spinner = $.createSpinner( {
68                                 size: 'large',
69                                 type: 'block'
70                         } )
71                                 // Copy the old content dimensions equal so that the current scroll position is not
72                                 // lost between emptying the table is and receiving the new contents.
73                                 .css( {
74                                         height: $tr.outerHeight(),
75                                         width: $tr.outerWidth()
76                                 } );
78                         $multipageimage.empty().append( $spinner );
79                 }
81                 promise.done( function ( $contents ) {
82                         $spinner = undefined;
84                         // Replace table contents
85                         $multipageimage.empty().append( $contents.clone() );
87                         bindPageNavigation( $multipageimage );
89                         // Fire hook because the page's content has changed
90                         mw.hook( 'wikipage.content' ).fire( $multipageimage );
92                         // Update browser history and address bar. But not if we came here from a history
93                         // event, in which case the url is already updated by the browser.
94                         if ( history.pushState && !hist ) {
95                                 history.pushState( { tag: 'mw-pagination' }, document.title, url );
96                         }
97                 } );
98         }
100         function bindPageNavigation( $container ) {
101                 $container.find( '.multipageimagenavbox' ).one( 'click', 'a', function ( e ) {
102                         var page, uri;
104                         // Generate the same URL on client side as the one generated in ImagePage::openShowImage.
105                         // We avoid using the URL in the link directly since it could have been manipulated (bug 66608)
106                         page = Number( mw.util.getParamValue( 'page', this.href ) );
107                         uri = new mw.Uri( mw.util.wikiScript() )
108                                 .extend( { title: mw.config.get( 'wgPageName' ), page: page } )
109                                 .toString();
111                         switchPage( uri );
112                         e.preventDefault();
113                 } );
115                 $container.find( 'form[name="pageselector"]' ).one( 'change submit', function ( e ) {
116                         switchPage( this.action + '?' + $( this ).serialize() );
117                         e.preventDefault();
118                 } );
119         }
121         $( function () {
122                 if ( mw.config.get( 'wgCanonicalNamespace' ) !== 'File' ) {
123                         return;
124                 }
125                 $multipageimage = $( 'table.multipageimage' );
126                 if ( !$multipageimage.length ) {
127                         return;
128                 }
130                 bindPageNavigation( $multipageimage );
132                 // Update the url using the History API (if available)
133                 if ( history.pushState && history.replaceState ) {
134                         history.replaceState( { tag: 'mw-pagination' }, '' );
135                         $( window ).on( 'popstate', function ( e ) {
136                                 var state = e.originalEvent.state;
137                                 if ( state && state.tag === 'mw-pagination' ) {
138                                         switchPage( location.href, true );
139                                 }
140                         } );
141                 }
142         } );
143 }( mediaWiki, jQuery ) );