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

Reply via email to