2014-04-02 09:37:13 +00:00
|
|
|
( function ( $, mw ) {
|
2014-05-19 22:48:32 +00:00
|
|
|
'use strict';
|
2014-04-22 14:16:54 +00:00
|
|
|
|
|
|
|
/**
|
2014-04-25 11:43:42 +00:00
|
|
|
* @class mw.popups
|
|
|
|
* @singleton
|
2014-04-22 14:16:54 +00:00
|
|
|
*/
|
2014-04-25 11:43:42 +00:00
|
|
|
mw.popups = {};
|
2014-04-22 14:16:54 +00:00
|
|
|
|
2014-06-17 11:08:05 +00:00
|
|
|
mw.popups.enabled = $.jStorage.get( 'mwe-popups-enabled' ) !== 'false';
|
|
|
|
|
2014-04-22 14:16:54 +00:00
|
|
|
/**
|
2014-04-25 11:43:42 +00:00
|
|
|
* Checks SVG support on the browser
|
2014-06-26 09:30:18 +00:00
|
|
|
*
|
|
|
|
* Set to false on Internet Explorer because adding SVGs
|
|
|
|
* through JavaScript in IE is failing. Thus, falling back to PNGs
|
|
|
|
*
|
2014-04-25 11:43:42 +00:00
|
|
|
* @property {Boolean} supportsSVG
|
2014-04-22 14:16:54 +00:00
|
|
|
*/
|
2014-06-26 09:30:18 +00:00
|
|
|
mw.popups.supportsSVG = ( $.client.profile().name === 'msie' ) ?
|
|
|
|
false :
|
|
|
|
document.implementation.hasFeature( 'http://www.w3.org/TR/SVG11/feature#Image', '1.1' );
|
2014-02-11 09:48:00 +00:00
|
|
|
|
2014-04-22 14:16:54 +00:00
|
|
|
/**
|
2014-04-25 11:43:42 +00:00
|
|
|
* The API object used for all this extension's requests
|
|
|
|
* @property {Object} api
|
2014-04-22 14:16:54 +00:00
|
|
|
*/
|
2014-04-25 11:43:42 +00:00
|
|
|
mw.popups.api = new mw.Api();
|
2014-04-22 14:16:54 +00:00
|
|
|
|
|
|
|
/**
|
2014-04-25 11:43:42 +00:00
|
|
|
* Whether the page is being scrolled.
|
|
|
|
* @property {Boolean} scrolled
|
2014-04-22 14:16:54 +00:00
|
|
|
*/
|
2014-04-25 11:43:42 +00:00
|
|
|
mw.popups.scrolled = false;
|
2014-04-22 14:16:54 +00:00
|
|
|
|
|
|
|
/**
|
2014-04-25 11:43:42 +00:00
|
|
|
* List of classes of which links are ignored
|
|
|
|
* @property {Array} IGNORE_CLASSES
|
2014-04-22 14:16:54 +00:00
|
|
|
*/
|
2014-04-25 11:43:42 +00:00
|
|
|
mw.popups.IGNORE_CLASSES = [
|
2014-05-19 22:30:29 +00:00
|
|
|
'.extiw',
|
2014-04-25 11:43:42 +00:00
|
|
|
'.image',
|
|
|
|
'.new',
|
2014-06-03 08:13:40 +00:00
|
|
|
'.internal',
|
2014-06-04 04:13:50 +00:00
|
|
|
'.external',
|
2015-02-17 12:45:55 +00:00
|
|
|
'.oo-ui-buttonedElement-button'
|
2014-04-25 11:43:42 +00:00
|
|
|
];
|
2014-04-22 14:16:54 +00:00
|
|
|
|
|
|
|
/**
|
2014-04-25 11:43:42 +00:00
|
|
|
* If SVG is supported, creates the SVG mask used to create the
|
|
|
|
* the triangle pointer on popups with images
|
|
|
|
*
|
|
|
|
* @method createSVGMask
|
2014-04-22 14:16:54 +00:00
|
|
|
*/
|
2014-04-25 11:43:42 +00:00
|
|
|
mw.popups.createSVGMask = function () {
|
|
|
|
if ( !mw.popups.supportsSVG ) {
|
2014-04-22 14:16:54 +00:00
|
|
|
return false;
|
|
|
|
}
|
2014-02-11 09:48:00 +00:00
|
|
|
|
2014-04-25 11:43:42 +00:00
|
|
|
$( '<div>' )
|
|
|
|
.attr( 'id', 'mwe-popups-svg' )
|
|
|
|
.appendTo( document.body )
|
|
|
|
.html(
|
|
|
|
'<svg width="0" height="0">' +
|
|
|
|
'<defs>' +
|
|
|
|
'<clippath id="mwe-popups-mask">' +
|
|
|
|
'<polygon points="0 8, 10 8, 18 0, 26 8, 1000 8, 1000 1000, 0 1000"/>' +
|
|
|
|
'</clippath>' +
|
|
|
|
'<clippath id="mwe-popups-mask-flip">' +
|
|
|
|
'<polygon points="0 8, 274 8, 282 0, 290 8, 1000 8, 1000 1000, 0 1000"/>' +
|
|
|
|
'</clippath>' +
|
|
|
|
'<clippath id="mwe-popups-landscape-mask">' +
|
|
|
|
'<polygon points="0 8, 174 8, 182 0, 190 8, 1000 8, 1000 1000, 0 1000"/>' +
|
|
|
|
'</clippath>' +
|
2014-04-30 11:13:05 +00:00
|
|
|
'<clippath id="mwe-popups-landscape-mask-flip">' +
|
|
|
|
'<polygon points="0 0, 1000 0, 1000 243, 190 243, 182 250, 174 243, 0 243"/>' +
|
|
|
|
'</clippath>' +
|
2014-04-25 11:43:42 +00:00
|
|
|
'</defs>' +
|
|
|
|
'</svg>'
|
|
|
|
);
|
|
|
|
return true;
|
|
|
|
};
|
2014-04-22 14:16:54 +00:00
|
|
|
|
|
|
|
/**
|
2014-04-25 11:43:42 +00:00
|
|
|
* Create the element that holds the popups
|
|
|
|
*
|
|
|
|
* @method createPopupElement
|
2014-04-22 14:16:54 +00:00
|
|
|
*/
|
2014-04-25 11:43:42 +00:00
|
|
|
mw.popups.createPopupElement = function () {
|
|
|
|
mw.popups.$popup = $( '<div>' )
|
2014-05-19 22:48:32 +00:00
|
|
|
.attr( {
|
|
|
|
'class': 'mwe-popups',
|
|
|
|
'role': 'tooltip',
|
|
|
|
'aria-hidden': 'true'
|
|
|
|
} )
|
2014-04-22 14:16:54 +00:00
|
|
|
.appendTo( document.body );
|
2014-04-25 11:43:42 +00:00
|
|
|
};
|
2014-02-11 09:48:00 +00:00
|
|
|
|
2014-04-25 11:43:42 +00:00
|
|
|
/**
|
|
|
|
* Temorarily remove tooltips from links on hover
|
|
|
|
*
|
|
|
|
* @method removeTooltips
|
|
|
|
*/
|
2014-05-19 22:35:58 +00:00
|
|
|
mw.popups.removeTooltips = function ( $elements ) {
|
|
|
|
$elements
|
2014-05-19 22:42:41 +00:00
|
|
|
.filter( '[title]:not([title=""])' )
|
2014-03-23 02:32:37 +00:00
|
|
|
.on( 'mouseenter focus', function () {
|
|
|
|
$( this )
|
2014-04-25 11:43:42 +00:00
|
|
|
.data( 'title', $( this ).attr( 'title' ) )
|
2014-04-02 09:37:13 +00:00
|
|
|
.attr( 'title', '' );
|
2014-03-23 02:32:37 +00:00
|
|
|
} )
|
|
|
|
.on( 'mouseleave blur', function () {
|
|
|
|
$( this )
|
2014-04-25 11:43:42 +00:00
|
|
|
.attr( 'title', $( this ).data( 'title' ) );
|
2014-03-23 02:32:37 +00:00
|
|
|
} );
|
2014-04-25 11:43:42 +00:00
|
|
|
};
|
2014-02-06 11:15:05 +00:00
|
|
|
|
2014-04-25 11:43:42 +00:00
|
|
|
/**
|
|
|
|
* Checks if the user is scrolling, sets to false on mousemove
|
|
|
|
*
|
|
|
|
* @method checkScroll
|
|
|
|
*/
|
|
|
|
mw.popups.checkScroll = function () {
|
|
|
|
$( window ).on( 'scroll', function () {
|
|
|
|
mw.popups.scrolled = true;
|
|
|
|
} );
|
|
|
|
|
|
|
|
$( window ).on( 'mousemove', function () {
|
|
|
|
mw.popups.scrolled = false;
|
|
|
|
} );
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2014-07-23 02:18:13 +00:00
|
|
|
* Register a hover event that may render a popup on an appropriate link.
|
2014-04-25 11:43:42 +00:00
|
|
|
*
|
|
|
|
* @method setupTriggers
|
|
|
|
*/
|
2014-05-19 22:35:58 +00:00
|
|
|
mw.popups.setupTriggers = function ( $elements ) {
|
|
|
|
$elements.on( 'mouseenter focus', function ( event ) {
|
2014-07-15 15:41:58 +00:00
|
|
|
if ( mw.popups.scrolled ) {
|
2014-02-06 10:49:28 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-02-17 14:03:13 +00:00
|
|
|
mw.popups.render.render( $( this ), event );
|
2014-04-25 11:43:42 +00:00
|
|
|
} );
|
|
|
|
};
|
2014-02-06 10:49:28 +00:00
|
|
|
|
2015-03-25 20:53:27 +00:00
|
|
|
/**
|
|
|
|
* Given an href string for the local wiki, return the title, or undefined if
|
|
|
|
* the link is external, has extra query parameters, or contains no title.
|
|
|
|
*
|
|
|
|
* Note that the returned title is not sanitized (may contain underscores).
|
|
|
|
*
|
|
|
|
* @param {string} href
|
|
|
|
* @return {string|undefined}
|
|
|
|
*/
|
|
|
|
mw.popups.getTitle = function ( href ) {
|
2015-04-09 01:16:09 +00:00
|
|
|
var title, titleRegex, matches, linkHref;
|
|
|
|
|
|
|
|
// Skip every URI that mw.Uri cannot parse
|
|
|
|
try {
|
2015-03-25 20:53:27 +00:00
|
|
|
linkHref = new mw.Uri( href );
|
2015-04-09 01:16:09 +00:00
|
|
|
} catch ( e ) {
|
|
|
|
return undefined;
|
|
|
|
}
|
2015-03-25 20:53:27 +00:00
|
|
|
|
|
|
|
// External links
|
|
|
|
if ( linkHref.host !== location.hostname ) {
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( linkHref.query.hasOwnProperty( 'title' ) ) {
|
|
|
|
// linkHref is not a pretty URL, e.g. /w/index.php?title=Foo
|
|
|
|
|
|
|
|
title = linkHref.query.title;
|
|
|
|
// Return undefined if there are query parameters other than title
|
|
|
|
delete linkHref.query.title;
|
|
|
|
return $.isEmptyObject( linkHref.query ) ? title : undefined;
|
|
|
|
} else {
|
|
|
|
// linkHref is a pretty URL, e.g. /wiki/Foo
|
|
|
|
|
|
|
|
// Return undefined if there are any query parameters
|
|
|
|
if ( !$.isEmptyObject( linkHref.query ) ) {
|
|
|
|
return undefined;
|
|
|
|
}
|
2015-06-26 07:48:18 +00:00
|
|
|
titleRegex = new RegExp( mw.RegExp.escape( mw.config.get( 'wgArticlePath' ) )
|
2015-03-25 20:53:27 +00:00
|
|
|
.replace( '\\$1', '(.+)' ) );
|
|
|
|
matches = titleRegex.exec( linkHref.path );
|
|
|
|
return matches ? decodeURIComponent( matches[1] ) : undefined;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-05-19 22:35:58 +00:00
|
|
|
/**
|
|
|
|
* Returns links that can have Popups
|
|
|
|
*
|
|
|
|
* @method selectPopupElements
|
|
|
|
*/
|
|
|
|
mw.popups.selectPopupElements = function () {
|
2015-03-25 20:53:27 +00:00
|
|
|
var contentNamespaces = mw.config.get( 'wgContentNamespaces' );
|
2015-02-17 14:03:13 +00:00
|
|
|
return mw.popups.$content
|
2014-07-15 15:41:58 +00:00
|
|
|
.find( 'a[href][title]:not(' + mw.popups.IGNORE_CLASSES.join(', ') + ')' )
|
|
|
|
.filter( function () {
|
2015-03-25 20:53:27 +00:00
|
|
|
var title,
|
|
|
|
titleText = mw.popups.getTitle( this.href );
|
|
|
|
if ( !titleText ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// Is titleText in a content namespace?
|
|
|
|
title = mw.Title.newFromText( titleText );
|
|
|
|
return title && ( $.inArray( title.namespace, contentNamespaces ) >= 0 );
|
2014-07-15 15:41:58 +00:00
|
|
|
} );
|
2014-05-19 22:35:58 +00:00
|
|
|
};
|
|
|
|
|
2014-04-25 11:43:42 +00:00
|
|
|
mw.hook( 'wikipage.content').add( function ( $content ) {
|
2015-03-26 01:25:54 +00:00
|
|
|
mw.popups.$content = $content;
|
|
|
|
var $elements = mw.popups.selectPopupElements();
|
2014-05-19 22:35:58 +00:00
|
|
|
|
2015-03-26 01:25:54 +00:00
|
|
|
if ( mw.popups.enabled ) {
|
2014-06-17 11:08:05 +00:00
|
|
|
mw.popups.removeTooltips( $elements );
|
|
|
|
mw.popups.setupTriggers( $elements );
|
2015-03-26 01:25:54 +00:00
|
|
|
} else {
|
|
|
|
// Events are logged even when Hovercards are disabled
|
|
|
|
// See T88166 for details
|
|
|
|
$elements.on( 'click', function ( event ) {
|
|
|
|
if ( mw.popups.logger === undefined ) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
var
|
|
|
|
$this = $( this ),
|
|
|
|
href = $this.attr( 'href' ),
|
|
|
|
action = mw.popups.logger.getAction( event ),
|
|
|
|
logEvent = {
|
|
|
|
pageTitleHover: $this.attr( 'title' ),
|
|
|
|
pageTitleSource: mw.config.get( 'wgTitle' ),
|
|
|
|
popupEnabled: mw.popups.enabled,
|
|
|
|
action: action
|
|
|
|
},
|
|
|
|
logPromise = mw.popups.logger.log( logEvent );
|
|
|
|
|
|
|
|
if ( action === 'opened in same tab' ) {
|
|
|
|
event.preventDefault();
|
|
|
|
logPromise.then( function () {
|
|
|
|
window.location.href = href;
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
} );
|
2014-06-17 11:08:05 +00:00
|
|
|
}
|
2014-04-25 11:43:42 +00:00
|
|
|
} );
|
2014-02-06 10:49:28 +00:00
|
|
|
|
2014-04-25 11:43:42 +00:00
|
|
|
$( function () {
|
2014-06-17 11:08:05 +00:00
|
|
|
if ( mw.popups.enabled ) {
|
|
|
|
mw.popups.checkScroll();
|
|
|
|
mw.popups.createSVGMask();
|
|
|
|
mw.popups.createPopupElement();
|
|
|
|
}
|
2014-02-06 10:49:28 +00:00
|
|
|
} );
|
2014-02-07 07:35:34 +00:00
|
|
|
|
2014-04-25 11:43:42 +00:00
|
|
|
} ) ( jQuery, mediaWiki );
|