Current File : /home/jvzmxxx/wiki1/extensions/Flow/modules/flow/ui/widgets/mw.flow.ui.NavigationWidget.js
( function ( $ ) {
	/**
	 * Flow navigation widget
	 *
	 * @extends OO.ui.Widget
	 *
	 * @constructor
	 * @param {mw.flow.dm.System} system System model
	 * @param {Object} [config]
	 * @cfg {number} [tocPostLimit=50] The number of topics in the ToC per API request
	 * @cfg {string} [defaultSort='newest'] The current default topic sort order
	 */
	mw.flow.ui.NavigationWidget = function mwFlowUiNavigationWidget( system, config ) {
		config = config || {};

		// Parent constructor
		mw.flow.ui.NavigationWidget.parent.call( this, config );

		this.board = system.getBoard();

		this.tocWidget = new mw.flow.ui.ToCWidget( system, {
			classes: [ 'flow-ui-navigationWidget-tocWidget' ],
			tocPostLimit: config.tocPostLimit
		} );

		this.reorderTopicsWidget = new mw.flow.ui.ReorderTopicsWidget( this.board, config );

		// Events
		$( window ).on( 'scroll resize', this.onWindowScroll.bind( this ) );
		this.tocWidget.connect( this, { loadTopic: 'onToCWidgetLoadTopic' } );
		this.reorderTopicsWidget.connect( this, { reorder: 'onReorderTopicsWidgetReorder' } );

		// Initialize
		this.$element
			.append(
				this.tocWidget.$element,
				this.reorderTopicsWidget.$element,
				$( '<div>' ).addClass( 'flow-ui-navigationWidget-clear' )
			)
			.addClass( 'flow-ui-navigationWidget' );
	};

	/* Initialization */

	OO.inheritClass( mw.flow.ui.NavigationWidget, OO.ui.Widget );

	/* Methods */

	/**
	 * Propagate the scrollto event so the old code can
	 * work on it.
	 *
	 * @param {string} topicId Topic id
	 * @fires loadTopic
	 */
	mw.flow.ui.NavigationWidget.prototype.onToCWidgetLoadTopic = function ( topicId ) {
		this.emit( 'loadTopic', topicId );
	};

	/**
	 * Propagate the reorder event from the reorderTopicsWidget
	 * so the old code can be updated
	 *
	 * @param {string} order New order
	 * @fires reorderTopics
	 */
	mw.flow.ui.NavigationWidget.prototype.onReorderTopicsWidgetReorder = function ( order ) {
		this.emit( 'reorderTopics', order );
	};

	/**
	 * Respond to window scroll
	 */
	mw.flow.ui.NavigationWidget.prototype.onWindowScroll = function () {
		var scrollTop, isScrolledDown, topicId,
			/*!
			 * Check if element is in the viewport.
			 *
			 * @param {jQuery} $el Element to test
			 * @return {boolean} Element is in screen
			 */
			isElementInView = function ( $el ) {
				var scrollTop, containerHeight,
					height = $el.height(),
					top = $el.offset().top,
					bottom = top + height;

				scrollTop = $( window ).scrollTop();
				containerHeight = $( window ).height();

				return (
					// Topic top is visible
					(
						top >= scrollTop &&
						top <= scrollTop + containerHeight
					) ||
					// Topic bottom is visible
					(
						bottom >= scrollTop &&
						bottom <= scrollTop + containerHeight
					) ||
					// Topic is long and we are in the middle of it
					(
						top < scrollTop &&
						bottom > scrollTop + containerHeight
					)
				);
			};

		// HACK: Quit if the widget is unattached. This happens when we are
		// waiting to rebuild the board when reordering the topics
		// This should not be needed when the board is wigdetized
		if ( this.$element.parent().length === 0 ) {
			return;
		}

		scrollTop = $( window ).scrollTop();
		isScrolledDown = scrollTop >= this.$element.parent().offset().top;

		if ( isScrolledDown ) {
			// TODO use binary search
			$( '.flow-topic' ).each( function ( index, element ) {
				if ( isElementInView( $( this ) ) ) {
					topicId = $( this ).data( 'flowId' );
					return false;
				}
			} );
		}
		// Update the toc selection
		this.tocWidget.updateSelection( topicId );

		// Fix the widget to the top when we scroll down below its original
		// location
		this.$element.toggleClass(
			'flow-ui-navigationWidget-affixed',
			isScrolledDown
		);
		if ( isScrolledDown ) {
			// Copy width from parent, width: 100% doesn't do what we want when
			// position: fixed; is set
			this.$element.css( 'width', this.$element.parent().width() );
		} else {
			// Unset width when we no longer have position: fixed;
			this.$element.css( 'width', '' );
		}

		this.reorderTopicsWidget.toggle( !isScrolledDown );
	};
}( jQuery ) );