r70200 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r70199‎ | r70200 | r70201 >
Date:18:53, 30 July 2010
Author:tparscal
Status:ok
Tags:
Comment:
Changed mw to mediawiki, while mw will be a common reference to the MediaWiki global, module files should not be called mw.* any more than jQuery plugin files should be called $.*
Modified paths:
  • /branches/resourceloader/phase3/resources/Resources.php (modified) (history)
  • /branches/resourceloader/phase3/resources/mediawiki (added) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.IEFixes.js (added) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.ajax.js (added) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.ajaxwatch.js (added) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.block.js (added) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.changepassword.js (added) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.edit.js (added) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.enhancedchanges.js (added) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.history.js (added) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.htmlform.js (added) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.metadata.js (added) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.mwsuggest.js (added) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.prefs.js (added) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.preview.js (added) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.protect.js (added) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.rightclickedit.js (added) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.search.js (added) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.upload.js (added) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.wikibits.js (added) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mw.legacy.IEFixes.js (deleted) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mw.legacy.ajax.js (deleted) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mw.legacy.ajaxwatch.js (deleted) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mw.legacy.block.js (deleted) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mw.legacy.changepassword.js (deleted) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mw.legacy.edit.js (deleted) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mw.legacy.enhancedchanges.js (deleted) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mw.legacy.history.js (deleted) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mw.legacy.htmlform.js (deleted) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mw.legacy.metadata.js (deleted) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mw.legacy.mwsuggest.js (deleted) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mw.legacy.prefs.js (deleted) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mw.legacy.preview.js (deleted) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mw.legacy.protect.js (deleted) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mw.legacy.rightclickedit.js (deleted) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mw.legacy.search.js (deleted) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mw.legacy.upload.js (deleted) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/legacy/mw.legacy.wikibits.js (deleted) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/mediawiki.js (added) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/mw.js (deleted) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/utilities/mediawiki.utilities.client.js (added) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/utilities/mw.utilities.client.js (deleted) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/views/mediawiki.views.diff.js (added) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/views/mediawiki.views.install.js (added) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/views/mw.views.diff.js (deleted) (history)
  • /branches/resourceloader/phase3/resources/mediawiki/views/mw.views.installer.js (deleted) (history)
  • /branches/resourceloader/phase3/resources/mw (deleted) (history)

Diff [purge]

Index: branches/resourceloader/phase3/resources/Resources.php
@@ -9,64 +9,76 @@
1010 'script' => 'resources/jquery/jquery.tabIndex.js',
1111 'raw' => true,
1212 ),
13 - 'mw' => array(
14 - 'script' => 'resources/mw/mw.js',
 13+ 'mediawiki' => array(
 14+ 'script' => 'resources/mediawiki/mediawiki.js',
1515 'raw' => true,
1616 ),
17 - 'mw.legacy.ajax' => array(
18 - 'script' => 'resources/mw/legacy/mw.legacy.ajax.js',
 17+ 'mediawiki.legacy.ajax' => array(
 18+ 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.ajax.js',
1919 ),
20 - 'mw.legacy.ajaxwatch' => array(
21 - 'script' => 'resources/mw/legacy/mw.legacy.ajaxwatch.js',
 20+ 'mediawiki.legacy.ajaxwatch' => array(
 21+ 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.ajaxwatch.js',
2222 ),
23 - 'mw.legacy.block' => array(
24 - 'script' => 'resources/mw/legacy/mw.legacy.block.js',
 23+ 'mediawiki.legacy.block' => array(
 24+ 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.block.js',
2525 ),
26 - 'mw.legacy.changepassword' => array(
27 - 'script' => 'resources/mw/legacy/mw.legacy.changepassword.js',
 26+ 'mediawiki.legacy.changepassword' => array(
 27+ 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.changepassword.js',
2828 ),
29 - 'mw.legacy.edit' => array(
30 - 'script' => 'resources/mw/legacy/mw.legacy.edit.js',
 29+ 'mediawiki.legacy.edit' => array(
 30+ 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.edit.js',
3131 ),
32 - 'mw.legacy.enhancedchanges' => array(
33 - 'script' => 'resources/mw/legacy/mw.legacy.enhancedchanges.js',
 32+ 'mediawiki.legacy.enhancedchanges' => array(
 33+ 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.enhancedchanges.js',
3434 ),
35 - 'mw.legacy.history' => array(
36 - 'script' => 'resources/mw/legacy/mw.legacy.history.js',
 35+ 'mediawiki.legacy.history' => array(
 36+ 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.history.js',
3737 ),
38 - 'mw.legacy.htmlform' => array(
39 - 'script' => 'resources/mw/legacy/mw.legacy.htmlform.js',
 38+ 'mediawiki.legacy.htmlform' => array(
 39+ 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.htmlform.js',
4040 ),
41 - 'mw.legacy.IEFixes' => array(
42 - 'script' => 'resources/mw/legacy/mw.legacy.IEFixes.js',
 41+ 'mediawiki.legacy.IEFixes' => array(
 42+ 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.IEFixes.js',
4343 ),
44 - 'mw.legacy.metadata' => array(
45 - 'script' => 'resources/mw/legacy/mw.legacy.metadata.js',
 44+ 'mediawiki.legacy.metadata' => array(
 45+ 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.metadata.js',
4646 ),
47 - 'mw.legacy.mwsuggest' => array(
48 - 'script' => 'resources/mw/legacy/mw.legacy.mwsuggest.js',
 47+ 'mediawiki.legacy.mwsuggest' => array(
 48+ 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.mwsuggest.js',
4949 ),
50 - 'mw.legacy.prefs' => array(
51 - 'script' => 'resources/mw/legacy/mw.legacy.prefs.js',
 50+ 'mediawiki.legacy.prefs' => array(
 51+ 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.prefs.js',
5252 ),
53 - 'mw.legacy.preview' => array(
54 - 'script' => 'resources/mw/legacy/mw.legacy.preview.js',
 53+ 'mediawiki.legacy.preview' => array(
 54+ 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.preview.js',
5555 ),
56 - 'mw.legacy.protect' => array(
57 - 'script' => 'resources/mw/legacy/mw.legacy.protect.js',
 56+ 'mediawiki.legacy.protect' => array(
 57+ 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.protect.js',
5858 ),
59 - 'mw.legacy.rightclickedit' => array(
60 - 'script' => 'resources/mw/legacy/mw.legacy.rightclickedit.js',
 59+ 'mediawiki.legacy.rightclickedit' => array(
 60+ 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.rightclickedit.js',
6161 ),
62 - 'mw.legacy.search' => array(
63 - 'script' => 'resources/mw/legacy/mw.legacy.search.js',
 62+ 'mediawiki.legacy.search' => array(
 63+ 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.search.js',
6464 ),
65 - 'mw.legacy.upload' => array(
66 - 'script' => 'resources/mw/legacy/mw.legacy.upload.js',
 65+ 'mediawiki.legacy.upload' => array(
 66+ 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.upload.js',
6767 ),
68 - 'mw.legacy.wikibits' => array(
69 - 'script' => 'resources/mw/legacy/mw.legacy.wikibits.js',
 68+ 'mediawiki.legacy.wikibits' => array(
 69+ 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.wikibits.js',
7070 ),
 71+
 72+ 'mediawiki.utilities.client' => array(
 73+ 'script' => 'resources/mediawiki/utilities/mediawiki.utilities.client.js',
 74+ ),
 75+
 76+ 'mediawiki.views.diff' => array(
 77+ 'script' => 'resources/mediawiki/views/mediawiki.views.diff.js',
 78+ ),
 79+ 'mediawiki.views.install' => array(
 80+ 'script' => 'resources/mediawiki/views/mediawiki.views.install.js',
 81+ ),
 82+
7183 'test' => array(
7284 'script' => 'resources/test/test.js',
7385 'loader' => 'resources/test/loader.js',
Index: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.history.js
@@ -0,0 +1,115 @@
 2+/*
 3+ * Legacy emulation for the now depricated skins/common/history.js
 4+ */
 5+
 6+( function( $, mw ) {
 7+
 8+/* Extension */
 9+
 10+$.extend( true, mw.legacy, {
 11+
 12+ /* Functions */
 13+
 14+ 'historyRadios': function( parent ) {
 15+ var inputs = parent.getElementsByTagName('input');
 16+ var radios = [];
 17+ for (var i = 0; i < inputs.length; i++) {
 18+ if (inputs[i].name == 'diff' || inputs[i].name == 'oldid') {
 19+ radios[radios.length] = inputs[i];
 20+ }
 21+ }
 22+ return radios;
 23+ },
 24+ /*
 25+ * Check selection and tweak visibility/class onclick
 26+ */
 27+ 'diffcheck': function() {
 28+ var dli = false; // the li where the diff radio is checked
 29+ var oli = false; // the li where the oldid radio is checked
 30+ var hf = document.getElementById('pagehistory');
 31+ if (!hf) {
 32+ return true;
 33+ }
 34+ var lis = hf.getElementsByTagName('li');
 35+ for (var i=0;i<lis.length;i++) {
 36+ var inputs = historyRadios(lis[i]);
 37+ if (inputs[1] && inputs[0]) {
 38+ if (inputs[1].checked || inputs[0].checked) { // this row has a checked radio button
 39+ if (inputs[1].checked && inputs[0].checked && inputs[0].value == inputs[1].value) {
 40+ return false;
 41+ }
 42+ if (oli) { // it's the second checked radio
 43+ if (inputs[1].checked) {
 44+ if ( (typeof oli.className) != 'undefined') {
 45+ oli.classNameOriginal = oli.className.replace( 'selected', '' );
 46+ } else {
 47+ oli.classNameOriginal = '';
 48+ }
 49+
 50+ oli.className = 'selected '+oli.classNameOriginal;
 51+ return false;
 52+ }
 53+ } else if (inputs[0].checked) {
 54+ return false;
 55+ }
 56+ if (inputs[0].checked) {
 57+ dli = lis[i];
 58+ }
 59+ if (!oli) {
 60+ inputs[0].style.visibility = 'hidden';
 61+ }
 62+ if (dli) {
 63+ inputs[1].style.visibility = 'hidden';
 64+ }
 65+ if ( (typeof lis[i].className) != 'undefined') {
 66+ lis[i].classNameOriginal = lis[i].className.replace( 'selected', '' );
 67+ } else {
 68+ lis[i].classNameOriginal = '';
 69+ }
 70+
 71+ lis[i].className = 'selected '+lis[i].classNameOriginal;
 72+ oli = lis[i];
 73+ } else { // no radio is checked in this row
 74+ if (!oli) {
 75+ inputs[0].style.visibility = 'hidden';
 76+ } else {
 77+ inputs[0].style.visibility = 'visible';
 78+ }
 79+ if (dli) {
 80+ inputs[1].style.visibility = 'hidden';
 81+ } else {
 82+ inputs[1].style.visibility = 'visible';
 83+ }
 84+ if ( typeof lis[i].classNameOriginal != 'undefined' ) {
 85+ lis[i].className = lis[i].classNameOriginal;
 86+ }
 87+ }
 88+ }
 89+ }
 90+ return true;
 91+ },
 92+ /*
 93+ * Attach event handlers to the input elements on history page
 94+ */
 95+ 'histrowinit': function() {
 96+ var hf = document.getElementById('pagehistory');
 97+ if (!hf) return;
 98+ var lis = hf.getElementsByTagName('li');
 99+ for (var i = 0; i < lis.length; i++) {
 100+ var inputs = historyRadios(lis[i]);
 101+ if (inputs[0] && inputs[1]) {
 102+ inputs[0].onclick = diffcheck;
 103+ inputs[1].onclick = diffcheck;
 104+ }
 105+ }
 106+ diffcheck();
 107+ }
 108+} );
 109+
 110+/* Initialization */
 111+
 112+$( document ).ready( function() {
 113+ mw.legacy.histrowinit();
 114+} );
 115+
 116+} )( jQuery, MediaWiki );
\ No newline at end of file
Property changes on: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.history.js
___________________________________________________________________
Added: svn:eol-style
1117 + native
Index: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.search.js
@@ -0,0 +1,63 @@
 2+/*
 3+ * Legacy emulation for the now depricated skins/common/search.js
 4+ *
 5+ * Progressive enhancement for Special:Search
 6+ */
 7+
 8+( function( $, mw ) {
 9+
 10+/* Extension */
 11+
 12+$.extend( true, mw.legacy, {
 13+
 14+ /* Functions */
 15+
 16+ /**
 17+ * Change the search link to what user entered
 18+ */
 19+ 'mwSearchHeaderClick': function( obj ) {
 20+ var searchbox = document.getElementById( 'searchText' );
 21+ if ( searchbox === null ) {
 22+ searchbox = document.getElementById( 'powerSearchText' );
 23+ }
 24+ if ( searchbox === null ) {
 25+ return; // should always have either normal or advanced search
 26+ }
 27+ var searchterm = searchbox.value;
 28+ var parts = obj.href.split( 'search=' );
 29+ var lastpart = '';
 30+ var prefix = 'search=';
 31+ if ( parts.length > 1 && parts[1].indexOf('&') >= 0 ) {
 32+ lastpart = parts[1].substring( parts[1].indexOf('&') );
 33+ } else {
 34+ prefix = '&search=';
 35+ }
 36+ obj.href = parts[0] + prefix + encodeURIComponent( searchterm ) + lastpart;
 37+ },
 38+ 'mwToggleSearchCheckboxes': function( btn ) {
 39+ if ( !document.getElementById ) {
 40+ return;
 41+ }
 42+ var nsInputs = document.getElementById( 'powersearch' ).getElementsByTagName( 'input' );
 43+ var isChecked = false;
 44+ for ( var i = 0; i < nsInputs.length; i++ ) {
 45+ var pattern = /^ns/;
 46+ if ( ( nsInputs[i].type == 'checkbox' ) && ( pattern.test( nsInputs[i].name ) ) ) {
 47+ switch ( btn ) {
 48+ case 'none':
 49+ if ( nsInputs[i].checked ) {
 50+ nsInputs[i].checked = false;
 51+ }
 52+ break;
 53+ case 'all':
 54+ if ( !nsInputs[i].checked ) {
 55+ nsInputs[i].checked = true;
 56+ }
 57+ break;
 58+ }
 59+ }
 60+ }
 61+ }
 62+} );
 63+
 64+} )( jQuery, MediaWiki );
\ No newline at end of file
Property changes on: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.search.js
___________________________________________________________________
Added: svn:eol-style
165 + native
Index: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.changepassword.js
@@ -0,0 +1,29 @@
 2+/*
 3+ * Legacy emulation for the now depricated skins/common/changepassword.js
 4+ */
 5+
 6+( function( $, mw ) {
 7+
 8+/* Extension */
 9+
 10+$.extend( true, mw.legacy, {
 11+
 12+ /* Functions */
 13+
 14+ 'onNameChange': function() {
 15+ var state = mw.legacy.wgUserName != $( '#wpName' ).val();
 16+ $( '#wpPassword' ).attr( 'disabled', state );
 17+ $( '#wpComment' ).attr( 'disabled', !state );
 18+ },
 19+ 'onNameChangeHook': function() {
 20+ $( '#wpName' ).blur( mw.legacy.onNameChange );
 21+ }
 22+} );
 23+
 24+/* Initialization */
 25+
 26+$( document ).ready( function() {
 27+ mw.legacy.onNameChangeHook();
 28+} );
 29+
 30+} )( jQuery, MediaWiki );
\ No newline at end of file
Property changes on: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.changepassword.js
___________________________________________________________________
Added: svn:eol-style
131 + native
Index: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.ajaxwatch.js
@@ -0,0 +1,136 @@
 2+/*
 3+ * Legacy emulation for the now depricated skins/common/ajaxwatch.js
 4+ *
 5+ * AJAX functionality for the watch/unwatch link
 6+ *
 7+ * @depends mw.legacy.jsMsg() from mw.legacy.wikibits.js
 8+ */
 9+
 10+( function( $, mw ) {
 11+
 12+/* Extension */
 13+
 14+$.extend( true, mw.legacy, {
 15+
 16+ /* Global Variables */
 17+
 18+ 'wgAjaxWatch': {
 19+
 20+ /* Global Variables */
 21+
 22+ 'watchMsg': 'Watch',
 23+ 'unwatchMsg': 'Unwatch',
 24+ 'watchingMsg': 'Watching...',
 25+ 'unwatchingMsg': 'Unwatching...',
 26+ 'tooltip-ca-watchMsg': 'Add this page to your watchlist',
 27+ 'tooltip-ca-unwatchMsg': 'Remove this page from your watchlist',
 28+
 29+ /* Functions */
 30+
 31+ /**
 32+ * Sets the text of the watch/unwatch link
 33+ *
 34+ * @param object link DOM node or jQuery selection of link to set text of
 35+ * @param string action message to use ('watch', 'unwatch', 'watching' or 'unwatching')
 36+ */
 37+ 'setLinkText': function( link, action ) {
 38+ var $link = $( link );
 39+ if ( action == 'watch' || action == 'unwatch' ) {
 40+ // save the accesskey from the title
 41+ var keyCommand = $link.attr( 'title' ).match( /\[.*?\]$/ ) ?
 42+ $link.attr( 'title' ).match( /\[.*?\]$/ )[0] : '';
 43+ $link.attr( 'title', wgAjaxWatch['tooltip-ca-' + action + 'Msg'] + ' ' + keyCommand );
 44+ }
 45+ if ( $link.data( 'icon' ) ) {
 46+ $link.attr( 'alt', wgAjaxWatch[action + 'Msg'] );
 47+ if ( action == 'watching' || action == 'unwatching' ) {
 48+ $link.addClass( 'loading' );
 49+ } else {
 50+ $link.removeClass( 'loading' );
 51+ }
 52+ } else {
 53+ $link.html( wgAjaxWatch[action+'Msg'] );
 54+ }
 55+ },
 56+ /**
 57+ * Processes responses from the server
 58+ *
 59+ * @param object response data from server
 60+ */
 61+ 'processResult': function( response ) {
 62+ response = response.watch;
 63+ var $link = $(this);
 64+ // To ensure we set the same status for all watch links with the same target we trigger a custom event on
 65+ // *all* watch links.
 66+ if ( response.watched !== undefined ) {
 67+ wgAjaxWatch.$links.trigger( 'mw-ajaxwatch', [response.title, 'watch'] );
 68+ } else if ( response.unwatched !== undefined ){
 69+ wgAjaxWatch.$links.trigger( 'mw-ajaxwatch', [response.title, 'unwatch'] );
 70+ } else {
 71+ // Either we got an error code or it just plain broke.
 72+ window.location.href = $link.attr( 'href' );
 73+ return;
 74+ }
 75+ mw.legacy.jsMsg( response.message, 'watch' );
 76+ // Bug 12395 - update the watch checkbox on edit pages when the page is watched or unwatched via the tab.
 77+ if ( response.watched !== undefined ) {
 78+ $j( '#wpWatchthis' ).attr( 'checked', '1' );
 79+ } else {
 80+ $j( '#wpWatchthis' ).removeAttr( 'checked' );
 81+ }
 82+ }
 83+ } );
 84+} );
 85+
 86+/* Initialization */
 87+
 88+$( document ).ready( function() {
 89+ var $links = $( '.mw-watchlink a, a.mw-watchlink' );
 90+ // BC with older skins...
 91+ $links = $links
 92+ .add( $( '#ca-watch a, #ca-unwatch a, a#mw-unwatch-link1' ) )
 93+ .add( $( 'a#mw-unwatch-link2, a#mw-watch-link2, a#mw-watch-link1' ) );
 94+ // ...allowing people to add inline animated links is a little scary
 95+ $links = $links.filter( ':not( #bodyContent *, #content * )' );
 96+ $links.each( function() {
 97+ var $link = $(this);
 98+ $link
 99+ .data( 'icon', $link.parent().hasClass( 'icon' ) )
 100+ .data( 'action', $link.attr( 'href' ).match( /[\?\&]action=unwatch/i ) ? 'unwatch' : 'watch' );
 101+ var title = $link.attr( 'href' ).match( /[\?\&]title=(.*?)&/i )[1];
 102+ $link.data( 'target', decodeURIComponent( title ).replace( /_/g, ' ' ) );
 103+ } );
 104+ $links.click( function( event ) {
 105+ var $link = $(this);
 106+ if ( mw.legacy.wgAjaxWatch.supported === false || !mw.legacy.wgEnableWriteAPI || !mw.legacy.wfSupportsAjax() ) {
 107+ // Lazy initialization so we don't toss up ActiveX warnings on initial page load for IE 6 users with
 108+ // security settings.
 109+ mw.legacy.wgAjaxWatch.$links.unbind( 'click' );
 110+ return true;
 111+ }
 112+ mw.legacy.wgAjaxWatch.setLinkText( $link, $link.data( 'action' ) + 'ing' );
 113+ var url = mw.legacy.wgScriptPath + '/api' + mw.legacy.wgScriptExtension + '?action=watch&format=json&title='
 114+ + encodeURIComponent( $link.data( 'target' ) ) + ( $link.data( 'action' ) == 'unwatch' ? '&unwatch' : '' );
 115+ $.get( url, {}, mw.legacy.wgAjaxWatch.processResult, 'json' );
 116+ return false;
 117+ } );
 118+ // When a request returns, a custom event 'mw-ajaxwatch' is triggered on *all* watch links, so they can be updated
 119+ // if necessary
 120+ $links.bind( 'mw-ajaxwatch', function( event, target, action ) {
 121+ var $link = $(this);
 122+ var foo = $link.data( 'target' );
 123+ if ( $link.data( 'target' ) == target ) {
 124+ var otheraction = action == 'watch' ? 'unwatch' : 'watch';
 125+ $link.data( 'action', otheraction );
 126+ wgAjaxWatch.setLinkText( $link, otheraction );
 127+ $link.attr( 'href', $link.attr( 'href' ).replace( '/&action=' + action + '/', '&action=' + otheraction ) );
 128+ if ( $link.parent().attr( 'id' ) == 'ca-' + action ){
 129+ $link.parent().attr( 'id', 'ca-' + otheraction );
 130+ }
 131+ }
 132+ return false;
 133+ } );
 134+ mw.legacy.wgAjaxWatch.$links = $links;
 135+} );
 136+
 137+} )( jQuery, MediaWiki );
\ No newline at end of file
Property changes on: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.ajaxwatch.js
___________________________________________________________________
Added: svn:eol-style
1138 + native
Index: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.prefs.js
@@ -0,0 +1,233 @@
 2+/*
 3+ * Legacy emulation for the now depricated skins/common/prefs.js
 4+ *
 5+ * Generate toc from prefs form, fold sections
 6+ *
 7+ * FIXME: Needs testing on IE/Mac and Safari
 8+ */
 9+
 10+( function( $, mw ) {
 11+
 12+/* Extension */
 13+
 14+$.extend( true, mw.legacy, {
 15+
 16+ /* Functions */
 17+
 18+ 'tabbedprefs': function() {
 19+ var prefform = document.getElementById( 'preferences' );
 20+ if ( !prefform || !document.createElement ) {
 21+ return;
 22+ }
 23+ if ( prefform.nodeName.toLowerCase() == 'a' ) {
 24+ return; // Occasional IE problem
 25+ }
 26+ prefform.className = prefform.className + 'jsprefs';
 27+ var sections = [];
 28+ var children = prefform.childNodes;
 29+ var seci = 0;
 30+ for ( var i = 0; i < children.length; i++ ) {
 31+ if ( children[i].nodeName.toLowerCase() == 'fieldset' ) {
 32+ children[i].id = 'prefsection-' + seci;
 33+ children[i].className = 'prefsection';
 34+ if ( is_opera ) {
 35+ children[i].className = 'prefsection operaprefsection';
 36+ }
 37+ var legends = children[i].getElementsByTagName('legend');
 38+ sections[seci] = {};
 39+ if ( legends[0] ) {
 40+ legends[0].className = 'mainLegend';
 41+ }
 42+ if ( legends[0] && legends[0].firstChild.nodeValue ) {
 43+ sections[seci].text = legends[0].firstChild.nodeValue;
 44+ } else {
 45+ sections[seci].text = '# ' + seci;
 46+ }
 47+ sections[seci].secid = children[i].id;
 48+ seci++;
 49+ if ( sections.length != 1 ) {
 50+ children[i].style.display = 'none';
 51+ } else {
 52+ var selectedid = children[i].id;
 53+ }
 54+ }
 55+ }
 56+ var toc = document.createElement( 'ul' );
 57+ toc.id = 'preftoc';
 58+ toc.selectedid = selectedid;
 59+ for ( i = 0; i < sections.length; i++ ) {
 60+ var li = document.createElement( 'li' );
 61+ if ( i === 0 ) {
 62+ li.className = 'selected';
 63+ }
 64+ var a = document.createElement( 'a' );
 65+ a.href = '#' + sections[i].secid;
 66+ a.onmousedown = a.onclick = uncoversection;
 67+ a.appendChild( document.createTextNode( sections[i].text ) );
 68+ a.secid = sections[i].secid;
 69+ li.appendChild( a );
 70+ toc.appendChild( li );
 71+ }
 72+ prefform.parentNode.insertBefore( toc, prefform.parentNode.childNodes[0] );
 73+ document.getElementById( 'prefsubmit' ).id = 'prefcontrol';
 74+ },
 75+ 'uncoversection': function() {
 76+ var oldsecid = this.parentNode.parentNode.selectedid;
 77+ var newsec = document.getElementById( this.secid );
 78+ if ( oldsecid != this.secid ) {
 79+ var ul = document.getElementById( 'preftoc' );
 80+ document.getElementById( oldsecid ).style.display = 'none';
 81+ newsec.style.display = 'block';
 82+ ul.selectedid = this.secid;
 83+ var lis = ul.getElementsByTagName( 'li' );
 84+ for ( var i = 0; i< lis.length; i++ ) {
 85+ lis[i].className = '';
 86+ }
 87+ this.parentNode.className = 'selected';
 88+ }
 89+ return false;
 90+ },
 91+ /**
 92+ * Timezone stuff tz in format [+-]HHMM
 93+ */
 94+ 'checkTimezone': function( tz, msg ) {
 95+ var localclock = new Date();
 96+ // returns negative offset from GMT in minutes
 97+ var tzRaw = localclock.getTimezoneOffset();
 98+ var tzHour = Math.floor( Math.abs( tzRaw ) / 60 );
 99+ var tzMin = Math.abs( tzRaw ) % 60;
 100+ var tzString = ( ( tzRaw >= 0 ) ? '-' : '+' ) + ( ( tzHour < 10 ) ? '0' : '' ) + tzHour + ( ( tzMin < 10 ) ? '0' : '' ) + tzMin;
 101+ if ( tz != tzString ) {
 102+ var junk = msg.split('$1');
 103+ document.write( junk[0] + 'UTC' + tzString + junk[1] );
 104+ }
 105+ },
 106+ 'timezoneSetup': function() {
 107+ var tzSelect = document.getElementById( 'mw-input-timecorrection' );
 108+ var tzTextbox = document.getElementById( 'mw-input-timecorrection-other' );
 109+
 110+ if ( tzSelect && tzTextbox ) {
 111+ addHandler( tzSelect, 'change', function( e ) { updateTimezoneSelection( false ); } );
 112+ addHandler( tzTextbox, 'blur', function( e ) { updateTimezoneSelection( true ); } );
 113+ }
 114+
 115+ updateTimezoneSelection( false );
 116+ },
 117+ /**
 118+ * Timezone stuff tz in format [-]HH:MM - won't yet work with non-even tzs
 119+ */
 120+ 'fetchTimezone': function() {
 121+ // FIXME: work around Safari bug
 122+ var localclock = new Date();
 123+ // returns negative offset from GMT in minutes
 124+ var tzRaw = localclock.getTimezoneOffset();
 125+ var tzHour = Math.floor( Math.abs( tzRaw ) / 60 );
 126+ var tzMin = Math.abs( tzRaw ) % 60;
 127+ var tzString = ( ( tzRaw >= 0 ) ? '-' : '' ) + ( ( tzHour < 10 ) ? '0' : '' ) + tzHour +
 128+ ':' + ( ( tzMin < 10 ) ? '0' : '' ) + tzMin;
 129+ return tzString;
 130+ },
 131+ 'guessTimezone': function() {
 132+ var textbox = document.getElementById( 'mw-input-timecorrection-other' );
 133+ var selector = document.getElementById( 'mw-input-timecorrection' );
 134+
 135+ selector.value = 'other';
 136+ textbox.value = fetchTimezone();
 137+ textbox.disabled = false; // The changed handler doesn't trip, obviously.
 138+ updateTimezoneSelection( true );
 139+ },
 140+ 'updateTimezoneSelection': function( force_offset ) {
 141+ var selector = document.getElementById( 'mw-input-timecorrection' );
 142+
 143+ if ( selector.value == 'guess' ) {
 144+ return guessTimezone();
 145+ }
 146+
 147+ var textbox = document.getElementById( 'mw-input-timecorrection-other' );
 148+ var localtimeHolder = document.getElementById( 'wpLocalTime' );
 149+ var servertime = document.getElementsByName( 'wpServerTime' )[0].value;
 150+ var minDiff = 0;
 151+
 152+ // Compatibility code.
 153+ if ( !selector.value ) {
 154+ selector.value = selector.options[selector.selectedIndex].value;
 155+ }
 156+
 157+ // Handle force_offset
 158+ if ( force_offset ) {
 159+ selector.value = 'other';
 160+ }
 161+
 162+ // Get min_diff
 163+ if ( selector.value == 'other' ) {
 164+ // Grab data from the textbox, parse it.
 165+ var diffArr = textbox.value.split(':');
 166+ if ( diffArr.length == 1 ) {
 167+ // Specification is of the form [-]XX
 168+ minDiff = parseInt( diffArr[0], 10 ) * 60;
 169+ } else {
 170+ // Specification is of the form [-]XX:XX
 171+ minDiff = Math.abs( parseInt( diffArr[0], 10 ) ) * 60 + parseInt( diffArr[1], 10 );
 172+ if ( parseInt( diffArr[0], 10 ) < 0 ) {
 173+ minDiff = -minDiff;
 174+ }
 175+ }
 176+ } else {
 177+ // Grab data from the selector value
 178+ var diffArr = selector.value.split('|');
 179+ minDiff = parseInt( diffArr[1], 10 );
 180+ }
 181+
 182+ // Gracefully handle non-numbers.
 183+ if ( isNaN( minDiff ) ) {
 184+ minDiff = 0;
 185+ }
 186+
 187+ // Determine local time from server time and minutes difference, for display.
 188+ var localTime = parseInt( servertime, 10 ) + minDiff;
 189+
 190+ // Bring time within the [0,1440) range.
 191+ while ( localTime < 0 ) {
 192+ localTime += 1440;
 193+ }
 194+ while ( localTime >= 1440 ) {
 195+ localTime -= 1440;
 196+ }
 197+
 198+ // Split to hour and minute
 199+ var hour = String( Math.floor( localTime / 60 ) );
 200+ if ( hour.length < 2 ) {
 201+ hour = '0' + hour;
 202+ }
 203+ var min = String(localTime%60);
 204+ if ( min.length < 2 ) {
 205+ min = '0' + min;
 206+ }
 207+ changeText( localtimeHolder, hour + ':' + min );
 208+
 209+ // If the user selected from the drop-down, fill the offset field.
 210+ if ( selector.value != 'other' ) {
 211+ hour = String( Math.abs( Math.floor( minDiff / 60 ) ) );
 212+ if ( hour.length < 2 ) {
 213+ hour = '0' + hour;
 214+ }
 215+ if ( minDiff < 0 ) {
 216+ hour = '-' + hour;
 217+ }
 218+ min = String(minDiff%60);
 219+ if ( min.length < 2 ) {
 220+ min = '0' + min;
 221+ }
 222+ textbox.value = hour + ':' + min;
 223+ }
 224+ }
 225+} );
 226+
 227+/* Initialization */
 228+
 229+$( document ).ready( function() {
 230+ mw.legacy.timezoneSetup();
 231+ mw.legacy.tabbedprefs();
 232+} );
 233+
 234+} )( jQuery, MediaWiki );
\ No newline at end of file
Property changes on: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.prefs.js
___________________________________________________________________
Added: svn:eol-style
1235 + native
Index: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.metadata.js
@@ -0,0 +1,53 @@
 2+/*
 3+ * Legacy emulation for the now depricated skins/common/metadata.js
 4+ */
 5+
 6+( function( $, mw ) {
 7+
 8+/* Extension */
 9+
 10+$.extend( true, mw.legacy, {
 11+ /**
 12+ * Exif metadata display for MediaWiki file uploads
 13+ *
 14+ * Add an expand/collapse link and collapse by default if set to (with JS disabled, user will see all items)
 15+ *
 16+ * Example:
 17+ * attachMetadataToggle( 'mw_metadata', 'More...', 'Fewer...' );
 18+ */
 19+ 'attachMetadataToggle': function( tableId, showText, hideText ) {
 20+ if ( document.createTextNode ) {
 21+ var box = document.getElementById( tableId );
 22+ if ( !box ) {
 23+ return false;
 24+ }
 25+ var tbody = box.getElementsByTagName('tbody')[0];
 26+ var row = document.createElement( 'tr' );
 27+ var col = document.createElement( 'td' );
 28+ col.colSpan = 2;
 29+ var link = document.createElement( 'a' );
 30+ link.href = '#';
 31+ link.onclick = function() {
 32+ if ( box.className == 'mw_metadata collapsed' ) {
 33+ changeText( link, hideText );
 34+ box.className = 'mw_metadata expanded';
 35+ } else {
 36+ changeText( link, showText );
 37+ box.className = 'mw_metadata collapsed';
 38+ }
 39+ return false;
 40+ };
 41+ var text = document.createTextNode( hideText );
 42+ link.appendChild( text );
 43+ col.appendChild( link );
 44+ row.appendChild( col );
 45+ tbody.appendChild( row );
 46+ // And collapse!
 47+ link.onclick();
 48+ return true;
 49+ }
 50+ return false;
 51+ }
 52+} );
 53+
 54+} )( jQuery, MediaWiki );
\ No newline at end of file
Property changes on: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.metadata.js
___________________________________________________________________
Added: svn:eol-style
155 + native
Index: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.protect.js
@@ -0,0 +1,346 @@
 2+/*
 3+ * Legacy emulation for the now depricated skins/common/protect.js
 4+ */
 5+
 6+( function( $, mw ) {
 7+
 8+/* Extension */
 9+
 10+$.extend( true, mw.legacy, {
 11+
 12+ /* Global Variables */
 13+
 14+ 'ProtectionForm': {
 15+
 16+ /* Global Variables */
 17+
 18+ 'existingMatch': false,
 19+
 20+ /* Functions */
 21+
 22+ /**
 23+ * Set up the protection chaining interface (i.e. "unlock move permissions" checkbox)
 24+ * on the protection form
 25+ *
 26+ * @param Object opts : parameters with members:
 27+ * tableId Identifier of the table containing UI bits
 28+ * labelText Text to use for the checkbox label
 29+ * numTypes The number of protection types
 30+ * existingMatch True if all the existing expiry times match
 31+ */
 32+ 'init': function( opts ) {
 33+ if( !( document.createTextNode && document.getElementById && document.getElementsByTagName ) )
 34+ return false;
 35+ var box = document.getElementById( opts.tableId );
 36+ if( !box )
 37+ return false;
 38+ var boxbody = box.getElementsByTagName('tbody')[0]
 39+ var row = document.createElement( 'tr' );
 40+ boxbody.insertBefore( row, boxbody.firstChild.nextSibling );
 41+ this.existingMatch = opts.existingMatch;
 42+ var cell = document.createElement( 'td' );
 43+ row.appendChild( cell );
 44+ // If there is only one protection type, there is nothing to chain
 45+ if( opts.numTypes > 1 ) {
 46+ var check = document.createElement( 'input' );
 47+ check.id = 'mwProtectUnchained';
 48+ check.type = 'checkbox';
 49+ cell.appendChild( check );
 50+ addClickHandler( check, function() { ProtectionForm.onChainClick(); } );
 51+
 52+ cell.appendChild( document.createTextNode( ' ' ) );
 53+ var label = document.createElement( 'label' );
 54+ label.htmlFor = 'mwProtectUnchained';
 55+ label.appendChild( document.createTextNode( opts.labelText ) );
 56+ cell.appendChild( label );
 57+
 58+ check.checked = !this.areAllTypesMatching();
 59+ this.enableUnchainedInputs( check.checked );
 60+ }
 61+ this.updateCascadeCheckbox();
 62+ return true;
 63+ },
 64+
 65+ /**
 66+ * Sets the disabled attribute on the cascade checkbox depending on the current selected levels
 67+ */
 68+ 'updateCascadeCheckbox': function() {
 69+ // For non-existent titles, there is no cascade option
 70+ if( !document.getElementById( 'mwProtect-cascade' ) ) {
 71+ return;
 72+ }
 73+ var lists = this.getLevelSelectors();
 74+ for( var i = 0; i < lists.length; i++ ) {
 75+ if( lists[i].selectedIndex > -1 ) {
 76+ var items = lists[i].getElementsByTagName( 'option' );
 77+ var selected = items[ lists[i].selectedIndex ].value;
 78+ if( !this.isCascadeableLevel(selected) ) {
 79+ document.getElementById( 'mwProtect-cascade' ).checked = false;
 80+ document.getElementById( 'mwProtect-cascade' ).disabled = true;
 81+ return;
 82+ }
 83+ }
 84+ }
 85+ document.getElementById( 'mwProtect-cascade' ).disabled = false;
 86+ },
 87+ /**
 88+ * Is this protection level cascadeable?
 89+ * @param String level
 90+ *
 91+ * @return boolean
 92+ *
 93+ */
 94+ 'isCascadeableLevel': function( level ) {
 95+ for (var k = 0; k < wgCascadeableLevels.length; k++) {
 96+ if ( wgCascadeableLevels[k] == level ) {
 97+ return true;
 98+ }
 99+ }
 100+ return false;
 101+ },
 102+ /**
 103+ * When protection levels are locked together, update the rest
 104+ * when one action's level changes
 105+ *
 106+ * @param Element source Level selector that changed
 107+ */
 108+ 'updateLevels': function(source) {
 109+ if( !this.isUnchained() )
 110+ this.setAllSelectors( source.selectedIndex );
 111+ this.updateCascadeCheckbox();
 112+ },
 113+ /**
 114+ * When protection levels are locked together, update the
 115+ * expiries when one changes
 116+ *
 117+ * @param Element source expiry input that changed
 118+ */
 119+ 'updateExpiry': function(source) {
 120+ if( !this.isUnchained() ) {
 121+ var expiry = source.value;
 122+ this.forEachExpiryInput(function(element) {
 123+ element.value = expiry;
 124+ });
 125+ }
 126+ var listId = source.id.replace( /^mwProtect-(\w+)-expires$/, 'mwProtectExpirySelection-$1' );
 127+ var list = document.getElementById( listId );
 128+ if (list && list.value != 'othertime' ) {
 129+ if ( this.isUnchained() ) {
 130+ list.value = 'othertime';
 131+ } else {
 132+ this.forEachExpirySelector(function(element) {
 133+ element.value = 'othertime';
 134+ });
 135+ }
 136+ }
 137+ },
 138+ /**
 139+ * When protection levels are locked together, update the
 140+ * expiry lists when one changes and clear the custom inputs
 141+ *
 142+ * @param Element source expiry selector that changed
 143+ */
 144+ 'updateExpiryList': function(source) {
 145+ if( !this.isUnchained() ) {
 146+ var expiry = source.value;
 147+ this.forEachExpirySelector(function(element) {
 148+ element.value = expiry;
 149+ });
 150+ this.forEachExpiryInput(function(element) {
 151+ element.value = '';
 152+ });
 153+ }
 154+ },
 155+ /**
 156+ * Update chain status and enable/disable various bits of the UI
 157+ * when the user changes the "unlock move permissions" checkbox
 158+ */
 159+ 'onChainClick': function() {
 160+ if( this.isUnchained() ) {
 161+ this.enableUnchainedInputs( true );
 162+ } else {
 163+ this.setAllSelectors( this.getMaxLevel() );
 164+ this.enableUnchainedInputs( false );
 165+ }
 166+ this.updateCascadeCheckbox();
 167+ },
 168+ /**
 169+ * Returns true if the named attribute in all objects in the given array are matching
 170+ */
 171+ 'matchAttribute' : function( objects, attrName ) {
 172+ var value = null;
 173+
 174+ // Check levels
 175+ for ( var i = 0; i < objects.length; i++ ) {
 176+ var element = objects[i];
 177+ if ( value == null ) {
 178+ value = element[attrName];
 179+ } else {
 180+ if ( value != element[attrName] ) {
 181+ return false;
 182+ }
 183+ }
 184+ }
 185+ return true;
 186+ },
 187+ /**
 188+ * Are all actions protected at the same level, with the same expiry time?
 189+ *
 190+ * @return boolean
 191+ */
 192+ 'areAllTypesMatching': function() {
 193+ return this.existingMatch
 194+ && this.matchAttribute( this.getLevelSelectors(), 'selectedIndex' )
 195+ && this.matchAttribute( this.getExpirySelectors(), 'selectedIndex' )
 196+ && this.matchAttribute( this.getExpiryInputs(), 'value' );
 197+ },
 198+ /**
 199+ * Is protection chaining off?
 200+ *
 201+ * @return bool
 202+ */
 203+ 'isUnchained': function() {
 204+ var element = document.getElementById( 'mwProtectUnchained' );
 205+ return element
 206+ ? element.checked
 207+ : true; // No control, so we need to let the user set both levels
 208+ },
 209+ /**
 210+ * Find the highest protection level in any selector
 211+ */
 212+ 'getMaxLevel': function() {
 213+ var maxIndex = -1;
 214+ this.forEachLevelSelector(function(element) {
 215+ if (element.selectedIndex > maxIndex) {
 216+ maxIndex = element.selectedIndex;
 217+ }
 218+ });
 219+ return maxIndex;
 220+ },
 221+ /**
 222+ * Protect all actions at the specified level
 223+ *
 224+ * @param int index Protection level
 225+ */
 226+ 'setAllSelectors': function(index) {
 227+ this.forEachLevelSelector(function(element) {
 228+ if (element.selectedIndex != index) {
 229+ element.selectedIndex = index;
 230+ }
 231+ });
 232+ },
 233+ /**
 234+ * Apply a callback to each protection selector
 235+ *
 236+ * @param callable func Callback function
 237+ */
 238+ 'forEachLevelSelector': function(func) {
 239+ var selectors = this.getLevelSelectors();
 240+ for (var i = 0; i < selectors.length; i++) {
 241+ func(selectors[i]);
 242+ }
 243+ },
 244+ /**
 245+ * Get a list of all protection selectors on the page
 246+ *
 247+ * @return Array
 248+ */
 249+ 'getLevelSelectors': function() {
 250+ var all = document.getElementsByTagName('select');
 251+ var ours = new Array();
 252+ for (var i = 0; i < all.length; i++) {
 253+ var element = all[i];
 254+ if (element.id.match(/^mwProtect-level-/)) {
 255+ ours[ours.length] = element;
 256+ }
 257+ }
 258+ return ours;
 259+ },
 260+ /**
 261+ * Apply a callback to each expiry input
 262+ *
 263+ * @param callable func Callback function
 264+ */
 265+ 'forEachExpiryInput': function(func) {
 266+ var inputs = this.getExpiryInputs();
 267+ for (var i = 0; i < inputs.length; i++) {
 268+ func(inputs[i]);
 269+ }
 270+ },
 271+ /**
 272+ * Get a list of all expiry inputs on the page
 273+ *
 274+ * @return Array
 275+ */
 276+ 'getExpiryInputs': function() {
 277+ var all = document.getElementsByTagName('input');
 278+ var ours = new Array();
 279+ for (var i = 0; i < all.length; i++) {
 280+ var element = all[i];
 281+ if (element.name.match(/^mwProtect-expiry-/)) {
 282+ ours[ours.length] = element;
 283+ }
 284+ }
 285+ return ours;
 286+ },
 287+ /**
 288+ * Apply a callback to each expiry selector list
 289+ * @param callable func Callback function
 290+ */
 291+ 'forEachExpirySelector': function(func) {
 292+ var inputs = this.getExpirySelectors();
 293+ for (var i = 0; i < inputs.length; i++) {
 294+ func(inputs[i]);
 295+ }
 296+ },
 297+ /**
 298+ * Get a list of all expiry selector lists on the page
 299+ *
 300+ * @return Array
 301+ */
 302+ 'getExpirySelectors': function() {
 303+ var all = document.getElementsByTagName('select');
 304+ var ours = new Array();
 305+ for (var i = 0; i < all.length; i++) {
 306+ var element = all[i];
 307+ if (element.id.match(/^mwProtectExpirySelection-/)) {
 308+ ours[ours.length] = element;
 309+ }
 310+ }
 311+ return ours;
 312+ },
 313+ /**
 314+ * Enable/disable protection selectors and expiry inputs
 315+ *
 316+ * @param boolean val Enable?
 317+ */
 318+ 'enableUnchainedInputs': function(val) {
 319+ var first = true;
 320+ this.forEachLevelSelector(function(element) {
 321+ if (first) {
 322+ first = false;
 323+ } else {
 324+ element.disabled = !val;
 325+ }
 326+ });
 327+ first = true;
 328+ this.forEachExpiryInput(function(element) {
 329+ if (first) {
 330+ first = false;
 331+ } else {
 332+ element.disabled = !val;
 333+ }
 334+ });
 335+ first = true;
 336+ this.forEachExpirySelector(function(element) {
 337+ if (first) {
 338+ first = false;
 339+ } else {
 340+ element.disabled = !val;
 341+ }
 342+ });
 343+ }
 344+ }
 345+} );
 346+
 347+} )( jQuery, MediaWiki );
\ No newline at end of file
Property changes on: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.protect.js
___________________________________________________________________
Added: svn:eol-style
1348 + native
Index: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.preview.js
@@ -0,0 +1,121 @@
 2+/*
 3+ * Legacy emulation for the now depricated skins/common/preview.js
 4+ *
 5+ * Inline ("Live") preview
 6+ */
 7+
 8+( function( $, mw ) {
 9+
 10+/* Extension */
 11+
 12+$.extend( true, mw.legacy, {
 13+
 14+ /* Functions */
 15+
 16+ 'doLivePreview': function( e ) {
 17+ e.preventDefault();
 18+ $j( mw ).trigger( 'LivePreviewPrepare' );
 19+ var postData = $j('#editform').formToArray();
 20+ postData.push( { 'name' : 'wpPreview', 'value' : '1' } );
 21+ // Hide active diff, used templates, old preview if shown
 22+ var copyElements = ['#wikiPreview', '.templatesUsed', '.hiddencats', '#catlinks'];
 23+ var copySelector = copyElements.join(',');
 24+ $j.each( copyElements, function(k,v) { $j(v).fadeOut('fast'); } );
 25+ // Display a loading graphic
 26+ var loadSpinner = $j('<div class="mw-ajax-loader"/>');
 27+ $j('#wikiPreview').before( loadSpinner );
 28+ var page = $j('<div/>');
 29+ var target = $j('#editform').attr('action');
 30+ if ( !target ) {
 31+ target = window.location.href;
 32+ }
 33+ page.load( target + ' ' + copySelector, postData, function() {
 34+ for ( var i=0; i<copyElements.length; ++i) {
 35+ // For all the specified elements, find the elements in the loaded page
 36+ // and the real page, empty the element in the real page, and fill it
 37+ // with the content of the loaded page
 38+ var copyContent = page.find( copyElements[i] ).contents();
 39+ $j(copyElements[i]).empty().append( copyContent );
 40+ var newClasses = page.find( copyElements[i] ).attr('class');
 41+ $j(copyElements[i]).attr( 'class', newClasses );
 42+ }
 43+ $j.each( copyElements, function(k,v) {
 44+ // Don't belligerently show elements that are supposed to be hidden
 45+ $j(v).fadeIn( 'fast', function() { $j(this).css('display', ''); } );
 46+ } );
 47+ loadSpinner.remove();
 48+ $j( mw ).trigger( 'LivePreviewDone', [copyElements] );
 49+ } );
 50+ }
 51+} );
 52+
 53+/* Initialization */
 54+
 55+$( document ).ready( function() {
 56+ // Shamelessly stolen from the jQuery form plugin, which is licensed under the GPL.
 57+ // http://jquery.malsup.com/form/#download
 58+ $j.fn.formToArray = function() {
 59+ var a = [];
 60+ if (this.length == 0) return a;
 61+ var form = this[0];
 62+ var els = form.elements;
 63+ if (!els) return a;
 64+ for(var i=0, max=els.length; i < max; i++) {
 65+ var el = els[i];
 66+ var n = el.name;
 67+ if (!n) continue;
 68+ var v = $j.fieldValue(el, true);
 69+ if (v && v.constructor == Array) {
 70+ for(var j=0, jmax=v.length; j < jmax; j++)
 71+ a.push({name: n, value: v[j]});
 72+ }
 73+ else if (v !== null && typeof v != 'undefined')
 74+ a.push({name: n, value: v});
 75+ }
 76+ if (form.clk) {
 77+ // input type=='image' are not found in elements array! handle it here
 78+ var $input = $(form.clk), input = $input[0], n = input.name;
 79+ if (n && !input.disabled && input.type == 'image') {
 80+ a.push({name: n, value: $input.val()});
 81+ a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
 82+ }
 83+ }
 84+ return a;
 85+ }
 86+ /**
 87+ * Returns the value of the field element.
 88+ */
 89+ $j.fieldValue = function(el, successful) {
 90+ var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
 91+ if (typeof successful == 'undefined') successful = true;
 92+ if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
 93+ (t == 'checkbox' || t == 'radio') && !el.checked ||
 94+ (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
 95+ tag == 'select' && el.selectedIndex == -1))
 96+ return null;
 97+ if (tag == 'select') {
 98+ var index = el.selectedIndex;
 99+ if (index < 0) return null;
 100+ var a = [], ops = el.options;
 101+ var one = (t == 'select-one');
 102+ var max = (one ? index+1 : ops.length);
 103+ for(var i=(one ? index : 0); i < max; i++) {
 104+ var op = ops[i];
 105+ if (op.selected) {
 106+ var v = op.value;
 107+ if (!v) // extra pain for IE...
 108+ v = (op.attributes && op.attributes['value'] &&
 109+ !(op.attributes['value'].specified))
 110+ ? op.text : op.value;
 111+ if (one) return v;
 112+ a.push(v);
 113+ }
 114+ }
 115+ return a;
 116+ }
 117+ return el.value;
 118+ };
 119+ $j('#wpPreview').click( doLivePreview );
 120+} );
 121+
 122+} )( jQuery, MediaWiki );
\ No newline at end of file
Property changes on: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.preview.js
___________________________________________________________________
Added: svn:eol-style
1123 + native
Index: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.ajax.js
@@ -0,0 +1,176 @@
 2+/*
 3+ * Legacy emulation for the now depricated skins/common/ajax.js
 4+ *
 5+ * Original licensing information:
 6+ * Remote Scripting Library
 7+ * (c) Copyright 2005 ModernMethod, Inc.
 8+ */
 9+
 10+( function( $, mw ) {
 11+
 12+/* Extension */
 13+
 14+$.extend( true, mw.legacy, {
 15+
 16+ /* Global Variables */
 17+
 18+ 'sajax_debug_mode': false,
 19+ 'sajax_debug_mode': 'GET',
 20+
 21+ /* Functions */
 22+
 23+ /**
 24+ * If sajax_debug_mode is true, this function outputs given the message into the element with id = sajax_debug; if no
 25+ * such element exists in the document, it is injected
 26+ *
 27+ * @param string text debug message to append to log
 28+ * @return boolean true when in debug mode, false when not
 29+ */
 30+ 'sajax_debug': function( text ) {
 31+ if ( mw.legacy.sajax_debug_mode ) {
 32+ var $e = $( '#sajax_debug' );
 33+ if ( !$e.length ) {
 34+ $e = $( '<p class="sajax_debug" id="sajax_debug"></p>' ).prependTo( $( 'body' ) );
 35+ }
 36+ $e.append( $( '<div></div>' ).text( text ) );
 37+ return true;
 38+ }
 39+ return false;
 40+ },
 41+ /**
 42+ * Gets an XMLHttpRequest or equivilant ActiveXObject
 43+ *
 44+ * @reuturn mixed request object on success, boolean false on failure
 45+ */
 46+ 'sajax_init_object': function() {
 47+ mw.legacy.sajax_debug( 'sajax_init_object() called..' );
 48+ var request = false;
 49+ try {
 50+ // Try the 'new' style before ActiveX so we don't unnecessarily trigger warnings in IE 7 when the user's
 51+ // security settings are set to prompt about ActiveX usage
 52+ request = new XMLHttpRequest();
 53+ } catch ( e ) {
 54+ try {
 55+ request = new ActiveXObject( 'Msxml2.XMLHTTP' );
 56+ } catch ( e ) {
 57+ try {
 58+ request = new ActiveXObject( 'Microsoft.XMLHTTP' );
 59+ } catch ( oc ) {
 60+ request = null;
 61+ }
 62+ }
 63+ }
 64+ if ( !request ) {
 65+ mw.legacy.sajax_debug( 'Could not create connection object.' );
 66+ }
 67+ return request;
 68+ },
 69+ /**
 70+ * Performs an ajax call to mediawiki. Calls are handeled by AjaxDispatcher.php
 71+ *
 72+ * @param string method name of the function to call. Must be registered in $wgAjaxExportList
 73+ * @param array arguments arguments to that function
 74+ * @param mixed target the target that will handle the result of the call. If this is a function, if will be called
 75+ * with the XMLHttpRequest as a parameter; if it's an input element, its value will be set to the resultText; if
 76+ * it's another type of element, its innerHTML will be set to the resultText.
 77+ *
 78+ * @example
 79+ * // This will call the doFoo function via MediaWiki's AjaxDispatcher, with (1, 2, 3) as the parameter list,
 80+ * // and will show the result in the element with id = showFoo
 81+ * sajax_do_call( 'doFoo', [1, 2, 3], document.getElementById( 'showFoo' ) );
 82+ */
 83+ 'sajax_do_call': function( method, arguments, target ) {
 84+ var post_data;
 85+ var uri = mw.legacy.wgServer +
 86+ ( ( mw.legacy.wgScript == null ) ? ( mw.legacy.wgScriptPath + '/index.php' ) : mw.legacy.wgScript ) +
 87+ '?action=ajax';
 88+ if ( mw.legacy.sajax_request_type == 'GET' ) {
 89+ if ( uri.indexOf( '?' ) == -1 ) {
 90+ uri = uri + '?rs=' + encodeURIComponent( method );
 91+ } else {
 92+ uri = uri + '&rs=' + encodeURIComponent( method );
 93+ }
 94+ for ( var i = 0; i < arguments.length; i++ ) {
 95+ uri = uri + '&rsargs[]=' + encodeURIComponent( arguments[i] );
 96+ }
 97+ post_data = null;
 98+ } else {
 99+ post_data = 'rs=' + encodeURIComponent( method );
 100+ for ( var i = 0; i < arguments.length; i++ ) {
 101+ post_data = post_data + '&rsargs[]=' + encodeURIComponent( arguments[i] );
 102+ }
 103+ }
 104+ var request = mw.legacy.sajax_init_object();
 105+ if ( !request ) {
 106+ alert( 'AJAX not supported' );
 107+ return false;
 108+ }
 109+ try {
 110+ request.open( mw.legacy.sajax_request_type, uri, true );
 111+ } catch ( e ) {
 112+ if ( window.location.hostname == 'localhost' ) {
 113+ alert(
 114+ 'Your browser blocks XMLHttpRequest to \'localhost\', ' +
 115+ 'try using a real hostname for development/testing.'
 116+ );
 117+ }
 118+ throw e;
 119+ }
 120+ if ( mw.legacy.sajax_request_type == 'POST' ) {
 121+ request.setRequestHeader( 'Method', 'POST ' + uri + ' HTTP/1.1' );
 122+ request.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' );
 123+ }
 124+ request.setRequestHeader( 'Pragma', 'cache=yes' );
 125+ request.setRequestHeader( 'Cache-Control', 'no-transform' );
 126+ request.onreadystatechange = function() {
 127+ if ( request.readyState != 4 ) {
 128+ return;
 129+ }
 130+ mw.legacy.sajax_debug(
 131+ 'received (' + request.status + ' ' + request.statusText + ') ' + request.responseText
 132+ );
 133+ if ( typeof( target ) == 'function' ) {
 134+ target( request );
 135+ } else if ( typeof( target ) == 'object' ) {
 136+ $target = $( target );
 137+ if ( $target.is( 'input' ) ) {
 138+ if ( request.status == 200 ) {
 139+ $target.val();
 140+ }
 141+ } else {
 142+ if ( request.status == 200 ) {
 143+ $target.html( request.responseText );
 144+ } else {
 145+ $target.html(
 146+ '<div class="error">' +
 147+ 'Error: ' + request.status + ' ' + request.statusText +
 148+ ' (' + request.responseText + ')' +
 149+ '</div>'
 150+ );
 151+ }
 152+ }
 153+ } else {
 154+ alert( 'Bad target for sajax_do_call: not a function or object: ' + target );
 155+ }
 156+ return;
 157+ }
 158+ mw.legacy.sajax_debug( method + ' uri = ' + uri + ' / post = ' + post_data );
 159+ request.send( post_data );
 160+ mw.legacy.sajax_debug( method + ' waiting..' );
 161+ delete x;
 162+ return true;
 163+ },
 164+ /**
 165+ * Ajax compatibility test
 166+ *
 167+ * @return boolean whether the browser supports XMLHttpRequest
 168+ */
 169+ 'wfSupportsAjax': function() {
 170+ var request = mw.legacy.sajax_init_object();
 171+ var result = request ? true : false;
 172+ delete request;
 173+ return result;
 174+ }
 175+} );
 176+
 177+} )( jQuery, MediaWiki );
\ No newline at end of file
Property changes on: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.ajax.js
___________________________________________________________________
Added: svn:eol-style
1178 + native
Index: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.upload.js
@@ -0,0 +1,333 @@
 2+/*
 3+ * Legacy emulation for the now depricated skins/common/upload.js
 4+ */
 5+
 6+( function( $, mw ) {
 7+
 8+/* Extension */
 9+
 10+$.extend( true, mw.legacy, {
 11+
 12+ /* Global Variables */
 13+
 14+ 'wgUploadWarningObj': {
 15+
 16+ /* Global Variables */
 17+
 18+ 'responseCache' : { '' : '&nbsp;' },
 19+ 'nameToCheck' : '',
 20+ 'typing': false,
 21+ 'delay': 500, // ms
 22+ 'timeoutID': false,
 23+
 24+ /* Functions */
 25+
 26+ 'keypress': function () {
 27+ if ( !wgAjaxUploadDestCheck || !sajax_init_object() ) return;
 28+
 29+ // Find file to upload
 30+ var destFile = document.getElementById( 'wpDestFile' );
 31+ var warningElt = document.getElementById( 'wpDestFile-warning' );
 32+ if ( !destFile || !warningElt ) return ;
 33+ this.nameToCheck = destFile.value ;
 34+ // Clear timer
 35+ if ( this.timeoutID ) {
 36+ window.clearTimeout( this.timeoutID );
 37+ }
 38+ // Check response cache
 39+ for ( cached in this.responseCache ) {
 40+ if ( this.nameToCheck == cached ) {
 41+ this.setWarning( this.responseCache[this.nameToCheck] );
 42+ return;
 43+ }
 44+ }
 45+ this.timeoutID = window.setTimeout( 'wgUploadWarningObj.timeout()', this.delay );
 46+ },
 47+ 'checkNow': function ( fname ) {
 48+ if ( !wgAjaxUploadDestCheck || !sajax_init_object() ) return;
 49+ if ( this.timeoutID ) {
 50+ window.clearTimeout( this.timeoutID );
 51+ }
 52+ this.nameToCheck = fname;
 53+ this.timeout();
 54+ },
 55+ 'timeout' : function() {
 56+ if ( !wgAjaxUploadDestCheck || !sajax_init_object() ) return;
 57+ injectSpinner( document.getElementById( 'wpDestFile' ), 'destcheck' );
 58+
 59+ // Get variables into local scope so that they will be preserved for the
 60+ // anonymous callback. fileName is copied so that multiple overlapping
 61+ // ajax requests can be supported.
 62+ var obj = this;
 63+ var fileName = this.nameToCheck;
 64+ sajax_do_call( 'SpecialUpload::ajaxGetExistsWarning', [this.nameToCheck],
 65+ function ( result ) {
 66+ obj.processResult( result, fileName )
 67+ }
 68+ );
 69+ },
 70+ 'processResult' : function ( result, fileName ) {
 71+ removeSpinner( 'destcheck' );
 72+ this.setWarning( result.responseText );
 73+ this.responseCache[fileName] = result.responseText;
 74+ },
 75+ 'setWarning' : function ( warning ) {
 76+ var warningElt = document.getElementById( 'wpDestFile-warning' );
 77+ var ackElt = document.getElementsByName( 'wpDestFileWarningAck' );
 78+
 79+ this.setInnerHTML( warningElt, warning );
 80+
 81+ // Set a value in the form indicating that the warning is acknowledged and
 82+ // doesn't need to be redisplayed post-upload
 83+ if ( warning == '' || warning == '&nbsp;' ) {
 84+ ackElt[0].value = '';
 85+ } else {
 86+ ackElt[0].value = '1';
 87+ }
 88+ },
 89+ 'setInnerHTML' : function ( element, text ) {
 90+ // Check for no change to avoid flicker in IE 7
 91+ if ( element.innerHTML != text ) {
 92+ element.innerHTML = text;
 93+ }
 94+ }
 95+ },
 96+ var wgUploadLicenseObj = {
 97+
 98+ /* Global Variables */
 99+
 100+ 'responseCache' : { '' : '' },
 101+
 102+ /* Functions */
 103+
 104+ 'fetchPreview': function( license ) {
 105+ if ( !wgAjaxLicensePreview ) return;
 106+ for ( cached in this.responseCache ) {
 107+ if ( cached == license ) {
 108+ this.showPreview( this.responseCache[license] );
 109+ return;
 110+ }
 111+ }
 112+ injectSpinner( document.getElementById( 'wpLicense' ), 'license' );
 113+ var title = document.getElementById( 'wpDestFile' ).value;
 114+ if ( !title ) title = 'File:Sample.jpg';
 115+ var url = wgScriptPath + '/api' + wgScriptExtension
 116+ + '?action=parse&text={{' + encodeURIComponent( license ) + '}}'
 117+ + '&title=' + encodeURIComponent( title )
 118+ + '&prop=text&pst&format=json';
 119+ var req = sajax_init_object();
 120+ req.onreadystatechange = function() {
 121+ if ( req.readyState == 4 && req.status == 200 )
 122+ wgUploadLicenseObj.processResult( eval( '( ' + req.responseText + ' )' ), license );
 123+ };
 124+ req.open( 'GET', url, true );
 125+ req.send( '' );
 126+ },
 127+ 'processResult' : function( result, license ) {
 128+ removeSpinner( 'license' );
 129+ this.responseCache[license] = result['parse']['text']['*'];
 130+ this.showPreview( this.responseCache[license] );
 131+ },
 132+ 'showPreview' : function( preview ) {
 133+ var previewPanel = document.getElementById( 'mw-license-preview' );
 134+ if( previewPanel.innerHTML != preview )
 135+ previewPanel.innerHTML = preview;
 136+ }
 137+ },
 138+
 139+ /* Functions */
 140+
 141+ 'licenseSelectorCheck': function() {
 142+ var selector = document.getElementById( 'wpLicense' );
 143+ var selection = selector.options[selector.selectedIndex].value;
 144+ if( selector.selectedIndex > 0 ) {
 145+ if( selection == '' ) {
 146+ // Option disabled, but browser is broken and doesn't respect this
 147+ selector.selectedIndex = 0;
 148+ }
 149+ }
 150+ // We might show a preview
 151+ wgUploadLicenseObj.fetchPreview( selection );
 152+ },
 153+ 'wgUploadSetup': function() {
 154+ // Disable URL box if the URL copy upload source type is not selected
 155+ var e = document.getElementById( 'wpSourceTypeurl' );
 156+ if( e ) {
 157+ if( !e.checked ) {
 158+ var ein = document.getElementById( 'wpUploadFileURL' );
 159+ if( ein )
 160+ ein.setAttribute( 'disabled', 'disabled' );
 161+ }
 162+ }
 163+ // For MSIE/Mac: non-breaking spaces cause the <option> not to render.
 164+ // But for some reason, setting the text to itself works
 165+ var selector = document.getElementById( 'wpLicense' );
 166+ if ( selector ) {
 167+ var ua = navigator.userAgent;
 168+ var isMacIe = ( ua.indexOf( 'MSIE' ) != -1 ) && ( ua.indexOf( 'Mac' ) != -1 );
 169+ if ( isMacIe ) {
 170+ for ( var i = 0; i < selector.options.length; i++ ) {
 171+ selector.options[i].text = selector.options[i].text;
 172+ }
 173+ }
 174+ }
 175+ // Toggle source type
 176+ var sourceTypeCheckboxes = document.getElementsByName( 'wpSourceType' );
 177+ for ( var i = 0; i < sourceTypeCheckboxes.length; i++ ) {
 178+ sourceTypeCheckboxes[i].onchange = toggleUploadInputs;
 179+ }
 180+ // AJAX wpDestFile warnings
 181+ if ( wgAjaxUploadDestCheck ) {
 182+ // Insert an event handler that fetches upload warnings when wpDestFile
 183+ // has been changed
 184+ document.getElementById( 'wpDestFile' ).onchange = function ( e ) {
 185+ wgUploadWarningObj.checkNow( this.value );
 186+ };
 187+ // Insert a row where the warnings will be displayed just below the
 188+ // wpDestFile row
 189+ var optionsTable = document.getElementById( 'mw-htmlform-description' ).tBodies[0];
 190+ var row = optionsTable.insertRow( 1 );
 191+ var td = document.createElement( 'td' );
 192+ td.id = 'wpDestFile-warning';
 193+ td.colSpan = 2;
 194+ row.appendChild( td );
 195+ }
 196+ if ( wgAjaxLicensePreview ) {
 197+ // License selector check
 198+ document.getElementById( 'wpLicense' ).onchange = licenseSelectorCheck;
 199+ // License selector table row
 200+ var wpLicense = document.getElementById( 'wpLicense' );
 201+ var wpLicenseRow = wpLicense.parentNode.parentNode;
 202+ var wpLicenseTbody = wpLicenseRow.parentNode;
 203+ var row = document.createElement( 'tr' );
 204+ var td = document.createElement( 'td' );
 205+ row.appendChild( td );
 206+ td = document.createElement( 'td' );
 207+ td.id = 'mw-license-preview';
 208+ row.appendChild( td );
 209+ wpLicenseTbody.insertBefore( row, wpLicenseRow.nextSibling );
 210+ }
 211+ // fillDestFile setup
 212+ for ( var i = 0; i < wgUploadSourceIds.length; i++ )
 213+ document.getElementById( wgUploadSourceIds[i] ).onchange = function ( e ) {
 214+ fillDestFilename( this.id );
 215+ };
 216+ },
 217+ /**
 218+ * Iterate over all upload source fields and disable all except the selected one.
 219+ *
 220+ * @param enabledId
 221+ * The id of the selected radio button
 222+ * @return emptiness
 223+ */
 224+ 'toggleUploadInputs': function() {
 225+ // Iterate over all rows with UploadSourceField
 226+ var rows;
 227+ if ( document.getElementsByClassName ) {
 228+ rows = document.getElementsByClassName( 'mw-htmlform-field-UploadSourceField' );
 229+ } else {
 230+ // Older browsers don't support getElementsByClassName
 231+ rows = new Array();
 232+ var allRows = document.getElementsByTagName( 'tr' );
 233+ for ( var i = 0; i < allRows.length; i++ ) {
 234+ if ( allRows[i].className == 'mw-htmlform-field-UploadSourceField' )
 235+ rows.push( allRows[i] );
 236+ }
 237+ }
 238+ for ( var i = 0; i < rows.length; i++ ) {
 239+ var inputs = rows[i].getElementsByTagName( 'input' );
 240+ // Check if this row is selected
 241+ var isChecked = true; // Default true in case wpSourceType is not found
 242+ for ( var j = 0; j < inputs.length; j++ ) {
 243+ if ( inputs[j].name == 'wpSourceType' )
 244+ isChecked = inputs[j].checked;
 245+ }
 246+ // Disable all unselected rows
 247+ for ( var j = 0; j < inputs.length; j++ ) {
 248+ if ( inputs[j].type != 'radio' )
 249+ inputs[j].disabled = !isChecked;
 250+ }
 251+ }
 252+ },
 253+ 'fillDestFilename': function( id ) {
 254+ if ( !wgUploadAutoFill ) {
 255+ return;
 256+ }
 257+ if ( !document.getElementById ) {
 258+ return;
 259+ }
 260+ // Remove any previously flagged errors
 261+ var e = document.getElementById( 'mw-upload-permitted' );
 262+ if( e ) e.className = '';
 263+ var e = document.getElementById( 'mw-upload-prohibited' );
 264+ if( e ) e.className = '';
 265+ var path = document.getElementById( id ).value;
 266+ // Find trailing part
 267+ var slash = path.lastIndexOf( '/' );
 268+ var backslash = path.lastIndexOf( '\\' );
 269+ var fname;
 270+ if ( slash == -1 && backslash == -1 ) {
 271+ fname = path;
 272+ } else if ( slash > backslash ) {
 273+ fname = path.substring( slash+1, 10000 );
 274+ } else {
 275+ fname = path.substring( backslash+1, 10000 );
 276+ }
 277+ // Clear the filename if it does not have a valid extension.
 278+ // URLs are less likely to have a useful extension, so don't include them in the
 279+ // extension check.
 280+ if( wgStrictFileExtensions && wgFileExtensions && id != 'wpUploadFileURL' ) {
 281+ var found = false;
 282+ if ( fname.lastIndexOf( '.' ) != -1 ) {
 283+ var ext = fname.substr( fname.lastIndexOf( '.' ) + 1 );
 284+ for ( var i = 0; i < wgFileExtensions.length; i++ ) {
 285+ if ( wgFileExtensions[i].toLowerCase() == ext.toLowerCase() ) {
 286+ found = true;
 287+ break;
 288+ }
 289+ }
 290+ }
 291+ if ( !found ) {
 292+ // Not a valid extension
 293+ // Clear the upload and set mw-upload-permitted to error
 294+ document.getElementById( id ).value = '';
 295+ var e = document.getElementById( 'mw-upload-permitted' );
 296+ if ( e ) e.className = 'error';
 297+ var e = document.getElementById( 'mw-upload-prohibited' );
 298+ if ( e ) e.className = 'error';
 299+ // Clear wpDestFile as well
 300+ var e = document.getElementById( 'wpDestFile' )
 301+ if ( e ) e.value = '';
 302+
 303+ return false;
 304+ }
 305+ }
 306+ // Capitalise first letter and replace spaces by underscores
 307+ // FIXME: $wgCapitalizedNamespaces
 308+ fname = fname.charAt( 0 ).toUpperCase().concat( fname.substring( 1,10000 ) ).replace( / /g, '_' );
 309+ // Output result
 310+ var destFile = document.getElementById( 'wpDestFile' );
 311+ if ( destFile ) {
 312+ destFile.value = fname;
 313+ wgUploadWarningObj.checkNow( fname ) ;
 314+ }
 315+ },
 316+ 'toggleFilenameFiller': function() {
 317+ if ( !document.getElementById ) return;
 318+ var upfield = document.getElementById( 'wpUploadFile' );
 319+ var destName = document.getElementById( 'wpDestFile' ).value;
 320+ if ( destName=='' || destName==' ' ) {
 321+ wgUploadAutoFill = true;
 322+ } else {
 323+ wgUploadAutoFill = false;
 324+ }
 325+ }
 326+} );
 327+
 328+/* Initialization */
 329+
 330+$( document ).ready( function() {
 331+ mw.legacy.wgUploadSetup();
 332+} );
 333+
 334+} )( jQuery, MediaWiki );
\ No newline at end of file
Property changes on: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.upload.js
___________________________________________________________________
Added: svn:eol-style
1335 + native
Index: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.wikibits.js
@@ -0,0 +1,1090 @@
 2+/*
 3+ * Legacy emulation for the now depricated skins/common/wikibits.js
 4+ *
 5+ * MediaWiki JavaScript support functions
 6+ *
 7+ * Global external objects used by this script: ta, stylepath, skin
 8+ */
 9+
 10+( function( $, mw ) {
 11+
 12+/* Extension */
 13+
 14+/*
 15+ * Scary user-agent detection stuff
 16+ */
 17+mw.legacy.clientPC = navigator.userAgent.toLowerCase(); // Get client info
 18+mw.legacy.is_gecko = /gecko/.test( mw.legacy.clientPC ) && !/khtml|spoofer|netscape\/7\.0/.test(mw.legacy.clientPC);
 19+mw.legacy.webkit_match = mw.legacy.clientPC.match(/applewebkit\/(\d+)/);
 20+if (mw.legacy.webkit_match) {
 21+ mw.legacy.is_safari = mw.legacy.clientPC.indexOf('applewebkit') != -1 &&
 22+ mw.legacy.clientPC.indexOf('spoofer') == -1;
 23+ mw.legacy.is_safari_win = mw.legacy.is_safari && mw.legacy.clientPC.indexOf('windows') != -1;
 24+ mw.legacy.webkit_version = parseInt(mw.legacy.webkit_match[1]);
 25+ // Tests for chrome here, to avoid breaking old scripts safari left alone
 26+ // This is here for accesskeys
 27+ mw.legacy.is_chrome = mw.legacy.clientPC.indexOf('chrome') !== -1 &&
 28+ mw.legacy.clientPC.indexOf('spoofer') === -1;
 29+ mw.legacy.is_chrome_mac = mw.legacy.is_chrome && mw.legacy.clientPC.indexOf('mac') !== -1
 30+}
 31+// For accesskeys; note that FF3+ is included here!
 32+mw.legacy.is_ff2 = /firefox\/[2-9]|minefield\/3/.test( mw.legacy.clientPC );
 33+mw.legacy.ff2_bugs = /firefox\/2/.test( mw.legacy.clientPC );
 34+// These aren't used here, but some custom scripts rely on them
 35+mw.legacy.is_ff2_win = mw.legacy.is_ff2 && mw.legacy.clientPC.indexOf('windows') != -1;
 36+mw.legacy.is_ff2_x11 = mw.legacy.is_ff2 && mw.legacy.clientPC.indexOf('x11') != -1;
 37+if (mw.legacy.clientPC.indexOf('opera') != -1) {
 38+ mw.legacy.is_opera = true;
 39+ mw.legacy.is_opera_preseven = window.opera && !document.childNodes;
 40+ mw.legacy.is_opera_seven = window.opera && document.childNodes;
 41+ mw.legacy.is_opera_95 = /opera\/(9\.[5-9]|[1-9][0-9])/.test( mw.legacy.clientPC );
 42+ mw.legacy.opera6_bugs = mw.legacy.is_opera_preseven;
 43+ mw.legacy.opera7_bugs = mw.legacy.is_opera_seven && !mw.legacy.is_opera_95;
 44+ mw.legacy.opera95_bugs = /opera\/(9\.5)/.test( mw.legacy.clientPC );
 45+}
 46+// As recommended by <http://msdn.microsoft.com/en-us/library/ms537509.aspx>,
 47+// avoiding false positives from moronic extensions that append to the IE UA
 48+// string (bug 23171)
 49+mw.legacy.ie6_bugs = false;
 50+if ( /MSIE ([0-9]{1,}[\.0-9]{0,})/.exec( mw.legacy.clientPC ) != null && parseFloat( RegExp.$1 ) <= 6.0 ) {
 51+ mw.legacy.ie6_bugs = true;
 52+}
 53+
 54+$.extend( true, mw.legacy, {
 55+
 56+ /*
 57+ * Events
 58+ *
 59+ * Add any onload functions in this hook (please don't hard-code any events in the xhtml source)
 60+ */
 61+
 62+ /* Global Variables */
 63+
 64+ 'doneOnloadHook': null,
 65+ 'onloadFuncts': [],
 66+
 67+ /* Functions */
 68+
 69+ 'addOnloadHook': function( hookFunct ) {
 70+ // Allows add-on scripts to add onload functions
 71+ if( !mw.legacy.doneOnloadHook ) {
 72+ mw.legacy.onloadFuncts[mw.legacy.onloadFuncts.length] = hookFunct;
 73+ } else {
 74+ hookFunct(); // bug in MSIE script loading
 75+ }
 76+ },
 77+ 'hookEvent': function( hookName, hookFunct ) {
 78+ addHandler( window, hookName, hookFunct );
 79+ },
 80+ 'killEvt': function( evt ) {
 81+ evt = evt || window.event || window.Event; // W3C, IE, Netscape
 82+ if ( typeof ( evt.preventDefault ) != 'undefined' ) {
 83+ evt.preventDefault(); // Don't follow the link
 84+ evt.stopPropagation();
 85+ } else {
 86+ evt.cancelBubble = true; // IE
 87+ }
 88+ return false; // Don't follow the link (IE)
 89+ },
 90+
 91+ /*
 92+ * Dynamic loading
 93+ */
 94+
 95+ /* Global Variables */
 96+
 97+ 'loadedScripts': {},
 98+
 99+ /* Functions */
 100+
 101+ 'importScript': function( page ) {
 102+ // TODO: might want to introduce a utility function to match wfUrlencode() in PHP
 103+ var uri = wgScript + '?title=' +
 104+ encodeURIComponent(page.replace(/ /g,'_')).replace(/%2F/ig,'/').replace(/%3A/ig,':') +
 105+ '&action=raw&ctype=text/javascript';
 106+ return importScriptURI( uri );
 107+ },
 108+ 'importScriptURI': function( url ) {
 109+ if ( mw.legacy.loadedScripts[url] ) {
 110+ return null;
 111+ }
 112+ mw.legacy.loadedScripts[url] = true;
 113+ var s = document.createElement( 'script' );
 114+ s.setAttribute( 'src', url );
 115+ s.setAttribute( 'type', 'text/javascript' );
 116+ document.getElementsByTagName('head')[0].appendChild( s );
 117+ return s;
 118+ },
 119+ 'importStylesheet': function( page ) {
 120+ return importStylesheetURI( wgScript + '?action=raw&ctype=text/css&title=' + encodeURIComponent( page.replace(/ /g,'_') ) );
 121+ },
 122+ 'importStylesheetURI': function( url, media ) {
 123+ var l = document.createElement( 'link' );
 124+ l.type = 'text/css';
 125+ l.rel = 'stylesheet';
 126+ l.href = url;
 127+ if( media ) {
 128+ l.media = media;
 129+ }
 130+ document.getElementsByTagName('head')[0].appendChild( l );
 131+ return l;
 132+ },
 133+ 'appendCSS': function( text ) {
 134+ var s = document.createElement( 'style' );
 135+ s.type = 'text/css';
 136+ s.rel = 'stylesheet';
 137+ if ( s.styleSheet ) {
 138+ s.styleSheet.cssText = text; // IE
 139+ } else {
 140+ s.appendChild( document.createTextNode( text + '' ) ); // Safari sometimes borks on null
 141+ }
 142+ document.getElementsByTagName('head')[0].appendChild( s );
 143+ return s;
 144+ },
 145+ 'runOnloadHook': function() {
 146+ // don't run anything below this for non-dom browsers
 147+ if ( mw.legacy.doneOnloadHook || !( document.getElementById && document.getElementsByTagName ) ) {
 148+ return;
 149+ }
 150+ // set this before running any hooks, since any errors below
 151+ // might cause the function to terminate prematurely
 152+ mw.legacy.doneOnloadHook = true;
 153+ updateTooltipAccessKeys( null );
 154+ setupCheckboxShiftClick();
 155+ sortables_init();
 156+ // Run any added-on functions
 157+ for ( var i = 0; i < mw.legacy.onloadFuncts.length; i++ ) {
 158+ mw.legacy.onloadFuncts[i]();
 159+ }
 160+ },
 161+ /**
 162+ * Add an event handler to an element
 163+ *
 164+ * @param Element element Element to add handler to
 165+ * @param String attach Event to attach to
 166+ * @param callable handler Event handler callback
 167+ */
 168+ 'addHandler': function( element, attach, handler ) {
 169+ if( window.addEventListener ) {
 170+ element.addEventListener( attach, handler, false );
 171+ } else if( window.attachEvent ) {
 172+ element.attachEvent( 'on' + attach, handler );
 173+ }
 174+ },
 175+ /**
 176+ * Add a click event handler to an element
 177+ *
 178+ * @param Element element Element to add handler to
 179+ * @param callable handler Event handler callback
 180+ */
 181+ 'addClickHandler': function( element, handler ) {
 182+ addHandler( element, 'click', handler );
 183+ },
 184+ /**
 185+ * Removes an event handler from an element
 186+ *
 187+ * @param Element element Element to remove handler from
 188+ * @param String remove Event to remove
 189+ * @param callable handler Event handler callback to remove
 190+ */
 191+ 'removeHandler': function( element, remove, handler ) {
 192+ if( window.removeEventListener ) {
 193+ element.removeEventListener( remove, handler, false );
 194+ } else if( window.detachEvent ) {
 195+ element.detachEvent( 'on' + remove, handler );
 196+ }
 197+ },
 198+
 199+ /*
 200+ * Toolbar
 201+ */
 202+
 203+ /* Global Variables */
 204+
 205+ 'mwEditButtons': [],
 206+ 'mwCustomEditButtons': [],
 207+
 208+ /**
 209+ * Tooltips and access-keys
 210+ */
 211+
 212+ /* Global Variables */
 213+
 214+ /**
 215+ * Set the accesskey prefix based on browser detection.
 216+ */
 217+ 'tooltipAccessKeyPrefix': ( function() {
 218+ if ( mw.legacy.is_opera ) {
 219+ return 'shift-esc-';
 220+ } else if ( mw.legacy.is_chrome ) {
 221+ return mw.legacy.is_chrome_mac ? 'ctrl-option-' : 'alt-';
 222+ } else if ( !mw.legacy.is_safari_win && mw.legacy.is_safari && mw.legacy.webkit_version > 526 ) {
 223+ return 'ctrl-alt-';
 224+ } else if (
 225+ !mw.legacy.is_safari_win &&
 226+ (
 227+ mw.legacy.is_safari ||
 228+ mw.legacy.clientPC.indexOf( 'mac' ) != -1 ||
 229+ mw.legacy.clientPC.indexOf( 'konqueror' ) != -1
 230+ )
 231+ ) {
 232+ return = 'ctrl-';
 233+ } else if ( mw.legacy.is_ff2 ) {
 234+ return = 'alt-shift-';
 235+ }
 236+ return 'alt-';
 237+ } )(),
 238+ 'tooltipAccessKeyRegexp': /\[(ctrl-)?(alt-)?(shift-)?(esc-)?(.)\]$/,
 239+ // Dummy for deprecated function
 240+ 'ta': [],
 241+
 242+ /* Functions */
 243+
 244+ /**
 245+ * Add the appropriate prefix to the accesskey shown in the tooltip.
 246+ * If the nodeList parameter is given, only those nodes are updated;
 247+ * otherwise, all the nodes that will probably have accesskeys by
 248+ * default are updated.
 249+ *
 250+ * @param Array nodeList -- list of elements to update
 251+ */
 252+ 'updateTooltipAccessKeys': function( nodeList ) {
 253+ if ( !nodeList ) {
 254+ // Rather than scan all links on the whole page, we can just scan these
 255+ // containers which contain the relevant links. This is really just an
 256+ // optimization technique.
 257+ var linkContainers = [
 258+ 'column-one', // Monobook and Modern
 259+ 'mw-head', 'mw-panel', 'p-logo' // Vector
 260+ ];
 261+ for ( var i in linkContainers ) {
 262+ var linkContainer = document.getElementById( linkContainers[i] );
 263+ if ( linkContainer ) {
 264+ updateTooltipAccessKeys( linkContainer.getElementsByTagName( 'a' ) );
 265+ }
 266+ }
 267+ // these are rare enough that no such optimization is needed
 268+ updateTooltipAccessKeys( document.getElementsByTagName( 'input' ) );
 269+ updateTooltipAccessKeys( document.getElementsByTagName( 'label' ) );
 270+ return;
 271+ }
 272+ for ( var i = 0; i < nodeList.length; i++ ) {
 273+ var element = nodeList[i];
 274+ var tip = element.getAttribute( 'title' );
 275+ if ( tip && mw.legacy.tooltipAccessKeyRegexp.exec( tip ) ) {
 276+ tip = tip.replace(mw.legacy.tooltipAccessKeyRegexp,
 277+ '[' + mw.legacy.tooltipAccessKeyPrefix + '$5]');
 278+ element.setAttribute( 'title', tip );
 279+ }
 280+ }
 281+ },
 282+ // Dummy function for depricated feature
 283+ 'akeytt': function( doId ) { },
 284+
 285+ /*
 286+ * Checkboxes
 287+ */
 288+
 289+ /* Global Varibles */
 290+
 291+ 'checkboxes': null,
 292+ 'lastCheckbox': null,
 293+
 294+ /* Functions */
 295+
 296+ 'setupCheckboxShiftClick': function() {
 297+ mw.legacy.checkboxes = [];
 298+ mw.legacy.lastCheckbox = null;
 299+ var inputs = document.getElementsByTagName( 'input' );
 300+ addCheckboxClickHandlers( inputs );
 301+ },
 302+ 'addCheckboxClickHandlers': function( inputs, start ) {
 303+ if ( !start ) {
 304+ start = 0;
 305+ }
 306+ var finish = start + 250;
 307+ if ( finish > inputs.length ) {
 308+ finish = inputs.length;
 309+ }
 310+ for ( var i = start; i < finish; i++ ) {
 311+ var cb = inputs[i];
 312+ if ( !cb.type || cb.type.toLowerCase() != 'checkbox' ) {
 313+ continue;
 314+ }
 315+ var end = mw.legacy.checkboxes.length;
 316+ mw.legacy.checkboxes[end] = cb;
 317+ cb.index = end;
 318+ addClickHandler( cb, checkboxClickHandler );
 319+ }
 320+ if ( finish < inputs.length ) {
 321+ setTimeout( function() {
 322+ addCheckboxClickHandlers( inputs, finish );
 323+ }, 200 );
 324+ }
 325+ },
 326+ 'checkboxClickHandler': function( e ) {
 327+ if ( typeof e == 'undefined' ) {
 328+ e = window.event;
 329+ }
 330+ if ( !e.shiftKey || mw.legacy.lastCheckbox === null ) {
 331+ mw.legacy.lastCheckbox = this.index;
 332+ return true;
 333+ }
 334+ var endState = this.checked;
 335+ var start, finish;
 336+ if ( this.index < mw.legacy.lastCheckbox ) {
 337+ start = this.index + 1;
 338+ finish = mw.legacy.lastCheckbox;
 339+ } else {
 340+ start = mw.legacy.lastCheckbox;
 341+ finish = this.index - 1;
 342+ }
 343+ for ( var i = start; i <= finish; ++i ) {
 344+ mw.legacy.checkboxes[i].checked = endState;
 345+ if( i > start && typeof mw.legacy.checkboxes[i].onchange == 'function' ) {
 346+ mw.legacy.checkboxes[i].onchange(); // fire triggers
 347+ }
 348+ }
 349+ mw.legacy.lastCheckbox = this.index;
 350+ return true;
 351+ },
 352+
 353+ /*
 354+ * Table of contents
 355+ */
 356+
 357+ /* Functions */
 358+
 359+ 'showTocToggle': function() {
 360+ if ( document.createTextNode ) {
 361+ // Uses DOM calls to avoid document.write + XHTML issues
 362+ var linkHolder = document.getElementById( 'toctitle' );
 363+ var existingLink = document.getElementById( 'togglelink' );
 364+ if ( !linkHolder || existingLink ) {
 365+ // Don't add the toggle link twice
 366+ return;
 367+ }
 368+ var outerSpan = document.createElement( 'span' );
 369+ outerSpan.className = 'toctoggle';
 370+ var toggleLink = document.createElement( 'a' );
 371+ toggleLink.id = 'togglelink';
 372+ toggleLink.className = 'internal';
 373+ toggleLink.href = '#';
 374+ addClickHandler( toggleLink, function( evt ) { toggleToc(); return killEvt( evt ); } );
 375+ toggleLink.appendChild( document.createTextNode( tocHideText ) );
 376+ outerSpan.appendChild( document.createTextNode( '[' ) );
 377+ outerSpan.appendChild( toggleLink );
 378+ outerSpan.appendChild( document.createTextNode( ']' ) );
 379+ linkHolder.appendChild( document.createTextNode( ' ' ) );
 380+ linkHolder.appendChild( outerSpan );
 381+ var cookiePos = document.cookie.indexOf( 'hidetoc=' );
 382+ if ( cookiePos > -1 && document.cookie.charAt( cookiePos + 8 ) == 1 ) {
 383+ toggleToc();
 384+ }
 385+ }
 386+ },
 387+ 'toggleToc': function() {
 388+ var tocmain = document.getElementById( 'toc' );
 389+ var toc = document.getElementById('toc').getElementsByTagName('ul')[0];
 390+ var toggleLink = document.getElementById( 'togglelink' );
 391+
 392+ if ( toc && toggleLink && toc.style.display == 'none' ) {
 393+ changeText( toggleLink, tocHideText );
 394+ toc.style.display = 'block';
 395+ document.cookie = 'hidetoc=0';
 396+ tocmain.className = 'toc';
 397+ } else {
 398+ changeText( toggleLink, tocShowText );
 399+ toc.style.display = 'none';
 400+ document.cookie = 'hidetoc=1';
 401+ tocmain.className = 'toc tochidden';
 402+ }
 403+ return false;
 404+ },
 405+
 406+ /*
 407+ * Table sorting
 408+ *
 409+ * Script based on one (c) 1997-2006 Stuart Langridge and Joost de Valk:
 410+ * http://www.joostdevalk.nl/code/sortable-table/
 411+ * http://www.kryogenix.org/code/browser/sorttable/
 412+ *
 413+ * @todo don't break on colspans/rowspans (bug 8028)
 414+ * @todo language-specific digit grouping/decimals (bug 8063)
 415+ * @todo support all accepted date formats (bug 8226)
 416+ */
 417+
 418+ /* Global Variables */
 419+
 420+ 'ts_image_path': mw.legacy.stylepath + '/common/images/',
 421+ 'ts_image_up': 'sort_up.gif',
 422+ 'ts_image_down': 'sort_down.gif',
 423+ 'ts_image_none': 'sort_none.gif',
 424+ // The non-American-inclined can change to "true"
 425+ 'ts_europeandate': mw.legacy.wgContentLanguage != 'en',
 426+ 'ts_alternate_row_colors': false,
 427+ 'ts_number_transform_table': null,
 428+ 'ts_number_regex': null,
 429+
 430+ /* Functions */
 431+
 432+ 'sortables_init': function() {
 433+ var idnum = 0;
 434+ // Find all tables with class sortable and make them sortable
 435+ var tables = getElementsByClassName( document, 'table', 'sortable' );
 436+ for ( var ti = 0; ti < tables.length ; ti++ ) {
 437+ if ( !tables[ti].id ) {
 438+ tables[ti].setAttribute( 'id', 'sortable_table_id_' + idnum );
 439+ ++idnum;
 440+ }
 441+ mw.legacy.ts_makeSortable( tables[ti] );
 442+ }
 443+ },
 444+ 'ts_makeSortable': function( table ) {
 445+ var firstRow;
 446+ if ( table.rows && table.rows.length > 0 ) {
 447+ if ( table.tHead && table.tHead.rows.length > 0 ) {
 448+ firstRow = table.tHead.rows[table.tHead.rows.length-1];
 449+ } else {
 450+ firstRow = table.rows[0];
 451+ }
 452+ }
 453+ if ( !firstRow ) {
 454+ return;
 455+ }
 456+ // We have a first row: assume it's the header, and make its contents clickable links
 457+ for ( var i = 0; i < firstRow.cells.length; i++ ) {
 458+ var cell = firstRow.cells[i];
 459+ if ( (' ' + cell.className + ' ').indexOf(' unsortable ') == -1 ) {
 460+ cell.innerHTML += '<a href="#" class="sortheader" '
 461+ + 'onclick="mw.legacy.ts_resortTable(this);return false;">'
 462+ + '<span class="sortarrow">'
 463+ + '<img src="'
 464+ + mw.legacy.ts_image_path
 465+ + mw.legacy.ts_image_none
 466+ + '" alt="&darr;"/></span></a>';
 467+ }
 468+ }
 469+ if ( mw.legacy.ts_alternate_row_colors ) {
 470+ mw.legacy.ts_alternate( table );
 471+ }
 472+ },
 473+ 'ts_getInnerText': function( el ) {
 474+ return getInnerText( el );
 475+ },
 476+ 'ts_resortTable': function( lnk ) {
 477+ // get the span
 478+ var span = lnk.getElementsByTagName('span')[0];
 479+ var td = lnk.parentNode;
 480+ var tr = td.parentNode;
 481+ var column = td.cellIndex;
 482+ var table = tr.parentNode;
 483+ while ( table && !( table.tagName && table.tagName.toLowerCase() == 'table' ) ) {
 484+ table = table.parentNode;
 485+ }
 486+ if ( !table ) {
 487+ return;
 488+ }
 489+ if ( table.rows.length <= 1 ) {
 490+ return;
 491+ }
 492+ // Generate the number transform table if it's not done already
 493+ if ( mw.legacy.ts_number_transform_table === null ) {
 494+ mw.legacy.ts_initTransformTable();
 495+ }
 496+ // Work out a type for the column
 497+ // Skip the first row if that's where the headings are
 498+ var rowStart = ( table.tHead && table.tHead.rows.length > 0 ? 0 : 1 );
 499+ var bodyRows = 0;
 500+ if (rowStart == 0 && table.tBodies) {
 501+ for (var i=0; i < table.tBodies.length; i++ ) {
 502+ bodyRows += table.tBodies[i].rows.length;
 503+ }
 504+ if (bodyRows < table.rows.length)
 505+ rowStart = 1;
 506+ }
 507+ var itm = '';
 508+ for ( var i = rowStart; i < table.rows.length; i++ ) {
 509+ if ( table.rows[i].cells.length > column ) {
 510+ itm = mw.legacy.ts_getInnerText(table.rows[i].cells[column]);
 511+ itm = itm.replace(/^[\s\xa0]+/, '').replace(/[\s\xa0]+$/, '');
 512+ if ( itm != '' ) {
 513+ break;
 514+ }
 515+ }
 516+ }
 517+ // TODO: bug 8226, localised date formats
 518+ var sortfn = mw.legacy.ts_sort_generic;
 519+ var preprocessor = mw.legacy.ts_toLowerCase;
 520+ if ( /^\d\d[\/. -][a-zA-Z]{3}[\/. -]\d\d\d\d$/.test( itm ) ) {
 521+ preprocessor = mw.legacy.ts_dateToSortKey;
 522+ } else if ( /^\d\d[\/.-]\d\d[\/.-]\d\d\d\d$/.test( itm ) ) {
 523+ preprocessor = mw.legacy.ts_dateToSortKey;
 524+ } else if ( /^\d\d[\/.-]\d\d[\/.-]\d\d$/.test( itm ) ) {
 525+ preprocessor = mw.legacy.ts_dateToSortKey;
 526+ // (minus sign)([pound dollar euro yen currency]|cents)
 527+ } else if ( /(^([-\u2212] *)?[\u00a3$\u20ac\u00a4\u00a5]|\u00a2$)/.test( itm ) ) {
 528+ preprocessor = mw.legacy.ts_currencyToSortKey;
 529+ } else if ( mw.legacy.ts_number_regex.test( itm ) ) {
 530+ preprocessor = mw.legacy.ts_parseFloat;
 531+ }
 532+ var reverse = ( span.getAttribute( 'sortdir' ) == 'down' );
 533+ var newRows = new Array();
 534+ var staticRows = new Array();
 535+ for ( var j = rowStart; j < table.rows.length; j++ ) {
 536+ var row = table.rows[j];
 537+ if( (' ' + row.className + ' ').indexOf(' unsortable ') < 0 ) {
 538+ var keyText = mw.legacy.ts_getInnerText( row.cells[column] );
 539+ if( keyText === undefined ) {
 540+ keyText = '';
 541+ }
 542+ var oldIndex = ( reverse ? -j : j );
 543+ var preprocessed = preprocessor( keyText.replace(/^[\s\xa0]+/, '').replace(/[\s\xa0]+$/, '') );
 544+ newRows[newRows.length] = new Array( row, preprocessed, oldIndex );
 545+ } else {
 546+ staticRows[staticRows.length] = new Array( row, false, j-rowStart );
 547+ }
 548+ }
 549+ newRows.sort( sortfn );
 550+ var arrowHTML;
 551+ if ( reverse ) {
 552+ arrowHTML = '<img src="' + mw.legacy.ts_image_path + mw.legacy.ts_image_down + '" alt="&darr;"/>';
 553+ newRows.reverse();
 554+ span.setAttribute( 'sortdir', 'up' );
 555+ } else {
 556+ arrowHTML = '<img src="' + mw.legacy.ts_image_path + mw.legacy.ts_image_up + '" alt="&uarr;"/>';
 557+ span.setAttribute( 'sortdir', 'down' );
 558+ }
 559+ for ( var i = 0; i < staticRows.length; i++ ) {
 560+ var row = staticRows[i];
 561+ newRows.splice( row[2], 0, row );
 562+ }
 563+ // We appendChild rows that already exist to the tbody, so it moves them rather than creating new ones
 564+ // don't do sortbottom rows
 565+ for ( var i = 0; i < newRows.length; i++ ) {
 566+ if ( ( ' ' + newRows[i][0].className + ' ').indexOf(' sortbottom ') == -1 ) {
 567+ table.tBodies[0].appendChild( newRows[i][0] );
 568+ }
 569+ }
 570+ // do sortbottom rows only
 571+ for ( var i = 0; i < newRows.length; i++ ) {
 572+ if ( ( ' ' + newRows[i][0].className + ' ').indexOf(' sortbottom ') != -1 ) {
 573+ table.tBodies[0].appendChild( newRows[i][0] );
 574+ }
 575+ }
 576+ // Delete any other arrows there may be showing
 577+ var spans = getElementsByClassName( tr, 'span', 'sortarrow' );
 578+ for ( var i = 0; i < spans.length; i++ ) {
 579+ spans[i].innerHTML = '<img src="' + mw.legacy.ts_image_path + mw.legacy.ts_image_none + '" alt="&darr;"/>';
 580+ }
 581+ span.innerHTML = arrowHTML;
 582+
 583+ if ( mw.legacy.ts_alternate_row_colors ) {
 584+ mw.legacy.ts_alternate( table );
 585+ }
 586+ },
 587+ 'ts_initTransformTable': function() {
 588+ if ( typeof wgSeparatorTransformTable == 'undefined'
 589+ || ( wgSeparatorTransformTable[0] == '' && wgDigitTransformTable[2] == '' ) )
 590+ {
 591+ var digitClass = '[0-9,.]';
 592+ mw.legacy.ts_number_transform_table = false;
 593+ } else {
 594+ mw.legacy.ts_number_transform_table = {};
 595+ // Unpack the transform table
 596+ // Separators
 597+ var ascii = wgSeparatorTransformTable[0].split('\t');
 598+ var localised = wgSeparatorTransformTable[1].split('\t');
 599+ for ( var i = 0; i < ascii.length; i++ ) {
 600+ mw.legacy.ts_number_transform_table[localised[i]] = ascii[i];
 601+ }
 602+ // Digits
 603+ ascii = wgDigitTransformTable[0].split('\t');
 604+ localised = wgDigitTransformTable[1].split('\t');
 605+ for ( var i = 0; i < ascii.length; i++ ) {
 606+ mw.legacy.ts_number_transform_table[localised[i]] = ascii[i];
 607+ }
 608+ // Construct regex for number identification
 609+ var digits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ',', '\\.'];
 610+ var maxDigitLength = 1;
 611+ for ( var digit in mw.legacy.ts_number_transform_table ) {
 612+ // Escape regex metacharacters
 613+ digits.push(
 614+ digit.replace( /[\\\\$\*\+\?\.\(\)\|\{\}\[\]\-]/,
 615+ function( s ) { return '\\' + s; } )
 616+ );
 617+ if ( digit.length > maxDigitLength ) {
 618+ maxDigitLength = digit.length;
 619+ }
 620+ }
 621+ if ( maxDigitLength > 1 ) {
 622+ var digitClass = '[' + digits.join( '', digits ) + ']';
 623+ } else {
 624+ var digitClass = '(' + digits.join( '|', digits ) + ')';
 625+ }
 626+ }
 627+ // We allow a trailing percent sign, which we just strip. This works fine
 628+ // if percents and regular numbers aren't being mixed.
 629+ mw.legacy.ts_number_regex = new RegExp(
 630+ '^(' +
 631+ '[-+\u2212]?[0-9][0-9,]*(\\.[0-9,]*)?(E[-+\u2212]?[0-9][0-9,]*)?' + // Fortran-style scientific
 632+ '|' +
 633+ '[-+\u2212]?' + digitClass + '+%?' + // Generic localised
 634+ ')$', 'i'
 635+ );
 636+ },
 637+ 'ts_toLowerCase': function( s ) {
 638+ return s.toLowerCase();
 639+ },
 640+ 'ts_dateToSortKey': function( date ) {
 641+ // y2k notes: two digit years less than 50 are treated as 20XX, greater than 50 are treated as 19XX
 642+ if ( date.length == 11 ) {
 643+ switch ( date.substr( 3, 3 ).toLowerCase() ) {
 644+ case 'jan':
 645+ var month = '01';
 646+ break;
 647+ case 'feb':
 648+ var month = '02';
 649+ break;
 650+ case 'mar':
 651+ var month = '03';
 652+ break;
 653+ case 'apr':
 654+ var month = '04';
 655+ break;
 656+ case 'may':
 657+ var month = '05';
 658+ break;
 659+ case 'jun':
 660+ var month = '06';
 661+ break;
 662+ case 'jul':
 663+ var month = '07';
 664+ break;
 665+ case 'aug':
 666+ var month = '08';
 667+ break;
 668+ case 'sep':
 669+ var month = '09';
 670+ break;
 671+ case 'oct':
 672+ var month = '10';
 673+ break;
 674+ case 'nov':
 675+ var month = '11';
 676+ break;
 677+ case 'dec':
 678+ var month = '12';
 679+ break;
 680+ // default: var month = '00';
 681+ }
 682+ return date.substr( 7, 4 ) + month + date.substr( 0, 2 );
 683+ } else if ( date.length == 10 ) {
 684+ if ( mw.legacy.ts_europeandate == false ) {
 685+ return date.substr( 6, 4 ) + date.substr( 0, 2 ) + date.substr( 3, 2 );
 686+ } else {
 687+ return date.substr( 6, 4 ) + date.substr( 3, 2 ) + date.substr( 0, 2 );
 688+ }
 689+ } else if ( date.length == 8 ) {
 690+ var yr = date.substr( 6, 2 );
 691+ if ( parseInt( yr ) < 50 ) {
 692+ yr = '20' + yr;
 693+ } else {
 694+ yr = '19' + yr;
 695+ }
 696+ if ( mw.legacy.ts_europeandate == true ) {
 697+ return yr + date.substr( 3, 2 ) + date.substr( 0, 2 );
 698+ } else {
 699+ return yr + date.substr( 0, 2 ) + date.substr( 3, 2 );
 700+ }
 701+ }
 702+ return '00000000';
 703+ },
 704+ 'ts_parseFloat': function( s ) {
 705+ if ( !s ) {
 706+ return 0;
 707+ }
 708+ if ( mw.legacy.ts_number_transform_table != false ) {
 709+ var newNum = '', c;
 710+
 711+ for ( var p = 0; p < s.length; p++ ) {
 712+ c = s.charAt( p );
 713+ if ( c in mw.legacy.ts_number_transform_table ) {
 714+ newNum += mw.legacy.ts_number_transform_table[c];
 715+ } else {
 716+ newNum += c;
 717+ }
 718+ }
 719+ s = newNum;
 720+ }
 721+ var num = parseFloat( s.replace(/[, ]/g, '').replace('\u2212', '-') );
 722+ return ( isNaN( num ) ? -Infinity : num );
 723+ },
 724+ 'ts_currencyToSortKey': function( s ) {
 725+ return mw.legacy.ts_parseFloat(s.replace(/[^-\u22120-9.,]/g,''));
 726+ },
 727+ 'ts_sort_generic': function( a, b ) {
 728+ return a[1] < b[1] ? -1 : a[1] > b[1] ? 1 : a[2] - b[2];
 729+ },
 730+ 'ts_alternate': function( table ) {
 731+ // Take object table and get all it's tbodies.
 732+ var tableBodies = table.getElementsByTagName( 'tbody' );
 733+ // Loop through these tbodies
 734+ for ( var i = 0; i < tableBodies.length; i++ ) {
 735+ // Take the tbody, and get all it's rows
 736+ var tableRows = tableBodies[i].getElementsByTagName( 'tr' );
 737+ // Loop through these rows
 738+ // Start at 1 because we want to leave the heading row untouched
 739+ for ( var j = 0; j < tableRows.length; j++ ) {
 740+ // Check if j is even, and apply classes for both possible results
 741+ var oldClasses = tableRows[j].className.split(' ');
 742+ var newClassName = '';
 743+ for ( var k = 0; k < oldClasses.length; k++ ) {
 744+ if ( oldClasses[k] != '' && oldClasses[k] != 'even' && oldClasses[k] != 'odd' ) {
 745+ newClassName += oldClasses[k] + ' ';
 746+ }
 747+ }
 748+ tableRows[j].className = newClassName + ( j % 2 == 0 ? 'even' : 'odd' );
 749+ }
 750+ }
 751+ },
 752+
 753+ /*
 754+ * Skins
 755+ */
 756+
 757+ /* Functions */
 758+
 759+ 'changeText': function( el, newText ) {
 760+ // Safari work around
 761+ if ( el.innerText ) {
 762+ el.innerText = newText;
 763+ } else if ( el.firstChild && el.firstChild.nodeValue ) {
 764+ el.firstChild.nodeValue = newText;
 765+ }
 766+ },
 767+ 'escapeQuotes': function( text ) {
 768+ var re = new RegExp( '\'', 'g' );
 769+ text = text.replace( re, '\\'' );
 770+ re = new RegExp( '\\n', 'g' );
 771+ text = text.replace( re, '\\n' );
 772+ return escapeQuotesHTML( text );
 773+ },
 774+ 'escapeQuotesHTML': function( text ) {
 775+ var re = new RegExp( '&', 'g' );
 776+ text = text.replace( re, '&amp;' );
 777+ re = new RegExp( '\'', 'g' );
 778+ text = text.replace( re, '&quot;' );
 779+ re = new RegExp( '<', 'g' );
 780+ text = text.replace( re, '&lt;' );
 781+ re = new RegExp( '>', 'g' );
 782+ text = text.replace( re, '&gt;' );
 783+ return text;
 784+ },
 785+ /**
 786+ * Add a link to one of the portlet menus on the page, including:
 787+ *
 788+ * p-cactions: Content actions (shown as tabs above the main content in Monobook)
 789+ * p-personal: Personal tools (shown at the top right of the page in Monobook)
 790+ * p-navigation: Navigation
 791+ * p-tb: Toolbox
 792+ *
 793+ * This function exists for the convenience of custom JS authors. All
 794+ * but the first three parameters are optional, though providing at
 795+ * least an id and a tooltip is recommended.
 796+ *
 797+ * By default the new link will be added to the end of the list. To
 798+ * add the link before a given existing item, pass the DOM node of
 799+ * that item (easily obtained with document.getElementById()) as the
 800+ * nextnode parameter; to add the link _after_ an existing item, pass
 801+ * the node's nextSibling instead.
 802+ *
 803+ * @param String portlet -- id of the target portlet ("p-cactions", "p-personal", "p-navigation" or "p-tb")
 804+ * @param String href -- link URL
 805+ * @param String text -- link text (will be automatically lowercased by CSS for p-cactions in Monobook)
 806+ * @param String id -- id of the new item, should be unique and preferably have the appropriate prefix ("ca-", "pt-", "n-" or "t-")
 807+ * @param String tooltip -- text to show when hovering over the link, without accesskey suffix
 808+ * @param String accesskey -- accesskey to activate this link (one character, try to avoid conflicts)
 809+ * @param Node nextnode -- the DOM node before which the new item should be added, should be another item in the same list
 810+ *
 811+ * @return Node -- the DOM node of the new item (an LI element) or null
 812+ */
 813+ 'addPortletLink': function( portlet, href, text, id, tooltip, accesskey, nextnode ) {
 814+ var root = document.getElementById( portlet );
 815+ if ( !root ) {
 816+ return null;
 817+ }
 818+ var uls = root.getElementsByTagName( 'ul' );
 819+ var node;
 820+ if ( uls.length > 0 ) {
 821+ node = uls[0];
 822+ } else {
 823+ node = document.createElement( 'ul' );
 824+ var lastElementChild = null;
 825+ for ( var i = 0; i < root.childNodes.length; ++i ) { /* get root.lastElementChild */
 826+ if ( root.childNodes[i].nodeType == 1 ) {
 827+ lastElementChild = root.childNodes[i];
 828+ }
 829+ }
 830+ if ( lastElementChild && lastElementChild.nodeName.match( /div/i ) ) {
 831+ /* Insert into the menu divs */
 832+ lastElementChild.appendChild( node );
 833+ } else {
 834+ root.appendChild( node );
 835+ }
 836+ }
 837+ if ( !node ) {
 838+ return null;
 839+ }
 840+ // unhide portlet if it was hidden before
 841+ root.className = root.className.replace( /(^| )emptyPortlet( |$)/, '$2' );
 842+ var span = document.createElement( 'span' );
 843+ span.appendChild( document.createTextNode( text ) );
 844+ var link = document.createElement( 'a' );
 845+ link.appendChild( span );
 846+ link.href = href;
 847+ var item = document.createElement( 'li' );
 848+ item.appendChild( link );
 849+ if ( id ) {
 850+ item.id = id;
 851+ }
 852+ if ( accesskey ) {
 853+ link.setAttribute( 'accesskey', accesskey );
 854+ tooltip += ' [' + accesskey + ']';
 855+ }
 856+ if ( tooltip ) {
 857+ link.setAttribute( 'title', tooltip );
 858+ }
 859+ if ( accesskey && tooltip ) {
 860+ updateTooltipAccessKeys( new Array( link ) );
 861+ }
 862+ if ( nextnode && nextnode.parentNode == node ) {
 863+ node.insertBefore( item, nextnode );
 864+ } else {
 865+ node.appendChild( item ); // IE compatibility (?)
 866+ }
 867+ return item;
 868+ },
 869+ /**
 870+ * Add a cute little box at the top of the screen to inform the user of
 871+ * something, replacing any preexisting message.
 872+ *
 873+ * @param String -or- Dom Object message HTML to be put inside the right div
 874+ * @param String className Used in adding a class; should be different for each
 875+ * call to allow CSS/JS to hide different boxes. null = no class used.
 876+ * @return Boolean True on success, false on failure
 877+ */
 878+ 'jsMsg': function( message, className ) {
 879+ if ( !document.getElementById ) {
 880+ return false;
 881+ }
 882+ // We special-case skin structures provided by the software. Skins that
 883+ // choose to abandon or significantly modify our formatting can just define
 884+ // an mw-js-message div to start with.
 885+ var messageDiv = document.getElementById( 'mw-js-message' );
 886+ if ( !messageDiv ) {
 887+ messageDiv = document.createElement( 'div' );
 888+ if ( document.getElementById( 'column-content' )
 889+ && document.getElementById( 'content' ) ) {
 890+ // MonoBook, presumably
 891+ document.getElementById( 'content' ).insertBefore(
 892+ messageDiv,
 893+ document.getElementById( 'content' ).firstChild
 894+ );
 895+ } else if ( document.getElementById( 'content' )
 896+ && document.getElementById( 'article' ) ) {
 897+ // Non-Monobook but still recognizable (old-style)
 898+ document.getElementById( 'article').insertBefore(
 899+ messageDiv,
 900+ document.getElementById( 'article' ).firstChild
 901+ );
 902+ } else {
 903+ return false;
 904+ }
 905+ }
 906+ messageDiv.setAttribute( 'id', 'mw-js-message' );
 907+ messageDiv.style.display = 'block';
 908+ if( className ) {
 909+ messageDiv.setAttribute( 'class', 'mw-js-message-' + className );
 910+ }
 911+ if ( typeof message === 'object' ) {
 912+ while ( messageDiv.hasChildNodes() ) { // Remove old content
 913+ messageDiv.removeChild( messageDiv.firstChild );
 914+ }
 915+ messageDiv.appendChild( message ); // Append new content
 916+ } else {
 917+ messageDiv.innerHTML = message;
 918+ }
 919+ return true;
 920+ },
 921+ /**
 922+ * Inject a cute little progress spinner after the specified element
 923+ *
 924+ * @param element Element to inject after
 925+ * @param id Identifier string (for use with removeSpinner(), below)
 926+ */
 927+ 'injectSpinner': function( element, id ) {
 928+ var spinner = document.createElement( 'img' );
 929+ spinner.id = 'mw-spinner-' + id;
 930+ spinner.src = mw.legacy.stylepath + '/common/images/spinner.gif';
 931+ spinner.alt = spinner.title = '...';
 932+ if( element.nextSibling ) {
 933+ element.parentNode.insertBefore( spinner, element.nextSibling );
 934+ } else {
 935+ element.parentNode.appendChild( spinner );
 936+ }
 937+ },
 938+ /**
 939+ * Remove a progress spinner added with injectSpinner()
 940+ *
 941+ * @param id Identifier string
 942+ */
 943+ 'removeSpinner': function( id ) {
 944+ var spinner = document.getElementById( 'mw-spinner-' + id );
 945+ if( spinner ) {
 946+ spinner.parentNode.removeChild( spinner );
 947+ }
 948+ },
 949+
 950+ /*
 951+ * DOM manipulation and traversal
 952+ */
 953+
 954+ /* Functions */
 955+
 956+ 'getInnerText': function( el ) {
 957+ if ( typeof el == 'string' ) {
 958+ return el;
 959+ }
 960+ if ( typeof el == 'undefined' ) {
 961+ return el;
 962+ }
 963+ if ( el.textContent ) {
 964+ return el.textContent; // not needed but it is faster
 965+ }
 966+ if ( el.innerText ) {
 967+ return el.innerText; // IE doesn't have textContent
 968+ }
 969+ var str = '';
 970+ var cs = el.childNodes;
 971+ var l = cs.length;
 972+ for ( var i = 0; i < l; i++ ) {
 973+ switch ( cs[i].nodeType ) {
 974+ case 1: // ELEMENT_NODE
 975+ str += mw.legacy.ts_getInnerText( cs[i] );
 976+ break;
 977+ case 3: // TEXT_NODE
 978+ str += cs[i].nodeValue;
 979+ break;
 980+ }
 981+ }
 982+ return str;
 983+ },
 984+ /**
 985+ * Written by Jonathan Snook, http://www.snook.ca/jonathan
 986+ * Add-ons by Robert Nyman, http://www.robertnyman.com
 987+ * Author says "The credit comment is all it takes, no license. Go crazy with it!:-)"
 988+ * From http://www.robertnyman.com/2005/11/07/the-ultimate-getelementsbyclassname/
 989+ */
 990+ 'getElementsByClassName': function( oElm, strTagName, oClassNames ) {
 991+ var arrReturnElements = new Array();
 992+ if ( typeof( oElm.getElementsByClassName ) == 'function' ) {
 993+ /* Use a native implementation where possible FF3, Saf3.2, Opera 9.5 */
 994+ var arrNativeReturn = oElm.getElementsByClassName( oClassNames );
 995+ if ( strTagName == '*' ) {
 996+ return arrNativeReturn;
 997+ }
 998+ for ( var h = 0; h < arrNativeReturn.length; h++ ) {
 999+ if( arrNativeReturn[h].tagName.toLowerCase() == strTagName.toLowerCase() ) {
 1000+ arrReturnElements[arrReturnElements.length] = arrNativeReturn[h];
 1001+ }
 1002+ }
 1003+ return arrReturnElements;
 1004+ }
 1005+ var arrElements = ( strTagName == '*' && oElm.all ) ? oElm.all : oElm.getElementsByTagName( strTagName );
 1006+ var arrRegExpClassNames = new Array();
 1007+ if( typeof oClassNames == 'object' ) {
 1008+ for( var i = 0; i < oClassNames.length; i++ ) {
 1009+ arrRegExpClassNames[arrRegExpClassNames.length] =
 1010+ new RegExp('(^|\\s)' + oClassNames[i].replace(/\-/g, '\\-') + '(\\s|$)');
 1011+ }
 1012+ } else {
 1013+ arrRegExpClassNames[arrRegExpClassNames.length] =
 1014+ new RegExp('(^|\\s)' + oClassNames.replace(/\-/g, '\\-') + '(\\s|$)');
 1015+ }
 1016+ var oElement;
 1017+ var bMatchesAll;
 1018+ for( var j = 0; j < arrElements.length; j++ ) {
 1019+ oElement = arrElements[j];
 1020+ bMatchesAll = true;
 1021+ for( var k = 0; k < arrRegExpClassNames.length; k++ ) {
 1022+ if( !arrRegExpClassNames[k].test( oElement.className ) ) {
 1023+ bMatchesAll = false;
 1024+ break;
 1025+ }
 1026+ }
 1027+ if( bMatchesAll ) {
 1028+ arrReturnElements[arrReturnElements.length] = oElement;
 1029+ }
 1030+ }
 1031+ return ( arrReturnElements );
 1032+ },
 1033+ 'redirectToFragment': function( fragment ) {
 1034+ var match = navigator.userAgent.match(/AppleWebKit\/(\d+)/);
 1035+ if ( match ) {
 1036+ var webKitVersion = parseInt( match[1] );
 1037+ if ( webKitVersion < 420 ) {
 1038+ // Released Safari w/ WebKit 418.9.1 messes up horribly
 1039+ // Nightlies of 420+ are ok
 1040+ return;
 1041+ }
 1042+ }
 1043+ if ( window.location.hash == '' ) {
 1044+ window.location.hash = fragment;
 1045+ // Mozilla needs to wait until after load, otherwise the window doesn't
 1046+ // scroll. See <https://bugzilla.mozilla.org/show_bug.cgi?id=516293>.
 1047+ // There's no obvious way to detect this programmatically, so we use
 1048+ // version-testing. If Firefox fixes the bug, they'll jump twice, but
 1049+ // better twice than not at all, so make the fix hit future versions as
 1050+ // well.
 1051+ if ( mw.legacy.is_gecko ) {
 1052+ addOnloadHook(function() {
 1053+ if ( window.location.hash == fragment ) {
 1054+ window.location.hash = fragment;
 1055+ }
 1056+ });
 1057+ }
 1058+ }
 1059+ }
 1060+} );
 1061+
 1062+/* Initialization */
 1063+
 1064+$( document ).ready( function() {
 1065+ if ( wgBreakFrames ) {
 1066+ // Un-trap us from framesets
 1067+ if ( window.top != window ) {
 1068+ window.top.location = window.location;
 1069+ }
 1070+ }
 1071+ // Special stylesheet links for Monobook only (see bug 14717)
 1072+ if ( typeof stylepath != 'undefined' && skin == 'monobook' ) {
 1073+ if ( mw.legacy.opera6_bugs ) {
 1074+ importStylesheetURI( stylepath + '/' + skin + '/Opera6Fixes.css' );
 1075+ } else if ( mw.legacy.opera7_bugs ) {
 1076+ importStylesheetURI( stylepath + '/' + skin + '/Opera7Fixes.css' );
 1077+ } else if ( mw.legacy.opera95_bugs ) {
 1078+ importStylesheetURI( stylepath + '/' + skin + '/Opera9Fixes.css' );
 1079+ } else if ( mw.legacy.ff2_bugs ) {
 1080+ importStylesheetURI( stylepath + '/' + skin + '/FF2Fixes.css' );
 1081+ }
 1082+ }
 1083+ if ( mw.legacy.ie6_bugs ) {
 1084+ importScriptURI( mw.legacy.stylepath + '/common/IEFixes.js' );
 1085+ }
 1086+ // NOTE: All skins should call runOnloadHook() at the end of html output, so this should be redundant - it's here
 1087+ // just in case
 1088+ runOnloadHook();
 1089+} );
 1090+
 1091+} )( jQuery, MediaWiki );
\ No newline at end of file
Property changes on: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.wikibits.js
___________________________________________________________________
Added: svn:eol-style
11092 + native
Index: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.edit.js
@@ -0,0 +1,264 @@
 2+/*
 3+ * Legacy emulation for the now depricated skins/common/edit.js
 4+ */
 5+
 6+( function( $, mw ) {
 7+
 8+/* Extension */
 9+
 10+$.extend( true, mw.legacy, {
 11+
 12+ /* Global Variables */
 13+
 14+ 'currentFocused': null,
 15+
 16+ /* Functions */
 17+
 18+ /**
 19+ * Generates the actual toolbar buttons with localized text we use it to avoid creating the toolbar
 20+ * where javascript is not enabled
 21+ */
 22+ 'addButton': function( imageFile, speedTip, tagOpen, tagClose, sampleText, imageId ) {
 23+ // Don't generate buttons for browsers which don't fully support it.
 24+ mw.legacy.mwEditButtons.push( {
 25+ 'imageId': imageId,
 26+ 'imageFile': imageFile,
 27+ 'speedTip': speedTip,
 28+ 'tagOpen': tagOpen,
 29+ 'tagClose': tagClose,
 30+ 'sampleText': sampleText
 31+ } );
 32+ },
 33+ /**
 34+ * Generates the actual toolbar buttons with localized text we use it to avoid creating the toolbar where JavaScript
 35+ * is not enabled
 36+ */
 37+ 'mwInsertEditButton': function( parent, item ) {
 38+ var $image = $( '<img />' )
 39+ .attr( {
 40+ 'width': 23,
 41+ 'height': 22,
 42+ 'class': 'mw-toolbar-editbutton',
 43+ 'id': item.imageId ? item.imageId : null,
 44+ 'src': = item.imageFile,
 45+ 'border': 0,
 46+ 'alt': item.speedTip,
 47+ 'title': item.speedTip
 48+ } )
 49+ .css( 'cursor', 'pointer' )
 50+ .click( function() {
 51+ mw.legacy.insertTags( item.tagOpen, item.tagClose, item.sampleText );
 52+ // Click tracking
 53+ if ( typeof $.trackAction != 'undefined' ) {
 54+ $.trackAction( 'oldedit.' + item.speedTip.replace( / /g, '-' ) );
 55+ }
 56+ return false;
 57+ } )
 58+ .appendTo( $( parent ) );
 59+ return true;
 60+ },
 61+ /**
 62+ * Sets up the toolbar
 63+ */
 64+ 'mwSetupToolbar': function() {
 65+ var $toolbar = $( '#toolbar' );
 66+ var $textbox = $( 'textarea' ).get( 0 );
 67+ if ( !$toolbar.length || !$textbox.length ) {
 68+ return false;
 69+ }
 70+ // Only check for selection capability if the textarea is visible - errors will occur otherwise - just because
 71+ // the textarea is not visible, doesn't mean we shouldn't build out the toolbar though - it might have been
 72+ // replaced with some other kind of control
 73+ if (
 74+ $textbox.is( ':visible' ) &&
 75+ !( document.selection && document.selection.createRange ) &&
 76+ textboxes[0].selectionStart === null
 77+ ) {
 78+ return false;
 79+ }
 80+ for ( var i = 0; i < mw.legacy.mwEditButtons.length; i++ ) {
 81+ mw.legacy.mwInsertEditButton( $toolbar, mw.legacy.mwEditButtons[i] );
 82+ }
 83+ for ( var i = 0; i < mw.legacy.mwCustomEditButtons.length; i++ ) {
 84+ mw.legacy.mwInsertEditButton( $toolbar, mw.legacy.mwCustomEditButtons[i] );
 85+ }
 86+ return true;
 87+ },
 88+ /**
 89+ * Apply tagOpen/tagClose to selection in textarea, use sampleText instead of selection if there is none
 90+ */
 91+ 'insertTags': function( tagOpen, tagClose, sampleText ) {
 92+ function checkSelectedText() {
 93+ if ( !selText ) {
 94+ selText = sampleText;
 95+ isSample = true;
 96+ } else if ( selText.charAt( selText.length - 1 ) == ' ' ) { // exclude ending space char
 97+ selText = selText.substring( 0, selText.length - 1 );
 98+ tagClose += ' ';
 99+ }
 100+ }
 101+ var currentFocused = $( mw.legacy.currentFocused );
 102+ if (
 103+ typeof $.fn.textSelection != 'undefined' &&
 104+ ( $currentFocused.name().toLowerCase() == 'iframe' || $currentFocused.attr( 'id' ) == 'wpTextbox1' )
 105+ ) {
 106+ $j( '#wpTextbox1' ).textSelection(
 107+ 'encapsulateSelection', { 'pre': tagOpen, 'peri': sampleText, 'post': tagClose }
 108+ );
 109+ return;
 110+ }
 111+ var $textarea;
 112+ if ( $( 'form[name=editform]' ) {
 113+ $textarea = $currentFocused;
 114+ } else {
 115+ // Some alternate form? take the first one we can find
 116+ $textarea = $( 'textarea' ).get( 0 );
 117+ }
 118+ var selText, isSample = false;
 119+ // Text selection implementation for IE and Opera
 120+ if ( document.selection && document.selection.createRange ) {
 121+ // Save window scroll position
 122+ if ( document.documentElement && document.documentElement.scrollTop ) {
 123+ var winScroll = document.documentElement.scrollTop
 124+ } else if ( document.body ) {
 125+ var winScroll = document.body.scrollTop;
 126+ }
 127+ // Get current selection
 128+ $textarea.focus();
 129+ var range = document.selection.createRange();
 130+ selText = range.text;
 131+ // Insert tags
 132+ checkSelectedText();
 133+ range.text = tagOpen + selText + tagClose;
 134+ // Mark sample text as selected
 135+ if ( isSample && range.moveStart ) {
 136+ if ( window.opera ) {
 137+ tagClose = tagClose.replace( /\n/g,'' );
 138+ }
 139+ range.moveStart( 'character', - tagClose.length - selText.length );
 140+ range.moveEnd( 'character', - tagClose.length );
 141+ }
 142+ range.select();
 143+ // Restore window scroll position
 144+ if ( document.documentElement && document.documentElement.scrollTop ) {
 145+ document.documentElement.scrollTop = winScroll;
 146+ } else if ( document.body ) {
 147+ document.body.scrollTop = winScroll;
 148+ }
 149+ }
 150+ // Text selection implementation for Mozilla, Chrome and Safari
 151+ else if ( $textarea[0].selectionStart || $textarea[0].selectionStart == '0' ) {
 152+ // Save textarea scroll position
 153+ var textScroll = $textarea.scrollTop;
 154+ // Get current selection
 155+ $textarea.focus();
 156+ var startPos = $textarea[0].selectionStart;
 157+ var endPos = $textarea[0].selectionEnd;
 158+ selText = $textarea.value.substring( startPos, endPos );
 159+ // Insert tags
 160+ checkSelectedText();
 161+ $textarea.val(
 162+ $textarea.val().substring( 0, startPos ) +
 163+ tagOpen + selText + tagClose +
 164+ $textarea.val().substring( endPos, $textarea.val().length )
 165+ );
 166+ // Set new selection
 167+ if ( isSample ) {
 168+ $textarea[0].selectionStart = startPos + tagOpen.length;
 169+ $textarea[0].selectionEnd = startPos + tagOpen.length + selText.length;
 170+ } else {
 171+ $textarea[0].selectionStart = startPos + tagOpen.length + selText.length + tagClose.length;
 172+ $textarea[0].selectionEnd = $textarea[0].selectionStart;
 173+ }
 174+ // Restore textarea scroll position
 175+ $textarea[0].scrollTop = textScroll;
 176+ }
 177+ },
 178+ /**
 179+ * Restore the edit box scroll state following a preview operation,
 180+ * and set up a form submission handler to remember this state
 181+ */
 182+ 'scrollEditBox': function() {
 183+ var $textbox = $( '#wpTextbox1' );
 184+ var $scrollTop = $( '#wpScrolltop' );
 185+ var $editForm = $( '#editform' );
 186+ if ( $editForm.length && $textbox.length && $scrollTop.length ) {
 187+ if ( scrollTop.val() ) {
 188+ $textbox.scrollTop = $scrollTop.val();
 189+ }
 190+ $editForm.submit( function() {
 191+ $scrollTop.val( $textbox.scrollTop );
 192+ } );
 193+ }
 194+ }
 195+} );
 196+
 197+/* Initialization */
 198+
 199+$( document ).ready( function() {
 200+ mw.legacy.scrollEditBox();
 201+ mw.legacy.mwSetupToolbar();
 202+ mw.legacy.currentFocused = $( '#wpTextbox1' ).get( 0 );
 203+ // http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html focus does not bubble normally, but using a
 204+ // trick we can do event delegation on the focus event on all text inputs to make the toolbox usable on all of them
 205+ $( '#editform' ).focus( function() {
 206+ $(this).each( function( e ) {
 207+ var elm = e.target || e.srcElement;
 208+ if ( !elm ) {
 209+ return;
 210+ }
 211+ var tagName = elm.tagName.toLowerCase();
 212+ var type = elm.type || '';
 213+ if ( tagName !== 'textarea' && tagName !== 'input' ) {
 214+ return;
 215+ }
 216+ if ( tagName === 'input' && type.toLowerCase() !== 'text' ) {
 217+ return;
 218+ }
 219+ mw.legacy.currentFocused = elm;
 220+ } );
 221+ } );
 222+ // HACK: make currentFocused work with the usability iframe - with proper focus detection support (HTML 5!) this'll
 223+ // be much cleaner
 224+ var $iframe = $j( '.wikiEditor-ui-text iframe' );
 225+ if ( $iframe.length > 0 ) {
 226+ $j( $iframe.get( 0 ).contentWindow.document )
 227+ // For IE
 228+ .add( $iframe.get( 0 ).contentWindow.document.body )
 229+ .focus( function() { mw.legacy.currentFocused = $iframe.get( 0 ); } );
 230+ }
 231+ // Make sure edit summary does not exceed byte limit
 232+ var $summary = $( '#wpSummary' );
 233+ if ( !$summary.length ) {
 234+ return;
 235+ }
 236+ // L must be capitalized in length
 237+ $summary.get( 0 ).maxLength = 250;
 238+ $summary.keypress( function( e ) {
 239+ // First check to see if this is actually a character key being pressed. Based on key-event info from
 240+ // http://unixpapa.com/js/key.html note === sign, if undefined, still could be a real key
 241+ if ( e.which === 0 || e.charCode === 0 || e.ctrlKey || e.altKey || e.metaKey ) {
 242+ // A special key (backspace, etc) so don't interefere.
 243+ return true;
 244+ }
 245+ // This basically figures out how many bytes a utf-16 string (which is what js sees) will take in utf-8 by
 246+ // replacing a 2 byte character with 2 *'s, etc, and counting that. Note, surogate (\uD800-\uDFFF) characters
 247+ // are counted as 2 bytes, since theres two of them and the actual character takes 4 bytes in utf-8 (2*2=4).
 248+ // Might not work perfectly in edge cases such as such as illegal sequences, but that should never happen.
 249+ len = summary.value
 250+ .replace(/[\u0080-\u07FF\uD800-\uDFFF]/g, '**')
 251+ .replace(/[\u0800-\uD7FF\uE000-\uFFFF]/g, '***')
 252+ .length;
 253+ // 247 as this doesn't count character about to be inserted.
 254+ if ( len > 247 ) {
 255+ if ( e.preventDefault ) {
 256+ e.preventDefault();
 257+ }
 258+ // IE
 259+ e.returnValue = false;
 260+ return false;
 261+ }
 262+ } );
 263+} );
 264+
 265+} )( jQuery, MediaWiki );
\ No newline at end of file
Property changes on: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.edit.js
___________________________________________________________________
Added: svn:eol-style
1266 + native
Index: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.mwsuggest.js
@@ -0,0 +1,1031 @@
 2+/*
 3+ * Legacy emulation for the now depricated skins/common/mwsuggest.js
 4+ *
 5+ * OpenSearch ajax suggestion engine for MediaWiki
 6+ *
 7+ * Uses core MediaWiki open search support to fetch suggestions and show them below search boxes and other inputs
 8+ *
 9+ * by Robert Stojnic (April 2008)
 10+ */
 11+
 12+( function( $, mw ) {
 13+
 14+/* Extension */
 15+
 16+$.extend( true, mw.legacy, {
 17+
 18+ /* Global Variables */
 19+
 20+ // search_box_id -> Results object
 21+ 'os_map': {},
 22+ // cached data, url -> json_text
 23+ 'os_cache': {},
 24+ // global variables for suggest_keypress
 25+ 'os_cur_keypressed': 0,
 26+ 'os_keypressed_count': 0,
 27+ // type: Timer
 28+ 'os_timer': null,
 29+ // tie mousedown/up events
 30+ 'os_mouse_pressed': false,
 31+ 'os_mouse_num': -1,
 32+ // if true, the last change was made by mouse (and not keyboard)
 33+ 'os_mouse_moved': false,
 34+ // delay between keypress and suggestion (in ms)
 35+ 'os_search_timeout': 250,
 36+ // these pairs of inputs/forms will be autoloaded at startup
 37+ 'os_autoload_inputs': new Array('searchInput', 'searchInput2', 'powerSearchText', 'searchText'),
 38+ 'os_autoload_forms': new Array('searchform', 'searchform2', 'powersearch', 'search' ),
 39+ // if we stopped the service
 40+ 'os_is_stopped': false,
 41+ // max lines to show in suggest table
 42+ 'os_max_lines_per_suggest': 7,
 43+ // number of steps to animate expansion/contraction of container width
 44+ 'os_animation_steps': 6,
 45+ // num of pixels of smallest step
 46+ 'os_animation_min_step': 2,
 47+ // delay between steps (in ms)
 48+ 'os_animation_delay': 30,
 49+ // max width of container in percent of normal size (1 == 100%)
 50+ 'os_container_max_width': 2,
 51+ // currently active animation timer
 52+ 'os_animation_timer': null,
 53+ // <datalist> is a new HTML5 element that allows you to manually supply
 54+ // suggestion lists and have them rendered according to the right platform
 55+ // conventions. However, the only shipping browser as of early 2010 is Opera,
 56+ // and that has a fatal problem: the suggestion lags behind what the user types
 57+ // by one keypress. (Reported as DSK-276870 to Opera's secret bug tracker.)
 58+ // The code here otherwise seems to work, though, so this can be flipped on
 59+ // (maybe with a UA check) when some browser has a better implementation.
 60+ // 'os_use_datalist': 'list' in document.createElement( 'input' ),
 61+ 'os_use_datalist': false,
 62+
 63+ /* Functions */
 64+
 65+ /**
 66+ * Timeout timer class that will fetch the results
 67+ */
 68+ 'os_Timer': function( id, r, query ) {
 69+ this.id = id;
 70+ this.r = r;
 71+ this.query = query;
 72+ },
 73+ /**
 74+ * Property class for single search box
 75+ */
 76+ 'os_Results': function( name, formname ) {
 77+ this.searchform = formname; // id of the searchform
 78+ this.searchbox = name; // id of the searchbox
 79+ this.container = name + 'Suggest'; // div that holds results
 80+ this.resultTable = name + 'Result'; // id base for the result table (+num = table row)
 81+ this.resultText = name + 'ResultText'; // id base for the spans within result tables (+num)
 82+ this.toggle = name + 'Toggle'; // div that has the toggle (enable/disable) link
 83+ this.query = null; // last processed query
 84+ this.results = null; // parsed titles
 85+ this.resultCount = 0; // number of results
 86+ this.original = null; // query that user entered
 87+ this.selected = -1; // which result is selected
 88+ this.containerCount = 0; // number of results visible in container
 89+ this.containerRow = 0; // height of result field in the container
 90+ this.containerTotal = 0; // total height of the container will all results
 91+ this.visible = false; // if container is visible
 92+ this.stayHidden = false; // don't try to show if lost focus
 93+ },
 94+ /**
 95+ * Timer user to animate expansion/contraction of container width
 96+ */
 97+ 'os_AnimationTimer': function( r, target ) {
 98+ this.r = r;
 99+ var current = document.getElementById(r.container).offsetWidth;
 100+ this.inc = Math.round( ( target - current ) / os_animation_steps );
 101+ if( this.inc < os_animation_min_step && this.inc >=0 ) {
 102+ this.inc = os_animation_min_step; // minimal animation step
 103+ }
 104+ if( this.inc > -os_animation_min_step && this.inc < 0 ) {
 105+ this.inc = -os_animation_min_step;
 106+ }
 107+ this.target = target;
 108+ },
 109+
 110+ /* Intialization Functions */
 111+
 112+ /**
 113+ * Initialization, call upon page onload
 114+ */
 115+ 'os_MWSuggestInit': function() {
 116+ for( i = 0; i < os_autoload_inputs.length; i++ ) {
 117+ var id = os_autoload_inputs[i];
 118+ var form = os_autoload_forms[i];
 119+ element = document.getElementById( id );
 120+ if( element != null ) {
 121+ os_initHandlers( id, form, element );
 122+ }
 123+ }
 124+ },
 125+ /**
 126+ * Init Result objects and event handlers
 127+ */
 128+ 'os_initHandlers': function( name, formname, element ) {
 129+ var r = new os_Results( name, formname );
 130+ var formElement = document.getElementById( formname );
 131+ if( !formElement ) {
 132+ // Older browsers (Opera 8) cannot get form elements
 133+ return;
 134+ }
 135+ // event handler
 136+ os_hookEvent( element, 'keyup', function( event ) { os_eventKeyup( event ); } );
 137+ os_hookEvent( element, 'keydown', function( event ) { os_eventKeydown( event ); } );
 138+ os_hookEvent( element, 'keypress', function( event ) { os_eventKeypress( event ); } );
 139+ if ( !os_use_datalist ) {
 140+ // These are needed for the div hack to hide it if the user blurs.
 141+ os_hookEvent( element, 'blur', function( event ) { os_eventBlur( event ); } );
 142+ os_hookEvent( element, 'focus', function( event ) { os_eventFocus( event ); } );
 143+ // We don't want browser auto-suggestions interfering with our div, but
 144+ // autocomplete must be on for datalist to work (at least in Opera
 145+ // 10.10).
 146+ element.setAttribute( 'autocomplete', 'off' );
 147+ }
 148+ // stopping handler
 149+ os_hookEvent( formElement, 'submit', function( event ) { return os_eventOnsubmit( event ); } );
 150+ os_map[name] = r;
 151+ // toggle link
 152+ if( document.getElementById( r.toggle ) == null ) {
 153+ // TODO: disable this while we figure out a way for this to work in all browsers
 154+ /* if( name == 'searchInput' ) {
 155+ // special case: place above the main search box
 156+ var t = os_createToggle( r, 'os-suggest-toggle' );
 157+ var searchBody = document.getElementById( 'searchBody' );
 158+ var first = searchBody.parentNode.firstChild.nextSibling.appendChild(t);
 159+ } else {
 160+ // default: place below search box to the right
 161+ var t = os_createToggle( r, 'os-suggest-toggle-def' );
 162+ var top = element.offsetTop + element.offsetHeight;
 163+ var left = element.offsetLeft + element.offsetWidth;
 164+ t.style.position = 'absolute';
 165+ t.style.top = top + 'px';
 166+ t.style.left = left + 'px';
 167+ element.parentNode.appendChild( t );
 168+ // only now width gets calculated, shift right
 169+ left -= t.offsetWidth;
 170+ t.style.left = left + 'px';
 171+ t.style.visibility = 'visible';
 172+ } */
 173+ }
 174+ },
 175+ 'os_hookEvent': function( element, hookName, hookFunct ) {
 176+ if ( element.addEventListener ) {
 177+ element.addEventListener( hookName, hookFunct, false );
 178+ } else if ( window.attachEvent ) {
 179+ element.attachEvent( 'on' + hookName, hookFunct );
 180+ }
 181+ },
 182+
 183+ /* Keyboard Event Functions */
 184+
 185+ /**
 186+ * Event handler that will fetch results on keyup
 187+ */
 188+ 'os_eventKeyup': function( e ) {
 189+ var targ = os_getTarget( e );
 190+ var r = os_map[targ.id];
 191+ if( r == null ) {
 192+ return; // not our event
 193+ }
 194+
 195+ // some browsers won't generate keypressed for arrow keys, catch it
 196+ if( os_keypressed_count == 0 ) {
 197+ os_processKey( r, os_cur_keypressed, targ );
 198+ }
 199+ var query = targ.value;
 200+ os_fetchResults( r, query, os_search_timeout );
 201+ },
 202+ /**
 203+ * Catch arrows up/down and escape to hide the suggestions
 204+ */
 205+ 'os_processKey': function( r, keypressed, targ ) {
 206+ if ( keypressed == 40 && !r.visible && os_timer == null ) {
 207+ // If the user hits the down arrow, fetch results immediately if none
 208+ // are already displayed.
 209+ r.query = '';
 210+ os_fetchResults( r, targ.value, 0 );
 211+ }
 212+ // Otherwise, if we're not using datalist, we need to handle scrolling and
 213+ // so on.
 214+ if ( os_use_datalist ) {
 215+ return;
 216+ }
 217+ if ( keypressed == 40 ) { // Arrow Down
 218+ if ( r.visible ) {
 219+ os_changeHighlight( r, r.selected, r.selected + 1, true );
 220+ }
 221+ } else if ( keypressed == 38 ) { // Arrow Up
 222+ if ( r.visible ) {
 223+ os_changeHighlight( r, r.selected, r.selected - 1, true );
 224+ }
 225+ } else if( keypressed == 27 ) { // Escape
 226+ document.getElementById( r.searchbox ).value = r.original;
 227+ r.query = r.original;
 228+ os_hideResults( r );
 229+ } else if( r.query != document.getElementById( r.searchbox ).value ) {
 230+ // os_hideResults( r ); // don't show old suggestions
 231+ }
 232+ },
 233+ /**
 234+ * When keys is held down use a timer to output regular events
 235+ */
 236+ 'os_eventKeypress': function( e ) {
 237+ var targ = os_getTarget( e );
 238+ var r = os_map[targ.id];
 239+ if( r == null ) {
 240+ return; // not our event
 241+ }
 242+
 243+ var keypressed = os_cur_keypressed;
 244+
 245+ os_keypressed_count++;
 246+ os_processKey( r, keypressed, targ );
 247+ },
 248+ /**
 249+ * Catch the key code (Firefox bug)
 250+ */
 251+ 'os_eventKeydown': function( e ) {
 252+ if ( !e ) {
 253+ e = window.event;
 254+ }
 255+ var targ = os_getTarget( e );
 256+ var r = os_map[targ.id];
 257+ if( r == null ) {
 258+ return; // not our event
 259+ }
 260+
 261+ os_mouse_moved = false;
 262+
 263+ os_cur_keypressed = ( e.keyCode == undefined ) ? e.which : e.keyCode;
 264+ os_keypressed_count = 0;
 265+ },
 266+ /**
 267+ * When the form is submitted hide everything, cancel updates...
 268+ */
 269+ 'os_eventOnsubmit': function( e ) {
 270+ var targ = os_getTarget( e );
 271+
 272+ os_is_stopped = true;
 273+ // kill timed requests
 274+ if( os_timer != null && os_timer.id != null ) {
 275+ clearTimeout( os_timer.id );
 276+ os_timer = null;
 277+ }
 278+ // Hide all suggestions
 279+ for( i = 0; i < os_autoload_inputs.length; i++ ) {
 280+ var r = os_map[os_autoload_inputs[i]];
 281+ if( r != null ) {
 282+ var b = document.getElementById( r.searchform );
 283+ if( b != null && b == targ ) {
 284+ // set query value so the handler won't try to fetch additional results
 285+ r.query = document.getElementById( r.searchbox ).value;
 286+ }
 287+ os_hideResults( r );
 288+ }
 289+ }
 290+ return true;
 291+ },
 292+ /**
 293+ * Hide results from the user, either making the div visibility=hidden or detaching the datalist from the input.
 294+ */
 295+ 'os_hideResults': function( r ) {
 296+ if ( os_use_datalist ) {
 297+ document.getElementById( r.searchbox ).setAttribute( 'list', '' );
 298+ } else {
 299+ var c = document.getElementById( r.container );
 300+ if ( c != null ) {
 301+ c.style.visibility = 'hidden';
 302+ }
 303+ }
 304+ r.visible = false;
 305+ r.selected = -1;
 306+ },
 307+ 'os_decodeValue': function( value ) {
 308+ if ( decodeURIComponent ) {
 309+ return decodeURIComponent( value );
 310+ }
 311+ if( unescape ) {
 312+ return unescape( value );
 313+ }
 314+ return null;
 315+ },
 316+ 'os_encodeQuery': function( value ) {
 317+ if ( encodeURIComponent ) {
 318+ return encodeURIComponent( value );
 319+ }
 320+ if( escape ) {
 321+ return escape( value );
 322+ }
 323+ return null;
 324+ },
 325+ /**
 326+ * Handles data from XMLHttpRequest, and updates the suggest results
 327+ */
 328+ 'os_updateResults': function( r, query, text, cacheKey ) {
 329+ os_cache[cacheKey] = text;
 330+ r.query = query;
 331+ r.original = query;
 332+ if( text == '' ) {
 333+ r.results = null;
 334+ r.resultCount = 0;
 335+ os_hideResults( r );
 336+ } else {
 337+ try {
 338+ var p = eval( '(' + text + ')' ); // simple json parse, could do a safer one
 339+ if( p.length < 2 || p[1].length == 0 ) {
 340+ r.results = null;
 341+ r.resultCount = 0;
 342+ os_hideResults( r );
 343+ return;
 344+ }
 345+ if ( os_use_datalist ) {
 346+ os_setupDatalist( r, p[1] );
 347+ } else {
 348+ os_setupDiv( r, p[1] );
 349+ }
 350+ } catch( e ) {
 351+ // bad response from server or such
 352+ os_hideResults( r );
 353+ os_cache[cacheKey] = null;
 354+ }
 355+ }
 356+ },
 357+ /**
 358+ * Create and populate a <datalist>.
 359+ *
 360+ * @param r os_Result object
 361+ * @param results Array of the new results to replace existing ones
 362+ */
 363+ 'os_setupDatalist': function( r, results ) {
 364+ var s = document.getElementById( r.searchbox );
 365+ var c = document.getElementById( r.container );
 366+ if ( c == null ) {
 367+ c = document.createElement( 'datalist' );
 368+ c.setAttribute( 'id', r.container );
 369+ document.body.appendChild( c );
 370+ } else {
 371+ c.innerHTML = '';
 372+ }
 373+ s.setAttribute( 'list', r.container );
 374+
 375+ r.results = new Array();
 376+ r.resultCount = results.length;
 377+ r.visible = true;
 378+ for ( i = 0; i < results.length; i++ ) {
 379+ var title = os_decodeValue( results[i] );
 380+ var opt = document.createElement( 'option' );
 381+ opt.value = title;
 382+ r.results[i] = title;
 383+ c.appendChild( opt );
 384+ }
 385+ },
 386+ /**
 387+ * Fetch namespaces from checkboxes or hidden fields in the search form, if none defined use wgSearchNamespaces
 388+ * global
 389+ */
 390+ 'os_getNamespaces': function( r ) {
 391+ var namespaces = '';
 392+ var elements = document.forms[r.searchform].elements;
 393+ for( i = 0; i < elements.length; i++ ) {
 394+ var name = elements[i].name;
 395+ if( typeof name != 'undefined' && name.length > 2 && name[0] == 'n' &&
 396+ name[1] == 's' && (
 397+ ( elements[i].type == 'checkbox' && elements[i].checked ) ||
 398+ ( elements[i].type == 'hidden' && elements[i].value == '1' )
 399+ )
 400+ ) {
 401+ if( namespaces != '' ) {
 402+ namespaces += '|';
 403+ }
 404+ namespaces += name.substring( 2 );
 405+ }
 406+ }
 407+ if( namespaces == '' ) {
 408+ namespaces = wgSearchNamespaces.join('|');
 409+ }
 410+ return namespaces;
 411+ },
 412+ /**
 413+ * Update results if user hasn't already typed something else
 414+ */
 415+ 'os_updateIfRelevant': function( r, query, text, cacheKey ) {
 416+ var t = document.getElementById( r.searchbox );
 417+ if( t != null && t.value == query ) { // check if response is still relevant
 418+ os_updateResults( r, query, text, cacheKey );
 419+ }
 420+ r.query = query;
 421+ },
 422+ /**
 423+ * Fetch results after some timeout
 424+ */
 425+ 'os_delayedFetch': function() {
 426+ if( os_timer == null ) {
 427+ return;
 428+ }
 429+ var r = os_timer.r;
 430+ var query = os_timer.query;
 431+ os_timer = null;
 432+ var path = wgMWSuggestTemplate.replace( '{namespaces}', os_getNamespaces( r ) )
 433+ .replace( '{dbname}', wgDBname )
 434+ .replace( '{searchTerms}', os_encodeQuery( query ) );
 435+ // try to get from cache, if not fetch using ajax
 436+ var cached = os_cache[path];
 437+ if( cached != null && cached != undefined ) {
 438+ os_updateIfRelevant( r, query, cached, path );
 439+ } else {
 440+ var xmlhttp = sajax_init_object();
 441+ if( xmlhttp ) {
 442+ try {
 443+ xmlhttp.open( 'GET', path, true );
 444+ xmlhttp.onreadystatechange = function() {
 445+ if ( xmlhttp.readyState == 4 && typeof os_updateIfRelevant == 'function' ) {
 446+ os_updateIfRelevant( r, query, xmlhttp.responseText, path );
 447+ }
 448+ };
 449+ xmlhttp.send( null );
 450+ } catch ( e ) {
 451+ if ( window.location.hostname == 'localhost' ) {
 452+ alert( 'Your browser blocks XMLHttpRequest to "localhost", try using a real hostname for development/testing.' );
 453+ }
 454+ throw e;
 455+ }
 456+ }
 457+ }
 458+ },
 459+ /**
 460+ * Init timed update via os_delayedUpdate()
 461+ */
 462+ 'os_fetchResults': function( r, query, timeout ) {
 463+ if( query == '' ) {
 464+ r.query = '';
 465+ os_hideResults( r );
 466+ return;
 467+ } else if( query == r.query ) {
 468+ return; // no change
 469+ }
 470+
 471+ os_is_stopped = false; // make sure we're running
 472+
 473+ // cancel any pending fetches
 474+ if( os_timer != null && os_timer.id != null ) {
 475+ clearTimeout( os_timer.id );
 476+ }
 477+ // schedule delayed fetching of results
 478+ if( timeout != 0 ) {
 479+ os_timer = new os_Timer( setTimeout( 'os_delayedFetch()', timeout ), r, query );
 480+ } else {
 481+ os_timer = new os_Timer( null, r, query );
 482+ os_delayedFetch(); // do it now!
 483+ }
 484+ },
 485+ /**
 486+ * Find event target
 487+ */
 488+ 'os_getTarget': function( e ) {
 489+ if ( !e ) {
 490+ e = window.event;
 491+ }
 492+ if ( e.target ) {
 493+ return e.target;
 494+ } else if ( e.srcElement ) {
 495+ return e.srcElement;
 496+ } else {
 497+ return null;
 498+ }
 499+ },
 500+ /**
 501+ * Check if x is a valid integer
 502+ */
 503+ 'os_isNumber': function( x ) {
 504+ if( x == '' || isNaN( x ) ) {
 505+ return false;
 506+ }
 507+ for( var i = 0; i < x.length; i++ ) {
 508+ var c = x.charAt( i );
 509+ if( !( c >= '0' && c <= '9' ) ) {
 510+ return false;
 511+ }
 512+ }
 513+ return true;
 514+ },
 515+ /**
 516+ * Call this to enable suggestions on input (id=inputId), on a form (name=formName)
 517+ */
 518+ 'os_enableSuggestionsOn': function( inputId, formName ) {
 519+ os_initHandlers( inputId, formName, document.getElementById( inputId ) );
 520+ },
 521+ /**
 522+ * Call this to disable suggestios on input box (id=inputId)
 523+ */
 524+ 'os_disableSuggestionsOn': function( inputId ) {
 525+ r = os_map[inputId];
 526+ if( r != null ) {
 527+ // cancel/hide results
 528+ os_timer = null;
 529+ os_hideResults( r );
 530+ // turn autocomplete on !
 531+ document.getElementById( inputId ).setAttribute( 'autocomplete', 'on' );
 532+ // remove descriptor
 533+ os_map[inputId] = null;
 534+ }
 535+
 536+ // Remove the element from the os_autoload_* arrays
 537+ var index = os_autoload_inputs.indexOf( inputId );
 538+ if ( index >= 0 ) {
 539+ os_autoload_inputs[index] = os_autoload_forms[index] = '';
 540+ }
 541+ },
 542+
 543+ /* Div-only Functions */
 544+
 545+ /**
 546+ * Event: loss of focus of input box
 547+ */
 548+ 'os_eventBlur': function( e ) {
 549+ var targ = os_getTarget( e );
 550+ var r = os_map[targ.id];
 551+ if( r == null ) {
 552+ return; // not our event
 553+ }
 554+ if( !os_mouse_pressed ) {
 555+ os_hideResults( r );
 556+ // force canvas to stay hidden
 557+ r.stayHidden = true;
 558+ // cancel any pending fetches
 559+ if( os_timer != null && os_timer.id != null ) {
 560+ clearTimeout( os_timer.id );
 561+ }
 562+ os_timer = null;
 563+ }
 564+ },
 565+ /**
 566+ * Event: focus (catch only when stopped)
 567+ */
 568+ 'os_eventFocus': function( e ) {
 569+ var targ = os_getTarget( e );
 570+ var r = os_map[targ.id];
 571+ if( r == null ) {
 572+ return; // not our event
 573+ }
 574+ r.stayHidden = false;
 575+ },
 576+ /**
 577+ * Create and populate a <div>, for non-<datalist>-supporting browsers.
 578+ *
 579+ * @param r os_Result object
 580+ * @param results Array of the new results to replace existing ones
 581+ */
 582+ 'os_setupDiv': function( r, results ) {
 583+ var c = document.getElementById( r.container );
 584+ if ( c == null ) {
 585+ c = os_createContainer( r );
 586+ }
 587+ c.innerHTML = os_createResultTable( r, results );
 588+ // init container table sizes
 589+ var t = document.getElementById( r.resultTable );
 590+ r.containerTotal = t.offsetHeight;
 591+ r.containerRow = t.offsetHeight / r.resultCount;
 592+ os_fitContainer( r );
 593+ os_trimResultText( r );
 594+ os_showResults( r );
 595+ },
 596+ /**
 597+ * Create the result table to be placed in the container div
 598+ */
 599+ 'os_createResultTable': function( r, results ) {
 600+ var c = document.getElementById( r.container );
 601+ var width = c.offsetWidth - os_operaWidthFix( c.offsetWidth );
 602+ var html = '<table class="os-suggest-results" id="' + r.resultTable + '" style="width: ' + width + 'px;">';
 603+ r.results = new Array();
 604+ r.resultCount = results.length;
 605+ for( i = 0; i < results.length; i++ ) {
 606+ var title = os_decodeValue( results[i] );
 607+ r.results[i] = title;
 608+ html += '<tr><td class="os-suggest-result" id="' + r.resultTable + i + '"><span id="' + r.resultText + i + '">' + title + '</span></td></tr>';
 609+ }
 610+ html += '</table>';
 611+ return html;
 612+ },
 613+ /**
 614+ * Show results div
 615+ */
 616+ 'os_showResults': function( r ) {
 617+ if( os_is_stopped ) {
 618+ return;
 619+ }
 620+ if( r.stayHidden ) {
 621+ return;
 622+ }
 623+ os_fitContainer( r );
 624+ var c = document.getElementById( r.container );
 625+ r.selected = -1;
 626+ if( c != null ) {
 627+ c.scrollTop = 0;
 628+ c.style.visibility = 'visible';
 629+ r.visible = true;
 630+ }
 631+ },
 632+ 'os_operaWidthFix': function( x ) {
 633+ // For browsers that don't understand overflow-x, estimate scrollbar width
 634+ if( typeof document.body.style.overflowX != 'string' ) {
 635+ return 30;
 636+ }
 637+ return 0;
 638+ },
 639+
 640+ /* Brower-dependent Functions */
 641+
 642+ 'f_clientWidth': function() {
 643+ return f_filterResults(
 644+ window.innerWidth ? window.innerWidth : 0,
 645+ document.documentElement ? document.documentElement.clientWidth : 0,
 646+ document.body ? document.body.clientWidth : 0
 647+ );
 648+ },
 649+ 'f_clientHeight': function() {
 650+ return f_filterResults(
 651+ window.innerHeight ? window.innerHeight : 0,
 652+ document.documentElement ? document.documentElement.clientHeight : 0,
 653+ document.body ? document.body.clientHeight : 0
 654+ );
 655+ },
 656+ 'f_scrollLeft': function() {
 657+ return f_filterResults(
 658+ window.pageXOffset ? window.pageXOffset : 0,
 659+ document.documentElement ? document.documentElement.scrollLeft : 0,
 660+ document.body ? document.body.scrollLeft : 0
 661+ );
 662+ },
 663+ 'f_scrollTop': function() {
 664+ return f_filterResults(
 665+ window.pageYOffset ? window.pageYOffset : 0,
 666+ document.documentElement ? document.documentElement.scrollTop : 0,
 667+ document.body ? document.body.scrollTop : 0
 668+ );
 669+ },
 670+ 'f_filterResults': function( n_win, n_docel, n_body ) {
 671+ var n_result = n_win ? n_win : 0;
 672+ if ( n_docel && ( !n_result || ( n_result > n_docel ) ) ) {
 673+ n_result = n_docel;
 674+ }
 675+ return n_body && ( !n_result || ( n_result > n_body ) ) ? n_body : n_result;
 676+ },
 677+ /**
 678+ * Get the height available for the results container
 679+ */
 680+ 'os_availableHeight': function( r ) {
 681+ var absTop = document.getElementById( r.container ).style.top;
 682+ var px = absTop.lastIndexOf( 'px' );
 683+ if( px > 0 ) {
 684+ absTop = absTop.substring( 0, px );
 685+ }
 686+ return f_clientHeight() - ( absTop - f_scrollTop() );
 687+ },
 688+ /**
 689+ * Get element absolute position {left,top}
 690+ */
 691+ 'os_getElementPosition': function( elemID ) {
 692+ var offsetTrail = document.getElementById( elemID );
 693+ var offsetLeft = 0;
 694+ var offsetTop = 0;
 695+ while ( offsetTrail ) {
 696+ offsetLeft += offsetTrail.offsetLeft;
 697+ offsetTop += offsetTrail.offsetTop;
 698+ offsetTrail = offsetTrail.offsetParent;
 699+ }
 700+ if ( navigator.userAgent.indexOf('Mac') != -1 && typeof document.body.leftMargin != 'undefined' ) {
 701+ offsetLeft += document.body.leftMargin;
 702+ offsetTop += document.body.topMargin;
 703+ }
 704+ return { left:offsetLeft, top:offsetTop };
 705+ },
 706+ /**
 707+ * Create the container div that will hold the suggested titles
 708+ */
 709+ 'os_createContainer': function( r ) {
 710+ var c = document.createElement( 'div' );
 711+ var s = document.getElementById( r.searchbox );
 712+ var pos = os_getElementPosition( r.searchbox );
 713+ var left = pos.left;
 714+ var top = pos.top + s.offsetHeight;
 715+ c.className = 'os-suggest';
 716+ c.setAttribute( 'id', r.container );
 717+ document.body.appendChild( c );
 718+
 719+ // dynamically generated style params
 720+ // IE workaround, cannot explicitely set "style" attribute
 721+ c = document.getElementById( r.container );
 722+ c.style.top = top + 'px';
 723+ c.style.left = left + 'px';
 724+ c.style.width = s.offsetWidth + 'px';
 725+
 726+ // mouse event handlers
 727+ c.onmouseover = function( event ) { os_eventMouseover( r.searchbox, event ); };
 728+ c.onmousemove = function( event ) { os_eventMousemove( r.searchbox, event ); };
 729+ c.onmousedown = function( event ) { return os_eventMousedown( r.searchbox, event ); };
 730+ c.onmouseup = function( event ) { os_eventMouseup( r.searchbox, event ); };
 731+ return c;
 732+ },
 733+ /**
 734+ * Change container height to fit to screen
 735+ */
 736+ 'os_fitContainer': function( r ) {
 737+ var c = document.getElementById( r.container );
 738+ var h = os_availableHeight( r ) - 20;
 739+ var inc = r.containerRow;
 740+ h = parseInt( h / inc ) * inc;
 741+ if( h < ( 2 * inc ) && r.resultCount > 1 ) { // min: two results
 742+ h = 2 * inc;
 743+ }
 744+ if( ( h / inc ) > os_max_lines_per_suggest ) {
 745+ h = inc * os_max_lines_per_suggest;
 746+ }
 747+ if( h < r.containerTotal ) {
 748+ c.style.height = h + 'px';
 749+ r.containerCount = parseInt( Math.round( h / inc ) );
 750+ } else {
 751+ c.style.height = r.containerTotal + 'px';
 752+ r.containerCount = r.resultCount;
 753+ }
 754+ },
 755+ /**
 756+ * If some entries are longer than the box, replace text with "..."
 757+ */
 758+ 'os_trimResultText': function( r ) {
 759+ // find max width, first see if we could expand the container to fit it
 760+ var maxW = 0;
 761+ for( var i = 0; i < r.resultCount; i++ ) {
 762+ var e = document.getElementById( r.resultText + i );
 763+ if( e.offsetWidth > maxW ) {
 764+ maxW = e.offsetWidth;
 765+ }
 766+ }
 767+ var w = document.getElementById( r.container ).offsetWidth;
 768+ var fix = 0;
 769+ if( r.containerCount < r.resultCount ) {
 770+ fix = 20; // give 20px for scrollbar
 771+ } else {
 772+ fix = os_operaWidthFix( w );
 773+ }
 774+ if( fix < 4 ) {
 775+ fix = 4; // basic padding
 776+ }
 777+ maxW += fix;
 778+
 779+ // resize container to fit more data if permitted
 780+ var normW = document.getElementById( r.searchbox ).offsetWidth;
 781+ var prop = maxW / normW;
 782+ if( prop > os_container_max_width ) {
 783+ prop = os_container_max_width;
 784+ } else if( prop < 1 ) {
 785+ prop = 1;
 786+ }
 787+ var newW = Math.round( normW * prop );
 788+ if( w != newW ) {
 789+ w = newW;
 790+ if( os_animation_timer != null ) {
 791+ clearInterval( os_animation_timer.id );
 792+ }
 793+ os_animation_timer = new os_AnimationTimer( r, w );
 794+ os_animation_timer.id = setInterval( 'os_animateChangeWidth()', os_animation_delay );
 795+ w -= fix; // this much is reserved
 796+ }
 797+
 798+ // trim results
 799+ if( w < 10 ) {
 800+ return;
 801+ }
 802+ for( var i = 0; i < r.resultCount; i++ ) {
 803+ var e = document.getElementById( r.resultText + i );
 804+ var replace = 1;
 805+ var lastW = e.offsetWidth + 1;
 806+ var iteration = 0;
 807+ var changedText = false;
 808+ while( e.offsetWidth > w && ( e.offsetWidth < lastW || iteration < 2 ) ) {
 809+ changedText = true;
 810+ lastW = e.offsetWidth;
 811+ var l = e.innerHTML;
 812+ e.innerHTML = l.substring( 0, l.length - replace ) + '...';
 813+ iteration++;
 814+ replace = 4; // how many chars to replace
 815+ }
 816+ if( changedText ) {
 817+ // show hint for trimmed titles
 818+ document.getElementById( r.resultTable + i ).setAttribute( 'title', r.results[i] );
 819+ }
 820+ }
 821+ },
 822+ /**
 823+ * Invoked on timer to animate change in container width
 824+ */
 825+ 'os_animateChangeWidth': function() {
 826+ var r = os_animation_timer.r;
 827+ var c = document.getElementById( r.container );
 828+ var w = c.offsetWidth;
 829+ var normW = document.getElementById( r.searchbox ).offsetWidth;
 830+ var normL = os_getElementPosition( r.searchbox ).left;
 831+ var inc = os_animation_timer.inc;
 832+ var target = os_animation_timer.target;
 833+ var nw = w + inc;
 834+ if( ( inc > 0 && nw >= target ) || ( inc <= 0 && nw <= target ) ) {
 835+ // finished !
 836+ c.style.width = target + 'px';
 837+ clearInterval( os_animation_timer.id );
 838+ os_animation_timer = null;
 839+ } else {
 840+ // in-progress
 841+ c.style.width = nw + 'px';
 842+ if( document.documentElement.dir == 'rtl' ) {
 843+ c.style.left = ( normL + normW + ( target - nw ) - os_animation_timer.target - 1 ) + 'px';
 844+ }
 845+ }
 846+ },
 847+ /**
 848+ * Change the highlighted row (i.e. suggestion), from position cur to next
 849+ */
 850+ 'os_changeHighlight': function( r, cur, next, updateSearchBox ) {
 851+ if ( next >= r.resultCount ) {
 852+ next = r.resultCount - 1;
 853+ }
 854+ if ( next < -1 ) {
 855+ next = -1;
 856+ }
 857+ r.selected = next;
 858+ if ( cur == next ) {
 859+ return; // nothing to do.
 860+ }
 861+
 862+ if( cur >= 0 ) {
 863+ var curRow = document.getElementById( r.resultTable + cur );
 864+ if( curRow != null ) {
 865+ curRow.className = 'os-suggest-result';
 866+ }
 867+ }
 868+ var newText;
 869+ if( next >= 0 ) {
 870+ var nextRow = document.getElementById( r.resultTable + next );
 871+ if( nextRow != null ) {
 872+ nextRow.className = os_HighlightClass();
 873+ }
 874+ newText = r.results[next];
 875+ } else {
 876+ newText = r.original;
 877+ }
 878+
 879+ // adjust the scrollbar if any
 880+ if( r.containerCount < r.resultCount ) {
 881+ var c = document.getElementById( r.container );
 882+ var vStart = c.scrollTop / r.containerRow;
 883+ var vEnd = vStart + r.containerCount;
 884+ if( next < vStart ) {
 885+ c.scrollTop = next * r.containerRow;
 886+ } else if( next >= vEnd ) {
 887+ c.scrollTop = ( next - r.containerCount + 1 ) * r.containerRow;
 888+ }
 889+ }
 890+
 891+ // update the contents of the search box
 892+ if( updateSearchBox ) {
 893+ os_updateSearchQuery( r, newText );
 894+ }
 895+ },
 896+ 'os_HighlightClass': function() {
 897+ var match = navigator.userAgent.match(/AppleWebKit\/(\d+)/);
 898+ if ( match ) {
 899+ var webKitVersion = parseInt( match[1] );
 900+ if ( webKitVersion < 523 ) {
 901+ // CSS system highlight colors broken on old Safari
 902+ // https://bugs.webkit.org/show_bug.cgi?id=6129
 903+ // Safari 3.0.4, 3.1 known ok
 904+ return 'os-suggest-result-hl-webkit';
 905+ }
 906+ }
 907+ return 'os-suggest-result-hl';
 908+ },
 909+ 'os_updateSearchQuery': function( r, newText ) {
 910+ document.getElementById( r.searchbox ).value = newText;
 911+ r.query = newText;
 912+ },
 913+
 914+ /* Mouse Event Functions */
 915+
 916+ /**
 917+ * Mouse over the container
 918+ */
 919+ 'os_eventMouseover': function( srcId, e ) {
 920+ var targ = os_getTarget( e );
 921+ var r = os_map[srcId];
 922+ if( r == null || !os_mouse_moved ) {
 923+ return; // not our event
 924+ }
 925+ var num = os_getNumberSuffix( targ.id );
 926+ if( num >= 0 ) {
 927+ os_changeHighlight( r, r.selected, num, false );
 928+ }
 929+ },
 930+ /**
 931+ * Get row where the event occured (from its id)
 932+ */
 933+ 'os_getNumberSuffix': function( id ) {
 934+ var num = id.substring( id.length - 2 );
 935+ if( !( num.charAt( 0 ) >= '0' && num.charAt( 0 ) <= '9' ) ) {
 936+ num = num.substring( 1 );
 937+ }
 938+ if( os_isNumber( num ) ) {
 939+ return parseInt( num );
 940+ } else {
 941+ return -1;
 942+ }
 943+ },
 944+ /**
 945+ * Save mouse move as last action
 946+ */
 947+ 'os_eventMousemove': function( srcId, e ) {
 948+ os_mouse_moved = true;
 949+ },
 950+ /**
 951+ * Mouse button held down, register possible click
 952+ */
 953+ 'os_eventMousedown': function( srcId, e ) {
 954+ var targ = os_getTarget( e );
 955+ var r = os_map[srcId];
 956+ if( r == null ) {
 957+ return; // not our event
 958+ }
 959+ var num = os_getNumberSuffix( targ.id );
 960+
 961+ os_mouse_pressed = true;
 962+ if( num >= 0 ) {
 963+ os_mouse_num = num;
 964+ // os_updateSearchQuery( r, r.results[num] );
 965+ }
 966+ // keep the focus on the search field
 967+ document.getElementById( r.searchbox ).focus();
 968+
 969+ return false; // prevents selection
 970+ },
 971+ /**
 972+ * Mouse button released, check for click on some row
 973+ */
 974+ 'os_eventMouseup': function( srcId, e ) {
 975+ var targ = os_getTarget( e );
 976+ var r = os_map[srcId];
 977+ if( r == null ) {
 978+ return; // not our event
 979+ }
 980+ var num = os_getNumberSuffix( targ.id );
 981+
 982+ if( num >= 0 && os_mouse_num == num ) {
 983+ os_updateSearchQuery( r, r.results[num] );
 984+ os_hideResults( r );
 985+ document.getElementById( r.searchform ).submit();
 986+ }
 987+ os_mouse_pressed = false;
 988+ // keep the focus on the search field
 989+ document.getElementById( r.searchbox ).focus();
 990+ },
 991+ /**
 992+ * Return the span element that contains the toggle link (dead code?)
 993+ */
 994+ 'os_createToggle': function( r, className ) {
 995+ var t = document.createElement( 'span' );
 996+ t.className = className;
 997+ t.setAttribute( 'id', r.toggle );
 998+ var link = document.createElement( 'a' );
 999+ link.setAttribute( 'href', 'javascript:void(0);' );
 1000+ link.onclick = function() { os_toggle( r.searchbox, r.searchform ); };
 1001+ var msg = document.createTextNode( wgMWSuggestMessages[0] );
 1002+ link.appendChild( msg );
 1003+ t.appendChild( link );
 1004+ return t;
 1005+ },
 1006+ /**
 1007+ * Call when user clicks on some of the toggle links (dead code?)
 1008+ */
 1009+ 'os_toggle': function( inputId, formName ) {
 1010+ r = os_map[inputId];
 1011+ var msg = '';
 1012+ if( r == null ) {
 1013+ os_enableSuggestionsOn( inputId, formName );
 1014+ r = os_map[inputId];
 1015+ msg = wgMWSuggestMessages[0];
 1016+ } else{
 1017+ os_disableSuggestionsOn( inputId, formName );
 1018+ msg = wgMWSuggestMessages[1];
 1019+ }
 1020+ // change message
 1021+ var link = document.getElementById( r.toggle ).firstChild;
 1022+ link.replaceChild( document.createTextNode( msg ), link.firstChild );
 1023+ }
 1024+} );
 1025+
 1026+/* Initialization */
 1027+
 1028+$( document ).ready( function() {
 1029+ mw.legacy.os_MWSuggestInit();
 1030+} );
 1031+
 1032+} )( jQuery, MediaWiki );
\ No newline at end of file
Property changes on: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.mwsuggest.js
___________________________________________________________________
Added: svn:eol-style
11033 + native
Index: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.htmlform.js
@@ -0,0 +1,50 @@
 2+/*
 3+ * Legacy emulation for the now depricated skins/common/htmlform.js
 4+ */
 5+
 6+( function( $, mw ) {
 7+
 8+/* Extension */
 9+
 10+$.extend( true, mw.legacy, {
 11+
 12+ /* Global Variables */
 13+
 14+ 'htmlforms': {
 15+ 'selectOrOtherSelectChanged': function( e ) {
 16+ var select;
 17+ if ( !e ) {
 18+ e = window.event;
 19+ }
 20+ if ( e.target ) {
 21+ select = e.target;
 22+ } else if ( e.srcElement ) {
 23+ select = e.srcElement;
 24+ }
 25+ // Defeat Safari bug
 26+ if ( select.nodeType == 3 ) {
 27+ select = select.parentNode;
 28+ }
 29+ var id = select.id;
 30+ var textbox = document.getElementById( id + '-other' );
 31+ if ( select.value == 'other' ) {
 32+ textbox.disabled = false;
 33+ } else {
 34+ textbox.disabled = true;
 35+ }
 36+ }
 37+ }
 38+} );
 39+
 40+/* Initialization */
 41+
 42+$( document ).ready( function() {
 43+ // Find select-or-other fields
 44+ $( 'select .mw-htmlform-select-or-other' ).each( function() {
 45+ $(this).change( function() { mw.legacy.htmlforms.selectOrOtherSelectChanged(); } );
 46+ // Use a fake event to update it.
 47+ mw.legacy.htmlforms.selectOrOtherSelectChanged( { 'target': $(this).get( 0 ) } );
 48+ } );
 49+} );
 50+
 51+} )( jQuery, MediaWiki );
\ No newline at end of file
Property changes on: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.htmlform.js
___________________________________________________________________
Added: svn:eol-style
152 + native
Index: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.rightclickedit.js
@@ -0,0 +1,65 @@
 2+/*
 3+ * Legacy emulation for the now depricated skins/common/rightclick.js
 4+ */
 5+
 6+( function( $, mw ) {
 7+
 8+/* Extension */
 9+
 10+$.extend( true, mw.legacy, {
 11+
 12+ /* Functions */
 13+
 14+ 'setupRightClickEdit': function() {
 15+ if (document.getElementsByTagName) {
 16+ var spans = document.getElementsByTagName('span');
 17+ for (var i = 0; i < spans.length; i++) {
 18+ var el = spans[i];
 19+ if(el.className == 'editsection') {
 20+ mw.legacy.addRightClickEditHandler(el);
 21+ }
 22+ }
 23+ }
 24+ }
 25+ 'addRightClickEditHandler': function(el) {
 26+ for (var i = 0; i < el.childNodes.length; i++) {
 27+ var link = el.childNodes[i];
 28+ if (link.nodeType == 1 && link.nodeName.toLowerCase() == 'a') {
 29+ var editHref = link.getAttribute('href');
 30+ // find the enclosing (parent) header
 31+ var prev = el.parentNode;
 32+ if (prev && prev.nodeType == 1 &&
 33+ prev.nodeName.match(/^[Hh][1-6]$/)) {
 34+ prev.oncontextmenu = function(e) {
 35+ if (!e) { e = window.event; }
 36+ // e is now the event in all browsers
 37+ var targ;
 38+ if (e.target) { targ = e.target; }
 39+ else if (e.srcElement) { targ = e.srcElement; }
 40+ if (targ.nodeType == 3) { // defeat Safari bug
 41+ targ = targ.parentNode;
 42+ }
 43+ // targ is now the target element
 44+ // We don't want to deprive the noble reader of a context menu
 45+ // for the section edit link, do we? (Might want to extend this
 46+ // to all <a>'s?)
 47+ if (targ.nodeName.toLowerCase() != 'a'
 48+ || targ.parentNode.className != 'editsection') {
 49+ document.location = editHref;
 50+ return false;
 51+ }
 52+ return true;
 53+ };
 54+ }
 55+ }
 56+ }
 57+ }
 58+} );
 59+
 60+/* Initialization */
 61+
 62+$( document ).ready( function() {
 63+ mw.legacy.setupRightClickEdit();
 64+} );
 65+
 66+} )( jQuery, MediaWiki );
\ No newline at end of file
Property changes on: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.rightclickedit.js
___________________________________________________________________
Added: svn:eol-style
167 + native
Index: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.block.js
@@ -0,0 +1,44 @@
 2+/*
 3+ * Legacy emulation for the now depricated skins/common/block.js
 4+ */
 5+
 6+( function( $, mw ) {
 7+
 8+/* Extension */
 9+
 10+$.extend( true, mw.legacy, {
 11+
 12+ /* Functions */
 13+
 14+ 'considerChangingExpiryFocus': function() {
 15+ var $expiry = $( '#wpBlockExpiry' );
 16+ var $other = $( '#wpBlockOther' );
 17+ if ( $expiry.length && $other.length ) {
 18+ if ( $expiry.val() == 'other' ) {
 19+ $other.css( 'display', '' );
 20+ } else {
 21+ $other.css( 'display', 'none' );
 22+ }
 23+ }
 24+ },
 25+ 'updateBlockOptions': function() {
 26+ var $target = $( '#mw-bi-target' );
 27+ if ( $target.length ) {
 28+ var address = $target.val();
 29+ var isEmpty = address.match( /^\s*$/ );
 30+ var isIp = address.match( /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|:(:[0-9A-Fa-f]{1,4}){1,7}|[0-9A-Fa-f]{1,4}(:{1,2}[0-9A-Fa-f]{1,4}|::$){1,7})(\/\d+)?$/ );
 31+ var isIpRange = isIp && address.match( /\/\d+$/ );
 32+ $( '#wpAnonOnlyRow' ).css( 'display', !isIp && !isEmpty ? 'none' : '' );
 33+ $( '#wpEnableAutoblockRow,#wpEnableHideUser' ).css( 'display', isIp && !isEmpty ? 'none' : '' );
 34+ $( '#wpEnableWatchUser' ).css( 'display', isIpRange && !isEmpty ? 'none' : '' );
 35+ }
 36+ }
 37+} );
 38+
 39+/* Initialization */
 40+
 41+$( document ).ready( function() {
 42+ mw.legacy.considerChangingExpiryFocus();
 43+} );
 44+
 45+} )( jQuery, MediaWiki );
\ No newline at end of file
Property changes on: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.block.js
___________________________________________________________________
Added: svn:eol-style
146 + native
Index: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.IEFixes.js
@@ -0,0 +1,141 @@
 2+/*
 3+ * Legacy emulation for the now depricated skins/common/IEFixes.js
 4+ *
 5+ * Internet Explorer JavaScript fixes
 6+ */
 7+
 8+( function( $, mw ) {
 9+
 10+/* Support */
 11+
 12+/**
 13+ * Expand links for printing
 14+ */
 15+String.prototype.hasClass = function( classWanted ) {
 16+ var classArr = this.split(/\s/);
 17+ for ( var i = 0; i < classArr.length; i++ ) {
 18+ if ( classArr[i].toLowerCase() == classWanted.toLowerCase() ) {
 19+ return true;
 20+ }
 21+ }
 22+ return false;
 23+}
 24+
 25+/* Extension */
 26+
 27+$.extend( true, mw.legacy, {
 28+
 29+ /* Global Variables */
 30+
 31+ 'isMSIE55': ( window.showModalDialog && window.clipboardData && window.createPopup ),
 32+ 'doneIETransform': null,
 33+ 'doneIEAlphaFix': null,
 34+ 'expandedURLs': null,
 35+
 36+ /* Functions */
 37+
 38+ 'hookit': function() {
 39+ if ( !doneIETransform && document.getElementById && document.getElementById( 'bodyContent' ) ) {
 40+ doneIETransform = true;
 41+ relativeforfloats();
 42+ fixalpha();
 43+ }
 44+ },
 45+ /**
 46+ * Fixes PNG alpha transparency
 47+ */
 48+ function fixalpha( logoId ) {
 49+ // bg
 50+ if ( isMSIE55 && !doneIEAlphaFix ) {
 51+ var plogo = document.getElementById( logoId || 'p-logo' );
 52+ if ( !plogo ) {
 53+ return;
 54+ }
 55+ var logoa = plogo.getElementsByTagName('a')[0];
 56+ if ( !logoa ) {
 57+ return;
 58+ }
 59+ var bg = logoa.currentStyle.backgroundImage;
 60+ var imageUrl = bg.substring( 5, bg.length - 2 );
 61+ doneIEAlphaFix = true;
 62+ if ( imageUrl.substr( imageUrl.length - 4 ).toLowerCase() == '.png' ) {
 63+ var logospan = logoa.appendChild( document.createElement( 'span' ) );
 64+ logoa.style.backgroundImage = 'none';
 65+ logospan.style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=' + imageUrl + ')';
 66+ logospan.style.height = '100%';
 67+ logospan.style.position = 'absolute';
 68+ logospan.style.width = logoa.currentStyle.width;
 69+ logospan.style.cursor = 'hand';
 70+ // Center image with hack for IE5.5
 71+ if ( document.documentElement.dir == 'rtl' ) {
 72+ logospan.style.right = '50%';
 73+ logospan.style.setExpression( 'marginRight', '"-" + (this.offsetWidth / 2) + "px"' );
 74+ } else {
 75+ logospan.style.left = '50%';
 76+ logospan.style.setExpression( 'marginLeft', '"-" + (this.offsetWidth / 2) + "px"' );
 77+ }
 78+ logospan.style.top = '50%';
 79+ logospan.style.setExpression( 'marginTop', '"-" + (this.offsetHeight / 2) + "px"' );
 80+ var linkFix = logoa.appendChild( logoa.cloneNode() );
 81+ linkFix.style.position = 'absolute';
 82+ linkFix.style.height = '100%';
 83+ linkFix.style.width = '100%';
 84+ }
 85+ }
 86+ },
 87+ /*
 88+ * Fixes IE6 disappering float bug
 89+ */
 90+ 'relativeforfloats': function() {
 91+ var bc = document.getElementById( 'bodyContent' );
 92+ if ( bc ) {
 93+ var tables = bc.getElementsByTagName( 'table' );
 94+ var divs = bc.getElementsByTagName( 'div' );
 95+ }
 96+ setrelative( tables );
 97+ setrelative( divs );
 98+ },
 99+ 'setrelative': function ( nodes ) {
 100+ var i = 0;
 101+ while ( i < nodes.length ) {
 102+ if( ( ( nodes[i].style.float && nodes[i].style.float != ( 'none' ) ||
 103+ ( nodes[i].align && nodes[i].align != ( 'none' ) ) ) &&
 104+ ( !nodes[i].style.position || nodes[i].style.position != 'relative' ) ) )
 105+ {
 106+ nodes[i].style.position = 'relative';
 107+ }
 108+ i++;
 109+ }
 110+ },
 111+ 'onbeforeprint': function() {
 112+ expandedURLs = [];
 113+ var contentEl = document.getElementById( 'content' );
 114+ if ( contentEl ) {
 115+ var allLinks = contentEl.getElementsByTagName( 'a' );
 116+ for ( var i = 0; i < allLinks.length; i++ ) {
 117+ if ( allLinks[i].className.hasClass( 'external' ) && !allLinks[i].className.hasClass( 'free' ) ) {
 118+ var expandedLink = document.createElement( 'span' );
 119+ var expandedText = document.createTextNode( ' (' + allLinks[i].href + ')' );
 120+ expandedLink.appendChild( expandedText );
 121+ allLinks[i].parentNode.insertBefore( expandedLink, allLinks[i].nextSibling );
 122+ expandedURLs[i] = expandedLink;
 123+ }
 124+ }
 125+ }
 126+ },
 127+ 'onafterprint': function() {
 128+ for ( var i = 0; i < expandedURLs.length; i++ ) {
 129+ if ( expandedURLs[i] ) {
 130+ expandedURLs[i].removeNode( true );
 131+ }
 132+ }
 133+ }
 134+} );
 135+
 136+/* Initialization */
 137+
 138+$( document ).ready( function() {
 139+ mw.legacy.hookit();
 140+} );
 141+
 142+} )( jQuery, MediaWiki );
\ No newline at end of file
Property changes on: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.IEFixes.js
___________________________________________________________________
Added: svn:eol-style
1143 + native
Index: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.enhancedchanges.js
@@ -0,0 +1,46 @@
 2+/*
 3+ * Legacy emulation for the now depricated skins/common/enhancedchanges.js
 4+ */
 5+
 6+( function( $, mw ) {
 7+
 8+/* Extension */
 9+
 10+$.extend( true, mw.legacy, {
 11+
 12+ /* Functions */
 13+
 14+ /**
 15+ * Switch an RC line between hidden/shown
 16+ *
 17+ * @param integer idNumber : the id number of the RC group
 18+ */
 19+ 'toggleVisibility': function( idNumber ) {
 20+ var elements = [
 21+ '#mw-rc-openarrow-' + idNumber,
 22+ '#mw-rc-closearrow-' + idNumber,
 23+ '#mw-rc-subentries-' + idNumber
 24+ ];
 25+ $( elements.join( ',' ) ).toggleClass( 'mw-changeslist-hidden' ).toggleClass( 'mw-changeslist-expanded' );
 26+ }
 27+} );
 28+
 29+/* Initialization */
 30+
 31+$( document ).ready( function() {
 32+ /*
 33+ * Add the CSS to hide parts that should be collapsed
 34+ *
 35+ * We do this with JS so everything will be expanded by default
 36+ * if JS is disabled
 37+ */
 38+ $( 'head' ).append(
 39+ '<style type="text/css">\
 40+ .mw-changeslist-hidden { display:none; }\
 41+ div.mw-changeslist-expanded { display:block; }\
 42+ span.mw-changeslist-expanded { display:inline !important; visibility:visible !important; }\
 43+ </style>'
 44+ );
 45+} );
 46+
 47+} )( jQuery, MediaWiki );
\ No newline at end of file
Property changes on: branches/resourceloader/phase3/resources/mediawiki/legacy/mediawiki.legacy.enhancedchanges.js
___________________________________________________________________
Added: svn:eol-style
148 + native
Index: branches/resourceloader/phase3/resources/mediawiki/utilities/mediawiki.utilities.client.js
@@ -0,0 +1,185 @@
 2+/*
 3+ * User-agent detection
 4+ */
 5+
 6+( function( $, mw ) {
 7+
 8+/* Extension */
 9+
 10+$.extend( mw.utilities, {
 11+ 'client': {
 12+ /**
 13+ * Returns an object containing information about the browser
 14+ *
 15+ * The resulting client object will be in the following format:
 16+ * {
 17+ * 'name': 'firefox',
 18+ * 'layout': 'gecko',
 19+ * 'os': 'linux'
 20+ * 'version': '3.5.1',
 21+ * 'versionBase': '3',
 22+ * 'versionNumber': 3.5,
 23+ * }
 24+ */
 25+ this.profile = function() {
 26+ // Use the cached version if possible
 27+ if ( typeof this.profile === 'undefined' ) {
 28+
 29+ /* Configuration */
 30+
 31+ // Name of browsers or layout engines we don't recognize
 32+ var uk = 'unknown';
 33+ // Generic version digit
 34+ var x = 'x';
 35+ // Strings found in user agent strings that need to be conformed
 36+ var wildUserAgents = [ 'Opera', 'Navigator', 'Minefield', 'KHTML', 'Chrome', 'PLAYSTATION 3'];
 37+ // Translations for conforming user agent strings
 38+ var userAgentTranslations = [
 39+ // Tons of browsers lie about being something they are not
 40+ [/(Firefox|MSIE|KHTML,\slike\sGecko|Konqueror)/, ''],
 41+ // Chrome lives in the shadow of Safari still
 42+ ['Chrome Safari', 'Chrome'],
 43+ // KHTML is the layout engine not the browser - LIES!
 44+ ['KHTML', 'Konqueror'],
 45+ // Firefox nightly builds
 46+ ['Minefield', 'Firefox'],
 47+ // This helps keep differnt versions consistent
 48+ ['Navigator', 'Netscape'],
 49+ // This prevents version extraction issues, otherwise translation would happen later
 50+ ['PLAYSTATION 3', 'PS3'],
 51+ ];
 52+ // Strings which precede a version number in a user agent string - combined and used as match 1 in
 53+ // version detectection
 54+ var versionPrefixes = [
 55+ 'camino', 'chrome', 'firefox', 'netscape', 'netscape6', 'opera', 'version', 'konqueror', 'lynx',
 56+ 'msie', 'safari', 'ps3'
 57+ ];
 58+ // Used as matches 2, 3 and 4 in version extraction - 3 is used as actual version number
 59+ var versionSuffix = '(\/|\;?\s|)([a-z0-9\.\+]*?)(\;|dev|rel|\\)|\s|$)';
 60+ // Names of known browsers
 61+ var browserNames = [
 62+ 'camino', 'chrome', 'firefox', 'netscape', 'konqueror', 'lynx', 'msie', 'opera', 'safari', 'ipod',
 63+ 'iphone', 'blackberry', 'ps3'
 64+ ];
 65+ // Tanslations for conforming browser names
 66+ var browserTranslations = [];
 67+ // Names of known layout engines
 68+ var layoutNames = ['gecko', 'konqueror', 'msie', 'opera', 'webkit'];
 69+ // Translations for conforming layout names
 70+ var layoutTranslations = [['konqueror', 'khtml'], ['msie', 'trident'], ['opera', 'presto']];
 71+ // Names of known operating systems
 72+ var osNames = ['win', 'mac', 'linux', 'sunos', 'solaris', 'iphone'];
 73+ // Translations for conforming operating system names
 74+ var osTranslations = [['sunos', 'solaris']];
 75+
 76+ /* Methods */
 77+
 78+ // Performs multiple replacements on a string
 79+ function translate( source, translations ) {
 80+ for ( var i = 0; i < translations.length; i++ ) {
 81+ source = source.replace( translations[i][0], translations[i][1] );
 82+ }
 83+ return source;
 84+ };
 85+
 86+ /* Pre-processing */
 87+
 88+ var userAgent = navigator.userAgent, match, browser = uk, layout = uk, os = uk, version = x;
 89+ if ( match = new RegExp( '(' + wildUserAgents.join( '|' ) + ')' ).exec( userAgent ) ) {
 90+ // Takes a userAgent string and translates given text into something we can more easily work with
 91+ userAgent = translate( userAgent, userAgentTranslations );
 92+ }
 93+ // Everything will be in lowercase from now on
 94+ userAgent = userAgent.toLowerCase();
 95+
 96+ /* Extraction */
 97+
 98+ if ( match = new RegExp( '(' + browserNames.join( '|' ) + ')' ).exec( userAgent ) ) {
 99+ browser = translate( match[1], browserTranslations );
 100+ }
 101+ if ( match = new RegExp( '(' + layoutNames.join( '|' ) + ')' ).exec( userAgent ) ) {
 102+ layout = translate( match[1], layoutTranslations );
 103+ }
 104+ if ( match = new RegExp( '(' + osNames.join( '|' ) + ')' ).exec( navigator.platform.toLowerCase() ) ) {
 105+ var os = translate( match[1], osTranslations );
 106+ }
 107+ if ( match = new RegExp( '(' + versionPrefixes.join( '|' ) + ')' + versionSuffix ).exec( userAgent ) ) {
 108+ version = match[3];
 109+ }
 110+
 111+ /* Edge Cases -- did I mention about how user agent string lie? */
 112+
 113+ // Decode Safari's crazy 400+ version numbers
 114+ if ( name.match( /safari/ ) && version > 400 ) {
 115+ version = '2.0';
 116+ }
 117+ // Expose Opera 10's lies about being Opera 9.8
 118+ if ( name === 'opera' && version >= 9.8) {
 119+ version = userAgent.match( /version\/([0-9\.]*)/i )[1] || 10;
 120+ }
 121+
 122+ /* Caching */
 123+
 124+ this.profile = {
 125+ 'browser': browser,
 126+ 'layout': layout,
 127+ 'os': os,
 128+ 'version': version,
 129+ 'versionBase': ( version !== x ? new String( version ).substr( 0, 1 ) : x ),
 130+ 'versionNumber': ( parseFloat( version, 10 ) || 0.0 )
 131+ };
 132+ }
 133+ return this.profile;
 134+ };
 135+ /**
 136+ * Checks the current browser against a support map object to determine if the browser has been black-listed or
 137+ * not. If the browser was not configured specifically it is assumed to work. It is assumed that the body
 138+ * element is classified as either "ltr" or "rtl". If neither is set, "ltr" is assumed.
 139+ *
 140+ * A browser map is in the following format:
 141+ * {
 142+ * 'ltr': {
 143+ * // Multiple rules with configurable operators
 144+ * 'msie': [['>=', 7], ['!=', 9]],
 145+ * // Blocked entirely
 146+ * 'iphone': false
 147+ * },
 148+ * 'rtl': {
 149+ * // Test against a string
 150+ * 'msie': [['!==', '8.1.2.3']],
 151+ * // RTL rules do not fall through to LTR rules, you must explicity set each of them
 152+ * 'iphone': false
 153+ * }
 154+ * }
 155+ *
 156+ * @param map Object of browser support map
 157+ *
 158+ * @return Boolean true if browser known or assumed to be supported, false if blacklisted
 159+ */
 160+ this.test = function( map ) {
 161+ var client = this.client();
 162+ // Check over each browser condition to determine if we are running in a compatible client
 163+ var browser = map[$( 'body' ).is( '.rtl' ) ? 'rtl' : 'ltr'][client.browser];
 164+ if ( typeof browser !== 'object' ) {
 165+ // Unknown, so we assume it's working
 166+ return true;
 167+ }
 168+ for ( var condition in browser ) {
 169+ var op = browser[condition][0];
 170+ var val = browser[condition][1];
 171+ if ( val === false ) {
 172+ return false;
 173+ } else if ( typeof val == 'string' ) {
 174+ if ( !( eval( 'client.version' + op + '"' + val + '"' ) ) ) {
 175+ return false;
 176+ }
 177+ } else if ( typeof val == 'number' ) {
 178+ if ( !( eval( 'client.versionNumber' + op + val ) ) ) {
 179+ return false;
 180+ }
 181+ }
 182+ }
 183+ return true;
 184+ };
 185+ }
 186+} );
\ No newline at end of file
Property changes on: branches/resourceloader/phase3/resources/mediawiki/utilities/mediawiki.utilities.client.js
___________________________________________________________________
Added: svn:eol-style
1187 + native
Index: branches/resourceloader/phase3/resources/mediawiki/views/mediawiki.views.install.js
@@ -0,0 +1,100 @@
 2+/*
 3+ * Web-installer progressive enhancement (ported from skins/common/config.js)
 4+ *
 5+ * Makes elements in the configuration form interactive and hides portions of the form when not in-use
 6+ */
 7+
 8+( function( $, mw ) {
 9+
 10+/* Initialization */
 11+
 12+$( document ).ready( function() {
 13+ // Show/hide code for help text
 14+ $( '.config-show-help a' ).click( function() {
 15+ $(this).parent().siblings( '.config-help-message' ).show( 'slow' );
 16+ $(this).parent().siblings( '.config-hide-help' ).show();
 17+ $(this).parent().hide();
 18+ return false;
 19+ } );
 20+ $( '.config-hide-help a' ).click( function() {
 21+ $(this).parent().siblings( '.config-help-message' ).hide( 'slow' );
 22+ $(this).parent().siblings( '.config-show-help' ).show();
 23+ $(this).parent().hide();
 24+ return false;
 25+ } );
 26+ // Show/hide code for DB-specific options
 27+ // FIXME: Do we want slow, fast, or even non-animated (instantaneous) showing/hiding here?
 28+ $( '.dbRadio' ).each( function() { $( '#' + $(this).attr( 'rel' ) ).hide(); } );
 29+ $( '#' + $( '.dbRadio:checked' ).attr( 'rel' ) ).show();
 30+ $( '.dbRadio' ).click( function() {
 31+ var $checked = $( '.dbRadio:checked' );
 32+ var $wrapper = $( '#' + $checked.attr( 'rel' ) );
 33+ if ( !$wrapper.is( ':visible' ) ) {
 34+ $( '.dbWrapper' ).hide( 'slow' );
 35+ $wrapper.show( 'slow' );
 36+ }
 37+ } );
 38+ // Scroll to the bottom of upgrade log
 39+ $( "#config-update-log" ).each( function() { this.scrollTop = this.scrollHeight; } );
 40+ // Show/hide Creative Commons thingy
 41+ $( '.licenseRadio' ).click( function() {
 42+ var $wrapper = $( '#config-cc-wrapper' );
 43+ if ( $( '#config__LicenseCode_cc-choose' ).is( ':checked' ) ) {
 44+ $wrapper.show( 'slow' );
 45+ } else {
 46+ $wrapper.hide( 'slow' );
 47+ }
 48+ } );
 49+ // Show/hide random stuff (email, upload)
 50+ $( '.showHideRadio' ).click( function() {
 51+ var $wrapper = $( '#' + $(this).attr( 'rel' ) );
 52+ if ( $(this).is( ':checked' ) ) {
 53+ $wrapper.show( 'slow' );
 54+ } else {
 55+ $wrapper.hide( 'slow' );
 56+ }
 57+ } );
 58+ $( '.hideShowRadio' ).click( function() {
 59+ var $wrapper = $( '#' + $(this).attr( 'rel' ) );
 60+ if ( $(this).is( ':checked' ) ) {
 61+ $wrapper.hide( 'slow' );
 62+ } else {
 63+ $wrapper.show( 'slow' );
 64+ }
 65+ } );
 66+ // Enable/disable "other" textboxes
 67+ $( '.enableForOther' ).click( function() {
 68+ var $textbox = $( '#' + $(this).attr( 'rel' ) );
 69+ if ( $(this).val() == 'other' ) { // FIXME: Ugh, this is ugly
 70+ $textbox.removeAttr( 'disabled' );
 71+ } else {
 72+ $textbox.attr( 'disabled', 'disabled' );
 73+ }
 74+ } );
 75+ // Synchronize radio button label for sitename with textbox
 76+ $label = $( 'label[for=config__NamespaceType_site-name]' );
 77+ labelText = $label.text();
 78+ $label.text( labelText.replace( '$1', '' ) );
 79+ $( '#config_wgSitename' ).bind( 'keyup change', syncText ).each( syncText );
 80+ function syncText() {
 81+ var value = $(this).val()
 82+ .replace( /[\[\]\{\}|#<>%+? ]/g, '_' )
 83+ .replace( /&/, '&amp;' )
 84+ .replace( /__+/g, '_' )
 85+ .replace( /^_+/, '' )
 86+ .replace( /_+$/, '' );
 87+ value = value.substr( 0, 1 ).toUpperCase() + value.substr( 1 );
 88+ $label.text( labelText.replace( '$1', value ) );
 89+ }
 90+ // Show/Hide memcached servers when needed
 91+ $( "input[name$='config_wgMainCacheType']" ).change( function() {
 92+ var $memc = $( "#config-memcachewrapper" );
 93+ if ( $( "input[name$='config_wgMainCacheType']:checked" ).val() == 'memcached' ) {
 94+ $memc.show( 'slow' );
 95+ } else {
 96+ $memc.hide( 'slow' );
 97+ }
 98+ } );
 99+} );
 100+
 101+} )( jQuery, MediaWiki );
\ No newline at end of file
Property changes on: branches/resourceloader/phase3/resources/mediawiki/views/mediawiki.views.install.js
___________________________________________________________________
Added: svn:eol-style
1102 + native
Index: branches/resourceloader/phase3/resources/mediawiki/views/mediawiki.views.diff.js
@@ -0,0 +1,30 @@
 2+/*
 3+ * Diff-view progressive enhancement (ported from skins/common/diff.js)
 4+ *
 5+ * Fixes an overflow bug in old versions of Firefox
 6+ */
 7+
 8+( function( $, mw ) {
 9+
 10+/* Initialization */
 11+
 12+$( document ).ready( function() {
 13+ /*
 14+ * Workaround for overflow bug in Mozilla 1.1 and earlier, where scrolling <div>s in <td> cells collapse their
 15+ * height to a single line.
 16+ *
 17+ * Known to be fixed in 1.2.1 (Gecko 20021130), but the CSS hacks I've tried with overflow-x disable the scrolling
 18+ * all the way until Mozilla 1.8 / FF 1.5 and break Opera as well.
 19+ *
 20+ * So... we check for reaaaally old Gecko and hack in an alternate rule to let the wide cells spill instead of
 21+ * scrolling them. Not ideal as it won't work if JS is disabled, of course.
 22+ */
 23+ if ( window.navigator && window.navigator.product == 'Gecko' && window.navigator.productSub < '20021130' ) {
 24+ document.styleSheets[document.styleSheets.length - 1].insertRule(
 25+ 'table.diff td div { overflow: visible; }',
 26+ document.styleSheets[document.styleSheets.length - 1].cssRules.length
 27+ );
 28+ }
 29+} );
 30+
 31+} )( jQuery, MediaWiki );
\ No newline at end of file
Property changes on: branches/resourceloader/phase3/resources/mediawiki/views/mediawiki.views.diff.js
___________________________________________________________________
Added: svn:eol-style
132 + native
Index: branches/resourceloader/phase3/resources/mediawiki/mediawiki.js
@@ -0,0 +1,502 @@
 2+/*
 3+ * JavaScript Backwards Compatibility
 4+ */
 5+
 6+// Make calling .indexOf() on an array work on older browsers
 7+if ( typeof Array.prototype.indexOf === 'undefined' ) {
 8+ Array.prototype.indexOf = function( needle ) {
 9+ for ( var i = 0; i < this.length; i++ ) {
 10+ if ( this[i] === needle ) {
 11+ return i;
 12+ }
 13+ }
 14+ return -1;
 15+ };
 16+}
 17+
 18+/*
 19+ * Core MediaWiki JavaScript Library
 20+ */
 21+( function() {
 22+
 23+ /* Constants */
 24+
 25+ // This will not change until we are 100% ready to turn off legacy globals
 26+ const LEGACY_GLOBALS = true;
 27+
 28+ /* Members */
 29+
 30+ this.legacy = LEGACY_GLOBALS ? window : {};
 31+
 32+ /* Methods */
 33+
 34+ /**
 35+ * Log a string msg to the console
 36+ *
 37+ * All mw.log statements will be removed on minification so lots of mw.log calls will not impact performance in non-debug
 38+ * mode. This is done using simple regular expressions, so the input of this function needs to not contain things like a
 39+ * self-executing closure. In the case that the browser does not have a console available, one is created by appending a
 40+ * <div> element to the bottom of the body and then appending a <div> element to that for each message. In the case that
 41+ * the browser does have a console available
 42+ *
 43+ * @author Michael Dale <mdale@wikimedia.org>, Trevor Parscal <tparscal@wikimedia.org>
 44+ * @param string string message to output to console
 45+ */
 46+ this.log = function( string ) {
 47+ // Allow log messages to use a configured prefix
 48+ if ( mw.config.exists( 'mw.log.prefix' ) ) {
 49+ string = mw.config.get( 'mw.log.prefix' ) + string;
 50+ }
 51+ // Try to use an existing console
 52+ if ( typeof window.console !== 'undefined' && typeof window.console.log == 'function' ) {
 53+ window.console.log( string );
 54+ } else {
 55+ // Show a log box for console-less browsers
 56+ var $log = $( '#mw_log_console' );
 57+ if ( !$log.length ) {
 58+ $log = $( '<div id="mw_log_console"></div>' )
 59+ .css( {
 60+ 'position': 'absolute',
 61+ 'overflow': 'auto',
 62+ 'z-index': 500,
 63+ 'bottom': '0px',
 64+ 'left': '0px',
 65+ 'right': '0px',
 66+ 'height': '150px',
 67+ 'background-color': 'white',
 68+ 'border-top': 'solid 1px #DDDDDD'
 69+ } )
 70+ .appendTo( $( 'body' ) );
 71+ }
 72+ if ( $log.length ) {
 73+ $log.append(
 74+ $( '<div>' + string + '</div>' )
 75+ .css( {
 76+ 'border-bottom': 'solid 1px #DDDDDD',
 77+ 'font-size': 'small',
 78+ 'font-family': 'monospace',
 79+ 'padding': '0.125em 0.25em'
 80+ } )
 81+ );
 82+ }
 83+ }
 84+ };
 85+ /*
 86+ * An object which allows single and multiple existence, setting and getting on a list of key / value pairs
 87+ */
 88+ this.config = new ( function() {
 89+
 90+ /* Private Members */
 91+
 92+ var that = this;
 93+ // List of configuration values - in legacy mode these configurations were ALL in the global space
 94+ var values = LEGACY_GLOBALS ? window : {};
 95+
 96+ /* Public Methods */
 97+
 98+ /**
 99+ * Sets one or multiple configuration values using a key and a value or an object of keys and values
 100+ */
 101+ this.set = function( keys, value ) {
 102+ if ( typeof keys === 'object' ) {
 103+ for ( var key in keys ) {
 104+ values[key] = keys[key];
 105+ }
 106+ } else if ( typeof keys === 'string' && typeof value !== 'undefined' ) {
 107+ values[keys] = value;
 108+ }
 109+ };
 110+ /**
 111+ * Gets one or multiple configuration values using a key and an optional fallback or an array of keys
 112+ */
 113+ this.get = function( keys, fallback ) {
 114+ if ( typeof keys === 'object' ) {
 115+ var result = {};
 116+ for ( var k = 0; k < keys.length; k++ ) {
 117+ if ( typeof values[keys[k]] !== 'undefined' ) {
 118+ result[keys[k]] = values[keys[k]];
 119+ }
 120+ }
 121+ return result;
 122+ } else if ( typeof values[keys] === 'undefined' ) {
 123+ return typeof fallback !== 'undefined' ? fallback : null;
 124+ } else {
 125+ return values[keys];
 126+ }
 127+ };
 128+ /**
 129+ * Checks if one or multiple configuration fields exist
 130+ */
 131+ this.exists = function( keys ) {
 132+ if ( typeof keys === 'object' ) {
 133+ for ( var k = 0; k < keys.length; k++ ) {
 134+ if ( !( keys[k] in values ) ) {
 135+ return false;
 136+ }
 137+ }
 138+ return true;
 139+ } else {
 140+ return keys in values;
 141+ }
 142+ };
 143+ } )();
 144+ /*
 145+ * Localization system
 146+ */
 147+ this.msg = new ( function() {
 148+
 149+ /* Private Members */
 150+
 151+ var that = this;
 152+ // List of localized messages
 153+ var messages = {};
 154+
 155+ /* Public Methods */
 156+
 157+ this.set = function( keys, value ) {
 158+ if ( typeof keys === 'object' ) {
 159+ for ( var key in keys ) {
 160+ messages[key] = keys[key];
 161+ }
 162+ } else if ( typeof keys === 'string' && typeof value !== 'undefined' ) {
 163+ messages[keys] = value;
 164+ }
 165+ };
 166+ this.get = function( key, args ) {
 167+ if ( !( key in messages ) ) {
 168+ return '<' + key + '>';
 169+ }
 170+ var msg = messages[key];
 171+ if ( typeof args == 'object' || typeof args == 'array' ) {
 172+ for ( var argKey in args ) {
 173+ msg = msg.replace( '\$' + ( parseInt( argKey ) + 1 ), args[argKey] );
 174+ }
 175+ } else if ( typeof args == 'string' || typeof args == 'number' ) {
 176+ msg = msg.replace( '$1', args );
 177+ }
 178+ return msg;
 179+ };
 180+ } )();
 181+ /*
 182+ * Client-side module loader which integrates with the MediaWiki ResourceLoader
 183+ */
 184+ this.loader = new ( function() {
 185+
 186+ /* Private Members */
 187+
 188+ var that = this;
 189+ var server = 'load.php';
 190+ /*
 191+ * Mapping of registered modules
 192+ *
 193+ * Format:
 194+ * {
 195+ * 'moduleName': {
 196+ * 'needs': ['required module', 'required module', ...],
 197+ * 'state': 'registered, loading, loaded, or ready',
 198+ * 'script': function() {},
 199+ * 'style': 'css code string',
 200+ * 'localization': { 'key': 'value' }
 201+ * }
 202+ * }
 203+ */
 204+ var registry = {};
 205+ // List of callbacks waiting on dependent modules to be loaded so they can be executed
 206+ var queue = [];
 207+ // Until document ready, load requests will be collected in a batch queue
 208+ var batch = [];
 209+ // True after document ready occurs
 210+ var ready = false;
 211+
 212+ /* Private Methods */
 213+
 214+ /**
 215+ * Gets a list of modules names that a module needs in their proper dependency order
 216+ *
 217+ * @param string module name
 218+ * @return
 219+ * @throws Error if circular reference is detected
 220+ */
 221+ function needs( module ) {
 222+ if ( !( module in registry ) ) {
 223+ // Undefined modules have no needs
 224+ return [];
 225+ }
 226+ var resolved = [];
 227+ var unresolved = [];
 228+ if ( arguments.length === 3 ) {
 229+ // Use arguemnts on inner call
 230+ resolved = arguments[1];
 231+ unresolved = arguments[2];
 232+ }
 233+ unresolved[unresolved.length] = module;
 234+ for ( n in registry[module].needs ) {
 235+ if ( resolved.indexOf( registry[module].needs[n] ) === -1 ) {
 236+ if ( unresolved.indexOf( registry[module].needs[n] ) !== -1 ) {
 237+ throw new Error(
 238+ 'Circular reference detected: ' + module + ' -> ' + registry[module].needs[n]
 239+ );
 240+ }
 241+ needs( registry[module].needs[n], resolved, unresolved );
 242+ }
 243+ }
 244+ resolved[resolved.length] = module;
 245+ unresolved.slice( unresolved.indexOf( module ), 1 );
 246+ if ( arguments.length === 1 ) {
 247+ // Return resolved list on outer call
 248+ return resolved;
 249+ }
 250+ };
 251+ /**
 252+ * Narrows a list of module names down to those matching a specific state. Possible states are 'undefined',
 253+ * 'registered', 'loading', 'loaded', or 'ready'
 254+ *
 255+ * @param mixed string or array of strings of module states to filter by
 256+ * @param array list of module names to filter (optional, all modules will be used by default)
 257+ * @return array list of filtered module names
 258+ */
 259+ function filter( states, modules ) {
 260+ var list = [];
 261+ if ( typeof modules === 'undefined' ) {
 262+ modules = [];
 263+ for ( module in registry ) {
 264+ modules[modules.length] = module;
 265+ }
 266+ }
 267+ for ( var s in states ) {
 268+ for ( var m in modules ) {
 269+ if (
 270+ ( states[s] == 'undefined' && typeof registry[modules[m]] === 'undefined' ) ||
 271+ ( typeof registry[modules[m]] === 'object' && registry[modules[m]].state === states[s] )
 272+ ) {
 273+ list[list.length] = modules[m];
 274+ }
 275+ }
 276+ }
 277+ return list;
 278+ }
 279+ /**
 280+ * Executes a loaded module, making it ready to use
 281+ *
 282+ * @param string module name to execute
 283+ */
 284+ function execute( module ) {
 285+ if ( typeof registry[module] === 'undefined' ) {
 286+ throw new Error( 'module has not been registered: ' + module );
 287+ }
 288+ switch ( registry[module].state ) {
 289+ case 'registered':
 290+ throw new Error( 'module has not completed loading: ' + module );
 291+ break;
 292+ case 'loading':
 293+ throw new Error( 'module has not completed loading: ' + module );
 294+ break;
 295+ case 'ready':
 296+ throw new Error( 'module has already been loaded: ' + module );
 297+ break;
 298+ }
 299+ // Add style sheet to document
 300+ if ( typeof registry[module].style === 'string' && registry[module].style.length ) {
 301+ $( 'head' ).append( '<style type="text/css">' + registry[module].style + '</style>' );
 302+ }
 303+ // Add localizations to message system
 304+ if ( typeof registry[module].localization === 'object' ) {
 305+ mw.msg.set( registry[module].localization );
 306+ }
 307+ // Execute script
 308+ try {
 309+ registry[module].script();
 310+ } catch( e ) {
 311+ mw.log( 'Exception thrown by ' + module + ': ' + e.message );
 312+ }
 313+ // Change state
 314+ registry[module].state = 'ready';
 315+
 316+ // Execute all modules which were waiting for this to be ready
 317+ for ( r in registry ) {
 318+ if ( registry[r].state == 'loaded' ) {
 319+ if ( filter( ['ready'], registry[r].needs ).length == registry[r].needs.length ) {
 320+ execute( r );
 321+ }
 322+ }
 323+ }
 324+ }
 325+ /**
 326+ * Adds a callback and it's needs to the queue
 327+ *
 328+ * @param array list of module names the callback needs to be ready before being executed
 329+ * @param function callback to execute when needs are met
 330+ */
 331+ function request( needs, callback ) {
 332+ queue[queue.length] = { 'needs': filter( ['undefined', 'registered'], needs ), 'callback': callback };
 333+ }
 334+
 335+ /* Public Methods */
 336+
 337+ /**
 338+ * Processes the queue, loading and executing when things when ready.
 339+ */
 340+ this.work = function() {
 341+ // Appends a list of modules to the batch
 342+ function append( modules ) {
 343+ for ( m in modules ) {
 344+ // Prevent requesting modules which are loading, loaded or ready
 345+ if ( modules[m] in registry && registry[modules[m]].state == 'registered' ) {
 346+ // Since the batch can live between calls to work until document ready, we need to make sure
 347+ // we aren't making a duplicate entry
 348+ if ( batch.indexOf( modules[m] ) == -1 ) {
 349+ batch[batch.length] = modules[m];
 350+ registry[modules[m]].state = 'loading';
 351+ }
 352+ }
 353+ }
 354+ }
 355+ // Fill batch with modules that need to be loaded
 356+ for ( var q in queue ) {
 357+ append( queue[q].needs );
 358+ for ( n in queue[q].needs ) {
 359+ append( needs( queue[q].needs[n] ) );
 360+ }
 361+ }
 362+ // After document ready, handle the batch
 363+ if ( ready && batch.length ) {
 364+ // Always order modules alphabetically to help reduce cache misses for otherwise identical content
 365+ batch.sort();
 366+
 367+ var base = $.extend( {},
 368+ // Pass configuration values through the URL
 369+ mw.config.get( [ 'user', 'skin', 'space', 'view', 'language' ] ),
 370+ // Ensure request comes back in the proper mode (debug or not)
 371+ { 'debug': typeof mw.debug !== 'undefined' ? '1' : '0' }
 372+ );
 373+ var requests = [];
 374+ if ( base.debug == '1' ) {
 375+ for ( b in batch ) {
 376+ requests[requests.length] = $.extend( { 'modules': batch[b] }, base );
 377+ }
 378+ } else {
 379+ requests[requests.length] = $.extend( { 'modules': batch.join( '|' ) }, base );
 380+ }
 381+ // It may be more performant to do this with an Ajax call, but that's limited to same-domain, so we
 382+ // can either auto-detect (if there really is any benefit) or just use this method, which is safe
 383+ setTimeout( function() {
 384+ // Clear the batch - this MUST happen before we append the script element to the body or it's
 385+ // possible that the script will be locally cached, instantly load, and work the batch again,
 386+ // all before we've cleared it causing each request to include modules which are already loaded
 387+ batch = [];
 388+ var html = '';
 389+ for ( r in requests ) {
 390+ // Build out the HTML
 391+ var src = mw.config.get( 'wgScriptPath' ) + '/load.php?' + jQuery.param( requests[r] );
 392+ html += '<script type="text/javascript" src="' + src + '"></script>';
 393+ }
 394+ // Append script to head
 395+ $( 'head' ).append( html );
 396+ }, 0 )
 397+ }
 398+ };
 399+ /**
 400+ * Registers a module, letting the system know about it and it's dependencies. loader.js files contain calls
 401+ * to this function.
 402+ */
 403+ this.register = function( name, needs ) {
 404+ // Validate input
 405+ if ( typeof name !== 'string' ) {
 406+ throw new Error( 'name must be a string, not a ' + typeof name );
 407+ }
 408+ if ( typeof registry[name] !== 'undefined' ) {
 409+ throw new Error( 'module already implemeneted: ' + name );
 410+ }
 411+ // List the module as registered
 412+ registry[name] = { 'state': 'registered', 'needs': [] };
 413+ // Allow needs to be given as a function which returns a string or array
 414+ if ( typeof needs === 'function' ) {
 415+ needs = needs();
 416+ }
 417+ if ( typeof needs === 'string' ) {
 418+ // Allow needs to be given as a single module name
 419+ registry[name].needs = [needs];
 420+ } else if ( typeof needs === 'object' ) {
 421+ // Allow needs to be given as an array of module names
 422+ registry[name].needs = needs;
 423+ }
 424+ };
 425+ /**
 426+ * Implements a module, giving the system a course of action to take upon loading. Results of a request for
 427+ * one or more modules contain calls to this function.
 428+ */
 429+ this.implement = function( name, script, style, localization ) {
 430+ // Automaically register module
 431+ if ( typeof registry[name] === 'undefined' ) {
 432+ that.register( name, needs );
 433+ }
 434+ // Validate input
 435+ if ( typeof script !== 'function' ) {
 436+ throw new Error( 'script must be a function, not a ' + typeof script );
 437+ }
 438+ if ( typeof style !== 'undefined' && typeof style !== 'string' ) {
 439+ throw new Error( 'style must be a string, not a ' + typeof style );
 440+ }
 441+ if ( typeof localization !== 'undefined' && typeof localization !== 'object' ) {
 442+ throw new Error( 'localization must be an object, not a ' + typeof localization );
 443+ }
 444+ if ( typeof registry[name] !== 'undefined' && typeof registry[name].script !== 'undefined' ) {
 445+ throw new Error( 'module already implemeneted: ' + name );
 446+ }
 447+ // Mark module as loaded
 448+ registry[name].state = 'loaded';
 449+ // Attach components
 450+ registry[name].script = script;
 451+ if ( typeof style === 'string' ) {
 452+ registry[name].style = style;
 453+ }
 454+ if ( typeof localization === 'object' ) {
 455+ registry[name].localization = localization;
 456+ }
 457+ // Execute or queue callback
 458+ if ( filter( ['ready'], registry[name].needs ).length == registry[name].needs.length ) {
 459+ execute( name );
 460+ } else {
 461+ request( registry[name].needs, function() { execute( name ); } );
 462+ }
 463+ };
 464+ /**
 465+ * Executes a function as soon as one or more required modules are ready
 466+ *
 467+ * @param mixed string or array of strings of modules names the callback needs to be ready before executing
 468+ * @param function callback to execute when all needs are met
 469+ */
 470+ this.using = function( needs, callback ) {
 471+ // Validate input
 472+ if ( typeof needs !== 'object' && typeof needs !== 'string' ) {
 473+ throw new Error( 'needs must be a string or an array, not a ' + typeof needs )
 474+ }
 475+ if ( typeof callback !== 'function' ) {
 476+ throw new Error( 'callback must be a function, not a ' + typeof callback )
 477+ }
 478+ if ( typeof needs === 'string' ) {
 479+ needs = [needs];
 480+ }
 481+ // Execute or queue callback
 482+ if ( filter( ['ready'], needs ).length == needs.length ) {
 483+ callback();
 484+ } else {
 485+ request( needs, callback );
 486+ }
 487+ };
 488+
 489+ /* Event Bindings */
 490+
 491+ $( document ).ready( function() {
 492+ ready = true;
 493+ that.work();
 494+ } );
 495+ } )();
 496+
 497+ /* Extension points */
 498+
 499+ this.utilities = {};
 500+
 501+ // Attach to window
 502+ window.MediaWiki = window.mw = $.extend( 'mw' in window ? window.mw : {}, this );
 503+} )();
\ No newline at end of file
Property changes on: branches/resourceloader/phase3/resources/mediawiki/mediawiki.js
___________________________________________________________________
Added: svn:eol-style
1504 + native

Status & tagging log