<commit_before>import { format } from 'util';
import _ from 'lodash';
import { Record, RepeatableItemValue } from 'fulcrum-core';
import pgformat from 'pg-format';

export default class RecordValues {
  static updateForRecordStatements(db, record, options = {}) {
    const statements = [];

    statements.push.apply(statements, this.deleteForRecordStatements(db, record, record.form, options));
    statements.push.apply(statements, this.insertForRecordStatements(db, record, record.form, options));

    return statements;
  }

  static insertForRecordStatements(db, record, form, options = {}) {
    const statements = [];

    statements.push(this.insertRowForFeatureStatement(db, form, record, null, record, options));
    statements.push.apply(statements, this.insertChildFeaturesForFeatureStatements(db, form, record, record, options));
    statements.push.apply(statements, this.insertMultipleValuesForFeatureStatements(db, form, record, record, options));
    statements.push.apply(statements, this.insertChildMultipleValuesForFeatureStatements(db, form, record, record, options));

    return statements;
  }

  static insertRowForFeatureStatement(db, form, feature, parentFeature, record, options = {}) {
    const values = this.columnValuesForFeature(feature, options);
    const systemValues = this.systemColumnValuesForFeature(feature, parentFeature, record, options);

    Object.assign(values, systemValues);

    let tableName = null;

    if (feature instanceof RepeatableItemValue) {
      // TODO(zhm) add public interface for accessing _element, like `get repeatableElement()`
      tableName = this.tableNameWithForm(form, feature._element);
    } else {
      tableName = this.tableNameWithForm(form, null);
    }

    return db.insertStatement(tableName, values, {pk: 'id'});
  }

  static insertChildFeaturesForFeatureStatements(db, form, feature, record, options = {}) {
    const statements = [];

    for (const formValue of feature.formValues.all) {
      if (formValue.element.isRepeatableElement) {
        // TODO(zhm) add public interface for _items
        for (const repeatableItem of formValue._items) {
          statements.push(this.insertRowForFeatureStatement(db, form, repeatableItem, feature, record, options));
          statements.push.apply(statements, this.insertChildFeaturesForFeatureStatements(db, form, repeatableItem, record, options));
        }
      }
    }

    return statements;
  }

  static columnValuesForFeature(feature, options = {}) {
    const values = {};

    for (const formValue of feature.formValues.all) {
      if (formValue.isEmpty) {
        continue;
      }

      let columnValue = formValue.columnValue;

      if (_.isNumber(columnValue) || _.isString(columnValue) || _.isArray(columnValue) || _.isDate(columnValue)) {
        // don't allow dates greater than 9999, yes - they exist in the wild
        if (_.isDate(columnValue) && columnValue.getFullYear() > 9999) {
          columnValue = null;
        }

        values['f' + formValue.element.key.toLowerCase()] = columnValue;
      } else if (columnValue) {
        Object.assign(values, columnValue);

        const element = formValue.element;

        if (element && options.mediaURLFormatter) {
          if (element.isPhotoElement || element.isVideoElement || element.isAudioElement) {
            const prefix = 'f' + formValue.element.key.toLowerCase();

            values[prefix + '_urls'] = options.mediaURLFormatter(formValue);

            if (options.mediaViewURLFormatter) {
              values[prefix + '_view_url'] = options.mediaViewURLFormatter(formValue);
            }
          }
        }
      }
    }

    return values;
  }

  static insertMultipleValuesForFeatureStatements(db, form, feature, record, options = {}) {
    const statements = [];

    const values = this.multipleValuesForFeature(feature, record);

    const tableName = this.multipleValueTableNameWithForm(form);

    let parentResourceId = null;

    if (feature instanceof RepeatableItemValue) {
      parentResourceId = feature.id;
    }

    for (const multipleValueItem of values) {
      const insertValues = Object.assign({}, {key: multipleValueItem.element.key, text_value: multipleValueItem.value},
                                         {record_id: record.rowID, record_resource_id: record.id, parent_resource_id: parentResourceId});

      statements.push(db.insertStatement(tableName, insertValues, {pk: 'id'}));
    }

    return statements;
  }

  static insertChildMultipleValuesForFeatureStatements(db, form, feature, record, options = {}) {
    const statements = [];

    for (const formValue of feature.formValues.all) {
      if (formValue.isRepeatableElement) {
        for (const repeatableItem of formValue._items) {
          statements.push.apply(statements, this.insertMultipleValuesForFeatureStatements(db, form, repeatableItem, record, options));
          statements.push.apply(statements, this.insertChildMultipleValuesForFeatureStatements(db, form, repeatableItem, record, options));
        }
      }
    }

    return statements;
  }

  static multipleValuesForFeature(feature, record) {
    const values = [];

    for (const formValue of feature.formValues.all) {
      if (formValue.isEmpty) {
        continue;
      }

      const featureValues = formValue.multipleValues;

      if (featureValues) {
        values.push.apply(values, featureValues);
      }
    }

    return values;
  }

  static systemColumnValuesForFeature(feature, parentFeature, record, options = {}) {
    const values = {};

    values.record_id = record.rowID;
    values.record_resource_id = record.id;

    if (options.reportURLFormatter) {
      values.report_url = options.reportURLFormatter(feature);
    }

    if (feature instanceof Record) {
      if (record._projectRowID) {
        values.project_id = record._projectRowID;
      }

      if (record.projectID) {
        values.project_resource_id = record.projectID;
      }

      if (record._assignedToRowID) {
        values.assigned_to_id = record._assignedToRowID;
      }

      if (record.assignedToID) {
        values.assigned_to_resource_id = record.assignedToID;
      }

      if (record._createdByRowID) {
        values.created_by_id = record._createdByRowID;
      }

      if (record.createdByID) {
        values.created_by_resource_id = record.createdByID;
      }

      if (record._updatedByRowID) {
        values.updated_by_id = record._updatedByRowID;
      }

      if (record.updatedByID) {
        values.updated_by_resource_id = record.updatedByID;
      }

      if (record._changesetRowID) {
        values.changeset_id = record._changesetRowID;
      }

      if (record.changesetID) {
        values.changeset_resource_id = record.changesetID;
      }

      if (record.status) {
        values.status = record.status;
      }

      if (record.latitude != null) {
        values.latitude = record.latitude;
      }

      if (record.longitude != null) {
        values.longitude = record.longitude;
      }

      values.altitude = record.altitude;
      values.speed = record.speed;
      values.course = record.course;
      values.vertical_accuracy = record.verticalAccuracy;
      values.horizontal_accuracy = record.horizontalAccuracy;
    } else if (feature instanceof RepeatableItemValue) {
      values.resource_id = feature.id;
      values.index = feature.index;
      values.parent_resource_id = parentFeature.id;

      if (feature.hasCoordinate) {
        values.latitude = feature.latitude;
        values.longitude = feature.longitude;
      }

      // record values
      if (record.status) {
        values.record_status = record.status;
      }

      if (record._projectRowID) {
        values.record_project_id = record._projectRowID;
      }

      if (record.projectID) {
        values.record_project_resource_id = record.projectID;
      }

      if (record._assignedToRowID) {
        values.record_assigned_to_id = record._assignedToRowID;
      }

      if (record.assignedToID) {
        values.record_assigned_to_resource_id = record.assignedToID;
      }

      // linked fields
      if (feature.createdBy) {
        values.created_by_id = feature.createdBy.rowID;
      }

      if (feature.createdByID) {
        values.created_by_resource_id = feature.createdByID;
      }

      if (feature.updatedBy) {
        values.updated_by_id = feature.updatedBy.rowID;
      }

      if (feature.updatedByID) {
        values.updated_by_resource_id = feature.updatedByID;
      }

      if (feature.changeset) {
        values.changeset_id = feature.changeset.rowID;
        values.changeset_resource_id = feature.changesetID;
      } else if (record._changesetRowID) {
        values.changeset_id = record._changesetRowID;
        values.changeset_resource_id = record.changesetID;
      }
    }

    values.title = feature.displayValue;

    values.form_values = JSON.stringify(feature.formValues.toJSON());

    this.setupSearch(values, feature);

    if (feature.hasCoordinate) {
      values.geometry = this.setupPoint(values, feature.latitude, feature.longitude);
    } else {
      values.geometry = null;
    }

    values.created_at = feature.clientCreatedAt || feature.createdAt;
    values.updated_at = feature.clientUpdatedAt || feature.updatedAt;
    values.version = feature.version;

    if (values.created_by_id == null) {
      values.created_by_id = -1;
    }

    if (values.updated_by_id == null) {
      values.updated_by_id = -1;
    }

    values.server_created_at = feature.createdAt;
    values.server_updated_at = feature.updatedAt;

    values.created_duration = feature.createdDuration;
    values.updated_duration = feature.updatedDuration;
    values.edited_duration = feature.editedDuration;

    values.created_latitude = feature.createdLatitude;
    values.created_longitude = feature.createdLongitude;
    values.created_altitude = feature.createdAltitude;
    values.created_horizontal_accuracy = feature.createdAccuracy;

    if (feature.hasCreatedCoordinate) {
      values.created_geometry = this.setupPoint(values, feature.createdLatitude, feature.createdLongitude);
    }

    values.updated_latitude = feature.updatedLatitude;
    values.updated_longitude = feature.updatedLongitude;
    values.updated_altitude = feature.updatedAltitude;
    values.updated_horizontal_accuracy = feature.updatedAccuracy;

    if (feature.hasUpdatedCoordinate) {
      values.updated_geometry = this.setupPoint(values, feature.updatedLatitude, feature.updatedLongitude);
    }

    return values;
  }

  static deleteRowsForRecordStatement(db, record, tableName) {
    return db.deleteStatement(tableName, {record_resource_id: record.id});
  }

  static deleteRowsStatement(db, tableName) {
    return db.deleteStatement(tableName, {});
  }

  static deleteForRecordStatements(db, record, form) {
    const repeatables = form.elementsOfType('Repeatable');

    const statements = [];

    let tableName = this.tableNameWithForm(form, null);

    statements.push(this.deleteRowsForRecordStatement(db, record, tableName));

    for (const repeatable of repeatables) {
      tableName = this.tableNameWithForm(form, repeatable);

      statements.push(this.deleteRowsForRecordStatement(db, record, tableName));
    }

    tableName = this.multipleValueTableNameWithForm(form);

    statements.push(this.deleteRowsForRecordStatement(db, record, tableName));

    return statements;
  }

  static deleteForFormStatements(db, form) {
    const repeatables = form.elementsOfType('Repeatable');

    const statements = [];

    let tableName = this.tableNameWithForm(form, null);

    statements.push(this.deleteRowsStatement(db, tableName));

    for (const repeatable of repeatables) {
      tableName = this.tableNameWithForm(form, repeatable);

      statements.push(this.deleteRowsStatement(db, tableName));
    }

    tableName = this.multipleValueTableNameWithForm(form);

    statements.push(this.deleteRowsStatement(db, tableName));

    return statements;
  }

  static multipleValueTableNameWithForm(form) {
    return format('account_%s_form_%s_values', form._accountRowID, form.rowID);
  }

  static tableNameWithForm(form, repeatable) {
    if (repeatable == null) {
      return format('account_%s_form_%s', form._accountRowID, form.rowID);
    }

    return format('account_%s_form_%s_%s', form._accountRowID, form.rowID, repeatable.key);
  }

  static setupSearch(values, feature) {
    const searchableValue = feature.searchableValue;

    values.record_index_text = searchableValue;
    values.record_index = {raw: `to_tsvector(${ pgformat('%L', searchableValue) })`};

    return values;
  }

  static setupPoint(values, latitude, longitude) {
    const wkt = pgformat('POINT(%s %s)', longitude, latitude);

    return {raw: `ST_Force2D(ST_SetSRID(ST_GeomFromText('${ wkt }'), 4326))`};
  }
}
<commit_msg>Add support for disabling array types in the record values for usage by plugins<commit_after>import { format } from 'util';
import _ from 'lodash';
import { Record, RepeatableItemValue } from 'fulcrum-core';
import pgformat from 'pg-format';

export default class RecordValues {
  static updateForRecordStatements(db, record, options = {}) {
    const statements = [];

    statements.push.apply(statements, this.deleteForRecordStatements(db, record, record.form, options));
    statements.push.apply(statements, this.insertForRecordStatements(db, record, record.form, options));

    return statements;
  }

  static insertForRecordStatements(db, record, form, options = {}) {
    const statements = [];

    statements.push(this.insertRowForFeatureStatement(db, form, record, null, record, options));
    statements.push.apply(statements, this.insertChildFeaturesForFeatureStatements(db, form, record, record, options));
    statements.push.apply(statements, this.insertMultipleValuesForFeatureStatements(db, form, record, record, options));
    statements.push.apply(statements, this.insertChildMultipleValuesForFeatureStatements(db, form, record, record, options));

    return statements;
  }

  static insertRowForFeatureStatement(db, form, feature, parentFeature, record, options = {}) {
    const values = this.columnValuesForFeature(feature, options);
    const systemValues = this.systemColumnValuesForFeature(feature, parentFeature, record, options);

    Object.assign(values, systemValues);

    let tableName = null;

    if (feature instanceof RepeatableItemValue) {
      // TODO(zhm) add public interface for accessing _element, like `get repeatableElement()`
      tableName = this.tableNameWithForm(form, feature._element);
    } else {
      tableName = this.tableNameWithForm(form, null);
    }

    return db.insertStatement(tableName, values, {pk: 'id'});
  }

  static insertChildFeaturesForFeatureStatements(db, form, feature, record, options = {}) {
    const statements = [];

    for (const formValue of feature.formValues.all) {
      if (formValue.element.isRepeatableElement) {
        // TODO(zhm) add public interface for _items
        for (const repeatableItem of formValue._items) {
          statements.push(this.insertRowForFeatureStatement(db, form, repeatableItem, feature, record, options));
          statements.push.apply(statements, this.insertChildFeaturesForFeatureStatements(db, form, repeatableItem, record, options));
        }
      }
    }

    return statements;
  }

  static maybeAssignArray(values, key, value, disableArrays) {
    if (value == null) {
      return;
    }

    values[key] = (_.isArray(value) && disableArrays) ? value.join(',')
                                                      : value;
  }

  static columnValuesForFeature(feature, options = {}) {
    const values = {};

    for (const formValue of feature.formValues.all) {
      if (formValue.isEmpty) {
        continue;
      }

      let columnValue = formValue.columnValue;

      if (_.isNumber(columnValue) || _.isString(columnValue) || _.isArray(columnValue) || _.isDate(columnValue)) {
        // don't allow dates greater than 9999, yes - they exist in the wild
        if (_.isDate(columnValue) && columnValue.getFullYear() > 9999) {
          columnValue = null;
        }

        this.maybeAssignArray(values, 'f' + formValue.element.key.toLowerCase(), columnValue, options.disableArrays);
      } else if (columnValue) {
        const element = formValue.element;

        if (element && options.mediaURLFormatter) {
          if (element.isPhotoElement || element.isVideoElement || element.isAudioElement) {
            const prefix = 'f' + formValue.element.key.toLowerCase();

            columnValue[prefix + '_urls'] = options.mediaURLFormatter(formValue);

            if (options.mediaViewURLFormatter) {
              columnValue[prefix + '_view_url'] = options.mediaViewURLFormatter(formValue);
            }
          }
        }

        // if array types are disabled, convert all the props to delimited values
        if (options.disableArrays) {
          for (const key of Object.keys(columnValue)) {
            this.maybeAssignArray(columnValue, key, columnValue[key], options.disableArrays);
          }
        }

        Object.assign(values, columnValue);
      }
    }

    return values;
  }

  static insertMultipleValuesForFeatureStatements(db, form, feature, record, options = {}) {
    const statements = [];

    const values = this.multipleValuesForFeature(feature, record);

    const tableName = this.multipleValueTableNameWithForm(form);

    let parentResourceId = null;

    if (feature instanceof RepeatableItemValue) {
      parentResourceId = feature.id;
    }

    for (const multipleValueItem of values) {
      const insertValues = Object.assign({}, {key: multipleValueItem.element.key, text_value: multipleValueItem.value},
                                         {record_id: record.rowID, record_resource_id: record.id, parent_resource_id: parentResourceId});

      statements.push(db.insertStatement(tableName, insertValues, {pk: 'id'}));
    }

    return statements;
  }

  static insertChildMultipleValuesForFeatureStatements(db, form, feature, record, options = {}) {
    const statements = [];

    for (const formValue of feature.formValues.all) {
      if (formValue.isRepeatableElement) {
        for (const repeatableItem of formValue._items) {
          statements.push.apply(statements, this.insertMultipleValuesForFeatureStatements(db, form, repeatableItem, record, options));
          statements.push.apply(statements, this.insertChildMultipleValuesForFeatureStatements(db, form, repeatableItem, record, options));
        }
      }
    }

    return statements;
  }

  static multipleValuesForFeature(feature, record) {
    const values = [];

    for (const formValue of feature.formValues.all) {
      if (formValue.isEmpty) {
        continue;
      }

      const featureValues = formValue.multipleValues;

      if (featureValues) {
        values.push.apply(values, featureValues);
      }
    }

    return values;
  }

  static systemColumnValuesForFeature(feature, parentFeature, record, options = {}) {
    const values = {};

    values.record_id = record.rowID;
    values.record_resource_id = record.id;

    if (options.reportURLFormatter) {
      values.report_url = options.reportURLFormatter(feature);
    }

    if (feature instanceof Record) {
      if (record._projectRowID) {
        values.project_id = record._projectRowID;
      }

      if (record.projectID) {
        values.project_resource_id = record.projectID;
      }

      if (record._assignedToRowID) {
        values.assigned_to_id = record._assignedToRowID;
      }

      if (record.assignedToID) {
        values.assigned_to_resource_id = record.assignedToID;
      }

      if (record._createdByRowID) {
        values.created_by_id = record._createdByRowID;
      }

      if (record.createdByID) {
        values.created_by_resource_id = record.createdByID;
      }

      if (record._updatedByRowID) {
        values.updated_by_id = record._updatedByRowID;
      }

      if (record.updatedByID) {
        values.updated_by_resource_id = record.updatedByID;
      }

      if (record._changesetRowID) {
        values.changeset_id = record._changesetRowID;
      }

      if (record.changesetID) {
        values.changeset_resource_id = record.changesetID;
      }

      if (record.status) {
        values.status = record.status;
      }

      if (record.latitude != null) {
        values.latitude = record.latitude;
      }

      if (record.longitude != null) {
        values.longitude = record.longitude;
      }

      values.altitude = record.altitude;
      values.speed = record.speed;
      values.course = record.course;
      values.vertical_accuracy = record.verticalAccuracy;
      values.horizontal_accuracy = record.horizontalAccuracy;
    } else if (feature instanceof RepeatableItemValue) {
      values.resource_id = feature.id;
      values.index = feature.index;
      values.parent_resource_id = parentFeature.id;

      if (feature.hasCoordinate) {
        values.latitude = feature.latitude;
        values.longitude = feature.longitude;
      }

      // record values
      if (record.status) {
        values.record_status = record.status;
      }

      if (record._projectRowID) {
        values.record_project_id = record._projectRowID;
      }

      if (record.projectID) {
        values.record_project_resource_id = record.projectID;
      }

      if (record._assignedToRowID) {
        values.record_assigned_to_id = record._assignedToRowID;
      }

      if (record.assignedToID) {
        values.record_assigned_to_resource_id = record.assignedToID;
      }

      // linked fields
      if (feature.createdBy) {
        values.created_by_id = feature.createdBy.rowID;
      }

      if (feature.createdByID) {
        values.created_by_resource_id = feature.createdByID;
      }

      if (feature.updatedBy) {
        values.updated_by_id = feature.updatedBy.rowID;
      }

      if (feature.updatedByID) {
        values.updated_by_resource_id = feature.updatedByID;
      }

      if (feature.changeset) {
        values.changeset_id = feature.changeset.rowID;
        values.changeset_resource_id = feature.changesetID;
      } else if (record._changesetRowID) {
        values.changeset_id = record._changesetRowID;
        values.changeset_resource_id = record.changesetID;
      }
    }

    values.title = feature.displayValue;

    values.form_values = JSON.stringify(feature.formValues.toJSON());

    this.setupSearch(values, feature);

    if (feature.hasCoordinate) {
      values.geometry = this.setupPoint(values, feature.latitude, feature.longitude);
    } else {
      values.geometry = null;
    }

    values.created_at = feature.clientCreatedAt || feature.createdAt;
    values.updated_at = feature.clientUpdatedAt || feature.updatedAt;
    values.version = feature.version;

    if (values.created_by_id == null) {
      values.created_by_id = -1;
    }

    if (values.updated_by_id == null) {
      values.updated_by_id = -1;
    }

    values.server_created_at = feature.createdAt;
    values.server_updated_at = feature.updatedAt;

    values.created_duration = feature.createdDuration;
    values.updated_duration = feature.updatedDuration;
    values.edited_duration = feature.editedDuration;

    values.created_latitude = feature.createdLatitude;
    values.created_longitude = feature.createdLongitude;
    values.created_altitude = feature.createdAltitude;
    values.created_horizontal_accuracy = feature.createdAccuracy;

    if (feature.hasCreatedCoordinate) {
      values.created_geometry = this.setupPoint(values, feature.createdLatitude, feature.createdLongitude);
    }

    values.updated_latitude = feature.updatedLatitude;
    values.updated_longitude = feature.updatedLongitude;
    values.updated_altitude = feature.updatedAltitude;
    values.updated_horizontal_accuracy = feature.updatedAccuracy;

    if (feature.hasUpdatedCoordinate) {
      values.updated_geometry = this.setupPoint(values, feature.updatedLatitude, feature.updatedLongitude);
    }

    return values;
  }

  static deleteRowsForRecordStatement(db, record, tableName) {
    return db.deleteStatement(tableName, {record_resource_id: record.id});
  }

  static deleteRowsStatement(db, tableName) {
    return db.deleteStatement(tableName, {});
  }

  static deleteForRecordStatements(db, record, form) {
    const repeatables = form.elementsOfType('Repeatable');

    const statements = [];

    let tableName = this.tableNameWithForm(form, null);

    statements.push(this.deleteRowsForRecordStatement(db, record, tableName));

    for (const repeatable of repeatables) {
      tableName = this.tableNameWithForm(form, repeatable);

      statements.push(this.deleteRowsForRecordStatement(db, record, tableName));
    }

    tableName = this.multipleValueTableNameWithForm(form);

    statements.push(this.deleteRowsForRecordStatement(db, record, tableName));

    return statements;
  }

  static deleteForFormStatements(db, form) {
    const repeatables = form.elementsOfType('Repeatable');

    const statements = [];

    let tableName = this.tableNameWithForm(form, null);

    statements.push(this.deleteRowsStatement(db, tableName));

    for (const repeatable of repeatables) {
      tableName = this.tableNameWithForm(form, repeatable);

      statements.push(this.deleteRowsStatement(db, tableName));
    }

    tableName = this.multipleValueTableNameWithForm(form);

    statements.push(this.deleteRowsStatement(db, tableName));

    return statements;
  }

  static multipleValueTableNameWithForm(form) {
    return format('account_%s_form_%s_values', form._accountRowID, form.rowID);
  }

  static tableNameWithForm(form, repeatable) {
    if (repeatable == null) {
      return format('account_%s_form_%s', form._accountRowID, form.rowID);
    }

    return format('account_%s_form_%s_%s', form._accountRowID, form.rowID, repeatable.key);
  }

  static setupSearch(values, feature) {
    const searchableValue = feature.searchableValue;

    values.record_index_text = searchableValue;
    values.record_index = {raw: `to_tsvector(${ pgformat('%L', searchableValue) })`};

    return values;
  }

  static setupPoint(values, latitude, longitude) {
    const wkt = pgformat('POINT(%s %s)', longitude, latitude);

    return {raw: `ST_Force2D(ST_SetSRID(ST_GeomFromText('${ wkt }'), 4326))`};
  }
}
<|endoftext|>


<commit_before>/**
* Copyright (c) 2015, Peter W Moresi
*/

import React from 'react';
import {Table, Column} from './Table';

import Colors from './CrayolaColors';

/* Write some great components about what data
 * this application presents and how it needs to be
 * organized.
 */
export default class TestPage extends React.Component {

  constructor() {
    super();
    this.state = {
      rows: Colors,
      startRow: 1,
      numberOfRows: 5
    };
  }

  handleStartRowChanged(event) {
    this.setState({ startRow: +event.currentTarget.value });
  }

  render() {
    return (

        Start Row:

        <input type="number" className="form-control" min="1"
              onChange={ this.handleStartRowChanged.bind(this) } value={ this.state.startRow } />

Default

 this.state.rows[rowIndex] }
          headerRenderers={['#', 'Color', 'Hex Value']}
          columnRenderers={[
            (row) => row.id,
            (row) => `${row.name} (${row.hex})`,
            (row) => ]
          }
          />

Fixed Header Off

 this.state.rows[rowIndex] }
            headerRenderers={['#', 'Color', Hex Value]}>
              <Column column="id" />
              <Column cellRenderer={(row) => `${row.name} (${row.hex})`}/>
              <Column cellRenderer={(row) => }/>

Header Off

 this.state.rows[rowIndex] }
            headerRenderers={['#', 'Color', Hex Value]}>
              <Column column="id" />
              <Column cellRenderer={(row) => `${row.name} (${row.hex})`}/>
              <Column cellRenderer={(row) => }/>

    );
  }
}
<commit_msg>Tweak test page<commit_after>/**
* Copyright (c) 2015, Peter W Moresi
*/

import React from 'react';
import {Table, Column} from './Table';

import Colors from './CrayolaColors';

/* Write some great components about what data
 * this application presents and how it needs to be
 * organized.
 */
export default class TestPage extends React.Component {

  constructor() {
    super();
    this.state = {
      rows: Colors,
      startRow: 1,
      numberOfRows: 5
    };
  }

  handleStartRowChanged(event) {
    this.setState({ startRow: +event.currentTarget.value });
  }

  render() {
    return (

        Start Row:

        <input type="number" className="form-control" min="1"
              onChange={ this.handleStartRowChanged.bind(this) } value={ this.state.startRow } />

Default

 this.state.rows[rowIndex] }
          headerRenderers={['#', 'Color', 'Hex Value']}
          columnRenderers={[
            (row) => row.id,
            (row) => `${row.name} (${row.hex})`,
            (row) => ]
          }
          />

Fixed Header Off

 this.state.rows[rowIndex] }
            headerRenderers={['#', 'Color', Hex Value]}>
              <Column column="id" />
              <Column cellRenderer={(row) => `${row.name} (${row.hex})`}/>
              <Column cellRenderer={(row) => }/>

Header Off

 this.state.rows[rowIndex] }
            headerRenderers={['#', 'Color', Hex Value]}>
              <Column column="id" />
              <Column cellRenderer={(row) => `${row.name} (${row.hex})`}/>
              <Column cellRenderer={(row) => }/>

    );
  }
}
<|endoftext|>


<commit_before>/*jshint indent:2, curly:true eqeqeq:true, immed:true, latedef:true,
newcap:true, noarg:true, regexp:true, undef:true, strict:true, trailing:true
white:true*/
/*global XT:true, XM:true, Backbone:true, _:true, console:true */

(function () {
  "use strict";

  /**
    @class
	@name XM.Characteristic
    @extends XM.Document
  */
  XM.Characteristic = XM.Document.extend(/** @lends XM.Characteristic# */{

    recordType: 'XM.Characteristic',

    documentKey: 'name',

    defaults: {
      characteristicType: 0,
      isAddresses: false,
      isContacts: false,
      isItems: false,
      order: 0
    },

    requiredAttributes: [
      "name",
      "characteristicType",
      "isAddresses",
      "isContacts",
      "isItems",
      "order"
    ],

    //..................................................
    // METHODS
    //

    initialize: function () {
      XM.Document.prototype.initialize.apply(this, arguments);
      this.on('change:characteristicType', this.characteristicTypeDidChange);
      this.characteristicTypeDidChange();
    },

    /**
      Check characteristicType to disable unassociated properties.
    */
    characteristicTypeDidChange: function () {
      var type = this.get('characteristicType');
      switch (type) {
      case XM.Characteristic.TEXT:
        this.setReadOnly('options', true);
        this.setReadOnly('mask', false);
        this.setReadOnly('validator', false);
        break;
      case XM.Characteristic.LIST:
        this.setReadOnly('options', false);
        this.setReadOnly('mask', true);
        this.setReadOnly('validator', true);
        break;
      default:
        this.setReadOnly('options', true);
        this.setReadOnly('mask', true);
        this.setReadOnly('validator', true);
      }
    },

    statusDidChange: function () {
      var status = this.getStatus(),
        K = XM.Model;

      if (status !== K.READY_NEW) {
        this.setReadOnly('characteristicType', true);
      }
      XM.Document.prototype.statusDidChange.apply(this, arguments);
    },

    validateSave: function () {
      var models = this.get('options').models,
        values = [],
        i;

      // Validate at least one context selected
      if (!(this.get('isItems') || this.get('isContacts') ||
            this.get('isAddresses') || this.get('isAccounts'))) {
        return XT.Error.clone('xt2002');
      }

      // Validate options for duplicates
      for (i = 0; i < models.length; i += 1) {
        values.push(models[i].get('value'));
      }
      if (!_.isEqual(values, _.unique(values))) {
        return XT.Error.clone('xt2003');
      }
    }

  });

  _.extend(XM.Characteristic, /** @lends XM.Characteristic# */{

    /**
      @static
      @constant
      @type Number
      @default 0
    */
    TEXT: 0,

    /**
      @static
      @constant
      @type Number
      @default 1
    */
    LIST: 1,

    /**
      @static
      @constant
      @type Number
      @default 2
    */
    DATE: 2

  });

  /**
    @class
    @name XM.CharacteristicOption
    @extends XM.Model
  */
  XM.CharacteristicOption = XM.Model.extend(/** @lends XM.CharacteristicOption# */{

    recordType: 'XM.CharacteristicOption',

    defaults: {
      order: 0
    },

    requiredAttributes: [
      "order"
    ]

  });

  /**
    @class Base class for use on characteristic assignment classes.
    @name XM.CharacteristicAssignment
    @extends XM.Model
  */
  XM.CharacteristicAssignment = XM.Model.extend(/** @lends XM.CharacteristicAssignment# */{

    requiredAttributes: [
      "characteristic"
    ],

    //..................................................
    // METHODS
    //

    initialize: function () {
      XM.Model.prototype.initialize.apply(this, arguments);
      this.on('change:characteristic', this.characteristicDidChange);
    },

    characteristicDidChange: function (model, value, options) {
      var status = this.getStatus(),
        K = XM.Model;
      if ((options && options.force) || !(status & K.READY)) { return; }
      this.set('value', '');
    }

  });

  // ..........................................................
  // COLLECTIONS
  //

  /**
    @class
    @name XM.CharacteristicCollection
    @extends XM.Collection
  */
  XM.CharacteristicCollection = XM.Collection.extend(/** @lends XM.CharacteristicCollection# */{

    model: XM.Characteristic

  });

}());
<commit_msg>Issue 18848: Changed characteristics model to require any of the context attributes, not just the first three.<commit_after>/*jshint indent:2, curly:true eqeqeq:true, immed:true, latedef:true,
newcap:true, noarg:true, regexp:true, undef:true, strict:true, trailing:true
white:true*/
/*global XT:true, XM:true, Backbone:true, _:true, console:true */

(function () {
  "use strict";

  /**
    @class
	@name XM.Characteristic
    @extends XM.Document
  */
  XM.Characteristic = XM.Document.extend(/** @lends XM.Characteristic# */{

    recordType: 'XM.Characteristic',

    documentKey: 'name',

    defaults: {
      characteristicType: 0,
      isAddresses: false,
      isContacts: false,
      isItems: false,
      order: 0
    },

    requiredAttributes: [
      "name",
      "characteristicType",
      "isAddresses",
      "isContacts",
      "isItems",
      "order"
    ],

    contextAttributes: [
      "isAddresses",
      "isContacts",
      "isAccounts",
      "isItems",
      "isIncidents",
      "isOpportunities"
    ],

    //..................................................
    // METHODS
    //

    initialize: function () {
      XM.Document.prototype.initialize.apply(this, arguments);
      this.on('change:characteristicType', this.characteristicTypeDidChange);
      this.characteristicTypeDidChange();
    },

    /**
      Check characteristicType to disable unassociated properties.
    */
    characteristicTypeDidChange: function () {
      var type = this.get('characteristicType');
      switch (type) {
      case XM.Characteristic.TEXT:
        this.setReadOnly('options', true);
        this.setReadOnly('mask', false);
        this.setReadOnly('validator', false);
        break;
      case XM.Characteristic.LIST:
        this.setReadOnly('options', false);
        this.setReadOnly('mask', true);
        this.setReadOnly('validator', true);
        break;
      default:
        this.setReadOnly('options', true);
        this.setReadOnly('mask', true);
        this.setReadOnly('validator', true);
      }
    },

    statusDidChange: function () {
      var status = this.getStatus(),
        K = XM.Model;

      if (status !== K.READY_NEW) {
        this.setReadOnly('characteristicType', true);
      }
      XM.Document.prototype.statusDidChange.apply(this, arguments);
    },

    validateSave: function () {
      var models = this.get('options').models,
        values = [],
        i;

      var contextError = false;
      for (i = 0; i < this.contextAttributes.length; i++) {
        var attr = this.contextAttributes[i];
        if (this.get(attr)) {
          contextError = true;
          break;
        }
      }
      if (!contextError) {
        return XT.Error.clone('xt2002');
      }

      // Validate options for duplicates
      for (i = 0; i < models.length; i += 1) {
        values.push(models[i].get('value'));
      }
      if (!_.isEqual(values, _.unique(values))) {
        return XT.Error.clone('xt2003');
      }
    }

  });

  _.extend(XM.Characteristic, /** @lends XM.Characteristic# */{

    /**
      @static
      @constant
      @type Number
      @default 0
    */
    TEXT: 0,

    /**
      @static
      @constant
      @type Number
      @default 1
    */
    LIST: 1,

    /**
      @static
      @constant
      @type Number
      @default 2
    */
    DATE: 2

  });

  /**
    @class
    @name XM.CharacteristicOption
    @extends XM.Model
  */
  XM.CharacteristicOption = XM.Model.extend(/** @lends XM.CharacteristicOption# */{

    recordType: 'XM.CharacteristicOption',

    defaults: {
      order: 0
    },

    requiredAttributes: [
      "order"
    ]

  });

  /**
    @class Base class for use on characteristic assignment classes.
    @name XM.CharacteristicAssignment
    @extends XM.Model
  */
  XM.CharacteristicAssignment = XM.Model.extend(/** @lends XM.CharacteristicAssignment# */{

    requiredAttributes: [
      "characteristic"
    ],

    //..................................................
    // METHODS
    //

    initialize: function () {
      XM.Model.prototype.initialize.apply(this, arguments);
      this.on('change:characteristic', this.characteristicDidChange);
    },

    characteristicDidChange: function (model, value, options) {
      var status = this.getStatus(),
        K = XM.Model;
      if ((options && options.force) || !(status & K.READY)) { return; }
      this.set('value', '');
    }

  });

  // ..........................................................
  // COLLECTIONS
  //

  /**
    @class
    @name XM.CharacteristicCollection
    @extends XM.Collection
  */
  XM.CharacteristicCollection = XM.Collection.extend(/** @lends XM.CharacteristicCollection# */{

    model: XM.Characteristic

  });

}());
<|endoftext|>


<commit_before>'use strict';
app.requires.push('smart-table');

angular.module("umbraco").controller("DiploTraceLogEditController",
    function ($scope, $http, $routeParams, $route, $filter, $q, $templateCache, $timeout, $window, dialogService, notificationsService, stConfig, diploTraceLogResources) {

        var timer;
        var lastModified = 0;
        var persistKey = "diploTraceLogPersist";
        var pollingOnText = "Polling ";
        var pollingOffText = "Polling Off";
        var pollingIndicatorChar = "▪";

        $scope.isLoading = true;
        $scope.pageSize = {};
        $scope.persist = localStorage.getItem(persistKey) === "true" || false;

        $scope.polling = {
            enabled: false,
            interval: 5,
            buttonText: pollingOffText,
            indicator: ""
        };

        $scope.id = $routeParams.id;

        $scope.levelOptions = [
            { label: "Info", value: "INFO" },
            { label: "Warn", value: "WARN" },
            { label: "Error", value: "ERROR" }
        ];

        $scope.pollOptions = [
            { label: "Disabled", value: 0 },
            { label: "1 Second", value: 1 },
            { label: "5 Seconds", value: 5 },
            { label: "10 Seconds", value: 10 },
            { label: "60 Seconds", value: 60 },
        ];

        $scope.itemsPerPage = [20, 50, 100, 200, 500, 1000];

        $scope.isCurrentLog = $routeParams.id.endsWith('.txt');

        // Gets the log data and populates the row collection
        var getLogData = function () {
            diploTraceLogResources.getLogDataResponse($routeParams.id).then(function (data) {
                $scope.rowCollection = data.LogDataItems;
                lastModified = data.LastModifiedTicks;
                $scope.isLoading = false;
            });
        }

        // Open detail modal
        $scope.openDetail = function (logItem, data) {

            var dialog = dialogService.open({
                template: '/App_Plugins/DiploTraceLogViewer/backoffice/diplotracelog/detail.html',
                dialogData: { logItem: logItem, items: data }, show: true, width: 800
            });
        }

        // Used for continous polling
        var tick = function () {

            $scope.polling.indicator += pollingIndicatorChar;

            if ($scope.polling.indicator.length > 9) {
                $scope.polling.indicator = "";
            }

            if ($scope.polling.interval > 0) {

                diploTraceLogResources.getLastModifiedTime($routeParams.id).then(function (data) {
                    var modified = parseInt(data);

                    if (modified > lastModified) {
                        lastModified = modified;
                        notificationsService.success("Log Updated", "New entries where added to the log file.");
                        getLogData();
                    }

                    timer = $timeout(tick, parseInt($scope.polling.interval) * 1000);
                });
            }
        }

        // Calls the get log data service
        getLogData();

        // Cancels the timer when polling is enabled
        var cancelTimer = function () {
            if (timer) {
                $timeout.cancel(timer);
                timer = null;
                notificationsService.warning("Polling Stopped", "Log file polling has been stopped.");
            }
        }

        // Starts the timer when polling is enabled based on polling interval
        var startTimer = function () {

            if ($scope.isCurrentLog) {
                cancelTimer();
                $scope.polling.enabled = true;

                timer = $timeout(tick, parseInt($scope.polling.interval) * 1000);
                console.log("Polling started...");
                $scope.polling.indicator = pollingIndicatorChar;
            }
        }

        // Checks whether polling is enabled and starts or stops the timer
        $scope.checkTimer = function () {

            if ($scope.polling.enabled) {
                notificationsService.info("Polling Enabled", "Your log file will now be checked every " + $scope.polling.interval + " seconds for changes.");
                startTimer();
            }
            else {
                cancelTimer();
                $scope.polling.indicator = "";
            }

            $scope.polling.buttonText = $scope.polling.enabled ? pollingOnText + " " + $scope.polling.interval + "s" : pollingOffText;
        }

        // Sets the polling interval
        $scope.setPollInterval = function (seconds) {
            $scope.polling.interval = seconds;
            $scope.polling.enabled = true;
            $scope.checkTimer();
        }

        // Toggles whether polling is enabled or not
        $scope.togglePolling = function () {
            $scope.polling.enabled = !$scope.polling.enabled;
            $scope.checkTimer();
        }

        // Reloads the log file
        $scope.reload = function (clear) {
            $route.reload();
            if (clear === true) {
                localStorage.removeItem("diploTraceLogTable");
                $scope.changePersist(false);
            }
        }

        // Cancels timer when focus is lost
        $window.onblur = function () {
            cancelTimer();
        };

        // Checks whether to enable timer when window focused
        $window.onfocus = function () {
            $scope.checkTimer();
        };

        // Stores the perist status
        $scope.changePersist = function (persist) {
            localStorage.setItem(persistKey, persist);
        }

        // Destroys the timer when the app is killed
        $scope.$on("$destroy", function (event) {
            cancelTimer();
        });

    });

// Directive to persist smart table state to local storage
app.directive('stPersist', function () {
    return {
        require: '^stTable',
        link: function (scope, element, attr, ctrl) {
            var nameSpace = attr.stPersist;

            //save the table state every time it changes
            scope.$watch(function () {
                return ctrl.tableState();
            }, function (newValue, oldValue) {
                if (newValue !== oldValue) {
                    localStorage.setItem(nameSpace, JSON.stringify(newValue));
                }
            }, true);

            //fetch the table state when the directive is loaded
            if (scope.persist && localStorage.getItem(nameSpace)) {
                var savedState = JSON.parse(localStorage.getItem(nameSpace));
                var tableState = ctrl.tableState();

                scope.pageSize = savedState.pagination.number;

                angular.extend(tableState, savedState);
                ctrl.pipe();
            }
            else if (!scope.persist) {
                ctrl.tableState().sort = { "predicate": "Date", "reverse": true };
                scope.pageSize = 100;
            }
        }
    };
});

// Directive to reset all smart table filters
app.directive("stResetSearch", function () {
    return {
        restrict: 'EA',
        require: '^stTable',
        link: function (scope, element, attrs, ctrl) {
            return element.bind('click', function () {
                return scope.$apply(function () {
                    var tableState;
                    tableState = ctrl.tableState();
                    tableState.search.predicateObject = {};
                    tableState.pagination.start = 0;
                    return ctrl.pipe();
                });
            });
        }
    };
})

// Directive to make the adjacent input clearable with a [x]
app.directive('diploClearable', function () {
    return {
        restrict: 'E',
        require: '^stTable',
        template: '',
        link: function (scope, element, attrs, ctrl) {
            return element.bind('click', function () {
                return scope.$apply(function () {

                    var name = element.next().attr('st-search');
                    var params = ctrl.tableState().search.predicateObject;

                    if (params && params[name] !== undefined) {
                        params[name] = '';
                    }

                    return ctrl.pipe();
                });

            });
        }
    }
});

// Directive to highlight last word in a class name
app.filter('diploLastWordHighlight', function () {
    return function (input) {
        var items = input.split(".");
        var last = items.pop();
        return "" + items.join(".") + "." + last;
    }
});<commit_msg>Added syncTree so that the currently selected log file is highlighted in the tree<commit_after>'use strict';
app.requires.push('smart-table');

angular.module("umbraco").controller("DiploTraceLogEditController",
    function ($scope, $http, $routeParams, $route, $filter, $q, $templateCache, $timeout, $window, dialogService, notificationsService, navigationService, stConfig, diploTraceLogResources) {

        var timer;
        var lastModified = 0;
        var persistKey = "diploTraceLogPersist";
        var pollingOnText = "Polling ";
        var pollingOffText = "Polling Off";
        var pollingIndicatorChar = "▪";

        $scope.isLoading = true;
        $scope.pageSize = {};
        $scope.persist = localStorage.getItem(persistKey) === "true" || false;

        $scope.polling = {
            enabled: false,
            interval: 5,
            buttonText: pollingOffText,
            indicator: ""
        };

        $scope.id = $routeParams.id;

        $scope.levelOptions = [
            { label: "Info", value: "INFO" },
            { label: "Warn", value: "WARN" },
            { label: "Error", value: "ERROR" }
        ];

        $scope.pollOptions = [
            { label: "Disabled", value: 0 },
            { label: "1 Second", value: 1 },
            { label: "5 Seconds", value: 5 },
            { label: "10 Seconds", value: 10 },
            { label: "60 Seconds", value: 60 },
        ];

        $scope.itemsPerPage = [20, 50, 100, 200, 500, 1000];

        $scope.isCurrentLog = $routeParams.id.endsWith('.txt');

        navigationService.syncTree({ tree: 'diploTraceLog', path: ["-1", $routeParams.id], forceReload: false });

        // Gets the log data and populates the row collection
        var getLogData = function () {
            diploTraceLogResources.getLogDataResponse($routeParams.id).then(function (data) {
                $scope.rowCollection = data.LogDataItems;
                lastModified = data.LastModifiedTicks;
                $scope.isLoading = false;
            });
        }

        // Open detail modal
        $scope.openDetail = function (logItem, data) {

            var dialog = dialogService.open({
                template: '/App_Plugins/DiploTraceLogViewer/backoffice/diplotracelog/detail.html',
                dialogData: { logItem: logItem, items: data }, show: true, width: 800
            });
        }

        // Used for continous polling
        var tick = function () {

            $scope.polling.indicator += pollingIndicatorChar;

            if ($scope.polling.indicator.length > 9) {
                $scope.polling.indicator = "";
            }

            if ($scope.polling.interval > 0) {

                diploTraceLogResources.getLastModifiedTime($routeParams.id).then(function (data) {
                    var modified = parseInt(data);

                    if (modified > lastModified) {
                        lastModified = modified;
                        notificationsService.success("Log Updated", "New entries where added to the log file.");
                        getLogData();
                    }

                    timer = $timeout(tick, parseInt($scope.polling.interval) * 1000);
                });
            }
        }

        // Calls the get log data service
        getLogData();

        // Cancels the timer when polling is enabled
        var cancelTimer = function () {
            if (timer) {
                $timeout.cancel(timer);
                timer = null;
                notificationsService.warning("Polling Stopped", "Log file polling has been stopped.");
            }
        }

        // Starts the timer when polling is enabled based on polling interval
        var startTimer = function () {

            if ($scope.isCurrentLog) {
                cancelTimer();
                $scope.polling.enabled = true;

                timer = $timeout(tick, parseInt($scope.polling.interval) * 1000);
                console.log("Polling started...");
                $scope.polling.indicator = pollingIndicatorChar;
            }
        }

        // Checks whether polling is enabled and starts or stops the timer
        $scope.checkTimer = function () {

            if ($scope.polling.enabled) {
                notificationsService.info("Polling Enabled", "Your log file will now be checked every " + $scope.polling.interval + " seconds for changes.");
                startTimer();
            }
            else {
                cancelTimer();
                $scope.polling.indicator = "";
            }

            $scope.polling.buttonText = $scope.polling.enabled ? pollingOnText + " " + $scope.polling.interval + "s" : pollingOffText;
        }

        // Sets the polling interval
        $scope.setPollInterval = function (seconds) {
            $scope.polling.interval = seconds;
            $scope.polling.enabled = true;
            $scope.checkTimer();
        }

        // Toggles whether polling is enabled or not
        $scope.togglePolling = function () {
            $scope.polling.enabled = !$scope.polling.enabled;
            $scope.checkTimer();
        }

        // Reloads the log file
        $scope.reload = function (clear) {
            $route.reload();
            if (clear === true) {
                localStorage.removeItem("diploTraceLogTable");
                $scope.changePersist(false);
            }
        }

        // Cancels timer when focus is lost
        $window.onblur = function () {
            cancelTimer();
        };

        // Checks whether to enable timer when window focused
        $window.onfocus = function () {
            $scope.checkTimer();
        };

        // Stores the perist status
        $scope.changePersist = function (persist) {
            localStorage.setItem(persistKey, persist);
        }

        // Destroys the timer when the app is killed
        $scope.$on("$destroy", function (event) {
            cancelTimer();
        });

    });

// Directive to persist smart table state to local storage
app.directive('stPersist', function () {
    return {
        require: '^stTable',
        link: function (scope, element, attr, ctrl) {
            var nameSpace = attr.stPersist;

            //save the table state every time it changes
            scope.$watch(function () {
                return ctrl.tableState();
            }, function (newValue, oldValue) {
                if (newValue !== oldValue) {
                    localStorage.setItem(nameSpace, JSON.stringify(newValue));
                }
            }, true);

            //fetch the table state when the directive is loaded
            if (scope.persist && localStorage.getItem(nameSpace)) {
                var savedState = JSON.parse(localStorage.getItem(nameSpace));
                var tableState = ctrl.tableState();

                scope.pageSize = savedState.pagination.number;

                angular.extend(tableState, savedState);
                ctrl.pipe();
            }
            else if (!scope.persist) {
                ctrl.tableState().sort = { "predicate": "Date", "reverse": true };
                scope.pageSize = 100;
            }
        }
    };
});

// Directive to reset all smart table filters
app.directive("stResetSearch", function () {
    return {
        restrict: 'EA',
        require: '^stTable',
        link: function (scope, element, attrs, ctrl) {
            return element.bind('click', function () {
                return scope.$apply(function () {
                    var tableState;
                    tableState = ctrl.tableState();
                    tableState.search.predicateObject = {};
                    tableState.pagination.start = 0;
                    return ctrl.pipe();
                });
            });
        }
    };
})

// Directive to make the adjacent input clearable with a [x]
app.directive('diploClearable', function () {
    return {
        restrict: 'E',
        require: '^stTable',
        template: '',
        link: function (scope, element, attrs, ctrl) {
            return element.bind('click', function () {
                return scope.$apply(function () {

                    var name = element.next().attr('st-search');
                    var params = ctrl.tableState().search.predicateObject;

                    if (params && params[name] !== undefined) {
                        params[name] = '';
                    }

                    return ctrl.pipe();
                });

            });
        }
    }
});

// Directive to highlight last word in a class name
app.filter('diploLastWordHighlight', function () {
    return function (input) {
        var items = input.split(".");
        var last = items.pop();
        return "" + items.join(".") + "." + last;
    }
});<|endoftext|>


<commit_before>//
// release_initializer.js - read user's program and eval it (if it exists)
//
// This file is put on the end the lib/biwascheme.js.
//
(function(){ //local namespace
  var dumper = null;
  if ($("#biwascheme-debugger")[0]) {
    dumper = new BiwaScheme.Dumper($("#biwascheme-debugger")[0]);
  }

  // Error handler (show message to console div)
  var onError = function(e, state){
    BiwaScheme.Port.current_error.puts(e.message);
    if (dumper) {
      dumper.dump(state);
      dumper.dump_move(1);
    } else if (typeof(console) !== "undefined" && console.error) {
      console.error(e.message);
    } else {
      throw(e);
    }
  };

  // Start user's program
  var script = $("script[src$='biwascheme.js']").html() ||
               $("script[src$='biwascheme-min.js']").html();
  if (script) {
    var intp = new BiwaScheme.Interpreter(onError);
    try{
      intp.evaluate(script, function(){});
    }
    catch(e){
      onError(e);
    }
  }
})();
<commit_msg>fix "BiwaScheme.Port.current_error.puts is not a function"<commit_after>//
// release_initializer.js - read user's program and eval it (if it exists)
//
// This file is put on the end the lib/biwascheme.js.
//
(function(){ //local namespace
  var dumper = null;
  if ($("#biwascheme-debugger")[0]) {
    dumper = new BiwaScheme.Dumper($("#biwascheme-debugger")[0]);
  }

  // Error handler (show message to console div)
  var onError = function(e, state){
    BiwaScheme.Port.current_error.put_string(e.message + "\n");
    if (dumper) {
      dumper.dump(state);
      dumper.dump_move(1);
    } else if (typeof(console) !== "undefined" && console.error) {
      console.error(e.message);
    } else {
      throw(e);
    }
  };

  // Start user's program
  var script = $("script[src$='biwascheme.js']").html() ||
               $("script[src$='biwascheme-min.js']").html();
  if (script) {
    var intp = new BiwaScheme.Interpreter(onError);
    try{
      intp.evaluate(script, function(){});
    }
    catch(e){
      onError(e);
    }
  }
})();
<|endoftext|>


<commit_before>/* Copyright Théo Zimmermann 2014
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

define(["app/dom", "app/i18n", "app/utils", "diff_match_patch"], function($, i18n, utils) {

    "use strict";

    // mode can take values "reading", "reading_modification" and "commenting"
    var mode = "reading";
    // if mode is "reading_modification", currently_showing stores id of comment
    var currently_showing;

    // there must be only one <article> on the page
    var article = $("article");
    // but there can be many blocks in an article
    var blocks = $(".block", article, false);
    // in the case there is no block, current_block will always represent the full article
    var current_block = article;

    var original_content, new_content;

    // button to show the original version
    var original_button = $.htmlify('<button type="button">' + i18n.translate("show-original") + '</button>');

    // make a diff_match_patch object once and for all
    var dmp = new diff_match_patch();

    // remember some of the DOM elements
    var cancel_button, comment_field;

    // FUNCTION WHICH ENABLE COMMENTING AND EDITING

    var init = function(comment_postbox) {
        comment_field = $(".textarea", comment_postbox);
        // let's curry!
        return function() {
            show_original();
            if (mode === "reading" && comment_field.innerHTML !== "") {
                mode = "commenting";
                original_content = utils.clean_html(current_block.innerHTML);
                new_content = null;
                current_block.setAttribute("contenteditable", true);
                // first time : create cancel button and associate event
                if (!cancel_button) {
                    cancel_button = $(".post-action", comment_postbox).prepend(
                      '<input type="reset" value="' + i18n.translate("postbox-cancel") + '"></input>');
                    cancel_button.on("click", function(e) {
                        if (new_content === null ||
                            confirm(i18n.translate("postbox-confirm-cancel"))) {
                            comment_field.innerHTML = "";
                            cancel();
                        }
                    });
                }
                else {
                  cancel_button.style.display = "inline";
                }
            }
            else if (mode === "commenting" && comment_field.innerHTML === ""
                                           && new_content === null) {
                cancel();
            }
        };
    };

    var maybe_article_just_changed = function() {
        var current = utils.clean_html(current_block.innerHTML);
        if (current !== original_content) {
            new_content = current;
        }
        else {
            new_content = null;
            if (comment_field.innerHTML === i18n.translate("postbox-text") ||
                comment_field.innerHTML === "") {
                cancel();
            }
        }
    };

    var cancel = function() {
        if (mode === "commenting") {
            current_block.setAttribute("contenteditable", false);
            if (new_content !== null) {
                current_block.innerHTML = original_content;
                new_content = null;
            }
            cancel_button.hide();
            mode = "reading";
        }
    };

    // FUNCTIONS TO SHOW COMMENTS / EDITS

    var show_block_comments = function() {
        // when showing an edit or commenting, the current block is locked
        // this function is useless if there are no blocks
        if (mode == "reading" && blocks !== null) {
            // current block = block in the middle
            var center = window.pageYOffset + window.innerHeight/2;
            var i = 0;
            while (i < blocks.length && blocks[i].offsetTop <= center) { i++; }
            current_block = blocks[i - 1];
            for (var i = 0; i < blocks.length; i++) {
                blocks[i].style.background = "transparent";
            }
            current_block.style.background = "rgba(211,211,211,0.5)";
        }
    };

    var show_edit = function(el, comment) {
        // let's curry!
        return function() {
            if (mode === "reading" || mode === "reading_modification") {
                if (currently_showing === comment.id) {
                    show_original();
                }
                else {
                    // print diffs
                    var array = JSON.parse(utils.tags_from_text(comment.edit));
                    var html = dmp.diff_prettyHtml(array);
                    current_block.innerHTML = html;

                    // add button to go back to standard reading mode
                    original_button.style.visibility = "visible";

                    // display selected comment in green and all others are set back to default
                    var comments = $(".isso-comment", null, false);
                    for (var i = 0; i < comments.length; i++) {
                        comments[i].style.background = "transparent";
                    }
                    el.style.background = "#e6ffe6";

                    // scroll to first change
                    $("#edit").scrollIntoView();

                    mode = "reading_modification";
                    currently_showing = comment.id;
                }
            }
        };
    };

    var show_original = function() {
        if (mode === "reading_modification") {
            // restore original display
            current_block.innerHTML = original_content;
            original_button.style.visibility = "hidden";
            var comments = $(".isso-comment", null, false);
            for (var i = 0; i < comments.length; i++) {
                comments[i].style.background = "transparent";
            }
            mode = "reading";
            currently_showing = null;
            // now show the current block like if we had just scrolled
            show_block_comments();
        }
    };

    // DEFINE EVENTS

    original_button.on("click", show_original);

    article.on("keyup", maybe_article_just_changed);
    document.addEventListener("keydown", function(e) {
        if (e.keyCode === 27) {
            show_original();
        }
    });

    window.addEventListener("scroll", show_block_comments);

    // ADD HTML ELEMENTS
    original_button.style.visibility = "hidden";
    $("#isso-thread").prepend(original_button);

    // FIRST CALLS
    show_block_comments();

    // PUBLIC METHODS

    return {
        init: init,
        new_article: function() {
            if (new_content === null) {
                return null;
            }
            // otherwise we apply some pre-treatment before returning
            var new_text = utils.tags_from_text(new_content);
            var diffs = dmp.diff_main(original_content, new_text);
            dmp.diff_cleanupSemantic(diffs);
            return JSON.stringify(diffs);
        },
        cancel: cancel,
        show: show_edit
    };
});

<commit_msg>remove focus from text when not editable anymore<commit_after>/* Copyright Théo Zimmermann 2014
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

define(["app/dom", "app/i18n", "app/utils", "diff_match_patch"], function($, i18n, utils) {

    "use strict";

    // mode can take values "reading", "reading_modification" and "commenting"
    var mode = "reading";
    // if mode is "reading_modification", currently_showing stores id of comment
    var currently_showing;

    // there must be only one <article> on the page
    var article = $("article");
    // but there can be many blocks in an article
    var blocks = $(".block", article, false);
    // in the case there is no block, current_block will always represent the full article
    var current_block = article;

    var original_content, new_content;

    // button to show the original version
    var original_button = $.htmlify('<button type="button">' + i18n.translate("show-original") + '</button>');

    // make a diff_match_patch object once and for all
    var dmp = new diff_match_patch();

    // remember some of the DOM elements
    var cancel_button, comment_field;

    // FUNCTION WHICH ENABLE COMMENTING AND EDITING

    var init = function(comment_postbox) {
        comment_field = $(".textarea", comment_postbox);
        // let's curry!
        return function() {
            show_original();
            if (mode === "reading" && comment_field.innerHTML !== "") {
                mode = "commenting";
                original_content = utils.clean_html(current_block.innerHTML);
                new_content = null;
                current_block.setAttribute("contenteditable", true);
                // first time : create cancel button and associate event
                if (!cancel_button) {
                    cancel_button = $(".post-action", comment_postbox).prepend(
                      '<input type="reset" value="' + i18n.translate("postbox-cancel") + '"></input>');
                    cancel_button.on("click", function(e) {
                        if (new_content === null ||
                            confirm(i18n.translate("postbox-confirm-cancel"))) {
                            comment_field.innerHTML = "";
                            cancel();
                        }
                    });
                }
                else {
                  cancel_button.style.display = "inline";
                }
            }
            else if (mode === "commenting" && comment_field.innerHTML === ""
                                           && new_content === null) {
                cancel();
            }
        };
    };

    var maybe_article_just_changed = function() {
        var current = utils.clean_html(current_block.innerHTML);
        if (current !== original_content) {
            new_content = current;
        }
        else {
            new_content = null;
            if (comment_field.innerHTML === i18n.translate("postbox-text") ||
                comment_field.innerHTML === "") {
                current_block.blur();
                cancel();
            }
        }
    };

    var cancel = function() {
        if (mode === "commenting") {
            current_block.setAttribute("contenteditable", false);
            if (new_content !== null) {
                current_block.innerHTML = original_content;
                new_content = null;
            }
            cancel_button.hide();
            mode = "reading";
        }
    };

    // FUNCTIONS TO SHOW COMMENTS / EDITS

    var show_block_comments = function() {
        // when showing an edit or commenting, the current block is locked
        // this function is useless if there are no blocks
        if (mode == "reading" && blocks !== null) {
            // current block = block in the middle
            var center = window.pageYOffset + window.innerHeight/2;
            var i = 0;
            while (i < blocks.length && blocks[i].offsetTop <= center) { i++; }
            current_block = blocks[i - 1];
            for (var i = 0; i < blocks.length; i++) {
                blocks[i].style.background = "transparent";
            }
            current_block.style.background = "rgba(211,211,211,0.5)";
        }
    };

    var show_edit = function(el, comment) {
        // let's curry!
        return function() {
            if (mode === "reading" || mode === "reading_modification") {
                if (currently_showing === comment.id) {
                    show_original();
                }
                else {
                    // print diffs
                    var array = JSON.parse(utils.tags_from_text(comment.edit));
                    var html = dmp.diff_prettyHtml(array);
                    current_block.innerHTML = html;

                    // add button to go back to standard reading mode
                    original_button.style.visibility = "visible";

                    // display selected comment in green and all others are set back to default
                    var comments = $(".isso-comment", null, false);
                    for (var i = 0; i < comments.length; i++) {
                        comments[i].style.background = "transparent";
                    }
                    el.style.background = "#e6ffe6";

                    // scroll to first change
                    $("#edit").scrollIntoView();

                    mode = "reading_modification";
                    currently_showing = comment.id;
                }
            }
        };
    };

    var show_original = function() {
        if (mode === "reading_modification") {
            // restore original display
            current_block.innerHTML = original_content;
            original_button.style.visibility = "hidden";
            var comments = $(".isso-comment", null, false);
            for (var i = 0; i < comments.length; i++) {
                comments[i].style.background = "transparent";
            }
            mode = "reading";
            currently_showing = null;
            // now show the current block like if we had just scrolled
            show_block_comments();
        }
    };

    // DEFINE EVENTS

    original_button.on("click", show_original);

    article.on("keyup", maybe_article_just_changed);
    document.addEventListener("keydown", function(e) {
        if (e.keyCode === 27) {
            show_original();
        }
    });

    window.addEventListener("scroll", show_block_comments);

    // ADD HTML ELEMENTS
    original_button.style.visibility = "hidden";
    $("#isso-thread").prepend(original_button);

    // FIRST CALLS
    show_block_comments();

    // PUBLIC METHODS

    return {
        init: init,
        new_article: function() {
            if (new_content === null) {
                return null;
            }
            // otherwise we apply some pre-treatment before returning
            var new_text = utils.tags_from_text(new_content);
            var diffs = dmp.diff_main(original_content, new_text);
            dmp.diff_cleanupSemantic(diffs);
            return JSON.stringify(diffs);
        },
        cancel: cancel,
        show: show_edit
    };
});

<|endoftext|>


<commit_before>var _ = require('lodash');

module.exports = function(email, page) {
    var folders = new Object;

    /*
    HUGE MEMORY ALLOCATION PER REQUEST
    SELECTION SHOULD BE LIMITED TO A FOLDER
    & A SINGLE OBJECT IN FUTURE RELEASES.
    */

    folders.OUTBOX = {
        collection: 'queue',
        find: new Object,
        where: {
            association: { contains: email },
            state: { '!=': 'draft' } /* MIGHT CAUSE POSTGRES ISSUES -> http://stackoverflow.com/a/22600564/804759 */
        },
        sort: {
            createdAt: 'desc'
        },
        paginate: {
            page: page,
            limit: 10
        },
        filter: function(mails) {
            // Sort (Time asc) & Filter - Note: Sorting could be moved to Waterline native sorting
            return _.chain(mails)
                .map(function(t) {
                    // Filter
                    t = _.pick(t, ['eID', 'sender', 'to', 'schedule', 'subject', 'text', 'html', 'attachments']);
                    // Remove path from Attachments
                    t.attachments = _.map(t.attachments, function(attachment) {
                        return _.pick(attachment, ['fileName', 'checksum', 'id', 'length']);
                    });
                    // Prepend Indicator to the eID
                    t.eID = 'O' + t.eID;
                    // Set all Outbox emails to read/!spam/!trash
                    t.read = true;
                    t.spam = false;
                    t.trash = false;
                    // Stamp doesn't exist in QUEUE so we create it here
                    t.stamp = {
                        sent: (new Date(t.schedule.scheduled)),
                        received: (new Date(t.schedule.attempted))
                    }
                    // Pass to sort
                    return t;
                })
                .sortBy(function(t) {
                    return (t.stamp.sent.getTime())
                })
                .value();
        }
    }

    folders.DRAFT = _.extend(_.clone(folders.OUTBOX, true), {
        where: {
            association: { contains: email },
            state: 'draft'
        },
    });

    folders.INBOX = {
        collection: 'mail',
        find: new Object,
        where: {
            association: { contains: email },
            trash: false,
            spam: false,
            sent: false,
            spamScore: {
                '<=': 5
            } /* Spam filter */
        },
        sort: {
            createdAt: 'desc'
        },
        paginate: {
            page: page,
            limit: 10
        },
        filter: function(mails) {
            // Sort (Time asc) & Filter - Note: Sorting could be moved to Waterline native sorting
            return _.chain(mails)
                .map(function(t) {
                    // Filter
                    t = _.pick(t, ['eID', 'sender', 'receiver', 'to', 'stamp', 'subject', 'text', 'html', 'read', 'spam', 'trash', 'attachments']);
                    // Remove path from Attachments
                    t.attachments = _.map(t.attachments, function(attachment) {
                        return _.pick(attachment, ['fileName', 'checksum', 'id', 'length']);
                    });
                    // Prepend Indicator to the eID
                    t.eID = 'I' + t.eID;
                    // Covert stamps to JS Dates
                    t.stamp.sent = (new Date(t.stamp.sent));
                    t.stamp.received = (new Date(t.stamp.received));
                    // Pass to sort
                    return t;
                })
                .sortBy(function(t) {
                    return (t.stamp.sent.getTime())
                })
                .value();
        }
    }

    folders.SENT = _.extend(_.clone(folders.INBOX, true), {
        where: {
            association: { contains: email },
            sent: true,
			spam: false,
			trash: false,
        },
    });

    folders.SPAM = _.extend(_.clone(folders.INBOX, true), {
        where: {
            association: { contains: email },
            trash: false,
            or: [{
                spam: true
            }, {
                spamScore: {
                    '>': 5
                }
            }]
        },
    });

    folders.TRASH = _.extend(_.clone(folders.INBOX, true), {
        where: {
            association: { contains: email },
            trash: true
        },
    });

    return folders;
}
<commit_msg>[fix] Query Builder now handles undefined page var<commit_after>var _ = require('lodash');

module.exports = function(email, page) {
    var folders = new Object;

    /*
    HUGE MEMORY ALLOCATION PER REQUEST
    SELECTION SHOULD BE LIMITED TO A FOLDER
    & A SINGLE OBJECT IN FUTURE RELEASES.
    */

    folders.OUTBOX = {
        collection: 'queue',
        find: new Object,
        where: {
            association: { contains: email },
            state: { '!=': 'draft' } /* MIGHT CAUSE POSTGRES ISSUES -> http://stackoverflow.com/a/22600564/804759 */
        },
        sort: {
            createdAt: 'desc'
        },
        paginate: {
            page: page || 1,
            limit: 10
        },
        filter: function(mails) {
            // Sort (Time asc) & Filter - Note: Sorting could be moved to Waterline native sorting
            return _.chain(mails)
                .map(function(t) {
                    // Filter
                    t = _.pick(t, ['eID', 'sender', 'to', 'schedule', 'subject', 'text', 'html', 'attachments']);
                    // Remove path from Attachments
                    t.attachments = _.map(t.attachments, function(attachment) {
                        return _.pick(attachment, ['fileName', 'checksum', 'id', 'length']);
                    });
                    // Prepend Indicator to the eID
                    t.eID = 'O' + t.eID;
                    // Set all Outbox emails to read/!spam/!trash
                    t.read = true;
                    t.spam = false;
                    t.trash = false;
                    // Stamp doesn't exist in QUEUE so we create it here
                    t.stamp = {
                        sent: (new Date(t.schedule.scheduled)),
                        received: (new Date(t.schedule.attempted))
                    }
                    // Pass to sort
                    return t;
                })
                .sortBy(function(t) {
                    return (t.stamp.sent.getTime())
                })
                .value();
        }
    }

    folders.DRAFT = _.extend(_.clone(folders.OUTBOX, true), {
        where: {
            association: { contains: email },
            state: 'draft'
        },
    });

    folders.INBOX = {
        collection: 'mail',
        find: new Object,
        where: {
            association: { contains: email },
            trash: false,
            spam: false,
            sent: false,
            spamScore: {
                '<=': 5
            } /* Spam filter */
        },
        sort: {
            createdAt: 'desc'
        },
        paginate: {
            page: page,
            limit: 10
        },
        filter: function(mails) {
            // Sort (Time asc) & Filter - Note: Sorting could be moved to Waterline native sorting
            return _.chain(mails)
                .map(function(t) {
                    // Filter
                    t = _.pick(t, ['eID', 'sender', 'receiver', 'to', 'stamp', 'subject', 'text', 'html', 'read', 'spam', 'trash', 'attachments']);
                    // Remove path from Attachments
                    t.attachments = _.map(t.attachments, function(attachment) {
                        return _.pick(attachment, ['fileName', 'checksum', 'id', 'length']);
                    });
                    // Prepend Indicator to the eID
                    t.eID = 'I' + t.eID;
                    // Covert stamps to JS Dates
                    t.stamp.sent = (new Date(t.stamp.sent));
                    t.stamp.received = (new Date(t.stamp.received));
                    // Pass to sort
                    return t;
                })
                .sortBy(function(t) {
                    return (t.stamp.sent.getTime())
                })
                .value();
        }
    }

    folders.SENT = _.extend(_.clone(folders.INBOX, true), {
        where: {
            association: { contains: email },
            sent: true,
			spam: false,
			trash: false,
        },
    });

    folders.SPAM = _.extend(_.clone(folders.INBOX, true), {
        where: {
            association: { contains: email },
            trash: false,
            or: [{
                spam: true
            }, {
                spamScore: {
                    '>': 5
                }
            }]
        },
    });

    folders.TRASH = _.extend(_.clone(folders.INBOX, true), {
        where: {
            association: { contains: email },
            trash: true
        },
    });

    return folders;
}
<|endoftext|>


<commit_before>const xmlbuilder = require('xmlbuilder');
const metadata = require('./utils/metadata');

module.exports = function(config){
  this.constructPackage = function(structuredDiffs) {
    return new Promise(function(resolve,reject){
      let filesContent = {};
      const sorted_packageType = Object.keys(structuredDiffs).sort();
      sorted_packageType.forEach(function(packageType){
        if(Object.keys(structuredDiffs[packageType]).length  > 0 ) {
          const strucDiffPerType = structuredDiffs[packageType];
          let xml = xmlbuilder.create('Package')
                      .att('xmlns', 'http://soap.sforce.com/2006/04/metadata')
                      .dec('1.0', 'UTF-8');
          for(let structuredDiff in strucDiffPerType) {
            if(metadata[structuredDiff] !== undefined) {
              // Handle different type of package.xml build
              let type = xml.ele('types');
              for(var elem in strucDiffPerType[structuredDiff]) if(elem) {
                  type.ele('members')
                  .t(strucDiffPerType[structuredDiff][elem]);
              }
              type.ele('name').t(metadata[structuredDiff].xmlName);
            }
          }
          xml.ele('version')
          .t(config.apiVersion);
          filesContent[packageType] = xml.end({ pretty: true, indent: '  ', newline: '\n' });
        }
      });
      resolve(filesContent);
    });
  };
};<commit_msg>fix destructive packages handling<commit_after>const xmlbuilder = require('xmlbuilder');
const metadata = require('./utils/metadata');

module.exports = function(config) {
  this.constructPackage = structuredDiffs => {
    return new Promise((resolve,reject) => {
      let filesContent = {};
      const sorted_packageType = Object.keys(structuredDiffs).sort();
      sorted_packageType.forEach(packageType => {
        const strucDiffPerType = structuredDiffs[packageType];
        let xml = xmlbuilder.create('Package')
                    .att('xmlns', 'http://soap.sforce.com/2006/04/metadata')
                    .dec('1.0', 'UTF-8');
        for(let structuredDiff in strucDiffPerType) {
          if(metadata[structuredDiff] !== undefined) {
            // Handle different type of package.xml build
            let type = xml.ele('types');
            for(var elem in strucDiffPerType[structuredDiff]) if(elem) {
                type.ele('members')
                .t(strucDiffPerType[structuredDiff][elem]);
            }
            type.ele('name').t(metadata[structuredDiff].xmlName);
          }
        }
        xml.ele('version')
        .t(config.apiVersion);
        filesContent[packageType] = xml.end({ pretty: true, indent: '  ', newline: '\n' });
      });
      resolve(filesContent);
    });
  };
};<|endoftext|>