MediaWiki:Gadget-refTooltip.js
Przejdź do nawigacji
Przejdź do wyszukiwania
Uwaga: aby zobaczyć zmiany po opublikowaniu, może zajść potrzeba wyczyszczenia pamięci podręcznej przeglądarki.
- Firefox / Safari: Przytrzymaj Shift podczas klikania Odśwież bieżącą stronę, lub naciśnij klawisze Ctrl+F5, lub Ctrl+R (⌘-R na komputerze Mac)
- Google Chrome: Naciśnij Ctrl-Shift-R (⌘-Shift-R na komputerze Mac)
- Internet Explorer / Edge: Przytrzymaj Ctrl, jednocześnie klikając Odśwież, lub naciśnij klawisze Ctrl+F5
- Opera: Naciśnij klawisze Ctrl+F5.
$( function() {
'use strict';
var i18n = {
cancelButton: 'Anuluj',
doneButton: 'Zapisz',
enableLabel: 'Włącz pokazywanie przypisów',
optionsButtonTitle: 'Zmień opcje pokazywania przypisów',
referencesSectionName: 'Przypisy',
saveFailedStorageFull: "Czy pamięć podręczna Twojej przeglądarki jest pełna?",
saveFailedTitle: 'Zapisywanie opcji zakończone niepowodzeniem'
};
var $win = $( window );
var $body = $( '.mw-body' );
var $content = $( '#mw-content-text' );
var $tooltip = $();
var $tooltipText = $();
var tooltipRect, tooltipInnerWidth, tooltipOffset, $anchor, anchorRect;
var showTimer, hideTimer;
var loggedIn = !!mw.config.get( 'wgUserId' );
var options = {
enabled: true
};
if ( !loggedIn ) {
try {
options = JSON.parse( localStorage.refTooltip );
} catch ( e ) {}
}
var createTooltip = function( $anchor, content, showOptions ) {
// Get rid of any existing tooltip
$tooltip.remove();
// Create the tooltip
$tooltip = $( '<div>' ).addClass( 'ref-tooltip' ).data( {
anchor: $anchor,
fresh: true,
} ).hover( function() {
// Callback to the ref's hover functions when the tooltip is hovered over
$anchor.mouseenter();
}, function() {
$anchor.mouseleave();
} );
$tooltipText = $( '<div>' ).addClass( 'ref-tooltip-text' )
.append( content ).appendTo( $tooltip );
if ( showOptions ) {
$tooltipText.prepend(
$( '<button>' ).addClass( 'pixel-image ref-tooltip-options-button' )
.attr( 'title', i18n.optionsButtonTitle )
);
}
$( '<div>' ).addClass( 'ref-tooltip-arrow' ).appendTo( $tooltip );
$tooltip.appendTo( 'body' );
// Set width to content size
$tooltipText.width( $tooltipText.width() + 1 );
setPos( true );
// Data prevents tooltips being immediately closed if opened via a click
setTimeout( function() {
$tooltip.removeData( 'fresh' );
}, 0 );
};
var removeTooltip = function() {
$tooltip.trigger( 'refTooltip-close' );
$tooltip.remove();
$tooltip = $();
};
var getRefText = function( $ref ) {
var refId = $ref.find( 'a' ).attr( 'href' ).split( '#' )[1];
var $refText = $( document.getElementById( refId ) ).clone();
$refText.find( '.mw-cite-backlink' ).remove();
return $refText.html();
};
var setPos = function( initial ) {
if ( !$tooltip.length ) {
return;
}
if ( initial ) {
tooltipRect = $tooltipText[0].getBoundingClientRect();
tooltipInnerWidth = $tooltipText.width();
tooltipOffset = {
top: parseFloat( $tooltipText.css( 'margin-top' ) ),
left: parseFloat( $tooltipText.css( 'margin-left' ) )
};
$anchor = $tooltip.data( 'anchor' );
anchorRect = $anchor[0].getBoundingClientRect();
} else {
$tooltip.removeClass( 'ref-tooltip-flipped' );
$tooltipText.css( 'margin-left', '' );
}
// Position the tooltip
var tooltipPos = {
top: $win.scrollTop(),
left: $win.scrollLeft()
};
if ( anchorRect.top + tooltipOffset.top < tooltipRect.height ) {
$tooltip.addClass( 'ref-tooltip-flipped' );
tooltipPos.top += anchorRect.bottom;
} else {
tooltipPos.top += anchorRect.top - tooltipRect.height;
}
tooltipPos.left += anchorRect.left + anchorRect.width / 2;
// Stop it going off the side of the page
var contentPadding = parseFloat( $body.css( 'padding-right' ) );
var contentBoundary = $body[0].getBoundingClientRect().right - contentPadding / 2;
var overlap = anchorRect.left + tooltipOffset.left + tooltipRect.width - contentBoundary;
if ( overlap > 0 ) {
$tooltipText.css(
'margin-left',
Math.max( tooltipOffset.left - overlap, -tooltipInnerWidth )
);
}
$tooltip.css( tooltipPos );
};
var bindRefHandlers = function() {
$content.on( {
'mouseenter.refTooltip': function() {
var $this = $( this );
clearTimeout( hideTimer );
// Current tooltip, do nothing
if ( $tooltip.length && (
$this.is( $tooltip.data( 'anchor' ) ) || $.contains( $tooltip[0], this )
) ) {
return;
}
// Create the tooltip if timeout succeeds
showTimer = setTimeout( function() {
createTooltip( $this, getRefText( $this ), true );
}, 200 );
},
'mouseleave.refTooltip': function() {
clearTimeout( showTimer );
// Remove the tooltip if timeout succeeds
hideTimer = setTimeout( function() {
removeTooltip();
}, 300 );
}
}, '.reference' );
};
// When anywhere but the tooltip or anchor is clicked, remove it immediately
$( window ).on( 'click.refTooltip', function( e ) {
if ( $tooltip.length && !$tooltip.data( 'fresh' ) && !$.contains( $tooltip[0], e.target ) ) {
clearTimeout( showTimer );
removeTooltip();
}
} );
// TODO: Replace with mw.util.escapeId on MW 1.27
var escapeId = function( id ) {
return mw.util.rawurlencode( String( id ).replace( / /g, '_' ) )
.replace( /%3A/g, ':' )
.replace( /%/g, '.' );
};
$( document.getElementById( escapeId( i18n.referencesSectionName ) ) ).before(
$( '<button>' ).addClass( 'pixel-image ref-tooltip-options-button' )
.attr( 'title', i18n.optionsButtonTitle )
);
$( 'body' ).on( 'click.refTooltip', '.ref-tooltip-options-button', function( e ) {
// Just close the tooltip if it is already open
if ( $tooltip.length && $tooltip.data( 'anchor' ).is( e.target ) ) {
return;
}
// Disable ref handlers while options are open
$content.off( 'mouseenter.refTooltip mouseleave.refTooltip' );
$tooltip.on( 'refTooltip-close', function() {
if ( options.enabled ) {
bindRefHandlers();
}
} );
var $anchor = $( this );
$anchor.addClass( 'ref-tooltip-loading' );
// Replace current tooltip if clicking the options button within a tooltip
if ( $tooltip.length && $.contains( $tooltip[0], $anchor[0] ) ) {
$anchor = $tooltip.data( 'anchor' );
}
mw.loader.using( [ 'mediawiki.api', 'mediawiki.ui.button', 'mediawiki.ui.checkbox' ], function() {
$anchor.removeClass( 'ref-tooltip-loading' );
var $optionsText = $( '<div>' ).addClass( 'ref-tooltip-options' ).append(
$( '<div>' ).addClass( 'mw-ui-checkbox' ).append(
$( '<input>' ).attr( {
type: 'checkbox',
id: 'ref-tooltip-options-enabled',
checked: options.enabled
} ),
$( '<label>' ).attr( 'for', 'ref-tooltip-options-enabled' ).text( i18n.enableLabel )
),
$( '<div>' ).addClass( 'ref-tooltip-actions' ).append(
$( '<button>' ).addClass( 'mw-ui-button mw-ui-quiet' ).text( i18n.cancelButton )
.on( 'click.refTooltip', function() {
removeTooltip();
} ),
$( '<button>' ).addClass( 'mw-ui-button mw-ui-progressive' ).text( i18n.doneButton )
.on( 'click.refTooltip', function() {
options.enabled = $( '#ref-tooltip-options-enabled' ).prop( 'checked' );
var saveOptions = $.Deferred();
if ( loggedIn ) {
saveOptions = new mw.Api().postWithToken( 'edit', {
action: 'options',
optionname: 'gadget-refTooltip',
optionvalue: options.enabled ? undefined : 0
} );
} else {
try {
localStorage.refTooltip = JSON.stringify( options );
saveOptions.resolve();
} catch ( e ) {
saveOptions.reject( 'storage' );
}
}
saveOptions.then( function() {
removeTooltip();
}, function( code, error ) {
mw.notify(
code === 'storage' ? i18n.saveFailedStorageFull : error,
{ title: i18n.saveFailedTitle }
);
} );
} )
)
);
createTooltip( $anchor, $optionsText, false );
$tooltip.on( 'refTooltip-close', function() {
if ( options.enabled ) {
bindRefHandlers();
}
} );
} );
} );
// Finally, enable tooltips
if ( options.enabled ) {
bindRefHandlers();
}
} );
// Add width and height to Element.getBoundingClientRect() in IE8
// TODO: Remove on 1.27
if ( window.TextRectangle && !TextRectangle.prototype.width ) {
Object.defineProperty( TextRectangle.prototype, 'width', {
get: function() { return this.right - this.left; }
} );
Object.defineProperty( TextRectangle.prototype, 'height', {
get: function() { return this.bottom - this.top; }
} );
}