APIs

Show:
/**
  @module ember-flexberry
 */

import $ from 'jquery';
import { inject as service } from '@ember/service';
import { isBlank, isNone } from '@ember/utils';
import { isArray } from '@ember/array';
import { assert } from '@ember/debug';
import ProjectedModelFormRoute from './projected-model-form';
import ReloadListMixin from '../mixins/reload-list-mixin';
import LimitedRouteMixin from '../mixins/limited-route';
import SortableRouteMixin from '../mixins/sortable-route';
import FlexberryGroupeditRouteMixin from '../mixins/flexberry-groupedit-route';
import FlexberryObjectlistviewRouteMixin from '../mixins/flexberry-objectlistview-route';
import FlexberryObjectlistviewHierarchicalRouteMixin from '../mixins/flexberry-objectlistview-hierarchical-route';
import ErrorableRouteMixin from '../mixins/errorable-route';

/**
  Base route for the Edit Forms.

  This class re-exports to the application as `/routes/edit-form`.
  So, you can inherit from `./edit-form`, even if file `app/routes/edit-form.js` is not presented in the application.

  Example:
  ```javascript
  // app/routes/employee.js
  import EditFormRoute from './edit-form';
  export default EditFormRoute.extend({
  });
  ```

  If you want to add some common logic on all Edit Forms, you can override `app/routes/edit-form.js` as follows:
  ```javascript
  // app/routes/edit-form.js
  import EditFormRoute from 'ember-flexberry/routes/edit-form';
  export default EditFormRoute.extend({
  });
  ```

  @class EditFormRoute
  @extends ProjectedModelForm
  @uses FlexberryGroupeditRouteMixin
 */
export default ProjectedModelFormRoute.extend(
FlexberryObjectlistviewRouteMixin,
FlexberryGroupeditRouteMixin,
FlexberryObjectlistviewHierarchicalRouteMixin,
ErrorableRouteMixin,
LimitedRouteMixin,
SortableRouteMixin,
ReloadListMixin, {
  actions: {
    /**
      It sends message about transition to corresponding controller.

      The willTransition action is fired at the beginning of any attempted transition with a Transition object as the sole argument.
      [More info](https://www.emberjs.com/api/ember/release/classes/Route/events/willTransition?anchor=willTransition).

      @method actions.willTransition
      @param {Object} transition
     */
    willTransition(transition) {
      this._super(transition);
      this.controller.send('routeWillTransition');
    },
  },

  /**
    Configuration hash for this route's queryParams. [More info](https://www.emberjs.com/api/ember/release/classes/Route/properties/queryParams?anchor=queryParams).

    @property queryParams
    @type Object
   */
  queryParams: {
    page: { refreshModel: false },
    perPage: { refreshModel: false },
    sort: { refreshModel: false },
    filter: { refreshModel: false },
    filterCondition: { refreshModel: false }
  },

  /**
    Route name corresponding edit form.

    @property parentRoute
    @type String
  */
  parentRoute: undefined,

  /**
    Route id corresponding edit form.

    @property parentRouteRecordId
    @type String
  */
  parentRouteRecordId: undefined,

  /**
    Suffix for new route (has value only on new routes).

    @property newSuffix
    @type String
  */
  newSuffix: undefined,

  /**
    Service for managing the state of the application.

    @property appState
    @type AppStateService
  */
  appState: service(),

  /**
    @property colsConfigMenu
    @type Service
  */
  colsConfigMenu: service(),

  /**
    This hook is the first of the route entry validation hooks called when an attempt is made to transition into a route or one of its children.
    [More info](https://www.emberjs.com/api/ember/release/classes/Route/methods/beforeModel?anchor=beforeModel).

    @method beforeModel
    @param {Transition} transition
    @return {Promise}
  */
  beforeModel(transition) {
    this._super(...arguments);

    this.get('appState').validationHide();
    if (!isNone(transition.queryParams.parentRoute)) {
      let thisRouteName = transition.queryParams.parentRoute;
      let thisRecordId = transition.queryParams.parentRouteRecordId;
      if (!isNone(thisRouteName)) {
        this.set('parentRoute', thisRouteName);
        this.set('parentRouteRecordId', thisRecordId);
      }
    }

    let webPage = transition.targetName;
    let newSuffix = this.get('newSuffix');
    if (!isBlank(newSuffix) && webPage.substr(webPage.length - newSuffix.length) === newSuffix) {
      webPage = webPage.substr(0, webPage.length - newSuffix.length);
    }

    let userSettingsService = this.get('userSettingsService');
    userSettingsService.setCurrentWebPage(webPage);
    let developerUserSettings = this.get('developerUserSettings') || {};

    let componentName;
    for (componentName in developerUserSettings) {
      let componentDesc = developerUserSettings[componentName];
      switch (typeof componentDesc) {
        case 'string':
          developerUserSettings[componentName] = JSON.parse(componentDesc);
          break;
        case 'object':
          break;
        default:
          assert('Component description ' + 'developerUserSettings.' + componentName +
            'in /app/routes/' + transition.targetName + '.js must have types object or string', false);
      }
    }

    userSettingsService.setDefaultDeveloperUserSettings(developerUserSettings);
    return userSettingsService.setDeveloperUserSettings(developerUserSettings);
  },

  /**
    A hook you can implement to convert the URL into the model for this route.
    [More info](https://www.emberjs.com/api/ember/release/classes/Route/methods/model?anchor=model).

    @method model
    @param {Object} params
    @param {Object} transition
   */
  /* eslint-disable no-unused-vars */
  model(params, transition) {
    this._super.apply(this, arguments);

    let modelName = transition.queryParams.modelName || this.get('modelName');
    let modelProjName = this.get('modelProjection');

    // Get data from service in order to decide if it is necessary to reload data or not.
    // If already visited detail's route is observed or it is come back to agregators's route,
    // it is not necessary (otherwise data merge with loaded data can occur occasionally).
    let flexberryDetailInteractionService = this.get('flexberryDetailInteractionService');
    let modelCurrentNotSaved = flexberryDetailInteractionService.get('modelCurrentNotSaved');
    let modelSelectedDetail = flexberryDetailInteractionService.get('modelSelectedDetail');
    let needReload = !!(modelCurrentNotSaved || (modelSelectedDetail && modelSelectedDetail.get('hasDirtyAttributes')));

    // TODO: now 'findRecord' at ember-flexberry-projection not support 'reload: false' flag.
    let findRecordParameters = { reload: needReload, projection: modelProjName };

    // :id param defined in router.js
    return this.store.findRecord(modelName, params.id, findRecordParameters);
  },
  /* eslint-enable no-unused-vars */

  /**
    A hook you can use to reset controller values either when the model changes or the route is exiting.
    [More info](https://www.emberjs.com/api/ember/release/classes/Route/methods/resetController?anchor=resetController).

    @method resetController
    @param {Controller} controller
    @param {Boolean} isExisting
    @param {Object} transition
   */
  /* eslint-disable no-unused-vars */
  resetController(controller, isExisting, transition) {
    this._super.apply(this, arguments);
    controller.set('readonly', false);
    controller.set('parentRouteRecordId', undefined);
    let modelCurrentAgregators = controller.get('modelCurrentAgregators');
    let keptAgregators = modelCurrentAgregators && isArray(modelCurrentAgregators) ? modelCurrentAgregators.slice() : [];

    controller.send('dismissErrorMessages');
    controller.set('modelCurrentAgregatorPathes', undefined);
    controller.set('modelCurrentAgregators', undefined);

    // If flag 'modelNoRollBack' is set, leave current model as is and remove flag.
    if (controller.get('modelNoRollBack') === true) {
      controller.set('modelNoRollBack', false);
      return;
    }

    // If flag 'modelNoRollBack' is not set, we have to roll back this model and its agregators.
    let modelsToRollBack;
    let model = controller.get('model');
    if (this.get('flexberryDetailInteractionService').hasValues(keptAgregators)) {
      keptAgregators.push(model);
      keptAgregators.reverse();
      modelsToRollBack = keptAgregators;
    } else {
      modelsToRollBack = [model];
    }

    // Roll back all found agregators and its has-many relations.
    modelsToRollBack.forEach(function(processedModel) {
      if (processedModel) {
        processedModel.rollbackAll();
      }
    });
  },
  /* eslint-enable no-unused-vars */

  /**
    A hook you can use to setup the controller for the current route.
    [More info](https://www.emberjs.com/api/ember/release/classes/Route/methods/setupController?anchor=setupController).

    @method setupController
    @param {Controller} controller
    @param {Object} model
   */
  setupController(controller, model) {
    this._super(...arguments);

    // Define 'modelProjection' for controller instance.
    let modelClass = model.constructor;
    let modelProjName = this.get('modelProjection');
    let proj = modelClass.projections.get(modelProjName);
    controller.set('modelProjection', proj);
    controller.set('routeName', this.get('routeName'));
    controller.set('developerUserSettings', this.get('developerUserSettings'));
    if (isNone(controller.get('defaultDeveloperUserSettings'))) {
      controller.set('defaultDeveloperUserSettings', $.extend(true, {}, this.get('developerUserSettings')));
    }

    this.get('appState').reset();

    let parentRoute = this.get('parentRoute');
    if (!isNone(parentRoute)) {
      controller.set('parentRoute', parentRoute);
      controller.set('parentRouteRecordId', this.get('parentRouteRecordId'));
    }

    let flexberryDetailInteractionService = this.get('flexberryDetailInteractionService');
    let modelCurrentAgregatorPath = flexberryDetailInteractionService.get('modelCurrentAgregatorPathes');
    let modelCurrentAgregator = flexberryDetailInteractionService.get('modelCurrentAgregators');
    let modelLastUpdatedDetail = flexberryDetailInteractionService.get('modelLastUpdatedDetail');
    let saveBeforeRouteLeave = flexberryDetailInteractionService.get('saveBeforeRouteLeave');

    flexberryDetailInteractionService.set('modelSelectedDetail', undefined);
    flexberryDetailInteractionService.set('modelCurrentAgregators', undefined);
    flexberryDetailInteractionService.set('modelCurrentAgregatorPathes', undefined);
    flexberryDetailInteractionService.set('saveBeforeRouteLeave', undefined);

    flexberryDetailInteractionService.set('modelCurrentNotSaved', undefined);
    flexberryDetailInteractionService.set('modelLastUpdatedDetail', undefined);

    if (modelLastUpdatedDetail &&
          ((modelLastUpdatedDetail.get('isDeleted') && modelLastUpdatedDetail.get('id')) ||
              modelLastUpdatedDetail.get('hasDirtyAttributes'))) {
      // If detail changed, agregator has to be marked as changed.
      model.makeDirty();
    }

    let returnToAgregatorRoute = controller.get('returnToAgregatorRoute');
    if (!returnToAgregatorRoute) {
      // There is no need to set parameters to return to agregator.
      return;
    }

    if (flexberryDetailInteractionService.hasValues(modelCurrentAgregatorPath)) {
      controller.set('modelCurrentAgregatorPathes', modelCurrentAgregatorPath);
      controller.set('modelCurrentAgregators', modelCurrentAgregator);
      controller.set('saveBeforeRouteLeave', saveBeforeRouteLeave);
    }
  },
});