summaryrefslogtreecommitdiff
path: root/resources/mediawiki.special
diff options
context:
space:
mode:
authorPierre Schmitz <pierre@archlinux.de>2011-12-03 13:29:22 +0100
committerPierre Schmitz <pierre@archlinux.de>2011-12-03 13:29:22 +0100
commitca32f08966f1b51fcb19460f0996bb0c4048e6fe (patch)
treeec04cc15b867bc21eedca904cea9af0254531a11 /resources/mediawiki.special
parenta22fbfc60f36f5f7ee10d5ae6fe347340c2ee67c (diff)
Update to MediaWiki 1.18.0
* also update ArchLinux skin to chagnes in MonoBook * Use only css to hide our menu bar when printing
Diffstat (limited to 'resources/mediawiki.special')
-rw-r--r--resources/mediawiki.special/mediawiki.special.block.js46
-rw-r--r--resources/mediawiki.special/mediawiki.special.changeslist.css47
-rw-r--r--resources/mediawiki.special/mediawiki.special.css274
-rw-r--r--resources/mediawiki.special/mediawiki.special.js1
-rw-r--r--resources/mediawiki.special/mediawiki.special.movePage.js5
-rw-r--r--resources/mediawiki.special/mediawiki.special.preferences.js172
-rw-r--r--resources/mediawiki.special/mediawiki.special.recentchanges.js39
-rw-r--r--resources/mediawiki.special/mediawiki.special.search.css14
-rw-r--r--resources/mediawiki.special/mediawiki.special.search.js32
-rw-r--r--resources/mediawiki.special/mediawiki.special.undelete.js10
-rw-r--r--resources/mediawiki.special/mediawiki.special.upload.js272
11 files changed, 872 insertions, 40 deletions
diff --git a/resources/mediawiki.special/mediawiki.special.block.js b/resources/mediawiki.special/mediawiki.special.block.js
new file mode 100644
index 00000000..6f79929b
--- /dev/null
+++ b/resources/mediawiki.special/mediawiki.special.block.js
@@ -0,0 +1,46 @@
+/* JavaScript for Special:Block */
+
+jQuery( function( $ ) {
+
+ var DO_INSTANT = true,
+ $blockTarget = $( '#mw-bi-target' ),
+ $anonOnlyRow = $( '#mw-input-wpHardBlock' ).closest( 'tr' ),
+ $enableAutoblockRow = $( '#mw-input-wpAutoBlock' ).closest( 'tr' ),
+ $hideUser = $( '#mw-input-wpHideUser' ).closest( 'tr' ),
+ $watchUser = $( '#mw-input-wpWatch' ).closest( 'tr' );
+
+ var updateBlockOptions = function( instant ) {
+ if ( !$blockTarget.length ) {
+ return;
+ }
+
+ var blocktarget = $.trim( $blockTarget.val() );
+ var isEmpty = ( blocktarget === '' );
+ var isIp = mw.util.isIPv4Address( blocktarget, true ) || mw.util.isIPv6Address( blocktarget, true );
+ var isIpRange = isIp && blocktarget.match( /\/\d+$/ );
+
+ if ( isIp && !isEmpty ) {
+ $enableAutoblockRow.goOut( instant );
+ $hideUser.goOut( instant );
+ } else {
+ $enableAutoblockRow.goIn( instant );
+ $hideUser.goIn( instant );
+ }
+ if ( !isIp && !isEmpty ) {
+ $anonOnlyRow.goOut( instant );
+ } else {
+ $anonOnlyRow.goIn( instant );
+ }
+ if ( isIpRange && !isEmpty ) {
+ $watchUser.goOut( instant );
+ } else {
+ $watchUser.goIn( instant );
+ }
+ };
+
+ // Bind functions so they're checked whenever stuff changes
+ $blockTarget.keyup( updateBlockOptions );
+
+ // Call them now to set initial state (ie. Special:Block/Foobar?wpBlockExpiry=2+hours)
+ updateBlockOptions( DO_INSTANT );
+});
diff --git a/resources/mediawiki.special/mediawiki.special.changeslist.css b/resources/mediawiki.special/mediawiki.special.changeslist.css
new file mode 100644
index 00000000..cb4d2156
--- /dev/null
+++ b/resources/mediawiki.special/mediawiki.special.changeslist.css
@@ -0,0 +1,47 @@
+/**
+ * Styling for Special:Watchlist and Special:RecentChanges
+ */
+
+table.mw-enhanced-rc {
+ border: 0;
+ border-spacing: 0;
+}
+
+table.mw-enhanced-rc th, table.mw-enhanced-rc td {
+ padding: 0;
+ vertical-align: top;
+}
+
+td.mw-enhanced-rc {
+ white-space: nowrap;
+ font-family: monospace;
+}
+
+.mw-enhanced-rc-time {
+ font-family: monospace;
+}
+
+table.mw-enhanced-rc td.mw-enhanced-rc-nested {
+ padding-left: 1em;
+}
+
+/* Show/hide arrows in enhanced changeslist */
+.mw-enhanced-rc .collapsible-expander {
+ float: none;
+}
+
+/* If JS is disabled, the arrow is still needed
+ for spacing, but ideally shouldn't be shown */
+.mw-enhanced-rc .mw-rc-openarrow {
+ visibility: hidden;
+}
+
+.mw-enhanced-rc.mw-made-collapsible .mw-rc-openarrow,
+.mw-enhanced-rc .mw-rc-closearrow {
+ visibility: visible;
+ display: none;
+}
+.mw-enhanced-rc.mw-made-collapsible .mw-collapsible-toggle-collapsed .mw-rc-openarrow,
+.mw-enhanced-rc.mw-made-collapsible .mw-collapsible-toggle-expanded .mw-rc-closearrow {
+ display: inline;
+}
diff --git a/resources/mediawiki.special/mediawiki.special.css b/resources/mediawiki.special/mediawiki.special.css
new file mode 100644
index 00000000..3cd97397
--- /dev/null
+++ b/resources/mediawiki.special/mediawiki.special.css
@@ -0,0 +1,274 @@
+
+/**** Special:AllMessages ****/
+#mw-allmessagestable .allmessages-customised td.am_default {
+ background-color: #fcffc4;
+}
+
+#mw-allmessagestable tr.allmessages-customised:hover td.am_default {
+ background-color: #faff90;
+}
+
+#mw-allmessagestable td.am_actual {
+ background-color: #e2ffe2;
+}
+
+#mw-allmessagestable tr.allmessages-customised:hover + tr.allmessages-customised td.am_actual {
+ background-color: #b1ffb1;
+}
+
+/**** Special:Allpages ****/
+table.mw-allpages-table-form, table.mw-allpages-table-chunk {
+ width: 100%;
+}
+td.mw-allpages-alphaindexline {
+ text-align: right;
+}
+.mw-allpages-nav {
+ text-align: right;
+ margin-bottom: 1em;
+}
+table.mw-allpages-table-form tr {
+ vertical-align: top;
+}
+
+/**** Special:Block ****/
+tr.mw-block-hideuser {
+ font-weight: bold;
+}
+
+/**** Special:BlockList ****/
+table.mw-blocklist span.mw-usertoollinks,
+span.mw-blocklist-actions{
+ white-space: nowrap;
+ font-size: 90%;
+}
+
+/**** Special:Contributions ****/
+.mw-uctop {
+ font-weight: bold;
+}
+
+/**** Special:EmailUser ****/
+table.mw-emailuser-table {
+ width: 98%;
+}
+td#mw-emailuser-sender,
+td#mw-emailuser-recipient {
+ font-weight: bold;
+}
+
+/**** Special:ListGroupRights ****/
+table.mw-listgrouprights-table tr {
+ vertical-align: top;
+}
+.listgrouprights-revoked {
+ text-decoration: line-through;
+}
+
+/**** Special:Prefixindex ****/
+table#mw-prefixindex-list-table,
+table#mw-prefixindex-nav-table {
+ width: 98%;
+}
+td#mw-prefixindex-nav-form {
+ margin-bottom: 1em;
+ vertical-align: top;
+}
+.mw-prefixindex-nav {
+ text-align: right;
+}
+
+
+/**** Special:Search ****/
+.searchresults {
+}
+
+.searchresults p {
+ margin-left: 0.4em;
+ margin-top: 1em;
+ margin-bottom: 1.2em;
+}
+div.searchresult {
+ font-size: 95%;
+ width: 38em;
+}
+.mw-search-results {
+ margin-left: 0.4em;
+}
+.mw-search-results li {
+ padding-bottom: 1em;
+ list-style: none;
+ list-style-image: none;
+}
+.mw-search-results li a {
+ font-size: 108%;
+}
+.mw-search-result-data {
+ color: green;
+ font-size: 97%;
+}
+.mw-search-formheader {
+ background-color: #f3f3f3;
+ margin-top: 1em;
+ border: 1px solid silver;
+}
+.mw-search-formheader div.search-types {
+ float: left;
+ padding-left: 0.25em;
+}
+.mw-search-formheader div.search-types ul {
+ margin: 0 !important;
+ padding: 0 !important;
+ list-style: none !important;
+}
+.mw-search-formheader div.search-types ul li {
+ float: left;
+ margin: 0;
+ padding: 0;
+}
+.mw-search-formheader div.search-types ul li a {
+ display: block;
+ padding: 0.5em;
+}
+.mw-search-formheader div.search-types ul li.current a {
+ color: #333333;
+ cursor: default;
+}
+.mw-search-formheader div.search-types ul li.current a:hover {
+ text-decoration: none;
+}
+.mw-search-formheader div.results-info {
+ float: right;
+ padding: 0.5em;
+ padding-right: 0.75em;
+}
+.mw-search-formheader div.results-info ul {
+ margin: 0 !important;
+ padding: 0 !important;
+ list-style: none !important;
+}
+.mw-search-formheader div.results-info ul li {
+ float: right;
+ margin: 0;
+ padding: 0;
+}
+fieldset#mw-searchoptions {
+ margin: 0;
+ padding: 0.5em 0.75em 0.75em 0.75em !important;
+ border: none;
+ background-color: #f9f9f9;
+ border: 1px solid silver !important;
+ border-top-width: 0 !important;
+}
+fieldset#mw-searchoptions legend {
+ display: none;
+}
+fieldset#mw-searchoptions h4 {
+ padding: 0;
+ margin: 0;
+ float: left;
+}
+fieldset#mw-searchoptions div#mw-search-togglebox {
+ float: right;
+}
+fieldset#mw-searchoptions div#mw-search-togglebox label {
+ margin-right: 0.25em;
+}
+fieldset#mw-searchoptions div#mw-search-togglebox input {
+ margin-left: 0.25em;
+}
+fieldset#mw-searchoptions table {
+ float: left;
+ margin-right: 3em;
+}
+fieldset#mw-searchoptions table td {
+ padding-right: 1em;
+}
+fieldset#mw-searchoptions div.divider {
+ clear: both;
+ border-bottom: 1px solid #DDDDDD;
+ padding-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+td#mw-search-menu {
+ padding-left:6em;
+ font-size:85%;
+}
+div#mw-search-interwiki {
+ float: right;
+ width: 18em;
+ border: 1px solid #AAAAAA;
+ margin-top: 2ex;
+}
+div#mw-search-interwiki li {
+ font-size: 95%;
+}
+.mw-search-interwiki-more {
+ float: right;
+ font-size: 90%;
+}
+div#mw-search-interwiki-caption {
+ text-align: center;
+ font-weight: bold;
+ font-size: 95%;
+}
+.mw-search-interwiki-project {
+ font-size: 97%;
+ text-align: left;
+ padding: 0.15em 0.15em 0.2em 0.2em;
+ background-color: #ececec;
+ border-top: 1px solid #BBBBBB;
+}
+span.searchalttitle {
+ font-size: 95%;
+}
+div.searchdidyoumean {
+ font-size: 127%;
+ margin-top: 0.8em;
+ /* Note that this color won't affect the link, as desired. */
+ color: #c00;
+}
+div.searchdidyoumean em {
+ font-weight: bold;
+}
+.searchmatch {
+ font-weight: bold;
+}
+/* Advanced PowerSearch box */
+td#mw-search-togglebox {
+ text-align: right;
+}
+table#mw-search-powertable {
+ width: 100%;
+}
+form#powersearch {
+ clear: both;
+}
+
+/**** Special:Specialpages ****/
+.mw-specialpagerestricted {
+ font-weight: bold;
+}
+
+.mw-specialpages-table {
+ margin-top: -1em;
+ margin-bottom: 1em;
+}
+
+.mw-specialpages-table td {
+ vertical-align: top;
+}
+
+/**** Special:Statistics ****/
+td.mw-statistics-numbers {
+ text-align: right;
+}
+
+/**** Special:UserRights ****/
+.mw-userrights-disabled {
+ color: #888;
+}
+table.mw-userrights-groups * td,
+table.mw-userrights-groups * th {
+ padding-right: 1.5em;
+}
diff --git a/resources/mediawiki.special/mediawiki.special.js b/resources/mediawiki.special/mediawiki.special.js
new file mode 100644
index 00000000..3526cef4
--- /dev/null
+++ b/resources/mediawiki.special/mediawiki.special.js
@@ -0,0 +1 @@
+mw.special = {};
diff --git a/resources/mediawiki.special/mediawiki.special.movePage.js b/resources/mediawiki.special/mediawiki.special.movePage.js
new file mode 100644
index 00000000..2f94cc06
--- /dev/null
+++ b/resources/mediawiki.special/mediawiki.special.movePage.js
@@ -0,0 +1,5 @@
+/* JavaScript for Special:MovePage */
+
+jQuery( function( $ ) {
+ $( '#wpReason' ).byteLimit();
+});
diff --git a/resources/mediawiki.special/mediawiki.special.preferences.js b/resources/mediawiki.special/mediawiki.special.preferences.js
index 1775bec4..2e07e7f1 100644
--- a/resources/mediawiki.special/mediawiki.special.preferences.js
+++ b/resources/mediawiki.special/mediawiki.special.preferences.js
@@ -2,44 +2,61 @@
* JavaScript for Special:Preferences
*/
( function( $, mw ) {
-
$( '#prefsubmit' ).attr( 'id', 'prefcontrol' );
-$( '#preferences' )
+var $preftoc = $('<ul id="preftoc"></ul>');
+var $preferences = $( '#preferences' )
.addClass( 'jsprefs' )
- .before( $( '<ul id="preftoc"></ul>' ) )
- .children( 'fieldset' )
- .hide()
- .addClass( 'prefsection' )
- .children( 'legend' )
- .addClass( 'mainLegend' )
- .each( function( i ) {
- $(this).parent().attr( 'id', 'prefsection-' + i );
- if ( i === 0 ) {
- $(this).parent().show();
- }
- $( '#preftoc' ).append(
- $( '<li></li>' )
- .addClass( i === 0 ? 'selected' : null )
- .append(
- $( '<a></a>')
- .text( $(this).text() )
- .attr( 'href', '#prefsection-' + i )
- .mousedown( function( e ) {
- $(this).parent().parent().find( 'li' ).removeClass( 'selected' );
- $(this).parent().addClass( 'selected' );
- e.preventDefault();
- return false;
- } )
- .click( function( e ) {
- $( '#preferences > fieldset' ).hide();
- $( '#prefsection-' + i ).show();
- e.preventDefault();
- return false;
- } )
- )
- );
- }
- );
+ .before( $preftoc );
+
+var $fieldsets = $preferences.children( 'fieldset' )
+ .hide()
+ .addClass( 'prefsection' );
+
+var $legends = $fieldsets.children( 'legend' )
+ .addClass( 'mainLegend' );
+
+// Populate the prefToc
+$legends.each( function( i, legend ) {
+ var $legend = $(legend);
+ if ( i === 0 ) {
+ $legend.parent().show();
+ }
+ var ident = $legend.parent().attr( 'id' );
+
+ var $li = $( '<li/>', {
+ 'class' : ( i === 0 ) ? 'selected' : null
+ });
+ var $a = $( '<a/>', {
+ text : $legend.text(),
+ id : ident.replace( 'mw-prefsection', 'preftab' ),
+ href : '#' + ident
+ }).click( function( e ) {
+ e.preventDefault();
+ // Handle hash manually to prevent jumping
+ // Therefore save and restore scrollTop to prevent jumping
+ var scrollTop = $(window).scrollTop();
+ window.location.hash = $(this).attr('href');
+ $(window).scrollTop(scrollTop);
+
+ $preftoc.find( 'li' ).removeClass( 'selected' );
+ $(this).parent().addClass( 'selected' );
+ $( '#preferences > fieldset' ).hide();
+ $( '#' + ident ).show();
+ });
+ $li.append( $a );
+ $preftoc.append( $li );
+} );
+
+// If we've reloaded the page or followed an open-in-new-window,
+// make the selected tab visible.
+// On document ready:
+$( function() {
+ var hash = window.location.hash;
+ if( hash.match( /^#mw-prefsection-[\w-]+/ ) ) {
+ var $tab = $( hash.replace( 'mw-prefsection', 'preftab' ) );
+ $tab.click();
+ }
+} );
/**
* Given an email validity status (true, false, null) update the label CSS class
@@ -74,4 +91,85 @@ $( '#mw-input-wpemailaddress' ).one( 'blur', function() {
updateMailValidityLabel( $(this).val() );
} );
} );
-} )( jQuery, mediaWiki ); \ No newline at end of file
+
+
+
+/**
+* Timezone functions.
+* Guesses Timezone from browser and updates fields onchange
+*/
+
+var $tzSelect = $( '#mw-input-wptimecorrection' );
+var $tzTextbox = $( '#mw-input-wptimecorrection-other' );
+
+var $localtimeHolder = $( '#wpLocalTime' );
+var servertime = parseInt( $( 'input[name=wpServerTime]' ).val(), 10 );
+var minuteDiff = 0;
+
+var minutesToHours = function( min ) {
+ var tzHour = Math.floor( Math.abs( min ) / 60 );
+ var tzMin = Math.abs( min ) % 60;
+ var tzString = ( ( min >= 0 ) ? '' : '-' ) + ( ( tzHour < 10 ) ? '0' : '' ) + tzHour +
+ ':' + ( ( tzMin < 10 ) ? '0' : '' ) + tzMin;
+ return tzString;
+};
+
+var hoursToMinutes = function( hour ) {
+ var arr = hour.split( ':' );
+ arr[0] = parseInt( arr[0], 10 );
+
+ var minutes;
+ if ( arr.length == 1 ) {
+ // Specification is of the form [-]XX
+ minutes = arr[0] * 60;
+ } else {
+ // Specification is of the form [-]XX:XX
+ minutes = Math.abs( arr[0] ) * 60 + parseInt( arr[1], 10 );
+ if ( arr[0] < 0 ) {
+ minutes *= -1;
+ }
+ }
+ // Gracefully handle non-numbers.
+ if ( isNaN( minutes ) ) {
+ return 0;
+ } else {
+ return minutes;
+ }
+};
+
+var updateTimezoneSelection = function() {
+ var type = $tzSelect.val();
+ if ( type == 'guess' ) {
+ // Get browser timezone & fill it in
+ minuteDiff = -new Date().getTimezoneOffset();
+ $tzTextbox.val( minutesToHours( minuteDiff ) );
+ $tzSelect.val( 'other' );
+ $tzTextbox.get( 0 ).disabled = false;
+ } else if ( type == 'other' ) {
+ // Grab data from the textbox, parse it.
+ minuteDiff = hoursToMinutes( $tzTextbox.val() );
+ } else {
+ // Grab data from the $tzSelect value
+ minuteDiff = parseInt( type.split( '|' )[1], 10 ) || 0;
+ $tzTextbox.val( minutesToHours( minuteDiff ) );
+ }
+
+ // Determine local time from server time and minutes difference, for display.
+ var localTime = servertime + minuteDiff;
+
+ // Bring time within the [0,1440) range.
+ while ( localTime < 0 ) {
+ localTime += 1440;
+ }
+ while ( localTime >= 1440 ) {
+ localTime -= 1440;
+ }
+ $localtimeHolder.text( minutesToHours( localTime ) );
+};
+
+if ( $tzSelect.length && $tzTextbox.length ) {
+ $tzSelect.change( function() { updateTimezoneSelection(); } );
+ $tzTextbox.blur( function() { updateTimezoneSelection(); } );
+ updateTimezoneSelection();
+}
+} )( jQuery, mediaWiki );
diff --git a/resources/mediawiki.special/mediawiki.special.recentchanges.js b/resources/mediawiki.special/mediawiki.special.recentchanges.js
new file mode 100644
index 00000000..7e284fbd
--- /dev/null
+++ b/resources/mediawiki.special/mediawiki.special.recentchanges.js
@@ -0,0 +1,39 @@
+/* JavaScript for Special:RecentChanges */
+( function( $ ) {
+
+ var checkboxes = [ 'nsassociated', 'nsinvert' ];
+
+ /**
+ * @var select {jQuery}
+ */
+ var $select = null;
+
+ var rc = mw.special.recentchanges = {
+
+ /**
+ * Handler to disable/enable the namespace selector checkboxes when the
+ * special 'all' namespace is selected/unselected respectively.
+ */
+ updateCheckboxes: function() {
+ // The option element for the 'all' namespace has an empty value
+ var isAllNS = ('' === $select.find('option:selected').val() );
+
+ // Iterates over checkboxes and propagate the selected option
+ $.each( checkboxes, function( i, id ) {
+ $( '#' + id ).attr( 'disabled', isAllNS );
+ });
+ },
+
+ init: function() {
+ // Populate
+ $select = $( '#namespace' );
+
+ // Bind to change event, and trigger once to set the initial state of the checkboxes.
+ $select.change( rc.updateCheckboxes ).change();
+ }
+ };
+
+ // Run when document is ready
+ $( rc.init );
+
+})( jQuery );
diff --git a/resources/mediawiki.special/mediawiki.special.search.css b/resources/mediawiki.special/mediawiki.special.search.css
new file mode 100644
index 00000000..89d55b0b
--- /dev/null
+++ b/resources/mediawiki.special/mediawiki.special.search.css
@@ -0,0 +1,14 @@
+/**
+ * Fixes sister projects box moving down the extract
+ * of the first result (bug #16886).
+ * It only happens when the window is small and
+ * This changes slightly the layout for big screens
+ * where there was space for the extracts and the
+ * sister projects and thus it showed like in any
+ * other browser.
+ *
+ * This will only affect IE 7 and lower
+ */
+.searchresult {
+ display: inline !ie;
+}
diff --git a/resources/mediawiki.special/mediawiki.special.search.js b/resources/mediawiki.special/mediawiki.special.search.js
index d4317188..bac27fc6 100644
--- a/resources/mediawiki.special/mediawiki.special.search.js
+++ b/resources/mediawiki.special/mediawiki.special.search.js
@@ -1,11 +1,37 @@
/*
- * JavaScript for Specical:Search
+ * JavaScript for Special:Search
*/
-( function( $, mw ) {
+jQuery( function( $ ) {
// Emulate HTML5 autofocus behavior in non HTML5 compliant browsers
if ( !( 'autofocus' in document.createElement( 'input' ) ) ) {
$( 'input[autofocus]:first' ).focus();
}
-} )( jQuery, mediaWiki ); \ No newline at end of file
+// Bind check all/none button
+var $checkboxes = $('#powersearch input[id^=mw-search-ns]');
+$('#mw-search-toggleall').click( function() {
+ $checkboxes.prop("checked", true);
+} );
+$('#mw-search-togglenone').click( function() {
+ $checkboxes.prop("checked", false);
+} );
+
+// Change the header search links to what user entered
+var headerLinks = $('.search-types a');
+$('#searchText, #powerSearchText').change(function() {
+ var searchterm = $(this).val();
+ headerLinks.each( function() {
+ var parts = this.href.split( 'search=' );
+ var lastpart = '';
+ var prefix = 'search=';
+ if( parts.length > 1 && parts[1].indexOf('&') >= 0 ) {
+ lastpart = parts[1].substring( parts[1].indexOf('&') );
+ } else {
+ prefix = '&search=';
+ }
+ this.href = parts[0] + prefix + encodeURIComponent( searchterm ) + lastpart;
+ });
+}).trigger('change');
+
+} ); \ No newline at end of file
diff --git a/resources/mediawiki.special/mediawiki.special.undelete.js b/resources/mediawiki.special/mediawiki.special.undelete.js
new file mode 100644
index 00000000..33b80275
--- /dev/null
+++ b/resources/mediawiki.special/mediawiki.special.undelete.js
@@ -0,0 +1,10 @@
+/*
+ * JavaScript for Specical:Undelete
+ */
+jQuery( document ).ready( function( $ ) {
+ $( '#mw-undelete-invert' ).click( function( e ) {
+ e.preventDefault();
+ $( '#undelete' ).find( 'input:checkbox' )
+ .prop( 'checked', function( i, val ) { return !val; } );
+ } );
+} );
diff --git a/resources/mediawiki.special/mediawiki.special.upload.js b/resources/mediawiki.special/mediawiki.special.upload.js
new file mode 100644
index 00000000..4a8622f5
--- /dev/null
+++ b/resources/mediawiki.special/mediawiki.special.upload.js
@@ -0,0 +1,272 @@
+/*
+ * JavaScript for Special:Upload
+ * Note that additional code still lives in skins/common/upload.js
+ */
+
+/**
+ * Add a preview to the upload form
+ */
+jQuery( function( $ ) {
+ /**
+ * Is the FileAPI available with sufficient functionality?
+ */
+ function hasFileAPI(){
+ return typeof window.FileReader !== 'undefined';
+ }
+
+ /**
+ * Check if this is a recognizable image type...
+ * Also excludes files over 10M to avoid going insane on memory usage.
+ *
+ * @todo is there a way we can ask the browser what's supported in <img>s?
+ * @todo put SVG back after working around Firefox 7 bug <https://bugzilla.wikimedia.org/show_bug.cgi?id=31643>
+ *
+ * @param {File} file
+ * @return boolean
+ */
+ function fileIsPreviewable( file ) {
+ var known = ['image/png', 'image/gif', 'image/jpeg'],
+ tooHuge = 10 * 1024 * 1024;
+ return ( $.inArray( file.type, known ) !== -1 ) && file.size > 0 && file.size < tooHuge;
+ }
+
+ /**
+ * Show a thumbnail preview of PNG, JPEG, GIF, and SVG files prior to upload
+ * in browsers supporting HTML5 FileAPI.
+ *
+ * As of this writing, known good:
+ * - Firefox 3.6+
+ * - Chrome 7.something
+ *
+ * @todo check file size limits and warn of likely failures
+ *
+ * @param {File} file
+ */
+ function showPreview( file ) {
+ var previewSize = 180,
+ thumb = $( '<div id="mw-upload-thumbnail" class="thumb tright">' +
+ '<div class="thumbinner">' +
+ '<canvas width="' + previewSize + '" height="' + previewSize + '" ></canvas>' +
+ '<div class="thumbcaption"><div class="filename"></div><div class="fileinfo"></div></div>' +
+ '</div>' +
+ '</div>' );
+ thumb.find( '.filename' ).text( file.name ).end()
+ .find( '.fileinfo' ).text( prettySize( file.size ) ).end();
+
+ var ctx = thumb.find( 'canvas' )[0].getContext( '2d' ),
+ spinner = new Image();
+ spinner.onload = function() {
+ ctx.drawImage( spinner, (previewSize - spinner.width) / 2,
+ (previewSize - spinner.height) / 2 );
+ };
+ spinner.src = mw.config.get( 'wgScriptPath' ) + '/skins/common/images/spinner.gif';
+ $( '#mw-htmlform-source' ).parent().prepend( thumb );
+
+ var meta;
+ fetchPreview( file, function( dataURL ) {
+ var img = new Image(),
+ rotation = 0;
+
+ if ( meta && meta.tiff && meta.tiff.Orientation ) {
+ rotation = (360 - function () {
+ // See includes/media/Bitmap.php
+ switch ( meta.tiff.Orientation.value ) {
+ case 8:
+ return 90;
+ case 3:
+ return 180;
+ case 6:
+ return 270;
+ default:
+ return 0;
+ }
+ }() ) % 360;
+ }
+
+ img.onload = function() {
+ var width, height, x, y, dx, dy, logicalWidth, logicalHeight;
+ // Fit the image within the previewSizexpreviewSize box
+ if ( img.width > img.height ) {
+ width = previewSize;
+ height = img.height / img.width * previewSize;
+ } else {
+ height = previewSize;
+ width = img.width / img.height * previewSize;
+ }
+ // Determine the offset required to center the image
+ dx = (180 - width) / 2;
+ dy = (180 - height) / 2;
+ switch ( rotation ) {
+ // If a rotation is applied, the direction of the axis
+ // changes as well. You can derive the values below by
+ // drawing on paper an axis system, rotate it and see
+ // where the positive axis direction is
+ case 0:
+ x = dx;
+ y = dy;
+ logicalWidth = img.width;
+ logicalHeight = img.height;
+ break;
+ case 90:
+
+ x = dx;
+ y = dy - previewSize;
+ logicalWidth = img.height;
+ logicalHeight = img.width;
+ break;
+ case 180:
+ x = dx - previewSize;
+ y = dy - previewSize;
+ logicalWidth = img.width;
+ logicalHeight = img.height;
+ break;
+ case 270:
+ x = dx - previewSize;
+ y = dy;
+ logicalWidth = img.height;
+ logicalHeight = img.width;
+ break;
+ }
+
+ ctx.clearRect( 0, 0, 180, 180 );
+ ctx.rotate( rotation / 180 * Math.PI );
+ ctx.drawImage( img, x, y, width, height );
+
+ // Image size
+ var info = mw.msg( 'widthheight', logicalWidth, logicalHeight ) +
+ ', ' + prettySize( file.size );
+ $( '#mw-upload-thumbnail .fileinfo' ).text( info );
+ };
+ img.src = dataURL;
+ }, mw.config.get( 'wgFileCanRotate' ) ? function ( data ) {
+ try {
+ meta = mw.libs.jpegmeta( data, file.fileName );
+ meta._binary_data = null;
+ } catch ( e ) {
+ meta = null;
+ }
+ } : null );
+ }
+
+ /**
+ * Start loading a file into memory; when complete, pass it as a
+ * data URL to the callback function. If the callbackBinary is set it will
+ * first be read as binary and afterwards as data URL. Useful if you want
+ * to do preprocessing on the binary data first.
+ *
+ * @param {File} file
+ * @param {function} callback
+ * @param {function} callbackBinary
+ */
+ function fetchPreview( file, callback, callbackBinary ) {
+ var reader = new FileReader();
+ reader.onload = function() {
+ if ( callbackBinary ) {
+ callbackBinary( reader.result );
+ reader.onload = function() {
+ callback( reader.result );
+ };
+ reader.readAsDataURL( file );
+ } else {
+ callback( reader.result );
+ }
+ };
+ if ( callbackBinary ) {
+ reader.readAsBinaryString( file );
+ } else {
+ reader.readAsDataURL( file );
+ }
+ }
+
+ /**
+ * Format a file size attractively.
+ * @todo match numeric formatting
+ *
+ * @param {number} s
+ * @return string
+ */
+ function prettySize( s ) {
+ var sizes = ['size-bytes', 'size-kilobytes', 'size-megabytes', 'size-gigabytes'];
+ while ( s >= 1024 && sizes.length > 1 ) {
+ s /= 1024;
+ sizes = sizes.slice( 1 );
+ }
+ return mw.msg( sizes[0], Math.round( s ) );
+ }
+
+ /**
+ * Clear the file upload preview area.
+ */
+ function clearPreview() {
+ $( '#mw-upload-thumbnail' ).remove();
+ }
+
+ /**
+ * Check if the file does not exceed the maximum size
+ */
+ function checkMaxUploadSize( file ) {
+ function getMaxUploadSize( type ) {
+ var sizes = mw.config.get( 'wgMaxUploadSize' );
+ if ( sizes[type] !== undefined ) {
+ return sizes[type];
+ }
+ return sizes['*'];
+ }
+ $( '.mw-upload-source-error' ).remove();
+
+ var maxSize = getMaxUploadSize( 'file' );
+ if ( file.size > maxSize ) {
+ var error = $( '<p class="error mw-upload-source-error" id="wpSourceTypeFile-error">' +
+ mw.message( 'largefileserver', file.size, maxSize ).escaped() + '</p>' );
+ $( '#wpUploadFile' ).after( error );
+ return false;
+ }
+ return true;
+ }
+
+
+ /**
+ * Initialization
+ */
+ if ( hasFileAPI() ) {
+ // Update thumbnail when the file selection control is updated.
+ $( '#wpUploadFile' ).change( function() {
+ clearPreview();
+ if ( this.files && this.files.length ) {
+ // Note: would need to be updated to handle multiple files.
+ var file = this.files[0];
+
+ if ( !checkMaxUploadSize( file ) ) {
+ return;
+ }
+
+ if ( fileIsPreviewable( file ) ) {
+ showPreview( file );
+ }
+ }
+ } );
+ }
+} );
+
+/**
+ * Disable all upload source fields except the selected one
+ */
+jQuery( function ( $ ) {
+ var rows = $( '.mw-htmlform-field-UploadSourceField' );
+ for ( var i = rows.length; i; i-- ) {
+ var row = rows[i - 1];
+ $( 'input[name="wpSourceType"]', row ).change( function () {
+ var currentRow = row; // Store current row in our own scope
+ return function () {
+ $( '.mw-upload-source-error' ).remove();
+ if ( this.checked ) {
+ // Disable all inputs
+ $( 'input[name!="wpSourceType"]', rows ).attr( 'disabled', true );
+ // Re-enable the current one
+ $( 'input', currentRow ).attr( 'disabled', false );
+ }
+ };
+ }() );
+ }
+} );
+