wikimedia/mediawiki-extensions-VisualEditor

View on GitHub
modules/ve-mw/ui/pages/ve.ui.MWAdvancedSettingsPage.js

Summary

Maintainability
F
6 days
Test Coverage
/*!
 * VisualEditor user interface MWAdvancedSettingsPage class.
 *
 * @copyright See AUTHORS.txt
 * @license The MIT License (MIT); see LICENSE.txt
 */

/**
 * MediaWiki meta dialog advanced settings page.
 *
 * @class
 * @extends OO.ui.PageLayout
 *
 * @constructor
 * @param {string} name Unique symbolic name of page
 * @param {Object} [config] Configuration options
 * @param {jQuery} [config.$overlay] Overlay to render dropdowns in
 */
ve.ui.MWAdvancedSettingsPage = function VeUiMWAdvancedSettingsPage( name, config ) {
    // Parent constructor
    ve.ui.MWAdvancedSettingsPage.super.apply( this, arguments );

    // Properties
    this.fragment = null;
    this.indexingOptionTouched = false;
    this.newSectionEditLinkOptionTouched = false;

    this.advancedSettingsFieldset = new OO.ui.FieldsetLayout( {
        label: ve.msg( 'visualeditor-dialog-meta-advancedsettings-label' ),
        icon: 'settings'
    } );

    // Initialization

    // Indexing items
    this.indexing = new OO.ui.FieldLayout(
        new OO.ui.ButtonSelectWidget()
            .addItems( [
                new OO.ui.ButtonOptionWidget( {
                    data: 'mw:PageProp/index',
                    label: ve.msg( 'visualeditor-dialog-meta-settings-index-force' )
                } ),
                new OO.ui.ButtonOptionWidget( {
                    data: 'default',
                    label: ve.msg( 'visualeditor-dialog-meta-settings-index-default' )
                } ),
                new OO.ui.ButtonOptionWidget( {
                    data: 'mw:PageProp/noindex',
                    label: ve.msg( 'visualeditor-dialog-meta-settings-index-disable' )
                } )
            ] )
            .connect( this, { select: 'onIndexingOptionChange' } ),
        {
            $overlay: config.$overlay,
            align: 'top',
            label: ve.msg( 'visualeditor-dialog-meta-settings-index-label' ),
            help: ve.msg( 'visualeditor-dialog-meta-settings-index-help' )
        }
    );

    // New edit section link items
    this.newEditSectionLink = new OO.ui.FieldLayout(
        new OO.ui.ButtonSelectWidget()
            .addItems( [
                new OO.ui.ButtonOptionWidget( {
                    data: 'mw:PageProp/newsectionlink',
                    label: ve.msg( 'visualeditor-dialog-meta-settings-newsectioneditlink-force' )
                } ),
                new OO.ui.ButtonOptionWidget( {
                    data: 'default',
                    label: ve.msg( 'visualeditor-dialog-meta-settings-newsectioneditlink-default' )
                } ),
                new OO.ui.ButtonOptionWidget( {
                    data: 'mw:PageProp/nonewsectionlink',
                    label: ve.msg( 'visualeditor-dialog-meta-settings-newsectioneditlink-disable' )
                } )
            ] )
            .connect( this, { select: 'onNewSectionEditLinkOptionChange' } ),
        {
            $overlay: config.$overlay,
            align: 'top',
            label: ve.msg( 'visualeditor-dialog-meta-settings-newsectioneditlink-label' ),
            // eslint-disable-next-line no-jquery/no-global-selector
            help: ve.msg( 'visualeditor-dialog-meta-settings-newsectioneditlink-help', $( '#ca-edit' ).text() )
        }
    );

    this.displayTitleTouched = false;
    this.displayTitleInput = new OO.ui.TextInputWidget();
    this.displayTitleInput.connect( this, { change: 'onDisplayTitleInputChange' } );
    this.displayTitleField = new OO.ui.FieldLayout(
        this.displayTitleInput,
        {
            $overlay: config.$overlay,
            align: 'top',
            label: ve.msg( 'visualeditor-dialog-meta-settings-displaytitle' ),
            help: ve.msg( 'visualeditor-dialog-meta-settings-displaytitle-help' )
        }
    );

    this.advancedSettingsFieldset.addItems( [ this.indexing, this.newEditSectionLink, this.displayTitleField ] );

    this.metaItemCheckboxes = [];
    if ( mw.config.get( 'wgVariantArticlePath' ) ) {
        this.metaItemCheckboxes.push(
            {
                metaName: 'mwNoContentConvert',
                label: ve.msg( 'visualeditor-dialog-meta-settings-nocontentconvert-label' ),
                help: ve.msg( 'visualeditor-dialog-meta-settings-nocontentconvert-help' )
            },
            {
                metaName: 'mwNoTitleConvert',
                label: ve.msg( 'visualeditor-dialog-meta-settings-notitleconvert-label' ),
                help: ve.msg( 'visualeditor-dialog-meta-settings-notitleconvert-help' )
            }
        );
    }

    this.metaItemCheckboxes.forEach( ( metaItemCheckbox ) => {
        metaItemCheckbox.fieldLayout = new OO.ui.FieldLayout(
            new OO.ui.CheckboxInputWidget(),
            {
                $overlay: config.$overlay,
                align: 'inline',
                label: metaItemCheckbox.label,
                help: metaItemCheckbox.help
            }
        );
        this.advancedSettingsFieldset.addItems( [ metaItemCheckbox.fieldLayout ] );
    } );

    this.$element.append( this.advancedSettingsFieldset.$element );
};

/* Inheritance */

OO.inheritClass( ve.ui.MWAdvancedSettingsPage, OO.ui.PageLayout );

/* Methods */

/**
 * Handle display title input change events.
 *
 * @param {string} value Current value of input widget
 */
ve.ui.MWAdvancedSettingsPage.prototype.onDisplayTitleInputChange = function () {
    this.displayTitleTouched = true;
};

/**
 * @inheritdoc
 */
ve.ui.MWAdvancedSettingsPage.prototype.setupOutlineItem = function () {
    this.outlineItem
        .setIcon( 'settings' )
        .setLabel( ve.msg( 'visualeditor-dialog-meta-advancedsettings-section' ) );
};

/* Indexing option methods */

/**
 * Handle indexing option state change events.
 */
ve.ui.MWAdvancedSettingsPage.prototype.onIndexingOptionChange = function () {
    this.indexingOptionTouched = true;
};

/**
 * Get the first meta item of a given name
 *
 * @param {string} name Name of the meta item
 * @return {Object|null} Meta item, if any
 */
ve.ui.MWAdvancedSettingsPage.prototype.getMetaItem = function ( name ) {
    return this.fragment.getDocument().getMetaList().getItemsInGroup( name )[ 0 ] || null;
};

/* New edit section link option methods */

/**
 * Handle new edit section link change events.
 */
ve.ui.MWAdvancedSettingsPage.prototype.onNewSectionEditLinkOptionChange = function () {
    this.newSectionEditLinkOptionTouched = true;
};

/**
 * Setup settings page.
 *
 * @param {ve.dm.SurfaceFragment} fragment Surface fragment
 * @param {Object} config
 * @param {Object} [config.data] Dialog setup data
 * @param {boolean} [config.isReadOnly=false] Dialog is in read-only mode
 * @return {jQuery.Promise}
 */
ve.ui.MWAdvancedSettingsPage.prototype.setup = function ( fragment, config ) {
    this.fragment = fragment;

    // Indexing items
    const indexingField = this.indexing.getField();
    const indexingOption = this.getMetaItem( 'mwIndex' );
    const indexingType = indexingOption && indexingOption.getAttribute( 'property' ) || 'default';
    indexingField
        .selectItemByData( indexingType )
        .setDisabled( config.isReadOnly );
    this.indexingOptionTouched = false;

    // New section edit link items
    const newSectionEditField = this.newEditSectionLink.getField();
    const newSectionEditLinkOption = this.getMetaItem( 'mwNewSectionEdit' );
    const newSectionEditLinkType = newSectionEditLinkOption && newSectionEditLinkOption.getAttribute( 'property' ) || 'default';
    newSectionEditField
        .selectItemByData( newSectionEditLinkType )
        .setDisabled( config.isReadOnly );
    this.newSectionEditLinkOptionTouched = false;

    // Display title items
    const displayTitleItem = this.getMetaItem( 'mwDisplayTitle' );
    let displayTitle = displayTitleItem && displayTitleItem.getAttribute( 'content' ) || '';
    if ( !displayTitle ) {
        displayTitle = mw.Title.newFromText( ve.init.target.getPageName() ).getPrefixedText();
    }
    this.displayTitleInput
        .setValue( displayTitle )
        .setReadOnly( config.isReadOnly );
    this.displayTitleTouched = false;

    // Simple checkbox items
    this.metaItemCheckboxes.forEach( ( metaItemCheckbox ) => {
        const isSelected = !!this.getMetaItem( metaItemCheckbox.metaName );
        metaItemCheckbox.fieldLayout.getField()
            .setSelected( isSelected )
            .setDisabled( config.isReadOnly );
    } );

    return ve.createDeferred().resolve().promise();
};

/**
 * Tear down settings page.
 *
 * @param {Object} [data] Dialog tear down data
 */
ve.ui.MWAdvancedSettingsPage.prototype.teardown = function ( data ) {
    // Data initialization
    data = data || {};
    if ( data.action !== 'done' ) {
        return;
    }

    // Indexing items
    const currentIndexingItem = this.getMetaItem( 'mwIndex' );
    const newIndexingData = this.indexing.getField().findSelectedItem();

    // Alter the indexing option flag iff it's been touched & is actually different
    if ( this.indexingOptionTouched ) {
        if ( newIndexingData.data === 'default' ) {
            if ( currentIndexingItem ) {
                this.fragment.removeMeta( currentIndexingItem );
            }
        } else {
            const newIndexingItem = { type: 'mwIndex', attributes: { property: newIndexingData.data } };

            if ( !currentIndexingItem ) {
                this.fragment.insertMeta( newIndexingItem );
            } else if ( currentIndexingItem.getAttribute( 'property' ) !== newIndexingData.data ) {
                this.fragment.replaceMeta(
                    currentIndexingItem,
                    ve.extendObject( true, {}, currentIndexingItem.getElement(), newIndexingItem )
                );
            }
        }
    }

    // New section edit link items
    const currentNewSectionEditLinkItem = this.getMetaItem( 'mwNewSectionEdit' );
    const newNewSectionEditLinkData = this.newEditSectionLink.getField().findSelectedItem();

    // Alter the new section edit option flag iff it's been touched & is actually different
    if ( this.newSectionEditLinkOptionTouched ) {
        if ( newNewSectionEditLinkData.data === 'default' ) {
            if ( currentNewSectionEditLinkItem ) {
                this.fragment.removeMeta( currentNewSectionEditLinkItem );
            }
        } else {
            const newNewSectionEditLinkItem = { type: 'mwNewSectionEdit', attributes: { property: newNewSectionEditLinkData.data } };

            if ( !currentNewSectionEditLinkItem ) {
                this.fragment.insertMeta( newNewSectionEditLinkItem );
            } else if ( currentNewSectionEditLinkItem.getAttribute( 'property' ) !== newNewSectionEditLinkData.data ) {
                this.fragment.replaceMeta(
                    currentNewSectionEditLinkItem,
                    ve.extendObject( true, {}, currentNewSectionEditLinkItem.getElement(), newNewSectionEditLinkItem )
                );
            }
        }
    }

    // Display title items
    const currentDisplayTitleItem = this.getMetaItem( 'mwDisplayTitle' );
    let newDisplayTitle = this.displayTitleInput.getValue();
    if ( newDisplayTitle === mw.Title.newFromText( ve.init.target.getPageName() ).getPrefixedText() ) {
        newDisplayTitle = '';
    }
    const newDisplayTitleItem = { type: 'mwDisplayTitle', attributes: { content: newDisplayTitle } };

    // Alter the display title flag iff it's been touched & is actually different
    if ( this.displayTitleTouched ) {
        if ( currentDisplayTitleItem ) {
            if ( newDisplayTitle ) {
                if ( currentDisplayTitleItem.getAttribute( 'content' ) !== newDisplayTitle ) {
                    // There was a display title and is a new one, but they differ, so replace
                    this.fragment.replaceMeta(
                        currentDisplayTitleItem,
                        ve.extendObject( true, {},
                            currentDisplayTitleItem.getElement(),
                            newDisplayTitleItem
                        )
                    );
                }
            } else {
                // There was a display title and is no new one, so remove
                this.fragment.removeMeta( currentDisplayTitleItem );
            }
        } else {
            if ( newDisplayTitle ) {
                // There's no existing display title but there is a new one, so create
                // HACK: Putting this at position 0 so that it works – T63862
                this.fragment.insertMeta( newDisplayTitleItem, 0 );
            }
        }
    }

    this.metaItemCheckboxes.forEach( ( metaItemCheckbox ) => {
        const currentItem = this.getMetaItem( metaItemCheckbox.metaName ),
            isSelected = metaItemCheckbox.fieldLayout.getField().isSelected();

        if ( currentItem && !isSelected ) {
            this.fragment.removeMeta( currentItem );
        } else if ( !currentItem && isSelected ) {
            this.fragment.insertMeta( { type: metaItemCheckbox.metaName } );
        }
    } );

    this.fragment = null;
};

ve.ui.MWAdvancedSettingsPage.prototype.getFieldsets = function () {
    return [
        this.advancedSettingsFieldset
    ];
};