All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scout.util.fonts.js Maven / Gradle / Ivy

There is a newer version: 25.1.0-beta.0
Show newest version
/*******************************************************************************
 * Copyright (c) 2014-2015 BSI Business Systems Integration AG.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     BSI Business Systems Integration AG - initial API and implementation
 ******************************************************************************/
scout.fonts = {

  _deferred: $.Deferred(),

  /**
   * Indicates whether all fonts have been loaded successfully. Check this variable before
   * waiting for the promise object returned by preloader().
   */
  loadingComplete: true,

  /**
   * Start preloading the specified fonts.
   * @param fonts (optional) array of fonts
   */
  bootstrap: function(fonts) {
    if (!fonts || fonts.length === 0) {
      return;
    }

    // Start preloading
    this.loadingComplete = false;
    this.preload({
      fonts: fonts,
      onComplete: function(success) {
        this.loadingComplete = true;
        this._deferred.resolve();
      }.bind(this)
    });
  },

  /**
   * @return  a promise object that is notified when the font preloading was completed.
   *          Important: Before waiting for this promise, always check that value of
   *          this.loadingComplete first! Do not wait for the promise when loadingComplete
   *          is true, because the promise will never be resolved.
   */
  preloader: function() {
    return this._deferred.promise();
  },

  /**
   * Loads the specified fonts in a hidden div, forcing the browser to load them.
   *
   * Options:
   *   [fonts]
   *     A single string or object (or an array of them) specifying which fonts should
   *     be preloaded. A string is interpreted as font-family. If the style is relevant,
   *     too, an object with the properties 'font-family' and 'style' should be provided.
   *   [onComplete]
   *     Mandatory function to be called when all of the specified fonts have been
   *     loaded or if a timeout occurs. An argument 'success' is given to indicate
   *     whether loading was completed successfully or execution was interrupted by
   *     a timeout. If this option is omitted, the call to this method returns immediately.
   *   [timeout]
   *     Optional timeout in milliseconds. If fonts could not be loaded within this time,
   *     loading is stopped and the onComplete method is called with argument 'false'.
   *     Default is 30 seconds.
   *
   * Examples:
   *   preload({fonts: "Sauna Pro"});
   *   preload({fonts: "Sauna Pro", onComplete: handleLoadFinished});
   *   preload({fonts: ["Sauna Pro", "Dolly Pro"]});
   *   preload({fonts: {family:"Sauna", style: "font-style:italic; font-weight:700"}, timeout: 999});
   *   preload({fonts: ["Fakir-Black", {family:"Fakir-Italic", style:"font-style:italic"}], timeout: 2500, onComplete: function() { setCookie("fakir","loaded") }});
   *
   * Inspired by Zenfonts (https://github.com/zengabor/zenfonts, public domain).
   */
  preload: function(options) {
    options = options || {};
    var fonts = options.fonts || [];
    if (!Array.isArray(fonts)) {
      fonts = [fonts];
    }
    if (!options.onComplete) {
      // preloading is not useful, because there is no callback on success
      return;
    }

    // these fonts are compared to the custom fonts, strings separated by comma
    var testFonts = 'monospace';

    // Create a DIV for each font
    var divs = [];
    fonts.forEach(function(font) {
      // Convert to object
      if (typeof font === 'string') {
        font = {
          family: font
        };
      }
      font.family = font.family || '';
      font.style = font.style || '';

      // Create DIV with default font
      // (Hide explicitly with inline style to prevent visible text when, for some reason, the CSS file cannot be loaded)
      var $body = $('body'),
        $div = $body.appendDiv('font-preloader')
          .text('ABC abc 123 .,_')
          .css('visibility', 'hidden')
          .css('font-family', testFonts);

      // Remember size, set new font, and then measure again
      var originalWidth = $div.outerWidth();
      $div.data('original-width', originalWidth);
      $div.css('font-family', '\'' + font.family + '\',' + testFonts);

      if ($div.outerWidth() !== originalWidth) {
        // Font already loaded, nothing to do
        $div.remove();
      } else {
        // Remember DIV
        divs.push($div);
      }
    }.bind(this));
    if (divs.length === 0) {
      // No fonts need to be watched, everything is loaded already
      complete(true);
      return;
    }

    var onFinished = complete;
    var timeout = scout.nvl(options.timeout, 30 * 1000); // default timeout is 30 sec
    var watchTimerId, timeoutTimerId;
    if (timeout && timeout >= 0) {
      // Add timeout
      timeoutTimerId = setTimeout(function() {
        clearTimeout(watchTimerId);
        complete(false);
      }.bind(this), timeout);
      onFinished = function() {
        clearTimeout(timeoutTimerId);
        complete(true);
      };
    }

    // Start watching (initially 50ms delay)
    watchWidthChange(50, onFinished);

    // ----- Helper functions -----

    function watchWidthChange(delay, onFinished) {
      // Check each DIV
      var i = divs.length;
      while (i--) {
        var $div = divs[i];
        if ($div.outerWidth() !== $div.data('original-width')) {
          divs.splice(i, 1);
          $div.remove();
        }
      }
      if (divs.length === 0) {
        // All completed
        onFinished(true);
        return;
      }

      // Watch again after a small delay
      watchTimerId = setTimeout(function() {
        // Slowly increase delay up to 1 second
        if (delay < 1000) {
          delay = delay * 1.2;
        }
        watchWidthChange(delay, onFinished);
      }, delay);
    }

    function complete(success) {
      options.onComplete(success);
    }
  }
};




© 2015 - 2025 Weber Informatics LLC | Privacy Policy