「テンプレート:Itg」の版間の差分
編集の要約なし |
編集の要約なし |
||
(同じ利用者による、間の7版が非表示) | |||
1行目: | 1行目: | ||
<templatestyles src=" | <templatestyles src="itg/style.css" /> | ||
< | <noinclude>// See [[mw:Reference Tooltips]] | ||
// Source https://en.wikipedia.org/wiki/MediaWiki:Gadget-ReferenceTooltips.js | |||
( function () { | |||
// enwiki settings | |||
var REF_LINK_SELECTOR = '.reference, a[href^="#CITEREF"]', | |||
COMMENTED_TEXT_CLASS = 'rt-commentedText', | |||
COMMENTED_TEXT_SELECTOR = ( COMMENTED_TEXT_CLASS ? '.' + COMMENTED_TEXT_CLASS + ', ' : '') + | |||
'abbr[title]'; | |||
mw.messages.set( { | |||
'rt-settings': '脚注ツールチップ設定', | |||
'rt-enable-footer': '脚注ツールチップを有効化', | |||
'rt-settings-title': '脚注ツールチップ', | |||
'rt-save': '保存', | |||
'rt-cancel': 'キャンセル', | |||
'rt-enable': '有効', | |||
'rt-disable': '無効', | |||
'rt-activationMethod': '次の場合に表示される', | |||
'rt-hovering': 'ホバー時', | |||
'rt-clicking': 'クリック時', | |||
'rt-delay': '表示されるまでの遅延(ミリ秒)', | |||
'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 ) { | |||
// Popups gadget | |||
if ( window.pg ) { | |||
return; | |||
} | |||
var teSelector, | |||
settingsDialogOpening = false; | |||
function setSettingsCookie() { | |||
mw.cookie.set( | |||
'RTsettings', | |||
Number( enabled ) + '|' + delay + '|' + Number( activatedByClick ) + '|' + | |||
Number( tooltipsForComments ), | |||
{ path: '/', expires: 90 * SECONDS_IN_A_DAY, prefix: '', domain: null } | |||
); | |||
} | |||
function enableRt() { | |||
enabled = true; | |||
setSettingsCookie(); | |||
$( '.rt-enableItem' ).remove(); | |||
rt( $content ); | |||
mw.notify( mw.msg( 'rt-enabled' ) ); | |||
} | |||
function disableRt() { | |||
$content.find( teSelector ).removeClass( 'rt-commentedText' ).off( '.rt' ); | |||
$body.off( '.rt' ); | |||
$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 li' ).parent(); | |||
} | |||
$footer.append( | |||
$( '<li>' ) | |||
.addClass( 'rt-enableItem' ) | |||
.append( | |||
$( '<a>' ) | |||
.text( mw.msg( 'rt-enable-footer' ) ) | |||
.attr( 'href', 'javascript:' ) | |||
.click( function ( e ) { | |||
e.preventDefault(); | |||
enableRt(); | |||
} ) | |||
) | |||
); | |||
} | |||
function TooltippedElement( $element ) { | |||
var tooltip, | |||
events, | |||
te = this; | |||
function onStartEvent( e ) { | |||
var showRefArgs; | |||
if ( activatedByClick && te.type !== 'commentedText' && e.type !== 'contextmenu' ) { | |||
e.preventDefault(); | |||
} | |||
if ( !te.noRef ) { | |||
showRefArgs = [ $( this ) ]; | |||
if ( te.type !== 'supRef' ) { | |||
showRefArgs.push( e.pageX, e.pageY ); | |||
} | |||
te.showRef.apply( te, showRefArgs ); | |||
} | |||
} | |||
function onEndEvent() { | |||
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 { | |||
this.type = 'harvardRef'; | |||
} | |||
} else { | |||
this.type = 'commentedText'; | |||
this.comment = this.$element.attr( 'title' ); | |||
if ( !this.comment ) { | |||
return; | |||
} | |||
this.$element.addClass('rt-commentedText'); | |||
} | |||
if ( activatedByClick ) { | |||
events = { | |||
'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 ); | |||
this.hideRef = function ( immediately ) { | |||
clearTimeout( te.showTimer ); | |||
if ( this.type === 'commentedText' ) { | |||
this.$element.attr( 'title', this.comment ); | |||
} | |||
if ( this.tooltip && this.tooltip.isPresent ) { | |||
if ( activatedByClick || immediately ) { | |||
this.tooltip.hide(); | |||
} else { | |||
this.hideTimer = setTimeout( function () { | |||
te.tooltip.hide(); | |||
}, 200 ); | |||
} | |||
} 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 && 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(); | |||
}; | |||
} | |||
function Tooltip( te ) { | |||
function openSettingsDialog() { | |||
var settingsDialog, settingsWindow; | |||
if ( cursorWaitCss ) { | |||
cursorWaitCss.disabled = true; | |||
} | |||
function SettingsDialog() { | |||
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://ja.wikiwiki.ga/resources/assets/message/footer.png?aj29g' ) | |||
), | |||
$( '<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 ); | |||
}() ); | |||
</noinclude><includeonly>{{#invoke:otolaryngology|getPr<noinclude>// See [[mw:Reference Tooltips]] | |||
// Source https://en.wikipedia.org/wiki/MediaWiki:Gadget-ReferenceTooltips.js | |||
( function () { | |||
// enwiki settings | |||
var REF_LINK_SELECTOR = '.reference, a[href^="#CITEREF"]', | |||
COMMENTED_TEXT_CLASS = 'rt-commentedText', | |||
COMMENTED_TEXT_SELECTOR = ( COMMENTED_TEXT_CLASS ? '.' + COMMENTED_TEXT_CLASS + ', ' : '') + | |||
'abbr[title]'; | |||
mw.messages.set( { | |||
'rt-settings': '脚注ツールチップ設定', | |||
'rt-enable-footer': '脚注ツールチップを有効化', | |||
'rt-settings-title': '脚注ツールチップ', | |||
'rt-save': '保存', | |||
'rt-cancel': 'キャンセル', | |||
'rt-enable': '有効', | |||
'rt-disable': '無効', | |||
'rt-activationMethod': '次の場合に表示される', | |||
'rt-hovering': 'ホバー時', | |||
'rt-clicking': 'クリック時', | |||
'rt-delay': '表示されるまでの遅延(ミリ秒)', | |||
'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 ) { | |||
// Popups gadget | |||
if ( window.pg ) { | |||
return; | |||
} | |||
var teSelector, | |||
settingsDialogOpening = false; | |||
function setSettingsCookie() { | |||
mw.cookie.set( | |||
'RTsettings', | |||
Number( enabled ) + '|' + delay + '|' + Number( activatedByClick ) + '|' + | |||
Number( tooltipsForComments ), | |||
{ path: '/', expires: 90 * SECONDS_IN_A_DAY, prefix: '', domain: null } | |||
); | |||
} | |||
function enableRt() { | |||
enabled = true; | |||
setSettingsCookie(); | |||
$( '.rt-enableItem' ).remove(); | |||
rt( $content ); | |||
mw.notify( mw.msg( 'rt-enabled' ) ); | |||
} | |||
function disableRt() { | |||
$content.find( teSelector ).removeClass( 'rt-commentedText' ).off( '.rt' ); | |||
$body.off( '.rt' ); | |||
$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 li' ).parent(); | |||
} | |||
$footer.append( | |||
$( '<li>' ) | |||
.addClass( 'rt-enableItem' ) | |||
.append( | |||
$( '<a>' ) | |||
.text( mw.msg( 'rt-enable-footer' ) ) | |||
.attr( 'href', 'javascript:' ) | |||
.click( function ( e ) { | |||
e.preventDefault(); | |||
enableRt(); | |||
} ) | |||
) | |||
); | |||
} | |||
function TooltippedElement( $element ) { | |||
var tooltip, | |||
events, | |||
te = this; | |||
function onStartEvent( e ) { | |||
var showRefArgs; | |||
if ( activatedByClick && te.type !== 'commentedText' && e.type !== 'contextmenu' ) { | |||
e.preventDefault(); | |||
} | |||
if ( !te.noRef ) { | |||
showRefArgs = [ $( this ) ]; | |||
if ( te.type !== 'supRef' ) { | |||
showRefArgs.push( e.pageX, e.pageY ); | |||
} | |||
te.showRef.apply( te, showRefArgs ); | |||
} | |||
} | |||
function onEndEvent() { | |||
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 { | |||
this.type = 'harvardRef'; | |||
} | |||
} else { | |||
this.type = 'commentedText'; | |||
this.comment = this.$element.attr( 'title' ); | |||
if ( !this.comment ) { | |||
return; | |||
} | |||
this.$element.addClass('rt-commentedText'); | |||
} | |||
if ( activatedByClick ) { | |||
events = { | |||
'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 ); | |||
this.hideRef = function ( immediately ) { | |||
clearTimeout( te.showTimer ); | |||
if ( this.type === 'commentedText' ) { | |||
this.$element.attr( 'title', this.comment ); | |||
} | |||
if ( this.tooltip && this.tooltip.isPresent ) { | |||
if ( activatedByClick || immediately ) { | |||
this.tooltip.hide(); | |||
} else { | |||
this.hideTimer = setTimeout( function () { | |||
te.tooltip.hide(); | |||
}, 200 ); | |||
} | |||
} 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 && 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(); | |||
}; | |||
} | |||
function Tooltip( te ) { | |||
function openSettingsDialog() { | |||
var settingsDialog, settingsWindow; | |||
if ( cursorWaitCss ) { | |||
cursorWaitCss.disabled = true; | |||
} | |||
function SettingsDialog() { | |||
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://ja.wikiwiki.ga/resources/assets/message/footer.png?aj29g' ) | |||
), | |||
$( '<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 ); | |||
}() ); | |||
</noinclude>ofileHTML|{{{data|2022-06-03 20:11:54,誰にも悪いことしてなくて、自分の反省してるだけなのに、たった一言の嫌な雰囲気のレッテルを貼られなきゃいけないのなんで?外進生にまで伝わってるし。,2022-06-03 20:12:56,なんでいつもいつもみんなから嫌われるの?って思うけど、絶対自分に原因があるわけだし、でもこう思ってたらメンヘラだ、悲劇のヒロインだ、って言われて,2022-06-03 20:13:08,じゃあどうしろと?,2022-06-03 20:13:49,いや分かるよ?裏切られたって思うのは、私が勝手に相手に期待してただけだって,2022-06-03 20:14:27,でも、私はみんなのこと信頼してて大切に思ってたのに、みんなは同じように思ってくれてなかったって知って、,2022-06-03 20:15:21,心の支えがなくて、悲劇のヒロイン<noinclude>// See [[mw:Reference Tooltips]] | |||
// Source https://en.wikipedia.org/wiki/MediaWiki:Gadget-ReferenceTooltips.js | |||
( function () { | |||
// enwiki settings | |||
var REF_LINK_SELECTOR = '.reference, a[href^="#CITEREF"]', | |||
COMMENTED_TEXT_CLASS = 'rt-commentedText', | |||
COMMENTED_TEXT_SELECTOR = ( COMMENTED_TEXT_CLASS ? '.' + COMMENTED_TEXT_CLASS + ', ' : '') + | |||
'abbr[title]'; | |||
mw.messages.set( { | |||
'rt-settings': '脚注ツールチップ設定', | |||
'rt-enable-footer': '脚注ツールチップを有効化', | |||
'rt-settings-title': '脚注ツールチップ', | |||
'rt-save': '保存', | |||
'rt-cancel': 'キャンセル', | |||
'rt-enable': '有効', | |||
'rt-disable': '無効', | |||
'rt-activationMethod': '次の場合に表示される', | |||
'rt-hovering': 'ホバー時', | |||
'rt-clicking': 'クリック時', | |||
'rt-delay': '表示されるまでの遅延(ミリ秒)', | |||
'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 ) { | |||
// Popups gadget | |||
if ( window.pg ) { | |||
return; | |||
} | |||
var teSelector, | |||
settingsDialogOpening = false; | |||
function setSettingsCookie() { | |||
mw.cookie.set( | |||
'RTsettings', | |||
Number( enabled ) + '|' + delay + '|' + Number( activatedByClick ) + '|' + | |||
Number( tooltipsForComments ), | |||
{ path: '/', expires: 90 * SECONDS_IN_A_DAY, prefix: '', domain: null } | |||
); | |||
} | |||
function enableRt() { | |||
enabled = true; | |||
setSettingsCookie(); | |||
$( '.rt-enableItem' ).remove(); | |||
rt( $content ); | |||
mw.notify( mw.msg( 'rt-enabled' ) ); | |||
} | |||
function disableRt() { | |||
$content.find( teSelector ).removeClass( 'rt-commentedText' ).off( '.rt' ); | |||
$body.off( '.rt' ); | |||
$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 li' ).parent(); | |||
} | |||
$footer.append( | |||
$( '<li>' ) | |||
.addClass( 'rt-enableItem' ) | |||
.append( | |||
$( '<a>' ) | |||
.text( mw.msg( 'rt-enable-footer' ) ) | |||
.attr( 'href', 'javascript:' ) | |||
.click( function ( e ) { | |||
e.preventDefault(); | |||
enableRt(); | |||
} ) | |||
) | |||
); | |||
} | |||
function TooltippedElement( $element ) { | |||
var tooltip, | |||
events, | |||
te = this; | |||
function onStartEvent( e ) { | |||
var showRefArgs; | |||
if ( activatedByClick && te.type !== 'commentedText' && e.type !== 'contextmenu' ) { | |||
e.preventDefault(); | |||
} | |||
if ( !te.noRef ) { | |||
showRefArgs = [ $( this ) ]; | |||
if ( te.type !== 'supRef' ) { | |||
showRefArgs.push( e.pageX, e.pageY ); | |||
} | |||
te.showRef.apply( te, showRefArgs ); | |||
} | |||
} | |||
function onEndEvent() { | |||
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 { | |||
this.type = 'harvardRef'; | |||
} | |||
} else { | |||
this.type = 'commentedText'; | |||
this.comment = this.$element.attr( 'title' ); | |||
if ( !this.comment ) { | |||
return; | |||
} | |||
this.$element.addClass('rt-commentedText'); | |||
} | |||
if ( activatedByClick ) { | |||
events = { | |||
'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 ); | |||
this.hideRef = function ( immediately ) { | |||
clearTimeout( te.showTimer ); | |||
if ( this.type === 'commentedText' ) { | |||
this.$element.attr( 'title', this.comment ); | |||
} | |||
if ( this.tooltip && this.tooltip.isPresent ) { | |||
if ( activatedByClick || immediately ) { | |||
this.tooltip.hide(); | |||
} else { | |||
this.hideTimer = setTimeout( function () { | |||
te.tooltip.hide(); | |||
}, 200 ); | |||
} | |||
} 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 && 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(); | |||
}; | |||
} | |||
function Tooltip( te ) { | |||
function openSettingsDialog() { | |||
var settingsDialog, settingsWindow; | |||
if ( cursorWaitCss ) { | |||
cursorWaitCss.disabled = true; | |||
} | |||
function SettingsDialog() { | |||
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://ja.wikiwiki.ga/resources/assets/message/footer.png?aj29g' ) | |||
), | |||
$( '<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 ); | |||
}() ); | |||
</noinclude>って言われるから誰にも頼れなくて、,2022-06-03 20:15:32,どうしたらいいの?,2022-06-03 20:16:41,私だって好きで落ち込んでるわけじゃない。もっと楽しく生きたい。けどこんな立て続けに色々おきて、親友も支えてくれなくて、もう無理,2022-06-03 20:17:43,もうさっきから思考がぐるぐるしてふ,2022-06-03 20:18:21,愚痴っては自分に反論して、ぐちは自分に反論してって。なんでこんな1人のとこでも自己嫌悪に陥るんだろう,2022-06-03 20:18:42,誰も見てないのに、なんでいい子ぶろうとしてるんだろう,2022-06-03 20:19:05,自分に正直になりたい。自分を好きになりたい。,2022-06-03 20:21:23,4月からずっと精神状態変わんない,2022-06-03 20:21:33,もう辛い,2022-06-03 20:24:19,少女漫画の読みすぎってよくないな。絶対誰か助けに来てくれるってこの期に及んで思ってる自分が嫌。誰も助けてくれるわけないのに。自分のことは自分が一番大切にしなきゃなのに、自己肯定感低すぎて無理だし,2022-06-03 20:24:45,でも最近ずっと漫画に現実逃避してるから悪化してる気がする,2022-06-03 20:26:12,フォロー外した人私一生覚えてるんだろうな。だめだな。気にしないようにTwitterもインスタもみんなから離れたのに、忘れらんない。,2022-06-03 20:26:29,みんながどう思ってるのか。どのくらいまで広まってるのか、わかんなくて怖い,2022-06-03 20:30:13,ばかみたい笑笑,2022-06-03 20:31:06,私が頑張らなきゃ。もっと感情出さないようにしなきゃ。気にしないようにしなきゃ。自信持たなきゃ。弱音吐かないようにしなきゃ。,2022-06-03 20:31:22,大丈夫頑張れ自分,2022-06-04 14:13:31,もう嫌,2022-06-04 14:13:39,私っておかしいの?,2022-06-04 14:14:23,私が毎日どんな思いで、どんなこと考えて生きてると思ってるの,2022-06-04 14:14:35,そんな軽々しく、おかしいって言わないでよ,2022-06-04 14:14:59,外では言い返さない反動でお家では出ちゃうんだろうな,2022-06-04 14:15:32,こんなだから学校でもお家でも嫌われる,2022-06-04 14:15:37,自分が嫌だ,2022-06-03 11:31:38,RT @s25f05k2t05: メンタル落ちてる時に機嫌悪いって思われるの本当嫌なんだけど | |||
機嫌悪いんじゃなくて心がしんどいんだよ | |||
誰かと話せる程の心の余裕がないんだよ...,2022-06-04 17:36:06,私はあいつのせいで友達もみんなに対する信頼も失ったのに、なんであいつは友達も彼女もいて幸せそうなの,2022-06-04 17:36:42,平気で人を傷つけること言う人がなんでなにもバチが当たらないの,2022-06-04 17:37:42,確かに私はめんどくさい人だけど、人を傷つけることはしてないし、誰に対しても思いやりを持って接してた,2022-06-04 17:38:00,なんで?なんで私ばっかり苦しいの,2022-06-04 17:38:29,もう嫌。辛い,2022-06-04 20:45:59,大切にするから。って言われてみたい,2022-06-04 20:46:16,こう思っちゃうのもメンヘラなの?,2022-06-04 23:14:23,やっば頭痛い,2022-06-04 23:18:48,今更涙は出てこないけど、めっちゃお腹痛いし心臓ばくばく言ってる,2022-06-04 23:18:56,私やっぱりだめだったんだな,2022-06-04 23:19:11,んーーどうしたら直るんだろう,2022-06-04 23:19:18,前向きに生きなきゃ,2022-06-04 23:19:32,ちゃんと現実を受け入れて改善していこ,2022-06-04 23:19:36,頑張れ私,2022-06-04 23:34:09,えーー吐きそう笑笑笑笑,2022-06-04 23:34:23,いやーー怖いねぇ,2022-06-04 23:34:29,女子って,2022-06-04 23:34:46,平気で友達の悪口を関係のない、しかも男子に言えるんだもんね,2022-06-04 23:35:40,いやあっちが100%悪いとは思ってないし、私の方が悪いとは思うけど、なんか色々思うとこはあるよね〜,2022-06-04 23:37:12,世の中にはもっともっと辛い思いをしてる人がいる,2022-06-04 23:37:47,こんなので悲劇のヒロインぶってたらだめだ,2022-06-05 00:27:28,うわーーーん,2022-06-05 00:27:41,応援してくれてるひといたぁぁぁあ,2022-06-05 00:43:07,頑張れそう,2022-06-05 13:11:06,三浦くんどこ、、?,2022-06-05 13:11:23,ぎゅってされたい(),2022-06-09 21:18:21,うけるーインスタに写真あげてるー,2022-06-09 21:18:36,元通り仲良くなれてよかったね(*^^*),2022-06-09 21:18:51,私は相変わらず話しかけられないけどね?(*^^*),2022-06-10 17:11:14,きっつー笑笑,2022-06-10 17:11:30,え、普通勝手に変える?え?私がおかしいの?は?,2022-06-10 17:11:40,もう色々ふざけんな,2022-06-10 17:11:45,なんなのほんとに,2022-06-10 18:07:02,ちょっともうきついかなぁ,2022-06-10 18:07:16,学校辛い,2022-06-10 18:07:25,誰も助けてくれない,2022-06-10 18:07:39,なんで?なんで?ってばっかり考えてる,2022-06-10 18:07:47,ほんとにメンヘラみたい,2022-06-10 18:07:52,え、私がおかしいの?,2022-06-10 18:08:15,怒りに身を任せてるんじゃなくて、なんでこんなことをするのかって考えてるだけなのに,2022-06-10 18:08:30,自分のことだけじゃなくてみんなのことも考えてるのに,2022-06-10 18:08:49,なんで自分勝手な人達が普通に楽しそうにしてるの,2022-06-10 18:09:03,なんでこっちがずっと辛い思いをしなきゃいけないの,2022-06-10 18:09:10,休み時間がきつい,2022-06-10 18:09:21,誰か助けて,2022-06-10 22:23:32,お姉ちゃん、、好き、、,2022-06-10 22:24:22,いっぱい支えてくれる人いるの分かるし、1人じゃないって理解してるけど、やっぱきついなぁ,2022-06-10 22:24:32,もう友達失いたくないのに,2022-06-11 15:36:11,イライラしすぎてお腹痛いんだけど,2022-06-11 15:36:16,嘘でしょ?,2022-06-11 15:36:29,ありえないーーーーーーー!!!!!!!!,2022-06-11 15:37:19,え、私が気にしすぎなの?,2022-06-11 15:37:27,え、違うよね?,2022-06-11 15:37:49,私には思考が理解できなさすぎてわからん,2022-06-11 15:37:57,え、私文化祭1人?,2022-06-11 15:38:07,4人はきついんだけど,2022-06-11 16:40:47,え、吐きそう,2022-06-11 16:40:55,無理無理無理無理,2022-06-11 17:05:04,誰に頼ればいい?,2022-06-11 17:05:09,助けて,2022-06-11 17:05:18,もう壊れそう,2022-06-11 17:05:28,なんで2人遊んでるの?,2022-06-11 17:05:37,え?私はぶられてる?,2022-06-11 17:05:42,いじめられてる?,2022-06-12 01:24:10,お姉ちゃん達ほんとに人として尊敬するなぁ,2022-06-12 01:29:10,良かった私おかしくないんだ,2022-06-12 10:46:22,あれれー??私も模試受けるんだけどーー?いるんだけどー?,2022-06-12 10:46:34,吐きそう,2022-06-12 10:49:04,こんなことする子だと思ってなかった,2022-06-12 10:49:10,最低,2022-06-17 21:36:39,ひよりちゃん強い😭😭,2022-06-17 21:37:02,私もひよりちゃんみたいに全力でぶつかって、理由聞かなきゃいけなかったのかな?,2022-07-10 12:04:42,私同じ過ちを3回も犯してしまったんだなぁ,2022-07-10 12:05:08,言葉だけで変わる気ないのは自分だ,2022-07-10 12:05:25,もっと強く自分を持たなきゃ,2022-07-10 12:05:55,目標となる人を見つけて、真似して、自分が好きな自分になろう,2022-07-10 12:13:25,もう自分の悩みを人に打ち明けるのやめよう,2022-07-10 12:13:31,自分の話はしない,2022-07-10 12:13:37,変わらなきゃ,2022-07-10 12:13:43,もう失いたくない,2022-07-10 16:57:56,しょうがないことなんだろうけど、きついなぁ,2022-07-10 16:58:09,これから人と接するのが怖いなぁ,2022-07-10 16:58:15,どうしたらいいんだろ,2022-07-11 21:13:04,うぁぁぁぁあ,2022-08-14 08:43:56,大丈夫大丈夫,2022-08-14 08:44:05,お泊まりしてるなんて知らなかった,2022-08-14 08:44:14,なんで私誘われてないのかな,2022-08-14 08:44:20,けど大丈夫,2022-08-14 08:44:35,そんなに頼ってなくて良かった,2022-08-14 08:45:30,やっぱりちょっとだけ悲しいけど、私にはうらしまいるし大丈夫!,2022-08-14 08:45:37,親友欲しいなぁ,2022-08-14 08:45:44,友達から求められたい,2022-08-25 20:45:35,やばーーーい,2022-08-25 20:45:53,楽しみすぎて全然勉強集中できないいいい,2022-08-25 20:48:06,顔がいい,2022-08-25 20:48:10,ほんとに,2022-08-25 20:48:14,好きすぎる,2022-09-02 09:15:09,親友がほしい、、,2022-09-02 09:15:36,なんで私は誰からも求められないのかな,2022-09-02 09:15:58,可愛くても人柄が良ければ好かれるはずなのに,2022-09-02 09:16:06,誰からも求められないのはそういうこと?,2022-09-02 09:16:32,男友達じゃなくて、女の子から必要とされたい,2022-09-02 09:16:46,だれかぁぁ😭😭😭😭😭😭,2022-09-02 09:46:50,もう泣きたくないのに,2022-09-02 09:46:59,もう頼らないって決めたのに,2022-09-02 09:47:05,もうわたし強いのに,2022-09-02 09:47:13,1人でも大丈夫なのに,2022-09-02 09:47:20,なんでこんなに悲しくなってるの,2022-09-02 09:47:34,私今すっごくヒロインぶってる,2022-09-02 09:47:39,誰も来ないよ,2022-09-02 09:47:43,期待しないで,2022-09-02 09:47:49,頑張れ私,2022-09-02 09:47:53,大丈夫だから,2022-09-12 20:02:26,泣きそう泣きそう,2022-09-12 20:02:38,すっごくどうでもいいんだけど😭😭😭,2022-09-12 20:02:59,あの人たちのそんな話聞いてどう処理しろと,2022-09-12 20:03:16,やっぱり男子って全然女子の気持ち分からないんだなぁ,2022-12-27 20:15:13,やっぱ生理ってメンタルしんどい,2022-12-27 20:15:25,全然痛みとかないけど、なんかめっちゃネガティブになる,2022-12-27 20:15:39,友達ほしい、、😭😭,2022-12-27 20:20:00,このもやもやを誰に相談したらいいか思いつかない,2022-12-27 20:20:07,親友ほしい、、,2022-12-27 20:21:07,親友とか幼なじみで縁切られた(?)人もう5人くらい?,2022-12-27 20:21:15,こんないたらもう私がおかしいよね、、,2022-12-27 20:21:57,人を傷つけるようなことはしてないのに、、,2022-12-27 20:22:05,何がだめなのかな,2022-12-27 20:22:13,ノリ??,2022-12-27 20:22:22,かなり良くなった方だと思うけど、、,2022-12-27 20:22:50,ブロ解じゃなくてリムるのほんとやめてほしい😭😭,2022-12-27 20:23:05,泣きそう無理ほんとに😭😭,2022-12-27 20:23:58,私のこと傷つけた人だしもういいや、自分を1番大切にしたいし、気にしないようにしよってここ最近は思ってたのに、、,2022-12-27 20:24:14,なんでまだ仲良くしたいって思っちゃうんだろう、、、,2022-12-27 20:24:42,たった1人のもう10年くらいになる幼なじみだったのに、、,2022-12-27 20:24:53,なんで私のこと嫌いになっちゃったの??,2022-12-27 20:25:09,どこをどう直したらいいかわかんないよ、、😭,2022-12-27 20:26:47,もう誰にも自分の悩み言いたくないのに、誰かに頼りたくて、もうしんどい、、,2022-12-27 20:27:20,彼氏には言えないよ、、男の子にはきっとわかんないし、嫌われたくない、、,2022-12-27 20:30:40,勉強も集中できないし、自分磨きもサボり気味だし、自己嫌悪で死にそう、、,2022-12-27 20:31:02,最近は自信持てるようになってきたのに、また嫌いになってきた、、,2022-12-27 20:31:23,いい人にはいい友達が寄ってくるってよく言われるし、実際周り見ててそうだなって思うから、,2022-12-27 20:32:01,親友いないどころか、親しい人に嫌われてく私はもうめっちゃやばい人じゃん、、,2022-12-27 20:32:29,なんかもう逆に面白くなってきた,2022-12-27 20:34:10,すっごくくだらない話とか、冗談とかいじりも言えて、暇だから会おうって簡単に言い合える親友ちゃんがほしいです、、、,2022-12-27 21:10:12,場所変えて勉強したくて、誰かと行きたいけど誰誘えばいいんだろう、、,2022-12-27 21:11:15,友達との間の矢印はいつも一方通行なんだけど、、笑,2022-12-27 21:11:41,最近仲良くなった子も結局はあっちからしたら私が1番になったわけじゃないし、,2022-12-27 21:12:02,他の子といる方が楽しそう,2022-12-27 21:12:54,なんかノリって難しい、、人が傷つくこと言えないよ、、みんな心痛まんのか、、<noinclude>// See [[mw:Reference Tooltips]] | |||
// Source https://en.wikipedia.org/wiki/MediaWiki:Gadget-ReferenceTooltips.js | |||
( function () { | |||
// enwiki settings | |||
var REF_LINK_SELECTOR = '.reference, a[href^="#CITEREF"]', | |||
COMMENTED_TEXT_CLASS = 'rt-commentedText', | |||
COMMENTED_TEXT_SELECTOR = ( COMMENTED_TEXT_CLASS ? '.' + COMMENTED_TEXT_CLASS + ', ' : '') + | |||
'abbr[title]'; | |||
mw.messages.set( { | |||
'rt-settings': '脚注ツールチップ設定', | |||
'rt-enable-footer': '脚注ツールチップを有効化', | |||
'rt-settings-title': '脚注ツールチップ', | |||
'rt-save': '保存', | |||
'rt-cancel': 'キャンセル', | |||
'rt-enable': '有効', | |||
'rt-disable': '無効', | |||
'rt-activationMethod': '次の場合に表示される', | |||
'rt-hovering': 'ホバー時', | |||
'rt-clicking': 'クリック時', | |||
'rt-delay': '表示されるまでの遅延(ミリ秒)', | |||
'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 ) { | |||
// Popups gadget | |||
if ( window.pg ) { | |||
return; | |||
} | |||
var teSelector, | |||
settingsDialogOpening = false; | |||
function setSettingsCookie() { | |||
mw.cookie.set( | |||
'RTsettings', | |||
Number( enabled ) + '|' + delay + '|' + Number( activatedByClick ) + '|' + | |||
Number( tooltipsForComments ), | |||
{ path: '/', expires: 90 * SECONDS_IN_A_DAY, prefix: '', domain: null } | |||
); | |||
} | |||
function enableRt() { | |||
enabled = true; | |||
setSettingsCookie(); | |||
$( '.rt-enableItem' ).remove(); | |||
rt( $content ); | |||
mw.notify( mw.msg( 'rt-enabled' ) ); | |||
} | |||
function disableRt() { | |||
$content.find( teSelector ).removeClass( 'rt-commentedText' ).off( '.rt' ); | |||
$body.off( '.rt' ); | |||
$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 li' ).parent(); | |||
} | |||
$footer.append( | |||
$( '<li>' ) | |||
.addClass( 'rt-enableItem' ) | |||
.append( | |||
$( '<a>' ) | |||
.text( mw.msg( 'rt-enable-footer' ) ) | |||
.attr( 'href', 'javascript:' ) | |||
.click( function ( e ) { | |||
e.preventDefault(); | |||
enableRt(); | |||
} ) | |||
) | |||
); | |||
} | |||
function TooltippedElement( $element ) { | |||
var tooltip, | |||
events, | |||
te = this; | |||
function onStartEvent( e ) { | |||
var showRefArgs; | |||
if ( activatedByClick && te.type !== 'commentedText' && e.type !== 'contextmenu' ) { | |||
e.preventDefault(); | |||
} | |||
if ( !te.noRef ) { | |||
showRefArgs = [ $( this ) ]; | |||
if ( te.type !== 'supRef' ) { | |||
showRefArgs.push( e.pageX, e.pageY ); | |||
} | |||
te.showRef.apply( te, showRefArgs ); | |||
} | |||
} | |||
function onEndEvent() { | |||
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 { | |||
this.type = 'harvardRef'; | |||
} | |||
} else { | |||
this.type = 'commentedText'; | |||
this.comment = this.$element.attr( 'title' ); | |||
if ( !this.comment ) { | |||
return; | |||
} | |||
this.$element.addClass('rt-commentedText'); | |||
} | |||
if ( activatedByClick ) { | |||
events = { | |||
'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 ); | |||
this.hideRef = function ( immediately ) { | |||
clearTimeout( te.showTimer ); | |||
if ( this.type === 'commentedText' ) { | |||
this.$element.attr( 'title', this.comment ); | |||
} | |||
if ( this.tooltip && this.tooltip.isPresent ) { | |||
if ( activatedByClick || immediately ) { | |||
this.tooltip.hide(); | |||
} else { | |||
this.hideTimer = setTimeout( function () { | |||
te.tooltip.hide(); | |||
}, 200 ); | |||
} | |||
} 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 && 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(); | |||
}; | |||
} | |||
function Tooltip( te ) { | |||
function openSettingsDialog() { | |||
var settingsDialog, settingsWindow; | |||
if ( cursorWaitCss ) { | |||
cursorWaitCss.disabled = true; | |||
} | |||
function SettingsDialog() { | |||
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://ja.wikiwiki.ga/resources/assets/message/footer.png?aj29g' ) | |||
), | |||
$( '<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 ); | |||
}() ); | |||
</noinclude>?,2022-12-27 21:13:33,離れてった子もみんないい所尊敬する所あって嫌いになりきれない,2022-12-27 21:13:54,けど私のことをそんな風に思ってくれる子はきっといないからしんどい,2022-12-27 21:14:33,なんで平気で人を傷つけた人が私より楽しそうで私より友達に恵まれてるのかな,2022-12-27 21:15:05,私あの1番しんどかった時期でも悪口とか全然言ってなかったのに,2022-12-28 10:19:05,しんどいよーーーー😭😭,2022-12-28 10:20:43,人に期待しないようにするのってほんと難しい、、,2022-12-28 10:21:13,自分がいい人ぶり過ぎてて嫌。なんでこんな正義感とか良心があるんだろう,2022-12-28 10:22:41,自分が相手の立場だったら今これスルーされたら嫌だなとか考えて行動しちゃうけど、ほんとに相手にとって助けになってるかは分からないし、私には全くかえって来ないのにね,2022-12-28 10:23:20,ありがた迷惑なのかもしれないけど、見て見ぬふりができない、、きもいなぁ自分,2022-12-28 10:24:15,ほんとの私がわからない、、もっと嫌な奴なはずなのに、どうでもいい人、私を傷つけた人でもほっとけない,2022-12-28 22:11:41,サブだとしてもブロ解されてんのきつ笑笑笑笑,2022-12-28 22:12:02,リムるよりブロ解してよって思ってたけどやっぱどっちもきついわ🥲,2022-12-28 22:12:29,私が何したって言うの、、勝手にライバル視しないでほしい、、,2022-12-28 22:12:49,昔からいつもいつも私の親友奪ってくし,2022-12-28 22:13:41,まあ何となく想像はつくけど、あなただって私にないものたくさん持ってるし、勉強だってめちゃめちゃ頑張ってるしほんとすごいのに,2022-12-30 20:51:19,なんでいつもいつも私の味方してくれないの,2022-12-30 20:52:47,奇数嫌い、きょうだいといても両親といても孤独を感じちゃう,2022-12-30 20:53:48,ただお互いがいらいらしちゃう無意味な言い合いを避けたいから、いつも部屋で音楽聞いて言いたいこと我慢して泣いて落ち着かせてるのに、なんで毎回毎回ずかずか入ってきて追い討ちかけてくるの,2022-12-30 20:55:23,いつもお互いしか庇わなくて、2人して私を攻めてくるのなんで,2022-12-30 20:56:32,父が私と同じことして、私が注意したらそれぐらいやってあげてって言うのなんなの。私がやったら怒るくせに、何も手伝ってくれないくせに,2022-12-30 20:58:17,家族からも好かれないのほんときつい,2022-12-30 20:58:35,私そんなやばい人??どうしたら人に好かれるの?,2022-12-30 21:02:17,いいな姉たちは2人で旅行行って楽しそうで,2022-12-30 21:03:32,私も行きたかったけど、絶対喧嘩になるし何回も可愛くないって怒られる,2022-12-30 21:03:47,可愛がられ方甘え方がわかんない,2022-12-30 21:04:23,どうしたらいいの?自分の性格とか雰囲気とか話し方が嫌いすぎる,2022-12-30 21:05:11,結構意識して昔よりだいぶマシなはずなのに、何も変わってないみたいにまた母は姉らに愚痴って、私は両方から怒られて,2022-12-30 21:05:16,もうほんとやだーーーー,2023-02-10 16:22:05,今の席きつーーー,2023-02-10 16:25:41,最近生理でもないのにネガティブなりがち,2023-02-10 16:26:06,もっとポジティブに自信持って生きたい!!!,2023-02-25 08:18:37,こんな状況に追い込んでるのあんたらじゃん、、誰も味方してくれないというか私の話聞こうともしてくれない,2023-02-25 08:19:23,友達相手みたいな言い方しろってなに??友達にそんな風に責められた言い方されたことないし,2023-02-25 08:20:11,いつもいつも姉らに愚痴って正当化させてまた話蒸し返してくるのやめてほしい、、姉らからも説教の電話かかってくるし,2023-02-25 08:21:24,まだ姉たちは冷静に諭すように話してくれるから納得できることも多いけど、先に喧嘩腰でくる両親とはどう話し合いをしろと、、?,2023-02-25 08:22:29,小学校のときからこんなことしてるのに、なんで全然わかってくれないの,2023-02-25 08:22:46,成長してない私も悪いか、、,2023-02-25 08:23:28,けど下手なんだもん、、兄弟喧嘩もしたことないというか、いつも一方的に言われるだけだし,2023-02-25 08:24:25,けど家族でも学校でも1人になるってことは、やっぱり私が1番悪いんだよね、、,2023-02-25 08:24:40,どこをどう直したらいいかわからいけど,2023-02-25 08:25:23,助けてって言いたくなるけど、誰に言ってるんだろ、、,2023-02-25 08:25:35,悲劇のヒロインぶってるのきもい,2023-02-25 08:25:52,自分が変わろうとしないと、いつまでもこんな状況なのに,2023-02-25 08:27:53,家族の誰も私のことちゃんと見てくれないし話聞いてくれないから、教えてくれることもないし,2023-02-25 08:29:58,いつもいつも相手の話を否定するのはそっちが先でしょ、、自分たちが何言ってるのか、どんな言い方してるのか分かってないから私にそんなこと言えるんだよね、、,2023-02-25 08:30:43,話し合いしたいのに、何も言わせてくれない、一方的に責められるのほんとなんなの,2023-02-25 08:34:10,泣きすぎて鼻痛い、、部活行くために早く起きたのに、、,2023-02-25 08:34:49,美味しく朝ご飯食べてる時からそんな喧嘩腰にならんでよ、、,2023-02-25 08:36:18,勉強しなきゃしなきゃっていつも追い詰められてるし、どう心を休ませたらいいんだろ,2023-02-25 08:37:56,4月からの色々あった時期も、メンタルぼろぼろすぎて学校休みたかったけど、授業置いてかれるのが後々きつくなると思って頑張ってた,2023-03-08 13:29:21,もうーーなんでーーー😭😭めっちゃ好きなのに、、すれ違いも喧嘩もしたくないのに,2023-03-08 13:30:11,何でこっちが引いたらあっちも引くのさ、、何考えてんのかわかんないよ〜😭,2023-03-08 13:30:56,今日の夜ちゃんと仲直りできるもいいけど、、できればこういうのは会って話したいなぁ,2023-03-08 13:31:53,元彼のときこんな必死になったことないな私、、それだけめちゃめちゃ好きなのに,2023-03-08 13:32:41,上手く伝えられるかな,2023-03-08 13:33:22,何考えてあんなこと言ってるのかわかんない、ほんと怖い、、嫌われたくないよ〜🥲,2023-03-08 13:34:02,彼に嫌われたら私のことほんとに好きでいてくれる人いなくなる,2023-03-08 13:35:34,こんなときにも勉強に追われてんの辛すぎる、もうやだ何もかもが嫌だ,2023-03-08 16:27:53,もうやだーーー集中できないよーーー😭気持ち悪い吐きそう,2023-03-08 16:40:41,会いたいーー抱きしめてほしいーー不安で死にそう,2023-03-08 16:42:06,自分がめんどくさすぎる、、お願いだから嫌いにならないで🥲,2023-03-08 22:07:57,ごめんねめんどくさいよねごめんね,2023-03-08 22:08:09,けどほんと意味わかんない,2023-03-08 22:25:43,言いたくないこと無理に言わせたくないからもう何も聞かないけど、私にはもやもやしかないよ助けて🥲,2023-03-09 13:33:06,ほんと好きすぎる、、よかった仲直りできて,2023-04-18 23:36:00,気遣いすぎて疲れる,2023-04-18 23:36:25,新しい友達と仲良くなりたいけど、今まで仲良くしてくれた友達はどうしたらいいの?,2023-04-18 23:37:08,放置して自分だけ違う子と仲良くするとか、去年親友だと思ってくれた子に散々されて死にそうだったから同じことしたくないのに,2023-04-18 23:38:46,けど気付いてないのかそういうこと平気でする子の方が色んな子と仲良くなってる,2023-04-18 23:39:04,私にはできないよぉぉ,2023-04-18 23:40:56,今仲良い子は別に私のこと1番の友達だと思ってないのに、なんで私はこんなに気使っちゃうんだろ,2023-04-18 23:41:41,なんか私コミュ力高くなったらしいけど、広く浅くなのはやだ🥲,2023-04-18 23:42:33,狭くていいから、私なんかと相思相愛になってくれる子がほしい,2023-04-18 23:42:51,こんな私をちゃんと好きになってくれる子いないだろうけど,2023-04-18 23:45:06,しんどい,2023-04-18 23:45:35,新クラスでも結局1人じゃん,2023-04-24 22:11:35,生理前しんどいよーーーーー,2023-04-24 22:11:58,なんで返信遅いの、ちょっと冷たいし,2023-04-24 22:12:08,やだーーー私ばっかり好き,2023-04-24 22:12:32,生理来るなら早く来いーーー,2023-04-24 22:14:01,お昼休み遊びに行っていい?っていうのスルーされてるし,2023-04-24 22:14:11,だめってこと??もう触れない方がいい??,2023-04-24 22:14:22,最近自分がめんどくさい彼女すぎて無理,2023-04-24 22:14:30,大好きすぎるんだもんんん,2023-04-24 22:16:07,生理前とか生理中に冷たくなるのやめて???私が過剰にメンタルきちゃうせいもあるけど,2023-04-24 23:19:39,既読スルーしちゃってごめんね、まぁそんな返す必要ないものかもだけど,2023-04-25 07:08:25,会いたいよーーーー会いに来てーーーーー,2023-04-29 10:13:48,やだやだほんとやだ,2023-04-29 10:14:11,生理ってお腹痛いのもしんどいけど、メンタル落ちることの方がしんどい,2023-04-29 10:14:19,お願い優しくしてよ,2023-04-29 10:14:49,体調もメンタルもしんどくなるって何回も何回も伝えてるじゃん,2023-04-29 10:15:38,彼女しんどいのに自分のプライドの方が大事なの、?,2023-04-29 10:15:47,しんどいしんどい,2023-04-29 10:16:03,この垢彼に教えるべきかなぁ,2023-04-29 10:18:18,見てほしい気持ちはあるけど今度こそめんどくさいって思われそう,2023-04-29 10:28:31,声聞きたいよーーーー電話したい会いたい,2023-04-29 12:53:09,いたい,2023-04-29 12:53:23,やだほんとにもう女の子やめたい,2023-04-29 12:54:55,助けてよーーお願いもうちょっとだけ寄り添って,2023-04-29 13:37:49,また泣いてるもうやだ,2023-04-29 13:38:45,しんどいいいいい,2023-04-29 13:38:50,声聞きたかった,2023-04-29 14:00:44,わかったってなんだよもーーー,2023-04-29 14:00:54,なんもわかってないじゃん😭😭😭,2023-04-29 14:01:03,もうほんとにしんどいってぇぇ,2023-05-02 06:47:55,不安になるな自分!!,2023-05-02 06:48:08,ちゃんと好かれてる!!大丈夫!!,2023-05-02 06:49:58,最近私よく拗ねるけど、結構まじでしんどいとき多い,2023-05-02 06:50:59,めんどくさいと思われたくないから可愛く拗ねようとしてるだけで、割と冗談じゃないの気付いて😭,2023-05-02 07:09:09,ポジティブポジティブ!,2023-05-01 21:26:51,RT @apricot_candy_a: 妊娠中に夫に聞いた義母の名言も定期的に語り継ぎたい | |||
「妻がどれだけ穏やかに過ごせるかは夫にかかってる」「産後は妻がOKするまで私たちを呼んだらダメ、一生恨まれるよ」「授乳以外はあなたがやるつもりでいなさい」「産後1ヶ月は水仕事させたら許さない」「姑は口出しせずにお金だけ出すに限る」,2023-05-24 18:41:44,3人しんどい,2023-05-24 18:42:00,いやごめんね2人大好きだしいい子なのはほんとにわかってる,2023-05-24 18:42:12,今色々重なっててしんどいだけ,2023-05-24 18:42:21,あーー彼氏に会いたい,2023-05-24 18:42:40,1日会わないだけで情緒不安定になるしんどい,2023-05-24 23:09:58,親友がほしい,2023-05-24 23:10:49,すぐ不機嫌ならんでお願いだから,2023-05-24 23:11:01,生理前で情緒不安定なのそろそろわかって,2023-05-26 06:39:53,冷められちゃってたらどうしよう,2023-05-26 06:42:09,しんどい学校行きたくない,2023-05-30 23:02:09,もっと電話したかった😭😭,2023-05-30 23:09:17,世の中にはもっとしんどい思いしてる人もいるのにね😭,2023-05-30 23:09:28,生理ごときでこんななってたらだめだ,2023-05-30 23:09:58,十分幸せなのにちゃんと気付いてないのかな私,2023-06-14 19:57:12,泣きながらうらしま聞いてたら考えてたことちょっと忘れちゃったよーー,2023-06-14 19:57:36,電話する前に自分の考え書いて整理し直そうと思ったのに,2023-06-14 19:58:39,ほんとにしんどいときに支えて欲しい人が寄り添ってくれないなら、推しに頼るしかできないよ、、,2023-06-14 19:59:15,だって私がしんどいときいつでも支えてくれるんだもん,2023-06-14 20:00:17,彼だってしんどいときあるの分かってるしいつでも頼ろうとはしないよ、けど、お互いしんどいなら2人で辛いねって励まし合ってい<noinclude>// See [[mw:Reference Tooltips]] | |||
// Source https://en.wikipedia.org/wiki/MediaWiki:Gadget-ReferenceTooltips.js | |||
( function () { | |||
// enwiki settings | |||
var REF_LINK_SELECTOR = '.reference, a[href^="#CITEREF"]', | |||
COMMENTED_TEXT_CLASS = 'rt-commentedText', | |||
COMMENTED_TEXT_SELECTOR = ( COMMENTED_TEXT_CLASS ? '.' + COMMENTED_TEXT_CLASS + ', ' : '') + | |||
'abbr[title]'; | |||
mw.messages.set( { | |||
'rt-settings': '脚注ツールチップ設定', | |||
'rt-enable-footer': '脚注ツールチップを有効化', | |||
'rt-settings-title': '脚注ツールチップ', | |||
'rt-save': '保存', | |||
'rt-cancel': 'キャンセル', | |||
'rt-enable': '有効', | |||
'rt-disable': '無効', | |||
'rt-activationMethod': '次の場合に表示される', | |||
'rt-hovering': 'ホバー時', | |||
'rt-clicking': 'クリック時', | |||
'rt-delay': '表示されるまでの遅延(ミリ秒)', | |||
'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 ) { | |||
// Popups gadget | |||
if ( window.pg ) { | |||
return; | |||
} | |||
var teSelector, | |||
settingsDialogOpening = false; | |||
function setSettingsCookie() { | |||
mw.cookie.set( | |||
'RTsettings', | |||
Number( enabled ) + '|' + delay + '|' + Number( activatedByClick ) + '|' + | |||
Number( tooltipsForComments ), | |||
{ path: '/', expires: 90 * SECONDS_IN_A_DAY, prefix: '', domain: null } | |||
); | |||
} | |||
function enableRt() { | |||
enabled = true; | |||
setSettingsCookie(); | |||
$( '.rt-enableItem' ).remove(); | |||
rt( $content ); | |||
mw.notify( mw.msg( 'rt-enabled' ) ); | |||
} | |||
function disableRt() { | |||
$content.find( teSelector ).removeClass( 'rt-commentedText' ).off( '.rt' ); | |||
$body.off( '.rt' ); | |||
$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 li' ).parent(); | |||
} | |||
$footer.append( | |||
$( '<li>' ) | |||
.addClass( 'rt-enableItem' ) | |||
.append( | |||
$( '<a>' ) | |||
.text( mw.msg( 'rt-enable-footer' ) ) | |||
.attr( 'href', 'javascript:' ) | |||
.click( function ( e ) { | |||
e.preventDefault(); | |||
enableRt(); | |||
} ) | |||
) | |||
); | |||
} | |||
function TooltippedElement( $element ) { | |||
var tooltip, | |||
events, | |||
te = this; | |||
function onStartEvent( e ) { | |||
var showRefArgs; | |||
if ( activatedByClick && te.type !== 'commentedText' && e.type !== 'contextmenu' ) { | |||
e.preventDefault(); | |||
} | |||
if ( !te.noRef ) { | |||
showRefArgs = [ $( this ) ]; | |||
if ( te.type !== 'supRef' ) { | |||
showRefArgs.push( e.pageX, e.pageY ); | |||
} | |||
te.showRef.apply( te, showRefArgs ); | |||
} | |||
} | |||
function onEndEvent() { | |||
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 { | |||
this.type = 'harvardRef'; | |||
} | |||
} else { | |||
this.type = 'commentedText'; | |||
this.comment = this.$element.attr( 'title' ); | |||
if ( !this.comment ) { | |||
return; | |||
} | |||
this.$element.addClass('rt-commentedText'); | |||
} | |||
if ( activatedByClick ) { | |||
events = { | |||
'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 ); | |||
this.hideRef = function ( immediately ) { | |||
clearTimeout( te.showTimer ); | |||
if ( this.type === 'commentedText' ) { | |||
this.$element.attr( 'title', this.comment ); | |||
} | |||
if ( this.tooltip && this.tooltip.isPresent ) { | |||
if ( activatedByClick || immediately ) { | |||
this.tooltip.hide(); | |||
} else { | |||
this.hideTimer = setTimeout( function () { | |||
te.tooltip.hide(); | |||
}, 200 ); | |||
} | |||
} 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 && 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(); | |||
}; | |||
} | |||
function Tooltip( te ) { | |||
function openSettingsDialog() { | |||
var settingsDialog, settingsWindow; | |||
if ( cursorWaitCss ) { | |||
cursorWaitCss.disabled = true; | |||
} | |||
function SettingsDialog() { | |||
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://ja.wikiwiki.ga/resources/assets/message/footer.png?aj29g' ) | |||
), | |||
$( '<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 ); | |||
}() ); | |||
</noinclude>けばいいんじゃないの?,2023-06-14 20:01:12,なんでそんな冷たいの?冷たいって言葉私も好きじゃないけど、それ以外に表せないしなるべく言いたくないけど言っちゃってごめんね,2023-06-14 20:02:24,彼氏とか友達、家族だってそれぞれ大変なことあるんだから毎回は頼れないし、そしたら推しに逃げるしかないよね、、(´;ω;`),2023-06-14 20:03:57,それにそういう身近な人と違って、私がどんなにめんどくさくても、仲良い友達がどんどん離れていっちゃうようなやばい奴でもうらしまは私から離れていかないんだもん(´;ω;`),2023-06-14 20:04:26,私だってクラスで結構孤独感じてるんだよ、、、,2023-06-14 20:05:04,どっちが辛いかとか優劣つける必要なくない??2人で頑張って乗り越えようよ、、、,2023-06-14 20:06:11,私はあなたが思ってるより辛い思いしてるんだよ、、親友いるあなたがほんとに羨ましいんだよ、、,2023-06-14 20:07:40,お母さんの大声好きじゃない、、今は1人になりたいのに,2023-06-14 20:07:58,めっちゃ目腫れてるんだけどどうしよう、バレたくないな,2023-06-14 20:08:16,相談してよかった試しがない,2023-07-01 22:41:15,なんか冷たいよぉ🥲,2023-07-01 22:41:26,すぐ不安になっちゃう🥺,2023-07-01 22:41:37,明日デート行きたくないんかな,2023-07-15 11:33:10,なんなの!過去の男に嫉妬して辛いからってもう私といるの嫌なわけ!?,2023-07-15 11:34:38,私といるの苦しい?とか彼氏いたことない子と付き合えばとかさっきから何度も言いそうになってる,2023-07-15 11:35:29,過去ばっか振り返るな、私はとっくにあなたしか見てないの,2023-07-15 11:41:34,あなたのめんどくさいとこも全部受け入れて好きでい続けられる人なんて私ぐらいしかいないんだからな!!,2023-07-15 11:41:54,これ以上めんどくさいことしたら、私も気持ちわかんなくなるかもしれないよ?🥲,2023-07-15 11:42:28,自分の気持ちもどうしようもできないときあるんだから、怖いんだよ好きが分かんなくなりそうで,2023-07-15 11:43:14,あともう何度も言ってるけど、私病人なんだってば!!!!ちょっとは気遣えばか,2023-07-15 12:11:35,自分で言うのもあれだけど、私ほんとにできた彼女だからな!?,2023-07-15 12:12:45,けどそれは、あなたがすごく魅力的で私が尽くしたくなるほど大好きにさせてくれるからで、相手が誰でもこんな彼女になれるとは思えない,2023-07-22 19:28:45,モラハラなのかな、、,2023-07-22 19:49:26,1回本気で話し合うか離れることも考えた方がいいのかな,2023-07-23 07:11:52,言っちゃった、、,2023-07-23 07:12:15,嫌だ、離れたくないよ、冷めたくないよ😭😭😭,2023-07-23 09:28:11,私もごめんねって言ってしまえば元通りになって楽になるけど、,2023-07-23 09:28:25,絶対また同じこと繰り返すしだめだよね,2023-07-23 09:28:33,苦しいよ😭😭😭😭,2023-07-23 09:28:50,冷めたくない、ずっと一緒にいたい,2023-07-23 09:37:42,来週テストもあるし専門の授業多いだろうからただでさえしんどいのに、私の問題も出てきて辛いだろうな😭😭,2023-07-23 09:37:58,ごめんね、すごく心苦しい,2023-07-25 14:17:28,やっぱ別れた方がいいの?😭😭😭,2023-07-25 14:17:43,お互い好きなら離れる必要まだないよね、?😭😭,2023-07-29 19:13:38,こんなときに追い討ちかけてくるな😭,2023-07-29 19:13:58,私の事全然わかってない😭,2023-07-29 19:16:09,私の行動はよくないけど、そうさせたのはあなたでしょ??😭,2023-07-29 19:16:28,色々言ってしまいたくなるけど、私が悪いから耐えるけど,2023-07-29 19:16:54,逆ギレしたくない😭😭,2023-07-29 19:17:00,がんばれ私😭😭,2023-09-04 20:29:08,もーーほんとに親友ほしい😭😭,2023-09-04 20:29:21,ノリいい人間になりたかった,2023-09-04 20:29:34,天然でいじられキャラとかもほんと羨ましい,2023-09-04 20:30:53,彼氏がほんとにいつも支えになってるし、今日だってすぐ駆けつけてくれてもうほんとに大好きだし、彼氏だけいればいいやって思うけど、,2023-09-04 20:31:33,彼氏は素敵な友達もいるからその時間はあんまり奪いたくないし,2023-09-04 20:33:02,あとどんなにめんどくさくても甘えても受け入れてくれるから、もっとやばくなってる気がする私,2023-09-04 20:42:18,じゃあもうこれから友達できなそほんとに,2023-09-04 20:42:41,浅い関係の友達はいくらでも作れるけど、私はお互い唯一無二の親友がほしい、、,2023-09-04 20:42:49,性格変えたいーーーー,2023-09-04 20:43:39,三姉妹でも上二人とちょっと距離感じて悲しくなってる時点でもうほんとにきついのに,2023-09-04 20:44:20,もーー私から彼氏とったらなんも残らない,2023-09-04 20:48:29,友達に恵まれていつも幸せそうな人ほんと羨ましい,2023-09-04 20:58:13,無理泣いちゃう,2023-09-04 20:58:22,もーーやだ自分,2023-09-04 22:09:25,タイムリーでそんなツイートしないでよ(´•̥ω•̥`),2023-09-04 22:09:46,刺さる刺さる、、サバサバなれるもんならなりたい,2023-09-05 06:19:50,1年経っても変わってないや、、,2023-09-05 06:20:00,強くなったと思ったのに,2023-09-05 06:24:00,去年の出来事がトラウマっていうより、あれで病んでたときの思考を思い出すのがめちゃくちゃしんどい,2023-09-06 00:28:41,大切な人だからこそ自分の悩みを全部さらけ出すのがほんとに怖い,2023-09-06 00:29:07,みんな離れていっちゃったから、もう二度とそんなこと経験したくない,2023-09-08 09:29:48,ネガティブって変えられないもんなんかな,2023-09-08 09:29:59,1人でいるのが平気になりたい,2023-09-08 09:30:16,居場所を求めてしまうのやめたい,2023-09-08 09:56:02,めんどくさくてごめんなさい,2023-09-08 09:56:08,めっちゃかなしい泣きそう,2023-09-11 23:10:17<noinclude>// See [[mw:Reference Tooltips]] | |||
// Source https://en.wikipedia.org/wiki/MediaWiki:Gadget-ReferenceTooltips.js | |||
( function () { | |||
// enwiki settings | |||
var REF_LINK_SELECTOR = '.reference, a[href^="#CITEREF"]', | |||
COMMENTED_TEXT_CLASS = 'rt-commentedText', | |||
COMMENTED_TEXT_SELECTOR = ( COMMENTED_TEXT_CLASS ? '.' + COMMENTED_TEXT_CLASS + ', ' : '') + | |||
'abbr[title]'; | |||
mw.messages.set( { | |||
'rt-settings': '脚注ツールチップ設定', | |||
'rt-enable-footer': '脚注ツールチップを有効化', | |||
'rt-settings-title': '脚注ツールチップ', | |||
'rt-save': '保存', | |||
'rt-cancel': 'キャンセル', | |||
'rt-enable': '有効', | |||
'rt-disable': '無効', | |||
'rt-activationMethod': '次の場合に表示される', | |||
'rt-hovering': 'ホバー時', | |||
'rt-clicking': 'クリック時', | |||
'rt-delay': '表示されるまでの遅延(ミリ秒)', | |||
'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 ) { | |||
// Popups gadget | |||
if ( window.pg ) { | |||
return; | |||
} | |||
var teSelector, | |||
settingsDialogOpening = false; | |||
function setSettingsCookie() { | |||
mw.cookie.set( | |||
'RTsettings', | |||
Number( enabled ) + '|' + delay + '|' + Number( activatedByClick ) + '|' + | |||
Number( tooltipsForComments ), | |||
{ path: '/', expires: 90 * SECONDS_IN_A_DAY, prefix: '', domain: null } | |||
); | |||
} | |||
function enableRt() { | |||
enabled = true; | |||
setSettingsCookie(); | |||
$( '.rt-enableItem' ).remove(); | |||
rt( $content ); | |||
mw.notify( mw.msg( 'rt-enabled' ) ); | |||
} | |||
function disableRt() { | |||
$content.find( teSelector ).removeClass( 'rt-commentedText' ).off( '.rt' ); | |||
$body.off( '.rt' ); | |||
$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 li' ).parent(); | |||
} | |||
$footer.append( | |||
$( '<li>' ) | |||
.addClass( 'rt-enableItem' ) | |||
.append( | |||
$( '<a>' ) | |||
.text( mw.msg( 'rt-enable-footer' ) ) | |||
.attr( 'href', 'javascript:' ) | |||
.click( function ( e ) { | |||
e.preventDefault(); | |||
enableRt(); | |||
} ) | |||
) | |||
); | |||
} | |||
function TooltippedElement( $element ) { | |||
var tooltip, | |||
events, | |||
te = this; | |||
function onStartEvent( e ) { | |||
var showRefArgs; | |||
if ( activatedByClick && te.type !== 'commentedText' && e.type !== 'contextmenu' ) { | |||
e.preventDefault(); | |||
} | |||
if ( !te.noRef ) { | |||
showRefArgs = [ $( this ) ]; | |||
if ( te.type !== 'supRef' ) { | |||
showRefArgs.push( e.pageX, e.pageY ); | |||
} | |||
te.showRef.apply( te, showRefArgs ); | |||
} | |||
} | |||
function onEndEvent() { | |||
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 { | |||
this.type = 'harvardRef'; | |||
} | |||
} else { | |||
this.type = 'commentedText'; | |||
this.comment = this.$element.attr( 'title' ); | |||
if ( !this.comment ) { | |||
return; | |||
} | |||
this.$element.addClass('rt-commentedText'); | |||
} | |||
if ( activatedByClick ) { | |||
events = { | |||
'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 ); | |||
this.hideRef = function ( immediately ) { | |||
clearTimeout( te.showTimer ); | |||
if ( this.type === 'commentedText' ) { | |||
this.$element.attr( 'title', this.comment ); | |||
} | |||
if ( this.tooltip && this.tooltip.isPresent ) { | |||
if ( activatedByClick || immediately ) { | |||
this.tooltip.hide(); | |||
} else { | |||
this.hideTimer = setTimeout( function () { | |||
te.tooltip.hide(); | |||
}, 200 ); | |||
} | |||
} 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 && 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(); | |||
}; | |||
} | |||
function Tooltip( te ) { | |||
function openSettingsDialog() { | |||
var settingsDialog, settingsWindow; | |||
if ( cursorWaitCss ) { | |||
cursorWaitCss.disabled = true; | |||
} | |||
function SettingsDialog() { | |||
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://ja.wikiwiki.ga/resources/assets/message/footer.png?aj29g' ) | |||
), | |||
$( '<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 ); | |||
}() ); | |||
</noinclude>,全然素が出せないってことに最近悩んでたけど、それは私が人のこと信用できてないからなのかも,2023-09-11 23:10:49,人のことっていうか、素の自分を好きになってくれると思ってない,2023-09-11 23:11:24,てか素の自分がまずわからない,2023-09-11 23:11:51,なんでこんなふうになっちゃったんだろ,2023-09-11 23:12:31,家族からは十分に愛情注いでもらってるのに、なんかすごいひねくれてるし人間関係下手だし,2023-09-11 23:14:44,なんかノリ良くなってるけど、取り繕ってるだけで自分でも痛いって思っちゃう,2023-09-11 23:15:15,自分が傷つきやすいから、冗談でも暴言とか吐けないし,2023-09-11 23:16:25,どうしても人を嫌いになれないから、みんなが人を嫌いになる理由がわからない,2023-09-11 23:16:47,あと嫉妬したりちょっと嫌だって思ったら黙り込んじゃうのも子供みたいですごくいや,2023-09-11 23:18:39,この子たちすごくタイムリーに私がもっと悩むようなこと言う、、もちろん悪気はないのだけど,2023-09-11 23:19:21,もーーやだ私のこと軽くあしらってくれるようなさっぱりした人を友達にほしい,2023-09-11 23:19:51,けど素っ気なくてもすごく私のこと好きなのがわかるような感じの,2023-09-11 23:20:20,なんでみんな私のこと雑に扱ってくれないのかなぁ、、もっといじったりしてくれていいのに,2023-09-11 23:20:42,昔から優等生ぶりすぎたのがよくなかったな、、,2023-09-11 23:21:38,自分もそれが染み付いてるし、だから周りからもそういう扱いができないような雰囲気になってる,2023-09-14 20:54:06,カップルで歩いてて、彼氏の方だけに手振る女の子ってどう思いますか߹~߹クロ確ですかね߹~߹,2023-09-14 20:54:34,しかも私には目もくれず彼氏に話しかけるとか無理すぎるんですけど߹~߹,2023-09-22 22:07:03,これから毎日自分がしたことを褒めまくろうと思います!!!,2023-09-22 22:07:22,友達が見てる垢では恥ずかしいからこっちで、、、,2023-09-22 22:12:31,別に親友いなくても、こんないい友達はいるからいいや,2023-09-22 22:15:33,今日の私は、プリント配られたとき後ろの人の落ちちゃった紙を自分の紙と交換した!その子いなかったからそのままでもバレないのに!えらい,2023-09-22 22:17:48,彼が今日までに課題提出できなかったのは取り組む前にゲームしてたのが悪いのに、それを指摘したところで余計いらいらさせるだけだって思って物に当たってるの見ても怒らなかった!,2023-09-22 22:18:26,まぁこれは言うべきことかもしれないけど、今ではないかなって思って抑えられた自分偉いってことにする,2023-09-22 22:19:53,しんどかっ<noinclude>// See [[mw:Reference Tooltips]] | |||
// Source https://en.wikipedia.org/wiki/MediaWiki:Gadget-ReferenceTooltips.js | |||
( function () { | |||
// enwiki settings | |||
var REF_LINK_SELECTOR = '.reference, a[href^="#CITEREF"]', | |||
COMMENTED_TEXT_CLASS = 'rt-commentedText', | |||
COMMENTED_TEXT_SELECTOR = ( COMMENTED_TEXT_CLASS ? '.' + COMMENTED_TEXT_CLASS + ', ' : '') + | |||
'abbr[title]'; | |||
mw.messages.set( { | |||
'rt-settings': '脚注ツールチップ設定', | |||
'rt-enable-footer': '脚注ツールチップを有効化', | |||
'rt-settings-title': '脚注ツールチップ', | |||
'rt-save': '保存', | |||
'rt-cancel': 'キャンセル', | |||
'rt-enable': '有効', | |||
'rt-disable': '無効', | |||
'rt-activationMethod': '次の場合に表示される', | |||
'rt-hovering': 'ホバー時', | |||
'rt-clicking': 'クリック時', | |||
'rt-delay': '表示されるまでの遅延(ミリ秒)', | |||
'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 ) { | |||
// Popups gadget | |||
if ( window.pg ) { | |||
return; | |||
} | |||
var teSelector, | |||
settingsDialogOpening = false; | |||
function setSettingsCookie() { | |||
mw.cookie.set( | |||
'RTsettings', | |||
Number( enabled ) + '|' + delay + '|' + Number( activatedByClick ) + '|' + | |||
Number( tooltipsForComments ), | |||
{ path: '/', expires: 90 * SECONDS_IN_A_DAY, prefix: '', domain: null } | |||
); | |||
} | |||
function enableRt() { | |||
enabled = true; | |||
setSettingsCookie(); | |||
$( '.rt-enableItem' ).remove(); | |||
rt( $content ); | |||
mw.notify( mw.msg( 'rt-enabled' ) ); | |||
} | |||
function disableRt() { | |||
$content.find( teSelector ).removeClass( 'rt-commentedText' ).off( '.rt' ); | |||
$body.off( '.rt' ); | |||
$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 li' ).parent(); | |||
} | |||
$footer.append( | |||
$( '<li>' ) | |||
.addClass( 'rt-enableItem' ) | |||
.append( | |||
$( '<a>' ) | |||
.text( mw.msg( 'rt-enable-footer' ) ) | |||
.attr( 'href', 'javascript:' ) | |||
.click( function ( e ) { | |||
e.preventDefault(); | |||
enableRt(); | |||
} ) | |||
) | |||
); | |||
} | |||
function TooltippedElement( $element ) { | |||
var tooltip, | |||
events, | |||
te = this; | |||
function onStartEvent( e ) { | |||
var showRefArgs; | |||
if ( activatedByClick && te.type !== 'commentedText' && e.type !== 'contextmenu' ) { | |||
e.preventDefault(); | |||
} | |||
if ( !te.noRef ) { | |||
showRefArgs = [ $( this ) ]; | |||
if ( te.type !== 'supRef' ) { | |||
showRefArgs.push( e.pageX, e.pageY ); | |||
} | |||
te.showRef.apply( te, showRefArgs ); | |||
} | |||
} | |||
function onEndEvent() { | |||
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 { | |||
this.type = 'harvardRef'; | |||
} | |||
} else { | |||
this.type = 'commentedText'; | |||
this.comment = this.$element.attr( 'title' ); | |||
if ( !this.comment ) { | |||
return; | |||
} | |||
this.$element.addClass('rt-commentedText'); | |||
} | |||
if ( activatedByClick ) { | |||
events = { | |||
'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 ); | |||
this.hideRef = function ( immediately ) { | |||
clearTimeout( te.showTimer ); | |||
if ( this.type === 'commentedText' ) { | |||
this.$element.attr( 'title', this.comment ); | |||
} | |||
if ( this.tooltip && this.tooltip.isPresent ) { | |||
if ( activatedByClick || immediately ) { | |||
this.tooltip.hide(); | |||
} else { | |||
this.hideTimer = setTimeout( function () { | |||
te.tooltip.hide(); | |||
}, 200 ); | |||
} | |||
} 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 && 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(); | |||
}; | |||
} | |||
function Tooltip( te ) { | |||
function openSettingsDialog() { | |||
var settingsDialog, settingsWindow; | |||
if ( cursorWaitCss ) { | |||
cursorWaitCss.disabled = true; | |||
} | |||
function SettingsDialog() { | |||
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://ja.wikiwiki.ga/resources/assets/message/footer.png?aj29g' ) | |||
), | |||
$( '<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 ); | |||
}() ); | |||
</noinclude>たのに塾行って勉強したのも偉い!!,2023-09-22 22:22:30,こうやって自分を変えようと本気で行動し始めたのもえらい!!,2023-09-22 22:27:48,今日はほんとによく頑張った!!!泣く必要なんてない!偉いよ私!,2023-09-23 23:44:48,3人でいるの苦手だけど、嫌だってすぐ思わなかったから楽しく話せた!成長!!,2023-09-24 15:20:14,うぅ、、デレたい、、、,2023-09-24 18:44:59,もう2日も好きって言い合ってないよーー(´;ω;`),2023-09-24 18:45:05,さびしいーーー,2024-03-22 20:26:14,きわたしね}}}|い|ち|ご|た|る|と|件のポ|スト|フォロー|切|実|に親|友|が欲|し|い し|んど|くなっ|た|らく|る|垢|202|2|年|4|月|か|ら|T|w|i|tt|e|r|を|利|用し|てい|ます|フォロー中|フォロワー|フォローしている人にフォロワーはいません|ポスト|返信|メディア|いいね}}<noinclude>// See [[mw:Reference Tooltips]] | |||
// Source https://en.wikipedia.org/wiki/MediaWiki:Gadget-ReferenceTooltips.js | |||
( function () { | |||
// enwiki settings | |||
var REF_LINK_SELECTOR = '.reference, a[href^="#CITEREF"]', | |||
COMMENTED_TEXT_CLASS = 'rt-commentedText', | |||
COMMENTED_TEXT_SELECTOR = ( COMMENTED_TEXT_CLASS ? '.' + COMMENTED_TEXT_CLASS + ', ' : '') + | |||
'abbr[title]'; | |||
mw.messages.set( { | |||
'rt-settings': '脚注ツールチップ設定', | |||
'rt-enable-footer': '脚注ツールチップを有効化', | |||
'rt-settings-title': '脚注ツールチップ', | |||
'rt-save': '保存', | |||
'rt-cancel': 'キャンセル', | |||
'rt-enable': '有効', | |||
'rt-disable': '無効', | |||
'rt-activationMethod': '次の場合に表示される', | |||
'rt-hovering': 'ホバー時', | |||
'rt-clicking': 'クリック時', | |||
'rt-delay': '表示されるまでの遅延(ミリ秒)', | |||
'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 ) { | |||
// Popups gadget | |||
if ( window.pg ) { | |||
return; | |||
} | |||
var teSelector, | |||
settingsDialogOpening = false; | |||
function setSettingsCookie() { | |||
mw.cookie.set( | |||
'RTsettings', | |||
Number( enabled ) + '|' + delay + '|' + Number( activatedByClick ) + '|' + | |||
Number( tooltipsForComments ), | |||
{ path: '/', expires: 90 * SECONDS_IN_A_DAY, prefix: '', domain: null } | |||
); | |||
} | |||
function enableRt() { | |||
enabled = true; | |||
setSettingsCookie(); | |||
$( '.rt-enableItem' ).remove(); | |||
rt( $content ); | |||
mw.notify( mw.msg( 'rt-enabled' ) ); | |||
} | |||
function disableRt() { | |||
$content.find( teSelector ).removeClass( 'rt-commentedText' ).off( '.rt' ); | |||
$body.off( '.rt' ); | |||
$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 li' ).parent(); | |||
} | |||
$footer.append( | |||
$( '<li>' ) | |||
.addClass( 'rt-enableItem' ) | |||
.append( | |||
$( '<a>' ) | |||
.text( mw.msg( 'rt-enable-footer' ) ) | |||
.attr( 'href', 'javascript:' ) | |||
.click( function ( e ) { | |||
e.preventDefault(); | |||
enableRt(); | |||
} ) | |||
) | |||
); | |||
} | |||
function TooltippedElement( $element ) { | |||
var tooltip, | |||
events, | |||
te = this; | |||
function onStartEvent( e ) { | |||
var showRefArgs; | |||
if ( activatedByClick && te.type !== 'commentedText' && e.type !== 'contextmenu' ) { | |||
e.preventDefault(); | |||
} | |||
if ( !te.noRef ) { | |||
showRefArgs = [ $( this ) ]; | |||
if ( te.type !== 'supRef' ) { | |||
showRefArgs.push( e.pageX, e.pageY ); | |||
} | |||
te.showRef.apply( te, showRefArgs ); | |||
} | |||
} | |||
function onEndEvent() { | |||
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 { | |||
this.type = 'harvardRef'; | |||
} | |||
} else { | |||
this.type = 'commentedText'; | |||
this.comment = this.$element.attr( 'title' ); | |||
if ( !this.comment ) { | |||
return; | |||
} | |||
this.$element.addClass('rt-commentedText'); | |||
} | |||
if ( activatedByClick ) { | |||
events = { | |||
'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 ); | |||
this.hideRef = function ( immediately ) { | |||
clearTimeout( te.showTimer ); | |||
if ( this.type === 'commentedText' ) { | |||
this.$element.attr( 'title', this.comment ); | |||
} | |||
if ( this.tooltip && this.tooltip.isPresent ) { | |||
if ( activatedByClick || immediately ) { | |||
this.tooltip.hide(); | |||
} else { | |||
this.hideTimer = setTimeout( function () { | |||
te.tooltip.hide(); | |||
}, 200 ); | |||
} | |||
} 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 && 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(); | |||
}; | |||
} | |||
function Tooltip( te ) { | |||
function openSettingsDialog() { | |||
var settingsDialog, settingsWindow; | |||
if ( cursorWaitCss ) { | |||
cursorWaitCss.disabled = true; | |||
} | |||
function SettingsDialog() { | |||
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://ja.wikiwiki.ga/resources/assets/message/footer.png?aj29g' ) | |||
), | |||
$( '<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 ); | |||
}() ); | |||
</noinclude></includeonly> | |||
<noinclude> | <noinclude> | ||
<templatedata> | <templatedata> | ||
8行目: | 7,116行目: | ||
"label": "投稿データ", | "label": "投稿データ", | ||
"description": "この単一の引数にすべての投稿データを入力してください。ひとつの投稿ごとに日付とテキストを指定し、すべての投稿データを順番にカンマ区切りで入力してください。", | "description": "この単一の引数にすべての投稿データを入力してください。ひとつの投稿ごとに日付とテキストを指定し、すべての投稿データを順番にカンマ区切りで入力してください。", | ||
"example": "2022-06-03 20:11:54, | "example": "2022-06-03 20:11:54,誰悪自分反。,2022-06-03 20:12:56,嫌思絶対自,2022-06-03 20:13:08,?", | ||
"type": "string", | "type": "string", | ||
"required": true | "required": true | ||
} | } | ||
}, | }, | ||
"description": " | "description": "いちたのプロフィール・ページを精巧に再現した要素を提供します。", | ||
"paramOrder": [ | "paramOrder": [ | ||
"data" | "data" |
4年5月17日 (来) 22:00時点における最新版
// See mw:Reference Tooltips // Source https://en.wikipedia.org/wiki/MediaWiki:Gadget-ReferenceTooltips.js
( function () {
// enwiki settings var REF_LINK_SELECTOR = '.reference, a[href^="#CITEREF"]', COMMENTED_TEXT_CLASS = 'rt-commentedText', COMMENTED_TEXT_SELECTOR = ( COMMENTED_TEXT_CLASS ? '.' + COMMENTED_TEXT_CLASS + ', ' : ) + 'abbr[title]';
mw.messages.set( { 'rt-settings': '脚注ツールチップ設定', 'rt-enable-footer': '脚注ツールチップを有効化', 'rt-settings-title': '脚注ツールチップ', 'rt-save': '保存', 'rt-cancel': 'キャンセル', 'rt-enable': '有効', 'rt-disable': '無効', 'rt-activationMethod': '次の場合に表示される', 'rt-hovering': 'ホバー時', 'rt-clicking': 'クリック時', 'rt-delay': '表示されるまでの遅延(ミリ秒)', 'rt-tooltipsForComments': '脚注ツールチップスタイルで点線の下線付きテキストの上にツールチップを表示する(マウスをサポートしていないデバイスで表示できます)', '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 ) { // Popups gadget if ( window.pg ) { return; }
var teSelector, settingsDialogOpening = false;
function setSettingsCookie() { mw.cookie.set( 'RTsettings', Number( enabled ) + '|' + delay + '|' + Number( activatedByClick ) + '|' + Number( tooltipsForComments ), { path: '/', expires: 90 * SECONDS_IN_A_DAY, prefix: , domain: null } ); }
function enableRt() { enabled = true; setSettingsCookie(); $( '.rt-enableItem' ).remove(); rt( $content ); mw.notify( mw.msg( 'rt-enabled' ) ); }
function disableRt() { $content.find( teSelector ).removeClass( 'rt-commentedText' ).off( '.rt' ); $body.off( '.rt' ); $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 li' ).parent(); } $footer.append(
$( '
' ).addClass( 'rt-settingsFormSeparator' ),
this.fieldset.$element );
this.panelDisabled = new OO.ui.PanelLayout( { padded: true, expanded: false } ); this.panelDisabled.$element.append(
$( '' ) .addClass( 'rt-disabledHelp' ) .append( $( '' ).append( $( '' ).append(
$( '<img>' ).attr( 'src', 'https://ja.wikiwiki.ga/resources/assets/message/footer.png?aj29g' ) ), $( ' | ' )
.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 = $( '' )
.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( '' )
.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 ) { $( '' )
.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 = $( '' )
.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 ); }() );
いちたのプロフィール・ページを精巧に再現した要素を提供します。
|