mediawiki-extensions-Visual.../modules/ve-mw/ui/elements/ve.ui.MWExpandableContentElement.js
Thiemo Kreuz 224e73d91b Minor performance improvement for collapsible template docs
I benchmarked the template dialog before and after the change made in
I0f35a19 with a large 200 part multi-part template. I measured only
the time spend in .updateSize().
Before I0f35a19: 3.6s
After: 4.6s
With this small fix here: 3.6s

Bug: T309875
Change-Id: I2c2892e173ba70c746fb71624c65b7f4ffde4419
2022-06-14 16:04:27 +02:00

146 lines
3.7 KiB
JavaScript

/**
* Container for textual elements, which should be collapsed to one line by default.
*
* A "more / less" button is used to toggle additional lines.
*
* @class
* @extends OO.ui.Element
* @mixins OO.EventEmitter
*
* @constructor
* @param {Object} config
* @cfg {jQuery} $content
*/
ve.ui.MWExpandableContentElement = function VeUiMWExpandableContentElement( config ) {
// Parent constructor
ve.ui.MWExpandableContentElement.super.call( this, config );
// Mixin constructors
OO.EventEmitter.call( this );
this.$content = config.$content;
this.collapsed = true;
this.toggle( false );
};
/* Inheritance */
OO.inheritClass( ve.ui.MWExpandableContentElement, OO.ui.Element );
OO.mixinClass( ve.ui.MWExpandableContentElement, OO.EventEmitter );
/* Methods */
/**
* @private
* @return {number}
*/
ve.ui.MWExpandableContentElement.prototype.getLineHeight = function () {
return parseInt( this.$content.css( 'line-height' ) );
};
/**
* @private
* @return {number}
*/
ve.ui.MWExpandableContentElement.prototype.getTextHeight = function () {
var currentHeight = this.$content.height(),
expandedHeight = this.$content.css( 'height', 'auto' ).height();
if ( expandedHeight !== currentHeight ) {
this.$content.css( { height: currentHeight } );
}
return expandedHeight;
};
/**
* @private
*/
ve.ui.MWExpandableContentElement.prototype.makeCollapsible = function () {
this.button = new OO.ui.ButtonWidget( {
framed: false,
flags: [ 'progressive' ],
label: ve.msg( 'visualeditor-expandable-more' ),
classes: [ 've-ui-expandableContent-toggle' ],
invisibleLabel: ve.ui.MWTransclusionDialog.static.isSmallScreen(),
icon: 'expand'
} ).on( 'click', this.onButtonClick.bind( this ) );
this.$content.on( 'click', this.onDescriptionClick.bind( this ) )
.addClass( 've-ui-expandableContent-collapsible' );
this.$container = $( '<div>' )
.addClass( 've-ui-expandableContent-container' )
.append(
$( '<div>' )
.addClass( 've-ui-expandableContent-fade' )
)
.append( this.button.$element )
.appendTo( this.$element );
};
/**
* @private
* @param {boolean} collapse
*/
ve.ui.MWExpandableContentElement.prototype.collapse = function ( collapse ) {
var collapsedHeight = this.getLineHeight();
if ( collapse ) {
this.button.setLabel( ve.msg( 'visualeditor-expandable-more' ) );
this.$content.css( { height: collapsedHeight } );
this.button.setIcon( 'expand' );
} else {
this.button.setLabel( ve.msg( 'visualeditor-expandable-less' ) );
this.$content.css( 'height', this.getTextHeight() + this.button.$element.height() );
this.button.setIcon( 'collapse' );
}
this.$container.removeClass( 'oo-ui-element-hidden' );
this.$container.height( collapsedHeight );
this.button.setInvisibleLabel( ve.ui.MWTransclusionDialog.static.isSmallScreen() );
};
/**
* @private
*/
ve.ui.MWExpandableContentElement.prototype.reset = function () {
this.$content.css( 'height', 'auto' );
this.$container.addClass( 'oo-ui-element-hidden' );
this.button.setInvisibleLabel( false );
};
/**
* @private
*/
ve.ui.MWExpandableContentElement.prototype.onButtonClick = function () {
this.collapse( !this.collapsed );
this.collapsed = !this.collapsed;
};
/**
* @private
*/
ve.ui.MWExpandableContentElement.prototype.onDescriptionClick = function () {
if ( this.button.invisibleLabel ) {
// Don't toggle the description if the user is trying to select the text.
if ( window.getSelection().toString() === '' ) {
this.onButtonClick();
}
}
};
ve.ui.MWExpandableContentElement.prototype.updateSize = function () {
this.toggle( true );
if ( this.getTextHeight() / this.getLineHeight() >= 3 ) {
if ( !this.$container ) {
this.makeCollapsible();
}
this.collapse( this.collapsed );
} else {
if ( this.$container ) {
this.reset();
}
}
};