Difference between revisions of "MediaWiki:Gadget-AjaxSetListTabs.js"

From Yugipedia
Jump to: navigation, search
(top: Restoring revision 4843897 by User:Becasita on 2021-12-14 22:40:05. Add timeout to the set lists request.)
(Tag: New user edit)
 
(document that blanket-removing `style` elements could theoretically come back to bite us (since if it ever *does* this will probably save some time finding the cause), but for now it's fine)
 
(4 intermediate revisions by one other user not shown)
Line 7: Line 7:
 
( function _gadgetAjaxSetListTabs( window, $, mw, console ) {
 
( function _gadgetAjaxSetListTabs( window, $, mw, console ) {
 
"use strict";
 
"use strict";
var LAST_LOG = '22:39, 14 December 2021 (UTC)';
+
 
 +
var LAST_LOG = '18:45, 26 February 2024 (UTC)';
 +
 
 
function getListData( setListPagePath ) {
 
function getListData( setListPagePath ) {
 
return $.ajax( {
 
return $.ajax( {
Line 15: Line 17:
 
} );
 
} );
 
}
 
}
 +
 
function parseData( data ) {
 
function parseData( data ) {
 
return $( '<div>' )
 
return $( '<div>' )
 
.append( $.parseHTML( data ) )
 
.append( $.parseHTML( data ) )
 
.find( '#mw-content-text .mw-parser-output' )
 
.find( '#mw-content-text .mw-parser-output' )
.children()
+
.find('.page-header').remove().end()
.remove( ':first' )
+
// removing all styles theoretically could cause issues if we ever
.remove('.page-header')
+
// add other stuff to set lists, *and* that stuff uses its own
.end()
+
// TemplateStyles, *and* that stuff only gets used on a page's
 +
// non-default list(s), but there's nothing like that currently
 +
// for set lists and nothing like it is planned or even being
 +
// thought about, so for now it's fine
 +
.find('style').remove().end()
 
.html()
 
.html()
 
;
 
;
 
}
 
}
 +
 
function SetListLoader( $container ) {
 
function SetListLoader( $container ) {
 
this.$container = $container;
 
this.$container = $container;
Line 35: Line 43:
 
].join( '' );
 
].join( '' );
 
}
 
}
 +
 
SetListLoader.prototype.resetTimeoutTriesCounter = function() {
 
SetListLoader.prototype.resetTimeoutTriesCounter = function() {
 
this.remainingTimeoutTries = 2;
 
this.remainingTimeoutTries = 2;
 
};
 
};
 +
 
SetListLoader.prototype.makePageRedLink = function() {
 
SetListLoader.prototype.makePageRedLink = function() {
 
var href = [
 
var href = [
Line 44: Line 54:
 
'&action=edit&redlink=1'
 
'&action=edit&redlink=1'
 
].join( '' );
 
].join( '' );
 +
 
var title = [
 
var title = [
 
this.setListFullpagename,
 
this.setListFullpagename,
 
'(page does not exist)'
 
'(page does not exist)'
 
].join( ' ' );
 
].join( ' ' );
 +
 
var redLink = $( '<a>', {
 
var redLink = $( '<a>', {
 
href: href,
 
href: href,
Line 54: Line 66:
 
text: this.setListFullpagename
 
text: this.setListFullpagename
 
} );
 
} );
 +
 
return $( '<p>' ).append( redLink );
 
return $( '<p>' ).append( redLink );
 
};
 
};
 +
 
SetListLoader.prototype.makeError = function() {
 
SetListLoader.prototype.makeError = function() {
 
var self = this;
 
var self = this;
 +
 
var $errorContainer = $( '<div>', {
 
var $errorContainer = $( '<div>', {
 
'class': 'set-list-ajax-tab__error'
 
'class': 'set-list-ajax-tab__error'
 
} );
 
} );
 +
 
var $pageLink = $( '<a>', {
 
var $pageLink = $( '<a>', {
 
href: this.setListPagePath,
 
href: this.setListPagePath,
 
text: this.setListFullpagename
 
text: this.setListFullpagename
 
} );
 
} );
 +
 
var $tryAgainLink = $( '<a>', {
 
var $tryAgainLink = $( '<a>', {
 
href: '#',
 
href: '#',
Line 70: Line 87:
 
click: function( e ) {
 
click: function( e ) {
 
e.preventDefault();
 
e.preventDefault();
 +
 
self.$container.html( self.defaultContent );
 
self.$container.html( self.defaultContent );
 +
 
return self.load();
 
return self.load();
 
}
 
}
 
} );
 
} );
 +
 
var $refreshLink = $( '<a>', {
 
var $refreshLink = $( '<a>', {
 
href: '#',
 
href: '#',
Line 79: Line 99:
 
click: function( e ) {
 
click: function( e ) {
 
e.preventDefault();
 
e.preventDefault();
 +
 
window.location.reload();
 
window.location.reload();
 
}
 
}
 
} );
 
} );
 +
 
return $errorContainer
 
return $errorContainer
 
.append( 'Could not load ' )
 
.append( 'Could not load ' )
Line 92: Line 114:
 
;
 
;
 
};
 
};
 +
 
SetListLoader.prototype.getHtml = function() {
 
SetListLoader.prototype.getHtml = function() {
 
var self = this;
 
var self = this;
 +
 
return getListData( this.setListPagePath )
 
return getListData( this.setListPagePath )
 
.then( parseData )
 
.then( parseData )
Line 100: Line 124:
 
return self.makePageRedLink();
 
return self.makePageRedLink();
 
}
 
}
 +
 
if ( textStatus === 'timeout' && self.remainingTimeoutTries-- > 0 ) {
 
if ( textStatus === 'timeout' && self.remainingTimeoutTries-- > 0 ) {
 
return new Promise( function( resolve ) {
 
return new Promise( function( resolve ) {
Line 107: Line 132:
 
;
 
;
 
}
 
}
 +
 
console.warn(
 
console.warn(
 
'[Gadget]', '[AjaxSetListTabs]',
 
'[Gadget]', '[AjaxSetListTabs]',
Line 112: Line 138:
 
'-', jqXHR, textStatus, error
 
'-', jqXHR, textStatus, error
 
);
 
);
 +
 
return self.makeError();
 
return self.makeError();
 
} )
 
} )
 
;
 
;
 
};
 
};
 +
 +
SetListLoader.prototype.makeTableSortable = function() {
 +
// Adapted from /resources/src/mediawiki/page/ready.js
 +
// Because otherwise would fire at a similar time as the lists loading,
 +
// but the lists loading would always resolve later.
 +
 +
var $sortable = this.$container.find( 'table.sortable' );
 +
 +
if ( $sortable.length ) {
 +
mw.loader.using( 'jquery.tablesorter', function() {
 +
$sortable.tablesorter();
 +
} );
 +
}
 +
};
 +
 
SetListLoader.prototype.display = function( html ) {
 
SetListLoader.prototype.display = function( html ) {
 
this.$container.html( html );
 
this.$container.html( html );
 +
 +
this.makeTableSortable();
 
};
 
};
 +
 
SetListLoader.prototype.load = function() {
 
SetListLoader.prototype.load = function() {
 
this.resetTimeoutTriesCounter();
 
this.resetTimeoutTriesCounter();
 +
 
this.getHtml()
 
this.getHtml()
 
.then( this.display.bind( this ) )
 
.then( this.display.bind( this ) )
 
;
 
;
 
};
 
};
 +
 
function loadLists() {
 
function loadLists() {
 
$( '.set-list-ajax-tab' ).each( function( i, el ) {
 
$( '.set-list-ajax-tab' ).each( function( i, el ) {
 
var $el = $( el );
 
var $el = $( el );
 +
 
new SetListLoader( $el ).load();
 
new SetListLoader( $el ).load();
 
} );
 
} );
 
}
 
}
 +
 
mw.hook( 'wikipage.content' ).add( loadLists );
 
mw.hook( 'wikipage.content' ).add( loadLists );
 +
 
console.log( '[Gadget] AjaxSetListTabs last updated at', LAST_LOG );
 
console.log( '[Gadget] AjaxSetListTabs last updated at', LAST_LOG );
 +
 
} )( window, window.jQuery, window.mediaWiki, window.console );
 
} )( window, window.jQuery, window.mediaWiki, window.console );

Latest revision as of 19:11, 26 February 2024

/**
 * Dynamically load set lists on the set pages.
 * Idea by Deltaneos.
 * @author Becasita
 * @contact [[User:Becasita]]
 */
( function _gadgetAjaxSetListTabs( window, $, mw, console ) {
	"use strict";

	var LAST_LOG = '18:45, 26 February 2024 (UTC)';

	function getListData( setListPagePath ) {
		return $.ajax( {
			url: setListPagePath,
			dataType: 'html',
			timeout: 5000
		} );
	}

	function parseData( data ) {
		return $( '<div>' )
			.append( $.parseHTML( data ) )
			.find( '#mw-content-text .mw-parser-output' )
				.find('.page-header').remove().end()
				// removing all styles theoretically could cause issues if we ever
				// add other stuff to set lists, *and* that stuff uses its own
				// TemplateStyles, *and* that stuff only gets used on a page's
				// non-default list(s), but there's nothing like that currently
				// for set lists and nothing like it is planned or even being
				// thought about, so for now it's fine
				.find('style').remove().end()
				.html()
		;
	}

	function SetListLoader( $container ) {
		this.$container = $container;
		this.defaultContent = $container.html();
		this.setListFullpagename = $container.data( 'page' );
		this.setListPagePath = [
			/wiki/,
			window.encodeURI( this.setListFullpagename )
		].join( '' );
	}

	SetListLoader.prototype.resetTimeoutTriesCounter = function() {
		this.remainingTimeoutTries = 2;
	};

	SetListLoader.prototype.makePageRedLink = function() {
		var href = [
			'/index.php?title=',
			window.encodeURI( this.setListFullpagename ),
			'&action=edit&redlink=1'
		].join( '' );

		var title = [
			this.setListFullpagename,
			'(page does not exist)'
		].join( ' ' );

		var redLink = $( '<a>', {
			href: href,
			'class': 'new',
			title: title,
			text: this.setListFullpagename
		} );

		return $( '<p>' ).append( redLink );
	};

	SetListLoader.prototype.makeError = function() {
		var self = this;

		var $errorContainer = $( '<div>', {
			'class': 'set-list-ajax-tab__error'
		} );

		var $pageLink = $( '<a>', {
			href: this.setListPagePath,
			text: this.setListFullpagename
		} );

		var $tryAgainLink = $( '<a>', {
			href: '#',
			text: 'try again',
			click: function( e ) {
				e.preventDefault();

				self.$container.html( self.defaultContent );

				return self.load();
			}
		} );

		var $refreshLink = $( '<a>', {
			href: '#',
			text: 'refresh this page',
			click: function( e ) {
				e.preventDefault();

				window.location.reload();
			}
		} );

		return $errorContainer
			.append( 'Could not load ' )
			.append( $pageLink )
			.append( '. Please ' )
			.append( $tryAgainLink )
			.append( ' or ' )
			.append( $refreshLink )
			.append( '.' )
		;
	};

	SetListLoader.prototype.getHtml = function() {
		var self = this;

		return getListData( this.setListPagePath )
			.then( parseData )
			[ 'catch' ]( function( jqXHR, textStatus, error ) {
				if ( jqXHR.status === 404 ) {
					return self.makePageRedLink();
				}

				if ( textStatus === 'timeout' && self.remainingTimeoutTries-- > 0 ) {
					return new Promise( function( resolve ) {
						window.setTimeout( resolve, Math.random() * 5000 );
					} )
						.then( self.getHtml.bind( self ) )
					;
				}

				console.warn(
					'[Gadget]', '[AjaxSetListTabs]',
					'Error loading', self.setListFullpagename,
					'-', jqXHR, textStatus, error
				);

				return self.makeError();
			} )
		;
	};

	SetListLoader.prototype.makeTableSortable = function() {
		// Adapted from /resources/src/mediawiki/page/ready.js
		// Because otherwise would fire at a similar time as the lists loading,
		// but the lists loading would always resolve later.

		var $sortable = this.$container.find( 'table.sortable' );

		if ( $sortable.length ) {
			mw.loader.using( 'jquery.tablesorter', function() {
				$sortable.tablesorter();
			} );
		}
	};

	SetListLoader.prototype.display = function( html ) {
		this.$container.html( html );

		this.makeTableSortable();
	};

	SetListLoader.prototype.load = function() {
		this.resetTimeoutTriesCounter();

		this.getHtml()
			.then( this.display.bind( this ) )
		;
	};

	function loadLists() {
		$( '.set-list-ajax-tab' ).each( function( i, el ) {
			var $el = $( el );

			new SetListLoader( $el ).load();
		} );
	}

	mw.hook( 'wikipage.content' ).add( loadLists );

	console.log( '[Gadget] AjaxSetListTabs last updated at', LAST_LOG );

} )( window, window.jQuery, window.mediaWiki, window.console );