summaryrefslogtreecommitdiff
path: root/resources/mediawiki.special
diff options
context:
space:
mode:
Diffstat (limited to 'resources/mediawiki.special')
-rw-r--r--resources/mediawiki.special/images/arrow-collapsed-ltr.pngbin0 -> 206 bytes
-rw-r--r--resources/mediawiki.special/images/arrow-collapsed-rtl.pngbin0 -> 205 bytes
-rw-r--r--resources/mediawiki.special/images/arrow-expanded.pngbin0 -> 205 bytes
-rw-r--r--resources/mediawiki.special/mediawiki.special.changeemail.css2
-rw-r--r--resources/mediawiki.special/mediawiki.special.changeemail.js28
-rw-r--r--resources/mediawiki.special/mediawiki.special.changeslist.css39
-rw-r--r--resources/mediawiki.special/mediawiki.special.javaScriptTest.js54
-rw-r--r--resources/mediawiki.special/mediawiki.special.preferences.css11
-rw-r--r--resources/mediawiki.special/mediawiki.special.preferences.js91
-rw-r--r--resources/mediawiki.special/mediawiki.special.recentchanges.js12
-rw-r--r--resources/mediawiki.special/mediawiki.special.search.js30
-rw-r--r--resources/mediawiki.special/mediawiki.special.upload.js516
12 files changed, 440 insertions, 343 deletions
diff --git a/resources/mediawiki.special/images/arrow-collapsed-ltr.png b/resources/mediawiki.special/images/arrow-collapsed-ltr.png
new file mode 100644
index 00000000..467a555a
--- /dev/null
+++ b/resources/mediawiki.special/images/arrow-collapsed-ltr.png
Binary files differ
diff --git a/resources/mediawiki.special/images/arrow-collapsed-rtl.png b/resources/mediawiki.special/images/arrow-collapsed-rtl.png
new file mode 100644
index 00000000..2246254f
--- /dev/null
+++ b/resources/mediawiki.special/images/arrow-collapsed-rtl.png
Binary files differ
diff --git a/resources/mediawiki.special/images/arrow-expanded.png b/resources/mediawiki.special/images/arrow-expanded.png
new file mode 100644
index 00000000..58a9fc66
--- /dev/null
+++ b/resources/mediawiki.special/images/arrow-expanded.png
Binary files differ
diff --git a/resources/mediawiki.special/mediawiki.special.changeemail.css b/resources/mediawiki.special/mediawiki.special.changeemail.css
index 3d53e8db..9461fbdc 100644
--- a/resources/mediawiki.special/mediawiki.special.changeemail.css
+++ b/resources/mediawiki.special/mediawiki.special.changeemail.css
@@ -5,6 +5,8 @@
border-bottom-right-radius: 0.8em;
border-top-right-radius: 0.8em;
}
+
+/** colors also used in mediawiki.special.preferences.css */
#mw-emailaddress-validity.valid {
border: 1px solid #80FF80;
background-color: #C0FFC0;
diff --git a/resources/mediawiki.special/mediawiki.special.changeemail.js b/resources/mediawiki.special/mediawiki.special.changeemail.js
index 6b4ed81d..cab0bbd3 100644
--- a/resources/mediawiki.special/mediawiki.special.changeemail.js
+++ b/resources/mediawiki.special/mediawiki.special.changeemail.js
@@ -1,12 +1,12 @@
/*
* JavaScript for Special:ChangeEmail
*/
-( function( $, mw ) {
+( function ( mw, $ ) {
/**
* Given an email validity status (true, false, null) update the label CSS class
*/
-var updateMailValidityLabel = function( mail ) {
+function updateMailValidityLabel( mail ) {
var isValid = mw.util.validateEmail( mail ),
$label = $( '#mw-emailaddress-validity' );
@@ -22,19 +22,21 @@ var updateMailValidityLabel = function( mail ) {
} else {
$label.text( mw.msg( 'email-address-validity-invalid' ) ).addClass( 'invalid' ).removeClass( 'valid' );
}
-};
+}
-// Lame tip to let user know if its email is valid. See bug 22449
-// Only bind once for 'blur' so that the user can fill it in without errors
-// After that look at every keypress for direct feedback if it was invalid onblur
-$( '#wpNewEmail' ).one( 'blur', function() {
- if ( $( '#mw-emailaddress-validity' ).length === 0 ) {
- $(this).after( '<label for="wpNewEmail" id="mw-emailaddress-validity"></label>' );
- }
- updateMailValidityLabel( $(this).val() );
- $(this).keyup( function() {
+$( document ).ready( function () {
+ // Lame tip to let user know if its email is valid. See bug 22449
+ // Only bind once for 'blur' so that the user can fill it in without errors
+ // After that look at every keypress for direct feedback if it was invalid onblur
+ $( '#wpNewEmail' ).one( 'blur', function () {
+ if ( $( '#mw-emailaddress-validity' ).length === 0 ) {
+ $(this).after( '<label for="wpNewEmail" id="mw-emailaddress-validity"></label>' );
+ }
updateMailValidityLabel( $(this).val() );
+ $(this).keyup( function () {
+ updateMailValidityLabel( $(this).val() );
+ } );
} );
} );
-} )( jQuery, mediaWiki );
+}( mediaWiki, jQuery ) );
diff --git a/resources/mediawiki.special/mediawiki.special.changeslist.css b/resources/mediawiki.special/mediawiki.special.changeslist.css
index 42afbcd7..8a5421e8 100644
--- a/resources/mediawiki.special/mediawiki.special.changeslist.css
+++ b/resources/mediawiki.special/mediawiki.special.changeslist.css
@@ -31,20 +31,33 @@ table.mw-enhanced-rc td.mw-enhanced-rc-nested {
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;
+/* If JS is disabled, the arrow shouldn't be shown */
+.client-nojs .mw-enhancedchanges-arrow.mw-collapsible-toggle {
+ display: none;
}
-.mw-enhanced-rc.mw-made-collapsible .mw-rc-openarrow,
-.mw-enhanced-rc .mw-rc-closearrow {
- visibility: visible;
- display: none;
+.mw-enhancedchanges-arrow {
+ display: inline-block;
+ *display: inline; /* IE7 and below */
+ zoom: 1;
+ width: 15px;
+ height: 15px;
+}
+
+.mw-enhancedchanges-arrow.mw-enhancedchanges-arrow-space {
+ background: 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;
+
+.mw-enhancedchanges-arrow.mw-collapsible-toggle-collapsed {
+ /* @embed */
+ background: url(images/arrow-collapsed-ltr.png) no-repeat left center;
+}
+
+.mw-enhancedchanges-arrow.mw-collapsible-toggle-expanded {
+ /* @embed */
+ background: url(images/arrow-expanded.png) no-repeat left center;
+}
+
+.mw-changeslist-line-watched .mw-title {
+ font-weight: bold;
}
diff --git a/resources/mediawiki.special/mediawiki.special.javaScriptTest.js b/resources/mediawiki.special/mediawiki.special.javaScriptTest.js
index d413f602..808d5fe8 100644
--- a/resources/mediawiki.special/mediawiki.special.javaScriptTest.js
+++ b/resources/mediawiki.special/mediawiki.special.javaScriptTest.js
@@ -1,33 +1,37 @@
-/*
+/**
* JavaScript for Special:JavaScriptTest
*/
-jQuery( document ).ready( function( $ ) {
+( function ( mw, $ ) {
+ $( function () {
- // Create useskin dropdown menu and reload onchange to the selected skin
- // (only if a framework was found, not on error pages).
- $( '#mw-javascripttest-summary.mw-javascripttest-frameworkfound' ).append( function() {
+ // Create useskin dropdown menu and reload onchange to the selected skin
+ // (only if a framework was found, not on error pages).
+ $( '#mw-javascripttest-summary.mw-javascripttest-frameworkfound' ).append( function () {
- var $html = $( '<p><label for="useskin">'
- + mw.message( 'javascripttest-pagetext-skins' ).escaped()
- + ' '
- + '</label></p>' ),
- select = '<select name="useskin" id="useskin">';
+ var $html = $( '<p><label for="useskin">'
+ + mw.message( 'javascripttest-pagetext-skins' ).escaped()
+ + ' '
+ + '</label></p>' ),
+ select = '<select name="useskin" id="useskin">';
- // Build <select> further
- $.each( mw.config.get( 'wgAvailableSkins' ), function( id ) {
- select += '<option value="' + id + '"'
- + ( mw.config.get( 'skin' ) === id ? ' selected="selected"' : '' )
- + '>' + mw.message( 'skinname-' + id ).escaped() + '</option>';
- } );
- select += '</select>';
+ // Build <select> further
+ $.each( mw.config.get( 'wgAvailableSkins' ), function ( id ) {
+ select += '<option value="' + id + '"'
+ + ( mw.config.get( 'skin' ) === id ? ' selected="selected"' : '' )
+ + '>' + mw.message( 'skinname-' + id ).escaped() + '</option>';
+ } );
+ select += '</select>';
- // Bind onchange event handler and append to form
- $html.append(
- $( select ).change( function() {
- window.location = QUnit.url( { useskin: $(this).val() } );
- } )
- );
+ // Bind onchange event handler and append to form
+ $html.append(
+ $( select ).change( function () {
+ window.location = QUnit.url( { useskin: $(this).val() } );
+ } )
+ );
- return $html;
+ return $html;
+ } );
} );
-} );
+
+}( mediaWiki, jQuery ) );
+
diff --git a/resources/mediawiki.special/mediawiki.special.preferences.css b/resources/mediawiki.special/mediawiki.special.preferences.css
new file mode 100644
index 00000000..161efde3
--- /dev/null
+++ b/resources/mediawiki.special/mediawiki.special.preferences.css
@@ -0,0 +1,11 @@
+/** Reuses colors from mediawiki.special.changeemail.css */
+.mw-email-not-authenticated .mw-input,
+.mw-email-none .mw-input{
+ border: 1px solid #FF8080;
+ background-color: #FFC0C0;
+ color: black;
+}
+/** Authenticated email field has its own class too. Unstyled by default */
+/*
+.mw-email-authenticated .mw-input { }
+*/
diff --git a/resources/mediawiki.special/mediawiki.special.preferences.js b/resources/mediawiki.special/mediawiki.special.preferences.js
index b7200826..47872907 100644
--- a/resources/mediawiki.special/mediawiki.special.preferences.js
+++ b/resources/mediawiki.special/mediawiki.special.preferences.js
@@ -1,7 +1,7 @@
/*
* JavaScript for Special:Preferences
*/
-( function( $, mw ) {
+jQuery( document ).ready( function ( $ ) {
$( '#prefsubmit' ).attr( 'id', 'prefcontrol' );
var $preftoc = $('<ul id="preftoc"></ul>');
var $preferences = $( '#preferences' )
@@ -15,8 +15,35 @@ var $fieldsets = $preferences.children( 'fieldset' )
var $legends = $fieldsets.children( 'legend' )
.addClass( 'mainLegend' );
+/**
+ * It uses document.getElementById for security reasons (html injections in
+ * jQuery()).
+ *
+ * @param String name: the name of a tab without the prefix ("mw-prefsection-")
+ * @param String mode: [optional] A hash will be set according to the current
+ * open section. Set mode 'noHash' to surpress this.
+ */
+function switchPrefTab( name, mode ) {
+ var $tab, scrollTop;
+ // Handle hash manually to prevent jumping,
+ // therefore save and restore scrollTop to prevent jumping.
+ scrollTop = $( window ).scrollTop();
+ if ( mode !== 'noHash' ) {
+ window.location.hash = '#mw-prefsection-' + name;
+ }
+ $( window ).scrollTop( scrollTop );
+
+ $preftoc.find( 'li' ).removeClass( 'selected' );
+ $tab = $( document.getElementById( 'preftab-' + name ) );
+ if ( $tab.length ) {
+ $tab.parent().addClass( 'selected' );
+ $preferences.children( 'fieldset' ).hide();
+ $( document.getElementById( 'mw-prefsection-' + name ) ).show();
+ }
+}
+
// Populate the prefToc
-$legends.each( function( i, legend ) {
+$legends.each( function ( i, legend ) {
var $legend = $(legend);
if ( i === 0 ) {
$legend.parent().show();
@@ -30,18 +57,6 @@ $legends.each( function( i, legend ) {
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 );
@@ -49,15 +64,35 @@ $legends.each( function( i, legend ) {
// 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();
- }
-} );
+var hash = window.location.hash;
+if ( hash.match( /^#mw-prefsection-[\w\-]+/ ) ) {
+ switchPrefTab( hash.replace( '#mw-prefsection-' , '' ) );
+}
+// In browsers that support the onhashchange event we will not bind click
+// handlers and instead let the browser do the default behavior (clicking the
+// <a href="#.."> will naturally set the hash, handled by onhashchange.
+// But other things that change the hash will also be catched (e.g. using
+// the Back and Forward browser navigation).
+if ( 'onhashchange' in window ) {
+ $(window).on( 'hashchange' , function () {
+ var hash = window.location.hash;
+ if ( hash.match( /^#mw-prefsection-[\w\-]+/ ) ) {
+ switchPrefTab( hash.replace( '#mw-prefsection-', '' ) );
+ } else if ( hash === '' ) {
+ switchPrefTab( 'personal', 'noHash' );
+ }
+ });
+// In older browsers we'll bind a click handler as fallback.
+// We must not have onhashchange *and* the click handlers, other wise
+// the click handler calls switchPrefTab() which sets the hash value,
+// which triggers onhashcange and calls switchPrefTab() again.
+} else {
+ $preftoc.on( 'click', 'li a', function ( e ) {
+ switchPrefTab( $( this ).attr( 'href' ).replace( '#mw-prefsection-', '' ) );
+ e.preventDefault();
+ });
+}
/**
* Timezone functions.
@@ -71,7 +106,7 @@ var $localtimeHolder = $( '#wpLocalTime' );
var servertime = parseInt( $( 'input[name=wpServerTime]' ).val(), 10 );
var minuteDiff = 0;
-var minutesToHours = function( min ) {
+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 +
@@ -79,7 +114,7 @@ var minutesToHours = function( min ) {
return tzString;
};
-var hoursToMinutes = function( hour ) {
+var hoursToMinutes = function ( hour ) {
var arr = hour.split( ':' );
arr[0] = parseInt( arr[0], 10 );
@@ -102,7 +137,7 @@ var hoursToMinutes = function( hour ) {
}
};
-var updateTimezoneSelection = function() {
+var updateTimezoneSelection = function () {
var type = $tzSelect.val();
if ( type == 'guess' ) {
// Get browser timezone & fill it in
@@ -133,8 +168,8 @@ var updateTimezoneSelection = function() {
};
if ( $tzSelect.length && $tzTextbox.length ) {
- $tzSelect.change( function() { updateTimezoneSelection(); } );
- $tzTextbox.blur( function() { updateTimezoneSelection(); } );
+ $tzSelect.change( function () { updateTimezoneSelection(); } );
+ $tzTextbox.blur( function () { updateTimezoneSelection(); } );
updateTimezoneSelection();
}
-} )( jQuery, mediaWiki ); \ No newline at end of file
+} );
diff --git a/resources/mediawiki.special/mediawiki.special.recentchanges.js b/resources/mediawiki.special/mediawiki.special.recentchanges.js
index 3d520f5e..7996d935 100644
--- a/resources/mediawiki.special/mediawiki.special.recentchanges.js
+++ b/resources/mediawiki.special/mediawiki.special.recentchanges.js
@@ -1,5 +1,5 @@
/* JavaScript for Special:RecentChanges */
-( function( $ ) {
+( function ( mw, $ ) {
var checkboxes = [ 'nsassociated', 'nsinvert' ];
@@ -14,17 +14,17 @@
* Handler to disable/enable the namespace selector checkboxes when the
* special 'all' namespace is selected/unselected respectively.
*/
- updateCheckboxes: function() {
+ updateCheckboxes: function () {
// The option element for the 'all' namespace has an empty value
- var isAllNS = ('' === $select.find('option:selected').val() );
+ var isAllNS = $select.find('option:selected').val() === '';
// Iterates over checkboxes and propagate the selected option
- $.each( checkboxes, function( i, id ) {
+ $.each( checkboxes, function ( i, id ) {
$( '#' + id ).prop( 'disabled', isAllNS );
});
},
- init: function() {
+ init: function () {
// Populate
$select = $( '#namespace' );
@@ -36,4 +36,4 @@
// Run when document is ready
$( rc.init );
-})( jQuery );
+}( mediaWiki, jQuery ) );
diff --git a/resources/mediawiki.special/mediawiki.special.search.js b/resources/mediawiki.special/mediawiki.special.search.js
index 8865d04c..04954e8d 100644
--- a/resources/mediawiki.special/mediawiki.special.search.js
+++ b/resources/mediawiki.special/mediawiki.special.search.js
@@ -1,21 +1,33 @@
/*
* JavaScript for Special:Search
*/
-jQuery( function( $ ) {
+( function( $, mw ) { $( function() {
// Emulate HTML5 autofocus behavior in non HTML5 compliant browsers
if ( !( 'autofocus' in document.createElement( 'input' ) ) ) {
$( 'input[autofocus]:first' ).focus();
}
-// Bind check all/none button
+// Create 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);
-} );
+$('#mw-search-togglebox').append(
+ $('<label />')
+ .text(mw.msg('powersearch-togglelabel'))
+).append(
+ $('<input type="button" />')
+ .attr('id', 'mw-search-toggleall')
+ .attr('value', mw.msg('powersearch-toggleall'))
+ .click( function() {
+ $checkboxes.prop('checked', true);
+ } )
+).append(
+ $('<input type="button" />')
+ .attr('id', 'mw-search-togglenone')
+ .attr('value', mw.msg('powersearch-togglenone'))
+ .click( function() {
+ $checkboxes.prop('checked', false);
+ } )
+);
// Change the header search links to what user entered
var headerLinks = $('.search-types a');
@@ -34,4 +46,4 @@ $('#searchText, #powerSearchText').change(function() {
});
}).trigger('change');
-} );
+} ); } )( jQuery, mediaWiki );
diff --git a/resources/mediawiki.special/mediawiki.special.upload.js b/resources/mediawiki.special/mediawiki.special.upload.js
index 85b3f3f5..63e89713 100644
--- a/resources/mediawiki.special/mediawiki.special.upload.js
+++ b/resources/mediawiki.special/mediawiki.special.upload.js
@@ -1,281 +1,299 @@
-/*
+/**
* JavaScript for Special:Upload
* Note that additional code still lives in skins/common/upload.js
*/
-
-/**
- * Add a preview to the upload form
- */
-jQuery( function( $ ) {
+( function ( mw, $ ) {
/**
- * Is the FileAPI available with sufficient functionality?
+ * Add a preview to the upload form
*/
- function hasFileAPI(){
- return typeof window.FileReader !== 'undefined';
- }
+ $( 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', 'image/svg+xml'],
- tooHuge = 10 * 1024 * 1024;
- return ( $.inArray( file.type, known ) !== -1 ) && file.size > 0 && file.size < tooHuge;
- }
+ /**
+ * 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', 'image/svg+xml'],
+ 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">' +
- '<div class="mw-small-spinner" style="width: 180px; height: 180px"></div>' +
- '<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();
+ /**
+ * 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">' +
+ '<div class="mw-small-spinner" style="width: 180px; height: 180px"></div>' +
+ '<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 $canvas = $('<canvas width="' + previewSize + '" height="' + previewSize + '" ></canvas>'),
+ ctx = $canvas[0].getContext( '2d' );
+ $( '#mw-htmlform-source' ).parent().prepend( thumb );
+
+ var meta;
+ fetchPreview( file, function( dataURL ) {
+ var img = new Image(),
+ rotation = 0;
- var $canvas = $('<canvas width="' + previewSize + '" height="' + previewSize + '" ></canvas>'),
- ctx = $canvas[0].getContext( '2d' );
- $( '#mw-htmlform-source' ).parent().prepend( thumb );
+ 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;
+ }
- var meta;
- fetchPreview( file, function( dataURL ) {
- var img = new Image(),
- rotation = 0;
+ 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:
- 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;
+ 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;
}
- }() ) % 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:
+ ctx.clearRect( 0, 0, 180, 180 );
+ ctx.rotate( rotation / 180 * Math.PI );
+ ctx.drawImage( img, x, y, width, height );
+ thumb.find('.mw-small-spinner').replaceWith($canvas);
- 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;
+ // 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 );
+ }
- ctx.clearRect( 0, 0, 180, 180 );
- ctx.rotate( rotation / 180 * Math.PI );
- ctx.drawImage( img, x, y, width, height );
- thumb.find('.mw-small-spinner').replaceWith($canvas);
-
- // 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();
+ if ( callbackBinary && 'readAsBinaryString' in reader ) {
+ // To fetch JPEG metadata we need a binary string; start there.
+ // todo:
+ reader.onload = function() {
+ callbackBinary( reader.result );
- /**
- * 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();
- if ( callbackBinary ) {
- // To fetch JPEG metadata we need a binary string; start there.
- // todo:
- reader.onload = function() {
- callbackBinary( reader.result );
+ // Now run back through the regular code path.
+ fetchPreview( file, callback );
+ };
+ reader.readAsBinaryString( file );
+ } else if ( callbackBinary && 'readAsArrayBuffer' in reader ) {
+ // readAsArrayBuffer replaces readAsBinaryString
+ // However, our JPEG metadata library wants a string.
+ // So, this is going to be an ugly conversion.
+ reader.onload = function() {
+ var buffer = new Uint8Array( reader.result ),
+ string = '';
+ for ( var i = 0; i < buffer.byteLength; i++ ) {
+ string += String.fromCharCode( buffer[i] );
+ }
+ callbackBinary( string );
- // Now run back through the regular code path.
- fetchPreview(file, callback );
- };
- reader.readAsBinaryString( file );
- } else if ('URL' in window && 'createObjectURL' in window.URL) {
- // Supported in Firefox 4.0 and above <https://developer.mozilla.org/en/DOM/window.URL.createObjectURL>
- // WebKit has it in a namespace for now but that's ok. ;)
- //
- // Lifetime of this URL is until document close, which is fine
- // for Special:Upload -- if this code gets used on longer-running
- // pages, add a revokeObjectURL() when it's no longer needed.
- //
- // Prefer this over readAsDataURL for Firefox 7 due to bug reading
- // some SVG files from data URIs <https://bugzilla.mozilla.org/show_bug.cgi?id=694165>
- callback(window.URL.createObjectURL(file));
- } else {
- // This ends up decoding the file to base-64 and back again, which
- // feels horribly inefficient.
- reader.onload = function() {
- callback( reader.result );
- };
- reader.readAsDataURL( file );
+ // Now run back through the regular code path.
+ fetchPreview( file, callback );
+ };
+ reader.readAsArrayBuffer( file );
+ } else if ( 'URL' in window && 'createObjectURL' in window.URL ) {
+ // Supported in Firefox 4.0 and above <https://developer.mozilla.org/en/DOM/window.URL.createObjectURL>
+ // WebKit has it in a namespace for now but that's ok. ;)
+ //
+ // Lifetime of this URL is until document close, which is fine
+ // for Special:Upload -- if this code gets used on longer-running
+ // pages, add a revokeObjectURL() when it's no longer needed.
+ //
+ // Prefer this over readAsDataURL for Firefox 7 due to bug reading
+ // some SVG files from data URIs <https://bugzilla.mozilla.org/show_bug.cgi?id=694165>
+ callback( window.URL.createObjectURL( file ) );
+ } else {
+ // This ends up decoding the file to base-64 and back again, which
+ // feels horribly inefficient.
+ reader.onload = function() {
+ callback( reader.result );
+ };
+ 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 );
+ /**
+ * Format a file size attractively.
+ * @todo match numeric formatting
+ *
+ * @param {number} s
+ * @return string
+ */
+ function prettySize( s ) {
+ var sizeMsgs = ['size-bytes', 'size-kilobytes', 'size-megabytes', 'size-gigabytes'];
+ while ( s >= 1024 && sizeMsgs.length > 1 ) {
+ s /= 1024;
+ sizeMsgs = sizeMsgs.slice( 1 );
+ }
+ return mw.msg( sizeMsgs[0], Math.round( s ) );
}
- return mw.msg( sizes[0], Math.round( s ) );
- }
- /**
- * Clear the file upload preview area.
- */
- function clearPreview() {
- $( '#mw-upload-thumbnail' ).remove();
- }
+ /**
+ * 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];
+ /**
+ * 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['*'];
}
- return sizes['*'];
- }
- $( '.mw-upload-source-error' ).remove();
+ $( '.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;
+ 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;
}
- 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];
+ /**
+ * 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 ( !checkMaxUploadSize( file ) ) {
+ return;
+ }
- if ( fileIsPreviewable( file ) ) {
- showPreview( file );
+ 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 ).prop( 'disabled', 'disabled' );
- // Re-enable the current one
- $( 'input', currentRow ).prop( 'disabled', false );
- }
- };
- }() );
- }
-} );
+ /**
+ * Disable all upload source fields except the selected one
+ */
+ $( function ( $ ) {
+ var i, row,
+ rows = $( '.mw-htmlform-field-UploadSourceField' );
+ for ( i = rows.length; i; i-- ) {
+ 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 ).prop( 'disabled', true );
+ // Re-enable the current one
+ $( 'input', currentRow ).prop( 'disabled', false );
+ }
+ };
+ }() ) );
+ }
+ } );
+}( mediaWiki, jQuery ) );