<commit_before>'use strict';

/**
 * Refreshes the session if expired and provides user roles.
 */

const co = require('co');

const api = requireLocal('services/api-proxy');
const passport = requireLocal('services/auth');

let ses = {};

/**
 * Refreshes the session if it is expired.
 * @param req
 */
ses.refreshSession = (req) => co(function*() {
  req.login(yield passport.createSession(req.user.email, req.user), (error) => {
    if (error) throw error;
  });
}).catch(ex => {
  throw ex;
});

/**
 * Middleware to ensure the user is properly authenticated, tells the user what went wrong.
 * @param failURL
 * @param role
 * @param auth
 */
ses.generalAuth = (failURL, role, auth) => (req, res, next) => {
  if (req.isAuthenticated() && auth(req.user.status)) {
    return next();
  } else {
    console.log(req.url);
    req.flash(`error`, `Um diese Seite aufzurufen, musst Du ${role} sein.`);
    req.flash(`url`, req.url);
    res.redirect(failURL);
  }
};

ses.isUser = ses.generalAuth('/login', 'eingeloggt', (status) => status.is.user);
ses.isParticipant = ses.generalAuth('/selection', 'ein Teilnehmer', (status) => status.is.participant);
ses.isSponsor = ses.generalAuth('/selection', 'ein Sponsor', (status) => status.is.sponsor);
ses.hasTeam = ses.generalAuth('/team-invite', 'Teil eines Teams', (status) => status.is.team);
ses.isAdmin = ses.generalAuth('/login', 'Administrator', (status) => status.is.admin);

module.exports = ses;
<commit_msg>fixes error when redirecting after login<commit_after>'use strict';

/**
 * Refreshes the session if expired and provides user roles.
 */

const co = require('co');

const api = requireLocal('services/api-proxy');
const passport = requireLocal('services/auth');

let ses = {};

/**
 * Refreshes the session if it is expired.
 * @param req
 */
ses.refreshSession = (req) => co(function*() {
  req.login(yield passport.createSession(req.user.email, req.user), (error) => {
    if (error) throw error;
  });
}).catch(ex => {
  throw ex;
});

/**
 * Middleware to ensure the user is properly authenticated, tells the user what went wrong.
 * @param failURL
 * @param role
 * @param auth
 */
ses.generalAuth = (failURL, role, auth) => (req, res, next) => {
  if (req.isAuthenticated() && auth(req.user.status)) {
    return next();
  } else {
    req.flash(`error`, `Um diese Seite aufzurufen, musst Du ${role} sein.`);
    req.flash(`url`, req.originalUrl);
    res.redirect(failURL);
  }
};

ses.isUser = ses.generalAuth('/login', 'eingeloggt', (status) => status.is.user);
ses.isParticipant = ses.generalAuth('/selection', 'ein Teilnehmer', (status) => status.is.participant);
ses.isSponsor = ses.generalAuth('/selection', 'ein Sponsor', (status) => status.is.sponsor);
ses.hasTeam = ses.generalAuth('/team-invite', 'Teil eines Teams', (status) => status.is.team);
ses.isAdmin = ses.generalAuth('/login', 'Administrator', (status) => status.is.admin);

module.exports = ses;
<|endoftext|>


<commit_before>/*
The canvas renderer was written by Yue Dong.

Modifications tracked on Github.
*/

/* global OffscreenCanvas */

import * as util from '../../../util';
import * as is from '../../../is';
import { makeBoundingBox } from '../../../math';
import ElementTextureCache from './ele-texture-cache';
import LayeredTextureCache from './layered-texture-cache';

import arrowShapes from './arrow-shapes';
import drawingElements from './drawing-elements';
import drawingEdges from './drawing-edges';
import drawingImages from './drawing-images';
import drawingLabelText from './drawing-label-text';
import drawingNodes from './drawing-nodes';
import drawingRedraw from './drawing-redraw';
import drawingShapes from './drawing-shapes';
import exportImage from './export-image';
import nodeShapes from './node-shapes';

var CR = CanvasRenderer;
var CRp = CanvasRenderer.prototype;

CRp.CANVAS_LAYERS = 3;
//
CRp.SELECT_BOX = 0;
CRp.DRAG = 1;
CRp.NODE = 2;

CRp.BUFFER_COUNT = 3;
//
CRp.TEXTURE_BUFFER = 0;
CRp.MOTIONBLUR_BUFFER_NODE = 1;
CRp.MOTIONBLUR_BUFFER_DRAG = 2;

function CanvasRenderer( options ){
  var r = this;

  r.data = {
    canvases: new Array( CRp.CANVAS_LAYERS ),
    contexts: new Array( CRp.CANVAS_LAYERS ),
    canvasNeedsRedraw: new Array( CRp.CANVAS_LAYERS ),

    bufferCanvases: new Array( CRp.BUFFER_COUNT ),
    bufferContexts: new Array( CRp.CANVAS_LAYERS ),
  };

  var tapHlOff = '-webkit-tap-highlight-color: rgba(0,0,0,0);';
  var tapHlOffAttr = '-webkit-tap-highlight-color';
  var tapHlOffStyle = 'rgba(0,0,0,0)';
  r.data.canvasContainer = document.createElement( 'div' ); // eslint-disable-line no-undef
  var containerStyle = r.data.canvasContainer.style;
  r.data.canvasContainer.style[tapHlOffAttr] = tapHlOffStyle;
  containerStyle.position = 'relative';
  containerStyle.zIndex = '0';
  containerStyle.overflow = 'hidden';

  var container = options.cy.container();
  container.appendChild( r.data.canvasContainer );

  if( (container.getAttribute('style') || '').indexOf(tapHlOff) < 0 ){
    container.style[tapHlOffAttr] = tapHlOffStyle;
  }

  var styleMap = {
    '-webkit-user-select': 'none',
    '-moz-user-select': '-moz-none',
    'user-select': 'none',
    '-webkit-tap-highlight-color': 'rgba(0,0,0,0)',
    'outline-style': 'none',
  };

  if(is.ms()) {
    styleMap['-ms-touch-action'] = 'none';
    styleMap['touch-action'] = 'none';
  }

  for( var i = 0; i < CRp.CANVAS_LAYERS; i++ ){
    var canvas = r.data.canvases[ i ] = document.createElement( 'canvas' );  // eslint-disable-line no-undef
    r.data.contexts[ i ] = canvas.getContext( '2d' );
    for(const [k,v] of Object.entries(styleMap)) {
      canvas.style[k] = v;
    }
    canvas.style.position = 'absolute';
    canvas.setAttribute( 'data-id', 'layer' + i );
    canvas.style.zIndex = String( CRp.CANVAS_LAYERS - i );
    r.data.canvasContainer.appendChild( canvas );

    r.data.canvasNeedsRedraw[ i ] = false;
  }
  r.data.topCanvas = r.data.canvases[0];

  r.data.canvases[ CRp.NODE ].setAttribute( 'data-id', 'layer' + CRp.NODE + '-node' );
  r.data.canvases[ CRp.SELECT_BOX ].setAttribute( 'data-id', 'layer' + CRp.SELECT_BOX + '-selectbox' );
  r.data.canvases[ CRp.DRAG ].setAttribute( 'data-id', 'layer' + CRp.DRAG + '-drag' );

  for( var i = 0; i < CRp.BUFFER_COUNT; i++ ){
    r.data.bufferCanvases[ i ] = document.createElement( 'canvas' );  // eslint-disable-line no-undef
    r.data.bufferContexts[ i ] = r.data.bufferCanvases[ i ].getContext( '2d' );
    r.data.bufferCanvases[ i ].style.position = 'absolute';
    r.data.bufferCanvases[ i ].setAttribute( 'data-id', 'buffer' + i );
    r.data.bufferCanvases[ i ].style.zIndex = String( -i - 1 );
    r.data.bufferCanvases[ i ].style.visibility = 'hidden';
    //r.data.canvasContainer.appendChild(r.data.bufferCanvases[i]);
  }

  r.pathsEnabled = true;

  let emptyBb = makeBoundingBox();

  let getBoxCenter = bb => ({ x: (bb.x1 + bb.x2)/2, y: (bb.y1 + bb.y2)/2 });

  let getCenterOffset = bb => ({ x: -bb.w/2, y: -bb.h/2 });

  let backgroundTimestampHasChanged = ele => {
    let _p = ele[0]._private;
    let same = _p.oldBackgroundTimestamp === _p.backgroundTimestamp;

    return !same;
  };

  let getStyleKey = ele => ele[0]._private.nodeKey;
  let getLabelKey = ele => ele[0]._private.labelStyleKey;
  let getSourceLabelKey = ele => ele[0]._private.sourceLabelStyleKey;
  let getTargetLabelKey = ele => ele[0]._private.targetLabelStyleKey;

  let drawElement = (context, ele, bb, scaledLabelShown, useEleOpacity) => r.drawElement( context, ele, bb, false, false, useEleOpacity );
  let drawLabel = (context, ele, bb, scaledLabelShown, useEleOpacity) => r.drawElementText( context, ele, bb, scaledLabelShown, 'main', useEleOpacity );
  let drawSourceLabel = (context, ele, bb, scaledLabelShown, useEleOpacity) => r.drawElementText( context, ele, bb, scaledLabelShown, 'source', useEleOpacity );
  let drawTargetLabel = (context, ele, bb, scaledLabelShown, useEleOpacity) => r.drawElementText( context, ele, bb, scaledLabelShown, 'target', useEleOpacity );

  let getElementBox = ele => { ele.boundingBox(); return ele[0]._private.bodyBounds; };
  let getLabelBox = ele => { ele.boundingBox(); return ele[0]._private.labelBounds.main || emptyBb; };
  let getSourceLabelBox = ele => { ele.boundingBox(); return ele[0]._private.labelBounds.source || emptyBb; };
  let getTargetLabelBox = ele => { ele.boundingBox(); return ele[0]._private.labelBounds.target || emptyBb; };

  let isLabelVisibleAtScale = (ele, scaledLabelShown) => scaledLabelShown;

  let getElementRotationPoint = ele => getBoxCenter( getElementBox(ele) );

  let addTextMargin = (pt, ele) => {
    return {
      x: pt.x + ele.pstyle('text-margin-x').pfValue,
      y: pt.y + ele.pstyle('text-margin-y').pfValue
    };
  };

  let getRsPt = (ele, x, y) => {
    let rs = ele[0]._private.rscratch;

    return { x: rs[x], y: rs[y] };
  };

  let getLabelRotationPoint = ele => addTextMargin(getRsPt(ele, 'labelX', 'labelY'), ele);
  let getSourceLabelRotationPoint = ele => addTextMargin(getRsPt(ele, 'sourceLabelX', 'sourceLabelY'), ele);
  let getTargetLabelRotationPoint = ele => addTextMargin(getRsPt(ele, 'targetLabelX', 'targetLabelY'), ele);

  let getElementRotationOffset = ele => getCenterOffset( getElementBox(ele) );
  let getSourceLabelRotationOffset = ele => getCenterOffset( getSourceLabelBox(ele) );
  let getTargetLabelRotationOffset = ele => getCenterOffset( getTargetLabelBox(ele) );

  let getLabelRotationOffset = ele => {
    let bb = getLabelBox(ele);
    let p = getCenterOffset( getLabelBox(ele) );

    if( ele.isNode() ){
      switch( ele.pstyle('text-halign').value ){
        case 'left':
          p.x = -bb.w;
          break;
        case 'right':
          p.x = 0;
          break;
      }

      switch( ele.pstyle('text-valign').value ){
        case 'top':
          p.y = -bb.h;
          break;
        case 'bottom':
          p.y = 0;
          break;
      }
    }

    return p;
  };

  let eleTxrCache = r.data.eleTxrCache = new ElementTextureCache( r, {
    getKey: getStyleKey,
    doesEleInvalidateKey: backgroundTimestampHasChanged,
    drawElement: drawElement,
    getBoundingBox: getElementBox,
    getRotationPoint: getElementRotationPoint,
    getRotationOffset: getElementRotationOffset,
    allowEdgeTxrCaching: false,
    allowParentTxrCaching: false
  } );

  let lblTxrCache = r.data.lblTxrCache = new ElementTextureCache( r, {
    getKey: getLabelKey,
    drawElement: drawLabel,
    getBoundingBox: getLabelBox,
    getRotationPoint: getLabelRotationPoint,
    getRotationOffset: getLabelRotationOffset,
    isVisible: isLabelVisibleAtScale
  } );

  let slbTxrCache = r.data.slbTxrCache = new ElementTextureCache( r, {
    getKey: getSourceLabelKey,
    drawElement: drawSourceLabel,
    getBoundingBox: getSourceLabelBox,
    getRotationPoint: getSourceLabelRotationPoint,
    getRotationOffset: getSourceLabelRotationOffset,
    isVisible: isLabelVisibleAtScale
  } );

  let tlbTxrCache = r.data.tlbTxrCache = new ElementTextureCache( r, {
    getKey: getTargetLabelKey,
    drawElement: drawTargetLabel,
    getBoundingBox: getTargetLabelBox,
    getRotationPoint: getTargetLabelRotationPoint,
    getRotationOffset: getTargetLabelRotationOffset,
    isVisible: isLabelVisibleAtScale
  } );

  let lyrTxrCache = r.data.lyrTxrCache = new LayeredTextureCache( r );

  r.onUpdateEleCalcs(function invalidateTextureCaches( willDraw, eles ){
    // each cache should check for sub-key diff to see that the update affects that cache particularly
    eleTxrCache.invalidateElements( eles );
    lblTxrCache.invalidateElements( eles );
    slbTxrCache.invalidateElements( eles );
    tlbTxrCache.invalidateElements( eles );

    // any change invalidates the layers
    lyrTxrCache.invalidateElements( eles );

    // update the old bg timestamp so diffs can be done in the ele txr caches
    for( let i = 0; i < eles.length; i++ ){
      let _p = eles[i]._private;

      _p.oldBackgroundTimestamp = _p.backgroundTimestamp;
    }
  });

  let refineInLayers = reqs => {
    for( var i = 0; i < reqs.length; i++ ){
      lyrTxrCache.enqueueElementRefinement( reqs[i].ele );
    }
  };

  eleTxrCache.onDequeue(refineInLayers);
  lblTxrCache.onDequeue(refineInLayers);
  slbTxrCache.onDequeue(refineInLayers);
  tlbTxrCache.onDequeue(refineInLayers);
}

CRp.redrawHint = function( group, bool ){
  var r = this;

  switch( group ){
    case 'eles':
      r.data.canvasNeedsRedraw[ CRp.NODE ] = bool;
      break;
    case 'drag':
      r.data.canvasNeedsRedraw[ CRp.DRAG ] = bool;
      break;
    case 'select':
      r.data.canvasNeedsRedraw[ CRp.SELECT_BOX ] = bool;
      break;
  }
};

// whether to use Path2D caching for drawing
var pathsImpld = typeof Path2D !== 'undefined';

CRp.path2dEnabled = function( on ){
  if( on === undefined ){
    return this.pathsEnabled;
  }

  this.pathsEnabled = on ? true : false;
};

CRp.usePaths = function(){
  return pathsImpld && this.pathsEnabled;
};

CRp.setImgSmoothing = function( context, bool ){
  if( context.imageSmoothingEnabled != null ){
    context.imageSmoothingEnabled = bool;
  } else {
    context.webkitImageSmoothingEnabled = bool;
    context.mozImageSmoothingEnabled = bool;
    context.msImageSmoothingEnabled = bool;
  }
};

CRp.getImgSmoothing = function( context ){
  if( context.imageSmoothingEnabled != null ){
    return context.imageSmoothingEnabled;
  } else {
    return context.webkitImageSmoothingEnabled || context.mozImageSmoothingEnabled || context.msImageSmoothingEnabled;
  }
};

CRp.makeOffscreenCanvas = function(width, height){
  let canvas;

  if( typeof OffscreenCanvas !== typeof undefined ){
    canvas = new OffscreenCanvas(width, height);
  } else {
    canvas = document.createElement('canvas'); // eslint-disable-line no-undef
    canvas.width = width;
    canvas.height = height;
  }

  return canvas;
};

[
  arrowShapes,
  drawingElements,
  drawingEdges,
  drawingImages,
  drawingLabelText,
  drawingNodes,
  drawingRedraw,
  drawingShapes,
  exportImage,
  nodeShapes
].forEach( function( props ){
  util.extend( CRp, props );
} );

export default CR;
<commit_msg>remove unnecessary check<commit_after>/*
The canvas renderer was written by Yue Dong.

Modifications tracked on Github.
*/

/* global OffscreenCanvas */

import * as util from '../../../util';
import * as is from '../../../is';
import { makeBoundingBox } from '../../../math';
import ElementTextureCache from './ele-texture-cache';
import LayeredTextureCache from './layered-texture-cache';

import arrowShapes from './arrow-shapes';
import drawingElements from './drawing-elements';
import drawingEdges from './drawing-edges';
import drawingImages from './drawing-images';
import drawingLabelText from './drawing-label-text';
import drawingNodes from './drawing-nodes';
import drawingRedraw from './drawing-redraw';
import drawingShapes from './drawing-shapes';
import exportImage from './export-image';
import nodeShapes from './node-shapes';

var CR = CanvasRenderer;
var CRp = CanvasRenderer.prototype;

CRp.CANVAS_LAYERS = 3;
//
CRp.SELECT_BOX = 0;
CRp.DRAG = 1;
CRp.NODE = 2;

CRp.BUFFER_COUNT = 3;
//
CRp.TEXTURE_BUFFER = 0;
CRp.MOTIONBLUR_BUFFER_NODE = 1;
CRp.MOTIONBLUR_BUFFER_DRAG = 2;

function CanvasRenderer( options ){
  var r = this;

  r.data = {
    canvases: new Array( CRp.CANVAS_LAYERS ),
    contexts: new Array( CRp.CANVAS_LAYERS ),
    canvasNeedsRedraw: new Array( CRp.CANVAS_LAYERS ),

    bufferCanvases: new Array( CRp.BUFFER_COUNT ),
    bufferContexts: new Array( CRp.CANVAS_LAYERS ),
  };

  var tapHlOffAttr = '-webkit-tap-highlight-color';
  var tapHlOffStyle = 'rgba(0,0,0,0)';
  r.data.canvasContainer = document.createElement( 'div' ); // eslint-disable-line no-undef
  var containerStyle = r.data.canvasContainer.style;
  r.data.canvasContainer.style[tapHlOffAttr] = tapHlOffStyle;
  containerStyle.position = 'relative';
  containerStyle.zIndex = '0';
  containerStyle.overflow = 'hidden';

  var container = options.cy.container();
  container.appendChild( r.data.canvasContainer );
  container.style[tapHlOffAttr] = tapHlOffStyle;

  var styleMap = {
    '-webkit-user-select': 'none',
    '-moz-user-select': '-moz-none',
    'user-select': 'none',
    '-webkit-tap-highlight-color': 'rgba(0,0,0,0)',
    'outline-style': 'none',
  };

  if(is.ms()) {
    styleMap['-ms-touch-action'] = 'none';
    styleMap['touch-action'] = 'none';
  }

  for( var i = 0; i < CRp.CANVAS_LAYERS; i++ ){
    var canvas = r.data.canvases[ i ] = document.createElement( 'canvas' );  // eslint-disable-line no-undef
    r.data.contexts[ i ] = canvas.getContext( '2d' );
    for(const [k,v] of Object.entries(styleMap)) {
      canvas.style[k] = v;
    }
    canvas.style.position = 'absolute';
    canvas.setAttribute( 'data-id', 'layer' + i );
    canvas.style.zIndex = String( CRp.CANVAS_LAYERS - i );
    r.data.canvasContainer.appendChild( canvas );

    r.data.canvasNeedsRedraw[ i ] = false;
  }
  r.data.topCanvas = r.data.canvases[0];

  r.data.canvases[ CRp.NODE ].setAttribute( 'data-id', 'layer' + CRp.NODE + '-node' );
  r.data.canvases[ CRp.SELECT_BOX ].setAttribute( 'data-id', 'layer' + CRp.SELECT_BOX + '-selectbox' );
  r.data.canvases[ CRp.DRAG ].setAttribute( 'data-id', 'layer' + CRp.DRAG + '-drag' );

  for( var i = 0; i < CRp.BUFFER_COUNT; i++ ){
    r.data.bufferCanvases[ i ] = document.createElement( 'canvas' );  // eslint-disable-line no-undef
    r.data.bufferContexts[ i ] = r.data.bufferCanvases[ i ].getContext( '2d' );
    r.data.bufferCanvases[ i ].style.position = 'absolute';
    r.data.bufferCanvases[ i ].setAttribute( 'data-id', 'buffer' + i );
    r.data.bufferCanvases[ i ].style.zIndex = String( -i - 1 );
    r.data.bufferCanvases[ i ].style.visibility = 'hidden';
    //r.data.canvasContainer.appendChild(r.data.bufferCanvases[i]);
  }

  r.pathsEnabled = true;

  let emptyBb = makeBoundingBox();

  let getBoxCenter = bb => ({ x: (bb.x1 + bb.x2)/2, y: (bb.y1 + bb.y2)/2 });

  let getCenterOffset = bb => ({ x: -bb.w/2, y: -bb.h/2 });

  let backgroundTimestampHasChanged = ele => {
    let _p = ele[0]._private;
    let same = _p.oldBackgroundTimestamp === _p.backgroundTimestamp;

    return !same;
  };

  let getStyleKey = ele => ele[0]._private.nodeKey;
  let getLabelKey = ele => ele[0]._private.labelStyleKey;
  let getSourceLabelKey = ele => ele[0]._private.sourceLabelStyleKey;
  let getTargetLabelKey = ele => ele[0]._private.targetLabelStyleKey;

  let drawElement = (context, ele, bb, scaledLabelShown, useEleOpacity) => r.drawElement( context, ele, bb, false, false, useEleOpacity );
  let drawLabel = (context, ele, bb, scaledLabelShown, useEleOpacity) => r.drawElementText( context, ele, bb, scaledLabelShown, 'main', useEleOpacity );
  let drawSourceLabel = (context, ele, bb, scaledLabelShown, useEleOpacity) => r.drawElementText( context, ele, bb, scaledLabelShown, 'source', useEleOpacity );
  let drawTargetLabel = (context, ele, bb, scaledLabelShown, useEleOpacity) => r.drawElementText( context, ele, bb, scaledLabelShown, 'target', useEleOpacity );

  let getElementBox = ele => { ele.boundingBox(); return ele[0]._private.bodyBounds; };
  let getLabelBox = ele => { ele.boundingBox(); return ele[0]._private.labelBounds.main || emptyBb; };
  let getSourceLabelBox = ele => { ele.boundingBox(); return ele[0]._private.labelBounds.source || emptyBb; };
  let getTargetLabelBox = ele => { ele.boundingBox(); return ele[0]._private.labelBounds.target || emptyBb; };

  let isLabelVisibleAtScale = (ele, scaledLabelShown) => scaledLabelShown;

  let getElementRotationPoint = ele => getBoxCenter( getElementBox(ele) );

  let addTextMargin = (pt, ele) => {
    return {
      x: pt.x + ele.pstyle('text-margin-x').pfValue,
      y: pt.y + ele.pstyle('text-margin-y').pfValue
    };
  };

  let getRsPt = (ele, x, y) => {
    let rs = ele[0]._private.rscratch;

    return { x: rs[x], y: rs[y] };
  };

  let getLabelRotationPoint = ele => addTextMargin(getRsPt(ele, 'labelX', 'labelY'), ele);
  let getSourceLabelRotationPoint = ele => addTextMargin(getRsPt(ele, 'sourceLabelX', 'sourceLabelY'), ele);
  let getTargetLabelRotationPoint = ele => addTextMargin(getRsPt(ele, 'targetLabelX', 'targetLabelY'), ele);

  let getElementRotationOffset = ele => getCenterOffset( getElementBox(ele) );
  let getSourceLabelRotationOffset = ele => getCenterOffset( getSourceLabelBox(ele) );
  let getTargetLabelRotationOffset = ele => getCenterOffset( getTargetLabelBox(ele) );

  let getLabelRotationOffset = ele => {
    let bb = getLabelBox(ele);
    let p = getCenterOffset( getLabelBox(ele) );

    if( ele.isNode() ){
      switch( ele.pstyle('text-halign').value ){
        case 'left':
          p.x = -bb.w;
          break;
        case 'right':
          p.x = 0;
          break;
      }

      switch( ele.pstyle('text-valign').value ){
        case 'top':
          p.y = -bb.h;
          break;
        case 'bottom':
          p.y = 0;
          break;
      }
    }

    return p;
  };

  let eleTxrCache = r.data.eleTxrCache = new ElementTextureCache( r, {
    getKey: getStyleKey,
    doesEleInvalidateKey: backgroundTimestampHasChanged,
    drawElement: drawElement,
    getBoundingBox: getElementBox,
    getRotationPoint: getElementRotationPoint,
    getRotationOffset: getElementRotationOffset,
    allowEdgeTxrCaching: false,
    allowParentTxrCaching: false
  } );

  let lblTxrCache = r.data.lblTxrCache = new ElementTextureCache( r, {
    getKey: getLabelKey,
    drawElement: drawLabel,
    getBoundingBox: getLabelBox,
    getRotationPoint: getLabelRotationPoint,
    getRotationOffset: getLabelRotationOffset,
    isVisible: isLabelVisibleAtScale
  } );

  let slbTxrCache = r.data.slbTxrCache = new ElementTextureCache( r, {
    getKey: getSourceLabelKey,
    drawElement: drawSourceLabel,
    getBoundingBox: getSourceLabelBox,
    getRotationPoint: getSourceLabelRotationPoint,
    getRotationOffset: getSourceLabelRotationOffset,
    isVisible: isLabelVisibleAtScale
  } );

  let tlbTxrCache = r.data.tlbTxrCache = new ElementTextureCache( r, {
    getKey: getTargetLabelKey,
    drawElement: drawTargetLabel,
    getBoundingBox: getTargetLabelBox,
    getRotationPoint: getTargetLabelRotationPoint,
    getRotationOffset: getTargetLabelRotationOffset,
    isVisible: isLabelVisibleAtScale
  } );

  let lyrTxrCache = r.data.lyrTxrCache = new LayeredTextureCache( r );

  r.onUpdateEleCalcs(function invalidateTextureCaches( willDraw, eles ){
    // each cache should check for sub-key diff to see that the update affects that cache particularly
    eleTxrCache.invalidateElements( eles );
    lblTxrCache.invalidateElements( eles );
    slbTxrCache.invalidateElements( eles );
    tlbTxrCache.invalidateElements( eles );

    // any change invalidates the layers
    lyrTxrCache.invalidateElements( eles );

    // update the old bg timestamp so diffs can be done in the ele txr caches
    for( let i = 0; i < eles.length; i++ ){
      let _p = eles[i]._private;

      _p.oldBackgroundTimestamp = _p.backgroundTimestamp;
    }
  });

  let refineInLayers = reqs => {
    for( var i = 0; i < reqs.length; i++ ){
      lyrTxrCache.enqueueElementRefinement( reqs[i].ele );
    }
  };

  eleTxrCache.onDequeue(refineInLayers);
  lblTxrCache.onDequeue(refineInLayers);
  slbTxrCache.onDequeue(refineInLayers);
  tlbTxrCache.onDequeue(refineInLayers);
}

CRp.redrawHint = function( group, bool ){
  var r = this;

  switch( group ){
    case 'eles':
      r.data.canvasNeedsRedraw[ CRp.NODE ] = bool;
      break;
    case 'drag':
      r.data.canvasNeedsRedraw[ CRp.DRAG ] = bool;
      break;
    case 'select':
      r.data.canvasNeedsRedraw[ CRp.SELECT_BOX ] = bool;
      break;
  }
};

// whether to use Path2D caching for drawing
var pathsImpld = typeof Path2D !== 'undefined';

CRp.path2dEnabled = function( on ){
  if( on === undefined ){
    return this.pathsEnabled;
  }

  this.pathsEnabled = on ? true : false;
};

CRp.usePaths = function(){
  return pathsImpld && this.pathsEnabled;
};

CRp.setImgSmoothing = function( context, bool ){
  if( context.imageSmoothingEnabled != null ){
    context.imageSmoothingEnabled = bool;
  } else {
    context.webkitImageSmoothingEnabled = bool;
    context.mozImageSmoothingEnabled = bool;
    context.msImageSmoothingEnabled = bool;
  }
};

CRp.getImgSmoothing = function( context ){
  if( context.imageSmoothingEnabled != null ){
    return context.imageSmoothingEnabled;
  } else {
    return context.webkitImageSmoothingEnabled || context.mozImageSmoothingEnabled || context.msImageSmoothingEnabled;
  }
};

CRp.makeOffscreenCanvas = function(width, height){
  let canvas;

  if( typeof OffscreenCanvas !== typeof undefined ){
    canvas = new OffscreenCanvas(width, height);
  } else {
    canvas = document.createElement('canvas'); // eslint-disable-line no-undef
    canvas.width = width;
    canvas.height = height;
  }

  return canvas;
};

[
  arrowShapes,
  drawingElements,
  drawingEdges,
  drawingImages,
  drawingLabelText,
  drawingNodes,
  drawingRedraw,
  drawingShapes,
  exportImage,
  nodeShapes
].forEach( function( props ){
  util.extend( CRp, props );
} );

export default CR;
<|endoftext|>


<commit_before>define(function (require, exports, module) {

  const { around } = require('meld');
  const Events = require('plug/core/Events');
  const ChatView = require('plug/views/rooms/chat/ChatView');
  const util = require('plug/util/util');
  const settings = require('plug/store/settings');
  const Plugin = require('../Plugin');

  /**
   * The ChatType Plugin adds a "custom" chat type. Any chat messages
   * passed through the ChatView "onReceived" handler will be affected,
   * so in particular all "chat:receive" events are handled properly.
   *
   * A chat message with "custom" in its type property can take a few
   * additional options:
   *
   *  * the "badge" property can contain an emoji name (eg ":eyes:") or
   *    an icon class (eg "icon-plugdj") as well as the standard badge
   *    names.
   *  * the "color" property takes a CSS colour, which will be used for
   *    the message text.
   *  * the "timestamp" property always defaults to the current time if
   *    it is left empty.
   *
   * This is especially useful for showing notifications in chat.
   * The "type" property can be a list of CSS class names, if it contains
   * "custom", (eg `{ type: "custom inline my-notification" }`) so you
   * can use those classes to style your message as well. Note that you
   * cannot add additional classes for the other message types.
   */
  const ChatTypePlugin = Plugin.extend({
    enable() {
      // chatView.onReceived will still be the old method after adding advice
      // so the event listener should also be swapped out
      let chatView = this.ext.appView.room.chat;
      if (chatView) {
        Events.off('chat:receive', chatView.onReceived);
      }
      this._chatTypeAdvice = around(ChatView.prototype, 'onReceived', this.onReceived);
      if (chatView) {
        Events.on('chat:receive', chatView.onReceived, chatView);
      }
    },
    disable() {
      // remove custom chat type advice, and restore
      // the original event listener
      let chatView = this.ext.appView.room.chat;
      if (chatView) {
        Events.off('chat:receive', chatView.onReceived);
      }
      this._chatTypeAdvice.remove();
      if (chatView) {
        Events.on('chat:receive', chatView.onReceived, chatView);
      }
    },

    // bound to the ChatView instance
    onReceived(joinpoint) {
      let message = joinpoint.args[0];
      if (message.type.split(' ').indexOf('custom') !== -1) {
        // plug.dj has some nice default styling on "update" messages
        message.type += ' update';
        if (!message.timestamp) {
          message.timestamp = util.getChatTimestamp(settings.settings.chatTimestamps === 24);
        }
        // insert the chat message element
        joinpoint.proceed();
        if (message.badge) {
          // emoji badge
          if (/^:(.*?):$/.test(message.badge)) {
            let badgeBox = this.$chatMessages.children().last().find('.badge-box');
            let emojiName = message.badge.slice(1, -1);
            if (emoji.map[emojiName]) {
              badgeBox.find('i').remove();
              badgeBox.append(
                $('<span />').addClass('emoji-glow extplug-badji').append(
                  $('<span />').addClass('emoji emoji-' + emoji.map[emojiName])
                )
              );
            }
          }
          // icon badge
          else if (/^icon-(.*?)$/.test(message.badge)) {
            let badgeBox = this.$chatMessages.children().last().find('.badge-box');
            badgeBox.find('i')
              .removeClass()
              .addClass('icon').addClass(message.badge);
          }
        }
        if (message.color) {
          this.$chatMessages.children().last().find('.msg .text').css('color', message.color);
        }
      }
      else {
        joinpoint.proceed();
      }
    }
  });

  module.exports = ChatTypePlugin;

});
<commit_msg>fix missing emoji import for emoji chat badges<commit_after>define(function (require, exports, module) {

  const { around } = require('meld');
  const Events = require('plug/core/Events');
  const ChatView = require('plug/views/rooms/chat/ChatView');
  const util = require('plug/util/util');
  const emoji = require('plug/util/emoji');
  const settings = require('plug/store/settings');
  const Plugin = require('../Plugin');

  /**
   * The ChatType Plugin adds a "custom" chat type. Any chat messages
   * passed through the ChatView "onReceived" handler will be affected,
   * so in particular all "chat:receive" events are handled properly.
   *
   * A chat message with "custom" in its type property can take a few
   * additional options:
   *
   *  * the "badge" property can contain an emoji name (eg ":eyes:") or
   *    an icon class (eg "icon-plugdj") as well as the standard badge
   *    names.
   *  * the "color" property takes a CSS colour, which will be used for
   *    the message text.
   *  * the "timestamp" property always defaults to the current time if
   *    it is left empty.
   *
   * This is especially useful for showing notifications in chat.
   * The "type" property can be a list of CSS class names, if it contains
   * "custom", (eg `{ type: "custom inline my-notification" }`) so you
   * can use those classes to style your message as well. Note that you
   * cannot add additional classes for the other message types.
   */
  const ChatTypePlugin = Plugin.extend({
    enable() {
      // chatView.onReceived will still be the old method after adding advice
      // so the event listener should also be swapped out
      let chatView = this.ext.appView.room.chat;
      if (chatView) {
        Events.off('chat:receive', chatView.onReceived);
      }
      this._chatTypeAdvice = around(ChatView.prototype, 'onReceived', this.onReceived);
      if (chatView) {
        Events.on('chat:receive', chatView.onReceived, chatView);
      }
    },
    disable() {
      // remove custom chat type advice, and restore
      // the original event listener
      let chatView = this.ext.appView.room.chat;
      if (chatView) {
        Events.off('chat:receive', chatView.onReceived);
      }
      this._chatTypeAdvice.remove();
      if (chatView) {
        Events.on('chat:receive', chatView.onReceived, chatView);
      }
    },

    // bound to the ChatView instance
    onReceived(joinpoint) {
      let message = joinpoint.args[0];
      if (message.type.split(' ').indexOf('custom') !== -1) {
        // plug.dj has some nice default styling on "update" messages
        message.type += ' update';
        if (!message.timestamp) {
          message.timestamp = util.getChatTimestamp(settings.settings.chatTimestamps === 24);
        }
        // insert the chat message element
        joinpoint.proceed();
        if (message.badge) {
          // emoji badge
          if (/^:(.*?):$/.test(message.badge)) {
            let badgeBox = this.$chatMessages.children().last().find('.badge-box');
            let emojiName = message.badge.slice(1, -1);
            if (emoji.map[emojiName]) {
              badgeBox.find('i').remove();
              badgeBox.append(
                $('<span />').addClass('emoji-glow extplug-badji').append(
                  $('<span />').addClass('emoji emoji-' + emoji.map[emojiName])
                )
              );
            }
          }
          // icon badge
          else if (/^icon-(.*?)$/.test(message.badge)) {
            let badgeBox = this.$chatMessages.children().last().find('.badge-box');
            badgeBox.find('i')
              .removeClass()
              .addClass('icon').addClass(message.badge);
          }
        }
        if (message.color) {
          this.$chatMessages.children().last().find('.msg .text').css('color', message.color);
        }
      }
      else {
        joinpoint.proceed();
      }
    }
  });

  module.exports = ChatTypePlugin;

});
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2018 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.nanos.logger',
  name: 'AbstractLogger',
  implements: [ 'foam.nanos.logger.Logger' ],

  abstract: true,

  javaImports: [
    'java.io.PrintWriter',
    'java.io.StringWriter',
    'java.io.Writer',
    'java.text.SimpleDateFormat'
  ],

  axioms: [
    {
      name: 'javaExtras',
      buildJavaClass: function(cls) {
        cls.extras.push(foam.java.Code.create({
          data:
`protected static final ThreadLocal<SimpleDateFormat> sdf = new ThreadLocal<SimpleDateFormat>() {
  @Override
  protected SimpleDateFormat initialValue() {
    return new SimpleDateFormat("yyyy.MM.dd.HH.mm.ss.SSS");
  }
};

protected ThreadLocal<StringBuilder> sb = new ThreadLocal<StringBuilder>() {
  @Override
  protected StringBuilder initialValue() {
    return new StringBuilder();
  }

  @Override
  public StringBuilder get() {
    StringBuilder b = super.get();
    b.setLength(0);
    return b;
  }
};`
        }))
      }
    }
  ],

  methods: [
    {
      name: 'formatArg',
      args: [
        {
          name: 'obj',
          javaType: 'Object'
        }
      ],
      javaReturns: 'String',
      javaCode:
`if ( obj instanceof Throwable ) {
  Throwable   t  = (Throwable) obj;
  Writer      w  = new StringWriter();
  PrintWriter pw = new PrintWriter(w);

  t.printStackTrace(pw);

  return w.toString();
}

return String.valueOf(obj);`
    },
    {
      name: 'combine',
      args: [
        {
          name: 'args',
          javaType: 'Object[]'
        }
      ],
      javaReturns: 'String',
      javaCode:
      `StringBuilder str = sb.get();
for ( Object n : args ) {
  str.append(formatArg(n));
}
return str.toString();`
    }
  ]
});
<commit_msg>revert to previous version of combine function<commit_after>/**
 * @license
 * Copyright 2018 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.nanos.logger',
  name: 'AbstractLogger',
  implements: [ 'foam.nanos.logger.Logger' ],

  abstract: true,

  javaImports: [
    'java.io.PrintWriter',
    'java.io.StringWriter',
    'java.io.Writer',
    'java.text.SimpleDateFormat'
  ],

  axioms: [
    {
      name: 'javaExtras',
      buildJavaClass: function(cls) {
        cls.extras.push(foam.java.Code.create({
          data:
`protected static final ThreadLocal<SimpleDateFormat> sdf = new ThreadLocal<SimpleDateFormat>() {
  @Override
  protected SimpleDateFormat initialValue() {
    return new SimpleDateFormat("yyyy.MM.dd.HH.mm.ss.SSS");
  }
};

protected ThreadLocal<StringBuilder> sb = new ThreadLocal<StringBuilder>() {
  @Override
  protected StringBuilder initialValue() {
    return new StringBuilder();
  }

  @Override
  public StringBuilder get() {
    StringBuilder b = super.get();
    b.setLength(0);
    return b;
  }
};`
        }))
      }
    }
  ],

  methods: [
    {
      name: 'formatArg',
      args: [
        {
          name: 'obj',
          javaType: 'Object'
        }
      ],
      javaReturns: 'String',
      javaCode:
`if ( obj instanceof Throwable ) {
  Throwable   t  = (Throwable) obj;
  Writer      w  = new StringWriter();
  PrintWriter pw = new PrintWriter(w);

  t.printStackTrace(pw);

  return w.toString();
}

return String.valueOf(obj);`
    },
    {
      name: 'combine',
      args: [
        {
          name: 'args',
          javaType: 'Object[]'
        }
      ],
      javaReturns: 'String',
      javaCode:
      `StringBuilder str = sb.get();
for ( Object n : args ) {
  str.append(',');
  str.append(formatArg(n));
}
return str.toString();`
    }
  ]
});
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 */
import CustomElementInternals from './CustomElementInternals.js';
 import * as Utilities from './Utilities.js';

let elementDefinitionIsRunning = false;

export default class CustomElementDefinitionProducer {

  /**
   *
   * @param {string} localName
   * @param {!Function} constructorOrGetter
   * @param {boolean} isGetter
   * @param {!CustomElementInternals} internals
   */
  constructor(localName, constructorOrGetter, isGetter, internals) {

    /**
     * @private
     * @const {!CustomElementInternals}
     */
    this._internals = internals;

    /**
     * @private
     * @const {!Function}
     */
    this._constructorOrGetter = constructorOrGetter;

    /**
     * @private
     * @const {boolean}
     */
    this._isGetter = isGetter;

    /** @const {string} */
    this.localName = localName;

    /**
     * @private
     * @type {!CustomElementDefinition|undefined}
     */
    this._definition = undefined;

    if (this._isGetter && !(constructorOrGetter instanceof Function)) {
      throw new TypeError('Custom element constructor getters must be functions.');
    }

    if (!Utilities.isValidCustomElementName(localName)) {
      throw new SyntaxError(`The element name '${localName}' is not valid.`);
    }

    const existingProducer = this._internals.localNameToDefinitionProducer(localName);
    // Note, only throw if the existing producer has a valid definition.
    // If it does not, then re-defining is ok.
    if (existingProducer && existingProducer.definition) {
      throw new Error(`A custom element with name '${localName}' has already been defined.`);
    }

    if (elementDefinitionIsRunning) {
      throw new Error('A custom element is already being defined.');
    }

    // Per spec, reify the definition immediately if possible.
    if (!this._isGetter) {
      this._ensureDefinition();
    }

    this._internals.setDefinitionProducer(this.localName, this);
  }

  /** @return {!CustomElementDefinition} */
  get definition() {
    try {
      return this._ensureDefinition();
    } catch (e) {
      // If this definition is invalid, release it so it can be defined again.
      this._internals.removeDefinitionProducer(this.localName);
      // Note, if an error is generated while reading the definition, it's when
      // the polyfill is in the processing of upgrading an entire tree and we
      // don't want this to fail.
      console.error(e);
    }
  }

  /** @return {!CustomElementDefinition} */
  _ensureDefinition() {
    if (this._definition) {
      return this._definition;
    }
    elementDefinitionIsRunning = true;
    let connectedCallback;
    let disconnectedCallback;
    let adoptedCallback;
    let attributeChangedCallback;
    let observedAttributes;
    let constructorFunction;
    try {
      constructorFunction = this._isGetter ? this._constructorOrGetter() :
        this._constructorOrGetter;
      if (!(constructorFunction instanceof Function)) {
        throw new TypeError('Custom element constructors must be functions.');
      }
      /** @type {!Object} */
      const prototype = constructorFunction.prototype;
      if (!(prototype instanceof Object)) {
        throw new TypeError('The custom element constructor\'s prototype is not an object.');
      }

      function getCallback(name) {
        const callbackValue = prototype[name];
        if (callbackValue !== undefined && !(callbackValue instanceof Function)) {
          throw new Error(`The '${name}' callback must be a function.`);
        }
        return callbackValue;
      }
      connectedCallback = getCallback('connectedCallback');
      disconnectedCallback = getCallback('disconnectedCallback');
      adoptedCallback = getCallback('adoptedCallback');
      attributeChangedCallback = getCallback('attributeChangedCallback');
      // Note, `observedAttributes` should only be read if
      // `attributeChangedCallback` exists.
      observedAttributes = (attributeChangedCallback &&
        constructorFunction['observedAttributes']) || [];
    } catch (e) {
      throw e;
    } finally {
      elementDefinitionIsRunning = false;
    }

    this._definition = {
      localName: this.localName,
      constructorFunction,
      connectedCallback,
      disconnectedCallback,
      adoptedCallback,
      attributeChangedCallback,
      observedAttributes,
      constructionStack: []
    }

    this._internals.setDefinitionConstructor(this._definition);

    return this._definition;
  }

}
<commit_msg>Update src/CustomElementDefinitionProducer.js<commit_after>/**
 * @license
 * Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 */
import CustomElementInternals from './CustomElementInternals.js';
import * as Utilities from './Utilities.js';

let elementDefinitionIsRunning = false;

export default class CustomElementDefinitionProducer {

  /**
   *
   * @param {string} localName
   * @param {!Function} constructorOrGetter
   * @param {boolean} isGetter
   * @param {!CustomElementInternals} internals
   */
  constructor(localName, constructorOrGetter, isGetter, internals) {

    /**
     * @private
     * @const {!CustomElementInternals}
     */
    this._internals = internals;

    /**
     * @private
     * @const {!Function}
     */
    this._constructorOrGetter = constructorOrGetter;

    /**
     * @private
     * @const {boolean}
     */
    this._isGetter = isGetter;

    /** @const {string} */
    this.localName = localName;

    /**
     * @private
     * @type {!CustomElementDefinition|undefined}
     */
    this._definition = undefined;

    if (this._isGetter && !(constructorOrGetter instanceof Function)) {
      throw new TypeError('Custom element constructor getters must be functions.');
    }

    if (!Utilities.isValidCustomElementName(localName)) {
      throw new SyntaxError(`The element name '${localName}' is not valid.`);
    }

    const existingProducer = this._internals.localNameToDefinitionProducer(localName);
    // Note, only throw if the existing producer has a valid definition.
    // If it does not, then re-defining is ok.
    if (existingProducer && existingProducer.definition) {
      throw new Error(`A custom element with name '${localName}' has already been defined.`);
    }

    if (elementDefinitionIsRunning) {
      throw new Error('A custom element is already being defined.');
    }

    // Per spec, reify the definition immediately if possible.
    if (!this._isGetter) {
      this._ensureDefinition();
    }

    this._internals.setDefinitionProducer(this.localName, this);
  }

  /** @return {!CustomElementDefinition} */
  get definition() {
    try {
      return this._ensureDefinition();
    } catch (e) {
      // If this definition is invalid, release it so it can be defined again.
      this._internals.removeDefinitionProducer(this.localName);
      // Note, if an error is generated while reading the definition, it's when
      // the polyfill is in the processing of upgrading an entire tree and we
      // don't want this to fail.
      console.error(e);
    }
  }

  /** @return {!CustomElementDefinition} */
  _ensureDefinition() {
    if (this._definition) {
      return this._definition;
    }
    elementDefinitionIsRunning = true;
    let connectedCallback;
    let disconnectedCallback;
    let adoptedCallback;
    let attributeChangedCallback;
    let observedAttributes;
    let constructorFunction;
    try {
      constructorFunction = this._isGetter ? this._constructorOrGetter() :
        this._constructorOrGetter;
      if (!(constructorFunction instanceof Function)) {
        throw new TypeError('Custom element constructors must be functions.');
      }
      /** @type {!Object} */
      const prototype = constructorFunction.prototype;
      if (!(prototype instanceof Object)) {
        throw new TypeError('The custom element constructor\'s prototype is not an object.');
      }

      function getCallback(name) {
        const callbackValue = prototype[name];
        if (callbackValue !== undefined && !(callbackValue instanceof Function)) {
          throw new Error(`The '${name}' callback must be a function.`);
        }
        return callbackValue;
      }
      connectedCallback = getCallback('connectedCallback');
      disconnectedCallback = getCallback('disconnectedCallback');
      adoptedCallback = getCallback('adoptedCallback');
      attributeChangedCallback = getCallback('attributeChangedCallback');
      // Note, `observedAttributes` should only be read if
      // `attributeChangedCallback` exists.
      observedAttributes = (attributeChangedCallback &&
        constructorFunction['observedAttributes']) || [];
    } catch (e) {
      throw e;
    } finally {
      elementDefinitionIsRunning = false;
    }

    this._definition = {
      localName: this.localName,
      constructorFunction,
      connectedCallback,
      disconnectedCallback,
      adoptedCallback,
      attributeChangedCallback,
      observedAttributes,
      constructionStack: []
    }

    this._internals.setDefinitionConstructor(this._definition);

    return this._definition;
  }

}
<|endoftext|>


<commit_before>window.templates = window.templates || ( window.templates = {} );

window.templates.header_definition_list = function(headers)
{
    var alphaheaders = [];
    for (name in headers) {alphaheaders.push(name)}
    alphaheaders = alphaheaders.sort();

    var dlbody = [];

    for (var i=0, name; name=alphaheaders[i]; i++)
    {
        var value = headers[name];
        var dt = ['dt', name + ": "]
        if (name in header_specification_urls)
        {
            dt.push(['a', '(spec)',
                          'href', header_specification_urls[name],
                          'target', '_blank']);
        }

        dlbody.push(dt);

        if (typeof value == "string")
        {
            var dd = ['dd', value]
        }
        else
        {
            var dd = [];
            for (var n=0, e; e=value[n]; n++)
            {
                dd.push(['dd', e]);
            }
        }
        dlbody.push(dd);
    }
    var dl = ['dl', dlbody,
              'class', 'headerlist'
             ];

    return dl;
}

window.templates.request_list_row = function(n, r, sel)
{
    var a = [ 'tr',
        ['th',
             map_mime_to_type(get_mime_from_extension(r.request.path))
         ],
        ['td', r.request.headers["Host" || "?" ] ],
        ['td', r.request.path],
        ['td', r.request.method],
        ['td', (r.response ? r.response.status : "-"), 'class', 'status-cell'],
        ['td', (r.response ? r.response.time - r.request.time : "-"), 'class', 'time-cell'],
        'data-requestid', r.id,
        'handler', 'request-list-select',
        'class', 'typeicon mime-' + map_mime_to_type(get_mime_from_extension(r.request.path))
        //,
        //'class', (r.id==sel ? 'request-list-select' : '')
    ];
    return a;
}<commit_msg>Added some jsdocs<commit_after>/**
 * @fileoverview
 * Templates used by the http logger views
 */

window.templates = window.templates || ( window.templates = {} );

/**
 * Render the a definition list with a dt for each header and the dd with
 * the value. Add link to the relevant header spec if we have the URL
 */
 window.templates.header_definition_list = function(headers)
{
    var alphaheaders = [];
    for (name in headers) {alphaheaders.push(name)}
    alphaheaders = alphaheaders.sort();

    var dlbody = [];

    for (var i=0, name; name=alphaheaders[i]; i++)
    {
        var value = headers[name];
        var dt = ['dt', name + ": "]
        if (name in header_specification_urls)
        {
            dt.push(['a', '(spec)',
                          'href', header_specification_urls[name],
                          'target', '_blank']);
        }

        dlbody.push(dt);

        if (typeof value == "string")
        {
            var dd = ['dd', value]
        }
        else
        {
            var dd = [];
            for (var n=0, e; e=value[n]; n++)
            {
                dd.push(['dd', e]);
            }
        }
        dlbody.push(dd);
    }
    var dl = ['dl', dlbody,
              'class', 'headerlist'
             ];

    return dl;
}

/**
 * Renders a single row of request data in the request list
 */
window.templates.request_list_row = function(n, r, sel)
{
    var a = [ 'tr',
        ['th',
             map_mime_to_type(get_mime_from_extension(r.request.path))
         ],
        ['td', r.request.headers["Host" || "?" ] ],
        ['td', r.request.path],
        ['td', r.request.method],
        ['td', (r.response ? r.response.status : "-"), 'class', 'status-cell'],
        ['td', (r.response ? r.response.time - r.request.time : "-"), 'class', 'time-cell'],
        'data-requestid', r.id,
        'handler', 'request-list-select',
        'class', 'typeicon mime-' + map_mime_to_type(get_mime_from_extension(r.request.path))
        //,
        //'class', (r.id==sel ? 'request-list-select' : '')
    ];
    return a;
}

<|endoftext|>


<commit_before>/**
 * Creates a <div> that can serve as a tooltip.
 * Math and styles derived from hojberg/cssarrowplease, MIT License
 *
 */
betterlink_user_interface.createModule("FTE Tooltip", function(api, apiInternal) {
	api.requireModules( ["Util.DOM", "Drawer Reset CSS", "Event Messaging"] );

	var TOOLTIP_ID = 'betterlink-tooltip';
	var TOOLTIP_SELECTOR = "#" + TOOLTIP_ID;
	var SHOW_TOOLTIP_CLASS = 'betterlink-tooltip-show';
	var MEASURE_CLASS = 'betterlink-tooltip-measure-drawer';

	var backgroundColor = '#E9E9E9;';
	var backgroundRGB = hexToRGB(backgroundColor.replace(';',''));
	var backgroundRGBa = 'rgba(' + backgroundRGB.join(', ') + ', 0);';

	var borderColor = '#BCBCBC;';
	var borderRGB = hexToRGB(borderColor.replace(';',''));
	var borderRGBa = 'rgba(' + borderRGB.join(', ') + ', 0);';

	var borderWidth = 2;
	var arrowSize = 15; // the 'height' of the arrow from base-to-tip
	var arrowBorder = arrowSize + Math.round(borderWidth * 1.41421356); // cos(PI/4) * 2

	var tooltipCss =
		[   TOOLTIP_SELECTOR + " {",
					"background: " + backgroundColor,
					"border: " + borderWidth + "px solid " + borderColor,
					"box-shadow: 0px 8px 6px -6px rgba(0,0,0,.4);",
					"border-radius: 0;",
					"color: #424242;",
					"clear: none;",
					"font-family: Arial, sans-serif;",
					"font-size: 18px;",
					"font-weight: normal;",
					"letter-spacing: normal;",
					"line-height: normal;",
					"margin: 0;",
					"padding: 5px;",
					"text-align: left;",
					"min-width: " + (2 * (arrowSize+borderWidth)) + "px;",
					"min-height: " + (2 * (arrowSize+borderWidth)) + "px;",
					"max-width: 250px;",
					"text-shadow: none;",
					"width: auto;",
					"z-index: 2147483647;",

					"display: inline-block;",
					"position: absolute;",
					"visibility: hidden; }",

			// Arrow Definition
			TOOLTIP_SELECTOR + ":after," + TOOLTIP_SELECTOR + ":before {",
					"border: solid transparent;",
					"content: ' ';",
					"height: 0;",
					"width: 0;",
					"position: absolute;",
					"pointer-events: none; }",
			TOOLTIP_SELECTOR + ":after {",
					"border-color: " + backgroundRGBa,
					"border-width: " + arrowSize + "px; }",
			TOOLTIP_SELECTOR + ":before {",
					"border-color: " + borderRGBa,
					"border-width: " + arrowBorder + "px; }",

			// Arrow on Right
			TOOLTIP_SELECTOR + ".betterlink-right:after {",
					"left: 100%;",
					"top: 50%;",
					"margin-top: -" + arrowSize + "px;",
					"border-left-color: " + backgroundColor + " }",
			TOOLTIP_SELECTOR + ".betterlink-right:before {",
					"left: 100%;",
					"top: 50%;",
					"margin-top: -" + arrowBorder + "px;",
					"border-left-color: " + borderColor + " }",

			// Arrow on Bottom
			TOOLTIP_SELECTOR + ".betterlink-bottom:after {",
					"top: 100%;",
					"left: 50%;",
					"margin-left: -" + arrowSize + "px;",
					"border-top-color: " + backgroundColor + " }",
			TOOLTIP_SELECTOR + ".betterlink-bottom:before {",
					"top: 100%;",
					"left: 50%;",
					"margin-left: -" + arrowBorder + "px;",
					"border-top-color: " + borderColor + " }",

			// Arrow on Left
			TOOLTIP_SELECTOR + ".betterlink-left:after {",
					"right: 100%;",
					"top: 50%;",
					"margin-top: -" + arrowSize + "px;",
					"border-right-color: " + backgroundColor + " }",
			TOOLTIP_SELECTOR + ".betterlink-left:before {",
					"right: 100%;",
					"top: 50%;",
					"margin-top: -" + arrowBorder + "px;",
					"border-right-color: " + borderColor + " }",

			// Arrow on Top
			TOOLTIP_SELECTOR + ".betterlink-top { box-shadow: 0px -7px 7px -7px rgba(0,0,0,.4); }",
			TOOLTIP_SELECTOR + ".betterlink-top:after {",
					"bottom: 100%;",
					"left: 50%;",
					"margin-left: -" + arrowSize + "px;",
					"border-bottom-color: " + backgroundColor + " }",
			TOOLTIP_SELECTOR + ".betterlink-top:before {",
					"bottom: 100%;",
					"left: 50%;",
					"margin-left: -" + arrowBorder + "px;",
					"border-bottom-color: " + borderColor + " }",

			TOOLTIP_SELECTOR + "." + SHOW_TOOLTIP_CLASS + " { visibility: visible; }",

			// This class is used to get an accurate measurement of the tooltip
			// when it's placed on the DOM. It needs to be sufficiently far from
			// the end of the page for an accurate measurement.
			TOOLTIP_SELECTOR + "." + MEASURE_CLASS + " { left: -" + 100 + "px; }"
		].join(' ');

	var stylesInitialized = false;
	var tooltip;

	apiInternal.fteTooltip = {
		addTooltipToDrawer: addTooltipToDrawer,
		addTooltipToPage: addTooltipToPage,
		remove: removeTooltipFromDom
	};
	/****************************************************************************************************/

	apiInternal.events.registerObserverForRemoveBetterlink(removeTooltipFromDom);

	// If the tooltip is present in the DOM, remove it
	function removeTooltipFromDom() {
		if(tooltip.parentNode) {
			tooltip.parentNode.removeChild(tooltip);
		}
	}

	// Accepts an optional direction (right, left, top, bottom) to
	// indicate which direction the tooltip should point. If not
	// provided, the tooltip will just be a rectangle, no pointer.
	//
	// If the tooltip has already been created, this resets the content
	// and styles.
	function createTooltip(opt_direction) {
		initializeStyles();

		if(!tooltip) {
			tooltip = document.createElement('div');
			tooltip.id = TOOLTIP_ID;
		}
		else {
			removeTooltipFromDom();
			apiInternal.util.dom.removeAllChildren(tooltip);
			tooltip.className = '';
			tooltip.style.left = '';
			tooltip.style.top = '';
			tooltip.style.marginLeft = '';
			tooltip.style.marginTop = '';
		}

		if(opt_direction) {
			apiInternal.util.dom.applyClassToElement(tooltip, "betterlink-" + opt_direction);
		}

		return tooltip;
	}

	function initializeStyles() {
		if(!stylesInitialized) {
			stylesInitialized = true;

			// Writes the styles twice. Once when positioned inside of the drawer. The
			// other when positioned outside of the drawer.
			var regex = new RegExp(TOOLTIP_SELECTOR, 'g');
			apiInternal.util.dom.createAndAppendStyleElement(tooltipCss + tooltipCss.replace(regex, apiInternal.drawerSelector + TOOLTIP_SELECTOR));
		}
	}

	// Create and position the tooltip appropriately as an element
	// nested within the drawer. This means applying the 'left' and
	// 'top' attributes to get the right distances.
	//
	// This assumes that drawerElement has been appended to the DOM
	// already.
	function addTooltipToDrawer(drawerElement, tooltipContent) {
		createTooltip('right');
		apiInternal.util.dom.addOrReplaceChild(tooltip, tooltipContent);

		// Append the tooltip as the first child of the provided element.
		// This ensures that the 'top' of the tooltip will be the top of
		// the drawerElement.
		//
		// The tooltip needs to be on the DOM before checking its
		// dimensions.
		appendAsFirstChild(tooltip, drawerElement);

		apiInternal.util.dom.applyClassToElement(tooltip, MEASURE_CLASS);
		var left = arrowSize + tooltip.offsetWidth;
		tooltip.style.left = '-' + left + 'px';
		apiInternal.util.dom.removeClassFromElement(tooltip, MEASURE_CLASS);

		apiInternal.util.dom.applyClassToElement(tooltip, SHOW_TOOLTIP_CLASS);
	}

	// Create and position the tooltip appropriately as an element
	// nested within the DOM (outside of the drawer). This is likely
	// within a Betterlink-created element (like .betterlink-selected).
	//
	// This assumes that pageElement has been appended to the DOM
	// already.
	function addTooltipToPage(pageElement, tooltipContent) {
		createTooltip('bottom');
		apiInternal.util.dom.addOrReplaceChild(tooltip, tooltipContent);

		// Append the tooltip as the prior sibling of the provided element.
		// This ensures that the tooltip rests at the very beginning and
		// inline with the pageElement. This means we simply move the
		// tooltip up its full height.
		//
		// The tooltip needs to be on the DOM before checking its
		// dimensions.
		pageElement.parentNode.insertBefore(tooltip, pageElement);

		var top, left;
		// Make sure we're not going to put the element offpage
		if(!tooltipWillGoOffpage(tooltip.offsetHeight + arrowSize)) {
			top = tooltip.offsetHeight + arrowSize;
			tooltip.style.marginTop = '-' + top + 'px';
		}
		else {
			// If we can't position it right on top of element, then we'll
			// position it right underneath
			apiInternal.util.dom.removeClassFromElement(tooltip, "betterlink-bottom");
			apiInternal.util.dom.applyClassToElement(tooltip, "betterlink-top");

			// Move the tooltip as the last sibling of the pageElement
			removeTooltipFromDom();
			pageElement.parentNode.insertBefore(tooltip, pageElement.nextSibling);

			var approximateElementLineSize = 30;
			var horizontalOffset = 10;
			top = arrowSize + approximateElementLineSize;
			left = (tooltip.offsetWidth / 2) + horizontalOffset;
			tooltip.style.marginTop = top + 'px';
			tooltip.style.marginLeft = '-' + left + 'px';
		}

		apiInternal.util.dom.applyClassToElement(tooltip, SHOW_TOOLTIP_CLASS);
	}

	// Appends the newElement to the DOM as the first child of the
	// provided parentElement
	function appendAsFirstChild(newElement, parentElement) {
		if(parentElement.firstChild) {
			parentElement.insertBefore(newElement, parentElement.firstChild);
		}
		else {
			parentElement.appendChild(newElement);
		}
	}

	// Return whether moving the tooltip the provided distance up will
	// move the element offpage
	function tooltipWillGoOffpage(distanceToMove) {
		var supportPageOffset = window.pageYOffset !== undefined;
		var isCSS1Compat = ((document.compatMode || "") === "CSS1Compat");
		var y = supportPageOffset ? window.pageYOffset : isCSS1Compat ? document.documentElement.scrollTop : document.body.scrollTop;

		var currentOffset = tooltip.getBoundingClientRect().top + y - document.documentElement.clientTop;

		return currentOffset < distanceToMove;
	}

	// Returns an array specifying an RGB color from a provided hex color
	// ex: #88b7d5 ==> [136, 183, 213]
	function hexToRGB(h) {
		if ( typeof h !== 'string' || !h.match(/^#([0-9A-F]{3}$)|([0-9A-F]{6}$)/i) ) return [0, 0, 0];
		else if ( h.match(/^(#[0-9a-f]{3})$/i) ) h = '#' + h[1] + h[1] + h[2] + h[2] + h[3] + h[3];
		var rgb = [],
			i = 1;

		for(; i < 6; i+=2) {
			rgb.push(parseInt(h.substring(i, i + 2), 16));
		}
		return rgb;
	}
});
<commit_msg>increase width of tooltip to 300px<commit_after>/**
 * Creates a <div> that can serve as a tooltip.
 * Math and styles derived from hojberg/cssarrowplease, MIT License
 *
 */
betterlink_user_interface.createModule("FTE Tooltip", function(api, apiInternal) {
	api.requireModules( ["Util.DOM", "Drawer Reset CSS", "Event Messaging"] );

	var TOOLTIP_ID = 'betterlink-tooltip';
	var TOOLTIP_SELECTOR = "#" + TOOLTIP_ID;
	var SHOW_TOOLTIP_CLASS = 'betterlink-tooltip-show';
	var MEASURE_CLASS = 'betterlink-tooltip-measure-drawer';

	var backgroundColor = '#E9E9E9;';
	var backgroundRGB = hexToRGB(backgroundColor.replace(';',''));
	var backgroundRGBa = 'rgba(' + backgroundRGB.join(', ') + ', 0);';

	var borderColor = '#BCBCBC;';
	var borderRGB = hexToRGB(borderColor.replace(';',''));
	var borderRGBa = 'rgba(' + borderRGB.join(', ') + ', 0);';

	var borderWidth = 2;
	var arrowSize = 15; // the 'height' of the arrow from base-to-tip
	var arrowBorder = arrowSize + Math.round(borderWidth * 1.41421356); // cos(PI/4) * 2

	var tooltipCss =
		[   TOOLTIP_SELECTOR + " {",
					"background: " + backgroundColor,
					"border: " + borderWidth + "px solid " + borderColor,
					"box-shadow: 0px 8px 6px -6px rgba(0,0,0,.4);",
					"border-radius: 0;",
					"color: #424242;",
					"clear: none;",
					"font-family: Arial, sans-serif;",
					"font-size: 18px;",
					"font-weight: normal;",
					"letter-spacing: normal;",
					"line-height: normal;",
					"margin: 0;",
					"padding: 5px;",
					"text-align: left;",
					"min-width: " + (2 * (arrowSize+borderWidth)) + "px;",
					"min-height: " + (2 * (arrowSize+borderWidth)) + "px;",
					"max-width: 300px;",
					"text-shadow: none;",
					"width: auto;",
					"z-index: 2147483647;",

					"display: inline-block;",
					"position: absolute;",
					"visibility: hidden; }",

			// Arrow Definition
			TOOLTIP_SELECTOR + ":after," + TOOLTIP_SELECTOR + ":before {",
					"border: solid transparent;",
					"content: ' ';",
					"height: 0;",
					"width: 0;",
					"position: absolute;",
					"pointer-events: none; }",
			TOOLTIP_SELECTOR + ":after {",
					"border-color: " + backgroundRGBa,
					"border-width: " + arrowSize + "px; }",
			TOOLTIP_SELECTOR + ":before {",
					"border-color: " + borderRGBa,
					"border-width: " + arrowBorder + "px; }",

			// Arrow on Right
			TOOLTIP_SELECTOR + ".betterlink-right:after {",
					"left: 100%;",
					"top: 50%;",
					"margin-top: -" + arrowSize + "px;",
					"border-left-color: " + backgroundColor + " }",
			TOOLTIP_SELECTOR + ".betterlink-right:before {",
					"left: 100%;",
					"top: 50%;",
					"margin-top: -" + arrowBorder + "px;",
					"border-left-color: " + borderColor + " }",

			// Arrow on Bottom
			TOOLTIP_SELECTOR + ".betterlink-bottom:after {",
					"top: 100%;",
					"left: 50%;",
					"margin-left: -" + arrowSize + "px;",
					"border-top-color: " + backgroundColor + " }",
			TOOLTIP_SELECTOR + ".betterlink-bottom:before {",
					"top: 100%;",
					"left: 50%;",
					"margin-left: -" + arrowBorder + "px;",
					"border-top-color: " + borderColor + " }",

			// Arrow on Left
			TOOLTIP_SELECTOR + ".betterlink-left:after {",
					"right: 100%;",
					"top: 50%;",
					"margin-top: -" + arrowSize + "px;",
					"border-right-color: " + backgroundColor + " }",
			TOOLTIP_SELECTOR + ".betterlink-left:before {",
					"right: 100%;",
					"top: 50%;",
					"margin-top: -" + arrowBorder + "px;",
					"border-right-color: " + borderColor + " }",

			// Arrow on Top
			TOOLTIP_SELECTOR + ".betterlink-top { box-shadow: 0px -7px 7px -7px rgba(0,0,0,.4); }",
			TOOLTIP_SELECTOR + ".betterlink-top:after {",
					"bottom: 100%;",
					"left: 50%;",
					"margin-left: -" + arrowSize + "px;",
					"border-bottom-color: " + backgroundColor + " }",
			TOOLTIP_SELECTOR + ".betterlink-top:before {",
					"bottom: 100%;",
					"left: 50%;",
					"margin-left: -" + arrowBorder + "px;",
					"border-bottom-color: " + borderColor + " }",

			TOOLTIP_SELECTOR + "." + SHOW_TOOLTIP_CLASS + " { visibility: visible; }",

			// This class is used to get an accurate measurement of the tooltip
			// when it's placed on the DOM. It needs to be sufficiently far from
			// the end of the page for an accurate measurement.
			TOOLTIP_SELECTOR + "." + MEASURE_CLASS + " { left: -" + 100 + "px; }"
		].join(' ');

	var stylesInitialized = false;
	var tooltip;

	apiInternal.fteTooltip = {
		addTooltipToDrawer: addTooltipToDrawer,
		addTooltipToPage: addTooltipToPage,
		remove: removeTooltipFromDom
	};
	/****************************************************************************************************/

	apiInternal.events.registerObserverForRemoveBetterlink(removeTooltipFromDom);

	// If the tooltip is present in the DOM, remove it
	function removeTooltipFromDom() {
		if(tooltip.parentNode) {
			tooltip.parentNode.removeChild(tooltip);
		}
	}

	// Accepts an optional direction (right, left, top, bottom) to
	// indicate which direction the tooltip should point. If not
	// provided, the tooltip will just be a rectangle, no pointer.
	//
	// If the tooltip has already been created, this resets the content
	// and styles.
	function createTooltip(opt_direction) {
		initializeStyles();

		if(!tooltip) {
			tooltip = document.createElement('div');
			tooltip.id = TOOLTIP_ID;
		}
		else {
			removeTooltipFromDom();
			apiInternal.util.dom.removeAllChildren(tooltip);
			tooltip.className = '';
			tooltip.style.left = '';
			tooltip.style.top = '';
			tooltip.style.marginLeft = '';
			tooltip.style.marginTop = '';
		}

		if(opt_direction) {
			apiInternal.util.dom.applyClassToElement(tooltip, "betterlink-" + opt_direction);
		}

		return tooltip;
	}

	function initializeStyles() {
		if(!stylesInitialized) {
			stylesInitialized = true;

			// Writes the styles twice. Once when positioned inside of the drawer. The
			// other when positioned outside of the drawer.
			var regex = new RegExp(TOOLTIP_SELECTOR, 'g');
			apiInternal.util.dom.createAndAppendStyleElement(tooltipCss + tooltipCss.replace(regex, apiInternal.drawerSelector + TOOLTIP_SELECTOR));
		}
	}

	// Create and position the tooltip appropriately as an element
	// nested within the drawer. This means applying the 'left' and
	// 'top' attributes to get the right distances.
	//
	// This assumes that drawerElement has been appended to the DOM
	// already.
	function addTooltipToDrawer(drawerElement, tooltipContent) {
		createTooltip('right');
		apiInternal.util.dom.addOrReplaceChild(tooltip, tooltipContent);

		// Append the tooltip as the first child of the provided element.
		// This ensures that the 'top' of the tooltip will be the top of
		// the drawerElement.
		//
		// The tooltip needs to be on the DOM before checking its
		// dimensions.
		appendAsFirstChild(tooltip, drawerElement);

		apiInternal.util.dom.applyClassToElement(tooltip, MEASURE_CLASS);
		var left = arrowSize + tooltip.offsetWidth;
		tooltip.style.left = '-' + left + 'px';
		apiInternal.util.dom.removeClassFromElement(tooltip, MEASURE_CLASS);

		apiInternal.util.dom.applyClassToElement(tooltip, SHOW_TOOLTIP_CLASS);
	}

	// Create and position the tooltip appropriately as an element
	// nested within the DOM (outside of the drawer). This is likely
	// within a Betterlink-created element (like .betterlink-selected).
	//
	// This assumes that pageElement has been appended to the DOM
	// already.
	function addTooltipToPage(pageElement, tooltipContent) {
		createTooltip('bottom');
		apiInternal.util.dom.addOrReplaceChild(tooltip, tooltipContent);

		// Append the tooltip as the prior sibling of the provided element.
		// This ensures that the tooltip rests at the very beginning and
		// inline with the pageElement. This means we simply move the
		// tooltip up its full height.
		//
		// The tooltip needs to be on the DOM before checking its
		// dimensions.
		pageElement.parentNode.insertBefore(tooltip, pageElement);

		var top, left;
		// Make sure we're not going to put the element offpage
		if(!tooltipWillGoOffpage(tooltip.offsetHeight + arrowSize)) {
			top = tooltip.offsetHeight + arrowSize;
			tooltip.style.marginTop = '-' + top + 'px';
		}
		else {
			// If we can't position it right on top of element, then we'll
			// position it right underneath
			apiInternal.util.dom.removeClassFromElement(tooltip, "betterlink-bottom");
			apiInternal.util.dom.applyClassToElement(tooltip, "betterlink-top");

			// Move the tooltip as the last sibling of the pageElement
			removeTooltipFromDom();
			pageElement.parentNode.insertBefore(tooltip, pageElement.nextSibling);

			var approximateElementLineSize = 30;
			var horizontalOffset = 10;
			top = arrowSize + approximateElementLineSize;
			left = (tooltip.offsetWidth / 2) + horizontalOffset;
			tooltip.style.marginTop = top + 'px';
			tooltip.style.marginLeft = '-' + left + 'px';
		}

		apiInternal.util.dom.applyClassToElement(tooltip, SHOW_TOOLTIP_CLASS);
	}

	// Appends the newElement to the DOM as the first child of the
	// provided parentElement
	function appendAsFirstChild(newElement, parentElement) {
		if(parentElement.firstChild) {
			parentElement.insertBefore(newElement, parentElement.firstChild);
		}
		else {
			parentElement.appendChild(newElement);
		}
	}

	// Return whether moving the tooltip the provided distance up will
	// move the element offpage
	function tooltipWillGoOffpage(distanceToMove) {
		var supportPageOffset = window.pageYOffset !== undefined;
		var isCSS1Compat = ((document.compatMode || "") === "CSS1Compat");
		var y = supportPageOffset ? window.pageYOffset : isCSS1Compat ? document.documentElement.scrollTop : document.body.scrollTop;

		var currentOffset = tooltip.getBoundingClientRect().top + y - document.documentElement.clientTop;

		return currentOffset < distanceToMove;
	}

	// Returns an array specifying an RGB color from a provided hex color
	// ex: #88b7d5 ==> [136, 183, 213]
	function hexToRGB(h) {
		if ( typeof h !== 'string' || !h.match(/^#([0-9A-F]{3}$)|([0-9A-F]{6}$)/i) ) return [0, 0, 0];
		else if ( h.match(/^(#[0-9a-f]{3})$/i) ) h = '#' + h[1] + h[1] + h[2] + h[2] + h[3] + h[3];
		var rgb = [],
			i = 1;

		for(; i < 6; i+=2) {
			rgb.push(parseInt(h.substring(i, i + 2), 16));
		}
		return rgb;
	}
});
<|endoftext|>


<commit_before>(function(undefined) {
  'use strict';
  angularSpectrumColorpicker.directive('spectrumColorpicker', function() {
    return {
      restrict: 'E',
      require: 'ngModel',
      scope: {
        fallbackValue: '=',
        format: '=?',
        options: '=?',
        triggerId: '@?'
      },
      replace: true,
      templateUrl: 'directive.html',
      link: function($scope, $element, attrs, $ngModel) {

        var $input = $element.find('input');

        function setViewValue(color) {
          var value = $scope.fallbackValue;

          if (color) {
            value = color.toString($scope.format);
          } else if (angular.isUndefined($scope.fallbackValue)) {
            value = color;
          }

          $ngModel.$setViewValue(value);
        }

        var onChange = function(color) {
          $scope.$apply(function() {
            setViewValue(color);
          });
        };
        var onToggle = function() {
          $input.spectrum('toggle');
          return false;
        };
        var options = angular.extend({
          color: $ngModel.$viewValue,
          change: onChange,
          move: onChange,
          hide: onChange
        }, $scope.options);

        function getTriggerElement() {
          return angular.element(document.body).find('#' + $scope.triggerId);
        }

        if ($scope.triggerId) {
          getTriggerElement().on('click', onToggle);
        }

        $ngModel.$render = function() {
          $input.spectrum('set', $ngModel.$viewValue || '');
        };

        if (options.color) {
          $input.spectrum('set', options.color || '');
          setViewValue(options.color);
        }

        $input.spectrum(options);

        $scope.$on('$destroy', function() {
          $input.spectrum('destroy');
        });
      }
    };
  });
})();
<commit_msg>deregister trigger handler<commit_after>(function(undefined) {
  'use strict';
  angularSpectrumColorpicker.directive('spectrumColorpicker', function() {
    return {
      restrict: 'E',
      require: 'ngModel',
      scope: {
        fallbackValue: '=',
        format: '=?',
        options: '=?',
        triggerId: '@?'
      },
      replace: true,
      templateUrl: 'directive.html',
      link: function($scope, $element, attrs, $ngModel) {

        var $input = $element.find('input');

        function setViewValue(color) {
          var value = $scope.fallbackValue;

          if (color) {
            value = color.toString($scope.format);
          } else if (angular.isUndefined($scope.fallbackValue)) {
            value = color;
          }

          $ngModel.$setViewValue(value);
        }

        var onChange = function(color) {
          $scope.$apply(function() {
            setViewValue(color);
          });
        };
        var onToggle = function() {
          $input.spectrum('toggle');
          return false;
        };
        var options = angular.extend({
          color: $ngModel.$viewValue,
          change: onChange,
          move: onChange,
          hide: onChange
        }, $scope.options);

        function getTriggerElement() {
          return angular.element(document.body).find('#' + $scope.triggerId);
        }

        if ($scope.triggerId) {
          getTriggerElement().on('click', onToggle);
        }

        $ngModel.$render = function() {
          $input.spectrum('set', $ngModel.$viewValue || '');
        };

        if (options.color) {
          $input.spectrum('set', options.color || '');
          setViewValue(options.color);
        }

        $input.spectrum(options);

        $scope.$on('$destroy', function() {
          if ($scope.triggerId) {
            getTriggerElement().off('click', onToggle);
          }
          $input.spectrum('destroy');
        });
      }
    };
  });
})();
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { connect } from 'react-redux';

import fetchData from '../../lib/fetchData';
import { fetchGene, fetchGeneSuccess, fetchGeneFailure } from '../../actions/genes';
import { selectGene } from '../../selectors/geneSelectors';

import BasicGeneInfo from './basicGeneInfo';
import GenePageHeader from './genePageHeader';
import { OrthologyTable, mockOrthologData } from '../../components/orthology';
import { DiseaseTable, mockDiseaseData } from '../../components/disease';
import Subsection from '../../components/subsection';
import TranscriptViewer from './transcriptViewer';

class GenePage extends Component {
  componentDidMount() {
    this.props.dispatch(fetchGene());
    fetchData(`/api/gene/${this.props.params.geneId}`)
      .then(data => this.props.dispatch(fetchGeneSuccess(data)))
      .catch(error => this.props.dispatch(fetchGeneFailure(error)));
  }

  render() {
    if (this.props.loading) {
      return loading...;
    }

    if (this.props.error) {
      return
{this.props.error}
;
    }

    if (!this.props.data) {
      return null;
    }

    return (

        <GenePageHeader symbol={this.props.data.symbol} />

        <Subsection>
          <BasicGeneInfo geneData={this.props.data} />
        </Subsection>

        <Subsection hardcoded title='Transcript Viewer'>
          <TranscriptViewer geneSymbol={this.props.data.symbol} species={this.props.data.species} />
        </Subsection>

        <Subsection hardcoded title='Orthology'>
          <OrthologyTable data={mockOrthologData} />
        </Subsection>

        <Subsection hardcoded title='Disease Associations'>
          <DiseaseTable data={mockDiseaseData} />
        </Subsection>

    );
  }
}

GenePage.propTypes = {
  data: React.PropTypes.object,
  dispatch: React.PropTypes.func,
  error: React.PropTypes.object,
  loading: React.PropTypes.bool,
  params: React.PropTypes.object,
};

function mapStateToProps(state) {
  return selectGene(state);
}

export { GenePage as GenePage };
export default connect(mapStateToProps)(GenePage);
<commit_msg>Added react-helmet support to update the Gene/page head<commit_after>import React, { Component } from 'react';
import Helmet from 'react-helmet';
import { connect } from 'react-redux';

import fetchData from '../../lib/fetchData';
import { fetchGene, fetchGeneSuccess, fetchGeneFailure } from '../../actions/genes';
import { selectGene } from '../../selectors/geneSelectors';

import BasicGeneInfo from './basicGeneInfo';
import GenePageHeader from './genePageHeader';
import { OrthologyTable, mockOrthologData } from '../../components/orthology';
import { DiseaseTable, mockDiseaseData } from '../../components/disease';
import Subsection from '../../components/subsection';
import TranscriptViewer from './transcriptViewer';

class GenePage extends Component {
  componentDidMount() {
    this.props.dispatch(fetchGene());
    fetchData(`/api/gene/${this.props.params.geneId}`)
      .then(data => this.props.dispatch(fetchGeneSuccess(data)))
      .catch(error => this.props.dispatch(fetchGeneFailure(error)));
  }

  render() {
    if (this.props.loading) {
      return loading...;
    }

    if (this.props.error) {
      return
{this.props.error}
;
    }

    if (!this.props.data) {
      return null;
    }

    return (

        <Helmet
           title={'AGR gene page for ' + this.props.data.species + ' gene: ' + this.props.data.symbol}
           meta={[
               {property: 'og:title', content: 'Gene'},
           ]} />
        <GenePageHeader symbol={this.props.data.symbol} />

        <Subsection>
          <BasicGeneInfo geneData={this.props.data} />
        </Subsection>

        <Subsection hardcoded title='Transcript Viewer'>
          <TranscriptViewer geneSymbol={this.props.data.symbol} species={this.props.data.species} />
        </Subsection>

        <Subsection hardcoded title='Orthology'>
          <OrthologyTable data={mockOrthologData} />
        </Subsection>

        <Subsection hardcoded title='Disease Associations'>
          <DiseaseTable data={mockDiseaseData} />
        </Subsection>

    );
  }
}

GenePage.propTypes = {
  data: React.PropTypes.object,
  dispatch: React.PropTypes.func,
  error: React.PropTypes.object,
  loading: React.PropTypes.bool,
  params: React.PropTypes.object,
};

function mapStateToProps(state) {
  return selectGene(state);
}

export { GenePage as GenePage };
export default connect(mapStateToProps)(GenePage);
<|endoftext|>