User:Se4598/testpopups.js

mw.loader.using( [ 'ext.popups' ], function { //wait for popups to be loaded	// inject gerrit change 232236	   mw.popups.render.render = function ( link, event ) {       // 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 ( mw.popups.render.currentLink && mw.popups.render.currentLink[ 0 ] === link[ 0 ] ) {          if ( mw.popups.render.closeTimer ) {               mw.popups.render.closeTimer.abort;           }           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 ( mw.popups.render.currentLink ) {           mw.popups.render.closePopup;       }       // Ignore if its meant to call a function       // TODO: Remove this when adding reference popups       if ( link.attr( 'href' ) === '#' ) {           return;       }       // Disable Navigration Popups       mw.popups.disableNavPopup;       mw.popups.render.currentLink = link;       link.on( 'mouseleave blur', mw.popups.render.leaveInactive );       if ( mw.popups.render.cache[ link.attr( 'href' ) ] ) {           mw.popups.render.openTimer = mw.popups.render.wait( mw.popups.render.POPUP_DELAY )               .done( function  { mw.popups.render.openPopup( link, event ); } );      } else {           // Wait for timer before making API queries and showing hovercard           mw.popups.render.openTimer = mw.popups.render.wait( mw.popups.render.API_DELAY )               .done( function  { var cachePopup, key, renderers = mw.popups.render.renderers; // Check run the matcher method of all renderers to find the right one for ( key in renderers ) { if ( renderers.hasOwnProperty( key ) && key !== 'article' ) { if ( !!renderers[ key ].matcher( link.attr( 'href' ) ) ) { cachePopup = renderers[ key ].init( link ); }                      }                   }                   // Use the article renderer if nothing else matches if ( cachePopup === undefined ) { cachePopup = mw.popups.render.renderers.article.init( link ); }                  mw.popups.render.openTimer = mw.popups.render.wait( mw.popups.render.POPUP_DELAY - mw.popups.render.API_DELAY ); $.when( mw.popups.render.openTimer, cachePopup ).done( function {                       mw.popups.render.openPopup( link, event );                   } ); } );      }   };	// ############# END of patched function	    /**    * @class mw.popups.render.artblue    * @singleton    */   var artblue = {};   /**    * Size constants for popup images    * @property SIZES    */   artblue.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       pokeySize: 8 // Height of the triangle used to point at the link   };   /**    * Survey link, if any, for this renderer    * @property surveyLink    */   artblue.surveyLink = mw.config.get( 'wgPopupsSurveyLink' );   artblue.matcher =  function ( xxx ) {   		console.log(xxx);       return true;   }   /**    * Send an API request and cache the jQuery element *   * @param {jQuery} link * @return {jQuery.Promise} */  artblue.init = function ( link ) { var href = link.attr( 'href' ), title = mw.popups.getTitle( href ), deferred = $.Deferred; if ( !title ) { return deferred.reject.promise; }      mw.popups.render.currentRequest = mw.popups.api.get( {           action: 'query',           prop: 'extracts|pageimages|revisions',           formatversion: 2,           redirects: true,           exintro: true,           exsentences: 5,           // 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',           titles: title,           smaxage: 300,           maxage: 300,           uselang: 'content'       } ); mw.popups.render.currentRequest.fail( deferred.reject ); mw.popups.render.currentRequest.done( function ( re ) {          mw.popups.render.currentRequest = undefined;           if ( !re.query || !re.query.pages || !re.query.pages[0].extract || re.query.pages[0].extract === '' ) {              deferred.reject;               return;           }           mw.popups.render.cache[ href ] = {};           mw.popups.render.cache[ href ].popup = artblue.createPopup( re.query.pages[0], href );           mw.popups.render.cache[ href ].getOffset = artblue.getOffset;           mw.popups.render.cache[ href ].getClasses = artblue.getClasses;           mw.popups.render.cache[ href ].process = artblue.processPopup;           deferred.resolve;       } ); return deferred.promise; };  /**    * 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. *   * @method createPopup * @param {Object} page Information about the linked page * @param {String} href * @return {jQuery} */  artblue.createPopup = function ( page, href ) { var $div, $contentbox = $( '' ) .attr( 'href', href ) .addClass( 'mwe-popups-extract' ) .append(                  'i am blue'               ), thumbnail = page.thumbnail, tall = thumbnail && thumbnail.height > thumbnail.width, $thumbnail = artblue.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', $settingsImage = $( '' ).addClass( 'mwe-popups-icon mwe-popups-settings-icon' ), $surveyImage, $timestamp = $( ' ' ) .addClass( timestampclass ) .append(                  $( ' ' ).text( mw.message( 'popups-last-edited',                       moment( timestamp ).fromNow ).text ),                   $settingsImage               ); if ( artblue.surveyLink ) { $surveyImage = $( '' ) .attr( 'href', artblue.surveyLink ) .attr( 'target', '_blank' ) .attr( 'title', mw.message( 'popups-send-feedback' ) ) .addClass( 'mwe-popups-icon mwe-popups-survey-icon' ); $timestamp.append( $surveyImage ); }      if ( $thumbnail.prop( 'tagName' ) !== 'SPAN' ) { $thumbnail = $( '' ) .addClass( 'mwe-popups-discreet' ) .attr( 'href', href ) .append( $thumbnail ); } else { tall = thumbnail = undefined; }      $div = $( ' ' ).append( $thumbnail, $contentbox, $timestamp ).css( 'background-color', 'blue' ); mw.popups.render.cache[ href ].settings = { 'title': page.title, 'tall': ( tall === undefined ) ? false : tall, 'thumbnail': ( thumbnail === undefined ) ? false : thumbnail };      return $div; };  /**    * Returns an array of elements to be appended after removing parentheses * and making the title in the extract bold. *   * @method getProcessedElements * @param {String} extract Should be unescaped * @param {String} title Should be unescaped * @return {Array} of elements to appended */  artblue.getProcessedElements = function ( extract, title ) { title = title.replace( /([.?*+^$[\]\\{}|-])/g, '\\$1' ); // Escape RegExp elements var elements = [], regExp = new RegExp( '(^|\\s)(' + title + ')(|$)', 'ig' ), boldIdentifier = '', snip = ''; // Remove text in parentheses along with the parentheses extract = artblue.removeParensFromText( extract ); extract = extract.replace(/\s+/g, ' '); // Remove extra white spaces // Make title bold in the extract text // As the extract is html escaped there can be no such string in it      // Also, the title is escaped of RegExp elements thus can't have "*" extract = extract.replace( regExp, '$1' + snip + boldIdentifier + '$2' + snip + '$3' ); extract = extract.split( snip ); $.each( extract, function ( index, part ) {          if ( part.indexOf( boldIdentifier ) === 0 ) {               elements.push( $( '' ).text( part.substring( boldIdentifier.length ) ) );           } else {               elements.push( document.createTextNode( part ) );           }       } ); return elements; };  /**    * Removes content in parentheses from a string. Returns the original * string as is if the parentheses are unbalanced or out or order. Does not * remove extra spaces. *   * @method removeParensFromText * @param {String} string * @return {String} */  artblue.removeParensFromText = function ( string ) { var ch, newString = '', level = 0, i = 0; for( i; i < string.length; i++ ) { ch = string.charAt( i ); if ( ch === ')' && level === 0 ) {               return string;           }           if ( ch === '(' ) { level++; continue; } else if ( ch === ')' ) {              level--;               continue;           }           if ( level === 0 ) {               // Remove leading spaces before brackets               if ( ch === ' ' && string.charAt( i + 1 ) === '(' ) { continue; }              newString += ch; }      }       return ( level === 0 ) ? newString : string; };  /**    * 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. *   * @method createSVGTag * @param {String} tag * @return {Object} */  artblue.createSVGTag = function ( tag ) { return document.createElementNS( 'http://www.w3.org/2000/svg', tag ); };  /**    * 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. *   * @method createThumbnail * @param {Object} thumbnail * @param {boolean} tall * @return {Object} jQuery DOM element of the thumbnail */  artblue.createThumbnail = function ( thumbnail, tall ) { var svg = mw.popups.supportsSVG; if (          // No thumbnail           !thumbnail ||           // Image too small for landscape display           ( !tall && thumbnail.width < artblue.SIZES.landscapeImage.w ) ||           // Image too small for protrait display           ( tall && thumbnail.height < artblue.SIZES.portraitImage.h ) ||           // These characters in URL that could inject CSS and thus JS           ( thumbnail.source.indexOf( '\\' ) > -1 || thumbnail.source.indexOf( '\'' ) > -1 || thumbnail.source.indexOf( '\"' ) > -1          )       ) {           return $( ' ' );       }       if ( tall && svg ) {           return artblue.createSvgImageThumbnail(               'mwe-popups-is-not-tall',               thumbnail.source,               ( thumbnail.width > artblue.SIZES.portraitImage.w ) ?                       ( ( thumbnail.width - artblue.SIZES.portraitImage.w ) / -2 ) :                       ( artblue.SIZES.portraitImage.w - thumbnail.width ),               ( thumbnail.height > artblue.SIZES.portraitImage.h ) ?                       ( ( thumbnail.height - artblue.SIZES.portraitImage.h ) / -2 ) :                       0,               thumbnail.width,               thumbnail.height,               artblue.SIZES.portraitImage.w,               artblue.SIZES.portraitImage.h           );       }       if ( tall && !svg ) {           return artblue.createImgThumbnail( 'mwe-popups-is-tall', thumbnail.source ); }      if ( !tall && svg ) { return artblue.createSvgImageThumbnail(              'mwe-popups-is-not-tall',               thumbnail.source,               0,               ( thumbnail.height > artblue.SIZES.landscapeImage.h ) ?                       ( ( thumbnail.height - artblue.SIZES.landscapeImage.h ) / -2 ) :                       0,               thumbnail.width,               thumbnail.height,               artblue.SIZES.landscapeImage.w + 3,               ( thumbnail.height > artblue.SIZES.landscapeImage.h ) ?                       artblue.SIZES.landscapeImage.h :                       thumbnail.height,               'mwe-popups-mask'           ); }      if ( !tall && !svg ) { return artblue.createImgThumbnail( 'mwe-popups-is-not-tall', thumbnail.source ); }  };   /**    * Returns the `svg:image` object for thumbnail *   * @method createSvgImageThumbnail * @param {String} className * @param {String} url * @param {Number} x   * @param {Number} y    * @param {Number} thumbnailWidth * @param {Number} thumbnailHeight * @param {Number} width * @param {Number} height * @param {String} clipPath * @return {jQuery} */  artblue.createSvgImageThumbnail = function (       className, url, x, y, thumbnailWidth, thumbnailHeight, width, height, clipPath   ) { var $thumbnailSVGImage, $thumbnail; $thumbnailSVGImage = $( artblue.createSVGTag( 'image' ) ); $thumbnailSVGImage .addClass( className ) .attr( {              'xlink:href': url,               x: x,               y: y,               width: thumbnailWidth,               height: thumbnailHeight,               'clip-path': 'url(#' + clipPath + ')'           } ); $thumbnail = $( ' ' ) .attr( {              xmlns: 'http://www.w3.org/2000/svg',               width: width,               height: height           } ) .append( $thumbnailSVGImage ); return $thumbnail; };  /**    * Returns the `img` object for thumbnail *   * @method createImgThumbnail * @param {String} className * @param {String} url * @return {jQuery} */  artblue.createImgThumbnail = function ( className, url ) { return $( ' ' ) .addClass( className ) .css( 'background-image', 'url(' + url + ')' ); };  /**    * Positions the popup based on the mouse position and popup size * Default popup positioning is below and to the right of the mouse or link, * unless flippedX or flippedY is true. flippedX and flippedY are cached. *   * @method getOffset * @param {jQuery} link * @param {Object} event * @return {Object} This can be passed to `.css` to position the element */  artblue.getOffset = function ( link, event ) { var href = link.attr( 'href' ), flippedX = false, flippedY = false, settings = mw.popups.render.cache[ href ].settings, offsetTop = ( event.pageY ) ? // If it was a mouse event // Position according to mouse event.pageY + 20 : // Position according to link position or size link.offset.top + link.height + 9, clientTop = ( event.clientY ) ? event.clientY : offsetTop, offsetLeft = ( event.pageX ) ? event.pageX : link.offset.left; // X Flip if ( offsetLeft > ( $( window ).width / 2 ) ) { offsetLeft += ( !event.pageX ) ? link.width : 0; offsetLeft -= ( !settings.tall ) ? artblue.SIZES.portraitPopupWidth : artblue.SIZES.landscapePopupWidth; flippedX = true; }      if ( event.pageX ) { offsetLeft += ( flippedX ) ? 20 : -20;      }       mw.popups.render.cache[ href ].settings.flippedX = flippedX; // Y Flip if ( clientTop > ( $( window ).height / 2 ) ) { flippedY = true; }      if ( event.pageY && flippedY ) { offsetTop += 30; }      mw.popups.render.cache[ href ].settings.flippedY = flippedY; return { top: offsetTop + 'px', left: offsetLeft + 'px' };  };   /**    * Returns an array of classes based on the size and setting of the popup *   * @method getClassses * @param {jQuery} link * @return {Array} List of classes to applied to the parent `div` */  artblue.getClasses = function ( link ) { var classes = [], cache = mw.popups.render.cache [ link.attr( 'href' ) ], tall = cache.settings.tall, thumbnail = cache.settings.thumbnail, flippedY = cache.settings.flippedY, flippedX = cache.settings.flippedX; if ( flippedY ) { classes.push( 'mwe-popups-fade-in-down' ); } else { classes.push( 'mwe-popups-fade-in-up' ); }      if ( flippedY && flippedX ) { classes.push( 'flipped_x_y' ); }      if ( flippedY && !flippedX ) { classes.push( 'flipped_y' ); }      if ( flippedX && !flippedY ) { classes.push( 'flipped_x' ); }      if ( ( !thumbnail || tall ) && !flippedY ) { classes.push( 'mwe-popups-no-image-tri' ); }      if ( ( thumbnail && !tall ) && !flippedY ) { classes.push( 'mwe-popups-image-tri' ); }      if ( tall ) { classes.push( 'mwe-popups-is-tall' ); } else { classes.push( 'mwe-popups-is-not-tall' ); }      return classes; };  /**    * Processed the popup div after it has been displayed * to correctly render the triangle/pokeys *   * @method processPopups * @param {jQuery} link */  artblue.processPopup = function ( link ) { var svg = mw.popups.supportsSVG, cache = mw.popups.render.cache [ link.attr( 'href' ) ], popup = mw.popups.$popup, tall = cache.settings.tall, thumbnail = cache.settings.thumbnail, flippedY = cache.settings.flippedY, flippedX = cache.settings.flippedX; popup.find( '.mwe-popups-settings-icon' ).click( function {           mw.popups.settings.open;       } ); if ( !flippedY && !tall && cache.settings.thumbnail.height < artblue.SIZES.landscapeImage.h ) { $( '.mwe-popups-extract').css(              'margin-top',               cache.settings.thumbnail.height - artblue.SIZES.pokeySize           ); }      if ( !svg && flippedY && !tall ) { $( '.mwe-popups-extract' ).css( 'margin-top', '206px' ); }      if ( flippedY ) { popup.css( {              top: popup.offset.top - ( popup.outerHeight + 50 )           } ); }      if ( flippedY && thumbnail && svg ) { mw.popups.$popup .find( 'image' )[ 0 ] .setAttribute( 'clip-path', '' ); }      if ( flippedY && flippedX && thumbnail && tall && svg ) { mw.popups.$popup .find( 'image' )[ 0 ] .setAttribute( 'clip-path', 'url(#mwe-popups-landscape-mask-flip)' ); }      if ( flippedX && !flippedY && thumbnail && !tall && svg ) { mw.popups.$popup .find( 'image' )[ 0 ] .setAttribute( 'clip-path', 'url(#mwe-popups-mask-flip)' ); }      if ( flippedX && !flippedY && thumbnail && tall && svg ) { mw.popups.$popup .removeClass( 'mwe-popups-no-image-tri' ) .find( 'image' )[ 0 ] .setAttribute( 'clip-path', 'url(#mwe-popups-landscape-mask)' ); }  };	// register custom renderer mw.popups.render.renderers.artblue = artblue; });