<commit_before>"use babel";
// @flow

import { Record } from "immutable";
import { lifecycle, withProps, withState } from "recompose";
import Rx from "rxjs/Rx";

function execStep(step, answers, ...data) {
  if (typeof step == "function") {
    const result = step(answers, ...data);
    if (result != null && typeof result == "object" && result.then) {
      return Rx.Observable.fromPromise(result);
    } else if (result instanceof Rx.Observable) {
      return result;
    } else {
      return Rx.Observable.create(obs => {
        obs.next(result);
        obs.complete();
      });
    }
  } else {
    return Rx.Observable.create(obs => {
      obs.next(step);
      obs.complete();
    });
  }
}

export default (questions, onAnswer) => Component =>
  withState("formState", "setFormState", () => {
    const Answers = Record(
      questions
        .map(q => q.name)
        .reduce((red, value) => Object.assign({}, red, { [value]: null }), {}),
    );
    const ReducerState = Record({
      index: 0,
      step: "when",
      answers: null,
      questions: null,
      prevState: null,
      loaded: null,
    });
    return new ReducerState({
      questions: questions,
      answers: new Answers(),
    });
  })(
    lifecycle({
      testQuestion() {
        execStep(
          this.props.formState.questions[this.props.formState.index].when ||
            true,
          this.props.formState.answers,
        )
          .toPromise()
          .then(
            response => {
              if (response) {
                this.props.setFormState(current =>
                  current.set("step", "loader"),
                );
              } else {
                this.props.setFormState(current =>
                  current.set("index", current.index + 1),
                );
              }
            },
            () => {},
          );
      },
      loadData() {
        execStep(
          this.props.formState.questions[this.props.formState.index].loader ||
            null,
          this.props.formState.answers,
        )
          .toPromise()
          .then(response => {
            this.props.setFormState(current =>
              current.set("step", "ask").set("loaded", response),
            );
          });
      },
      componentDidMount() {
        if (this.props.formState.step == "when") {
          this.testQuestion();
        }
      },
      componentDidUpdate(prevProps) {
        if (this.props.formState.index == this.props.formState.questions.length)
          onAnswer(this.props.formState.answers);
        else if (
          (prevProps.formState.step != "when" ||
            prevProps.formState.index != this.props.formState.index) &&
          this.props.formState.step == "when"
        ) {
          this.testQuestion();
        } else if (
          prevProps.formState.step == "when" &&
          this.props.formState.step == "loader"
        ) {
          this.loadData();
        }
      },
    })(
      withProps(props => ({
        onNext(data) {
          props.setFormState(current => current.set("step", "validation"));
          execStep(
            props.formState.questions[props.formState.index].validator || true,
            Object.assign({}, props.formState.answers, {
              [props.formState.questions[props.formState.index].name]: data,
            }),
            data,
          )
            .toPromise()
            .then(validated => {
              if (validated) {
                props.setFormState(current =>
                  current
                    .set("index", current.index + 1)
                    .setIn(
                      [
                        "answers",
                        props.formState.questions[props.formState.index].name,
                      ],
                      data,
                    )
                    .set("prevState", current.set("step", "ask"))
                    .set("loaded", null)
                    .set("step", "when"),
                );
              } else {
                props.setFormState(current => current.set("step", "ask"));
              }
            });
        },
        onPrev() {
          props.setFormState(props.formState.prevState);
        },
        onEscape() {
          onAnswer(null);
        },
        index: props.formState.index,
        step: props.formState.step,
        first: props.formState.prevState == null,
        questions: props.formState.questions.map(question => {
          let dflt =
            typeof question.default == "function"
              ? question.default(
                  props.formState.answers,
                  props.formState.loaded,
                )
              : question.default;
          dflt =
            typeof dflt == "string" ? { value: dflt, description: dflt } : dflt;
          const message =
            typeof question.message == "function"
              ? question.message(
                  props.formState.answers,
                  props.formState.loaded,
                )
              : question.message;
          const choices = (
            (typeof question.choices == "function"
              ? question.choices(
                  props.formState.answers,
                  props.formState.loaded,
                )
              : question.choices) || []
          ).map(
            choice =>
              typeof choice == "string"
                ? { value: choice, description: choice }
                : choice,
          );
          const accept =
            typeof question.accept == "string"
              ? { description: accept, value: true }
              : accept;
          const decline =
            typeof question.decline == "string"
              ? { description: decline, value: false }
              : decline;
          return {
            type: question.type,
            default: dflt,
            message: message,
            choices: choices,
            accept: accept,
            decline: decline,
          };
        }),
      }))(Component),
    ),
  );
<commit_msg>QuestionSystem: accept and decline is not define. (#410)<commit_after>"use babel";
// @flow

import { Record } from "immutable";
import { lifecycle, withProps, withState } from "recompose";
import Rx from "rxjs/Rx";

function execStep(step, answers, ...data) {
  if (typeof step == "function") {
    const result = step(answers, ...data);
    if (result != null && typeof result == "object" && result.then) {
      return Rx.Observable.fromPromise(result);
    } else if (result instanceof Rx.Observable) {
      return result;
    } else {
      return Rx.Observable.create(obs => {
        obs.next(result);
        obs.complete();
      });
    }
  } else {
    return Rx.Observable.create(obs => {
      obs.next(step);
      obs.complete();
    });
  }
}

export default (questions, onAnswer) => Component =>
  withState("formState", "setFormState", () => {
    const Answers = Record(
      questions
        .map(q => q.name)
        .reduce((red, value) => Object.assign({}, red, { [value]: null }), {}),
    );
    const ReducerState = Record({
      index: 0,
      step: "when",
      answers: null,
      questions: null,
      prevState: null,
      loaded: null,
    });
    return new ReducerState({
      questions: questions,
      answers: new Answers(),
    });
  })(
    lifecycle({
      testQuestion() {
        execStep(
          this.props.formState.questions[this.props.formState.index].when ||
            true,
          this.props.formState.answers,
        )
          .toPromise()
          .then(
            response => {
              if (response) {
                this.props.setFormState(current =>
                  current.set("step", "loader"),
                );
              } else {
                this.props.setFormState(current =>
                  current.set("index", current.index + 1),
                );
              }
            },
            () => {},
          );
      },
      loadData() {
        execStep(
          this.props.formState.questions[this.props.formState.index].loader ||
            null,
          this.props.formState.answers,
        )
          .toPromise()
          .then(response => {
            this.props.setFormState(current =>
              current.set("step", "ask").set("loaded", response),
            );
          });
      },
      componentDidMount() {
        if (this.props.formState.step == "when") {
          this.testQuestion();
        }
      },
      componentDidUpdate(prevProps) {
        if (this.props.formState.index == this.props.formState.questions.length)
          onAnswer(this.props.formState.answers);
        else if (
          (prevProps.formState.step != "when" ||
            prevProps.formState.index != this.props.formState.index) &&
          this.props.formState.step == "when"
        ) {
          this.testQuestion();
        } else if (
          prevProps.formState.step == "when" &&
          this.props.formState.step == "loader"
        ) {
          this.loadData();
        }
      },
    })(
      withProps(props => ({
        onNext(data) {
          props.setFormState(current => current.set("step", "validation"));
          execStep(
            props.formState.questions[props.formState.index].validator || true,
            Object.assign({}, props.formState.answers, {
              [props.formState.questions[props.formState.index].name]: data,
            }),
            data,
          )
            .toPromise()
            .then(validated => {
              if (validated) {
                props.setFormState(current =>
                  current
                    .set("index", current.index + 1)
                    .setIn(
                      [
                        "answers",
                        props.formState.questions[props.formState.index].name,
                      ],
                      data,
                    )
                    .set("prevState", current.set("step", "ask"))
                    .set("loaded", null)
                    .set("step", "when"),
                );
              } else {
                props.setFormState(current => current.set("step", "ask"));
              }
            });
        },
        onPrev() {
          props.setFormState(props.formState.prevState);
        },
        onEscape() {
          onAnswer(null);
        },
        index: props.formState.index,
        step: props.formState.step,
        first: props.formState.prevState == null,
        questions: props.formState.questions.map(question => {
          let dflt =
            typeof question.default == "function"
              ? question.default(
                  props.formState.answers,
                  props.formState.loaded,
                )
              : question.default;
          dflt =
            typeof dflt == "string" ? { value: dflt, description: dflt } : dflt;
          const message =
            typeof question.message == "function"
              ? question.message(
                  props.formState.answers,
                  props.formState.loaded,
                )
              : question.message;
          const choices = (
            (typeof question.choices == "function"
              ? question.choices(
                  props.formState.answers,
                  props.formState.loaded,
                )
              : question.choices) || []
          ).map(
            choice =>
              typeof choice == "string"
                ? { value: choice, description: choice }
                : choice,
          );
          const accept =
            typeof question.accept == "string"
              ? { description: question.accept, value: true }
              : question.accept;
          const decline =
            typeof question.decline == "string"
              ? { description: question.decline, value: false }
              : question.decline;
          return {
            type: question.type,
            default: dflt,
            message: message,
            choices: choices,
            accept: accept,
            decline: decline,
          };
        }),
      }))(Component),
    ),
  );
<|endoftext|>


<commit_before>var Backbone = require('backbone');
var $ = require('jquery');
var CoreView = require('backbone/core-view');
var VisDefinitionModel = require('../../data/vis-definition-model');
var CreationModalView = require('../../components/modals/creation/modal-creation-view');
var errorParser = require('../../helpers/error-parser');
var PanelWithOptionsView = require('../../components/view-options/panel-with-options-view');
var TabPaneView = require('../../components/tab-pane/tab-pane-view');
var TabPaneCollection = require('../../components/tab-pane/tab-pane-collection');
var Toggler = require('../../components/toggler/toggler-view');
var DatasetEditorView = require('./dataset-sql-view');
var ActionView = require('./dataset-actions-view');
var PreviewMapView = require('./preview-map-view');
var ActionViewEdition = require('./dataset-actions-edition-view');
var DataSQLModel = require('../data-sql-model');

module.exports = CoreView.extend({
  events: {
    'click .js-createMap': '_createMap'
  },

  initialize: function (opts) {
    if (!opts.router) throw new Error('router is required');
    if (!opts.tableModel) throw new Error('tableModel is required');
    if (!opts.modals) throw new Error('modals is required');
    if (!opts.visModel) throw new Error('visModel is required');
    if (!opts.syncModel) throw new Error('syncModel is required');
    if (!opts.userModel) throw new Error('userModel is required');
    if (!opts.querySchemaModel) throw new Error('querySchemaModel is required');
    if (!opts.configModel) throw new Error('configModel is required');
    if (!opts.editorModel) throw new Error('editorModel is required');
    if (!opts.layerDefinitionModel) throw new Error('layerDefinitionModel is required');

    this._tableModel = opts.tableModel;
    this._configModel = opts.configModel;
    this._userModel = opts.userModel;
    this._modals = opts.modals;
    this._querySchemaModel = opts.querySchemaModel;
    this._syncModel = opts.syncModel;
    this._visModel = opts.visModel;
    this._router = opts.router;
    this._editorModel = opts.editorModel;
    this._layerDefinitionModel = opts.layerDefinitionModel;

    if (!this._layerDefinitionModel.sqlModel) {
      var sqlHistory = this._layerDefinitionModel.options && this._layerDefinitionModel.options.sql_history;
      this._layerDefinitionModel.sqlModel = new DataSQLModel({
        content: this._querySchemaModel.get('query')
      }, {
        history: sqlHistory || []
      });
    }

    this._codemirrorModel = new Backbone.Model({
      content: this._querySchemaModel.get('query'),
      readonly: false
    });

    this._clearSQLModel = new Backbone.Model({
      visible: false
    });

    this._sqlModel = this._layerDefinitionModel.sqlModel;

    this._configPanes();
    this._initBinds();
  },

  render: function () {
    this.clearSubViews();
    this.$el.empty();
    this._initViews();
    this._checkClearButton();
    return this;
  },

  _initBinds: function () {
    this.listenTo(this._editorModel, 'change:edition', this._onChangeEdition);
    this.add_related_model(this._editorModel);

    this._querySchemaModel.bind('change:query_errors', this._showErrors, this);
    this.add_related_model(this._querySchemaModel);

    this._sqlModel.bind('undo redo', function () {
      this._codemirrorModel.set('content', this._sqlModel.get('content'));
    }, this);
    this.add_related_model(this._sqlModel);
  },

  _initViews: function () {
    var self = this;

    var panelWithOptionsView = new PanelWithOptionsView({
      editorModel: self._editorModel,
      createContentView: function () {
        return new TabPaneView({
          collection: self._collectionPane
        });
      },
      createControlView: function () {
        return new Toggler({
          editorModel: self._editorModel,
          labels: ['Metadata', 'SQL']
        });
      },
      createActionView: function () {
        return new TabPaneView({
          collection: self._collectionPane,
          createContentKey: 'createActionView'
        });
      }
    });

    this.$el.append(panelWithOptionsView.render().el);
    this.addView(panelWithOptionsView);
  },

  _onChangeEdition: function () {
    this.$el.toggleClass('is-dark', this._editorModel.isEditing());

    var edition = this._editorModel.get('edition');
    var index = edition ? 1 : 0;
    this._collectionPane.at(index).set({ selected: true });
  },

  _configPanes: function () {
    var self = this;
    var tabPaneTabs = [{
      selected: !this._editorModel.get('edition'),
      createContentView: function () {
        return new CoreView();
      },
      createActionView: function () {
        return new ActionView({
          mapAction: self._createMap.bind(self),
          previewAction: self._previewMap.bind(self)
        });
      }
    }, {
      selected: this._editorModel.get('edition'),
      createContentView: function () {
        return new DatasetEditorView({
          editorModel: self._editorModel,
          codemirrorModel: self._codemirrorModel,
          onApplyEvent: self._parseSQL.bind(self)
        });
      },
      createActionView: function () {
        return new ActionViewEdition({
          clearSQLModel: self._clearSQLModel,
          trackModel: self._sqlModel,
          editorModel: self._editorModel,
          onApply: self._parseSQL.bind(self),
          mapAction: self._createMap.bind(self),
          previewAction: self._previewMap.bind(self),
          onClear: self._clearSQL.bind(self)
        });
      }
    }];

    this._collectionPane = new TabPaneCollection(tabPaneTabs);
  },

  _parseSQL: function () {
    var self = this;
    var content = this._codemirrorModel.get('content');

    // Parser errors SQL here and saving
    this._querySchemaModel.set({
      query: content
    });

    this._querySchemaModel.fetch({
      success: self._saveSQL.bind(self)
    });
  },

  _showErrors: function (model) {
    var errors = this._querySchemaModel.get('query_errors');
    this._codemirrorModel.set('errors', this._parseErrors(errors));
  },

  _parseErrors: function (errors) {
    return errors.map(function (error) {
      return {
        message: error
      };
    });
  },

  _saveSQL: function () {
    var content = this._codemirrorModel.get('content');
    this._sqlModel.set('content', content);
    this._querySchemaModel.set('query_errors', []);
    this._layerDefinitionModel.save({
      sql: content
    });
    this._checkClearButton();
  },

  _clearSQL: function () {
    var sql = this._defaultSQL();
    this._codemirrorModel.set({content: sql});
    this._parseSQL();
  },

  _defaultSQL: function () {
    return 'SELECT * FROM ' + this._tableModel.getUnquotedName();
  },

  _checkClearButton: function () {
    var custom_sql = this._codemirrorModel.get('content').toLowerCase();
    var default_sql = this._defaultSQL().toLowerCase();
    this._clearSQLModel.set({visible: custom_sql !== default_sql});
  },

  _previewMap: function () {
    var previewMap = new PreviewMapView({
      tableModel: this._tableModel,
      configModel: this._configModel,
      querySchemaModel: this._querySchemaModel,
      syncModel: this._syncModel,
      userModel: this._userModel,
      visModel: this._visModel,
      modals: this._modals
    });
    $('body').append(previewMap.render().el);
    this.addView(previewMap);
  },

  _createMap: function () {
    var self = this;
    var tableName = this._tableModel.getUnquotedName();

    this._modals.create(function (modalModel) {
      return new CreationModalView({
        modalModel: modalModel,
        loadingTitle: _t('dataset.create-map.loading', { tableName: tableName }),
        errorTitle: _t('dataset.create-map.error', { tableName: tableName }),
        runAction: function (opts) {
          var newVisModel = new VisDefinitionModel({
            name: self._visModel.get('name') + ' ' + _t('editor.map')
          }, {
            configModel: self._configModel
          });

          newVisModel.save({
            source_visualization_id: self._visModel.get('id')
          }, {
            success: function (visModel) {
              window.location = visModel.builderURL();
            },
            error: function (mdl, e) {
              opts.error && opts.error(errorParser(e));
            }
          });
        }
      });
    });
  }

});
<commit_msg>Replace name in query.<commit_after>var Backbone = require('backbone');
var $ = require('jquery');
var CoreView = require('backbone/core-view');
var VisDefinitionModel = require('../../data/vis-definition-model');
var CreationModalView = require('../../components/modals/creation/modal-creation-view');
var errorParser = require('../../helpers/error-parser');
var PanelWithOptionsView = require('../../components/view-options/panel-with-options-view');
var TabPaneView = require('../../components/tab-pane/tab-pane-view');
var TabPaneCollection = require('../../components/tab-pane/tab-pane-collection');
var Toggler = require('../../components/toggler/toggler-view');
var DatasetEditorView = require('./dataset-sql-view');
var ActionView = require('./dataset-actions-view');
var PreviewMapView = require('./preview-map-view');
var ActionViewEdition = require('./dataset-actions-edition-view');
var DataSQLModel = require('../data-sql-model');

module.exports = CoreView.extend({
  events: {
    'click .js-createMap': '_createMap'
  },

  initialize: function (opts) {
    if (!opts.router) throw new Error('router is required');
    if (!opts.tableModel) throw new Error('tableModel is required');
    if (!opts.modals) throw new Error('modals is required');
    if (!opts.visModel) throw new Error('visModel is required');
    if (!opts.syncModel) throw new Error('syncModel is required');
    if (!opts.userModel) throw new Error('userModel is required');
    if (!opts.querySchemaModel) throw new Error('querySchemaModel is required');
    if (!opts.configModel) throw new Error('configModel is required');
    if (!opts.editorModel) throw new Error('editorModel is required');
    if (!opts.layerDefinitionModel) throw new Error('layerDefinitionModel is required');

    this._tableModel = opts.tableModel;
    this._configModel = opts.configModel;
    this._userModel = opts.userModel;
    this._modals = opts.modals;
    this._querySchemaModel = opts.querySchemaModel;
    this._syncModel = opts.syncModel;
    this._visModel = opts.visModel;
    this._router = opts.router;
    this._editorModel = opts.editorModel;
    this._layerDefinitionModel = opts.layerDefinitionModel;

    if (!this._layerDefinitionModel.sqlModel) {
      var sqlHistory = this._layerDefinitionModel.options && this._layerDefinitionModel.options.sql_history;
      this._layerDefinitionModel.sqlModel = new DataSQLModel({
        content: this._querySchemaModel.get('query')
      }, {
        history: sqlHistory || []
      });
    }

    this._codemirrorModel = new Backbone.Model({
      content: this._querySchemaModel.get('query'),
      readonly: false
    });

    this._clearSQLModel = new Backbone.Model({
      visible: false
    });

    this._sqlModel = this._layerDefinitionModel.sqlModel;

    this._configPanes();
    this._initBinds();
  },

  render: function () {
    this.clearSubViews();
    this.$el.empty();
    this._initViews();
    this._checkClearButton();
    return this;
  },

  _initBinds: function () {
    this.listenTo(this._editorModel, 'change:edition', this._onChangeEdition);
    this.add_related_model(this._editorModel);

    this._querySchemaModel.bind('change:query_errors', this._showErrors, this);
    this.add_related_model(this._querySchemaModel);

    this._visModel.on('change:name', this._onChangeName, this);
    this.add_related_model(this._visModel);

    this._sqlModel.bind('undo redo', function () {
      this._codemirrorModel.set('content', this._sqlModel.get('content'));
    }, this);
    this.add_related_model(this._sqlModel);
  },

  _onChangeName: function (model, name) {
    var oldName = model.previous('name');
    var newName = name;
    var content = this._codemirrorModel.get('content');
    var re = new RegExp(oldName, 'gi');
    var newContent = content.replace(re, newName);
    this._codemirrorModel.set('content', newContent);
  },

  _initViews: function () {
    var self = this;

    var panelWithOptionsView = new PanelWithOptionsView({
      editorModel: self._editorModel,
      createContentView: function () {
        return new TabPaneView({
          collection: self._collectionPane
        });
      },
      createControlView: function () {
        return new Toggler({
          editorModel: self._editorModel,
          labels: ['Metadata', 'SQL']
        });
      },
      createActionView: function () {
        return new TabPaneView({
          collection: self._collectionPane,
          createContentKey: 'createActionView'
        });
      }
    });

    this.$el.append(panelWithOptionsView.render().el);
    this.addView(panelWithOptionsView);
  },

  _onChangeEdition: function () {
    this.$el.toggleClass('is-dark', this._editorModel.isEditing());

    var edition = this._editorModel.get('edition');
    var index = edition ? 1 : 0;
    this._collectionPane.at(index).set({ selected: true });
  },

  _configPanes: function () {
    var self = this;
    var tabPaneTabs = [{
      selected: !this._editorModel.get('edition'),
      createContentView: function () {
        return new CoreView();
      },
      createActionView: function () {
        return new ActionView({
          mapAction: self._createMap.bind(self),
          previewAction: self._previewMap.bind(self)
        });
      }
    }, {
      selected: this._editorModel.get('edition'),
      createContentView: function () {
        return new DatasetEditorView({
          editorModel: self._editorModel,
          codemirrorModel: self._codemirrorModel,
          onApplyEvent: self._parseSQL.bind(self)
        });
      },
      createActionView: function () {
        return new ActionViewEdition({
          clearSQLModel: self._clearSQLModel,
          trackModel: self._sqlModel,
          editorModel: self._editorModel,
          onApply: self._parseSQL.bind(self),
          mapAction: self._createMap.bind(self),
          previewAction: self._previewMap.bind(self),
          onClear: self._clearSQL.bind(self)
        });
      }
    }];

    this._collectionPane = new TabPaneCollection(tabPaneTabs);
  },

  _parseSQL: function () {
    var self = this;
    var content = this._codemirrorModel.get('content');

    // Parser errors SQL here and saving
    this._querySchemaModel.set({
      query: content
    });

    this._querySchemaModel.fetch({
      success: self._saveSQL.bind(self)
    });
  },

  _showErrors: function (model) {
    var errors = this._querySchemaModel.get('query_errors');
    this._codemirrorModel.set('errors', this._parseErrors(errors));
  },

  _parseErrors: function (errors) {
    return errors.map(function (error) {
      return {
        message: error
      };
    });
  },

  _saveSQL: function () {
    var content = this._codemirrorModel.get('content');
    this._sqlModel.set('content', content);
    this._querySchemaModel.set('query_errors', []);
    this._layerDefinitionModel.save({
      sql: content
    });
    this._checkClearButton();
  },

  _clearSQL: function () {
    var sql = this._defaultSQL();
    this._codemirrorModel.set({content: sql});
    this._parseSQL();
  },

  _defaultSQL: function () {
    return 'SELECT * FROM ' + this._tableModel.getUnquotedName();
  },

  _checkClearButton: function () {
    var custom_sql = this._codemirrorModel.get('content').toLowerCase();
    var default_sql = this._defaultSQL().toLowerCase();
    this._clearSQLModel.set({visible: custom_sql !== default_sql});
  },

  _previewMap: function () {
    var previewMap = new PreviewMapView({
      tableModel: this._tableModel,
      configModel: this._configModel,
      querySchemaModel: this._querySchemaModel,
      syncModel: this._syncModel,
      userModel: this._userModel,
      visModel: this._visModel,
      modals: this._modals
    });
    $('body').append(previewMap.render().el);
    this.addView(previewMap);
  },

  _createMap: function () {
    var self = this;
    var tableName = this._tableModel.getUnquotedName();

    this._modals.create(function (modalModel) {
      return new CreationModalView({
        modalModel: modalModel,
        loadingTitle: _t('dataset.create-map.loading', { tableName: tableName }),
        errorTitle: _t('dataset.create-map.error', { tableName: tableName }),
        runAction: function (opts) {
          var newVisModel = new VisDefinitionModel({
            name: self._visModel.get('name') + ' ' + _t('editor.map')
          }, {
            configModel: self._configModel
          });

          newVisModel.save({
            source_visualization_id: self._visModel.get('id')
          }, {
            success: function (visModel) {
              window.location = visModel.builderURL();
            },
            error: function (mdl, e) {
              opts.error && opts.error(errorParser(e));
            }
          });
        }
      });
    });
  }

});
<|endoftext|>


<commit_before>import React from 'react'
import OneMp from './OneMp'
import styles from '../../../styles/views/results.css'

const ListOfMps = (props) => {
  const {
    mps,
    fractions,
    user_answers,
    selected_fractions,
    show_all_mps,
    topics,
    expanded_mp } = props

  const selected_mps = mps.filter(mp => selected_fractions.indexOf(mp.fraction_id) > -1 || selected_fractions.length === 0)
  return (

        Kuo didesnis procentas, tuo labiau Seimo narys atitinka Jūsų pažiūras.

      {(show_all_mps)
        ? selected_mps.map(mp => {
            let fraction = fractions.find((element, index, array) => mp.fraction_id === element.id) || {}
            return <OneMp mp={mp}
                          key={mp.id}
                          fraction={fraction}
                          topics={topics}
                          user_answers={user_answers}
                          expanded_mp={expanded_mp}
                          expandTopics={props.expandTopics} />
        })
        : [0, 1, 2, 3, 4, selected_mps.length-5, selected_mps.length-4, selected_mps.length-3, selected_mps.length-2, selected_mps.length-1].map(item => {
          let mp = selected_mps[item]
          let fraction = fractions.find((element, index, array) => mp.fraction_id === element.id) || {}
          return

            <OneMp mp={mp}
                   fraction={fraction}
                   topics={topics}
                   user_answers={user_answers}
                   expanded_mp={expanded_mp}
                   expandTopics={props.expandTopics} />
            {(item === 4)
              ?  props.showAllMps()}>
                   > Kiti {selected_mps.length - 4} parlamentarai <

              : null
            }

        })
      }

  )
}

export default ListOfMps
<commit_msg>Don't show mps when similarity is NaN<commit_after>import React from 'react'
import OneMp from './OneMp'
import styles from '../../../styles/views/results.css'

const ListOfMps = (props) => {
  const {
    mps,
    fractions,
    user_answers,
    selected_fractions,
    show_all_mps,
    topics,
    expanded_mp } = props

  const selected_mps = mps.filter(mp => selected_fractions.indexOf(mp.fraction_id) > -1 || selected_fractions.length === 0)
  return (

        Kuo didesnis procentas, tuo labiau Seimo narys atitinka Jūsų pažiūras.

      {(show_all_mps)
        ? selected_mps.map(mp => {
            let fraction = fractions.find((element, index, array) => mp.fraction_id === element.id) || {}
            if (!isNaN(mp.similarity))
                return <OneMp mp={mp}
                              key={mp.id}
                              fraction={fraction}
                              topics={topics}
                              user_answers={user_answers}
                              expanded_mp={expanded_mp}
                              expandTopics={props.expandTopics} />
        })
        : [0, 1, 2, 3, 4, selected_mps.length-5, selected_mps.length-4, selected_mps.length-3, selected_mps.length-2, selected_mps.length-1].map(item => {
          let mp = selected_mps[item]
          let fraction = fractions.find((element, index, array) => mp.fraction_id === element.id) || {}
          return

            <OneMp mp={mp}
                   fraction={fraction}
                   topics={topics}
                   user_answers={user_answers}
                   expanded_mp={expanded_mp}
                   expandTopics={props.expandTopics} />
            {(item === 4)
              ?  props.showAllMps()}>
                   > Kiti {selected_mps.length - 4} parlamentarai <

              : null
            }

        })
      }

  )
}

export default ListOfMps
<|endoftext|>


<commit_before>const fs = require('fs')
const merge = require('lodash.merge')
const stripIndent = require('common-tags/lib/stripIndent')
const utils = require('../server/helpers/utils')
const logger = require('../server/logger')
const crypto = require('crypto')
// @ts-ignore
const { version } = require('../../package.json')

/**
 * Reads all companion configuration set via environment variables
 * and via the config file path
 *
 * @returns {object}
 */
exports.getCompanionOptions = () => {
  return merge({}, getConfigFromEnv(), getConfigFromFile())
}

/**
 * Loads the config from environment variables
 *
 * @returns {object}
 */
const getConfigFromEnv = () => {
  const uploadUrls = process.env.COMPANION_UPLOAD_URLS
  const domains = process.env.COMPANION_DOMAINS || process.env.COMPANION_DOMAIN || null
  const validHosts = domains ? domains.split(',') : []

  return {
    providerOptions: {
      google: {
        key: process.env.COMPANION_GOOGLE_KEY,
        secret: getSecret('COMPANION_GOOGLE_SECRET')
      },
      dropbox: {
        key: process.env.COMPANION_DROPBOX_KEY,
        secret: getSecret('COMPANION_DROPBOX_SECRET')
      },
      instagram: {
        key: process.env.COMPANION_INSTAGRAM_KEY,
        secret: getSecret('COMPANION_INSTAGRAM_SECRET')
      },
      facebook: {
        key: process.env.COMPANION_FACEBOOK_KEY,
        secret: getSecret('COMPANION_FACEBOOK_SECRET')
      },
      microsoft: {
        key: process.env.COMPANION_ONEDRIVE_KEY,
        secret: getSecret('COMPANION_ONEDRIVE_SECRET')
      },
      s3: {
        key: process.env.COMPANION_AWS_KEY,
        secret: getSecret('COMPANION_AWS_SECRET'),
        bucket: process.env.COMPANION_AWS_BUCKET,
        endpoint: process.env.COMPANION_AWS_ENDPOINT,
        region: process.env.COMPANION_AWS_REGION,
        useAccelerateEndpoint:
          process.env.COMPANION_AWS_USE_ACCELERATE_ENDPOINT === 'true',
        expires: parseInt(process.env.COMPANION_AWS_EXPIRES || '300', 10),
        acl: process.env.COMPANION_AWS_ACL || 'public-read'
      }
    },
    server: {
      host: process.env.COMPANION_DOMAIN,
      protocol: process.env.COMPANION_PROTOCOL,
      path: process.env.COMPANION_PATH,
      implicitPath: process.env.COMPANION_IMPLICIT_PATH,
      oauthDomain: process.env.COMPANION_OAUTH_DOMAIN,
      validHosts: validHosts
    },
    filePath: process.env.COMPANION_DATADIR,
    redisUrl: process.env.COMPANION_REDIS_URL,
    // adding redisOptions to keep all companion options easily visible
    //  redisOptions refers to https://www.npmjs.com/package/redis#options-object-properties
    redisOptions: {},
    sendSelfEndpoint: process.env.COMPANION_SELF_ENDPOINT,
    uploadUrls: uploadUrls ? uploadUrls.split(',') : null,
    secret: getSecret('COMPANION_SECRET') || generateSecret(),
    debug: process.env.NODE_ENV !== 'production',
    // TODO: this is a temporary hack to support distributed systems.
    // it is not documented, because it should be changed soon.
    cookieDomain: process.env.COMPANION_COOKIE_DOMAIN,
    multipleInstances: true
  }
}

/**
 * Tries to read the secret from a file if the according environment variable is set.
 * Otherwise it falls back to the standard secret environment variable.
 *
 * @param {string} baseEnvVar
 *
 * @returns {string}
 */
const getSecret = (baseEnvVar) => {
  return `${baseEnvVar}_FILE` in process.env
    ? fs.readFileSync(process.env[`${baseEnvVar}_FILE`]).toString()
    : process.env[baseEnvVar]
}

/**
 * Auto-generates server secret
 *
 * @returns {string}
 */
const generateSecret = () => {
  logger.warn('auto-generating server secret because none was specified', 'startup.secret')
  return crypto.randomBytes(64).toString('hex')
}

/**
 * Loads the config from a file and returns it as an object
 *
 * @returns {object}
 */
const getConfigFromFile = () => {
  const path = getConfigPath()
  if (!path) return {}

  const rawdata = fs.readFileSync(getConfigPath())
  // @ts-ignore
  return JSON.parse(rawdata)
}

/**
 * Returns the config path specified via cli arguments
 *
 * @returns {string}
 */
const getConfigPath = () => {
  let configPath

  for (let i = process.argv.length - 1; i >= 0; i--) {
    const isConfigFlag = process.argv[i] === '-c' || process.argv[i] === '--config'
    const flagHasValue = i + 1 <= process.argv.length
    if (isConfigFlag && flagHasValue) {
      configPath = process.argv[i + 1]
      break
    }
  }

  return configPath
}

/**
 * validates that the mandatory companion options are set.
 * If it is invalid, it will console an error of unset options and exits the process.
 * If it is valid, nothing happens.
 *
 * @param {object} config
 */
exports.validateConfig = (config) => {
  const mandatoryOptions = ['secret', 'filePath', 'server.host']
  /** @type {string[]} */
  const unspecified = []

  mandatoryOptions.forEach((i) => {
    const value = i.split('.').reduce((prev, curr) => prev[curr], config)

    if (!value) unspecified.push(`"${i}"`)
  })

  // vaidate that all required config is specified
  if (unspecified.length) {
    console.error('\x1b[31m', 'Please specify the following options',
      'to run companion as Standalone:\n', unspecified.join(',\n'), '\x1b[0m')
    process.exit(1)
  }

  // validate that specified filePath is writeable/readable.
  // TODO: consider moving this into the companion module itself.
  try {
    // @ts-ignore
    fs.accessSync(`${config.filePath}`, fs.R_OK | fs.W_OK)
  } catch (err) {
    console.error('\x1b[31m', `No access to "${config.filePath}".`,
      'Please ensure the directory exists and with read/write permissions.', '\x1b[0m')
    process.exit(1)
  }
}

/**
 *
 * @param {string} url
 */
exports.hasProtocol = (url) => {
  return url.startsWith('http://') || url.startsWith('https://')
}

exports.buildHelpfulStartupMessage = (companionOptions) => {
  const buildURL = utils.getURLBuilder(companionOptions)
  const callbackURLs = []
  Object.keys(companionOptions.providerOptions).forEach((providerName) => {
    // s3 does not need redirect_uris
    if (providerName === 's3') {
      return
    }

    callbackURLs.push(buildURL(`/connect/${providerName}/callback`, true))
  })

  return stripIndent`
    Welcome to Companion v${version}
    ===================================

    Congratulations on setting up Companion! Thanks for joining our cause, you have taken
    the first step towards the future of file uploading! We
    hope you are as excited about this as we are!

    While you did an awesome job on getting Companion running, this is just the welcome
    message, so let's talk about the places that really matter:

    - Be sure to add ${callbackURLs.join(', ')} as your Oauth redirect uris on their corresponding developer interfaces.
    - The URL ${buildURL('/metrics', true)} is available for  statistics to keep Companion running smoothly
    - https://github.com/transloadit/uppy/issues - report your bugs here

    So quit lollygagging, start uploading and experience the future!
  `
}
<commit_msg>companion: set debug based on NODE_ENV only if the env is available to begin with (#2189)<commit_after>const fs = require('fs')
const merge = require('lodash.merge')
const stripIndent = require('common-tags/lib/stripIndent')
const utils = require('../server/helpers/utils')
const logger = require('../server/logger')
const crypto = require('crypto')
// @ts-ignore
const { version } = require('../../package.json')

/**
 * Reads all companion configuration set via environment variables
 * and via the config file path
 *
 * @returns {object}
 */
exports.getCompanionOptions = () => {
  return merge({}, getConfigFromEnv(), getConfigFromFile())
}

/**
 * Loads the config from environment variables
 *
 * @returns {object}
 */
const getConfigFromEnv = () => {
  const uploadUrls = process.env.COMPANION_UPLOAD_URLS
  const domains = process.env.COMPANION_DOMAINS || process.env.COMPANION_DOMAIN || null
  const validHosts = domains ? domains.split(',') : []

  return {
    providerOptions: {
      google: {
        key: process.env.COMPANION_GOOGLE_KEY,
        secret: getSecret('COMPANION_GOOGLE_SECRET')
      },
      dropbox: {
        key: process.env.COMPANION_DROPBOX_KEY,
        secret: getSecret('COMPANION_DROPBOX_SECRET')
      },
      instagram: {
        key: process.env.COMPANION_INSTAGRAM_KEY,
        secret: getSecret('COMPANION_INSTAGRAM_SECRET')
      },
      facebook: {
        key: process.env.COMPANION_FACEBOOK_KEY,
        secret: getSecret('COMPANION_FACEBOOK_SECRET')
      },
      microsoft: {
        key: process.env.COMPANION_ONEDRIVE_KEY,
        secret: getSecret('COMPANION_ONEDRIVE_SECRET')
      },
      s3: {
        key: process.env.COMPANION_AWS_KEY,
        secret: getSecret('COMPANION_AWS_SECRET'),
        bucket: process.env.COMPANION_AWS_BUCKET,
        endpoint: process.env.COMPANION_AWS_ENDPOINT,
        region: process.env.COMPANION_AWS_REGION,
        useAccelerateEndpoint:
          process.env.COMPANION_AWS_USE_ACCELERATE_ENDPOINT === 'true',
        expires: parseInt(process.env.COMPANION_AWS_EXPIRES || '300', 10),
        acl: process.env.COMPANION_AWS_ACL || 'public-read'
      }
    },
    server: {
      host: process.env.COMPANION_DOMAIN,
      protocol: process.env.COMPANION_PROTOCOL,
      path: process.env.COMPANION_PATH,
      implicitPath: process.env.COMPANION_IMPLICIT_PATH,
      oauthDomain: process.env.COMPANION_OAUTH_DOMAIN,
      validHosts: validHosts
    },
    filePath: process.env.COMPANION_DATADIR,
    redisUrl: process.env.COMPANION_REDIS_URL,
    // adding redisOptions to keep all companion options easily visible
    //  redisOptions refers to https://www.npmjs.com/package/redis#options-object-properties
    redisOptions: {},
    sendSelfEndpoint: process.env.COMPANION_SELF_ENDPOINT,
    uploadUrls: uploadUrls ? uploadUrls.split(',') : null,
    secret: getSecret('COMPANION_SECRET') || generateSecret(),
    debug: process.env.NODE_ENV && process.env.NODE_ENV !== 'production',
    // TODO: this is a temporary hack to support distributed systems.
    // it is not documented, because it should be changed soon.
    cookieDomain: process.env.COMPANION_COOKIE_DOMAIN,
    multipleInstances: true
  }
}

/**
 * Tries to read the secret from a file if the according environment variable is set.
 * Otherwise it falls back to the standard secret environment variable.
 *
 * @param {string} baseEnvVar
 *
 * @returns {string}
 */
const getSecret = (baseEnvVar) => {
  return `${baseEnvVar}_FILE` in process.env
    ? fs.readFileSync(process.env[`${baseEnvVar}_FILE`]).toString()
    : process.env[baseEnvVar]
}

/**
 * Auto-generates server secret
 *
 * @returns {string}
 */
const generateSecret = () => {
  logger.warn('auto-generating server secret because none was specified', 'startup.secret')
  return crypto.randomBytes(64).toString('hex')
}

/**
 * Loads the config from a file and returns it as an object
 *
 * @returns {object}
 */
const getConfigFromFile = () => {
  const path = getConfigPath()
  if (!path) return {}

  const rawdata = fs.readFileSync(getConfigPath())
  // @ts-ignore
  return JSON.parse(rawdata)
}

/**
 * Returns the config path specified via cli arguments
 *
 * @returns {string}
 */
const getConfigPath = () => {
  let configPath

  for (let i = process.argv.length - 1; i >= 0; i--) {
    const isConfigFlag = process.argv[i] === '-c' || process.argv[i] === '--config'
    const flagHasValue = i + 1 <= process.argv.length
    if (isConfigFlag && flagHasValue) {
      configPath = process.argv[i + 1]
      break
    }
  }

  return configPath
}

/**
 * validates that the mandatory companion options are set.
 * If it is invalid, it will console an error of unset options and exits the process.
 * If it is valid, nothing happens.
 *
 * @param {object} config
 */
exports.validateConfig = (config) => {
  const mandatoryOptions = ['secret', 'filePath', 'server.host']
  /** @type {string[]} */
  const unspecified = []

  mandatoryOptions.forEach((i) => {
    const value = i.split('.').reduce((prev, curr) => prev[curr], config)

    if (!value) unspecified.push(`"${i}"`)
  })

  // vaidate that all required config is specified
  if (unspecified.length) {
    console.error('\x1b[31m', 'Please specify the following options',
      'to run companion as Standalone:\n', unspecified.join(',\n'), '\x1b[0m')
    process.exit(1)
  }

  // validate that specified filePath is writeable/readable.
  // TODO: consider moving this into the companion module itself.
  try {
    // @ts-ignore
    fs.accessSync(`${config.filePath}`, fs.R_OK | fs.W_OK)
  } catch (err) {
    console.error('\x1b[31m', `No access to "${config.filePath}".`,
      'Please ensure the directory exists and with read/write permissions.', '\x1b[0m')
    process.exit(1)
  }
}

/**
 *
 * @param {string} url
 */
exports.hasProtocol = (url) => {
  return url.startsWith('http://') || url.startsWith('https://')
}

exports.buildHelpfulStartupMessage = (companionOptions) => {
  const buildURL = utils.getURLBuilder(companionOptions)
  const callbackURLs = []
  Object.keys(companionOptions.providerOptions).forEach((providerName) => {
    // s3 does not need redirect_uris
    if (providerName === 's3') {
      return
    }

    callbackURLs.push(buildURL(`/connect/${providerName}/callback`, true))
  })

  return stripIndent`
    Welcome to Companion v${version}
    ===================================

    Congratulations on setting up Companion! Thanks for joining our cause, you have taken
    the first step towards the future of file uploading! We
    hope you are as excited about this as we are!

    While you did an awesome job on getting Companion running, this is just the welcome
    message, so let's talk about the places that really matter:

    - Be sure to add ${callbackURLs.join(', ')} as your Oauth redirect uris on their corresponding developer interfaces.
    - The URL ${buildURL('/metrics', true)} is available for  statistics to keep Companion running smoothly
    - https://github.com/transloadit/uppy/issues - report your bugs here

    So quit lollygagging, start uploading and experience the future!
  `
}
<|endoftext|>


<commit_before>import React from "react";

import { storiesOf } from "@storybook/react";
import { action } from "@storybook/addon-actions";
import { text, select, boolean } from "@storybook/addon-knobs/react";
import { withInfo } from "@storybook/addon-info";
import { makeSelectOptions } from "@hig/storybook/utils";

import { Button } from "hig-react";
import Banner from "../Banner";

const typeOptions = makeSelectOptions(Banner.types);
const placementOptions = makeSelectOptions(Banner.placements);

const knobGroupIds = {
  basic: "Basic",
  animation: "Animation",
  a11y: "Accessibility",
  actions: "Actions"
};

const knobLabels = {
  type: "Style",
  children: "Message",
  placement: "Placement",
  isVisible: "Visible",
  label: "Label",
  dismissButtonTitle: "Dismiss title",
  onDismiss: "Banner dismissed"
};

function getBannerKnobs(props) {
  const {
    type,
    placement,
    children,
    isVisible = true,
    label,
    dismissButtonTitle,
    onDismiss,
    ...otherProps
  } = props;

  return {
    ...otherProps,
    type: select(knobLabels.type, typeOptions, type, knobGroupIds.basic),
    children: text(knobLabels.children, children, knobGroupIds.basic),
    placement: select(
      knobLabels.placement,
      placementOptions,
      placement,
      knobGroupIds.animation
    ),
    isVisible: boolean(knobLabels.isVisible, isVisible, knobGroupIds.animation),
    label: text(knobLabels.label, label, knobLabels.a11y),
    dismissButtonTitle: text(
      knobLabels.dismissButtonTitle,
      dismissButtonTitle,
      knobGroupIds.a11y
    ),
    onDismiss: action(knobLabels.onDismiss, onDismiss, knobGroupIds.actions)
  };
}

function BannerDemo(props) {
  const { children, ...otherProps } = getBannerKnobs(props);

  return (
    <div style={{ marginBottom: "15px" }}>
      <Banner {...otherProps}>{children}</Banner>
    </div>
  );
}

function BannerStory({ props }) {
  return <BannerDemo {...props} />;
}

const stories = [
  {
    description: "default",
    props: {}
  },
  {
    description: "verbose, with interactions",
    props: {
      type: Banner.types.WARNING,
      children:
        // eslint-disable-next-line max-len
        "PROCESS COMPLETE: Changes have been made to you document. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam.",
      /** @todo Cleanup/refactor */
      actions: ({ isWrappingActions }) => (
        <Banner.Interactions isWrappingActions={isWrappingActions}>
          <Banner.Action>
            <Button
              type="secondary"
              size="small"
              width={isWrappingActions ? "grow" : "shrink"}
              title={text("Resolve text", "Accept Changes")}
            />
          </Banner.Action>
          <Banner.Action>
            <Button
              type="secondary"
              size="small"
              width={isWrappingActions ? "grow" : "shrink"}
              title={text("Reject text", "Reject Changes")}
            />
          </Banner.Action>
        </Banner.Interactions>
      )
    }
  }
];

const bannerStories = storiesOf("Banner", module);

stories.forEach(({ description, props }) => {
  bannerStories.add(description, withInfo({
    propTables: [Banner]
  })(() => <BannerStory props={props} />));
});
<commit_msg>Refactor Banner story so story source is readable<commit_after>import React from "react";

import { storiesOf } from "@storybook/react";
import { action } from "@storybook/addon-actions";
import { text, select, boolean } from "@storybook/addon-knobs/react";
import { withInfo } from "@storybook/addon-info";
import { makeSelectOptions } from "@hig/storybook/utils";

import { Button } from "hig-react";
import Banner from "../Banner";

const typeOptions = makeSelectOptions(Banner.types);
const placementOptions = makeSelectOptions(Banner.placements);

const knobGroupIds = {
  basic: "Basic",
  animation: "Animation",
  a11y: "Accessibility",
  actions: "Actions"
};

const knobLabels = {
  type: "Style",
  children: "Message",
  placement: "Placement",
  isVisible: "Visible",
  label: "Label",
  dismissButtonTitle: "Dismiss title",
  onDismiss: "Banner dismissed"
};

function getBannerKnobs(props) {
  const {
    type,
    placement,
    children,
    isVisible = true,
    label,
    dismissButtonTitle,
    onDismiss,
    ...otherProps
  } = props;

  return {
    ...otherProps,
    type: select(knobLabels.type, typeOptions, type, knobGroupIds.basic),
    children: text(knobLabels.children, children, knobGroupIds.basic),
    placement: select(
      knobLabels.placement,
      placementOptions,
      placement,
      knobGroupIds.animation
    ),
    isVisible: boolean(knobLabels.isVisible, isVisible, knobGroupIds.animation),
    label: text(knobLabels.label, label, knobLabels.a11y),
    dismissButtonTitle: text(
      knobLabels.dismissButtonTitle,
      dismissButtonTitle,
      knobGroupIds.a11y
    ),
    onDismiss: action(knobLabels.onDismiss, onDismiss, knobGroupIds.actions)
  };
}

const bannerStories = storiesOf("Banner", module);

bannerStories.add("default", withInfo({
  propTables: [Banner]
})(() => {
  const { children, ...otherProps } = getBannerKnobs({});
  return (<Banner {...otherProps}>{children}</Banner>)
}));

bannerStories.add("verbose, with interactions", withInfo({
  propTables: [Banner]
})(() => {
  const props = {
    type: Banner.types.WARNING,
      children:
        // eslint-disable-next-line max-len
        "PROCESS COMPLETE: Changes have been made to you document. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam.",
      /** @todo Cleanup/refactor */
      actions: ({ isWrappingActions }) => (
        <Banner.Interactions isWrappingActions={isWrappingActions}>
          <Banner.Action>
            <Button
              type="secondary"
              size="small"
              width={isWrappingActions ? "grow" : "shrink"}
              title={text("Resolve text", "Accept Changes")}
            />
          </Banner.Action>
          <Banner.Action>
            <Button
              type="secondary"
              size="small"
              width={isWrappingActions ? "grow" : "shrink"}
              title={text("Reject text", "Reject Changes")}
            />
          </Banner.Action>
        </Banner.Interactions>
      )
  }
  const { children, ...otherProps } = getBannerKnobs(props);
  return (<Banner {...otherProps}>{children}</Banner>)
}));
<|endoftext|>


<commit_before>/**
 * @fileoverview
 * Structure routines utilizing OpenBabel library.
 * @author Partridge Jiang
 */

/*
 * requires /lan/classes.js
 * requires /core/kekule.common.js
 * requires /io/kekule.io.js
 * requires /core/kekule.chemUtils.js
 * requires /_extras/OpenBabel/kekule.openbabel.adapters.js
 * requires /_extras/kekule.emscriptenUtils.js
 * requires /xbrowsers/kekule.x.js
 * requires /calculation/kekule.calc.base.js
 * requires /localization
 */

(function(){
"use strict";

/** @ignore */
var EU = Kekule.EmscriptenUtils;
/** @ignore */
var OB = Kekule.OpenBabel;
/** @ignore */
var AU = Kekule.OpenBabel.AdaptUtils;

/**
 * Util class to handle structures using OpenBabel
 * @object
 */
Kekule.OpenBabel.StructUtils = {
	/**
	 * Generate new structure with 2D coords.
	 * @param {Kekule.StructureFragment} mol
	 * @param {Hash} options Options to generate 2D structure. Currently omitted.
	 * @returns {Kekule.StructureFragment} New molecule instance that containing all 3D coords.
	 */
	generate2DStructure: function(mol, options)
	{
		var op = options || {};
		try
		{
			var obMol = AU.kObjToOB(mol);
			if (!Kekule.OpenBabel.StructUtils._gen2DByObOperation(obMol, op))  // failed
			{
				obMol['delete']();
				obMol = null
			}

			if (!obMol)  // failed
			{
				Kekule.raise(Kekule.$L('ErrorMsg.OpenBabel.FAIL_TO_GENERATE_3D_STRUCTURE'));
			}
			else  // success
			{
				// fetch back coords of obMol to mol
				var mol = AU.obObjToKekule(obMol);
				//console.log(mol3D);
			}
		}
		finally
		{
			if (obMol)
				obMol['delete']();
		}

		return mol;
	},
	/**
	 * Generate new structure with 3D coords of mol.
	 * Note: mol should not contain any sub groups.
	 * @param {Kekule.StructureFragment} mol
	 * @param {Hash} options Options to generate 3D structure, may including fields: {speed, 'applyFFCalc', 'forceField'}.
	 * @returns {Kekule.StructureFragment} New molecule instance that containing all 3D coords.
	 */
	generate3DStructure: function(mol, options)
	{
		var op = options || {};
		var forceFieldName = op.forceField;
		try
		{
			//var obMol = AU.kObjToOB(mol);

			/*
			var r = _obGen.generate3DStructure(obMol, forceFieldName || 'MMFF94');
			if (r < 0)  // less than 0 means error occurs
			{
				console.log('error', r);
				//Kekule.raise(Kekule.$L('ErrorMsg.OpenBabel.FAIL_TO_GENERATE_3D_STRUCTURE'));
			}
			*/
			var obMol;
			if (op.applyFFCalc)
			{
				var _obGen = new (OB.getClassCtor('OB3DGenWrapper'))();
				try
				{
					var data = Kekule.IO.saveFormatData(mol, Kekule.IO.DataFormat.MOL);
					obMol = _obGen.generate3DStructureFromMolData(data, forceFieldName || '');
				} finally
				{
					_obGen['delete']();
				}
			}
			else
			{
				obMol = AU.kObjToOB(mol);
				if (!Kekule.OpenBabel.StructUtils._gen3DByObOperation(obMol, op))  // failed
				{
					obMol['delete']();
					obMol = null
				}
			}
			if (!obMol)  // failed
			{
				Kekule.raise(Kekule.$L('ErrorMsg.OpenBabel.FAIL_TO_GENERATE_3D_STRUCTURE'));
			}
			else  // success
			{
				// fetch back coords of obMol to mol
				var mol3D = AU.obObjToKekule(obMol);
				//console.log(mol3D);
			}
		}
		finally
		{
			if (obMol)
				obMol['delete']();
		}

		return mol3D;
	},
	/** @private */
	_gen2DByObOperation: function(obMol, dimension, options)
	{
		var result = false;
		var Module = OB.getModule();
		var gen2d = Module['OBOp'].FindType('Gen2D');
		if (gen2d)
		{
			gen2d.Do(obMol, speed);
			result = true;
		}
		return result;
	},
	/** @private */
	_gen3DByObOperation: function(obMol, options)
	{
		var speed = ('' + options.speed) || '';  // ensure speed is string
		var result = false;

		var Module = OB.getModule();
		var gen3d = Module['OBOp'].FindType('Gen3D');
		if (gen3d)
		{
			gen3d.Do(obMol, speed);
			result = true;
		}

		return result;
	}
};

if (Kekule.Calculator)
{

	/**
	 * Class to generate 2D/3D structure from 3D/2D or 0D one utilizing Open Babel lib.
	 * @class
	 * @augments Kekule.Calculator.AbstractStructureGenerator
	 */
	Kekule.Calculator.ObStructureBaseGenerator = Class.create(Kekule.Calculator.AbstractStructureGenerator,
	/** @lends Kekule.Calculator.ObStructureBaseGenerator# */
	{
		/** @private */
		CLASS_NAME: 'Kekule.Calculator.ObStructureBaseGenerator',
		/** @private */
		getOutputDimension: function()  // descendants should override this to decide generating 2D or 3D structure
		{
			return 3;  // default one
		},
		/** @private */
		_getInputMsgName: function()
		{
			return 'gen' + this.getOutputDimension() + 'D';
		},
		/** @private */
		_getOutputMsgName: function()
		{
			return 'output' + this.getOutputDimension() + 'D';
		},
		/** @private */
		getObInitOptions: function()
		{
			return Kekule.OpenBabel.getObInitOptions();
		},
		/** @private */
		getForceField: function()
		{
			return this.getOptions().forceField;
		},
		/** @ignore */
		createWorker: function(/*$super*/)
		{
			var w = this.tryApplySuper('createWorker')  /* $super() */;
			if (w)
			{
				//var url = Kekule.getScriptPath() + '_extras/OpenBabel/openbabel.js.O1';
				var url = Kekule.OpenBabel.getObScriptUrl();
				this.importWorkerScriptFile(url);
				var initOps = this.getObInitOptions();
				this.postWorkerMessage({
					'type': 'obInit',
					'usingModulaize': initOps.usingModulaize,
					'moduleName': initOps.moduleName,
					'initCallbackName': initOps.moduleInitCallbackName
				});
			}
			return w;
		},
		/** @ignore */
		getWorkerScriptFile: function()
		{
			//return this.getWorkerBasePath() + 'kekule.worker.obStructureGenerator.js';
			var result = Kekule.OpenBabel.getObPath() + 'kekule.worker.obStructureGenerator.js'; //'workers/kekule.worker.obStructureGenerator.js';
			return result;
		},
		/** @ignore */
		doReactWorkerMessage: function(/*$super, */data, e)
		{
			this.tryApplySuper('doReactWorkerMessage', [data, e])  /* $super(data, e) */;
			if (data.type === /*'output3D'*/this._getOutputMsgName())  // receive generated structure
			{
				var genData = data.molData;
				if (genData)  // successful
				{
					var m = Kekule.IO.loadMimeData(genData, 'chemical/x-mdl-molfile');
					this.setGeneratedMol(m);
					this.done();
				}
			}
		},
		/** @ignore */
		workerStartCalc: function(worker)
		{
			var mol = this.getSourceMol();
			var molData = Kekule.IO.saveMimeData(mol, 'chemical/x-mdl-molfile');
			var msg = Object.extend(this.getOptions(), {'type': /*'gen3D'*/this._getInputMsgName(), 'molData': molData});
			this.postWorkerMessage(msg);
		},

		/** @ignore */
		executeSync: function(callback)
		{
			if (Kekule.OpenBabel && document)
			{
				var self = this;
				Kekule.OpenBabel.loadObScript(document, function()
				{
					var err;
					try
					{
						var mol = Kekule.OpenBabel.StructUtils.generate3DStructure(self.getSourceMol(), /*self.getForceField()*/self.getOptions());
						self.setGeneratedMol(mol);
					}
					catch (e)
					{
						err = e;
					}
					if (callback)
						callback(err);
				});
			}
			else
			{
				Kekule.error(Kekule.$L('ErrorMsg.MODULE_NOT_LOADED').format('OpenBabel'));
			}
			return false;
		}
	});

	/**
	 * Class to generate 3D structure from 0D/2D one utilizing Open Babel lib.
	 * @class
	 * @augments Kekule.Calculator.ObStructureBaseGenerator
	 */
	Kekule.Calculator.ObStructure3DGenerator = Class.create(Kekule.Calculator.ObStructureBaseGenerator,
	/** @lends Kekule.Calculator.ObStructure3DGenerator# */
	{
		/** @private */
		CLASS_NAME: 'Kekule.Calculator.ObStructure3DGenerator',
		/** @ignore */
		getOutputDimension: function()
		{
			return 3;
		}
	});

	/**
	 * Class to generate 2D structure from 0D/2D one utilizing Open Babel lib.
	 * @class
	 * @augments Kekule.Calculator.ObStructureBaseGenerator
	 */
	Kekule.Calculator.ObStructure2DGenerator = Class.create(Kekule.Calculator.ObStructureBaseGenerator,
	/** @lends Kekule.Calculator.ObStructure2DGenerator# */
	{
		/** @private */
		CLASS_NAME: 'Kekule.Calculator.ObStructure2DGenerator',
		/** @ignore */
		getOutputDimension: function()
		{
			return 2;
		}
	});

	Kekule.Calculator.ServiceManager.register(Kekule.Calculator.Services.GEN3D, Kekule.Calculator.ObStructure3DGenerator);
	Kekule.Calculator.ServiceManager.register(Kekule.Calculator.Services.GEN2D, Kekule.Calculator.ObStructure2DGenerator);

}

})();<commit_msg>Refine 2D/3D coords generator functions of OpenBabel<commit_after>/**
 * @fileoverview
 * Structure routines utilizing OpenBabel library.
 * @author Partridge Jiang
 */

/*
 * requires /lan/classes.js
 * requires /core/kekule.common.js
 * requires /io/kekule.io.js
 * requires /core/kekule.chemUtils.js
 * requires /_extras/OpenBabel/kekule.openbabel.adapters.js
 * requires /_extras/kekule.emscriptenUtils.js
 * requires /xbrowsers/kekule.x.js
 * requires /calculation/kekule.calc.base.js
 * requires /localization
 */

(function(){
"use strict";

/** @ignore */
var EU = Kekule.EmscriptenUtils;
/** @ignore */
var OB = Kekule.OpenBabel;
/** @ignore */
var AU = Kekule.OpenBabel.AdaptUtils;

/**
 * Util class to handle structures using OpenBabel
 * @object
 */
Kekule.OpenBabel.StructUtils = {
	/**
	 * Generate new structure with 2D coords.
	 * @param {Kekule.StructureFragment} mol
	 * @param {Hash} options Options to generate 2D structure. Currently omitted.
	 * @returns {Kekule.StructureFragment} New molecule instance that containing all 3D coords.
	 */
	generate2DStructure: function(mol, options, childObjMap)
	{
		var mol;
		var op = options || {};
		try
		{
			var srcToObMap = new Kekule.MapEx();
			var obToDestMap = new Kekule.MapEx();

			var obMol = AU.kObjToOB(mol, null, srcToObMap);
			if (!Kekule.OpenBabel.StructUtils._gen2DByObOperation(obMol, op))  // failed
			{
				obMol['delete']();
				obMol = null
			}

			if (!obMol)  // failed
			{
				Kekule.raise(Kekule.$L('ErrorMsg.OpenBabel.FAIL_TO_GENERATE_3D_STRUCTURE'));
			}
			else  // success
			{
				// fetch back coords of obMol to mol
				mol = AU.obObjToKekule(obMol, null, obToDestMap);
				//console.log(mol3D);
				if (childObjMap)  // fill the map from src to dest
				{
					var keyObjs = srcToObMap.getKeys();
					for (var i = 0, l = keyObjs.length; i < l; ++i)
					{
						var keyObj = keyObjs[i];
						var obObj = srcToObMap.get(keyObj);
						if (obObj)
						{
							var destObj = obToDestMap.get(obObj);
							if (destObj)
								childObjMap.set(keyObj, destObj);
						}
					}
				}
			}
		}
		finally
		{
			if (obMol)
				obMol['delete']();
		}

		return mol;
	},
	/**
	 * Generate new structure with 3D coords of mol.
	 * Note: mol should not contain any sub groups.
	 * @param {Kekule.StructureFragment} mol
	 * @param {Hash} options Options to generate 3D structure, may including fields: {speed, 'applyFFCalc', 'forceField'}.
	 * @returns {Kekule.StructureFragment} New molecule instance that containing all 3D coords.
	 */
	generate3DStructure: function(mol, options, childObjMap)
	{
		var mol3D;
		var op = options || {};
		var forceFieldName = op.forceField;
		try
		{
			//var obMol = AU.kObjToOB(mol);

			/*
			var r = _obGen.generate3DStructure(obMol, forceFieldName || 'MMFF94');
			if (r < 0)  // less than 0 means error occurs
			{
				console.log('error', r);
				//Kekule.raise(Kekule.$L('ErrorMsg.OpenBabel.FAIL_TO_GENERATE_3D_STRUCTURE'));
			}
			*/
			var srcToObMap = new Kekule.MapEx();
			var obToDestMap = new Kekule.MapEx();

			var obMol = AU.kObjToOB(mol, null, srcToObMap);
			if (op.applyFFCalc)
			{
				var _obGen = new (OB.getClassCtor('OB3DGenWrapper'))();
				try
				{
					/*
					var data = Kekule.IO.saveFormatData(mol, Kekule.IO.DataFormat.MOL);
					obMol = _obGen.generate3DStructureFromMolData(data, forceFieldName || '');
					*/
					_obGen.generate3DStructure(obMol, forceFieldName || '');
				} finally
				{
					_obGen['delete']();
				}
			}
			else
			{
				if (!Kekule.OpenBabel.StructUtils._gen3DByObOperation(obMol, op))  // failed
				{
					obMol['delete']();
					obMol = null
				}
			}
			if (!obMol)  // failed
			{
				Kekule.raise(Kekule.$L('ErrorMsg.OpenBabel.FAIL_TO_GENERATE_3D_STRUCTURE'));
			}
			else  // success
			{
				// fetch back coords of obMol to mol
				mol3D = AU.obObjToKekule(obMol, null, obToDestMap);
				//console.log(mol3D);
				if (childObjMap)  // fill the map from src to dest
				{
					var keyObjs = srcToObMap.getKeys();
					for (var i = 0, l = keyObjs.length; i < l; ++i)
					{
						var keyObj = keyObjs[i];
						var obObj = srcToObMap.get(keyObj);
						if (obObj)
						{
							var destObj = obToDestMap.get(obObj);
							if (destObj)
								childObjMap.set(keyObj, destObj);
						}
					}
				}
			}
		}
		finally
		{
			if (obMol)
				obMol['delete']();
		}

		return mol3D;
	},
	/** @private */
	_gen2DByObOperation: function(obMol, options)
	{
		var result = false;
		var Module = OB.getModule();
		var gen2d = Module['OBOp'].FindType('Gen2D');
		if (gen2d)
		{
			gen2d.Do(obMol, speed);
			result = true;
		}
		return result;
	},
	/** @private */
	_gen3DByObOperation: function(obMol, options)
	{
		var speed = ('' + options.speed) || '';  // ensure speed is string
		var result = false;

		var Module = OB.getModule();
		var gen3d = Module['OBOp'].FindType('Gen3D');
		if (gen3d)
		{
			gen3d.Do(obMol, speed);
			result = true;
		}

		return result;
	}
};

if (Kekule.Calculator)
{

	/**
	 * Class to generate 2D/3D structure from 3D/2D or 0D one utilizing Open Babel lib.
	 * @class
	 * @augments Kekule.Calculator.AbstractStructureGenerator
	 */
	Kekule.Calculator.ObStructureBaseGenerator = Class.create(Kekule.Calculator.AbstractStructureGenerator,
	/** @lends Kekule.Calculator.ObStructureBaseGenerator# */
	{
		/** @private */
		CLASS_NAME: 'Kekule.Calculator.ObStructureBaseGenerator',
		/** @ignore */
		getGeneratorCoordMode: function()
		{
			var dim = this.getOutputDimension();
			return (dim === 2)? Kekule.CoordMode.COORD2D: Kekule.CoordMode.COORD3D;
		},
		/** @private */
		getOutputDimension: function()  // descendants should override this to decide generating 2D or 3D structure
		{
			return 3;  // default one
		},
		/** @private */
		_getInputMsgName: function()
		{
			return 'gen' + this.getOutputDimension() + 'D';
		},
		/** @private */
		_getOutputMsgName: function()
		{
			return 'output' + this.getOutputDimension() + 'D';
		},
		/** @private */
		getObInitOptions: function()
		{
			return Kekule.OpenBabel.getObInitOptions();
		},
		/** @private */
		getForceField: function()
		{
			return this.getOptions().forceField;
		},
		/** @ignore */
		createWorker: function(/*$super*/)
		{
			var w = this.tryApplySuper('createWorker')  /* $super() */;
			if (w)
			{
				//var url = Kekule.getScriptPath() + '_extras/OpenBabel/openbabel.js.O1';
				var url = Kekule.OpenBabel.getObScriptUrl();
				this.importWorkerScriptFile(url);
				var initOps = this.getObInitOptions();
				this.postWorkerMessage({
					'type': 'obInit',
					'usingModulaize': initOps.usingModulaize,
					'moduleName': initOps.moduleName,
					'initCallbackName': initOps.moduleInitCallbackName
				});
			}
			return w;
		},
		/** @ignore */
		getWorkerScriptFile: function()
		{
			//return this.getWorkerBasePath() + 'kekule.worker.obStructureGenerator.js';
			var result = Kekule.OpenBabel.getObPath() + 'kekule.worker.obStructureGenerator.js'; //'workers/kekule.worker.obStructureGenerator.js';
			return result;
		},
		/** @ignore */
		doReactWorkerMessage: function(/*$super, */data, e)
		{
			this.tryApplySuper('doReactWorkerMessage', [data, e])  /* $super(data, e) */;
			if (data.type === /*'output3D'*/this._getOutputMsgName())  // receive generated structure
			{
				var genData = data.molData;
				if (genData)  // successful
				{
					var m = Kekule.IO.loadMimeData(genData, 'chemical/x-mdl-molfile');
					var childObjMap = this.getChildObjMap();
					if (childObjMap)  // fill the map, since we transform the molecule by MOL format data, sequences of atoms/bonds are our only clue
					{
						var srcMol = this.getSourceMol().getFlattenedShadowFragment(true);
						for (var i = 0, l = srcMol.getNodeCount(); i < l; ++i)
						{
							childObjMap.set(srcMol.getNodeAt(i), m.getNodeAt(i));
						}
						for (var i = 0, l = srcMol.getConnectorCount(); i < l; ++i)
						{
							childObjMap.set(srcMol.getConnectorAt(i), m.getConnectorAt(i));
						}
					}
					this.setGeneratedMol(m);
					this.done();
				}
			}
		},
		/** @ignore */
		workerStartCalc: function(worker)
		{
			var mol = this.getSourceMol();
			var flattenMol = mol.getFlattenedShadowFragment(true);
			//var molData = Kekule.IO.saveMimeData(mol, 'chemical/x-mdl-molfile');
			var molData = Kekule.IO.saveMimeData(flattenMol, 'chemical/x-mdl-molfile');
			var msg = Object.extend(this.getOptions(), {'type': /*'gen3D'*/this._getInputMsgName(), 'molData': molData});
			this.postWorkerMessage(msg);
		},

		/** @ignore */
		doExecuteSync: function(callback)
		{
			if (Kekule.OpenBabel)
			{
				var self = this;
				Kekule.OpenBabel.loadObScript(null, function()
				{
					var err;
					try
					{
						var mol = Kekule.OpenBabel.StructUtils.generate3DStructure(self.getSourceMol(), /*self.getForceField()*/self.getOptions());
						self.setGeneratedMol(mol);
					}
					catch (e)
					{
						err = e;
					}

					if (!err)  // successful
						self.done();
					if (callback)
						callback(err);

					return true;
				});
			}
			else
			{
				Kekule.error(Kekule.$L('ErrorMsg.MODULE_NOT_LOADED').format('OpenBabel'));
			}
			return false;
		}
	});

	/**
	 * Class to generate 3D structure from 0D/2D one utilizing Open Babel lib.
	 * @class
	 * @augments Kekule.Calculator.ObStructureBaseGenerator
	 */
	Kekule.Calculator.ObStructure3DGenerator = Class.create(Kekule.Calculator.ObStructureBaseGenerator,
	/** @lends Kekule.Calculator.ObStructure3DGenerator# */
	{
		/** @private */
		CLASS_NAME: 'Kekule.Calculator.ObStructure3DGenerator',
		/** @ignore */
		getOutputDimension: function()
		{
			return 3;
		}
	});

	/**
	 * Class to generate 2D structure from 0D/2D one utilizing Open Babel lib.
	 * @class
	 * @augments Kekule.Calculator.ObStructureBaseGenerator
	 */
	Kekule.Calculator.ObStructure2DGenerator = Class.create(Kekule.Calculator.ObStructureBaseGenerator,
	/** @lends Kekule.Calculator.ObStructure2DGenerator# */
	{
		/** @private */
		CLASS_NAME: 'Kekule.Calculator.ObStructure2DGenerator',
		/** @ignore */
		getOutputDimension: function()
		{
			return 2;
		}
	});

	Kekule.Calculator.ServiceManager.register(Kekule.Calculator.Services.GEN3D, Kekule.Calculator.ObStructure3DGenerator, 'openbabel', 10);
	Kekule.Calculator.ServiceManager.register(Kekule.Calculator.Services.GEN2D, Kekule.Calculator.ObStructure2DGenerator, 'openbabel', 10);

}

})();<|endoftext|>


<commit_before>// ==========================================================================
// Project:   Ember - JavaScript Application Framework
// Copyright: ©2006-2011 Strobe Inc. and contributors.
//            Portions ©2008-2011 Apple Inc. All rights reserved.
// License:   Licensed under MIT license (see license.js)
// ==========================================================================

require('ember-views/views/container_view');
require('ember-runtime/system/string');

var get = Ember.get, set = Ember.set, fmt = Ember.String.fmt;

/**
  @class
  @since Ember 0.9
  @extends Ember.View
*/
Ember.CollectionView = Ember.ContainerView.extend(
/** @scope Ember.CollectionView.prototype */ {

  /**
    A list of items to be displayed by the Ember.CollectionView.

    @type Ember.Array
    @default null
  */
  content: null,

  /**
    An optional view to display if content is set to an empty array.

    @type Ember.View
    @default null
  */
  emptyView: null,

  /**
    @type Ember.View
    @default Ember.View
  */
  itemViewClass: Ember.View,

  init: function() {
    var ret = this._super();
    this._contentDidChange();
    return ret;
  },

  _contentWillChange: Ember.beforeObserver(function() {
    var content = this.get('content');

    if (content) { content.removeArrayObserver(this); }
    var len = content ? get(content, 'length') : 0;
    this.arrayWillChange(content, 0, len);
  }, 'content'),

  /**
    @private

    Check to make sure that the content has changed, and if so,
    update the children directly. This is always scheduled
    asynchronously, to allow the element to be created before
    bindings have synchronized and vice versa.
  */
  _contentDidChange: Ember.observer(function() {
    var content = get(this, 'content');

    if (content) {
      ember_assert(fmt("an Ember.CollectionView's content must implement Ember.Array. You passed %@", [content]), Ember.Array.detectInstance(content));
      content.addArrayObserver(this);
    }

    var len = content ? get(content, 'length') : 0;
    this.arrayDidChange(content, 0, null, len);
  }, 'content'),

  destroy: function() {
    var content = get(this, 'content');
    if (content) { content.removeArrayObserver(this); }

    this._super();

    return this;
  },

  arrayWillChange: function(content, start, removedCount) {
    // If the contents were empty before and this template collection has an
    // empty view remove it now.
    var emptyView = get(this, 'emptyView');
    if (emptyView && emptyView instanceof Ember.View) {
      emptyView.removeFromParent();
    }

    // Loop through child views that correspond with the removed items.
    // Note that we loop from the end of the array to the beginning because
    // we are mutating it as we go.
    var childViews = get(this, 'childViews'), childView, idx, len;

    len = get(childViews, 'length');
    for (idx = start + removedCount - 1; idx >= start; idx--) {
      childViews[idx].destroy();
    }
  },

  /**
    Called when a mutation to the underlying content array occurs.

    This method will replay that mutation against the views that compose the
    Ember.CollectionView, ensuring that the view reflects the model.

    This array observer is added in contentDidChange.

    @param {Array} addedObjects
      the objects that were added to the content

    @param {Array} removedObjects
      the objects that were removed from the content

    @param {Number} changeIndex
      the index at which the changes occurred
  */
  arrayDidChange: function(content, start, removed, added) {
    var itemViewClass = get(this, 'itemViewClass'),
        childViews = get(this, 'childViews'),
        addedViews = [], view, item, idx, len, itemTagName;

    if ('string' === typeof itemViewClass) {
      itemViewClass = Ember.getPath(itemViewClass);
    }

    ember_assert(fmt("itemViewClass must be a subclass of Ember.View, not %@", [itemViewClass]), Ember.View.detect(itemViewClass));

    len = content ? get(content, 'length') : 0;
    if (len) {
      for (idx = start; idx < start+added; idx++) {
        item = content.objectAt(idx);

        view = this.createChildView(itemViewClass, {
          content: item,
          contentIndex: idx
        });

        addedViews.push(view);
      }
    } else {
      var emptyView = get(this, 'emptyView');
      if (!emptyView) { return; }

      emptyView = this.createChildView(emptyView);
      addedViews.push(emptyView);
      set(this, 'emptyView', emptyView);
    }

    childViews.replace(start, 0, addedViews);
  },

  createChildView: function(view, attrs) {
    view = this._super(view, attrs);

    var itemTagName = get(view, 'tagName');
    var tagName = (itemTagName === null || itemTagName === undefined) ? Ember.CollectionView.CONTAINER_MAP[get(this, 'tagName')] : itemTagName;

    set(view, 'tagName', tagName);

    return view;
  }
});

/**
  @static

  A map of parent tags to their default child tags. You can add
  additional parent tags if you want collection views that use
  a particular parent tag to default to a child tag.

  @type Hash
  @constant
*/
Ember.CollectionView.CONTAINER_MAP = {
  ul: 'li',
  ol: 'li',
  table: 'tr',
  thead: 'tr',
  tbody: 'tr',
  tfoot: 'tr',
  tr: 'td',
  select: 'option'
};
<commit_msg>Mixins should use detect, not detectInstance<commit_after>// ==========================================================================
// Project:   Ember - JavaScript Application Framework
// Copyright: ©2006-2011 Strobe Inc. and contributors.
//            Portions ©2008-2011 Apple Inc. All rights reserved.
// License:   Licensed under MIT license (see license.js)
// ==========================================================================

require('ember-views/views/container_view');
require('ember-runtime/system/string');

var get = Ember.get, set = Ember.set, fmt = Ember.String.fmt;

/**
  @class
  @since Ember 0.9
  @extends Ember.View
*/
Ember.CollectionView = Ember.ContainerView.extend(
/** @scope Ember.CollectionView.prototype */ {

  /**
    A list of items to be displayed by the Ember.CollectionView.

    @type Ember.Array
    @default null
  */
  content: null,

  /**
    An optional view to display if content is set to an empty array.

    @type Ember.View
    @default null
  */
  emptyView: null,

  /**
    @type Ember.View
    @default Ember.View
  */
  itemViewClass: Ember.View,

  init: function() {
    var ret = this._super();
    this._contentDidChange();
    return ret;
  },

  _contentWillChange: Ember.beforeObserver(function() {
    var content = this.get('content');

    if (content) { content.removeArrayObserver(this); }
    var len = content ? get(content, 'length') : 0;
    this.arrayWillChange(content, 0, len);
  }, 'content'),

  /**
    @private

    Check to make sure that the content has changed, and if so,
    update the children directly. This is always scheduled
    asynchronously, to allow the element to be created before
    bindings have synchronized and vice versa.
  */
  _contentDidChange: Ember.observer(function() {
    var content = get(this, 'content');

    if (content) {
      ember_assert(fmt("an Ember.CollectionView's content must implement Ember.Array. You passed %@", [content]), Ember.Array.detect(content));
      content.addArrayObserver(this);
    }

    var len = content ? get(content, 'length') : 0;
    this.arrayDidChange(content, 0, null, len);
  }, 'content'),

  destroy: function() {
    var content = get(this, 'content');
    if (content) { content.removeArrayObserver(this); }

    this._super();

    return this;
  },

  arrayWillChange: function(content, start, removedCount) {
    // If the contents were empty before and this template collection has an
    // empty view remove it now.
    var emptyView = get(this, 'emptyView');
    if (emptyView && emptyView instanceof Ember.View) {
      emptyView.removeFromParent();
    }

    // Loop through child views that correspond with the removed items.
    // Note that we loop from the end of the array to the beginning because
    // we are mutating it as we go.
    var childViews = get(this, 'childViews'), childView, idx, len;

    len = get(childViews, 'length');
    for (idx = start + removedCount - 1; idx >= start; idx--) {
      childViews[idx].destroy();
    }
  },

  /**
    Called when a mutation to the underlying content array occurs.

    This method will replay that mutation against the views that compose the
    Ember.CollectionView, ensuring that the view reflects the model.

    This array observer is added in contentDidChange.

    @param {Array} addedObjects
      the objects that were added to the content

    @param {Array} removedObjects
      the objects that were removed from the content

    @param {Number} changeIndex
      the index at which the changes occurred
  */
  arrayDidChange: function(content, start, removed, added) {
    var itemViewClass = get(this, 'itemViewClass'),
        childViews = get(this, 'childViews'),
        addedViews = [], view, item, idx, len, itemTagName;

    if ('string' === typeof itemViewClass) {
      itemViewClass = Ember.getPath(itemViewClass);
    }

    ember_assert(fmt("itemViewClass must be a subclass of Ember.View, not %@", [itemViewClass]), Ember.View.detect(itemViewClass));

    len = content ? get(content, 'length') : 0;
    if (len) {
      for (idx = start; idx < start+added; idx++) {
        item = content.objectAt(idx);

        view = this.createChildView(itemViewClass, {
          content: item,
          contentIndex: idx
        });

        addedViews.push(view);
      }
    } else {
      var emptyView = get(this, 'emptyView');
      if (!emptyView) { return; }

      emptyView = this.createChildView(emptyView);
      addedViews.push(emptyView);
      set(this, 'emptyView', emptyView);
    }

    childViews.replace(start, 0, addedViews);
  },

  createChildView: function(view, attrs) {
    view = this._super(view, attrs);

    var itemTagName = get(view, 'tagName');
    var tagName = (itemTagName === null || itemTagName === undefined) ? Ember.CollectionView.CONTAINER_MAP[get(this, 'tagName')] : itemTagName;

    set(view, 'tagName', tagName);

    return view;
  }
});

/**
  @static

  A map of parent tags to their default child tags. You can add
  additional parent tags if you want collection views that use
  a particular parent tag to default to a child tag.

  @type Hash
  @constant
*/
Ember.CollectionView.CONTAINER_MAP = {
  ul: 'li',
  ol: 'li',
  table: 'tr',
  thead: 'tr',
  tbody: 'tr',
  tfoot: 'tr',
  tr: 'td',
  select: 'option'
};
<|endoftext|>