<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import withStyles from '../styles/withStyles';
import { capitalize } from '../utils/helpers';
import SwitchBase from '../internal/SwitchBase';

export const styles = theme => ({
  /* Styles applied to the root element. */
  root: {
    display: 'inline-flex',
    width: 62,
    position: 'relative',
    flexShrink: 0,
    // For correct alignment with the text.
    verticalAlign: 'middle',
  },
  /* Styles used to create the `icon` passed to the internal `SwitchBase` component `icon` prop. */
  icon: {
    boxShadow: theme.shadows[1],
    backgroundColor: 'currentColor',
    width: 20,
    height: 20,
    borderRadius: '50%',
  },
  /* Styles applied the icon element component if `checked={true}`. */
  iconChecked: {
    boxShadow: theme.shadows[2],
  },
  /* Styles applied to the internal `SwitchBase` component's `root` class. */
  switchBase: {
    zIndex: 1,
    padding: 0,
    height: 48,
    width: 48,
    color: theme.palette.type === 'light' ? theme.palette.grey[50] : theme.palette.grey[400],
    transition: theme.transitions.create('transform', {
      duration: theme.transitions.duration.shortest,
    }),
  },
  /* Styles applied to the internal `SwitchBase` component's `checked` class. */
  checked: {
    transform: 'translateX(14px)',
    '& + $bar': {
      opacity: 0.5,
    },
  },
  /* Styles applied to the internal SwitchBase component's root element if `color="primary"`. */
  colorPrimary: {
    '&$checked': {
      color: theme.palette.primary.main,
      '& + $bar': {
        backgroundColor: theme.palette.primary.main,
      },
    },
  },
  /* Styles applied to the internal SwitchBase component's root element if `color="secondary"`. */
  colorSecondary: {
    '&$checked': {
      color: theme.palette.secondary.main,
      '& + $bar': {
        backgroundColor: theme.palette.secondary.main,
      },
    },
  },
  /* Styles applied to the internal SwitchBase component's disabled class. */
  disabled: {
    '& + $bar': {
      opacity: theme.palette.type === 'light' ? 0.12 : 0.1,
    },
    '& $icon': {
      boxShadow: theme.shadows[1],
    },
    '&$switchBase': {
      color: theme.palette.type === 'light' ? theme.palette.grey[400] : theme.palette.grey[800],
      '& + $bar': {
        backgroundColor:
          theme.palette.type === 'light' ? theme.palette.common.black : theme.palette.common.white,
      },
    },
  },
  /* Styles applied to the bar element. */
  bar: {
    borderRadius: 14 / 2,
    display: 'block',
    position: 'absolute',
    width: 34,
    height: 14,
    top: '50%',
    left: '50%',
    marginTop: -7,
    marginLeft: -17,
    transition: theme.transitions.create(['opacity', 'background-color'], {
      duration: theme.transitions.duration.shortest,
    }),
    backgroundColor:
      theme.palette.type === 'light' ? theme.palette.common.black : theme.palette.common.white,
    opacity: theme.palette.type === 'light' ? 0.38 : 0.3,
  },
});

function Switch(props) {
  const { classes, className, color, ...other } = props;

  return (

      <SwitchBase
        type="checkbox"
        icon={}
        classes={{
          root: classNames(classes.switchBase, classes[`color${capitalize(color)}`]),
          checked: classes.checked,
          disabled: classes.disabled,
        }}
        checkedIcon={}
        {...other}
      />

  );
}

Switch.propTypes = {
  /**
   * If `true`, the component is checked.
   */
  checked: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
  /**
   * The icon to display when the component is checked.
   */
  checkedIcon: PropTypes.node,
  /**
   * Override or extend the styles applied to the component.
   * See [CSS API](#css-api) below for more details.
   */
  classes: PropTypes.object.isRequired,
  /**
   * @ignore
   */
  className: PropTypes.string,
  /**
   * The color of the component. It supports those theme colors that make sense for this component.
   */
  color: PropTypes.oneOf(['primary', 'secondary', 'default']),
  /**
   * @ignore
   */
  defaultChecked: PropTypes.bool,
  /**
   * If `true`, the switch will be disabled.
   */
  disabled: PropTypes.bool,
  /**
   * If `true`, the ripple effect will be disabled.
   */
  disableRipple: PropTypes.bool,
  /**
   * The icon to display when the component is unchecked.
   */
  icon: PropTypes.node,
  /**
   * The id of the `input` element.
   */
  id: PropTypes.string,
  /**
   * Attributes applied to the `input` element.
   */
  inputProps: PropTypes.object,
  /**
   * Use that property to pass a ref callback to the native input component.
   */
  inputRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
  /**
   * Callback fired when the state is changed.
   *
   * @param {object} event The event source of the callback.
   * You can pull out the new value by accessing `event.target.checked`.
   * @param {boolean} checked The `checked` value of the switch
   */
  onChange: PropTypes.func,
  /**
   * The input component property `type`.
   */
  type: PropTypes.string,
  /**
   * The value of the component.
   */
  value: PropTypes.string,
};

Switch.defaultProps = {
  color: 'secondary',
};

export default withStyles(styles, { name: 'MuiSwitch' })(Switch);
<commit_msg>[Switch] Fix stacking context (#13122)<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import withStyles from '../styles/withStyles';
import { capitalize } from '../utils/helpers';
import SwitchBase from '../internal/SwitchBase';

export const styles = theme => ({
  /* Styles applied to the root element. */
  root: {
    display: 'inline-flex',
    width: 62,
    position: 'relative',
    flexShrink: 0,
    zIndex: 0, // Reset the stacking context.
    // For correct alignment with the text.
    verticalAlign: 'middle',
  },
  /* Styles used to create the `icon` passed to the internal `SwitchBase` component `icon` prop. */
  icon: {
    boxShadow: theme.shadows[1],
    backgroundColor: 'currentColor',
    width: 20,
    height: 20,
    borderRadius: '50%',
  },
  /* Styles applied the icon element component if `checked={true}`. */
  iconChecked: {
    boxShadow: theme.shadows[2],
  },
  /* Styles applied to the internal `SwitchBase` component's `root` class. */
  switchBase: {
    padding: 0,
    height: 48,
    width: 48,
    color: theme.palette.type === 'light' ? theme.palette.grey[50] : theme.palette.grey[400],
    transition: theme.transitions.create('transform', {
      duration: theme.transitions.duration.shortest,
    }),
  },
  /* Styles applied to the internal `SwitchBase` component's `checked` class. */
  checked: {
    transform: 'translateX(14px)',
    '& + $bar': {
      opacity: 0.5,
    },
  },
  /* Styles applied to the internal SwitchBase component's root element if `color="primary"`. */
  colorPrimary: {
    '&$checked': {
      color: theme.palette.primary.main,
      '& + $bar': {
        backgroundColor: theme.palette.primary.main,
      },
    },
  },
  /* Styles applied to the internal SwitchBase component's root element if `color="secondary"`. */
  colorSecondary: {
    '&$checked': {
      color: theme.palette.secondary.main,
      '& + $bar': {
        backgroundColor: theme.palette.secondary.main,
      },
    },
  },
  /* Styles applied to the internal SwitchBase component's disabled class. */
  disabled: {
    '& + $bar': {
      opacity: theme.palette.type === 'light' ? 0.12 : 0.1,
    },
    '& $icon': {
      boxShadow: theme.shadows[1],
    },
    '&$switchBase': {
      color: theme.palette.type === 'light' ? theme.palette.grey[400] : theme.palette.grey[800],
      '& + $bar': {
        backgroundColor:
          theme.palette.type === 'light' ? theme.palette.common.black : theme.palette.common.white,
      },
    },
  },
  /* Styles applied to the bar element. */
  bar: {
    borderRadius: 14 / 2,
    display: 'block',
    position: 'absolute',
    zIndex: -1,
    width: 34,
    height: 14,
    top: '50%',
    left: '50%',
    marginTop: -7,
    marginLeft: -17,
    transition: theme.transitions.create(['opacity', 'background-color'], {
      duration: theme.transitions.duration.shortest,
    }),
    backgroundColor:
      theme.palette.type === 'light' ? theme.palette.common.black : theme.palette.common.white,
    opacity: theme.palette.type === 'light' ? 0.38 : 0.3,
  },
});

function Switch(props) {
  const { classes, className, color, ...other } = props;

  return (

      <SwitchBase
        type="checkbox"
        icon={}
        classes={{
          root: classNames(classes.switchBase, classes[`color${capitalize(color)}`]),
          checked: classes.checked,
          disabled: classes.disabled,
        }}
        checkedIcon={}
        {...other}
      />

  );
}

Switch.propTypes = {
  /**
   * If `true`, the component is checked.
   */
  checked: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
  /**
   * The icon to display when the component is checked.
   */
  checkedIcon: PropTypes.node,
  /**
   * Override or extend the styles applied to the component.
   * See [CSS API](#css-api) below for more details.
   */
  classes: PropTypes.object.isRequired,
  /**
   * @ignore
   */
  className: PropTypes.string,
  /**
   * The color of the component. It supports those theme colors that make sense for this component.
   */
  color: PropTypes.oneOf(['primary', 'secondary', 'default']),
  /**
   * @ignore
   */
  defaultChecked: PropTypes.bool,
  /**
   * If `true`, the switch will be disabled.
   */
  disabled: PropTypes.bool,
  /**
   * If `true`, the ripple effect will be disabled.
   */
  disableRipple: PropTypes.bool,
  /**
   * The icon to display when the component is unchecked.
   */
  icon: PropTypes.node,
  /**
   * The id of the `input` element.
   */
  id: PropTypes.string,
  /**
   * Attributes applied to the `input` element.
   */
  inputProps: PropTypes.object,
  /**
   * Use that property to pass a ref callback to the native input component.
   */
  inputRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
  /**
   * Callback fired when the state is changed.
   *
   * @param {object} event The event source of the callback.
   * You can pull out the new value by accessing `event.target.checked`.
   * @param {boolean} checked The `checked` value of the switch
   */
  onChange: PropTypes.func,
  /**
   * The input component property `type`.
   */
  type: PropTypes.string,
  /**
   * The value of the component.
   */
  value: PropTypes.string,
};

Switch.defaultProps = {
  color: 'secondary',
};

export default withStyles(styles, { name: 'MuiSwitch' })(Switch);
<|endoftext|>


<commit_before>import some from 'lodash/some'
import find from 'lodash/find'
import typesConstructors from './index'

// Avoid recreate existing types
export const types = {}

export const initializeType = typeConfig => {
  if (types[typeConfig]) {
    return types[typeConfig]
  }

  const { typeConstructor } =
    find(typesConstructors, type => !!typeConfig.match(type.matcher)) || {}

  if (!typeConstructor) {
    throw new Error(`No type found for ${typeConfig}`)
  }

  types[typeConfig] = typeConstructor(typeConfig)

  return types[typeConfig]
}

export default class Type {
  constructor(value) {
    this.value = value
  }

  isValid() {
    return some(this.matchers, matcher => this.value.match(matcher))
  }

  getErrorMessage() {
    if (this.isValid()) {
      return
    }

    const errorMessage =
      this.constructor.errorMessage ||
      `has invalid value: ${this.value} for type ${this.constructor.name} `

    return errorMessage.replace(/\$value/g, this.value)
  }

  static check(type) {
    return !!type.match(this.constructor.typeChecker)
  }

  getValue() {
    return this.value
  }
}
<commit_msg>fix #1287 tolerate non-string in json input<commit_after>import some from 'lodash/some'
import find from 'lodash/find'
import typesConstructors from './index'

// Avoid recreate existing types
export const types = {}

export const initializeType = typeConfig => {
  if (types[typeConfig]) {
    return types[typeConfig]
  }

  const { typeConstructor } =
    find(typesConstructors, type => !!typeConfig.match(type.matcher)) || {}

  if (!typeConstructor) {
    throw new Error(`No type found for ${typeConfig}`)
  }

  types[typeConfig] = typeConstructor(typeConfig)

  return types[typeConfig]
}

export default class Type {
  constructor(value) {
    this.value = value
  }

  isValid() {
    return some(this.matchers, matcher => `${this.value}`.match(matcher))
  }

  getErrorMessage() {
    if (this.isValid()) {
      return
    }

    const errorMessage =
      this.constructor.errorMessage ||
      `has invalid value: ${this.value} for type ${this.constructor.name} `

    return errorMessage.replace(/\$value/g, this.value)
  }

  static check(type) {
    return !!type.match(this.constructor.typeChecker)
  }

  getValue() {
    return this.value
  }
}
<|endoftext|>


<commit_before>define([
    'backbone',
    'knockout',
    'd3'
], function(Backbone, ko, d3) {
    var GraphView = Backbone.View.extend({
        initialize: function(options) {
            var self = this;
            this.nodes = ko.observableArray([]);
            this.edges = ko.observableArray([]);
            _.extend(this, _.pick(options, 'nodes', 'edges'));

            var diameter = 960;

            this.tree = d3.layout.tree()
                .children(function (d) {
                    var nodes = self.nodes();
                    var edges = self.edges();
                    var children = [];

                    edges.forEach(function(edge) {
                        if (edge.domainnode_id === d.nodeid) {
                            nodes.forEach(function(node) {
                                if (edge.rangenode_id === node.nodeid) {
                                    children.push(node);
                                }
                            })
                        }
                    });

                    return children;
                })
                .size([360, diameter / 2 ])
                .separation(function(a, b) { return (a.parent == b.parent ? 1 : 2) / a.depth; });

            this.diagonal = d3.svg.diagonal.radial()
                .projection(function(d) { return [d.y, d.x / 180 * Math.PI]; });

            this.svg = d3.select(this.el).append("svg")
                .attr("width", "100%")
                .attr("height", diameter - 150)
                .call(d3.behavior.zoom().on("zoom", function() {
                    self.redraw();
                }))
                .append("g")
                .attr("transform", "translate(" + diameter / 2 + "," + diameter / 2 + "), rotate(0)");

            d3.select(this.el).style("height", diameter - 150 + "px");

            this.render();

            this.nodes.subscribe(function() {
                self.render();
            });
            this.edges.subscribe(function() {
                self.render();
            });
        },
        render: function () {
            var self = this;
            var nodesize = 6;
            var nodeMouseOver = 8;
            var root;
            this.nodes().forEach(function (node) {
                if (node.istopnode) {
                    root = node;
                }
                if (node.children) {
                    delete node.children;
                }
            });
            var nodes = this.tree.nodes(root);
            var links = this.tree.links(nodes);
            if (isNaN(nodes[0].x)) {
                nodes[0].x = 0;
            }

            var link = this.svg.selectAll(".link")
                .data(links, function(d) { return d.target.nodeid });
            link.enter().append("path")
                .attr("class", "link")
                .attr("d", this.diagonal);
            link.exit()
                .remove();

            var allNodes = this.svg.selectAll(".node")
                .data(nodes, function(d) { return d.nodeid });

            var node = allNodes.enter().append("g")
                .attr("class", "node")
                .attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; });

            node.append("circle")
                .attr("r", nodesize)
                .on("mouseover", function() {
                    d3.select(this)
                        .attr("r", nodeMouseOver)
                        .attr("class", "nodeMouseOver")
                })
                .on("click", function (d) {
                    self.trigger('node-selected', d);
                })
                .on("mouseout", function(d) {
                    d3.select(this)
                        .attr("r", nodesize)
                        .attr("class", "node");
                });

            node.append("text")
                .attr("dy", ".31em")
                .attr("class", "node-text")
                .attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
                .attr("transform", function(d) { return d.x < 180 ? "translate(8)" : "rotate(180)translate(-8)"; })
                .text(function (d) {
                    if(d.name.length > 13) {
                        return d.name.substring(0,13)+'...';
                    }
                    return d.name;
                });

            allNodes.exit()
                .remove();

        },
        redraw: function () {
            var xt = d3.event.translate[0] + 180;

            this.svg.attr("transform",
                "translate(" + xt + "," + d3.event.translate[1] + ")" +
                " scale(" + d3.event.scale + ")");
        }
    });
    return GraphView;
});
<commit_msg>better graph view sizing, fixing issue with pan/zoom jumping<commit_after>define([
    'backbone',
    'knockout',
    'd3'
], function(Backbone, ko, d3) {
    var GraphView = Backbone.View.extend({
        initialize: function(options) {
            var self = this;
            this.nodes = ko.observableArray([]);
            this.edges = ko.observableArray([]);
            _.extend(this, _.pick(options, 'nodes', 'edges'));

            var diameter = this.$el.width();

            this.tree = d3.layout.tree()
                .children(function (d) {
                    var nodes = self.nodes();
                    var edges = self.edges();
                    var children = [];

                    edges.forEach(function(edge) {
                        if (edge.domainnode_id === d.nodeid) {
                            nodes.forEach(function(node) {
                                if (edge.rangenode_id === node.nodeid) {
                                    children.push(node);
                                }
                            })
                        }
                    });

                    return children;
                })
                .size([360, diameter / 2 ])
                .separation(function(a, b) { return (a.parent == b.parent ? 1 : 2) / a.depth; });

            this.diagonal = d3.svg.diagonal.radial()
                .projection(function(d) { return [d.y, d.x / 180 * Math.PI]; });

            this.svg = d3.select(this.el).append("svg")
                .attr("width", "100%")
                .attr("height", $(window).height()-200)
                .call(d3.behavior.zoom().on("zoom", function() {
                    self.redraw();
                }))
                .append("g")

            this.center = [(this.$el.width() / 2) - 220, this.$el.height() / 2];

            this.svg.attr("transform", "translate(" + this.center[0] + "," + this.center[1] + "), rotate(0)");

            d3.select(this.el).style("height", $(window).height()-200 + "px");

            this.render();

            this.nodes.subscribe(function() {
                self.render();
            });
            this.edges.subscribe(function() {
                self.render();
            });
        },
        render: function () {
            var self = this;
            var nodesize = 6;
            var nodeMouseOver = 8;
            var root;
            this.nodes().forEach(function (node) {
                if (node.istopnode) {
                    root = node;
                }
                if (node.children) {
                    delete node.children;
                }
            });
            var nodes = this.tree.nodes(root);
            var links = this.tree.links(nodes);
            if (isNaN(nodes[0].x)) {
                nodes[0].x = 0;
            }

            var link = this.svg.selectAll(".link")
                .data(links, function(d) { return d.target.nodeid });
            link.enter().append("path")
                .attr("class", "link")
                .attr("d", this.diagonal);
            link.exit()
                .remove();

            var allNodes = this.svg.selectAll(".node")
                .data(nodes, function(d) { return d.nodeid });

            var node = allNodes.enter().append("g")
                .attr("class", "node")
                .attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; });

            node.append("circle")
                .attr("r", nodesize)
                .on("mouseover", function() {
                    d3.select(this)
                        .attr("r", nodeMouseOver)
                        .attr("class", "nodeMouseOver")
                })
                .on("click", function (d) {
                    self.trigger('node-selected', d);
                })
                .on("mouseout", function(d) {
                    d3.select(this)
                        .attr("r", nodesize)
                        .attr("class", "node");
                });

            node.append("text")
                .attr("dy", ".31em")
                .attr("class", "node-text")
                .attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
                .attr("transform", function(d) { return d.x < 180 ? "translate(8)" : "rotate(180)translate(-8)"; })
                .text(function (d) {
                    if(d.name.length > 13) {
                        return d.name.substring(0,13)+'...';
                    }
                    return d.name;
                });

            allNodes.exit()
                .remove();

        },
        redraw: function () {
            var xt = d3.event.translate[0] + this.center[0];
            var yt = d3.event.translate[1] + this.center[1];

            this.svg.attr("transform",
                "translate(" + xt + "," + yt + ")" +
                " scale(" + d3.event.scale + ")");
        }
    });
    return GraphView;
});
<|endoftext|>


<commit_before>define([
    'jquery',
    'underscore',
    'knockout',
    'moment',
    'views/base-manager',
    'viewmodels/alert',
    'models/graph',
    'models/report',
    'viewmodels/card',
    'viewmodels/provisional-tile',
    'arches',
    'resource-editor-data',
    'views/search/search-results',
    'views/resource/related-resources-manager',
    'report-templates',
    'bindings/resizable-sidepanel',
    'bindings/sortable',
    'widgets',
    'card-components'
], function($, _, ko, moment, BaseManagerView, AlertViewModel, GraphModel, ReportModel, CardViewModel, ProvisionalTileViewModel, arches, data, searchResults, RelatedResourcesManager, reportLookup) {
    var handlers = {
        'after-update': [],
        'tile-reset': []
    };
    var tiles = data.tiles;
    var filter = ko.observable('');
    var loading = ko.observable(false);
    var selection = ko.observable();
    var scrollTo = ko.observable();
    var displayname = ko.observable(data.displayname);
    var resourceId = ko.observable(data.resourceid);
    var selectedTile = ko.computed(function() {
        var item = selection();
        if (item && typeof item !== 'string') {
            if (item.tileid) {
                return item;
            }
            return item.getNewTile();
        }
    });
    var provisionalTileViewModel = new ProvisionalTileViewModel({tile: selectedTile, reviewer: data.user_is_reviewer});

    var flattenTree = function(parents, flatList) {
        _.each(ko.unwrap(parents), function(parent) {
            flatList.push(parent);
            var childrenKey = parent.tiles ? 'tiles' : 'cards';
            flattenTree(
                ko.unwrap(parent[childrenKey]),
                flatList
            );
        });
        return flatList;
    };

    var toggleAll = function(state) {
        var nodes = flattenTree(vm.topCards, []);
        _.each(nodes, function(node) {
            node.expanded(state);
        });
        if (state) {
            vm.rootExpanded(true);
        }
    };
    var createLookup = function(list, idKey) {
        return _.reduce(list, function(lookup, item) {
            lookup[item[idKey]] = item;
            return lookup;
        }, {});
    };

    var graphModel = new GraphModel({
        data: {nodes: data.nodes, nodegroups: data.nodegroups, edges: []},
        datatypes: data.datatypes
    });

    var vm = {
        loading: loading,
        scrollTo: scrollTo,
        filterEnterKeyHandler: function(context, e) {
            if (e.keyCode === 13) {
                var highlightedItems = _.filter(flattenTree(vm.topCards, []), function(item) {
                    return item.highlight && item.highlight();
                });
                var previousItem = scrollTo();
                scrollTo(null);
                if (highlightedItems.length > 0) {
                    var scrollIndex = 0;
                    var previousIndex = highlightedItems.indexOf(previousItem);
                    if (previousItem && highlightedItems[previousIndex+1]) {
                        scrollIndex = previousIndex + 1;
                    }
                    scrollTo(highlightedItems[scrollIndex]);
                }
                return false;
            }
            return true;
        },
        widgetLookup: createLookup(data.widgets, 'widgetid'),
        cardComponentLookup: createLookup(data.cardComponents, 'componentid'),
        nodeLookup: createLookup(graphModel.get('nodes')(), 'nodeid'),
        graphid: data.graphid,
        graphname: data.graphname,
        reviewer: data.userisreviewer,
        graphiconclass: data.graphiconclass,
        relationship_types: data.relationship_types,
        graph: {
            graphid: data.graphid,
            name: data.graphname,
            iconclass: data.graphiconclass,
            ontologyclass: data.ontologyclass
        },
        displayname: displayname,
        expandAll: function() {
            toggleAll(true);
        },
        collapseAll: function() {
            toggleAll(false);
        },
        rootExpanded: ko.observable(true),
        topCards: _.filter(data.cards, function(card) {
            var nodegroup = _.find(data.nodegroups, function(group) {
                return group.nodegroupid === card.nodegroup_id;
            });
            return !nodegroup || !nodegroup.parentnodegroup_id;
        }).map(function(card) {
            return new CardViewModel({
                card: card,
                graphModel: graphModel,
                tile: null,
                resourceId: resourceId,
                displayname: displayname,
                handlers: handlers,
                cards: data.cards,
                tiles: tiles,
                selection: selection,
                scrollTo: scrollTo,
                loading: loading,
                filter: filter,
                provisionalTileViewModel: provisionalTileViewModel,
                cardwidgets: data.cardwidgets,
                userisreviewer: data.userisreviewer
            });
        }),
        selection: selection,
        selectedTile: selectedTile,
        selectedCard: ko.computed(function() {
            var item = selection();
            if (item && typeof item !== 'string') {
                if (item.tileid) {
                    return item.parent;
                }
                return item;
            }
        }),
        provisionalTileViewModel: provisionalTileViewModel,
        filter: filter,
        on: function(eventName, handler) {
            if (handlers[eventName]) {
                handlers[eventName].push(handler);
            }
        },
        resourceId: resourceId,
        reportLookup: reportLookup,
        copyResource: function() {
            if (resourceId()) {
                vm.menuActive(false);
                loading(true);
                $.ajax({
                    type: "GET",
                    url: arches.urls.resource_copy.replace('//', '/' + resourceId() + '/'),
                    success: function() {
                        vm.alert(new AlertViewModel('ep-alert-blue', arches.resourceCopySuccess.title, '', null, function(){}));
                    },
                    error: function() {
                        vm.alert(new AlertViewModel('ep-alert-red', arches.resourceCopyFailed.title, arches.resourceCopyFailed.text, null, function(){}));
                    },
                    complete: function() {
                        loading(false);
                    },
                });
            }
        },
        deleteResource: function() {
            if (resourceId()) {
                vm.menuActive(false);
                vm.alert(new AlertViewModel('ep-alert-red', arches.confirmResourceDelete.title, arches.confirmResourceDelete.text, function() {
                    return;
                }, function(){
                    loading(true);
                    $.ajax({
                        type: "DELETE",
                        url: arches.urls.resource_editor + resourceId(),
                        complete: function(request, status) {
                            loading(false);
                            if (status === 'success') {
                                vm.navigate(arches.urls.resource);
                            }
                        },
                    });
                }));
            }
        },
        deleteTile: function(tile) {
            tile.deleteTile(function(response) {
                vm.alert(new AlertViewModel('ep-alert-red', response.responseJSON.message[0], response.responseJSON.message[1], null, function(){}));
            });
        },
        saveTile: function(tile) {
            tile.save(function(response) {
                vm.alert(new AlertViewModel('ep-alert-red', response.responseJSON.message[0], response.responseJSON.message[1], null, function(){}));
            });
        },
        viewEditHistory: function() {
            if (resourceId()) {
                vm.menuActive(false);
                vm.navigate(arches.urls.get_resource_edit_log(resourceId()));
            }
        },
        viewReport: function() {
            if (resourceId()) {
                vm.menuActive(false);
                vm.navigate(arches.urls.resource_report + resourceId());
            }
        }
    };
    var topCard = vm.topCards[0];
    if (topCard) {
        selection(topCard.tiles().length > 0 ? topCard.tiles()[0] : topCard);
    }

    vm.report = null;
    if (data.report) {
        vm.report = new ReportModel(_.extend(data, {graphModel: graphModel, cards: vm.topCards}));
    }

    vm.resourceId.subscribe(function(){
        //switches the url from 'create-resource' once the resource id is available
        history.pushState({}, '', arches.urls.resource_editor + resourceId());
    });

    vm.showRelatedResourcesManager = function(){
        if (vm.graph.domain_connections == undefined) {
            $.ajax({
                url: arches.urls.relatable_resources,
                data: {graphid: vm.graphid}
            }).done(function(relatable){
                vm.graph.relatable_resources = relatable;
                $.ajax({
                    url: arches.urls.get_domain_connections(vm.graphid),
                    data: {"ontology_class": vm.graph.ontologyclass}
                }).done(function(data){
                    vm.graph.domain_connections = data;
                    vm.relatedResourcesManager = new RelatedResourcesManager({
                        searchResults: new searchResults(),
                        resourceEditorContext: true,
                        editing_instance_id: vm.resourceId(),
                        relationship_types: vm.relationship_types,
                        graph: vm.graph
                    });
                    vm.selection('related-resources');
                });
            });

        } else {
            vm.selection('related-resources');
        }
    };

    vm.selectionBreadcrumbs = ko.computed(function() {
        var item = vm.selectedTile();
        var crumbs = [];
        if (item) {
            while (item.parent) {
                item = item.parent;
                crumbs.unshift(item);
            }
        }
        return crumbs;
    });

    return new BaseManagerView({
        viewModel: vm
    });
});
<commit_msg>Make 'Jump to Report' link open in new window, re #3799<commit_after>define([
    'jquery',
    'underscore',
    'knockout',
    'moment',
    'views/base-manager',
    'viewmodels/alert',
    'models/graph',
    'models/report',
    'viewmodels/card',
    'viewmodels/provisional-tile',
    'arches',
    'resource-editor-data',
    'views/search/search-results',
    'views/resource/related-resources-manager',
    'report-templates',
    'bindings/resizable-sidepanel',
    'bindings/sortable',
    'widgets',
    'card-components'
], function($, _, ko, moment, BaseManagerView, AlertViewModel, GraphModel, ReportModel, CardViewModel, ProvisionalTileViewModel, arches, data, searchResults, RelatedResourcesManager, reportLookup) {
    var handlers = {
        'after-update': [],
        'tile-reset': []
    };
    var tiles = data.tiles;
    var filter = ko.observable('');
    var loading = ko.observable(false);
    var selection = ko.observable();
    var scrollTo = ko.observable();
    var displayname = ko.observable(data.displayname);
    var resourceId = ko.observable(data.resourceid);
    var selectedTile = ko.computed(function() {
        var item = selection();
        if (item && typeof item !== 'string') {
            if (item.tileid) {
                return item;
            }
            return item.getNewTile();
        }
    });
    var provisionalTileViewModel = new ProvisionalTileViewModel({tile: selectedTile, reviewer: data.user_is_reviewer});

    var flattenTree = function(parents, flatList) {
        _.each(ko.unwrap(parents), function(parent) {
            flatList.push(parent);
            var childrenKey = parent.tiles ? 'tiles' : 'cards';
            flattenTree(
                ko.unwrap(parent[childrenKey]),
                flatList
            );
        });
        return flatList;
    };

    var toggleAll = function(state) {
        var nodes = flattenTree(vm.topCards, []);
        _.each(nodes, function(node) {
            node.expanded(state);
        });
        if (state) {
            vm.rootExpanded(true);
        }
    };
    var createLookup = function(list, idKey) {
        return _.reduce(list, function(lookup, item) {
            lookup[item[idKey]] = item;
            return lookup;
        }, {});
    };

    var graphModel = new GraphModel({
        data: {nodes: data.nodes, nodegroups: data.nodegroups, edges: []},
        datatypes: data.datatypes
    });

    var vm = {
        loading: loading,
        scrollTo: scrollTo,
        filterEnterKeyHandler: function(context, e) {
            if (e.keyCode === 13) {
                var highlightedItems = _.filter(flattenTree(vm.topCards, []), function(item) {
                    return item.highlight && item.highlight();
                });
                var previousItem = scrollTo();
                scrollTo(null);
                if (highlightedItems.length > 0) {
                    var scrollIndex = 0;
                    var previousIndex = highlightedItems.indexOf(previousItem);
                    if (previousItem && highlightedItems[previousIndex+1]) {
                        scrollIndex = previousIndex + 1;
                    }
                    scrollTo(highlightedItems[scrollIndex]);
                }
                return false;
            }
            return true;
        },
        widgetLookup: createLookup(data.widgets, 'widgetid'),
        cardComponentLookup: createLookup(data.cardComponents, 'componentid'),
        nodeLookup: createLookup(graphModel.get('nodes')(), 'nodeid'),
        graphid: data.graphid,
        graphname: data.graphname,
        reviewer: data.userisreviewer,
        graphiconclass: data.graphiconclass,
        relationship_types: data.relationship_types,
        graph: {
            graphid: data.graphid,
            name: data.graphname,
            iconclass: data.graphiconclass,
            ontologyclass: data.ontologyclass
        },
        displayname: displayname,
        expandAll: function() {
            toggleAll(true);
        },
        collapseAll: function() {
            toggleAll(false);
        },
        rootExpanded: ko.observable(true),
        topCards: _.filter(data.cards, function(card) {
            var nodegroup = _.find(data.nodegroups, function(group) {
                return group.nodegroupid === card.nodegroup_id;
            });
            return !nodegroup || !nodegroup.parentnodegroup_id;
        }).map(function(card) {
            return new CardViewModel({
                card: card,
                graphModel: graphModel,
                tile: null,
                resourceId: resourceId,
                displayname: displayname,
                handlers: handlers,
                cards: data.cards,
                tiles: tiles,
                selection: selection,
                scrollTo: scrollTo,
                loading: loading,
                filter: filter,
                provisionalTileViewModel: provisionalTileViewModel,
                cardwidgets: data.cardwidgets,
                userisreviewer: data.userisreviewer
            });
        }),
        selection: selection,
        selectedTile: selectedTile,
        selectedCard: ko.computed(function() {
            var item = selection();
            if (item && typeof item !== 'string') {
                if (item.tileid) {
                    return item.parent;
                }
                return item;
            }
        }),
        provisionalTileViewModel: provisionalTileViewModel,
        filter: filter,
        on: function(eventName, handler) {
            if (handlers[eventName]) {
                handlers[eventName].push(handler);
            }
        },
        resourceId: resourceId,
        reportLookup: reportLookup,
        copyResource: function() {
            if (resourceId()) {
                vm.menuActive(false);
                loading(true);
                $.ajax({
                    type: "GET",
                    url: arches.urls.resource_copy.replace('//', '/' + resourceId() + '/'),
                    success: function() {
                        vm.alert(new AlertViewModel('ep-alert-blue', arches.resourceCopySuccess.title, '', null, function(){}));
                    },
                    error: function() {
                        vm.alert(new AlertViewModel('ep-alert-red', arches.resourceCopyFailed.title, arches.resourceCopyFailed.text, null, function(){}));
                    },
                    complete: function() {
                        loading(false);
                    },
                });
            }
        },
        deleteResource: function() {
            if (resourceId()) {
                vm.menuActive(false);
                vm.alert(new AlertViewModel('ep-alert-red', arches.confirmResourceDelete.title, arches.confirmResourceDelete.text, function() {
                    return;
                }, function(){
                    loading(true);
                    $.ajax({
                        type: "DELETE",
                        url: arches.urls.resource_editor + resourceId(),
                        complete: function(request, status) {
                            loading(false);
                            if (status === 'success') {
                                vm.navigate(arches.urls.resource);
                            }
                        },
                    });
                }));
            }
        },
        deleteTile: function(tile) {
            tile.deleteTile(function(response) {
                vm.alert(new AlertViewModel('ep-alert-red', response.responseJSON.message[0], response.responseJSON.message[1], null, function(){}));
            });
        },
        saveTile: function(tile) {
            tile.save(function(response) {
                vm.alert(new AlertViewModel('ep-alert-red', response.responseJSON.message[0], response.responseJSON.message[1], null, function(){}));
            });
        },
        viewEditHistory: function() {
            if (resourceId()) {
                vm.menuActive(false);
                vm.navigate(arches.urls.get_resource_edit_log(resourceId()));
            }
        },
        viewReport: function() {
            if (resourceId()) {
                vm.menuActive(false);
                window.open(arches.urls.resource_report + resourceId(), "_blank");
            }
        }
    };
    var topCard = vm.topCards[0];
    if (topCard) {
        selection(topCard.tiles().length > 0 ? topCard.tiles()[0] : topCard);
    }

    vm.report = null;
    if (data.report) {
        vm.report = new ReportModel(_.extend(data, {graphModel: graphModel, cards: vm.topCards}));
    }

    vm.resourceId.subscribe(function(){
        //switches the url from 'create-resource' once the resource id is available
        history.pushState({}, '', arches.urls.resource_editor + resourceId());
    });

    vm.showRelatedResourcesManager = function(){
        if (vm.graph.domain_connections == undefined) {
            $.ajax({
                url: arches.urls.relatable_resources,
                data: {graphid: vm.graphid}
            }).done(function(relatable){
                vm.graph.relatable_resources = relatable;
                $.ajax({
                    url: arches.urls.get_domain_connections(vm.graphid),
                    data: {"ontology_class": vm.graph.ontologyclass}
                }).done(function(data){
                    vm.graph.domain_connections = data;
                    vm.relatedResourcesManager = new RelatedResourcesManager({
                        searchResults: new searchResults(),
                        resourceEditorContext: true,
                        editing_instance_id: vm.resourceId(),
                        relationship_types: vm.relationship_types,
                        graph: vm.graph
                    });
                    vm.selection('related-resources');
                });
            });

        } else {
            vm.selection('related-resources');
        }
    };

    vm.selectionBreadcrumbs = ko.computed(function() {
        var item = vm.selectedTile();
        var crumbs = [];
        if (item) {
            while (item.parent) {
                item = item.parent;
                crumbs.unshift(item);
            }
        }
        return crumbs;
    });

    return new BaseManagerView({
        viewModel: vm
    });
});
<|endoftext|>


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

import Hostname from 'components/Hostname'
import Summary from 'components/Summary'

import Waypoint from 'react-waypoint'
import ProgressiveImage from 'react-progressive-image'

import * as ArticleActions from 'actions/Articles'

@connect()
class Article extends Component {

    trackEngagement = e => this.props.dispatch(
        ArticleActions.engage(this.props.object.id, (this.props.index + 7))
    )

    trackImpression = () => this.props.dispatch(
        ArticleActions.impression(this.props.object.id)
    )

    render() {

        return (

                    <Waypoint onEnter={() => {
                        this.trackImpression(this.props.object.id)
                    }} />

                        <ProgressiveImage src={this.props.object.imageSrc} placeholder='/img/app/placeholder.png'>
                            {(src) => }
                        </ProgressiveImage>

                        {this.props.object.title}

                        {this.props.object.summary}

                        {this.props.site.name || this.props.site.siteUrl}

        )
    }

}

@connect(state => ({ articles: state.Articles, }))
class Articles extends Component {

    state = {
        appending: false,
        page: 1,
        version: null,
    }

    handleScroll = e => {

        if (this.$i || this.state.appending) {
            clearTimeout(this.$i)
        }

        this.$i = setTimeout(() => {

            if (this.state.appending) return

            if (((this.$scrollY || 0) - window.scrollY) >= 0) {
                return
            }

            this.$scrollY = window.scrollY

            const offset = document.body.scrollTop + window.innerHeight,
                  height = document.body.offsetHeight

            if (offset > (height - 100)) {
                this.setState({ appending: true, page: this.state.page + 1, })
                this.props.dispatch(ArticleActions.load(this.state.page))
                    .then(() => this.setState({ appending: false, }))
            }
        }, 200)
    }

    componentDidMount() {
        window.addEventListener('scroll', this.handleScroll)
    }

    componentWillUnmount() {
        window.removeEventListener('scroll', this.handleScroll)
    }

    render() {
        return (

                {this.props.articles.slice(7).map((article, index) =>
                    <Article {...article} index={index} key={`article-${article.object.id}`} />
                )}
                {this.state.appending ?

                    <svg width="35px" height="35px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" className="uil-ring">
                        <rect x="0" y="0" width="100" height="100" fill="none" className="bk"></rect>
                        <defs>
                            <filter id="uil-ring-shadow" x="-100%" y="-100%" width="300%" height="300%">
                                <feOffset result="offOut" in="SourceGraphic" dx="0" dy="0"></feOffset>
                                <feGaussianBlur result="blurOut" in="offOut" stdDeviation="0"></feGaussianBlur>
                                <feBlend in="SourceGraphic" in2="blurOut" mode="normal"></feBlend>
                            </filter>
                        </defs>
                        <path d="M10,50c0,0,0,0.5,0.1,1.4c0,0.5,0.1,1,0.2,1.7c0,0.3,0.1,0.7,0.1,1.1c0.1,0.4,0.1,0.8,0.2,1.2c0.2,0.8,0.3,1.8,0.5,2.8 c0.3,1,0.6,2.1,0.9,3.2c0.3,1.1,0.9,2.3,1.4,3.5c0.5,1.2,1.2,2.4,1.8,3.7c0.3,0.6,0.8,1.2,1.2,1.9c0.4,0.6,0.8,1.3,1.3,1.9 c1,1.2,1.9,2.6,3.1,3.7c2.2,2.5,5,4.7,7.9,6.7c3,2,6.5,3.4,10.1,4.6c3.6,1.1,7.5,1.5,11.2,1.6c4-0.1,7.7-0.6,11.3-1.6 c3.6-1.2,7-2.6,10-4.6c3-2,5.8-4.2,7.9-6.7c1.2-1.2,2.1-2.5,3.1-3.7c0.5-0.6,0.9-1.3,1.3-1.9c0.4-0.6,0.8-1.3,1.2-1.9 c0.6-1.3,1.3-2.5,1.8-3.7c0.5-1.2,1-2.4,1.4-3.5c0.3-1.1,0.6-2.2,0.9-3.2c0.2-1,0.4-1.9,0.5-2.8c0.1-0.4,0.1-0.8,0.2-1.2 c0-0.4,0.1-0.7,0.1-1.1c0.1-0.7,0.1-1.2,0.2-1.7C90,50.5,90,50,90,50s0,0.5,0,1.4c0,0.5,0,1,0,1.7c0,0.3,0,0.7,0,1.1 c0,0.4-0.1,0.8-0.1,1.2c-0.1,0.9-0.2,1.8-0.4,2.8c-0.2,1-0.5,2.1-0.7,3.3c-0.3,1.2-0.8,2.4-1.2,3.7c-0.2,0.7-0.5,1.3-0.8,1.9 c-0.3,0.7-0.6,1.3-0.9,2c-0.3,0.7-0.7,1.3-1.1,2c-0.4,0.7-0.7,1.4-1.2,2c-1,1.3-1.9,2.7-3.1,4c-2.2,2.7-5,5-8.1,7.1 c-0.8,0.5-1.6,1-2.4,1.5c-0.8,0.5-1.7,0.9-2.6,1.3L66,87.7l-1.4,0.5c-0.9,0.3-1.8,0.7-2.8,1c-3.8,1.1-7.9,1.7-11.8,1.8L47,90.8 c-1,0-2-0.2-3-0.3l-1.5-0.2l-0.7-0.1L41.1,90c-1-0.3-1.9-0.5-2.9-0.7c-0.9-0.3-1.9-0.7-2.8-1L34,87.7l-1.3-0.6 c-0.9-0.4-1.8-0.8-2.6-1.3c-0.8-0.5-1.6-1-2.4-1.5c-3.1-2.1-5.9-4.5-8.1-7.1c-1.2-1.2-2.1-2.7-3.1-4c-0.5-0.6-0.8-1.4-1.2-2 c-0.4-0.7-0.8-1.3-1.1-2c-0.3-0.7-0.6-1.3-0.9-2c-0.3-0.7-0.6-1.3-0.8-1.9c-0.4-1.3-0.9-2.5-1.2-3.7c-0.3-1.2-0.5-2.3-0.7-3.3 c-0.2-1-0.3-2-0.4-2.8c-0.1-0.4-0.1-0.8-0.1-1.2c0-0.4,0-0.7,0-1.1c0-0.7,0-1.2,0-1.7C10,50.5,10,50,10,50z" fill="#16c98d" filter="url(#uil-ring-shadow)">
                            <animateTransform attributeName="transform" type="rotate" from="0 50 50" to="360 50 50" repeatCount="indefinite" dur="1s"></animateTransform>
                        </path>
                    </svg>

 : null}

        )
    }

}

export default Articles
<commit_msg>Source check for images that are tracking pixels or null<commit_after>import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import { connect } from 'react-redux'

import Hostname from 'components/Hostname'
import Summary from 'components/Summary'

import Waypoint from 'react-waypoint'
import ProgressiveImage from 'react-progressive-image'

import * as ArticleActions from 'actions/Articles'

@connect()
class Article extends Component {

    trackEngagement = e => this.props.dispatch(
        ArticleActions.engage(this.props.object.id, (this.props.index + 7))
    )

    trackImpression = () => this.props.dispatch(
        ArticleActions.impression(this.props.object.id)
    )

    handleImgLoad = (src, id) => {
        if (src == null || src.indexOf('track') != -1) {
            document.getElementById(id).src = '../img/app/placeholder.png'
        }
    }

    render() {

        return (

                    <Waypoint onEnter={() => {
                        this.trackImpression(this.props.object.id)
                    }} />

                        <ProgressiveImage src={this.props.object.imageSrc} placeholder='../img/app/placeholder.png'>
                            {(src) =>
                                 this.handleImgLoad(src, this.props.object.id)}
                                    id={this.props.object.id} />
                            }
                        </ProgressiveImage>

                            {this.props.object.title}

                        {this.props.object.summary}

                        {this.props.site.name || this.props.site.siteUrl}

        )
    }

}

@connect(state => ({ articles: state.Articles, }))
class Articles extends Component {

    state = {
        appending: false,
        page: 1,
        version: null,
    }

    handleScroll = e => {

        if (this.$i || this.state.appending) {
            clearTimeout(this.$i)
        }

        this.$i = setTimeout(() => {

            if (this.state.appending) return

            if (((this.$scrollY || 0) - window.scrollY) >= 0) {
                return
            }

            this.$scrollY = window.scrollY

            const offset = document.body.scrollTop + window.innerHeight,
                  height = document.body.offsetHeight

            if (offset > (height - 100)) {
                this.setState({ appending: true, page: this.state.page + 1, })
                this.props.dispatch(ArticleActions.load(this.state.page))
                    .then(() => this.setState({ appending: false, }))
            }
        }, 200)
    }

    componentDidMount() {
        window.addEventListener('scroll', this.handleScroll)
    }

    componentWillUnmount() {
        window.removeEventListener('scroll', this.handleScroll)
    }

    render() {
        return (

                {this.props.articles.slice(7).map((article, index) =>
                    <Article {...article} index={index} key={`article-${article.object.id}`} />
                )}
                {this.state.appending ?

                    <svg width="35px" height="35px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" className="uil-ring">
                        <rect x="0" y="0" width="100" height="100" fill="none" className="bk"></rect>
                        <defs>
                            <filter id="uil-ring-shadow" x="-100%" y="-100%" width="300%" height="300%">
                                <feOffset result="offOut" in="SourceGraphic" dx="0" dy="0"></feOffset>
                                <feGaussianBlur result="blurOut" in="offOut" stdDeviation="0"></feGaussianBlur>
                                <feBlend in="SourceGraphic" in2="blurOut" mode="normal"></feBlend>
                            </filter>
                        </defs>
                        <path d="M10,50c0,0,0,0.5,0.1,1.4c0,0.5,0.1,1,0.2,1.7c0,0.3,0.1,0.7,0.1,1.1c0.1,0.4,0.1,0.8,0.2,1.2c0.2,0.8,0.3,1.8,0.5,2.8 c0.3,1,0.6,2.1,0.9,3.2c0.3,1.1,0.9,2.3,1.4,3.5c0.5,1.2,1.2,2.4,1.8,3.7c0.3,0.6,0.8,1.2,1.2,1.9c0.4,0.6,0.8,1.3,1.3,1.9 c1,1.2,1.9,2.6,3.1,3.7c2.2,2.5,5,4.7,7.9,6.7c3,2,6.5,3.4,10.1,4.6c3.6,1.1,7.5,1.5,11.2,1.6c4-0.1,7.7-0.6,11.3-1.6 c3.6-1.2,7-2.6,10-4.6c3-2,5.8-4.2,7.9-6.7c1.2-1.2,2.1-2.5,3.1-3.7c0.5-0.6,0.9-1.3,1.3-1.9c0.4-0.6,0.8-1.3,1.2-1.9 c0.6-1.3,1.3-2.5,1.8-3.7c0.5-1.2,1-2.4,1.4-3.5c0.3-1.1,0.6-2.2,0.9-3.2c0.2-1,0.4-1.9,0.5-2.8c0.1-0.4,0.1-0.8,0.2-1.2 c0-0.4,0.1-0.7,0.1-1.1c0.1-0.7,0.1-1.2,0.2-1.7C90,50.5,90,50,90,50s0,0.5,0,1.4c0,0.5,0,1,0,1.7c0,0.3,0,0.7,0,1.1 c0,0.4-0.1,0.8-0.1,1.2c-0.1,0.9-0.2,1.8-0.4,2.8c-0.2,1-0.5,2.1-0.7,3.3c-0.3,1.2-0.8,2.4-1.2,3.7c-0.2,0.7-0.5,1.3-0.8,1.9 c-0.3,0.7-0.6,1.3-0.9,2c-0.3,0.7-0.7,1.3-1.1,2c-0.4,0.7-0.7,1.4-1.2,2c-1,1.3-1.9,2.7-3.1,4c-2.2,2.7-5,5-8.1,7.1 c-0.8,0.5-1.6,1-2.4,1.5c-0.8,0.5-1.7,0.9-2.6,1.3L66,87.7l-1.4,0.5c-0.9,0.3-1.8,0.7-2.8,1c-3.8,1.1-7.9,1.7-11.8,1.8L47,90.8 c-1,0-2-0.2-3-0.3l-1.5-0.2l-0.7-0.1L41.1,90c-1-0.3-1.9-0.5-2.9-0.7c-0.9-0.3-1.9-0.7-2.8-1L34,87.7l-1.3-0.6 c-0.9-0.4-1.8-0.8-2.6-1.3c-0.8-0.5-1.6-1-2.4-1.5c-3.1-2.1-5.9-4.5-8.1-7.1c-1.2-1.2-2.1-2.7-3.1-4c-0.5-0.6-0.8-1.4-1.2-2 c-0.4-0.7-0.8-1.3-1.1-2c-0.3-0.7-0.6-1.3-0.9-2c-0.3-0.7-0.6-1.3-0.8-1.9c-0.4-1.3-0.9-2.5-1.2-3.7c-0.3-1.2-0.5-2.3-0.7-3.3 c-0.2-1-0.3-2-0.4-2.8c-0.1-0.4-0.1-0.8-0.1-1.2c0-0.4,0-0.7,0-1.1c0-0.7,0-1.2,0-1.7C10,50.5,10,50,10,50z" fill="#16c98d" filter="url(#uil-ring-shadow)">
                            <animateTransform attributeName="transform" type="rotate" from="0 50 50" to="360 50 50" repeatCount="indefinite" dur="1s"></animateTransform>
                        </path>
                    </svg>

 : null}

        )
    }

}

export default Articles
<|endoftext|>


<commit_before>import React, {Component} from 'react'
import {Button, Panel} from 'react-bootstrap'
import Helmet from 'react-helmet'
import {Page, ScrollView, View} from 'zanata-ui'

const contentViewContainerTheme = {
  base: {
    w: 'W(100%)'
  }
}
const title = (

Panel title

)
const panelsInstance = (

    <Panel header={title}>

Panel content

    </Panel>

)

class ManageSearch extends Component {

  render () {
    return (
      <Page>
        <Helmet title='ManageSearch' />
        <ScrollView>
          <View theme={contentViewContainerTheme}>

Manage Search

                  <panelsInstance>
                    <Panel bsStyle='primary' header={title}>
                        Panel content
                    </Panel>
                  </panelsInstance>

                          Username

                            admin

                            [user, glossary-admin]

                            <Button bsSize='small'>

                            Delete</Button>

                            glossarist

                            <Button bsSize='small'>

                            Delete</Button>

                            glossary-admin

                            [glossarist]

                            <Button bsSize='small'>

                            Delete</Button>

                            project-creator

                            <Button bsSize='small'>

                            Delete</Button>

                            translator

                            ar

                            <Button bsSize='small'>

                            Delete</Button>

                            user

                            [project-creator]

                            <Button bsSize='small'>

                            Delete</Button>

          </View>
        </ScrollView>
      </Page>
    )
  }
}
export default ManageSearch
<commit_msg>added button and table cells<commit_after>import React, {Component} from 'react'
import {Button} from 'react-bootstrap'
import Helmet from 'react-helmet'
import {Page, ScrollView, View} from 'zanata-ui'

const contentViewContainerTheme = {
  base: {
    w: 'W(100%)'
  }
}

class ManageSearch extends Component {

  render () {
    return (
      <Page>
        <Helmet title='ManageSearch' />
        <ScrollView>
          <View theme={contentViewContainerTheme}>

Manage Search

Current progress

                      No operations are running

                          Table
                          Purge index
                          Reindex
                          Optimise

              <Button bsStyle='primary'>
              Perform selected actions</Button>

          </View>
        </ScrollView>
      </Page>
    )
  }
}
export default ManageSearch
<|endoftext|>


<commit_before>var r = 1;
require('classpath:/com/nominanuda/rhino/JUnit.js').assert(r === 1);<commit_msg>added console test<commit_after>require('console').log('blah');
var r = 1;
require('classpath:/com/nominanuda/rhino/JUnit.js').assert(r === 1);<|endoftext|>


<commit_before>/*
* Copyright (C) 2015-2016 by Arena of Titans Contributors.
*
* This file is part of Arena of Titans.
*
* Arena of Titans is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Arena of Titans is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Arena of Titans. If not, see <http://www.gnu.org/licenses/>.
*/

import { bindable, inject } from 'aurelia-framework';
import { CssAnimator } from 'aurelia-animator-css';
import { Game } from '../../game/game';
import { AssetSource } from '../../services/assets';

@inject(CssAnimator)
export class AotSelectHeroesCustomElement {
    @bindable selectedHero = null;
    // Referenced in the template.
    heroImage;

    constructor(animator) {
        this._animator = animator;

        this.assetSource = AssetSource;
        this.heroes = [];
        for (let hero of Game.heroes) {
            this.heroes.push({
                name: hero,
                next: null,
                previous: this.heroes.length > 0 ? this.heroes[this.heroes.length - 1] : null,
            });
        }
        this.heroes[0].previous = this.heroes[this.heroes.length - 1];
        this.heroes.forEach((hero, index) => {
            if (index < this.heroes.length - 1) {
                let nextIndex = index + 1;
                hero.next = this.heroes[nextIndex];
            } else {
                hero.next = this.heroes[0];
            }
        });
    }

    bind() {
        this._updateDisplayedHeroFromSelected();

        // Listen to keyup event to change hero with keyboard.
        this._keyupEventListener = event => {
            // code doesn't exist on IE, we need to use key.
            let keyCode = event.code || event.key;

            // The player must validate the game over popup
            if (keyCode === 'ArrowRight') {
                this.viewNextHero();
            } else if (keyCode === 'ArrowLeft') {
                this.viewPreviousHero();
            }
        };
        window.addEventListener('keyup', this._keyupEventListener);
    }

    /**
     * Update the _displayedHero property used to navigate between heroes from the selectedHero
     * property.
     *
     * This must be done on component initialization and each time the selectedHero property is
     * changed outside this component so the navigation is correct.
     */
    _updateDisplayedHeroFromSelected() {
        for (let hero of this.heroes) {
            if (hero.name === this.selectedHero) {
                this._displayedHero = hero;
                break;
            }
        }
    }

    viewNextHero() {
        this._displayedHero = this._displayedHero.next;
        this.selectedHero = this._displayedHero.name;
    }

    /**
     * When we change the hero, we use the animator to add the .change-hero class to animate the
     * transition between hero images. We reduce the opacity of the image, change the image and
     * increase the opacity agin. This is done with the aurelia-animator-css plugin. According
     * to the documentation of the plugin, the heroImage element will have the following classes
     * (each class is removed before the next one is added):
     * - the .change-hero-add class to animate the addition of the class, we must fade out to
     *   change the image of the hero.
     * - the .change-hero class when we change the image.
     * - the .change-hero-remove class to animate the removal of the class, we must fade in to
     *   display the image of the new hero.
     */
    _animateHero() {
        return this._animator.addClass(this.heroImage, 'change-hero').then(() => {
            return this._animator.removeClass(this.heroImage, 'change-hero');
        });
    }

    viewPreviousHero() {
        this._displayedHero = this._displayedHero.previous;
        this.selectedHero = this._displayedHero.name;
    }

    selectedHeroChanged() {
        this._animateHero();
        this._updateDisplayedHeroFromSelected();
    }

    unbind() {
        window.removeEventListener('keyup', this._keyupEventListener);
    }
}
<commit_msg>fix(select-heroes): don't change hero if the user is in an input<commit_after>/*
* Copyright (C) 2015-2016 by Arena of Titans Contributors.
*
* This file is part of Arena of Titans.
*
* Arena of Titans is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Arena of Titans is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Arena of Titans. If not, see <http://www.gnu.org/licenses/>.
*/

import { bindable, inject } from 'aurelia-framework';
import { CssAnimator } from 'aurelia-animator-css';
import { Game } from '../../game/game';
import { AssetSource } from '../../services/assets';

const INPUT_NODE_NAMES = ['INPUT', 'TEXTAREA'];

@inject(CssAnimator)
export class AotSelectHeroesCustomElement {
    @bindable selectedHero = null;
    // Referenced in the template.
    heroImage;

    constructor(animator) {
        this._animator = animator;

        this.assetSource = AssetSource;
        this.heroes = [];
        for (let hero of Game.heroes) {
            this.heroes.push({
                name: hero,
                next: null,
                previous: this.heroes.length > 0 ? this.heroes[this.heroes.length - 1] : null,
            });
        }
        this.heroes[0].previous = this.heroes[this.heroes.length - 1];
        this.heroes.forEach((hero, index) => {
            if (index < this.heroes.length - 1) {
                let nextIndex = index + 1;
                hero.next = this.heroes[nextIndex];
            } else {
                hero.next = this.heroes[0];
            }
        });
    }

    bind() {
        this._updateDisplayedHeroFromSelected();

        // Listen to keyup event to change hero with keyboard.
        this._keyupEventListener = event => {
            // Don't change hero if the user is using arrow keys in an input/textarea.
            if (INPUT_NODE_NAMES.includes(event.target.nodeName)) {
                return;
            }

            // code doesn't exist on IE, we need to use key.
            let keyCode = event.code || event.key;

            // The player must validate the game over popup
            if (keyCode === 'ArrowRight') {
                this.viewNextHero();
            } else if (keyCode === 'ArrowLeft') {
                this.viewPreviousHero();
            }
        };
        window.addEventListener('keyup', this._keyupEventListener);
    }

    /**
     * Update the _displayedHero property used to navigate between heroes from the selectedHero
     * property.
     *
     * This must be done on component initialization and each time the selectedHero property is
     * changed outside this component so the navigation is correct.
     */
    _updateDisplayedHeroFromSelected() {
        for (let hero of this.heroes) {
            if (hero.name === this.selectedHero) {
                this._displayedHero = hero;
                break;
            }
        }
    }

    viewNextHero() {
        this._displayedHero = this._displayedHero.next;
        this.selectedHero = this._displayedHero.name;
    }

    /**
     * When we change the hero, we use the animator to add the .change-hero class to animate the
     * transition between hero images. We reduce the opacity of the image, change the image and
     * increase the opacity agin. This is done with the aurelia-animator-css plugin. According
     * to the documentation of the plugin, the heroImage element will have the following classes
     * (each class is removed before the next one is added):
     * - the .change-hero-add class to animate the addition of the class, we must fade out to
     *   change the image of the hero.
     * - the .change-hero class when we change the image.
     * - the .change-hero-remove class to animate the removal of the class, we must fade in to
     *   display the image of the new hero.
     */
    _animateHero() {
        return this._animator.addClass(this.heroImage, 'change-hero').then(() => {
            return this._animator.removeClass(this.heroImage, 'change-hero');
        });
    }

    viewPreviousHero() {
        this._displayedHero = this._displayedHero.previous;
        this.selectedHero = this._displayedHero.name;
    }

    selectedHeroChanged() {
        this._animateHero();
        this._updateDisplayedHeroFromSelected();
    }

    unbind() {
        window.removeEventListener('keyup', this._keyupEventListener);
    }
}
<|endoftext|>


<commit_before>function checkForPeevskiDomain(url) {
  var blockedDomains = [
    'monitor.bg',
    'telegraph.bg',
    'politika.bg',
    'europost.eu',
    'europost.bg',
    'borbabg.com',
    'tv7.bg',
    'news7.bg',
    'super7.bg',
    '3bay.bg',
    'econ.bg',
    'inews.bg',
    'jenite.bg',
    'div.bg',
    'sporta.bg',
    'fitwell.bg',
    'sportuvaj.bg',
    'peika.bg',
    'kulinar.bg',
    'sever.bg',
    'get.bg',
    'bnews.bg',
    'bsport.bg',
    'blife.bg',
    'bpost.bg',
    'bmobile.bg',
    'blitz.bg',
    'standartnews.com',
    'struma.bg',
    'marica.bg',
    'vsekiden.com',
    'novinar.bg',
    'radiovitosha.com',
    'radioveselina.bg',
    'magicfm.bg',
    'thevoice.bg'
  ];

  var urlPattern;
  for (var i = 0; i < blockedDomains.length; i++) {
    urlPattern = new RegExp("^http(s)?\\:\\/\\/([^\\/]+\\.)?" + blockedDomains[i]);
    if (urlPattern.test(url)) {
      return blockedDomains[i];
    }
  }

  return false;
}

if (typeof exports !== 'undefined') {
  exports.checkForPeevskiDomain = checkForPeevskiDomain;
}
<commit_msg>sportuvaj.bg е всъщност sportuvai.bg<commit_after>function checkForPeevskiDomain(url) {
  var blockedDomains = [
    'monitor.bg',
    'telegraph.bg',
    'politika.bg',
    'europost.eu',
    'europost.bg',
    'borbabg.com',
    'tv7.bg',
    'news7.bg',
    'super7.bg',
    '3bay.bg',
    'econ.bg',
    'inews.bg',
    'jenite.bg',
    'div.bg',
    'sporta.bg',
    'fitwell.bg',
    'sportuvai.bg',
    'peika.bg',
    'kulinar.bg',
    'sever.bg',
    'get.bg',
    'bnews.bg',
    'bsport.bg',
    'blife.bg',
    'bpost.bg',
    'bmobile.bg',
    'blitz.bg',
    'standartnews.com',
    'struma.bg',
    'marica.bg',
    'vsekiden.com',
    'novinar.bg',
    'radiovitosha.com',
    'radioveselina.bg',
    'magicfm.bg',
    'thevoice.bg'
  ];

  var urlPattern;
  for (var i = 0; i < blockedDomains.length; i++) {
    urlPattern = new RegExp("^http(s)?\\:\\/\\/([^\\/]+\\.)?" + blockedDomains[i]);
    if (urlPattern.test(url)) {
      return blockedDomains[i];
    }
  }

  return false;
}

if (typeof exports !== 'undefined') {
  exports.checkForPeevskiDomain = checkForPeevskiDomain;
}
<|endoftext|>


<commit_before>var _jade = require('jade');
var fs = require('fs');
var usersDB = require("mongoose").model("User");
var transport = require("../../config/mail");
var hostName = require('os').hostname();
var templateDir = process.cwd()+"/app_api/controllers/mails/";
var centralTo = transport.transport.centralTo;

var compileJade = function(jadeFile, locals, cb){
  var template = process.cwd()+"/app_api/controllers/mails/"+jadeFile;

  fs.readFile(template, "utf8", function(err, file){
    if (err){
      console.log(err);
      cb(null);
    }else {
      var compiledTmpl = _jade.compile(file);

      var toto = compiledTmpl(locals);
      cb(toto);

    }
  });
};

var _classeFromDefiNiveau = require("../utils").classeFromDefiNiveau;

function _toNodeMailerString2(users){
  if (centralTo !== undefined){
    return centralTo;
  }

  var res="";
  var recipientVars = {};
  users.forEach(function(user){
    res +=user.name+" <"+user.email+">,";
    var m = user.email;
    recipientVars[m] = {name: user.name};
  });

  return {
    recipientVars: recipientVars,
    toString: res
  }
};

function _toNodeMailerString(users){
  return _toNodeMailerString2(users).toString;
}

module.exports = {
  newUserNeedValidations: function(req, newUser){

    usersDB.find({role: "admin"}, "name email", function(err, admins){
      if (err){
        console.error(err);
      }else{

        var toString = _toNodeMailerString(admins);
        var userPageUrl = "http://"+req.headers.host+"/users";

        compileJade("newUser.jade", {newUser:newUser, usersUrl: userPageUrl}, function(html){

          // setup e-mail data with unicode symbols
          var mailOptions = {
              from: '"zenigmes" <zenigmes@bzenigmes.fr>', // sender address
              to: toString,
              subject: "Un nouvel utilisateur s'est inscrit aux zenigmes", // Subject line
              html: html // html body
          };

          // send mail with defined transport object
          transport.sendMail(mailOptions, module.exports.cb);
        });

      }
    });
  },
  messageToAdmin: function(req, message, fromUser){
    usersDB.find({role: "admin"}, "name email", function(err, admins){
      if (err){
        console.error(err);
      }else{
        var recipients = _toNodeMailerString2(admins);

        var userPageUrl = "http://"+req.headers.host+"/users";

        var context = {fromUser:fromUser, message: message};

        // setup e-mail data with unicode symbols
        var mailOptions = {
            from: '"zenigmes" <zenigmes@bzenigmes.fr>', // sender address
            to: recipients.toString,
            "recipient-variables": recipients.recipientVars,
            subject: context.fromUser.name+" vous contacte directement", // Subject line

            template: {
              name: templateDir+"adminMessage.jade",
              engine: "jade",
              context: context
            },
        };

        // send mail with defined transport object
        transport.sendMail(mailOptions, module.exports.cb);

      }
    });
  },
  defiHasBeenCreated: function(req, newDefi){

     // retrieve the participants of the session
    usersDB.find({$or: [
      {"_id":{$in: newDefi.participants}},
      {"classe":{$in: _classeFromDefiNiveau(newDefi)}},
    ]},"name email",function(err, users){

      var recipients = _toNodeMailerString2(users);

      var mesDefisPageUrl = "http://"+req.headers.host+"/mesdefis";

      compileJade("newDefi.jade", {defi:newDefi, mesDefis: mesDefisPageUrl}, function(html){

          // setup e-mail data with unicode symbols
          var mailOptions = {
              from: '"zenigmes" <zenigmes@bzenigmes.fr>', // sender address
              to: recipients.toString,
              "recipient-variables": recipients.recipientVars,
              subject: "Un nouveau défi vient d'être créé", // Subject line
              html: html // html body
          };

          // send mail with defined transport object
          transport.sendMail(mailOptions, module.exports.cb);
      });

    });

  },
  accountValidated: function(req, user){

    var toString = _toNodeMailerString([user]);

    var mesDefisPageUrl = "http://"+req.headers.host+"/mesdefis";

    compileJade("accountValidated.jade", {mesDefis: mesDefisPageUrl}, function(html){

        // setup e-mail data with unicode symbols
        var mailOptions = {
            from: '"zenigmes" <zenigmes@zenigmes.fr>', // sender address
            to: toString,
            subject: "Votre compte a été validé", // Subject line
            html: html // html body
        };

        // send mail with defined transport object
        transport.sendMail(mailOptions, module.exports.cb);
      });

  },
  enigmeAboutToStart: function(defi, enigme){
    usersDB.find({$or: [
      {"_id":{$in: defi.participants}},
      {"classe":{$in: _classeFromDefiNiveau(defi)}},
    ]},"name email",function(err, users){
      var recipients = _toNodeMailerString2(users);

      // no request objects for scheduled mail to derive the host name
      // for the moment, I'll put it hardcoded. But this needs to change
      var enigmeUrl = "http://www.zenigmes.fr/enigmes/"+enigme._id+"?sessionid="+defi._id;

      compileJade("enigmeAboutToStart.jade", {enigme: enigme,enigmeAnswer: enigmeUrl}, function(html){

        // setup e-mail data with unicode symbols
        var mailOptions = {
            from: '"zenigmes" <zenigmes@zenigmes.fr>', // sender address
            to: recipients.toString,
            "recipient-variables": recipients.recipientVars,
            subject: "Une énigme de votre défi est disponible: répondez vite ", // Subject line
            html: html // html body
        };

        // send mail with defined transport object
        transport.sendMail(mailOptions, module.exports.cb);
      });

    });
  },
  passwordReset: function(req, user){
      var toString = _toNodeMailerString([user]);

      var passResetUrl = "http://"+req.headers.host+"/reset/"+user.resetPasswordToken;

      compileJade("passwordReset.jade", {passResetUrl: passResetUrl}, function(html){

        // setup e-mail data with unicode symbols
        var mailOptions = {
            from: '"zenigmes" <zenigmes@zenigmes.fr>', // sender address
            to: toString,
            subject: "Demande de nouveau mot de passe pour les Zenigmes", // Subject line
            html: html // html body
        };

        // send mail with defined transport object
        transport.sendMail(mailOptions, module.exports.cb);
      });
  },
  passwordHasChanged: function(req, user){
      var toString = _toNodeMailerString([user]);

      compileJade("passwordChanged.jade", {user: user}, function(html){

        // setup e-mail data with unicode symbols
        var mailOptions = {
            from: '"zenigmes" <zenigmes@zenigmes.fr>', // sender address
            to: toString,
            subject: "Mot de passe changé", // Subject line
            html: html // html body
        };

        // send mail with defined transport object
        transport.sendMail(mailOptions, module.exports.cb);
      });
  },
  cb: function(error, info){
        if(error){
          console.error(error);
        }
      }
};<commit_msg>correct mail host because original host is no longer used<commit_after>var _jade = require('jade');
var fs = require('fs');
var usersDB = require("mongoose").model("User");
var transport = require("../../config/mail");
var hostName = require('os').hostname();
var templateDir = process.cwd()+"/app_api/controllers/mails/";
var centralTo = transport.transport.centralTo;

var compileJade = function(jadeFile, locals, cb){
  var template = process.cwd()+"/app_api/controllers/mails/"+jadeFile;

  fs.readFile(template, "utf8", function(err, file){
    if (err){
      console.log(err);
      cb(null);
    }else {
      var compiledTmpl = _jade.compile(file);

      var toto = compiledTmpl(locals);
      cb(toto);

    }
  });
};

var _classeFromDefiNiveau = require("../utils").classeFromDefiNiveau;

function _toNodeMailerString2(users){
  if (centralTo !== undefined){
    return centralTo;
  }

  var res="";
  var recipientVars = {};
  users.forEach(function(user){
    res +=user.name+" <"+user.email+">,";
    var m = user.email;
    recipientVars[m] = {name: user.name};
  });

  return {
    recipientVars: recipientVars,
    toString: res
  }
};

function _toNodeMailerString(users){
  return _toNodeMailerString2(users).toString;
}

module.exports = {
  newUserNeedValidations: function(req, newUser){

    usersDB.find({role: "admin"}, "name email", function(err, admins){
      if (err){
        console.error(err);
      }else{

        var toString = _toNodeMailerString(admins);
        var userPageUrl = "http://"+req.headers.host+"/users";

        compileJade("newUser.jade", {newUser:newUser, usersUrl: userPageUrl}, function(html){

          // setup e-mail data with unicode symbols
          var mailOptions = {
              from: '"zenigmes" <zenigmes@bzenigmes.fr>', // sender address
              to: toString,
              subject: "Un nouvel utilisateur s'est inscrit aux zenigmes", // Subject line
              html: html // html body
          };

          // send mail with defined transport object
          transport.sendMail(mailOptions, module.exports.cb);
        });

      }
    });
  },
  messageToAdmin: function(req, message, fromUser){
    usersDB.find({role: "admin"}, "name email", function(err, admins){
      if (err){
        console.error(err);
      }else{
        var recipients = _toNodeMailerString2(admins);

        var userPageUrl = "http://"+req.headers.host+"/users";

        var context = {fromUser:fromUser, message: message};

        // setup e-mail data with unicode symbols
        var mailOptions = {
            from: '"zenigmes" <zenigmes@bzenigmes.fr>', // sender address
            to: recipients.toString,
            "recipient-variables": recipients.recipientVars,
            subject: context.fromUser.name+" vous contacte directement", // Subject line

            template: {
              name: templateDir+"adminMessage.jade",
              engine: "jade",
              context: context
            },
        };

        // send mail with defined transport object
        transport.sendMail(mailOptions, module.exports.cb);

      }
    });
  },
  defiHasBeenCreated: function(req, newDefi){

     // retrieve the participants of the session
    usersDB.find({$or: [
      {"_id":{$in: newDefi.participants}},
      {"classe":{$in: _classeFromDefiNiveau(newDefi)}},
    ]},"name email",function(err, users){

      var recipients = _toNodeMailerString2(users);

      var mesDefisPageUrl = "http://"+req.headers.host+"/mesdefis";

      compileJade("newDefi.jade", {defi:newDefi, mesDefis: mesDefisPageUrl}, function(html){

          // setup e-mail data with unicode symbols
          var mailOptions = {
              from: '"zenigmes" <zenigmes@bzenigmes.fr>', // sender address
              to: recipients.toString,
              "recipient-variables": recipients.recipientVars,
              subject: "Un nouveau défi vient d'être créé", // Subject line
              html: html // html body
          };

          // send mail with defined transport object
          transport.sendMail(mailOptions, module.exports.cb);
      });

    });

  },
  accountValidated: function(req, user){

    var toString = _toNodeMailerString([user]);

    var mesDefisPageUrl = "http://"+req.headers.host+"/mesdefis";

    compileJade("accountValidated.jade", {mesDefis: mesDefisPageUrl}, function(html){

        // setup e-mail data with unicode symbols
        var mailOptions = {
            from: '"zenigmes" <zenigmes@zenigmes.fr>', // sender address
            to: toString,
            subject: "Votre compte a été validé", // Subject line
            html: html // html body
        };

        // send mail with defined transport object
        transport.sendMail(mailOptions, module.exports.cb);
      });

  },
  enigmeAboutToStart: function(defi, enigme){
    usersDB.find({$or: [
      {"_id":{$in: defi.participants}},
      {"classe":{$in: _classeFromDefiNiveau(defi)}},
    ]},"name email",function(err, users){
      var recipients = _toNodeMailerString2(users);

      // no request objects for scheduled mail to derive the host name
      // for the moment, I'll put it hardcoded. But this needs to change
      var enigmeUrl = "https://zenigmes.herokuapp.com/enigmes/"+enigme._id+"?sessionid="+defi._id;

      compileJade("enigmeAboutToStart.jade", {enigme: enigme,enigmeAnswer: enigmeUrl}, function(html){

        // setup e-mail data with unicode symbols
        var mailOptions = {
            from: '"zenigmes" <zenigmes@zenigmes.fr>', // sender address
            to: recipients.toString,
            "recipient-variables": recipients.recipientVars,
            subject: "Une énigme de votre défi est disponible: répondez vite ", // Subject line
            html: html // html body
        };

        // send mail with defined transport object
        transport.sendMail(mailOptions, module.exports.cb);
      });

    });
  },
  passwordReset: function(req, user){
      var toString = _toNodeMailerString([user]);

      var passResetUrl = "http://"+req.headers.host+"/reset/"+user.resetPasswordToken;

      compileJade("passwordReset.jade", {passResetUrl: passResetUrl}, function(html){

        // setup e-mail data with unicode symbols
        var mailOptions = {
            from: '"zenigmes" <zenigmes@zenigmes.fr>', // sender address
            to: toString,
            subject: "Demande de nouveau mot de passe pour les Zenigmes", // Subject line
            html: html // html body
        };

        // send mail with defined transport object
        transport.sendMail(mailOptions, module.exports.cb);
      });
  },
  passwordHasChanged: function(req, user){
      var toString = _toNodeMailerString([user]);

      compileJade("passwordChanged.jade", {user: user}, function(html){

        // setup e-mail data with unicode symbols
        var mailOptions = {
            from: '"zenigmes" <zenigmes@zenigmes.fr>', // sender address
            to: toString,
            subject: "Mot de passe changé", // Subject line
            html: html // html body
        };

        // send mail with defined transport object
        transport.sendMail(mailOptions, module.exports.cb);
      });
  },
  cb: function(error, info){
        if(error){
          console.error(error);
        }
      }
};<|endoftext|>


<commit_before>const Bookmark = require('../models/bookmark');

module.exports = {
   buildBookmarkFromRequest: function (req) {
    const descriptionHtml = req.body.descriptionHtml ? req.body.descriptionHtml : converter.makeHtml(req.body.description);
    const bookmark = new Bookmark({
      name: req.body.name,
      location: req.body.location,
      userId: req.body.userId,
      language: req.body.language,
      description: req.body.description,
      descriptionHtml: descriptionHtml,
      category: req.body.category,
      tags: req.body.tags,
      publishedOn: req.body.publishedOn,
      githubURL: req.body.githubURL,
      userId: req.body.userId || req.params.userId,
      shared: req.body.shared,
      starredBy: req.body.starredBy,
      lastAccessedAt: req.body.lastAccessedAt
    });

    return bookmark;
  }
}
<commit_msg>add missing import for converter<commit_after>//showdown converter - https://github.com/showdownjs/showdown
const showdown = require('showdown'),
  converter = new showdown.Converter();

const Bookmark = require('../models/bookmark');

module.exports = {
   buildBookmarkFromRequest: function (req) {
    const descriptionHtml = req.body.descriptionHtml ? req.body.descriptionHtml : converter.makeHtml(req.body.description);
    const bookmark = new Bookmark({
      name: req.body.name,
      location: req.body.location,
      userId: req.body.userId,
      language: req.body.language,
      description: req.body.description,
      descriptionHtml: descriptionHtml,
      category: req.body.category,
      tags: req.body.tags,
      publishedOn: req.body.publishedOn,
      githubURL: req.body.githubURL,
      userId: req.body.userId || req.params.userId,
      shared: req.body.shared,
      starredBy: req.body.starredBy,
      lastAccessedAt: req.body.lastAccessedAt
    });

    return bookmark;
  }
}
<|endoftext|>


<commit_before>import * as RA from '../src';
import eq from './shared/eq';

describe('flattenProp', function() {
  let prop;
  let obj;

  beforeEach(function() {
    prop = 'b';
    obj = {
      a: 1,
      b: { c: 3, d: 4 },
    };
  });

  it('should curry', function() {
    eq(RA.flattenProp('prop', {}), {});
    eq(RA.flattenProp('prop')({}), {});
  });

  context("given prop doesn't exist", function() {
    specify(
      'should return object with identical structure as provided object',
      function() {
        eq(RA.flattenProp('not_exist', obj), obj);
      }
    );
  });

  context('given prop leads to non object', function() {
    specify(
      'should return object with identical structure as provided object',
      function() {
        obj = {
          a: 1,
          b: 999,
        };
        eq(RA.flattenProp(prop, obj), obj);
      }
    );
  });

  context('given prop leads to object with same prop name', function() {
    specify('should override existing props on provided object', function() {
      obj = {
        a: 1,
        b: { b: 999, c: 3, d: 4 },
      };
      const expected = {
        a: 1,
        c: 3,
        d: 4,
        b: 999,
      };

      eq(RA.flattenProp(prop, obj), expected);
    });
  });

  it('should return object with flattened prop', function() {
    const expected = {
      a: 1,
      c: 3,
      d: 4,
      b: { c: 3, d: 4 },
    };

    eq(RA.flattenProp(prop, obj), expected);
  });
});
<commit_msg>test(flattenProp): fix tests ordering<commit_after>import * as RA from '../src';
import eq from './shared/eq';

describe('flattenProp', function() {
  let prop;
  let obj;

  beforeEach(function() {
    prop = 'b';
    obj = {
      a: 1,
      b: { c: 3, d: 4 },
    };
  });

  context("given prop doesn't exist", function() {
    specify(
      'should return object with identical structure as provided object',
      function() {
        eq(RA.flattenProp('not_exist', obj), obj);
      }
    );
  });

  context('given prop leads to non object', function() {
    specify(
      'should return object with identical structure as provided object',
      function() {
        obj = {
          a: 1,
          b: 999,
        };
        eq(RA.flattenProp(prop, obj), obj);
      }
    );
  });

  context('given prop leads to object with same prop name', function() {
    specify('should override existing props on provided object', function() {
      obj = {
        a: 1,
        b: { b: 999, c: 3, d: 4 },
      };
      const expected = {
        a: 1,
        c: 3,
        d: 4,
        b: 999,
      };

      eq(RA.flattenProp(prop, obj), expected);
    });
  });

  it('should return object with flattened prop', function() {
    const expected = {
      a: 1,
      c: 3,
      d: 4,
      b: { c: 3, d: 4 },
    };

    eq(RA.flattenProp(prop, obj), expected);
  });

  it('should curry', function() {
    eq(RA.flattenProp('prop', {}), {});
    eq(RA.flattenProp('prop')({}), {});
  });
});
<|endoftext|>