<commit_before>import { vec3, mat4, quat } from 'gl-matrix';
import { gltfCamera } from './camera.js';
import { clamp } from './utils.js';
import { getSceneExtents } from './gltf_utils.js';

const PanSpeedDenominator = 1200;
const MaxNearFarRatio = 10000;

class UserCamera extends gltfCamera
{
    /**
     * Create a new user camera
     */
    constructor()
    {
        super();

        this.transform = mat4.create();
        this.rotAroundY = 0;
        this.rotAroundX = 0;
        this.distance = 1;
        this.zoomFactor = 1.04;
        this.orbitSpeed = 1 / 180;
        this.panSpeed = 1;
        this.sceneExtents = {
            min: vec3.create(),
            max: vec3.create()
        };
    }

    /**
     * Sets the vertical FoV of the user camera
     * @param {number} yfov
     */
    setVerticalFoV(yfov)
    {
        this.yfov = yfov;
    }

    /**
     * Returns the current position of the user camera as a vec3
     */
    getPosition()
    {
        let pos = vec3.create();
        mat4.getTranslation(pos, this.transform);
        return pos;
    }

    /**
     * Returns the current rotation of the user camera as quat
     */
    getRotation()
    {
        let rot = quat.create();
        mat4.getRotation(rot, this.transform);
        return rot;
    }

    /**
     * Returns the normalized direction the user camera looks at as vec3
     */
    getLookDirection()
    {
        let dir = [-this.transform[8], -this.transform[9], -this.transform[10]];
        vec3.normalize(dir, dir);
        return dir;
    }

    /**
     * Returns the current target the camera looks at as vec3
     * This multiplies the viewing direction with the distance.
     * For distance 0 the normalized viewing direction is used.
     */
    getTarget()
    {
        const target = vec3.create();
        const position = this.getPosition();
        let lookDirection = this.getLookDirection();
        if (this.distance != 0 && this.distance != 1)
        {
            lookDirection = lookDirection.map(x => x * this.distance);
        }
        vec3.add(target, lookDirection, position);
        return target;
    }

    /**
     * Look from user camera to target
     * This changes the transformation of the user camera
     * @param {vec3} from
     * @param {vec3} to
     */
    lookAt(from, to)
    {
        this.transform = mat4.create();
        mat4.lookAt(this.transform, from, to, vec3.fromValues(0, 1, 0));
    }

    /**
     * Sets the position of the user camera
     * @param {vec3} position
     */
    setPosition(position)
    {
        this.transform[12] = position[0];
        this.transform[13] = position[1];
        this.transform[14] = position[2];
    }

    /**
     * This rotates the user camera towards the target and sets the position of the user camera
     * according to the current distance
     * @param {vec3} target
     */
    setTarget(target)
    {
        let pos = vec3.create();
        mat4.getTranslation(pos, this.transform);
        this.transform = mat4.create();
        mat4.lookAt(this.transform, pos, target, vec3.fromValues(0, 1, 0));
        this.setDistanceFromTarget(this.distance, target);
    }

    /**
     * Sets the rotation of the camera
     * Yaw and pitch should be in gradient
     * @param {number} yaw
     * @param {number} pitch
     */
    setRotation(yaw, pitch)
    {
        const tmpPos = this.getPosition();
        let mat4x = mat4.create();
        let mat4y = mat4.create();
        mat4.fromXRotation(mat4x, pitch);
        mat4.fromYRotation(mat4y, yaw);
        this.transform = mat4y;
        this.setPosition(tmpPos);
        mat4.multiply(this.transform, this.transform, mat4x);
    }

    /**
     * Transforms the user camera to look at a target from a specfic distance using the current rotation
     * This will only change the position of the user camera, not the rotation
     * Use this function to set the distance
     * @param {number} distance
     * @param {vec3} target
     */
    setDistanceFromTarget(distance, target)
    {
        const lookDirection = this.getLookDirection();
        const distVec = lookDirection.map(x => x * -distance);
        let pos = vec3.create();
        vec3.add(pos, target, distVec);
        this.setPosition(pos);
        this.distance = distance;

    }

    /**
     * Does a logarithmic zoom step according to this.zoomFactor
     * sign determines the direction of the zoom
     * @param {number} sign
     */
    zoomStep(sign)
    {
        let target = this.getTarget();
        if (sign > 0)
        {
            this.distance *= this.zoomFactor;
        }
        else
        {
            this.distance /= this.zoomFactor;
        }
        this.setDistanceFromTarget(this.distance, target);
        this.fitCameraPlanesToExtents(this.sceneExtents.min, this.sceneExtents.max);
    }

    /**
     * Orbit around the target
     * x and y should be in radient and are added to the current rotation
     * The rotation around the x-axis is limited to 180 degree
     * @param {number} x
     * @param {number} y
     */
    orbit(x, y)
    {
        const target = this.getTarget();
        const rotAroundXMax = Math.PI / 2 - 0.01;
        this.rotAroundY += (-x * this.orbitSpeed);
        this.rotAroundX += (-y * this.orbitSpeed);
        this.rotAroundX = clamp(this.rotAroundX, -rotAroundXMax, rotAroundXMax);
        this.setRotation(this.rotAroundY, this.rotAroundX);
        this.setDistanceFromTarget(this.distance, target);
    }

    /**
     * Pan the user camera
     * x and y are added to the position
     * @param {number} x
     * @param {number} y
     */
    pan(x, y)
    {
        const left = vec3.fromValues(-this.transform[0], -this.transform[1], -this.transform[2]);
        vec3.scale(left, left, x * this.panSpeed);

        const up = vec3.fromValues(this.transform[4], this.transform[5], this.transform[6]);
        vec3.scale(up, up, y * this.panSpeed);

        let pos = this.getPosition();

        vec3.add(pos, pos, up);
        vec3.add(pos, pos, left);

        this.setPosition(pos);
    }

    fitPanSpeedToScene(min, max)
    {
        const longestDistance = vec3.distance(min, max);
        this.panSpeed = longestDistance / PanSpeedDenominator;
    }

    reset()
    {
        this.transform = mat4.create();
        this.rotAroundX = 0;
        this.rotAroundY = 0;
        this.fitDistanceToExtents(this.sceneExtents.min, this.sceneExtents.max);
        this.fitCameraTargetToExtents(this.sceneExtents.min, this.sceneExtents.max);
    }

    /**
     * Calculates a camera position which looks at the center of the scene from an appropriate distance
     * This calculates near and far plane as well
     * @param {Gltf} gltf
     * @param {number} sceneIndex
     */
    fitViewToScene(gltf, sceneIndex)
    {
        this.transform = mat4.create();
        this.rotAroundX = 0;
        this.rotAroundY = 0;
        getSceneExtents(gltf, sceneIndex, this.sceneExtents.min, this.sceneExtents.max);
        this.fitDistanceToExtents(this.sceneExtents.min, this.sceneExtents.max);
        this.fitCameraTargetToExtents(this.sceneExtents.min, this.sceneExtents.max);

        this.fitPanSpeedToScene(this.sceneExtents.min, this.sceneExtents.max);
        this.fitCameraPlanesToExtents(this.sceneExtents.min, this.sceneExtents.max);

    }

    fitDistanceToExtents(min, max)
    {
        const maxAxisLength = Math.max(max[0] - min[0], max[1] - min[1]);
        const yfov = this.yfov;
        const xfov = this.yfov * this.aspectRatio;

        const yZoom = maxAxisLength / 2 / Math.tan(yfov / 2);
        const xZoom = maxAxisLength / 2 / Math.tan(xfov / 2);

        this.distance = Math.max(xZoom, yZoom);
    }

    fitCameraTargetToExtents(min, max)
    {
        let target = [0,0,0];
        for (const i of [0, 1, 2])
        {
            target[i] = (max[i] + min[i]) / 2;
        }
        this.setRotation(this.rotAroundY, this.rotAroundX);
        this.setDistanceFromTarget(this.distance, target);
    }

    fitCameraPlanesToExtents(min, max)
    {
        // depends only on scene min/max and the camera distance

        // Manually increase scene extent just for the camera planes to avoid camera clipping in most situations.
        const longestDistance = 10 * vec3.distance(min, max);
        let zNear = this.distance - (longestDistance * 0.6);
        let zFar = this.distance + (longestDistance * 0.6);

        // minimum near plane value needs to depend on far plane value to avoid z fighting or too large near planes
        zNear = Math.max(zNear, zFar / MaxNearFarRatio);

        this.znear = zNear;
        this.zfar = zFar;
    }
}

export { UserCamera };
<commit_msg>Add periods to user camera<commit_after>import { vec3, mat4, quat } from 'gl-matrix';
import { gltfCamera } from './camera.js';
import { clamp } from './utils.js';
import { getSceneExtents } from './gltf_utils.js';

const PanSpeedDenominator = 1200;
const MaxNearFarRatio = 10000;

class UserCamera extends gltfCamera
{
    /**
     * Create a new user camera.
     */
    constructor()
    {
        super();

        this.transform = mat4.create();
        this.rotAroundY = 0;
        this.rotAroundX = 0;
        this.distance = 1;
        this.zoomFactor = 1.04;
        this.orbitSpeed = 1 / 180;
        this.panSpeed = 1;
        this.sceneExtents = {
            min: vec3.create(),
            max: vec3.create()
        };
    }

    /**
     * Sets the vertical FoV of the user camera.
     * @param {number} yfov
     */
    setVerticalFoV(yfov)
    {
        this.yfov = yfov;
    }

    /**
     * Returns the current position of the user camera as a vec3.
     */
    getPosition()
    {
        let pos = vec3.create();
        mat4.getTranslation(pos, this.transform);
        return pos;
    }

    /**
     * Returns the current rotation of the user camera as quat.
     */
    getRotation()
    {
        let rot = quat.create();
        mat4.getRotation(rot, this.transform);
        return rot;
    }

    /**
     * Returns the normalized direction the user camera looks at as vec3.
     */
    getLookDirection()
    {
        let dir = [-this.transform[8], -this.transform[9], -this.transform[10]];
        vec3.normalize(dir, dir);
        return dir;
    }

    /**
     * Returns the current target the camera looks at as vec3.
     * This multiplies the viewing direction with the distance.
     * For distance 0 the normalized viewing direction is used.
     */
    getTarget()
    {
        const target = vec3.create();
        const position = this.getPosition();
        let lookDirection = this.getLookDirection();
        if (this.distance != 0 && this.distance != 1)
        {
            lookDirection = lookDirection.map(x => x * this.distance);
        }
        vec3.add(target, lookDirection, position);
        return target;
    }

    /**
     * Look from user camera to target.
     * This changes the transformation of the user camera.
     * @param {vec3} from
     * @param {vec3} to
     */
    lookAt(from, to)
    {
        this.transform = mat4.create();
        mat4.lookAt(this.transform, from, to, vec3.fromValues(0, 1, 0));
    }

    /**
     * Sets the position of the user camera.
     * @param {vec3} position
     */
    setPosition(position)
    {
        this.transform[12] = position[0];
        this.transform[13] = position[1];
        this.transform[14] = position[2];
    }

    /**
     * This rotates the user camera towards the target and sets the position of the user camera
     * according to the current distance.
     * @param {vec3} target
     */
    setTarget(target)
    {
        let pos = vec3.create();
        mat4.getTranslation(pos, this.transform);
        this.transform = mat4.create();
        mat4.lookAt(this.transform, pos, target, vec3.fromValues(0, 1, 0));
        this.setDistanceFromTarget(this.distance, target);
    }

    /**
     * Sets the rotation of the camera.
     * Yaw and pitch should be in gradient.
     * @param {number} yaw
     * @param {number} pitch
     */
    setRotation(yaw, pitch)
    {
        const tmpPos = this.getPosition();
        let mat4x = mat4.create();
        let mat4y = mat4.create();
        mat4.fromXRotation(mat4x, pitch);
        mat4.fromYRotation(mat4y, yaw);
        this.transform = mat4y;
        this.setPosition(tmpPos);
        mat4.multiply(this.transform, this.transform, mat4x);
    }

    /**
     * Transforms the user camera to look at a target from a specfic distance using the current rotation.
     * This will only change the position of the user camera, not the rotation.
     * Use this function to set the distance.
     * @param {number} distance
     * @param {vec3} target
     */
    setDistanceFromTarget(distance, target)
    {
        const lookDirection = this.getLookDirection();
        const distVec = lookDirection.map(x => x * -distance);
        let pos = vec3.create();
        vec3.add(pos, target, distVec);
        this.setPosition(pos);
        this.distance = distance;

    }

    /**
     * Does a logarithmic zoom step according to this.zoomFactor.
     * sign determines the direction of the zoom.
     * @param {number} sign
     */
    zoomStep(sign)
    {
        let target = this.getTarget();
        if (sign > 0)
        {
            this.distance *= this.zoomFactor;
        }
        else
        {
            this.distance /= this.zoomFactor;
        }
        this.setDistanceFromTarget(this.distance, target);
        this.fitCameraPlanesToExtents(this.sceneExtents.min, this.sceneExtents.max);
    }

    /**
     * Orbit around the target.
     * x and y should be in radient and are added to the current rotation.
     * The rotation around the x-axis is limited to 180 degree.
     * @param {number} x
     * @param {number} y
     */
    orbit(x, y)
    {
        const target = this.getTarget();
        const rotAroundXMax = Math.PI / 2 - 0.01;
        this.rotAroundY += (-x * this.orbitSpeed);
        this.rotAroundX += (-y * this.orbitSpeed);
        this.rotAroundX = clamp(this.rotAroundX, -rotAroundXMax, rotAroundXMax);
        this.setRotation(this.rotAroundY, this.rotAroundX);
        this.setDistanceFromTarget(this.distance, target);
    }

    /**
     * Pan the user camera.
     * x and y are added to the position.
     * @param {number} x
     * @param {number} y
     */
    pan(x, y)
    {
        const left = vec3.fromValues(-this.transform[0], -this.transform[1], -this.transform[2]);
        vec3.scale(left, left, x * this.panSpeed);

        const up = vec3.fromValues(this.transform[4], this.transform[5], this.transform[6]);
        vec3.scale(up, up, y * this.panSpeed);

        let pos = this.getPosition();

        vec3.add(pos, pos, up);
        vec3.add(pos, pos, left);

        this.setPosition(pos);
    }

    fitPanSpeedToScene(min, max)
    {
        const longestDistance = vec3.distance(min, max);
        this.panSpeed = longestDistance / PanSpeedDenominator;
    }

    reset()
    {
        this.transform = mat4.create();
        this.rotAroundX = 0;
        this.rotAroundY = 0;
        this.fitDistanceToExtents(this.sceneExtents.min, this.sceneExtents.max);
        this.fitCameraTargetToExtents(this.sceneExtents.min, this.sceneExtents.max);
    }

    /**
     * Calculates a camera position which looks at the center of the scene from an appropriate distance.
     * This calculates near and far plane as well.
     * @param {Gltf} gltf
     * @param {number} sceneIndex
     */
    fitViewToScene(gltf, sceneIndex)
    {
        this.transform = mat4.create();
        this.rotAroundX = 0;
        this.rotAroundY = 0;
        getSceneExtents(gltf, sceneIndex, this.sceneExtents.min, this.sceneExtents.max);
        this.fitDistanceToExtents(this.sceneExtents.min, this.sceneExtents.max);
        this.fitCameraTargetToExtents(this.sceneExtents.min, this.sceneExtents.max);

        this.fitPanSpeedToScene(this.sceneExtents.min, this.sceneExtents.max);
        this.fitCameraPlanesToExtents(this.sceneExtents.min, this.sceneExtents.max);

    }

    fitDistanceToExtents(min, max)
    {
        const maxAxisLength = Math.max(max[0] - min[0], max[1] - min[1]);
        const yfov = this.yfov;
        const xfov = this.yfov * this.aspectRatio;

        const yZoom = maxAxisLength / 2 / Math.tan(yfov / 2);
        const xZoom = maxAxisLength / 2 / Math.tan(xfov / 2);

        this.distance = Math.max(xZoom, yZoom);
    }

    fitCameraTargetToExtents(min, max)
    {
        let target = [0,0,0];
        for (const i of [0, 1, 2])
        {
            target[i] = (max[i] + min[i]) / 2;
        }
        this.setRotation(this.rotAroundY, this.rotAroundX);
        this.setDistanceFromTarget(this.distance, target);
    }

    fitCameraPlanesToExtents(min, max)
    {
        // depends only on scene min/max and the camera distance

        // Manually increase scene extent just for the camera planes to avoid camera clipping in most situations.
        const longestDistance = 10 * vec3.distance(min, max);
        let zNear = this.distance - (longestDistance * 0.6);
        let zFar = this.distance + (longestDistance * 0.6);

        // minimum near plane value needs to depend on far plane value to avoid z fighting or too large near planes
        zNear = Math.max(zNear, zFar / MaxNearFarRatio);

        this.znear = zNear;
        this.zfar = zFar;
    }
}

export { UserCamera };
<|endoftext|>


<commit_before>let React = require("react")
let higherOrderComponent = require("./higher_order_component.js")
/*
 * A higher order component that passes a focused attribute to it's child
 * component. The focused is true when the component should be focused
 * (ie. when it is clicked on or tabbed into) and false when it is not (ie.
 * initially, when it is clicked off of and when another input is selected).
 *
 * This is useful for implementing popups in Frig Themes.
 */

@higherOrderComponent()
export default class extends React.Component {
  displayName = "Frig.HigherOrderComponents.ErrorNormalizer"

  static propTypes = {
    errors: React.PropTypes.oneOfType([
      React.PropTypes.object,
      React.PropTypes.array,
    ]),
    internalErrors: React.PropTypes.oneOfType([
      React.PropTypes.object,
      React.PropTypes.array,
    ]),
  }

  _toErrorObject(errors) {
    let isArray = Array.isArray(errors)
    if (errors == null || (isArray && errors.length == 0)) return {}
    // If errors is an array then convert it into an object. "base" is
    // used to store all top-level errors that are not specific to an
    // input.
    if (isArray) errors = {base: errors}
    return errors
  }

  _errors() {
    let errors = {}
    for (let k of ["errors", "internalErrors"]) {
      let errorsSubset = this._toErrorObject(this.props[k])
      for (let k2 in errorsSubset) {
        errors[k2] = (errors[k2] || []).concat(errorsSubset[k2])
      }
    }
    return errors
  }

  _normalizedErrors() {
    let errors = this._errors()
    // let normalizedErrorClass = opts.as
    let normalizedErrorClass = this.opts().as
    // Convert the errors object into the normalized error class
    if (normalizedErrorClass == Array) {
      let errorsArray = []
      for (let k in errors) errorsArray = errorsArray.concat(errors[k])
      return errorsArray
    }
    else if (normalizedErrorClass == Object) {
      return errors
    }
    else {
      throw(
        "ErrorsNormalizer \"as\" attribute must be either Array or Object"
      )
    }
  }

  render() {
    let childProps = Object.assign({}, this.props, {
      ref: "child",
      errors: this._normalizedErrors(),
    })
    delete childProps.internalErrors

    return React.createElement(this.componentClass(), childProps)
  }

}
<commit_msg>Removing erroneous copy and paste<commit_after>let React = require("react")
let higherOrderComponent = require("./higher_order_component.js")

@higherOrderComponent()
export default class extends React.Component {
  displayName = "Frig.HigherOrderComponents.ErrorNormalizer"

  static propTypes = {
    errors: React.PropTypes.oneOfType([
      React.PropTypes.object,
      React.PropTypes.array,
    ]),
    internalErrors: React.PropTypes.oneOfType([
      React.PropTypes.object,
      React.PropTypes.array,
    ]),
  }

  _toErrorObject(errors) {
    let isArray = Array.isArray(errors)
    if (errors == null || (isArray && errors.length == 0)) return {}
    // If errors is an array then convert it into an object. "base" is
    // used to store all top-level errors that are not specific to an
    // input.
    if (isArray) errors = {base: errors}
    return errors
  }

  _errors() {
    let errors = {}
    for (let k of ["errors", "internalErrors"]) {
      let errorsSubset = this._toErrorObject(this.props[k])
      for (let k2 in errorsSubset) {
        errors[k2] = (errors[k2] || []).concat(errorsSubset[k2])
      }
    }
    return errors
  }

  _normalizedErrors() {
    let errors = this._errors()
    // let normalizedErrorClass = opts.as
    let normalizedErrorClass = this.opts().as
    // Convert the errors object into the normalized error class
    if (normalizedErrorClass == Array) {
      let errorsArray = []
      for (let k in errors) errorsArray = errorsArray.concat(errors[k])
      return errorsArray
    }
    else if (normalizedErrorClass == Object) {
      return errors
    }
    else {
      throw(
        "ErrorsNormalizer \"as\" attribute must be either Array or Object"
      )
    }
  }

  render() {
    let childProps = Object.assign({}, this.props, {
      ref: "child",
      errors: this._normalizedErrors(),
    })
    delete childProps.internalErrors

    return React.createElement(this.componentClass(), childProps)
  }

}
<|endoftext|>


<commit_before>function load_image(id, image) {
	var dimensions = new Array();
	$('').on("load", function () {
		dimensions[ "height"] = this.naturalHeight;
		dimensions[ "width"] = this.naturalWidth;
		render_map(id, image, dimensions);
	}).attr('src', image).appendTo('#image-container');
}

function render_map(id, image, dimensions) {
	var height = + dimensions[ "height"];
	var width = + dimensions[ "width"];
	var div_id = $('.annot').attr('id');

	//get ratio between height and width and set bounds
	if (height > width) {
		var ratio = height / width;
		var bounds = new Array(- 1, - Math.abs(ratio), 1, ratio);
	} else {
		var ratio = width / height;
		var bounds = new Array(- Math.abs(ratio), - 1, ratio, 1);
	}

	//instantiate map
	var map = new OpenLayers.Map(div_id, {
		numZoomLevels: 3, units: "pixels", isBaseLayer: true
	});
	var baseLayer = new OpenLayers.Layer.Image('image', image, new OpenLayers.Bounds(bounds), new OpenLayers.Size(600 * ratio, 600));

	//add baseLayer, zoom to extent
	map.addLayer(baseLayer);
	map.zoomToMaxExtent();

	//handle annotations
	anno.makeAnnotatable(map);

	//import annotations
	import_annotations(id);

	//set handlers
	anno.addHandler('onAnnotationCreated', function (annotation) {
		//construct HTML links from regular expressions
		var desc = replaceURLWithHTMLLinks(annotation.text);
		//reset annotation.text
		annotation.text = desc;
		//generate id
		var id = 'a' + Math.random().toString(36).substr(2);
		annotation.id = id;
		//coordinates
		var ulx = annotation.shapes[0].geometry.x;
		var lrx = annotation.shapes[0].geometry.x + annotation.shapes[0].geometry.width;
		var uly = annotation.shapes[0].geometry.y;
		var lry = annotation.shapes[0].geometry.y - annotation.shapes[0].geometry.height;

		//write values to instances
		ORBEON.xforms.Document.setValue('annotation-text', desc);
		ORBEON.xforms.Document.setValue('annotation-id', id);
		ORBEON.xforms.Document.setValue('annotation-ulx', ulx);
		ORBEON.xforms.Document.setValue('annotation-uly', uly);
		ORBEON.xforms.Document.setValue('annotation-lrx', lrx);
		ORBEON.xforms.Document.setValue('annotation-lry', lry);

		//generate key for xforms-value-changed observer to put data into the TEI document
		ORBEON.xforms.Document.setValue('an-action', 'create');
		ORBEON.xforms.Document.setValue('key', Math.random().toString(36).substr(2));

		//set modified to true
		ORBEON.xforms.Document.setValue('doc-modified', 'true');
	});
	anno.addHandler('onAnnotationRemoved', function (annotation) {
		//delete annotation from TEI
		ORBEON.xforms.Document.setValue('an-id', annotation.id);
		ORBEON.xforms.Document.setValue('an-action', 'delete');
		ORBEON.xforms.Document.setValue('key', Math.random().toString(36).substr(2));

		//set modified to true
		ORBEON.xforms.Document.setValue('doc-modified', 'true');
	});
	anno.addHandler('onAnnotationUpdated', function (annotation) {
		var desc = replaceURLWithHTMLLinks(annotation.text);
		//reset annotation.text
		annotation.text = desc;

		//update annotation
		ORBEON.xforms.Document.setValue('an-id', annotation.id);
		ORBEON.xforms.Document.setValue('annotation-text', desc);
		ORBEON.xforms.Document.setValue('an-action', 'update');
		ORBEON.xforms.Document.setValue('key', Math.random().toString(36).substr(2));

		//set modified to true
		ORBEON.xforms.Document.setValue('doc-modified', 'true');
	});
}

function import_annotations(id) {
	var path = '../../../' + ORBEON.xforms.Document.getValue('collection-name') + '/';
	var doc = ORBEON.xforms.Document.getValue('doc-id');
	$.get(path + 'get_annotations/', {
		facsimile: id, doc: doc, mode: 'admin'
	},
	function (data) {
		var obj = $.parseJSON(data);
		$.each(obj, function (index, value) {
			anno.addAnnotation(value);
		});
	});
}

function annotate() {
	anno.activateSelector();
}

/********** URI PARSING **********/
//construct HTML links from regular expressions
function replaceURLWithHTMLLinks(text) {
	var exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
	return text.replace(exp, constructLink);
}

function constructLink(match, p1, offset, string) {
	return "" + getLabel(p1) + "";
}

//construct the linkable text depending on the URI (handle nomisma and Mantis URIs)
function getLabel(uri) {
	var label;
	var path = '../../../' + ORBEON.xforms.Document.getValue('collection-name') + '/';
	$.ajaxSetup({async: false});
	$.getJSON(path + 'get_label/', {
		uri: uri
	},
	function (data) {
		label = data.label;
	});
	return label;
}<commit_msg>moved anno handlers out of the function (they are firing multiple times<commit_after>function load_image(id, image) {
	var dimensions = new Array();
	$('').on("load", function () {
		dimensions[ "height"] = this.naturalHeight;
		dimensions[ "width"] = this.naturalWidth;
		render_map(id, image, dimensions);
	}).attr('src', image).appendTo('#image-container');
}

function render_map(id, image, dimensions) {
	var height = + dimensions[ "height"];
	var width = + dimensions[ "width"];
	var div_id = $('.annot').attr('id');

	//get ratio between height and width and set bounds
	if (height > width) {
		var ratio = height / width;
		var bounds = new Array(- 1, - Math.abs(ratio), 1, ratio);
	} else {
		var ratio = width / height;
		var bounds = new Array(- Math.abs(ratio), - 1, ratio, 1);
	}

	//instantiate map
	var map = new OpenLayers.Map(div_id, {
		numZoomLevels: 3, units: "pixels", isBaseLayer: true
	});
	var baseLayer = new OpenLayers.Layer.Image('image', image, new OpenLayers.Bounds(bounds), new OpenLayers.Size(600 * ratio, 600));

	//add baseLayer, zoom to extent
	map.addLayer(baseLayer);
	map.zoomToMaxExtent();

	//handle annotations
	anno.makeAnnotatable(map);

	//import annotations
	import_annotations(id);
}

function import_annotations(id) {
	var path = '../../../' + ORBEON.xforms.Document.getValue('collection-name') + '/';
	var doc = ORBEON.xforms.Document.getValue('doc-id');
	$.get(path + 'get_annotations/', {
		facsimile: id, doc: doc, mode: 'admin'
	},
	function (data) {
		var obj = $.parseJSON(data);
		$.each(obj, function (index, value) {
			anno.addAnnotation(value);
		});
	});
}

function annotate() {
	anno.activateSelector();
}

//set handlers
anno.addHandler('onAnnotationCreated', function (annotation) {
	//construct HTML links from regular expressions
	var desc = replaceURLWithHTMLLinks(annotation.text);
	//reset annotation.text
	annotation.text = desc;
	//generate id
	var id = 'a' + Math.random().toString(36).substr(2);
	annotation.id = id;
	//coordinates
	var ulx = annotation.shapes[0].geometry.x;
	var lrx = annotation.shapes[0].geometry.x + annotation.shapes[0].geometry.width;
	var uly = annotation.shapes[0].geometry.y;
	var lry = annotation.shapes[0].geometry.y - annotation.shapes[0].geometry.height;

	//write values to instances
	ORBEON.xforms.Document.setValue('annotation-text', desc);
	ORBEON.xforms.Document.setValue('annotation-id', id);
	ORBEON.xforms.Document.setValue('annotation-ulx', ulx);
	ORBEON.xforms.Document.setValue('annotation-uly', uly);
	ORBEON.xforms.Document.setValue('annotation-lrx', lrx);
	ORBEON.xforms.Document.setValue('annotation-lry', lry);

	//generate key for xforms-value-changed observer to put data into the TEI document
	ORBEON.xforms.Document.setValue('an-action', 'create');
	ORBEON.xforms.Document.setValue('key', Math.random().toString(36).substr(2));

	//set modified to true
	ORBEON.xforms.Document.setValue('doc-modified', 'true');
});
anno.addHandler('onAnnotationRemoved', function (annotation) {
	//delete annotation from TEI
	ORBEON.xforms.Document.setValue('an-id', annotation.id);
	ORBEON.xforms.Document.setValue('an-action', 'delete');
	ORBEON.xforms.Document.setValue('key', Math.random().toString(36).substr(2));

	//set modified to true
	ORBEON.xforms.Document.setValue('doc-modified', 'true');
});
anno.addHandler('onAnnotationUpdated', function (annotation) {
	var desc = replaceURLWithHTMLLinks(annotation.text);
	//reset annotation.text
	annotation.text = desc;

	//update annotation
	ORBEON.xforms.Document.setValue('an-id', annotation.id);
	ORBEON.xforms.Document.setValue('annotation-text', desc);
	ORBEON.xforms.Document.setValue('an-action', 'update');
	ORBEON.xforms.Document.setValue('key', Math.random().toString(36).substr(2));

	//set modified to true
	ORBEON.xforms.Document.setValue('doc-modified', 'true');
});
/********** URI PARSING **********/
//construct HTML links from regular expressions
function replaceURLWithHTMLLinks(text) {
	var exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
	return text.replace(exp, constructLink);
}

function constructLink(match, p1, offset, string) {
	return "" + getLabel(p1) + "";
}

//construct the linkable text depending on the URI (handle nomisma and Mantis URIs)
function getLabel(uri) {
	var label;
	var path = '../../../' + ORBEON.xforms.Document.getValue('collection-name') + '/';
	$.ajaxSetup({
		async: false
	});
	$.getJSON(path + 'get_label/', {
		uri: uri
	},
	function (data) {
		label = data.label;
	});
	return label;
}<|endoftext|>


<commit_before>NGApp.factory('TicketViewService', function($rootScope, $resource, $routeParams, $timeout, NotificationService, AccountService, SocketService, MainNavigationService, TicketService) {

	var service = {
		isTyping: false,
		id_support: false,
		messages: [],
		socket: SocketService.socket
	};

	service.sideInfo = { id_support: null };

	service.sideInfo.setTicket = function( id_support ){
		service.sideInfo.id_support = id_support;
		service.sideInfo.reset();
	}

	service.sideInfo.reset = function(){
		service.sideInfo.data = { id_support: service.sideInfo.id_support, messages: [], page: 0, loaded: 0, total: null, has_more: false };
		service._private = { first_load: true, current_scroll: 0, could_load: true };
		service.sideInfo.update_controller()
	};

	service.sideInfo.force_first_page = function(){
		service.sideInfo.reset();
		service.sideInfo.load();
	}

	service.sideInfo.scroll = function( action ){
		var container = $('.support-chat-contents-scroll');
		switch( action ){
			case 'begin':
				$timeout( function(){
					container.stop( true, false ).animate( { scrollTop: container[0].scrollHeight }, 0 );
					service.sideInfo.release();
				}, 300 );
				break;
			case 'current':
				service._private.current_scroll = container[0].scrollHeight;
				break;
			default:
				var position = action;
				setTimeout(function() {
					var finalScroll = container[0].scrollHeight;
					var goToScroll = finalScroll - service._private.current_scroll;
					container[0].scrollTop = goToScroll;
					service.sideInfo.release();
				}, 100 );
				break;
		}
	}

	service.sideInfo.release = function(){
		setTimeout(function() { service._private.could_load = true }, 500 );
	}

	service.sideInfo.add_message = function( message ){
		service.sideInfo.data.messages.push( message );
		service.sideInfo.data.total++;
		service.sideInfo.data.loaded++;
		service.sideInfo.update_controller();
		service.sideInfo.scroll( 'begin' );
	}

	service.sideInfo.load_ticket_page = function(){
		if( service.sideInfo.id_support ){
			MainNavigationService.link( '/ticket/' + service.sideInfo.id_support );
		}
	}

	service.sideInfo.update_controller = function(){
		$rootScope.$broadcast( 'triggerTicketInfoUpdated', service.sideInfo.data );
	}

	service.sideInfo.load = function(){

		console.log('service.sideInfo.load');

		if( service.sideInfo.id_support ){

			if( !service._private.could_load ){
				return false;
			}

			if( service.sideInfo.data.total !== null && service.sideInfo.data.loaded >= service.sideInfo.data.total ){
				return;
			}

			service._private.could_load = false;

			service.sideInfo.data.page++;

			var params = { id_support: service.sideInfo.id_support, page: service.sideInfo.data.page };

			TicketService.side_info( params, function( data ){

				service.sideInfo.scroll( 'current' );

				service.sideInfo.data.pexcard = data.pexcard;
				service.sideInfo.data.restaurant = data.restaurant;
				service.sideInfo.data.order = data.order;
				service.sideInfo.data.total = data.messages.total;

				var messages = [];
				for( x in data.messages.list ){
					if( data.messages.list[ x ].id_support_message ){
						messages.push( data.messages.list[ x ] );
					}
				}

				for( x in service.sideInfo.data.messages ){
					if( service.sideInfo.data.messages[ x ].id_support_message ){
						messages.push( service.sideInfo.data.messages[ x ] );
					}
				}
				service.sideInfo.data.messages = messages;
				service.sideInfo.data.loaded = service.sideInfo.data.messages.length;
				service.sideInfo.data.has_more = ( service.sideInfo.data.loaded >= service.sideInfo.data.total ) ? false : true;
				service.sideInfo.update_controller();
				if( service._private.first_load ){
					service.sideInfo.scroll( 'begin' );
					service._private.first_load = false;
					service.sideInfo.load_ticket_page();
				} else {
					service.sideInfo.scroll();
				}

			} );
			return true;
		}
	};

	service.setViewTicket = function(id) {
		service.scope.viewTicket = id;
		service.sideInfo.setTicket( id );
	};

	$rootScope.$on('triggerViewTicket', function(e, ticket) {

		NotificationService.check();

		service.scope.viewTicket = ticket;
		service.scope.ticket = ticket;

		if (service.scope.viewTicket) {
			if( typeof service.scope.viewTicket == 'object' ){
				var id_support = service.scope.viewTicket.id_support
			} else {
				var id_support = service.scope.viewTicket;
			}
			service.socket.emit('event.subscribe', 'ticket.' + id_support);
		}
	});

	var notified  = new Array();

	$rootScope.$on('userAuth', function(e, data) {

		if (AccountService.user && AccountService.user.id_admin) {

			service.socket.on('user.preference', function(payload) {
				console.debug('Recieved preference update', payload);
				AccountService.user.prefs[payload.key] = payload.value;
				$rootScope.$apply();
			});

			if (AccountService.isSupport) {

				SocketService.listen('tickets', $rootScope)
					.on('message', function(d) {
						console.debug('Recieved chat message: ', d);

						if (notified.indexOf(d.id_support_message) > -1) {
							console.log('already notified ', d.id_support_message);
							return;
						}

						notified.push(d.id_support_message);

						// update the chat room
						console.log('service.sideInfo.id_support',service.sideInfo.id_support);
						console.log('d.id_support',d.id_support);
						if( service.sideInfo.id_support && d.id_support && service.sideInfo.id_support != d.id_support ){
							service.sideInfo.force_first_page();
						}

						if (d.id_admin == AccountService.user.id_admin) {
							return;
						}

						if (d.id_support == service.scope.viewTicket) {
							//App.playAudio('support-message-recieved');
						} else {
							//App.playAudio('support-message-new');
						}

						NotificationService.notify(d.name, d.body, null, function() {
							document.getElementById('support-chat-box').focus();
						});

					});
			}

		} else {
			//service.socket.close();
			//service.socket = null;
		}
	});

	$rootScope.$watch('account.user.prefs["notification-desktop-support-all"]', function(e, value) {
		if (!service.socket) {
			return;
		}
		if (value == '1') {
			console.debug('Subscribing to all tickets');
			service.socket.emit('event.subscribe', 'tickets');
		} else {
			console.debug('Unsubscribing to all tickets');
			service.socket.emit('event.unsubscribe', 'tickets');
		}
	});

	service.send = function(message, add_as_note, callback) {
		var add_as_note = ( add_as_note ? true : false );
		var guid = App.guid();
		console.log('guid',guid);
		if( !service.sideInfo.id_support ){
			return;
		}
		TicketService.message( {
			id_support: service.sideInfo.id_support,
			body: message,
			guid: guid,
			note: add_as_note
		},
		// callback
		function(d) {
			console.log('message added:::');
			console.log('d',d);
			for ( var x in service.sideInfo.data.messages ) {
				if ( service.sideInfo.data.messages[x].guid == guid ) {
					d.guid = guid;
					service.sideInfo.data.messages[x] = d;
					notified.push( d.id_support_message );
					break;
				}
			}
		});
		if( callback ){
			console.log('callback:::: ',callback);
			callback()
		} else {
			service.scope.$apply(function() {
				console.log('no callback');
				service.sideInfo.add_message( { body: message, name: AccountService.user.firstName, timestamp: new Date().getTime(), sending: true, guid: guid } );
			});
		}
	};

	service.scroll = function(instant) {
		setTimeout(function() {
			$('.support-chat-contents-scroll').stop(true,false).animate({
				scrollTop: $('.support-chat-contents-scroll')[0].scrollHeight
			}, instant ? 0 : 800);
		}, 100);
	};

	/*
	var typingTimer;

	service.typing = function(val) {
		return;
		if (!service.isTyping) {
			service.isTyping = true;
			service.websocket.send({
				type: 'ticket.typing.start'
			});

		} else {
			if (!val) {
				service.isTyping = false;
				service.websocket.send({
					type: 'ticket.typing.stop'
				});
			}
		}

		if (typingTimer) {
			clearTimeout(typingTimer);
		}
		typingTimer = setTimeout(function() {
			if (service.isTyping) {
				service.isTyping = false;
				service.websocket.send({
					type: 'ticket.typing.stop'
				});
			}
		}, 5000);
	};
	*/

	return service;
});
<commit_msg>partial #6216<commit_after>NGApp.factory('TicketViewService', function($rootScope, $resource, $routeParams, $timeout, NotificationService, AccountService, SocketService, MainNavigationService, TicketService) {

	var service = {
		isTyping: false,
		id_support: false,
		messages: [],
		socket: SocketService.socket
	};

	service.sideInfo = { id_support: null };

	service.sideInfo.setTicket = function( id_support ){
		service.sideInfo.id_support = id_support;
		service.sideInfo.reset();
	}

	service.sideInfo.reset = function(){
		service.sideInfo.data = { id_support: service.sideInfo.id_support, messages: [], page: 0, loaded: 0, total: null, has_more: false };
		service._private = { first_load: true, current_scroll: 0, could_load: true };
		service.sideInfo.update_controller()
	};

	service.sideInfo.force_first_page = function(){
		service.sideInfo.reset();
		service.sideInfo.load();
	}

	service.sideInfo.scroll = function( action ){
		var container = $('.support-chat-contents-scroll');
		switch( action ){
			case 'begin':
				$timeout( function(){
					container.stop( true, false ).animate( { scrollTop: container[0].scrollHeight }, 0 );
					service.sideInfo.release();
				}, 300 );
				break;
			case 'current':
				service._private.current_scroll = container[0].scrollHeight;
				break;
			default:
				var position = action;
				setTimeout(function() {
					var finalScroll = container[0].scrollHeight;
					var goToScroll = finalScroll - service._private.current_scroll;
					container[0].scrollTop = goToScroll;
					service.sideInfo.release();
				}, 100 );
				break;
		}
	}

	service.sideInfo.release = function(){
		setTimeout(function() { service._private.could_load = true }, 500 );
	}

	service.sideInfo.add_message = function( message ){
		service.sideInfo.data.messages.push( message );
		service.sideInfo.data.total++;
		service.sideInfo.data.loaded++;
		service.sideInfo.update_controller();
		service.sideInfo.scroll( 'begin' );
	}

	service.sideInfo.load_ticket_page = function(){
		if( service.sideInfo.id_support ){
			MainNavigationService.link( '/ticket/' + service.sideInfo.id_support );
		}
	}

	service.sideInfo.update_controller = function(){
		$rootScope.$broadcast( 'triggerTicketInfoUpdated', service.sideInfo.data );
	}

	service.sideInfo.load = function(){

		console.log('service.sideInfo.load');

		if( service.sideInfo.id_support ){

			if( !service._private.could_load ){
				return false;
			}

			if( service.sideInfo.data.total !== null && service.sideInfo.data.loaded >= service.sideInfo.data.total ){
				return;
			}

			service._private.could_load = false;

			service.sideInfo.data.page++;

			var params = { id_support: service.sideInfo.id_support, page: service.sideInfo.data.page };

			TicketService.side_info( params, function( data ){

				service.sideInfo.scroll( 'current' );

				service.sideInfo.data.pexcard = data.pexcard;
				service.sideInfo.data.restaurant = data.restaurant;
				service.sideInfo.data.order = data.order;
				service.sideInfo.data.total = data.messages.total;

				var messages = [];
				for( x in data.messages.list ){
					if( data.messages.list[ x ].id_support_message ){
						messages.push( data.messages.list[ x ] );
					}
				}

				for( x in service.sideInfo.data.messages ){
					if( service.sideInfo.data.messages[ x ].id_support_message ){
						messages.push( service.sideInfo.data.messages[ x ] );
					}
				}
				service.sideInfo.data.messages = messages;
				service.sideInfo.data.loaded = service.sideInfo.data.messages.length;
				service.sideInfo.data.has_more = ( service.sideInfo.data.loaded >= service.sideInfo.data.total ) ? false : true;
				service.sideInfo.update_controller();
				if( service._private.first_load ){
					service.sideInfo.scroll( 'begin' );
					service._private.first_load = false;
					service.sideInfo.load_ticket_page();
				} else {
					service.sideInfo.scroll();
				}

			} );
			return true;
		}
	};

	service.setViewTicket = function(id) {
		service.scope.viewTicket = id;
		service.sideInfo.setTicket( id );
	};

	$rootScope.$on('triggerViewTicket', function(e, ticket) {

		NotificationService.check();

		service.scope.viewTicket = ticket;
		service.scope.ticket = ticket;

		if (service.scope.viewTicket) {
			if( typeof service.scope.viewTicket == 'object' ){
				var id_support = service.scope.viewTicket.id_support
			} else {
				var id_support = service.scope.viewTicket;
			}
			service.socket.emit('event.subscribe', 'ticket.' + id_support);
		}
	});

	var notified  = new Array();

	$rootScope.$on('userAuth', function(e, data) {

		if (AccountService.user && AccountService.user.id_admin) {

			service.socket.on('user.preference', function(payload) {
				console.debug('Recieved preference update', payload);
				AccountService.user.prefs[payload.key] = payload.value;
				$rootScope.$apply();
			});

			if (AccountService.isSupport) {

				SocketService.listen('tickets', $rootScope)
					.on('message', function(d) {
						console.debug('Recieved chat message: ', d);

						if (notified.indexOf(d.id_support_message) > -1) {
							console.log('already notified ', d.id_support_message);
							return;
						}

						notified.push(d.id_support_message);

						// update the chat room
						console.log('service.sideInfo.id_support',service.sideInfo.id_support);
						console.log('d.id_support',d.id_support);
						if( service.sideInfo.id_support && d.id_support && service.sideInfo.id_support != d.id_support ){
							console.log('force_first_page??');
							// service.sideInfo.force_first_page();
						}

						if (d.id_admin == AccountService.user.id_admin) {
							return;
						}

						if (d.id_support == service.scope.viewTicket) {
							//App.playAudio('support-message-recieved');
						} else {
							//App.playAudio('support-message-new');
						}

						NotificationService.notify(d.name, d.body, null, function() {
							document.getElementById('support-chat-box').focus();
						});

					});
			}

		} else {
			//service.socket.close();
			//service.socket = null;
		}
	});

	$rootScope.$watch('account.user.prefs["notification-desktop-support-all"]', function(e, value) {
		if (!service.socket) {
			return;
		}
		if (value == '1') {
			console.debug('Subscribing to all tickets');
			service.socket.emit('event.subscribe', 'tickets');
		} else {
			console.debug('Unsubscribing to all tickets');
			service.socket.emit('event.unsubscribe', 'tickets');
		}
	});

	service.send = function(message, add_as_note, callback) {
		var add_as_note = ( add_as_note ? true : false );
		var guid = App.guid();
		console.log('guid',guid);
		if( !service.sideInfo.id_support ){
			return;
		}
		TicketService.message( {
			id_support: service.sideInfo.id_support,
			body: message,
			guid: guid,
			note: add_as_note
		},
		// callback
		function(d) {
			console.log('message added:::');
			console.log('d',d);
			for ( var x in service.sideInfo.data.messages ) {
				if ( service.sideInfo.data.messages[x].guid == guid ) {
					d.guid = guid;
					service.sideInfo.data.messages[x] = d;
					notified.push( d.id_support_message );
					break;
				}
			}
		});
		if( callback ){
			console.log('callback:::: ',callback);
			callback()
		} else {
			service.scope.$apply(function() {
				console.log('no callback');
				service.sideInfo.add_message( { body: message, name: AccountService.user.firstName, timestamp: new Date().getTime(), sending: true, guid: guid } );
			});
		}
	};

	service.scroll = function(instant) {
		setTimeout(function() {
			$('.support-chat-contents-scroll').stop(true,false).animate({
				scrollTop: $('.support-chat-contents-scroll')[0].scrollHeight
			}, instant ? 0 : 800);
		}, 100);
	};

	/*
	var typingTimer;

	service.typing = function(val) {
		return;
		if (!service.isTyping) {
			service.isTyping = true;
			service.websocket.send({
				type: 'ticket.typing.start'
			});

		} else {
			if (!val) {
				service.isTyping = false;
				service.websocket.send({
					type: 'ticket.typing.stop'
				});
			}
		}

		if (typingTimer) {
			clearTimeout(typingTimer);
		}
		typingTimer = setTimeout(function() {
			if (service.isTyping) {
				service.isTyping = false;
				service.websocket.send({
					type: 'ticket.typing.stop'
				});
			}
		}, 5000);
	};
	*/

	return service;
});
<|endoftext|>


<commit_before>import React, { useContext, useState, useEffect } from 'react';
import axios from 'axios';
import { Link, useParams } from 'react-router-dom';
import { UserContext } from './contexts/UserContext';
import { toURL } from './utils/url';
import TabEdit from './TabEdit';
import TabLink from './TabLink';
import UserLink from './UserLink';
import {
  FaPen as EditIcon,
  FaRegStar as AddIcon,
  FaLastfmSquare as LastFMIcon,
} from 'react-icons/fa';

import './Tab.scss';

function Tab({history}) {
  const { user } = useContext(UserContext)
  const params = useParams();
  const [loading, setLoading] = useState(false);
  const [loaded, setLoaded] = useState(false);

  const [tabID, setTabID] = useState(null);
  const [artist, setArtist] = useState(null);
  const [createdByUsername, setCreatedByUsername] = useState(null);
  const [tab, setTab] = useState(null);
  const [title, setTitle] = useState(null);

  const [error, setError] = useState(null);
  const [edit, setEdit] = useState(false);

  const canEdit = () => createdByUsername === user.username;
  const canAdd = () => user.isLoggedIn;

  const sameTabLoaded = (artist, title, params) => {
    if (!artist || !title || !params.artist || !params.title) return false;

    function toLowerURL(artistName, title) {
      return toURL(`${artistName}/${title}`).toLowerCase();
    }

    return toLowerURL(artist.name, title) === toLowerURL(params.artist, params.title);
  };

  const onEditSave = data => {
    setEdit(false);

    if (sameTabLoaded(data.artist, data.title, params)) {
      setTabID(data.id);
      setArtist(data.artist);
      setCreatedByUsername(data.created_by_username);
      setTab(data.tab);
      setTitle(data.title);
    } else {
      history.push(`/tabs/${toURL(data.artist.name)}/${toURL(data.title)}`);
      setLoaded(false);
    }
  };

  useEffect(function loadTab() {
    if (loading || error || (loaded && sameTabLoaded(artist, title, params))) {
      return;
    }

    if (loading || error || loaded) return;

    setLoading(true);

    axios.get(`/api/tabs/${params.artist}/${params.title}`).then(response => {
      const data = response.data;

      setTabID(data.id);
      setArtist(data.artist);
      setCreatedByUsername(data.created_by_username);
      setTab(data.tab);
      setTitle(data.title);

      setLoaded(true);
      setLoading(false);
    }).catch(e => {
      const data = e.response.data;
      console.log(data.message);

      setError(data.message);
      setLoaded(true);
      setLoading(false);
    });
  }, [loading, loaded, error, artist, title, params]);

  if (!loaded) {
    return
loading...
;
  }

  if (error) {
    let message =
{error}
;

    if (error === "Tab not found") {
      message =
No tab found. Add a new tab <Link to="/tabs/new">here</Link>.
;
    }

    return message;
  }

  if (edit) {
    return(
      <TabEdit
        id={tabID}
        user={user}
        artist={artist}
        createdByUsername={createdByUsername}
        title={title}
        tab={tab}
        onSave={onEditSave}
      />
    );
  }

  return (

            <TabLink artist={artist.name} title={title} />{' '}
            by{' '}
            <Link to={`/tabs/${toURL(artist.name)}`}>{artist.name}</Link>{' '}

            created by <UserLink username={createdByUsername} />

          {canEdit() &&
             setEdit(true)}
            >
              <EditIcon /> edit

          }
          {canAdd() &&

              <AddIcon /> add

          }
          <LastFMIcon /> lastfm

{tab}

  );
}

export default Tab;
<commit_msg>removes unused actions<commit_after>import React, { useContext, useState, useEffect } from 'react';
import axios from 'axios';
import { Link, useParams } from 'react-router-dom';
import { UserContext } from './contexts/UserContext';
import { toURL } from './utils/url';
import TabEdit from './TabEdit';
import TabLink from './TabLink';
import UserLink from './UserLink';
import {
  FaPen as EditIcon,
} from 'react-icons/fa';

import './Tab.scss';

function Tab({history}) {
  const { user } = useContext(UserContext)
  const params = useParams();
  const [loading, setLoading] = useState(false);
  const [loaded, setLoaded] = useState(false);

  const [tabID, setTabID] = useState(null);
  const [artist, setArtist] = useState(null);
  const [createdByUsername, setCreatedByUsername] = useState(null);
  const [tab, setTab] = useState(null);
  const [title, setTitle] = useState(null);

  const [error, setError] = useState(null);
  const [edit, setEdit] = useState(false);

  const canEdit = () => createdByUsername === user.username;

  const sameTabLoaded = (artist, title, params) => {
    if (!artist || !title || !params.artist || !params.title) return false;

    function toLowerURL(artistName, title) {
      return toURL(`${artistName}/${title}`).toLowerCase();
    }

    return toLowerURL(artist.name, title) === toLowerURL(params.artist, params.title);
  };

  const onEditSave = data => {
    setEdit(false);

    if (sameTabLoaded(data.artist, data.title, params)) {
      setTabID(data.id);
      setArtist(data.artist);
      setCreatedByUsername(data.created_by_username);
      setTab(data.tab);
      setTitle(data.title);
    } else {
      history.push(`/tabs/${toURL(data.artist.name)}/${toURL(data.title)}`);
      setLoaded(false);
    }
  };

  useEffect(function loadTab() {
    if (loading || error || (loaded && sameTabLoaded(artist, title, params))) {
      return;
    }

    if (loading || error || loaded) return;

    setLoading(true);

    axios.get(`/api/tabs/${params.artist}/${params.title}`).then(response => {
      const data = response.data;

      setTabID(data.id);
      setArtist(data.artist);
      setCreatedByUsername(data.created_by_username);
      setTab(data.tab);
      setTitle(data.title);

      setLoaded(true);
      setLoading(false);
    }).catch(e => {
      const data = e.response.data;
      console.log(data.message);

      setError(data.message);
      setLoaded(true);
      setLoading(false);
    });
  }, [loading, loaded, error, artist, title, params]);

  if (!loaded) {
    return
loading...
;
  }

  if (error) {
    let message =
{error}
;

    if (error === "Tab not found") {
      message =
No tab found. Add a new tab <Link to="/tabs/new">here</Link>.
;
    }

    return message;
  }

  if (edit) {
    return(
      <TabEdit
        id={tabID}
        user={user}
        artist={artist}
        createdByUsername={createdByUsername}
        title={title}
        tab={tab}
        onSave={onEditSave}
      />
    );
  }

  return (

            <TabLink artist={artist.name} title={title} />{' '}
            by{' '}
            <Link to={`/tabs/${toURL(artist.name)}`}>{artist.name}</Link>{' '}

            created by <UserLink username={createdByUsername} />

          {canEdit() &&
             setEdit(true)}
            >
              <EditIcon /> edit

          }

{tab}

  );
}

export default Tab;
<|endoftext|>


<commit_before>// @flow
import os from 'os';
import {uniq, upperFirst, get, includes} from 'lodash';
import { version } from '../../package.json';
import { stateDirectoryPath } from './config';
import type { Environment } from '../common/types/environment.types';
import {
  DEVELOPMENT,
  LINUX,
  MAC_OS,
  MAINNET,
  OS_NAMES,
  PRODUCTION,
  STAGING,
  TEST,
  TESTNET,
  WINDOWS,
} from '../common/types/environment.types';

// environment variables
const CURRENT_NODE_ENV = process.env.NODE_ENV || DEVELOPMENT;
const NETWORK = process.env.NETWORK || DEVELOPMENT;
const isDev = CURRENT_NODE_ENV === DEVELOPMENT;
const isTest = CURRENT_NODE_ENV === TEST;
const isProduction = CURRENT_NODE_ENV === PRODUCTION;
const isMainnet = NETWORK === MAINNET;
const isStaging = NETWORK === STAGING;
const isTestnet = NETWORK === TESTNET;
const isDevelopment = NETWORK === DEVELOPMENT;
const isWatchMode = process.env.IS_WATCH_MODE;
const API_VERSION = process.env.API_VERSION || 'dev';
const mainProcessID = get(process, 'ppid', '-');
const rendererProcessID = process.pid;
const PLATFORM = os.platform();
const PLATFORM_VERSION = os.release();
const OS = OS_NAMES[PLATFORM] || PLATFORM;
const cpu = os.cpus();
const ram = os.totalmem();
const isInSafeMode = includes(process.argv.slice(1), '--safe-mode');
const BUILD = process.env.BUILD_NUMBER || 'dev';
const BUILD_NUMBER = uniq([API_VERSION, BUILD]).join('.');
const BUILD_LABEL = (() => {
  const networkLabel = !(isMainnet || isDev) ? ` ${upperFirst(NETWORK)}` : '';
  let buildLabel = `Daedalus${networkLabel} (${version}#${BUILD_NUMBER})`;
  if (!isProduction) buildLabel += ` ${CURRENT_NODE_ENV}`;
  return buildLabel;
})();
const INSTALLER_VERSION = uniq([API_VERSION, BUILD]).join('.');
const MOBX_DEV_TOOLS = process.env.MOBX_DEV_TOOLS || false;
const isMacOS = PLATFORM === MAC_OS;
const isWindows = PLATFORM === WINDOWS;
const isLinux = PLATFORM === LINUX;

// compose environment
export const environment: Environment = Object.assign(
  {},
  {
    network: NETWORK,
    apiVersion: API_VERSION,
    mobxDevTools: MOBX_DEV_TOOLS,
    current: CURRENT_NODE_ENV,
    isDev,
    isTest,
    isProduction,
    isMainnet,
    isStaging,
    isTestnet,
    isDevelopment,
    isWatchMode,
    build: BUILD,
    buildNumber: BUILD_NUMBER,
    buildLabel: BUILD_LABEL,
    platform: PLATFORM,
    platformVersion: PLATFORM_VERSION,
    mainProcessID,
    rendererProcessID,
    os: OS,
    cpu,
    ram,
    installerVersion: INSTALLER_VERSION,
    version,
    isWindows,
    isMacOS,
    isLinux,
    stateDirectoryPath,
    isInSafeMode,
  },
  process.env
);
<commit_msg>[DDW-611] Implement new Network status dialog design - Windows fixes<commit_after>// @flow
import os from 'os';
import { uniq, upperFirst, get, includes } from 'lodash';
import { version } from '../../package.json';
import { stateDirectoryPath } from './config';
import type { Environment } from '../common/types/environment.types';
import {
  DEVELOPMENT,
  LINUX,
  MAC_OS,
  MAINNET,
  OS_NAMES,
  PRODUCTION,
  STAGING,
  TEST,
  TESTNET,
  WINDOWS,
} from '../common/types/environment.types';

// environment variables
const CURRENT_NODE_ENV = process.env.NODE_ENV || DEVELOPMENT;
const NETWORK = process.env.NETWORK || DEVELOPMENT;
const isDev = CURRENT_NODE_ENV === DEVELOPMENT;
const isTest = CURRENT_NODE_ENV === TEST;
const isProduction = CURRENT_NODE_ENV === PRODUCTION;
const isMainnet = NETWORK === MAINNET;
const isStaging = NETWORK === STAGING;
const isTestnet = NETWORK === TESTNET;
const isDevelopment = NETWORK === DEVELOPMENT;
const isWatchMode = process.env.IS_WATCH_MODE;
const API_VERSION = process.env.API_VERSION || 'dev';
const mainProcessID = get(process, 'ppid', '-');
const rendererProcessID = process.pid;
const PLATFORM = os.platform();
const PLATFORM_VERSION = os.release();
const OS = OS_NAMES[PLATFORM] || PLATFORM;
const cpu = os.cpus();
const ram = os.totalmem();
const isInSafeMode = includes(process.argv.slice(1), '--safe-mode');
const BUILD = process.env.BUILD_NUMBER || 'dev';
const BUILD_NUMBER = uniq([API_VERSION, BUILD]).join('.');
const BUILD_LABEL = (() => {
  const networkLabel = !(isMainnet || isDev) ? ` ${upperFirst(NETWORK)}` : '';
  let buildLabel = `Daedalus${networkLabel} (${version}#${BUILD_NUMBER})`;
  if (!isProduction) buildLabel += ` ${CURRENT_NODE_ENV}`;
  return buildLabel;
})();
const INSTALLER_VERSION = uniq([API_VERSION, BUILD]).join('.');
const MOBX_DEV_TOOLS = process.env.MOBX_DEV_TOOLS || false;
const isMacOS = PLATFORM === MAC_OS;
const isWindows = PLATFORM === WINDOWS;
const isLinux = PLATFORM === LINUX;

// compose environment
export const environment: Environment = Object.assign(
  {},
  {
    network: NETWORK,
    apiVersion: API_VERSION,
    mobxDevTools: MOBX_DEV_TOOLS,
    current: CURRENT_NODE_ENV,
    isDev,
    isTest,
    isProduction,
    isMainnet,
    isStaging,
    isTestnet,
    isDevelopment,
    isWatchMode,
    build: BUILD,
    buildNumber: BUILD_NUMBER,
    buildLabel: BUILD_LABEL,
    platform: PLATFORM,
    platformVersion: PLATFORM_VERSION,
    mainProcessID,
    rendererProcessID,
    os: OS,
    cpu,
    ram,
    installerVersion: INSTALLER_VERSION,
    version,
    isWindows,
    isMacOS,
    isLinux,
    stateDirectoryPath,
    isInSafeMode,
  },
  process.env
);
<|endoftext|>


<commit_before>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

'use strict';

const gulp = require('gulp');
const filter = require('gulp-filter');
const es = require('event-stream');
const gulptslint = require('gulp-tslint');
const gulpeslint = require('gulp-eslint');
const tsfmt = require('typescript-formatter');
const tslint = require('tslint');
const VinylFile = require('vinyl');
const vfs = require('vinyl-fs');
const path = require('path');
const fs = require('fs');
const pall = require('p-all');

/**
 * Hygiene works by creating cascading subsets of all our files and
 * passing them through a sequence of checks. Here are the current subsets,
 * named according to the checks performed on them. Each subset contains
 * the following one, as described in mathematical notation:
 *
 * all ⊃ eol ⊇ indentation ⊃ copyright ⊃ typescript
 */

const all = [
	'*',
	'build/**/*',
	'extensions/**/*',
	'scripts/**/*',
	'src/**/*',
	'test/**/*',
	'!**/node_modules/**'
];

const indentationFilter = [
	'**',

	// except specific files
	'!ThirdPartyNotices.txt',
	'!LICENSE.txt',
	'!src/vs/nls.js',
	'!src/vs/css.js',
	'!src/vs/loader.js',
	'!src/vs/base/common/marked/marked.js',
	'!src/vs/base/common/winjs.base.js',
	'!src/vs/base/node/terminateProcess.sh',
	'!test/assert.js',

	// except specific folders
	'!test/smoke/out/**',
	'!extensions/vscode-api-tests/testWorkspace/**',
	'!extensions/vscode-api-tests/testWorkspace2/**',
	'!build/monaco/**',
	'!build/win32/**',

	// except multiple specific files
	'!**/package.json',
	'!**/yarn.lock',
	'!**/yarn-error.log',

	// except multiple specific folders
	'!**/octicons/**',
	'!**/fixtures/**',
	'!**/lib/**',
	'!extensions/**/out/**',
	'!extensions/**/snippets/**',
	'!extensions/**/syntaxes/**',
	'!extensions/**/themes/**',
	'!extensions/**/colorize-fixtures/**',

	// except specific file types
	'!src/vs/*/**/*.d.ts',
	'!src/typings/**/*.d.ts',
	'!extensions/**/*.d.ts',
	'!**/*.{svg,exe,png,bmp,scpt,bat,cmd,cur,ttf,woff,eot,md,ps1,template,yaml,yml,d.ts.recipe}',
	'!build/{lib,tslintRules}/**/*.js',
	'!build/**/*.sh',
	'!build/tfs/**/*.js',
	'!**/Dockerfile',
	'!extensions/markdown-language-features/media/*.js'
];

const copyrightFilter = [
	'**',
	'!**/*.desktop',
	'!**/*.json',
	'!**/*.html',
	'!**/*.template',
	'!**/*.md',
	'!**/*.bat',
	'!**/*.cmd',
	'!**/*.xml',
	'!**/*.sh',
	'!**/*.txt',
	'!**/*.xpm',
	'!**/*.opts',
	'!**/*.disabled',
	'!**/*.code-workspace',
	'!build/**/*.init',
	'!resources/linux/snap/snapcraft.yaml',
	'!resources/win32/bin/code.js',
	'!extensions/markdown-language-features/media/tomorrow.css',
	'!extensions/html-language-features/server/src/modes/typescript/*',
	'!extensions/*/server/bin/*'
];

const eslintFilter = [
	'src/**/*.js',
	'build/gulpfile.*.js',
	'!src/vs/loader.js',
	'!src/vs/css.js',
	'!src/vs/nls.js',
	'!src/vs/css.build.js',
	'!src/vs/nls.build.js',
	'!src/**/winjs.base.js',
	'!src/**/marked.js',
	'!**/test/**'
];

const tslintFilter = [
	'src/**/*.ts',
	'test/**/*.ts',
	'extensions/**/*.ts',
	'!**/fixtures/**',
	'!**/typings/**',
	'!**/node_modules/**',
	'!extensions/typescript/test/colorize-fixtures/**',
	'!extensions/vscode-api-tests/testWorkspace/**',
	'!extensions/vscode-api-tests/testWorkspace2/**',
	'!extensions/**/*.test.ts',
	'!extensions/html-language-features/server/lib/jquery.d.ts'
];

const copyrightHeaderLines = [
	'/*---------------------------------------------------------------------------------------------',
	' *  Copyright (c) Microsoft Corporation. All rights reserved.',
	' *  Licensed under the MIT License. See License.txt in the project root for license information.',
	' *--------------------------------------------------------------------------------------------*/'
];

gulp.task('eslint', () => {
	return vfs.src(all, { base: '.', follow: true, allowEmpty: true })
		.pipe(filter(eslintFilter))
		.pipe(gulpeslint('src/.eslintrc'))
		.pipe(gulpeslint.formatEach('compact'))
		.pipe(gulpeslint.failAfterError());
});

gulp.task('tslint', () => {
	const options = { emitError: true };

	return vfs.src(all, { base: '.', follow: true, allowEmpty: true })
		.pipe(filter(tslintFilter))
		.pipe(gulptslint.default({ rulesDirectory: 'build/lib/tslint' }))
		.pipe(gulptslint.default.report(options));
});

function hygiene(some) {
	let errorCount = 0;

	const indentation = es.through(function (file) {
		const lines = file.contents.toString('utf8').split(/\r\n|\r|\n/);
		file.__lines = lines;

		lines
			.forEach((line, i) => {
				if (/^\s*$/.test(line)) {
					// empty or whitespace lines are OK
				} else if (/^[\t]*[^\s]/.test(line)) {
					// good indent
				} else if (/^[\t]* \*/.test(line)) {
					// block comment using an extra space
				} else {
					console.error(file.relative + '(' + (i + 1) + ',1): Bad whitespace indentation');
					errorCount++;
				}
			});

		this.emit('data', file);
	});

	const copyrights = es.through(function (file) {
		const lines = file.__lines;

		for (let i = 0; i < copyrightHeaderLines.length; i++) {
			if (lines[i] !== copyrightHeaderLines[i]) {
				console.error(file.relative + ': Missing or bad copyright statement');
				errorCount++;
				break;
			}
		}

		this.emit('data', file);
	});

	const formatting = es.map(function (file, cb) {
		tsfmt.processString(file.path, file.contents.toString('utf8'), {
			verify: false,
			tsfmt: true,
			// verbose: true
			// keep checkJS happy
			editorconfig: undefined,
			replace: undefined,
			tsconfig: undefined,
			tslint: undefined
		}).then(result => {
			let original = result.src.replace(/\r\n/gm, '\n');
			let formatted = result.dest.replace(/\r\n/gm, '\n');

			if (original !== formatted) {
				console.error('File not formatted:', file.relative);
				errorCount++;
			}
			cb(null, file);

		}, err => {
			cb(err);
		});
	});

	const tslintConfiguration = tslint.Configuration.findConfiguration('tslint.json', '.');
	const tslintOptions = { fix: false, formatter: 'json' };
	const tsLinter = new tslint.Linter(tslintOptions);

	const tsl = es.through(function (file) {
		const contents = file.contents.toString('utf8');
		tsLinter.lint(file.relative, contents, tslintConfiguration.results);
		this.emit('data', file);
	});

	let input;

	if (Array.isArray(some) || typeof some === 'string' || !some) {
		input = vfs.src(some || all, { base: '.', follow: true, allowEmpty: true });
	} else {
		input = some;
	}

	const result = input
		.pipe(filter(f => !f.stat.isDirectory()))
		.pipe(filter(indentationFilter))
		.pipe(indentation)
		.pipe(filter(copyrightFilter))
		.pipe(copyrights);

	const typescript = result
		.pipe(filter(tslintFilter))
		.pipe(formatting)
		.pipe(tsl);

	const javascript = result
		.pipe(filter(eslintFilter))
		.pipe(gulpeslint('src/.eslintrc'))
		.pipe(gulpeslint.formatEach('compact'))
		.pipe(gulpeslint.failAfterError());

	let count = 0;
	return es.merge(typescript, javascript)
		.pipe(es.through(function (data) {
			count++;
			if (process.env['TRAVIS'] && count % 10 === 0) {
				process.stdout.write('.');
			}
			this.emit('data', data);
		}, function () {
			process.stdout.write('\n');

			const tslintResult = tsLinter.getResult();
			if (tslintResult.failures.length > 0) {
				for (const failure of tslintResult.failures) {
					const name = failure.getFileName();
					const position = failure.getStartPosition();
					const line = position.getLineAndCharacter().line;
					const character = position.getLineAndCharacter().character;

					console.error(`${name}:${line + 1}:${character + 1}:${failure.getFailure()}`);
				}
				errorCount += tslintResult.failures.length;
			}

			if (errorCount > 0) {
				this.emit('error', 'Hygiene failed with ' + errorCount + ' errors. Check \'build/gulpfile.hygiene.js\'.');
			} else {
				this.emit('end');
			}
		}));
}

function createGitIndexVinyls(paths) {
	const cp = require('child_process');
	const repositoryPath = process.cwd();

	const fns = paths.map(relativePath => () => new Promise((c, e) => {
		const fullPath = path.join(repositoryPath, relativePath);

		fs.stat(fullPath, (err, stat) => {
			if (err && err.code === 'ENOENT') { // ignore deletions
				return c(null);
			} else if (err) {
				return e(err);
			}

			cp.exec(`git show :${relativePath}`, { maxBuffer: 2000 * 1024, encoding: 'buffer' }, (err, out) => {
				if (err) {
					return e(err);
				}

				c(new VinylFile({
					path: fullPath,
					base: repositoryPath,
					contents: out,
					stat
				}));
			});
		});
	}));

	return pall(fns, { concurrency: 4 })
		.then(r => r.filter(p => !!p));
}

gulp.task('hygiene', () => hygiene());

// this allows us to run hygiene as a git pre-commit hook
if (require.main === module) {
	const cp = require('child_process');

	process.on('unhandledRejection', (reason, p) => {
		console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
		process.exit(1);
	});

	if (process.argv.length > 2) {
		hygiene(process.argv.slice(2)).on('error', err => {
			console.error();
			console.error(err);
			process.exit(1);
		});
	} else {
		cp.exec('git diff --cached --name-only', { maxBuffer: 2000 * 1024 }, (err, out) => {
			if (err) {
				console.error();
				console.error(err);
				process.exit(1);
				return;
			}

			const some = out
				.split(/\r?\n/)
				.filter(l => !!l);

			if (some.length > 0) {
				console.log('Reading git index versions...');

				createGitIndexVinyls(some)
					.then(vinyls => new Promise((c, e) => hygiene(es.readArray(vinyls))
						.on('end', () => c())
						.on('error', e)))
					.catch(err => {
						console.error();
						console.error(err);
						process.exit(1);
					});
			}
		});
	}
}
<commit_msg>keep @ts-check happy<commit_after>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

'use strict';

const gulp = require('gulp');
const filter = require('gulp-filter');
const es = require('event-stream');
const gulptslint = require('gulp-tslint');
const gulpeslint = require('gulp-eslint');
const tsfmt = require('typescript-formatter');
const tslint = require('tslint');
const VinylFile = require('vinyl');
const vfs = require('vinyl-fs');
const path = require('path');
const fs = require('fs');
const pall = require('p-all');

/**
 * Hygiene works by creating cascading subsets of all our files and
 * passing them through a sequence of checks. Here are the current subsets,
 * named according to the checks performed on them. Each subset contains
 * the following one, as described in mathematical notation:
 *
 * all ⊃ eol ⊇ indentation ⊃ copyright ⊃ typescript
 */

const all = [
	'*',
	'build/**/*',
	'extensions/**/*',
	'scripts/**/*',
	'src/**/*',
	'test/**/*',
	'!**/node_modules/**'
];

const indentationFilter = [
	'**',

	// except specific files
	'!ThirdPartyNotices.txt',
	'!LICENSE.txt',
	'!src/vs/nls.js',
	'!src/vs/css.js',
	'!src/vs/loader.js',
	'!src/vs/base/common/marked/marked.js',
	'!src/vs/base/common/winjs.base.js',
	'!src/vs/base/node/terminateProcess.sh',
	'!test/assert.js',

	// except specific folders
	'!test/smoke/out/**',
	'!extensions/vscode-api-tests/testWorkspace/**',
	'!extensions/vscode-api-tests/testWorkspace2/**',
	'!build/monaco/**',
	'!build/win32/**',

	// except multiple specific files
	'!**/package.json',
	'!**/yarn.lock',
	'!**/yarn-error.log',

	// except multiple specific folders
	'!**/octicons/**',
	'!**/fixtures/**',
	'!**/lib/**',
	'!extensions/**/out/**',
	'!extensions/**/snippets/**',
	'!extensions/**/syntaxes/**',
	'!extensions/**/themes/**',
	'!extensions/**/colorize-fixtures/**',

	// except specific file types
	'!src/vs/*/**/*.d.ts',
	'!src/typings/**/*.d.ts',
	'!extensions/**/*.d.ts',
	'!**/*.{svg,exe,png,bmp,scpt,bat,cmd,cur,ttf,woff,eot,md,ps1,template,yaml,yml,d.ts.recipe}',
	'!build/{lib,tslintRules}/**/*.js',
	'!build/**/*.sh',
	'!build/tfs/**/*.js',
	'!**/Dockerfile',
	'!extensions/markdown-language-features/media/*.js'
];

const copyrightFilter = [
	'**',
	'!**/*.desktop',
	'!**/*.json',
	'!**/*.html',
	'!**/*.template',
	'!**/*.md',
	'!**/*.bat',
	'!**/*.cmd',
	'!**/*.xml',
	'!**/*.sh',
	'!**/*.txt',
	'!**/*.xpm',
	'!**/*.opts',
	'!**/*.disabled',
	'!**/*.code-workspace',
	'!build/**/*.init',
	'!resources/linux/snap/snapcraft.yaml',
	'!resources/win32/bin/code.js',
	'!extensions/markdown-language-features/media/tomorrow.css',
	'!extensions/html-language-features/server/src/modes/typescript/*',
	'!extensions/*/server/bin/*'
];

const eslintFilter = [
	'src/**/*.js',
	'build/gulpfile.*.js',
	'!src/vs/loader.js',
	'!src/vs/css.js',
	'!src/vs/nls.js',
	'!src/vs/css.build.js',
	'!src/vs/nls.build.js',
	'!src/**/winjs.base.js',
	'!src/**/marked.js',
	'!**/test/**'
];

const tslintFilter = [
	'src/**/*.ts',
	'test/**/*.ts',
	'extensions/**/*.ts',
	'!**/fixtures/**',
	'!**/typings/**',
	'!**/node_modules/**',
	'!extensions/typescript/test/colorize-fixtures/**',
	'!extensions/vscode-api-tests/testWorkspace/**',
	'!extensions/vscode-api-tests/testWorkspace2/**',
	'!extensions/**/*.test.ts',
	'!extensions/html-language-features/server/lib/jquery.d.ts'
];

const copyrightHeaderLines = [
	'/*---------------------------------------------------------------------------------------------',
	' *  Copyright (c) Microsoft Corporation. All rights reserved.',
	' *  Licensed under the MIT License. See License.txt in the project root for license information.',
	' *--------------------------------------------------------------------------------------------*/'
];

gulp.task('eslint', () => {
	return vfs.src(all, { base: '.', follow: true, allowEmpty: true })
		.pipe(filter(eslintFilter))
		.pipe(gulpeslint('src/.eslintrc'))
		.pipe(gulpeslint.formatEach('compact'))
		.pipe(gulpeslint.failAfterError());
});

gulp.task('tslint', () => {
	const options = { emitError: true };

	return vfs.src(all, { base: '.', follow: true, allowEmpty: true })
		.pipe(filter(tslintFilter))
		.pipe(gulptslint.default({ rulesDirectory: 'build/lib/tslint' }))
		.pipe(gulptslint.default.report(options));
});

function hygiene(some) {
	let errorCount = 0;

	const indentation = es.through(function (file) {
		const lines = file.contents.toString('utf8').split(/\r\n|\r|\n/);
		file.__lines = lines;

		lines
			.forEach((line, i) => {
				if (/^\s*$/.test(line)) {
					// empty or whitespace lines are OK
				} else if (/^[\t]*[^\s]/.test(line)) {
					// good indent
				} else if (/^[\t]* \*/.test(line)) {
					// block comment using an extra space
				} else {
					console.error(file.relative + '(' + (i + 1) + ',1): Bad whitespace indentation');
					errorCount++;
				}
			});

		this.emit('data', file);
	});

	const copyrights = es.through(function (file) {
		const lines = file.__lines;

		for (let i = 0; i < copyrightHeaderLines.length; i++) {
			if (lines[i] !== copyrightHeaderLines[i]) {
				console.error(file.relative + ': Missing or bad copyright statement');
				errorCount++;
				break;
			}
		}

		this.emit('data', file);
	});

	const formatting = es.map(function (file, cb) {
		tsfmt.processString(file.path, file.contents.toString('utf8'), {
			verify: false,
			tsfmt: true,
			// verbose: true,
			// keep checkJS happy
			editorconfig: undefined,
			replace: undefined,
			tsconfig: undefined,
			tsconfigFile: undefined,
			tslint: undefined,
			tslintFile: undefined,
			tsfmtFile: undefined,
			vscode: undefined,
			vscodeFile: undefined
		}).then(result => {
			let original = result.src.replace(/\r\n/gm, '\n');
			let formatted = result.dest.replace(/\r\n/gm, '\n');

			if (original !== formatted) {
				console.error('File not formatted:', file.relative);
				errorCount++;
			}
			cb(null, file);

		}, err => {
			cb(err);
		});
	});

	const tslintConfiguration = tslint.Configuration.findConfiguration('tslint.json', '.');
	const tslintOptions = { fix: false, formatter: 'json' };
	const tsLinter = new tslint.Linter(tslintOptions);

	const tsl = es.through(function (file) {
		const contents = file.contents.toString('utf8');
		tsLinter.lint(file.relative, contents, tslintConfiguration.results);
		this.emit('data', file);
	});

	let input;

	if (Array.isArray(some) || typeof some === 'string' || !some) {
		input = vfs.src(some || all, { base: '.', follow: true, allowEmpty: true });
	} else {
		input = some;
	}

	const result = input
		.pipe(filter(f => !f.stat.isDirectory()))
		.pipe(filter(indentationFilter))
		.pipe(indentation)
		.pipe(filter(copyrightFilter))
		.pipe(copyrights);

	const typescript = result
		.pipe(filter(tslintFilter))
		.pipe(formatting)
		.pipe(tsl);

	const javascript = result
		.pipe(filter(eslintFilter))
		.pipe(gulpeslint('src/.eslintrc'))
		.pipe(gulpeslint.formatEach('compact'))
		.pipe(gulpeslint.failAfterError());

	let count = 0;
	return es.merge(typescript, javascript)
		.pipe(es.through(function (data) {
			count++;
			if (process.env['TRAVIS'] && count % 10 === 0) {
				process.stdout.write('.');
			}
			this.emit('data', data);
		}, function () {
			process.stdout.write('\n');

			const tslintResult = tsLinter.getResult();
			if (tslintResult.failures.length > 0) {
				for (const failure of tslintResult.failures) {
					const name = failure.getFileName();
					const position = failure.getStartPosition();
					const line = position.getLineAndCharacter().line;
					const character = position.getLineAndCharacter().character;

					console.error(`${name}:${line + 1}:${character + 1}:${failure.getFailure()}`);
				}
				errorCount += tslintResult.failures.length;
			}

			if (errorCount > 0) {
				this.emit('error', 'Hygiene failed with ' + errorCount + ' errors. Check \'build/gulpfile.hygiene.js\'.');
			} else {
				this.emit('end');
			}
		}));
}

function createGitIndexVinyls(paths) {
	const cp = require('child_process');
	const repositoryPath = process.cwd();

	const fns = paths.map(relativePath => () => new Promise((c, e) => {
		const fullPath = path.join(repositoryPath, relativePath);

		fs.stat(fullPath, (err, stat) => {
			if (err && err.code === 'ENOENT') { // ignore deletions
				return c(null);
			} else if (err) {
				return e(err);
			}

			cp.exec(`git show :${relativePath}`, { maxBuffer: 2000 * 1024, encoding: 'buffer' }, (err, out) => {
				if (err) {
					return e(err);
				}

				c(new VinylFile({
					path: fullPath,
					base: repositoryPath,
					contents: out,
					stat
				}));
			});
		});
	}));

	return pall(fns, { concurrency: 4 })
		.then(r => r.filter(p => !!p));
}

gulp.task('hygiene', () => hygiene());

// this allows us to run hygiene as a git pre-commit hook
if (require.main === module) {
	const cp = require('child_process');

	process.on('unhandledRejection', (reason, p) => {
		console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
		process.exit(1);
	});

	if (process.argv.length > 2) {
		hygiene(process.argv.slice(2)).on('error', err => {
			console.error();
			console.error(err);
			process.exit(1);
		});
	} else {
		cp.exec('git diff --cached --name-only', { maxBuffer: 2000 * 1024 }, (err, out) => {
			if (err) {
				console.error();
				console.error(err);
				process.exit(1);
				return;
			}

			const some = out
				.split(/\r?\n/)
				.filter(l => !!l);

			if (some.length > 0) {
				console.log('Reading git index versions...');

				createGitIndexVinyls(some)
					.then(vinyls => new Promise((c, e) => hygiene(es.readArray(vinyls))
						.on('end', () => c())
						.on('error', e)))
					.catch(err => {
						console.error();
						console.error(err);
						process.exit(1);
					});
			}
		});
	}
}
<|endoftext|>


<commit_before>import axios from 'axios';
import { CLEAR_AUTH, SET_AUTH_JWT_FULFILLED } from '../reducers/login';

export function setUserAuthCredentials(user) {
  return {
    type: SET_AUTH_JWT_FULFILLED,
    payload: user
  };
}

export function clearAuthCredentials() {
  return {
    type: CLEAR_AUTH
  };
}

export function loginUser(loginInfo, history) {
  const { email, password } = loginInfo;

  return dispatch => axios.post('/authenticate', {
    email,
    password
  })
  .then((res) => {
    const { token, id } = res.data;
    localStorage.setItem('auth_token', token);
    dispatch(setUserAuthCredentials({ id }));
    history.push('/');
  })
  .catch((err) => {
    const customError = {
      message: `error fetching user info in account_info action fetchUserInfo: ${err}`,
      name: 'user info post request from account_info component'
    };
    throw customError;
  })
}

export function logoutUser(userInfo, history) {
  return dispatch => axios.get('/logout')
  .then(() => {
    localStorage.removeItem('auth_token');
    history.push('/login');
  })
  .catch((err) => {
    const customError = {
      message: `error with user logout: ${err}`,
      name: 'logoutUser function error'
    };
    throw customError;
  });
}

export function authTransition(storeInstance) {
  const { auth } = storeInstance.getState();
  const { id } = auth;
  const token = localStorage.getItem('auth_token');
  return !!id && !!token;
}
// export function userValidation(cb) {
//   return dispatch => axios.get('/session',
//     {
//       headers: {'Authoization': 'JWT' + localStorage.getItem('auth_token')}
//     })
//   .then((res) => {
//     const { id } = res.data;
//     return dispatch(setUserAuthCredentials({ id: id }));
//   })
//   .then(() => {
//     cb();
//   })
//   .catch((err) => {
//     const customError = {
//       message: `error with user validation: ${err}`,
//       name: 'function userValidation'
//     };
//     throw customError;
//     cb();
//   });
// }

<commit_msg>removed unneccessary action for /session route<commit_after>import axios from 'axios';
import { CLEAR_AUTH, SET_AUTH_JWT_FULFILLED } from '../reducers/login';

export function setUserAuthCredentials(user) {
  return {
    type: SET_AUTH_JWT_FULFILLED,
    payload: user
  };
}

export function clearAuthCredentials() {
  return {
    type: CLEAR_AUTH
  };
}

export function loginUser(loginInfo, history) {
  const { email, password } = loginInfo;

  return dispatch => axios.post('/authenticate', {
    email,
    password
  })
  .then((res) => {
    const { token, id } = res.data;
    localStorage.setItem('auth_token', token);
    dispatch(setUserAuthCredentials({ id }));
    history.push('/');
  })
  .catch((err) => {
    const customError = {
      message: `error fetching user info in account_info action fetchUserInfo: ${err}`,
      name: 'user info post request from account_info component'
    };
    throw customError;
  });
}

export function logoutUser(userInfo, history) {
  return dispatch => axios.get('/logout')
  .then(() => {
    localStorage.removeItem('auth_token');
    history.push('/login');
  })
  .catch((err) => {
    const customError = {
      message: `error with user logout: ${err}`,
      name: 'logoutUser function error'
    };
    throw customError;
  });
}

export function authTransition(storeInstance) {
  const { auth } = storeInstance.getState();
  const { id } = auth;
  const token = localStorage.getItem('auth_token');
  return !!id && !!token;
}

<|endoftext|>


<commit_before>/**
 * Created by sun yi on 2016/7/15.
 */

var mergeHtmlAndCss = function( css, html) {
    return '<style>' + css + '</style>' + html;
};

module.exports = Backbone.Router.extend({    //创建路由

    routes: {
        "": "indexAction",
        "teams": "getTeamsAction",
        "teams/:country": "getTeamsCountryAction",
        "teams/:country/:name": "getTeamAction",
        "error": "fourOfOurAction"
    },

    indexAction: function() {

        //html,css
        var module1Page =  require('../views/part1/module1.html'),
            module1Css = require('../less/index/module1.less'),
            merge = mergeHtmlAndCss(module1Css, module1Page);
        $('body').addClass('animated fadeIn').html( merge );

        //js
        var module1 = require('../js/index/module1.js');
        module1.onLoad();

    },

    getTeamsAction: function() {
        var module2 = require('../views/part1/module2.html');
        $('body').addClass('animated fadeIn').html( module2 );
    },

    getTeamsCountryAction: function(a, b, c) {    console.log('a:', a, ',b:', b, ',c:', c);
        console.log('i will get all countries!');
    },

    getTeamAction: function(a, b, c) {    console.log('a:', a, ',b:', b, ',c:', c);
        console.log('get team!');
    },

    fourOfOurAction: function() {    console.log( 'error' );
        //404 page
    }

});<commit_msg>xiugai<commit_after>/**
 * Created by sun yi on 2016/7/15.
 */

var mergeHtmlAndCss = function( css, html) {
    return '<style>' + css + '</style>' + html;
};

module.exports = Backbone.Router.extend({    //创建路由

    routes: {
        "": "indexAction",
        "teams": "getTeamsAction",
        "teams/:country": "getTeamsCountryAction",
        "teams/:country/:name": "getTeamAction",
        "error": "fourOfOurAction"
    },

    indexAction: function() {

        //html,css
        var module1Page =  require('../views/part1/module1.html'),
            module1Css = require('../less/index/module1.less'),
            merge = mergeHtmlAndCss(module1Css, module1Page);
        $('body').addClass('animated fadeIn').html( merge );

        //js
        var module1 = require('../js/index/module1.js');
        module1.onLoad();

    },

    getTeamsAction: function() {
        console.log('dsff');
        var module2 = require('../views/part1/module2.html');
        $('body').addClass('animated fadeIn').html( module2 );
    },

    getTeamsCountryAction: function(a, b, c) {    console.log('a:', a, ',b:', b, ',c:', c);
        console.log('i will get all countries!');
    },

    getTeamAction: function(a, b, c) {    console.log('a:', a, ',b:', b, ',c:', c);
        console.log('get team!');
    },

    fourOfOurAction: function() {    console.log( 'error' );
        //404 page
    }

});<|endoftext|>


<commit_before><commit_msg>add seeds clear test<commit_after>import { expect } from 'chai';

import User from '../../../src/models/user.model';
import Post from '../../../src/models/post.model';
import UserFactory from '../../../__mocks__/factories/user.factory';
import PostFactory from '../../../__mocks__/factories/post.factory';
import server from '../../../__mocks__/utils/server.mock';

const ENDPOINT = '/api/seeds/clear';

describe(`GET ${ENDPOINT}`, () => {
  beforeEach(async () => {
    await User.remove();
    await Post.remove();
    const testUser = await User.create(UserFactory.generate());
    await Post.create(PostFactory.generate({ author: testUser._id }));
  });

  describe('Delete with status 200', () => {
    it('should delete all collections', done => {
      server.get(ENDPOINT).end((err, res) => {
        const { text, status } = res;
        expect(status).to.equal(200);
        expect(text).to.equal('All collections clear');
        done();
      });
    });
  });
});
<|endoftext|>


<commit_before>frappe.listview_settings['Task'] = {
	add_fields: ["project", "status", "priority", "exp_start_date",
		"exp_end_date", "subject", "progress", "depends_on_tasks"],
	filters: [["status", "=", "Open"]],
	onload: function(listview) {
		var method = "erpnext.projects.doctype.task.task.set_multiple_status";

		listview.page.add_menu_item(__("Set as Open"), function() {
			listview.call_for_selected_items(method, {"status": "Open"});
		});

		listview.page.add_menu_item(__("Set as Closed"), function() {
			listview.call_for_selected_items(method, {"status": "Completed"});
		});
	},
	get_indicator: function(doc) {
		var colors = {
			"Open": "orange",
			"Overdue": "red",
			"Pending Review": "orange",
			"Working": "orange",
			"Completed": "green",
			"Cancelled": "dark grey"
		}
		return [__(doc.status), colors[doc.status], "status,=," + doc.status];
	},
	gantt_custom_popup_html: function(ganttobj, task) {
		var html = `
 ${ganttobj.name}
`;

		if(task.project) html += `<p>Project: ${task.project}</p>`;
		html += `<p>Progress: ${ganttobj.progress}</p>`;

		if(task._assign_list) {
			html += task._assign_list.reduce(
				(html, user) => html + frappe.avatar(user)
			, '');
		}

		return html;
	}

};
<commit_msg>fix(minor): update task list label from Closed to Completed<commit_after>frappe.listview_settings['Task'] = {
	add_fields: ["project", "status", "priority", "exp_start_date",
		"exp_end_date", "subject", "progress", "depends_on_tasks"],
	filters: [["status", "=", "Open"]],
	onload: function(listview) {
		var method = "erpnext.projects.doctype.task.task.set_multiple_status";

		listview.page.add_menu_item(__("Set as Open"), function() {
			listview.call_for_selected_items(method, {"status": "Open"});
		});

		listview.page.add_menu_item(__("Set as Completed"), function() {
			listview.call_for_selected_items(method, {"status": "Completed"});
		});
	},
	get_indicator: function(doc) {
		var colors = {
			"Open": "orange",
			"Overdue": "red",
			"Pending Review": "orange",
			"Working": "orange",
			"Completed": "green",
			"Cancelled": "dark grey"
		}
		return [__(doc.status), colors[doc.status], "status,=," + doc.status];
	},
	gantt_custom_popup_html: function(ganttobj, task) {
		var html = `
 ${ganttobj.name}
`;

		if(task.project) html += `<p>Project: ${task.project}</p>`;
		html += `<p>Progress: ${ganttobj.progress}</p>`;

		if(task._assign_list) {
			html += task._assign_list.reduce(
				(html, user) => html + frappe.avatar(user)
			, '');
		}

		return html;
	}

};
<|endoftext|>