/** * Module containing presentation logic for the revision pointer lines * * @class PointerLine * @param {Pointer} pointer * @param {string} name * @constructor */ function PointerLine( pointer, name ) { this.pointer = pointer; this.name = name; } $.extend( PointerLine.prototype, { /** * @type {string} */ name: '', /** * @type {Pointer} */ pointer: null, /** * @type {jQuery} */ $html: null, /** * Calculate the relative distance in between the given pointer and column * * @private * @param {jQuery} $sourcePointer * @param {jQuery} $targetColumn * @return {number} distance between the given elements */ calculateDistance: function ( $sourcePointer, $targetColumn ) { return ( $targetColumn.offset().left + $targetColumn.width() / 2 ) - ( $sourcePointer.offset().left + ( $sourcePointer.width() ) / 2 ); }, /** * Calculate and set line's width and position with the given pointer and column * * @private * @param {jQuery} $sourcePointer * @param {jQuery} $targetColumn */ setCssProperties: function ( $sourcePointer, $targetColumn ) { const distance = this.calculateDistance( $sourcePointer, $targetColumn ); const widthToSet = Math.abs( distance ); let leftToSet = ( $targetColumn.offset().left + $targetColumn.width() / 2 ) - $( '.mw-revslider-revision-slider' ).offset().left; if ( distance > 0 ) { // targetColumn is right relative to sourcePointer leftToSet -= widthToSet; leftToSet -= 1; } else { // targetColumn is left relative to sourcePointer leftToSet += 1; } this.$html.css( { width: widthToSet + 'px', left: leftToSet + 'px' } ); }, /** * Check if the target column is located right form the source pointer * * @private * @param {jQuery} $sourcePointer * @param {jQuery} $targetColumn * @return {boolean} */ targetColumnIsRightFromPointer: function ( $sourcePointer, $targetColumn ) { return this.calculateDistance( $sourcePointer, $targetColumn ) > 0; }, /** * Draws the line between pointer and column by setting borders, position and width of the line box */ drawLine: function () { const isNewer = this.pointer.getView().isNewerPointer(); const $targetColumn = $( isNewer ? '.diff-ntitle' : '.diff-otitle' ); // don't draw lines when the diff view is not as expected or offset not available if ( !$targetColumn.length || !$targetColumn.offset() ) { return; } const $upperLineDiv = this.$html.find( '.mw-revslider-pointer-line-upper' ), $lowerLineDiv = this.$html.find( '.mw-revslider-pointer-line-lower' ), $underline = this.$html.find( '.mw-revslider-pointer-line-underline' ), $sourcePointer = this.pointer.getView().getElement(); $lowerLineDiv.add( $upperLineDiv ).add( $underline ) .toggleClass( 'mw-revslider-lower-color', !isNewer ) .toggleClass( 'mw-revslider-upper-color', isNewer ); this.setCssProperties( $sourcePointer, $targetColumn ); const columnWidth = $targetColumn.width(); $upperLineDiv.addClass( 'mw-revslider-bottom-line' ); $underline.css( 'width', columnWidth + 'px' ); if ( this.targetColumnIsRightFromPointer( $sourcePointer, $targetColumn ) ) { $upperLineDiv.addClass( 'mw-revslider-left-line' ); $lowerLineDiv.addClass( 'mw-revslider-right-line' ); $underline.css( { 'margin-right': -columnWidth / 2 + 'px', 'margin-left': 0, float: 'right' } ); } else { $upperLineDiv.addClass( 'mw-revslider-right-line' ); $lowerLineDiv.addClass( 'mw-revslider-left-line' ); $underline.css( { 'margin-left': -columnWidth / 2 + 'px', 'margin-right': 0, float: 'left' } ); } }, /** * Initializes the DOM element with the line-box for drawing the lines */ initialize: function () { // eslint-disable-next-line mediawiki/class-doc this.$html = $( '<div>' ) .addClass( 'mw-revslider-pointer-line ' + this.name ) .append( // eslint-disable-next-line mediawiki/class-doc $( '<div>' ).addClass( 'mw-revslider-pointer-line-upper ' + this.name ), // eslint-disable-next-line mediawiki/class-doc $( '<div>' ).addClass( 'mw-revslider-pointer-line-lower ' + this.name ), // eslint-disable-next-line mediawiki/class-doc $( '<div>' ).addClass( 'mw-revslider-pointer-line-underline ' + this.name ) ); }, /** * Adds colored top-borders for the diff columns fitting the line colors between pointers and columns * * @param {boolean} [show=true] * @private */ addColoredColumnBorders: function ( show ) { show = show !== false; $( '#mw-diff-otitle1' ).toggleClass( 'mw-revslider-older-diff-column', show ); $( '#mw-diff-ntitle1' ).toggleClass( 'mw-revslider-newer-diff-column', show ); }, /** * Remove colored top-borders for the diff columns fitting the line colors between pointers and columns * * @private */ removeColoredColumnBorders: function () { this.addColoredColumnBorders( false ); }, /** * Sets the hooks to draw the column borders * * @private */ setColumnBorderHooks: function () { mw.hook( 'wikipage.diff' ).add( this.addColoredColumnBorders ); mw.hook( 'revslider.expand' ).add( this.addColoredColumnBorders ); mw.hook( 'revslider.collapse' ).add( this.removeColoredColumnBorders ); }, /** * @return {jQuery} */ render: function () { this.initialize(); this.setColumnBorderHooks(); return this.getElement(); }, /** * @return {jQuery} */ getElement: function () { return this.$html; } } ); module.exports = PointerLine;