<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { isEqual } from 'lodash';
import Headline from '@folio/stripes-components/lib/Headline';
import { Dropdown } from '@folio/stripes-components/lib/Dropdown'; // eslint-disable-line
import { withRouter } from 'react-router';
import localforage from 'localforage';

import { modules } from 'stripes-config'; // eslint-disable-line

import { clearOkapiToken, clearCurrentUser } from '../../okapiActions';
import { resetStore } from '../../mainActions';
import { updateQueryResource, updateLocation } from '../../locationService';

import css from './MainNav.css';
import NavButton from './NavButton';
import NavDivider from './NavDivider';
import NavGroup from './NavGroup';
import Breadcrumbs from './Breadcrumbs';
import CurrentApp from './CurrentApp';
import MyProfile from './MyProfile';
import NotificationsDropdown from './Notifications/NotificationsDropdown';
import settingsIcon from './settings.svg';

// Temporary until settings becomes an app
const settingsIconData = {
  src: settingsIcon,
  alt: 'Tenant Settings',
  title: 'Settings',
};

if (!Array.isArray(modules.app) || modules.app.length < 1) {
  throw new Error('At least one module of type "app" must be enabled.');
}

class MainNav extends Component {
  static contextTypes = {
    router: PropTypes.object.isRequired,
  }

  static childContextTypes = {
    // It seems wrong that we have to tell this generic component what specific properties to put in the context
    stripes: PropTypes.object,
  };

  static propTypes = {
    stripes: PropTypes.shape({
      config: PropTypes.shape({
        showPerms: PropTypes.bool,
      }),
      store: PropTypes.shape({
        dispatch: PropTypes.func.isRequired,
      }),
      hasPerm: PropTypes.func.isRequired,
      withOkapi: PropTypes.bool,
    }),
    history: PropTypes.shape({
      listen: PropTypes.func.isRequired,
      replace: PropTypes.func.isRequired,
      push: PropTypes.func.isRequired,
    }).isRequired,
    location: PropTypes.shape({
      pathname: PropTypes.string,
    }).isRequired,
  };

  constructor(props) {
    super(props);
    this.state = {
      userMenuOpen: false,
    };
    this.store = props.stripes.store;
    this.logout = this.logout.bind(this);
    this.lastVisited = {};
    this.queryValues = null;

    this.moduleList = modules.app.concat({
      route: '/settings',
      module: '@folio/x_settings',
    });

    props.history.listen((hist) => {
      for (const entry of this.moduleList) {
        if (hist.pathname === entry.route || hist.pathname.startsWith(`${entry.route}/`)) {
          const name = entry.module.replace(/^@folio\//, '');
          this.lastVisited[name] = `${hist.pathname}${hist.search}`;
        }
      }
    });
  }

  getChildContext() {
    return {
      stripes: this.props.stripes,
    };
  }

  componentDidMount() {
    let curQuery = null;
    this.store.subscribe(() => {
      const { history, location } = this.props;
      const module = this.curModule;
      if (module && location.pathname.startsWith(module.route)) {
        curQuery = updateLocation(module, curQuery, this.store, history, location);
      }
    });
  }

  componentDidUpdate(prevProps) {
    const { location } = this.props;
    this.curModule = this.moduleList.find(m => location.pathname.startsWith(m.route) && m.queryResource);
    if (this.curModule && !isEqual(location, prevProps.location)) {
      updateQueryResource(location, this.curModule, this.store);
    }
  }

  toggleUserMenu() {
    const isOpen = this.state.userMenuOpen;
    this.setState({
      userMenuOpen: !isOpen,
    });
  }

  logout() {
    this.store.dispatch(clearOkapiToken());
    this.store.dispatch(clearCurrentUser());
    this.store.dispatch(resetStore());
    localforage.removeItem('okapiSess');
    this.context.router.history.push('/');
  }

  render() {
    const { stripes, location: { pathname } } = this.props;
    const selectedApp = modules.app.find(entry => pathname.startsWith(entry.route));

    const menuLinks = modules.app.map((entry) => {
      const name = entry.module.replace(/^@[a-z0-9_]+\//, '');
      const perm = `module.${name}.enabled`;

      if (!stripes.hasPerm(perm)) {
        return null;
      }

      const navId = `clickable-${name}-module`;
      const isActive = pathname.startsWith(entry.route);
      const href = !isActive ? (this.lastVisited[name] || entry.home || entry.route) : null;

      return (
        <NavButton
          label={entry.displayName}
          id={navId}
          selected={isActive}
          href={href}
          title={entry.displayName}
          key={entry.route}
          iconKey={name}
        />);
    });

    let firstNav;
    let breadcrumbArray = []; // eslint-disable-line

    // Temporary solution until Settings becomes a standalone app
    let settingsApp;
    if (stripes.hasPerm('settings.enabled') && pathname.startsWith('/settings')) {
      settingsApp = { displayName: 'Settings', description: 'FOLIO settings' };
    }

    if (breadcrumbArray.length === 0) {
      firstNav = (
        <NavGroup md="hide">

            <svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 26 26">
              <polygon style={{ fill: '#999' }} points="13 16.5 1.2 5.3 3.2 3.1 13 12.4 22.8 3.1 24.8 5.3 " />
              <polygon style={{ fill: '#999' }} points="13 24.8 1.2 13.5 3.2 11.3 13 20.6 22.8 11.3 24.8 13.5 " />
            </svg>

          <CurrentApp
            id="ModuleMainHeading"
            currentApp={selectedApp || settingsApp}
            iconData={settingsApp && settingsIconData}
          />
        </NavGroup>
      );
    } else {
      firstNav = (
        <NavGroup>
          <NavButton md="hide" />
          <Breadcrumbs linkArray={breadcrumbArray} />
        </NavGroup>
      );
    }

    return (

        {firstNav}

          <Headline tag="h2" className="sr-only">Main Navigation</Headline>
        <NavGroup>
          <NavGroup>
            {menuLinks}
            {
              !stripes.hasPerm('settings.enabled') ? '' : (
                <NavButton
                  label="Settings"
                  id="clickable-settings"
                  title="Settings"
                  iconData={settingsIconData}
                  selected={pathname.startsWith('/settings')}
                  href={pathname.startsWith('/settings') ? null : (this.lastVisited.x_settings || '/settings')}
                />
              )
            }
          </NavGroup>
          <NavGroup className={css.smallAlignRight}>
            <NavDivider md="hide" />
            { this.props.stripes.withOkapi && this.props.stripes.hasPerm('notify.item.get,notify.item.put,notify.collection.get') && <NotificationsDropdown stripes={stripes} {...this.props} /> }
            { /* temporary divider solution.. */ }
            { this.props.stripes.hasPerm('notify.item.get,notify.item.put,notify.collection.get') && (<NavDivider md="hide" />) }
            <MyProfile
              onLogout={this.logout}
              stripes={stripes}
            />
          </NavGroup>
        </NavGroup>

    );
  }
}

export default withRouter(MainNav);
<commit_msg>YOU. YOU must LINT!<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { isEqual } from 'lodash';
import Headline from '@folio/stripes-components/lib/Headline';
import { Dropdown } from '@folio/stripes-components/lib/Dropdown'; // eslint-disable-line
import { withRouter } from 'react-router';
import localforage from 'localforage';

import { modules } from 'stripes-config'; // eslint-disable-line

import { clearOkapiToken, clearCurrentUser } from '../../okapiActions';
import { resetStore } from '../../mainActions';
import { updateQueryResource, updateLocation } from '../../locationService';

import css from './MainNav.css';
import NavButton from './NavButton';
import NavDivider from './NavDivider';
import NavGroup from './NavGroup';
import Breadcrumbs from './Breadcrumbs';
import CurrentApp from './CurrentApp';
import MyProfile from './MyProfile';
import NotificationsDropdown from './Notifications/NotificationsDropdown';
import settingsIcon from './settings.svg';

// Temporary until settings becomes an app
const settingsIconData = {
  src: settingsIcon,
  alt: 'Tenant Settings',
  title: 'Settings',
};

if (!Array.isArray(modules.app) || modules.app.length < 1) {
  throw new Error('At least one module of type "app" must be enabled.');
}

class MainNav extends Component {
  static contextTypes = {
    router: PropTypes.object.isRequired,
  }

  static childContextTypes = {
    // It seems wrong that we have to tell this generic component what specific properties to put in the context
    stripes: PropTypes.object,
  };

  static propTypes = {
    stripes: PropTypes.shape({
      config: PropTypes.shape({
        showPerms: PropTypes.bool,
      }),
      store: PropTypes.shape({
        dispatch: PropTypes.func.isRequired,
      }),
      hasPerm: PropTypes.func.isRequired,
      withOkapi: PropTypes.bool,
    }),
    history: PropTypes.shape({
      listen: PropTypes.func.isRequired,
      replace: PropTypes.func.isRequired,
      push: PropTypes.func.isRequired,
    }).isRequired,
    location: PropTypes.shape({
      pathname: PropTypes.string,
    }).isRequired,
  };

  constructor(props) {
    super(props);
    this.state = {
      userMenuOpen: false,
    };
    this.store = props.stripes.store;
    this.logout = this.logout.bind(this);
    this.lastVisited = {};
    this.queryValues = null;

    this.moduleList = modules.app.concat({
      route: '/settings',
      module: '@folio/x_settings',
    });

    props.history.listen((hist) => {
      for (const entry of this.moduleList) {
        if (hist.pathname === entry.route || hist.pathname.startsWith(`${entry.route}/`)) {
          const name = entry.module.replace(/^@folio\//, '');
          this.lastVisited[name] = `${hist.pathname}${hist.search}`;
        }
      }
    });
  }

  getChildContext() {
    return {
      stripes: this.props.stripes,
    };
  }

  componentDidMount() {
    let curQuery = null;
    this.store.subscribe(() => {
      const { history, location } = this.props;
      const module = this.curModule;
      if (module && location.pathname.startsWith(module.route)) {
        curQuery = updateLocation(module, curQuery, this.store, history, location);
      }
    });
  }

  componentDidUpdate(prevProps) {
    const { location } = this.props;
    this.curModule = this.moduleList.find(m => location.pathname.startsWith(m.route) && m.queryResource);
    if (this.curModule && !isEqual(location, prevProps.location)) {
      updateQueryResource(location, this.curModule, this.store);
    }
  }

  toggleUserMenu() {
    const isOpen = this.state.userMenuOpen;
    this.setState({
      userMenuOpen: !isOpen,
    });
  }

  logout() {
    this.store.dispatch(clearOkapiToken());
    this.store.dispatch(clearCurrentUser());
    this.store.dispatch(resetStore());
    localforage.removeItem('okapiSess');
    this.context.router.history.push('/');
  }

  render() {
    const { stripes, location: { pathname } } = this.props;
    const selectedApp = modules.app.find(entry => pathname.startsWith(entry.route));

    const menuLinks = modules.app.map((entry) => {
      const name = entry.module.replace(/^@[a-z0-9_]+\//, '');
      const perm = `module.${name}.enabled`;

      if (!stripes.hasPerm(perm)) {
        return null;
      }

      const navId = `clickable-${name}-module`;
      const isActive = pathname.startsWith(entry.route);
      const href = !isActive ? (this.lastVisited[name] || entry.home || entry.route) : null;

      return (
        <NavButton
          label={entry.displayName}
          id={navId}
          selected={isActive}
          href={href}
          title={entry.displayName}
          key={entry.route}
          iconKey={name}
        />);
    });

    let firstNav;
    let breadcrumbArray = []; // eslint-disable-line

    // Temporary solution until Settings becomes a standalone app
    let settingsApp;
    if (stripes.hasPerm('settings.enabled') && pathname.startsWith('/settings')) {
      settingsApp = { displayName: 'Settings', description: 'FOLIO settings' };
    }

    if (breadcrumbArray.length === 0) {
      firstNav = (
        <NavGroup md="hide">

            <svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 26 26">
              <polygon style={{ fill: '#999' }} points="13 16.5 1.2 5.3 3.2 3.1 13 12.4 22.8 3.1 24.8 5.3 " />
              <polygon style={{ fill: '#999' }} points="13 24.8 1.2 13.5 3.2 11.3 13 20.6 22.8 11.3 24.8 13.5 " />
            </svg>

          <CurrentApp
            id="ModuleMainHeading"
            currentApp={selectedApp || settingsApp}
            iconData={settingsApp && settingsIconData}
          />
        </NavGroup>
      );
    } else {
      firstNav = (
        <NavGroup>
          <NavButton md="hide" />
          <Breadcrumbs linkArray={breadcrumbArray} />
        </NavGroup>
      );
    }

    return (

        {firstNav}

          <Headline tag="h2" className="sr-only">Main Navigation</Headline>
          <NavGroup>
            <NavGroup>
              {menuLinks}
              {
                !stripes.hasPerm('settings.enabled') ? '' : (
                  <NavButton
                    label="Settings"
                    id="clickable-settings"
                    title="Settings"
                    iconData={settingsIconData}
                    selected={pathname.startsWith('/settings')}
                    href={pathname.startsWith('/settings') ? null : (this.lastVisited.x_settings || '/settings')}
                  />
                )
              }
            </NavGroup>
            <NavGroup className={css.smallAlignRight}>
              <NavDivider md="hide" />
              {this.props.stripes.withOkapi && this.props.stripes.hasPerm('notify.item.get,notify.item.put,notify.collection.get') && <NotificationsDropdown stripes={stripes} {...this.props} />}
              { /* temporary divider solution.. */}
              {this.props.stripes.hasPerm('notify.item.get,notify.item.put,notify.collection.get') && (<NavDivider md="hide" />)}
              <MyProfile
                onLogout={this.logout}
                stripes={stripes}
              />
            </NavGroup>
          </NavGroup>

    );
  }
}

export default withRouter(MainNav);
<|endoftext|>


<commit_before>var Vis = require('vis');
var remote = require('remote');
var dialog = remote.require('dialog');
var fs = require('fs');

var network;
var inc = 0;

$(document).ready(function () {
    $('#submit-btn').click(function () {
        var obj = getBFSPath(network.body.data.nodes.get()[0]);
        markAllNodesAsUnvisited(obj.path);
        bfsRootAnimation(obj.path);
        rootCodeLineAnimation();
        bfsNodesAnimation(obj.path, obj.iter);
    });
});

// create a network
var container = $('#tree-simple')[0];

var options = {
    autoResize: true,
    manipulation: {
        enabled: true,
        initiallyActive: true,
        addNode: function (nodeData, callback) {
            if (network.body.nodes === {}) {
                inc = 1;
            }
            else {
                inc++;
            }
            nodeData.label = inc;
            nodeData.color = '#009688';
            nodeData.font = {
                color: '#fff'
            };
            nodeData.visited = false;
            nodeData.adjacencyList = [];
            nodeData.predecessor = null;
            callback(nodeData);
        },
        editNode: function (nodeData, callback) {
            editNode(nodeData, callback);
        },
        addEdge: function (edgeData, callback) {
            var fromNode = network.body.data.nodes.get().filter(function (x) {
                    return x.id === edgeData.from;
                }
            );
            var toNode = network.body.data.nodes.get().filter(function (x) {
                    return x.id === edgeData.to;
                }
            );
            fromNode[0].adjacencyList.push(toNode[0]);
            if (edgeData.from === edgeData.to) {
                var r = confirm('Do you want to connect the node to itself?');
                if (r === true) {
                    callback(edgeData);
                }
            }
            else {
                callback(edgeData);
            }
        },
        editEdge: {
            editWithoutDrag: function (data, callback) {
                editEdgeWithoutDrag(data, callback);
            }
        }
    },
    interaction: {
        navigationButtons: true
    },
    physics: {
        enabled: false
    }
};

network = new Vis.Network(container, [], options);

function bfsRootAnimation(path) {
    var root = path[0];
    for (var index = 1; index < 3; index++) {
        (function (ind) {
            setTimeout(function () {
                if (ind === 1) {
                    root.visited = true;
                    root.color = '#3f51b5';
                    network = rebuildNetwork(path);
                }
                else {
                    appendToQueue(root.label);
                }
            }, (1000 * ind));
        })(index);
    }
}

function bfsNodesAnimation(path, iter) {
    var queue = [path[0]];
    for (var index = 0; index < iter; index++) {
        (function (ind) {
            setTimeout(function () {
                var u = queue.pop();
                removeFromQueue();
                if (u) {
                    var adjacencyList = u.adjacencyList;
                    for (var index1 = 0; index1 < adjacencyList.length; index1++) {
                        (function (ind1) {
                            setTimeout(function () {
                                if (!adjacencyList[ind1].visited) {
                                    adjacencyList[ind1].visited = true;
                                    adjacencyList[ind1].color = '#3f51b5';
                                    adjacencyList[ind1].predecessor = u;
                                    network = rebuildNetwork(path);
                                    queue.push(adjacencyList[ind1]);
                                    appendToQueue(adjacencyList[ind1].label);
                                }
                            }, (4000 + 4000 * ind + ind1 * (parseFloat(2800) / adjacencyList.length)));
                        })(index1);
                    }
                }
            }, (3000 + (4000 * ind)));
        })(index);
    }
}

function getBFSPath(root) {
    var queue = [];
    var numberOfQueueIterations = 0;
    var path = [root];
    queue.push(root);
    while (queue.length > 0) {
        var u = queue.pop();
        var adjacencyList = u.adjacencyList;
        for (var i = 0; i < adjacencyList.length; i++) {
            if (!adjacencyList[i].visited) {
                adjacencyList[i].visited = true;
                adjacencyList[i].predecessor = u;
                queue.push(adjacencyList[i]);
                path.push(adjacencyList[i]);
            }
        }
        numberOfQueueIterations++;
    }
    return {path: path, iter: numberOfQueueIterations};
}

function rootCodeLineAnimation() {
    for (var index1 = 0; index1 < 3; index1++) {
        (function (ind1) {
            setTimeout(function () {
                unHighlightCodeLine(ind1 - 1);
                highlightCodeLine(ind1);
            }, (1000 * ind1));
        })(index1);
    }
}

function bfsNodesCodeLineAnimation(iter) {
    for (var index = 0; index < iter; index++) {
        (function (ind) {
            setTimeout(function () {
                removeFromQueue();
                var adjacencyList = u.adjacencyList;
                for (var index1 = 0; index1 < adjacencyList.length; index1++) {
                    (function (ind1) {
                        setTimeout(function () {
                            if (!adjacencyList[ind1].visited) {
                                adjacencyList[ind1].visited = true;
                                adjacencyList[ind1].color = '#3f51b5';
                                adjacencyList[ind1].predecessor = u;
                                network = rebuildNetwork(path);
                                queue.push(adjacencyList[ind1]);
                                appendToQueue(adjacencyList[ind1].label);
                            }
                        }, (3000 + (4000 * ind) + (ind1 * (parseFloat(4000) / adjacencyList.length))));
                    })(index1);
                }
            }, (3000 + (4000 * ind)));
        })(index);
    }
}

function highlightCodeLine(number) {
    $('#line-' + number).css('color', 'red');
}

function unHighlightCodeLine(number) {
    $('#line-' + number).css('color', '#3f51b5');
}

function appendToQueue(text) {
    var th = '' + text + '	';
    $('#queue-row').append(th);
}

function removeFromQueue() {
    $('#queue-row').find('th:last').remove();
}

function markAllNodesAsUnvisited(path) {
    for (var i = 0; i < path.length; i++) {
        path[i].visited = false;
    }
}

function createAlert(alertText) {
    var alert = "
 <button type='button' class='close' data-dismiss='alert'> x </button> Oh snap! " + alertText + '
';
    return alert;
}

function rebuildNetwork(nodes) {
    var data = {
        nodes: nodes,
        edges: network.body.data.edges
    };

    network.destroy();
    network = new Vis.Network(container, data, options);
    return network;
}

function editEdgeWithoutDrag(data, callback) {
    $('#edge-label-text').removeClass('is-empty');
    $('#edge-label').val(data.label);
    $('#edge-saveButton').click(saveEdgeData.bind(this, data, callback));
    $('#edge-cancelButton').click(cancelEdgeEdit.bind(this,callback));
    $('#close-x').click(cancelEdgeEdit.bind(this,callback));
    $('#edge-popUp').css('display', 'block');
}

function clearEdgePopUp() {
    $('#edge-saveButton').click(null);
    $('#edge-cancelButton').click(null);
    $('#close-x').click(null);
    $('#edge-popUp').css('display', 'none');
}

function cancelEdgeEdit(callback) {
    clearEdgePopUp();
    callback(null);
}

function saveEdgeData(data, callback) {
    if (typeof data.to === 'object')
        data.to = data.to.id;
    if (typeof data.from === 'object')
        data.from = data.from.id;
    data.label = $('#edge-label').val();
    clearEdgePopUp();
    callback(data);
}

function editNode(data, callback) {
    if (data.root) {
        $('#node-root-checkbox').prop('checked', true);
    }
    else {
        $('#node-root-checkbox').prop('checked', false);
    }
    $('#node-label-text').removeClass('is-empty');
    $('#node-label').val(data.label);
    $('#node-saveButton').click(saveNodeData.bind(this, data, callback));
    $('#node-cancelButton').click(cancelNodeEdit.bind(this, callback));
    $('#close-x1').click(cancelNodeEdit.bind(this, callback));
    $('#node-popUp').css('display', 'block');
}

function clearNodePopUp() {
    $('#node-saveButton').click(null);
    $('#node-cancelButton').click(null);
    $('#close-x1').click(null);
    $('#node-popUp').css('display', 'none');
}

function cancelNodeEdit(callback) {
    clearNodePopUp();
    callback(null);
}

function saveNodeData(data, callback) {
    data.label = $('#node-label').val();
    data.root = $('#node-root-checkbox').prop('checked');
    clearNodePopUp();
    callback(data);
}
<commit_msg>Changing how finding the bfs path method works<commit_after>var Vis = require('vis');
var remote = require('remote');
var dialog = remote.require('dialog');
var fs = require('fs');

var network;
var inc = 0;

$(document).ready(function () {
    $('#submit-btn').click(function () {
        var obj = getBFSPath(findRootNode(network.body.data.nodes.get()));
        markAllNodesAsUnvisited(obj.path);
        bfsRootAnimation(obj.path);
        rootCodeLineAnimation();
        bfsNodesAnimation(obj.path, obj.iter);
    });
});

// create a network
var container = $('#tree-simple')[0];

var options = {
    autoResize: true,
    manipulation: {
        enabled: true,
        initiallyActive: true,
        addNode: function (nodeData, callback) {
            if (network.body.nodes === {}) {
                inc = 1;
            }
            else {
                inc++;
            }
            nodeData.root = false;
            nodeData.label = inc;
            nodeData.color = '#009688';
            nodeData.font = {
                color: '#fff'
            };
            nodeData.visited = false;
            nodeData.adjacencyList = [];
            nodeData.predecessor = null;
            callback(nodeData);
        },
        editNode: function (nodeData, callback) {
            editNode(nodeData, callback);
        },
        addEdge: function (edgeData, callback) {
            var fromNode = network.body.data.nodes.get().filter(function (x) {
                    return x.id === edgeData.from;
                }
            );
            var toNode = network.body.data.nodes.get().filter(function (x) {
                    return x.id === edgeData.to;
                }
            );
            fromNode[0].adjacencyList.push(toNode[0]);
            if (edgeData.from === edgeData.to) {
                var r = confirm('Do you want to connect the node to itself?');
                if (r === true) {
                    callback(edgeData);
                }
            }
            else {
                callback(edgeData);
            }
        },
        editEdge: {
            editWithoutDrag: function (data, callback) {
                editEdgeWithoutDrag(data, callback);
            }
        }
    },
    interaction: {
        navigationButtons: true
    },
    physics: {
        enabled: false
    }
};

network = new Vis.Network(container, [], options);

function bfsRootAnimation(path) {
    var root = findRootNode(path);
    console.log(root);
    for (var index = 1; index < 3; index++) {
        (function (ind) {
            setTimeout(function () {
                if (ind === 1) {
                    root.visited = true;
                    root.color = '#3f51b5';
                    network = rebuildNetwork(path);
                }
                else {
                    appendToQueue(root.label);
                }
            }, (1000 * ind));
        })(index);
    }
}

function bfsNodesAnimation(path, iter) {
    var queue = [path[0]];
    for (var index = 0; index < iter; index++) {
        (function (ind) {
            setTimeout(function () {
                var u = queue.pop();
                removeFromQueue();
                if (u) {
                    var adjacencyList = u.adjacencyList;
                    for (var index1 = 0; index1 < adjacencyList.length; index1++) {
                        (function (ind1) {
                            setTimeout(function () {
                                if (!adjacencyList[ind1].visited) {
                                    adjacencyList[ind1].visited = true;
                                    adjacencyList[ind1].color = '#3f51b5';
                                    adjacencyList[ind1].predecessor = u;
                                    network = rebuildNetwork(path);
                                    queue.push(adjacencyList[ind1]);
                                    appendToQueue(adjacencyList[ind1].label);
                                }
                            }, (4000 + 4000 * ind + ind1 * (parseFloat(2800) / adjacencyList.length)));
                        })(index1);
                    }
                }
            }, (3000 + (4000 * ind)));
        })(index);
    }
}

function getBFSPath(root) {
    var queue = [];
    var numberOfQueueIterations = 0;
    var path = [root];
    queue.push(root);
    while (queue.length > 0) {
        var u = queue.pop();
        var adjacencyList = u.adjacencyList;
        for (var i = 0; i < adjacencyList.length; i++) {
            if (!adjacencyList[i].visited) {
                adjacencyList[i].visited = true;
                adjacencyList[i].predecessor = u;
                queue.push(adjacencyList[i]);
                path.push(adjacencyList[i]);
            }
        }
        numberOfQueueIterations++;
    }
    return {path: path, iter: numberOfQueueIterations};
}

function rootCodeLineAnimation() {
    for (var index1 = 0; index1 < 3; index1++) {
        (function (ind1) {
            setTimeout(function () {
                unHighlightCodeLine(ind1 - 1);
                highlightCodeLine(ind1);
            }, (1000 * ind1));
        })(index1);
    }
}

function bfsNodesCodeLineAnimation(iter) {
    for (var index = 0; index < iter; index++) {
        (function (ind) {
            setTimeout(function () {
                removeFromQueue();
                var adjacencyList = u.adjacencyList;
                for (var index1 = 0; index1 < adjacencyList.length; index1++) {
                    (function (ind1) {
                        setTimeout(function () {
                            if (!adjacencyList[ind1].visited) {
                                adjacencyList[ind1].visited = true;
                                adjacencyList[ind1].color = '#3f51b5';
                                adjacencyList[ind1].predecessor = u;
                                network = rebuildNetwork(path);
                                queue.push(adjacencyList[ind1]);
                                appendToQueue(adjacencyList[ind1].label);
                            }
                        }, (3000 + (4000 * ind) + (ind1 * (parseFloat(4000) / adjacencyList.length))));
                    })(index1);
                }
            }, (3000 + (4000 * ind)));
        })(index);
    }
}

function highlightCodeLine(number) {
    $('#line-' + number).css('color', 'red');
}

function unHighlightCodeLine(number) {
    $('#line-' + number).css('color', '#3f51b5');
}

function appendToQueue(text) {
    var th = '' + text + '	';
    $('#queue-row').append(th);
}

function removeFromQueue() {
    $('#queue-row').find('th:last').remove();
}

function markAllNodesAsUnvisited(path) {
    for (var i = 0; i < path.length; i++) {
        path[i].visited = false;
    }
}

function createAlert(alertText) {
    var alert = "
 <button type='button' class='close' data-dismiss='alert'> x </button> Oh snap! " + alertText + '
';
    return alert;
}

function rebuildNetwork(nodes) {
    var data = {
        nodes: nodes,
        edges: network.body.data.edges
    };

    network.destroy();
    network = new Vis.Network(container, data, options);
    return network;
}

function editEdgeWithoutDrag(data, callback) {
    $('#edge-label-text').removeClass('is-empty');
    $('#edge-label').val(data.label);
    $('#edge-saveButton').click(saveEdgeData.bind(this, data, callback));
    $('#edge-cancelButton').click(cancelEdgeEdit.bind(this,callback));
    $('#close-x').click(cancelEdgeEdit.bind(this,callback));
    $('#edge-popUp').css('display', 'block');
}

function clearEdgePopUp() {
    $('#edge-saveButton').click(null);
    $('#edge-cancelButton').click(null);
    $('#close-x').click(null);
    $('#edge-popUp').css('display', 'none');
}

function cancelEdgeEdit(callback) {
    clearEdgePopUp();
    callback(null);
}

function saveEdgeData(data, callback) {
    if (typeof data.to === 'object')
        data.to = data.to.id;
    if (typeof data.from === 'object')
        data.from = data.from.id;
    data.label = $('#edge-label').val();
    clearEdgePopUp();
    callback(data);
}

function editNode(data, callback) {
    if (data.root) {
        $('#node-root-checkbox').prop('checked', true);
    }
    else {
        $('#node-root-checkbox').prop('checked', false);
    }
    $('#node-label-text').removeClass('is-empty');
    $('#node-label').val(data.label);
    $('#node-saveButton').click(saveNodeData.bind(this, data, callback));
    $('#node-cancelButton').click(cancelNodeEdit.bind(this, callback));
    $('#close-x1').click(cancelNodeEdit.bind(this, callback));
    $('#node-popUp').css('display', 'block');
}

function clearNodePopUp() {
    $('#node-saveButton').click(null);
    $('#node-cancelButton').click(null);
    $('#close-x1').click(null);
    $('#node-popUp').css('display', 'none');
}

function cancelNodeEdit(callback) {
    clearNodePopUp();
    callback(null);
}

function saveNodeData(data, callback) {
    data.label = $('#node-label').val();
    data.root = $('#node-root-checkbox').prop('checked');
    clearNodePopUp();
    callback(data);
}

function findRootNode(path) {
    for (var i = 0; i < path.length; i++) {
        if (path[i].root) {
            return path[i];
        }
    }
}
<|endoftext|>


<commit_before>/* eslint-env node */
'use strict';

var path = require('path');
var Funnel = require('broccoli-funnel');
var MergeTrees = require('broccoli-merge-trees');

module.exports = {
  name: 'ember-credit-card',
  included: function(app) {
    this._super.included.apply(this, arguments);
    this.import('vendor/card.js');
  },

  treeForVendor(vendorTree) {
    let momentTree = new Funnel(path.join(this.project.root, 'node_modules', 'card', 'dist'), {
      files: ['card.js'],
    });

    return new MergeTrees([vendorTree, momentTree]);
  },
};
<commit_msg>Fix for #15<commit_after>/* eslint-env node */
'use strict';

const path = require('path');
const Funnel = require('broccoli-funnel');
const MergeTrees = require('broccoli-merge-trees');

module.exports = {
  name: 'ember-credit-card',
  included: function(app) {
    this._super.included.apply(this, arguments);
    this.import('vendor/card.js');
  },

  treeForVendor(vendorTree) {
    let trees = [];

    if (vendorTree) {
      trees.push(vendorTree);
    }

    trees.push(
      new Funnel(path.join(this.project.root, 'node_modules', 'card', 'dist'), {
        files: ['card.js'],
      })
    );

    return new MergeTrees(trees);
  },
};
<|endoftext|>


<commit_before>const React = require("react");
const classnames = require("classnames");
const ManagedTree = React.createFactory(require("./utils/ManagedTree"));
const Svg = require("./utils/Svg");
const Rep = require("./Rep");
const { DOM: dom, PropTypes } = React;

require("./ObjectInspector.css");

// This implements a component that renders an interactive inspector
// for looking at JavaScript objects. It expects descriptions of
// objects from the protocol, and will dynamically fetch child
// properties as objects are expanded.
//
// If you want to inspect a single object, pass the name and the
// protocol descriptor of it:
//
//  ObjectInspector({
//    name: "foo",
//    desc: { writable: true, ..., { value: { actor: "1", ... }}},
//    ...
//  })
//
// If you want multiple top-level objects (like scopes), you can pass
// an array of manually constructed nodes as `roots`:
//
//  ObjectInspector({
//    roots: [{ name: ... }, ...],
//    ...
//  });

// There are 3 types of nodes: a simple node with a children array, an
// object that has properties that should be children when they are
// fetched, and a primitive value that should be displayed with no
// children.

function nodeHasChildren(item) {
  return Array.isArray(item.contents);
}

function nodeIsOptimizedOut(item) {
  return !nodeHasChildren(item) && item.contents.value.optimizedOut === true;
}

function nodeIsMissingArguments(item) {
  return !nodeHasChildren(item) &&
    item.contents.value.missingArguments === true;
}

function nodeHasProperties(item) {
  return !nodeHasChildren(item) && item.contents.value.type === "object";
}

function nodeIsPrimitive(item) {
  return !nodeHasChildren(item) && !nodeHasProperties(item);
}

function makeNodesForProperties(objProps, parentPath) {
  const { ownProperties, prototype } = objProps;

  const nodes = Object.keys(ownProperties).sort().filter(name => {
    // Ignore non-concrete values like getters and setters
    // for now by making sure we have a value.
    return "value" in ownProperties[name];
  }).map(name => {
    return createNode(name, `${parentPath}/${name}`, ownProperties[name]);
  });

  // Add the prototype if it exists and is not null
  if (prototype && prototype.type !== "null") {
    nodes.push(createNode(
      "__proto__",
      `${parentPath}/__proto__`,
      { value: prototype }
    ));
  }

  return nodes;
}

function createNode(name, path, contents) {
  // The path is important to uniquely identify the item in the entire
  // tree. This helps debugging & optimizes React's rendering of large
  // lists. The path will be separated by property name,
  // i.e. `{ foo: { bar: { baz: 5 }}}` will have a path of `foo/bar/baz`
  // for the inner object.
  return { name, path, contents };
}

const ObjectInspector = React.createClass({
  propTypes: {
    autoExpandDepth: PropTypes.number,
    name: PropTypes.string,
    desc: PropTypes.object,
    roots: PropTypes.array,
    getObjectProperties: PropTypes.func.isRequired,
    loadObjectProperties: PropTypes.func.isRequired,
    onLabelClick: PropTypes.func
  },

  displayName: "ObjectInspector",

  getInitialState() {
    // Cache of dynamically built nodes. We shouldn't need to clear
    // this out ever, since we don't ever "switch out" the object
    // being inspected.
    this.actorCache = {};
    return {};
  },

  getDefaultProps() {
    return {
      onLabelClick: () => {},
      autoExpandDepth: 1
    };
  },

  getChildren(item) {
    const { getObjectProperties } = this.props;
    const obj = item.contents;

    // Nodes can either have children already, or be an object with
    // properties that we need to go and fetch.
    if (nodeHasChildren(item)) {
      return item.contents;
    }

    if (nodeHasProperties(item)) {
      const actor = obj.value.actor;

      // Because we are dynamically creating the tree as the user
      // expands it (not precalcuated tree structure), we cache child
      // arrays. This not only helps performance, but is necessary
      // because the expanded state depends on instances of nodes
      // being the same across renders. If we didn't do this, each
      // node would be a new instance every render.
      const key = item.path;
      if (this.actorCache[key]) {
        return this.actorCache[key];
      }

      const loadedProps = getObjectProperties(actor);
      const { ownProperties, prototype } = loadedProps || {};
      if (!ownProperties && !prototype) {
        return [];
      }

      const children = makeNodesForProperties(loadedProps, item.path);
      this.actorCache[actor] = children;
      return children;
    }

    return [];
  },

  renderItem(item, depth, focused, _, expanded, { setExpanded }) {
    let objectValue;
    if (nodeIsOptimizedOut(item)) {
      objectValue = dom.span({ className: "unavailable" }, "(optimized away)");
    } else if (nodeIsMissingArguments(item)) {
      objectValue = dom.span({ className: "unavailable" }, "(unavailable)");
    } else if (nodeHasProperties(item) || nodeIsPrimitive(item)) {
      const object = item.contents.value;
      objectValue = Rep({ object, mode: "tiny" });
    }

    return dom.div(
      {
        className: classnames("node object-node",
          {
            focused,
            "not-enumerable": (!item.contents.enumerable &&
                               !nodeHasChildren(item))
          }),
        style: { marginLeft: depth * 15 },
        onClick: e => {
          e.stopPropagation();
          setExpanded(item, !expanded);
        }
      },
      Svg("arrow", {
        className: classnames({
          expanded: expanded,
          hidden: nodeIsPrimitive(item)
        })
      }),
      dom.span(
        {
          className: "object-label",
          onClick: event => {
            event.stopPropagation();
            this.props.onLabelClick(item, { depth, focused, expanded });
          }
        },
        item.name
      ),
      dom.span({ className: "object-delimiter" },
               objectValue ? ": " : ""),
      dom.span({ className: "object-value" }, objectValue || "")
    );
  },

  render() {
    const { name, desc, loadObjectProperties,
            autoExpandDepth } = this.props;

    let roots = this.props.roots;
    if (!roots) {
      roots = [createNode(name, name, desc)];
    }

    return ManagedTree({
      itemHeight: 20,
      getParent: item => null,
      getChildren: this.getChildren,
      getRoots: () => roots,
      getKey: item => item.path,
      autoExpand: 0,
      autoExpandDepth,
      autoExpandAll: false,
      disabledFocus: true,
      onExpand: item => {
        if (nodeHasProperties(item)) {
          loadObjectProperties(item.contents.value);
        }
      },

      renderItem: this.renderItem
    });
  }
});

module.exports = ObjectInspector;
<commit_msg>Use reps modes (#1674)<commit_after>const React = require("react");
const classnames = require("classnames");
const ManagedTree = React.createFactory(require("./utils/ManagedTree"));
const Svg = require("./utils/Svg");
const Rep = require("./Rep");
const { MODE } = require("devtools-reps");

const { DOM: dom, PropTypes } = React;

require("./ObjectInspector.css");

// This implements a component that renders an interactive inspector
// for looking at JavaScript objects. It expects descriptions of
// objects from the protocol, and will dynamically fetch child
// properties as objects are expanded.
//
// If you want to inspect a single object, pass the name and the
// protocol descriptor of it:
//
//  ObjectInspector({
//    name: "foo",
//    desc: { writable: true, ..., { value: { actor: "1", ... }}},
//    ...
//  })
//
// If you want multiple top-level objects (like scopes), you can pass
// an array of manually constructed nodes as `roots`:
//
//  ObjectInspector({
//    roots: [{ name: ... }, ...],
//    ...
//  });

// There are 3 types of nodes: a simple node with a children array, an
// object that has properties that should be children when they are
// fetched, and a primitive value that should be displayed with no
// children.

function nodeHasChildren(item) {
  return Array.isArray(item.contents);
}

function nodeIsOptimizedOut(item) {
  return !nodeHasChildren(item) && item.contents.value.optimizedOut === true;
}

function nodeIsMissingArguments(item) {
  return !nodeHasChildren(item) &&
    item.contents.value.missingArguments === true;
}

function nodeHasProperties(item) {
  return !nodeHasChildren(item) && item.contents.value.type === "object";
}

function nodeIsPrimitive(item) {
  return !nodeHasChildren(item) && !nodeHasProperties(item);
}

function makeNodesForProperties(objProps, parentPath) {
  const { ownProperties, prototype } = objProps;

  const nodes = Object.keys(ownProperties).sort().filter(name => {
    // Ignore non-concrete values like getters and setters
    // for now by making sure we have a value.
    return "value" in ownProperties[name];
  }).map(name => {
    return createNode(name, `${parentPath}/${name}`, ownProperties[name]);
  });

  // Add the prototype if it exists and is not null
  if (prototype && prototype.type !== "null") {
    nodes.push(createNode(
      "__proto__",
      `${parentPath}/__proto__`,
      { value: prototype }
    ));
  }

  return nodes;
}

function createNode(name, path, contents) {
  // The path is important to uniquely identify the item in the entire
  // tree. This helps debugging & optimizes React's rendering of large
  // lists. The path will be separated by property name,
  // i.e. `{ foo: { bar: { baz: 5 }}}` will have a path of `foo/bar/baz`
  // for the inner object.
  return { name, path, contents };
}

const ObjectInspector = React.createClass({
  propTypes: {
    autoExpandDepth: PropTypes.number,
    name: PropTypes.string,
    desc: PropTypes.object,
    roots: PropTypes.array,
    getObjectProperties: PropTypes.func.isRequired,
    loadObjectProperties: PropTypes.func.isRequired,
    onLabelClick: PropTypes.func
  },

  displayName: "ObjectInspector",

  getInitialState() {
    // Cache of dynamically built nodes. We shouldn't need to clear
    // this out ever, since we don't ever "switch out" the object
    // being inspected.
    this.actorCache = {};
    return {};
  },

  getDefaultProps() {
    return {
      onLabelClick: () => {},
      autoExpandDepth: 1
    };
  },

  getChildren(item) {
    const { getObjectProperties } = this.props;
    const obj = item.contents;

    // Nodes can either have children already, or be an object with
    // properties that we need to go and fetch.
    if (nodeHasChildren(item)) {
      return item.contents;
    }

    if (nodeHasProperties(item)) {
      const actor = obj.value.actor;

      // Because we are dynamically creating the tree as the user
      // expands it (not precalcuated tree structure), we cache child
      // arrays. This not only helps performance, but is necessary
      // because the expanded state depends on instances of nodes
      // being the same across renders. If we didn't do this, each
      // node would be a new instance every render.
      const key = item.path;
      if (this.actorCache[key]) {
        return this.actorCache[key];
      }

      const loadedProps = getObjectProperties(actor);
      const { ownProperties, prototype } = loadedProps || {};
      if (!ownProperties && !prototype) {
        return [];
      }

      const children = makeNodesForProperties(loadedProps, item.path);
      this.actorCache[actor] = children;
      return children;
    }

    return [];
  },

  renderItem(item, depth, focused, _, expanded, { setExpanded }) {
    let objectValue;
    if (nodeIsOptimizedOut(item)) {
      objectValue = dom.span({ className: "unavailable" }, "(optimized away)");
    } else if (nodeIsMissingArguments(item)) {
      objectValue = dom.span({ className: "unavailable" }, "(unavailable)");
    } else if (nodeHasProperties(item) || nodeIsPrimitive(item)) {
      const object = item.contents.value;
      objectValue = Rep({ object, mode: MODE.TINY });
    }

    return dom.div(
      {
        className: classnames("node object-node",
          {
            focused,
            "not-enumerable": (!item.contents.enumerable &&
                               !nodeHasChildren(item))
          }),
        style: { marginLeft: depth * 15 },
        onClick: e => {
          e.stopPropagation();
          setExpanded(item, !expanded);
        }
      },
      Svg("arrow", {
        className: classnames({
          expanded: expanded,
          hidden: nodeIsPrimitive(item)
        })
      }),
      dom.span(
        {
          className: "object-label",
          onClick: event => {
            event.stopPropagation();
            this.props.onLabelClick(item, { depth, focused, expanded });
          }
        },
        item.name
      ),
      dom.span({ className: "object-delimiter" },
               objectValue ? ": " : ""),
      dom.span({ className: "object-value" }, objectValue || "")
    );
  },

  render() {
    const { name, desc, loadObjectProperties,
            autoExpandDepth } = this.props;

    let roots = this.props.roots;
    if (!roots) {
      roots = [createNode(name, name, desc)];
    }

    return ManagedTree({
      itemHeight: 20,
      getParent: item => null,
      getChildren: this.getChildren,
      getRoots: () => roots,
      getKey: item => item.path,
      autoExpand: 0,
      autoExpandDepth,
      autoExpandAll: false,
      disabledFocus: true,
      onExpand: item => {
        if (nodeHasProperties(item)) {
          loadObjectProperties(item.contents.value);
        }
      },

      renderItem: this.renderItem
    });
  }
});

module.exports = ObjectInspector;
<|endoftext|>


<commit_before>/**
 * @providesModule RNUtils.Index
 */

import DeviceUtils from './src/DeviceUtils';
import FontUtils from './src/FontUtils';
import Logger from './src/Logger';
import SearchUtils from './src/SearchUtils';
import ValidationUtils from './src/ValidationUtils';

export { DeviceUtils, FontUtils, Logger, SearchUtils, ValidationUtils };
<commit_msg>Export Extensions<commit_after>/**
 * @providesModule RNUtils.Index
 */

import DeviceUtils from './src/DeviceUtils';
import Extensions from './src/Extensions';
import FontUtils from './src/FontUtils';
import Logger from './src/Logger';
import SearchUtils from './src/SearchUtils';
import ValidationUtils from './src/ValidationUtils';

export { DeviceUtils, Extensions, FontUtils, Logger, SearchUtils, ValidationUtils };
<|endoftext|>


<commit_before>// Any plugins you want to use has to be imported
// Detail plugins list see https://www.tinymce.com/docs/plugins/
// Custom builds see https://www.tinymce.com/download/custom-builds/

const plugins = ['advlist anchor autolink autosave code codesample colorpicker colorpicker contextmenu directionality emoticons fullscreen hr image imagetools importcss insertdatetime legacyoutput link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textcolor textpattern visualblocks visualchars wordcount']

export default plugins
<commit_msg>perf[Tinymce]: remove legacyoutput #745<commit_after>// Any plugins you want to use has to be imported
// Detail plugins list see https://www.tinymce.com/docs/plugins/
// Custom builds see https://www.tinymce.com/download/custom-builds/

const plugins = ['advlist anchor autolink autosave code codesample colorpicker colorpicker contextmenu directionality emoticons fullscreen hr image imagetools importcss insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textcolor textpattern visualblocks visualchars wordcount']

export default plugins
<|endoftext|>


<commit_before>/*
 * CMS.js v1.0.0
 * Copyright 2015 Chris Diana
 * www.cdmedia.github.io/cms.js
 * Free to use under the MIT license.
 * http://www.opensource.org/licenses/mit-license.php
 */

var CMS = {

  settings: {
    siteName: 'CMS.js',
    siteTagline: 'Your site tagline',
    siteEmail: 'your_email@example.com',
    siteAuthor: 'Your Name',
    siteUrl: '',
    siteNavItems: [
      { name: 'Github', href: '#', newWindow: false },
      { name: 'About' }
    ],
    pagination: 3,
    postsFolder: 'posts',
    postSnippetLength: 120,
    pagesFolder: 'pages',
    fadeSpeed: 300,
    mainContainer: $('.cms_main'),
    footerContainer: $('.cms_footer'),
    footerText: '© ' + new Date().getFullYear() + ' All Rights Reserved.',
    parseSeperator: '---',
    postsOnFrontpage: true,
    pageAsFrontpage: '',
    postsOnUrl: '',
    loader: '
Loading...
',
    get siteAttributes() {
      return [
        { attr: 'title', value: CMS.settings.siteName },
        { attr: '.cms_sitename', value: CMS.settings.siteName },
        { attr: '.cms_tagline', value: CMS.settings.siteTagline },
        { attr: '.cms_footer_text', value: CMS.settings.footerText }
      ];
    },
    mode: 'Github',
    githubUserSettings: {
      username: 'yourusername',
      repo: 'yourrepo',
    },
    githubSettings: {
      branch: 'gh-pages',
      host: 'https://api.github.com'
    }
  },

  posts: [],
  pages: [],
  loaded: {},

  extend: function (target, opts, callback) {
    var next;
    if (typeof opts === 'undefined') {
      opts = target;
      target = CMS;
    }
    for (next in opts) {
      if (Object.prototype.hasOwnProperty.call(opts, next)) {
        target[next] = opts[next];
      }
    }
    callback(); // check user config options
    return target;
  },

  render: function (url) {
    CMS.settings.mainContainer.html('').fadeOut(CMS.settings.fadeSpeed);
    CMS.settings.footerContainer.hide();

    var type = url.split('/')[0];

    var map = {

      // Main view / Frontpage
      '' : function () {
          CMS.renderPosts();
      },

      // Post view / single view
      '#post' : function () {
        var id = url.split('#post/')[1].trim();
        CMS.renderPost(id);
      },

      // Page view
      '#page' : function () {
        var title = url.split('#page/')[1].trim();
        CMS.renderPage(title);
      }

    };

    if (map[type]) {
      map[type]();
    } else {
      // Error view
      var errorMsg = 'Error loading page.';
      CMS.renderError(errorMsg);
    }
  },

  renderPage: function (title) {
    CMS.pages.sort(function (a,b) { return CMS.settings.sortDateOrder ? b.date - a.date : a.date - b.date; });
    CMS.pages.forEach(function (page){
      if (page.title == title) {

        var tpl = $('#page-template').html(),
          $tpl = $(tpl);

        $tpl.find('.page-title').html(page.title);
        $tpl.find('.page-content').html(page.contentData);

        CMS.settings.mainContainer.html($tpl).hide().fadeIn(CMS.settings.fadeSpeed);
      }
    });
    CMS.renderFooter();
  },

  renderPost: function (id) {
    CMS.posts.forEach(function (post){
      if (post.id == id) {

        var tpl = $('#post-template').html(),
          $tpl = $(tpl);

        $tpl.find('.post-title').html(post.title);
        $tpl.find('.post-date').html((post.date.getMonth() + 1) + '/' + post.date.getDate() + '/' +  post.date.getFullYear());
        $tpl.find('.post-content').html(post.contentData);

        CMS.settings.mainContainer.html($tpl).hide().fadeIn(CMS.settings.fadeSpeed);
      }
    });
    CMS.renderFooter();
  },

  renderPosts: function () {
    CMS.posts.sort(function (a,b) { return CMS.settings.sortDateOrder ? b.date - a.date : a.date - b.date; });
    CMS.posts.forEach(function (post){
      var tpl = $('#post-template').html(),
        $tpl = $(tpl);

      var title = '' + post.title + '',
        date = (post.date.getMonth() + 1) + '/' + post.date.getDate() + '/' +  post.date.getFullYear(),
        snippet = post.contentData.split('.')[0] + '.';

      var postLink = $tpl.find('.post-title'),
        postDate = $tpl.find('.post-date'),
        postSnippet = $tpl.find('.post-content');

      postLink.on('click', function (e) {
        e.preventDefault();
        window.location.hash = 'post/' + post.id;
      });

      postLink.html(title);
      postSnippet.html(snippet);
      postDate.html(date);
      CMS.settings.mainContainer.append($tpl).hide().fadeIn(CMS.settings.fadeSpeed);
    });
    CMS.renderFooter();
  },

  renderFooter: function () {
    // Delay footer loading while waiting on ajax requests
    setTimeout(function () {
      CMS.settings.footerContainer.fadeIn(CMS.settings.fadeSpeed);
    }, 800);
  },

  renderError: function (msg) {
    var tpl = $('#error-template').html(),
      $tpl = $(tpl);

    $tpl.find('.error_text').html(msg);

    CMS.settings.mainContainer.html('').fadeOut(CMS.settings.fadeSpeed, function (){
      CMS.settings.mainContainer.html($tpl).fadeIn(CMS.settings.fadeSpeed);
    });
  },

  contentLoaded: function (type) {

    CMS.loaded[type] = true;

    if (CMS.loaded.page && CMS.loaded.post) {

      // Set navigation
      this.setNavigation();

      // Manually trigger on initial load
      $(window).trigger('hashchange');
    }
  },

  parseContent: function (content, type, file, counter, numFiles) {

    var data = content.split(CMS.settings.parseSeperator),
      contentObj = {},
      id = counter,
      date = file.date;

    contentObj.id = id;
    contentObj.date = date;

    // Get content info
    var infoData = data[1].split(/[\n\r]+/);

    $.each(infoData, function (k, v) {
      if (v.length) {
        v.replace(/^\s+|\s+$/g, '').trim();
        var i = v.split(':');
        var val = v.slice(v.indexOf(':')+1);
        k = i[0];

        val = (k == 'date' ? (new Date(val)) : val);

        contentObj[k] = (val.trim ? val.trim() : val);
      }
    });

    // Drop data we don't need
    data.splice(0,2);

    // Put everything back together if broken
    var contentData = data.join();
    contentObj.contentData = marked(contentData);

    switch(type) {
      case 'post':
        CMS.posts.push(contentObj);
        break;
      case 'page':
        CMS.pages.push(contentObj);
        break;
    }

    // Execute after all content is loaded
    if (counter === numFiles) {
      CMS.contentLoaded(type);
    }
  },

  getContent: function (type, file, counter, numFiles) {

    var urlFolder = '';

    switch(type) {
      case 'post':
        urlFolder = CMS.settings.postsFolder;
        break;
      case 'page':
        urlFolder = CMS.settings.pagesFolder;
        break;
    }

    if (CMS.settings.mode == 'Github') {
      url = file.link;
    } else {
      url = urlFolder + '/' + file.name;
    }

    $.ajax({
      type: 'GET',
      url: url,
      dataType: 'html',
      success: function (content) {
        CMS.parseContent(content, type, file, counter, numFiles);
      },
      error: function () {
        var errorMsg = 'Error loading ' + type + ' content';
        CMS.renderError(errorMsg);
      }
    });
  },

  getFiles: function (type) {

    var folder = '',
      url = '';

    switch(type) {
      case 'post':
        folder = CMS.settings.postsFolder;
        break;
      case 'page':
        folder = CMS.settings.pagesFolder;
        break;
    }

    if (CMS.settings.mode == 'Github') {
      var gus = CMS.settings.githubUserSettings,
        gs = CMS.settings.githubSettings;
      url = gs.host + '/repos/' + gus.username + '/' + gus.repo + '/contents/' + folder + '?ref=' + gs.branch;
    } else {
      url = folder;
    }

    $.ajax({
      url: url,
      success: function (data) {

        var files = [],
          linkFiles;

        if (CMS.settings.mode == 'Github') {
          linkFiles = data;
        } else {
          linkFiles = $(data).find('a');
        }

        $(linkFiles).each(function (k, f) {

          var filename,
            downloadLink;

          if (CMS.settings.mode == 'Github') {
            filename = f.name;
            downloadLink = f.download_url;
          } else {
            filename = $(f).attr('href');
          }

          if (filename.endsWith('.md')) {
            var file = {};
            file.date = new Date(filename.substring(0, 10));
            file.name = filename;
            if (downloadLink) {
              file.link = downloadLink;
            }
            files.push(file);
          }

        });

        var counter = 0,
          numFiles = files.length;

        if (files.length > 0) {
          $(files).each(function (k, file) {
            counter++;
            CMS.getContent(type, file, counter, numFiles);
          });
        } else {
          var errorMsg = 'Error loading ' + type + 's in directory. Make sure ' +
            'there are Markdown ' + type + 's in the ' + type + 's folder.';
          CMS.renderError(errorMsg);
        }
      },
      error: function () {
        var errorMsg;
        if (CMS.settings.mode == 'Github') {
          errorMsg = 'Error loading ' + type + 's directory. Make sure ' +
            'your Github settings are correctly set in your config.js file.';
        } else {
          errorMsg = 'Error loading ' + type + 's directory. Make sure ' +
            type + 's directory is set correctly in config and .htaccess is in ' +
            type + 's directory with Apache "Options Indexes" set on.';
        }
        CMS.renderError(errorMsg);
      }
    });
  },

  setNavigation: function () {

    var navBuilder = ['
'];
    CMS.settings.siteNavItems.forEach(function (navItem) {
      if (navItem.hasOwnProperty('href')) {
        navBuilder.push('
', navItem.name, '
');
      } else {
        CMS.pages.forEach(function (page) {
          if (navItem.name == page.title) {
            navBuilder.push('
', navItem.name, '
');
          }
        });
      }
    });
    navBuilder.push('
');
    var nav = navBuilder.join('');

    $('.cms_nav').html(nav).hide().fadeIn(CMS.settings.fadeSpeed);

    // Set onclicks for nav links
    $.each($('.cms_nav_link'), function (k, link) {
      var title =  $(this).attr('id');
      $(this).on('click', function (e) {
        e.preventDefault();
        window.location.hash = 'page/' + title;
      });

    });
  },

  setSiteAttributes: function () {
    CMS.settings.siteAttributes.forEach(function (attribute) {

      var value;

      // Set brand
      if (attribute.attr == '.cms_sitename') {
        if (attribute.value.match(/\.(jpeg|jpg|gif|png)$/)) {
          value = '';
        } else {
          value = attribute.value;
        }
      } else {
        value = attribute.value;
      }
      $(attribute.attr).html(value).hide().fadeIn(CMS.settings.fadeSpeed);
    });
  },

  generateSite: function () {

    this.setSiteAttributes();

    var types = ['post', 'page'];

    types.forEach(function (type){
      CMS.getFiles(type);
    });

    // Check for hash changes
    $(window).on('hashchange', function () {
      CMS.render(window.location.hash);
    });
  },

  init: function (options) {
    if ($.isPlainObject(options)) {
      return this.extend(this.settings, options, function () {
        CMS.generateSite();
      });
    }
  }

};

<commit_msg>Get elements using pure JS.<commit_after>/*
 * CMS.js v1.0.0
 * Copyright 2015 Chris Diana
 * www.cdmedia.github.io/cms.js
 * Free to use under the MIT license.
 * http://www.opensource.org/licenses/mit-license.php
 */

var CMS = {

  settings: {
    siteName: 'CMS.js',
    siteTagline: 'Your site tagline',
    siteEmail: 'your_email@example.com',
    siteAuthor: 'Your Name',
    siteUrl: '',
    siteNavItems: [
      { name: 'Github', href: '#', newWindow: false },
      { name: 'About' }
    ],
    pagination: 3,
    postsFolder: 'posts',
    postSnippetLength: 120,
    pagesFolder: 'pages',
    fadeSpeed: 300,
    mainContainer: $(document.getElementsByClassName('cms_main')),
    footerContainer: $(document.getElementsByClassName('cms_footer')),
    footerText: '© ' + new Date().getFullYear() + ' All Rights Reserved.',
    parseSeperator: '---',
    postsOnFrontpage: true,
    pageAsFrontpage: '',
    postsOnUrl: '',
    loader: '
Loading...
',
    get siteAttributes() {
      return [
        { attr: 'title', value: CMS.settings.siteName },
        { attr: '.cms_sitename', value: CMS.settings.siteName },
        { attr: '.cms_tagline', value: CMS.settings.siteTagline },
        { attr: '.cms_footer_text', value: CMS.settings.footerText }
      ];
    },
    mode: 'Github',
    githubUserSettings: {
      username: 'yourusername',
      repo: 'yourrepo',
    },
    githubSettings: {
      branch: 'gh-pages',
      host: 'https://api.github.com'
    }
  },

  posts: [],
  pages: [],
  loaded: {},

  extend: function (target, opts, callback) {
    var next;
    if (typeof opts === 'undefined') {
      opts = target;
      target = CMS;
    }
    for (next in opts) {
      if (Object.prototype.hasOwnProperty.call(opts, next)) {
        target[next] = opts[next];
      }
    }
    callback(); // check user config options
    return target;
  },

  render: function (url) {
    CMS.settings.mainContainer.html('').fadeOut(CMS.settings.fadeSpeed);
    CMS.settings.footerContainer.hide();

    var type = url.split('/')[0];

    var map = {

      // Main view / Frontpage
      '' : function () {
          CMS.renderPosts();
      },

      // Post view / single view
      '#post' : function () {
        var id = url.split('#post/')[1].trim();
        CMS.renderPost(id);
      },

      // Page view
      '#page' : function () {
        var title = url.split('#page/')[1].trim();
        CMS.renderPage(title);
      }

    };

    if (map[type]) {
      map[type]();
    } else {
      // Error view
      var errorMsg = 'Error loading page.';
      CMS.renderError(errorMsg);
    }
  },

  renderPage: function (title) {
    CMS.pages.sort(function (a,b) { return CMS.settings.sortDateOrder ? b.date - a.date : a.date - b.date; });
    CMS.pages.forEach(function (page){
      if (page.title == title) {

        var tpl = $(document.getElementById('page-template')).html(),
          $tpl = $(tpl);

        $tpl.find('.page-title').html(page.title);
        $tpl.find('.page-content').html(page.contentData);

        CMS.settings.mainContainer.html($tpl).hide().fadeIn(CMS.settings.fadeSpeed);
      }
    });
    CMS.renderFooter();
  },

  renderPost: function (id) {
    CMS.posts.forEach(function (post){
      if (post.id == id) {

        var tpl = $(document.getElementById('post-template')).html(),
          $tpl = $(tpl);

        $tpl.find('.post-title').html(post.title);
        $tpl.find('.post-date').html((post.date.getMonth() + 1) + '/' + post.date.getDate() + '/' +  post.date.getFullYear());
        $tpl.find('.post-content').html(post.contentData);

        CMS.settings.mainContainer.html($tpl).hide().fadeIn(CMS.settings.fadeSpeed);
      }
    });
    CMS.renderFooter();
  },

  renderPosts: function () {
    CMS.posts.sort(function (a,b) { return CMS.settings.sortDateOrder ? b.date - a.date : a.date - b.date; });
    CMS.posts.forEach(function (post){
      var tpl = $(document.getElementById('post-template')).html(),
        $tpl = $(tpl);

      var title = '' + post.title + '',
        date = (post.date.getMonth() + 1) + '/' + post.date.getDate() + '/' +  post.date.getFullYear(),
        snippet = post.contentData.split('.')[0] + '.';

      var postLink = $tpl.find('.post-title'),
        postDate = $tpl.find('.post-date'),
        postSnippet = $tpl.find('.post-content');

      postLink.on('click', function (e) {
        e.preventDefault();
        window.location.hash = 'post/' + post.id;
      });

      postLink.html(title);
      postSnippet.html(snippet);
      postDate.html(date);
      CMS.settings.mainContainer.append($tpl).hide().fadeIn(CMS.settings.fadeSpeed);
    });
    CMS.renderFooter();
  },

  renderFooter: function () {
    // Delay footer loading while waiting on ajax requests
    setTimeout(function () {
      CMS.settings.footerContainer.fadeIn(CMS.settings.fadeSpeed);
    }, 800);
  },

  renderError: function (msg) {
    var tpl = $(document.getElementById('error-template')).html(),
      $tpl = $(tpl);

    $tpl.find('.error_text').html(msg);

    CMS.settings.mainContainer.html('').fadeOut(CMS.settings.fadeSpeed, function (){
      CMS.settings.mainContainer.html($tpl).fadeIn(CMS.settings.fadeSpeed);
    });
  },

  contentLoaded: function (type) {

    CMS.loaded[type] = true;

    if (CMS.loaded.page && CMS.loaded.post) {

      // Set navigation
      this.setNavigation();

      // Manually trigger on initial load
      $(window).trigger('hashchange');
    }
  },

  parseContent: function (content, type, file, counter, numFiles) {

    var data = content.split(CMS.settings.parseSeperator),
      contentObj = {},
      id = counter,
      date = file.date;

    contentObj.id = id;
    contentObj.date = date;

    // Get content info
    var infoData = data[1].split(/[\n\r]+/);

    $.each(infoData, function (k, v) {
      if (v.length) {
        v.replace(/^\s+|\s+$/g, '').trim();
        var i = v.split(':');
        var val = v.slice(v.indexOf(':')+1);
        k = i[0];

        val = (k == 'date' ? (new Date(val)) : val);

        contentObj[k] = (val.trim ? val.trim() : val);
      }
    });

    // Drop data we don't need
    data.splice(0,2);

    // Put everything back together if broken
    var contentData = data.join();
    contentObj.contentData = marked(contentData);

    switch(type) {
      case 'post':
        CMS.posts.push(contentObj);
        break;
      case 'page':
        CMS.pages.push(contentObj);
        break;
    }

    // Execute after all content is loaded
    if (counter === numFiles) {
      CMS.contentLoaded(type);
    }
  },

  getContent: function (type, file, counter, numFiles) {

    var urlFolder = '';

    switch(type) {
      case 'post':
        urlFolder = CMS.settings.postsFolder;
        break;
      case 'page':
        urlFolder = CMS.settings.pagesFolder;
        break;
    }

    if (CMS.settings.mode == 'Github') {
      url = file.link;
    } else {
      url = urlFolder + '/' + file.name;
    }

    $.ajax({
      type: 'GET',
      url: url,
      dataType: 'html',
      success: function (content) {
        CMS.parseContent(content, type, file, counter, numFiles);
      },
      error: function () {
        var errorMsg = 'Error loading ' + type + ' content';
        CMS.renderError(errorMsg);
      }
    });
  },

  getFiles: function (type) {

    var folder = '',
      url = '';

    switch(type) {
      case 'post':
        folder = CMS.settings.postsFolder;
        break;
      case 'page':
        folder = CMS.settings.pagesFolder;
        break;
    }

    if (CMS.settings.mode == 'Github') {
      var gus = CMS.settings.githubUserSettings,
        gs = CMS.settings.githubSettings;
      url = gs.host + '/repos/' + gus.username + '/' + gus.repo + '/contents/' + folder + '?ref=' + gs.branch;
    } else {
      url = folder;
    }

    $.ajax({
      url: url,
      success: function (data) {

        var files = [],
          linkFiles;

        if (CMS.settings.mode == 'Github') {
          linkFiles = data;
        } else {
          linkFiles = $(data).find('a');
        }

        $(linkFiles).each(function (k, f) {

          var filename,
            downloadLink;

          if (CMS.settings.mode == 'Github') {
            filename = f.name;
            downloadLink = f.download_url;
          } else {
            filename = $(f).attr('href');
          }

          if (filename.endsWith('.md')) {
            var file = {};
            file.date = new Date(filename.substring(0, 10));
            file.name = filename;
            if (downloadLink) {
              file.link = downloadLink;
            }
            files.push(file);
          }

        });

        var counter = 0,
          numFiles = files.length;

        if (files.length > 0) {
          $(files).each(function (k, file) {
            counter++;
            CMS.getContent(type, file, counter, numFiles);
          });
        } else {
          var errorMsg = 'Error loading ' + type + 's in directory. Make sure ' +
            'there are Markdown ' + type + 's in the ' + type + 's folder.';
          CMS.renderError(errorMsg);
        }
      },
      error: function () {
        var errorMsg;
        if (CMS.settings.mode == 'Github') {
          errorMsg = 'Error loading ' + type + 's directory. Make sure ' +
            'your Github settings are correctly set in your config.js file.';
        } else {
          errorMsg = 'Error loading ' + type + 's directory. Make sure ' +
            type + 's directory is set correctly in config and .htaccess is in ' +
            type + 's directory with Apache "Options Indexes" set on.';
        }
        CMS.renderError(errorMsg);
      }
    });
  },

  setNavigation: function () {

    var navBuilder = ['
'];
    CMS.settings.siteNavItems.forEach(function (navItem) {
      if (navItem.hasOwnProperty('href')) {
        navBuilder.push('
', navItem.name, '
');
      } else {
        CMS.pages.forEach(function (page) {
          if (navItem.name == page.title) {
            navBuilder.push('
', navItem.name, '
');
          }
        });
      }
    });
    navBuilder.push('
');
    var nav = navBuilder.join('');

    $(document.getElementsByClassName('cms_nav')).html(nav);

    // Set onclicks for nav links
    $.each($(document.getElementsByClassName('cms_nav_link')), function (k, link) {
      var title =  $(this).attr('id');
      $(this).on('click', function (e) {
        e.preventDefault();
        window.location.hash = 'page/' + title;
      });

    });
  },

  setSiteAttributes: function () {
    CMS.settings.siteAttributes.forEach(function (attribute) {

      var value;

      // Set brand
      if (attribute.attr == '.cms_sitename') {
        if (attribute.value.match(/\.(jpeg|jpg|gif|png)$/)) {
          value = '';
        } else {
          value = attribute.value;
        }
      } else {
        value = attribute.value;
      }
      $(attribute.attr).html(value).hide().fadeIn(CMS.settings.fadeSpeed);
    });
  },

  generateSite: function () {

    this.setSiteAttributes();

    var types = ['post', 'page'];

    types.forEach(function (type){
      CMS.getFiles(type);
    });

    // Check for hash changes
    $(window).on('hashchange', function () {
      CMS.render(window.location.hash);
    });
  },

  init: function (options) {
    if ($.isPlainObject(options)) {
      return this.extend(this.settings, options, function () {
        CMS.generateSite();
      });
    }
  }

};

<|endoftext|>


<commit_before>var rest = require('restler');

module.exports = {
  'gif': function(input, cb) {
    var self = this;
    var query = encodeURIComponent(input.parsed);
    var options = { rejectUnauthorized: false };
    var baseUrl = 'https://ticketap.com/rightgif';
    var url = baseUrl + '?text='+query;
    rest.get(url, options).on('complete', function(data) {
      var img;
      if(data.gifs && data.gifs.length > 0) {
        img = self.chooseRandom(data.gifs).url;
      } else {
        img = data.url;
      }
      cb(null, 'word!  ' + img);
    });
  },
  'chooseRandom': function(gifs) {
    return gifs[Math.floor(Math.random() * gifs.length)];
  }
};
<commit_msg>Add extra space for convention.<commit_after>var rest = require('restler');

module.exports = {
  'gif': function(input, cb) {
    var self = this;
    var query = encodeURIComponent(input.parsed);
    var options = { rejectUnauthorized: false };
    var baseUrl = 'https://ticketap.com/rightgif';
    var url = baseUrl + '?text='+query;
    rest.get(url, options).on('complete', function(data) {
      var img;
      if (data.gifs && data.gifs.length > 0) {
        img = self.chooseRandom(data.gifs).url;
      } else {
        img = data.url;
      }
      cb(null, 'word!  ' + img);
    });
  },
  'chooseRandom': function(gifs) {
    return gifs[Math.floor(Math.random() * gifs.length)];
  }
};
<|endoftext|>


<commit_before>var express = require('express');
var app = express();
var rquest = require('request');
app.set('port', (process.env.PORT || 5000));

app.use(express.static(__dirname + '/public'));

var bodyParser = require('body-parser')
app.use( bodyParser.json() );       // to support JSON-encoded bodies
app.use(bodyParser.urlencoded({     // to support URL-encoded bodies
  extended: true
}));

// views is directory for all template files
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');

app.get('/', function(request, response) {
  response.render('pages/index');
});

app.post('/', function(request, response) {
  if(request.body['command'] == "/onenoteurl"){
      var url = request.body['text'];

var decodedUrl = decodeURIComponent(url);
console.log(decodedUrl);
var first = decodedUrl.indexOf(".one|")+ 5
;
console.log(" first = " + first);
var second = decodedUrl.indexOf("/", first);
console.log(" second = " + second);
var third = decodedUrl.lastIndexOf("|");
console.log(" third = " + third);
var actualName = decodedUrl.substr(second, third-second);

var name = actualName+" (Webview)";
      var responseUrl = request.body['response_url'];
      var returnVal = {
    "response_type": "in_channel",
    "text": "A OneNote link to page was pasted",
    "attachments": [
        {
            "title": name + "<WebView>",
            "title_link": url
        }
    ]
};
}
    response.send({"response_type": "in_channel"});
    console.log(request.body['response_url']);

  //  request.post('http://service.com/upload', {form:{key:'value'}})
    rquest.post(request.body['response_url'], returnVal);
    // request.url = request.body['response_url'];
    // request.send(returnVal);
}

);

app.listen(app.get('port'), function() {
  console.log('Node app is running on port', app.get('port'));
});

<commit_msg>using request library to create post back to back to slack<commit_after>var express = require('express');
var app = express();
var rquest = require('request');
app.set('port', (process.env.PORT || 5000));

app.use(express.static(__dirname + '/public'));

var bodyParser = require('body-parser')
app.use( bodyParser.json() );       // to support JSON-encoded bodies
app.use(bodyParser.urlencoded({     // to support URL-encoded bodies
  extended: true
}));

// views is directory for all template files
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');

app.get('/', function(request, response) {
  response.render('pages/index');
});

app.post('/', function(request, response) {
  if(request.body['command'] == "/onenoteurl"){
      var url = request.body['text'];

var decodedUrl = decodeURIComponent(url);
console.log(decodedUrl);
var first = decodedUrl.indexOf(".one|")+ 5
;
console.log(" first = " + first);
var second = decodedUrl.indexOf("/", first);
console.log(" second = " + second);
var third = decodedUrl.lastIndexOf("|");
console.log(" third = " + third);
var actualName = decodedUrl.substr(second, third-second);

var name = actualName+" (Webview)";
      var responseUrl = request.body['response_url'];
      var returnVal = {
    "response_type": "in_channel",
    "text": "A OneNote link to page was pasted",
    "attachments": [
        {
            "title": name + "<WebView>",
            "title_link": url
        }
    ]
};
}
    response.send({"response_type": "ephemeral"});
    console.log(request.body['response_url']);

  //  request.post('http://service.com/upload', {form:{key:'value'}})
    rquest.post(request.body['response_url'], returnVal);
    // request.url = request.body['response_url'];
    // request.send(returnVal);
}

);

app.listen(app.get('port'), function() {
  console.log('Node app is running on port', app.get('port'));
});

<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import Dropzone from 'react-dropzone';
import strftime from 'strftime';

import Nav from 'react-bootstrap/lib/Nav';
import Navbar from 'react-bootstrap/lib/Navbar';
import NavItem from 'react-bootstrap/lib/NavItem';
import Button from 'react-bootstrap/lib/Button';
import Modal from 'react-bootstrap/lib/Modal';
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
import Alert from 'react-bootstrap/lib/Alert';

import FontAwesomeIcon from 'fm3/components/FontAwesomeIcon';

import { setTool, setActivePopup, closePopup } from 'fm3/actions/mainActions';
import { trackViewerSetData, trackViewerResetData, trackViewerResetTrackUID, trackViewerUploadTrack } from 'fm3/actions/trackViewerActions';
import { elevationChartSetTrackGeojson, elevationChartClose } from 'fm3/actions/elevationChartActions';
import { toastsAdd } from 'fm3/actions/toastsActions';

import { getMapLeafletElement } from 'fm3/leafletElementHolder';

import 'fm3/styles/trackViewer.scss';

class TrackViewerMenu extends React.Component {
  componentWillMount() {
    const startingWithBlankTrackViewer = this.props.trackUID === null;
    if (startingWithBlankTrackViewer) {
      this.props.onLaunchPopup('upload-track');
    }
  }

  componentWillReceiveProps(newProps) {
    if (newProps.trackGeojson && JSON.stringify(this.props.trackGeojson) !== JSON.stringify(newProps.trackGeojson)) {
      const geojsonBounds = L.geoJson(newProps.trackGeojson).getBounds();
      getMapLeafletElement().fitBounds(geojsonBounds);
    }

    const userHasUploadedTrackAndWantsToShareIt = this.props.trackUID === null && newProps.trackUID != null;
    if (userHasUploadedTrackAndWantsToShareIt) {
      this.props.onLaunchPopup('track-viewer-share');
    }
  }

  onFileDrop = (acceptedFiles, rejectedFiles) => {
    if (acceptedFiles.length > 0) {
      const reader = new FileReader();
      reader.readAsText(acceptedFiles[0], 'UTF-8');
      reader.onload = (event) => {
        const gpxAsString = event.target.result;
        this.props.onResetTrackUID();
        this.props.onTrackViewerSetData(gpxAsString);
        this.props.onClosePopup();
        this.props.onElevationChartClose();
      };

      reader.onerror = (e) => {
        this.props.onLoadError(`Nepodarilo sa spracovať súbor: ${e && e.message}`);
      };
    }

    if (rejectedFiles.length) {
      this.props.onLoadError('Nesprávny formát súboru: Nahraný súbor musí mať príponu .gpx');
    }
  }

  shareTrack = () => {
    if (this.props.trackUID) {
      this.props.onLaunchPopup('track-viewer-share');
    } else {
      this.props.onTrackViewerUploadTrack();
    }
  }

  toggleElevationChart = () => {
    const isActive = this.props.elevationChartTrackGeojson;
    if (isActive) {
      this.props.onElevationChartClose();
    } else {
      // this is bit confusing. TrackViewerMenu.props.trackGeojson is actually a feature set of geojsons (thought typically contains only one geojson), while in ElevationChart.props.trackGeojson we use first "real" feature, e.g. LineString
      this.props.onElevationChartSetTrackGeojson(this.props.trackGeojson.features[0]);
    }
  }

  trackGeojsonIsSuitableForElevationChart = () => {
    const trackGeojson = this.props.trackGeojson;
    if (trackGeojson && trackGeojson.features) {
      const firstGeojsonFeature = trackGeojson.features[0];
      const isLineString = firstGeojsonFeature && firstGeojsonFeature.geometry.type === 'LineString';
      return isLineString;
    }

    return false;
  }

  showTrackInfo = () => {
    const tableData = [];
    const startTime = new Date(this.props.startPoints[0].startTime);
    tableData.push(['čas štartu', strftime('%H:%M', startTime)]);
    const finishTime = new Date(this.props.finishPoints[0].finishTime);
    tableData.push(['čas v cieli', strftime('%H:%M', finishTime)]);
    const durationWithTimezone = new Date(finishTime - startTime);
    const duration = new Date(durationWithTimezone.getTime() + durationWithTimezone.getTimezoneOffset() * 60 * 1000);
    tableData.push(['trvanie', `${strftime('%k', duration)}h ${strftime('%M', duration)}m`]);
    const lengthInKm = this.props.finishPoints[0].lengthInKm;
    tableData.push(['vzdialenosť', `${lengthInKm.toFixed(1)}km`]);
    const durationInHours = duration.getHours() + duration.getMinutes() / 60.0;
    const avgSpeed = lengthInKm / durationInHours;
    tableData.push(['priem. rýchlosť', `${avgSpeed.toFixed(1)}km/h`]);
    const firstRealFeature = this.props.trackGeojson.features[0];
    const coords = firstRealFeature.geometry.coordinates;
    let minEle = Infinity;
    let maxEle = -Infinity;
    coords.forEach((latLonEle) => {
      const ele = latLonEle[2];
      if (ele < minEle) {
        minEle = ele;
      }
      if (maxEle < ele) {
        maxEle = ele;
      }
    });
    tableData.push(['najvyšší bod', `${maxEle.toFixed(0)} m.n.m.`]);
    tableData.push(['najnižší bod', `${minEle.toFixed(0)} m.n.m.`]);
    const infoMessage = (

            { tableData.map(labelAndValue => (

                {labelAndValue[0]}:
                {labelAndValue[1]}

            ))}

    );
    this.props.onShowTrackInfo(infoMessage);
  }

  render() {
    const { activePopup, onCancel, onLaunchPopup, onClosePopup, trackGpx, trackUID, elevationChartTrackGeojson } = this.props;

    let shareURL = '';
    if (trackUID) {
      shareURL = `${window.location.origin}/?tool=track-viewer&track-uid=${trackUID}`;
    }
    return (

        <Navbar.Form pullLeft>
          <Button onClick={() => onLaunchPopup('upload-track')}>
            <FontAwesomeIcon icon="upload" /> Nahrať trasu
          </Button>
          {' '}
          {this.trackGeojsonIsSuitableForElevationChart() &&
            <Button active={elevationChartTrackGeojson !== null} onClick={this.toggleElevationChart}>
              <FontAwesomeIcon icon="bar-chart" /> Výškový profil
            </Button>
          }
          {' '}
          {this.trackGeojsonIsSuitableForElevationChart() &&
            <Button onClick={this.showTrackInfo}>
              <FontAwesomeIcon icon="info-circle" /> Viac info
            </Button>
          }
          {' '}
          {trackGpx &&
            <Button onClick={this.shareTrack}>
              <FontAwesomeIcon icon="share-alt" /> Zdieľať
            </Button>
          }
        </Navbar.Form>

          <NavItem onClick={onCancel}><Glyphicon glyph="remove" /> Zavrieť</NavItem>

        <Modal show={activePopup === 'upload-track'} onHide={onClosePopup}>
          <Modal.Header closeButton>
            <Modal.Title>Nahrať záznam trasy</Modal.Title>
          </Modal.Header>
          <Modal.Body>
            <Dropzone onDrop={this.onFileDrop} multiple={false} accept=".gpx" className="dropzone">

Potiahnite sem .gpx súbor, alebo sem kliknite pre jeho výber.

            </Dropzone>
          </Modal.Body>
          <Modal.Footer>
            <Button onClick={onClosePopup}><Glyphicon glyph="remove" /> Zrušiť</Button>
          </Modal.Footer>
        </Modal>

        <Modal show={activePopup === 'track-viewer-share'} onHide={onClosePopup}>
          <Modal.Header closeButton>
            <Modal.Title>Zdieľať záznam trasy</Modal.Title>
          </Modal.Header>
          <Modal.Body>
            Trasa je dostupná na nasledovnej adrese:
            <Alert>
              {shareURL}
            </Alert>
          </Modal.Body>
          <Modal.Footer>
            <Button onClick={onClosePopup}><Glyphicon glyph="remove" /> Zavrieť</Button>
          </Modal.Footer>
        </Modal>

    );
  }
}

TrackViewerMenu.propTypes = {
  activePopup: PropTypes.string,
  onCancel: PropTypes.func.isRequired,
  onClosePopup: PropTypes.func.isRequired,
  onLaunchPopup: PropTypes.func.isRequired,
  onTrackViewerUploadTrack: PropTypes.func.isRequired,
  onTrackViewerSetData: PropTypes.func.isRequired,
  onLoadError: PropTypes.func.isRequired,
  onResetTrackUID: PropTypes.func.isRequired,
  trackGeojson: PropTypes.object,  // eslint-disable-line
  trackGpx: PropTypes.string,
  trackUID: PropTypes.string,
  onElevationChartSetTrackGeojson: PropTypes.func.isRequired,
  onElevationChartClose: PropTypes.func.isRequired,
  elevationChartTrackGeojson: PropTypes.object, // eslint-disable-line
  onShowTrackInfo: PropTypes.func.isRequired,
  startPoints: PropTypes.arrayOf(PropTypes.shape({
    startTime: PropTypes.string,
  })),
  finishPoints: PropTypes.arrayOf(PropTypes.shape({
    lengthInKm: PropTypes.number.isRequired,
    finishTime: PropTypes.string,
  })),
};

export default connect(
  state => ({
    activePopup: state.main.activePopup,
    trackGeojson: state.trackViewer.trackGeojson,
    trackGpx: state.trackViewer.trackGpx,
    startPoints: state.trackViewer.startPoints,
    finishPoints: state.trackViewer.finishPoints,
    trackUID: state.trackViewer.trackUID,
    elevationChartTrackGeojson: state.elevationChart.trackGeojson,
  }),
  dispatch => ({
    onCancel() {
      dispatch(trackViewerResetData());
      dispatch(setTool(null));
      dispatch(elevationChartClose());
    },
    onLaunchPopup(popupName) {
      dispatch(setActivePopup(popupName));
    },
    onClosePopup() {
      dispatch(closePopup());
    },
    onTrackViewerSetData(gpx) {
      dispatch(trackViewerSetData(gpx));
    },
    onResetTrackUID() {
      dispatch(trackViewerResetTrackUID());
    },
    onTrackViewerUploadTrack() {
      dispatch(trackViewerUploadTrack());
    },
    onElevationChartSetTrackGeojson(trackGeojson) {
      dispatch(elevationChartSetTrackGeojson(trackGeojson));
    },
    onElevationChartClose() {
      dispatch(elevationChartClose());
    },
    onShowTrackInfo(message) {
      dispatch(toastsAdd({
        collapseKey: 'trackViewer.trackInfo',
        message,
        style: 'info',
      }));
    },
    onLoadError(message) {
      dispatch(toastsAdd({
        collapseKey: 'trackViewer.loadError',
        message,
        style: 'danger',
        timeout: 3000,
      }));
    },
  }),
)(TrackViewerMenu);
<commit_msg>#129: auto hide info toast on new track or tool cancel<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import Dropzone from 'react-dropzone';
import strftime from 'strftime';

import Nav from 'react-bootstrap/lib/Nav';
import Navbar from 'react-bootstrap/lib/Navbar';
import NavItem from 'react-bootstrap/lib/NavItem';
import Button from 'react-bootstrap/lib/Button';
import Modal from 'react-bootstrap/lib/Modal';
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
import Alert from 'react-bootstrap/lib/Alert';

import FontAwesomeIcon from 'fm3/components/FontAwesomeIcon';

import { setTool, setActivePopup, closePopup } from 'fm3/actions/mainActions';
import { trackViewerSetData, trackViewerResetData, trackViewerResetTrackUID, trackViewerUploadTrack } from 'fm3/actions/trackViewerActions';
import { elevationChartSetTrackGeojson, elevationChartClose } from 'fm3/actions/elevationChartActions';
import { toastsAdd } from 'fm3/actions/toastsActions';

import { getMapLeafletElement } from 'fm3/leafletElementHolder';

import 'fm3/styles/trackViewer.scss';

class TrackViewerMenu extends React.Component {
  componentWillMount() {
    const startingWithBlankTrackViewer = this.props.trackUID === null;
    if (startingWithBlankTrackViewer) {
      this.props.onLaunchPopup('upload-track');
    }
  }

  componentWillReceiveProps(newProps) {
    if (newProps.trackGeojson && JSON.stringify(this.props.trackGeojson) !== JSON.stringify(newProps.trackGeojson)) {
      const geojsonBounds = L.geoJson(newProps.trackGeojson).getBounds();
      getMapLeafletElement().fitBounds(geojsonBounds);
    }

    const userHasUploadedTrackAndWantsToShareIt = this.props.trackUID === null && newProps.trackUID != null;
    if (userHasUploadedTrackAndWantsToShareIt) {
      this.props.onLaunchPopup('track-viewer-share');
    }
  }

  onFileDrop = (acceptedFiles, rejectedFiles) => {
    if (acceptedFiles.length > 0) {
      const reader = new FileReader();
      reader.readAsText(acceptedFiles[0], 'UTF-8');
      reader.onload = (event) => {
        const gpxAsString = event.target.result;
        this.props.onResetTrackUID();
        this.props.onTrackViewerSetData(gpxAsString);
        this.props.onClosePopup();
        this.props.onElevationChartClose();
      };

      reader.onerror = (e) => {
        this.props.onLoadError(`Nepodarilo sa spracovať súbor: ${e && e.message}`);
      };
    }

    if (rejectedFiles.length) {
      this.props.onLoadError('Nesprávny formát súboru: Nahraný súbor musí mať príponu .gpx');
    }
  }

  shareTrack = () => {
    if (this.props.trackUID) {
      this.props.onLaunchPopup('track-viewer-share');
    } else {
      this.props.onTrackViewerUploadTrack();
    }
  }

  toggleElevationChart = () => {
    const isActive = this.props.elevationChartTrackGeojson;
    if (isActive) {
      this.props.onElevationChartClose();
    } else {
      // this is bit confusing. TrackViewerMenu.props.trackGeojson is actually a feature set of geojsons (thought typically contains only one geojson), while in ElevationChart.props.trackGeojson we use first "real" feature, e.g. LineString
      this.props.onElevationChartSetTrackGeojson(this.props.trackGeojson.features[0]);
    }
  }

  trackGeojsonIsSuitableForElevationChart = () => {
    const trackGeojson = this.props.trackGeojson;
    if (trackGeojson && trackGeojson.features) {
      const firstGeojsonFeature = trackGeojson.features[0];
      const isLineString = firstGeojsonFeature && firstGeojsonFeature.geometry.type === 'LineString';
      return isLineString;
    }

    return false;
  }

  showTrackInfo = () => {
    const tableData = [];
    const startTime = new Date(this.props.startPoints[0].startTime);
    tableData.push(['čas štartu', strftime('%H:%M', startTime)]);
    const finishTime = new Date(this.props.finishPoints[0].finishTime);
    tableData.push(['čas v cieli', strftime('%H:%M', finishTime)]);
    const durationWithTimezone = new Date(finishTime - startTime);
    const duration = new Date(durationWithTimezone.getTime() + durationWithTimezone.getTimezoneOffset() * 60 * 1000);
    tableData.push(['trvanie', `${strftime('%k', duration)}h ${strftime('%M', duration)}m`]);
    const lengthInKm = this.props.finishPoints[0].lengthInKm;
    tableData.push(['vzdialenosť', `${lengthInKm.toFixed(1)}km`]);
    const durationInHours = duration.getHours() + duration.getMinutes() / 60.0;
    const avgSpeed = lengthInKm / durationInHours;
    tableData.push(['priem. rýchlosť', `${avgSpeed.toFixed(1)}km/h`]);
    const firstRealFeature = this.props.trackGeojson.features[0];
    const coords = firstRealFeature.geometry.coordinates;
    let minEle = Infinity;
    let maxEle = -Infinity;
    coords.forEach((latLonEle) => {
      const ele = latLonEle[2];
      if (ele < minEle) {
        minEle = ele;
      }
      if (maxEle < ele) {
        maxEle = ele;
      }
    });
    tableData.push(['najvyšší bod', `${maxEle.toFixed(0)} m.n.m.`]);
    tableData.push(['najnižší bod', `${minEle.toFixed(0)} m.n.m.`]);
    const infoMessage = (

            { tableData.map(labelAndValue => (

                {labelAndValue[0]}:
                {labelAndValue[1]}

            ))}

    );
    this.props.onShowTrackInfo(infoMessage);
  }

  render() {
    const { activePopup, onCancel, onLaunchPopup, onClosePopup, trackGpx, trackUID, elevationChartTrackGeojson } = this.props;

    let shareURL = '';
    if (trackUID) {
      shareURL = `${window.location.origin}/?tool=track-viewer&track-uid=${trackUID}`;
    }
    return (

        <Navbar.Form pullLeft>
          <Button onClick={() => onLaunchPopup('upload-track')}>
            <FontAwesomeIcon icon="upload" /> Nahrať trasu
          </Button>
          {' '}
          {this.trackGeojsonIsSuitableForElevationChart() &&
            <Button active={elevationChartTrackGeojson !== null} onClick={this.toggleElevationChart}>
              <FontAwesomeIcon icon="bar-chart" /> Výškový profil
            </Button>
          }
          {' '}
          {this.trackGeojsonIsSuitableForElevationChart() &&
            <Button onClick={this.showTrackInfo}>
              <FontAwesomeIcon icon="info-circle" /> Viac info
            </Button>
          }
          {' '}
          {trackGpx &&
            <Button onClick={this.shareTrack}>
              <FontAwesomeIcon icon="share-alt" /> Zdieľať
            </Button>
          }
        </Navbar.Form>

          <NavItem onClick={onCancel}><Glyphicon glyph="remove" /> Zavrieť</NavItem>

        <Modal show={activePopup === 'upload-track'} onHide={onClosePopup}>
          <Modal.Header closeButton>
            <Modal.Title>Nahrať záznam trasy</Modal.Title>
          </Modal.Header>
          <Modal.Body>
            <Dropzone onDrop={this.onFileDrop} multiple={false} accept=".gpx" className="dropzone">

Potiahnite sem .gpx súbor, alebo sem kliknite pre jeho výber.

            </Dropzone>
          </Modal.Body>
          <Modal.Footer>
            <Button onClick={onClosePopup}><Glyphicon glyph="remove" /> Zrušiť</Button>
          </Modal.Footer>
        </Modal>

        <Modal show={activePopup === 'track-viewer-share'} onHide={onClosePopup}>
          <Modal.Header closeButton>
            <Modal.Title>Zdieľať záznam trasy</Modal.Title>
          </Modal.Header>
          <Modal.Body>
            Trasa je dostupná na nasledovnej adrese:
            <Alert>
              {shareURL}
            </Alert>
          </Modal.Body>
          <Modal.Footer>
            <Button onClick={onClosePopup}><Glyphicon glyph="remove" /> Zavrieť</Button>
          </Modal.Footer>
        </Modal>

    );
  }
}

TrackViewerMenu.propTypes = {
  activePopup: PropTypes.string,
  onCancel: PropTypes.func.isRequired,
  onClosePopup: PropTypes.func.isRequired,
  onLaunchPopup: PropTypes.func.isRequired,
  onTrackViewerUploadTrack: PropTypes.func.isRequired,
  onTrackViewerSetData: PropTypes.func.isRequired,
  onLoadError: PropTypes.func.isRequired,
  onResetTrackUID: PropTypes.func.isRequired,
  trackGeojson: PropTypes.object,  // eslint-disable-line
  trackGpx: PropTypes.string,
  trackUID: PropTypes.string,
  onElevationChartSetTrackGeojson: PropTypes.func.isRequired,
  onElevationChartClose: PropTypes.func.isRequired,
  elevationChartTrackGeojson: PropTypes.object, // eslint-disable-line
  onShowTrackInfo: PropTypes.func.isRequired,
  startPoints: PropTypes.arrayOf(PropTypes.shape({
    startTime: PropTypes.string,
  })),
  finishPoints: PropTypes.arrayOf(PropTypes.shape({
    lengthInKm: PropTypes.number.isRequired,
    finishTime: PropTypes.string,
  })),
};

export default connect(
  state => ({
    activePopup: state.main.activePopup,
    trackGeojson: state.trackViewer.trackGeojson,
    trackGpx: state.trackViewer.trackGpx,
    startPoints: state.trackViewer.startPoints,
    finishPoints: state.trackViewer.finishPoints,
    trackUID: state.trackViewer.trackUID,
    elevationChartTrackGeojson: state.elevationChart.trackGeojson,
  }),
  dispatch => ({
    onCancel() {
      dispatch(trackViewerResetData());
      dispatch(setTool(null));
      dispatch(elevationChartClose());
    },
    onLaunchPopup(popupName) {
      dispatch(setActivePopup(popupName));
    },
    onClosePopup() {
      dispatch(closePopup());
    },
    onTrackViewerSetData(gpx) {
      dispatch(trackViewerSetData(gpx));
    },
    onResetTrackUID() {
      dispatch(trackViewerResetTrackUID());
    },
    onTrackViewerUploadTrack() {
      dispatch(trackViewerUploadTrack());
    },
    onElevationChartSetTrackGeojson(trackGeojson) {
      dispatch(elevationChartSetTrackGeojson(trackGeojson));
    },
    onElevationChartClose() {
      dispatch(elevationChartClose());
    },
    onShowTrackInfo(message) {
      dispatch(toastsAdd({
        collapseKey: 'trackViewer.trackInfo',
        message,
        cancelType: ['SET_TOOL', 'TRACK_VIEWER_SET_TRACK_DATA'],
        style: 'info',
      }));
    },
    onLoadError(message) {
      dispatch(toastsAdd({
        collapseKey: 'trackViewer.loadError',
        message,
        style: 'danger',
        timeout: 3000,
      }));
    },
  }),
)(TrackViewerMenu);
<|endoftext|>