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

scout.form.fields.wizard.WizardProgressField.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.WizardProgressField = function() {
  scout.WizardProgressField.parent.call(this);

  this.steps = [];

  // Used to determine direction of transition ("going backward" or "going forward")
  this.previousActiveStepIndex;

  // Helper map to find a step by step index. The step index does not necessarily correspond to the
  // array index, because invisible model steps can produce "holes" in the sequence of indices.
  this.stepsMap = {};
};
scout.inherits(scout.WizardProgressField, scout.FormField);


scout.WizardProgressField.prototype._init = function(model) {
  scout.WizardProgressField.parent.prototype._init.call(this, model);
  this._updateStepsMap();
};

scout.WizardProgressField.prototype._render = function($parent) {
  this.addContainer($parent, 'wizard-progress-field', new scout.WizardProgressFieldLayout(this));
  this.addField($parent.makeDiv('wizard-steps'));

  this.$wizardStepsBody = this.$field.appendDiv('wizard-steps-body');

  scout.scrollbars.install(this.$field, {
    parent: this,
    axis: 'x'
  });

  // If this field is the first field in a form's main box, mark the form as "wizard-container-form"
  if (this.parent instanceof scout.GroupBox && this.parent.controls[0] === this && this.parent.parent instanceof scout.Form) {
    var form = this.parent.parent;
    form.$container.addClass('wizard-container-form');
  }
};

scout.WizardProgressField.prototype._renderProperties = function() {
  scout.WizardProgressField.parent.prototype._renderProperties.call(this);
  this._renderSteps();
  this._renderActiveStepIndex();
};

scout.WizardProgressField.prototype._syncSteps = function(steps) {
  this.steps = steps;
  this._updateStepsMap();
};

scout.WizardProgressField.prototype._renderSteps = function() {
  this.$wizardStepsBody.empty();

  this.steps.forEach(function(step, index) {
    // Step
    var $step = this.$wizardStepsBody
      .appendDiv('wizard-step')
      .addClass(step.cssClass)
      .data('wizard-step', step);
    step.$step = $step;
    if (this.enabled && step.enabled && step.actionEnabled) {
      $step.addClass('action-enabled');
      $step.on('click', this._onStepClick.bind(this));
    } else if (!this.enabled || !step.enabled) {
      $step.addClass('disabled');
    }
    if (scout.strings.hasText(step.tooltipText)) {
      scout.tooltips.install($step, {
        parent: this,
        text: step.tooltipText,
        position: 'bottom'
      });
    }
    this._updateStepClasses(step);

    // Inspector info
    scout.inspector.applyInfo(step, $step);
    if (step.classId) { // true if inspector hints are enabled
      $step.attr('data-step-index', step.index);
    }

    // Content
    var $content = $step.appendDiv('wizard-step-content');
    // Icon
    if (step.iconId) {
      var $icon = $content.appendDiv('wizard-step-content-icon');
      $icon.icon(step.iconId);
    }
    // Text
    var $text = $content.appendDiv('wizard-step-content-text');
    $text.appendDiv('wizard-step-title').textOrNbsp(step.title);
    if (step.subTitle) {
      $text.appendDiv('wizard-step-sub-title').textOrNbsp(step.subTitle);
    }

    // Separator
    if (index < this.steps.length - 1) {
      $step.appendDiv('wizard-step-separator');
    }
  }.bind(this));

  this.invalidateLayoutTree(false);
};

scout.WizardProgressField.prototype._syncActiveStepIndex = function(activeStepIndex) {
  this.previousActiveStepIndex = this.activeStepIndex;
  // Ensure this.activeStepIndex always has a value. If the server has no active step set (may
  // happen during transition between steps), we use -1 as dummy value
  this.activeStepIndex = scout.nvl(activeStepIndex, -1);
};

scout.WizardProgressField.prototype._renderActiveStepIndex = function() {
  this.steps.forEach(function(step) {
    this._updateStepClasses(step);
  }.bind(this));

  // update background color for this.$wizardStepsBody, use same as for last step (otherwise there might be white space after last step)
  if (this.steps.length > 0) {
    this.$wizardStepsBody.css('background-color', this.steps[this.steps.length - 1].$step.css('background-color'));
  }

  this.invalidateLayoutTree(false);
};

scout.WizardProgressField.prototype._updateStepClasses = function(step) {
  var $step = step.$step;
  $step.removeClass('active before-active after-active left-of-active right-of-active first last');

  // Important: those indices correspond to the UI's data structures (this.steps) and are not necessarily
  // consistent with the server indices (because the server does not send invisible steps).
  var stepIndex = this.steps.indexOf(step);
  var activeStepIndex = this.steps.indexOf(this.stepsMap[this.activeStepIndex]);

  if (stepIndex >= 0 && activeStepIndex >= 0) {
    // Active
    if (stepIndex < activeStepIndex) {
      $step.addClass('before-active');
      if (stepIndex === activeStepIndex - 1) {
        $step.addClass('left-of-active');
      }
    } else if (stepIndex > activeStepIndex) {
      $step.addClass('after-active');
      if (stepIndex === activeStepIndex + 1) {
        $step.addClass('right-of-active');
      }
    } else {
      $step.addClass('active');
    }
    // First / last
    if (stepIndex === 0) {
      $step.addClass('first');
    }
    if (stepIndex === this.steps.length - 1) {
      $step.addClass('last');
    }
  }
};

scout.WizardProgressField.prototype._stepIndex = function($step) {
  if ($step) {
    var step = $step.data('wizard-step');
    if (step) {
      return step.index;
    }
  }
  return -1;
};

scout.WizardProgressField.prototype._updateStepsMap = function() {
  this.stepsMap = {};
  this.steps.forEach(function(step) {
    this.stepsMap[step.index] = step;
  }.bind(this));
};

scout.WizardProgressField.prototype._resolveStep = function(stepIndex) {
  // Because "step index" does not necessarily correspond to the array indices
  // (invisible model steps produce "holes"), we have to loop over the array.
  for (var i = 0; i < this.steps.length; i++) {
    var step = this.steps[i];
    if (step.index === stepIndex) {
      return step;
    }
  }
  return null;
};

scout.WizardProgressField.prototype._onStepClick = function(event) {
  var $step = $(event.currentTarget); // currentTarget instead of target to support event bubbling from inner divs
  var targetStepIndex = this._stepIndex($step);
  if (targetStepIndex >= 0 && targetStepIndex !== this.activeStepIndex) {
    this._send('doStepAction', {
      stepIndex: targetStepIndex
    });
  }
};

scout.WizardProgressField.prototype.scrollToActiveStep = function() {
  var currentStep = this.stepsMap[this.activeStepIndex];
  if (currentStep) {
    var $currentStep = currentStep.$step;
    var scrollLeft = this.$field.scrollLeft();
    var currentStepLeft = $currentStep.position().left;
    var currentStepWidth = $currentStep.width();
    var fieldWidth = this.$field.width();

    // If going forward, try to scroll the steps such that the center of active step is not after 75% of the available space.
    // If going backward, try to scroll the steps such that the center of the active step is not before 25% of the available space.
    var goingBack = (this.previousActiveStepIndex > this.activeStepIndex);
    var p1 = scrollLeft + Math.floor(fieldWidth * (goingBack ? 0.25 : 0.75));
    var p2 = currentStepLeft + Math.floor(currentStepWidth / 2);
    if ((goingBack && p2 < p1) || (!goingBack && p2 > p1)) {
      scout.scrollbars.scrollLeft(this.$field, scrollLeft + (p2 - p1));
    }
  }
};




© 2015 - 2025 Weber Informatics LLC | Privacy Policy