ShowFor.prototype.matchesCriteria = function()

in kitsune/sumo/static/sumo/js/showfor.js [412:530]


ShowFor.prototype.matchesCriteria = function (criteria) {
  /* The basic logic for showfor is that there are two kinds of
    * things: platforms and products. If one or more platforms are
    * in the criteria, at least one has to match. If one or more
    * products are in the criteria, at least one has to match.
    *
    * To be succinct, this has to be true for a set of criteria to match:
    *
    *    (any(browsers) or browsers.length == 0) and
    *    (any(platforms) or platforms.length == 0)
    *
    * Versions are seen as more specific products. Platforms don't
    * have versions.
    */
  var hasProduct = false;
  var matchProduct = false;
  var hasPlatform = false;
  var matchPlatform = false;

  /* This cheats a bit. Platforms are presented as being tied to a
    * platform, but we ignore that. Just assume that all selected
    * platforms apply to all products. */
  var enabledPlatforms = [];
  for (var slug in this.state) {
    var prod = this.state[slug];
    if (prod.enabled && prod.platform) {
      enabledPlatforms.push(prod.platform);
    }
  }

  /* This will loop through every item in criteria. It will set the
    * has/matches variables above to true if at least one
    * product/platform is found, and at least one of those matches
    * respectively. */
  criteria.forEach(function (name) {
    var productSlug, elemVersion;

    // Does this start with "not" ? Set a flag.
    var not = (name.indexOf('not') === 0);
    if (not) {
      name = name.replace(/^not ?/, '');
    }

    // "fx" -> "firefox", etc.
    name = this.productShortMap[name] || name;

    // Check for exact-equals. Maybe this will get smarter later.
    var oper = '>=';
    if (name[0] === '=') {
      name = name.slice(1);
      oper = '=';
    }

    /* Not that the below things never set anything false, only to
      * true. This way they work like a big OR. */

    // Is this a product? (without a version) {for fx}
    if (this.productSlugs.indexOf(name) >= 0) {
      hasProduct = true;
      if (this.state[name].enabled !== not) {
        matchProduct = true;
      }

      // Is this a product+version?  {for fx27}
    } else if (this.versionSlugs[name] !== undefined) {

      /* elemVersion is the version indicated in the element being
        * shown/hidden. stateMin and stateMax are the min and max
        * versions from this.state, which reflects the UI. */
      productSlug = this.versionSlugs[name];
      hasProduct = true;
      elemVersion = parseFloat(/^[a-z]+([\d\.]+)$/.exec(name)[1]);

      // name = 'fx27' -> productSlug = 'fx', elemVersion = 27

      var stateMin = this.state[productSlug].version.min;
      var stateMax = this.state[productSlug].version.max;

      var enabled = this.state[productSlug].enabled;
      var rightVersion = ((oper === '>=' && elemVersion < stateMax) ||
        (oper === '=' && elemVersion >= stateMin && elemVersion < stateMax));

      if ((enabled && rightVersion) !== not) {
        matchProduct = true;
      }

      // Is it a platform?
    } else if (this.platformSlugs.indexOf(name) >= 0) {
      hasPlatform = true;

      if ((enabledPlatforms.indexOf(name) >= 0) !== not) {
        matchPlatform = true;
      }

      // Special case for windows.
    } else if (name === 'win') {
      hasPlatform = true;

      /* Loop through each of the possible slugs for windows. If
        * any of them match, then this name matches. */
      var windowsTypes = ['winxp', 'win7', 'win8', 'win10', 'win11'];
      var winMatches = false;

      windowsTypes.forEach(function (fakeName) {
        if (enabledPlatforms.indexOf(fakeName) >= 0) {
          winMatches = true;
        }
      });

      if (winMatches !== not) {
        matchPlatform = true;
      }
    }
  }.bind(this));

  // If a platform matches, or no platform matchers exist AND
  // if a product matches, or no product matchers exist.
  return (!hasProduct || matchProduct) && (!hasPlatform || matchPlatform);
};