wikimedia/mediawiki-extensions-MobileFrontend

View on GitHub
src/mobile.startup/Browser.js

Summary

Maintainability
A
25 mins
Test Coverage
const util = require( './util' );

let browser;

/**
 * Memoize a class method. Caches the result of the method based on the
 * arguments. Instances do not share a cache.
 *
 * @private
 * @param {Function} method Method to be memoized
 * @return {Function}
 */
function memoize( method ) {
    /**
     * Memoized version of the method
     *
     * @return {Function}
     */
    const memoized = function () {
        const cache = this[ '__cache' + memoized.cacheId ] ||
            ( this[ '__cache' + memoized.cacheId ] = {} ),
            key = [].join.call( arguments, '|' );
        if ( Object.prototype.hasOwnProperty.call( cache, key ) ) {
            return cache[ key ];
        }
        return ( cache[ key ] = method.apply( this, arguments ) );
    };
    memoized.cacheId = Date.now().toString() + Math.random().toString();
    return memoized;
}

/**
 * Representation of user's current browser
 *
 * @class Browser
 * @private
 * @param {string} ua the user agent of the current browser
 * @param {jQuery.Object} $container an element to associate with the Browser object
 */
function Browser( ua, $container ) {
    this.userAgent = ua;
    this.$el = $container;
}

Browser.prototype = {
    /**
     * Returns whether the current browser is an ios device.
     * FIXME: jquery.client does not support iPad detection so we cannot use it.
     *
     * @memberof Browser
     * @instance
     * @param {number} [version] integer describing a specific version you want to test against.
     * @return {boolean}
     */
    isIos: memoize( function ( version ) {
        const ua = this.userAgent,
            ios = /ipad|iphone|ipod/i.test( ua );

        if ( ios && version ) {
            switch ( version ) {
                case 8:
                    // Test UA for iOS8. Or for simulator look for Version 8
                    // In the iOS simulator the OS is the host machine OS version
                    // This makes testing in iOS8 simulator work as expected
                    return /OS 8_/.test( ua ) || /Version\/8/.test( ua );
                case 4:
                    return /OS 4_/.test( ua );
                case 5:
                    return /OS 5_/.test( ua );
                default:
                    return false;
            }
        } else {
            return ios;
        }
    } ),
    /**
     * Determine if a device has a widescreen.
     *
     * @memberof Browser
     * @instance
     * @return {boolean}
     */
    isWideScreen: memoize( () => {
        const val = parseInt( mw.config.get( 'wgMFDeviceWidthTablet' ), 10 );
        // Check viewport width to determine mobile vs tablet.
        // Note: Mobile devices held in landscape mode might receive tablet treatment.
        return window.innerWidth >= val;
    } ),
    /**
     * Whether touchstart and other touch events are supported by the current browser.
     *
     * @memberof Browser
     * @instance
     * @return {boolean}
     */
    supportsTouchEvents: memoize( () => 'ontouchstart' in window )
};

/**
 * @memberof Browser
 * @return {Browser}
 */
Browser.getSingleton = function () {
    let $html;
    if ( !browser ) {
        $html = util.getDocument();
        browser = new Browser( window.navigator.userAgent, $html );
    }
    return browser;
};

module.exports = Browser;