<commit_before>import mongoose from 'mongoose';
const Schema = mongoose.Schema;

let UserSchema = new Schema({
  email: {type: String, required: true, index: true},
  password: {type: String, required: true}
});

let UserModel = mongoose.model('User', UserSchema);

export default UserModel;<commit_msg>adding createdAt and updatedAt attributes to mongoose model<commit_after>import mongoose from 'mongoose';
const Schema = mongoose.Schema;

let UserSchema = new Schema({
  email: {type: String, required: true, index: true},
  password: {type: String, required: true},
  createdAt: {type: Date, 'default': Date.now},
  updatedAt: {type: Date, 'default': Date.now}
});

let UserModel = mongoose.model('User', UserSchema);

export default UserModel;<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import { findDOMNode } from 'react-dom';
import withStyles from 'isomorphic-style-loader/lib/withStyles';
import s from './timetable.scss';
import { arrangeLessonsForWeek } from '../../utils/modules';
import TimetableBackground from './TimetableBackground';
import TimetableDayRow from './TimetableDayRow';
import TimeRow from './TimeRow';

// Ref: https://github.com/yangshun/nusmods-v3/tree/master/src/js

// Ignore Sundays since there is no school
const DAYS = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
const minColWidth = 100;
const dayRowWidth = 16.6666666666666;
const types = [
  'scroll',
  'mousewheel',
  'DOMMouseScroll',
  'MozMousePixelScroll',
  'resize',
  'touchmove',
  'touchend',
];

class Timetable extends Component {
  constructor(props) {
    super(props);
    this.state = {
      scrollTopOffset: 0,
    };
  }

  componentDidMount() {
    types.forEach((type) => {
      findDOMNode(this.refs.timetableWrapper)
        .addEventListener(type, this.onScroll.bind(this), false);
    });
  }

  componentWillUnmount() {
    types.forEach((type) => {
      findDOMNode(this.refs.timetableWrapper)
        .removeEventListener(type, this.onScroll.bind(this), false);
    });
  }

  onScroll() {
    this.setState({
      scrollTopOffset: ((window && window.scrollY) || 0),
    });
  }

  render() {
    const arrangedLessons = arrangeLessonsForWeek(this.props.lessons);
    const numCols = DAYS.reduce((prev, curr) => (
      prev + (arrangedLessons[curr] ? arrangedLessons[curr].length : 1)),
      0);
    const width = typeof window !== 'undefined' ?
      window.innerWidth * 0.85 :
      0;
    const style = {};
    const minInnerContainerWidth = minColWidth * numCols;
    if (minInnerContainerWidth > width) {
      style.minWidth = `${minInnerContainerWidth}px`;
    }

    const headerStyle= {
      ...style,
      marginTop: `${this.state.scrollTopOffset - 40}px`,
    };

    return (

          { this.props.timetable.isFetching }

        <TimeRow />

              {DAYS.map((day) => {
                const dayLessonRows = arrangedLessons[day];
                const size = dayLessonRows ? dayLessonRows.length : 1;
                return (
                  <div
                    className="timetable-day"
                    key={day}
                    style={{ width: `${dayRowWidth * size}%` }}
                  >
                    {day}

                );
              })}

              {DAYS.map((day) => {
                const dayLessonRows = arrangedLessons[day];
                const size = dayLessonRows ? dayLessonRows.length : 1;
                return (
                  <TimetableDayRow
                    key={day}
                    width={`${dayRowWidth * size}%`}
                    size={size}
                    day={day.substring(0, 3)}
                    dayLessonRows={dayLessonRows}
                    onLessonChange={this.props.onLessonChange}
                  />
                );
              })}

            <TimetableBackground />

    );
  }
}

Timetable.propTypes = {
  lessons: PropTypes.array,
  timetable: PropTypes.object,
  onLessonChange: PropTypes.func,
};

export default withStyles(s)(Timetable);
<commit_msg>lint fix<commit_after>/* eslint-disable react/no-string-refs, react/no-find-dom-node */

import React, { Component, PropTypes } from 'react';
import { findDOMNode } from 'react-dom';
import withStyles from 'isomorphic-style-loader/lib/withStyles';
import s from './timetable.scss';
import { arrangeLessonsForWeek } from '../../utils/modules';
import TimetableBackground from './TimetableBackground';
import TimetableDayRow from './TimetableDayRow';
import TimeRow from './TimeRow';

// Ref: https://github.com/yangshun/nusmods-v3/tree/master/src/js

// Ignore Sundays since there is no school
const DAYS = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
const minColWidth = 100;
const dayRowWidth = 16.6666666666666;
const types = [
  'scroll',
  'mousewheel',
  'DOMMouseScroll',
  'MozMousePixelScroll',
  'resize',
  'touchmove',
  'touchend',
];

class Timetable extends Component {
  constructor(props) {
    super(props);
    this.state = {
      scrollTopOffset: 0,
    };
  }

  componentDidMount() {
    types.forEach((type) => {
      findDOMNode(this.refs.timetableWrapper)
        .addEventListener(type, this.onScroll.bind(this), false);
    });
  }

  componentWillUnmount() {
    types.forEach((type) => {
      findDOMNode(this.refs.timetableWrapper)
        .removeEventListener(type, this.onScroll.bind(this), false);
    });
  }

  onScroll() {
    this.setState({
      scrollTopOffset: ((window && window.scrollY) || 0),
    });
  }

  render() {
    const arrangedLessons = arrangeLessonsForWeek(this.props.lessons);
    const numCols = DAYS.reduce((prev, curr) => (
      prev + (arrangedLessons[curr] ? arrangedLessons[curr].length : 1)),
      0);
    const width = typeof window !== 'undefined' ?
      window.innerWidth * 0.85 :
      0;
    const style = {};
    const minInnerContainerWidth = minColWidth * numCols;
    if (minInnerContainerWidth > width) {
      style.minWidth = `${minInnerContainerWidth}px`;
    }

    const headerStyle = {
      ...style,
      marginTop: `${this.state.scrollTopOffset - 40}px`,
    };

    return (

          { this.props.timetable.isFetching }

        <TimeRow />

              {DAYS.map((day) => {
                const dayLessonRows = arrangedLessons[day];
                const size = dayLessonRows ? dayLessonRows.length : 1;
                return (
                  <div
                    className="timetable-day"
                    key={day}
                    style={{ width: `${dayRowWidth * size}%` }}
                  >
                    {day}

                );
              })}

              {DAYS.map((day) => {
                const dayLessonRows = arrangedLessons[day];
                const size = dayLessonRows ? dayLessonRows.length : 1;
                return (
                  <TimetableDayRow
                    key={day}
                    width={`${dayRowWidth * size}%`}
                    size={size}
                    day={day.substring(0, 3)}
                    dayLessonRows={dayLessonRows}
                    onLessonChange={this.props.onLessonChange}
                  />
                );
              })}

            <TimetableBackground />

    );
  }
}

Timetable.propTypes = {
  lessons: PropTypes.array,
  timetable: PropTypes.object,
  onLessonChange: PropTypes.func,
};

export default withStyles(s)(Timetable);
<|endoftext|>


<commit_before>EsriLeaflet.Layers.RasterLayer =  L.Class.extend({
  includes: L.Mixin.Events,

  options: {
    opacity: 1,
    position: 'front',
    f: 'image'
  },

  onAdd: function (map) {
    this._map = map;

    this._update = L.Util.limitExecByInterval(this._update, this.options.updateInterval, this);

    if (map.options.crs && map.options.crs.code) {
      var sr = map.options.crs.code.split(':')[1];
      this.options.bboxSR = sr;
      this.options.imageSR = sr;
    }

    map.on('moveend', this._update, this);

    // if we had an image loaded and it matches the
    // current bounds show the image otherwise remove it
    if(this._currentImage && this._currentImage._bounds.equals(this._map.getBounds())){
      map.addLayer(this._currentImage);
    } else {
      map.removeLayer(this._currentImage);
      this._currentImage = null;
    }

    this._update();

    if(this._popup){
      this._map.on('click', this._getPopupData, this);
      this._map.on('dblclick', this._resetPopupState, this);
    }
  },

  bindPopup: function(fn, popupOptions){
    this._shouldRenderPopup = false;
    this._lastClick = false;
    this._popup = L.popup(popupOptions);
    this._popupFunction = fn;
    if(this._map){
      this._map.on('click', this._getPopupData, this);
      this._map.on('dblclick', this._resetPopupState, this);
    }
    return this;
  },

  unbindPopup: function(){
    if(this._map){
      this._map.closePopup(this._popup);
      this._map.off('click', this._getPopupData, this);
      this._map.off('dblclick', this._resetPopupState, this);
    }
    this._popup = false;
    return this;
  },

  onRemove: function (map) {
    if (this._currentImage) {
      this._map.removeLayer(this._currentImage);
    }

    if(this._popup){
      this._map.off('click', this._getPopupData, this);
      this._map.off('dblclick', this._resetPopupState, this);
    }

    this._map.off('moveend', this._update, this);
    this._map = null;
  },

  addTo: function(map){
    map.addLayer(this);
    return this;
  },

  removeFrom: function(map){
    map.removeLayer(this);
    return this;
  },

  bringToFront: function(){
    this.options.position = 'front';
    if(this._currentImage){
      this._currentImage.bringToFront();
    }
    return this;
  },

  bringToBack: function(){
    this.options.position = 'back';
    if(this._currentImage){
      this._currentImage.bringToBack();
    }
    return this;
  },

  getAttribution: function () {
    return this.options.attribution;
  },

  getOpacity: function(){
    return this.options.opacity;
  },

  setOpacity: function(opacity){
    this.options.opacity = opacity;
    this._currentImage.setOpacity(opacity);
    return this;
  },

  getTimeRange: function(){
    return [this.options.from, this.options.to];
  },

  setTimeRange: function(from, to){
    this.options.from = from;
    this.options.to = to;
    this._update();
    return this;
  },

  metadata: function(callback, context){
    this._service.metadata(callback, context);
    return this;
  },

  authenticate: function(token){
    this._service.authenticate(token);
    return this;
  },

  _renderImage: function(url, bounds){
    if(this._map){
      // create a new image overlay and add it to the map
      // to start loading the image
      // opacity is 0 while the image is loading
      var image = new L.ImageOverlay(url, bounds, {
        opacity: 0
      }).addTo(this._map);

      // once the image loads
      image.once('load', function(e){
        var newImage = e.target;
        var oldImage = this._currentImage;

        // if the bounds of this image matches the bounds that
        // _renderImage was called with and we have a map
        // hide the old image if there is one and set the opacity
        // of the new image otherwise remove the new image
        if(newImage._bounds.equals(bounds)){
          this._currentImage = newImage;

          if(this.options.position === 'front'){
            this.bringToFront();
          } else {
            this.bringToBack();
          }

          if(this._map && this._currentImage._map){
            this._currentImage.setOpacity(this.options.opacity);
          } else {
            this._currentImage._map.removeLayer(this._currentImage);
          }

          if(oldImage){
            this._map.removeLayer(oldImage);
          }
        } else {
          this._map.removeLayer(newImage);
        }

        this.fire('load', {
          bounds: bounds
        });

      }, this);

      this.fire('loading', {
        bounds: bounds
      });
    }
  },

  _update: function () {
    if(!this._map){
      return;
    }

    var zoom = this._map.getZoom();
    var bounds = this._map.getBounds();

    if(this._animatingZoom){
      return;
    }

    if (this._map._panTransition && this._map._panTransition._inProgress) {
      return;
    }

    if (zoom > this.options.maxZoom || zoom < this.options.minZoom) {
      return;
    }
    var params = this._buildExportParams();

    this._requestExport(params, bounds);
  },

  // TODO: refactor these into raster layer
  _renderPopup: function(latlng, error, results, response){
    latlng = L.latLng(latlng);
    if(this._shouldRenderPopup && this._lastClick.equals(latlng)){
      //add the popup to the map where the mouse was clicked at
      var content = this._popupFunction(error, results, response);
      if (content) {
        this._popup.setLatLng(latlng).setContent(content).openOn(this._map);
      }
    }
  },

  _resetPopupState: function(e){
    this._shouldRenderPopup = false;
    this._lastClick = e.latlng;
  },

  // from https://github.com/Leaflet/Leaflet/blob/v0.7.2/src/layer/FeatureGroup.js
  // @TODO remove at Leaflet 0.8
  _propagateEvent: function (e) {
    e = L.extend({
      layer: e.target,
      target: this
    }, e);
    this.fire(e.type, e);
  }
});<commit_msg>slightly better ux when toggleing layers<commit_after>EsriLeaflet.Layers.RasterLayer =  L.Class.extend({
  includes: L.Mixin.Events,

  options: {
    opacity: 1,
    position: 'front',
    f: 'image'
  },

  onAdd: function (map) {
    this._map = map;

    this._update = L.Util.limitExecByInterval(this._update, this.options.updateInterval, this);

    if (map.options.crs && map.options.crs.code) {
      var sr = map.options.crs.code.split(':')[1];
      this.options.bboxSR = sr;
      this.options.imageSR = sr;
    }

    map.on('moveend', this._update, this);

    // if we had an image loaded and it matches the
    // current bounds show the image otherwise remove it
    if(this._currentImage && this._currentImage._bounds.equals(this._map.getBounds())){
      map.addLayer(this._currentImage);
    } else if(this._currentImage) {
      this._map.removeLayer(this._currentImage);
      this._currentImage = null;
    }

    this._update();

    if(this._popup){
      this._map.on('click', this._getPopupData, this);
      this._map.on('dblclick', this._resetPopupState, this);
    }
  },

  bindPopup: function(fn, popupOptions){
    this._shouldRenderPopup = false;
    this._lastClick = false;
    this._popup = L.popup(popupOptions);
    this._popupFunction = fn;
    if(this._map){
      this._map.on('click', this._getPopupData, this);
      this._map.on('dblclick', this._resetPopupState, this);
    }
    return this;
  },

  unbindPopup: function(){
    if(this._map){
      this._map.closePopup(this._popup);
      this._map.off('click', this._getPopupData, this);
      this._map.off('dblclick', this._resetPopupState, this);
    }
    this._popup = false;
    return this;
  },

  onRemove: function (map) {
    if (this._currentImage) {
      this._map.removeLayer(this._currentImage);
    }

    if(this._popup){
      this._map.off('click', this._getPopupData, this);
      this._map.off('dblclick', this._resetPopupState, this);
    }

    this._map.off('moveend', this._update, this);
    this._map = null;
  },

  addTo: function(map){
    map.addLayer(this);
    return this;
  },

  removeFrom: function(map){
    map.removeLayer(this);
    return this;
  },

  bringToFront: function(){
    this.options.position = 'front';
    if(this._currentImage){
      this._currentImage.bringToFront();
    }
    return this;
  },

  bringToBack: function(){
    this.options.position = 'back';
    if(this._currentImage){
      this._currentImage.bringToBack();
    }
    return this;
  },

  getAttribution: function () {
    return this.options.attribution;
  },

  getOpacity: function(){
    return this.options.opacity;
  },

  setOpacity: function(opacity){
    this.options.opacity = opacity;
    this._currentImage.setOpacity(opacity);
    return this;
  },

  getTimeRange: function(){
    return [this.options.from, this.options.to];
  },

  setTimeRange: function(from, to){
    this.options.from = from;
    this.options.to = to;
    this._update();
    return this;
  },

  metadata: function(callback, context){
    this._service.metadata(callback, context);
    return this;
  },

  authenticate: function(token){
    this._service.authenticate(token);
    return this;
  },

  _renderImage: function(url, bounds){
    if(this._map){
      // create a new image overlay and add it to the map
      // to start loading the image
      // opacity is 0 while the image is loading
      var image = new L.ImageOverlay(url, bounds, {
        opacity: 0
      }).addTo(this._map);

      // once the image loads
      image.once('load', function(e){
        var newImage = e.target;
        var oldImage = this._currentImage;

        // if the bounds of this image matches the bounds that
        // _renderImage was called with and we have a map
        // hide the old image if there is one and set the opacity
        // of the new image otherwise remove the new image
        if(newImage._bounds.equals(bounds)){
          this._currentImage = newImage;

          if(this.options.position === 'front'){
            this.bringToFront();
          } else {
            this.bringToBack();
          }

          if(this._map && this._currentImage._map){
            this._currentImage.setOpacity(this.options.opacity);
          } else {
            this._currentImage._map.removeLayer(this._currentImage);
          }

          if(oldImage && this._map) {
            this._map.removeLayer(oldImage);
          }

          if(oldImage && oldImage._map){
            oldImage._map.removeLayer(oldImage);
          }
        } else {
          this._map.removeLayer(newImage);
        }

        this.fire('load', {
          bounds: bounds
        });

      }, this);

      this.fire('loading', {
        bounds: bounds
      });
    }
  },

  _update: function () {
    if(!this._map){
      return;
    }

    var zoom = this._map.getZoom();
    var bounds = this._map.getBounds();

    if(this._animatingZoom){
      return;
    }

    if (this._map._panTransition && this._map._panTransition._inProgress) {
      return;
    }

    if (zoom > this.options.maxZoom || zoom < this.options.minZoom) {
      return;
    }
    var params = this._buildExportParams();

    this._requestExport(params, bounds);
  },

  // TODO: refactor these into raster layer
  _renderPopup: function(latlng, error, results, response){
    latlng = L.latLng(latlng);
    if(this._shouldRenderPopup && this._lastClick.equals(latlng)){
      //add the popup to the map where the mouse was clicked at
      var content = this._popupFunction(error, results, response);
      if (content) {
        this._popup.setLatLng(latlng).setContent(content).openOn(this._map);
      }
    }
  },

  _resetPopupState: function(e){
    this._shouldRenderPopup = false;
    this._lastClick = e.latlng;
  },

  // from https://github.com/Leaflet/Leaflet/blob/v0.7.2/src/layer/FeatureGroup.js
  // @TODO remove at Leaflet 0.8
  _propagateEvent: function (e) {
    e = L.extend({
      layer: e.target,
      target: this
    }, e);
    this.fire(e.type, e);
  }
});<|endoftext|>


<commit_before>define(['app'], function (app) {
app.directive('searchFilterThemes', function ($http) {
    return {
        restrict: 'EAC',
        templateUrl: '/app/views/find_themes.partial.html',
        replace: true,
        // require : "?ngModel",
        scope: {
              // placeholder: '@',
              // ngDisabledFn : '&ngDisabled',
              title: '@title',
              items: '=ngModel',
              field: '@field',
              query: '=query',
              // locales    : '=',
              // rows       : '=',
              // required   : "@"
        },
        link: function ($scope, element, attrs, ngModelController)
        {
        },
        controller : ['$scope', '$element', '$location', 'Thesaurus', function ($scope, $element, $location, thesaurus)
        {
            $scope.expanded = false;
            $scope.selectedItems = [];
            $scope.facet = $scope.field.replace('_s', ''); // TODO: replace @field by @facet

            var parameters = $location.search();

            if (parameters[$scope.facet]) {
                $scope.selectedItems.push(parameters[$scope.facet]);
            }

            $scope.isSelected = function(item) {
                return $.inArray(item.symbol, $scope.selectedItems) >= 0;
            };

            $scope.closeDialog = function() {
                $element.find("#dialogSelect").modal("hide");
            };

            $scope.actionSelect = function(item) {

                if($scope.isSelected(item)) {
                    $scope.selectedItems.splice($.inArray(item.symbol, $scope.selectedItems), 1);
                } else {
                    $scope.selectedItems.push(item.symbol);
                }

                $scope.updateQuery();
            };

            $scope.actionExpand = function() {

                var count1 = Math.ceil($scope.items.length/3);
                var count2 = Math.ceil(($scope.items.length-count1)/2);
                var count3 = Math.ceil(($scope.items.length-count2-count1));

                $scope.items1 = $scope.items.slice(0, count1);
                $scope.items2 = $scope.items.slice(count1, count2+count2);
                $scope.items3 = $scope.items.slice(count1+count2, count1+count2+count3);

                console.log($scope.items1);
                console.log($scope.items2);
                console.log($scope.items3);

                $element.find("#dialogSelect").modal("show");

                //if(!$scope.expanded)
                    //$scope.$parent.$broadcast('onExpand', $scope);

                //$scope.expanded = !$scope.expanded;
            };

            $scope.$on('onExpand', function(scope) {
                if(scope!=$scope && $scope.expanded)
                    $scope.expanded = false;
            });

            $scope.filterx = function(item) {
                console.log(item);
                //return item.selected;
            };

            $scope.ccc = function(item) {
                return $scope.isSelected(item) ? 'facet selected' : 'facet unselected';
            };

            $scope.updateQuery = function() {

                console.log($scope.query);

                $scope.query = '';

                $scope.selectedItems.forEach(function(item) {
                    $scope.query += ($scope.query=='' ? '' : ' OR ') + $scope.field+':' + item;
                });

                if($scope.query!='')
                    $scope.query = '(' + $scope.query + ')';
                else
                    $scope.query = '*:*';

                console.log($scope.query);
            };

            function select(item) {
                if(!item.selected) item.indeterminate = true;
                if(item.narrowerTerms) item.narrowerTerms.forEach(select);
            }

            var unselect = $scope.unselect = function (item) {
                if(!item.selected) item.indeterminate = false;
                if(item.narrowerTerms) item.narrowerTerms.forEach(unselect);
            }

            function setBroaders(broaderTerms, selected) {

                if(!broaderTerms) return;

                broaderTerms.forEach(function (term) {

                    term.indeterminateCounterA = term.indeterminateCounterA + (selected ? 1 : -1);
                    console.log(term.indeterminateCounterA);
                    term.indeterminate = !term.selected && (term.indeterminateCounterA + term.indeterminateCounterB) > 0;

                    setBroaders(term.broaderTerms, selected);
                });

                // if(term.indeterminate) {
                //     term.state = term.selected;
                //     term.selected = false;
                // }

                // if(!term.indeterminate) {
                //     term.selected = term.state;
                //     term.state = null;
                // }

                // term.indeterminate = selected;

            }

            function setNarrowers(narrowerTerms, selected) {

                if(!narrowerTerms) return;

                narrowerTerms.forEach(function (term) {

                    term.indeterminateCounterB = term.indeterminateCounterB + (selected ? 1 : -1);
                    console.log(term.indeterminateCounterB);
                    term.indeterminate = !term.selected && (term.indeterminateCounterA + term.indeterminateCounterB) > 0;

                    setNarrowers(term.narrowerTerms, selected);
                });

                //

                //

                // term.indeterminate = selected;

            }

            $scope.onclick = function (scope, evt) {
                scope.item.selected = !scope.item.selected;
                $scope.ts(scope, evt);
            }

            $scope.ts = function (scope, evt) {

                var term = scope.item;

                term.indeterminate = !term.selected && (term.indeterminateCounterA + term.indeterminateCounterB) > 0;

                setBroaders(term.broaderTerms, term.selected);
                setNarrowers(term.narrowerTerms, term.selected);

                //if(scope.item.indeterminate)
                  //  scope.item.indeterminate = scope.item.indeterminate = false;

                //if(scope.item.selected==true) unselect(scope.item);
                //else
         //       if(scope.item.selected) { if(scope.item.narrowerTerms) scope.item.narrowerTerms.forEach(select); }
           //     else                    { if(scope.item.narrowerTerms) scope.item.narrowerTerms.forEach(unselect); }

                //var cb = evt.target;

                //if (cb.readOnly) cb.checked=cb.readOnly=false;
                //else if (!cb.checked) cb.readOnly=cb.indeterminate=true;

                //$scope.actionSelect(scope.item);

                buildQuery();
            }

            function buildQuery () {
                var conditions = [];
                buildConditions(conditions, $scope.terms);

                if(conditions.length==0) $scope.query = '*:*';
                else {
                    var query = '';
                    conditions.forEach(function (condition) { query = query + (query=='' ? '( ' : ' OR ') + condition; });
                    query += ' )';
                    $scope.query = query;
                }

                console.log($scope.query);
            }

            function buildConditions (conditions, items) {
                items.forEach(function (item) {
                    if(item.selected)
                        conditions.push('thematicAreas_REL_ss:'+item.identifier);
                    else if(item.narrowerTerms) {
                        buildConditions(conditions, item.narrowerTerms);
                    }
                });
            }

            function flatten(items, collection) {
                items.forEach(function (item) {
                    item.selected = false;
                    item.indeterminateCounterA = 0;
                    item.indeterminateCounterB = 0;
                    collection[item.identifier] = item;
                    if(item.narrowerTerms)
                        flatten(item.narrowerTerms, collection);
                });
                return collection;
            }

            $http.get('/api/v2013/thesaurus/domains/50616B56-12F3-4C46-BC43-2DFC26679177/terms').success(function (data) {
                $scope.terms = thesaurus.buildTree(data);

                $scope.termsMap   = flatten($scope.terms, {});
                $scope.termsArray = _.values($scope.termsMap);

                if($scope.items)
                    $scope.items.forEach(function (item) {
                        if(_.has($scope.termsMap, item.symbol))
                            $scope.termsMap[item.symbol].count = item.count;
                    });
               //console.log (data);
            });

            $scope.$watch('items', function (values) {

                if(!values) return;
                if($scope.termsMap)
                    values.forEach(function (item) {
                        if(_.has($scope.termsMap, item.symbol))
                            $scope.termsMap[item.symbol].count = item.count;
                    });
            });
        }]
    }
});
});

<commit_msg>theamatic area issue<commit_after>define(['app'], function (app) {
app.directive('searchFilterThemes', function ($http) {
    return {
        restrict: 'EAC',
        templateUrl: '/app/views/find_themes.partial.html',
        replace: true,
        // require : "?ngModel",
        scope: {
              // placeholder: '@',
              // ngDisabledFn : '&ngDisabled',
              title: '@title',
              items: '=ngModel',
              field: '@field',
              query: '=query',
              // locales    : '=',
              // rows       : '=',
              // required   : "@"
        },
        link: function ($scope, element, attrs, ngModelController)
        {
        },
        controller : ['$scope', '$element', '$location', 'Thesaurus', function ($scope, $element, $location, thesaurus)
        {
            $scope.expanded = false;
            $scope.selectedItems = [];
            $scope.facet = $scope.field.replace('_s', ''); // TODO: replace @field by @facet

            var parameters = $location.search();

            if (parameters[$scope.facet]) {
                $scope.selectedItems.push(parameters[$scope.facet]);
            }

            $scope.isSelected = function(item) {
                return $.inArray(item.symbol, $scope.selectedItems) >= 0;
            };

            $scope.closeDialog = function() {
                $element.find("#dialogSelect").modal("hide");
            };

            $scope.actionSelect = function(item) {

                if($scope.isSelected(item)) {
                    $scope.selectedItems.splice($.inArray(item.symbol, $scope.selectedItems), 1);
                } else {
                    $scope.selectedItems.push(item.symbol);
                }

                $scope.updateQuery();
            };

            $scope.actionExpand = function() {

                var count1 = Math.ceil($scope.items.length/3);
                var count2 = Math.ceil(($scope.items.length-count1)/2);
                var count3 = Math.ceil(($scope.items.length-count2-count1));

                $scope.items1 = $scope.items.slice(0, count1);
                $scope.items2 = $scope.items.slice(count1, count2+count2);
                $scope.items3 = $scope.items.slice(count1+count2, count1+count2+count3);

                console.log($scope.items1);
                console.log($scope.items2);
                console.log($scope.items3);

                $element.find("#dialogSelect").modal("show");

                //if(!$scope.expanded)
                    //$scope.$parent.$broadcast('onExpand', $scope);

                //$scope.expanded = !$scope.expanded;
            };

            $scope.$on('onExpand', function(scope) {
                if(scope!=$scope && $scope.expanded)
                    $scope.expanded = false;
            });

            $scope.filterx = function(item) {
                console.log(item);
                //return item.selected;
            };

            $scope.ccc = function(item) {
                return $scope.isSelected(item) ? 'facet selected' : 'facet unselected';
            };

            $scope.updateQuery = function() {

                console.log($scope.query );

                $scope.query = '';

                $scope.selectedItems.forEach(function(item) {
                    $scope.query += ($scope.query=='' ? '' : ' OR ') + $scope.field+':' + item;
                });

                if($scope.query!='')
                    $scope.query = '(' + $scope.query + ')';
                else
                    $scope.query = '*:*';

                console.log($scope.query);
            };

            function select(item) {
                if(!item.selected) item.indeterminate = true;
                if(item.narrowerTerms) item.narrowerTerms.forEach(select);
            }

            var unselect = $scope.unselect = function (item) {
                if(!item.selected) item.indeterminate = false;
                if(item.narrowerTerms) item.narrowerTerms.forEach(unselect);
            }

            function setBroaders(broaderTerms, selected) {

                if(!broaderTerms) return;

                broaderTerms.forEach(function (term) {

                    term.indeterminateCounterA = term.indeterminateCounterA + (selected ? 1 : -1);
                    console.log(term.indeterminateCounterA);
                    term.indeterminate = !term.selected && (term.indeterminateCounterA + term.indeterminateCounterB) > 0;

                    setBroaders(term.broaderTerms, selected);
                });

                // if(term.indeterminate) {
                //     term.state = term.selected;
                //     term.selected = false;
                // }

                // if(!term.indeterminate) {
                //     term.selected = term.state;
                //     term.state = null;
                // }

                // term.indeterminate = selected;

            }

            function setNarrowers(narrowerTerms, selected) {

                if(!narrowerTerms) return;

                narrowerTerms.forEach(function (term) {

                    term.indeterminateCounterB = term.indeterminateCounterB + (selected ? 1 : -1);
                    console.log(term.indeterminateCounterB);
                    term.indeterminate = !term.selected && (term.indeterminateCounterA + term.indeterminateCounterB) > 0;

                    setNarrowers(term.narrowerTerms, selected);
                });

                //

                //

                // term.indeterminate = selected;

            }

            $scope.onclick = function (scope, evt) {
                console.log('onclick');
                scope.item.selected = !scope.item.selected;
                $scope.ts(scope, evt);
            }

            $scope.ts = function (scope, evt) {

                var term = scope.item;
                term.selected = !scope.item.selected;
                term.indeterminate = !term.selected && (term.indeterminateCounterA + term.indeterminateCounterB) > 0;

                setBroaders(term.broaderTerms, term.selected);
                setNarrowers(term.narrowerTerms, term.selected);

                //if(scope.item.indeterminate)
                  //  scope.item.indeterminate = scope.item.indeterminate = false;

                //if(scope.item.selected==true) unselect(scope.item);
                //else
         //       if(scope.item.selected) { if(scope.item.narrowerTerms) scope.item.narrowerTerms.forEach(select); }
           //     else                    { if(scope.item.narrowerTerms) scope.item.narrowerTerms.forEach(unselect); }

                //var cb = evt.target;

                //if (cb.readOnly) cb.checked=cb.readOnly=false;
                //else if (!cb.checked) cb.readOnly=cb.indeterminate=true;

                //$scope.actionSelect(scope.item);

                buildQuery();
            }

            function buildQuery () {
                var conditions = [];
                buildConditions(conditions, $scope.terms);

                if(conditions.length==0) $scope.query = '*:*';
                else {
                    var query = '';
                    conditions.forEach(function (condition) { query = query + (query=='' ? '( ' : ' OR ') + condition; });
                    query += ' )';
                    $scope.query = query;
                }

                console.log($scope.query);
            }

            function buildConditions (conditions, items) {
                items.forEach(function (item) {
                    if(item.selected)
                        conditions.push('thematicAreas_REL_ss:'+item.identifier);
                    else if(item.narrowerTerms) {
                        buildConditions(conditions, item.narrowerTerms);
                    }
                });
            }

            function flatten(items, collection) {
                items.forEach(function (item) {
                    item.selected = false;
                    item.indeterminateCounterA = 0;
                    item.indeterminateCounterB = 0;
                    collection[item.identifier] = item;
                    if(item.narrowerTerms)
                        flatten(item.narrowerTerms, collection);
                });
                return collection;
            }

            $http.get('/api/v2013/thesaurus/domains/50616B56-12F3-4C46-BC43-2DFC26679177/terms').success(function (data) {
                $scope.terms = thesaurus.buildTree(data);

                $scope.termsMap   = flatten($scope.terms, {});
                $scope.termsArray = _.values($scope.termsMap);

                if($scope.items)
                    $scope.items.forEach(function (item) {
                        if(_.has($scope.termsMap, item.symbol))
                            $scope.termsMap[item.symbol].count = item.count;
                    });
               //console.log (data);
            });

            $scope.$watch('items', function (values) {

                if(!values) return;
                if($scope.termsMap)
                    values.forEach(function (item) {
                        if(_.has($scope.termsMap, item.symbol))
                            $scope.termsMap[item.symbol].count = item.count;
                    });
            });
        }]
    }
});
});

<|endoftext|>


<commit_before>import React from "react";
import { connect } from "react-redux";
import Flex from "./flex";
import { titleColors, titleBarHeight } from "../../util/globals";
import { titleFont, dataFont, darkGrey, medGrey, lightGrey, brandColor } from "../../globalStyles";
import Radium from "radium";
import Title from "./title";
import { Link } from "react-router-dom";

var RadiumLink = Radium(Link); // needed to style custom components with radium

@connect((state) => {
  return {
    browserDimensions: state.browserDimensions.browserDimensions
  };
})
@Radium
class TitleBar extends React.Component {
  constructor(props) {
    super(props);
  }
  // static propTypes = {
  //   dataName: React.PropTypes.string
  // }
  static contextTypes = {
    router: React.PropTypes.object.isRequired
  }
  getStyles() {
    return {
      logo: {
        paddingLeft: "8px",
        paddingRight: "8px",
        paddingTop: "20px",
        paddingBottom: "20px",
        color: "#fff",
        textDecoration: "none",
        fontSize: this.props.minified ? 12 : 16
      },
      title: {
        padding: "0px",
        color: "#fff",
        textDecoration: "none",
        fontSize: 20,
        fontWeight: 400
      },
      main: {
        maxWidth: 960,
        margin: "auto",
        height: titleBarHeight,
        justifyContent: "space-between",
        alignItems: "center",
        background: "#4b4e4e",
        marginBottom: 5,
        boxShadow: "1px 1px 2px 1px rgba(215,215,215,0.85)",
        overflow: "hidden"
      },
      link: {
        paddingLeft: this.props.minified ? "6px" : "12px",
        paddingRight: this.props.minified ? "6px" : "12px",
        paddingTop: "20px",
        paddingBottom: "20px",
        color: "#fff",
        textDecoration: "none",
        cursor: "pointer",
        fontSize: this.props.minified ? 12 : 16,
        ':hover': {
          background: "rgba(215,215,215,0.10)"
        }
      },
      inactive: {
        background: "rgba(215,215,215,0.10)",
        paddingLeft: "8px",
        paddingRight: "8px",
        paddingTop: "20px",
        paddingBottom: "20px",
        color: "#fff",
        textDecoration: "none",
        fontSize: this.props.minified ? 12 : 16
      },
      alerts: {
        textAlign: "center",
        verticalAlign: "middle",
        width: 70,
        color: brandColor
      },
      dataName: {
        alignSelf: "center",
        padding: "0px",
        color: "#fff",
        textDecoration: "none",
        fontSize: 20,
        fontWeight: 400
      }
    };
  }

  getLogo(styles) {
    return (
      this.props.logoHidden ?
 :
        <Link style={styles.logo} to="/">

        </Link>
    );
  }

  getTitle(styles) {
    return (
      this.props.titleHidden || this.props.browserDimensions.width < 600 || this.props.minified ?

 :
        <Link style={styles.title} to="/">
          <Title minified={true} style={styles.title}/>
        </Link>
    );
  }

  getDataName(dataName, styles) {
    return (
      this.props.dataNameHidden ?
 :

          {dataName}

    );
  }

  getLink(name, url, selected, styles) {
    return (
      selected ?

{name}
 :
        <RadiumLink style={styles.link} to={url}>{name}</RadiumLink>
    );
  }

  render() {
    const styles = this.getStyles();
    let dataName = this.context.router.location.pathname;
    dataName = dataName.replace(/^\//, '').replace(/\/$/, '');
    if (dataName.length === 1) {dataName = "";}
    return (

        <Flex style={styles.main}>
          {this.getLogo(styles)}
          {this.getTitle(styles)}
          {this.getDataName(dataName, styles)}

          {this.getLink("About", "/about", this.props.aboutSelected, styles)}
          {this.getLink("Methods", "/methods", this.props.methodsSelected, styles)}

        </Flex>

    );
  }
}

export default TitleBar;
<commit_msg>Dark colors for light background<commit_after>import React from "react";
import { connect } from "react-redux";
import Flex from "./flex";
import { titleColors, titleBarHeight } from "../../util/globals";
import { titleFont, dataFont, darkGrey, medGrey, lightGrey, brandColor } from "../../globalStyles";
import Radium from "radium";
import Title from "./title";
import { Link } from "react-router-dom";

var RadiumLink = Radium(Link); // needed to style custom components with radium

@connect((state) => {
  return {
    browserDimensions: state.browserDimensions.browserDimensions
  };
})
@Radium
class TitleBar extends React.Component {
  constructor(props) {
    super(props);
  }
  // static propTypes = {
  //   dataName: React.PropTypes.string
  // }
  static contextTypes = {
    router: React.PropTypes.object.isRequired
  }
  getStyles() {
    return {
      logo: {
        paddingLeft: "8px",
        paddingRight: "8px",
        paddingTop: "20px",
        paddingBottom: "20px",
        color: "#fff",
        textDecoration: "none",
        fontSize: this.props.minified ? 12 : 16
      },
      title: {
        padding: "0px",
        color: "#fff",
        textDecoration: "none",
        fontSize: 20,
        fontWeight: 400
      },
      main: {
        maxWidth: 960,
        margin: "auto",
        height: titleBarHeight,
        justifyContent: "space-between",
        alignItems: "center",
        background: "#fff",
        marginBottom: 5,
        overflow: "hidden"
      },
      link: {
        paddingLeft: this.props.minified ? "6px" : "12px",
        paddingRight: this.props.minified ? "6px" : "12px",
        paddingTop: "20px",
        paddingBottom: "20px",
        color: "black",
        textDecoration: "none",
        cursor: "pointer",
        fontSize: this.props.minified ? 12 : 16,
        ':hover': {
          color: "rgb(80, 151, 186)",
        }
      },
      inactive: {
        paddingLeft: "8px",
        paddingRight: "8px",
        paddingTop: "20px",
        paddingBottom: "20px",
        color: "rgb(80, 151, 186)",
        textDecoration: "none",
        fontSize: this.props.minified ? 12 : 16
      },
      alerts: {
        textAlign: "center",
        verticalAlign: "middle",
        width: 70,
        color: brandColor
      },
      dataName: {
        alignSelf: "center",
        padding: "0px",
        color: "#fff",
        textDecoration: "none",
        fontSize: 20,
        fontWeight: 400
      }
    };
  }

  getLogo(styles) {
    return (
      this.props.logoHidden ?
 :
        <Link style={styles.logo} to="/">

        </Link>
    );
  }

  getTitle(styles) {
    return (
      this.props.titleHidden || this.props.browserDimensions.width < 600 || this.props.minified ?

 :
        <Link style={styles.title} to="/">
          <Title minified={true} style={styles.title}/>
        </Link>
    );
  }

  getDataName(dataName, styles) {
    return (
      this.props.dataNameHidden ?
 :

          {dataName}

    );
  }

  getLink(name, url, selected, styles) {
    return (
      selected ?

{name}
 :
        <RadiumLink style={styles.link} to={url}>{name}</RadiumLink>
    );
  }

  render() {
    const styles = this.getStyles();
    let dataName = this.context.router.location.pathname;
    dataName = dataName.replace(/^\//, '').replace(/\/$/, '');
    if (dataName.length === 1) {dataName = "";}
    return (

        <Flex style={styles.main}>
          {this.getLogo(styles)}
          {this.getTitle(styles)}
          {this.getDataName(dataName, styles)}

          {this.getLink("About", "/about", this.props.aboutSelected, styles)}
          {this.getLink("Methods", "/methods", this.props.methodsSelected, styles)}

        </Flex>

    );
  }
}

export default TitleBar;
<|endoftext|>


<commit_before>import React from 'react'
import styled from 'styled-components'
import { Link } from 'gatsby'
import Img from 'gatsby-image'

const StyledLink = styled(Link)`
  position: relative;
  text-decoration: none;
  div {
    object-fit: cover !important;
    height: 100% !important;
    @media screen and (min-width: 52em) {
      height: 33vh !important;
    }
  }

  h5 {
    margin: 0;
    position: absolute;
    bottom: 1rem;
    left: 1rem;
    z-index: 3;
  }
  &::before {
    transition: all 0.3s;
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    top: 0;
    height: 100%;
    width: 100%;
    z-index: 2;
    background: var(--color-base-50);
  }
  box-shadow: 0px 5px 15px var(--color-secondary-50),
    0px 10px 25px var(--color-secondary-25),
    0px 15px 30px var(--color-secondary-15);
`

const BlogPosts = styled.div`
  display: grid;
  grid-template-columns: 1fr;

  @media screen and (min-width: 52em) {
    grid-template-columns: repeat(2, 1fr);
  }
  h5 {
    margin: 0 0 1rem;
    position: relative;
    bottom: 0;
    left: 0;
    z-index: 3;
  }
  div {
    z-index: 3;
  }
  .copy {
    padding: 1rem;
  }
`

const ContentList = props => {
  return (

  )
}

export default ContentList
<commit_msg>List styling<commit_after>import React from 'react'
import styled from 'styled-components'
import { Link } from 'gatsby'
import Img from 'gatsby-image'

const StyledLink = styled(Link)`
  position: relative;
  text-decoration: none;
  border-radius: 1rem;
  div {
    border-radius: 1rem;
    object-fit: cover !important;
    height: 100% !important;
    @media screen and (min-width: 52em) {
      height: 33vh !important;
    }
  }

  h5 {
    margin: 0;
    position: absolute;
    bottom: 1rem;
    left: 1rem;
    z-index: 3;
  }
  &::before {
    border-radius: 1rem;
    transition: all 0.3s;
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    top: 0;
    height: 100%;
    width: 100%;
    z-index: 2;
    background: var(--color-base-50);
  }

  box-shadow: 0px 5px 15px var(--color-secondary-50),
    0px 10px 25px var(--color-secondary-25),
    0px 15px 30px var(--color-secondary-15);
`

const BlogPosts = styled.div`
  display: grid;
  grid-template-columns: 1fr;
  border-radius: 1rem;
  div {
    border-radius: 1rem 1rem 0 0;
  }
  @media screen and (min-width: 52em) {
    div {
      border-radius: 1rem 0 0 1rem;
    }
    grid-template-columns: repeat(2, 1fr);
  }
  h5 {
    margin: 0 0 1rem;
    position: relative;
    bottom: 0;
    left: 0;
    z-index: 3;
  }
  div {
    z-index: 3;
  }
  .copy {
    padding: 1rem;
  }
`

const ContentList = props => {
  return (

  )
}

export default ContentList
<|endoftext|>


<commit_before>import React, { useRef } from 'react';
import { Box, NumericInput, TextBodyCompact } from '../../';
import theme from './theme.css';

const transformToPaddedNumber = (number) => (number < 10 ? `0${number}` : number.toString());

const DurationInput = ({ value, onChange, onBlur, onFocus, onKeyDown, autoFocus, className }) => {
  const ref = useRef();

  const handleHoursChanged = (_, hours) => {
    if (!onChange) {
      return;
    }

    if (hours === '') {
      onChange({
        minutes: value?.minutes,
      });
    }

    const parsedHours = parseInt(hours);
    if (!Number.isInteger(parsedHours)) {
      return;
    }

    onChange({
      ...value,
      hours: parsedHours,
    });
  };

  const handleMinutesChange = (_, minutes) => {
    if (!onChange) {
      return;
    }

    if (minutes === '') {
      onChange({
        hours: value?.hours,
      });
      return;
    }

    const parsedMinutes = parseInt(minutes);
    if (!Number.isInteger(parsedMinutes)) {
      return;
    }

    if (parsedMinutes >= 60) {
      onChange({
        hours: (value?.hours || 0) + 1,
        minutes: 0,
      });
      return;
    }

    if (parsedMinutes < 0) {
      onChange({
        hours: (value?.hours || 1) - 1,
        minutes: 59,
      });
      return;
    }

    onChange({
      ...value,
      minutes: parsedMinutes,
    });
  };

  /**
   * This blur handler is a special one, because this input consists of multiple focus points:
   * the two inputs themselves, and the four increment/decrement buttons
   * we filter out the blur events caused by changing focus between these, so the onBlur event only
   * gets triggered when really blurring outside of the entire component
   */
  const handleBlur = (event) => {
    if (!event.relatedTarget) {
      onBlur && onBlur(event);
      return;
    }

    const inputs = ref.current?.getElementsByTagName('input') || [];
    if (Array.from(inputs).find((node) => node === event.relatedTarget)) {
      return;
    }

    const buttons = ref.current?.getElementsByTagName('button') || [];
    if (Array.from(buttons).find((node) => node === event.relatedTarget)) {
      return;
    }

    onBlur && onBlur(event);
  };

  let minutes = value?.minutes;
  if (Number.isInteger(minutes)) {
    minutes = transformToPaddedNumber(minutes);
  }

  return (
    <Box display="flex" alignItems="center" ref={ref} className={className}>
      <NumericInput
        placeholder="0"
        min={0}
        value={value?.hours ?? ''}
        onChange={handleHoursChanged}
        onBlur={handleBlur}
        onFocus={onFocus}
        onKeyDown={onKeyDown}
        type="text"
        inputMode="numeric"
        flexGrow={1}
        className={theme['duration-input-numeric-input']}
        autoFocus={autoFocus}
      />
      <TextBodyCompact color="neutral" tint="darkest" className={theme['duration-input-colon']}>
        :
      </TextBodyCompact>
      <NumericInput
        placeholder="00"
        {...(!value?.hours ? { min: 0 } : {})}
        value={minutes ?? ''}
        onChange={handleMinutesChange}
        onBlur={handleBlur}
        onFocus={onFocus}
        onKeyDown={onKeyDown}
        type="text"
        inputMode="numeric"
        flexGrow={1}
        className={theme['duration-input-numeric-input']}
      />
    </Box>
  );
};

export default DurationInput;
<commit_msg>:recycle: don't allow entering numbers bigger than 60<commit_after>import React, { useRef } from 'react';
import { Box, NumericInput, TextBodyCompact } from '../../';
import theme from './theme.css';

const transformToPaddedNumber = (number) => (number < 10 ? `0${number}` : number.toString());

const DurationInput = ({ value, onChange, onBlur, onFocus, onKeyDown, autoFocus, className }) => {
  const ref = useRef();

  const handleHoursChanged = (_, hours) => {
    if (!onChange) {
      return;
    }

    if (hours === '') {
      onChange({
        minutes: value?.minutes,
      });
    }

    const parsedHours = parseInt(hours);
    if (!Number.isInteger(parsedHours)) {
      return;
    }

    onChange({
      ...value,
      hours: parsedHours,
    });
  };

  const handleMinutesChange = (_, minutes) => {
    if (!onChange) {
      return;
    }

    if (minutes === '') {
      onChange({
        hours: value?.hours,
      });
      return;
    }

    const parsedMinutes = parseInt(minutes);
    if (!Number.isInteger(parsedMinutes)) {
      return;
    }

    if (parsedMinutes > 60) {
      return;
    }

    if (parsedMinutes === 60) {
      onChange({
        hours: (value?.hours || 0) + 1,
        minutes: 0,
      });
      return;
    }

    if (parsedMinutes < 0) {
      onChange({
        hours: (value?.hours || 1) - 1,
        minutes: 59,
      });
      return;
    }

    onChange({
      ...value,
      minutes: parsedMinutes,
    });
  };

  /**
   * This blur handler is a special one, because this input consists of multiple focus points:
   * the two inputs themselves, and the four increment/decrement buttons
   * we filter out the blur events caused by changing focus between these, so the onBlur event only
   * gets triggered when really blurring outside of the entire component
   */
  const handleBlur = (event) => {
    if (!event.relatedTarget) {
      onBlur && onBlur(event);
      return;
    }

    const inputs = ref.current?.getElementsByTagName('input') || [];
    if (Array.from(inputs).find((node) => node === event.relatedTarget)) {
      return;
    }

    const buttons = ref.current?.getElementsByTagName('button') || [];
    if (Array.from(buttons).find((node) => node === event.relatedTarget)) {
      return;
    }

    onBlur && onBlur(event);
  };

  let minutes = value?.minutes;
  if (Number.isInteger(minutes)) {
    minutes = transformToPaddedNumber(minutes);
  }

  return (
    <Box display="flex" alignItems="center" ref={ref} className={className}>
      <NumericInput
        placeholder="0"
        min={0}
        value={value?.hours ?? ''}
        onChange={handleHoursChanged}
        onBlur={handleBlur}
        onFocus={onFocus}
        onKeyDown={onKeyDown}
        type="text"
        inputMode="numeric"
        flexGrow={1}
        className={theme['duration-input-numeric-input']}
        autoFocus={autoFocus}
      />
      <TextBodyCompact color="neutral" tint="darkest" className={theme['duration-input-colon']}>
        :
      </TextBodyCompact>
      <NumericInput
        placeholder="00"
        {...(!value?.hours ? { min: 0 } : {})}
        value={minutes ?? ''}
        onChange={handleMinutesChange}
        onBlur={handleBlur}
        onFocus={onFocus}
        onKeyDown={onKeyDown}
        type="text"
        inputMode="numeric"
        flexGrow={1}
        className={theme['duration-input-numeric-input']}
      />
    </Box>
  );
};

export default DurationInput;
<|endoftext|>


<commit_before>'use strict';

function GenericController() {
}

GenericController.prototype.route = function (app) {
    app.options('*', this.handleRequest.bind(this));
};

GenericController.prototype.handleRequest = function(req, res) {
    res.end();
};

module.exports = GenericController;
<commit_msg>ES6 class for generic controller<commit_after>'use strict';

module.exports = class GenericController {
    route (app) {
        app.options('*', (req, res) => res.end());
    }
};
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { withStyles, createStyleSheet } from 'material-ui/styles';
import Button from 'material-ui/Button';
import Dialog from 'material-ui/Dialog';
import List, { ListItem, ListItemText } from 'material-ui/List';
import Divider from 'material-ui/Divider';
import AppBar from 'material-ui/AppBar';
import Toolbar from 'material-ui/Toolbar';
import IconButton from 'material-ui/IconButton';
import Typography from 'material-ui/Typography';
import CloseIcon from 'material-ui-icons/Close';
import Slide from 'material-ui/transitions/Slide';
import Menu, { MenuItem } from 'material-ui/Menu'

import Tabs, { Tab } from 'material-ui/Tabs';
import Paper from 'material-ui/Paper';
import Grid from 'material-ui/Grid';
import RootReducer from './../../redux/RootReducer';

import  InputCell from './InputCell'
import { createStore } from 'redux'
import { Provider, connect } from 'react-redux'

const TabContainer = props =>

    {props.children}

;

const styleSheet = createStyleSheet('FirstDialog', {
  appBar: {
    position: 'relative',
  },
  flex: {
    flex: 1,
  },
   root: {
    flexGrow: 1,
    marginTop: 30,
  },
  paper: {
    padding: 16,
    textAlign: 'center',

  },
});

TabContainer.propTypes = {
  children: PropTypes.node.isRequired,
};

const styleSheet2 = createStyleSheet('BasicTabs', theme => ({
  root: {
    flexGrow: 1,
    marginTop: theme.spacing.unit * 3,
    backgroundColor: theme.palette.background.paper,
  },
}));

class FirstDialog extends Component {
  state = {
    open: false,
    index: 0,
  };

  handleChange = (event, index) => {
    this.setState({ index });
  };

  handleRequestClose = () => {
    this.setState({ open: false });
  };

  handleOpen = () => {
    this.setState({ open: true });
  };

  render() {
    const classes = this.props.classes;
    return (

           <MenuItem onClick={this.handleOpen}>权籍调查表</MenuItem>

        <Dialog
          fullScreen
          open={this.state.open}
          onRequestClose={this.handleRequestClose}
          transition={<Slide direction="up" />}
        >
          <AppBar className={classes.appBar}>

            <Toolbar>
               <Typography type="title" color="inherit" className={classes.flex}>
                 <Tabs index={this.state.index} onChange={this.handleChange}>
            <Tab label="权利信息" />
            <Tab label="宗地信息" />
            <Tab label="使用信息" />
          </Tabs>
              </Typography>
              <Button color="contrast" onClick={this.handleRequestClose}>
                 <IconButton color="contrast" onClick={this.handleRequestClose} aria-label="Close">
                <CloseIcon />
              </IconButton>
              </Button>

            </Toolbar>
          </AppBar>
        {this.state.index === 0 &&
          <TabContainer>
          <Provider store={store}>
    <InputCell />
   </Provider>
            {/* <InputDialog Title="权利人姓名" Tip="此处填写权利人姓名" DefaultValue="Peter"/>
           <InputDialog Title="通信地址" Tip="此处填写权利人通信地址" DefaultValue="武汉市洪山区珞瑜路129号"/>
         <InputDialog Title="权利人身份证号码" Tip="此处填写权利人身份证号码" DefaultValue="100000001"/> */}
          </TabContainer>}
        {this.state.index === 1 &&
          <TabContainer>
            {'Item Two'}
          </TabContainer>}
        {this.state.index === 2 &&
          <TabContainer>
            {'Item Three'}
          </TabContainer>}
        </Dialog>

    );
  }
}

FirstDialog.propTypes = {
  classes: PropTypes.object.isRequired,
};

export default withStyles(styleSheet)(FirstDialog);

// Reducer
function reducer(state = { value:"peter",show:false }, action) {
  const value = state.value
   const show = state.show
  switch (action.type) {
    case 'showInputDialog':
      return { value:value,show:!show }

    case 'completeInput':
     return { value:action.payload.inputValue,show:!show }

    default:
      return state
  }
}

// Store
const store = createStore(reducer);

RootReducer.merge(reducer);<commit_msg>add table but it is very ugly :(<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { withStyles, createStyleSheet } from 'material-ui/styles';
import Button from 'material-ui/Button';
import Dialog from 'material-ui/Dialog';
import List, { ListItem, ListItemText } from 'material-ui/List';
import Divider from 'material-ui/Divider';
import AppBar from 'material-ui/AppBar';
import Toolbar from 'material-ui/Toolbar';
import IconButton from 'material-ui/IconButton';
import Typography from 'material-ui/Typography';
import CloseIcon from 'material-ui-icons/Close';
import Slide from 'material-ui/transitions/Slide';
import Menu, { MenuItem } from 'material-ui/Menu'

import Tabs, { Tab } from 'material-ui/Tabs';
import Paper from 'material-ui/Paper';
import Grid from 'material-ui/Grid';
import RootReducer from './../../redux/RootReducer';

import  InputCell from './InputCell'
import { createStore } from 'redux'
import { Provider, connect } from 'react-redux'

const TabContainer = props =>

    {props.children}

;

const styleSheet = createStyleSheet('FirstDialog', {
  appBar: {
    position: 'relative',
  },
  flex: {
    flex: 1,
  },
   root: {
    flexGrow: 1,
    marginTop: 30,
  },
  paper: {
    padding: 16,
    textAlign: 'center',

  },
  table :{
    width: "100%",
    border:1,
    cellSpacing:1
  }

});

TabContainer.propTypes = {
  children: PropTypes.node.isRequired,
};

const styleSheet2 = createStyleSheet('BasicTabs', theme => ({
  root: {
    flexGrow: 1,
    marginTop: theme.spacing.unit * 3,
    backgroundColor: theme.palette.background.paper,
  },
}));

class FirstDialog extends Component {
  state = {
    open: false,
    index: 0,
  };

  handleChange = (event, index) => {
    this.setState({ index });
  };

  handleRequestClose = () => {
    this.setState({ open: false });
  };

  handleOpen = () => {
    this.setState({ open: true });
  };

  render() {
    const classes = this.props.classes;
    return (

           <MenuItem onClick={this.handleOpen}>权籍调查表</MenuItem>

        <Dialog
          fullScreen
          open={this.state.open}
          onRequestClose={this.handleRequestClose}
          transition={<Slide direction="up" />}
        >
          <AppBar className={classes.appBar}>

            <Toolbar>
               <Typography type="title" color="inherit" className={classes.flex}>
                 <Tabs index={this.state.index} onChange={this.handleChange}>
            <Tab label="权利信息" />
            <Tab label="宗地信息" />
            <Tab label="使用信息" />
          </Tabs>
              </Typography>
              <Button color="contrast" onClick={this.handleRequestClose}>
                 <IconButton color="contrast" onClick={this.handleRequestClose} aria-label="Close">
                <CloseIcon />
              </IconButton>
              </Button>

            </Toolbar>
          </AppBar>
        {this.state.index === 0 &&
          <TabContainer>

宗地基本信息表

权利人

所有权

/

使用权

xxxxxxxxxxxxx

权利人类型

企业

证件种类

营业执照

证件号

xxxxxxx

通讯地址

权利类型

国有建设用地使用权

权利性质

出让

土地权属来源证明材料

坐落

南宁市五象新区云村路南侧、英岭路东侧

法定代表人

      或负责人姓名

赵勇

证件种类

身份证

电话

证件号

xxxxxxxxxxxxxxx

代理人姓名

证件种类

电话

证件号

权利设定方式

地表

国民经济行业

      分类代码

预编宗地代码

宗地代码

450108001206GB00137

不动产单元号

450108001206GB00137W00000000

所在图幅号

比例尺

1:500

图幅号

5100053700,5102553700

          {/* <Provider store={store}>
    <InputCell />
   </Provider>  */}
            {/* <InputDialog Title="权利人姓名" Tip="此处填写权利人姓名" DefaultValue="Peter"/>
           <InputDialog Title="通信地址" Tip="此处填写权利人通信地址" DefaultValue="武汉市洪山区珞瑜路129号"/>
         <InputDialog Title="权利人身份证号码" Tip="此处填写权利人身份证号码" DefaultValue="100000001"/> */}
          </TabContainer>}
        {this.state.index === 1 &&
          <TabContainer>
            {'Item Two'}
          </TabContainer>}
        {this.state.index === 2 &&
          <TabContainer>
            {'Item Three'}
          </TabContainer>}
        </Dialog>

    );
  }
}

FirstDialog.propTypes = {
  classes: PropTypes.object.isRequired,
};

export default withStyles(styleSheet)(FirstDialog);

// Reducer
function reducer(state = { value:"peter",show:false }, action) {
  const value = state.value
   const show = state.show
  switch (action.type) {
    case 'showInputDialog':
      return { value:value,show:!show }

    case 'completeInput':
     return { value:action.payload.inputValue,show:!show }

    default:
      return state
  }
}

// Store
const store = createStore(reducer);

RootReducer.merge(reducer);<|endoftext|>


<commit_before>/* eslint-disable jsx-a11y/no-static-element-interactions */
import Immutable from 'immutable'
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { Link } from 'react-router'
import classNames from 'classnames'
import Mousetrap from 'mousetrap'
import ImageAsset from '../assets/ImageAsset'
import { ElloBuyButton } from '../editor/ElloBuyButton'
import { DismissButtonLGReverse } from '../buttons/Buttons'
import { SHORTCUT_KEYS } from '../../constants/application_types'
import { css, select } from '../../styles/jss'
import * as s from '../../styles/jso'

const STATUS = {
  PENDING: 'isPending',
  REQUEST: 'isRequesting',
  SUCCESS: null,
  FAILURE: 'isFailing',
}

const lightBoxInactiveImageStyle = css(
  s.inline,
  s.relative,
  s.center,
  s.bgcF2,
  select(
    '> .LightBoxMask',
    s.bgcTransparent,
    select(
      '> .LightBox',
      s.relative,
      s.alignTop,
      s.inline,
      select(
        '> .ImageAttachment',
        {
          transform: 'scale(1.0)',
        },
      ),
    ),
  ),
)

const lightBoxImageStyle = css(
  s.block,
  s.relative,
  s.bgcF2,
  { margin: '0 auto' },
  select(
    '> .LightBoxMask',
    s.fullscreen,
    s.fullWidth,
    s.fullHeight,
    s.bgcModal,
    s.zModal,
    { transition: `background-color 0.4s ${s.ease}` },
    select(
      '> .LightBox',
      s.relative,
      s.containedAlignMiddle,
      s.center,
      select(
        '> .ImageAttachment',
      ),
    ),
  ),
)

class ImageRegion extends Component {

  static propTypes = {
    asset: PropTypes.object,
    buyLinkURL: PropTypes.string,
    columnWidth: PropTypes.number,
    commentOffset: PropTypes.number,
    content: PropTypes.object.isRequired,
    contentWidth: PropTypes.number,
    detailPath: PropTypes.string.isRequired,
    isComment: PropTypes.bool,
    isPostBody: PropTypes.bool,
    isPostDetail: PropTypes.bool,
    isGridMode: PropTypes.bool.isRequired,
    isNotification: PropTypes.bool,
    shouldUseVideo: PropTypes.bool.isRequired,
  }

  static defaultProps = {
    asset: null,
    buyLinkURL: null,
    columnWidth: 0,
    commentOffset: 0,
    contentWidth: 0,
    isComment: false,
    isNotification: false,
    isPostBody: true,
    isPostDetail: false,
    isGridMode: false,
  }

  static contextTypes = {
    onTrackRelatedPostClick: PropTypes.func,
  }

  componentWillMount() {
    const { shouldUseVideo } = this.props

    this.state = {
      scale: null,
      currentImageHeight: null,
      currentImageWidth: null,
      measuredImageHeight: null,
      measuredImageWidth: null,
      lightBox: false,
      status: shouldUseVideo ? STATUS.SUCCESS : STATUS.REQUEST,
    }
  }

  shouldComponentUpdate(nextProps, nextState) {
    return !Immutable.is(nextProps.content, this.props.content) ||
      !Immutable.is(nextProps.asset, this.props.asset) ||
      ['buyLinkURL', 'columnWidth', 'contentWidth', 'isGridMode'].some(prop =>
        nextProps[prop] !== this.props[prop],
      ) ||
      ['scale', 'currentImageHeight', 'currentImageWidth', 'lightBox', 'status'].some(prop => nextState[prop] !== this.state[prop])
  }

  onClickStaticImageRegion = () => {
    const { lightBox } = this.state
    const { isPostBody, isPostDetail, isGridMode } = this.props

    if (isPostBody && (isPostDetail || !isGridMode)) {
      if (lightBox) {
        return this.resetImageScale()
      }
      return this.setImageScale()
    }
    return null
  }

  onLoadSuccess = (img) => {
    if (this.isBasicAttachment()) {
      const dimensions = this.getBasicAttachmentDimensions(img)
      this.setState({ width: dimensions.width, height: dimensions.height })
    }
    this.setState({ status: STATUS.SUCCESS })
  }

  onLoadFailure = () => {
    this.setState({ status: STATUS.FAILURE })
  }

  getAttachmentMetadata() {
    if (!this.attachment || this.isBasicAttachment()) { return null }
    const optimized = this.attachment.get('optimized')
    const xhdpi = this.attachment.get('xhdpi')
    const hdpi = this.attachment.get('hdpi')
    let width = null
    let height = null

    // Todo: Not sure if we need to calculate hdpi or if xhdpi will work
    if (optimized.getIn(['metadata', 'width'])) {
      width = Number(optimized.getIn(['metadata', 'width']))
      height = Number(optimized.getIn(['metadata', 'height']))
    } else if (xhdpi.getIn(['metadata', 'width'])) {
      width = Number(xhdpi.getIn(['metadata', 'width']))
      height = Number(xhdpi.getIn(['metadata', 'height']))
    } else if (hdpi.getIn(['metadata', 'width'])) {
      width = Number(hdpi.getIn(['metadata', 'width']))
      height = Number(hdpi.getIn(['metadata', 'height']))
    }
    return {
      width,
      height,
      ratio: width ? width / height : null,
    }
  }

  // Use the lowest of the size constraints to ensure we don't go askew, go
  // below 1:1 pixel density, or go above the desired grid cell height
  getImageDimensions(metadata = this.getAttachmentMetadata()) {
    if (!metadata) { return metadata }
    const { columnWidth, commentOffset, contentWidth, isGridMode, isComment } = this.props
    const { height, ratio } = metadata
    const allowableWidth = isGridMode ? columnWidth : contentWidth
    const widthOffset = isGridMode && isComment ? commentOffset : 0
    const calculatedWidth = allowableWidth - widthOffset
    const maxCellHeight = isGridMode ? 1200 : 7500
    const widthConstrainedRelativeHeight = Math.round(calculatedWidth * (1 / ratio))
    const hv = Math.min(widthConstrainedRelativeHeight, height, maxCellHeight)
    const wv = Math.round(hv * ratio)
    return {
      width: wv,
      height: hv,
      ratio,
    }
  }

  getBasicAttachmentDimensions(img) {
    const height = img.height
    const ratio = img.width / height
    return this.getImageDimensions({ height, ratio })
  }

  getImageSourceSet() {
    const { isGridMode } = this.props
    const images = []
    if (!this.isBasicAttachment()) {
      if (isGridMode) {
        images.push(`${this.attachment.getIn(['mdpi', 'url'])} 375w`)
        images.push(`${this.attachment.getIn(['hdpi', 'url'])} 1920w`)
      } else {
        images.push(`${this.attachment.getIn(['mdpi', 'url'])} 180w`)
        images.push(`${this.attachment.getIn(['hdpi', 'url'])} 750w`)
        images.push(`${this.attachment.getIn(['xhdpi', 'url'])} 1500w`)
        images.push(`${this.attachment.getIn(['optimized', 'url'])} 1920w`)
      }
    }
    return images.join(', ')
  }

  setImageScale() {
    const { measuredImageHeight, measuredImageWidth } = this.state

    const dimensions = this.getImageDimensions()
    let imageHeight = null
    let imageWidth = null

    if (dimensions) {
      imageHeight = dimensions.height
      imageWidth = dimensions.width
    } else {
      const { width, height } = this.state
      imageHeight = height
      imageWidth = width
    }

    const innerHeightPadded = (window.innerHeight - 80)
    const innerWidthPadded = (window.innerWidth - 80)

    const innerRatio = innerWidthPadded / innerHeightPadded
    const imageRatio = imageWidth / imageHeight

    let scale = null

    if (imageRatio < innerRatio) {
      scale = (innerHeightPadded / imageHeight)
    } else {
      scale = (innerWidthPadded / imageWidth)
    }

    this.setState({
      scale,
      currentImageHeight: measuredImageHeight,
      currentImageWidth: measuredImageWidth,
      lightBox: true,
    })

    Mousetrap.bind(SHORTCUT_KEYS.ESC, () => { this.resetImageScale() })
  }

  handleScreenDimensions = (measuredDimensions) => {
    if (measuredDimensions) {
      this.setState({
        measuredImageHeight: measuredDimensions.height,
        measuredImageWidth: measuredDimensions.width,
      })
    }
  }

  resetImageScale() {
    this.setState({
      scale: null,
      lightBox: false,
    })

    setTimeout(() => {
      this.setState({
        currentImageHeight: null,
        currentImageWidth: null,
      })
    }, 100)

    Mousetrap.unbind(SHORTCUT_KEYS.ESC)
  }

  isBasicAttachment() {
    const { asset } = this.props
    return !asset || !asset.get('attachment')
  }

  isGif() {
    return this.attachment.getIn(['optimized', 'metadata', 'type']) === 'image/gif'
  }

  renderGifAttachment() {
    const { content, isNotification, isPostBody, isPostDetail, isGridMode } = this.props
    const { scale } = this.state
    const dimensions = this.getImageDimensions()
    return (
      <ImageAsset
        alt={content.get('alt') ? content.get('alt').replace('.gif', '') : null}
        className="ImageAttachment"
        height={isNotification ? 'auto' : dimensions.height}
        onLoadFailure={this.onLoadFailure}
        onLoadSuccess={this.onLoadSuccess}
        role="presentation"
        isPostBody={isPostBody}
        isPostDetail={isPostDetail}
        isGridMode={isGridMode}
        src={this.attachment.getIn(['optimized', 'url'])}
        width={isNotification ? null : dimensions.width}
        style={{ transform: scale ? `scale(${scale})` : null }}
        screenDimensions={
          isPostBody && (isPostDetail || !isGridMode) ?
            ((measuredDimensions) => { this.handleScreenDimensions(measuredDimensions) }) :
            null
        }
      />
    )
  }

  renderImageAttachment() {
    const { content, isNotification, isPostBody, isPostDetail, isGridMode } = this.props
    const { scale } = this.state
    const srcset = this.getImageSourceSet()
    const dimensions = this.getImageDimensions()
    return (
      <ImageAsset
        alt={content.get('alt') ? content.get('alt').replace('.jpg', '') : null}
        className="ImageAttachment"
        height={isNotification ? 'auto' : dimensions.height}
        onLoadFailure={this.onLoadFailure}
        onLoadSuccess={this.onLoadSuccess}
        role="presentation"
        isPostBody={isPostBody}
        isPostDetail={isPostDetail}
        isGridMode={isGridMode}
        srcSet={srcset}
        src={this.attachment.getIn(['hdpi', 'url'])}
        width={isNotification ? null : dimensions.width}
        style={{ transform: scale ? `scale(${scale})` : null }}
        screenDimensions={
          isPostBody && (isPostDetail || !isGridMode) ?
            ((measuredDimensions) => { this.handleScreenDimensions(measuredDimensions) }) :
            null
        }
      />
    )
  }

  renderLegacyImageAttachment() {
    const { content, isNotification, isPostBody, isPostDetail, isGridMode } = this.props
    const attrs = { src: content.get('url') }
    const { scale, width, height } = this.state
    const stateDimensions = width ? { width, height } : {}
    if (isNotification) {
      attrs.height = 'auto'
    }
    return (
      <ImageAsset
        alt={content.get('alt') ? content.get('alt').replace('.jpg', '') : null}
        className="ImageAttachment"
        onLoadFailure={this.onLoadFailure}
        onLoadSuccess={this.onLoadSuccess}
        role="presentation"
        isPostBody={isPostBody}
        isPostDetail={isPostDetail}
        isGridMode={isGridMode}
        style={{ transform: scale ? `scale(${scale})` : null }}
        screenDimensions={
          isPostBody && (isPostDetail || !isGridMode) ?
            ((measuredDimensions) => { this.handleScreenDimensions(measuredDimensions) }) :
            null
        }
        {...stateDimensions}
        {...attrs}
      />
    )
  }

  renderVideoAttachment() {
    const { height, width } = this.getImageDimensions()
    return (
      <video
        autoPlay
        height={height}
        loop
        muted
        playsInline
        width={width}
      >
        <track kind="captions" />
        <source src={this.attachment.getIn(['video', 'url'])} />
      </video>
    )
  }

  renderAttachment() {
    const { asset, shouldUseVideo } = this.props
    if (!this.isBasicAttachment()) {
      this.attachment = asset.get('attachment')
      if (shouldUseVideo) {
        return this.renderVideoAttachment()
      } else if (this.isGif()) {
        return this.renderGifAttachment()
      }
      return this.renderImageAttachment()
    }
    return this.renderLegacyImageAttachment()
  }

  renderRegionAsLink() {
    const { buyLinkURL, detailPath } = this.props
    return (

        <Link to={detailPath} onClick={this.context.onTrackRelatedPostClick}>
          {this.renderAttachment()}
        </Link>
        {
          buyLinkURL && buyLinkURL.length ?
            <ElloBuyButton to={buyLinkURL} /> :
            null
        }

    )
  }

  renderRegionAsStatic() {
    const { lightBox } = this.state
    const { currentImageHeight, currentImageWidth } = this.state
    const { buyLinkURL } = this.props
    return (
      <div
        className={`${lightBox ? lightBoxImageStyle : lightBoxInactiveImageStyle}`}
        onClick={this.onClickStaticImageRegion}
        style={{ height: currentImageHeight, width: currentImageWidth }}
      >

          {
            lightBox ?
              <DismissButtonLGReverse /> :
              null
          }

            {this.renderAttachment()}
            {
              buyLinkURL && buyLinkURL.length && !lightBox ?
                <ElloBuyButton to={buyLinkURL} /> :
                null
            }

    )
  }

  render() {
    const { isGridMode, detailPath } = this.props
    const { status } = this.state
    const asLink = isGridMode && detailPath
    return (

        {asLink ? this.renderRegionAsLink() : this.renderRegionAsStatic()}

    )
  }
}

export default ImageRegion

<commit_msg>posts - buy button fix for firefox<commit_after>/* eslint-disable jsx-a11y/no-static-element-interactions */
import Immutable from 'immutable'
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { Link } from 'react-router'
import classNames from 'classnames'
import Mousetrap from 'mousetrap'
import ImageAsset from '../assets/ImageAsset'
import { ElloBuyButton } from '../editor/ElloBuyButton'
import { DismissButtonLGReverse } from '../buttons/Buttons'
import { SHORTCUT_KEYS } from '../../constants/application_types'
import { css, select } from '../../styles/jss'
import * as s from '../../styles/jso'

const STATUS = {
  PENDING: 'isPending',
  REQUEST: 'isRequesting',
  SUCCESS: null,
  FAILURE: 'isFailing',
}

const lightBoxInactiveImageStyle = css(
  s.inline,
  s.relative,
  s.center,
  s.bgcF2,
  select(
    '> .LightBoxMask',
    s.bgcTransparent,
    select(
      '> .LightBox',
      s.relative,
      s.alignTop,
      s.inline,
      select(
        '> .ImgHolder',
        s.relative,
        s.inlineBlock,
        select(
          '> .ImageAttachment',
          {
            transform: 'scale(1.0)',
          },
        ),
      ),
    ),
  ),
)

const lightBoxImageStyle = css(
  s.block,
  s.relative,
  s.bgcF2,
  { margin: '0 auto' },
  select(
    '> .LightBoxMask',
    s.fullscreen,
    s.fullWidth,
    s.fullHeight,
    s.bgcModal,
    s.zModal,
    { transition: `background-color 0.4s ${s.ease}` },
    select(
      '> .LightBox',
      s.relative,
      s.containedAlignMiddle,
      s.center,
      select(
        '> .ImageAttachment',
      ),
    ),
  ),
)

class ImageRegion extends Component {

  static propTypes = {
    asset: PropTypes.object,
    buyLinkURL: PropTypes.string,
    columnWidth: PropTypes.number,
    commentOffset: PropTypes.number,
    content: PropTypes.object.isRequired,
    contentWidth: PropTypes.number,
    detailPath: PropTypes.string.isRequired,
    isComment: PropTypes.bool,
    isPostBody: PropTypes.bool,
    isPostDetail: PropTypes.bool,
    isGridMode: PropTypes.bool.isRequired,
    isNotification: PropTypes.bool,
    shouldUseVideo: PropTypes.bool.isRequired,
  }

  static defaultProps = {
    asset: null,
    buyLinkURL: null,
    columnWidth: 0,
    commentOffset: 0,
    contentWidth: 0,
    isComment: false,
    isNotification: false,
    isPostBody: true,
    isPostDetail: false,
    isGridMode: false,
  }

  static contextTypes = {
    onTrackRelatedPostClick: PropTypes.func,
  }

  componentWillMount() {
    const { shouldUseVideo } = this.props

    this.state = {
      scale: null,
      currentImageHeight: null,
      currentImageWidth: null,
      measuredImageHeight: null,
      measuredImageWidth: null,
      lightBox: false,
      status: shouldUseVideo ? STATUS.SUCCESS : STATUS.REQUEST,
    }
  }

  shouldComponentUpdate(nextProps, nextState) {
    return !Immutable.is(nextProps.content, this.props.content) ||
      !Immutable.is(nextProps.asset, this.props.asset) ||
      ['buyLinkURL', 'columnWidth', 'contentWidth', 'isGridMode'].some(prop =>
        nextProps[prop] !== this.props[prop],
      ) ||
      ['scale', 'currentImageHeight', 'currentImageWidth', 'lightBox', 'status'].some(prop => nextState[prop] !== this.state[prop])
  }

  onClickStaticImageRegion = () => {
    const { lightBox } = this.state
    const { isPostBody, isPostDetail, isGridMode } = this.props

    if (isPostBody && (isPostDetail || !isGridMode)) {
      if (lightBox) {
        return this.resetImageScale()
      }
      return this.setImageScale()
    }
    return null
  }

  onLoadSuccess = (img) => {
    if (this.isBasicAttachment()) {
      const dimensions = this.getBasicAttachmentDimensions(img)
      this.setState({ width: dimensions.width, height: dimensions.height })
    }
    this.setState({ status: STATUS.SUCCESS })
  }

  onLoadFailure = () => {
    this.setState({ status: STATUS.FAILURE })
  }

  getAttachmentMetadata() {
    if (!this.attachment || this.isBasicAttachment()) { return null }
    const optimized = this.attachment.get('optimized')
    const xhdpi = this.attachment.get('xhdpi')
    const hdpi = this.attachment.get('hdpi')
    let width = null
    let height = null

    // Todo: Not sure if we need to calculate hdpi or if xhdpi will work
    if (optimized.getIn(['metadata', 'width'])) {
      width = Number(optimized.getIn(['metadata', 'width']))
      height = Number(optimized.getIn(['metadata', 'height']))
    } else if (xhdpi.getIn(['metadata', 'width'])) {
      width = Number(xhdpi.getIn(['metadata', 'width']))
      height = Number(xhdpi.getIn(['metadata', 'height']))
    } else if (hdpi.getIn(['metadata', 'width'])) {
      width = Number(hdpi.getIn(['metadata', 'width']))
      height = Number(hdpi.getIn(['metadata', 'height']))
    }
    return {
      width,
      height,
      ratio: width ? width / height : null,
    }
  }

  // Use the lowest of the size constraints to ensure we don't go askew, go
  // below 1:1 pixel density, or go above the desired grid cell height
  getImageDimensions(metadata = this.getAttachmentMetadata()) {
    if (!metadata) { return metadata }
    const { columnWidth, commentOffset, contentWidth, isGridMode, isComment } = this.props
    const { height, ratio } = metadata
    const allowableWidth = isGridMode ? columnWidth : contentWidth
    const widthOffset = isGridMode && isComment ? commentOffset : 0
    const calculatedWidth = allowableWidth - widthOffset
    const maxCellHeight = isGridMode ? 1200 : 7500
    const widthConstrainedRelativeHeight = Math.round(calculatedWidth * (1 / ratio))
    const hv = Math.min(widthConstrainedRelativeHeight, height, maxCellHeight)
    const wv = Math.round(hv * ratio)
    return {
      width: wv,
      height: hv,
      ratio,
    }
  }

  getBasicAttachmentDimensions(img) {
    const height = img.height
    const ratio = img.width / height
    return this.getImageDimensions({ height, ratio })
  }

  getImageSourceSet() {
    const { isGridMode } = this.props
    const images = []
    if (!this.isBasicAttachment()) {
      if (isGridMode) {
        images.push(`${this.attachment.getIn(['mdpi', 'url'])} 375w`)
        images.push(`${this.attachment.getIn(['hdpi', 'url'])} 1920w`)
      } else {
        images.push(`${this.attachment.getIn(['mdpi', 'url'])} 180w`)
        images.push(`${this.attachment.getIn(['hdpi', 'url'])} 750w`)
        images.push(`${this.attachment.getIn(['xhdpi', 'url'])} 1500w`)
        images.push(`${this.attachment.getIn(['optimized', 'url'])} 1920w`)
      }
    }
    return images.join(', ')
  }

  setImageScale() {
    const { measuredImageHeight, measuredImageWidth } = this.state

    const dimensions = this.getImageDimensions()
    let imageHeight = null
    let imageWidth = null

    if (dimensions) {
      imageHeight = dimensions.height
      imageWidth = dimensions.width
    } else {
      const { width, height } = this.state
      imageHeight = height
      imageWidth = width
    }

    const innerHeightPadded = (window.innerHeight - 80)
    const innerWidthPadded = (window.innerWidth - 80)

    const innerRatio = innerWidthPadded / innerHeightPadded
    const imageRatio = imageWidth / imageHeight

    let scale = null

    if (imageRatio < innerRatio) {
      scale = (innerHeightPadded / imageHeight)
    } else {
      scale = (innerWidthPadded / imageWidth)
    }

    this.setState({
      scale,
      currentImageHeight: measuredImageHeight,
      currentImageWidth: measuredImageWidth,
      lightBox: true,
    })

    Mousetrap.bind(SHORTCUT_KEYS.ESC, () => { this.resetImageScale() })
  }

  handleScreenDimensions = (measuredDimensions) => {
    if (measuredDimensions) {
      this.setState({
        measuredImageHeight: measuredDimensions.height,
        measuredImageWidth: measuredDimensions.width,
      })
    }
  }

  resetImageScale() {
    this.setState({
      scale: null,
      lightBox: false,
    })

    setTimeout(() => {
      this.setState({
        currentImageHeight: null,
        currentImageWidth: null,
      })
    }, 100)

    Mousetrap.unbind(SHORTCUT_KEYS.ESC)
  }

  isBasicAttachment() {
    const { asset } = this.props
    return !asset || !asset.get('attachment')
  }

  isGif() {
    return this.attachment.getIn(['optimized', 'metadata', 'type']) === 'image/gif'
  }

  renderGifAttachment() {
    const { content, isNotification, isPostBody, isPostDetail, isGridMode } = this.props
    const { scale } = this.state
    const dimensions = this.getImageDimensions()
    return (
      <ImageAsset
        alt={content.get('alt') ? content.get('alt').replace('.gif', '') : null}
        className="ImageAttachment"
        height={isNotification ? 'auto' : dimensions.height}
        onLoadFailure={this.onLoadFailure}
        onLoadSuccess={this.onLoadSuccess}
        role="presentation"
        isPostBody={isPostBody}
        isPostDetail={isPostDetail}
        isGridMode={isGridMode}
        src={this.attachment.getIn(['optimized', 'url'])}
        width={isNotification ? null : dimensions.width}
        style={{ transform: scale ? `scale(${scale})` : null }}
        screenDimensions={
          isPostBody && (isPostDetail || !isGridMode) ?
            ((measuredDimensions) => { this.handleScreenDimensions(measuredDimensions) }) :
            null
        }
      />
    )
  }

  renderImageAttachment() {
    const { content, isNotification, isPostBody, isPostDetail, isGridMode } = this.props
    const { scale } = this.state
    const srcset = this.getImageSourceSet()
    const dimensions = this.getImageDimensions()
    return (
      <ImageAsset
        alt={content.get('alt') ? content.get('alt').replace('.jpg', '') : null}
        className="ImageAttachment"
        height={isNotification ? 'auto' : dimensions.height}
        onLoadFailure={this.onLoadFailure}
        onLoadSuccess={this.onLoadSuccess}
        role="presentation"
        isPostBody={isPostBody}
        isPostDetail={isPostDetail}
        isGridMode={isGridMode}
        srcSet={srcset}
        src={this.attachment.getIn(['hdpi', 'url'])}
        width={isNotification ? null : dimensions.width}
        style={{ transform: scale ? `scale(${scale})` : null }}
        screenDimensions={
          isPostBody && (isPostDetail || !isGridMode) ?
            ((measuredDimensions) => { this.handleScreenDimensions(measuredDimensions) }) :
            null
        }
      />
    )
  }

  renderLegacyImageAttachment() {
    const { content, isNotification, isPostBody, isPostDetail, isGridMode } = this.props
    const attrs = { src: content.get('url') }
    const { scale, width, height } = this.state
    const stateDimensions = width ? { width, height } : {}
    if (isNotification) {
      attrs.height = 'auto'
    }
    return (
      <ImageAsset
        alt={content.get('alt') ? content.get('alt').replace('.jpg', '') : null}
        className="ImageAttachment"
        onLoadFailure={this.onLoadFailure}
        onLoadSuccess={this.onLoadSuccess}
        role="presentation"
        isPostBody={isPostBody}
        isPostDetail={isPostDetail}
        isGridMode={isGridMode}
        style={{ transform: scale ? `scale(${scale})` : null }}
        screenDimensions={
          isPostBody && (isPostDetail || !isGridMode) ?
            ((measuredDimensions) => { this.handleScreenDimensions(measuredDimensions) }) :
            null
        }
        {...stateDimensions}
        {...attrs}
      />
    )
  }

  renderVideoAttachment() {
    const { height, width } = this.getImageDimensions()
    return (
      <video
        autoPlay
        height={height}
        loop
        muted
        playsInline
        width={width}
      >
        <track kind="captions" />
        <source src={this.attachment.getIn(['video', 'url'])} />
      </video>
    )
  }

  renderAttachment() {
    const { asset, shouldUseVideo } = this.props
    if (!this.isBasicAttachment()) {
      this.attachment = asset.get('attachment')
      if (shouldUseVideo) {
        return this.renderVideoAttachment()
      } else if (this.isGif()) {
        return this.renderGifAttachment()
      }
      return this.renderImageAttachment()
    }
    return this.renderLegacyImageAttachment()
  }

  renderRegionAsLink() {
    const { buyLinkURL, detailPath } = this.props
    return (

        <Link to={detailPath} onClick={this.context.onTrackRelatedPostClick}>
          {this.renderAttachment()}
        </Link>
        {
          buyLinkURL && buyLinkURL.length ?
            <ElloBuyButton to={buyLinkURL} /> :
            null
        }

    )
  }

  renderRegionAsStatic() {
    const { lightBox } = this.state
    const { currentImageHeight, currentImageWidth } = this.state
    const { buyLinkURL } = this.props
    return (
      <div
        className={`${lightBox ? lightBoxImageStyle : lightBoxInactiveImageStyle}`}
        onClick={this.onClickStaticImageRegion}
        style={{ height: currentImageHeight, width: currentImageWidth }}
      >

          {
            lightBox ?
              <DismissButtonLGReverse /> :
              null
          }

              {this.renderAttachment()}
              {
                buyLinkURL && buyLinkURL.length && !lightBox ?
                  <ElloBuyButton to={buyLinkURL} /> :
                  null
              }

    )
  }

  render() {
    const { isGridMode, detailPath } = this.props
    const { status } = this.state
    const asLink = isGridMode && detailPath
    return (

        {asLink ? this.renderRegionAsLink() : this.renderRegionAsStatic()}

    )
  }
}

export default ImageRegion

<|endoftext|>