%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /www/varak.net/wiki.varak.net/extensions/MobileFrontend/resources/mobile.toggle/
Upload File :
Create Path :
Current File : /www/varak.net/wiki.varak.net/extensions/MobileFrontend/resources/mobile.toggle/toggle.js

( function ( M ) {
	var browser = M.require( 'mobile.startup/Browser' ).getSingleton(),
		util = M.require( 'mobile.startup/util' ),
		escapeHash = util.escapeHash,
		arrowOptions = {
			name: 'arrow',
			additionalClassNames: 'indicator'
		},
		Icon = M.require( 'mobile.startup/Icon' );

	/**
	 * A class for enabling toggling
	 *
	 * @class Toggler
	 * @extends OO.EventEmitter
	 */
	function Toggler() {
		OO.EventEmitter.call( this );
		this._enable.apply( this, arguments );
	}
	OO.mixinClass( Toggler, OO.EventEmitter );

	/**
	 * Using the settings module looks at what sections were previously expanded on
	 * existing page.
	 *
	 * @param {Page} page
	 * @return {Object} representing open sections
	 */
	function getExpandedSections( page ) {
		var expandedSections = JSON.parse(
			mw.storage.get( 'expandedSections' ) || '{}'
		);
		expandedSections[page.title] = expandedSections[page.title] || {};
		return expandedSections;
	}

	/**
	 * @param {Object} expandedSections
	 * Save expandedSections to localStorage
	 */
	function saveExpandedSections( expandedSections ) {
		mw.storage.set(
			'expandedSections', JSON.stringify( expandedSections )
		);
	}

	/**
	 * Given an expanded heading, store it to localStorage.
	 * If the heading is collapsed, remove it from localStorage.
	 *
	 * @param {jQuery.Object} $heading - A heading belonging to a section
	 * @param {Page} page
	 */
	function storeSectionToggleState( $heading, page ) {
		var headline = $heading.find( 'span' ).attr( 'id' ),
			isSectionOpen = $heading.hasClass( 'open-block' ),
			expandedSections = getExpandedSections( page );

		if ( headline ) {
			if ( isSectionOpen ) {
				expandedSections[page.title][headline] = ( new Date() ).getTime();
			} else {
				delete expandedSections[page.title][headline];
			}

			saveExpandedSections( expandedSections );
		}
	}

	/**
	 * Expand sections that were previously expanded before leaving this page.
	 * @param {Toggler} toggler
	 * @param {jQuery.Object} $container
	 * @param {Page} page
	 */
	function expandStoredSections( toggler, $container, page ) {
		var $sectionHeading, $headline,
			expandedSections = getExpandedSections( page ),
			$headlines = $container.find( '.section-heading span' );

		$headlines.each( function () {
			$headline = $container.find( this );
			$sectionHeading = $headline.parents( '.section-heading' );
			// toggle only if the section is not already expanded
			if (
				expandedSections[page.title][$headline.attr( 'id' )] &&
				!$sectionHeading.hasClass( 'open-block' )
			) {
				toggler.toggle( $sectionHeading, page );
			}
		} );
	}

	/**
	 * Clean obsolete (saved more than a day ago) expanded sections from
	 * localStorage.
	 * @param {Page} page
	 */
	function cleanObsoleteStoredSections( page ) {
		var now = ( new Date() ).getTime(),
			expandedSections = getExpandedSections( page ),
			// the number of days between now and the time a setting was saved
			daysDifference;
		Object.keys( expandedSections ).forEach( function ( page ) {
			var sections = expandedSections[ page ];
			// clean the setting if it is more than a day old
			Object.keys( sections ).forEach( function ( section ) {
				var timestamp = sections[ section ];
				daysDifference = Math.floor( ( now - timestamp ) / 1000 / 60 / 60 / 24 );
				if ( daysDifference >= 1 ) {
					delete expandedSections[page][section];
				}
			} );
		} );
		saveExpandedSections( expandedSections );
	}

	/**
	 * Given a heading, toggle it and any of its children
	 *
	 * @memberof Toggler
	 * @instance
	 * @param {jQuery.Object} $heading A heading belonging to a section
	 */
	Toggler.prototype.toggle = function ( $heading ) {
		var indicator,
			wasExpanded = $heading.is( '.open-block' ),
			page = $heading.data( 'page' ),
			sectionNumber = $heading.data( 'section-number' ),
			$content = $heading.next();

		$heading.toggleClass( 'open-block' );
		$heading.data( 'indicator' ).remove();

		/**
		 * @event toggled
		 */
		this.emit( 'toggled', wasExpanded, sectionNumber );
		arrowOptions.rotation = wasExpanded ? 0 : 180;
		indicator = new Icon( arrowOptions ).prependTo( $heading );
		$heading.data( 'indicator', indicator );

		/**
		 * Global event emitted before a section is being toggled
		 *
		 * @event section-toggling
		 * @type {Object}
		 * @property {Page} page
		 * @property {bool} wasExpanded
		 * @property {bool} isReferenceSection
		 * @property {jQuery.Object} $heading
		 */
		M.emit( 'before-section-toggled', {
			page: page,
			wasExpanded: wasExpanded,
			$heading: $heading,
			isReferenceSection: Boolean( $content.attr( 'data-is-reference-section' ) )
		} );

		$content
			.toggleClass( 'open-block' )
			.attr( {
				'aria-pressed': !wasExpanded,
				'aria-expanded': !wasExpanded
			} );

		/**
		 * Global event emitted after a section has been toggled
		 * @event section-toggled
		 */
		M.emit( 'section-toggled', wasExpanded, sectionNumber );

		if ( !browser.isWideScreen() ) {
			storeSectionToggleState( $heading, page );
		}
	};

	/**
	 * Enables toggling via enter and space keys
	 *
	 * @param {Toggler} toggler instance.
	 * @param {jQuery.Object} $heading
	 */
	function enableKeyboardActions( toggler, $heading ) {
		$heading.on( 'keypress', function ( ev ) {
			if ( ev.which === 13 || ev.which === 32 ) {
				// Only handle keypresses on the "Enter" or "Space" keys
				toggler.toggle( $heading );
			}
		} ).find( 'a' ).on( 'keypress mouseup', function ( ev ) {
			ev.stopPropagation();
		} );
	}

	/**
	 * Reveals an element and its parent section as identified by it's id
	 *
	 * @memberof Toggler
	 * @instance
	 * @param {string} selector A css selector that identifies a single element
	 * @param {Object} $container jQuery element to search in
	 */
	Toggler.prototype.reveal = function ( selector, $container ) {
		var $target, $heading;

		// jQuery will throw for hashes containing certain characters which can break toggling
		try {
			$target = $container.find( escapeHash( selector ) );
			$heading = $target.parents( '.collapsible-heading' );
			// The heading is not a section heading, check if in a content block!
			if ( !$heading.length ) {
				$heading = $target.parents( '.collapsible-block' ).prev( '.collapsible-heading' );
			}
			if ( $heading.length && !$heading.hasClass( 'open-block' ) ) {
				this.toggle( $heading );
			}
			if ( $heading.length ) {
				// scroll again after opening section (opening section makes the page longer)
				window.scrollTo( 0, $target.offset().top );
			}
		} catch ( e ) {}
	};

	/**
	 * Enables section toggling in a given container when wgMFCollapseSectionsByDefault
	 * is enabled.
	 *
	 * @memberof Toggler
	 * @instance
	 * @param {jQuery.Object} $container to apply toggling to
	 * @param {string} prefix a prefix to use for the id.
	 * @param {Page} [page] to allow storage of session for future visits
	 * @param {Page} [isClosed] whether the element should begin closed
	 * @private
	 */
	Toggler.prototype._enable = function ( $container, prefix, page, isClosed ) {
		var tagName, expandSections, indicator, $content,
			$firstHeading,
			$link,
			self = this,
			collapseSectionsByDefault = mw.config.get( 'wgMFCollapseSectionsByDefault' );

		// Also allow .section-heading if some extensions like Wikibase
		// want to toggle other headlines than direct descendants of $container.
		$firstHeading = $container.find( '> h1,> h2,> h3,> h4,> h5,> h6,.section-heading' ).eq( 0 );
		tagName = $firstHeading.prop( 'tagName' ) || 'H1';

		if ( collapseSectionsByDefault === undefined ) {
			// Old default behavior if on cached output
			collapseSectionsByDefault = true;
		}
		expandSections = !collapseSectionsByDefault ||
			( mw.config.get( 'wgMFExpandAllSectionsUserOption' ) && mw.storage.get( 'expandSections' ) === 'true' );

		$container.children( tagName ).each( function ( i ) {
			var isReferenceSection,
				$heading = $container.find( this ),
				$indicator = $heading.find( '.indicator' ),
				id = prefix + 'collapsible-block-' + i;
			// Be sure there is a div wrapping the section content.
			// Otherwise, collapsible sections for this page is not enabled.
			if ( $heading.next().is( 'div' ) ) {
				$content = $heading.next( 'div' );
				isReferenceSection = Boolean( $content.attr( 'data-is-reference-section' ) );
				$heading
					.addClass( 'collapsible-heading ' )
					.data( 'section-number', i )
					.data( 'page', page )
					.attr( {
						tabindex: 0,
						'aria-haspopup': 'true',
						'aria-controls': id
					} )
					.on( 'click', function ( ev ) {
						// don't toggle, if the click target was a link
						// (a link in a section heading)
						// See T117880
						if ( !ev.target.href ) {
							// prevent taps/clicks on edit button after toggling (bug 56209)
							ev.preventDefault();
							self.toggle( $heading );
						}
					} );

				arrowOptions.rotation = expandSections ? 180 : 0;
				indicator = new Icon( arrowOptions );
				if ( $indicator.length ) {
					// replace the existing indicator
					$indicator.replaceWith( indicator.$el );
				} else {
					indicator.prependTo( $heading );
				}
				$heading.data( 'indicator', indicator.$el );
				$content
					.addClass( 'collapsible-block' )
					.eq( 0 )
					.attr( {
						// We need to give each content block a unique id as that's
						// the only way we can tell screen readers what element we're
						// referring to (aria-controls)
						id: id,
						'aria-pressed': 'false',
						'aria-expanded': 'false'
					} );

				enableKeyboardActions( self, $heading );
				if (
					!isReferenceSection && (
						!isClosed && browser.isWideScreen() || expandSections
					)
				) {
					// Expand sections by default on wide screen devices
					// or if the expand sections setting is set.
					// The wide screen logic for determining whether to collapse sections initially
					// should be kept in sync with mobileoptions#initLocalStorageElements().
					self.toggle( $heading );
				}
			}
		} );

		/* eslint-disable no-restricted-properties */
		/**
		 * Checks the existing hash and toggles open any section that contains the fragment.
		 *
		 * @method
		 */
		function checkHash() {
			var hash = window.location.hash;
			if ( hash.indexOf( '#' ) === 0 ) {
				self.reveal( hash, $container );
			}
		}

		/**
		 * Checks the value of wgInternalRedirectTargetUrl and reveals the collapsed
		 * section that contains it if present
		 *
		 * @method
		 */
		function checkInternalRedirectAndHash() {
			var internalRedirect = mw.config.get( 'wgInternalRedirectTargetUrl' ),
				internalRedirectHash = internalRedirect ? internalRedirect.split( '#' )[1] : false;

			if ( internalRedirectHash ) {
				window.location.hash = internalRedirectHash;
				self.reveal( internalRedirectHash, $container );
			}
		}
		/* eslint-enable no-restricted-properties */

		checkInternalRedirectAndHash();
		checkHash();
		// Restricted to links created by editors and thus outside our control
		// T166544 - don't do this for reference links - they will be handled elsewhere
		$link = $container.find( 'a:not(.reference a)' );
		$link.on( 'click', function () {
			// the link might be an internal link with a hash.
			// if it is check if we need to reveal any sections.
			if ( $link.attr( 'href' ) !== undefined &&
				$link.attr( 'href' ).indexOf( '#' ) > -1
			) {
				checkHash();
			}
		} );
		util.getWindow().on( 'hashchange', function () {
			checkHash();
		} );

		if ( !browser.isWideScreen() && page ) {
			expandStoredSections( this, $container, page );
			cleanObsoleteStoredSections( page );
		}
	};

	Toggler._getExpandedSections = getExpandedSections;
	Toggler._expandStoredSections = expandStoredSections;
	Toggler._cleanObsoleteStoredSections = cleanObsoleteStoredSections;

	M.define( 'mobile.toggle/Toggler', Toggler ); // resource-modules-disable-line

}( mw.mobileFrontend ) );

Zerion Mini Shell 1.0