MediaWiki:Gadget-PageNumbers-core.js

Văn thư lưu trữ mở Wikisource

Cache: Sau khi lưu biểu mẫu này, phải xóa bộ nhớ đệm (cache) của trình duyệt để những thay đổi hiện ra:

Firefox, Chrome, Safari, Opera — Shift­Reload / Tải lại       Internet Explorer — Ctrl­Refresh / Làm tươi       Konqueror — Reload / Tải lại

Nếu bạn viết mã JavaScript, chú ý đọc hướng dẫn để tránh mâu thuẫn với mã mặc định của mạng.

/* eslint-disable camelcase */

( function ( mw, $ ) {

	function init_setting( variable_name, cookie_name, init ) {
	/* Sets JS variable to (in order of preference):
		1. previously initialized JS variable value
		2. current cookie value
		3. provided init parameter
		4. false

		Then, if cookie was not previously set, set it to current value of JS variable
		(this bit currently disabled)
	*/
		// get current value of appropriate cookie
		var cookie_val = mw.cookie.get( cookie_name );

		// If JS variable was not previously initialized in this page load, set
		// it now to the cookie value.
		self[ variable_name ] = self[ variable_name ] || cookie_val;

		// If JS variable still has no value, use provided init value. If no init
		// value provided, use false.
		if ( typeof self[ variable_name ] === 'undefined' || self[ variable_name ] === null ) {
			self[ variable_name ] = init || false;
		}

		// If JS variable is now the string "false", convert to boolean false
		// (to fix JS confusion where "false" string evaluates to true).
		if ( self[ variable_name ] === 'false' ) {
			self[ variable_name ] = false;
		}
	}

	if ( !self.ws_messages ) {
		self.ws_messages = {};
	}

	window.ws_msg = function ( name ) {
		var m = self.ws_messages[ name ];
		if ( m ) {
			return m;
		} else {
			return name;
		}
	};

	/**
	 * Messages are configurable here
	 */
	self.ws_messages = {
		do: 'Tùy chọn hiển thị',
		displayOptions: 'Tùy chọn hiển thị',
		optlist: 'Tùy chọn hiển thị',
		'p-do': 'Tùy chọn hiển thị',
		page_numbers_hidden: 'Liên kết trang: ẩn',
		page_numbers_displayed: 'Liên kết trang: hiện',
		page_numbers_inline: 'Trang trong văn bản',
		page_numbers_beside: 'Trang kế văn bản',
		layout_name: 'layout_1',
		layout: 'Bố cục'
	};

	// Dynamic layouts
	if ( !self.WSLayouts || $.isEmptyObject( self.WSLayouts ) ) {
		self.WSLayouts = [];
	}

	var standard_layouts = [
		{
			id: 'layout_1',
			name: 'Bố cục 1'
		},
		{
			id: 'layout_2',
			name: 'Bố cục 2'
		},
		{
			id: 'layout_3',
			name: 'Bố cục 3'
		},
		{
			id: 'layout_4',
			name: 'Bố cục 4'
		},
		{
			id: 'layout_5',
			name: 'Bố cục 5'
		}
	];

	// insert at the front of the list
	for ( var sl = standard_layouts.length - 1; sl >= 0; --sl ) {
		self.WSLayouts.unshift( standard_layouts[ sl ] );
	}

	// eslint-disable-next-line no-jquery/no-global-selector
	var $classedContainer = $( '#mw-content-text' );

	function removeClassesWithPrefix( el, prefix ) {
		var classes = el.className.split( ' ' ).filter( function ( c ) {
			return c.lastIndexOf( prefix, 0 ) !== 0;
		} );
		// eslint-disable-next-line mediawiki/class-doc
		el.className = classes.join( ' ' ).trim();
	}

	var layout = ( function () {

			function set_by_name( name, persist ) {

				var selected_layout;
				for ( var i = 0; i < self.WSLayouts.length; ++i ) {
					if ( self.WSLayouts[ i ].name === name ) {
						selected_layout = self.WSLayouts[ i ];
					}
				}

				if ( !selected_layout ) {
					return; // does not exist
				}

				$( '#d-textLayout' ).children( 'a' ).html( selected_layout.name );

				self.layout_name = selected_layout.name;
				if ( persist ) {
					mw.cookie.set( 'layout', name );
				}

				removeClassesWithPrefix( $classedContainer[ 0 ], 'dynlayout-' );
				// eslint-disable-next-line mediawiki/class-doc
				$classedContainer.addClass( 'dynlayout-' + selected_layout.id );

				pagenumbers.refresh_offsets();
			}

			function set_by_number( number, persist ) {
				set_by_name( self.WSLayouts[ number ].name, persist );
			}

			function toggle() {
				var cur = self.WSLayouts.findIndex( function ( l ) {
					return l.name === self.layout_name;
				} );
				set_by_number( ( cur + 1 ) % self.WSLayouts.length, true );
			}

			function isNumeric( candidate ) {
				return !isNaN( parseFloat( candidate ) ) && isFinite( candidate );
			}

			function init() {
				var name;
				// do return if we're already set up
				if ( document.getElementById( 'pageContainer' ) ) {
					return;
				}

				// get_optlist();
				var portletLink = mw.util.addPortletLink(
					'p-do',
					'#',
					ws_msg( 'layout' ),
					'd-textLayout',
					'Loại bố trí động đang hiển thị [alt-l]',
					'l'
				);
				$( portletLink ).on( 'click', function ( e ) {
					e.preventDefault();
					toggle();
				} );

				// remove all these classes to maintain backwards-compatibility
				$( 'div.text, .lefttext, .centertext, .indented-page, .prose' ).removeClass();
				// DynamicFlaw - a independent Div should have been the parent
				// to this 3-into-1 step
				$( '#mw-content-text .mw-parser-output' )
					.contents()
					.not( '.dynlayout-exempt' )
					.wrapAll( '<div id="pageContainer"><div id="regionContainer"><div id="columnContainer"></div></div></div>' );

				// If cookie is not set, default layout is first available option.
				// Use index "0" in case layout name is ever changed.
				init_setting( 'layout_name', 'layout', '0' );

				// If layouts have changed, the cookie might refer to a missing layout
				// in which case, set the first one
				if ( self.WSLayouts.findIndex( function ( l ) {
					return l.name === self.layout_name;
				} ) === -1 ) {
					set_by_number( 0, true );
				}

				if ( self.layout_overrides_have_precedence || !mw.cookie.get( 'layout' ) ) {
					name = $( '#dynamic_layout_overrider' ).text();
				}

				name = name || self.layout_name;

				if ( isNumeric( name ) ) {
					set_by_number( name, false );
				} else if ( name ) {
					set_by_name( name, false );
				} else {
					set_by_number( 0, false );
				}
			}

			return {
				init: init
			};
		}() ),

		pagenumbers = ( function () {

			// some shared variables to avoid selecting these elements repeatedly
			var $container,
				$div_pagenumbers,
				dp_y,
				y_prev,
				$pagenumbers_collection,
				$div_ss,
				$div_highlight,

				show_params = {
					link_text: ws_msg( 'page_numbers_displayed' ),
					visible: true
				},
				hide_params = {
					link_text: ws_msg( 'page_numbers_hidden' ),
					visible: false
				};

			function pagenum_in() {
				if ( self.proofreadpage_disable_highlighting ) {
					return false;
				}
				if ( !$div_highlight ) {
					return false; // could not find it
				}
				var id = this.id.substring( 11 ),

					$page_span = $( document.getElementById( id ) ),
					$next = self.$pagenum_ml.eq( self.$pagenum_ml.index( $page_span ) + 1 );
				if ( $next.length === 0 ) {
					$next = $div_ss;
				}

				// we need to use document offsets in case a page break occurs within
				// a positioned element
				var c_os = $container.offset(),
					ps_os = $page_span.offset(),
					n_os = $next.offset();

				ps_os = {
					top: ps_os.top - c_os.top,
					left: ps_os.left - c_os.left
				};
				n_os = {
					top: n_os.top - c_os.top,
					left: n_os.left - c_os.left
				};

				$div_highlight.css( {
					display: 'block',
					top: ps_os.top + 'px'
				} );
				$div_highlight.children().eq( 0 ).css( {
					height: $page_span.height() + 'px',
					width: ( ps_os.left < 1 ) ? '100%' : ( ( $container.width() - ps_os.left ) + 'px' )
				} );
				// div_ss.height() ~= height of 1 line of text
				$div_highlight.children().eq( 1 ).css( 'height', ( n_os.top - ps_os.top - $page_span.height() ) + 'px' );
				$div_highlight.children().eq( 2 ).css( {
					height: $next.height() + 'px',
					width: n_os.left + 'px'
				} );
				return true;
			}

			function pagenum_out() {
				if ( self.proofreadpage_disable_highlighting ) {
					return false;
				}
				if ( !$div_highlight ) {
					return false; // could not find it
				}
				$div_highlight.css( 'display', 'none' );
				$div_highlight.children().eq( 0 ).css( 'width', '0px' );
				$div_highlight.children().eq( 1 ).css( 'height', '0px' );
				$div_highlight.children().eq( 2 ).css( 'width', '0px' );
				return true;
			}

			function refresh_elem_offset( page_span, $pagenumber ) {
				var y = $( page_span ).offset().top;
				$pagenumber.css( 'top', y - dp_y );
				if ( self.proofreadpage_numbers_visible && y - y_prev.val > 5 ) {
					y_prev.val = y;
					$pagenumber.removeClass( 'pagenumber-invisible' );
				} else {
					$pagenumber.addClass( 'pagenumber-invisible' );
				}
			}

			function refresh_offsets() {
				// do nothing if container is not set up
				if ( self.proofreadpage_numbers_inline || !$div_pagenumbers ) {
					return false;
				}

				dp_y = $div_pagenumbers.offset().top;
				y_prev = {
					val: -10
				};

				var $pagenumber = $pagenumbers_collection.first();

				self.$pagenum_ml.each( function ( i, page_span ) {
					refresh_elem_offset( page_span, $pagenumber );
					$pagenumber = $pagenumber.next();
				} );

				return true;
			}

			var inline_params = {
					elem: 'span',
					link_pre: '&#x0020;[',
					link_post: ']'
				},
				beside_params = {
					elem: 'div',
					link_pre: '[',
					link_post: ']'
				};

			function setup_elem( i, page_span ) {
				var params = self.proofreadpage_numbers_inline ? inline_params : beside_params,

					// styled also by classes: div.pagenumber or span.pagenumber
					$pagenumber = $( '<' + params.elem + '>' )
						.attr( 'id', $.data( page_span, 'pagenumber_id' ) )
						.addClass( 'pagenumber noprint' )
						.append( params.link_pre + $.data( page_span, 'link_str' ) + params.link_post )
						.toggleClass( 'pagenumber-invisible', !self.proofreadpage_numbers_visible );

				if ( !self.proofreadpage_numbers_inline ) {
					refresh_elem_offset( page_span, $pagenumber );
				}

				// clear the span provided by [[MediaWiki:Proofreadpage pagenum template]]
				$( page_span ).find( '.pagenum-inner' ).empty();

				$pagenumber.appendTo(
					self.proofreadpage_numbers_inline ? page_span : $div_pagenumbers );

				$pagenumbers_collection = $pagenumbers_collection.add( $pagenumber );
			}

			function init_elem( i, page_span ) {
				var name = page_span.getAttribute( 'data-page-number' ) || page_span.id,

					// what if two pages have the same number? increment the id
					pagenumber_id = 'pagenumber_' + page_span.id,
					count;

				if ( $pagenumbers_collection.is( '#' + $.escapeSelector( pagenumber_id ) ) ) {
					count = ( $pagenumbers_collection.filter( "[id ^= '" + pagenumber_id + "']" ).length + 1 );
					page_span.id += ( '_' + count );
					pagenumber_id += ( '_' + count );
				}

				$.data( page_span, 'pagenumber_id', pagenumber_id );
				var page_title = decodeURI( page_span.title ).replace( /%26/g, '&' ).replace( /%3F/g, '?' ),
					page_url =
			mw.config.get( 'wgArticlePath' )
				.replace( '$1', encodeURIComponent( page_title.replace( / /g, '_' ) ) )
			// encodeURIComponent encodes '/', which breaks subpages
				.replace( /%2F/g, '/' ),

					// if transcluded Page: (ll) is a redlink then make page class
					// (class_str) a redlink also
					ll = page_span.parentNode.nextSibling,
					class_str = '',
					action_str = '';

				if ( ll && ll.tagName === 'A' && ll.className === 'new' ) {
					class_str = ' class="new" ';
					action_str = '?action=edit&redlink=1';
				}

				$.data(
					page_span,
					'link_str',
					'<a href= "' + page_url + action_str + '"' +
			class_str +
			' title= "' + mw.html.escape( page_title ) + '">' +
			mw.html.escape( name ) +
			'</a>'
				);

				setup_elem( i, page_span );
			}

			function refresh_display() {
				// determine if we need to set things up
				var inited = !$pagenumbers_collection;

				// JQuery collection of all pagenumber elements
				if ( !inited ) {
					$pagenumbers_collection.remove();
				}
				$pagenumbers_collection = $();

				if ( $div_pagenumbers ) {
					$div_pagenumbers.remove();
				}

				if ( !self.proofreadpage_numbers_inline ) {
					// html div container for page numbers stored in shared variable div_pagenumbers

					//  put pagenumbers container div in the outermost layout container
					$div_pagenumbers = $( '<div>' )
						.attr( 'id', 'ct-pagenumbers' )
						.appendTo( 'div#pageContainer' );
					dp_y = $div_pagenumbers.offset().top;
					y_prev = {
						val: -10
					};
				}
				self.$pagenum_ml.each( inited ? init_elem : setup_elem );

				if ( self.proofreadpage_numbers_inline ) {
					$pagenumbers_collection.off( 'mouseenter mouseleave' );
				} else {
					$pagenumbers_collection.on( {
						mouseenter: pagenum_in,
						mouseleave: pagenum_out
					} );
				}
			}

			function toggle_visible() {
				var params = self.proofreadpage_numbers_visible ? hide_params : show_params;

				$pagenumbers_collection.toggleClass( 'pagenumber-invisible', !params.visible );
				$( '#d-pageNumbers_visible' ).children( 'a' ).html( params.link_text );
				self.proofreadpage_numbers_visible = params.visible;
				mw.cookie.set( 'pagenums_visible', params.visible );
			}

			function toggle_inline() {
				// toggle inline view unless layouts are not set up
				self.proofreadpage_numbers_inline = !layout || !self.proofreadpage_numbers_inline;
				$( '#d-pageNumbers_inline' ).children( 'a' )
					.html( ws_msg( self.proofreadpage_numbers_inline ? 'page_numbers_inline' : 'page_numbers_beside' ) );
				mw.cookie.set( 'pagenums_inline', self.proofreadpage_numbers_inline );
				refresh_display();
			}

			function init() {
				// skip if pagenumbers are already set up
				if ( $pagenumbers_collection ) {
					return false;
				}

				// Mark the container as having pagenumbers.
				// Some layouts can use that information.
				$( '#pageContainer' )
					.addClass( 'dynlayout-haspagenums' );

				// get_optlist();
				init_setting( 'proofreadpage_numbers_visible', 'pagenums_visible', true );
				var portletLink = mw.util.addPortletLink(
					'p-do',
					'#',
					self.proofreadpage_numbers_visible ? ws_msg( 'page_numbers_displayed' ) : ws_msg( 'page_numbers_hidden' ),
					'd-pageNumbers_visible',
					'Vị trí trình bày hiện thời của liên kết trang [alt-n]',
					'n'
				);
				$( portletLink ).on( 'click', function ( e ) {
					e.preventDefault();
					toggle_visible();
				} );

				init_setting( 'proofreadpage_numbers_inline', 'pagenums_inline', false );

				// if layouts are not initialized show pagenumbers inline since
				// "beside" view won't work
				if ( !layout ) {
					self.proofreadpage_numbers_inline = true;
				}

				portletLink = mw.util.addPortletLink(
					'p-do',
					'#',
					self.proofreadpage_numbers_inline ? ws_msg( 'page_numbers_inline' ) : ws_msg( 'page_numbers_beside' ),
					'd-pageNumbers_inline',
					'The current positioning used for embedded link presentation [alt-i]',
					'i'
				);

				$( portletLink ).on( 'click', function ( e ) {
					e.preventDefault();
					toggle_inline();
				} );

				var opacity = 'background-color:#000000; opacity:0.2; filter:alpha(opacity=20);';
				// store container for the highlight to shared variable "div_highlight"
				$div_highlight = $( '<div id= "highlight-area" style= "display:none; position:absolute; width:100%;">' +
			'<div style= "' + opacity + ' float:right; width:0px;"><div class= "clearFix"></div></div>' +
			'<div style= "' + opacity + ' width:100%; height:0px; clear:both;"></div>' +
			'<div style= "' + opacity + ' width:0px;"><div class= "clearFix" style= "float:left; clear:both;"></div></div>' +
			'</div>' );

				// assign new div element to shared variable "div_ss"
				$div_ss = $( '<div id= "my-ss"><div class= "clearFix"></div></div>' ); // empty span following some text

				// put divs in the innermost dynamic layout container
				if ( layout ) {
					$container = $( '#columnContainer' )
						.append( $div_highlight );
					$( '.mw-content-ltr' ).append( $div_ss );
				} else {
					$( '.mw-content-ltr' ).append( $div_highlight, $div_ss );
				}

				self.$pagenum_ml = $( '.pagenum' );
				refresh_display();
			}

			return {
				init: init,
				refresh_offsets: refresh_offsets
			};
		}() );

	if ( [ 'view', 'submit', 'purge' ].indexOf( mw.config.get( 'wgAction' ) ) !== -1 ) {
		if ( !self.debug_page_layout &&
			// don't do anything on DoubleWiki or difference comparison views
			document.URL.indexOf( 'match=' ) === -1 &&
			document.URL.indexOf( 'diff=' ) === -1 &&
			( 'self.proofreadpage_source_href' ) ) {

			if ( !$.isEmptyObject( self.WSLayouts ) ) {
				layout.init();
			}

			$( function () {
				// eslint-disable-next-line no-jquery/no-global-selector
				if ( $( '.pagenum' ).length ) {
					pagenumbers.init();

					if ( document.readyState === 'complete' ) {
						$( pagenumbers.refresh_offsets );
					} else {
						$( window ).on( 'load', pagenumbers.refresh_offsets );
					}
				}
			} );
		}
		var position = window.location.hash.substring( 1 );
		if ( position && document.getElementById( position ) ) {
			document.getElementById( position ).scrollIntoView();
		}
	}

	/**
	 * Install the DOM-ready hook to force header and footer content out of
	 * Dynamic Layouts
	 */
	$( function () {

		$( '.acContainer' ).insertAfter( $( 'div.printfooter' ) );

		$( '<div>' )
			.addClass( 'dynlayout-exempt dynlayout-exempt-footer' )
			.insertBefore( 'div#catlinks' )
			.append( $( '.acContainer' ) )
			.append( $( 'div.licenseContainer' ).not( 'div.licenseContainer div.licenseContainer' ) )
			.append( $( '#editform' ) )
			.append( $( '#footertemplate' ) );

		$( '<div>' )
			.addClass( 'dynlayout-exempt dynlayout-exempt-header' )
			.insertBefore( 'div#pageContainer' )
			.prepend( $( 'div#headerContainer' ) )
			.prepend( $( 'div#heederContainer' ) )
			.prepend( $( 'div#heedertemplate' ) )
			.prepend( $( '#mw-previewheader' ) );
	} );

/* eslint-disable-next-line no-undef */
}( mediaWiki, jQuery ) );