mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/MultimediaViewer
synced 2024-12-12 16:25:10 +00:00
a10359e6e6
This requires MediaWiki 1.38 for mw.util.throttle. Bug: T213426 Change-Id: I3f689eea837ef72de9ab7afb68578093eab8db20
244 lines
7.8 KiB
JavaScript
244 lines
7.8 KiB
JavaScript
/*
|
|
* This file is part of the MediaWiki extension MultimediaViewer.
|
|
*
|
|
* MultimediaViewer is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* MultimediaViewer is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with MultimediaViewer. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
( function () {
|
|
var TTFP;
|
|
|
|
/**
|
|
* Represents any text field that might need to be truncated to be readable. Text will be adjusted to
|
|
* fit into its container.
|
|
*
|
|
* More specifically, TruncatableTextField should be invoked with a fixed-height container as the first
|
|
* parameter and a flexible-width content (which gets its size from the text inside it) as the second
|
|
* one. The container gets overflow: hidden, and the content is placed inside it; if the content
|
|
* overflows the container, TruncatableTextField will cycle through a set of styles and apply to the
|
|
* container the first one that makes the content not overflow anymore. If none of the styles do that,
|
|
* the last one is applied anyway.
|
|
*
|
|
* The list of styles can be customized; by default, they set progressively smaller font size, and the
|
|
* last one adds an ellipsis to the end. (An ellipsis element is automatically appended to the end of
|
|
* the container to help with this, but it is hidden unless made visible by one of the styles.)
|
|
*
|
|
* grow() and shrink() can be used to show full text (by making the container flexible-height) and hiding
|
|
* them again; TruncatableTextField will not call them automatically (the caller class should e.g. set up
|
|
* a click handler on the ellipsis).
|
|
*
|
|
* repaint() should be called after layout changes to keep the truncation accurate.
|
|
*
|
|
* @class mw.mmv.ui.TruncatableTextField
|
|
* @extends mw.mmv.ui.Element
|
|
* @constructor
|
|
* @param {jQuery} $container The container for the element.
|
|
* @param {jQuery} $element The element where we should put the text.
|
|
* @param {Object} [options]
|
|
* @param {string[]} [options.styles] a list of styles to try if the text does not fit into the container.
|
|
* Will stop at the first which makes the text fit; the last one will be used even if it does not make
|
|
* the text fit.
|
|
*/
|
|
function TruncatableTextField( $container, $element, options ) {
|
|
mw.mmv.ui.Element.call( this, $container );
|
|
|
|
/** @property {jQuery} $element The DOM element that holds text for this element. */
|
|
this.$element = $element;
|
|
|
|
/** @property {Object} options - */
|
|
this.options = $.extend( {}, this.defaultOptions, options );
|
|
|
|
/** @property {boolean} expanded true if the text is long enough to be truncated but the full text is shown */
|
|
this.expanded = false;
|
|
|
|
/** @property {jQuery} ellipsis the element which marks that the text was truncated */
|
|
this.$ellipsis = null;
|
|
|
|
/** @property {string} normalTitle title attribute to show when the text is not truncated */
|
|
this.normalTitle = null;
|
|
|
|
/** @property {string} truncatedTitle title attribute to show when the text is not truncated */
|
|
this.truncatedTitle = null;
|
|
|
|
/** @property {mw.mmv.HtmlUtils} htmlUtils Our HTML utility instance. */
|
|
this.htmlUtils = new mw.mmv.HtmlUtils();
|
|
|
|
this.init();
|
|
}
|
|
|
|
OO.inheritClass( TruncatableTextField, mw.mmv.ui.Element );
|
|
|
|
TTFP = TruncatableTextField.prototype;
|
|
|
|
/**
|
|
* Default options
|
|
*
|
|
* @property {Object} defaultOptions
|
|
*/
|
|
TTFP.defaultOptions = {
|
|
styles: [ 'mw-mmv-ttf-small', 'mw-mmv-ttf-smaller', 'mw-mmv-ttf-smallest' ]
|
|
};
|
|
|
|
/**
|
|
* Initializes the DOM.
|
|
*
|
|
* @private
|
|
*/
|
|
TTFP.init = function () {
|
|
this.$ellipsis = $( '<span>' )
|
|
.text( '…' )
|
|
.hide()
|
|
.addClass( 'mw-mmv-ttf-ellipsis' );
|
|
|
|
this.$container
|
|
.addClass( 'mw-mmv-ttf-container empty' )
|
|
.append( this.$element, this.$ellipsis );
|
|
};
|
|
|
|
TTFP.attach = function () {
|
|
$( window ).on( 'resize.mmv-ttf', mw.util.debounce( this.repaint.bind( this ), 100 ) );
|
|
};
|
|
|
|
TTFP.unattach = function () {
|
|
$( window ).off( 'resize.mmv-ttf' );
|
|
};
|
|
|
|
/**
|
|
* Sets the string for the element.
|
|
*
|
|
* @param {string} value Warning - unsafe HTML is allowed here.
|
|
*/
|
|
TTFP.set = function ( value ) {
|
|
this.$element.empty().append( this.htmlUtils.htmlToTextWithTags( value ) );
|
|
this.changeStyle();
|
|
this.$container.toggleClass( 'empty', !value );
|
|
this.$ellipsis.hide();
|
|
this.shrink();
|
|
};
|
|
|
|
TTFP.empty = function () {
|
|
this.$element.empty();
|
|
// eslint-disable-next-line mediawiki/class-doc
|
|
this.$container
|
|
.removeClass( this.options.styles.concat( [ 'mw-mmv-ttf-untruncated', 'mw-mmv-ttf-truncated' ] ) )
|
|
.addClass( 'empty' );
|
|
this.$ellipsis.hide();
|
|
this.setTitle( '', '' );
|
|
this.expanded = false;
|
|
};
|
|
|
|
/**
|
|
* Recalculate truncation after layout changes (such as resize)
|
|
*/
|
|
TTFP.repaint = function () {
|
|
this.changeStyle();
|
|
this.$ellipsis.hide();
|
|
this.shrink();
|
|
};
|
|
|
|
/**
|
|
* Allows setting different titles for fully visible and for truncated text.
|
|
*
|
|
* @param {string} normal
|
|
* @param {string} truncated
|
|
*/
|
|
TTFP.setTitle = function ( normal, truncated ) {
|
|
this.normalTitle = normal;
|
|
this.truncatedTitle = truncated;
|
|
this.updateTitle();
|
|
};
|
|
|
|
/**
|
|
* Selects the right title to use (for full or for truncated version). The title can be set with setTitle().
|
|
*/
|
|
TTFP.updateTitle = function () {
|
|
var $elementsWithTitle = this.$element.add( this.$ellipsis );
|
|
$elementsWithTitle.attr( 'original-title', this.isTruncated() ? this.truncatedTitle : this.normalTitle );
|
|
};
|
|
|
|
/**
|
|
* Returns true if the text is long enough that it needs to be truncated.
|
|
*
|
|
* @return {boolean}
|
|
*/
|
|
TTFP.isTruncatable = function () {
|
|
// height calculation logic does not work for expanded state since the container expands
|
|
// to envelop the element, but we never go into expanded state for non-truncatable elements anyway
|
|
return this.$container.height() < this.$element.height() || this.expanded;
|
|
};
|
|
|
|
/**
|
|
* Returns true if the text is truncated at the moment.
|
|
*
|
|
* @return {boolean}
|
|
*/
|
|
TTFP.isTruncated = function () {
|
|
return this.isTruncatable() && !this.expanded;
|
|
};
|
|
|
|
/**
|
|
* Makes the container fixed-width, clipping the text.
|
|
* This will only add a .mw-mmv-ttf-truncated class; it's the caller's responsibility to define the fixed
|
|
* height for that class.
|
|
*/
|
|
TTFP.shrink = function () {
|
|
if ( this.isTruncatable() ) {
|
|
this.expanded = false;
|
|
this.$container.addClass( 'mw-mmv-ttf-truncated' ).removeClass( 'mw-mmv-ttf-untruncated' );
|
|
this.$ellipsis.show();
|
|
this.updateTitle();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Makes the container flexible-width, thereby restoring the full text.
|
|
*/
|
|
TTFP.grow = function () {
|
|
if ( this.isTruncatable() ) {
|
|
this.expanded = true;
|
|
this.$container.removeClass( 'mw-mmv-ttf-truncated' ).addClass( 'mw-mmv-ttf-untruncated' );
|
|
this.$ellipsis.hide();
|
|
this.updateTitle();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Changes the element style if a certain length is reached.
|
|
*/
|
|
TTFP.changeStyle = function () {
|
|
var oldClass,
|
|
newClass = 'mw-mmv-ttf-normal',
|
|
field = this;
|
|
|
|
// eslint-disable-next-line mediawiki/class-doc
|
|
this.$container
|
|
.removeClass( this.options.styles.concat( [ 'mw-mmv-ttf-untruncated', 'mw-mmv-ttf-truncated' ] ) )
|
|
.addClass( newClass );
|
|
this.expanded = false;
|
|
|
|
// eslint-disable-next-line no-jquery/no-each-util
|
|
$.each( this.options.styles, function ( k, v ) {
|
|
if ( !field.isTruncatable() ) {
|
|
return false;
|
|
}
|
|
|
|
oldClass = newClass;
|
|
newClass = v;
|
|
// eslint-disable-next-line mediawiki/class-doc
|
|
field.$container.removeClass( oldClass ).addClass( newClass );
|
|
} );
|
|
};
|
|
|
|
mw.mmv.ui.TruncatableTextField = TruncatableTextField;
|
|
}() );
|