미디어위키:Gadget-ReferenceTooltips-ko.js: 두 판 사이의 차이

편집 요약 없음
편집 요약 없음
 
(같은 사용자의 중간 판 6개는 보이지 않습니다)
1번째 줄: 1번째 줄:
// See [[mw:Reference Tooltips]]
// This code is licensed under CC BY-SA 3.0
// Source https://en.wikipedia.org/wiki/MediaWiki:Gadget-ReferenceTooltips.js
// Source: https://librewiki.net/wiki/미디어위키:Gadget-ReferenceTooltips-ko.js
// Translated by Fracture_Ray
// Contributors: https://librewiki.net/index.php?title=미디어위키:Gadget-ReferenceTooltips-ko.js&action=history


( function () {
var isMobile = navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i);
var drawer, origin, content;
function showDrawer(id, name, orgId) {
origin.attr("href", id);
origin.attr("data-origin", orgId.replace(/\./g, "\\."));
origin.text(name);
content.html($(id.replace(/\./g, "\\.") + " > .reference-text").html());
drawer.addClass("visible");
}


// enwiki settings
function getSettings(key, type) {
var REF_LINK_SELECTOR = '.reference, a[href^="#CITEREF"]',
if ("localStorage" in window) {
COMMENTED_TEXT_CLASS = 'rt-commentedText',
if (type === "boolean") {
COMMENTED_TEXT_SELECTOR = ( COMMENTED_TEXT_CLASS ? '.' + COMMENTED_TEXT_CLASS + ', ' : '') +
return (window.localStorage[key] === "true");
'abbr[title]';
} else {
return window.localStorage[key];
}
} else {
var value = "; " + document.cookie;
var parts = value.split("; " + key + "=");
if (parts.length == 2) {
if (type === "boolean") {
return (parts.pop().split(";").shift() === "true");
} else {
return parts.pop().split(";").shift();
}
}
}
}


mw.messages.set( {
function setSettings(key, value) {
'rt-settings': '각주 툴팁 설정',
if ("localStorage" in window) {
'rt-enable-footer': '각주 툴팁 활성화',
window.localStorage[key] = value;
'rt-settings-title': '각주 툴팁',
} else {
'rt-save': '저장',
var now = new Date();
'rt-cancel': '취소',
var time = now.getTime();
'rt-enable': '활성화',
var expireTime = time + (10 * 365 * 24 * 24);
'rt-disable': '비활성화',
now.setTime(expireTime);
'rt-activationMethod': '툴팁 표시 설정',
document.cookie = key + "=" + value + ";expires=" + now.toGMTString() +";path=/";
'rt-hovering': '마우스를 가져다 대면 표시하기',
}
'rt-clicking': '클릭하면 표시하기',
}
'rt-delay': '툴팁 표시 지연 (밀리초(ms) 단위)',
'rt-tooltipsForComments': '각주를 <span title="툴팁 예시" class="' + ( COMMENTED_TEXT_CLASS || 'rt-commentedText' ) + '" style="border-bottom: 1px dotted; cursor: help;">점선으로 밑줄 친 텍스트</span> 위에서 각주 툴팁 스타일로 나타나게 설정하기 (마우스를 지원하지 않는 기기에서 툴팁을 볼 수 있게 해 줍니다.)',
'rt-disabledNote': '페이지 밑에 있는 링크를 이용하여 툴팁을 다시 활성화하실 수 있습니다.',
'rt-done': '완료',
'rt-enabled': '각주 툴팁이 활성화되었습니다.'
} );
 
// "Global" variables
var SECONDS_IN_A_DAY = 60 * 60 * 24,
CLASSES = {
FADE_IN_DOWN: 'rt-fade-in-down',
FADE_IN_UP: 'rt-fade-in-up',
FADE_OUT_DOWN: 'rt-fade-out-down',
FADE_OUT_UP: 'rt-fade-out-up'
},
IS_TOUCHSCREEN = 'ontouchstart' in document.documentElement,
// Quite a rough check for mobile browsers, a mix of what is advised at
// https://stackoverflow.com/a/24600597 (sends to
// https://developer.mozilla.org/en-US/docs/Browser_detection_using_the_user_agent)
// and https://stackoverflow.com/a/14301832
IS_MOBILE = /Mobi|Android/i.test( navigator.userAgent ) ||
typeof window.orientation !== 'undefined',
CLIENT_NAME = $.client.profile().name,
settingsString, settings, enabled, delay, activatedByClick, tooltipsForComments, cursorWaitCss,
windowManager,
$body = $( document.body ),
$window = $( window );


function rt( $content ) {
function initSettings() {
// Popups gadget
if (document.getElementById("reference-settings")) {
if ( window.pg ) {
$("#reference-settings").show();
return;
return;
}
}
var setbox = $("<form>").attr("id", "reference-settings").append(
$("<div>").addClass("content").append(
$("<label>").append(
$("<input>").attr({"type": "checkbox", "name": "showRefOnHover", "checked": getSettings("showRefOnHover", "boolean")}),
"갖다 대서 주석을 띄웁니다."
)
),
$("<div>").addClass("foot").append(
$("<input>").attr({"type": "button", "value": "취소"}).click(function() {
$("#reference-settings").hide();
}),
$("<input>").addClass("save-settings").attr({"type": "submit", "value": "저장"})
)
).submit(function(e) {
e.preventDefault();
setSettings("showRefOnHover", $(this).find("[name=showRefOnHover]").is(":checked"));
location.reload();
});
$(document.body).append(setbox);
}


var teSelector,
function showTooltip(elem) {
settingsDialogOpening = false;
showDrawer(elem.parentNode.getAttribute("href"), elem.textContent, elem.parentNode.parentNode.getAttribute("id"));
drawer.show();
drawer.css({ top: ($(elem).offset().top - drawer.outerHeight()), left: $(elem).offset().left });
drawer.stop().animate({opacity: 1}, 100);
}


function setSettingsCookie() {
function hideTooltip() {
mw.cookie.set(
drawer.removeClass("visible");
'RTsettings',
drawer.animate({opacity: 0}, 100, function() { $(this).hide(); });
Number( enabled ) + '|' + delay + '|' + Number( activatedByClick ) + '|' +
}
Number( tooltipsForComments ),
{ path: '/', expires: 90 * SECONDS_IN_A_DAY, prefix: '' }
);
}


function enableRt() {
$(document).ready(function($) {
enabled = true;
if (getSettings("showRefOnHover") === undefined) {
setSettingsCookie();
setSettings("showRefOnHover", true);
$( '.rt-enableItem' ).remove();
rt( $content );
mw.notify( mw.msg( 'rt-enabled' ) );
}
}
 
if (isMobile) {
function disableRt() {
$(document.body).addClass("mode-drawer");
$content.find( teSelector ).removeClass( 'rt-commentedText' ).off( '.rt' );
} else {
$body.off( '.rt' );
$(document.body).addClass("mode-tooltip");
$window.off( '.rt' );
}
 
function addEnableLink() {
// #footer-places – Vector
// #f-list – Timeless, Monobook, Modern
// parent of #footer li – Cologne Blue
var $footer = $( '#footer-places, #f-list' );
if ( !$footer.length ) {
$footer = $( '#footer-places, #footer li' ).parent();
}
$footer.append(
$( '<li>' )
.addClass( 'footer-places-enableItem' )
.append(
$( '<a>' )
.text( mw.msg( 'rt-enable-footer' ) )
.attr( 'href', 'javascript:' )
.click( function ( e ) {
e.preventDefault();
enableRt();
} )
)
);
}
}
 
/* create drawer */
function TooltippedElement( $element ) {
drawer = $("<div>").attr("id", "reference-drawer");
var tooltip,
origin = $("<a>").attr("id", "reference-origin").click(function() {
events,
$('html, body').animate({scrollTop: ($($(this).attr("href")).offset().top - 60)}, 400);
te = this;
});
 
content = $("<span>").attr("id", "reference-drawer-text");
function onStartEvent( e ) {
var settingsIcon = $("<span>").addClass("settings-icon").click(function() {
var showRefArgs;
initSettings();
 
});
if ( activatedByClick && te.type !== 'commentedText' && e.type !== 'contextmenu' ) {
var closeDrawer = $("<span>").addClass("close-icon").click(function() {
e.preventDefault();
drawer.removeClass("visible");
}
});
if ( !te.noRef ) {
drawer.append(settingsIcon);
showRefArgs = [ $( this ) ];
drawer.append(closeDrawer);
if ( te.type !== 'supRef' ) {
drawer.append(origin);
showRefArgs.push( e.pageX, e.pageY );
drawer.append(content);
}
$(document.body).append(drawer);
te.showRef.apply( te, showRefArgs );
}
$(document).click(function(e) {
}
if (!$(e.target).closest("#reference-drawer").length) {
 
if (!isMobile) {
function onEndEvent() {
hideTooltip();
if ( !te.noRef ) {
te.hideRef();
}
}
 
if ( !$element ) {
return;
}
 
// TooltippedElement.$element and TooltippedElement.$originalElement will be different when
// the first is changed after its cloned version is hovered in a tooltip
this.$element = $element;
this.$originalElement = $element;
if ( this.$element.is( REF_LINK_SELECTOR ) ) {
if ( this.$element.prop( 'tagName' ) === 'SUP' ) {
this.type = 'supRef';
} else {
} else {
this.type = 'harvardRef';
drawer.removeClass("visible");
}
} else {
this.type = 'commentedText';
this.comment = this.$element.attr( 'title' );
if ( !this.comment ) {
return;
}
}
this.$element.addClass('rt-commentedText');
}
}
}).scroll(function(e) {
if ( activatedByClick ) {
if ("ontouchstart" in window && isMobile) {
events = {
drawer.removeClass("visible");
'click.rt': onStartEvent
};
// Adds an ability to see tooltips for links
if ( this.type === 'commentedText' &&
( this.$element.closest( 'a' ).length ||
this.$element.has( 'a' ).length
)
) {
events[ 'contextmenu.rt' ] = onStartEvent;
}
} else {
events = {
'mouseenter.rt': onStartEvent,
'mouseleave.rt': onEndEvent
};
}
}
 
});
this.$element.on( events );
$(".reference a").each(function() {
 
var span = document.createElement("span");
this.hideRef = function ( immediately ) {
span.className = "reference-hooker";
clearTimeout( te.showTimer );
span.appendChild(this.childNodes[0]);
 
this.appendChild(span);
if ( this.type === 'commentedText' ) {
});
this.$element.attr( 'title', this.comment );
if (getSettings("showRefOnHover", "boolean") && !isMobile) {
}
drawer.hover(function(e) {
 
showTooltip($("#" + origin.attr("data-origin") + " .reference-hooker").get(0));
if ( this.tooltip && this.tooltip.isPresent ) {
}, function(e) {
if ( activatedByClick || immediately ) {
hideTooltip();
this.tooltip.hide();
});
} else {
$(".reference-hooker").hover(function(e) {
this.hideTimer = setTimeout( function () {
showTooltip(this);
te.tooltip.hide();
}, function(e) {
}, 200 );
hideTooltip();
}
});
} else if ( this.$ref && this.$ref.hasClass( 'rt-target' ) ) {
this.$ref.removeClass( 'rt-target' );
if ( activatedByClick ) {
$body.off( 'click.rt touchstart.rt', this.onBodyClick );
}
}
};
 
this.showRef = function ( $element, ePageX, ePageY ) {
// Popups gadget
if ( window.pg ) {
disableRt();
return;
}
if ( this.tooltip && !this.tooltip.$content.length ) {
return;
}
 
var tooltipInitiallyPresent = this.tooltip && this.tooltip.isPresent;
 
function reallyShow() {
var viewportTop, refOffsetTop, teHref;
 
if ( !te.$ref && !te.comment ) {
teHref = te.type === 'supRef' ?
te.$element.find( 'a' ).attr( 'href' ) :
te.$element.attr( 'href' ); // harvardRef
te.$ref = teHref &&
$( '#' + $.escapeSelector( teHref.slice( 1 ) ) );
if ( !te.$ref || !te.$ref.length || !te.$ref.text() ) {
te.noRef = true;
return;
}
}
 
if ( !tooltipInitiallyPresent && !te.comment ) {
viewportTop = $window.scrollTop();
refOffsetTop = te.$ref.offset().top;
if ( !activatedByClick &&
viewportTop < refOffsetTop &&
viewportTop + $window.height() > refOffsetTop + te.$ref.height() &&
// There can be gadgets/scripts that make references horizontally scrollable.
$window.width() > te.$ref.offset().left + te.$ref.width()
) {
// Highlight the reference itself
te.$ref.addClass( 'rt-target' );
return;
}
}
 
if ( !te.tooltip ) {
te.tooltip = new Tooltip( te );
if ( !te.tooltip.$content.length ) {
return;
}
}
 
// If this tooltip is called from inside another tooltip. We can't define it
// in the constructor since a ref can be cloned but have the same Tooltip object;
// so, Tooltip.parent is a floating value.
te.tooltip.parent = te.$element.closest( '.rt-tooltip' ).data( 'tooltip' );
if ( te.tooltip.parent && te.tooltip.parent.disappearing ) {
return;
}
 
te.tooltip.show();
 
if ( tooltipInitiallyPresent ) {
if ( te.tooltip.$element.hasClass( 'rt-tooltip-above' ) ) {
te.tooltip.$element.addClass( CLASSES.FADE_IN_DOWN );
} else {
te.tooltip.$element.addClass( CLASSES.FADE_IN_UP );
}
return;
}
 
te.tooltip.calculatePosition( ePageX, ePageY );
 
$window.on( 'resize.rt', te.onWindowResize );
}
 
// We redefine this.$element here because e.target can be a reference link inside
// a reference tooltip, not a link that was initially assigned to this.$element
this.$element = $element;
 
if ( this.type === 'commentedText' ) {
this.$element.attr( 'title', '' );
}
 
if ( activatedByClick ) {
if ( tooltipInitiallyPresent ||
( this.$ref && this.$ref.hasClass( 'rt-target' ) )
) {
return;
} else {
setTimeout( function () {
$body.on( 'click.rt touchstart.rt', te.onBodyClick );
}, 0 );
}
}
 
if ( activatedByClick || tooltipInitiallyPresent ) {
reallyShow();
} else {
this.showTimer = setTimeout( reallyShow, delay );
}
};
 
this.onBodyClick = function ( e ) {
if ( !te.tooltip && !te.$ref.hasClass( 'rt-target' ) ) {
return;
}
 
var $current = $( e.target );
 
function contextMatchesParameter( parameter ) {
return this === parameter;
}
 
// The last condition is used to determine cases when a clicked tooltip is the current
// element's tooltip or one of its descendants
while ( $current.length &&
( !$current.hasClass( 'rt-tooltip' ) ||
!$current.data( 'tooltip' ) ||
!$current.data( 'tooltip' ).upToTopParent(
contextMatchesParameter, [ te.tooltip ],
true
)
)
) {
$current = $current.parent();
}
if ( !$current.length ) {
te.hideRef();
}
};
 
this.onWindowResize = function () {
te.tooltip.calculatePosition();
};
}
}
 
$(".reference-hooker").click(function(e) {
function Tooltip( te ) {
if (isMobile) {
function openSettingsDialog() {
e.preventDefault();
var settingsDialog, settingsWindow;
e.stopPropagation();
 
showDrawer(this.parentNode.getAttribute("href"), this.textContent, this.parentNode.parentNode.getAttribute("id"));
if ( cursorWaitCss ) {
drawer.addClass("visible");
cursorWaitCss.disabled = true;
} else if (!getSettings("showRefOnHover", "boolean")) {
}
e.preventDefault();
 
e.stopPropagation();
function SettingsDialog() {
showTooltip(this);
SettingsDialog.parent.call( this );
}
OO.inheritClass( SettingsDialog, OO.ui.ProcessDialog );
 
SettingsDialog.static.name = 'settingsDialog';
SettingsDialog.static.title = mw.msg( 'rt-settings-title' );
SettingsDialog.static.actions = [
{
modes: 'basic',
action: 'save',
label: mw.msg( 'rt-save' ),
flags: [ 'primary', 'progressive' ]
},
{
modes: 'basic',
label: mw.msg( 'rt-cancel' ),
flags: 'safe'
},
{
modes: 'disabled',
action: 'deactivated',
label: mw.msg( 'rt-done' ),
flags: [ 'primary', 'progressive' ]
}
];
 
SettingsDialog.prototype.initialize = function () {
var dialog = this;
 
SettingsDialog.parent.prototype.initialize.apply( this, arguments );
 
this.enableOption = new OO.ui.RadioOptionWidget( {
label: mw.msg( 'rt-enable' )
} );
/* this.disableOption = new OO.ui.RadioOptionWidget( {
label: mw.msg( 'rt-disable' )
} ); */
this.enableSelect = new OO.ui.RadioSelectWidget( {
items: [ this.enableOption, this.disableOption ],
classes: [ 'rt-enableSelect' ]
} );
this.enableSelect.selectItem( this.enableOption );
this.enableSelect.on( 'choose', function ( item ) {
if ( item === dialog.disableOption ) {
dialog.activationMethodSelect.setDisabled( true );
dialog.delayInput.setDisabled( true );
dialog.tooltipsForCommentsCheckbox.setDisabled( true );
} else {
dialog.activationMethodSelect.setDisabled( false );
dialog.delayInput.setDisabled( dialog.clickOption.isSelected() );
dialog.tooltipsForCommentsCheckbox.setDisabled( false );
}
} );
 
this.hoverOption = new OO.ui.RadioOptionWidget( {
label: mw.msg( 'rt-hovering' )
} );
this.clickOption = new OO.ui.RadioOptionWidget( {
label: mw.msg( 'rt-clicking' )
} );
this.activationMethodSelect = new OO.ui.RadioSelectWidget( {
items: [ this.hoverOption, this.clickOption ]
} );
this.activationMethodSelect.selectItem( activatedByClick ?
this.clickOption :
this.hoverOption
);
this.activationMethodSelect.on( 'choose', function ( item ) {
if ( item === dialog.clickOption ) {
dialog.delayInput.setDisabled( true );
} else {
dialog.delayInput.setDisabled( dialog.clickOption.isSelected() );
}
} );
this.activationMethodField = new OO.ui.FieldLayout( this.activationMethodSelect, {
label: mw.msg( 'rt-activationMethod' ),
align: 'top'
} );
 
this.delayInput = new OO.ui.NumberInputWidget( {
input: { value: delay },
step: 50,
min: 0,
max: 5000,
disabled: activatedByClick,
classes: [ 'rt-numberInput' ]
} );
this.delayField = new OO.ui.FieldLayout( this.delayInput, {
label: mw.msg( 'rt-delay' ),
align: 'top'
} );
 
this.tooltipsForCommentsCheckbox = new OO.ui.CheckboxInputWidget( {
selected: tooltipsForComments
} );
this.tooltipsForCommentsField = new OO.ui.FieldLayout(
this.tooltipsForCommentsCheckbox,
{
label: new OO.ui.HtmlSnippet( mw.msg( 'rt-tooltipsForComments' ) ),
align: 'inline',
classes: [ 'rt-tooltipsForCommentsField' ]
}
);
new TooltippedElement(
this.tooltipsForCommentsField.$element.find(
'.' + ( COMMENTED_TEXT_CLASS || 'rt-commentedText' )
)
);
 
this.fieldset = new OO.ui.FieldsetLayout();
this.fieldset.addItems( [
this.activationMethodField,
this.delayField,
this.tooltipsForCommentsField
] );
 
this.panelSettings = new OO.ui.PanelLayout( {
padded: true,
expanded: false
} );
this.panelSettings.$element.append(
this.enableSelect.$element,
$( '<hr>' ).addClass( 'rt-settingsFormSeparator' ),
this.fieldset.$element
);
 
this.panelDisabled = new OO.ui.PanelLayout( {
padded: true,
expanded: false
} );
this.panelDisabled.$element.append(
$( '<table>' )
.addClass( 'rt-disabledHelp' )
.append(
$( '<tr>' ).append(
$( '<td>' ).append(
$( '<img>' ).attr( 'src', 'https://wiki.studyforus.com/w/load.php?modules=ext.popups.images&image=footer&format=rasterized&lang=ru&skin=vector&version=0uotisb' )
),
$( '<td>' )
.addClass( 'rt-disabledNote' )
.text( mw.msg( 'rt-disabledNote' ) )
)
)
);
 
this.stackLayout = new OO.ui.StackLayout( {
items: [ this.panelSettings, this.panelDisabled ]
} );
 
this.$body.append( this.stackLayout.$element );
};
 
SettingsDialog.prototype.getSetupProcess = function ( data ) {
return SettingsDialog.parent.prototype.getSetupProcess.call( this, data )
.next( function () {
this.stackLayout.setItem( this.panelSettings );
this.actions.setMode( 'basic' );
}, this );
};
 
SettingsDialog.prototype.getActionProcess = function ( action ) {
var dialog = this;
 
if ( action === 'save' ) {
return new OO.ui.Process( function () {
var newDelay = Number( dialog.delayInput.getValue() );
 
enabled = dialog.enableOption.isSelected();
if ( newDelay >= 0 && newDelay <= 5000 ) {
delay = newDelay;
}
activatedByClick = dialog.clickOption.isSelected();
tooltipsForComments = dialog.tooltipsForCommentsCheckbox.isSelected();
 
setSettingsCookie();
 
if ( enabled ) {
dialog.close();
disableRt();
rt( $content );
} else {
dialog.actions.setMode( 'disabled' );
dialog.stackLayout.setItem( dialog.panelDisabled );
disableRt();
addEnableLink();
}
} );
} else if ( action === 'deactivated' ) {
dialog.close();
}
return SettingsDialog.parent.prototype.getActionProcess.call( this, action );
};
 
SettingsDialog.prototype.getBodyHeight = function () {
return this.stackLayout.getCurrentItem().$element.outerHeight( true );
};
 
tooltip.upToTopParent( function adjustRightAndHide() {
if ( this.isPresent ) {
if ( this.$element[ 0 ].style.right ) {
this.$element.css(
'right',
'+=' + ( window.innerWidth - $window.width() )
);
}
this.te.hideRef( true );
}
} );
 
if ( !windowManager ) {
windowManager = new OO.ui.WindowManager();
$body.append( windowManager.$element );
}
 
settingsDialog = new SettingsDialog();
windowManager.addWindows( [ settingsDialog ] );
settingsWindow = windowManager.openWindow( settingsDialog );
settingsWindow.opened.then( function () {
settingsDialogOpening = false;
} );
settingsWindow.closed.then( function () {
windowManager.clearWindows();
} );
}
 
var tooltip = this;
 
// This variable can change: one tooltip can be called from a harvard-style reference link
// that is put into different tooltips
this.te = te;
 
switch ( this.te.type ) {
case 'supRef':
this.id = 'rt-' + this.te.$originalElement.attr( 'id' );
this.$content = this.te.$ref
.contents()
.filter( function ( i ) {
var $this = $( this );
return this.nodeType === Node.TEXT_NODE ||
!( $this.is( '.mw-cite-backlink' ) ||
( i === 0 &&
// Template:Cnote, Template:Note
( $this.is( 'b' ) ||
// Template:Note_label
$this.is( 'a' ) &&
$this.attr( 'href' ).indexOf( '#ref' ) === 0
)
)
);
} )
.clone( true );
break;
case 'harvardRef':
this.id = 'rt-' + this.te.$originalElement.closest( 'li' ).attr( 'id' );
this.$content = this.te.$ref
.clone( true )
.removeAttr( 'id' );
break;
case 'commentedText':
this.id = 'rt-' + String( Math.random() ).slice( 2 );
this.$content = $( document.createTextNode( this.te.comment ) );
break;
}
if ( !this.$content.length ) {
return;
}
 
this.insideWindow = Boolean( this.te.$element.closest( '.oo-ui-window' ).length );
 
this.$element = $( '<div>' )
.addClass( 'rt-tooltip' )
.attr( 'id', this.id )
.attr( 'role', 'tooltip' )
.data( 'tooltip', this );
if ( this.insideWindow ) {
this.$element.addClass( 'rt-tooltip-insideWindow' );
}
 
// We need the $content interlayer here in order for the settings icon to have correct
// margins
this.$content = this.$content
.wrapAll( '<div>' )
.parent()
.addClass( 'rt-tooltipContent' )
.addClass( 'mw-parser-output' )
.appendTo( this.$element );
 
if ( !activatedByClick ) {
this.$element
.mouseenter( function () {
if ( !tooltip.disappearing ) {
tooltip.upToTopParent( function () {
this.show();
} );
}
} )
.mouseleave( function ( e ) {
// https://stackoverflow.com/q/47649442 workaround. Relying on relatedTarget
// alone has pitfalls: when alt-tabbing, relatedTarget is empty too
if ( CLIENT_NAME !== 'chrome' ||
( !e.originalEvent ||
e.originalEvent.relatedTarget !== null ||
!tooltip.clickedTime ||
$.now() - tooltip.clickedTime > 50
)
) {
tooltip.upToTopParent( function () {
this.te.hideRef();
} );
}
} )
.click( function () {
tooltip.clickedTime = $.now();
} );
}
 
if ( !this.insideWindow ) {
$( '<div>' )
.addClass( 'rt-settingsLink' )
.attr( 'title', mw.msg( 'rt-settings' ) )
.click( function () {
if ( settingsDialogOpening ) {
return;
}
settingsDialogOpening = true;
 
if ( mw.loader.getState( 'oojs-ui' ) !== 'ready' ) {
if ( cursorWaitCss ) {
cursorWaitCss.disabled = false;
} else {
cursorWaitCss = mw.util.addCSS( 'body { cursor: wait; }' );
}
}
mw.loader.using( [ 'oojs', 'oojs-ui' ], openSettingsDialog );
} )
.prependTo( this.$content );
}
}
 
});
// Tooltip tail element is inside tooltip content element in order for the tooltip
})
// not to disappear when the mouse is above the tail
this.$tail = $( '<div>' )
.addClass( 'rt-tooltipTail' )
.prependTo( this.$element );
 
this.disappearing = false;
 
this.show = function () {
this.disappearing = false;
clearTimeout( this.te.hideTimer );
clearTimeout( this.te.removeTimer );
 
this.$element
.removeClass( CLASSES.FADE_OUT_DOWN )
.removeClass( CLASSES.FADE_OUT_UP );
 
if ( !this.isPresent ) {
$body.append( this.$element );
}
 
this.isPresent = true;
};
 
this.hide = function () {
var tooltip = this;
 
tooltip.disappearing = true;
 
if ( tooltip.$element.hasClass( 'rt-tooltip-above' ) ) {
tooltip.$element
.removeClass( CLASSES.FADE_IN_DOWN )
.addClass( CLASSES.FADE_OUT_UP );
} else {
tooltip.$element
.removeClass( CLASSES.FADE_IN_UP )
.addClass( CLASSES.FADE_OUT_DOWN );
}
 
tooltip.te.removeTimer = setTimeout( function () {
if ( tooltip.isPresent ) {
tooltip.$element.detach();
tooltip.$tail.css( 'left', '' );
 
if ( activatedByClick ) {
$body.off( 'click.rt touchstart.rt', tooltip.te.onBodyClick );
}
$window.off( 'resize.rt', tooltip.te.onWindowResize );
 
tooltip.isPresent = false;
}
}, 200 );
};
 
this.calculatePosition = function ( ePageX, ePageY ) {
var teElement, teOffsets, teOffset, tooltipTailOffsetX, tooltipTailLeft,
offsetYCorrection = 0;
 
this.$tail.css( 'left', '' );
 
teElement = this.te.$element.get( 0 );
if ( ePageX !== undefined ) {
tooltipTailOffsetX = ePageX;
teOffsets = teElement.getClientRects &&
teElement.getClientRects() ||
teElement.getBoundingClientRect();
if ( teOffsets.length > 1 ) {
for (var i = teOffsets.length - 1; i >= 0; i--) {
if ( ePageY >= Math.round( $window.scrollTop() + teOffsets[i].top ) &&
ePageY <= Math.round(
$window.scrollTop() + teOffsets[i].top + teOffsets[i].height
)
) {
teOffset = teOffsets[i];
}
}
}
}
 
if ( !teOffset ) {
teOffset = teElement.getClientRects &&
teElement.getClientRects()[0] ||
teElement.getBoundingClientRect();
}
teOffset = {
top: $window.scrollTop() + teOffset.top,
left: $window.scrollLeft() + teOffset.left,
width: teOffset.width,
height: teOffset.height
};
if ( !tooltipTailOffsetX ) {
tooltipTailOffsetX = ( teOffset.left * 2 + teOffset.width ) / 2;
}
if ( CLIENT_NAME === 'msie' && this.te.type === 'supRef' ) {
offsetYCorrection = -Number(
this.te.$element.parent().css( 'font-size' ).replace( 'px', '' )
) / 2;
}
this.$element.css( {
top: teOffset.top - this.$element.outerHeight() - 7 + offsetYCorrection,
left: tooltipTailOffsetX - 20,
right: ''
} );
 
// Is it squished against the right side of the page?
if ( this.$element.offset().left + this.$element.outerWidth() > $window.width() - 1 ) {
this.$element.css( {
left: '',
right: 0
} );
tooltipTailLeft = tooltipTailOffsetX - this.$element.offset().left - 5;
}
 
// Is a part of it above the top of the screen?
if ( teOffset.top < this.$element.outerHeight() + $window.scrollTop() + 6 ) {
this.$element
.removeClass( 'rt-tooltip-above' )
.addClass( 'rt-tooltip-below' )
.addClass( CLASSES.FADE_IN_UP )
.css( {
top: teOffset.top + teOffset.height + 9 + offsetYCorrection
} );
if ( tooltipTailLeft ) {
this.$tail.css( 'left', ( tooltipTailLeft + 12 ) + 'px' );
}
} else {
this.$element
.removeClass( 'rt-tooltip-below' )
.addClass( 'rt-tooltip-above' )
.addClass( CLASSES.FADE_IN_DOWN )
// A fix for cases when a tooltip shown once is then wrongly positioned when it
// is shown again after a window resize. We just repeat what is above.
.css( {
top: teOffset.top - this.$element.outerHeight() - 7 + offsetYCorrection
} );
if ( tooltipTailLeft ) {
// 12 is the tail element width/height
this.$tail.css( 'left', tooltipTailLeft + 'px' );
}
}
};
 
// Run some function for all the tooltips up to the top one in a tree. Its context will be
// the tooltip, while its parameters may be passed to Tooltip.upToTopParent as an array
// in the second parameter. If the third parameter passed to ToolTip.upToTopParent is true,
// the execution stops when the function in question returns true for the first time,
// and ToolTip.upToTopParent returns true as well.
this.upToTopParent = function ( func, parameters, stopAtTrue ) {
var returnValue,
currentTooltip = this;
 
do {
returnValue = func.apply( currentTooltip, parameters );
if ( stopAtTrue && returnValue ) {
break;
}
} while ( currentTooltip = currentTooltip.parent );
 
if ( stopAtTrue ) {
return returnValue;
}
};
}
 
if ( !enabled ) {
addEnableLink();
return;
}
 
teSelector = REF_LINK_SELECTOR;
if ( tooltipsForComments ) {
teSelector += ', ' + COMMENTED_TEXT_SELECTOR;
}
$content.find( teSelector ).each( function () {
new TooltippedElement( $( this ) );
} );
}
 
settingsString = mw.cookie.get( 'RTsettings', '' );
if ( settingsString ) {
settings = settingsString.split( '|' );
enabled = Boolean( Number( settings[ 0 ] ) );
delay = Number( settings[ 1 ] );
activatedByClick = Boolean( Number( settings[ 2 ] ) );
// The forth value was added later, so we provide for a default value. See comments below
// for why we use "IS_TOUCHSCREEN && IS_MOBILE".
tooltipsForComments = settings[ 3 ] === undefined ?
IS_TOUCHSCREEN && IS_MOBILE :
Boolean( Number( settings[ 3 ] ) );
} else {
enabled = true;
delay = 200;
// Since the mobile browser check is error-prone, adding IS_MOBILE condition here would probably
// leave cases where a user interacting with the browser using touches doesn't know how to call
// a tooltip in order to switch to activation by click. Some touch-supporting laptop users
// interacting by touch (though probably not the most popular use case) would not be happy too.
activatedByClick = IS_TOUCHSCREEN;
// Arguably we shouldn't convert native tooltips into gadget tooltips for devices that have
// mouse support, even if they have touchscreens (there are laptops with touchscreens).
// IS_TOUCHSCREEN check here is for reliability, since the mobile check is prone to false
// positives.
tooltipsForComments = IS_TOUCHSCREEN && IS_MOBILE;
}
 
mw.hook( 'wikipage.content' ).add( rt );
 
}() );

2021년 2월 1일 (월) 02:54 기준 최신판

// This code is licensed under CC BY-SA 3.0
// Source: https://librewiki.net/wiki/미디어위키:Gadget-ReferenceTooltips-ko.js
// Contributors: https://librewiki.net/index.php?title=미디어위키:Gadget-ReferenceTooltips-ko.js&action=history

var isMobile = navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i);
var drawer, origin, content;
function showDrawer(id, name, orgId) {
	origin.attr("href", id);
	origin.attr("data-origin", orgId.replace(/\./g, "\\."));
	origin.text(name);
	content.html($(id.replace(/\./g, "\\.") + " > .reference-text").html());
	drawer.addClass("visible");
}

function getSettings(key, type) {
	if ("localStorage" in window) {
		if (type === "boolean") {
			return (window.localStorage[key] === "true");
		} else {
			return window.localStorage[key];
		}
	} else {
		var value = "; " + document.cookie;
		var parts = value.split("; " + key + "=");
		if (parts.length == 2) {
			if (type === "boolean") {
				return (parts.pop().split(";").shift() === "true");
			} else {
				return parts.pop().split(";").shift();
			}
		}
	}
}

function setSettings(key, value) {
	if ("localStorage" in window) {
		window.localStorage[key] = value;
	} else {
		var now = new Date();
		var time = now.getTime();
		var expireTime = time + (10 * 365 * 24 * 24);
		now.setTime(expireTime);
		document.cookie = key + "=" + value + ";expires=" + now.toGMTString() +";path=/";
	}
}

function initSettings() {
	if (document.getElementById("reference-settings")) {
		$("#reference-settings").show();
		return;
	}
	var setbox = $("<form>").attr("id", "reference-settings").append(
		$("<div>").addClass("content").append(
			$("<label>").append(
				$("<input>").attr({"type": "checkbox", "name": "showRefOnHover", "checked": getSettings("showRefOnHover", "boolean")}),
				"갖다 대서 주석을 띄웁니다."
			)
		),
		$("<div>").addClass("foot").append(
			$("<input>").attr({"type": "button", "value": "취소"}).click(function() {
				$("#reference-settings").hide();
			}),
			$("<input>").addClass("save-settings").attr({"type": "submit", "value": "저장"})
		)
	).submit(function(e) {
		e.preventDefault();
		setSettings("showRefOnHover", $(this).find("[name=showRefOnHover]").is(":checked"));
		location.reload();
	});
	$(document.body).append(setbox);
}

function showTooltip(elem) {
	showDrawer(elem.parentNode.getAttribute("href"), elem.textContent, elem.parentNode.parentNode.getAttribute("id"));
	drawer.show();
	drawer.css({ top: ($(elem).offset().top - drawer.outerHeight()), left: $(elem).offset().left });
	drawer.stop().animate({opacity: 1}, 100);
}

function hideTooltip() {
	drawer.removeClass("visible");
	drawer.animate({opacity: 0}, 100, function() { $(this).hide(); });
}

$(document).ready(function($) {
	if (getSettings("showRefOnHover") === undefined) {
		setSettings("showRefOnHover", true);
	}
	if (isMobile) {
		$(document.body).addClass("mode-drawer");
	} else {
		$(document.body).addClass("mode-tooltip");
	}
	/* create drawer */
	drawer = $("<div>").attr("id", "reference-drawer");
	origin = $("<a>").attr("id", "reference-origin").click(function() {
		$('html, body').animate({scrollTop: ($($(this).attr("href")).offset().top - 60)}, 400);
	});
	content = $("<span>").attr("id", "reference-drawer-text");
	var settingsIcon = $("<span>").addClass("settings-icon").click(function() {
		initSettings();
	});
	var closeDrawer = $("<span>").addClass("close-icon").click(function() {
		drawer.removeClass("visible");
	});
	drawer.append(settingsIcon);
	drawer.append(closeDrawer);
	drawer.append(origin);
	drawer.append(content);
	$(document.body).append(drawer);
	
	$(document).click(function(e) {
		if (!$(e.target).closest("#reference-drawer").length)  {
			if (!isMobile) {
				hideTooltip();
			} else {
				drawer.removeClass("visible");
			}
		}
	}).scroll(function(e) {
		if ("ontouchstart" in window && isMobile) {
			drawer.removeClass("visible");
		}
	});
	$(".reference a").each(function() {
		var span = document.createElement("span");
		span.className = "reference-hooker";
		span.appendChild(this.childNodes[0]);
		this.appendChild(span);
	});
	if (getSettings("showRefOnHover", "boolean") && !isMobile) {
		drawer.hover(function(e) {
			showTooltip($("#" + origin.attr("data-origin") + " .reference-hooker").get(0));
		}, function(e) {
			hideTooltip();
		});
		$(".reference-hooker").hover(function(e) {
			showTooltip(this);
		}, function(e) {
			hideTooltip();
		});
	}
	$(".reference-hooker").click(function(e) {
		if (isMobile) {
			e.preventDefault();
			e.stopPropagation();
			showDrawer(this.parentNode.getAttribute("href"), this.textContent, this.parentNode.parentNode.getAttribute("id"));
			drawer.addClass("visible");
		} else if (!getSettings("showRefOnHover", "boolean")) {
			e.preventDefault();
			e.stopPropagation();
			showTooltip(this);
		}
	});
})