Prtksxna has submitted this change and it was merged. Change subject: Use mw.hook to rebind events after page content is reloaded ......................................................................
Use mw.hook to rebind events after page content is reloaded Also moved things that don't need to be in document-ready handler outside of it. Bug: 63169 Change-Id: Ie681ff6722b9909d38fc06359da7614e0fc1798e --- M resources/ext.popups.core.js 1 file changed, 470 insertions(+), 470 deletions(-) Approvals: Prtksxna: Verified; Looks good to me, approved diff --git a/resources/ext.popups.core.js b/resources/ext.popups.core.js index e759fc2..63e2d3d 100644 --- a/resources/ext.popups.core.js +++ b/resources/ext.popups.core.js @@ -3,462 +3,499 @@ */ ( function ( $, mw ) { - $( document ).ready( function () { - - var closeTimer, // The timer use to delay `closeBox` - openTimer, // The timer used to delay sending the API request/opening the popup form cache - scrolled = false, // true if user scrolled the page but haven't moved mouse cursor - elTime, // EL: UNIX timestamp of when the popup was rendered - elDuration, // EL: How long was the popup open in milliseconds - elAction, // EL: Was the popup clicked or middle clicked or dismissed - elSessionId, // EL: Get defined after the getSessionId method is created - currentLink, // DOM element of the current anchor tag - cache = {}, - curRequest, // Current API request - supportsSVG = document.implementation.hasFeature( 'http://www.w3.org/TR/SVG11/feature#Image', '1.1' ), - api = new mw.Api(), - SIZES = { - portraitImage: { - h: 250, // Exact height - w: 203 // Max width - }, - landscapeImage: { - h: 200, // Max height - w: 300 // Exact Width - }, - landscapePopupWidth: 450, // Exact width of a landscape popup - portraitPopupWidth: 300 // Exact width of a portrait popup + var closeTimer, // The timer use to delay `closeBox` + openTimer, // The timer used to delay sending the API request/opening the popup form cache + scrolled = false, // true if user scrolled the page but haven't moved mouse cursor + elTime, // EL: UNIX timestamp of when the popup was rendered + elDuration, // EL: How long was the popup open in milliseconds + elAction, // EL: Was the popup clicked or middle clicked or dismissed + elSessionId, // EL: Get defined after the getSessionId method is created + currentLink, // DOM element of the current anchor tag + cache = {}, + curRequest, // Current API request + supportsSVG = document.implementation.hasFeature( 'http://www.w3.org/TR/SVG11/feature#Image', '1.1' ), + api = new mw.Api(), + SIZES = { + portraitImage: { + h: 250, // Exact height + w: 203 // Max width }, - POPUP_DELAY = 150, // Time to wait in ms before showing a popup on hover - POPUP_CLOSE_DELAY = 100, // Time to wait in ms before closing a popup on de-hover - API_DELAY = 50, // Time to wait in ms before starting the API queries on hover, must be <= POPUP_DELAY - $svg, $box; // defined at the end of the file + landscapeImage: { + h: 200, // Max height + w: 300 // Exact Width + }, + landscapePopupWidth: 450, // Exact width of a landscape popup + portraitPopupWidth: 300 // Exact width of a portrait popup + }, + POPUP_DELAY = 150, // Time to wait in ms before showing a popup on hover + POPUP_CLOSE_DELAY = 100, // Time to wait in ms before closing a popup on de-hover + API_DELAY = 50, // Time to wait in ms before starting the API queries on hover, must be <= POPUP_DELAY + $svg, $box; // defined at the end of the file - /** - * Return a promise corresponding to a `setTimeout()` call. Call `.abort()` on the return value - * to perform the equivalent of `clearTimeout()`. - * - * @param {number} ms Milliseconds to wait - * @return {jQuery.Promise} - */ - function timeoutPromise( ms ) { - var deferred, promise, timeout; + /** + * Return a promise corresponding to a `setTimeout()` call. Call `.abort()` on the return value + * to perform the equivalent of `clearTimeout()`. + * + * @param {number} ms Milliseconds to wait + * @return {jQuery.Promise} + */ + function timeoutPromise( ms ) { + var deferred, promise, timeout; - deferred = $.Deferred(); + deferred = $.Deferred(); - timeout = setTimeout( function () { - deferred.resolve(); - }, ms ); + timeout = setTimeout( function () { + deferred.resolve(); + }, ms ); - promise = deferred.promise( { abort: function () { - clearTimeout( timeout ); - deferred.reject(); - } } ); + promise = deferred.promise( { abort: function () { + clearTimeout( timeout ); + deferred.reject(); + } } ); - return promise; + return promise; + } + + /** + * @method sendRequest + * Send an API request, create DOM elements and + * put them in the cache. Returns a promise. + * @param {String} href + * @param {String} title + * @return {jQuery.Promise} + */ + function sendRequest( href, title ) { + var deferred = $.Deferred(); + + curRequest = api.get( { + action: 'query', + prop: 'extracts|pageimages|revisions|info', + redirects: 'true', + exintro: 'true', + exsentences: 2, + // there is an added geometric limit on .mwe-popups-extract + // so that text does not overflow from the card + explaintext: 'true', + piprop: 'thumbnail', + pithumbsize: 300, + rvprop: 'timestamp', + inprop: 'watched', + indexpageids: true, + titles: title + } ); + + curRequest.done( function ( re ) { + curRequest = undefined; + + var $a, + page = re.query.pages[ re.query.pageids[ 0 ] ], + $contentbox = $( '<div>' ) + .addClass( 'mwe-popups-extract' ) + .text( page.extract ), + thumbnail = page.thumbnail, + tall = thumbnail && thumbnail.height > thumbnail.width, + $thumbnail = createThumbnail( thumbnail, tall ), + timestamp = new Date( page.revisions[ 0 ].timestamp ), + timediff = new Date() - timestamp, + oneDay = 1000 * 60 * 60 * 24, + timestampclass = ( timediff < oneDay ) ? + 'mwe-popups-timestamp-recent' : + 'mwe-popups-timestamp-older', + $timestamp = $( '<div>' ) + .addClass( timestampclass ) + .append( + $( '<span>' ).text( mw.message( 'popups-last-edited', + moment( timestamp ).fromNow() ).text() ) + ); + + $a = $( '<a>' ) + .append( $thumbnail, $contentbox, $timestamp ) + .attr( 'href', href ) + .on( 'click', logClick ); + + cache[ href ] = { + box: $a, + thumbnail: thumbnail, + tall: tall + }; + + deferred.resolve(); + } ); + + return deferred.promise(); + } + + /** + * @method createSVGTag + * Use createElementNS to create the svg:image tag as jQuery + * uses createElement instead. Some browsers map the `image` tag + * to `img` tag, thus an `svg:image` is required. + * @param {String} tag + * @return {Object} + */ + function createSVGTag( tag ) { + return document.createElementNS( 'http://www.w3.org/2000/svg', tag ); + } + + /** + * @method createThumbnail + * Returns a thumbnail object based on the ratio of the image + * Uses an SVG image where available to add the triangle/pokey + * mask on the image. Crops and resizes the SVG image so that + * is fits inside a rectangle of a particular size. + * @param {Object} thumbnail + * @param {boolean} tall + * @return {Object} jQuery DOM element of the thumbnail + */ + function createThumbnail( thumbnail, tall ) { + if ( !thumbnail ) { + return $( '<span>' ); } - /** - * @method sendRequest - * Send an API request, create DOM elements and - * put them in the cache. Returns a promise. - * @param {String} href - * @param {String} title - * @return {jQuery.Promise} - */ - function sendRequest( href, title ) { - var deferred = $.Deferred(); + var $thumbnailSVGImage, $thumbnail; - curRequest = api.get( { - action: 'query', - prop: 'extracts|pageimages|revisions|info', - redirects: 'true', - exintro: 'true', - exsentences: 2, - // there is an added geometric limit on .mwe-popups-extract - // so that text does not overflow from the card - explaintext: 'true', - piprop: 'thumbnail', - pithumbsize: 300, - rvprop: 'timestamp', - inprop: 'watched', - indexpageids: true, - titles: title - } ); + if ( tall ) { + if ( supportsSVG ) { + $thumbnailSVGImage = $( createSVGTag( 'image' ) ); + $thumbnailSVGImage + .addClass( 'mwe-popups-is-not-tall' ) + .attr( { + 'xlink:href': thumbnail.source, + x: ( thumbnail.width > SIZES.portraitImage.w ) ? + ( ( thumbnail.width - SIZES.portraitImage.w ) / -2 ) : + ( SIZES.portraitImage.w - thumbnail.width ), + y: ( thumbnail.height > SIZES.portraitImage.h ) ? + ( ( thumbnail.height - SIZES.portraitImage.h ) / -2 ) : + 0, + width: thumbnail.width, + height: thumbnail.height + } ); - curRequest.done( function ( re ) { - curRequest = undefined; - - var $a, - page = re.query.pages[ re.query.pageids[ 0 ] ], - $contentbox = $( '<div>' ) - .addClass( 'mwe-popups-extract' ) - .text( page.extract ), - thumbnail = page.thumbnail, - tall = thumbnail && thumbnail.height > thumbnail.width, - $thumbnail = createThumbnail( thumbnail, tall ), - timestamp = new Date( page.revisions[ 0 ].timestamp ), - timediff = new Date() - timestamp, - oneDay = 1000 * 60 * 60 * 24, - timestampclass = ( timediff < oneDay ) ? - 'mwe-popups-timestamp-recent' : - 'mwe-popups-timestamp-older', - $timestamp = $( '<div>' ) - .addClass( timestampclass ) - .append( - $( '<span>' ).text( mw.message( 'popups-last-edited', - moment( timestamp ).fromNow() ).text() ) - ); - - $a = $( '<a>' ) - .append( $thumbnail, $contentbox, $timestamp ) - .attr( 'href', href ) - .on( 'click', logClick ); - - cache[ href ] = { - box: $a, - thumbnail: thumbnail, - tall: tall - }; - - deferred.resolve(); - } ); - - return deferred.promise(); - } - - /** - * @method createSVGTag - * Use createElementNS to create the svg:image tag as jQuery - * uses createElement instead. Some browsers map the `image` tag - * to `img` tag, thus an `svg:image` is required. - * @param {String} tag - * @return {Object} - */ - function createSVGTag( tag ) { - return document.createElementNS( 'http://www.w3.org/2000/svg', tag ); - } - - /** - * @method createThumbnail - * Returns a thumbnail object based on the ratio of the image - * Uses an SVG image where available to add the triangle/pokey - * mask on the image. Crops and resizes the SVG image so that - * is fits inside a rectangle of a particular size. - * @param {Object} thumbnail - * @param {boolean} tall - * @return {Object} jQuery DOM element of the thumbnail - */ - function createThumbnail( thumbnail, tall ) { - if ( !thumbnail ) { - return $( '<span>' ); - } - - var $thumbnailSVGImage, $thumbnail; - - if ( tall ) { - if ( supportsSVG ) { - $thumbnailSVGImage = $( createSVGTag( 'image' ) ); - $thumbnailSVGImage - .addClass( 'mwe-popups-is-not-tall' ) - .attr( { - 'xlink:href': thumbnail.source, - x: ( thumbnail.width > SIZES.portraitImage.w ) ? - ( ( thumbnail.width - SIZES.portraitImage.w ) / -2 ) : - ( SIZES.portraitImage.w - thumbnail.width ), - y: ( thumbnail.height > SIZES.portraitImage.h ) ? - ( ( thumbnail.height - SIZES.portraitImage.h ) / -2 ) : - 0, - width: thumbnail.width, - height: thumbnail.height - } ); - - $thumbnail = $( '<svg>' ) - .attr( { - xmlns: 'http://www.w3.org/2000/svg', - width: SIZES.portraitImage.w, - height: SIZES.portraitImage.h - } ) - .append( $thumbnailSVGImage ); - } else { - $thumbnail = $( '<div>' ) - .addClass( 'mwe-popups-is-tall' ) - .css( 'background-image', 'url(' + thumbnail.source + ')' ); - } + $thumbnail = $( '<svg>' ) + .attr( { + xmlns: 'http://www.w3.org/2000/svg', + width: SIZES.portraitImage.w, + height: SIZES.portraitImage.h + } ) + .append( $thumbnailSVGImage ); } else { - if ( supportsSVG ) { - $thumbnailSVGImage = $( createSVGTag( 'image' ) ); - $thumbnailSVGImage - .addClass( 'mwe-popups-is-not-tall' ) - .attr( { - 'xlink:href': thumbnail.source, - 'clip-path': 'url(#mwe-popups-mask)', - x: 0, - y: ( thumbnail.height > SIZES.landscapeImage.h ) ? - ( ( thumbnail.height - SIZES.landscapeImage.h ) / -2 ) : - 0, - width: thumbnail.width, - height: thumbnail.height - } ); + $thumbnail = $( '<div>' ) + .addClass( 'mwe-popups-is-tall' ) + .css( 'background-image', 'url(' + thumbnail.source + ')' ); + } + } else { + if ( supportsSVG ) { + $thumbnailSVGImage = $( createSVGTag( 'image' ) ); + $thumbnailSVGImage + .addClass( 'mwe-popups-is-not-tall' ) + .attr( { + 'xlink:href': thumbnail.source, + 'clip-path': 'url(#mwe-popups-mask)', + x: 0, + y: ( thumbnail.height > SIZES.landscapeImage.h ) ? + ( ( thumbnail.height - SIZES.landscapeImage.h ) / -2 ) : + 0, + width: thumbnail.width, + height: thumbnail.height + } ); - $thumbnail = $( '<svg>' ) - .attr( { - xmlns: 'http://www.w3.org/2000/svg', - width: SIZES.landscapeImage.w + 3, - height: ( thumbnail.height > SIZES.landscapeImage.h ) ? - SIZES.landscapeImage.h : - thumbnail.height - } ) - .append( $thumbnailSVGImage ); - } else { - $thumbnail = $( '<div>' ) - .addClass( 'mwe-popups-is-not-tall' ) - .css( 'background-image', 'url(' + thumbnail.source + ')' ); + $thumbnail = $( '<svg>' ) + .attr( { + xmlns: 'http://www.w3.org/2000/svg', + width: SIZES.landscapeImage.w + 3, + height: ( thumbnail.height > SIZES.landscapeImage.h ) ? + SIZES.landscapeImage.h : + thumbnail.height + } ) + .append( $thumbnailSVGImage ); + } else { + $thumbnail = $( '<div>' ) + .addClass( 'mwe-popups-is-not-tall' ) + .css( 'background-image', 'url(' + thumbnail.source + ')' ); + } + } + + return $thumbnail; + } + + /** + * @method createBox + * Looks into the `cache` and uses the href to render the popup + * and offsets it to the link. Rebinds the `mouseleave` event + * for the anchor element to `leaveActive`. + * @param {String} href + * @param {Object} $el + * @param {Object} event + */ + function createBox( href, $el, event ) { + var + bar = cache[ href ], + offsetTop = ( event.pageY ) ? + event.pageY + 20 : + $el.offset().top + $el.height() + 9, + offsetLeft = ( event.pageX ) ? + event.pageX : + $el.offset().left, + flipped = false; + + elTime = mw.now(); + elAction = 'dismissed'; + + if ( bar.thumbnail === undefined ) { + bar.thumbnail = false; + } + + if ( bar.tall === undefined ) { + bar.tall = false; + } + + if ( offsetLeft > ( $( window ).width() / 2 ) ) { + offsetLeft += ( !event.pageX ) ? $el.width() : 0; + offsetLeft -= ( !bar.tall ) ? SIZES.portraitPopupWidth : SIZES.landscapePopupWidth; + flipped = true; + } + + if ( event.pageX ) { + offsetLeft += ( flipped ) ? 20 : -20; // compensating the position of the triangle + } + + $box + .children() + .detach() + // avoid .empty() to keep event handlers + .end() + .removeClass( 'mwe-popups-is-tall mwe-popups-is-not-tall mwe-popups-no-image-tri mwe-popups-image-tri flipped' ) + .toggleClass( 'flipped', flipped ) + // Add border triangle if there is no image or its landscape + .toggleClass( 'mwe-popups-no-image-tri', ( !bar.thumbnail || bar.tall ) ) + // If theres an image and the popup is portrait do the SVG stuff + .toggleClass( 'mwe-popups-image-tri', ( bar.thumbnail && !bar.tall ) ) + .addClass( bar.tall ? 'mwe-popups-is-tall' : 'mwe-popups-is-not-tall' ) + .css( { + top: offsetTop, + left: offsetLeft + } ) + .append( bar.box ) + .attr( 'aria-hidden', 'false' ) + .show() + .removeClass( 'mwe-popups-fade-out mwe-popups-fade-in' ) + .addClass( 'mwe-popups-fade-in' ) + // Hack to 'refresh' the SVG and thus display it + // Elements get added to the DOM and not to the screen because of different namespaces of HTML and SVG + // More information and workarounds here - http://stackoverflow.com/a/13654655/366138 + .html( $box.html() ); + + if ( flipped && bar.thumbnail ) { + if ( !bar.tall ) { + $box.find( 'image' )[ 0 ].setAttribute( 'clip-path', 'url(#mwe-popups-mask-flip)' ); + } else { + $box + .removeClass( 'mwe-popups-no-image-tri' ) + .find( 'image' )[ 0 ].setAttribute( 'clip-path', 'url(#mwe-popups-landscape-mask)' ); + } + } + + $el + .off( 'mouseleave blur', leaveInactive ) + .on( 'mouseleave blur', leaveActive ); + + $( document ).on( 'keydown', closeOnEsc ); + } + + /** + * @method closeOnEsc + * Use escape to close popup + */ + function closeOnEsc( e ) { + if ( e.keyCode === 27 ) { + closeBox(); + } + } + + /** + * @method leaveActive + * Closes the box after a delay + * Delay to give enough time for the user to move the pointer from + * the link to the popup box. Also avoids closing the popup by accident. + */ + function leaveActive() { + closeTimer = setTimeout( closeBox, POPUP_CLOSE_DELAY ); + } + + /** + * @method leaveInactive + * Unbinds events on the anchor tag and aborts AJAX request. + */ + function leaveInactive() { + $( currentLink ).off( 'mouseleave', leaveInactive ); + if ( openTimer ) { + openTimer.abort(); + } + if ( curRequest ) { + curRequest.abort(); + } + currentLink = openTimer = curRequest = undefined; + } + + /** + * @method closeBox + * Removes the hover class from the link and unbinds events + * Hides the popup, clears timers and sets it and the + * `currentLink` to undefined. + */ + function closeBox() { + elDuration = mw.now() - elTime; + + $( currentLink ).removeClass( 'mwe-popups-anchor-hover' ).off( 'mouseleave', leaveActive ); + + $box + .removeClass( 'mwe-popups-fade-out mwe-popups-fade-in' ) + .addClass( 'mwe-popups-fade-out' ) + .on( 'webkitAnimationEnd oanimationend msAnimationEnd animationend', function () { + if ( $( this ).hasClass( 'mwe-popups-fade-out' ) ) { + $( this ) + .off( 'webkitAnimationEnd oanimationend msAnimationEnd animationend' ) + .removeClass( 'mwe-popups-fade-out' ) + .attr( 'aria-hidden', 'true' ) + .hide(); } - } + } ); - return $thumbnail; + if ( closeTimer ) { + clearTimeout( closeTimer ); } - /** - * @method createBox - * Looks into the `cache` and uses the href to render the popup - * and offsets it to the link. Rebinds the `mouseleave` event - * for the anchor element to `leaveActive`. - * @param {String} href - * @param {Object} $el - * @param {Object} event - */ - function createBox( href, $el, event ) { - var - bar = cache[ href ], - offsetTop = ( event.pageY ) ? - event.pageY + 20 : - $el.offset().top + $el.height() + 9, - offsetLeft = ( event.pageX ) ? - event.pageX : - $el.offset().left, - flipped = false; + $( document ).off( 'keydown', closeOnEsc ); - elTime = mw.now(); - elAction = 'dismissed'; + logEvent(); + currentLink = closeTimer = undefined; + } - if ( bar.thumbnail === undefined ) { - bar.thumbnail = false; - } - - if ( bar.tall === undefined ) { - bar.tall = false; - } - - if ( offsetLeft > ( $( window ).width() / 2 ) ) { - offsetLeft += ( !event.pageX ) ? $el.width() : 0; - offsetLeft -= ( !bar.tall ) ? SIZES.portraitPopupWidth : SIZES.landscapePopupWidth; - flipped = true; - } - - if ( event.pageX ) { - offsetLeft += ( flipped ) ? 20 : -20; // compensating the position of the triangle - } - - $box - .children() - .detach() - // avoid .empty() to keep event handlers - .end() - .removeClass( 'mwe-popups-is-tall mwe-popups-is-not-tall mwe-popups-no-image-tri mwe-popups-image-tri flipped' ) - .toggleClass( 'flipped', flipped ) - // Add border triangle if there is no image or its landscape - .toggleClass( 'mwe-popups-no-image-tri', ( !bar.thumbnail || bar.tall ) ) - // If theres an image and the popup is portrait do the SVG stuff - .toggleClass( 'mwe-popups-image-tri', ( bar.thumbnail && !bar.tall ) ) - .addClass( bar.tall ? 'mwe-popups-is-tall' : 'mwe-popups-is-not-tall' ) - .css( { - top: offsetTop, - left: offsetLeft - } ) - .append( bar.box ) - .attr( 'aria-hidden', 'false' ) - .show() - .removeClass( 'mwe-popups-fade-out mwe-popups-fade-in' ) - .addClass( 'mwe-popups-fade-in' ) - // Hack to 'refresh' the SVG and thus display it - // Elements get added to the DOM and not to the screen because of different namespaces of HTML and SVG - // More information and workarounds here - http://stackoverflow.com/a/13654655/366138 - .html( $box.html() ); - - if ( flipped && bar.thumbnail ) { - if ( !bar.tall ) { - $box.find( 'image' )[ 0 ].setAttribute( 'clip-path', 'url(#mwe-popups-mask-flip)' ); - } else { - $box - .removeClass( 'mwe-popups-no-image-tri' ) - .find( 'image' )[ 0 ].setAttribute( 'clip-path', 'url(#mwe-popups-landscape-mask)' ); - } - } - - $el - .off( 'mouseleave blur', leaveInactive ) - .on( 'mouseleave blur', leaveActive ); - - $( document ).on( 'keydown', closeOnEsc ); - } - - /** - * @method closeOnEsc - * Use escape to close popup - */ - function closeOnEsc( e ) { - if ( e.keyCode === 27 ) { - closeBox(); - } - } - - /** - * @method leaveActive - * Closes the box after a delay - * Delay to give enough time for the user to move the pointer from - * the link to the popup box. Also avoids closing the popup by accident. - */ - function leaveActive() { - closeTimer = setTimeout( closeBox, POPUP_CLOSE_DELAY ); - } - - /** - * @method leaveInactive - * Unbinds events on the anchor tag and aborts AJAX request. - */ - function leaveInactive() { - $( currentLink ).off( 'mouseleave', leaveInactive ); - if ( openTimer ) { - openTimer.abort(); - } - if ( curRequest ) { - curRequest.abort(); - } - currentLink = openTimer = curRequest = undefined; - } - - /** - * @method closeBox - * Removes the hover class from the link and unbinds events - * Hides the popup, clears timers and sets it and the - * `currentLink` to undefined. - */ - function closeBox() { - elDuration = mw.now() - elTime; - - $( currentLink ).removeClass( 'mwe-popups-anchor-hover' ).off( 'mouseleave', leaveActive ); - - $box - .removeClass( 'mwe-popups-fade-out mwe-popups-fade-in' ) - .addClass( 'mwe-popups-fade-out' ) - .on( 'webkitAnimationEnd oanimationend msAnimationEnd animationend', function () { - if ( $( this ).hasClass( 'mwe-popups-fade-out' ) ) { - $( this ) - .off( 'webkitAnimationEnd oanimationend msAnimationEnd animationend' ) - .removeClass( 'mwe-popups-fade-out' ) - .attr( 'aria-hidden', 'true' ) - .hide(); - } - } ); - - if ( closeTimer ) { - clearTimeout( closeTimer ); - } - - $( document ).off( 'keydown', closeOnEsc ); - - logEvent(); - currentLink = closeTimer = undefined; - } - - /** - * @method logClick - * Logs different actions such as meta and shift click on the popup. - * Is bound to the `click` event. - * @param {Object} e - */ - function logClick( e ) { - if ( e.which === 2 ) { // middle click + /** + * @method logClick + * Logs different actions such as meta and shift click on the popup. + * Is bound to the `click` event. + * @param {Object} e + */ + function logClick( e ) { + if ( e.which === 2 ) { // middle click + elAction = 'opened in new tab'; + } else if ( e.which === 1 ) { + if ( e.ctrlKey || e.metaKey ) { elAction = 'opened in new tab'; - } else if ( e.which === 1 ) { - if ( e.ctrlKey || e.metaKey ) { - elAction = 'opened in new tab'; - } else if ( e.shiftKey ) { - elAction = 'opened in new window'; - } else { - elAction = 'opened in same tab'; - elDuration = mw.now() - elTime; - logEvent( this.href ); - e.preventDefault(); + } else if ( e.shiftKey ) { + elAction = 'opened in new window'; + } else { + elAction = 'opened in same tab'; + elDuration = mw.now() - elTime; + logEvent( this.href ); + e.preventDefault(); + } + } + } + + /** + * @method logEvent + * Logs the Popup event as defined in the following schema - + * https://meta.wikimedia.org/wiki/Schema:Popups + * If `href` is passed it redirects to that location after the event is logged. + * @param {string} href + */ + function logEvent( href ) { + if ( typeof mw.eventLog !== 'function' ) { + return false; + } + + var dfd = $.Deferred(), + event = { + duration: Math.round( elDuration ), + action: elAction + }; + + if ( elSessionId !== null ) { + event.sessionId = elSessionId; + } + + if ( href ) { + dfd.always( function () { + location.href = href; + } ); + } + + mw.eventLog.logEvent( 'Popups', event ).then( dfd.resolve, dfd.reject ); + setTimeout( dfd.reject, 1000 ); + elTime = elDuration = elAction = undefined; + } + + /** + * @method getSessionId + * Generates a unique sessionId or pulls an existing one from localStorage + * @return {string} sessionId + */ + function getSessionId() { + var sessionId = null; + try { + sessionId = localStorage.getItem( 'popupsSessionId' ); + if ( sessionId === null ) { + sessionId = mw.user.generateRandomSessionId(); + localStorage.setItem( 'popupsSessionId', sessionId ); + } + } catch ( e ) {} + return sessionId; + } + elSessionId = getSessionId(); + + // Prevent popups from showing up when the mouse cursor accidentally + // ends up hovering a link after scrolling + $( window ).on( 'scroll', function () { + scrolled = true; + } ); + $( window ).on( 'mousemove', function () { + scrolled = false; + } ); + + $( function () { + // Container for the popup + $box = $( '<div>' ) + .attr( 'role', 'tooltip' ) + .addClass( 'mwe-popups' ) + .on( { + mouseleave: leaveActive, + mouseenter: function () { + if ( closeTimer ) { + clearTimeout( closeTimer ); + } } - } + } ) + .appendTo( document.body ); + + // SVG for masking and creating the triangle/pokey + if ( supportsSVG ) { + $svg = $( '<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>' + + '</defs>' + + '</svg>' + ); } + } ); - /** - * @method logEvent - * Logs the Popup event as defined in the following schema - - * https://meta.wikimedia.org/wiki/Schema:Popups - * If `href` is passed it redirects to that location after the event is logged. - * @param {string} href - */ - function logEvent( href ) { - if ( typeof mw.eventLog !== 'function' ) { - return false; - } - - var dfd = $.Deferred(), - event = { - duration: Math.round( elDuration ), - action: elAction - }; - - if ( elSessionId !== null ) { - event.sessionId = elSessionId; - } - - if ( href ) { - dfd.always( function () { - location.href = href; - } ); - } - - mw.eventLog.logEvent( 'Popups', event ).then( dfd.resolve, dfd.reject ); - setTimeout( dfd.reject, 1000 ); - elTime = elDuration = elAction = undefined; - } - - /** - * @method getSessionId - * Generates a unique sessionId or pulls an existing one from localStorage - * @return {string} sessionId - */ - function getSessionId() { - var sessionId = null; - try { - sessionId = localStorage.getItem( 'popupsSessionId' ); - if ( sessionId === null ) { - sessionId = mw.user.generateRandomSessionId(); - localStorage.setItem( 'popupsSessionId', sessionId ); - } - } catch ( e ) {} - return sessionId; - } - elSessionId = getSessionId(); - - // Prevent popups from showing up when the mouse cursor accidentally - // ends up hovering a link after scrolling - $( window ).on( 'scroll', function () { - scrolled = true; - } ); - $( window ).on( 'mousemove', function () { - scrolled = false; - } ); - + mw.hook( 'wikipage.content' ).add( function ( $content ) { // Remove title attribute to remove the default yellow tooltip // Put the title back after the hover - $( '#mw-content-text a:not(.extiw):not(.image):not(.new):not(.internal):not([title=""])' ) + $content.find( 'a:not(.extiw):not(.image):not(.new):not(.internal):not([title=""])' ) .on( 'mouseenter focus', function () { $( this ) .attr( 'data-original-title', $( this ).attr( 'title' ) ) @@ -470,7 +507,7 @@ .attr( 'data-original-title', '' ); } ); - $( '#mw-content-text a' ).on( 'mouseenter focus', function ( event ) { + $content.find( 'a' ).on( 'mouseenter focus', function ( event ) { var $this = $( this ), href = $this.attr( 'href' ), title = $this.attr( 'data-original-title' ); @@ -527,43 +564,6 @@ } ); } } ); - - // Container for the popup - $box = $( '<div>' ) - .attr( 'role', 'tooltip' ) - .addClass( 'mwe-popups' ) - .on( { - mouseleave: leaveActive, - mouseenter: function () { - if ( closeTimer ) { - clearTimeout( closeTimer ); - } - } - } ) - .appendTo( document.body ); - - // SVG for masking and creating the triangle/pokey - if ( supportsSVG ) { - $svg = $( '<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>' + - '</defs>' + - '</svg>' - ); - } - } ); }( jQuery, mediaWiki ) ); -- To view, visit https://gerrit.wikimedia.org/r/128455 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ie681ff6722b9909d38fc06359da7614e0fc1798e Gerrit-PatchSet: 2 Gerrit-Project: mediawiki/extensions/Popups Gerrit-Branch: master Gerrit-Owner: Bartosz DziewoĆski <matma....@gmail.com> Gerrit-Reviewer: Prtksxna <psax...@wikimedia.org> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits