Файловый менеджер - Редактировать - /var/www/html/mediawiki-1.43.1/extensions/MultimediaViewer/resources/mmv/ui/mmv.ui.metadataPanel.js
Ðазад
/* * 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/>. */ const HtmlUtils = require( '../mmv.HtmlUtils.js' ); const Description = require( './mmv.ui.description.js' ); const UiElement = require( './mmv.ui.js' ); const MetadataPanelScroller = require( './mmv.ui.metadataPanelScroller.js' ); const Permission = require( './mmv.ui.permission.js' ); const ProgressBar = require( './mmv.ui.progressBar.js' ); const StripeButtons = require( './mmv.ui.stripeButtons.js' ); const TruncatableTextField = require( './mmv.ui.truncatableTextField.js' ); /** * Represents the metadata panel in the viewer */ class MetadataPanel extends UiElement { /** * @param {jQuery} $container The container for the panel (.mw-mmv-post-image). * @param {jQuery} $aboveFold The brighter headline of the metadata panel (.mw-mmv-above-fold). * Called "aboveFold" for historical reasons, but actually a part of the next sibling of the element * is also above the fold (bottom of the screen). */ constructor( $container, $aboveFold ) { super( $container ); this.$aboveFold = $aboveFold; this.initializeHeader(); this.initializeImageMetadata(); } /** * FIXME this should be in the jquery.fullscreen plugin. * * @return {boolean} */ isFullscreened() { return $( this.$container ).closest( '.jq-fullscreened' ).length > 0; } attach() { this.scroller.attach(); this.buttons.attach(); this.title.attach(); this.creditField.attach(); this.$title .add( this.$authorAndSource ) .add( this.title.$ellipsis ) .add( this.creditField.$ellipsis ) .on( 'click.mmv-mp', ( e ) => { const clickTargetIsLink = $( e.target ).is( 'a' ); const clickTargetIsTruncated = !!$( e.target ).closest( '.mw-mmv-ttf-truncated' ).length; const someTextIsExpanded = !!$( e.target ).closest( '.mw-mmv-untruncated' ).length; if ( !clickTargetIsLink && // don't interfere with clicks on links in the text clickTargetIsTruncated && // don't expand when non-truncated text is clicked !someTextIsExpanded // ignore clicks if text is already expanded ) { if ( this.isFullscreened() ) { this.revealTruncatedText(); } else { this.scroller.toggle( 'up' ); } } } ); $( this.$container ).on( 'mmv-metadata-open.mmv-mp mmv-metadata-reveal-truncated-text.mmv-mp', () => { this.revealTruncatedText(); } ).on( 'mmv-metadata-close.mmv-mp', () => { this.hideTruncatedText(); } ).on( 'mouseleave.mmv-mp', () => { if ( this.isFullscreened() ) { const duration = parseFloat( this.$container.css( 'transition-duration' ) ) * 1000 || 0; this.panelShrinkTimeout = setTimeout( () => { this.hideTruncatedText(); }, duration ); } } ).on( 'mouseenter.mmv-mp', () => { clearTimeout( this.panelShrinkTimeout ); } ).on( 'mmv-permission-grow.mmv-mp', () => { this.$permissionLink .text( mw.msg( 'multimediaviewer-permission-link-hide' ) ); } ).on( 'mmv-permission-shrink.mmv-mp', () => { this.$permissionLink .text( mw.msg( 'multimediaviewer-permission-link' ) ); } ); this.handleEvent( 'fullscreenchange.lip', () => { this.hideTruncatedText(); } ); } unattach() { this.scroller.freezeHeight(); this.$title .add( this.title.$ellipsis ) .add( this.$authorAndSource ) .add( this.creditField.$ellipsis ) .off( 'click.mmv-mp' ); $( this.$container ).off( '.mmv-mp' ); this.scroller.unattach(); this.buttons.unattach(); this.clearEvents(); } empty() { this.scroller.freezeHeight(); this.scroller.empty(); this.buttons.empty(); this.description.empty(); this.permission.empty(); this.$title.removeClass( 'error' ); this.title.empty(); this.creditField.empty(); this.$license.empty().prop( 'href', '#' ); this.$licenseLi.addClass( 'empty' ); this.$permissionLink.hide(); this.$restrictions.children().hide(); this.$filename.empty(); this.$filenamePrefix.empty(); this.$filenameLi.addClass( 'empty' ); this.$datetimeCreated.empty(); this.$datetimeCreatedLi.addClass( 'empty' ); this.$datetimeUpdated.empty(); this.$datetimeUpdatedLi.addClass( 'empty' ); this.$location.empty(); this.$locationLi.addClass( 'empty' ); this.progressBar.empty(); this.$container.removeClass( 'mw-mmv-untruncated' ); } /* Initialization methods */ /** * Initializes the header, which contains the title, credit, and license elements. */ initializeHeader() { this.progressBar = new ProgressBar( this.$aboveFold ); this.scroller = new MetadataPanelScroller( this.$container, this.$aboveFold ); this.$titleDiv = $( '<div>' ) .addClass( 'mw-mmv-title-contain' ) .appendTo( this.$aboveFold ); this.$container.append( this.$aboveFold ); this.initializeButtons(); // float, needs to be on top this.initializeTitle(); } /** * Initializes the title elements. */ initializeTitle() { this.$titlePara = $( '<p>' ) .addClass( 'mw-mmv-title-para mw-parser-output' ) .appendTo( this.$aboveFold ); this.$title = $( '<span>' ) .addClass( 'mw-mmv-title' ); this.title = new TruncatableTextField( this.$titlePara, this.$title, { styles: [ 'mw-mmv-title-small', 'mw-mmv-title-smaller' ] } ); this.title.setTitle( mw.message( 'multimediaviewer-title-popup-text' ), mw.message( 'multimediaviewer-title-popup-text-more' ) ); this.$title.add( this.title.$ellipsis ); } initializeButtons() { this.buttons = new StripeButtons( this.$titleDiv ); } /** * Initializes the main body of metadata elements. */ initializeImageMetadata() { this.$container.addClass( 'mw-mmv-ttf-ellipsis-container' ); this.$imageMetadata = $( '<div>' ) .addClass( 'mw-mmv-image-metadata' ) .appendTo( this.$container ); this.$imageMetadataLeft = $( '<div>' ) .addClass( 'mw-mmv-image-metadata-column mw-mmv-image-metadata-desc-column' ) .appendTo( this.$imageMetadata ); this.$imageMetadataRight = $( '<div>' ) .addClass( 'mw-mmv-image-metadata-column mw-mmv-image-metadata-links-column' ) .appendTo( this.$imageMetadata ); this.initializeCredit(); this.description = new Description( this.$imageMetadataLeft ); this.permission = new Permission( this.$imageMetadataLeft, this.scroller ); this.initializeImageLinks(); } /** * Initializes the credit elements. */ initializeCredit() { this.$credit = $( '<p>' ) .addClass( 'mw-mmv-credit empty' ) .appendTo( this.$imageMetadataLeft ); // we need an inline container for tipsy, otherwise it would be centered weirdly this.$authorAndSource = $( '<span>' ) .addClass( 'mw-mmv-source-author' ); this.creditField = new TruncatableTextField( this.$credit, this.$authorAndSource, { styles: [] } ); this.creditField.setTitle( mw.message( 'multimediaviewer-credit-popup-text' ), mw.message( 'multimediaviewer-credit-popup-text-more' ) ); this.$authorAndSource.add( this.creditField.$ellipsis ); } /** * Initializes the list of image metadata on the right side of the panel. */ initializeImageLinks() { this.$imageLinkDiv = $( '<div>' ) .addClass( 'mw-mmv-image-links-div' ) .appendTo( this.$imageMetadataRight ); this.$imageLinks = $( '<ul>' ) .addClass( 'mw-mmv-image-links' ) .appendTo( this.$imageLinkDiv ); this.initializeLicense(); this.initializeFilename(); this.initializeDatetime(); this.initializeLocation(); } /** * Initializes the license elements. */ initializeLicense() { this.$licenseLi = $( '<li>' ) .addClass( 'mw-mmv-license-li empty' ) .appendTo( this.$imageLinks ); this.$license = $( '<a>' ) .addClass( 'mw-mmv-license' ) .prop( 'href', '#' ) .appendTo( this.$licenseLi ); this.$restrictions = $( '<span>' ) .addClass( 'mw-mmv-restrictions' ) .appendTo( this.$licenseLi ); this.$permissionLink = $( '<span>' ) .addClass( 'mw-mmv-permission-link mw-mmv-label' ) .text( mw.msg( 'multimediaviewer-permission-link' ) ) .appendTo( this.$licenseLi ) .hide() .on( 'click', () => { if ( this.permission.isFullSize() ) { this.permission.shrink(); } else { this.permission.grow(); this.scroller.toggle( 'up' ); } return false; } ); } /** * Initializes the filename element. */ initializeFilename() { this.$filenameLi = $( '<li>' ) .addClass( 'mw-mmv-filename-li empty' ) .appendTo( this.$imageLinks ); this.$filenamePrefix = $( '<span>' ) .addClass( 'mw-mmv-filename-prefix' ) .appendTo( this.$filenameLi ); this.$filename = $( '<span>' ) .addClass( 'mw-mmv-filename' ) .appendTo( this.$filenameLi ); } /** * Initializes the upload date/time element. */ initializeDatetime() { this.$datetimeCreatedLi = $( '<li>' ) .addClass( 'mw-mmv-datetime-li empty' ) .appendTo( this.$imageLinks ); this.$datetimeCreated = $( '<span>' ) .addClass( 'mw-mmv-datetime' ) .appendTo( this.$datetimeCreatedLi ); this.$datetimeUpdatedLi = $( '<li>' ) .addClass( 'mw-mmv-datetime-li empty' ) .appendTo( this.$imageLinks ); this.$datetimeUpdated = $( '<span>' ) .addClass( 'mw-mmv-datetime' ) .appendTo( this.$datetimeUpdatedLi ); } /** * Initializes the geolocation element. */ initializeLocation() { this.$locationLi = $( '<li>' ) .addClass( 'mw-mmv-location-li empty' ) .appendTo( this.$imageLinks ); this.$location = $( '<a>' ) .addClass( 'mw-mmv-location' ) .appendTo( this.$locationLi ); } /* Setters */ /** * Sets the image title at the top of the metadata panel. * The title will be the first one available form the options below: * - the image caption * - the description from the filepage * - the filename (without extension) * * @param {LightboxImage} image * @param {ImageModel} imageData */ setTitle( image, imageData ) { let title; if ( image.caption ) { title = image.caption; } else if ( imageData.description ) { title = imageData.description; } else { title = image.filePageTitle.getNameText(); } this.title.set( title ); } /** * Sets the file name in the panel. * * @param {string} filename The file name to set, without prefix */ setFileName( filename ) { this.$filenamePrefix.text( mw.config.get( 'wgFormattedNamespaces' )[ mw.config.get( 'wgNamespaceIds' ).file ] + ':' ); this.$filename.text( filename ); this.$filenameLi.removeClass( 'empty' ); } /** * Set source and author. * * @param {string} attribution Custom attribution string * @param {string} source With unsafe HTML * @param {string} author With unsafe HTML * @param {number} authorCount * @param {string} filepageUrl URL of the file page (used when other data is not available) */ setCredit( attribution, source, author, authorCount, filepageUrl ) { // sanitization will be done by TruncatableTextField.set() if ( attribution && ( authorCount <= 1 || !authorCount ) ) { this.creditField.set( this.wrapAttribution( attribution ) ); } else if ( author && source ) { this.creditField.set( mw.message( 'multimediaviewer-credit', this.wrapAuthor( author, authorCount, filepageUrl ), this.wrapSource( source ) ).plain() ); } else if ( author ) { this.creditField.set( this.wrapAuthor( author, authorCount, filepageUrl ) ); } else if ( source ) { this.creditField.set( this.wrapSource( source ) ); } else { this.creditField.set( $( '<a>' ) .addClass( 'mw-mmv-credit-fallback' ) .prop( 'href', filepageUrl ) .text( mw.message( 'multimediaviewer-credit-fallback' ).plain() ) .get( 0 ).outerHTML ); } this.$credit.removeClass( 'empty' ); } /** * Wraps a source string it with MediaViewer styles * * @param {string} source Warning - unsafe HTML sometimes goes here * @return {string} unsafe HTML */ wrapSource( source ) { return $( '<span>' ) .addClass( 'mw-mmv-source' ) .append( $.parseHTML( source ) ) .get( 0 ).outerHTML; } /** * Wraps an author string with MediaViewer styles * * @param {string} author Warning - unsafe HTML sometimes goes here * @param {number} authorCount * @param {string} filepageUrl URL of the file page (used when some author data is not available) * @return {string} unsafe HTML */ wrapAuthor( author, authorCount, filepageUrl ) { const $wrapper = $( '<span>' ) .addClass( 'mw-mmv-author' ); if ( authorCount > 1 ) { const moreText = HtmlUtils.jqueryToHtml( $( '<a>' ) .addClass( 'mw-mmv-more-authors' ) .text( mw.msg( 'multimediaviewer-multiple-authors', authorCount - 1 ) ) .attr( 'href', filepageUrl ) ); $wrapper.append( mw.msg( 'multimediaviewer-multiple-authors-combine', author, moreText ) ); } else { $wrapper.append( author ); } return $wrapper.get( 0 ).outerHTML; } /** * Wraps an attribution string with MediaViewer styles * * @param {string} attribution Warning - unsafe HTML sometimes goes here * @return {string} unsafe HTML */ wrapAttribution( attribution ) { return $( '<span>' ) .addClass( 'mw-mmv-author' ) .addClass( 'mw-mmv-source' ) .append( $.parseHTML( attribution ) ) .get( 0 ).outerHTML; } /** * Sets the license display in the panel * * @param {License|null} license license data (could be missing) * @param {string} filePageUrl URL of the file description page */ setLicense( license, filePageUrl ) { let shortName; let url; let isCc; let isPd; filePageUrl += `?uselang=${ mw.config.get( 'wgUserLanguage' ) }#${ mw.msg( 'license-header' ) }`; if ( license ) { shortName = license.getShortName(); url = license.deedUrl || filePageUrl; isCc = license.isCc(); isPd = license.isPd(); } else { shortName = mw.msg( 'multimediaviewer-license-default' ); url = filePageUrl; isCc = isPd = false; } this.$license .text( shortName ) .prop( 'href', url ) .prop( 'target', license && license.deedUrl ? '_blank' : '' ); this.$licenseLi .toggleClass( 'cc-license', isCc ) .toggleClass( 'pd-license', isPd ) .removeClass( 'empty' ); } /** * Set an extra permission text which should be displayed. * * @param {string} permission */ setPermission( permission ) { this.$permissionLink.show(); this.permission.set( permission ); } /** * Sets any special restrictions that should be displayed. * * @param {string[]} restrictions Array of restrictions */ setRestrictions( restrictions ) { const restrictionsSet = {}; let showDefault = false; let validRestrictions = 0; restrictions.forEach( ( value, index ) => { // The following messages are used here: // * multimediaviewer-restriction-2257 // * multimediaviewer-restriction-aus-reserve // * multimediaviewer-restriction-communist // * multimediaviewer-restriction-costume // * multimediaviewer-restriction-currency // * multimediaviewer-restriction-design // * multimediaviewer-restriction-fan-art // * multimediaviewer-restriction-ihl // * multimediaviewer-restriction-insignia // * multimediaviewer-restriction-ita-mibac // * multimediaviewer-restriction-nazi // * multimediaviewer-restriction-personality // * multimediaviewer-restriction-trademarked // * multimediaviewer-restriction-default // * multimediaviewer-restriction-default-and-others if ( !mw.message( `multimediaviewer-restriction-${ value }` ).exists() || value === 'default' || index + 1 > MetadataPanel.MAX_RESTRICT ) { showDefault = true; // If the restriction isn't defined or there are more than MAX_RESTRICT of them, show a generic symbol at the end return; } if ( restrictionsSet[ value ] ) { return; // Only show one of each symbol } else { restrictionsSet[ value ] = true; } this.$restrictions.append( this.createRestriction( value ) ); validRestrictions++; // See how many defined restrictions are added so we know which default i18n msg to use } ); if ( showDefault ) { if ( validRestrictions ) { this.$restrictions.append( this.createRestriction( 'default-and-others' ) ); } else { this.$restrictions.append( this.createRestriction( 'default' ) ); } } } /** * Helper function that generates restriction labels * * @param {string} type Restriction type * @return {jQuery} jQuery object of label */ createRestriction( type ) { mw.loader.using( 'mmv.ui.restriction', () => {} ); // for restriction icons const $label = $( '<span>' ) .addClass( 'mw-mmv-label mw-mmv-restriction-label' ) // Messages duplicated from above for linter // * multimediaviewer-restriction-2257 // * multimediaviewer-restriction-aus-reserve // * multimediaviewer-restriction-communist // * multimediaviewer-restriction-costume // * multimediaviewer-restriction-currency // * multimediaviewer-restriction-design // * multimediaviewer-restriction-fan-art // * multimediaviewer-restriction-ihl // * multimediaviewer-restriction-insignia // * multimediaviewer-restriction-ita-mibac // * multimediaviewer-restriction-nazi // * multimediaviewer-restriction-personality // * multimediaviewer-restriction-trademarked // * multimediaviewer-restriction-default // * multimediaviewer-restriction-default-and-others .prop( 'title', mw.msg( `multimediaviewer-restriction-${ type }` ) ); $( '<span>' ) // The following classes are used here: // * mw-mmv-restriction-2257 // * mw-mmv-restriction-aus-reserve // * mw-mmv-restriction-communist // * mw-mmv-restriction-costume // * mw-mmv-restriction-currency // * mw-mmv-restriction-design // * mw-mmv-restriction-fan-art // * mw-mmv-restriction-ihl // * mw-mmv-restriction-insignia // * mw-mmv-restriction-ita-mibac // * mw-mmv-restriction-nazi // * mw-mmv-restriction-personality // * mw-mmv-restriction-trademarked:after // * mw-mmv-restriction-default .addClass( `mw-mmv-restriction-label-inner mw-mmv-restriction-${ type === 'default-and-others' ? 'default' : type }` ) .text( mw.msg( `multimediaviewer-restriction-${ type }` ) ) .appendTo( $label ); return $label; } /** * Sets location data in the interface. * * @param {ImageModel} imageData */ setLocationData( imageData ) { if ( !imageData.hasCoords() ) { return; } /** * Form at latitude or longitude as deg/min/sec array * * @param {number} value latitude or longitude * @return {string[]} formatted deg/min/sec array */ function convertDegMinSec( value ) { value = Math.abs( value ); const deg = Math.floor( value ); value -= deg; const min = Math.floor( value * 60 ); value -= min / 60; const sec = Math.round( value * 100 * 60 * 60 ) / 100; return [ deg, min, sec ].map( ( n ) => mw.language.convertNumber( n ) ); } this.$location.text( mw.msg( 'multimediaviewer-geolocation', mw.msg( 'multimediaviewer-geoloc-coords', mw.msg( 'multimediaviewer-geoloc-coord', ...convertDegMinSec( imageData.latitude ), // The following messages are used here: // * multimediaviewer-geoloc-north // * multimediaviewer-geoloc-south mw.msg( `multimediaviewer-geoloc-${ imageData.latitude >= 0 ? 'north' : 'south' }` ) ), mw.msg( 'multimediaviewer-geoloc-coord', ...convertDegMinSec( imageData.longitude ), // The following messages are used here: // * multimediaviewer-geoloc-east // * multimediaviewer-geoloc-west mw.msg( `multimediaviewer-geoloc-${ imageData.longitude >= 0 ? 'east' : 'west' }` ) ) ) ) ); this.$location.prop( 'href', ( 'https://geohack.toolforge.org/geohack.php?pagename=' + `${ imageData.title.getPrefixedText() }¶ms=${ Math.abs( imageData.latitude ) }${ imageData.latitude >= 0 ? '_N_' : '_S_' }${ Math.abs( imageData.longitude ) }${ imageData.longitude >= 0 ? '_E_' : '_W_' }&language=${ encodeURIComponent( mw.config.get( 'wgUserLanguage' ) ) }` ) ); this.$locationLi.removeClass( 'empty' ); } /** * Set all the image information in the panel * * @param {LightboxImage} image * @param {ImageModel} imageData */ setImageInfo( image, imageData ) { if ( imageData.creationDateTime ) { this.$datetimeCreated.text( mw.msg( 'multimediaviewer-datetime-created', this.formatDate( imageData.creationDateTime ) ) ); this.$datetimeCreatedLi.removeClass( 'empty' ); } if ( imageData.uploadDateTime ) { this.$datetimeUpdated.text( mw.msg( 'multimediaviewer-datetime-uploaded', this.formatDate( imageData.uploadDateTime ) ) ); this.$datetimeUpdatedLi.removeClass( 'empty' ); } this.buttons.set( image, imageData ); this.description.set( imageData.description, image.caption ); this.setLicense( imageData.license, imageData.descriptionUrl ); this.setFileName( imageData.title.getMainText() ); // these handle text truncation and should be called when everything that can push text down // (e.g. floated buttons) has already been laid out this.setTitle( image, imageData ); this.setCredit( imageData.attribution, imageData.source, imageData.author, imageData.authorCount, imageData.descriptionUrl ); if ( imageData.permission ) { this.setPermission( imageData.permission ); } if ( imageData.restrictions ) { this.setRestrictions( imageData.restrictions ); } this.setLocationData( imageData ); this.resetTruncatedText(); this.scroller.unfreezeHeight(); } /** * Show an error message, in case the data could not be loaded * * @param {string} title image title * @param {string} error error message */ showError( title, error ) { this.$credit.text( mw.msg( 'multimediaviewer-metadata-error', error ) ); this.$title.html( title ); } /** * Transforms a date string into localized, human-readable format. * Unrecognized strings are returned unchanged. * * @param {string} dateString * @return {string} formatted date */ formatDate( dateString ) { let lang = mw.config.get( 'wgUserLanguage' ); if ( lang === 'en' || lang === 'qqx' ) { // prefer "D MMMM YYYY" format // avoid passing invalid "qqx" to native toLocaleString(), // which would cause developer's browser locale to be used, // and thus sometimes cause tests to fail. lang = 'en-GB'; } if ( dateString.length === 4 ) { // assume yyyy return dateString; } const date = new Date( dateString ); try { if ( date instanceof Date && !isNaN( date ) ) { return date.toLocaleString( lang, { day: 'numeric', month: 'long', year: 'numeric', timeZone: 'UTC' } ); } } catch ( ignore ) { } // fallback to original date string return dateString; } /** * Shows truncated text in the title and credit (this also rearranges the layout a bit). */ revealTruncatedText() { if ( this.$container.hasClass( 'mw-mmv-untruncated' ) ) { return; } this.$container.addClass( 'mw-mmv-untruncated' ); this.title.grow(); this.creditField.grow(); } /** * Undoes changes made by revealTruncatedText(). */ hideTruncatedText() { if ( !this.$container.hasClass( 'mw-mmv-untruncated' ) ) { return; } this.title.shrink(); this.creditField.shrink(); this.$container.removeClass( 'mw-mmv-untruncated' ); } /** * Hide or reveal truncated text based on whether the panel is open. This is normally handled by * MetadataPanelScroller, but when the panel is reset (e.g. on a prev/next event) sometimes the panel position can change without a panel , such as on a * prev/next event; in such cases this function has to be called. */ resetTruncatedText() { if ( this.scroller.panelIsOpen() ) { this.revealTruncatedText(); } else { this.hideTruncatedText(); } } } /** * Maximum number of restriction icons before default icon is used * * @property {number} MAX_RESTRICT * @static */ MetadataPanel.MAX_RESTRICT = 4; module.exports = MetadataPanel;
| ver. 1.1 | |
.
| PHP 8.4.18 | Ð“ÐµÐ½ÐµÑ€Ð°Ñ†Ð¸Ñ Ñтраницы: 0 |
proxy
|
phpinfo
|
ÐаÑтройка