r70182 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r70181‎ | r70182 | r70183 >
Date:23:53, 29 July 2010
Author:tparscal
Status:deferred (Comments)
Tags:
Comment:
Ported more js from skins/common
Modified paths:
  • /branches/resourceloader/phase3/resources/mw/legacy/mw.legacy.IEFixes.js (modified) (history)
  • /branches/resourceloader/phase3/resources/mw/legacy/mw.legacy.htmlform.js (modified) (history)
  • /branches/resourceloader/phase3/resources/mw/legacy/mw.legacy.metadata.js (modified) (history)
  • /branches/resourceloader/phase3/resources/mw/legacy/mw.legacy.mwsuggest.js (modified) (history)
  • /branches/resourceloader/phase3/resources/mw/legacy/mw.legacy.prefs.js (modified) (history)
  • /branches/resourceloader/phase3/resources/mw/legacy/mw.legacy.preview.js (modified) (history)
  • /branches/resourceloader/phase3/resources/mw/legacy/mw.legacy.protect.js (modified) (history)
  • /branches/resourceloader/phase3/resources/mw/legacy/mw.legacy.rightclickedit.js (modified) (history)
  • /branches/resourceloader/phase3/resources/mw/legacy/mw.legacy.search.js (modified) (history)
  • /branches/resourceloader/phase3/resources/mw/legacy/mw.legacy.upload.js (modified) (history)
  • /branches/resourceloader/phase3/resources/mw/legacy/mw.legacy.wikibits.js (modified) (history)

Diff [purge]

Index: branches/resourceloader/phase3/resources/mw/legacy/mw.legacy.prefs.js
@@ -1,5 +1,9 @@
22 /*
33 * 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
48 */
59
610 ( function( $, mw ) {
@@ -7,13 +11,223 @@
812 /* Extension */
913
1014 $.extend( mw.legacy, {
11 - //
 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+ }
12225 } );
13226
14227 /* Initialization */
15228
16229 $( document ).ready( function() {
17 - //
 230+ mw.legacy.timezoneSetup();
 231+ mw.legacy.tabbedprefs();
18232 } );
19233
20234 } )( jQuery, MediaWiki );
\ No newline at end of file
Index: branches/resourceloader/phase3/resources/mw/legacy/mw.legacy.metadata.js
@@ -7,13 +7,47 @@
88 /* Extension */
99
1010 $.extend( mw.legacy, {
11 - //
 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+ }
1252 } );
1353
14 -/* Initialization */
15 -
16 -$( document ).ready( function() {
17 - //
18 -} );
19 -
2054 } )( jQuery, MediaWiki );
\ No newline at end of file
Index: branches/resourceloader/phase3/resources/mw/legacy/mw.legacy.protect.js
@@ -7,13 +7,340 @@
88 /* Extension */
99
1010 $.extend( mw.legacy, {
11 - //
12 -} );
 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(); } );
1351
14 -/* Initialization */
 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 );
1557
16 -$( document ).ready( function() {
17 - //
 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+ }
18345 } );
19346
20347 } )( jQuery, MediaWiki );
\ No newline at end of file
Index: branches/resourceloader/phase3/resources/mw/legacy/mw.legacy.preview.js
@@ -1,5 +1,7 @@
22 /*
33 * Legacy emulation for the now depricated skins/common/preview.js
 4+ *
 5+ * Inline ("Live") preview
46 */
57
68 ( function( $, mw ) {
@@ -7,13 +9,113 @@
810 /* Extension */
911
1012 $.extend( mw.legacy, {
11 - //
 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+ }
1251 } );
1352
1453 /* Initialization */
1554
1655 $( document ).ready( function() {
17 - //
 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 );
18120 } );
19121
20122 } )( jQuery, MediaWiki );
\ No newline at end of file
Index: branches/resourceloader/phase3/resources/mw/legacy/mw.legacy.upload.js
@@ -7,13 +7,326 @@
88 /* Extension */
99
1010 $.extend( mw.legacy, {
11 - //
 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 The id of the selected radio button
 221+ * @return emptiness
 222+ */
 223+ 'toggleUploadInputs': function() {
 224+ // Iterate over all rows with UploadSourceField
 225+ var rows;
 226+ if ( document.getElementsByClassName ) {
 227+ rows = document.getElementsByClassName( 'mw-htmlform-field-UploadSourceField' );
 228+ } else {
 229+ // Older browsers don't support getElementsByClassName
 230+ rows = new Array();
 231+ var allRows = document.getElementsByTagName( 'tr' );
 232+ for ( var i = 0; i < allRows.length; i++ ) {
 233+ if ( allRows[i].className == 'mw-htmlform-field-UploadSourceField' )
 234+ rows.push( allRows[i] );
 235+ }
 236+ }
 237+ for ( var i = 0; i < rows.length; i++ ) {
 238+ var inputs = rows[i].getElementsByTagName( 'input' );
 239+ // Check if this row is selected
 240+ var isChecked = true; // Default true in case wpSourceType is not found
 241+ for ( var j = 0; j < inputs.length; j++ ) {
 242+ if ( inputs[j].name == 'wpSourceType' )
 243+ isChecked = inputs[j].checked;
 244+ }
 245+ // Disable all unselected rows
 246+ for ( var j = 0; j < inputs.length; j++ ) {
 247+ if ( inputs[j].type != 'radio')
 248+ inputs[j].disabled = !isChecked;
 249+ }
 250+ }
 251+ },
 252+ 'fillDestFilename': function(id) {
 253+ if (!wgUploadAutoFill) {
 254+ return;
 255+ }
 256+ if (!document.getElementById) {
 257+ return;
 258+ }
 259+ // Remove any previously flagged errors
 260+ var e = document.getElementById( 'mw-upload-permitted' );
 261+ if( e ) e.className = '';
 262+ var e = document.getElementById( 'mw-upload-prohibited' );
 263+ if( e ) e.className = '';
 264+ var path = document.getElementById(id).value;
 265+ // Find trailing part
 266+ var slash = path.lastIndexOf('/');
 267+ var backslash = path.lastIndexOf('\\');
 268+ var fname;
 269+ if (slash == -1 && backslash == -1) {
 270+ fname = path;
 271+ } else if (slash > backslash) {
 272+ fname = path.substring(slash+1, 10000);
 273+ } else {
 274+ fname = path.substring(backslash+1, 10000);
 275+ }
 276+ // Clear the filename if it does not have a valid extension.
 277+ // URLs are less likely to have a useful extension, so don't include them in the
 278+ // extension check.
 279+ if( wgStrictFileExtensions && wgFileExtensions && id != 'wpUploadFileURL' ) {
 280+ var found = false;
 281+ if( fname.lastIndexOf( '.' ) != -1 ) {
 282+ var ext = fname.substr( fname.lastIndexOf( '.' ) + 1 );
 283+ for( var i = 0; i < wgFileExtensions.length; i++ ) {
 284+ if( wgFileExtensions[i].toLowerCase() == ext.toLowerCase() ) {
 285+ found = true;
 286+ break;
 287+ }
 288+ }
 289+ }
 290+ if( !found ) {
 291+ // Not a valid extension
 292+ // Clear the upload and set mw-upload-permitted to error
 293+ document.getElementById(id).value = '';
 294+ var e = document.getElementById( 'mw-upload-permitted' );
 295+ if( e ) e.className = 'error';
 296+ var e = document.getElementById( 'mw-upload-prohibited' );
 297+ if( e ) e.className = 'error';
 298+ // Clear wpDestFile as well
 299+ var e = document.getElementById( 'wpDestFile' )
 300+ if( e ) e.value = '';
 301+
 302+ return false;
 303+ }
 304+ }
 305+ // Capitalise first letter and replace spaces by underscores
 306+ // FIXME: $wgCapitalizedNamespaces
 307+ fname = fname.charAt(0).toUpperCase().concat(fname.substring(1,10000)).replace(/ /g, '_');
 308+ // Output result
 309+ var destFile = document.getElementById('wpDestFile');
 310+ if (destFile) {
 311+ destFile.value = fname;
 312+ wgUploadWarningObj.checkNow(fname) ;
 313+ }
 314+ },
 315+ 'toggleFilenameFiller': function() {
 316+ if(!document.getElementById) return;
 317+ var upfield = document.getElementById('wpUploadFile');
 318+ var destName = document.getElementById('wpDestFile').value;
 319+ if (destName=='' || destName==' ') {
 320+ wgUploadAutoFill = true;
 321+ } else {
 322+ wgUploadAutoFill = false;
 323+ }
 324+ }
12325 } );
13326
14327 /* Initialization */
15328
16329 $( document ).ready( function() {
17 - //
 330+ mw.legacy.wgUploadSetup();
18331 } );
19332
20333 } )( jQuery, MediaWiki );
\ No newline at end of file
Index: branches/resourceloader/phase3/resources/mw/legacy/mw.legacy.wikibits.js
@@ -1,5 +1,7 @@
22 /*
33 * Legacy emulation for the now depricated skins/common/wikibits.js
 4+ *
 5+ * MediaWiki JavaScript support functions
46 */
57
68 ( function( $, mw ) {
Index: branches/resourceloader/phase3/resources/mw/legacy/mw.legacy.mwsuggest.js
@@ -1,5 +1,11 @@
22 /*
33 * 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)
410 */
511
612 ( function( $, mw ) {
@@ -7,13 +13,1019 @@
814 /* Extension */
915
1016 $.extend( mw.legacy, {
11 - //
 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+ }
121024 } );
131025
141026 /* Initialization */
151027
161028 $( document ).ready( function() {
17 - //
 1029+ mw.legacy.os_MWSuggestInit();
181030 } );
191031
201032 } )( jQuery, MediaWiki );
\ No newline at end of file
Index: branches/resourceloader/phase3/resources/mw/legacy/mw.legacy.htmlform.js
@@ -7,13 +7,44 @@
88 /* Extension */
99
1010 $.extend( mw.legacy, {
11 - //
 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+ }
1238 } );
1339
1440 /* Initialization */
1541
1642 $( document ).ready( function() {
17 - //
 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+ } );
1849 } );
1950
2051 } )( jQuery, MediaWiki );
\ No newline at end of file
Index: branches/resourceloader/phase3/resources/mw/legacy/mw.legacy.rightclickedit.js
@@ -7,13 +7,60 @@
88 /* Extension */
99
1010 $.extend( mw.legacy, {
11 - //
 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+
 45+ // We don't want to deprive the noble reader of a context menu
 46+ // for the section edit link, do we? (Might want to extend this
 47+ // to all <a>'s?)
 48+ if (targ.nodeName.toLowerCase() != 'a'
 49+ || targ.parentNode.className != 'editsection') {
 50+ document.location = editHref;
 51+ return false;
 52+ }
 53+ return true;
 54+ };
 55+ }
 56+ }
 57+ }
 58+ }
1259 } );
1360
1461 /* Initialization */
1562
1663 $( document ).ready( function() {
17 - //
 64+ mw.legacy.setupRightClickEdit();
1865 } );
1966
2067 } )( jQuery, MediaWiki );
\ No newline at end of file
Index: branches/resourceloader/phase3/resources/mw/legacy/mw.legacy.IEFixes.js
@@ -1,19 +1,141 @@
22 /*
33 * Legacy emulation for the now depricated skins/common/IEFixes.js
 4+ *
 5+ * Internet Explorer JavaScript fixes
46 */
57
68 ( function( $, mw ) {
79
 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+
825 /* Extension */
926
1027 $.extend( mw.legacy, {
11 - //
 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+ }
12134 } );
13135
14136 /* Initialization */
15137
16138 $( document ).ready( function() {
17 - //
 139+ mw.legacy.hookit();
18140 } );
19141
20142 } )( jQuery, MediaWiki );
\ No newline at end of file
Index: branches/resourceloader/phase3/resources/mw/legacy/mw.legacy.search.js
@@ -1,5 +1,7 @@
22 /*
33 * Legacy emulation for the now depricated skins/common/search.js
 4+ *
 5+ * Progressive enhancement for Special:Search
46 */
57
68 ( function( $, mw ) {
@@ -7,13 +9,55 @@
810 /* Extension */
911
1012 $.extend( mw.legacy, {
11 - //
 13+
 14+ /* Functions */
 15+
 16+ /**
 17+ * Change the search link to what user entered
 18+ */
 19+ function mwSearchHeaderClick( 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+ function mwToggleSearchCheckboxes( 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+ }
1262 } );
1363
14 -/* Initialization */
15 -
16 -$( document ).ready( function() {
17 - //
18 -} );
19 -
2064 } )( jQuery, MediaWiki );
\ No newline at end of file

Comments

#Comment by Catrope (talk | contribs)   17:52, 4 August 2010

Plain function calls like fixalpha(); need to be changed to mw.legacy.fixalpha(); throughout mediawiki.legacy.IEFixes.js, mediawiki.legacy.history.js, mediawiki.legacy.metadata.js, mediawiki.legacy.mwsuggest.js, mediawiki.legacy.prefs.js, mediawiki.legacy.preview.js, mediawiki.legacy.protect.js and mediawiki.legacy.search.js. It also seems that, in most of these cases, the code was simply copypasted verbatim (except for putting initialization code in document ready) without any attempted porting whatsoever. The latter also applies to mediawiki.legacy.rightclickedit.js, mediawiki.legacy.upload.js and mw.legacy.wikibits.js.

Not introduced in this rev but related anyway:

In mediawiki.legacy.ajax.js:

delete x;

The variable x has been renamed to request, but you missed this statement.

In mediawiki.legacy.htmlform.js:

	$( 'select .mw-htmlform-select-or-other' ).each( function() {

This is not the correct translation of getElementsByClassName( document, 'select', 'mw-htmlform-select-or-other' );: it should be $( 'select.mw-htmlform-select-or-other' ), without the space.

		$(this).change( function() { mw.legacy.htmlforms.selectOrOtherSelectChanged(); } );

Should be .change( mw.legacy.htmlforms.selectOrOtherSelectChanged );, the current code breaks because selectOrOtherSelectChanged() expects an event object as its parameter. That, BTW, is unnecessary, because it can simply use this without spending 12 lines of code figuring out which DOM object it was called on.


In mediawiki.legacy.ajaxwatch.js:

			wgAjaxWatch.setLinkText( $link, otheraction );

Also needs mw.legacy. prefix.

// update the link text with the new message
$link.text( wgAjaxWatch[ otheraction + 'Msg'] );

These statements were in the old file but were dropped, why?

In mediawiki.legacy.block.js:

			if ( $expiry.val() == 'other' ) {
				$other.css( 'display', '' );
			} else {
				$other.css( 'display', 'none' );
			}
[...]
			$( '#wpAnonOnlyRow' ).css( 'display', !isIp && !isEmpty ? 'none' : '' );
			$( '#wpEnableAutoblockRow,#wpEnableHideUser' ).css( 'display', isIp && !isEmpty ? 'none' : '' );
			$( '#wpEnableWatchUser' ).css( 'display', isIpRange && !isEmpty ? 'none' : '' );

If you're gonna port it to jQuery anyway, why not go all the way and use .show() and .hide()

In mediawiki.legacy.edit.js:

		var $textbox = $( 'textarea' ).get( 0 );

.get() returns a DOM object, what you want is .eq().

			textboxes[0].selectionStart === null

textboxes is not defined here. You forgot to replace this instance of textboxes[0] with $textbox.get( 0 ).

			if ( scrollTop.val() ) {

Shoud be $scrollTop

$( '#editform' ).focus( function() {
		$(this).each( function( e ) {
			var elm = e.target || e.srcElement;
			if ( !elm ) {
				return;
			}
			var tagName = elm.tagName.toLowerCase();
			var type = elm.type || '';
			if ( tagName !== 'textarea' && tagName !== 'input' ) {
				return;
			}
			if ( tagName === 'input' && type.toLowerCase() !== 'text' ) {
				return;
			}
			mw.legacy.currentFocused = elm;
		} );
	} );

This looks wrong. The e parameter should be coming from the focus event instead, and the .each() call is useless.

	var $iframe = $j( '.wikiEditor-ui-text iframe' );
	if ( $iframe.length > 0 ) {
		$j( $iframe.get( 0 ).contentWindow.document )

Use $, not $j.

In mediawiki.legacy.wikibits.js:

		return importScriptURI( uri );
[...]
		return importStylesheetURI( wgScript + '?action=raw&ctype=text/css&title=' + encodeURIComponent( page.replace(/ /g,'_') ) );
[...]
		updateTooltipAccessKeys( null );
		setupCheckboxShiftClick();
		sortables_init();
[...]
		addHandler( element, 'click', handler );
[...]
					updateTooltipAccessKeys( linkContainer.getElementsByTagName( 'a' ) );
[...]
			updateTooltipAccessKeys( document.getElementsByTagName( 'input' ) );
			updateTooltipAccessKeys( document.getElementsByTagName( 'label' ) );
[...]
		addCheckboxClickHandlers( inputs );
[...]
			addClickHandler( cb, checkboxClickHandler );
[...]
				addCheckboxClickHandlers( inputs, finish );
[...]
			addClickHandler( toggleLink, function( evt ) { toggleToc(); return killEvt( evt ); } ); # That's 3 on one line
[...]
				toggleToc();
[...]
			changeText( toggleLink, tocHideText );
[...]
			changeText( toggleLink, tocShowText );
[...]
		return getInnerText( el );
[...]
				addOnloadHook(function() {
[...]
			importStylesheetURI( stylepath + '/' + skin + '/Opera6Fixes.css' );
[...]
	runOnloadHook();

All these need prefixing, and there's probably more in there too.

#Comment by Trevor Parscal (WMF) (talk | contribs)   17:57, 4 August 2010

All excellent points - I'm going to be taking some more time to finish this unfinished work soon. In the mean time, disregard this area of the code please :)

Status & tagging log