Database changes have finished applying - please report any issues you're (still) seeing to support@shoutwiki.com.

Järjestelmäviesti:Common.js

Jedipediasta, vapaasta Tähtien sota-tietosanakirjasta tänään, 9. heinäkuuta 2025
Siirry navigaatioonSiirry hakuun

Huomautus: Selaimen välimuisti pitää tyhjentää asetusten tallentamisen jälkeen, jotta muutokset tulisivat voimaan.

  • Firefox ja Safari: Napsauta Shift-näppäin pohjassa Päivitä, tai paina Ctrl-F5 tai Ctrl-R (⌘-R Macilla)
  • Google Chrome: Paina Ctrl-Shift-R (⌘-Shift-R Macilla)
  • Internet Explorer ja Edge: Napsauta Ctrl-näppäin pohjassa Päivitä tai paina Ctrl-F5
  • Opera: Paina Ctrl-F5.
   1 /* <nowiki> */
   2 /* global $, ActiveXObject, mw */
   3 /* If you need help with these JS functions (i.e. you want some features, like standard summaries, for your own wiki), please ask [[User:Jack Phoenix|Jack Phoenix]]. */
   4 
   5 // onload stuff
   6 var firstRun = true;
   7 
   8 function loadFunc() {
   9 	if ( firstRun ) {
  10 		firstRun = false;
  11 	} else {
  12 		return;
  13 	}
  14 
  15 	window.pageName = mw.config.get( 'wgPageName' );
  16 	window.storagePresent = ( typeof localStorage != 'undefined' );
  17 
  18 	// DEPRECATED
  19 	if ( document.getElementById( 'infoboxinternal' ) !== null && document.getElementById( 'infoboxend' ) !== null ) {
  20 		document.getElementById( 'infoboxend' ).innerHTML = '<a id="infoboxtoggle" href="javascript:infoboxToggle()">[Piilota]</a>';
  21 	}
  22 
  23 	// Upload form - need to run before adding hide buttons
  24 	if ( mw.config.get( 'wgCanonicalSpecialPageName' ) === 'Upload' ) {
  25 		setupUploadForm();
  26 		fixDestinationNamePrefill();
  27 	}
  28 
  29 	addHideButtons();
  30 
  31 	if ( document.getElementById( 'mp3-navlink' ) !== null ) {
  32 		document.getElementById( 'mp3-navlink' ).onclick = onArticleNavClick;
  33 		document.getElementById( 'mp3-navlink' ).getElementsByTagName( 'a' )[0].href = 'javascript:void(0)';
  34 	}
  35 
  36 	if ( window.storagePresent ) {
  37 		initVisibility();
  38 	}
  39 
  40 	fillEditSummaries();
  41 	fillPreloads();
  42 
  43 	substUsername();
  44 	substUsernameTOC();
  45 	showEras( 'title-eraicons' );
  46 	showEras( 'title-shortcut' );
  47 	checkblock();
  48 	hideContentSub();
  49 	addWookAttribution();
  50 
  51 	if ( typeof onPageLoad != 'undefined' ) {
  52 		onPageLoad();
  53 	}
  54 }
  55 
  56 function infoboxToggle() {
  57 	var page = window.pageName.replace( /\W/g, '_' );
  58 	var nowShown;
  59 
  60 	if ( document.getElementById( 'infoboxtoggle' ).innerHTML == '[Piilota]' ) {
  61 		document.getElementById( 'infoboxinternal' ).style.display = 'none';
  62 		document.getElementById( 'infoboxtoggle' ).innerHTML = '[Näytä]';
  63 		nowShown = false;
  64 	} else {
  65 		document.getElementById( 'infoboxinternal' ).style.display = 'block';
  66 		document.getElementById( 'infoboxtoggle' ).innerHTML = '[Piilota]';
  67 		nowShown = true;
  68 	}
  69 
  70 	if ( window.storagePresent ) {
  71 		localStorage.setItem( 'infoboxshow-' + page, nowShown );
  72 	}
  73 }
  74 
  75 /**
  76  * jQuery version of Sikon's fillEditSummaries
  77  * @author Grunny
  78  */
  79 function fillEditSummaries() {
  80 	if ( !$( '#wpSummaryLabel' ).length ) {
  81 		return;
  82 	}
  83 
  84 	$.get( mw.config.get( 'wgScript' ), { title: 'Malline:Yhteenvedot', action: 'raw', ctype: 'text/plain' } ).done( function( data ) {
  85 		var	$summaryOptionsList,
  86 			$summaryLabel = $( '#wpSummaryLabel' ),
  87 			lines = data.split( '\n' ),
  88 			$wrapper = $( '<div>').addClass( 'edit-widemode-hide' ).text( 'Yleiset yhteenvedot: ' );
  89 
  90 		$summaryOptionsList = $( '<select />' ).attr( 'id', 'stdEditSummaries' ).change( function() {
  91 			var editSummary = $( this ).val();
  92 			if ( editSummary !== '' ) {
  93 				$( '#wpSummaryWidget input[name="wpSummary"]' ).val( editSummary );
  94 			}
  95 		} );
  96 
  97 		for ( var i = 0; i < lines.length; i++ ) {
  98 			var editSummaryText = ( lines[i].indexOf( '-- ' ) === 0 ) ? lines[i].substring(3) : '';
  99 			$summaryOptionsList.append( $( '<option>' ).val( editSummaryText ).text( lines[i] ) );
 100 		}
 101 
 102 		$summaryLabel.prepend( $wrapper.append( $summaryOptionsList ) );
 103 	} );
 104 
 105 }
 106 
 107 /**
 108  * jQuery version of Sikon's fillPreloads
 109  * @author Grunny
 110  */
 111 function fillPreloads() {
 112 	if ( !$( '#lf-preload' ).length ) {
 113 		return;
 114 	}
 115 
 116 	$( '#lf-preload' ).attr( 'style', 'display: block' );
 117 
 118 	$.get( mw.config.get( 'wgScript' ), { title: 'Malline:Stdpreloads', action: 'raw', ctype: 'text/plain' } ).done( function( data ) {
 119 		var	$preloadOptionsList,
 120 			lines = data.split( '\n' );
 121 
 122 		$preloadOptionsList = $( '<select />' ).attr( 'id', 'stdSummaries' ).change( function() {
 123 			var templateName = $( this ).val();
 124 			if ( templateName !== '' ) {
 125 				templateName = 'Malline:' + templateName + '/preload';
 126 				templateName = templateName.replace( ' ', '_' );
 127 				$.get( mw.config.get( 'wgScript' ), { title: templateName, action: 'raw', ctype: 'text/plain' } ).done( function( data ) {
 128 					insertAtCursor( document.getElementById( 'wpTextbox1' ), data );
 129 				} );
 130 			}
 131 		} );
 132 
 133 		for ( var i = 0; i < lines.length; i++ ) {
 134 			var templateText = ( lines[i].indexOf( '-- ' ) === 0 ) ? lines[i].substring(3) : '';
 135 			$preloadOptionsList.append( $( '<option>' ).val( templateText ).text( lines[i] ) );
 136 		}
 137 
 138 		$( '#lf-preload-cbox' ).html( $preloadOptionsList );
 139 	} );
 140 
 141 	$( '#lf-preload-pagename' ).html( '<input type="text" class="textbox" />' );
 142 	$( '#lf-preload-button' ).html( '<input type="button" class="button" value="Insert" onclick="doCustomPreload()" />' );
 143 
 144 }
 145 
 146 function doCustomPreload() {
 147 	var value = $( '#lf-preload-pagename > input' ).val();
 148 	value = value.replace( ' ', '_' );
 149 	$.get( mw.config.get( 'wgScript' ), { title: value, action: 'raw', ctype: 'text/plain' } ).done( function( data ) {
 150 		insertAtCursor( document.getElementById( 'wpTextbox1' ), data );
 151 	} );
 152 }
 153 
 154 /* Stores the (unmodified) page title. */
 155 function storePageName() {
 156 	if ( mw.config.get( 'skin' ) == 'monobook' || mw.config.get( 'skin' ) == 'vector' ) {
 157 		window.pageName = $( 'h1#firstHeading span' ).text();
 158 	} else if ( mw.config.get( 'skin' ) == 'bluecloud' || mw.config.get( 'skin' ) == 'eminence' || mw.config.get( 'skin' ) == 'monaco' ) {
 159 		window.pageName = $( 'h1.firstHeading' ).text();
 160 	} else if ( mw.config.get( 'skin' ) == 'games' || mw.config.get( 'skin' ) == 'nimbus' || mw.config.get( 'skin' ) == 'sports' ) {
 161 		window.pageName = $( 'h1.pagetitle' ).text();
 162 	} else if ( mw.config.get( 'skin' ) == 'hope' ) {
 163 		window.pageName = $( 'h2#one' ).text();
 164 	} else if ( mw.config.get( 'skin' ) == 'modern' ) {
 165 		window.pageName = $( 'h1#firstHeading span' ).text();
 166 	} else if ( mw.config.get( 'skin' ) == 'truglass' ) {
 167 		window.pageName = $( 'h1#title' ).text();
 168 	}
 169 }
 170 
 171 /* Adds a trim method to string variables. */
 172 String.prototype.trim = function() {
 173 	return this.replace( /^\s+|\s+$/g, '' );
 174 };
 175 
 176 /* Searches an array for an element and returns its index, or -1 if it's not in the array. */
 177 function arrayFind( array, value ) {
 178 	for ( var i = 0; i < array.length; i++ ) {
 179 		if ( array[i] == value ) {
 180 			return i;
 181 		}
 182 	}
 183 
 184 	return -1;
 185 }
 186 
 187 /* Removes the first occurrence of an element in an array, if it is there. */
 188 function arrayRemove( array, value ) {
 189 	var i = arrayFind( array, value );
 190 
 191 	if ( i != -1 ) {
 192 		array.splice( i, 1 );
 193 	}
 194 }
 195 
 196 /*
 197 	the ContentLoader class to encapsulate "creative differences" with XHR
 198 
 199 	Usage:
 200 		- construct a ContentLoader object: var loader = new ContentLoader();
 201 		- set necessary state parameters (via fields); e.g. loader.myvar = 'mytext';
 202 		- set the callback: loader.callback = myfunc;
 203 		- send the request:
 204 			loader.send(url, postdata = null, contentType = 'application/x-www-form-urlencoded');
 205 			(if postdata isn't null or omitted, POST is used, otherwise GET)
 206 		- the callback function is called when the content is loaded
 207 			- the ContentLoader object is this
 208 			- the raw response data is this.text
 209 			- the XML DOM object, if any, is this.document
 210 */
 211 function ContentLoader() {
 212 	this.cache = true;
 213 }
 214 
 215 ContentLoader.prototype.enableCache = function( caching ) {
 216 	this.cache = ( caching === null ) ? true : this.cache;
 217 };
 218 
 219 ContentLoader.prototype.createRequest = function() {
 220 	if ( typeof XMLHttpRequest != 'undefined' ) {
 221 		return new XMLHttpRequest();
 222 	} else if ( typeof ActiveXObject != 'undefined' ) {
 223 		return new ActiveXObject( 'Msxml2.XMLHTTP' );
 224 	}
 225 
 226 	return null;
 227 };
 228 
 229 ContentLoader.prototype.send = function( url, postdata, contentType ) {
 230 	var method = ( postdata === null ) ? 'GET' : 'POST';
 231 	this.request = this.createRequest();
 232 	this.request.open( method, url );
 233 
 234 	if ( !this.cache ) {
 235 		this.request.setRequestHeader( 'If-Modified-Since', 'Sat, 1 Jan 2000 00:00:00 GMT' );
 236 	}
 237 
 238 	var request = this.request;
 239 	var loader = this;
 240 
 241 	if ( postdata === null ) {
 242 		if ( contentType === null ) {
 243 			contentType = 'application/x-www-form-urlencoded';
 244 		}
 245 
 246 		request.setRequestHeader( 'Content-type', contentType );
 247 	}
 248 
 249 	var f = function() {
 250 		if ( request.readyState == 4 ) {
 251 			loader.text = request.responseText;
 252 			loader.document = request.responseXML;
 253 			request = null;
 254 			loader.request = null;
 255 			loader.callback();
 256 		}
 257 	};
 258 
 259 	this.request.onreadystatechange = f;
 260 	this.request.send( postdata );
 261 };
 262 /* end ContentLoader */
 263 
 264 /*
 265 	Source: http://www.dustindiaz.com/getelementsbyclass/
 266 	getElementsByClass, which complements getElementById and getElementsByTagName, returns an array of all subelements of ''node'' that are tagged with a specific CSS class (''searchClass'') and are of the tag name ''tag''. If tag is null, it searches for any suitable elements regardless of the tag name.
 267 	Example: getElementsByClass('infobox', document.getElementById('content'), 'div') selects the same elements as the CSS declaration #content div.infobox
 268 */
 269 function ClassTester( className ) {
 270 	this.regex = new RegExp( "(^|\\s)" + className + "(\\s|$)" );
 271 }
 272 
 273 ClassTester.prototype.isMatch = function( element ) {
 274 	return this.regex.test( element.className );
 275 };
 276 
 277 function getElementsByClass( searchClass, node, tag ) {
 278 	var classElements = [];
 279 
 280 	if ( node === null || node === undefined ) {
 281 		node = document;
 282 	}
 283 
 284 	if ( tag === null ) {
 285 		tag = '*';
 286 	}
 287 
 288 	var els = node.getElementsByTagName( tag );
 289 	var elsLen = els.length;
 290 	var tester = new ClassTester( searchClass );
 291 
 292 	var i, j;
 293 	for ( i = 0, j = 0; i < elsLen; i++ ) {
 294 		if ( tester.isMatch( els[i] ) ) {
 295 			classElements[j] = els[i];
 296 			j++;
 297 		}
 298 	}
 299 
 300 	return classElements;
 301 }
 302 /* end getElementsByClass */
 303 
 304 /* Returns h1.firstHeading (the page title element). */
 305 function getFirstHeading() {
 306 	var elements = getElementsByClass( 'firstHeading', document.getElementById( 'content' ), 'h1' );
 307 	return ( elements !== null && elements.length > 0 ) ? elements[0] : null;
 308 }
 309 
 310 /* Returns the element's nearest parent that has the specified CSS class. */
 311 function getParentByClass( className, element ) {
 312 	var tester = new ClassTester( className );
 313 	var node = element.parentNode;
 314 
 315 	while ( node !== null && node != document ) {
 316 		if ( tester.isMatch( node ) ) {
 317 			return node;
 318 		}
 319 
 320 		node = node.parentNode;
 321 	}
 322 
 323 	return null;
 324 }
 325 
 326 /*
 327 	Replaces {{USERNAME}} with the name of the user browsing the page.
 328 	Requires copying Template:USERNAME.
 329 */
 330 function substUsername() {
 331 	var username = mw.config.get( 'wgUserName' );
 332 
 333 	if ( username === null ) {
 334 		return;
 335 	}
 336 
 337 	$( 'span.insertusername' ).html( username );
 338 }
 339 
 340 /* Force preview for anons */
 341 /* by Marc Mongenet, 2006, fr.wikipedia */
 342 function forcePreview() {
 343 	if ( mw.config.get( 'wgUserName' ) !== null || mw.config.get( 'wgAction' ) != 'edit' ) {
 344 		return;
 345 	}
 346 	var saveButton = document.getElementById( 'wpSave' );
 347 	if ( !saveButton ) {
 348 		return;
 349 	}
 350 	saveButton.disabled = true;
 351 	saveButton.value = 'Tallenna sivu (esikatsele muokkauksiasi ensiksi)';
 352 	saveButton.style.fontWeight = 'normal';
 353 	saveButton.style.color = 'gray';
 354 	document.getElementById( 'wpPreview' ).style.fontWeight = 'bold';
 355 }
 356 $( forcePreview );
 357 /* End of forcePreview */
 358 
 359 // ============================================================
 360 // BEGIN JavaScript title rewrite -- jQuery version and new wikia skin fixes by Grunny
 361 
 362 function showEras( className ) {
 363 	if ( typeof window.SKIP_ERAS != 'undefined' && window.SKIP_ERAS ) {
 364 		return;
 365 	}
 366 
 367 	var titleDiv = document.getElementById( className );
 368 
 369 	if ( titleDiv === null || titleDiv === undefined ) {
 370 		return;
 371 	}
 372 
 373 	var cloneNode = titleDiv.cloneNode( true );
 374 	var firstHeading = getFirstHeading();
 375 	firstHeading.insertBefore( cloneNode, firstHeading.childNodes[0] );
 376 	cloneNode.style.display = 'block';
 377 }
 378 // END JavaScript title rewrite
 379 
 380 function initVisibility() {
 381 	var page = window.pageName.replace( /\W/g, '_' );
 382 	var show = localStorage.getItem( 'infoboxshow-' + page );
 383 
 384 	if ( show == 'false' ) {
 385 		infoboxToggle();
 386 	}
 387 
 388 	var hidables = getElementsByClass( 'hidable' );
 389 
 390 	for ( var i = 0; i < hidables.length; i++ ) {
 391 		show = localStorage.getItem( 'hidableshow-' + i  + '_' + page );
 392 
 393 		var content, button;
 394 		if ( show == 'false' ) {
 395 			content = getElementsByClass( 'hidable-content', hidables[i] );
 396 			button = getElementsByClass( 'hidable-button', hidables[i] );
 397 
 398 			if (
 399 				content !== null && content.length > 0 &&
 400 				button !== null && button.length > 0 &&
 401 				content[0].style.display != 'none'
 402 			)
 403 			{
 404 				button[0].onclick( 'bypass' );
 405 			}
 406 		} else if ( show == 'true' ) {
 407 			content = getElementsByClass( 'hidable-content', hidables[i] );
 408 			button = getElementsByClass( 'hidable-button', hidables[i] );
 409 
 410 			if (
 411 				content !== null && content.length > 0 &&
 412 				button !== null && button.length > 0 &&
 413 				content[0].style.display == 'none'
 414 			)
 415 			{
 416 				button[0].onclick( 'bypass' );
 417 			}
 418 		}
 419 	}
 420 }
 421 
 422 function onArticleNavClick() {
 423 	var div = document.getElementById( 'mp3-nav' );
 424 
 425 	if ( div.style.display == 'block' ) {
 426 		div.style.display = 'none';
 427 	} else {
 428 		div.style.display = 'block';
 429 	}
 430 }
 431 
 432 function addHideButtons() {
 433 	var hidables = getElementsByClass( 'hidable' );
 434 
 435 	for ( var i = 0; i < hidables.length; i++ ) {
 436 		var box = hidables[i];
 437 		var button = getElementsByClass( 'hidable-button', box, 'span' );
 438 
 439 		if ( button !== null && button.length > 0 ) {
 440 			button = button[0];
 441 
 442 			button.onclick = toggleHidable;
 443 			button.appendChild( document.createTextNode( '[Piilota]' ) );
 444 
 445 			if ( new ClassTester( 'start-hidden' ).isMatch( box ) ) {
 446 				button.onclick( 'bypass' );
 447 			}
 448 		}
 449 	}
 450 }
 451 
 452 function toggleHidable( bypassStorage ) {
 453 	var parent = getParentByClass( 'hidable', this );
 454 	var content = getElementsByClass( 'hidable-content', parent );
 455 	var nowShown;
 456 
 457 	if ( content !== null && content.length > 0 ) {
 458 		content = content[0];
 459 
 460 		if ( content.style.display == 'none' ) {
 461 			content.style.display = content.oldDisplayStyle;
 462 			this.firstChild.nodeValue = '[Piilota]';
 463 			nowShown = true;
 464 		} else {
 465 			content.oldDisplayStyle = content.style.display;
 466 			content.style.display = 'none';
 467 			this.firstChild.nodeValue = '[Näytä]';
 468 			nowShown = false;
 469 		}
 470 
 471 		if ( window.storagePresent && ( typeof bypassStorage == 'undefined' || bypassStorage != 'bypass' ) ) {
 472 			var page = window.pageName.replace( /\W/g, '_' );
 473 			var items = getElementsByClass( 'hidable' );
 474 			var item = -1;
 475 
 476 			for ( var i = 0; i < items.length; i++ ) {
 477 				if ( items[i] == parent ) {
 478 					item = i;
 479 					break;
 480 				}
 481 			}
 482 
 483 			if ( item == -1 ) {
 484 				return;
 485 			}
 486 
 487 			localStorage.setItem( 'hidableshow-' + item + '_' + page, nowShown );
 488 		}
 489 	}
 490 }
 491 
 492 function substUsernameTOC() {
 493 	var toc = $( '#toc' );
 494 	var userpage = $( '#pt-userpage' );
 495 
 496 	if ( !userpage || !toc ) {
 497 		return;
 498 	}
 499 
 500 	var username = $( '#pt-userpage' ).children( ':first-child' ).text();
 501 	$( 'span.toctext:not(:has(*)), span.toctext i', toc ).each( function() {
 502 		$( this ).text( $( this ).text().replace( '<insert name here>', username ) );
 503 	} );
 504 }
 505 
 506 $( loadFunc );
 507 
 508 function checkblock() {
 509 	mw.loader.using( 'mediawiki.util', function () {
 510 		if ( mw.util.getParamValue( 'submitblock' ) == 'true' && document.getElementById( 'blockip' ) ) {
 511 			document.getElementById( 'blockip' ).wpBlock.click();
 512 		}
 513 	} );
 514 }
 515 
 516 
 517 /**
 518  * Start upload form customisations
 519  * @author Green tentacle
 520  */
 521 function setupUploadForm() {
 522 	// Check if cookie has been set for form style. Overrides URL parameter if set.
 523 	var formstyle = localStorage.getItem( 'uploadform' );
 524 
 525 	$( '#uploadBasicLinkJS' ).show();
 526 	$( '#uploadTemplateNoJS' ).hide();
 527 
 528 	var wpLicense = $( '#wpLicense' );
 529 
 530 	if ( wpLicense.length && window.location.search.indexOf( 'wpForReUpload=1' ) == -1 ) {
 531 		if (
 532 			formstyle == 'guided' ||
 533 			( formstyle === '' && window.location.search.indexOf( 'basic=true' ) == -1 )
 534 		)
 535 		{
 536 			// Add link to basic form
 537 			$( '#uploadtext' ).prepend( '<div style="float: right;" id="uploadBasicLinkJS"><a href="' + mw.config.get( 'wgServer' ) + mw.config.get( 'wgScriptPath' ) + '/index.php?title=Toiminnot:Tallenna&basic=true" onclick="javascript:localStorage.setItem(\'uploadform\', \'basic\')">Vaihda tavalliseen tallennukseen</a></div>' );
 538 
 539 			// Stretch table to full width
 540 			$( '#mw-htmlform-description' ).css( 'width', '100%' );
 541 
 542 			// Bind upload button to verify function
 543 			$( '#mw-upload-form' ).on( 'submit', verifySummary );
 544 
 545 			// Hide existing rows
 546 			var rows = $( '#mw-htmlform-description' ).find( 'tr' );
 547 			$( 'tr.mw-htmlform-field-HTMLTextAreaField' ).hide();
 548 			$( 'tr.mw-htmlform-field-HTMLTextAreaField' ).next().detach();
 549 
 550 			$( '#mw-htmlform-description' ).addClass( 'hidable start-hidden' );
 551 
 552 			// Add new required rows
 553 			rows.eq( 1 ).after( '<tr><td class="mw-label" style="width: 125px;">Lähde:</td><td class="mw-input"><textarea id="sourceBox" cols="60" rows="2" style="overflow: auto;"></textarea></td></tr>' );
 554 			$( '#mw-htmlform-description' ).append( '<tbody class="hidable-content"></tbody>' );
 555 			var tbody1 = $( '#mw-htmlform-description' ).children( 'tbody' ).eq( 0 );
 556 			tbody1.append( '<tr><td class="mw-label" style="width: 125px;">Kuvaus:</td><td class="mw-input"><textarea id="descriptionBox" cols="60" rows="2" style="overflow: auto;"></textarea></td></tr>' );
 557 			tbody1.append( '<tr><td colspan="2" style="text-align: center;">Valinnaiset kentät <span class="hidable-button"></span></td></tr>' );
 558 
 559 			// Add new optional rows
 560 			var tbody2 = $( '#mw-htmlform-description' ).children( 'tbody' ).eq( 1 );
 561 			tbody2.append( '<tr><td class="mw-label" style="width: 125px;">Huomio:</td><td class="mw-input"><textarea id="attentionBox" cols="60" rows="2" style="overflow: auto;"></textarea></td></tr>' );
 562 			tbody2.append( '<tr><td class="mw-label" style="width: 125px;">Alkuperäinen tekijä / artisti:</td><td class="mw-input"><textarea id="artistBox" cols="60" rows="2" style="overflow: auto;"></textarea></td></tr>' );
 563 			tbody2.append( '<tr><td class="mw-label" style="width: 125px;">Muut versiot:</td><td class="mw-input"><textarea id="versionsBox" cols="60" rows="2" style="overflow: auto;"></textarea></td></tr>' );
 564 			tbody2.append( '<tr><td class="mw-label" style="width: 125px;">Luokat:</td><td class="mw-input"><textarea id="catBox" cols="60" rows="2" style="overflow: auto;"></textarea></td></tr>' );
 565 		} else {
 566 			// Old style form just needs Information template in the summary box
 567 			//$( '#wpUploadDescription' ).val( '{{Tiedot\r\n|huomio=\r\n|kuvaus=\r\n|lähde=\r\n|tekijä=\r\n|lisenssi=\r\n|muut versiot=\r\n}}' );
 568 
 569 			// Add link to guided form
 570 			$( '#uploadtext' ).prepend( '<div style="float: right;" id="uploadBasicLinkJS"><a href="' + mw.config.get( 'wgServer' ) + mw.config.get( 'wgScriptPath' ) + '/index.php?title=Toiminnot:Tallenna" onclick="javascript:localStorage.setItem(\'uploadform\', \'guided\')">Vaihda ohjattuun tallennukseen</a></div>' );
 571 
 572 			$( '#mw-upload-form' ).on( 'submit', verifyName );
 573 		}
 574 	}
 575 }
 576 
 577 function verifySummary() {
 578 	var wpLicense = document.getElementById( 'wpLicense' );
 579 	var wpDestFile = document.getElementById( 'wpDestFile' );
 580 	var skipWarnings = document.getElementById( 'wpIgnoreWarning' ).value === '1'; // [sic]!
 581 
 582 	// Check for licensing
 583 	if ( wpLicense.value === '' && !skipWarnings ) {
 584 		alert( 'Lisenssi on merkittävä.' );
 585 		return false;
 586 	}
 587 
 588 	// Check for source
 589 	if ( document.getElementById( 'sourceBox' ).value === '' && !skipWarnings ) {
 590 		alert( 'Lähde on merkittävä.' );
 591 		return false;
 592 	}
 593 
 594 	// Check for duplicated or capitalized file extensions
 595 	if ( wpDestFile.value.match( /(JPG|PNG|GIF|SVG|jpeg|jpg\.jpg|png\.png|gif\.gif|svg\.svg|svg\.png|PNG\.png|JPG\.jpg)$/ ) && !skipWarnings ) {
 596 		alert( 'Älä käytä isokirjaimisia, pidennettyjä tai kaksinkertaisia tiedostopäätteitä tiedoston nimessä.' );
 597 		return false;
 598 	}
 599 
 600 	var strBuilder = '{{Tiedot\r\n';
 601 	strBuilder += '|huomio=' + document.getElementById( 'attentionBox' ).value + '\r\n';
 602 	strBuilder += '|kuvaus=' + document.getElementById( 'descriptionBox' ).value + '\r\n';
 603 	strBuilder += '|lähde=' + document.getElementById( 'sourceBox' ).value + '\r\n';
 604 	strBuilder += '|tekijä=' + document.getElementById( 'artistBox' ).value + '\r\n';
 605 	strBuilder += '|lisenssi=' + wpLicense.options[wpLicense.selectedIndex].title + '\r\n';
 606 	strBuilder += '|muut versiot=' + document.getElementById( 'versionsBox' ).value + '\r\n';
 607 	strBuilder += '|luokat=' + document.getElementById( 'catBox' ).value + '\r\n';
 608 	strBuilder += '}}';
 609 
 610 	document.getElementById( 'wpUploadDescription' ).value = strBuilder;
 611 
 612 	wpLicense.selectedIndex = 0;
 613 
 614 	return true;
 615 }
 616 
 617 function verifyName() {
 618 	var wpDestFile = document.getElementById( 'wpDestFile' );
 619 	var wpLicense = document.getElementById( 'wpLicense' );
 620 	var skipWarnings = document.getElementById( 'wpIgnoreWarning' ).value === '1'; // [sic]!
 621 
 622 	// Check for duplicated or capitalized file extensions
 623 	if ( wpDestFile.value.match( /(JPG|PNG|GIF|SVG|jpeg|jpg\.jpg|png\.png|gif\.gif|svg\.svg|svg\.png|PNG\.png|JPG\.jpg)$/ ) && !skipWarnings ) {
 624 		alert( 'Älä käytä isokirjaimisia, pidennetttyjä tai kaksinkertaisia tiedostopäätteitä tiedoston nimessä.' );
 625 		return false;
 626 	}
 627 
 628 	// Check for annoying characters
 629 	if ( wpDestFile.value.match( /(\(|\)|!|\?|,|\+|\'|\’)/ ) && !skipWarnings ) {
 630 		alert( 'Älä käytä erikoismerkkejä tiedoston nimessä.' );
 631 		return false;
 632 	}
 633 
 634 	if ( wpLicense.value !== '' ) {
 635 		$( '#wpUploadDescription' ).val(
 636 			$( '#wpUploadDescription' ).val().replace( '|lisenssi=', '|lisenssi=' + wpLicense.options[wpLicense.selectedIndex].title )
 637 		);
 638 
 639 		wpLicense.selectedIndex = 0;
 640 	}
 641 
 642 	return true;
 643 }
 644 
 645 /**
 646  * End upload form customisations
 647  */
 648 
 649 /** Archive edit tab disabling *************************************
 650  * Disables the edit tab on old forum topic pages to stop noobs bumping old topics.
 651  * Page can still be edited by going via the edit tab on the history etc, or by
 652  * typing the edit address manually.
 653  * By [[:en:User:Spang|Spang]]
 654  * Monaco support by [[:en:User:Uberfuzzy|Uberfuzzy]]
 655  * Removal of new section tab on talk pages added by [[:en:User:Grunny|Grunny]]
 656  * Vector support by [[User:--miki--|--miki--]]
 657  */
 658 function disableOldForumEdit() {
 659 	if ( typeof window.enableOldForumEdit != 'undefined' && window.enableOldForumEdit ) {
 660 		return;
 661 	}
 662 
 663 	if (
 664 		!document.getElementById( 'archive-page' ) ||
 665 		!document.getElementById( 'ca-edit' ) ||
 666 		mw.config.get( 'wgNamespaceNumber' ) === 10
 667 	)
 668 	{
 669 		return;
 670 	}
 671 
 672 	var $editLink;
 673 	if ( mw.config.get( 'skin' ) == 'monaco' ) {
 674 		$editLink = $( '#ca-edit' );
 675 	} else if ( mw.config.get( 'skin' ) == 'monobook' || mw.config.get( 'skin' ) == 'vector' ) {
 676 		$editLink = $( '#ca-edit a' );
 677 	}
 678 
 679 	$editLink.removeAttr( 'href title' );
 680 	$editLink.css( 'color', 'gray');
 681 	$editLink.text( 'Arkisto' );
 682 
 683 	$( 'span.mw-editsection' ).remove();
 684 	$( '#control_addsection, #ca-addsection' ).remove();
 685 }
 686 $( disableOldForumEdit );
 687 
 688 /**
 689  * Konami Code JavaScript from http://snipplr.com/view/15785/jquery-konami-code-listener/
 690  * Some fixes & MediaWikification by Jack Phoenix
 691  * @date February 5, 2010
 692  */
 693 function konamiCode() {
 694 	var kkeys = [],
 695 		// up, up, down, down, left, right, left, right, B, A
 696 		konami = '38,38,40,40,37,39,37,39,66,65';
 697 	$( document ).on( 'keydown', function( e ) {
 698 		kkeys.push( e.keyCode );
 699 		if ( kkeys.toString().indexOf( konami ) >= 0 ) {
 700 			var logoURL = 'https://images.shoutwiki.com/fi.darth/b/bc/Wiki.png';
 701 			// Hide the current logo...
 702 			mw.util.addCSS( '#p-logo a { display: none !important; }' );
 703 			// ...and append the new one!
 704 			mw.util.addCSS( '#p-logo {' +
 705 				'background-image: url("' + logoURL + '") !important;' +
 706 				'background-repeat: no-repeat !important;' +
 707 				'background-position: 35% 50% !important;' +
 708 				'display: block !important;' +
 709 			'}' );
 710 		}
 711 	} );
 712 }
 713 $( konamiCode );
 714 
 715 // Katso [[Foorumi:SH:Malline:Suositeltu]]
 716 /* Magic edit intro. Copied from Wikipedia's MediaWiki:Common.js, modified for use in both Monaco and Monobook skins by Sikon */
 717 function addEditIntro( name ) {
 718 	// Top link
 719 	var el = document.getElementById( 'ca-edit' );
 720 
 721 	if ( typeof el.href == 'undefined' ) {
 722 		el = el.getElementsByTagName( 'a' )[0];
 723 	}
 724 
 725 	if ( el ) {
 726 		el.href += '&editintro=' + name;
 727 	}
 728 
 729 	// Section links
 730 	var spans = document.getElementsByTagName( 'span' );
 731 	for ( var i = 0; i < spans.length; i++ ) {
 732 		el = null;
 733 
 734 		if ( spans[i].className == 'editsection' ) {
 735 			el = spans[i].getElementsByTagName( 'a' )[0];
 736 			if ( el ) {
 737 				el.href += '&editintro=' + name;
 738 			}
 739 		} else if ( spans[i].className == 'editsection-upper' ) {
 740 			el = spans[i].getElementsByTagName( 'a' )[0];
 741 			if ( el ) {
 742 				el.href += '&editintro=' + name;
 743 			}
 744 		}
 745 	}
 746 }
 747 
 748 if ( mw.config.get( 'wgNamespaceNumber' ) === 0 ) {
 749 	$( function() {
 750 		var cats = document.getElementById( 'catlinks' );
 751 		if ( !cats ) {
 752 			return;
 753 		}
 754 		cats = cats.getElementsByTagName( 'a' );
 755 		for ( var i = 0; i < cats.length; i++ ) {
 756 			if ( cats[i].title === 'Luokka:Työn alla olevat artikkelit' ) {
 757 				addEditIntro( 'Malline:Työn_alla' );
 758 				break;
 759 			} else if ( cats[i].title === 'Luokka:Suositellut sivut' ) {
 760 				addEditIntro( 'Malline:Suositeltu' );
 761 				break;
 762 			} else if ( cats[i].title === 'Luokka:Hyvät artikkelit' ) {
 763 				addEditIntro( 'Malline:Hyvä' );
 764 				break;
 765 			} else if ( cats[i].title === 'Luokka:Legends-artikkelit, joista on vastine kaanonissa' ) {
 766 				addEditIntro( 'Malline:Legendsintro' );
 767 				break;
 768 			} else if ( cats[i].title === 'Luokka:Kaanonartikkelit, joista on vastine Legendsissä' ) {
 769 				addEditIntro( 'Malline:Kaanonintro' );
 770 				break;
 771 			}
 772 		}
 773 	} );
 774 }
 775 
 776 /**
 777  * Hides the link to parent pages from subpages if {{HideContentSub}} is included
 778  */
 779 function hideContentSub() {
 780 	if ( mw.config.get( 'wgNamespaceNumber' ) === 0 || $( '#hideContentSub' ).length > 0 ) {
 781 		if ( $( '#contentSub span.subpages' ).text().substring( 0, 1 ) === '<' ) {
 782 			$( '#contentSub span.subpages' ).hide();
 783 		}
 784 	}
 785 }
 786 
 787 // Lisätään artikkelin alareunaan tieto, että se perustuu Wookieepedian artikkeliin.
 788 // {{HideWookAttribution}} poistaa tekstin kyseiseltä sivulta ja window.hideWookAttribution = true kokonaan käytöstä
 789 function addWookAttribution() {
 790 	if ( window.hideWookAttribution ) { return; }
 791 	var wookLink = $( 'li.interwiki-en a:first' );
 792 	if ( mw.config.get( 'wgNamespaceNumber' ) !== 0 || $( '#hideWookAttribution' ).length > 0 || !wookLink.length ) {
 793 		return;
 794 	}
 795 
 796 	var wookArticle = wookLink.attr( 'title' ).replace( ' — English', '' );
 797 
 798 	$( '#bodyContent' ).append( '<div id="WookAttribution"><hr />Tämä artikkeli tai osa siitä perustuu <a rel="nofollow" href="https://starwars.fandom.com/">Wookieepedian</a> artikkeliin ”<a rel="nofollow" href="' + wookLink.attr( 'href' ) + '">' + wookArticle + '</a>”.</div>' );
 799 }
 800 
 801 // Käytettävyyskorjaus uudelle navigaatiovalikolle, ks. [[Foorumi:YA:Uusi navigaatiovalikko]]
 802 $( function() {
 803 	if (
 804 		'ontouchstart' in window && // kosketusnäytöllinen laite
 805 		mw.config.get( 'wgTitle' ) === mw.config.get( 'wgMainPageTitle' ) // etusivu
 806 	)
 807 	{
 808 		$( '.topmenu > a' ).on( 'touchstart', function( e ) {
 809 			$( this ).off( 'touchstart' ).on( 'click', function( e ) {
 810 				e.preventDefault();
 811 			} );
 812 			e.preventDefault();
 813 		} );
 814 	}
 815 } );
 816 
 817 /**
 818  * Fix the upload form destination name prefilling for Wikia image URLs
 819  * (e.g. https://vignette.wikia.nocookie.net/starwars/images/0/0e/QueensShadow.png/revision/latest?cb=20190305210550&format=original)
 820  *
 821  * By default MediaWiki takes the part after the last slash and makes that the suggested
 822  * destination name. For Wikia domains this is always wrong and the part after
 823  * the last slash is garbage we don't care about.
 824  *
 825  * @date 18 March 2019
 826  */
 827 function fixDestinationNamePrefill() {
 828 	if ( window.location.search.indexOf( 'wpForReUpload=1' ) == -1 ) {
 829 		$( '#wpUploadFileURL' ).change( function() {
 830 			var val = $( this ).val(),
 831 				splitArr = val.split( '/' );
 832 			if ( !String( val ).match( /nocookie.net/gi ) ) {
 833 				return;
 834 			}
 835 			if ( splitArr.length !== 10 ) {
 836 				return;
 837 			}
 838 			$( '#wpDestFile' ).val( splitArr[7] );
 839 		} );
 840 	}
 841 }
 842 
 843 /* Link FA */
 844 
 845 window.FA_enabled = true;
 846 
 847 function addFAicon() {
 848 	// early return if explicitly disabled
 849 	if ( !window.FA_enabled ) {
 850 		return;
 851 	}
 852 	// article namespace only
 853 	if ( mw.config.get( 'wgNamespaceNumber' ) !== 0 ) {
 854 		return;
 855 	}
 856 
 857 	var pLang = document.getElementById( 'p-lang' );
 858 	if ( !pLang ) {
 859 		return;
 860 	}
 861 	var lis = pLang.getElementsByTagName( 'li' );
 862 	for ( var i = 0; i < lis.length; i++ ) {
 863 		var li = lis[i];
 864 		// only links with a corresponding FA/GA/CA templates are interesting
 865 		if ( document.getElementById( 'interwiki-' + li.firstChild.lang + '-fa' ) ) {
 866 			// additional class so the template can be hidden with CSS
 867 			li.className += ' FA';
 868 			// change title (description on mouseover)
 869 			li.title = 'Tämä artikkeli on suositeltu sivu.';
 870 		} else if ( document.getElementById( 'interwiki-' + li.firstChild.lang + '-ga' ) ) {
 871 			// additional class so the template can be hidden with CSS
 872 			li.className += ' GA';
 873 			// change title (description on mouseover)
 874 			li.title = 'Tämä artikkeli on hyvä artikkeli.';
 875 		} else if ( document.getElementById( 'interwiki-' + li.firstChild.lang + '-ca' ) ) {
 876 			// additional class so the template can be hidden with CSS
 877 			li.className += ' CA';
 878 			// change title (description on mouseover)
 879 			li.title = 'Tämä artikkeli on lupaava artikkeli.';
 880 		}
 881 	}
 882 }
 883 $( addFAicon );
 884 
 885 // Lazy load SWTOR article appearances list
 886 $( function lazyLoadTorApp() {
 887 	var	pageName = 'Star_Wars:_The_Old_Republic',
 888 		appPageName = encodeURIComponent( pageName + '/Esiintymiset' ),
 889 		$lazyLoadEl = $( '#WookTorLazyload' ),
 890 		includeHtml,
 891 		$editLink;
 892 	if ( mw.config.get( 'wgPageName' ) !== pageName || !$lazyLoadEl.length ) {
 893 		return;
 894 	}
 895  
 896 	$lazyLoadEl.html( '<img src="https://images.shoutwiki.com/fi.starwars/4/44/Spinner.gif" style="vertical-align: baseline;" border="0" alt="Ladataan..." />' );
 897 	$.getJSON( '/w/api.php?action=parse&page=' + appPageName + '&format=json' )
 898 		.done( function ( data ) {
 899 			if ( data.parse && data.parse.text ) {
 900 				includeHtml = data.parse.text['*'];
 901 				$lazyLoadEl.html( includeHtml );
 902 				$editLink = $lazyLoadEl.prev( 'h2' ).find( '.mw-editsection a' );
 903 				if ( $editLink.length ) {
 904 					$editLink.attr( 'href', '/w/index.php?title=' + appPageName + '&action=edit' );
 905 				}
 906 				// Korvaava toiminto MediaWikin omalle piilotustoiminnolle, joka ei toimi
 907 				$( '.mw-customtoggle-applist' ).click( function() {
 908 					$( '#mw-customcollapsible-applist' ).toggleClass( 'mw-collapsed' );
 909 				} );
 910 			}
 911 		} );
 912 } );
 913 
 914 //Etusivun navigaatiovalikoiden lataaminen
 915 $( function loadDropdownOOU() {
 916 	var	pageName = 'Etusivu',
 917 		appPageName = encodeURIComponent( 'Malline:Dropdown-OOU' ),
 918 		$lazyLoadEl = $( '#DropdownOOUload' ),
 919 		includeHtml;
 920 	if ( mw.config.get( 'wgPageName' ) !== pageName || !$lazyLoadEl.length ) {
 921 		return;
 922 	}
 923  
 924 	$lazyLoadEl.html( '<img src="https://images.shoutwiki.com/fi.starwars/4/44/Spinner.gif" style="vertical-align: baseline;" border="0" alt="Ladataan..." />' );
 925 	$.getJSON( '/w/api.php?action=parse&page=' + appPageName + '&format=json' )
 926 		.done( function ( data ) {
 927 			if ( data.parse && data.parse.text ) {
 928 				includeHtml = data.parse.text['*'];
 929 				$lazyLoadEl.html( includeHtml );
 930 			}
 931 		} );
 932 } );
 933 
 934 $( function loadDropdownIU() {
 935 	var	pageName = 'Etusivu',
 936 		appPageName = encodeURIComponent( 'Malline:Dropdown-IU' ),
 937 		$lazyLoadEl = $( '#DropdownIUload' ),
 938 		includeHtml;
 939 	if ( mw.config.get( 'wgPageName' ) !== pageName || !$lazyLoadEl.length ) {
 940 		return;
 941 	}
 942  
 943 	$lazyLoadEl.html( '<img src="https://images.shoutwiki.com/fi.starwars/4/44/Spinner.gif" style="vertical-align: baseline;" border="0" alt="Ladataan..." />' );
 944 	$.getJSON( '/w/api.php?action=parse&page=' + appPageName + '&format=json' )
 945 		.done( function ( data ) {
 946 			if ( data.parse && data.parse.text ) {
 947 				includeHtml = data.parse.text['*'];
 948 				$lazyLoadEl.html( includeHtml );
 949 			}
 950 		} );
 951 } );
 952 
 953 /**
 954  * Convert a number to have commas in it
 955  * from mredkj.com
 956  */
 957 function addCommas( nStr ) {
 958 	nStr += ''; // make it a string
 959 	var x = nStr;
 960 	var rgx = /(\d+)(\d{3})/;
 961 	while ( rgx.test( x ) ) {
 962 		x = x.replace( rgx, '$1' + ' ' + '$2' );
 963 	}
 964 	return x;
 965 }
 966 
 967 /* Mahdollistaa muiden wikien artikkelimäärän päivittämisen reaaliaikaisesti */
 968 ( function() {
 969 	var stats = [ 'articles', 'activeusers', 'admins', 'edits', 'images' ],
 970 		wikis = [],
 971 		regex = /^[0-9a-z\.-]+$/,
 972 		prefix = 'outwikistats-';
 973 	$( stats.map( function( name ) {
 974 		return '.outwikistats-' + name;
 975 	} ).join( ', ' ) ).each( function() {
 976 		var $this = $( this ),
 977 			wiki = $this.text();
 978 		$this.attr( {
 979 			'data-attr': $this.attr( 'class' ).substring( prefix.length ),
 980  			'data-wiki': wiki
 981 		} ).html( $( '<img>', {
 982 			src: 'https://images.shoutwiki.com/fi.starwars/4/44/Spinner.gif'
 983 		} ) );
 984 		if ( wikis.indexOf( wiki ) === -1 ) {
 985 			wikis.push( wiki );
 986 		}
 987 	} );
 988 	wikis.forEach( function( wiki ) {
 989 		if ( !wiki.match( regex ) ) {
 990 			return;
 991 		}
 992 		var url;
 993 		if ( wiki == 'de' ) {
 994 			url = 'https://www.jedipedia.net/w';
 995 		} else if ( wiki == 'pl' ) {
 996 			url = 'https://www.ossus.pl';
 997 		} else if ( wiki == 'tr' ) {
 998 			url = 'https://starwarsturkiye.com/wiki';
 999 		} else {
1000 			url = 'https://starwars.fandom.com/' + wiki;
1001 		}
1002 		$.ajax( {
1003 			type: 'GET',
1004 			url: url + '/api.php',
1005 			data: {
1006 				action: 'query',
1007 				meta: 'siteinfo',
1008 				siprop: 'statistics',
1009 				format: 'json'
1010 			},
1011 			dataType: 'jsonp',
1012 			jsonp: 'callback',
1013 			crossDomain: true,
1014 			success: function( data ) {
1015 				var stats = data.query.statistics;
1016 				if ( !stats ) {
1017 					return;
1018 				}
1019 				$( '[data-wiki="' + wiki + '"]' ).each( function() {
1020 					var $this = $( this ),
1021 					prop = $this.attr( 'data-attr' ),
1022 					result = stats[prop];
1023 					var cresult = addCommas( result );
1024 					$this.text( cresult );
1025 				} );
1026 			}
1027 		} );
1028 	} );
1029 } )();
1030 
1031 /* Piilotetaan poisto/siirtolokin merkintä niillä sivuilla, jotka on siirretty /Legends-päätteiseksi (ks. [[MediaWiki:Noarticletext]]) */
1032 $( function() {
1033 	if ( $( '#hidelog' ).length ) {
1034 		$( 'div.mw-warning-with-logexcerpt' ).remove();
1035 	}
1036 } );
1037 
1038 /* Sisäänkirjautuminen ei toimi vanhaa fi.starwars.shoutwiki.com-osoitetta käytettäessä (liittynee
1039  * evästeiden asettamiseen), joten kierrätetään nämä pyynnöt ShoutWikin suomenkielisen keskuswikin kautta
1040  */
1041 mw.loader.using( 'mediawiki.util', function () {
1042 	if ( location.hostname == 'fi.starwars.shoutwiki.com' ) {
1043 		$( '#pt-login a' ).attr( 'href', 'http://fi.shoutwiki.com/w/index.php?title=Toiminnot:Kirjaudu_sis%C3%A4%C3%A4n&returnto=s:w:fi.starwars:' + mw.util.wikiUrlencode( mw.config.get( 'wgPageName' ) ) );
1044 	}
1045 } );
1046 
1047 // </nowiki>