<commit_before>import AbstractGenerator from './AbstractGenerator';
import InsertIntoStatement from './InsertIntoStatement';
import Random from './../Random';

/*
 * Abstract output class. Should be inherited by all classes whose goal is to generate code from an Entity object.
 */
export default class AbstractSQLGenerator extends AbstractGenerator {

  constructor(options = {}) {
    super(options);
    this.results = {
      'create': {},
      'drop': {},
      'insert-into': {}
    };
  }

  addEntity(entity) {
    super.addEntity(entity);

    if (this.options['insert-into'])
      this.results['insert-into'][entity.plural.toLowerCase()] = [];
  }

  /**
   * Used in rare cases like when `name === 'user'` which is not allowed in PostgreSQL unless quoted (e.g. "user"). Its the responsibility of this method to do so.
   */
  escapeColumnName(name) {
    return name;
  }

  /*
   * Should generate code based on the 'entities' array.
   */
  generate() {
    if (!(this.options.create || this.options.drop || this.options['insert-into']))
      throw 'You must specify an operation as CLI argument, one of --create / --drop / --insert-into <count>';

    if (this.options.create)
      this.generateCreate();
    if (this.options.drop)
      this.generateDrop();
    if (this.options['insert-into']) {
      var n = 10;

      if (typeof this.options['insert-into'] === 'number')
        n = this.options['insert-into'];

      this.generateInserts(n);
    }
  }

  generateAttributes(e) {
    var self = this;
    var str = '';

    this.indentation++;
    e.attributes.forEach(function(attr, i) {
      str += self.indent() + attr.name + ' ' + self.toSQLType(attr).toUpperCase();

      if (attr.primaryKey) {
        str += ' PRIMARY KEY';

        if (self.getAutoIncrementString())
          str += ' ' + self.getAutoIncrementString();
      }
      else if (attr.required)
        str += ' NOT NULL';
      else {
        str += ' DEFAULT ' + self.toSQLValue(attr, true);
      }

      if (!attr.primaryKey && attr.unique)
        str += ' UNIQUE';

      if (i != (e.attributes.length - 1))
        str += ',\n';
    });

    if ((e.attributes.length > 0) && (e.references.length > 0))
      str += ',\n';

    e.references.forEach(function(ref, i) {
      str += self.indent() + self.escapeColumnName(ref.alias) + ' ' + self.toSQLType({ type: 'Integer' });

      if (ref.nullable)
        str += ' DEFAULT NULL';
      else {
        str += ' NOT NULL';

        if (ref.defaultValue !== undefined)
          str += ' DEFAULT ' + self.toSQLValue({
            defaultValue: ref.defaultValue,
            type: 'Integer'
          });
      }

      if (i < (e.references.length - 1))
        str += ',\n';
    });
    this.indentation--;

    return str;
  }

  generateCreate() {
    this.sortEntities();
    var self = this;

    this.entities.forEach(function(e, i) {
      var str = '';

      str += 'CREATE TABLE ' + e.plural + ' (\n';
      str += self.generateAttributes(e);

      if (e.references.length > 0) {
        str += ',\n';
        str += '\n';
        str += self.generateForeignKeys(e);
      }

      str += '\n';
      str += ');';

      self.results['create'][e.plural.toLowerCase()] = str;
    });
  }

  generateDrop() {
    this.sortEntities();
    this.entities.reverse();
    var self = this;

    this.entities.forEach(function(e, i) {
      var str = '';

      str += 'DROP TABLE IF EXISTS ' + e.plural + ';';

      self.results['drop'][e.plural.toLowerCase()] = str;
    });
  }

  generateForeignKeys(entity) {
    var e = entity;
    var self = this;
    var str = '';

    this.indentation++;
    e.references.forEach(function(ref, i) {
      str += self.indent() + 'FOREIGN KEY (' + self.escapeColumnName(ref.alias) + ') REFERENCES ' + ref.entity.plural + ' (' + ref.attribute + ')';

      if (i < (e.references.length - 1)) {
        str += ',\n';
      }
    });
    this.indentation--;

    return str;
  }

  generateInserts(n) {
    this.sortEntities();
    var self = this;

    this.entities.forEach(function(e, i) {
      for (var i = 0; i < n; i++) {
        var values = {};

        e.attributes.forEach(function(attr) {
          if (attr.primaryKey)
            return;

          if (attr.defaultValueIsFunction || attr.defaultValueIsRaw)
            values[attr.name] = self.toSQLValue(attr);
          else {
            values[attr.name] = self.toSQLValue({
              defaultValue: Random.value(attr),
              type: attr.type
            });
          }
        });
        e.references.forEach(function(ref) {
          var otherRefs = [];

          if (values[ref.alias] === undefined) // If no foreign key id set for this reference yet
            values[ref.alias] = Random.integer(1, n); // Choose a random foreign key id from the number of insert statements generated

          e.references.forEach(function(ref2) {
            if (ref2 == ref)
              return;

            otherRefs = otherRefs.concat(
              ref2.entity.references.filter(function(ref3) {
                return (ref3.entity === ref.entity)
                  && (ref3.attribute === ref.attribute);
              })
            );
          });

          // If another reference from this entity points to an entity having a reference to the same Entity-Attribute pair as the current reference
          if (otherRefs.length > 0) {
            // Ensure that the value for this foreign key is the same as the other entity's foreign key's value as they should both point to the same table record (for data integrity)

            otherRefs.forEach(function(ref3) {
              var referencedEntityName = ref3.source.plural.toLowerCase();

              if (self.results['insert-into'][referencedEntityName] === undefined)
                return; // No inserts for this entity

              var ref2 = e.references.filter(function(r) {
                return (r.source === ref.source) && (r.entity === ref3.source);
              })[0];
              // Look for an insert statement which has a foreign key to the same table & field and which value is the same as the randomly generated current foreign key id
              var inserts = self.results['insert-into'][referencedEntityName]
                .filter(function(val, i) {
                  return (val.values[ref3.alias] === values[ref.alias]);
                }
              );

              if (inserts.length === 0) // No inserts on the second table with the same value for the same foreign key
                values[ref2.alias] = null;
              else {
                // Choose randomly between the matching inserts
                values[ref2.alias] = self.results['insert-into'][referencedEntityName]
                  .indexOf(inserts[Random.integer(1, inserts.length) - 1]) + 1;
              }
            });
          }
        });

        var stmt = new InsertIntoStatement(self, e, values);
        self.results['insert-into'][e.plural.toLowerCase()].push(stmt);
      }
    });
  }

  getAllowedOptions() {
    return {
      'create': 'For each entity, will generate the SQL query to create the related database table.',
      'drop': 'For each entity, will generate the SQL query to drop the related database table.',
      'insert-into <rows-count>': 'For each entity, will generate <rows-count> SQL queries to insert randomly generated data in the related database table.'
    };
  }

  getAutoIncrementString() {
    return '';
  }

  getContent(fileName) {
    var content = '';

    if (fileName === 'execute.sh')
      return this.getExecuteScriptContent();

    if (~fileName.indexOf('-database')) {
      var ope = fileName.substring(0, fileName.lastIndexOf('-database'));

      if (ope === 'insert-into') {

        this.sortEntities();

        for (let entity of this.entities) {
          content += this.results[ope][entity.plural.toLowerCase()].join('\n') + '\n\n';
        }
      }
      else {
        for (let key of Object.keys(this.results[ope])) {
          content += this.results[ope][key] + '\n\n';
        }
      }
    }
    else {
      var ope = fileName.substring(0, fileName.lastIndexOf('-table'));
      var ent = fileName.substring(fileName.lastIndexOf('-') + 1, fileName.lastIndexOf('.'));

      if (ope === 'insert-into')
        content = this.results[ope][ent].join('\n') + '\n';
      else
        content = this.results[ope][ent] + '\n';
    }

    return content;
  }

  /*
   * Should return the content of the 'execute.sh' file placed in every output directory after generation to execute generated SQL files.
   *
   * Must be overrided by sub-classes.
   */
  getExecuteScriptContent() {
    return null;
  }

  getOutputFilesNames() {
    var allowedOptions = [ 'create', 'drop', 'insert-into' ];
    var names = [];
    var operation;
    var context;

    for (var opt of allowedOptions) {
      if (this.entities.length === 1)
        names.push(opt + '-table-' + this.entities[0].plural.toLowerCase() + '.sql');
      else {
        names.push(opt + '-database.sql');
      }
    }

    names.push('execute.sh');

    return names;
  }

  /*
   * Returns `this.indentation * 2` whitespaces (e.g. 2, 4...).
   */
  indent() {
    var str = '';

    for (var i = 0; i < this.indentation * 2; i++)
      str += ' ';

    return str;
  }

  sortEntities() {
    this.entities.sort(function(a, b) {
      return a.references.length - b.references.length;
    });
  }

  /**
   * Returns the SQL type corresponding to the given Jane attribute's type (e.g. VARCHAR(<...>) for String etc.) with desired length if appropriated (e.g. VARCHAR(255) etc.)
   *
   * Should be overrided by sub-classes only if needed.
   */
  toSQLType(attr) {
    var res = null;

    switch (attr.type) {
      case 'Decimal': {
        res = 'DECIMAL(' + attr.precision + ',' + attr.scale + ')';
      }
      break;
      default: { // sql type == js type
        res = new String(attr.type).toUpperCase();
      }
      break;
    }

    return res;
  }

  /**
   * Returns the SQL value corresponding to the given JS value (e.g. for 'false' should return 0 for SQLite, and FALSE for MySQL etc.)
   *
   * Should be overrided by sub-classes only if needed.
   */
  toSQLValue(attr, createStatement = false) {
    var res = null;

    if (attr.defaultValueIsFunction && (this.name !== 'sqlite')) {
      switch (attr.defaultValue) {
        case 'DATE()': {
          res = 'CURRENT_DATE'; // sql value == js value
        }
        break;
        case 'DATETIME()': {
          res = 'CURRENT_TIMESTAMP'; // sql value == js value
        }
        break;
        case 'TIME()': {
          res = 'CURRENT_TIME'; // sql value == js value
        }
        break;
        default: {
          console.log('Unknown function ' + attr.defaultValue);
        }
      }
    }
    else if ((this.name === 'sqlite') && createStatement)
      res = '(' + res + ')';

    return res;
  }
}
<commit_msg>FIXED bug when using functions with SQLite<commit_after>import AbstractGenerator from './AbstractGenerator';
import InsertIntoStatement from './InsertIntoStatement';
import Random from './../Random';

/*
 * Abstract output class. Should be inherited by all classes whose goal is to generate code from an Entity object.
 */
export default class AbstractSQLGenerator extends AbstractGenerator {

  constructor(options = {}) {
    super(options);
    this.results = {
      'create': {},
      'drop': {},
      'insert-into': {}
    };
  }

  addEntity(entity) {
    super.addEntity(entity);

    if (this.options['insert-into'])
      this.results['insert-into'][entity.plural.toLowerCase()] = [];
  }

  /**
   * Used in rare cases like when `name === 'user'` which is not allowed in PostgreSQL unless quoted (e.g. "user"). Its the responsibility of this method to do so.
   */
  escapeColumnName(name) {
    return name;
  }

  /*
   * Should generate code based on the 'entities' array.
   */
  generate() {
    if (!(this.options.create || this.options.drop || this.options['insert-into']))
      throw 'You must specify an operation as CLI argument, one of --create / --drop / --insert-into <count>';

    if (this.options.create)
      this.generateCreate();
    if (this.options.drop)
      this.generateDrop();
    if (this.options['insert-into']) {
      var n = 10;

      if (typeof this.options['insert-into'] === 'number')
        n = this.options['insert-into'];

      this.generateInserts(n);
    }
  }

  generateAttributes(e) {
    var self = this;
    var str = '';

    this.indentation++;
    e.attributes.forEach(function(attr, i) {
      str += self.indent() + attr.name + ' ' + self.toSQLType(attr).toUpperCase();

      if (attr.primaryKey) {
        str += ' PRIMARY KEY';

        if (self.getAutoIncrementString())
          str += ' ' + self.getAutoIncrementString();
      }
      else if (attr.required)
        str += ' NOT NULL';
      else {
        str += ' DEFAULT ' + self.toSQLValue(attr, true);
      }

      if (!attr.primaryKey && attr.unique)
        str += ' UNIQUE';

      if (i != (e.attributes.length - 1))
        str += ',\n';
    });

    if ((e.attributes.length > 0) && (e.references.length > 0))
      str += ',\n';

    e.references.forEach(function(ref, i) {
      str += self.indent() + self.escapeColumnName(ref.alias) + ' ' + self.toSQLType({ type: 'Integer' });

      if (ref.nullable)
        str += ' DEFAULT NULL';
      else {
        str += ' NOT NULL';

        if (ref.defaultValue !== undefined)
          str += ' DEFAULT ' + self.toSQLValue({
            defaultValue: ref.defaultValue,
            type: 'Integer'
          });
      }

      if (i < (e.references.length - 1))
        str += ',\n';
    });
    this.indentation--;

    return str;
  }

  generateCreate() {
    this.sortEntities();
    var self = this;

    this.entities.forEach(function(e, i) {
      var str = '';

      str += 'CREATE TABLE ' + e.plural + ' (\n';
      str += self.generateAttributes(e);

      if (e.references.length > 0) {
        str += ',\n';
        str += '\n';
        str += self.generateForeignKeys(e);
      }

      str += '\n';
      str += ');';

      self.results['create'][e.plural.toLowerCase()] = str;
    });
  }

  generateDrop() {
    this.sortEntities();
    this.entities.reverse();
    var self = this;

    this.entities.forEach(function(e, i) {
      var str = '';

      str += 'DROP TABLE IF EXISTS ' + e.plural + ';';

      self.results['drop'][e.plural.toLowerCase()] = str;
    });
  }

  generateForeignKeys(entity) {
    var e = entity;
    var self = this;
    var str = '';

    this.indentation++;
    e.references.forEach(function(ref, i) {
      str += self.indent() + 'FOREIGN KEY (' + self.escapeColumnName(ref.alias) + ') REFERENCES ' + ref.entity.plural + ' (' + ref.attribute + ')';

      if (i < (e.references.length - 1)) {
        str += ',\n';
      }
    });
    this.indentation--;

    return str;
  }

  generateInserts(n) {
    this.sortEntities();
    var self = this;

    this.entities.forEach(function(e, i) {
      for (var i = 0; i < n; i++) {
        var values = {};

        e.attributes.forEach(function(attr) {
          if (attr.primaryKey)
            return;

          if (attr.defaultValueIsFunction || attr.defaultValueIsRaw)
            values[attr.name] = self.toSQLValue(attr);
          else {
            values[attr.name] = self.toSQLValue({
              defaultValue: Random.value(attr),
              type: attr.type
            });
          }
        });
        e.references.forEach(function(ref) {
          var otherRefs = [];

          if (values[ref.alias] === undefined) // If no foreign key id set for this reference yet
            values[ref.alias] = Random.integer(1, n); // Choose a random foreign key id from the number of insert statements generated

          e.references.forEach(function(ref2) {
            if (ref2 == ref)
              return;

            otherRefs = otherRefs.concat(
              ref2.entity.references.filter(function(ref3) {
                return (ref3.entity === ref.entity)
                  && (ref3.attribute === ref.attribute);
              })
            );
          });

          // If another reference from this entity points to an entity having a reference to the same Entity-Attribute pair as the current reference
          if (otherRefs.length > 0) {
            // Ensure that the value for this foreign key is the same as the other entity's foreign key's value as they should both point to the same table record (for data integrity)

            otherRefs.forEach(function(ref3) {
              var referencedEntityName = ref3.source.plural.toLowerCase();

              if (self.results['insert-into'][referencedEntityName] === undefined)
                return; // No inserts for this entity

              var ref2 = e.references.filter(function(r) {
                return (r.source === ref.source) && (r.entity === ref3.source);
              })[0];
              // Look for an insert statement which has a foreign key to the same table & field and which value is the same as the randomly generated current foreign key id
              var inserts = self.results['insert-into'][referencedEntityName]
                .filter(function(val, i) {
                  return (val.values[ref3.alias] === values[ref.alias]);
                }
              );

              if (inserts.length === 0) // No inserts on the second table with the same value for the same foreign key
                values[ref2.alias] = null;
              else {
                // Choose randomly between the matching inserts
                values[ref2.alias] = self.results['insert-into'][referencedEntityName]
                  .indexOf(inserts[Random.integer(1, inserts.length) - 1]) + 1;
              }
            });
          }
        });

        var stmt = new InsertIntoStatement(self, e, values);
        self.results['insert-into'][e.plural.toLowerCase()].push(stmt);
      }
    });
  }

  getAllowedOptions() {
    return {
      'create': 'For each entity, will generate the SQL query to create the related database table.',
      'drop': 'For each entity, will generate the SQL query to drop the related database table.',
      'insert-into <rows-count>': 'For each entity, will generate <rows-count> SQL queries to insert randomly generated data in the related database table.'
    };
  }

  getAutoIncrementString() {
    return '';
  }

  getContent(fileName) {
    var content = '';

    if (fileName === 'execute.sh')
      return this.getExecuteScriptContent();

    if (~fileName.indexOf('-database')) {
      var ope = fileName.substring(0, fileName.lastIndexOf('-database'));

      if (ope === 'insert-into') {

        this.sortEntities();

        for (let entity of this.entities) {
          content += this.results[ope][entity.plural.toLowerCase()].join('\n') + '\n\n';
        }
      }
      else {
        for (let key of Object.keys(this.results[ope])) {
          content += this.results[ope][key] + '\n\n';
        }
      }
    }
    else {
      var ope = fileName.substring(0, fileName.lastIndexOf('-table'));
      var ent = fileName.substring(fileName.lastIndexOf('-') + 1, fileName.lastIndexOf('.'));

      if (ope === 'insert-into')
        content = this.results[ope][ent].join('\n') + '\n';
      else
        content = this.results[ope][ent] + '\n';
    }

    return content;
  }

  /*
   * Should return the content of the 'execute.sh' file placed in every output directory after generation to execute generated SQL files.
   *
   * Must be overrided by sub-classes.
   */
  getExecuteScriptContent() {
    return null;
  }

  getOutputFilesNames() {
    var allowedOptions = [ 'create', 'drop', 'insert-into' ];
    var names = [];
    var operation;
    var context;

    for (var opt of allowedOptions) {
      if (this.entities.length === 1)
        names.push(opt + '-table-' + this.entities[0].plural.toLowerCase() + '.sql');
      else {
        names.push(opt + '-database.sql');
      }
    }

    names.push('execute.sh');

    return names;
  }

  /*
   * Returns `this.indentation * 2` whitespaces (e.g. 2, 4...).
   */
  indent() {
    var str = '';

    for (var i = 0; i < this.indentation * 2; i++)
      str += ' ';

    return str;
  }

  sortEntities() {
    this.entities.sort(function(a, b) {
      return a.references.length - b.references.length;
    });
  }

  /**
   * Returns the SQL type corresponding to the given Jane attribute's type (e.g. VARCHAR(<...>) for String etc.) with desired length if appropriated (e.g. VARCHAR(255) etc.)
   *
   * Should be overrided by sub-classes only if needed.
   */
  toSQLType(attr) {
    var res = null;

    switch (attr.type) {
      case 'Decimal': {
        res = 'DECIMAL(' + attr.precision + ',' + attr.scale + ')';
      }
      break;
      default: { // sql type == js type
        res = new String(attr.type).toUpperCase();
      }
      break;
    }

    return res;
  }

  /**
   * Returns the SQL value corresponding to the given JS value (e.g. for 'false' should return 0 for SQLite, and FALSE for MySQL etc.)
   *
   * Should be overrided by sub-classes only if needed.
   */
  toSQLValue(attr, createStatement = false) {
    var res = null;

    if (attr.defaultValueIsFunction && (this.name !== 'sqlite')) {
      switch (attr.defaultValue) {
        case 'DATE()': {
          res = 'CURRENT_DATE'; // sql value == js value
        }
        break;
        case 'DATETIME()': {
          res = 'CURRENT_TIMESTAMP'; // sql value == js value
        }
        break;
        case 'TIME()': {
          res = 'CURRENT_TIME'; // sql value == js value
        }
        break;
        default: {
          console.log('Unknown function ' + attr.defaultValue);
        }
      }
    }
    else if (this.name === 'sqlite') {
      if (createStatement)
        res = '(' + attr.defaultValue + ')';
      else
        res = attr.defaultValue;
    }

    return res;
  }
}
<|endoftext|>


<commit_before>import React, {Component} from 'react';
import ElementContainer from './ElementContainer'
import ElementCheckbox from './ElementCheckbox';
import ElementCollectionLabels from './ElementCollectionLabels';
import ElementAnalysesLabels from './ElementAnalysesLabels';
import {Tooltip, OverlayTrigger, Table} from 'react-bootstrap';
import ArrayUtils from './utils/ArrayUtils';

import UIStore from './stores/UIStore';
import ElementStore from './stores/ElementStore';
import KeyboardStore from './stores/KeyboardStore';

import SVG from 'react-inlinesvg';
import DragDropItemTypes from './DragDropItemTypes';
import classnames from 'classnames';
import XTdCont from "./extra/ElementsTableEntriesXTdCont";

export default class ElementsTableEntries extends Component {
  constructor(props) {
    super(props)
    this.state = {
      keyboardElementIndex: null
    }

    this.entriesOnKeyDown = this.entriesOnKeyDown.bind(this)
  }

  componentDidMount() {
    KeyboardStore.listen(this.entriesOnKeyDown)
  }

  componentWillUnmount() {
    KeyboardStore.unlisten(this.entriesOnKeyDown)
  }

  entriesOnKeyDown(state) {
    let context = state.context
    const {elements} = this.props;

    if (elements[0] == null || context != elements[0].type)
      return false

    let documentKeyDownCode = state.documentKeyDownCode
    let {keyboardElementIndex} = this.state

    switch(documentKeyDownCode) {
      case 13: // Enter
      case 39: // Right
        if (keyboardElementIndex != null && elements[keyboardElementIndex] != null) {
          this.showDetails(elements[keyboardElementIndex])
        }
        break

      case 38: // Up
        if (keyboardElementIndex > 0) {
          keyboardElementIndex--
        } else {
          keyboardElementIndex = 0
        }
        break
      case 40: // Down
        if (keyboardElementIndex == null) {
          keyboardElementIndex = 0
        } else if (keyboardElementIndex < elements.length - 1){
          keyboardElementIndex++
        }

        break
    }
    this.setState({keyboardElementIndex})
  }

  isElementChecked(element) {
    let {checkedIds, uncheckedIds, checkedAll} = this.props.ui;
    return (checkedAll && ArrayUtils.isValNotInArray(uncheckedIds || [], element.id))
      || ArrayUtils.isValInArray(checkedIds || [], element.id);
  }

  isElementSelected(element) {
    const {currentElement} = this.props;
    return (currentElement && currentElement.id == element.id);
  }

  isCurrentElementDropTargetForType(type) {
    const {currentElement} = ElementStore.getState();
    const targets = {
      sample: ['reaction', 'wellplate'],
      wellplate: ['screen']
    };
    return type && currentElement && targets[type].includes(currentElement.type)
  }

  showDetails(element) {
    const {currentCollection,isSync} = UIStore.getState();
    Aviator.navigate(isSync
      ? `/scollection/${currentCollection.id}/${element.type}/${element.id}`
      : `/collection/${currentCollection.id}/${element.type}/${element.id}`
    );
  }

  dragHandle(element) {
    let sourceType =  "";
    if (element.type == 'sample' && this.isCurrentElementDropTargetForType('sample')) {
      sourceType = DragDropItemTypes.SAMPLE;
    } else if (element.type == 'wellplate' && this.isCurrentElementDropTargetForType('wellplate')) {
      sourceType = DragDropItemTypes.WELLPLATE;
    }
    return <ElementContainer key={element.id} sourceType={sourceType} element={element}/>;
  }

  topSecretIcon(element) {
    if (element.type == 'sample' && element.is_top_secret == true) {
      const tooltip = (<Tooltip id="top_secret_icon">Top secret</Tooltip>);
      return (
        <OverlayTrigger placement="top" overlay={tooltip}>

        </OverlayTrigger>
      )
    }
  }

  previewColumn(element) {
    const {ui} = this.props;
    const classNames = classnames(
      {
        'molecule': element.type == 'sample'
      },
      {
        'reaction': element.type == 'reaction'
      },
      {
        'molecule-selected': element.type == 'sample' && this.isElementSelected(element)
      },
      {
        'reaction': element.type == 'reaction' && this.isElementSelected(element)
      },
      {
        'research_plan': element.type == 'research_plan'
      }
    );

    let svgContainerStyle = {
      verticalAlign: 'middle',
      textAlign: 'center',
      cursor: 'pointer'
    };
    let tdExtraContents = [];
    for (let j=0;j < XTdCont.count;j++){
      let NoName = XTdCont["content"+j];
      tdExtraContents.push(<NoName element={element}/>);
    }

    if(ui.showPreviews && (element.type == 'sample' || element.type == 'reaction' || element.type == 'research_plan')) {
      return (
         this.showDetails(element)}>
          <SVG src={element.svgPath} className={classNames} key={element.svgPath}/>
          {tdExtraContents.map((e)=>{return e;})}

      );
    } else {
      return  this.showDetails(element)}/>;
    }
  }

  dragColumn(element) {
    const {showDragColumn} = this.props;
    if(showDragColumn) {
      return (

          {this.dragHandle(element)}

      );
    } else {
     return 	;
    }
  }

  reactionStatus(element) {

    let tooltip = null;
    if (element.type == 'reaction') {
      switch (element.status) {

        case "Successful":
          tooltip = (<Tooltip id="reaction_success">Successful Reaction</Tooltip>);
          return (
            <OverlayTrigger placement="top" overlay={tooltip}>

            </OverlayTrigger>
          )
          break;

        case "Planned":
          tooltip = (<Tooltip id="reaction_planned">Planned Reaction</Tooltip>);
          return (
            <OverlayTrigger placement="top" overlay={tooltip}>

            </OverlayTrigger>
          )
          break;

        case "Not Successful":
          tooltip = (<Tooltip id="reaction_fail">Not Successful Reaction</Tooltip>);
          return (
            <OverlayTrigger placement="top" overlay={tooltip}>

            </OverlayTrigger>
          )
          break;

        default:
          break;
      }
    }
  }

  sampleAnalysesLabels(element) {
    if (element.type == 'sample') {
      return (
        <ElementAnalysesLabels element={element} key={element.id+"_analyses"}/>
      )
    }
  }

  render() {
    const {elements} = this.props;
    let {keyboardElementIndex} = this.state

    return (

        {elements.map((element, index) => {
          const sampleMoleculeName = (element.type == 'sample') ? element.molecule.iupac_name: '';
          let style = {};
          if (this.isElementSelected(element) ||
             (keyboardElementIndex != null && keyboardElementIndex == index)) {
            style = {
            color: '#000',
            background: '#ddd',
            border: '4px solid #337ab7'
            }
          }

          return (

                <ElementCheckbox element={element} key={element.id} checked={this.isElementChecked(element)}/>

               this.showDetails(element)} style={{cursor: 'pointer'}}>
                {element.title()}
                {this.reactionStatus(element)}

                {sampleMoleculeName}
                <ElementCollectionLabels element={element} key={element.id}/>
                {this.sampleAnalysesLabels(element)}
                {this.topSecretIcon(element)}

              {this.previewColumn(element)}
              {this.dragColumn(element)}

          )
        })}

    );
  }
}
<commit_msg>Fix reaction scheme not shown<commit_after>import React, {Component} from 'react';
import ElementContainer from './ElementContainer'
import ElementCheckbox from './ElementCheckbox';
import ElementCollectionLabels from './ElementCollectionLabels';
import ElementAnalysesLabels from './ElementAnalysesLabels';
import {Tooltip, OverlayTrigger, Table} from 'react-bootstrap';
import ArrayUtils from './utils/ArrayUtils';

import UIStore from './stores/UIStore';
import ElementStore from './stores/ElementStore';
import KeyboardStore from './stores/KeyboardStore';

import SVG from 'react-inlinesvg';
import DragDropItemTypes from './DragDropItemTypes';
import classnames from 'classnames';
import XTdCont from "./extra/ElementsTableEntriesXTdCont";

export default class ElementsTableEntries extends Component {
  constructor(props) {
    super(props)
    this.state = {
      keyboardElementIndex: null
    }

    this.entriesOnKeyDown = this.entriesOnKeyDown.bind(this)
  }

  componentDidMount() {
    KeyboardStore.listen(this.entriesOnKeyDown)
  }

  componentWillUnmount() {
    KeyboardStore.unlisten(this.entriesOnKeyDown)
  }

  entriesOnKeyDown(state) {
    let context = state.context
    const {elements} = this.props;

    if (elements[0] == null || context != elements[0].type)
      return false

    let documentKeyDownCode = state.documentKeyDownCode
    let {keyboardElementIndex} = this.state

    switch(documentKeyDownCode) {
      case 13: // Enter
      case 39: // Right
        if (keyboardElementIndex != null && elements[keyboardElementIndex] != null) {
          this.showDetails(elements[keyboardElementIndex])
        }
        break

      case 38: // Up
        if (keyboardElementIndex > 0) {
          keyboardElementIndex--
        } else {
          keyboardElementIndex = 0
        }
        break
      case 40: // Down
        if (keyboardElementIndex == null) {
          keyboardElementIndex = 0
        } else if (keyboardElementIndex < elements.length - 1){
          keyboardElementIndex++
        }

        break
    }
    this.setState({keyboardElementIndex})
  }

  isElementChecked(element) {
    let {checkedIds, uncheckedIds, checkedAll} = this.props.ui;
    return (checkedAll && ArrayUtils.isValNotInArray(uncheckedIds || [], element.id))
      || ArrayUtils.isValInArray(checkedIds || [], element.id);
  }

  isElementSelected(element) {
    const {currentElement} = this.props;
    return (currentElement && currentElement.id == element.id);
  }

  isCurrentElementDropTargetForType(type) {
    const {currentElement} = ElementStore.getState();
    const targets = {
      sample: ['reaction', 'wellplate'],
      wellplate: ['screen']
    };
    return type && currentElement && targets[type].includes(currentElement.type)
  }

  showDetails(element) {
    const {currentCollection,isSync} = UIStore.getState();
    Aviator.navigate(isSync
      ? `/scollection/${currentCollection.id}/${element.type}/${element.id}`
      : `/collection/${currentCollection.id}/${element.type}/${element.id}`
    );
  }

  dragHandle(element) {
    let sourceType =  "";
    if (element.type == 'sample' && this.isCurrentElementDropTargetForType('sample')) {
      sourceType = DragDropItemTypes.SAMPLE;
    } else if (element.type == 'wellplate' && this.isCurrentElementDropTargetForType('wellplate')) {
      sourceType = DragDropItemTypes.WELLPLATE;
    }
    return <ElementContainer key={element.id} sourceType={sourceType} element={element}/>;
  }

  topSecretIcon(element) {
    if (element.type == 'sample' && element.is_top_secret == true) {
      const tooltip = (<Tooltip id="top_secret_icon">Top secret</Tooltip>);
      return (
        <OverlayTrigger placement="top" overlay={tooltip}>

        </OverlayTrigger>
      )
    }
  }

  previewColumn(element) {
    const {ui} = this.props;
    const classNames = classnames(
      {
        'molecule': element.type == 'sample'
      },
      {
        'reaction': element.type == 'reaction'
      },
      {
        'molecule-selected': element.type == 'sample' && this.isElementSelected(element)
      },
      {
        'reaction': element.type == 'reaction' && this.isElementSelected(element)
      },
      {
        'research_plan': element.type == 'research_plan'
      }
    );

    let svgContainerStyle = {
      verticalAlign: 'middle',
      textAlign: 'center',
      cursor: 'pointer'
    };
    let tdExtraContents = [];
    for (let j=0;j < XTdCont.count;j++){
      let NoName = XTdCont["content"+j];
      tdExtraContents.push(<NoName element={element}/>);
    }

    const {showPreviews} = UIStore.getState();
    if(showPreviews && (element.type == 'reaction' || element.type == 'research_plan')) {
      return (
         this.showDetails(element)}>
          <SVG src={element.svgPath} className={classNames} key={element.svgPath}/>
          {tdExtraContents.map((e)=>{return e;})}

      );
    } else {
      return  this.showDetails(element)}/>;
    }
  }

  dragColumn(element) {
    const {showDragColumn} = this.props;
    if(showDragColumn) {
      return (

          {this.dragHandle(element)}

      );
    } else {
     return 	;
    }
  }

  reactionStatus(element) {

    let tooltip = null;
    if (element.type == 'reaction') {
      switch (element.status) {

        case "Successful":
          tooltip = (<Tooltip id="reaction_success">Successful Reaction</Tooltip>);
          return (
            <OverlayTrigger placement="top" overlay={tooltip}>

            </OverlayTrigger>
          )
          break;

        case "Planned":
          tooltip = (<Tooltip id="reaction_planned">Planned Reaction</Tooltip>);
          return (
            <OverlayTrigger placement="top" overlay={tooltip}>

            </OverlayTrigger>
          )
          break;

        case "Not Successful":
          tooltip = (<Tooltip id="reaction_fail">Not Successful Reaction</Tooltip>);
          return (
            <OverlayTrigger placement="top" overlay={tooltip}>

            </OverlayTrigger>
          )
          break;

        default:
          break;
      }
    }
  }

  sampleAnalysesLabels(element) {
    if (element.type == 'sample') {
      return (
        <ElementAnalysesLabels element={element} key={element.id+"_analyses"}/>
      )
    }
  }

  render() {
    const {elements} = this.props;
    let {keyboardElementIndex} = this.state

    return (

        {elements.map((element, index) => {
          const sampleMoleculeName = (element.type == 'sample') ? element.molecule.iupac_name: '';
          let style = {};
          if (this.isElementSelected(element) ||
             (keyboardElementIndex != null && keyboardElementIndex == index)) {
            style = {
            color: '#000',
            background: '#ddd',
            border: '4px solid #337ab7'
            }
          }

          return (

                <ElementCheckbox element={element} key={element.id} checked={this.isElementChecked(element)}/>

               this.showDetails(element)} style={{cursor: 'pointer'}}>
                {element.title()}
                {this.reactionStatus(element)}

                {sampleMoleculeName}
                <ElementCollectionLabels element={element} key={element.id}/>
                {this.sampleAnalysesLabels(element)}
                {this.topSecretIcon(element)}

              {this.previewColumn(element)}
              {this.dragColumn(element)}

          )
        })}

    );
  }
}
<|endoftext|>


<commit_before>define([
	'goo/entities/EntityUtils',
	'goo/util/MeshBuilder',
	'goo/math/Transform',
	'goo/math/Vector3',
	'goo/renderer/bounds/BoundingBox',
	'goo/renderer/bounds/BoundingSphere'
],
/** @lends */
function(
	EntityUtils,
	MeshBuilder,
	Transform,
	Vector3,
	BoundingBox,
	BoundingSphere
) {
	"use strict";

	function EntityCombiner(gooWorld, gridCount) {
		this.world = gooWorld;
		this.gridCount = gridCount || 1;
	}

	EntityCombiner.prototype.combine = function() {
		this.world.process();

		var topEntities = this.world.entityManager.getTopEntities();
		this.gridSize = this._calculateBounds(topEntities) / this.gridCount;
		this._combineList(topEntities);
	};

	EntityCombiner.prototype._combineList = function(entities) {
		var removeOld = true;

		var baseSubs = new Map();
		for (var i = 0; i < entities.length; i++) {
			this._buildSubs(entities[i], baseSubs);
		}

		var keys = baseSubs.getKeys();
		for (var i = 0; i < keys.length; i++) {
			var entity = keys[i];
			var combineList = baseSubs.get(entity);

			this._combine(entity, combineList, removeOld);
		}
	};

	EntityCombiner.prototype._buildSubs = function (entity, baseSubs, subs) {
		if (entity.animationComponent || entity.particleComponent) {
			return;
		}

		// will be based on static setting when we add it to Create
		// if (!subs || !entity.isStatic || entity.fSMComponent) {
		if (!subs || entity.scriptComponent || entity.fSMComponent) {
			subs = [];
			baseSubs.put(entity, subs);
		}

		if (entity.meshDataComponent && entity.meshRendererComponent && entity.meshRendererComponent.worldBound) {
			subs.push(entity);
		}

		for (var i = 0; i < entity.transformComponent.children.length; i++) {
			var child = entity.transformComponent.children[i];
			this._buildSubs(child.entity, baseSubs, subs);
		}
	};

	EntityCombiner.prototype._combine = function(root, combineList, removeOld) {
		var rootTransform = root.transformComponent.worldTransform;
		var invertTransform = new Transform();
		var calcTransform = new Transform();
		rootTransform.invert(invertTransform);

		var entities = new Map();
		for (var i = 0; i < combineList.length; i++) {
			var entity = combineList[i];

			var key = entity.meshRendererComponent.materials[0];

			var attributeMap = entity.meshDataComponent.meshData.attributeMap;
			var key2 = Object.keys(attributeMap);
			key2.sort();
			key2 = key2.join('_');

			var xBucket = entity.meshRendererComponent.worldBound.center.x / this.gridSize;
			var zBucket = entity.meshRendererComponent.worldBound.center.z / this.gridSize;
			key2 = key2 + '_' + Math.round(xBucket) + '_' + Math.round(zBucket);

			var set = entities.get(key);
			if (!set) {
				set = new Map();
				entities.put(key, set);
			}
			var set2 = set.get(key2);
			if (!set2) {
				set2 = [];
				set.put(key2, set2);
			}

			set2.push(entity);
		}

		var sets = entities.getKeys();

		for (var i = 0; i < sets.length; i++) {
			var material = sets[i];
			var entities2 = entities.get(material);
			var sets2 = entities2.getKeys();
			for (var j = 0; j < sets2.length; j++) {
				var toCombine = entities2.get(sets2[j]);

				if (toCombine.length === 1) {
					continue;
				}

				var meshBuilder = new MeshBuilder();
				for (var k = 0; k < toCombine.length; k++) {
					var entity = toCombine[k];

					if (root !== entity) {
						calcTransform.multiply(invertTransform, entity.transformComponent.worldTransform);
					} else {
						calcTransform.setIdentity();
					}
					meshBuilder.addMeshData(entity.meshDataComponent.meshData, calcTransform);

					if (removeOld) {
						entity.clearComponent('meshDataComponent');
						entity.clearComponent('meshRendererComponent');
					} else {
						entity.skip = true;
						entity.hidden = true;
					}
				}
				var meshDatas = meshBuilder.build();

				for (var key in meshDatas) {
					var entity = EntityUtils.createTypicalEntity(this.world, meshDatas[key], material);
					entity.addToWorld();
					root.attachChild(entity);
				}
			}
		}
	};

	EntityCombiner.prototype._calculateBounds = function (entities) {
		var first = true;
		var wb = new BoundingBox();
		for (var i = 0; i < entities.length; i++) {
			var rootEntity = entities[i];
			EntityUtils.traverse(rootEntity, function(entity) {
				if (entity.meshRendererComponent && !entity.particleComponent) {
					if (first) {
						var bound = entity.meshRendererComponent.worldBound;
						if (bound instanceof BoundingBox) {
							bound.clone(wb);
						} else if (bound instanceof BoundingSphere) {
							wb.center.setv(bound.center);
							wb.xExtent = wb.yExtent = wb.zExtent = bound.radius;
						} else {
							wb.center.setv(Vector3.ZERO);
							wb.xExtent = wb.yExtent = wb.zExtent = 10;
						}

						first = false;
					} else {
						wb.merge(entity.meshRendererComponent.worldBound);
					}
				}
			});
		}
		return Math.max(wb.xExtent, wb.zExtent)*2.0;
	};

	function Map() {
		var keys = [],
			values = [];

		return {
			put: function(key, value) {
				var index = keys.indexOf(key);
				if (index === -1) {
					keys.push(key);
					values.push(value);
				} else {
					values[index] = value;
				}
			},
			get: function(key) {
				return values[keys.indexOf(key)];
			},
			getKeys: function() {
				return keys;
			},
			getValues: function() {
				return values;
			}
		};
	}

	return EntityCombiner;
});<commit_msg>Improved EntityCombiner<commit_after>define([
	'goo/entities/EntityUtils',
	'goo/util/MeshBuilder',
	'goo/math/Transform',
	'goo/math/Vector3',
	'goo/renderer/bounds/BoundingBox',
	'goo/renderer/bounds/BoundingSphere'
],
/** @lends */
function(
	EntityUtils,
	MeshBuilder,
	Transform,
	Vector3,
	BoundingBox,
	BoundingSphere
) {
	"use strict";

	function EntityCombiner(gooWorld, gridCount) {
		this.world = gooWorld;
		this.gridCount = gridCount || 1;
	}

	EntityCombiner.prototype.combine = function() {
		this.world.process();

		var topEntities = this.world.entityManager.getTopEntities();
		this.gridSize = this._calculateBounds(topEntities) / this.gridCount;
		this._combineList(topEntities);
	};

	EntityCombiner.prototype._combineList = function(entities) {
		var removeOld = true;

		var baseSubs = new Map();
		for (var i = 0; i < entities.length; i++) {
			this._buildSubs(entities[i], baseSubs);
		}

		var keys = baseSubs.getKeys();
		for (var i = 0; i < keys.length; i++) {
			var entity = keys[i];
			var combineList = baseSubs.get(entity);

			this._combine(entity, combineList, removeOld);
		}
	};

	EntityCombiner.prototype._buildSubs = function (entity, baseSubs, subs) {
		if (entity.animationComponent || entity.particleComponent) {
			return;
		}

		// will be based on static setting when we add it to Create
		// if (!subs || !entity.isStatic || entity.fSMComponent) {
		if (!subs || entity.scriptComponent || entity.fSMComponent) {
			subs = [];
			baseSubs.put(entity, subs);
		}

		if (entity.meshDataComponent && entity.meshRendererComponent && entity.meshRendererComponent.worldBound) {
			subs.push(entity);
		}

		for (var i = 0; i < entity.transformComponent.children.length; i++) {
			var child = entity.transformComponent.children[i];
			this._buildSubs(child.entity, baseSubs, subs);
		}
	};

	EntityCombiner.prototype._combine = function(root, combineList, removeOld) {
		var rootTransform = root.transformComponent.worldTransform;
		var invertTransform = new Transform();
		var calcTransform = new Transform();
		rootTransform.invert(invertTransform);

		var entities = new Map();
		for (var i = 0; i < combineList.length; i++) {
			var entity = combineList[i];

			var key = entity.meshRendererComponent.materials[0];

			var attributeMap = entity.meshDataComponent.meshData.attributeMap;
			var key2 = Object.keys(attributeMap);
			key2.sort();
			key2 = key2.join('_');

			var xBucket = entity.meshRendererComponent.worldBound.center.x / this.gridSize;
			var zBucket = entity.meshRendererComponent.worldBound.center.z / this.gridSize;
			key2 = key2 + '_' + Math.round(xBucket) + '_' + Math.round(zBucket);

			var set = entities.get(key);
			if (!set) {
				set = new Map();
				entities.put(key, set);
			}
			var set2 = set.get(key2);
			if (!set2) {
				set2 = [];
				set.put(key2, set2);
			}

			set2.push(entity);
		}

		var sets = entities.getKeys();

		for (var i = 0; i < sets.length; i++) {
			var material = sets[i];
			var entities2 = entities.get(material);
			var sets2 = entities2.getKeys();
			for (var j = 0; j < sets2.length; j++) {
				var toCombine = entities2.get(sets2[j]);

				if (toCombine.length === 1) {
					continue;
				}

				var meshBuilder = new MeshBuilder();
				for (var k = 0; k < toCombine.length; k++) {
					var entity = toCombine[k];

					if (root !== entity) {
						calcTransform.multiply(invertTransform, entity.transformComponent.worldTransform);
					} else {
						calcTransform.setIdentity();
					}
					meshBuilder.addMeshData(entity.meshDataComponent.meshData, calcTransform);

					if (removeOld) {
						// Remove empty leaf children
						if (entity._components.length === 3 && entity.transformComponent.children.length === 0) {
							entity.removeFromWorld();
						} else {
							entity.clearComponent('meshDataComponent');
							entity.clearComponent('meshRendererComponent');
						}
					} else {
						entity.skip = true;
						entity.hidden = true;
					}
				}
				var meshDatas = meshBuilder.build();

				for (var key in meshDatas) {
					var entity = EntityUtils.createTypicalEntity(this.world, meshDatas[key], material);
					entity.addToWorld();
					root.attachChild(entity);
				}
			}
		}
	};

	EntityCombiner.prototype._calculateBounds = function (entities) {
		var first = true;
		var wb = new BoundingBox();
		for (var i = 0; i < entities.length; i++) {
			var rootEntity = entities[i];
			EntityUtils.traverse(rootEntity, function(entity) {
				if (entity.meshRendererComponent && !entity.particleComponent) {
					if (first) {
						var bound = entity.meshRendererComponent.worldBound;
						if (bound instanceof BoundingBox) {
							bound.clone(wb);
						} else if (bound instanceof BoundingSphere) {
							wb.center.setv(bound.center);
							wb.xExtent = wb.yExtent = wb.zExtent = bound.radius;
						} else {
							wb.center.setv(Vector3.ZERO);
							wb.xExtent = wb.yExtent = wb.zExtent = 10;
						}

						first = false;
					} else {
						wb.merge(entity.meshRendererComponent.worldBound);
					}
				}
			});
		}
		return Math.max(wb.xExtent, wb.zExtent)*2.0;
	};

	function Map() {
		var keys = [],
			values = [];

		return {
			put: function(key, value) {
				var index = keys.indexOf(key);
				if (index === -1) {
					keys.push(key);
					values.push(value);
				} else {
					values[index] = value;
				}
			},
			get: function(key) {
				return values[keys.indexOf(key)];
			},
			getKeys: function() {
				return keys;
			},
			getValues: function() {
				return values;
			}
		};
	}

	return EntityCombiner;
});<|endoftext|>


<commit_before>
export default
function DefaultBehaviorsMixin(ElementClass) {

    // TODO This is here for now. Make it an extension to
    // element-behaviors so that it can be applied to any element
    // generically.
    return class DefaultBehaviors extends ElementClass {

        // override in subclasses
        static get defaultBehaviors() {
            return []
        }

        construct(...args) {
            if (super.construct) super.construct(...args)

            // If no geometry or material behavior is detected, add default ones.
            //
            // Deferring to a microtask doesn't work here, we must defer to a
            // macrotask with setTimeout, so we can detect if the element has
            // initial behaviors, otherwise the element's initial attributes
            // haven't been added yet (this is how HTML engines work, see
            // https://github.com/whatwg/dom/issues/522).
            //
            // TODO: If we use setTimeout (macrotask) deferral anywhere (like we do
            // here), and maybe even with microtask deferral (f.e. Promise), maybe
            // we should have a single place that initiate this deferral so that
            // everything in the engine can hook into it. Otherwise if different
            // call sites use setTimeout, logic will be firing at random and in
            // different order.
            setTimeout( () => this._setDefaultBehaviorsIfNeeded(), 0 )
        }

        _setDefaultBehaviorsIfNeeded() {
            let defaultBehaviors = this.constructor.defaultBehaviors

            // do nothing if there's no defaults
            if (!defaultBehaviors) return
            if (Object.keys(defaultBehaviors).length == 0) return

            const initialBehaviorNames = Array.from( this.behaviors.keys() )

            // small optimization: if there are no initial behaviors and we
            // have default behaviors, just set the default behaviors.
            if ( initialBehaviorNames.length == 0 ) {

                // if not an array, then it's an object.
                if (!defaultBehaviors instanceof Array) defaultBehaviors = Object.keys(defaultBehaviors)

                this.setAttribute( 'has', this.getAttribute( 'has' ) + ` ${defaultBehaviors.join(' ')}`)
            }

            // otherwise detect which default behavior(s) to add
            else {

                let behaviorNamesToAdd = ''

                // if defaultBehaviors is an array, use default logic to add
                // behaviors that aren't already added.
                if (defaultBehaviors instanceof Array) {
                    for (const defaultBehaviorName of defaultBehaviors) {

                        let hasBehavior = false

                        for ( const initialBehaviorName of initialBehaviorNames ) {
                            if ( defaultBehaviorName == initialBehaviorName ) {
                                hasBehavior = true
                                break
                            }
                        }

                        if (hasBehavior) continue
                        else {
                            // TODO programmatic API:
                            //this.behaviors.add('box-geometry')

                            // add a space in front of each name except the first
                            if ( behaviorNamesToAdd ) behaviorNamesToAdd += ' '

                            behaviorNamesToAdd += defaultBehaviorName
                        }
                    }
                }

                // if defaultBehaviors is an object, then behaviors are added
                // based on conditions.
                else if (typeof defaultBehaviors == 'object') {
                    const defaultBehaviorNames = Object.keys(defaultBehaviors)

                    for (const defaultBehaviorName of defaultBehaviorNames) {
                        const condition = defaultBehaviors[defaultBehaviorName]

                        if (
                            (typeof condition == 'function' && condition( initialBehaviorNames ) ) ||
                            (typeof condition != 'function' && condition )
                        ) {

                            // add a space in front of each name except the first
                            if ( behaviorNamesToAdd ) behaviorNamesToAdd += ' '

                            behaviorNamesToAdd += defaultBehaviorName

                        }

                    }
                }

                // add the needed behaviors all at once.
                if (behaviorNamesToAdd) {
                    let currentHasValue = this.getAttribute('has')

                    if (currentHasValue) currentHasValue + ' '

                    this.setAttribute( 'has', currentHasValue + behaviorNamesToAdd )
                }
            }

        }

    }
}
<commit_msg>fix typo<commit_after>
export default
function DefaultBehaviorsMixin(ElementClass) {

    // TODO This is here for now. Make it an extension to
    // element-behaviors so that it can be applied to any element
    // generically.
    return class DefaultBehaviors extends ElementClass {

        // override in subclasses
        static get defaultBehaviors() {
            return []
        }

        construct(...args) {
            if (super.construct) super.construct(...args)

            // If no geometry or material behavior is detected, add default ones.
            //
            // Deferring to a microtask doesn't work here, we must defer to a
            // macrotask with setTimeout, so we can detect if the element has
            // initial behaviors, otherwise the element's initial attributes
            // haven't been added yet (this is how HTML engines work, see
            // https://github.com/whatwg/dom/issues/522).
            //
            // TODO: If we use setTimeout (macrotask) deferral anywhere (like we do
            // here), and maybe even with microtask deferral (f.e. Promise), maybe
            // we should have a single place that initiate this deferral so that
            // everything in the engine can hook into it. Otherwise if different
            // call sites use setTimeout, logic will be firing at random and in
            // different order.
            setTimeout( () => this._setDefaultBehaviorsIfNeeded(), 0 )
        }

        _setDefaultBehaviorsIfNeeded() {
            let defaultBehaviors = this.constructor.defaultBehaviors

            // do nothing if there's no defaults
            if (!defaultBehaviors) return
            if (Object.keys(defaultBehaviors).length == 0) return

            const initialBehaviorNames = Array.from( this.behaviors.keys() )

            // small optimization: if there are no initial behaviors and we
            // have default behaviors, just set the default behaviors.
            if ( initialBehaviorNames.length == 0 ) {

                // if not an array, then it's an object.
                if (!defaultBehaviors instanceof Array) defaultBehaviors = Object.keys(defaultBehaviors)

                this.setAttribute( 'has', this.getAttribute( 'has' ) + ` ${defaultBehaviors.join(' ')}`)
            }

            // otherwise detect which default behavior(s) to add
            else {

                let behaviorNamesToAdd = ''

                // if defaultBehaviors is an array, use default logic to add
                // behaviors that aren't already added.
                if (defaultBehaviors instanceof Array) {
                    for (const defaultBehaviorName of defaultBehaviors) {

                        let hasBehavior = false

                        for ( const initialBehaviorName of initialBehaviorNames ) {
                            if ( defaultBehaviorName == initialBehaviorName ) {
                                hasBehavior = true
                                break
                            }
                        }

                        if (hasBehavior) continue
                        else {
                            // TODO programmatic API:
                            //this.behaviors.add('box-geometry')

                            // add a space in front of each name except the first
                            if ( behaviorNamesToAdd ) behaviorNamesToAdd += ' '

                            behaviorNamesToAdd += defaultBehaviorName
                        }
                    }
                }

                // if defaultBehaviors is an object, then behaviors are added
                // based on conditions.
                else if (typeof defaultBehaviors == 'object') {
                    const defaultBehaviorNames = Object.keys(defaultBehaviors)

                    for (const defaultBehaviorName of defaultBehaviorNames) {
                        const condition = defaultBehaviors[defaultBehaviorName]

                        if (
                            (typeof condition == 'function' && condition( initialBehaviorNames ) ) ||
                            (typeof condition != 'function' && condition )
                        ) {

                            // add a space in front of each name except the first
                            if ( behaviorNamesToAdd ) behaviorNamesToAdd += ' '

                            behaviorNamesToAdd += defaultBehaviorName

                        }

                    }
                }

                // add the needed behaviors all at once.
                if (behaviorNamesToAdd) {
                    let currentHasValue = this.getAttribute('has')

                    if (currentHasValue) currentHasValue += ' '

                    this.setAttribute( 'has', currentHasValue + behaviorNamesToAdd )
                }
            }

        }

    }
}
<|endoftext|>


<commit_before>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var sys = require('sys');
var url = require('url');
var fs = require('fs');

var async = require('extern/async');
var sprintf = require('extern/sprintf').sprintf;
var Errorf = require('util/misc').Errorf;

var dotfiles = require('util/client_dotfiles');
var http = require('util/http');
var terminal = require('util/terminal');

exports.config = {
  short_description: 'Add a remote',
  long_description: 'Add a reference to a remote cast-agent',
  required_arguments: [
    ['name', 'A name for the remote'],
    ['url', 'The URL to the remote']
  ],
  optional_arguments: [],
  options: [
    {
      names: ['--default', '-d'],
      dest: 'default',
      action: 'store_true',
      desc: 'Make this remote the default. Up to one default remote may be ' +
            'specified for each project, as well as one global default. If ' +
            'another default already exists, this will become the default ' +
            'instead.'
    },
    {
      names: ['--project', '-p'],
      dest: 'project',
      action: 'store_true',
      desc: 'Add the remote only to the current project. This will override ' +
            'any global remote with the same name, and a default project ' +
            'remote, if one exists, will take precedent over the global one.'
    }
  ]
};

exports.handle_command = function(args) {
  var conf = require('util/config').get();

  var calls = [
    // Make sure ~/.cast exists
    function(callback) {
      if (args.project) {
        // This also passes back the path which we don't want
        dotfiles.ensure_dot_cast_project(process.cwd(), function(err) {
          callback(err);
        });
      }
      else {
        dotfiles.ensure_dot_cast(callback);
      }
    },

    // Get or create the current remotes object
    function(callback) {
      if (args.project) {
        dotfiles.get_local_remotes(callback);
      }
      else {
        dotfiles.get_global_remotes(callback);
      }
    },

    function(remotes, callback) {
      // Check if remote with this name already exists
      if (remotes[args.name]) {
        callback(new Errorf("Remote with name '%s' already exists", args.name));
        return;
      }

      callback(null, remotes);
    }
  ];

  if (url.parse(args.url).protocol === 'https:') {
    calls = calls.concat([
      function(remotes, callback) {
        // Fetch the server SSL certificate information
        http.get_server_ssl_cert_info(args.url, function(err, cert_info) {
          if (err) {
            callback(err);
            return;
          }
          callback(null, remotes, cert_info);
        });
      },

      function(remotes, cert_info, callback) {
        var url_object, hostname, port, fingerprint;

        function print_cert_data(data) {
          var key;
          for (key in data) {
            if (data.hasOwnProperty(key)) {
              sys.puts(sprintf('    %s: %s', key, data[key]));
            }
          }
        }

        // Show ertificate information to user and ask before accepting
        sys.puts('Certificate information');
        sys.puts('  Subject:');
        print_cert_data(cert_info.subject);
        sys.puts('  Issuer:');
        print_cert_data(cert_info.issuer);
        sys.puts(sprintf('  Valid to: %s', cert_info.valid_to));
        sys.puts(sprintf('  Fingerprint: %s', cert_info.fingerprint));
        sys.puts('');

        terminal.prompt('Are you sure you want to accept this certificate?', ['y', 'n'], 'y', function(data) {
          if (data === 'y') {
           callback(null, remotes, cert_info.fingerprint);
           return;
          }

          callback(new Error('Certificate not accepted, remote not added'));
        });
      }
    ]);
  }
  else {
    calls.push(function(remotes, callback) {
      callback(null, remotes, null);
    });
  }

  // Insert the new remote
  calls.push(function(remotes, fingerprint, callback) {
    var url_object;
    var url_object = url.parse(args.url);
    var hostname = url_object.hostname;
    var port = url_object.port || 443;
    var is_default = args.default ? true : false;
    var name;

    // If this is the only global remote, make it the default
    if (!args.project && (Object.keys(remotes).length === 0)) {
      is_default = true;
    }

    // Make sure there are no other defaults if this one is default
    if (is_default) {
      for (name in remotes) {
        if (remotes.hasOwnProperty(name) && remotes[name].is_default) {
          remotes[name].is_default = false;
        }
      }
    }

    remotes[args.name] = {
      url: args.url,
      hostname: hostname,
      port: port,
      fingerprint: fingerprint,
      is_default: is_default
    };

    callback(null, remotes);
  });

  // Write it all back
  calls.push(function(remotes, callback) {
    var p = dotfiles.dot_cast_remotes_path;
    if (args.project) {
      p = dotfiles.local_remotes_path();
    }

    var fstream = fs.createWriteStream(p);

    fstream.write(JSON.stringify(remotes, null, 4));
    fstream.end();

    fstream.on('close', function() {
      return callback();
    });

    fstream.on('error', function(err) {
      fstream.removeAllListeners('end');
      return callback(new Error('Error writing remotes file: ' + err));
    });
  });

  async.waterfall(calls,
  function(err) {
    if (err) {
      sys.puts('Error: ' + err.message);
    }
    else {
      sys.puts('Remote added');
    }
  });
};
<commit_msg>jslint cleanup<commit_after>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var sys = require('sys');
var url = require('url');
var fs = require('fs');

var async = require('extern/async');
var sprintf = require('extern/sprintf').sprintf;
var Errorf = require('util/misc').Errorf;

var dotfiles = require('util/client_dotfiles');
var http = require('util/http');
var terminal = require('util/terminal');

exports.config = {
  short_description: 'Add a remote',
  long_description: 'Add a reference to a remote cast-agent',
  required_arguments: [
    ['name', 'A name for the remote'],
    ['url', 'The URL to the remote']
  ],
  optional_arguments: [],
  options: [
    {
      names: ['--default', '-d'],
      dest: 'make_default',
      action: 'store_true',
      desc: 'Make this remote the default. Up to one default remote may be ' +
            'specified for each project, as well as one global default. If ' +
            'another default already exists, this will become the default ' +
            'instead.'
    },
    {
      names: ['--project', '-p'],
      dest: 'project',
      action: 'store_true',
      desc: 'Add the remote only to the current project. This will override ' +
            'any global remote with the same name, and a default project ' +
            'remote, if one exists, will take precedent over the global one.'
    }
  ]
};

exports.handle_command = function(args) {
  var conf = require('util/config').get();

  var calls = [
    // Make sure ~/.cast exists
    function(callback) {
      if (args.project) {
        // This also passes back the path which we don't want
        dotfiles.ensure_dot_cast_project(process.cwd(), function(err) {
          callback(err);
        });
      }
      else {
        dotfiles.ensure_dot_cast(callback);
      }
    },

    // Get or create the current remotes object
    function(callback) {
      if (args.project) {
        dotfiles.get_local_remotes(callback);
      }
      else {
        dotfiles.get_global_remotes(callback);
      }
    },

    function(remotes, callback) {
      // Check if remote with this name already exists
      if (remotes[args.name]) {
        callback(new Errorf("Remote with name '%s' already exists", args.name));
        return;
      }

      callback(null, remotes);
    }
  ];

  if (url.parse(args.url).protocol === 'https:') {
    calls = calls.concat([
      function(remotes, callback) {
        // Fetch the server SSL certificate information
        http.get_server_ssl_cert_info(args.url, function(err, cert_info) {
          if (err) {
            callback(err);
            return;
          }
          callback(null, remotes, cert_info);
        });
      },

      function(remotes, cert_info, callback) {
        var hostname, port, fingerprint;

        function print_cert_data(data) {
          var key;
          for (key in data) {
            if (data.hasOwnProperty(key)) {
              sys.puts(sprintf('    %s: %s', key, data[key]));
            }
          }
        }

        // Show ertificate information to user and ask before accepting
        sys.puts('Certificate information');
        sys.puts('  Subject:');
        print_cert_data(cert_info.subject);
        sys.puts('  Issuer:');
        print_cert_data(cert_info.issuer);
        sys.puts(sprintf('  Valid to: %s', cert_info.valid_to));
        sys.puts(sprintf('  Fingerprint: %s', cert_info.fingerprint));
        sys.puts('');

        terminal.prompt('Are you sure you want to accept this certificate?', ['y', 'n'], 'y', function(data) {
          if (data === 'y') {
           callback(null, remotes, cert_info.fingerprint);
           return;
          }

          callback(new Error('Certificate not accepted, remote not added'));
        });
      }
    ]);
  }
  else {
    calls.push(function(remotes, callback) {
      callback(null, remotes, null);
    });
  }

  // Insert the new remote
  calls.push(function(remotes, fingerprint, callback) {
    var url_object = url.parse(args.url);
    var hostname = url_object.hostname;
    var port = url_object.port || 443;
    var is_default = args.make_default ? true : false;
    var name;

    // If this is the only global remote, make it the default
    if (!args.project && (Object.keys(remotes).length === 0)) {
      is_default = true;
    }

    // Make sure there are no other defaults if this one is default
    if (is_default) {
      for (name in remotes) {
        if (remotes.hasOwnProperty(name) && remotes[name].is_default) {
          remotes[name].is_default = false;
        }
      }
    }

    remotes[args.name] = {
      url: args.url,
      hostname: hostname,
      port: port,
      fingerprint: fingerprint,
      is_default: is_default
    };

    callback(null, remotes);
  });

  // Write it all back
  calls.push(function(remotes, callback) {
    var p = dotfiles.dot_cast_remotes_path;
    if (args.project) {
      p = dotfiles.local_remotes_path();
    }

    var fstream = fs.createWriteStream(p);

    fstream.write(JSON.stringify(remotes, null, 4));
    fstream.end();

    fstream.on('close', function() {
      return callback();
    });

    fstream.on('error', function(err) {
      fstream.removeAllListeners('end');
      return callback(new Error('Error writing remotes file: ' + err));
    });
  });

  async.waterfall(calls,
  function(err) {
    if (err) {
      sys.puts('Error: ' + err.message);
    }
    else {
      sys.puts('Remote added');
    }
  });
};
<|endoftext|>


<commit_before>import * as dom from '../utils/dom/index.js'
import { DismissReason } from '../utils/DismissReason.js'
import { callIfFunction } from '../utils/utils.js'
import { clickConfirm } from '../staticMethods/dom.js'

export const addKeydownHandler = (instance, globalState, innerParams, dismissWith) => {
  if (globalState.keydownTarget && globalState.keydownHandlerAdded) {
    globalState.keydownTarget.removeEventListener('keydown', globalState.keydownHandler, { capture: globalState.keydownListenerCapture })
    globalState.keydownHandlerAdded = false
  }

  if (!innerParams.toast) {
    globalState.keydownHandler = (e) => keydownHandler(instance, e, innerParams, dismissWith)
    globalState.keydownTarget = innerParams.keydownListenerCapture ? window : dom.getPopup()
    globalState.keydownListenerCapture = innerParams.keydownListenerCapture
    globalState.keydownTarget.addEventListener('keydown', globalState.keydownHandler, { capture: globalState.keydownListenerCapture })
    globalState.keydownHandlerAdded = true
  }
}

// Focus handling
export const setFocus = (innerParams, index, increment) => {
  const focusableElements = dom.getFocusableElements(innerParams.focusCancel)
  // search for visible elements and select the next possible match
  for (let i = 0; i < focusableElements.length; i++) {
    index = index + increment

    // rollover to first item
    if (index === focusableElements.length) {
      index = 0

      // go to last item
    } else if (index === -1) {
      index = focusableElements.length - 1
    }

    return focusableElements[index].focus()
  }
  // no visible focusable elements, focus the popup
  dom.getPopup().focus()
}

const arrowKeys = [
  'ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown',
  'Left', 'Right', 'Up', 'Down' // IE11
]

const escKeys = [
  'Escape',
  'Esc' // IE11
]

const keydownHandler = (instance, e, innerParams, dismissWith) => {
  if (innerParams.stopKeydownPropagation) {
    e.stopPropagation()
  }

  // ENTER
  if (e.key === 'Enter') {
    handleEnter(instance, e, innerParams)

  // TAB
  } else if (e.key === 'Tab') {
    handleTab(e, innerParams)

  // ARROWS - switch focus between buttons
  } else if (arrowKeys.includes(e.key)) {
    handleArrows()

  // ESC
  } else if (escKeys.includes(e.key)) {
    handleEsc(e, innerParams, dismissWith)
  }
}

const handleEnter = (instance, e, innerParams) => {
  // #720 #721
  if (e.isComposing) {
    return
  }

  if (e.target && instance.getInput() && e.target.outerHTML === instance.getInput().outerHTML) {
    if (['textarea', 'file'].includes(innerParams.input)) {
      return // do not submit
    }

    clickConfirm()
    e.preventDefault()
  }
}

const handleTab = (e, innerParams) => {
  const targetElement = e.target

  const focusableElements = dom.getFocusableElements(innerParams.focusCancel)
  let btnIndex = -1
  for (let i = 0; i < focusableElements.length; i++) {
    if (targetElement === focusableElements[i]) {
      btnIndex = i
      break
    }
  }

  if (!e.shiftKey) {
    // Cycle to the next button
    setFocus(innerParams, btnIndex, 1)
  } else {
    // Cycle to the prev button
    setFocus(innerParams, btnIndex, -1)
  }
  e.stopPropagation()
  e.preventDefault()
}

const handleArrows = () => {
  const confirmButton = dom.getConfirmButton()
  const cancelButton = dom.getCancelButton()
  // focus Cancel button if Confirm button is currently focused
  if (document.activeElement === confirmButton && dom.isVisible(cancelButton)) {
    cancelButton.focus()
    // and vice versa
  } else if (document.activeElement === cancelButton && dom.isVisible(confirmButton)) {
    confirmButton.focus()
  }
}

const handleEsc = (e, innerParams, dismissWith) => {
  if (callIfFunction(innerParams.allowEscapeKey)) {
    e.preventDefault()
    dismissWith(DismissReason.esc)
  }
}
<commit_msg>fix: remove superfluous arguments (#1742)<commit_after>import * as dom from '../utils/dom/index.js'
import { DismissReason } from '../utils/DismissReason.js'
import { callIfFunction } from '../utils/utils.js'
import { clickConfirm } from '../staticMethods/dom.js'

export const addKeydownHandler = (instance, globalState, innerParams, dismissWith) => {
  if (globalState.keydownTarget && globalState.keydownHandlerAdded) {
    globalState.keydownTarget.removeEventListener('keydown', globalState.keydownHandler, { capture: globalState.keydownListenerCapture })
    globalState.keydownHandlerAdded = false
  }

  if (!innerParams.toast) {
    globalState.keydownHandler = (e) => keydownHandler(instance, e, innerParams, dismissWith)
    globalState.keydownTarget = innerParams.keydownListenerCapture ? window : dom.getPopup()
    globalState.keydownListenerCapture = innerParams.keydownListenerCapture
    globalState.keydownTarget.addEventListener('keydown', globalState.keydownHandler, { capture: globalState.keydownListenerCapture })
    globalState.keydownHandlerAdded = true
  }
}

// Focus handling
export const setFocus = (innerParams, index, increment) => {
  const focusableElements = dom.getFocusableElements()
  // search for visible elements and select the next possible match
  for (let i = 0; i < focusableElements.length; i++) {
    index = index + increment

    // rollover to first item
    if (index === focusableElements.length) {
      index = 0

      // go to last item
    } else if (index === -1) {
      index = focusableElements.length - 1
    }

    return focusableElements[index].focus()
  }
  // no visible focusable elements, focus the popup
  dom.getPopup().focus()
}

const arrowKeys = [
  'ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown',
  'Left', 'Right', 'Up', 'Down' // IE11
]

const escKeys = [
  'Escape',
  'Esc' // IE11
]

const keydownHandler = (instance, e, innerParams, dismissWith) => {
  if (innerParams.stopKeydownPropagation) {
    e.stopPropagation()
  }

  // ENTER
  if (e.key === 'Enter') {
    handleEnter(instance, e, innerParams)

  // TAB
  } else if (e.key === 'Tab') {
    handleTab(e, innerParams)

  // ARROWS - switch focus between buttons
  } else if (arrowKeys.includes(e.key)) {
    handleArrows()

  // ESC
  } else if (escKeys.includes(e.key)) {
    handleEsc(e, innerParams, dismissWith)
  }
}

const handleEnter = (instance, e, innerParams) => {
  // #720 #721
  if (e.isComposing) {
    return
  }

  if (e.target && instance.getInput() && e.target.outerHTML === instance.getInput().outerHTML) {
    if (['textarea', 'file'].includes(innerParams.input)) {
      return // do not submit
    }

    clickConfirm()
    e.preventDefault()
  }
}

const handleTab = (e, innerParams) => {
  const targetElement = e.target

  const focusableElements = dom.getFocusableElements()
  let btnIndex = -1
  for (let i = 0; i < focusableElements.length; i++) {
    if (targetElement === focusableElements[i]) {
      btnIndex = i
      break
    }
  }

  if (!e.shiftKey) {
    // Cycle to the next button
    setFocus(innerParams, btnIndex, 1)
  } else {
    // Cycle to the prev button
    setFocus(innerParams, btnIndex, -1)
  }
  e.stopPropagation()
  e.preventDefault()
}

const handleArrows = () => {
  const confirmButton = dom.getConfirmButton()
  const cancelButton = dom.getCancelButton()
  // focus Cancel button if Confirm button is currently focused
  if (document.activeElement === confirmButton && dom.isVisible(cancelButton)) {
    cancelButton.focus()
    // and vice versa
  } else if (document.activeElement === cancelButton && dom.isVisible(confirmButton)) {
    confirmButton.focus()
  }
}

const handleEsc = (e, innerParams, dismissWith) => {
  if (callIfFunction(innerParams.allowEscapeKey)) {
    e.preventDefault()
    dismissWith(DismissReason.esc)
  }
}
<|endoftext|>


<commit_before>import sha256 from 'crypto-js/sha256';
import utmParams from 'driveback-utils/utmParams';
import getQueryParam from 'driveback-utils/getQueryParam';
import htmlGlobals from 'driveback-utils/htmlGlobals';
import cleanObject from 'driveback-utils/cleanObject';
import arrayMerge from 'driveback-utils/arrayMerge';
import size from 'driveback-utils/size';
import isCrawler from 'driveback-utils/isCrawler';
import each from 'driveback-utils/each';
import uuid from 'uuid/v1';
import Integration from './../Integration';
import StreamingFilters, {
  pageProps,
  listingProps,
  cartProps,
  productProps,
  transactionProps,
  campaignProps,
  listItemProps,
  websiteProps,
} from './DDManagerStreaming/Filters';
import {
  DIGITALDATA_VAR,
  PRODUCT_VAR,
} from './../variableTypes';
import {
  VIEWED_PAGE,
  VIEWED_CART,
  COMPLETED_TRANSACTION,
  VIEWED_PRODUCT,
  CLICKED_PRODUCT,
  VIEWED_PRODUCT_DETAIL,
  ADDED_PRODUCT,
  REMOVED_PRODUCT,
  VIEWED_PRODUCT_LISTING,
  SEARCHED_PRODUCTS,
  VIEWED_CAMPAIGN,
  CLICKED_CAMPAIGN,
  VIEWED_EXPERIMENT,
  INTEGRATION_VALIDATION_FAILED,
  EXCEPTION,
} from './../events/semanticEvents';

class DDManagerStreaming extends Integration {
  constructor(digitalData, options) {
    const optionsWithDefaults = Object.assign({
      projectId: '',
      projectName: '',
      trackingUrl: 'https://track.ddmanager.ru/collect',
      dimensions: {},
      metrics: {},
      internal: false,
    }, options);
    super(digitalData, optionsWithDefaults);
    this.website = {};

    this.dimensions = {};
    this.metrics = {};
    this.productDimensions = {};
    this.productMetrics = {};
    this.customEnrichableProps = [];

    // TODO: refactoring
    each(optionsWithDefaults.dimensions, (key, variable) => {
      if (variable.type === PRODUCT_VAR) {
        this.productDimensions[key] = variable.value;
      } else {
        if (variable.type === DIGITALDATA_VAR) {
          this.customEnrichableProps.push(variable.value);
        }
        this.dimensions[key] = variable.value;
      }
    });
    each(optionsWithDefaults.metrics, (key, variable) => {
      if (variable.type === PRODUCT_VAR) {
        this.productMetrics[key] = variable.value;
      } else {
        if (variable.type === DIGITALDATA_VAR) {
          this.customEnrichableProps.push(variable.value);
        }
        this.metrics[key] = variable.value;
      }
    });
    this.filters = new StreamingFilters(
      this.dimensions,
      this.metrics,
      this.productDimensions,
      this.productMetrics,
    );
  }

  initialize() {
    this._isLoaded = true;
    if (isCrawler(htmlGlobals.getNavigator().userAgent)) {
      return false;
    }
    return true;
  }

  getIgnoredEvents() {
    if (this.getOption('internal')) {
      return [VIEWED_PRODUCT, CLICKED_PRODUCT, INTEGRATION_VALIDATION_FAILED, EXCEPTION];
    }
    return [];
  }

  getEnrichableEventProps(event) {
    const mapping = {
      [VIEWED_PAGE]: ['page', 'user.userId', 'user.anonymousId', 'user.email', 'website'],
      [VIEWED_CART]: ['cart'],
      [COMPLETED_TRANSACTION]: ['transaction'],
      [VIEWED_PRODUCT_DETAIL]: ['product'],
      [VIEWED_PRODUCT_LISTING]: ['listing'],
      [SEARCHED_PRODUCTS]: ['listing'],
    };

    const enrichableProps = mapping[event.name] || [];
    arrayMerge(
      enrichableProps,
      this.customEnrichableProps,
    );
    return enrichableProps;
  }

  getValidationFields(...keys) {
    const fieldsMapping = {
      website: websiteProps,
      page: pageProps,
      cart: [...cartProps, 'vouchers'],
      listing: listingProps,
      transaction: [...transactionProps, 'vouchers'],
      product: productProps,
      campaign: campaignProps,
      listItem: listItemProps,
      experiment: ['id', 'name', 'variationId', 'variationName'],
    };

    const validationFields = (Array.isArray(keys)) ? keys.reduce((result, key) => {
      fieldsMapping[key].forEach((prop) => {
        result.push([key, prop].join('.'));
        if (key === 'campaign') {
          result.push(['campaigns[]', prop].join('.'));
        } else if (key === 'listItem') {
          result.push(['listItems[]', prop].join('.'));
        }
      });
      return result;
    }, []) : [];

    arrayMerge(validationFields, this.customEnrichableProps);
    arrayMerge(validationFields, ['category', 'label']);

    return validationFields;
  }

  getEventValidationConfig(event) {
    const productFields = () => this.getValidationFields('product');
    const mapping = {
      [VIEWED_PAGE]: {
        fields: this.getValidationFields('page', 'website'),
      },
      [VIEWED_CART]: {
        fields: this.getValidationFields('cart'),
      },
      [COMPLETED_TRANSACTION]: {
        fields: this.getValidationFields('transaction'),
      },
      [VIEWED_PRODUCT_DETAIL]: {
        fields: productFields,
      },
      [ADDED_PRODUCT]: {
        fields: productFields,
      },
      [REMOVED_PRODUCT]: {
        fields: productFields,
      },
      [VIEWED_PRODUCT_LISTING]: {
        fields: this.getValidationFields('listing'),
      },
      [SEARCHED_PRODUCTS]: {
        fields: this.getValidationFields('listing'),
      },
      [VIEWED_CAMPAIGN]: {
        fields: this.getValidationFields('campaign'),
      },
      [CLICKED_CAMPAIGN]: {
        fields: this.getValidationFields('campaign'),
      },
      [VIEWED_PRODUCT]: {
        fields: this.getValidationFields('listItem'),
      },
      [CLICKED_PRODUCT]: {
        fields: this.getValidationFields('listItem'),
      },
      [VIEWED_EXPERIMENT]: {
        fields: this.getValidationFields('experiment'),
      },
    };

    const validationConfig = mapping[event.name] || {};
    if (typeof validationConfig.fields === 'function') {
      validationConfig.fields = validationConfig.fields();
    } else {
      validationConfig.fields = validationConfig.fields || this.getValidationFields();
    }

    return validationConfig;
  }

  allowCustomEvents() {
    return true;
  }

  normalize(hitData) {
    const hitId = uuid();
    const gclid = getQueryParam('gclid');
    const campaign = utmParams(htmlGlobals.getLocation().search);
    if (gclid) {
      if (!campaign.source) campaign.source = 'google';
      if (!campaign.medium) campaign.medium = 'cpc';
    }
    const commonFields = cleanObject({
      hitId,
      projectId: this.getOption('projectId'),
      projectName: this.getOption('projectName'),
      anonymousId: this.getAnonymousId(),
      userId: this.getUserId(),
      emailHash: this.getEmailHash(),
      context: {
        campaign: size(campaign) ? campaign : undefined,
        library: this.library,
        page: {
          path: decodeURI(escape(htmlGlobals.getLocation().pathname)),
          referrer: decodeURI(escape(htmlGlobals.getDocument().referrer)),
          search: decodeURI(escape(htmlGlobals.getLocation().search)),
          title: htmlGlobals.getDocument().title,
          url: decodeURI(escape(htmlGlobals.getLocation().href)),
          hash: htmlGlobals.getLocation().hash,
        },
        userAgent: htmlGlobals.getNavigator().userAgent,
        screenWidth: window.screen ? window.screen.width : undefined,
        screenHeight: window.screen ? window.screen.height : undefined,
      },
      sentAt: (new Date()).toISOString(),
      version: 1,
    });

    return Object.assign(hitData, commonFields);
  }

  setAnonymousId(anonymousId) {
    this.anonymousId = anonymousId;
  }

  getAnonymousId() {
    return this.anonymousId;
  }

  getUserId() {
    return this.userId;
  }

  setUserId(userId) {
    this.userId = userId;
  }

  getEmailHash() {
    return this.emailHash;
  }

  setEmailHash(emailHash) {
    this.emailHash = emailHash;
  }

  trackEvent(event) {
    // identify
    if (size(event.user)) {
      const user = event.user || {};
      if (user.email) {
        this.setEmailHash(sha256(user.email.trim()).toString());
      }
      if (user.anonymousId) {
        this.setAnonymousId(user.anonymousId);
      }
      if (user.userId) {
        this.setUserId(String(user.userId));
      }
    }

    if (event.website) {
      const website = event.website;
      this.website = this.filters.filterWebsite(website);
    }

    this.sendEventHit(event);
  }

  sendEventHit(event) {
    const hitData = this.normalize({
      event: this.filters.filterEventHit(event),
      website: this.website,
      type: 'event',
    });
    this.send(hitData);
  }

  getCacheKey() {
    return ['ddm', 'stream', this.projectId].join(':');
  }

  send(hitData) {
    /*
    try {
      const streamCache = window.localStorage.getItem(this.getCacheKey());
      window.localStorage.setItem(this.getCacheKey(hitId), JSON.stringify(hitData));
    } catch (e) {
      // localstorage not supported
      // TODO: save to memory
    } */
    window.fetch(this.getOption('trackingUrl'), {
      method: 'post',
      credentials: 'include',
      mode: 'cors',
      body: JSON.stringify(hitData),
    }).then((response) => {
      if (response.ok) {
        // window.localStorage.removeItem(this.getCacheKey(hitData.hitId));
      }
    }).catch((e) => {
      console.warn(e);
    });
  }
}

export default DDManagerStreaming;
<commit_msg>website streaming fix<commit_after>import sha256 from 'crypto-js/sha256';
import utmParams from 'driveback-utils/utmParams';
import getQueryParam from 'driveback-utils/getQueryParam';
import htmlGlobals from 'driveback-utils/htmlGlobals';
import cleanObject from 'driveback-utils/cleanObject';
import arrayMerge from 'driveback-utils/arrayMerge';
import size from 'driveback-utils/size';
import isCrawler from 'driveback-utils/isCrawler';
import each from 'driveback-utils/each';
import uuid from 'uuid/v1';
import Integration from './../Integration';
import StreamingFilters, {
  pageProps,
  listingProps,
  cartProps,
  productProps,
  transactionProps,
  campaignProps,
  listItemProps,
  websiteProps,
} from './DDManagerStreaming/Filters';
import {
  DIGITALDATA_VAR,
  PRODUCT_VAR,
} from './../variableTypes';
import {
  VIEWED_PAGE,
  VIEWED_CART,
  COMPLETED_TRANSACTION,
  VIEWED_PRODUCT,
  CLICKED_PRODUCT,
  VIEWED_PRODUCT_DETAIL,
  ADDED_PRODUCT,
  REMOVED_PRODUCT,
  VIEWED_PRODUCT_LISTING,
  SEARCHED_PRODUCTS,
  VIEWED_CAMPAIGN,
  CLICKED_CAMPAIGN,
  VIEWED_EXPERIMENT,
  INTEGRATION_VALIDATION_FAILED,
  EXCEPTION,
} from './../events/semanticEvents';

class DDManagerStreaming extends Integration {
  constructor(digitalData, options) {
    const optionsWithDefaults = Object.assign({
      projectId: '',
      projectName: '',
      trackingUrl: 'https://track.ddmanager.ru/collect',
      dimensions: {},
      metrics: {},
      internal: false,
    }, options);
    super(digitalData, optionsWithDefaults);
    this.website = {};

    this.dimensions = {};
    this.metrics = {};
    this.productDimensions = {};
    this.productMetrics = {};
    this.customEnrichableProps = [];

    // TODO: refactoring
    each(optionsWithDefaults.dimensions, (key, variable) => {
      if (variable.type === PRODUCT_VAR) {
        this.productDimensions[key] = variable.value;
      } else {
        if (variable.type === DIGITALDATA_VAR) {
          this.customEnrichableProps.push(variable.value);
        }
        this.dimensions[key] = variable.value;
      }
    });
    each(optionsWithDefaults.metrics, (key, variable) => {
      if (variable.type === PRODUCT_VAR) {
        this.productMetrics[key] = variable.value;
      } else {
        if (variable.type === DIGITALDATA_VAR) {
          this.customEnrichableProps.push(variable.value);
        }
        this.metrics[key] = variable.value;
      }
    });
    this.filters = new StreamingFilters(
      this.dimensions,
      this.metrics,
      this.productDimensions,
      this.productMetrics,
    );
  }

  initialize() {
    this._isLoaded = true;
    if (isCrawler(htmlGlobals.getNavigator().userAgent)) {
      return false;
    }
    return true;
  }

  getIgnoredEvents() {
    if (this.getOption('internal')) {
      return [VIEWED_PRODUCT, CLICKED_PRODUCT, INTEGRATION_VALIDATION_FAILED, EXCEPTION];
    }
    return [];
  }

  getEnrichableEventProps(event) {
    const mapping = {
      [VIEWED_PAGE]: ['page', 'user.userId', 'user.anonymousId', 'user.email', 'website'],
      [VIEWED_CART]: ['cart'],
      [COMPLETED_TRANSACTION]: ['transaction'],
      [VIEWED_PRODUCT_DETAIL]: ['product'],
      [VIEWED_PRODUCT_LISTING]: ['listing'],
      [SEARCHED_PRODUCTS]: ['listing'],
    };

    const enrichableProps = mapping[event.name] || [];
    arrayMerge(
      enrichableProps,
      this.customEnrichableProps,
    );
    return enrichableProps;
  }

  getValidationFields(...keys) {
    const fieldsMapping = {
      website: websiteProps,
      page: pageProps,
      cart: [...cartProps, 'vouchers'],
      listing: listingProps,
      transaction: [...transactionProps, 'vouchers'],
      product: productProps,
      campaign: campaignProps,
      listItem: listItemProps,
      experiment: ['id', 'name', 'variationId', 'variationName'],
    };

    const validationFields = (Array.isArray(keys)) ? keys.reduce((result, key) => {
      fieldsMapping[key].forEach((prop) => {
        result.push([key, prop].join('.'));
        if (key === 'campaign') {
          result.push(['campaigns[]', prop].join('.'));
        } else if (key === 'listItem') {
          result.push(['listItems[]', prop].join('.'));
        }
      });
      return result;
    }, []) : [];

    arrayMerge(validationFields, this.customEnrichableProps);
    arrayMerge(validationFields, ['category', 'label']);

    return validationFields;
  }

  getEventValidationConfig(event) {
    const productFields = () => this.getValidationFields('product');
    const mapping = {
      [VIEWED_PAGE]: {
        fields: this.getValidationFields('page', 'website'),
      },
      [VIEWED_CART]: {
        fields: this.getValidationFields('cart'),
      },
      [COMPLETED_TRANSACTION]: {
        fields: this.getValidationFields('transaction'),
      },
      [VIEWED_PRODUCT_DETAIL]: {
        fields: productFields,
      },
      [ADDED_PRODUCT]: {
        fields: productFields,
      },
      [REMOVED_PRODUCT]: {
        fields: productFields,
      },
      [VIEWED_PRODUCT_LISTING]: {
        fields: this.getValidationFields('listing'),
      },
      [SEARCHED_PRODUCTS]: {
        fields: this.getValidationFields('listing'),
      },
      [VIEWED_CAMPAIGN]: {
        fields: this.getValidationFields('campaign'),
      },
      [CLICKED_CAMPAIGN]: {
        fields: this.getValidationFields('campaign'),
      },
      [VIEWED_PRODUCT]: {
        fields: this.getValidationFields('listItem'),
      },
      [CLICKED_PRODUCT]: {
        fields: this.getValidationFields('listItem'),
      },
      [VIEWED_EXPERIMENT]: {
        fields: this.getValidationFields('experiment'),
      },
    };

    const validationConfig = mapping[event.name] || {};
    if (typeof validationConfig.fields === 'function') {
      validationConfig.fields = validationConfig.fields();
    } else {
      validationConfig.fields = validationConfig.fields || this.getValidationFields();
    }

    return validationConfig;
  }

  allowCustomEvents() {
    return true;
  }

  normalize(hitData) {
    const hitId = uuid();
    const gclid = getQueryParam('gclid');
    const campaign = utmParams(htmlGlobals.getLocation().search);
    if (gclid) {
      if (!campaign.source) campaign.source = 'google';
      if (!campaign.medium) campaign.medium = 'cpc';
    }
    const commonFields = cleanObject({
      hitId,
      projectId: this.getOption('projectId'),
      projectName: this.getOption('projectName'),
      anonymousId: this.getAnonymousId(),
      userId: this.getUserId(),
      emailHash: this.getEmailHash(),
      context: {
        campaign: size(campaign) ? campaign : undefined,
        library: this.library,
        page: {
          path: decodeURI(escape(htmlGlobals.getLocation().pathname)),
          referrer: decodeURI(escape(htmlGlobals.getDocument().referrer)),
          search: decodeURI(escape(htmlGlobals.getLocation().search)),
          title: htmlGlobals.getDocument().title,
          url: decodeURI(escape(htmlGlobals.getLocation().href)),
          hash: htmlGlobals.getLocation().hash,
        },
        userAgent: htmlGlobals.getNavigator().userAgent,
        screenWidth: window.screen ? window.screen.width : undefined,
        screenHeight: window.screen ? window.screen.height : undefined,
      },
      sentAt: (new Date()).toISOString(),
      version: 1,
    });

    return Object.assign(hitData, commonFields);
  }

  setAnonymousId(anonymousId) {
    this.anonymousId = anonymousId;
  }

  getAnonymousId() {
    return this.anonymousId;
  }

  getUserId() {
    return this.userId;
  }

  setUserId(userId) {
    this.userId = userId;
  }

  getEmailHash() {
    return this.emailHash;
  }

  setEmailHash(emailHash) {
    this.emailHash = emailHash;
  }

  trackEvent(event) {
    // identify
    if (size(event.user)) {
      const user = event.user || {};
      if (user.email) {
        this.setEmailHash(sha256(user.email.trim()).toString());
      }
      if (user.anonymousId) {
        this.setAnonymousId(user.anonymousId);
      }
      if (user.userId) {
        this.setUserId(String(user.userId));
      }
    }

    if (event.name === VIEWED_PAGE && event.website) {
      const website = event.website;
      this.website = this.filters.filterWebsite(website);
    }

    this.sendEventHit(event);
  }

  sendEventHit(event) {
    const hitData = this.normalize({
      event: this.filters.filterEventHit(event),
      website: this.website,
      type: 'event',
    });
    this.send(hitData);
  }

  getCacheKey() {
    return ['ddm', 'stream', this.projectId].join(':');
  }

  send(hitData) {
    /*
    try {
      const streamCache = window.localStorage.getItem(this.getCacheKey());
      window.localStorage.setItem(this.getCacheKey(hitId), JSON.stringify(hitData));
    } catch (e) {
      // localstorage not supported
      // TODO: save to memory
    } */
    window.fetch(this.getOption('trackingUrl'), {
      method: 'post',
      credentials: 'include',
      mode: 'cors',
      body: JSON.stringify(hitData),
    }).then((response) => {
      if (response.ok) {
        // window.localStorage.removeItem(this.getCacheKey(hitData.hitId));
      }
    }).catch((e) => {
      console.warn(e);
    });
  }
}

export default DDManagerStreaming;
<|endoftext|>


<commit_before>/* File increment.js
 * Autoincrement the value of selected fields.
 * Author: Maxim Izmaylov (izmaylov.maxim@netcentrum.cz)
 * Copyright: NetCentrum @2007
 * Requirements: jquery.js
 */

$(function(){
	$('.increment').each(function(i){
		this.id = 'inc-' + i;
		$(this).focus(function(){
			if($(this).val() == ''){
				var elId = $(this).attr('id').replace('inc-', '') - 0;
				var order = $('#inc-' + (elId - 1)).val();
				if(elId > 0 && order != '' && /^\d+$/.test(order)){
					$(this).val(order - 0 + 1);
				} else if(elId > 1 && (order == '' || /\w/.test(order))){
					for(var x = elId - 2; x >= 0; x--){
						order = $('#inc-' + x).val();
						if(order != '' && /^\d+$/.test(order)){
							$(this).val(order - 0 + 1);
							return;
						}
					}
					$(this).val(1);
				} else {
					$(this).val(1);
				}
			}
		}).keyup(function(event){
			var c = event.keyCode;
			var changeValue = function(element, change){
				var val = element.val();
				if(/\d+/.test(val)){
					element.val(val - 0 + change);
				}
			}
			switch(c){
				case 27:
					$(this).val('');
					$(this).blur();
					break;
				case 32:
					$(this).val('');
					$(this).blur();
					$(this).focus();
					break;
				case 38:
					changeValue($(this), 1);
					break;
				case 39:
					changeValue($(this), 1);
					break;
				case 37:
					changeValue($(this), -1);
					break;
				case 40:
					changeValue($(this), -1);
					break;
			}
		});
	});
});<commit_msg>Change js incrementing order of objects displayed in Gallery.<commit_after>/* File increment.js
 * Autoincrement the value of selected fields.
 * Author: Maxim Izmaylov (izmaylov.maxim@netcentrum.cz)
 * Copyright: NetCentrum @2007
 * Requirements: jquery.js
 */

$(function(){
	$('.increment').each(function(i){
		this.id = 'inc-' + i;
		$(this).focus(function(){
			if($(this).val() == ''){
				var elId = $(this).attr('id').replace('inc-', '') - 0;
				var order = $('#inc-' + (elId - 1)).val();
				if(elId > 0 && order != '' && /^\d+$/.test(order)){
					$(this).val(order - 0 + 10);
				} else if(elId > 1 && (order == '' || /\w/.test(order))){
					for(var x = elId - 2; x >= 0; x--){
						order = $('#inc-' + x).val();
						if(order != '' && /^\d+$/.test(order)){
							$(this).val(order - 0 + 10);
							return;
						}
					}
					$(this).val(10);
				} else {
					$(this).val(10);
				}
			}
		}).keyup(function(event){
			var c = event.keyCode;
			var changeValue = function(element, change){
				var val = element.val();
				if(/\d+/.test(val)){
					element.val(val - 0 + change);
				}
			}
			switch(c){
				case 27:
					$(this).val('');
					$(this).blur();
					break;
				case 32:
					$(this).val('');
					$(this).blur();
					$(this).focus();
					break;
				case 38:
					changeValue($(this), 1);
					break;
				case 39:
					changeValue($(this), 1);
					break;
				case 37:
					changeValue($(this), -1);
					break;
				case 40:
					changeValue($(this), -1);
					break;
			}
		});
	});
});
<|endoftext|>