Prtksxna has uploaded a new change for review. https://gerrit.wikimedia.org/r/117169
Change subject: [wip] Reorganizing code ...................................................................... [wip] Reorganizing code Bug: 61267 Change-Id: I8edbab614b4cb7e858b6732a082e7c66684271b4 --- D resources/ext.popups.core.js A resources/ext.popups.eventlogging.js A resources/ext.popups.main.js A resources/ext.popups.popup.article.js A resources/ext.popups.popup.js 5 files changed, 464 insertions(+), 460 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Popups refs/changes/69/117169/1 diff --git a/resources/ext.popups.core.js b/resources/ext.popups.core.js deleted file mode 100644 index b370d84..0000000 --- a/resources/ext.popups.core.js +++ /dev/null @@ -1,460 +0,0 @@ -/* Code adapted from Yair Rand's NavPopupsRestyled.js - * https://en.wikipedia.org/wiki/User:Yair_rand/NavPopupsRestyled.js - */ - -/*global mw:false */ - -(function ( $ ) { - $( 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 - 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 - api = new mw.Api(), - $svg, $box; // defined at the end of the file - - /** - * @method sendRequest - * Send an API request, create DOM elements and - * put them in the cache. Call `createBox`. - * @param {String} href - * @param {String} title - * @param {Object} $el - */ - function sendRequest ( href, title, $el ) { - - curRequest = api.get( { - action: 'query', - prop: 'extracts|pageimages|revisions|info', - redirects: 'true', - exintro: 'true', - exsentences: 2, - explaintext: 'true', - piprop: 'thumbnail', - pithumbsize: 300, - rvprop: 'timestamp', - inprop: 'watched', - indexpageids: true, - titles: decodeURI( title ) - } ); - - curRequest.done( function ( re ) { - curRequest = undefined; - - var $a, - redirects = re.query.redirects, - 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( timeAgo( timediff ).text() ) - ); - - if ( redirects ) { - $contentbox.prepend( - $( '<div>' ) - .addClass( 'mwe-popups-redirect ') - .html( mw.message( 'popups-redirects', redirects[ 0 ].to ).text() ) - ); - } - - $a = $( '<a>' ) - .append( $thumbnail, $contentbox, $timestamp) - .attr( 'href', href ) - .on( 'click', logClick ); - - cache[ href ] = { box: $a, thumbnail: thumbnail, tall: tall }; - createBox( href, $el ); - }); - - return true; - } - - /** - * @method supportsSVG - * Checks for SVG support in browser - * @return {boolean} - */ - function supportsSVG() { - return document.implementation.hasFeature( 'http://www.w3.org/TR/SVG11/feature#Image', '1.1' ); - } - - /** - * @method createThumbnail - * Returns a thumbnail object based on the ratio of the image - * @param {Object} thumbnail - * @param {boolean} tall - * @return {Object} jQuery DOM element of the thumbnail - */ - function createThumbnail ( thumbnail, tall ) { - if ( !thumbnail ) { - return $( '<span>' ); - } - - var $thumbnail; - - if ( tall ) { - // This is to mask and center the image within a given size - $thumbnail = $( '<div>' ) - .addClass( 'mwe-popups-is-tall' ) - .css( 'background-image', 'url(' + thumbnail.source + ')'); - } else { - if ( supportsSVG() ) { - $thumbnail = $( '<image>' ) - .addClass( 'mwe-popups-is-not-tall' ) - .attr( { - 'xlink:href': thumbnail.source, - 'clip-path': 'url(#mwe-popups-mask)', - x: 0, - y: 0, - width: thumbnail.width, - height: thumbnail.height - } ); - - $thumbnail = $( '<svg>' ) - .attr( { - xmlns: 'http://www.w3.org/2000/svg', - viewBox: '0 0 ' + thumbnail.width + ' ' + thumbnail.height, - width: thumbnail.width, - height: thumbnail.height - } ) - .append( $thumbnail ); - } else { - $thumbnail = $( '<img>' ) - .attr( 'src', thumbnail.source ) - .addClass( 'mwe-popups-is-not-tall' ); - } - } - - 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 - */ - function createBox ( href, $el ) { - var bar = cache[ href ], - offsetTop = $el.offset().top + $el.height() + 9, - offsetLeft = $el.offset().left; - - elTime = mw.now(); - elAction = 'dismissed'; - - if ( bar.thumbnail === undefined ) { - bar.thumbnail = false; - } - - if ( bar.tall === undefined ) { - bar.tall = false; - } - - $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' ) - // 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 ) - .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() ); - $el - .off( 'mouseleave', leaveInactive ) - .on( 'mouseleave', leaveActive ); - } - - /** - * @method leaveActive - * Closes the box after a delay of 100ms - * Delay to give enough time for the use to move the pointer from - * the link to the popup box. Also avoids closing the popup by accident. - */ - function leaveActive () { - closeTimer = setTimeout( closeBox, 100 ); - } - - /** - * @method leaveInactive - * Unbinds events on the anchor tag and aborts AJAX request. - */ - function leaveInactive () { - $( currentLink ).off( 'mouseleave', leaveInactive ); - clearTimeout( openTimer ); - 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' ) - .hide(); - } - } ); - - if ( closeTimer ){ - clearTimeout( closeTimer ); - } - - 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 - 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(); - } - } - } - - /** - * @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 ) { - 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(); - - // 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( '[title=""]' ) - .hover( - function () { - $( this ) - .attr( 'data-original-title', $( this ).attr( 'title' ) ) - .attr( 'title', ''); - }, - function () { - $( this ) - .attr( 'title', $( this ).attr( 'data-original-title' ) ) - .attr( 'data-original-title', ''); - } - ); - - - $( '#mw-content-text a' ).on( 'mouseenter', function () { - var $this = $( this ), - href = $this.attr( 'href' ), - title = $this.attr( 'data-original-title' ); - - // If a popup for the following link can't be shown - if ( !title || - $this.hasClass( 'extiw' ) || - $this.hasClass( 'image' ) || - $this.hasClass( 'new' ) || - href.indexOf( '?' ) !== -1 || - href.indexOf( location.origin + location.pathname + '#' ) === 0 - ) { - return; - } - - // This will happen when the mouse goes from the popup box back to the - // anchor tag. In such a case, the timer to close the box is cleared. - if ( currentLink === this ) { - clearTimeout( closeTimer ); - return; - } - - // If the mouse moves to another link (we already check if its the same - // link in the previous condition), then close the popup. - if ( currentLink ) { - closeBox(); - } - - currentLink = this; - $this.on( 'mouseleave', leaveInactive ); - - if ( cache[ href ] ){ - openTimer = setTimeout( function () { - createBox( href, $this ); - }, 150 ); - } else { - openTimer = setTimeout( function () { - sendRequest( href, title, $this ); - }, 50 ); // sendRequest sooner so that it *hopefully* shows up in 150ms - } - // Delay to avoid triggering the popup and AJAX requests on accidental - // hovers (likes ones during srcolling or moving the pointer elsewhere). - - } ); - - // Container for the popup - $box = $( '<div>' ) - .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></defs></svg>' ); - } - - } ); - - // Util functions that should be separated out into their own files at some point - - /** - * @method timeAgo - * Formats a given time duration (in ms) into a relative string. - * - * @param {number} ms The time duration to convert to a relative string, in ms - * @return {Object} A mw.message object with the appropriate relative string. - */ - function timeAgo( ms ) { - var i, ts, timeSegments = [ - { - factor: 1000, - min: 60, - message: 'popups-edited-seconds' - }, - { - factor: 60, - min: 60, - message: 'popups-edited-minutes' - }, - { - factor: 60, - min: 24, - message: 'popups-edited-hours' - }, - { - factor: 24, - min: 365, - message: 'popups-edited-days' - }, - { - factor: 365, - message: 'popups-edited-years' - } - ], curDuration = ms; - - for ( i = 0; i <= timeSegments.length; i++ ) { - ts = timeSegments[ i ]; - curDuration = Math.floor( curDuration / ts.factor ); - if ( typeof ts.min === 'undefined' || curDuration < ts.min ) { - return mw.message( ts.message, curDuration ); - } - } - } -} ) ( jQuery ); diff --git a/resources/ext.popups.eventlogging.js b/resources/ext.popups.eventlogging.js new file mode 100644 index 0000000..48a14b9 --- /dev/null +++ b/resources/ext.popups.eventlogging.js @@ -0,0 +1,82 @@ +( function ( $, mw ) { + + /** + * @class EventLogging + * @singleton + */ + var EventLogging = {}; + + /** + * Logs different actions such as meta and shift click on the popup. + * Is bound to the `click` event. + * @method logClick + * @param {Object} e + */ + EventLogging.logClick = function ( 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.shiftKey ){ + elAction = 'opened in new window'; + } else { + elAction = 'opened in same tab'; + elDuration = mw.now() - elTime; // TODO What are these vars? + this.logEvent( this.href ); // TODO What is this? + e.preventDefault(); + } + } + } + + /** + * 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. + * @method logEvent + * @param {string} href + */ + EventLogging.logEvent = function ( href ) { + 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; // TODO What is this even? + } + + /** + * Generates a unique sessionId or pulls an existing one from localStorage + * @method getSessionId + * @return {String} sessionId + */ + EventLogging.getSessionId = function () { + var sessionId = null; + try { + sessionId = localStorage.getItem( 'popupsSessionId' ); + if ( sessionId === null ) { + sessionId = mw.user.generateRandomSessionId(); + localStorage.setItem( 'popupsSessionId', sessionId ); + } + } catch ( e ) {} + return sessionId; + } + + /** + * @property sessionId + */ + EventLogging.sessionId = EventLogging.getSessionId(); + + mw.popups.EventLogging = EventLogging; + +} ) ( jQuery, mediaWiki ); diff --git a/resources/ext.popups.main.js b/resources/ext.popups.main.js new file mode 100644 index 0000000..57703d0 --- /dev/null +++ b/resources/ext.popups.main.js @@ -0,0 +1,128 @@ +( function ( $, mw ) { + + /** + * @class mw.popups + * @singleton + */ + mw.popups = {}; + + /** + * Cache of all the popups that've been opened in this session + * @property {Object} cache + */ + mw.popups.cache = {}; + + /** + * Check SVG support on the browser + * @property {Boolean} supportsSVG + */ + mw.popups.supportsSVG = document + .implementation + .hasFeature( 'http://www.w3.org/TR/SVG11/feature#Image', '1.1' ); + + /** + * Remove the title attribute to remove the default tooltip + * on browsers. Put the title back on mouseout + * + * @method removeTooltips + */ + mw.popups.removeTooltips = function () { + $( '#mw-content-text a' ) + .not( '.extiw' ) + .not( '.image' ) + .not( '.new' ) + .not( '[title=""]' ) + .hover( + function () { + $( this ) + .attr( 'data-original-title', $( this ).attr( 'title' ) ) + .attr( 'title', ''); + }, + function () { + $( this ) + .attr( 'title', $( this ).attr( 'data-original-title' ) ) + .attr( 'data-original-title', ''); + } + ); + } + + /** + * @method bindMouseenter + */ + mw.popups.removeTooltips = function () { + $( '#mw-content-text a' ).on( 'mouseenter', function () { + var $this = $( this ), + href = $this.attr( 'href' ), + title = $this.attr( 'data-original-title' ); + + // If a popup for the following link can't be shown + if ( !title || + $this.hasClass( 'extiw' ) || + $this.hasClass( 'image' ) || + $this.hasClass( 'new' ) || + href.indexOf( '?' ) !== -1 || + href.indexOf( location.origin + location.pathname + '#' ) === 0 + ) { + return; + } + + // This will happen when the mouse goes from the popup box back to the + // anchor tag. In such a case, the timer to close the box is cleared. + if ( currentLink === this ) { + clearTimeout( closeTimer ); + return; + } + + // If the mouse moves to another link (we already check if its the same + // link in the previous condition), then close the popup. + if ( currentLink ) { + closeBox(); + } + + currentLink = this; + $this.on( 'mouseleave', leaveInactive ); + + if ( cache[ href ] ){ + openTimer = setTimeout( function () { + createBox( href, $this ); + }, 150 ); + } else { + openTimer = setTimeout( function () { + sendRequest( href, title, $this ); + }, 50 ); // sendRequest sooner so that it *hopefully* shows up in 150ms + } + // Delay to avoid triggering the popup and AJAX requests on accidental + // hovers (likes ones during srcolling or moving the pointer elsewhere). + + } ); + } + + /** + * Create masking SVG + * @method createSVG + * @return {Boolean} Whether the SVG was created or not + */ + mw.popups.createSVG = function () { + if ( !mw.popups.supportsSVG ) { + return false; + } + + $( '<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></defs></svg>' ); + return true; + } + + /** + * @property $popup + */ + mw.popups.$popup = $( '<div>' ) + .addClass( 'mwe-popups' ) + .on ( { + mouseleave: mw.popups.leaveActive, // TODO Move leaveActive here + mouseenter: mw.popups.closeBox // TODO This too + } ) + .appendTo( document.body ); + +} ) ( jQuery, mediaWiki ); diff --git a/resources/ext.popups.popup.article.js b/resources/ext.popups.popup.article.js new file mode 100644 index 0000000..9b89b1f --- /dev/null +++ b/resources/ext.popups.popup.article.js @@ -0,0 +1,178 @@ +( function ( $, mw ) { + + /** + * @class ArticlePopup + */ + function ArticlePopup () { + } + + ArticlePopup.prototype = mw.popups.Popup.prototype; + + /** + * Send an API request, create DOM elements and + * put them in the cache. Call `createBox`. + * @method init + * @param {String} href + * @param {String} title + * @param {Object} $el + */ + ArticlePopup.prototype.init = function () { + curRequest = api.get( { + action: 'query', + prop: 'extracts|pageimages|revisions|info', + redirects: 'true', + exintro: 'true', + exsentences: 2, + explaintext: 'true', + piprop: 'thumbnail', + pithumbsize: 300, + rvprop: 'timestamp', + inprop: 'watched', + indexpageids: true, + titles: decodeURI( title ) + } ); + + curRequest.done( function ( re ) { + curRequest = undefined; + var $a, + redirects = re.query.redirects, + 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( timeAgo( timediff ).text() ) + ); + + if ( redirects ) { + $contentbox.prepend( + $( '<div>' ) + .addClass( 'mwe-popups-redirect ') + .html( mw.message( 'popups-redirects', redirects[ 0 ].to ).text() ) + ); + } + + $a = $( '<a>' ) + .append( $thumbnail, $contentbox, $timestamp) + .attr( 'href', href ) + .on( 'click', logClick ); + + cache[ href ] = { box: $a, thumbnail: thumbnail, tall: tall }; + createBox( href, $el ); + }); + + return true; + } + + /** + * @method cachePopup + * 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 + */ + ArticlePopup.prototype.cachePopup = function () { + var bar = cache[ href ], + offsetTop = $el.offset().top + $el.height() + 9, + offsetLeft = $el.offset().left; + + elTime = mw.now(); + elAction = 'dismissed'; + + if ( bar.thumbnail === undefined ) { + bar.thumbnail = false; + } + + if ( bar.tall === undefined ) { + bar.tall = false; + } + + $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' ) + // 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 ) + .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() ); + $el + .off( 'mouseleave', leaveInactive ) + .on( 'mouseleave', leaveActive ); + } + + /** + * Returns a thumbnail object based on the ratio of the image + * @method createThumbnail + */ + Popup.prototype.createThumbnail = function () { + if ( !thumbnail ) { + return $( '<span>' ); + } + + var $thumbnail; + + if ( tall ) { + // This is to mask and center the image within a given size + $thumbnail = $( '<div>' ) + .addClass( 'mwe-popups-is-tall' ) + .css( 'background-image', 'url(' + thumbnail.source + ')'); + } else { + if ( supportsSVG() ) { + $thumbnail = $( '<image>' ) + .addClass( 'mwe-popups-is-not-tall' ) + .attr( { + 'xlink:href': thumbnail.source, + 'clip-path': 'url(#mwe-popups-mask)', + x: 0, + y: 0, + width: thumbnail.width, + height: thumbnail.height + } ); + $thumbnail = $( '<svg>' ) + .attr( { + xmlns: 'http://www.w3.org/2000/svg', + viewBox: '0 0 ' + thumbnail.width + ' ' + thumbnail.height, + width: thumbnail.width, + height: thumbnail.height + } ) + .append( $thumbnail ); + } else { + $thumbnail = $( '<img>' ) + .attr( 'src', thumbnail.source ) + .addClass( 'mwe-popups-is-not-tall' ); + } + } + + return $thumbnail; + } + + + + mw.popups.ArticlePopups = ArticlePopup; + +} ) ( jQuery, mediaWiki ); diff --git a/resources/ext.popups.popup.js b/resources/ext.popups.popup.js new file mode 100644 index 0000000..e6746df --- /dev/null +++ b/resources/ext.popups.popup.js @@ -0,0 +1,76 @@ +( function ( $, mw ) { + + /** + * @class Popup + */ + function Popup () { + } + + /** + * @method init + */ + Popup.prototype.init = function () { + } + + /** + * @method cachePopup + */ + Popup.prototype.cachePopup = function () { + } + + /** + * Closes the box after a delay of 100ms + * Delay to give enough time for the use to move the pointer from + * the link to the popup box. Also avoids closing the popup by accident. + * @method leaveActive + */ + Popup.prototype.leaveActive = function () { + this.closeTimer = setTimeout( this.closeBox, 100 ); // TODO refs + } + + /** + * Unbinds events on the anchor tag and aborts AJAX request. + * @method leaveInactive + */ + Popup.prototype.leaveInactive = function () { // TODO refs + $( currentLink ).off( 'mouseleave', leaveInactive ); + clearTimeout( openTimer ); + if ( curRequest ) { + curRequest.abort(); + } + currentLink = openTimer = curRequest = undefined; + } + + /** + * Removes the hover class from the link and unbinds events + * Hides the popup, clears timers and sets it and the + * `currentLink` to undefined. + * @method closeBox + */ + Popup.prototype.closeBox = function () { + 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' ) + .hide(); + } + } ); + + if ( closeTimer ){ + clearTimeout( closeTimer ); + } + logEvent(); + currentLink = closeTimer = undefined; + } + + mw.popups.Popup = Popup; + +} ) ( jQuery, mediaWiki ); -- To view, visit https://gerrit.wikimedia.org/r/117169 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I8edbab614b4cb7e858b6732a082e7c66684271b4 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/Popups Gerrit-Branch: master Gerrit-Owner: Prtksxna <psax...@wikimedia.org> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits