<commit_before>// @flow
import React, {Component, PropTypes as t} from 'react';
import AssignProducts from './assign-products';
import AddObservations from './add-observations';
import Breadcrumbs from '../share/breadcrumbs';
import ButtonSet from '../share/button-set';
import DataDisplay from './data-display';
import DataEntry from './data-entry';
import DateRange from '../share/date-range';
import DropupBtn from '../share/dropup-button';
import LookupInput from '../share/lookup-input';
import Select from '../share/select';
import WizardSteps from '../share/wizard-steps';
import moment from 'moment';
import NotImplemented from '../share/not-implemented';
import TargetSelect from './target-select';
import {defineSetState, setState} from '../util/state-util';
import {getLocationParts} from '../util/hash-route';
import {getUrl} from '../util/url-util';
import {handleError} from '../util/error';
import './app.css';

type BreadcrumbType = {
  id: number,
  label: string
};

type EventType = {
  target: {
    value: string
  }
};

async function loadProductCategories() {
  const url = getUrl('product-categories');
  try {
    const res = await fetch(url);
    if (!res.ok) return handleError(url, res);

    const productCategories = await res.json();

    setState({productCategories});
  } catch (e) {
    handleError(url, e);
  }
}

async function loadProjects() {
  const url = getUrl('project');
  try {
    const res = await fetch(url);
    if (!res.ok) return handleError(url, res);

    const projects = await res.json();

    const projectMap = {};
    for (const project of projects) {
      projectMap[project.id] = project;
    }

    setState({projectMap});
  } catch (e) {
    handleError(url, e);
  }
}

type PropsType = {
  date: Object
};

class App extends Component {
  static propTypes = {
    date: t.object, // moment (just for tests)
  };

  state = {
    crops: [],
    availableMcts: [],
    availableRegions: [],
    activeCrumb: undefined,
    description: '',
    endDate: undefined,
    error: '',
    name: '',
    productCategories: [],
    productTargets: [],
    projectMap: {},
    selectedCategory: '',
    selectedTarget: '',
    selectedCrop: '',
    selectedMct: '',
    selectedRegion: '',
    selected: '',
    startDate: undefined,
  };

  breadcrumbs = [
    {id: 1, label: 'Foo'},
    {id: 2, label: 'Bar'},
    {id: 3, label: 'Baz'},
  ];

  constructor(props: PropsType) {
    super(props);

    const date = props.date ? props.date : moment();
    // eslint-disable-next-line react/no-direct-mutation-state
    this.state.startDate = (this.state.endDate = date);

    // Allow any component to change the state of this top-most component.
    defineSetState(this);

    // Re-render any time the URL hash changes.
    window.addEventListener('hashchange', () => this.forceUpdate());
  }

  componentDidMount() {
    loadProjects();
    loadProductCategories();
  }

  onCategorySelect = (category: string) => {
    console.log('app.js onCategorySelect: category =', category);
  };

  onEndDateChanged = (endDate: Object) => {
    this.setState({endDate});
  };

  onNavigate = (crumb: BreadcrumbType) => {
    this.setState({activeCrumb: crumb.id});
  };

  onStartDateChanged = (startDate: Object) => {
    this.setState({startDate});
  };

  onSelected = (event: EventType) =>
    this.setState({selected: event.target.value});

  render() {
    const {hash} = getLocationParts(window.location);

    const {
      activeCrumb,
      description,
      endDate,
      error,
      name,
      productCategories,
      productTargets,
      projectMap,
      selectedCategory,
      selectedTarget,
      startDate,
    } = this.state;

    const buttons = [
      {
        disabled: true,
        text: 'Save',
        kind: 'primary',
        onClick: () => console.log('saved!'),
      },
      {
        disabled: false,
        text: 'Info',
        kind: 'info',
        onClick: () => console.log('info!'),
      },
      {
        text: 'Cancel',
        kind: 'danger',
        onClick: () => console.log('cancelled!'),
      },
    ];

    const input = {
      img: 'search',
      onChange: (event = {}) => console.log(event.target.value),
      onSubmit: () => console.log('clicked!'),
    };

    const dropupBtnParams = {
      btn: {
        disabled: false,
        kind: 'danger',
        btnText: 'My button',
      },
      links: [
        {
          onClick: () => console.log('clicked1'),
          separator: false,
          text: 'link 1',
        },
        {
          onClick: () => console.log('clicked2'),
          separator: false,
          text: 'link 2',
        },
      ],
    };

    const wizardSteps = {
      steps: ['Assign Products', 'Add Trail Data', 'Add Observations'],
      activeIndex: 0,
    };

    const categoryOptions = productCategories.map(cat => ({
      text: cat,
      value: cat,
    }));

    const targetOptions = productTargets.map(target => ({
      text: target,
      value: target,
    }));

    const router = () => {
      switch (hash) {
        case 'display':
          return <DataDisplay projectMap={projectMap} />;
        case 'entry':
          return <DataEntry description={description} name={name} />;
        case 'assign-products':
          return <AssignProducts crops={this.state.crops} />;
        case 'add-observations':
          return <NotImplemented name="AddObservations" />;
        default:
          return null;
      }
    };

    const selectProps = {
      disabled: false,
      multiple: false,
      onChange: this.onSelected,
      options: [
        {text: 'A', value: 'a'},
        {text: 'B', value: 'b'},
        {text: 'C', value: 'c'},
      ],
      size: 1,
      value: this.state.selected,
    };

    return (

Breadcrumbs

        <Breadcrumbs
          activeCrumb={activeCrumb}
          items={this.breadcrumbs}
          onNavigate={this.onNavigate}
        />

{error}

Routes

            Display

            Add

            Assign Products

            Add Observations

          {router()}

ButtonSet Component

        <ButtonSet buttons={buttons} />

LookupInput Component

        <LookupInput {...input} />

DropupBtn Component

        <DropupBtn {...dropupBtnParams} />

DateRange Component

          Date Range
          <DateRange
            startDate={startDate}
            endDate={endDate}
            onStartDateChanged={this.onStartDateChanged}
            onEndDateChanged={this.onEndDateChanged}
          />

WizardSteps Component

        <WizardSteps {...wizardSteps} />

TargetSelect Component

        <TargetSelect
          categories={categoryOptions}
          onChange={this.onCategorySelect}
          selectedCategory={selectedCategory}
          selectedTarget={selectedTarget}
          targets={targetOptions}
        />

        <Select {...selectProps} />

    );
  }
}

export default App;
<commit_msg>comment out AddObservations import for now<commit_after>// @flow
import React, {Component, PropTypes as t} from 'react';
import AssignProducts from './assign-products';
//import AddObservations from './add-observations';
import Breadcrumbs from '../share/breadcrumbs';
import ButtonSet from '../share/button-set';
import DataDisplay from './data-display';
import DataEntry from './data-entry';
import DateRange from '../share/date-range';
import DropupBtn from '../share/dropup-button';
import LookupInput from '../share/lookup-input';
import Select from '../share/select';
import WizardSteps from '../share/wizard-steps';
import moment from 'moment';
import NotImplemented from '../share/not-implemented';
import TargetSelect from './target-select';
import {defineSetState, setState} from '../util/state-util';
import {getLocationParts} from '../util/hash-route';
import {getUrl} from '../util/url-util';
import {handleError} from '../util/error';
import './app.css';

type BreadcrumbType = {
  id: number,
  label: string
};

type EventType = {
  target: {
    value: string
  }
};

async function loadProductCategories() {
  const url = getUrl('product-categories');
  try {
    const res = await fetch(url);
    if (!res.ok) return handleError(url, res);

    const productCategories = await res.json();

    setState({productCategories});
  } catch (e) {
    handleError(url, e);
  }
}

async function loadProjects() {
  const url = getUrl('project');
  try {
    const res = await fetch(url);
    if (!res.ok) return handleError(url, res);

    const projects = await res.json();

    const projectMap = {};
    for (const project of projects) {
      projectMap[project.id] = project;
    }

    setState({projectMap});
  } catch (e) {
    handleError(url, e);
  }
}

type PropsType = {
  date: Object
};

class App extends Component {
  static propTypes = {
    date: t.object, // moment (just for tests)
  };

  state = {
    crops: [],
    availableMcts: [],
    availableRegions: [],
    activeCrumb: undefined,
    description: '',
    endDate: undefined,
    error: '',
    name: '',
    productCategories: [],
    productTargets: [],
    projectMap: {},
    selectedCategory: '',
    selectedTarget: '',
    selectedCrop: '',
    selectedMct: '',
    selectedRegion: '',
    selected: '',
    startDate: undefined,
  };

  breadcrumbs = [
    {id: 1, label: 'Foo'},
    {id: 2, label: 'Bar'},
    {id: 3, label: 'Baz'},
  ];

  constructor(props: PropsType) {
    super(props);

    const date = props.date ? props.date : moment();
    // eslint-disable-next-line react/no-direct-mutation-state
    this.state.startDate = (this.state.endDate = date);

    // Allow any component to change the state of this top-most component.
    defineSetState(this);

    // Re-render any time the URL hash changes.
    window.addEventListener('hashchange', () => this.forceUpdate());
  }

  componentDidMount() {
    loadProjects();
    loadProductCategories();
  }

  onCategorySelect = (category: string) => {
    console.log('app.js onCategorySelect: category =', category);
  };

  onEndDateChanged = (endDate: Object) => {
    this.setState({endDate});
  };

  onNavigate = (crumb: BreadcrumbType) => {
    this.setState({activeCrumb: crumb.id});
  };

  onStartDateChanged = (startDate: Object) => {
    this.setState({startDate});
  };

  onSelected = (event: EventType) =>
    this.setState({selected: event.target.value});

  render() {
    const {hash} = getLocationParts(window.location);

    const {
      activeCrumb,
      description,
      endDate,
      error,
      name,
      productCategories,
      productTargets,
      projectMap,
      selectedCategory,
      selectedTarget,
      startDate,
    } = this.state;

    const buttons = [
      {
        disabled: true,
        text: 'Save',
        kind: 'primary',
        onClick: () => console.log('saved!'),
      },
      {
        disabled: false,
        text: 'Info',
        kind: 'info',
        onClick: () => console.log('info!'),
      },
      {
        text: 'Cancel',
        kind: 'danger',
        onClick: () => console.log('cancelled!'),
      },
    ];

    const input = {
      img: 'search',
      onChange: (event = {}) => console.log(event.target.value),
      onSubmit: () => console.log('clicked!'),
    };

    const dropupBtnParams = {
      btn: {
        disabled: false,
        kind: 'danger',
        btnText: 'My button',
      },
      links: [
        {
          onClick: () => console.log('clicked1'),
          separator: false,
          text: 'link 1',
        },
        {
          onClick: () => console.log('clicked2'),
          separator: false,
          text: 'link 2',
        },
      ],
    };

    const wizardSteps = {
      steps: ['Assign Products', 'Add Trail Data', 'Add Observations'],
      activeIndex: 0,
    };

    const categoryOptions = productCategories.map(cat => ({
      text: cat,
      value: cat,
    }));

    const targetOptions = productTargets.map(target => ({
      text: target,
      value: target,
    }));

    const router = () => {
      switch (hash) {
        case 'display':
          return <DataDisplay projectMap={projectMap} />;
        case 'entry':
          return <DataEntry description={description} name={name} />;
        case 'assign-products':
          return <AssignProducts crops={this.state.crops} />;
        case 'add-observations':
          return <NotImplemented name="AddObservations" />;
        default:
          return null;
      }
    };

    const selectProps = {
      disabled: false,
      multiple: false,
      onChange: this.onSelected,
      options: [
        {text: 'A', value: 'a'},
        {text: 'B', value: 'b'},
        {text: 'C', value: 'c'},
      ],
      size: 1,
      value: this.state.selected,
    };

    return (

Breadcrumbs

        <Breadcrumbs
          activeCrumb={activeCrumb}
          items={this.breadcrumbs}
          onNavigate={this.onNavigate}
        />

{error}

Routes

            Display

            Add

            Assign Products

            Add Observations

          {router()}

ButtonSet Component

        <ButtonSet buttons={buttons} />

LookupInput Component

        <LookupInput {...input} />

DropupBtn Component

        <DropupBtn {...dropupBtnParams} />

DateRange Component

          Date Range
          <DateRange
            startDate={startDate}
            endDate={endDate}
            onStartDateChanged={this.onStartDateChanged}
            onEndDateChanged={this.onEndDateChanged}
          />

WizardSteps Component

        <WizardSteps {...wizardSteps} />

TargetSelect Component

        <TargetSelect
          categories={categoryOptions}
          onChange={this.onCategorySelect}
          selectedCategory={selectedCategory}
          selectedTarget={selectedTarget}
          targets={targetOptions}
        />

        <Select {...selectProps} />

    );
  }
}

export default App;
<|endoftext|>


<commit_before>
var openspending = angular.module('openspending', ['templates-app','templates-common', 'ngCookies', 'ui.router', 'ui.bootstrap', 'localytics.directives', 'openspending.modeler']);

openspending.controller('AppCtrl', ['$scope', '$location', '$http', '$cookies', '$window', '$sce', 'flash',
  function($scope, $location, $http, $cookies, $window, $sce, flash) {

  $scope.flash = flash;

  // EU cookie warning
  $scope.showCookieWarning = !$cookies.neelieCookie;

  $scope.hideCookieWarning = function() {
    $cookies.neelieCookie = true;
    $scope.showCookieWarning = !$cookies.neelieCookie;
  };

  // Language selector
  $scope.setLocale = function(locale) {
    $http.post('/set-locale', {'locale': locale}).then(function(res) {
      $window.location.reload();
    });
    return false;
  };

  // Allow SCE escaping in the app
  $scope.trustAsHtml = function(text) {
    return $sce.trustAsHtml('' + text);
  };

}]);

openspending.factory('flash', ['$rootScope', function($rootScope) {
  // Message flashing.
  var currentMessage = null;

  $rootScope.$on("$routeChangeSuccess", function() {
    currentMessage = null;
  });

  return {
    setMessage: function(message, type) {
      currentMessage = [message, type];
    },
    getMessage: function() {
      return currentMessage;
    }
  };
}]);

openspending.factory('OSAPIservice', function($http) {

    var OSAPI = {};

    OSAPI.getDatasets = function(dataset_params) {
      //options include
      //fields=field1,feidl2, and getsources=true
      return $http({
        url: '/api/3/datasets',
        params: dataset_params
      });
    };
    return OSAPI;
  });

openspending.factory('validation', ['flash', function(flash) {
  // handle server-side form validation errors.
  return {
    handle: handle = function(form) {
      return function(res) {
        if (res.status == 400 || !form) {
            var errors = [];
            console.log(res.data.errors);
            for (var field in res.data.errors) {
                form[field].$setValidity('value', false);
                form[field].$message = res.data.errors[field];
                errors.push(field);
            }
            if (angular.isDefined(form._errors)) {
                angular.forEach(form._errors, function(field) {
                    if (errors.indexOf(field) == -1) {
                        form[field].$setValidity('value', true);
                    }
                });
            }
            form._errors = errors;
        } else {
          console.log(res);
          flash.setMessage(res.data.message || res.data.title || 'Server error', 'danger');
        }
      };
    }
  };
}]);

openspending.factory('referenceData', ['$http', function($http) {
  /* This is used to cache reference data once it has been retrieved from the
  server. Reference data includes the canonical lists of country names,
  currencies, etc. */
  var referenceData = $http.get('/api/3/reference');

  var getData = function(cb) {
    referenceData.then(function(res) {
      cb(res.data);
    });
  };

  return {'get': getData};
}]);

openspending.controller('DatasetNewCtrl', ['$scope', '$http', '$window', '$location', '$stateParams', 'referenceData', 'validation',
  function($scope, $http, $window, $location, $stateParams, referenceData, validation) {
  /* This controller is not activated via routing, but explicitly through the
  dataset.new flask route. */

  $scope.reference = {};
  $scope.permissions = {"create":false};
  $scope.dataset = {'category': 'budget', 'territories': []};

  referenceData.get(function(reference) {
    $scope.reference = reference;
  });

  if ($stateParams.datasetname){
    //get dataset info and update the scope
    //checks permission as well
    $http.get('/api/3/datasets/' + $stateParams.datasetname)
      .then(function(res){

        $scope.dataset = res.data;
        //need to add in error catch here
        $scope.canCreate = true;
        $scope.save = function(form) {
          var dfd = $http.post('/api/3/datasets/' + $stateParams.datasetname, $scope.dataset);
          dfd.then(function(res) {
            //$location.path('/' + res.data.name + '/manage/meta');
            if (res.data.Success === true){
              //flash message
              console.log("saved");
              $location.path('/datasetlist');
            }
            else{
              //error message
            }
          }, validation.handle(form));
        };
      });

  }
  else{
    $http.get('/api/2/permissions?dataset=new').then(function(res) {
      $scope.permissions = res.data;
    });
    $scope.save = function(form) {
      var dfd = $http.post('/api/3/datasets', $scope.dataset);
      dfd.then(function(res) {
        $location.path('/' + res.data.name + '/manage/meta');
      }, validation.handle(form));
    };
  }

}]);

openspending.controller('SourceFormCtrl', ['$scope', '$http', '$window', '$location', '$stateParams', 'referenceData', 'validation',
  function($scope, $http, $window, $location, $stateParams, referenceData, validation) {
    // if $stateProvider.sourcename then populate with data
    // muse have $stateProvider.dataset as dataset name

    $scope.permissions = {"create" : false};
    $scope.reference = {'frequpdate' : [
        {'code': 'never', 'label': 'Never'},
        {'code': 'daily', 'label': 'Daily'},
        {'code': 'weekly', 'label': 'Weekly'},
        {'code': 'monthly', 'label': 'Monthly'}
        ]
      };

    $scope.source = {"label":null, "url": null, "frequpdate":null};

    if (! $stateParams.sourcename){
      //check that user has permission
      $http.get('/api/3/permissions?dataset=new').then(function(res) {
        $scope.permissions = res.data;
      });
    }
    else{
      //populate the form with a call
    }

  $scope.save = function(form) {
    var dfd = $http.post('/api/3/datasets', $scope.dataset);
    dfd.then(function(res) {
      $location.path('/' + res.data.name + '/manage/meta');
    }, validation.handle(form));
  };

// can check this as we

}]);

openspending.controller('datasetListCrl', ['$scope', '$http', 'OSAPIservice', '$location',
  function($scope, $http, OSAPIservice, $location) {

    $scope.datasets = [];
    OSAPIservice.getDatasets({'fields':"name,label",
                              'getsources': true})
    .success(function (response) {
      $scope.datasets = response;
    });

    $scope.deleteSource = function(datasetname, sourcename){
      //delete is a reserved word
      var req = {
       method: 'DELETE',
       url: '/api/3/datasets/' + datasetname + '/sources/' + sourcename
      };

      $http(req)
      .then(function(res){
        if (res.data){
          $scope.datasets = res.data;
        }
        //remove it from the set or rerun dataListCrl
      });

    };

    $scope.newDatasource = function(){
      $location.path("dataform");
    };

}]);

openspending.config( function myAppConfig ( $stateProvider, $urlRouterProvider ) {
  $urlRouterProvider.otherwise( '/datasetlist' );
});

openspending.config(function OSStateProvider( $stateProvider ) {
  $stateProvider.state('datasetlist', {
    url: '/datasetlist',
    views: {
      "main": {
        controller: 'datasetListCrl',
        templateUrl: 'templates/dataset-list.tpl.html'
      }
    }
  })
  //create a new dataset
  .state('dataform', {
    url: '/dataform',
    views: {
      "main": {
        //controller: 'CubeOptionsCtrl',
        templateUrl: 'templates/data_form.tpl.html'
      }
    }
  })
  //manage an existing dataset
  .state('dataform_edit', {
    url: '/:datasetname/manage',
    views: {
      "main": {
        //controller: 'DatamanagerCrl',
        templateUrl: 'templates/data_form.tpl.html'
      }
    }
  });

});

<commit_msg>remove fields for flag for source<commit_after>
var openspending = angular.module('openspending', ['templates-app','templates-common', 'ngCookies', 'ui.router', 'ui.bootstrap', 'localytics.directives', 'openspending.modeler']);

openspending.controller('AppCtrl', ['$scope', '$location', '$http', '$cookies', '$window', '$sce', 'flash',
  function($scope, $location, $http, $cookies, $window, $sce, flash) {

  $scope.flash = flash;

  // EU cookie warning
  $scope.showCookieWarning = !$cookies.neelieCookie;

  $scope.hideCookieWarning = function() {
    $cookies.neelieCookie = true;
    $scope.showCookieWarning = !$cookies.neelieCookie;
  };

  // Language selector
  $scope.setLocale = function(locale) {
    $http.post('/set-locale', {'locale': locale}).then(function(res) {
      $window.location.reload();
    });
    return false;
  };

  // Allow SCE escaping in the app
  $scope.trustAsHtml = function(text) {
    return $sce.trustAsHtml('' + text);
  };

}]);

openspending.factory('flash', ['$rootScope', function($rootScope) {
  // Message flashing.
  var currentMessage = null;

  $rootScope.$on("$routeChangeSuccess", function() {
    currentMessage = null;
  });

  return {
    setMessage: function(message, type) {
      currentMessage = [message, type];
    },
    getMessage: function() {
      return currentMessage;
    }
  };
}]);

openspending.factory('OSAPIservice', function($http) {

    var OSAPI = {};

    OSAPI.getDatasets = function(dataset_params) {
      //options include
      //fields=field1,feidl2, and getsources=true
      return $http({
        url: '/api/3/datasets',
        params: dataset_params
      });
    };
    return OSAPI;
  });

openspending.factory('validation', ['flash', function(flash) {
  // handle server-side form validation errors.
  return {
    handle: handle = function(form) {
      return function(res) {
        if (res.status == 400 || !form) {
            var errors = [];
            console.log(res.data.errors);
            for (var field in res.data.errors) {
                form[field].$setValidity('value', false);
                form[field].$message = res.data.errors[field];
                errors.push(field);
            }
            if (angular.isDefined(form._errors)) {
                angular.forEach(form._errors, function(field) {
                    if (errors.indexOf(field) == -1) {
                        form[field].$setValidity('value', true);
                    }
                });
            }
            form._errors = errors;
        } else {
          console.log(res);
          flash.setMessage(res.data.message || res.data.title || 'Server error', 'danger');
        }
      };
    }
  };
}]);

openspending.factory('referenceData', ['$http', function($http) {
  /* This is used to cache reference data once it has been retrieved from the
  server. Reference data includes the canonical lists of country names,
  currencies, etc. */
  var referenceData = $http.get('/api/3/reference');

  var getData = function(cb) {
    referenceData.then(function(res) {
      cb(res.data);
    });
  };

  return {'get': getData};
}]);

openspending.controller('DatasetNewCtrl', ['$scope', '$http', '$window', '$location', '$stateParams', 'referenceData', 'validation',
  function($scope, $http, $window, $location, $stateParams, referenceData, validation) {
  /* This controller is not activated via routing, but explicitly through the
  dataset.new flask route. */

  $scope.reference = {};
  $scope.permissions = {"create":false};
  $scope.dataset = {'category': 'budget', 'territories': []};

  referenceData.get(function(reference) {
    $scope.reference = reference;
  });

  if ($stateParams.datasetname){
    //get dataset info and update the scope
    //checks permission as well
    $http.get('/api/3/datasets/' + $stateParams.datasetname)
      .then(function(res){

        $scope.dataset = res.data;
        //need to add in error catch here
        $scope.canCreate = true;
        $scope.save = function(form) {
          var dfd = $http.post('/api/3/datasets/' + $stateParams.datasetname, $scope.dataset);
          dfd.then(function(res) {
            //$location.path('/' + res.data.name + '/manage/meta');
            if (res.data.Success === true){
              //flash message
              console.log("saved");
              $location.path('/datasetlist');
            }
            else{
              //error message
            }
          }, validation.handle(form));
        };
      });

  }
  else{
    $http.get('/api/2/permissions?dataset=new').then(function(res) {
      $scope.permissions = res.data;
    });
    $scope.save = function(form) {
      var dfd = $http.post('/api/3/datasets', $scope.dataset);
      dfd.then(function(res) {
        $location.path('/' + res.data.name + '/manage/meta');
      }, validation.handle(form));
    };
  }

}]);

openspending.controller('SourceFormCtrl', ['$scope', '$http', '$window', '$location', '$stateParams', 'referenceData', 'validation',
  function($scope, $http, $window, $location, $stateParams, referenceData, validation) {
    // if $stateProvider.sourcename then populate with data
    // muse have $stateProvider.dataset as dataset name

    $scope.permissions = {"create" : false};
    $scope.reference = {'frequpdate' : [
        {'code': 'never', 'label': 'Never'},
        {'code': 'daily', 'label': 'Daily'},
        {'code': 'weekly', 'label': 'Weekly'},
        {'code': 'monthly', 'label': 'Monthly'}
        ]
      };

    $scope.source = {"label":null, "url": null, "frequpdate":null};

    if (! $stateParams.sourcename){
      //check that user has permission
      $http.get('/api/3/permissions?dataset=new').then(function(res) {
        $scope.permissions = res.data;
      });
    }
    else{
      //populate the form with a call
    }

  $scope.save = function(form) {
    var dfd = $http.post('/api/3/datasets', $scope.dataset);
    dfd.then(function(res) {
      $location.path('/' + res.data.name + '/manage/meta');
    }, validation.handle(form));
  };

// can check this as we

}]);

openspending.controller('datasetListCrl', ['$scope', '$http', 'OSAPIservice', '$location',
  function($scope, $http, OSAPIservice, $location) {

    $scope.datasets = [];
    OSAPIservice.getDatasets({'fields':"name,label"})
    .success(function (response) {
      $scope.datasets = response;
    });

    $scope.deleteSource = function(datasetname, sourcename){
      //delete is a reserved word
      var req = {
       method: 'DELETE',
       url: '/api/3/datasets/' + datasetname + '/sources/' + sourcename
      };

      $http(req)
      .then(function(res){
        if (res.data){
          $scope.datasets = res.data;
        }
        //remove it from the set or rerun dataListCrl
      });

    };

    $scope.newDatasource = function(){
      $location.path("dataform");
    };

}]);

openspending.config( function myAppConfig ( $stateProvider, $urlRouterProvider ) {
  $urlRouterProvider.otherwise( '/datasetlist' );
});

openspending.config(function OSStateProvider( $stateProvider ) {
  $stateProvider.state('datasetlist', {
    url: '/datasetlist',
    views: {
      "main": {
        controller: 'datasetListCrl',
        templateUrl: 'templates/dataset-list.tpl.html'
      }
    }
  })
  //create a new dataset
  .state('dataform', {
    url: '/dataform',
    views: {
      "main": {
        //controller: 'CubeOptionsCtrl',
        templateUrl: 'templates/data_form.tpl.html'
      }
    }
  })
  //manage an existing dataset
  .state('dataform_edit', {
    url: '/:datasetname/manage',
    views: {
      "main": {
        //controller: 'DatamanagerCrl',
        templateUrl: 'templates/data_form.tpl.html'
      }
    }
  });

});

<|endoftext|>


<commit_before>import { METADATA_REQUEST, METADATA_SUCCESS, SELECT_COLUMN, SORT_COLUMN, COUNT_SUCCESS, UPDATE_PAGE, LOAD_TABLE, MIGRATION_SUCCESS, COLPROPS_SUCCESS, DATA_SUCCESS, GROUP_BY, UPDATE_FILTER, ADD_FILTER, REMOVE_FILTER, APPLY_FILTER, CHANGE_DATEBY, SUM_BY } from '../actions'
import { routerReducer as routing } from 'react-router-redux'
import { combineReducers } from 'redux'
import merge from 'lodash/merge'
import union from 'lodash/union'
import uniq from 'lodash/uniq'

function dataset (state = { columns: {}, query: {}, table: { tablePage: 0 } }, action) {
  let copyState

  if (action.response) {
    switch (action.type) {
      case COUNT_SUCCESS:
      case METADATA_SUCCESS:
      case MIGRATION_SUCCESS:
      case COLPROPS_SUCCESS:
        if (COLPROPS_SUCCESS) {
          action.response.categoryColumns = union(state.categoryColumns, action.response.categoryColumns)
        }
        return merge({}, state, action.response)
      case DATA_SUCCESS:
        let merged = merge({}, state, action.response)
        if (action.response.query) {
          merged.query.data = action.response.query.data
        } else {
          merged.table.data = action.response.table.data
        }
        return Object.assign({}, state, merged)
      default:
        return state
    }
  }

  switch (action.type) {
    case LOAD_TABLE:
      return merge({}, state, {
        table: {
          tablePage: 0,
          isFetching: true
        }
      })
    case UPDATE_PAGE:
      return merge({}, state, {
        table: {
          tablePage: action.page
        }
      })
    case METADATA_REQUEST:
      let freshState = {
        query: {
          isFetching: false,
          dateBy: 'year'
        },
        columns: {}
      }
      return merge({}, freshState)
    case SORT_COLUMN:
      let updatedState = {
        table: {
          sorted: state.table.sorted ? uniq([action.key].concat(state.table.sorted)) : [action.key]
        },
        columns: {
          [action.key]: {
            sortDir: action.dir
          }
        }
      }
      return merge({}, state, updatedState)
    case SELECT_COLUMN:
      let updatedQuery = {
        query: {
          isFetching: true,
          selectedColumn: action.column
        }
      }
      if (state.query.groupBy === action.column) {
        updatedQuery.query.groupBy = null
      }
      return merge({}, state, updatedQuery)
    case GROUP_BY:
      let groupKey = action.key ? action.key.value : null
      return merge({}, state, {
        query: {
          groupBy: groupKey
        }
      })
    case SUM_BY:
      let sumKey = action.key ? action.key.value : null
      return merge({}, state, {
        query: {
          sumBy: sumKey
        }
      })
    case CHANGE_DATEBY:
      return merge({}, state, {
        query: {
          dateBy: action.dateBy
        }
      })
    case ADD_FILTER:
      return merge({}, state, {
        query: {
          filters: {
            [action.key.value]: {}
          }
        }
      })
    case REMOVE_FILTER:
      copyState = {...state}
      delete copyState.query.filters[action.key]
      return merge({}, state, copyState)
    case UPDATE_FILTER:
      let newOptions = action.options
      copyState = Object.assign({}, state)
      let existingOptions = copyState.query.filters[action.key].options || ''
      let isSelected = (newOptions.selected)
      let newState

      if (isSelected && Array.isArray(existingOptions.selected) &&
        (existingOptions.selected.length !== newOptions.selected.length || typeof newOptions.selected === 'string')) {
        copyState.query.filters[action.key].options.selected = action.options.selected
        newState = merge({}, copyState)
        console.log(copyState)
      } else {
        let updatedOptions = {
          query: {
            filters: {
              [action.key]: {
                options: action.options
              }
            }
          }
        }
        newState = merge({}, state, updatedOptions)
      }
      console.log(newState)
      return newState
    default:
      return state

  }
}

function messages (state = null, action) {
  return state
}

const rootReducer = combineReducers({
  dataset,
  messages,
  routing
})

export default rootReducer
<commit_msg>set isfetching to true during request<commit_after>import { METADATA_REQUEST, METADATA_SUCCESS, SELECT_COLUMN, SORT_COLUMN, COUNT_SUCCESS, UPDATE_PAGE, LOAD_TABLE, MIGRATION_SUCCESS, COLPROPS_SUCCESS, DATA_SUCCESS, GROUP_BY, UPDATE_FILTER, ADD_FILTER, REMOVE_FILTER, APPLY_FILTER, CHANGE_DATEBY, SUM_BY } from '../actions'
import { routerReducer as routing } from 'react-router-redux'
import { combineReducers } from 'redux'
import merge from 'lodash/merge'
import union from 'lodash/union'
import uniq from 'lodash/uniq'

function dataset (state = { columns: {}, query: {}, table: { tablePage: 0 } }, action) {
  let copyState

  if (action.response) {
    switch (action.type) {
      case COUNT_SUCCESS:
      case METADATA_SUCCESS:
      case MIGRATION_SUCCESS:
      case COLPROPS_SUCCESS:
        if (COLPROPS_SUCCESS) {
          action.response.categoryColumns = union(state.categoryColumns, action.response.categoryColumns)
        }
        return merge({}, state, action.response)
      case DATA_SUCCESS:
        let merged = merge({}, state, action.response)
        if (action.response.query) {
          merged.query.data = action.response.query.data
        } else {
          merged.table.data = action.response.table.data
        }
        return Object.assign({}, state, merged)
      default:
        return state
    }
  }

  switch (action.type) {
    case LOAD_TABLE:
      return merge({}, state, {
        table: {
          tablePage: 0,
          isFetching: true
        }
      })
    case UPDATE_PAGE:
      return merge({}, state, {
        table: {
          tablePage: action.page
        }
      })
    case METADATA_REQUEST:
      let freshState = {
        query: {
          isFetching: true,
          dateBy: 'year'
        },
        columns: {}
      }
      return merge({}, freshState)
    case SORT_COLUMN:
      let updatedState = {
        table: {
          sorted: state.table.sorted ? uniq([action.key].concat(state.table.sorted)) : [action.key]
        },
        columns: {
          [action.key]: {
            sortDir: action.dir
          }
        }
      }
      return merge({}, state, updatedState)
    case SELECT_COLUMN:
      let updatedQuery = {
        query: {
          isFetching: true,
          selectedColumn: action.column
        }
      }
      if (state.query.groupBy === action.column) {
        updatedQuery.query.groupBy = null
      }
      return merge({}, state, updatedQuery)
    case GROUP_BY:
      let groupKey = action.key ? action.key.value : null
      return merge({}, state, {
        query: {
          groupBy: groupKey
        }
      })
    case SUM_BY:
      let sumKey = action.key ? action.key.value : null
      return merge({}, state, {
        query: {
          sumBy: sumKey
        }
      })
    case CHANGE_DATEBY:
      return merge({}, state, {
        query: {
          dateBy: action.dateBy
        }
      })
    case ADD_FILTER:
      return merge({}, state, {
        query: {
          filters: {
            [action.key.value]: {}
          }
        }
      })
    case REMOVE_FILTER:
      copyState = {...state}
      delete copyState.query.filters[action.key]
      return merge({}, state, copyState)
    case UPDATE_FILTER:
      let newOptions = action.options
      copyState = Object.assign({}, state)
      let existingOptions = copyState.query.filters[action.key].options || ''
      let isSelected = (newOptions.selected)
      let newState

      if (isSelected && Array.isArray(existingOptions.selected) &&
        (existingOptions.selected.length !== newOptions.selected.length || typeof newOptions.selected === 'string')) {
        copyState.query.filters[action.key].options.selected = action.options.selected
        newState = merge({}, copyState)
        console.log(copyState)
      } else {
        let updatedOptions = {
          query: {
            filters: {
              [action.key]: {
                options: action.options
              }
            }
          }
        }
        newState = merge({}, state, updatedOptions)
      }
      console.log(newState)
      return newState
    default:
      return state

  }
}

function messages (state = null, action) {
  return state
}

const rootReducer = combineReducers({
  dataset,
  messages,
  routing
})

export default rootReducer
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import { shape, bool, string, object } from 'prop-types'

export const defaultConfig = {
  showSetup: false,
  color: 'byRole',
  characterName: 'YOU',
  showDuration: true,
  showTotalDps: true,
  showHps: true,
  showJobIcon: true,
  showRank: true,
  showDamagePercent: true,
  zoom: '1',
  configWindow: {
    width: 1300,
    height: 206
  },
  colorHealer: 'rgba(139, 195, 74, 0.3)',
  colorTank: 'rgba(33, 150, 243, 0.3)',
  colorDps: 'rgba(244, 67, 54, 0.3)'
}

export const withHelper = ({
  WrappedComponent,
  willMock = false,
  isConfig = false
}) => {
  return class withConfig extends Component {
    static defaultProps = {
      mockData: willMock ? mockData : null,
      config: defaultConfig
    }
    static propTypes = {
      config: shape({
        showSetup: bool.isRequired,
        color: string.isRequired,
        characterName: string.isRequired,
        showDuration: bool.isRequired,
        showTotalDps: bool.isRequired,
        showHps: bool.isRequired,
        showJobIcon: bool.isRequired,
        showRank: bool.isRequired,
        showDamagePercent: bool.isRequired,
        zoom: string.isRequired,
        configWindow: object.isRequired
      })
    }
    state = { ...this.props }
    resizeTimeout = undefined
    componentWillMount() {
      window.addEventListener('storage', this.updateState, false)
      // Check this before implementing
      // https://lodash.com/docs/4.17.4#throttle
      // if (isConfig)
      //   window.addEventListener('resize', this.handleResizeThrottler, false)
      this.updateState()
    }
    componentWillReceiveProps(nextProps) {
      this.updateState()
    }
    componentWillUnmount() {
      window.removeEventListener('storage', this.updateState)
      // if (isConfig)
      //   window.removeEventListener('resize', this.handleResizeThrottler)
    }
    updateState = () => {
      const configStore = localStorage.getItem('horizoverlay')
      if (!configStore) {
        const config = this.props.config
        localStorage.setItem('horizoverlay', JSON.stringify(config))
        this.setState({ config })
      } else {
        const config = JSON.parse(configStore)
        this.setState({ config })
      }
    }
    handleResize = () => {
      const config = { ...this.state.config }
      let width = window.innerWidth,
        height = window.innerHeight

      // update the value in our copied state...
      config.configWindow = { width, height }
      // ...and set it to component' state
      this.setState({ config })

      // And then save it to localStorage!
      localStorage.setItem('horizoverlay', JSON.stringify(config))
    }
    handleResizeThrottler = () => {
      if (!this.resizeTimeout) {
        this.resizeTimeout = setTimeout(() => {
          this.resizeTimeout = null
          this.handleResize()
        }, 66)
      }
    }
    openConfig = () => {
      this.setState({ isConfigOpen: true })
      const windowFeatures = `menubar=no,location=no,resizable=no,scrollbars=yes,status=no,width=${this
        .props.config.configWindow.width},height=${this.props.config
        .configWindow.height}`
      this.configWindow = window.open(
        '/#/config',
        'Horizoverlay Config',
        windowFeatures
      )
      this.configWindow.focus()
      this.configWindow.onbeforeunload = () => {
        this.setState({ isConfigOpen: false })
        this.configWindow = null
      }
    }
    render = () => {
      const { Combatant, Encounter, isActive } = this.props
      return (
        <WrappedComponent
          {...this.state}
          Combatant={Combatant}
          Encounter={Encounter}
          isActive={isActive}
          openConfig={this.openConfig}
          handleReset={this.updateState}
        />
      )
    }
  }
}

export function getRandom(min, max) {
  min = Math.ceil(min)
  max = Math.floor(max)
  return Math.floor(Math.random() * (max - min + 1)) + min
}

export const jobsTank = ['drk', 'gla', 'mrd', 'pld', 'war']
export const jobsHealer = ['ast', 'cnj', 'sch', 'whm']
export const jobsDps = [
  'acn',
  'arc',
  'blm',
  'brd',
  'drg',
  'lnc',
  'mch',
  'mnk',
  'nin',
  'pgl',
  'pug',
  'rdm',
  'rog',
  'sam',
  'smn',
  'thm'
]

export const mockData = [
  {
    isSelf: true,
    name: 'YOU',
    jobClass: 'Nin',
    jobFull: 'Ninja',
    job: 'nin',
    jobRole: 'job-dps',
    rank: 1,
    dps: '5450.30',
    hps: '0.0',
    isHealing: false,
    damagePct: '36'
  },
  {
    isSelf: false,
    name: 'Vivi Ornitier',
    jobClass: 'Blm',
    jobFull: 'Black Mage',
    job: 'blm',
    jobRole: 'job-dps',
    rank: 2,
    dps: '5283.29',
    hps: '0.0',
    isHealing: false,
    damagePct: '32'
  },
  {
    isSelf: false,
    name: 'Zidane Tribal',
    jobClass: 'Nin',
    jobFull: 'Ninja',
    job: 'nin',
    jobRole: 'job-dps',
    rank: 3,
    dps: '2648.91',
    hps: '4.12',
    isHealing: false,
    damagePct: '22'
  },
  {
    isSelf: false,
    name: 'Garnet Alexandros',
    jobClass: 'Smn',
    jobFull: 'Summoner',
    job: 'smn',
    jobRole: 'job-dps',
    rank: 4,
    dps: '1654.90',
    hps: '12.10',
    isHealing: false,
    damagePct: '15'
  },
  {
    isSelf: false,
    name: 'Freya Crescent',
    jobClass: 'Drg',
    jobFull: 'Dragoon',
    job: 'drg',
    jobRole: 'job-dps',
    rank: 5,
    dps: '1977.42',
    hps: '3.10',
    isHealing: false,
    damagePct: '16'
  },
  {
    isSelf: false,
    name: 'Adelbert Steiner',
    jobClass: 'Pld',
    jobFull: 'Paladin',
    job: 'pld',
    jobRole: 'job-tank',
    rank: 6,
    dps: '1548.24',
    hps: '588.50',
    isHealing: false,
    damagePct: '9'
  },
  {
    isSelf: false,
    name: 'Quina Quen',
    jobClass: 'War',
    jobFull: 'Warrior',
    job: 'war',
    jobRole: 'job-tank',
    rank: 8,
    dps: '1366.61',
    hps: '112.50',
    isHealing: false,
    damagePct: '6'
  },
  {
    isSelf: false,
    name: 'Eiko Carol',
    jobClass: 'Whm',
    jobFull: 'White Mage',
    job: 'whm',
    jobRole: 'job-healer',
    rank: 7,
    dps: '1461.64',
    hps: '9821.50',
    isHealing: true,
    damagePct: '7'
  },
  {
    isSelf: false,
    name: 'Alphinaud Cheater',
    jobClass: 'Sch',
    jobFull: 'Scholar',
    job: 'sch',
    jobRole: 'job-healer',
    rank: 9,
    dps: '447.18',
    hps: '5661.12',
    isHealing: true,
    damagePct: '2'
  }
]
<commit_msg>Unifying jobs within 1 object<commit_after>import React, { Component } from 'react'
import { shape, bool, string, object } from 'prop-types'

export const defaultConfig = {
  showSetup: false,
  color: 'byRole',
  characterName: 'YOU',
  showDuration: true,
  showTotalDps: true,
  showHps: true,
  showJobIcon: true,
  showRank: true,
  showDamagePercent: true,
  zoom: '1',
  configWindow: {
    width: 1300,
    height: 206
  },
  colorHealer: 'rgba(139, 195, 74, 0.3)',
  colorTank: 'rgba(33, 150, 243, 0.3)',
  colorDps: 'rgba(244, 67, 54, 0.3)'
}

export const withHelper = ({
  WrappedComponent,
  willMock = false,
  isConfig = false
}) => {
  return class withConfig extends Component {
    static defaultProps = {
      mockData: willMock ? mockData : null,
      config: defaultConfig
    }
    static propTypes = {
      config: shape({
        showSetup: bool.isRequired,
        color: string.isRequired,
        characterName: string.isRequired,
        showDuration: bool.isRequired,
        showTotalDps: bool.isRequired,
        showHps: bool.isRequired,
        showJobIcon: bool.isRequired,
        showRank: bool.isRequired,
        showDamagePercent: bool.isRequired,
        zoom: string.isRequired,
        configWindow: object.isRequired
      })
    }
    state = { ...this.props }
    resizeTimeout = undefined
    componentWillMount() {
      window.addEventListener('storage', this.updateState, false)
      // Check this before implementing
      // https://lodash.com/docs/4.17.4#throttle
      // if (isConfig)
      //   window.addEventListener('resize', this.handleResizeThrottler, false)
      this.updateState()
    }
    componentWillReceiveProps(nextProps) {
      this.updateState()
    }
    componentWillUnmount() {
      window.removeEventListener('storage', this.updateState)
      // if (isConfig)
      //   window.removeEventListener('resize', this.handleResizeThrottler)
    }
    updateState = () => {
      const configStore = localStorage.getItem('horizoverlay')
      if (!configStore) {
        const config = this.props.config
        localStorage.setItem('horizoverlay', JSON.stringify(config))
        this.setState({ config })
      } else {
        const config = JSON.parse(configStore)
        this.setState({ config })
      }
    }
    handleResize = () => {
      const config = { ...this.state.config }
      let width = window.innerWidth,
        height = window.innerHeight

      // update the value in our copied state...
      config.configWindow = { width, height }
      // ...and set it to component' state
      this.setState({ config })

      // And then save it to localStorage!
      localStorage.setItem('horizoverlay', JSON.stringify(config))
    }
    handleResizeThrottler = () => {
      if (!this.resizeTimeout) {
        this.resizeTimeout = setTimeout(() => {
          this.resizeTimeout = null
          this.handleResize()
        }, 66)
      }
    }
    openConfig = () => {
      this.setState({ isConfigOpen: true })
      const windowFeatures = `menubar=no,location=no,resizable=no,scrollbars=yes,status=no,width=${this
        .props.config.configWindow.width},height=${this.props.config
        .configWindow.height}`
      this.configWindow = window.open(
        '/#/config',
        'Horizoverlay Config',
        windowFeatures
      )
      this.configWindow.focus()
      this.configWindow.onbeforeunload = () => {
        this.setState({ isConfigOpen: false })
        this.configWindow = null
      }
    }
    render = () => {
      const { Combatant, Encounter, isActive } = this.props
      return (
        <WrappedComponent
          {...this.state}
          Combatant={Combatant}
          Encounter={Encounter}
          isActive={isActive}
          openConfig={this.openConfig}
          handleReset={this.updateState}
        />
      )
    }
  }
}

export function getRandom(min, max) {
  const first = Math.ceil(min)
  const last = Math.floor(max)
  return Math.floor(Math.random() * (last - first + 1)) + first
}

const jobRoles = {
  tank: ['drk', 'gla', 'mrd', 'pld', 'war'],
  healer: ['ast', 'cnj', 'sch', 'whm'],
  dps: [
    'acn',
    'arc',
    'blm',
    'brd',
    'drg',
    'lnc',
    'mch',
    'mnk',
    'nin',
    'pgl',
    'pug',
    'rdm',
    'rog',
    'sam',
    'smn',
    'thm'
  ]
}

export const mockData = [
  {
    isSelf: true,
    name: 'YOU',
    jobClass: 'Nin',
    jobFull: 'Ninja',
    job: 'nin',
    jobRole: 'job-dps',
    rank: 1,
    dps: '5450.30',
    hps: '0.0',
    isHealing: false,
    damagePct: '36'
  },
  {
    isSelf: false,
    name: 'Vivi Ornitier',
    jobClass: 'Blm',
    jobFull: 'Black Mage',
    job: 'blm',
    jobRole: 'job-dps',
    rank: 2,
    dps: '5283.29',
    hps: '0.0',
    isHealing: false,
    damagePct: '32'
  },
  {
    isSelf: false,
    name: 'Zidane Tribal',
    jobClass: 'Nin',
    jobFull: 'Ninja',
    job: 'nin',
    jobRole: 'job-dps',
    rank: 3,
    dps: '2648.91',
    hps: '4.12',
    isHealing: false,
    damagePct: '22'
  },
  {
    isSelf: false,
    name: 'Garnet Alexandros',
    jobClass: 'Smn',
    jobFull: 'Summoner',
    job: 'smn',
    jobRole: 'job-dps',
    rank: 4,
    dps: '1654.90',
    hps: '12.10',
    isHealing: false,
    damagePct: '15'
  },
  {
    isSelf: false,
    name: 'Freya Crescent',
    jobClass: 'Drg',
    jobFull: 'Dragoon',
    job: 'drg',
    jobRole: 'job-dps',
    rank: 5,
    dps: '1977.42',
    hps: '3.10',
    isHealing: false,
    damagePct: '16'
  },
  {
    isSelf: false,
    name: 'Adelbert Steiner',
    jobClass: 'Pld',
    jobFull: 'Paladin',
    job: 'pld',
    jobRole: 'job-tank',
    rank: 6,
    dps: '1548.24',
    hps: '588.50',
    isHealing: false,
    damagePct: '9'
  },
  {
    isSelf: false,
    name: 'Quina Quen',
    jobClass: 'War',
    jobFull: 'Warrior',
    job: 'war',
    jobRole: 'job-tank',
    rank: 8,
    dps: '1366.61',
    hps: '112.50',
    isHealing: false,
    damagePct: '6'
  },
  {
    isSelf: false,
    name: 'Eiko Carol',
    jobClass: 'Whm',
    jobFull: 'White Mage',
    job: 'whm',
    jobRole: 'job-healer',
    rank: 7,
    dps: '1461.64',
    hps: '9821.50',
    isHealing: true,
    damagePct: '7'
  },
  {
    isSelf: false,
    name: 'Alphinaud Cheater',
    jobClass: 'Sch',
    jobFull: 'Scholar',
    job: 'sch',
    jobRole: 'job-healer',
    rank: 9,
    dps: '447.18',
    hps: '5661.12',
    isHealing: true,
    damagePct: '2'
  }
]
<|endoftext|>


<commit_before>var express = require('express');
var router = express.Router();
var db = require('mongous').Mongous;
var yaml = require('js-yaml');
var fs = require('fs');
var async = require('async');

var property = yaml.safeLoad(fs.readFileSync('../config/property.yaml', 'utf-8'));

/* GET home page. */
router.get('/:articleid', function(req, res) {
    db('news.$cmd').auth(property.user, property.passwd, function(r) {
        console.log(r);
        var articleid = parseInt(req.params.articleid);
        db(property.database.article).find({articleid : articleid}, 1, function(reply) {
            var doc = reply.documents[0];
            if (!doc)
                doc = { title: 'oops', content: 'we can not find the article you want', keywords: [] };
            else {
                // find the keywords
                doc.keywords = doc.keywords.map(function(keyword) {
                    return keyword[0];
                });
                // find the articleid of similar articles and find the meta data or these articles
                db(property.database.similar).find({articleid: doc.articleid}, function(reply2) {
                    async.map(reply2.documents[0].similar, function(arti, cb) {
                        db(property.database.article).find({articleid: arti}, 1, function(reply3) {
                            var doc = reply3.documents[0];
                            cb(null, {title: doc.title, link: '/article/' + doc.articleid});
                        });
                    }, function(err, result) {
                        if (err)
                            console.log(err);
                        else {
                            res.render('article', {
                                title: doc.title,
                                content: doc.content,
                                keywords: doc.keywords,
                                recommends: result
                            });
                        }
                    });
                });
            }
        });
    });
});

module.exports = router;
<commit_msg>bug-fix: no keywords<commit_after>var express = require('express');
var router = express.Router();
var db = require('mongous').Mongous;
var yaml = require('js-yaml');
var fs = require('fs');
var async = require('async');

var property = yaml.safeLoad(fs.readFileSync('../config/property.yaml', 'utf-8'));

/* GET home page. */
router.get('/:articleid', function(req, res) {
    db('news.$cmd').auth(property.user, property.passwd, function(r) {
        console.log(r);
        var articleid = parseInt(req.params.articleid);
        db(property.database.article).find({articleid : articleid}, 1, function(reply) {
            var doc = reply.documents[0];
            if (!doc)
                doc = { title: 'oops', content: 'we can not find the article you want', keywords: [] };
            else {
                // find the keywords
                if (doc.keywords)
                    doc.keywords = doc.keywords.map(function(keyword) {
                        return keyword[0];
                    });
                else
                    doc.keywords = [];
                // find the articleid of similar articles and find the meta data or these articles
                db(property.database.similar).find({articleid: doc.articleid}, function(reply2) {
                    async.map(reply2.documents[0].similar, function(arti, cb) {
                        db(property.database.article).find({articleid: arti}, 1, function(reply3) {
                            var doc = reply3.documents[0];
                            cb(null, {title: doc.title, link: '/article/' + doc.articleid});
                        });
                    }, function(err, result) {
                        if (err)
                            console.log(err);
                        else {
                            res.render('article', {
                                title: doc.title,
                                content: doc.content,
                                keywords: doc.keywords,
                                recommends: result
                            });
                        }
                    });
                });
            }
        });
    });
});

module.exports = router;
<|endoftext|>


<commit_before>const globalObj = typeof window === 'undefined' ? global : window
// Constant node.nodeType for text nodes, see:
// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType#Node_type_constants
const TEXT_NODE = 3

// Currently this fn only supports jest timers, but it could support other test runners in the future.
function runWithRealTimers(callback) {
  // istanbul ignore else
  if (typeof jest !== 'undefined') {
    return runWithJestRealTimers(callback).callbackReturnValue
  }

  // istanbul ignore next
  return callback()
}

function runWithJestRealTimers(callback) {
  const timerAPI = {
    clearInterval,
    clearTimeout,
    setInterval,
    setTimeout,
  }

  // For more on why we have the check here,
  // checkout https://github.com/testing-library/dom-testing-library/issues/914
  if (typeof setImmediate === 'function') {
    timerAPI.setImmediate = setImmediate
  }
  if (typeof clearImmediate === 'function') {
    timerAPI.clearImmediate = clearImmediate
  }

  jest.useRealTimers()

  const callbackReturnValue = callback()

  const usedFakeTimers = Object.entries(timerAPI).some(
    ([name, func]) => func !== globalObj[name],
  )

  if (usedFakeTimers) {
    jest.useFakeTimers(timerAPI.setTimeout?.clock ? 'modern' : 'legacy')
  }

  return {
    callbackReturnValue,
    usedFakeTimers,
  }
}

function jestFakeTimersAreEnabled() {
  // istanbul ignore else
  if (typeof jest !== 'undefined') {
    return runWithJestRealTimers(() => {}).usedFakeTimers
  }

  // istanbul ignore next
  return false
}

// we only run our tests in node, and setImmediate is supported in node.
// istanbul ignore next
function setImmediatePolyfill(fn) {
  return globalObj.setTimeout(fn, 0)
}

function getTimeFunctions() {
  // istanbul ignore next
  return {
    clearTimeoutFn: globalObj.clearTimeout,
    setImmediateFn: globalObj.setImmediate || setImmediatePolyfill,
    setTimeoutFn: globalObj.setTimeout,
  }
}

const {clearTimeoutFn, setImmediateFn, setTimeoutFn} = runWithRealTimers(
  getTimeFunctions,
)

function getDocument() {
  /* istanbul ignore if */
  if (typeof window === 'undefined') {
    throw new Error('Could not find default container')
  }
  return window.document
}
function getWindowFromNode(node) {
  if (node.defaultView) {
    // node is document
    return node.defaultView
  } else if (node.ownerDocument && node.ownerDocument.defaultView) {
    // node is a DOM node
    return node.ownerDocument.defaultView
  } else if (node.window) {
    // node is window
    return node.window
  } else if (node.then instanceof Function) {
    throw new Error(
      `It looks like you passed a Promise object instead of a DOM node. Did you do something like \`fireEvent.click(screen.findBy...\` when you meant to use a \`getBy\` query \`fireEvent.click(screen.getBy...\`, or await the findBy query \`fireEvent.click(await screen.findBy...\`?`,
    )
  } else if (Array.isArray(node)) {
    throw new Error(
      `It looks like you passed an Array instead of a DOM node. Did you do something like \`fireEvent.click(screen.getAllBy...\` when you meant to use a \`getBy\` query \`fireEvent.click(screen.getBy...\`?`,
    )
  } else {
    // The user passed something unusual to a calling function
    throw new Error(
      `Unable to find the "window" object for the given node. Please file an issue with the code that's causing you to see this error: https://github.com/testing-library/dom-testing-library/issues/new`,
    )
  }
}

function checkContainerType(container) {
  if (
    !container ||
    !(typeof container.querySelector === 'function') ||
    !(typeof container.querySelectorAll === 'function')
  ) {
    throw new TypeError(
      `Expected container to be an Element, a Document or a DocumentFragment but got ${getTypeName(
        container,
      )}.`,
    )
  }

  function getTypeName(object) {
    if (typeof object === 'object') {
      return object === null ? 'null' : object.constructor.name
    }
    return typeof object
  }
}

export {
  getWindowFromNode,
  getDocument,
  clearTimeoutFn as clearTimeout,
  setImmediateFn as setImmediate,
  setTimeoutFn as setTimeout,
  runWithRealTimers,
  checkContainerType,
  jestFakeTimersAreEnabled,
  TEXT_NODE,
}
<commit_msg>fix: Guard against `jest.useRealTimers` not existing (#934)<commit_after>const globalObj = typeof window === 'undefined' ? global : window
// Constant node.nodeType for text nodes, see:
// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType#Node_type_constants
const TEXT_NODE = 3

// Currently this fn only supports jest timers, but it could support other test runners in the future.
function runWithRealTimers(callback) {
  return hasJestTimers()
    ? runWithJestRealTimers(callback).callbackReturnValue
    : // istanbul ignore next
      callback()
}

function hasJestTimers() {
  return (
    typeof jest !== 'undefined' &&
    jest !== null &&
    typeof jest.useRealTimers === 'function'
  )
}

function runWithJestRealTimers(callback) {
  const timerAPI = {
    clearInterval,
    clearTimeout,
    setInterval,
    setTimeout,
  }

  // For more on why we have the check here,
  // checkout https://github.com/testing-library/dom-testing-library/issues/914
  if (typeof setImmediate === 'function') {
    timerAPI.setImmediate = setImmediate
  }
  if (typeof clearImmediate === 'function') {
    timerAPI.clearImmediate = clearImmediate
  }

  jest.useRealTimers()

  const callbackReturnValue = callback()

  const usedFakeTimers = Object.entries(timerAPI).some(
    ([name, func]) => func !== globalObj[name],
  )

  if (usedFakeTimers) {
    jest.useFakeTimers(timerAPI.setTimeout?.clock ? 'modern' : 'legacy')
  }

  return {
    callbackReturnValue,
    usedFakeTimers,
  }
}

function jestFakeTimersAreEnabled() {
  return hasJestTimers()
    ? runWithJestRealTimers(() => {}).usedFakeTimers
    : // istanbul ignore next
      false
}

// we only run our tests in node, and setImmediate is supported in node.
// istanbul ignore next
function setImmediatePolyfill(fn) {
  return globalObj.setTimeout(fn, 0)
}

function getTimeFunctions() {
  // istanbul ignore next
  return {
    clearTimeoutFn: globalObj.clearTimeout,
    setImmediateFn: globalObj.setImmediate || setImmediatePolyfill,
    setTimeoutFn: globalObj.setTimeout,
  }
}

const {clearTimeoutFn, setImmediateFn, setTimeoutFn} = runWithRealTimers(
  getTimeFunctions,
)

function getDocument() {
  /* istanbul ignore if */
  if (typeof window === 'undefined') {
    throw new Error('Could not find default container')
  }
  return window.document
}
function getWindowFromNode(node) {
  if (node.defaultView) {
    // node is document
    return node.defaultView
  } else if (node.ownerDocument && node.ownerDocument.defaultView) {
    // node is a DOM node
    return node.ownerDocument.defaultView
  } else if (node.window) {
    // node is window
    return node.window
  } else if (node.then instanceof Function) {
    throw new Error(
      `It looks like you passed a Promise object instead of a DOM node. Did you do something like \`fireEvent.click(screen.findBy...\` when you meant to use a \`getBy\` query \`fireEvent.click(screen.getBy...\`, or await the findBy query \`fireEvent.click(await screen.findBy...\`?`,
    )
  } else if (Array.isArray(node)) {
    throw new Error(
      `It looks like you passed an Array instead of a DOM node. Did you do something like \`fireEvent.click(screen.getAllBy...\` when you meant to use a \`getBy\` query \`fireEvent.click(screen.getBy...\`?`,
    )
  } else {
    // The user passed something unusual to a calling function
    throw new Error(
      `Unable to find the "window" object for the given node. Please file an issue with the code that's causing you to see this error: https://github.com/testing-library/dom-testing-library/issues/new`,
    )
  }
}

function checkContainerType(container) {
  if (
    !container ||
    !(typeof container.querySelector === 'function') ||
    !(typeof container.querySelectorAll === 'function')
  ) {
    throw new TypeError(
      `Expected container to be an Element, a Document or a DocumentFragment but got ${getTypeName(
        container,
      )}.`,
    )
  }

  function getTypeName(object) {
    if (typeof object === 'object') {
      return object === null ? 'null' : object.constructor.name
    }
    return typeof object
  }
}

export {
  getWindowFromNode,
  getDocument,
  clearTimeoutFn as clearTimeout,
  setImmediateFn as setImmediate,
  setTimeoutFn as setTimeout,
  runWithRealTimers,
  checkContainerType,
  jestFakeTimersAreEnabled,
  TEXT_NODE,
}
<|endoftext|>


<commit_before>import { isArray } from '@ember/array';
import Route from '@ember/routing/route';
import DS from 'ember-data';

// Error handling for API
const handlers = new Map([
    // format: ['Message detail', 'page']
    ['Authentication credentials were not provided.', 'page-not-found'], // 401
    ['You do not have permission to perform this action.', 'page-not-found'], // 403
    ['Not found.', 'page-not-found'], // 404
    ['The requested node is no longer available.', 'resource-deleted'], // 410
]);

/**
 * @module ember-preprints
 * @submodule routes
 */

/**
 * @class Content Route Handler
 */
export default Route.extend({
    model(params) {
        return this
            .store
            .findRecord('preprint', params.preprint_id);
    },
    actions: {
        error(error) {
            // Handle API Errors
            if (error && !(error instanceof DS.AbortError)
                && error.errors && isArray(error.errors)) {
                // If  the error is not a AbortError (no connection), we handle it here.
                const { detail } = error.errors[0];
                const page = handlers.get(detail) || 'page-not-found';
                return this.intermediateTransitionTo(page);
            } else {
                // Otherwise, we bubble it to the error handler in our parent route.
                return true;
            }
        },
    },
});
<commit_msg>make another v2 request on content route<commit_after>import { isArray } from '@ember/array';
import Route from '@ember/routing/route';
import DS from 'ember-data';
import { inject as service } from '@ember/service';
import config from 'ember-get-config';

// Error handling for API
const handlers = new Map([
    // format: ['Message detail', 'page']
    ['Authentication credentials were not provided.', 'page-not-found'], // 401
    ['You do not have permission to perform this action.', 'page-not-found'], // 403
    ['Not found.', 'page-not-found'], // 404
    ['The requested node is no longer available.', 'resource-deleted'], // 410
]);

/**
 * @module ember-preprints
 * @submodule routes
 */

/**
 * @class Content Route Handler
 */
export default Route.extend({
    currentUser: service(),
    features: service(),
    model(params) {
        const opts = {
            method: 'GET',
            url: `${config.OSF.apiUrl}/${config.OSF.apiNamespace}/`,
            dataType: 'json',
            contentType: 'application/json',
            xhrFields: {
                withCredentials: true
            }
        }

        this.get('currentUser').authenticatedAJAX(opts).then(res => {
            if (Array.isArray(res.meta.active_flags)) {
                this.get('features').setup(
                    res.meta.active_flags.reduce(function(acc, flag) {
                        acc[flag] = true;
                        return acc;
                    }, {})
                )
            }
            // Push the result into the store for later use by the current-user service
            // Note: we have to deepcopy res because pushPayload mutates our data
            // and causes an infinite loop because reasons
            if (res['meta']['current_user'] !== null ){
                this.get('store').pushPayload(Ember.copy(res['meta']['current_user'], true));
            } else {
                return Ember.RSVP.reject();
            }
            return res['meta']['current_user']['data'];
        });

        return this
            .store
            .findRecord('preprint', params.preprint_id);
    },
    actions: {
        error(error) {
            // Handle API Errors
            if (error && !(error instanceof DS.AbortError)
                && error.errors && isArray(error.errors)) {
                // If  the error is not a AbortError (no connection), we handle it here.
                const { detail } = error.errors[0];
                const page = handlers.get(detail) || 'page-not-found';
                return this.intermediateTransitionTo(page);
            } else {
                // Otherwise, we bubble it to the error handler in our parent route.
                return true;
            }
        },
    },
});
<|endoftext|>


<commit_before>// Returns the version of Internet Explorer or -1
// (indicating the use of another browser).
// From: http://msdn.microsoft.com/en-us/library/ms537509(v=vs.85).aspx#ParsingUA
var ieVersion = (function () {
  var v = -1;
  if (navigator.appName === 'Microsoft Internet Explorer') {
    var ua = navigator.userAgent;
    var re = new RegExp('MSIE ([0-9]{1,}[\\.0-9]{0,})');
    if (re.exec(ua) !== null) v = parseFloat(RegExp.$1);
  }
  return v;
})();

// Check for oninput support
// IE9 supports oninput, but not when deleting text, so keyup is used.
// onpropertychange _is_ supported by IE8/9, but may not be fired unless
// attached with `attachEvent`
// (see: http://stackoverflow.com/questions/18436424/ie-onpropertychange-event-doesnt-fire),
// and so is avoided altogether.
var inputSupported = (
  'oninput' in document.createElement('input') && ieVersion !== 9
);

export var inputEvent = inputSupported ? 'input' : 'keyup';

export function style (element, styles) {
  for (var property in styles) element.style[property] = styles[property];
}

export function dispatch (eventName, options) {
  options = options || {};
  var event = document.createEvent('Event');
  event.initEvent(eventName, true, options.cancelable === true);
  event.data = options.data != null ? options.data : {};
  var target = options.target != null ? options.target : document;
  target.dispatchEvent(event);
}

export function warn(text) {
  if (window.console && console.warn) console.warn(text);
}
<commit_msg>Add iOS device detection to account for additional padding<commit_after>var userAgent = window.navigator.userAgent

// Returns the version of Internet Explorer or -1
// (indicating the use of another browser).
// From: http://msdn.microsoft.com/en-us/library/ms537509(v=vs.85).aspx#ParsingUA
var ieVersion = (function () {
  var version = -1
  if (window.navigator.appName === 'Microsoft Internet Explorer') {
    var regExp = new RegExp('MSIE ([0-9]{1,}[\\.0-9]{0,})')
    if (regExp.exec(userAgent) !== null) version = parseFloat(RegExp.$1)
  }
  return version
})()

// Check for oninput support
// IE9 supports oninput, but not when deleting text, so keyup is used.
// onpropertychange _is_ supported by IE8/9, but may not be fired unless
// attached with `attachEvent`
// (see: http://stackoverflow.com/questions/18436424/ie-onpropertychange-event-doesnt-fire),
// and so is avoided altogether.
var inputEventSupported = (
  'oninput' in document.createElement('input') && ieVersion !== 9
)

export var inputEvent = inputEventSupported ? 'input' : 'keyup'

export var isIosDevice = /iPad|iPhone|iPod/.test(userAgent) && !window.MSStream

export function style (element, styles) {
  for (var property in styles) element.style[property] = styles[property];
}

export function dispatch (eventName, options) {
  options = options || {};
  var event = document.createEvent('Event');
  event.initEvent(eventName, true, options.cancelable === true);
  event.data = options.data != null ? options.data : {};
  var target = options.target != null ? options.target : document;
  target.dispatchEvent(event);
}

export function warn(text) {
  if (window.console && console.warn) console.warn(text);
}
<|endoftext|>


<commit_before>import Ember from 'ember';
import ResetScrollMixin from '../mixins/reset-scroll';

export default Ember.Route.extend(ResetScrollMixin, {
    model(params) {
        return this.store.findRecord('preprint', params.preprint_id);
    },
    setupController(controller, model) {
        controller.set('activeFile', model.get('primaryFile'));
        return this._super(...arguments);
    },
    actions: {
        error(error, transition) {
            window.history.replaceState( {} , 'preprints', 'preprints/'+ transition.params.content.preprint_id);
            this.intermediateTransitionTo('page-not-found');
        }
    }
});
<commit_msg>Fix style issues<commit_after>import Ember from 'ember';
import ResetScrollMixin from '../mixins/reset-scroll';

export default Ember.Route.extend(ResetScrollMixin, {
    model(params) {
        return this.store.findRecord('preprint', params.preprint_id);
    },
    setupController(controller, model) {
        controller.set('activeFile', model.get('primaryFile'));
        return this._super(...arguments);
    },
    actions: {
        error(error, transition) {
            window.history.replaceState({}, 'preprints', 'preprints/' + transition.params.content.preprint_id);
            this.intermediateTransitionTo('page-not-found');
        }
    }
});
<|endoftext|>


<commit_before>// just so my syntastic complains less
var _ = _ || {};

// TODO get rid of this anchor shit, replace with well-formed tree rendering
function Anchor(id, x, y) {
    this.fixed = true; // tells d3 not to move it
    this.x = x || 0;
    this.y = y || 0;
    this.id = id;
}

Anchor.prototype.name = function() {
    return '';
};

Anchor.prototype.Typ = function() {
    return 'anchor';
};

Anchor.prototype.isVertex = function() {
    return true;
};

Anchor.prototype.prop = function() {
    return;
};

var vertexProto = {
    isVertex: function() { return true; },
    Typ: function() { return this.vertex.type; },
    prop: function(path) {
        if (_.has(this.vertex.properties, path)) {
            return this.vertex.properties[path];
        }
    }
};

// vertex factory
var Vertex = function(obj) {
    return _.assign(Object.create(vertexProto),
        obj, { outEdges: _.map(obj.outEdges, function(d) { return d.id; })}
    );
};

var edgeProto = {
    isVertex: function() { return false; },
    Typ: function() { return this.etype; },
    prop: function(path) {
        if (_.has(this.properties, path)) {
            return this.properties[path];
        }
    }
};

// edge factory
var Edge = function(obj) { return _.assign(Object.create(edgeProto), obj); };

// TODO this pretty much mirrors what we have serverside...for now. ugh.
// pipeviz datastore
function pvGraph(gdata) {
    // contains all objects, vertices and edges, keyed by objid
    this._objects = {};
    this.mid = gdata.id;

    var that = this;
    _.each(gdata.vertices, function(d) {
        // capture vertex
        that._objects[d.id] = Vertex(d);
        // and its out-edges
        _.each(d.outEdges, function(d2) { that._objects[d2.id] = Edge(d2); });
    });
}

pvGraph.prototype.get = function(id) {
    return this._objects[id];
};

pvGraph.prototype.verticesWithType = function(typ) {
    return _.filter(this._objects, function(d) {
        return  d.isVertex() && d.vertex.type === typ;
    });
};

var filters = {
    vertices: function(d) {
        return d.isVertex();
    },
    edges: function(d) {
        return !d.isVertex();
    }
};

var isType = function(typ) {
    return function(d) {
        return typ === d.Typ();
    };
};

// Returns a graphlib.Graph object representing the graph(s) of all known
// commit objects.
pvGraph.prototype.commitGraph = function() {
    var g = new graphlib.Graph();
    var that = this;

    //_.each(_.filter(this._objects, filters.vertices), function(vertex) {
    _.each(_.filter(this._objects, function(d) { return filters.vertices(d) && isType("commit")(d); }), function(commit) {
        g.setNode(commit.id);
        _.each(_.filter(_.map(commit.outEdges, function(edgeId) { return that.get(edgeId); }), isType("version")), function (edge) {
            g.setEdge(commit.id, edge.target);
        });
    });

    return g;
};
<commit_msg>Proper factory pattern for pvGraph<commit_after>// just so my syntastic complains less
var _ = _ || {};

// TODO get rid of this anchor shit, replace with well-formed tree rendering
function Anchor(id, x, y) {
    this.fixed = true; // tells d3 not to move it
    this.x = x || 0;
    this.y = y || 0;
    this.id = id;
}

Anchor.prototype.name = function() {
    return '';
};

Anchor.prototype.Typ = function() {
    return 'anchor';
};

Anchor.prototype.isVertex = function() {
    return true;
};

Anchor.prototype.prop = function() {
    return;
};

var vertexProto = {
    isVertex: function() { return true; },
    Typ: function() { return this.vertex.type; },
    prop: function(path) {
        if (_.has(this.vertex.properties, path)) {
            return this.vertex.properties[path];
        }
    }
};

// vertex factory
var Vertex = function(obj) {
    return _.assign(Object.create(vertexProto),
        obj, { outEdges: _.map(obj.outEdges, function(d) { return d.id; })}
    );
};

var edgeProto = {
    isVertex: function() { return false; },
    Typ: function() { return this.etype; },
    prop: function(path) {
        if (_.has(this.properties, path)) {
            return this.properties[path];
        }
    }
};

// edge factory
var Edge = function(obj) { return _.assign(Object.create(edgeProto), obj); };

var pvGraphProto = {
    get: function(id) {
        return this._objects[id];
    },
    // With no arguments, returns all vertices in the graph. If one argument
    // is passed, it is taken to be a filtering function, and each vertex will
    // be passed as a candidate for elimination.
    vertices: function() {
        if (arguments.length === 1) {
            return _.filter(this._objects, function(d) {
                return d.isVertex();
            });
        }

        var cf = arguments[1];
        return _.filter(this._objects, function(d) {
            return d.isVertex() && cf(d);
        });
    },
    verticesWithType:  function(typ) {
        return _.filter(this._objects, function(d) {
            return  d.isVertex() && d.vertex.type === typ;
        });
    },
    // Returns a graphlib.Graph object representing the graph(s) of all known
    // commit objects.
    commitGraph: function() {
        var g = new graphlib.Graph();
        var that = this;

        //_.each(_.filter(this._objects, filters.vertices), function(vertex) {
        _.each(_.filter(this._objects, function(d) { return filters.vertices(d) && isType("commit")(d); }), function(commit) {
            g.setNode(commit.id);
            _.each(_.filter(_.map(commit.outEdges, function(edgeId) { return that.get(edgeId); }), isType("version")), function (edge) {
                g.setEdge(commit.id, edge.target);
            });
        });

        return g;
    }
},
// TODO this pretty much mirrors what we have serverside...for now. ugh.
// pipeviz graph datastore factory
pvGraph = function(obj) {
    return _.assign(Object.create(pvGraphProto), (function() {
        var o = {
            _objects: {},
            mid: obj.id
        };

        _.each(obj.vertices, function(d) {
            o._objects[d.id] = Vertex(d);
            _.each(d.outEdges, function(d2) { o._objects[d2.id] = Edge(d2); });
        });

        return o;
    }())
    );
};

var filters = {
    vertices: function(d) {
        return d.isVertex();
    },
    edges: function(d) {
        return !d.isVertex();
    }
};

var isType = function(typ) {
    return function(d) {
        return typ === d.Typ();
    };
};
<|endoftext|>


<commit_before>export default class Carver {
    constructor() {
        this.canvas = $('#canvas')[0];
        this.ctx = this.canvas.getContext('2d');
        this.grayscaleCanvas = $('#grayscale-canvas')[0];
        this.grayscaleCtx = this.grayscaleCanvas.getContext('2d');
        this.xGradiantCanvas = $('#gradiant-canvas-x')[0];
        this.xGradiantCtx = this.xGradiantCanvas.getContext('2d');
        this.yGradiantCanvas = $('#gradiant-canvas-y')[0];
        this.yGradiantCtx = this.yGradiantCanvas.getContext('2d');
    }

    setImage(imgUrl) {
        this.image = new Image();
        this.image.onload = this.initCanvas.bind(this);
        this.image.src = imgUrl;
    }

    initCanvas() {
        $('#canvas').show();
        this.canvas.width = this.image.width;
        this.canvas.height = this.image.height;
        this.ctx.drawImage(this.image, 0, 0);
        $('input#horizontal-size').val(this.image.width);
        $('input#vertical-size').val(this.image.height);
        for(var i =0; i < 150; i++){
            this.resizeHorz();
            console.log(i/150 + "%")
        }
    }

    resizeHorz() {
        this.convertGrayscale();
        this.computeGradiant();
        this.computeEnergy();
        var seam = this.computeSeams(1)[0];
        var imageData = this.ctx.getImageData(0, 0, this.canvas.width, this.canvas.height);
        this.ripSeam(seam, imageData);
        this.canvas.width = this.canvas.width-1;
        this.ctx.putImageData(imageData, 0, 0);
    }

    copyArrayBuffer(src) {
        var target = new ArrayBuffer(src.length);
        new Uint32Array(target).set(new Uint32Array(src));
        return target;
    }

    convertGrayscale() {
        this.grayscaleCtx.drawImage(this.image, 0, 0, this.image.width, this.image.height);
        var imageData = this.ctx.getImageData(0, 0, this.image.width, this.image.height);
        this.grayscaleImage = new jsfeat.matrix_t(this.image.width, this.image.height, jsfeat.U8_t | jsfeat.C1_t);
        jsfeat.imgproc.grayscale(imageData.data, this.image.width, this.image.height, this.grayscaleImage);

        var data_u32 = new Uint32Array(imageData.data.buffer);
        var alpha = (0xff << 24);
        var i = this.grayscaleImage.cols*this.grayscaleImage.rows, pix = 0;
        while(--i >= 0) {
            pix = this.grayscaleImage.data[i];
            data_u32[i] = alpha | (pix << 16) | (pix << 8) | pix;
        }
        this.grayscaleCanvas.width = this.grayscaleImage.cols;
        this.grayscaleCanvas.height = this.grayscaleImage.rows;
        this.grayscaleCtx.putImageData(imageData, 0, 0);
    }

    computeGradiant() {
        this.xGradiantCanvas.width = this.grayscaleImage.cols;
        this.xGradiantCanvas.height = this.grayscaleImage.rows;
        this.xGradiantCtx.drawImage(this.image, 0, 0, this.image.width, this.image.height);

        this.yGradiantCanvas.width = this.grayscaleImage.cols;
        this.yGradiantCanvas.height = this.grayscaleImage.rows;
        this.yGradiantCtx.drawImage(this.image, 0, 0, this.image.width, this.image.height);

        var xImageData = this.ctx.getImageData(0, 0, this.image.width, this.image.height);
        var yImageData = this.ctx.getImageData(0, 0, this.image.width, this.image.height);
        this.gradiantImage = new jsfeat.matrix_t(this.image.width, this.image.height, jsfeat.S32C2_t);
        jsfeat.imgproc.sobel_derivatives(this.grayscaleImage, this.gradiantImage);

        var UInt32XData = new Uint32Array(xImageData.data.buffer);
        var UInt32YData = new Uint32Array(yImageData.data.buffer);
        this.UInt8XGradData = new jsfeat.matrix_t(this.image.width, this.image.height, jsfeat.U8_t | jsfeat.C1_t);
        this.UInt8YGradData = new jsfeat.matrix_t(this.image.width, this.image.height, jsfeat.U8_t | jsfeat.C1_t);
        var alpha = (0xff << 24);
        var i = this.gradiantImage.cols * this.gradiantImage.rows, pix = 0;
        while(--i >= 0) {
            // Bit shifting is multiplying by 2 (<<1) and mod'ing by 255 (&0xff)
            pix = Math.abs(this.gradiantImage.data[i << 1])&0xff;
            this.UInt8XGradData[i] = pix;
            UInt32XData[i] = alpha | (pix << 16) | (pix << 8) | pix;
            pix = Math.abs(this.gradiantImage.data[(i << 1) + 1])&0xff;
            this.UInt8YGradData[i] = pix;
            UInt32YData[i] = alpha | (pix << 16) | (pix << 8) | pix;

        }
        this.xGradiantCtx.putImageData(xImageData, 0, 0);
        this.yGradiantCtx.putImageData(yImageData, 0, 0);
    }

    computeEnergy() {
        // we compute the seams using dynamic programing

        this.costMatrix = [];
        this.parentMatrix = [];

        for (var i = 0; i < this.canvas.width; ++i) {
            this.costMatrix[i] = [];
            this.parentMatrix[i] = [];
            for (var j = 0; j < this.canvas.height; ++j) {
                this.costMatrix[i][j] = 255;
                this.parentMatrix[i][j] = null;
            }
        }

        for (var i = 0; i < this.canvas.width; i++) {
            for(var j = 0; j < this.canvas.height; j++) {
                this.costMatrix[i][j] = this.cost(i,j,'vertical');
            }
        }

    }

    cost(x, y, orientation) {
        if(orientation === 'vertical'){
            var gradiantMatrix = this.UInt8YGradData;
        } else if (orientation === 'horizontal') {
            var gradiantMatrix = this.UInt8XGradData;
        }
        var cost = gradiantMatrix[this.at(x,y)];

        if(y === 0){
            return cost;
        }
        var parents = this.getParents(x, y, gradiantMatrix);
        var minParentCost = parents[0].cost;
        this.parentMatrix[x][y] = parents[0];
        for(var i = 0; i < parents.length; i++) {
            var parentCost = parents[i].cost;
            if(parentCost<minParentCost){
                minParentCost = parentCost;
                this.parentMatrix[x][y] = parents[i];
            }
        }
        cost = cost + minParentCost;
        return cost;

    }

    at(x, y) {
        return (y * this.canvas.width + x);
    }

    getParents(x, y, gradiantMatrix) {
        var parents = [];
        if(y === 0){
            return parents;
        } else if(x === 0) {
            parents.push({
                'x': x,
                'y': y-1,
                'cost': gradiantMatrix[this.at(x,y-1)]
            });
            parents.push({
                'x': x+1,
                'y': y-1,
                'cost': gradiantMatrix[this.at(x+1,y-1)]
            });
        } else if(x === this.canvas.width-1) {
            parents.push({
                'x' :x-1,
                'y' :y-1,
                'cost' :gradiantMatrix[this.at(x-1,y-1)]
            });
            parents.push({
                'x' :x,
                'y' :y-1,
                'cost' :gradiantMatrix[this.at(x,y-1)]
            });
        } else {
            parents.push({
                'x': x-1,
                'y': y-1,
                'cost': gradiantMatrix[this.at(x-1,y-1)]
            });
            parents.push({
                'x': x,
                'y': y-1,
                'cost': gradiantMatrix[this.at(x,y-1)]
            });
            parents.push({
                'x': x+1,
                'y': y-1,
                'cost': gradiantMatrix[this.at(x+1,y-1)]
            });
        }
        return parents;
    }

    computeSeams(numSeams) {
        //scan last row of costs for minimum
        //TODO: Just sort the last row, and slice it?
        var lastRowIdx = this.canvas.height - 1;
        var minCosts = [{'pos': 0, 'cost': this.costMatrix[0][lastRowIdx]}];
        for (var i = 0; i < this.costMatrix.length; i++) {
            var curCost = this.costMatrix[i][lastRowIdx];
            if(Object.keys(minCosts).length <= numSeams){
                minCosts.push({'pos' : i, 'cost': curCost});
            } else {
                var maxItem = _.max(minCosts, function(item){return item.cost;});
                if (curCost < maxItem.cost) {
                    minCosts.push({'pos' : i, 'cost': curCost});
                    minCosts = _.filter(minCosts, function(item){ return item.cost < maxItem.cost;});
                }
            }
        }
        minCosts = minCosts.slice(0, numSeams);
        // take those positions and follow the min cost route back to the top
        var seams = [];
        for(var i = 0; i < minCosts.length; i++){
            var x =  minCosts[i].pos;
            var seam = [];
            for(var y = lastRowIdx; y >= 0; y--){
                seam.push({'x': x, 'y': y});
                //TODO: Shitty Construction, fix it
                if(y ===0) {
                    break;
                }
                var parent = this.parentMatrix[x][y];
                x = parent.x;
            }
            seams.push(seam);
        }

        return seams;
    }

    traceSeam(seams, imageData) {
        var uInt32Data = new Uint32Array(imageData.data.buffer);
        for(var i = 0; i < seams.length; i++){
            var seam = seams[i]
            for (var j = 0; j < seam.length; j++) {
                uInt32Data[this.at(seam[j].x, seam[j].y)] = (0xff << 24) | (0 << 16) | (0 << 8) | (0xff);
            }
        }
        return imageData;
    }

    ripSeam(seam, imageData) {
        var uInt32Data = new Uint32Array(imageData.data.buffer);
        var target = new Uint32Array((this.canvas.width-1)*(this.canvas.height))
        for (var y = 0; y < this.canvas.height; y++) {
            var pixel = _.find(seam, function (pix) { return pix.y === y});
            for (var x = 0; x < this.canvas.width; x++){
                if(x < pixel.x) {
                    uInt32Data[this.at(x,y)] = uInt32Data[this.at(x,y)];
                } else {
                    uInt32Data[this.at(x,y)] = uInt32Data[this.at(x+1,y)];
                }

            }
        }
    }

}<commit_msg>Move seam drawing code into their own functions<commit_after>export default class Carver {
    constructor() {
        this.canvas = $('#canvas')[0];
        this.ctx = this.canvas.getContext('2d');
        this.grayscaleCanvas = $('#grayscale-canvas')[0];
        this.grayscaleCtx = this.grayscaleCanvas.getContext('2d');
        this.xGradiantCanvas = $('#gradiant-canvas-x')[0];
        this.xGradiantCtx = this.xGradiantCanvas.getContext('2d');
        this.yGradiantCanvas = $('#gradiant-canvas-y')[0];
        this.yGradiantCtx = this.yGradiantCanvas.getContext('2d');
    }

    setImage(imgUrl) {
        this.image = new Image();
        this.image.onload = this.initCanvas.bind(this);
        this.image.src = imgUrl;
    }

    initCanvas() {
        $('#canvas').show();
        this.canvas.width = this.image.width;
        this.canvas.height = this.image.height;
        this.ctx.drawImage(this.image, 0, 0);
        $('input#horizontal-size').val(this.image.width);
        $('input#vertical-size').val(this.image.height);
        for(var i =0; i < 150; i++){
            this.resizeHorz();
            console.log(i/150 + "%")
        }
    }

    drawSeams () {
        this.convertGrayscale();
        this.computeGradiant();
        this.computeEnergy();
        var seam = this.computeSeams(20);
        var grayscaleData = this.grayscaleCtx.getImageData(0, 0, this.grayscaleCanvas.width, this.grayscaleCanvas.height);
        this.cachedGrayscaleData = copyArrayBuffer(grayscaleData);
        var data = this.traceSeam(seam, grayscaleData);
        this.grayscaleCtx.putImageData(grayscaleData, 0, 0);
    }

    hideSeams() {
        this.grayscaleCtx.putImageData(this.cachedGrayscaleData);
    }

    resizeHorz() {
        this.convertGrayscale();
        this.computeGradiant();
        this.computeEnergy();
        var seam = this.computeSeams(1)[0];
        var imageData = this.ctx.getImageData(0, 0, this.canvas.width, this.canvas.height);
        this.ripSeam(seam, imageData);
        this.canvas.width = this.canvas.width-1;
        this.ctx.putImageData(imageData, 0, 0);
    }

    copyArrayBuffer(src) {
        var target = new ArrayBuffer(src.length);
        new Uint32Array(target).set(new Uint32Array(src));
        return target;
    }

    convertGrayscale() {
        this.grayscaleCtx.drawImage(this.image, 0, 0, this.image.width, this.image.height);
        var imageData = this.ctx.getImageData(0, 0, this.image.width, this.image.height);
        this.grayscaleImage = new jsfeat.matrix_t(this.image.width, this.image.height, jsfeat.U8_t | jsfeat.C1_t);
        jsfeat.imgproc.grayscale(imageData.data, this.image.width, this.image.height, this.grayscaleImage);

        var data_u32 = new Uint32Array(imageData.data.buffer);
        var alpha = (0xff << 24);
        var i = this.grayscaleImage.cols*this.grayscaleImage.rows, pix = 0;
        while(--i >= 0) {
            pix = this.grayscaleImage.data[i];
            data_u32[i] = alpha | (pix << 16) | (pix << 8) | pix;
        }
        this.grayscaleCanvas.width = this.grayscaleImage.cols;
        this.grayscaleCanvas.height = this.grayscaleImage.rows;
        this.grayscaleCtx.putImageData(imageData, 0, 0);
    }

    computeGradiant() {
        this.xGradiantCanvas.width = this.grayscaleImage.cols;
        this.xGradiantCanvas.height = this.grayscaleImage.rows;
        this.xGradiantCtx.drawImage(this.image, 0, 0, this.image.width, this.image.height);

        this.yGradiantCanvas.width = this.grayscaleImage.cols;
        this.yGradiantCanvas.height = this.grayscaleImage.rows;
        this.yGradiantCtx.drawImage(this.image, 0, 0, this.image.width, this.image.height);

        var xImageData = this.ctx.getImageData(0, 0, this.image.width, this.image.height);
        var yImageData = this.ctx.getImageData(0, 0, this.image.width, this.image.height);
        this.gradiantImage = new jsfeat.matrix_t(this.image.width, this.image.height, jsfeat.S32C2_t);
        jsfeat.imgproc.sobel_derivatives(this.grayscaleImage, this.gradiantImage);

        var UInt32XData = new Uint32Array(xImageData.data.buffer);
        var UInt32YData = new Uint32Array(yImageData.data.buffer);
        this.UInt8XGradData = new jsfeat.matrix_t(this.image.width, this.image.height, jsfeat.U8_t | jsfeat.C1_t);
        this.UInt8YGradData = new jsfeat.matrix_t(this.image.width, this.image.height, jsfeat.U8_t | jsfeat.C1_t);
        var alpha = (0xff << 24);
        var i = this.gradiantImage.cols * this.gradiantImage.rows, pix = 0;
        while(--i >= 0) {
            // Bit shifting is multiplying by 2 (<<1) and mod'ing by 255 (&0xff)
            pix = Math.abs(this.gradiantImage.data[i << 1])&0xff;
            this.UInt8XGradData[i] = pix;
            UInt32XData[i] = alpha | (pix << 16) | (pix << 8) | pix;
            pix = Math.abs(this.gradiantImage.data[(i << 1) + 1])&0xff;
            this.UInt8YGradData[i] = pix;
            UInt32YData[i] = alpha | (pix << 16) | (pix << 8) | pix;

        }
        this.xGradiantCtx.putImageData(xImageData, 0, 0);
        this.yGradiantCtx.putImageData(yImageData, 0, 0);
    }

    computeEnergy() {
        // we compute the seams using dynamic programing

        this.costMatrix = [];
        this.parentMatrix = [];

        for (var i = 0; i < this.canvas.width; ++i) {
            this.costMatrix[i] = [];
            this.parentMatrix[i] = [];
            for (var j = 0; j < this.canvas.height; ++j) {
                this.costMatrix[i][j] = 255;
                this.parentMatrix[i][j] = null;
            }
        }

        for (var i = 0; i < this.canvas.width; i++) {
            for(var j = 0; j < this.canvas.height; j++) {
                this.costMatrix[i][j] = this.cost(i,j,'vertical');
            }
        }

    }

    cost(x, y, orientation) {
        if(orientation === 'vertical'){
            var gradiantMatrix = this.UInt8YGradData;
        } else if (orientation === 'horizontal') {
            var gradiantMatrix = this.UInt8XGradData;
        }
        var cost = gradiantMatrix[this.at(x,y)];

        if(y === 0){
            return cost;
        }
        var parents = this.getParents(x, y, gradiantMatrix);
        var minParentCost = parents[0].cost;
        this.parentMatrix[x][y] = parents[0];
        for(var i = 0; i < parents.length; i++) {
            var parentCost = parents[i].cost;
            if(parentCost<minParentCost){
                minParentCost = parentCost;
                this.parentMatrix[x][y] = parents[i];
            }
        }
        cost = cost + minParentCost;
        return cost;

    }

    at(x, y) {
        return (y * this.canvas.width + x);
    }

    getParents(x, y, gradiantMatrix) {
        var parents = [];
        if(y === 0){
            return parents;
        } else if(x === 0) {
            parents.push({
                'x': x,
                'y': y-1,
                'cost': gradiantMatrix[this.at(x,y-1)]
            });
            parents.push({
                'x': x+1,
                'y': y-1,
                'cost': gradiantMatrix[this.at(x+1,y-1)]
            });
        } else if(x === this.canvas.width-1) {
            parents.push({
                'x' :x-1,
                'y' :y-1,
                'cost' :gradiantMatrix[this.at(x-1,y-1)]
            });
            parents.push({
                'x' :x,
                'y' :y-1,
                'cost' :gradiantMatrix[this.at(x,y-1)]
            });
        } else {
            parents.push({
                'x': x-1,
                'y': y-1,
                'cost': gradiantMatrix[this.at(x-1,y-1)]
            });
            parents.push({
                'x': x,
                'y': y-1,
                'cost': gradiantMatrix[this.at(x,y-1)]
            });
            parents.push({
                'x': x+1,
                'y': y-1,
                'cost': gradiantMatrix[this.at(x+1,y-1)]
            });
        }
        return parents;
    }

    computeSeams(numSeams) {
        //scan last row of costs for minimum
        //TODO: Just sort the last row, and slice it?
        var lastRowIdx = this.canvas.height - 1;
        var minCosts = [{'pos': 0, 'cost': this.costMatrix[0][lastRowIdx]}];
        for (var i = 0; i < this.costMatrix.length; i++) {
            var curCost = this.costMatrix[i][lastRowIdx];
            if(Object.keys(minCosts).length <= numSeams){
                minCosts.push({'pos' : i, 'cost': curCost});
            } else {
                var maxItem = _.max(minCosts, function(item){return item.cost;});
                if (curCost < maxItem.cost) {
                    minCosts.push({'pos' : i, 'cost': curCost});
                    minCosts = _.filter(minCosts, function(item){ return item.cost < maxItem.cost;});
                }
            }
        }
        minCosts = minCosts.slice(0, numSeams);
        // take those positions and follow the min cost route back to the top
        var seams = [];
        for(var i = 0; i < minCosts.length; i++){
            var x =  minCosts[i].pos;
            var seam = [];
            for(var y = lastRowIdx; y >= 0; y--){
                seam.push({'x': x, 'y': y});
                //TODO: Shitty Construction, fix it
                if(y ===0) {
                    break;
                }
                var parent = this.parentMatrix[x][y];
                x = parent.x;
            }
            seams.push(seam);
        }

        return seams;
    }

    traceSeam(seams, imageData) {
        var uInt32Data = new Uint32Array(imageData.data.buffer);
        for(var i = 0; i < seams.length; i++){
            var seam = seams[i]
            for (var j = 0; j < seam.length; j++) {
                uInt32Data[this.at(seam[j].x, seam[j].y)] = (0xff << 24) | (0 << 16) | (0 << 8) | (0xff);
            }
        }
        return imageData;
    }

    ripSeam(seam, imageData) {
        var uInt32Data = new Uint32Array(imageData.data.buffer);
        var target = new Uint32Array((this.canvas.width-1)*(this.canvas.height))
        for (var y = 0; y < this.canvas.height; y++) {
            var pixel = _.find(seam, function (pix) { return pix.y === y});
            for (var x = 0; x < this.canvas.width; x++){
                if(x < pixel.x) {
                    uInt32Data[this.at(x,y)] = uInt32Data[this.at(x,y)];
                } else {
                    uInt32Data[this.at(x,y)] = uInt32Data[this.at(x+1,y)];
                }

            }
        }
    }

}<|endoftext|>