wikimedia/mediawiki-extensions-MobileFrontend

View on GitHub
src/mobile.special.watchlist.scripts/WatchList.js

Summary

Maintainability
A
0 mins
Test Coverage
const
    mfExtend = require( '../mobile.startup/mfExtend' ),
    PageList = require( '../mobile.startup/PageList' ),
    WatchstarPageList = require( '../mobile.startup/watchstar/WatchstarPageList' ),
    ScrollEndEventEmitter = require( './ScrollEndEventEmitter' ),
    util = require( '../mobile.startup/util' ),
    WatchListGateway = require( './WatchListGateway' );

/**
 * An extension of the WatchstarPageList which preloads pages as all being
 * watched.
 *
 * @extends WatchstarPageList
 * @class WatchList
 * @uses ScrollEndEventEmitter
 *
 * @fires watched
 * @fires watch
 * @param {Object} params Configuration options
 * @param {OO.EventEmitter} params.eventBus Object used to listen for scroll:throttled events
 * @private
 */
function WatchList( params ) {
    let lastTitle;
    const options = util.extend(
        {},
        {
            isBorderBox: false
        },
        params
    );

    // Set up infinite scroll helper and listen to events
    this.scrollEndEventEmitter = new ScrollEndEventEmitter( options.eventBus );
    this.scrollEndEventEmitter.on( ScrollEndEventEmitter.EVENT_SCROLL_END,
        this._loadPages.bind( this ) );

    if ( options.el ) {
        lastTitle = this.getLastTitle( options.el );
    }
    this.gateway = new WatchListGateway( options.api, lastTitle );

    WatchstarPageList.call( this, options );
}

mfExtend( WatchList, WatchstarPageList, {
    /**
     * @inheritdoc
     * @memberof WatchList
     * @instance
     */
    preRender: function () {
        // The DOM will be modified. Prevent any false scroll end events from
        // being emitted.
        this.scrollEndEventEmitter.disable();
        this.scrollEndEventEmitter.setElement( this.$el );
    },
    /**
     * Also sets a watch uploads funnel.
     *
     * @inheritdoc
     * @memberof WatchList
     * @instance
     */
    postRender: function () {
        // Skip a level from WatchstarPageList directly to PageList.
        PageList.prototype.postRender.apply( this );

        const $items = this.queryUnitializedItems();

        // WatchList requests list of watched pages. The list contains only
        // watched pages so it's safe to transform the title map to a status map
        // with each entry marked watched (true).
        const statuses = Object.keys( this.parsePagesFromItems( $items ) )
            .reduce( function ( arr, title ) {
                arr[ title ] = true;
                return arr;
            }, {} );
        this.renderItems( $items, statuses );

        // The list has been extended. Re-enable scroll end events.
        this.scrollEndEventEmitter.enable();
    },

    /**
     * Loads pages from the api and triggers render.
     * Infinite scroll is re-enabled in postRender.
     *
     * @memberof WatchList
     * @instance
     */
    _loadPages: function () {
        this.gateway.loadWatchlist().then( function ( pages ) {
            pages.forEach( function ( page ) {
                this.appendPage( page );
            }.bind( this ) );
            this.render();
        }.bind( this ) );
    },

    /**
     * Appends a list item
     *
     * @memberof WatchList
     * @instance
     * @param {Page} page
     */
    appendPage: function ( page ) {
        // wikidata descriptions should not show in this view.
        const templateOptions = util.extend( {}, page, {
            wikidataDescription: undefined
        } );
        this.$el.append( this.templatePartials.item.render( templateOptions ) );
    },

    /**
     * Get the last title from the rendered HTML.
     * Used for initializing the API
     *
     * @memberof WatchList
     * @instance
     * @param {jQuery.Object} $el Dom element of the list
     * @return {string}
     */
    getLastTitle: function ( $el ) {
        return $el.find( 'li' ).last().attr( 'title' );
    }
} );

module.exports = WatchList;