Anonymous edits have been disabled on the wiki. If you want to contribute please login or create an account.

Difference between revisions of "MediaWiki:Common.js"

From AppleGamingWiki, the wiki about gaming on M1 Apple silicon Macs
(added MediaWiki:Common.js from PCGW)
 
m (removed windows release dates)
Line 945: Line 945:
 
options: {
 
options: {
 
pre: "{{Infobox game/row/engine|",
 
pre: "{{Infobox game/row/engine|",
post: "}}",
 
ownline: true
 
}
 
}
 
},
 
'infoboxdatewindows': {
 
label: 'Windows release date',
 
action: {
 
type: 'encapsulate',
 
options: {
 
pre: "{{Infobox game/row/date|Windows|",
 
peri: "Month dd, yyyy",
 
 
post: "}}",
 
post: "}}",
 
ownline: true
 
ownline: true

Revision as of 20:13, 14 March 2021

//<nowiki>


/* ===== FIX: Suppress link click on user menu on tablet devices =========================================================================================================================
 * 
 * Fixes the user menu being inaccessible on tablets due to touch events going through to to the user page link.
 *
 * @source https://stackoverflow.com/a/15558423
 *
 */

function fixTabletLinks() {
            if(document.createEvent("TouchEvent")) { // using document.createEvent is more reliable than navigator (Modernizr uses this practice)
                 $("div#personal-bar-flyout > div > a").each(function() { // have to use an `each` here - either a jQuery `each` or a `for(...)` loop

                    var onClick; // this will be a function

                    var firstClick = function() {
                        $("a").trigger("JWUnhover"); // triggering hoverfix reset if any link gets touched

                        onClick = secondClick;
                        return false;
                    };

                    secondClick = function() {
                        onClick = firstClick;
                        return true;
                    };

                    onClick = firstClick;

                    $(this).click(function() {

                        if (Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0) > 800)
                        {
                            return onClick();
                        } else {
                            return true;
                        }
                    });

                    $(this).bind('JWUnhover', function(){ onClick = firstClick; });

                });
            }
        }

try {
  fixTabletLinks();
} catch (e) {
  // Suppress console error if device does not support touch events.
}



/* ===== FUNCTIONALITY : Style pages based on categories =========================================================================================================================
 * 
 * Adds CSS classes to the body tag based on the categories this page belongs to
 *
 * @source https://www.mediawiki.org/wiki/Snippets/Style_pages_based_on_categories
 * @revision 2016-01-18
 *
 */

(function($, mw) {
  var fn = function() {
    var cats = mw.config.get('wgCategories'), newClasses;
    if (cats) {
      newClasses = $.map(cats, function(el) {
        return 'cat-' + encodeURIComponent(el.replace(/[ .]/g, '_')).replace(/%/g, '_');
      }).join(' ');
      $(document.body).addClass(newClasses);
    }
  };
  if (document.body) {
    fn();
  } else {
    $(fn);
  }
})(jQuery, mw);



/* ===== FUNCTIONALITY : System Requirements Tabs =========================================================================================================================
 *
 */

function sysreqTabs() {

    // run tab code only if tabNav exists
    if ($('#tabNav')[0]) {

        // store the number of sysreq tables
        var sysreqcount = $('.sysreq').length

        // run tab code only if there are at least two sysreq tables
        if (sysreqcount > 1) {

            // Make tab nav visible
            $('#tabNav').css('display', 'inline-block');

            // hide sysreq table headings
            $('.sysreq_heading').css('display', 'none');

            // remove tabs for missing tables (if not already removed by the template)
            $('.sysreq_PC_booter')[0] || $('#sysreq_PC_booter').remove();
            $('.sysreq_DOS')[0] || $('#sysreq_DOS').remove();
            $('.sysreq_Windows_3x')[0] || $('#sysreq_Windows_3x').remove();
            $('.sysreq_Windows')[0] || $('#sysreq_Windows').remove();
            $('.sysreq_Mac_OS')[0] || $('#sysreq_Mac_OS').remove();
            $('.sysreq_OS_X')[0] || $('#sysreq_OS_X').remove();
            $('.sysreq_Linux')[0] || $('#sysreq_Linux').remove();

            // find first tab and apply style
            var firstTab = document.querySelector('.sysreqTab:first-child');
            $(firstTab).addClass('selectedTab');

            // ensure table matching first tab is visible (in case page order does not match OS order expected by tab template)
            $('.sysreq').css('display', 'none');
            $('.' + $(firstTab).attr('id')).css('display', 'block');

            // apply table visibility and tab style changes when tabs are clicked
            $('.sysreqTab').click(function() {
                $('.sysreqTab').removeClass('selectedTab');
                $(this).addClass('selectedTab');
                $('.sysreq').css('display', 'none');
                $('.' + $(this).attr('id')).css('display', 'block');
            })

        // remove tabs table if there are fewer than two sysreq tables
        } else {
            $('#tabNav').remove();
        }
    }
}

$(sysreqTabs);



/* ===== FUNCTIONALITY : Extend the WYSIWYG wiki editor with new functions =========================================================================================================================
 *
 */

// Retrieves todays date according to UTC and slices out the YYYY-MM-DD part of it.
var TodaysDateUTC = new Date().toJSON().slice(0,10);

var customizeToolbar = function() {

	// Removes the 'file' tool (the Image-icon) as this makes use of [[File:]] and not the preferred {{Image|}} template.
	$( '#wpTextbox1' ).wikiEditor( 'removeFromToolbar', {
		'section': 'main',
		'group': 'insert',
		'tool': 'file'
	});

	// Removes the 'reference' tool as using the templates are the preferred way of referencing stuff
	$( '#wpTextbox1' ).wikiEditor( 'removeFromToolbar', {
		'section': 'main',
		'group': 'insert',
		'tool': 'reference'
	});

	// Removes the 'redirect' tool as it have been moved to the search group
	$( '#wpTextbox1' ).wikiEditor( 'removeFromToolbar', {
		'section': 'advanced',
		'group': 'insert',
		'tool': 'redirect'
	});


	// Adds a custom Image icon to the insert group
	$( '#wpTextbox1' ).wikiEditor( 'addToToolbar', {
		'section': 'main',
		'group': 'insert',
		'tools': {
			'smile': {
				label: 'Image',
				type: 'button',
				icon: '/w/load.php?modules=oojs-ui.styles.icons-media&image=image&format=rasterized&lang=en&skin=overclocked',
				action: {
					type: 'encapsulate',
					options: {
						pre: "{{Image|",
						peri: "File.png|Caption",
						post: "}}",
						ownline: true
					}
				}
			}
		}
	});


	// Adds a custom Redirect icon to the search group
	$( '#wpTextbox1' ).wikiEditor( 'addToToolbar', {
		'section': 'advanced',
		'group': 'search',
		'tools': {
			'redirect': {
				label: 'Redirect',
				type: 'button',
				icon: '/w/load.php?modules=oojs-ui.styles.icons-content&image=articleRedirect&format=rasterized&lang=en&skin=overclocked',
				action: {
					type: 'encapsulate',
					options: {
						pre: "#REDIRECT [[",
						peri: "Target page name",
						post: "]]",
						ownline: true
					}
				}
			}
		}
	});


	// Adds custom byttons to the advanced > insert group
	$( '#wpTextbox1' ).wikiEditor( 'addToToolbar', {
		'section': 'advanced',
		'group': 'insert',
		'tools': {
			'fixbox': {
				label: 'Fixbox',
				type: 'button',
				icon: '//images.pcgamingwiki.com/d/d8/Editor_Icon_-_Fixbox.svg',
				action: {
					type: 'encapsulate',
					options: {
						pre: "{{Fixbox|description=",
						peri: "Name",
						post: "|ref=<ref>Reference</ref>|fix=\n}}",
						ownline: true
					}
				}
			}
		}
	});


	// Adds custom templates in a new group to the right of the advanced > insert group
	$( '#wpTextbox1' ).wikiEditor( 'addToToolbar', {
		'section': 'advanced',
		'groups': {
			'insert-sections': {
				'label': '',
				'tools': {
					'availabilityrow': {
						label: 'Availability row',
						type: 'button',
						icon: '//images.pcgamingwiki.com/6/67/Editor_Icon_-_Availability_Table_Row.svg',
						action: {
							type: 'encapsulate',
							options: {
								pre: "{{Availability/row| ",
								peri: "store",
								post: " | id | DRM | notes | Key | OS }}",
								ownline: true
							}
						}
					},
					'dlcrow': {
						label: 'DLC row',
						type: 'button',
						icon: '//images.pcgamingwiki.com/9/9f/Editor_Icon_-_DLCrow.svg',
						action: {
							type: 'encapsulate',
							options: {
								pre: "{{DLC/row| ",
								peri: "Name",
								post: " | notes | OS }}",
								ownline: true
							}
						}
					},
					'gamedataconfigrow': {
						label: 'Game data row - config',
						type: 'button',
						icon: '//images.pcgamingwiki.com/0/0c/Editor_Icon_-_Game_Data_Row.svg',
						action: {
							type: 'encapsulate',
							options: {
								pre: "{{Game data/config|",
								peri: "macOS",
								post: "|Path}}",
								ownline: true
							}
						}
					},
					'gamedatasavesrow': {
						label: 'Game data row - saves',
						type: 'button',
						icon: '//images.pcgamingwiki.com/0/0c/Editor_Icon_-_Game_Data_Row.svg',
						action: {
							type: 'encapsulate',
							options: {
								pre: "{{Game data/saves|",
								peri: "macOS",
								post: "|Path}}",
								ownline: true
							}
						}
					},
					'langrow': {
						label: 'Language row',
						type: 'button',
						icon: '//images.pcgamingwiki.com/2/22/Editor_Icon_-_Localizations.svg',
						action: {
							type: 'encapsulate',
							options: {
								pre: "{{L10n/switch \n |language  = ",
								post: "\n |interface = true\n |audio     = \n |subtitles = \n |notes     = \n |fan       = \n |ref       = \n}}",
								ownline: true
							}
						}
					}
				}
			}
		}
	});


	// Adds custom templates in a new group to the right of the advanced > insert-sections group
	$( '#wpTextbox1' ).wikiEditor( 'addToToolbar', {
		'section': 'advanced',
		'groups': {
			'main-templates': {
				'label': '',
				'tools': {
					'reftemplates': {
						label: 'Reference',
						type: 'select',
						list: {
							'refuser': {
								label: 'Checked by user',
								action: {
									type: 'encapsulate',
									options: {
										pre: "<ref>{{Refcheck|user=" + (wgUserName ? wgUserName : "User") + "|date=" + TodaysDateUTC + "|comment=Comment (optional)}}</ref>"
									}
								}
							},
							'refurl': {
								label: 'URL',
								action: {
									type: 'encapsulate',
									options: {
										pre: "<ref>{{Refurl|url=|title=|date=" + TodaysDateUTC + "}}</ref>"
									}
								}
							},
							'refsnippet': {
								label: 'Snippet from URL',
								action: {
									type: 'encapsulate',
									options: {
										pre: "<ref>{{Refurl|url=|title=|date=" + TodaysDateUTC + "|snippet=}}</ref>"
									}
								}
							},
							'cn': {
								label: 'Citation needed',
								action: {
									type: 'encapsulate',
									options: {
										pre: "{{cn|date=" + TodaysDateUTC + "|reason=}}"
									}
								}
							},
							'dubious': {
								label: 'Dubious',
								action: {
									type: 'encapsulate',
									options: {
										pre: "{{dubious|date=" + TodaysDateUTC + "|reason=}}"
									}
								}
							},
							'note': {
								label: 'Note',
								action: {
									type: 'encapsulate',
									options: {
										pre: "{{note|",
										peri: "The content of the note here.",
										post: "}}"
									}
								}
							}
						}
					},
					'termsection': {
						label: 'Term',
						type: 'select',
						list: {
							'categorygeneral': {
								label: 'General:',
							},
							'drm': {
								label: '· DRM',
								action: {
									type: 'encapsulate',
									options: {
										pre: "{{Term|DRM}}"
									}
								}
							},
							'fmv': {
								label: '· FMV (full motion video)',
								action: {
									type: 'encapsulate',
									options: {
										pre: "{{Term|FMV}}"
									}
								}
							},
							'categoryvr': {
								label: 'VR:',
							},
							'hmd': {
								label: '· HMD (head-mounted display)',
								action: {
									type: 'encapsulate',
									options: {
										pre: "{{Term|HMD}}"
									}
								}
							},
							'categorygraphics': {
								label: 'Graphics:',
							},
							'sdr': {
								label: '· SDR',
								action: {
									type: 'encapsulate',
									options: {
										pre: "{{Term|SDR}}"
									}
								}
							},
							'hdr': {
								label: '· HDR (modern HDR)',
								action: {
									type: 'encapsulate',
									options: {
										pre: "{{Term|HDR}}"
									}
								}
							},
							'hdrr': {
								label: '· HDR Rendering ("old-school HDR")',
								action: {
									type: 'encapsulate',
									options: {
										pre: "{{Term|HDR Rendering}}"
									}
								}
							},
							'categoryscaling': {
								label: 'Scaling:',
							},
							'horplus': {
								label: '· Hor+',
								action: {
									type: 'encapsulate',
									options: {
										pre: "{{Term|Hor+}}"
									}
								}
							},
							'vertminus': {
								label: '· Vert-',
								action: {
									type: 'encapsulate',
									options: {
										pre: "{{Term|Vert-}}"
									}
								}
							},
							'letterbox': {
								label: '· Letterbox',
								action: {
									type: 'encapsulate',
									options: {
										pre: "{{Term|Letterbox}}"
									}
								}
							},
							'pillarbox': {
								label: '· Pillarbox',
								action: {
									type: 'encapsulate',
									options: {
										pre: "{{Term|Pillarbox}}"
									}
								}
							},
							'anamorphic': {
								label: '· Anamorphic',
								action: {
									type: 'encapsulate',
									options: {
										pre: "{{Term|Anamorphic}}"
									}
								}
							},
							'pixelbased': {
								label: '· Pixel-based',
								action: {
									type: 'encapsulate',
									options: {
										pre: "{{Term|Pixel-based}}"
									}
								}
							},
							'pixelperfect': {
								label: '· Pixel-perfect / integer scaling',
								action: {
									type: 'encapsulate',
									options: {
										pre: "{{Term|Pixel-perfect}}"
									}
								}
							},
							'stretch': {
								label: '· Stretch',
								action: {
									type: 'encapsulate',
									options: {
										pre: "{{Term|Stretch}}"
									}
								}
							},
							'noscaling': {
								label: '· No scaling',
								action: {
									type: 'encapsulate',
									options: {
										pre: "{{Term|No scaling}}"
									}
								}
							},
							'nearestneighbor': {
								label: '· Nearest-neighbor (algorithm)',
								action: {
									type: 'encapsulate',
									options: {
										pre: "{{Term|Nearest-neighbor}}"
									}
								}
							}
						}
					},
					'filepath': {
						label: 'Path',
						type: 'select',
						list: {
							'categorygeneral': {
								label: 'General:',
							},
							'pathgame': {
								label: '· Path to game',
								action: {
									type: 'encapsulate',
									options: {
										pre: "{{P|game}}"
									}
								}
							},
							'pathlocalized': {
								label: '· Localized folder or file name',
								action: {
									type: 'encapsulate',
									options: {
										pre: "{{LocalizedPath|",
										peri: "Folder or file name",
										post: "}}"
									}
								}
							},
							'pathuid': {
								label: '· User ID',
								action: {
									type: 'encapsulate',
									options: {
										pre: "{{P|uid}}"
									}
								}
							},
							'pathsteam': {
								label: '· Steam install folder',
								action: {
									type: 'encapsulate',
									options: {
										pre: "{{P|steam}}"
									}
								}
							},
							'categoryosx': {
								label: 'macOS:',
							},
							'pathosxhome': {
								label: '· Home folder',
								action: {
									type: 'encapsulate',
									options: {
										pre: "{{P|macoshome}}"
									}
								}
							}
						}
					},
					'seesection': {
						label: 'See...',
						type: 'select',
						list: {
							'categoryvideo': {
								label: 'Video:',
							},
							'widescreen': {
								label: '· Widescreen resolution',
								action: {
									type: 'encapsulate',
									options: {
										pre: "See [[#Widescreen resolution|Widescreen resolution]]."
									}
								}
							},
							'multimonitor': {
								label: '· Multi-monitor',
								action: {
									type: 'encapsulate',
									options: {
										pre: "See [[#Multi-monitor|Multi-monitor]]."
									}
								}
							},
							'ultrawidescreen': {
								label: '· Ultra-widescreen',
								action: {
									type: 'encapsulate',
									options: {
										pre: "See [[#Ultra-widescreen|Ultra-widescreen]]."
									}
								}
							},
							'4kultrahd': {
								label: '· 4K Ultra HD',
								action: {
									type: 'encapsulate',
									options: {
										pre: "See [[#4K Ultra HD|4K Ultra HD]]."
									}
								}
							},
							'fieldofview': {
								label: '· Field of view (FOV)',
								action: {
									type: 'encapsulate',
									options: {
										pre: "See [[#Field of view (FOV)|Field of view (FOV)]]."
									}
								}
							},
							'windowed': {
								label: '· Windowed',
								action: {
									type: 'encapsulate',
									options: {
										pre: "See [[#Windowed|Windowed]]."
									}
								}
							},
							'borderless': {
								label: '· Borderless fullscreen windowed',
								action: {
									type: 'encapsulate',
									options: {
										pre: "See [[#Borderless fullscreen windowed|Borderless fullscreen windowed]]."
									}
								}
							},
							'anisotropic': {
								label: '· Anisotropic filtering (AF)',
								action: {
									type: 'encapsulate',
									options: {
										pre: "See [[#Anisotropic filtering (AF)|Anisotropic filtering (AF)]]."
									}
								}
							},
							'antialiasing': {
								label: '· Anti-aliasing (AA)',
								action: {
									type: 'encapsulate',
									options: {
										pre: "See [[#Anti-aliasing (AA)|Anti-aliasing (AA)]]."
									}
								}
							},
							'vsync': {
								label: '· Vertical sync (Vsync)',
								action: {
									type: 'encapsulate',
									options: {
										pre: "See [[#Vertical sync (Vsync)|Vertical sync (Vsync)]]."
									}
								}
							},
							'highframe': {
								label: '· High frame rate',
								action: {
									type: 'encapsulate',
									options: {
										pre: "See [[#High frame rate|High frame rate]]."
									}
								}
							},
							'raytracing': {
								label: '· Ray tracing',
								action: {
									type: 'encapsulate',
									options: {
										pre: "See [[#Ray tracing|Ray tracing]]."
									}
								}
							},
							'colorblind': {
								label: '· Color blind mode',
								action: {
									type: 'encapsulate',
									options: {
										pre: "See [[#Color blind mode|Color blind mode]]."
									}
								}
							},
							'categoryinput': {
								label: 'Input:',
							},
							'remapping': {
								label: '· Remapping',
								action: {
									type: 'encapsulate',
									options: {
										pre: "See [[#Remapping|Remapping]]."
									}
								}
							},
							'mouseaccel': {
								label: '· Mouse acceleration',
								action: {
									type: 'encapsulate',
									options: {
										pre: "See [[#Mouse acceleration|Mouse acceleration]]."
									}
								}
							},
							'controllersupport': {
								label: '· Controller support',
								action: {
									type: 'encapsulate',
									options: {
										pre: "See [[#Controller support|Controller support]]."
									}
								}
							},
							'controllerremap': {
								label: '· Controller remapping',
								action: {
									type: 'encapsulate',
									options: {
										pre: "See [[#Controller remapping|Controller remapping]]."
									}
								}
							},
							'touchscreen': {
								label: '· Touchscreen optimised',
								action: {
									type: 'encapsulate',
									options: {
										pre: "See [[#Touchscreen|Touchscreen]]."
									}
								}
							},
							'categoryvr': {
								label: 'VR:',
							},
							'oculus': {
								label: '· Oculus Rift',
								action: {
									type: 'encapsulate',
									options: {
										pre: "See [[#Oculus Rift|Oculus Rift]]."
									}
								}
							}
						}
					}
				}
			}
		}
	});


	// Adds custom controls to the toolbar
	$( '#wpTextbox1' ).wikiEditor( 'addToToolbar', {
		sections: {
			'section-templates': {
				type: 'toolbar',
				label: 'Sections',
				groups: {
					templates: {
						'label': '',
						'tools': {
							'introduction': {
								label: 'Introduction',
								type: 'button',
								icon: '//images.pcgamingwiki.com/4/40/Editor_Icon_-_Introduction.svg',
								action: {
									type: 'encapsulate',
									options: {
										pre: "{{Introduction\n|introduction      = ",
										post: "\n\n|release history   = \n\n|current state     = \n}}",
										ownline: true
									}
								}
							},
							'dlc': {
								label: 'DLC',
								type: 'button',
								icon: '//images.pcgamingwiki.com/3/38/Editor_Icon_-_DLCtable.svg',
								action: {
									type: 'encapsulate',
									options: {
										pre: "{{DLC|\n",
										peri: "{{DLC/row| Name | notes | OS }}",
										post: "\n}}",
										ownline: true
									}
								}
							},
							'cloud': {
								label: 'Cloud syncing',
								type: 'button',
								icon: '//images.pcgamingwiki.com/b/bc/Editor_Icon_-_Cloud_Sync.svg',
								action: {
									type: 'encapsulate',
									options: {
										pre: "===[[Glossary:Save game cloud syncing|Save game cloud syncing]]===\n{{Save game cloud syncing \n|epic games launcher       = \n|epic games launcher notes = \n|gog galaxy                = \n|gog galaxy notes          = \n|icloud                    = \n|icloud notes              = \n|origin                    = \n|origin notes              = \n|steam cloud               = \n|steam cloud notes         = \n}}",
										ownline: true
									}
								}
							},/*
							'vrtable': {
								label: 'VR',
								type: 'button',
								icon: '//images.pcgamingwiki.com/3/3c/Editor_Icon_-_VR.svg',
								action: {
									type: 'encapsulate',
									options: {
										pre: "==VR support==\n{{VR support\n|gg3d name                   = \n|native 3d gg3d award        = \n|nvidia 3d vision gg3d award = \n|tridef 3d gg3d award        = \n|iz3d gg3d award             = \n|native 3d                   = \n|native 3d notes             = \n|nvidia 3d vision            = \n|nvidia 3d vision notes      = \n|tridef 3d                   = \n|tridef 3d notes             = \n|iz3d                        = \n|iz3d notes                  = \n|vr only                     = \n|vorpx                       = \n|vorpx modes                 = \n|vorpx notes                 = \n|htc vive                    = \n|htc vive notes              = \n|oculus rift                 = \n|oculus rift notes           = \n|osvr                        = \n|osvr notes                  = \n|windows mixed reality       = \n|windows mixed reality notes = \n|keyboard-mouse              = \n|keyboard-mouse notes        = \n|3rd space gaming vest       = \n|3rd space gaming vest notes = \n|novint falcon               = \n|novint falcon notes         = \n|trackir                     = \n|trackir notes               = \n|tobii eye tracking          = \n|tobii eye tracking notes    = \n|play area seated            = \n|play area seated notes      = \n|play area standing          = \n|play area standing notes    = \n|play area room-scale        = \n|play area room-scale notes  = \n}}",
										ownline: true
									}
								}
							},
							'apitable': {
								label: 'API',
								type: 'button',
								icon: '//images.pcgamingwiki.com/c/cb/Editor_Icon_-_API.svg',
								action: {
									type: 'encapsulate',
									options: {
										pre: "===API===\n{{API\n|direct3d versions      = \n|direct3d notes         = \n|directdraw versions    = \n|directdraw notes       = \n|wing                   = \n|wing notes             = \n|opengl versions        = \n|opengl notes           = \n|glide versions         = \n|glide notes            = \n|software mode          = \n|software mode notes    = \n|mantle support         = \n|mantle support notes   = \n|metal support          = \n|metal support notes    = \n|vulkan versions        = \n|vulkan notes           = \n|dos modes              = \n|dos modes notes        = \n|shader model versions  = \n|shader model notes     = \n|windows 32-bit exe     = unknown\n|windows 64-bit exe     = unknown\n|windows exe notes      = \n|mac os x powerpc app   = \n|macos intel 32-bit app = unknown\n|macos intel 64-bit app = unknown\n|macos app notes        = \n|macos arm app          = unknown\n|macos arm notes        = \n|linux 32-bit executable= unknown\n|linux 64-bit executable= unknown\n|linux executable notes = \n}}",
										ownline: true
									}
								}
							},
							'middlewaretable': {
								label: 'Middleware',
								type: 'button',
								icon: '//images.pcgamingwiki.com/c/c2/Editor_Icon_-_Middleware.svg',
								action: {
									type: 'encapsulate',
									options: {
										pre: "===Middleware===\n{{Middleware\n|physics          = \n|physics notes    = \n|audio            = \n|audio notes      = \n|interface        = \n|interface notes  = \n|input            = \n|input notes      = \n|cutscenes        = \n|cutscenes notes  = \n|multiplayer      = \n|multiplayer notes= \n|anticheat        = \n|anticheat notes  = \n}}",
										ownline: true
									}
								}
							},
							'sysreq': {
								label: 'System requirements',
								type: 'button',
								icon: '//images.pcgamingwiki.com/4/4b/Editor_Icon_-_System_Requirements.svg',
								action: {
									type: 'encapsulate',
									options: {
										pre: "{{System requirements\n|OSfamily = ",
										peri: "System",
										post: "\n|minOS    = \n|minCPU   = \n|minRAM   = \n|minHD    = \n|minGPU   = \n\n|recOS    = \n|recCPU   = \n|recRAM   = \n|recHD    = \n|recGPU   = \n}}",
										ownline: true
									}
								}
							},*/
							'infoboxdrop': {
								label: 'Infobox row',
								type: 'select',
								list: {
									'infoboxdeveloper': {
										label: 'Developer',
										action: {
											type: 'encapsulate',
											options: {
												pre: "{{Infobox game/row/developer|",
												post: "}}",
												ownline: true
											}
										}
									},
									'infoboxporter': {
										label: 'Porter',
										action: {
											type: 'encapsulate',
											options: {
												pre: "{{Infobox game/row/porter|",
												post: "|OS}}",
												ownline: true
											}
										}
									},
									'infoboxpublisher': {
										label: 'Publisher',
										action: {
											type: 'encapsulate',
											options: {
												pre: "{{Infobox game/row/publisher|",
												post: "}}",
												ownline: true
											}
										}
									},
									'infoboxengine': {
										label: 'Engine',
										action: {
											type: 'encapsulate',
											options: {
												pre: "{{Infobox game/row/engine|",
												post: "}}",
												ownline: true
											}
										}
									},
									'infoboxdatemacos': {
										label: 'macOS release date',
										action: {
											type: 'encapsulate',
											options: {
												pre: "{{Infobox game/row/date|macOS|",
												peri: "Month dd, yyyy",
												post: "}}",
												ownline: true
											}
										}
									},
									'infoboxdateios': {
										label: 'iOS release date',
										action: {
											type: 'encapsulate',
											options: {
												pre: "{{Infobox game/row/date|iOS|",
												peri: "Month dd, yyyy",
												post: "}}",
												ownline: true
											}
										}
									},
									'infoboxdateipados': {
										label: 'iPadOS release date',
										action: {
											type: 'encapsulate',
											options: {
												pre: "{{Infobox game/row/date|iPadOS|",
												peri: "Month dd, yyyy",
												post: "}}",
												ownline: true
											}
										}
									},
									'infoboxdatetvos': {
										label: 'tvOS release date',
										action: {
											type: 'encapsulate',
											options: {
												pre: "{{Infobox game/row/date|tvOS|",
												peri: "Month dd, yyyy",
												post: "}}",
												ownline: true
											}
										}
									},
									'infoboxreception': {
										label: 'Reception rows',
										action: {
											type: 'encapsulate',
											options: {
												post: "|reception    = \n{{Infobox game/row/reception|Metacritic|link|rating}}\n{{Infobox game/row/reception|OpenCritic|link|rating}}\n{{Infobox game/row/reception|IGDB|link|rating}}",
												ownline: true
											}
										}
									}/*,
									'infobox taxonomy': {
										label: 'Taxonomy rows',
										action: {
											type: 'encapsulate',
											options: {
												post: "|taxonomy     = \n{{Infobox game/row/taxonomy/monetization      | }}\n{{Infobox game/row/taxonomy/microtransactions | }}\n{{Infobox game/row/taxonomy/modes             | }}\n{{Infobox game/row/taxonomy/pacing            | }}\n{{Infobox game/row/taxonomy/perspectives      | }}\n{{Infobox game/row/taxonomy/controls          | }}\n{{Infobox game/row/taxonomy/genres            | }}\n{{Infobox game/row/taxonomy/sports            | }}\n{{Infobox game/row/taxonomy/vehicles          | }}\n{{Infobox game/row/taxonomy/art styles        | }}\n{{Infobox game/row/taxonomy/themes            | }}\n{{Infobox game/row/taxonomy/series            | }}",
												ownline: true
											}
										}
									}*/
								}
							}
						}
					}
				}
			}
		}
	} );


	/* Adds fade out on mouse out for the dropdown menus */
	$( 'div.tool-select > div.menu > div' ).mouseleave(function(){
		$(this).fadeOut();
	});
};
 
/* Check if view is in edit mode and that the required modules are available. Then, customize the toolbar . . . */
if ( $.inArray( mw.config.get( 'wgAction' ), [ 'edit', 'submit' ] ) !== -1 ) {
	mw.loader.using( 'user.options', function () {
		// This can be the string "0" if the user disabled the preference ([[bugzilla:52542#c3]])
		if ( mw.user.options.get( 'usebetatoolbar' ) == 1 && mw.user.options.get( 'showtoolbar' ) == 1 ) {
			$.when(
				mw.loader.using( 'ext.wikiEditor' ),
				$.ready
			).then( customizeToolbar );
		}
	} );
}

function addAnchorInHeaders() {
	$('span.mw-headline', '#mw-content-text').each(function() {
		var $this = $(this);
		if ($this.attr('id') !== undefined) {
			$('<span class="mw-linkhere"></span>').text(' • ').append(
				$('<a></a>').text('Link').attr({title: 'Link', href: '#'+$this.attr('id')})
			).appendTo(this);
		}
	});
}

$(addAnchorInHeaders);



/* ===== FUNCTIONALITY : Collapsible TOC levels =========================================================================================================================
 * 
 * Adds collapsible TOC levels copied directly over from the French Wiktionary.
 * 
 * Source Code:
 *  - Javascript : https://fr.wiktionary.org/wiki/MediaWiki:Gadget-SommaireDeveloppable.js
 * 
 * 2019-07-21 - Added expand/collapse all options + storing the setting in a cookie.
 * 2019-07-20 - Localization, updated to automatically expand Essential Improvements, various changes.
 * 2019-07-19 - Initial commit, with a minor change to CollapsibleTOC_LabelNeither.
 *
 */
/* -----------------------------------------------------------------------------------------------------
Table of contents which shows by default only level 1 headers (so as not to clutter the screen)
but whose higher depth levels are viewable (or expandable) by clicking a [+] button (or [-]),
in a way similar to what classic file browsers do.
--------------------------------------------------------------------------------------------------------
Authors:
* Eiku April 25, 2012 for most of the code.
* ArséniureDeGallium for details and various additions.
* Inspired by WikiTravel (http://files.wikitravel.org/mw/skins/common/wikibits.js?0.1), but made differently
--------------------------------------------------------------------------------------------------------*/

/*----------------- config variables ------------------------------------------*/

// Which pages should we expand the first level 1 section automatically on?
var CollapsibleTOC_PreDevelop = (mw.config.get('wgNamespaceNumber') === 0); // only for the main namespace

// Should we number the sections in the TOC?
var CollapsibleTOC_NumberHeadings = mw.user.options.get('numberheadings'); // use the user's preferences, aka is "auto-number headings" enabled or not?

// What characters to use to indicate expanded/collapsed status?
var CollapsibleTOC_LabelExpand = '[+]';
var CollapsibleTOC_LabelCollapse = '[-]';
var CollapsibleTOC_LabelNeither = '&nbsp;&nbsp;&nbsp;';

// Help tooltips
var CollapsibleTOC_TooltipExpand = 'This section has subsections, click to expand them';
var CollapsibleTOC_TooltipCollapse = 'Click to collapse the subsections';
var CollapsibleTOC_TooltipNeither = 'This section has no subsections';

/*------------------- hooks the function ----------------------------------------------*/
// This is where the possible presence of the {{CollapsibleTOC}} template is managed in the page
// * CollapsibleTOC_NO has priority
// * CollapsibleTOC_YES afterwards
// * for the rest of the majority of pages it's the namespace that decides
var NoCollapsibleTOC = document.getElementById('CollapsibleTOC_NO');
var YesCollapsibleTOC = document.getElementById('CollapsibleTOC_YES') || (mw.config.get('wgNamespaceNumber') === 0);
if ((!NoCollapsibleTOC) && (YesCollapsibleTOC)) {
    $(CollapsibleTOC_Main);
    $(CollapsibleTOC_Toggle);
}

/*----------------- support function ------------------------------------------*/
jQuery.fn.cleanWhitespace = function() {
    this.contents().filter(
        function() { return (this.nodeType == 3 && !/\S/.test(this.nodeValue)); })
        .remove();
    return this;
};

/*----------------- main function ------------------------------------------*/
function CollapsibleTOC_Main() {

    alwaysExpand = $.cookie( 'pcgw_alwaysexpand' ) === '1';

    // for each reasonable level of depth of table of contents
    for (var level = 1; level < 7; level++) {

        // get the list of <li> class elements "toclevel-n"
        var lis = $('.toclevel-' + level);

        if (lis.length === 0) break; // no need to continue, there is no deeper level

        // for each
        for (var _i = 0; _i < lis.length; _i++) {
            var li = lis[_i];

            // check that it is a <li>
            if (li.tagName.toLowerCase() != 'li') continue;

            var plus;
            if (li.children.length >= 2) {
                var ul = li.children[1];

                // check that the 2nd child is a <ul>
                if (ul.tagName.toLowerCase() != 'ul') continue;

                // add (later) a clickable element
                plus = document.createElement('a');

                // add the 'collapsibletoc-section-toggle' CSS class to it
                plus.className = "collapsibletoc-section-toggle";

                // if we click on it and that ul is visible, it hides it, and vice versa
                plus.onclick = (function(ul, plus) {
                    return function() {
                        if (ul.style.display == 'none') {
                            ul.style.display = 'block';
                            plus.title = CollapsibleTOC_TooltipCollapse;
                            plus.innerHTML = CollapsibleTOC_LabelCollapse;
                        } else {
                            ul.style.display = 'none';
                            plus.title = CollapsibleTOC_TooltipExpand;
                            plus.innerHTML = CollapsibleTOC_LabelExpand;
                        }
                    };
                })(ul, plus);

                if (alwaysExpand) {
                    ul.style.display = 'block';
                    plus.title = CollapsibleTOC_TooltipCollapse;
                    plus.innerHTML = CollapsibleTOC_LabelCollapse;
                } else {
                    // hide by default, except for the first one section (to advertise)
                    if ((level == 1) && (li.children[0].innerText == "Essential improvements") && CollapsibleTOC_PreDevelop) {
                        ul.style.display = 'block';
                        plus.title = CollapsibleTOC_TooltipCollapse;
                        plus.innerHTML = CollapsibleTOC_LabelCollapse;
                    } else {
                        ul.style.display = 'none';
                        plus.title = CollapsibleTOC_TooltipExpand;
                        plus.innerHTML = CollapsibleTOC_LabelExpand;
                    }
                }

                plus.style.cursor = 'pointer'; // cursor to indicate its a link
            } else {
                // add a visual element that takes as many spaces for same width as + and - for elements without child headers
                plus = document.createElement('span');
                //plus.title = CollapsibleTOC_TooltipNeither;
                plus.innerHTML = CollapsibleTOC_LabelNeither;
                plus.style.cursor = 'default'; // force default pointer to hide the fact that users are currently hovering over a bunch of non-breaking spaces (&nbsp;)

                // add the 'collapsibletoc-section-neither' CSS class to it
                plus.className = "collapsibletoc-section-neither";
            }

            // use a monospaced font for the expand/collapse links so that they have the same width regardless of character
            plus.style.fontFamily = 'courier, monospace, mono';
            plus.style.color = '#000';
            plus.style.fontWeight = 'bold';
            plus.style.textDecoration = 'none';

            // insert the link as the 1st node of the current <li>
            $(li).children().first().before(plus);
        }
    }

    //---- visibility of auto-number headings ----
    var spans = $('.tocnumber');
    if (CollapsibleTOC_NumberHeadings) {
        for (var _i = 0; _i < spans.length; _i++) {
            spans[_i].style.display = "inline";
        }
    } /* else {
        for (var _i = 0; _i < spans.length; _i++) {
            spans[_i].style.display = "none";
        }
        // in Chrome, if you leave the display: table-cell by default,
        // a line break inserts between the added [+] and the <a> that follows.
        $('.toctext').css('display', 'inline');
    } */ // Unnecessary


    $('.toclevel-1 a').cleanWhitespace();
}

function CollapsibleTOC_ToggleAll(s) {
    for (var level = 1; level < 7; level++) {

        // get the list of <li> class elements "toclevel-n"
        var lis = $('.toclevel-' + level);

        if (lis.length === 0) break; // no need to continue, there is no deeper level

        // for each
        for (var _i = 0; _i < lis.length; _i++) {
            var li = lis[_i];

            // check that it is a <li>
            if (li.tagName.toLowerCase() != 'li') continue;

            if (li.children.length >= 3) {
                var toggle = li.children[0];
                var ul = li.children[2];

                // check that the 3rd child is a <ul>
                if (ul.tagName.toLowerCase() != 'ul') continue;

                if (s == 'block') {
                    ul.style.display = 'block';
                    toggle.title = CollapsibleTOC_TooltipCollapse;
                    toggle.innerHTML = CollapsibleTOC_LabelCollapse;
                } else {
                    ul.style.display = 'none';
                    toggle.title = CollapsibleTOC_TooltipExpand;
                    toggle.innerHTML = CollapsibleTOC_LabelExpand;
                }
            }
        }
    }
}

function CollapsibleTOC_Toggle() {

    // Table of contents toggle
    var $content = $('#mw-content-text');
    var $toc, $tocTitle, $tocToggleLink, $tocList, alwaysExpand;
    $toc = $content.find( '#toc' );
    $tocTitle = $content.find( '.toctitle' );
    $tocToggleLink = $content.find( '#alwaysToggle' );
    $tocList = $toc.find( 'ul' ).eq( 0 );

    // Hide/show the table of contents element
    function toggleSections() {
        if ( $.cookie( 'pcgw_alwaysexpand' ) === '1' ) {
            CollapsibleTOC_ToggleAll('none');
            $tocToggleLink.html( '<span class="tocExpandAll">e</span>' );
            $.cookie( 'pcgw_alwaysexpand', null, {
                expires: 365,
                path: '/'
            } );
        } else {
            CollapsibleTOC_ToggleAll('block');
            $tocToggleLink.html( '<span class="tocCollapseAll">c</span>' );
            $.cookie( 'pcgw_alwaysexpand', '1', {
                expires: 365,
                path: '/'
            } );
        }
    }

    // Only add it if there is a complete TOC and it doesn't
    // have a toggle added already

    if ( $toc.length && $tocTitle.length && $tocList.length && !$tocToggleLink.length ) {
        alwaysExpand = $.cookie( 'pcgw_alwaysexpand' ) === '1';

        $tocToggleLink = $( '<a href="#" id="togglelink"></a>' )
            .html( alwaysExpand ? '<span class="tocCollapseAll">c</span>' : '<span class="tocExpandAll">e</span>' )
            .click( function ( e ) {
                e.preventDefault();
                toggleSections();
            } );

        $tocTitle.append(
            $tocToggleLink
                .wrap( '<span class="toctoggle collapsibletoc-toggle"></span>' )
                .parent()
                .prepend( ' [' )
                .append( '] ' )
            );

        if ( alwaysExpand ) {
            CollapsibleTOC_ToggleAll('block');
        }
    }
}



/* ===== FUNCTIONALITY : Adds ReferenceTooltips =========================================================================================================================
 * 
 * Adds ReferenceTooltips copied directly over from the Russian Wikipedia.
 * 
 * Information: https://www.mediawiki.org/w/index.php?title=Topic:Ueqlcc482l9yw8gv&topic_showPostId=ueqlcc6fkvg15qzj#flow-post-ueqlcc6fkvg15qzj
 * 
 * Source Code:
 *  - Javascript : https://ru.wikipedia.org/wiki/MediaWiki:Gadget-referenceTooltips.js
 *  - CSS : https://ru.wikipedia.org/wiki/MediaWiki:Gadget-referenceTooltips.css
 * 
 * 2019-02-22 - Merged with latest version from https://ru.wikipedia.org/wiki/MediaWiki:Gadget-referenceTooltips.js
 * 2018-09-17 - Updated + added english text (Google Translated)
 *
 */

// See [[mw:Reference Tooltips]]

var referenceTooltips = function () {

// ruwiki settings
var REF_LINK_SELECTOR = '.reference, a[href^="#CITEREF"]',
	COMMENTED_TEXT_CLASS = 'ts-comment-commentedText',
	COMMENTED_TEXT_SELECTOR = '.' + COMMENTED_TEXT_CLASS + ', abbr[title]';

mw.messages.set( {
	'rt-settings': 'Tooltip settings', // hover alt text on the cog wheel shown on the tooltips.
	'rt-settings-title': 'Reference Tooltips settings',
	'rt-save': 'Save settings',
	'rt-cancel': 'Cancel',
	'rt-enable': 'Enable Reference Tooltips',
	'rt-disable': 'Disable Reference Tooltips',
	'rt-activationMethod': 'Tooltip is activated by:',
	'rt-hovering': 'hovering',
	'rt-clicking': 'clicking',
	'rt-delay': 'Delay before the tooltip appears (in milliseconds):',
	'rt-tooltipsForComments': 'Show tooltips over <span title="Tooltip example" class="'+ COMMENTED_TEXT_CLASS +'" style="border-bottom: 1px dotted; cursor: help;">underlined text</span> in the style of Reference Tooltips (allows you to see tooltips on devices without mouse support).',
	'rt-disabledNote': 'Once disabled, Reference Tooltips can be re-enabled using a link in the footer of the page.',
	'rt-ready': 'Done',
	'rt-enable-footer': 'Enable Reference Tooltips', // Text as shown in the footer among the category links
	'rt-enabled': 'Reference Tooltips have been enabled.' // Shown on the popup in the top right corner when re-enabling Reference Tooltips from the footer.
} );

// "Global" variables
var SECONDS_IN_A_DAY = 60 * 60 * 24,
	CLASSES = {
		FADE_IN_DOWN: 'rt-fade-in-down',
		FADE_IN_UP: 'rt-fade-in-up',
		FADE_OUT_DOWN: 'rt-fade-out-down',
		FADE_OUT_UP: 'rt-fade-out-up'
	},
	IS_TOUCHSCREEN = 'ontouchstart' in document.documentElement,
	// Quite a rough check for mobile browsers, a mix of what is advised at
	// https://stackoverflow.com/a/24600597 (sends to
	// https://developer.mozilla.org/en-US/docs/Browser_detection_using_the_user_agent)
	// and https://stackoverflow.com/a/14301832
	IS_MOBILE = /Mobi|Android/i.test( navigator.userAgent ) ||
		typeof window.orientation !== 'undefined',
	CLIENT_NAME = $.client.profile().name,
	settingsString, settings, enabled, delay, activatedByClick, tooltipsForComments, cursorWaitCss,
	windowManager,
	$body = $( document.body ),
	$window = $( window );

function rt( $content ) {
	// Popups gadget
	if ( window.pg ) {
		return;
	}

	var teSelector,
		settingsDialogOpening = false;

	function setSettingsCookie() {
		mw.cookie.set(
			'RTsettings',
			Number( enabled ) + '|' + delay + '|' + Number( activatedByClick ) + '|' +
				Number( tooltipsForComments ),
			{ path: '/', expires: 90 * SECONDS_IN_A_DAY }
		);
	}

	function enableRt() {
		enabled = true;
		setSettingsCookie();
		$( '.rt-enableItem' ).remove();
		rt( $content );
		mw.notify( mw.msg( 'rt-enabled' ) );
	}

	function disableRt() {
		$content.find( teSelector ).removeClass( 'rt-commentedText' ).off( '.rt' );
		$body.off( '.rt' );
		$window.off( '.rt' );
	}

	function addEnableLink() {
		// #footer-places – Vector
		// #f-list – Timeless, Monobook, Modern
		// parent of #footer li – Cologne Blue
		// var $footer = $( '#footer-places, #f-list' );
        var $footer = $( '#mw-normal-catlinks ul' );
		if ( !$footer.length ) {
			$footer = $( '#footer li' ).parent();
		}
		$footer.append(
			$( '<li>' )
				.addClass( 'rt-enableItem' )
				.append(
					$( '<a>' )
						.text( mw.msg( 'rt-enable-footer' ) )
						.attr( 'href', 'javascript:' )
						.click( function ( e ) {
							e.preventDefault();
							enableRt();
						} )
			)
		);
	}

	function TooltippedElement( $element ) {
		var tooltip,
			te = this;

		function onStartEvent( e ) {
			var showRefArgs;

			if ( activatedByClick ) {
				e.preventDefault();
			}
			if ( !te.noRef ) {
				showRefArgs = [ $( this ) ];
				if ( te.type !== 'supRef' ) {
					showRefArgs.push( e.pageX, e.pageY );
				}
				te.showRef.apply( te, showRefArgs );
			}
		}

		function onEndEvent() {
			if ( !te.noRef ) {
				te.hideRef();
			}
		}

		if ( !$element ) {
			return;
		}

		// TooltippedElement.$element and TooltippedElement.$originalElement will be different when
		// the first is changed after its cloned version is hovered in a tooltip
		this.$element = $element;
		this.$originalElement = $element;
		if ( this.$element.is( REF_LINK_SELECTOR ) ) {
			if ( this.$element.prop( 'tagName' ) === 'SUP' ) {
				this.type = 'supRef';
			} else {
				this.type = 'harvardRef';
			}
		} else {
			this.type = 'commentedText';
			this.comment = this.$element.attr( 'title' );
			if ( !this.comment ) {
				return;
			}
			this.$element.addClass('rt-commentedText');
		}

		this.$element.on( activatedByClick ?
			{ 'click.rt': onStartEvent } :
			{ 'mouseenter.rt': onStartEvent, 'mouseleave.rt': onEndEvent }
		);

		this.hideRef = function ( immediately ) {
			clearTimeout( te.showTimer );

			if ( this.type === 'commentedText' ) {
				this.$element.attr( 'title', this.comment );
			}

			if ( this.tooltip && this.tooltip.isPresent ) {
				if ( activatedByClick || immediately ) {
					this.tooltip.hide();
				} else {
					this.hideTimer = setTimeout( function () {
						te.tooltip.hide();
					}, 200 );
				}
			} else if ( this.$ref && this.$ref.hasClass( 'rt-target' ) ) {
				this.$ref.removeClass( 'rt-target' );
				if ( activatedByClick ) {
					$body.off( 'click.rt touchstart.rt', this.onBodyClick );
				}
			}
		};

		this.showRef = function ( $element, ePageX, ePageY ) {
			// Popups gadget
			if ( window.pg ) {
				disableRt();
				return;
			}

			var tooltipInitiallyPresent = this.tooltip && this.tooltip.isPresent;

			function reallyShow() {
				var viewportTop, refOffsetTop, teHref;

				if ( !te.$ref && !te.comment ) {
					teHref = te.type === 'supRef' ?
						te.$element.find( 'a' ).attr( 'href' ) :
						te.$element.attr( 'href' ); // harvardRef
					te.$ref = teHref &&
						$( '#' + $.escapeSelector( teHref.slice( 1 ) ) );
					if ( !te.$ref || !te.$ref.length || !te.$ref.text() ) {
						te.noRef = true;
						return;
					}
				}

				if ( !tooltipInitiallyPresent && !te.comment ) {
					viewportTop = $window.scrollTop();
					refOffsetTop = te.$ref.offset().top;
					if ( !activatedByClick &&
						viewportTop < refOffsetTop &&
						viewportTop + $window.height() > refOffsetTop + te.$ref.height() &&
						// There can be gadgets/scripts that make references horizontally scrollable.
						$window.width() > te.$ref.offset().left + te.$ref.width()
					) {
						// Highlight the reference itself
						te.$ref.addClass( 'rt-target' );
						return;
					}
				}

				if ( !te.tooltip ) {
					te.tooltip = new Tooltip( te );
					if ( !te.tooltip.$content.length ) {
						return;
					}
				}

				// If this tooltip is called from inside another tooltip. We can't define it
				// in the constructor since a ref can be cloned but have the same Tooltip object;
				// so, Tooltip.parent is a floating value.
				te.tooltip.parent = te.$element.closest( '.rt-tooltip' ).data( 'tooltip' );
				if ( te.tooltip.parent && te.tooltip.parent.disappearing ) {
					return;
				}

				te.tooltip.show();

				if ( tooltipInitiallyPresent ) {
					if ( te.tooltip.$element.hasClass( 'rt-tooltip-above' ) ) {
						te.tooltip.$element.addClass( CLASSES.FADE_IN_DOWN );
					} else {
						te.tooltip.$element.addClass( CLASSES.FADE_IN_UP );
					}
					return;
				}

				te.tooltip.calculatePosition( ePageX, ePageY );

				$window.on( 'resize.rt', te.onWindowResize );
			}

			// We redefine this.$element here because e.target can be a reference link inside
			// a reference tooltip, not a link that was initially assigned to this.$element
			this.$element = $element;

			if ( this.type === 'commentedText' ) {
				this.$element.attr( 'title', '' );
			}

			if ( activatedByClick ) {
				if ( tooltipInitiallyPresent ||
					( this.$ref && this.$ref.hasClass( 'rt-target' ) )
				) {
					return;
				} else {
					setTimeout( function () {
						$body.on( 'click.rt touchstart.rt', te.onBodyClick );
					}, 0 );
				}
			}

			if ( activatedByClick || tooltipInitiallyPresent ) {
				reallyShow();
			} else {
				this.showTimer = setTimeout( reallyShow, delay );
			}
		};

		this.onBodyClick = function ( e ) {
			if ( !te.tooltip && !te.$ref.hasClass( 'rt-target' ) ) {
				return;
			}

			var $current = $( e.target );

			function contextMatchesParameter( parameter ) {
				return this === parameter;
			}

			// The last condition is used to determine cases when a clicked tooltip is the current
			// element's tooltip or one of its descendants
			while ( $current.length &&
				( !$current.hasClass( 'rt-tooltip' ) ||
					!$current.data( 'tooltip' ) ||
					!$current.data( 'tooltip' ).upToTopParent(
						contextMatchesParameter, [ te.tooltip ],
						true
					)
				)
			) {
				$current = $current.parent();
			}
			if ( !$current.length ) {
				te.hideRef();
			}
		};

		this.onWindowResize = function () {
			te.tooltip.calculatePosition();
		};
	}

	function Tooltip( te ) {
		function openSettingsDialog() {
			var settingsDialog, settingsWindow;

			if ( cursorWaitCss ) {
				cursorWaitCss.disabled = true;
			}

			function SettingsDialog() {
				SettingsDialog.parent.call( this );
			}
			OO.inheritClass( SettingsDialog, OO.ui.ProcessDialog );

			SettingsDialog.static.name = 'settingsDialog';
            //SettingsDialog.static.size = 'large';
			SettingsDialog.static.title = mw.msg( 'rt-settings-title' );
			SettingsDialog.static.actions = [
				{
					modes: 'basic',
					action: 'save',
					label: mw.msg( 'rt-save' ),
					flags: [ 'primary', 'progressive' ]
				},
				{
					modes: 'basic',
					label: mw.msg( 'rt-cancel' ),
					flags: 'safe'
				},
				{
					modes: 'disabled',
					action: 'deactivated',
					label: mw.msg( 'rt-ready' ),
					flags: [ 'primary', 'progressive' ]
				}
			];

			SettingsDialog.prototype.initialize = function () {
				var dialog = this;

				SettingsDialog.parent.prototype.initialize.apply( this, arguments );

				this.enableOption = new OO.ui.RadioOptionWidget( {
					label: mw.msg( 'rt-enable' )
				} );
				this.disableOption = new OO.ui.RadioOptionWidget( {
					label: mw.msg( 'rt-disable' )
				} );
				this.enableSelect = new OO.ui.RadioSelectWidget( {
					items: [ this.enableOption, this.disableOption ],
					classes: [ 'rt-enableSelect' ]
				} );
				this.enableSelect.selectItem( this.enableOption );
				this.enableSelect.on( 'choose', function ( item ) {
					if ( item === dialog.disableOption ) {
						dialog.activationMethodSelect.setDisabled( true );
						dialog.delayInput.setDisabled( true );
						dialog.tooltipsForCommentsCheckbox.setDisabled( true );
					} else {
						dialog.activationMethodSelect.setDisabled( false );
						dialog.delayInput.setDisabled( dialog.clickOption.isSelected() );
						dialog.tooltipsForCommentsCheckbox.setDisabled( false );
					}
				} );

				this.hoverOption = new OO.ui.RadioOptionWidget( {
					label: mw.msg( 'rt-hovering' )
				} );
				this.clickOption = new OO.ui.RadioOptionWidget( {
					label: mw.msg( 'rt-clicking' )
				} );
				this.activationMethodSelect = new OO.ui.RadioSelectWidget( {
					items: [ this.hoverOption, this.clickOption ]
				} );
				this.activationMethodSelect.selectItem( activatedByClick ?
					this.clickOption :
					this.hoverOption
				);
				this.activationMethodSelect.on( 'choose', function ( item ) {
					if ( item === dialog.clickOption ) {
						dialog.delayInput.setDisabled( true );
					} else {
						dialog.delayInput.setDisabled( dialog.clickOption.isSelected() );
					}
				} );
				this.activationMethodField = new OO.ui.FieldLayout( this.activationMethodSelect, {
					label: mw.msg( 'rt-activationMethod' ),
					align: 'top'
				} );

				this.delayInput = new OO.ui.NumberInputWidget( {
					input: { value: delay },
					step: 50,
					min: 0,
					max: 5000,
					disabled: activatedByClick,
					classes: [ 'rt-numberInput' ]
				} );
				this.delayField = new OO.ui.FieldLayout( this.delayInput, {
					label: mw.msg( 'rt-delay' ),
					align: 'top'
				} );

				this.tooltipsForCommentsCheckbox = new OO.ui.CheckboxInputWidget( {
					selected: tooltipsForComments
				} );
				this.tooltipsForCommentsField = new OO.ui.FieldLayout(
					this.tooltipsForCommentsCheckbox,
					{
						label: new OO.ui.HtmlSnippet( mw.msg( 'rt-tooltipsForComments' ) ),
						align: 'inline',
						classes: [ 'rt-tooltipsForCommentsField' ]
					}
				);
				new TooltippedElement(
					this.tooltipsForCommentsField.$element.find( '.' + COMMENTED_TEXT_CLASS )
				);

				this.fieldset = new OO.ui.FieldsetLayout();
				this.fieldset.addItems( [
					this.activationMethodField,
					this.delayField,
					this.tooltipsForCommentsField
				] );

				this.panelSettings = new OO.ui.PanelLayout( {
					padded: true,
					expanded: false
				} );
				this.panelSettings.$element.append(
					this.enableSelect.$element,
					$( '<hr>' ).addClass( 'rt-settingsFormSeparator' ),
					this.fieldset.$element
				);

				this.panelDisabled = new OO.ui.PanelLayout( {
					padded: true,
					expanded: false
				} );
				this.panelDisabled.$element.append(
					$( '<table>' )
						.addClass( 'rt-disabledHelp' )
						.append(
							$( '<tr>' ).append(
								$( '<td>' ).append(
									$( '<img>' ).attr( 'src', '/images/b/b3/Reference_Tooltips_footer.png' )
								),
								$( '<td>' )
									.addClass( 'rt-disabledNote' )
									.text( mw.msg( 'rt-disabledNote' ) )
							)
						)
				);

				this.stackLayout = new OO.ui.StackLayout( {
					items: [ this.panelSettings, this.panelDisabled ]
				} );

				this.$body.append( this.stackLayout.$element );
			};

			SettingsDialog.prototype.getSetupProcess = function ( data ) {
				return SettingsDialog.parent.prototype.getSetupProcess.call( this, data )
					.next( function () {
						this.stackLayout.setItem( this.panelSettings );
						this.actions.setMode( 'basic' );
					}, this );
			};

			SettingsDialog.prototype.getActionProcess = function ( action ) {
				var dialog = this;

				if ( action === 'save' ) {
					return new OO.ui.Process( function () {
						var newDelay = Number( dialog.delayInput.getValue() );

						enabled = dialog.enableOption.isSelected();
						if ( newDelay >= 0 && newDelay <= 5000 ) {
							delay = newDelay;
						}
						activatedByClick = dialog.clickOption.isSelected();
						tooltipsForComments = dialog.tooltipsForCommentsCheckbox.isSelected();

						setSettingsCookie();

						if ( enabled ) {
							dialog.close();
							disableRt();
							rt( $content );
						} else {
							dialog.actions.setMode( 'disabled' );
							dialog.stackLayout.setItem( dialog.panelDisabled );
							disableRt();
							addEnableLink();
						}
					} );
				} else if ( action === 'deactivated' ) {
					dialog.close();
				}
				return SettingsDialog.parent.prototype.getActionProcess.call( this, action );
			};

			SettingsDialog.prototype.getBodyHeight = function () {
				return this.stackLayout.getCurrentItem().$element.outerHeight( true );
                //return 400; // sets height of the dialog to ~430px
			};

			tooltip.upToTopParent( function adjustRightAndHide() {
				if ( this.isPresent ) {
					if ( this.$element[ 0 ].style.right ) {
						this.$element.css(
							'right',
							'+=' + ( window.innerWidth - $window.width() )
						);
					}
					this.te.hideRef( true );
				}
			} );

			if ( !windowManager ) {
				windowManager = new OO.ui.WindowManager();
				$body.append( windowManager.$element );
			}

			settingsDialog = new SettingsDialog();
			windowManager.addWindows( [ settingsDialog ] );
			settingsWindow = windowManager.openWindow( settingsDialog );
			settingsWindow.opened.then( function () {
				settingsDialogOpening = false;
			} );
			settingsWindow.closed.then( function () {
				windowManager.clearWindows();
			} );
		}

		var tooltip = this;

		// This variable can change: one tooltip can be called from a harvard-style reference link
		// that is put into different tooltips
		this.te = te;

		switch ( this.te.type ) {
			case 'supRef':
				this.id = 'rt-' + this.te.$originalElement.attr( 'id' );
				this.$content = this.te.$ref
					.children()
					.not( '.mw-cite-backlink' )
					.clone( true );
				break;
			case 'harvardRef':
				this.id = 'rt-' + this.te.$originalElement.closest( 'li' ).attr( 'id' );
				this.$content = this.te.$ref
					.clone( true )
					.removeAttr( 'id' );
				break;
			case 'commentedText':
				this.id = 'rt-' + String( Math.random() ).slice( 2 );
				this.$content = $( document.createTextNode( this.te.comment ) );
				break;
		}
		if ( !this.$content.length ) {
			return;
		}

		this.insideWindow = Boolean( this.te.$element.closest( '.oo-ui-window' ).length );

		this.$element = $( '<div>' )
			.addClass( 'rt-tooltip' )
			.attr( 'id', this.id )
			.attr( 'role', 'tooltip' )
			.data( 'tooltip', this );
		if ( this.insideWindow ) {
			this.$element.addClass( 'rt-tooltip-insideWindow' );
		}

		// We need the $content interlayer here in order for the settings icon to have the correct
		// margins
		this.$content = this.$content
			.wrapAll( '<div>' )
			.parent()
			.addClass( 'rt-tooltipContent' )
			.appendTo( this.$element );

		if ( !activatedByClick ) {
			this.$element
				.mouseenter( function () {
					if ( !tooltip.disappearing ) {
						tooltip.upToTopParent( function () {
							this.show();
						} );
					}
				} )
				.mouseleave( function ( e ) {
					// https://stackoverflow.com/q/47649442 workaround. Relying on relatedTarget
					// alone has pitfalls: when alt-tabbing, relatedTarget is empty too
					if ( CLIENT_NAME !== 'chrome' ||
						( !e.originalEvent ||
							e.originalEvent.relatedTarget !== null ||
							!tooltip.clickedTime ||
							$.now() - tooltip.clickedTime > 50
						)
					) {
						tooltip.upToTopParent( function () {
							this.te.hideRef();
						} );
					}
				} )
				.click( function () {
					tooltip.clickedTime = $.now();
				} );
		}

		if ( !this.insideWindow ) {
			$( '<div>' )
				.addClass( 'rt-settingsLink' )
				.attr( 'title', mw.msg( 'rt-settings' ) )
				.click( function () {
					if ( settingsDialogOpening ) {
						return;
					}
					settingsDialogOpening = true;

					if ( mw.loader.getState( 'oojs-ui' ) !== 'ready' ) {
						if ( cursorWaitCss ) {
							cursorWaitCss.disabled = false;
						} else {
							cursorWaitCss = mw.util.addCSS( 'body { cursor: wait; }' );
						}
					}
					mw.loader.using( [ 'oojs', 'oojs-ui' ], openSettingsDialog );
				} )
				.prependTo( this.$content );
		}

		// Tooltip tail element is inside tooltip content element in order for the tooltip
		// not to disappear when the mouse is above the tail
		$( '<div>' )
			.addClass( 'rt-tooltipTail' )
			.prependTo( this.$element );

		this.disappearing = false;

		this.show = function () {
			this.disappearing = false;
			clearTimeout( this.te.hideTimer );
			clearTimeout( this.te.removeTimer );

			this.$element
				.removeClass( CLASSES.FADE_OUT_DOWN )
				.removeClass( CLASSES.FADE_OUT_UP );

			if ( !this.isPresent ) {
				$body.append( this.$element );
			}

			this.isPresent = true;
		};

		this.hide = function () {
			var tooltip = this;

			tooltip.disappearing = true;

			if ( tooltip.$element.hasClass( 'rt-tooltip-above' ) ) {
				tooltip.$element
					.removeClass( CLASSES.FADE_IN_DOWN )
					.addClass( CLASSES.FADE_OUT_UP );
			} else {
				tooltip.$element
					.removeClass( CLASSES.FADE_IN_UP )
					.addClass( CLASSES.FADE_OUT_DOWN );
			}

			tooltip.te.removeTimer = setTimeout( function () {
				if ( tooltip.isPresent ) {
					tooltip.$element.detach();

					if ( tooltip.tailCss ) {
						tooltip.tailCss.disabled = true;
					}

					if ( activatedByClick ) {
						$body.off( 'click.rt touchstart.rt', tooltip.te.onBodyClick );
					}
					$window.off( 'resize.rt', tooltip.te.onWindowResize );

					tooltip.isPresent = false;
				}
			}, 200 );
		};

		this.calculatePosition = function ( ePageX, ePageY ) {
			var teElement, teOffsets, teOffset, tooltipTailOffsetX, tooltipTailLeft,
				offsetYCorrection = 0;

			if ( this.tailCss ) {
				this.tailCss.disabled = true;
			}

			teElement = this.te.$element.get( 0 );
			if ( ePageX !== undefined ) {
				tooltipTailOffsetX = ePageX;
				teOffsets = teElement.getClientRects &&
					teElement.getClientRects() ||
					teElement.getBoundingClientRect();
				if ( teOffsets.length > 1 ) {
					for (var i = teOffsets.length - 1; i >= 0; i--) {
						if ( ePageY >= Math.round( $window.scrollTop() + teOffsets[i].top ) &&
							ePageY <= Math.round(
								$window.scrollTop() + teOffsets[i].top + teOffsets[i].height
							)
						) {
							teOffset = teOffsets[i];
						}
					}
				}
			}

			if ( !teOffset ) {
				teOffset = teElement.getClientRects &&
					teElement.getClientRects()[0] ||
					teElement.getBoundingClientRect();
			}
			teOffset = {
				top: $window.scrollTop() + teOffset.top,
				left: $window.scrollLeft() + teOffset.left,
				width: teOffset.width,
				height: teOffset.height
			};
			if ( !tooltipTailOffsetX ) {
				tooltipTailOffsetX = ( teOffset.left * 2 + teOffset.width ) / 2;
			}
			if ( CLIENT_NAME === 'msie' && this.te.type === 'supRef' ) {
				offsetYCorrection = -Number(
					this.te.$element.parent().css( 'font-size' ).replace( 'px', '' )
				) / 2;
			}
			this.$element.css( {
				top: teOffset.top - this.$element.outerHeight() - 7 + offsetYCorrection,
				left: tooltipTailOffsetX - 20,
				right: ''
			} );

			// Is it squished against the right side of the page?
			if ( this.$element.offset().left + this.$element.outerWidth() > $window.width() - 1 ) {
				this.$element.css( {
					left: '',
					right: 0
				} );
				tooltipTailLeft = tooltipTailOffsetX - this.$element.offset().left - 5;
			}

			// Is a part of it above the top of the screen?
			if ( teOffset.top < this.$element.outerHeight() + $window.scrollTop() + 6 ) {
				this.$element
					.removeClass( 'rt-tooltip-above' )
					.addClass( 'rt-tooltip-below' )
					.addClass( CLASSES.FADE_IN_UP )
					.css( {
						top: teOffset.top + teOffset.height + 9 + offsetYCorrection
					} );
				if ( tooltipTailLeft ) {
					this.tailCss = mw.util.addCSS(
						'#' + $.escapeSelector( tooltip.id ) + ' .rt-tooltipTail { left: ' +
						( tooltipTailLeft + 12 ) + 'px; }'
					);
				}
			} else {
				this.$element
					.removeClass( 'rt-tooltip-below' )
					.addClass( 'rt-tooltip-above' )
					.addClass( CLASSES.FADE_IN_DOWN )
					// A fix for cases when a tooltip shown once is then wrongly positioned when it
					// is shown again after a window resize. We just repeat what is above.
					.css( {
						top: teOffset.top - this.$element.outerHeight() - 7 + offsetYCorrection
					} );
				if ( tooltipTailLeft ) {
					// 12 is the tail element width/height
					this.tailCss = mw.util.addCSS(
						'#' + $.escapeSelector( tooltip.id ) + ' .rt-tooltipTail { left: ' +
							tooltipTailLeft + 'px; }'
					);
				}
			}
		};

		// Run some function for all the tooltips up to the top one in a tree. Its context will be
		// the tooltip, while its parameters may be passed to Tooltip.upToTopParent as an array
		// in the second parameter. If the third parameter passed to ToolTip.upToTopParent is true,
		// the execution stops when the function in question returns true for the first time,
		// and ToolTip.upToTopParent returns true as well.
		this.upToTopParent = function ( func, parameters, stopAtTrue ) {
			var returnValue,
				currentTooltip = this;

			do {
				returnValue = func.apply( currentTooltip, parameters );
				if ( stopAtTrue && returnValue ) {
					break;
				}
			} while ( currentTooltip = currentTooltip.parent );

			if ( stopAtTrue ) {
				return returnValue;
			}
		};
	}

	if ( !enabled ) {
		addEnableLink();
		return;
	}

	teSelector = REF_LINK_SELECTOR;
	if ( tooltipsForComments ) {
		teSelector += ', ' + COMMENTED_TEXT_SELECTOR;
	}
	$content.find( teSelector ).each( function () {
		new TooltippedElement( $( this ) );
	} );
}

try {
  settingsString = mw.cookie.get( 'RTsettings' );
} catch (e) {

}

if ( settingsString ) {
	settings = settingsString.split( '|' );
	enabled = Boolean( Number( settings[ 0 ] ) );
	delay = Number( settings[ 1 ] );
	activatedByClick = Boolean( Number( settings[ 2 ] ) );
	// The forth value was added later, so we provide for a default value. See comments below
	// for why we use "IS_TOUCHSCREEN && IS_MOBILE".
	tooltipsForComments = settings[ 3 ] === undefined ?
		IS_TOUCHSCREEN && IS_MOBILE :
		Boolean( Number( settings[ 3 ] ) );
} else {
	enabled = true;
	delay = 200;
	// Since the mobile browser check is error-prone, adding IS_MOBILE condition here would probably
	// leave cases where a user interacting with the browser using touches doesn't know how to call
	// a tooltip in order to switch to activation by click. Some touch-supporting laptop users
	// interacting by touch (though probably not the most popular use case) would not be happy too.
	activatedByClick = IS_TOUCHSCREEN;
	// Arguably we shouldn't convert native tooltips into gadget tooltips for devices that have
	// mouse support, even if they have touchscreens (there are laptops with touchscreens).
	// IS_TOUCHSCREEN check here is for reliability, since the mobile check is prone to false
	// positives.
	tooltipsForComments = IS_TOUCHSCREEN && IS_MOBILE;
}

mw.hook( 'wikipage.content' ).add( rt ); /* Default: Fired when wiki content is being added to the DOM */
/* mw.hook( 'wikipage.categories' ).add( rt ); */ /* Custom: Fired when categories are being added to the DOM */

};

$(referenceTooltips);


/* Stupid Firefox DOM related bugs */
/* Forces a refresh of the elements to fix rendering bugs */
jQuery( document ).ready( function ( $ ) {
  $(".article-image").hide().show(0);

  /* Hides Cargo's refresh option */
  $("#ca-cargo-purge").remove();
} );


//</nowiki>