<commit_before>'use strict';

import React, { Component } from 'react';
import {
    View,
    Text,
    RefreshControl,
    PanResponder,
    Animated,
    Easing,
    Dimensions,
    ActivityIndicator,
} from 'react-native';

import styles from './style/index.css';

// const padding = 2; //scrollview与外面容器的距离
const pullOkMargin = 100; //下拉到ok状态时topindicator距离顶部的距离
const defaultTopIndicatorHeight = 30; //顶部刷新指示器的高度
const defaultDuration = 300;
const isDownGesture = (x, y) => {
    return y > 0 && (y > Math.abs(x));
};
const isUpGesture = (x, y) => {
    return y < 0 && (Math.abs(x) < Math.abs(y));
};
const isVerticalGesture = (x, y) => {
    return (Math.abs(x) < Math.abs(y));
};

export default class extends Component {
    constructor(props) {
        super(props);
        this.pullable = this.props.refreshControl == null;
        this.defaultScrollEnabled = false; //!(this.props.onPulling || this.props.onPullOk || this.props.onPullRelease); //定义onPull***属性时scrollEnabled为false
        let topIndicatorHeight = this.props.topIndicatorHeight ? this.props.topIndicatorHeight : defaultTopIndicatorHeight;
        this.defaultXY = {x: 0, y: topIndicatorHeight * -1};
        this.pullOkMargin = this.props.pullOkMargin ? this.props.pullOkMargin : pullOkMargin;
        this.duration = this.props.duration ? this.props.duration : defaultDuration;
        this.state = Object.assign({}, props, {
            pullPan: new Animated.ValueXY(this.defaultXY),
            scrollEnabled: this.defaultScrollEnabled,
            height: 0,
            topIndicatorHeight: topIndicatorHeight,
            gesturePosition: {x: 0, y: 0}
        });
        this.onScroll = this.onScroll.bind(this);
        this.onLayout = this.onLayout.bind(this);
        this.isPullState = this.isPullState.bind(this);
        this.resetDefaultXYHandler = this.resetDefaultXYHandler.bind(this);
        this.panResponder = PanResponder.create({
            onStartShouldSetPanResponder: this.onShouldSetPanResponder.bind(this),
            onMoveShouldSetPanResponder: this.onShouldSetPanResponder.bind(this),
            onPanResponderGrant: () => {},
            onPanResponderMove: this.onPanResponderMove.bind(this),
            onPanResponderRelease: this.onPanResponderRelease.bind(this),
            onPanResponderTerminate: this.onPanResponderRelease.bind(this),
        });
    }

    onShouldSetPanResponder(e, gesture) {
        if (!this.pullable || !isVerticalGesture(gesture.dx, gesture.dy)) { //不使用pullable,或非向上 或向下手势不响应
            return false;
        }
        // if (this.props.onPulling || this.props.onPullOk || this.props.onPullRelease) {
        //     return !this.state.scrollEnabled;
        // }
        if (!this.state.scrollEnabled) {
            this.lastY = this.state.pullPan.y._value;
            return true;
        } else {
            return false;
        }
    }

    onPanResponderMove(e, gesture) {
        this.state.gesturePosition = {x: this.defaultXY.x, y: gesture.dy};
        if (isUpGesture(gesture.dx, gesture.dy)) { //向上滑动
            if(this.isPullState()) {
                this.resetDefaultXYHandler()
            } else if(this.props.onPushing && this.props.onPushing(this.state.gesturePosition)) {
                // do nothing, handling by this.props.onPushing
            } else {
                this.scroll.scrollTo({x:0, y: gesture.dy * -1});
            }
            return;
        } else if (isDownGesture(gesture.dx, gesture.dy)) { //下拉
            this.state.pullPan.setValue({x: this.defaultXY.x, y: this.lastY + gesture.dy / 3});
            if (gesture.dy < this.state.topIndicatorHeight + this.pullOkMargin) { //正在下拉
                if (!this.state.pulling) {
                    this.props.onPulling && this.props.onPulling(this.resetDefaultXYHandler);
                }
                this.setState({pulling: true, pullok: false, pullrelease: false});
            } else { //下拉到位
                if (!this.state.pullok) {
                    this.props.onPullOk && this.props.onPullOk(this.resetDefaultXYHandler);
                }
                this.setState({pulling: false, pullok: true, pullrelease: false});
            }
        }
    }

    onPanResponderRelease(e, gesture) {
        if (this.state.pulling) { //没有下拉到位
            this.resetDefaultXYHandler(); //重置状态
        }
        if (this.state.pullok) {
            if (!this.state.pullrelease) {
                if (this.props.onPullRelease) {
                     this.props.onPullRelease(this.resetDefaultXYHandler);
                } else {
                    setTimeout(() => {this.resetDefaultXYHandler()}, 3000);
                }
            }
            this.setState({pulling: false, pullok: false, pullrelease: true}); //完成下拉，已松开
            Animated.timing(this.state.pullPan, {
                toValue: {x: 0, y: 0},
                easing: Easing.linear,
                duration: this.duration
            }).start();
        }
    }

    onScroll(e) {
        if (e.nativeEvent.contentOffset.y <= 0) {
            this.setState({scrollEnabled: this.defaultScrollEnabled});
        } else if(!this.isPullState()) {
            this.setState({scrollEnabled: true});
        }
    }

    isPullState() {
        return this.state.pulling || this.state.pullok || this.state.pullrelease;
    }

    resetDefaultXYHandler() {
        if (this.state.pulling || this.state.pullrelease) {
            this.setState({pulling: false, pullok: false, pullrelease: false});
            this.state.pullPan.setValue(this.defaultXY);
        }
    }

    componentWillUpdate(nextProps, nextState) {
        if (nextProps.isPullEnd && this.state.pullrelease) {
            this.resetDefaultXYHandler();
        }
    }

    onLayout(e) {
        this.setState({width: e.nativeEvent.layout.width});
        this.setState({height: e.nativeEvent.layout.height});
    }

    render() {
        let refreshControl = this.props.refreshControl;
        // if (this.props.refreshControl == null && this.props.refreshing != null && this.props.onRefresh != null) {
        //     refreshControl = <RefreshControl refreshing={this.props.refreshing} onRefresh={this.props.onRefresh} />;
        // }
        let topIndicator;
        if (this.props.topIndicatorRender == null) {
            topIndicator = (
                <View style={{flex: 1, flexDirection: 'row', justifyContent: 'center', alignItems: 'center', height: defaultTopIndicatorHeight}}>
                    <ActivityIndicator size="small" color="gray" />
                    {this.state.pulling ? <Text>下拉刷新...</Text> : null}
                    {this.state.pullok ? <Text>松开刷新......</Text> : null}
                    {this.state.pullrelease ? <Text>玩命刷新中......</Text> : null}
                </View>
            );
        } else {
            let {pulling, pullok, pullrelease} = this.state;
            topIndicator = this.props.topIndicatorRender(pulling, pullok, pullrelease, this.state.gesturePosition);
        }

        return (
            <View style={[styles.wrap, this.props.style]} onLayout={this.onLayout}>
                <Animated.View ref={(c) => {this.ani = c;}} style={[this.state.pullPan.getLayout()]}>
                    {topIndicator}
                    <View {...this.panResponder.panHandlers} style={{width: this.state.width, height: this.state.height}}>
                        {this.getScrollable(refreshControl)}
                    </View>
                </Animated.View>
            </View>
        );
    }
}
<commit_msg>modify onLayout, prevent repeat draw<commit_after>'use strict';

import React, { Component } from 'react';
import {
    View,
    Text,
    RefreshControl,
    PanResponder,
    Animated,
    Easing,
    Dimensions,
    ActivityIndicator,
} from 'react-native';

import styles from './style/index.css';

// const padding = 2; //scrollview与外面容器的距离
const pullOkMargin = 100; //下拉到ok状态时topindicator距离顶部的距离
const defaultTopIndicatorHeight = 30; //顶部刷新指示器的高度
const defaultDuration = 300;
const isDownGesture = (x, y) => {
    return y > 0 && (y > Math.abs(x));
};
const isUpGesture = (x, y) => {
    return y < 0 && (Math.abs(x) < Math.abs(y));
};
const isVerticalGesture = (x, y) => {
    return (Math.abs(x) < Math.abs(y));
};

export default class extends Component {
    constructor(props) {
        super(props);
        this.pullable = this.props.refreshControl == null;
        this.defaultScrollEnabled = false; //!(this.props.onPulling || this.props.onPullOk || this.props.onPullRelease); //定义onPull***属性时scrollEnabled为false
        let topIndicatorHeight = this.props.topIndicatorHeight ? this.props.topIndicatorHeight : defaultTopIndicatorHeight;
        this.defaultXY = {x: 0, y: topIndicatorHeight * -1};
        this.pullOkMargin = this.props.pullOkMargin ? this.props.pullOkMargin : pullOkMargin;
        this.duration = this.props.duration ? this.props.duration : defaultDuration;
        this.state = Object.assign({}, props, {
            pullPan: new Animated.ValueXY(this.defaultXY),
            scrollEnabled: this.defaultScrollEnabled,
            height: 0,
            topIndicatorHeight: topIndicatorHeight,
            gesturePosition: {x: 0, y: 0}
        });
        this.onScroll = this.onScroll.bind(this);
        this.onLayout = this.onLayout.bind(this);
        this.isPullState = this.isPullState.bind(this);
        this.resetDefaultXYHandler = this.resetDefaultXYHandler.bind(this);
        this.panResponder = PanResponder.create({
            onStartShouldSetPanResponder: this.onShouldSetPanResponder.bind(this),
            onMoveShouldSetPanResponder: this.onShouldSetPanResponder.bind(this),
            onPanResponderGrant: () => {},
            onPanResponderMove: this.onPanResponderMove.bind(this),
            onPanResponderRelease: this.onPanResponderRelease.bind(this),
            onPanResponderTerminate: this.onPanResponderRelease.bind(this),
        });
    }

    onShouldSetPanResponder(e, gesture) {
        if (!this.pullable || !isVerticalGesture(gesture.dx, gesture.dy)) { //不使用pullable,或非向上 或向下手势不响应
            return false;
        }
        // if (this.props.onPulling || this.props.onPullOk || this.props.onPullRelease) {
        //     return !this.state.scrollEnabled;
        // }
        if (!this.state.scrollEnabled) {
            this.lastY = this.state.pullPan.y._value;
            return true;
        } else {
            return false;
        }
    }

    onPanResponderMove(e, gesture) {
        this.state.gesturePosition = {x: this.defaultXY.x, y: gesture.dy};
        if (isUpGesture(gesture.dx, gesture.dy)) { //向上滑动
            if(this.isPullState()) {
                this.resetDefaultXYHandler()
            } else if(this.props.onPushing && this.props.onPushing(this.state.gesturePosition)) {
                // do nothing, handling by this.props.onPushing
            } else {
                this.scroll.scrollTo({x:0, y: gesture.dy * -1});
            }
            return;
        } else if (isDownGesture(gesture.dx, gesture.dy)) { //下拉
            this.state.pullPan.setValue({x: this.defaultXY.x, y: this.lastY + gesture.dy / 3});
            if (gesture.dy < this.state.topIndicatorHeight + this.pullOkMargin) { //正在下拉
                if (!this.state.pulling) {
                    this.props.onPulling && this.props.onPulling(this.resetDefaultXYHandler);
                }
                this.setState({pulling: true, pullok: false, pullrelease: false});
            } else { //下拉到位
                if (!this.state.pullok) {
                    this.props.onPullOk && this.props.onPullOk(this.resetDefaultXYHandler);
                }
                this.setState({pulling: false, pullok: true, pullrelease: false});
            }
        }
    }

    onPanResponderRelease(e, gesture) {
        if (this.state.pulling) { //没有下拉到位
            this.resetDefaultXYHandler(); //重置状态
        }
        if (this.state.pullok) {
            if (!this.state.pullrelease) {
                if (this.props.onPullRelease) {
                     this.props.onPullRelease(this.resetDefaultXYHandler);
                } else {
                    setTimeout(() => {this.resetDefaultXYHandler()}, 3000);
                }
            }
            this.setState({pulling: false, pullok: false, pullrelease: true}); //完成下拉，已松开
            Animated.timing(this.state.pullPan, {
                toValue: {x: 0, y: 0},
                easing: Easing.linear,
                duration: this.duration
            }).start();
        }
    }

    onScroll(e) {
        if (e.nativeEvent.contentOffset.y <= 0) {
            this.setState({scrollEnabled: this.defaultScrollEnabled});
        } else if(!this.isPullState()) {
            this.setState({scrollEnabled: true});
        }
    }

    isPullState() {
        return this.state.pulling || this.state.pullok || this.state.pullrelease;
    }

    resetDefaultXYHandler() {
        if (this.state.pulling || this.state.pullrelease) {
            this.setState({pulling: false, pullok: false, pullrelease: false});
            this.state.pullPan.setValue(this.defaultXY);
        }
    }

    componentWillUpdate(nextProps, nextState) {
        if (nextProps.isPullEnd && this.state.pullrelease) {
            this.resetDefaultXYHandler();
        }
    }

    onLayout(e) {
        if (this.state.width != e.nativeEvent.layout.width || this.state.height != e.nativeEvent.layout.height) {
            this.setState({width: e.nativeEvent.layout.width});
            this.setState({height: e.nativeEvent.layout.height});
        }
    }

    render() {
        let refreshControl = this.props.refreshControl;
        // if (this.props.refreshControl == null && this.props.refreshing != null && this.props.onRefresh != null) {
        //     refreshControl = <RefreshControl refreshing={this.props.refreshing} onRefresh={this.props.onRefresh} />;
        // }
        let topIndicator;
        if (this.props.topIndicatorRender == null) {
            topIndicator = (
                <View style={{flex: 1, flexDirection: 'row', justifyContent: 'center', alignItems: 'center', height: defaultTopIndicatorHeight}}>
                    <ActivityIndicator size="small" color="gray" />
                    {this.state.pulling ? <Text>下拉刷新...</Text> : null}
                    {this.state.pullok ? <Text>松开刷新......</Text> : null}
                    {this.state.pullrelease ? <Text>玩命刷新中......</Text> : null}
                </View>
            );
        } else {
            let {pulling, pullok, pullrelease} = this.state;
            topIndicator = this.props.topIndicatorRender(pulling, pullok, pullrelease, this.state.gesturePosition);
        }

        return (
            <View style={[styles.wrap, this.props.style]} onLayout={this.onLayout}>
                <Animated.View ref={(c) => {this.ani = c;}} style={[this.state.pullPan.getLayout()]}>
                    {topIndicator}
                    <View {...this.panResponder.panHandlers} style={{width: this.state.width, height: this.state.height}}>
                        {this.getScrollable(refreshControl)}
                    </View>
                </Animated.View>
            </View>
        );
    }
}
<|endoftext|>


<commit_before>$(function() {
  function setVideoRatio() {
    video = $('#home-video');
    videoRatio = video.width() / video.height();
    video.data('ratio', videoRatio);
  }

  function resizeHomeVideo() {
    video = $('#home-video');
    videoRatio = video.data('ratio');
    container = $('.video-container');
    containerRatio = container.width() / container.height();
    if(containerRatio > videoRatio){ // WIDE
      video.attr('class', 'wide');
    } else { // TALL
      video.attr('class', 'tall');
    }
  }

  video = document.getElementById('home-video');
  if(!$.isEmptyObject(video)){
    video.addEventListener('loadeddata', function() {
      if (video.readyState === 4) {
        setVideoRatio()
        resizeHomeVideo()
        $('#home-video').fadeIn(2000);
      }
    });

    $(window).resize(function() {
      resizeHomeVideo()
    });
  }
})
<commit_msg>use onloadeddata for safari<commit_after>$(function() {
  function setVideoRatio() {
    video = $('#home-video');
    videoRatio = video.width() / video.height();
    video.data('ratio', videoRatio);
  }

  function resizeHomeVideo() {
    video = $('#home-video');
    videoRatio = video.data('ratio');
    container = $('.video-container');
    containerRatio = container.width() / container.height();
    if(containerRatio > videoRatio){ // WIDE
      video.attr('class', 'wide');
    } else { // TALL
      video.attr('class', 'tall');
    }
  }

  video = document.getElementById('home-video');
  if(!$.isEmptyObject(video)){
    video.onloadeddata = function() {
      if (video.readyState === 4) {
        setVideoRatio()
        resizeHomeVideo()
        $('#home-video').fadeIn(2000);
      }
    };

    $(window).resize(function() {
      resizeHomeVideo()
    });
  }
})
<|endoftext|>


<commit_before>import React, { useState, useEffect } from 'react';
import { PropTypes as T } from 'prop-types';
import { connect } from 'react-redux';
import { useHistory, useLocation } from 'react-router-dom';
import qs from 'qs';

import { openDownloadModal } from '../../actions/action-creators';
import config from '../../config';
import { HeaderMessage } from '../../components/header';
import Header from '../../components/header';

import DetailsCard from '../../components/dashboard/details-card';
import NearbyLocations from './nearby-locations';
import LatestMeasurementsCard from '../../components/dashboard/lastest-measurements-card';
import SourcesCard from '../../components/dashboard/sources-card';
import MeasureandsCard from '../../components/dashboard/measurands-card';
import TemporalCoverageCard from '../../components/dashboard/temporal-coverage-card';
import TimeSeriesCard from '../../components/dashboard/time-series-card';
import DateSelector from '../../components/date-selector';

import { buildQS } from '../../utils/url';
import { NO_CITY } from '../../utils/constants';

const defaultState = {
  fetched: false,
  fetching: false,
  error: null,
  data: null,
};

function Location(props) {
  let history = useHistory();
  let location = useLocation();
  const { id } = props.match.params;

  const [dateRange, setDateRange] = useState(
    qs.parse(location.search, { ignoreQueryPrefix: true }).dateRange
  );

  useEffect(() => {
    let query = qs.parse(location.search, {
      ignoreQueryPrefix: true,
    });
    query.dateRange = dateRange;
    history.push(`${location.pathname}?${buildQS(query)}`);
  }, [dateRange]);

  const [{ fetched, fetching, error, data }, setState] = useState(defaultState);

  useEffect(() => {
    const fetchData = id => {
      setState(state => ({ ...state, fetching: true, error: null }));

      fetch(`${config.api}/locations/${encodeURIComponent(id)}`)
        .then(response => {
          if (response.status >= 400) {
            throw new Error('Bad response');
          }
          return response.json();
        })
        .then(
          json => {
            setState(state => ({
              ...state,
              fetched: true,
              fetching: false,
              data: json.results[0],
            }));
          },
          e => {
            console.log('e', e);
            setState(state => ({
              ...state,
              fetched: true,
              fetching: false,
              error: e,
            }));
          }
        );
    };

    fetchData(id);

    return () => {
      setState(defaultState);
    };
  }, [id]);

  if (!fetched && !fetching) {
    return null;
  }

  if (fetching) {
    return (
      <HeaderMessage>

Take a deep breath.

Location data is loading...

      </HeaderMessage>
    );
  }

  if (error || !data) {
    return (
      <HeaderMessage>

Uh oh, something went wrong.

            There was a problem getting the data. If you continue to have
            problems, please let us know.

              Send us an Email

      </HeaderMessage>
    );
  }

  function onDownloadClick() {
    props._openDownloadModal({
      country: data.country,
      area: data.city,
      location: data.location,
    });
  }

  //
  // Lifecycle stage of different sources.
  const lifecycle = (data.sources || [])
    .map(s => s.lifecycle_stage)
    .filter(Boolean);

  return (

      <Header
        tagline="Location"
        title={data.name}
        subtitle={`in ${data.city || NO_CITY}, ${data.country}`}
        action={{
          api: `${config.apiDocs}`,
          download: onDownloadClick,
          compare: `/compare/${encodeURIComponent(data.id)}`,
        }}
        sourceType={data.sensorType}
        isMobile={data.isMobile}
      />

        <DateSelector setDateRange={setDateRange} dateRange={dateRange} />

          <DetailsCard
            measurements={data.measurements}
            lifecycle={lifecycle}
            coords={{
              lat: data.coordinates.latitude,
              lng: data.coordinates.longitude,
            }}
            date={{
              start: data.firstUpdated,
              end: data.lastUpdated,
            }}
          />
          <LatestMeasurementsCard parameters={data.parameters} />
          <SourcesCard sources={data.sources} />
          <TimeSeriesCard
            locationId={data.id}
            parameters={data.parameters}
            xUnit="day"
            dateRange={dateRange}
            titleInfo={
              'The value of a pollutant over time during the specified window. While locations have varying time intervals over which they report, all time series charts show data at the same intervals. For one day or one month of data the hourly average is shown. For the project lifetime the daily averages are shown for the most recent week of data.'
            }
          />
          <TemporalCoverageCard
            parameters={data.parameters}
            spatial="location"
            id={data.id}
            dateRange={dateRange}
            titleInfo={
              'The average number of measurements for each pollutant by hour, day, or month. In some views a window may be turned off if that view is not applicable to the selected time window.'
            }
            isMobile={data.isMobile}
          />
          <MeasureandsCard
            parameters={data.parameters}
            titleInfo={
              'The average of all values and total number of measurements for each pollutant during the chosen time window.'
            }
          />

        <NearbyLocations
          locationId={data.id}
          center={[data.coordinates.longitude, data.coordinates.latitude]}
          city={data.city || NO_CITY}
          country={data.country}
          parameters={data.parameters}
          initialActiveParameter={data.parameters[0]}
        />

  );
}

Location.propTypes = {
  match: T.object,
  _openDownloadModal: T.func,
  sources: T.array,
  measurements: T.array,
  parameters: T.array,
};

// /////////////////////////////////////////////////////////////////// //
// Connect functions

function selector(state) {
  return {
    parameters: state.baseData.data.parameters,
    sources: state.baseData.data.sources,
    measurements: state.measurements,
    latestMeasurements: state.latestMeasurements,
  };
}

function dispatcher(dispatch) {
  return {
    _openDownloadModal: (...args) => dispatch(openDownloadModal(...args)),
  };
}

export default connect(selector, dispatcher)(Location);
<commit_msg>Remove unused selector from location page<commit_after>import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import qs from 'qs';

import { openDownloadModal as openDownloadModalAction } from '../../actions/action-creators';
import config from '../../config';
import { HeaderMessage } from '../../components/header';
import Header from '../../components/header';

import DetailsCard from '../../components/dashboard/details-card';
import NearbyLocations from './nearby-locations';
import LatestMeasurementsCard from '../../components/dashboard/lastest-measurements-card';
import SourcesCard from '../../components/dashboard/sources-card';
import MeasureandsCard from '../../components/dashboard/measurands-card';
import TemporalCoverageCard from '../../components/dashboard/temporal-coverage-card';
import TimeSeriesCard from '../../components/dashboard/time-series-card';
import DateSelector from '../../components/date-selector';

import { buildQS } from '../../utils/url';
import { NO_CITY } from '../../utils/constants';

const defaultState = {
  fetched: false,
  fetching: false,
  error: null,
  data: null,
};

function Location({ location, history, match, openDownloadModal }) {
  const { id } = match.params;

  const [dateRange, setDateRange] = useState(
    qs.parse(location.search, { ignoreQueryPrefix: true }).dateRange
  );

  useEffect(() => {
    let query = qs.parse(location.search, {
      ignoreQueryPrefix: true,
    });
    query.dateRange = dateRange;
    history.push(`${location.pathname}?${buildQS(query)}`);
  }, [dateRange]);

  const [{ fetched, fetching, error, data }, setState] = useState(defaultState);

  useEffect(() => {
    const fetchData = id => {
      setState(state => ({ ...state, fetching: true, error: null }));

      fetch(`${config.api}/locations/${encodeURIComponent(id)}`)
        .then(response => {
          if (response.status >= 400) {
            throw new Error('Bad response');
          }
          return response.json();
        })
        .then(
          json => {
            setState(state => ({
              ...state,
              fetched: true,
              fetching: false,
              data: json.results[0],
            }));
          },
          e => {
            console.log('e', e);
            setState(state => ({
              ...state,
              fetched: true,
              fetching: false,
              error: e,
            }));
          }
        );
    };

    fetchData(id);

    return () => {
      setState(defaultState);
    };
  }, [id]);

  if (!fetched && !fetching) {
    return null;
  }

  if (fetching) {
    return (
      <HeaderMessage>

Take a deep breath.

Location data is loading...

      </HeaderMessage>
    );
  }

  if (error || !data) {
    return (
      <HeaderMessage>

Uh oh, something went wrong.

            There was a problem getting the data. If you continue to have
            problems, please let us know.

              Send us an Email

      </HeaderMessage>
    );
  }

  function onDownloadClick() {
    openDownloadModal({
      country: data.country,
      area: data.city,
      location: data.location,
    });
  }

  //
  // Lifecycle stage of different sources.
  const lifecycle = (data.sources || [])
    .map(s => s.lifecycle_stage)
    .filter(Boolean);

  return (

      <Header
        tagline="Location"
        title={data.name}
        subtitle={`in ${data.city || NO_CITY}, ${data.country}`}
        action={{
          api: `${config.apiDocs}`,
          download: onDownloadClick,
          compare: `/compare/${encodeURIComponent(data.id)}`,
        }}
        sourceType={data.sensorType}
        isMobile={data.isMobile}
      />

        <DateSelector setDateRange={setDateRange} dateRange={dateRange} />

          <DetailsCard
            measurements={data.measurements}
            lifecycle={lifecycle}
            coords={{
              lat: data.coordinates.latitude,
              lng: data.coordinates.longitude,
            }}
            date={{
              start: data.firstUpdated,
              end: data.lastUpdated,
            }}
          />
          <LatestMeasurementsCard parameters={data.parameters} />
          <SourcesCard sources={data.sources} />
          <TimeSeriesCard
            locationId={data.id}
            parameters={data.parameters}
            xUnit="day"
            dateRange={dateRange}
            titleInfo={
              'The value of a pollutant over time during the specified window. While locations have varying time intervals over which they report, all time series charts show data at the same intervals. For one day or one month of data the hourly average is shown. For the project lifetime the daily averages are shown for the most recent week of data.'
            }
          />
          <TemporalCoverageCard
            parameters={data.parameters}
            spatial="location"
            id={data.id}
            dateRange={dateRange}
            titleInfo={
              'The average number of measurements for each pollutant by hour, day, or month. In some views a window may be turned off if that view is not applicable to the selected time window.'
            }
            isMobile={data.isMobile}
          />
          <MeasureandsCard
            parameters={data.parameters}
            titleInfo={
              'The average of all values and total number of measurements for each pollutant during the chosen time window.'
            }
          />

        <NearbyLocations
          locationId={data.id}
          center={[data.coordinates.longitude, data.coordinates.latitude]}
          city={data.city || NO_CITY}
          country={data.country}
          parameters={data.parameters}
          initialActiveParameter={data.parameters[0]}
        />

  );
}

Location.propTypes = {
  location: PropTypes.object.isRequired,
  history: PropTypes.object.isRequired,
  match: PropTypes.object.isRequired,

  openDownloadModal: PropTypes.func.isRequired,
};

// /////////////////////////////////////////////////////////////////// //
// Connect functions

function dispatcher(dispatch) {
  return {
    openDownloadModal: (...args) => dispatch(openDownloadModalAction(...args)),
  };
}

export default connect(null, dispatcher)(Location);
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

define(function (require, exports) {
    "use strict";

    var _ = require("lodash");

    var PlayObject = require("../playObject"),
        referenceBy = require("./reference").wrapper("layer"),
        referenceOf = require("./reference").refersTo,
        inUnits = require("./unit"),
        color = require("./color"),
        assert = require("../util").assert;

    /**
     * Generically build a PlayObject for a layerEffect
     * The layerEffectValue parameter should be a fully constructed object that can be supplied to the "to._value"
     * property of the descriptor.
     *
     * @private
     * @param {ActionDescriptor} ref layer(s) reference
     * @param {string} layerEffectType type of layerEffect (example: dropShadow)
     * @param {object} layerEffectValue object that can be supplied for "to._value" in the descriptor
     * @param {boolean=} multi value that allows function to return the Multi Layer Effect friendly descriptor
     *
     * @return {PlayObject}
     */
    var _layerEffectDescriptor = function (ref, layerEffectType, layerEffectValue, multi) {
        var val = {};

        if (multi) {
            val[layerEffectType] = layerEffectValue;
        } else {
            val[layerEffectType] = {
                _obj: layerEffectType,
                _value: layerEffectValue
            };
        }

        return new PlayObject(
            "set",
            {
                "null": {
                    "_ref": [
                        {
                            "_property": "layerEffects",
                            "_ref": "property"
                        },
                        ref
                    ]
                },
                "to": {
                    "_obj": "layerEffects",
                    "_value": val
                }
            }
        );
    };

    /**
     * Generically build an PlayObject for a layerEffect which uses the useExtendedReference option
     * The layerEffectValue parameter should be a fully constructed object that can be supplied to the "to._value"
     * property of the descriptor.
     *
     * @private
     * @param {ActionDescriptor} ref layer(s) reference
     * @param {string} layerEffectType type of layerEffect (example: dropShadow)
     * @param {object} layerEffectValue object that can be supplied for "to._value" in the descriptor
     *
     * @return {PlayObject}
     */

    var _extendedLayerEffectDescriptor = function (ref, layerEffectType, layerEffectValue) {
        return new PlayObject(
            "set",
            {
                "null": {
                    "_ref": [
                        {
                            _ref: null,
                            "_property": layerEffectType
                        },
                        {
                            "_property": "layerEffects",
                            "_ref": "property"
                        },
                        ref
                    ]
                },
                "to": layerEffectValue
            },
            {
                useExtendedReference: true
            }
        );
    };
    /**
     * Helper Function to set blend mode correctly. We should have a blend mode object in the future
     *
     * @param {string} mode the blend mode
     * @return {object} the PS friendly blend mode object
     */
    var _blendMode = function (mode) {
        return {
            _enum: "blendMode",
            _value: mode
        };
    };

    /**
     * Parse Shadow JS properties and assign units to make them acceptable to PS
     *
     * The expected format of the properties object is like:
     * {enabled: true, color: {r: 255, g: 0, b: 0}, blur: 20}
     * Distance/positions values in pixels
     * Angles in degrees
     * Opacity percentage [0,100]
     *
     * @private
     * @param {object} properties intermediate object format using Photoshop names, but without units
     *
     * @return {object} PS friendly Properties
     */
    var _shadowProperties = function (properties) {
        var layerEffectPsProperties = {
            enabled: properties.enabled === undefined ? true : properties.enabled,
            useGlobalAngle: properties.useGlobalAngle === undefined ? true : properties.useGlobalAngle
        };

        if (_.isObject(properties.color)) {
            layerEffectPsProperties.color = color.colorObject(properties.color);
        }
        if (_.isNumber(properties.opacity)) {
            layerEffectPsProperties.opacity = inUnits.percent(properties.opacity);
        }
        if (_.isNumber(properties.chokeMatte)) {
            layerEffectPsProperties.chokeMatte = inUnits.pixels(properties.chokeMatte);
        }
        if (_.isNumber(properties.blur)) {
            layerEffectPsProperties.blur = inUnits.pixels(properties.blur);
        }
        if (_.isNumber(properties.localLightingAngle)) {
            layerEffectPsProperties.localLightingAngle = inUnits.degrees(properties.localLightingAngle);
        }
        if (_.isNumber(properties.distance)) {
            layerEffectPsProperties.distance = inUnits.pixels(properties.distance);
        }
        if (_.isString(properties.blendMode)) {
            layerEffectPsProperties.mode = _blendMode(properties.blendMode);
        }
        return layerEffectPsProperties;
    };

    /**
     * Return drop shadow descriptor for the given properties
     *
     * The expected format of the properties object is like:
     * {enabled: true, color: {r: 255, g: 0, b: 0}, blur: 20}
     * Distance/positions values in pixels
     * Angles in degrees
     * Opacity percentage [0,100]
     *
     * @private
     * @param {object} properties intermediate object format using Photoshop names, but without units
     *
     * @return {Descriptor}
     */

    var _dropShadowDescriptor = function (properties) {
        return {
            "_obj": "dropShadow",
            "_value": _shadowProperties(properties)
        };
    };

    /**
     * Return inner shadow descriptor for the given properties
     *
     * The expected format of the properties object is like:
     * {enabled: true, color: {r: 255, g: 0, b: 0}, blur: 20}
     * Distance/positions values in pixels
     * Angles in degrees
     * Opacity percentage [0,100]
     *
     * @private
     * @param {object} properties intermediate object format using Photoshop names, but without units
     *
     * @return {Descriptor}
     */

    var _innerShadowDescriptor = function (properties) {
        return {
            "_obj": "innerShadow",
            "_value": _shadowProperties(properties)
        };
    };
    /**
     * Update multiple drop shadow layer effect properties for the given layer(s)
     *
     * @param {ActionDescriptor} ref - Reference of layer(s) to update
     * @param {Array.<object>} propertyArray Array of DropShadow properties
     *
     * @return {PlayObject}
     */
    var _setDropShadows = function (ref, propertyArray) {
        assert(referenceOf(ref) === "layer", "setDropShadow is passed a non-layer reference");

        var descriptorArray = propertyArray.map(function (properties) {
            return _dropShadowDescriptor(properties);
        });

        return _layerEffectDescriptor(ref, "dropShadowMulti", descriptorArray, true);
    };

    /**
     * Update multiple drop shadow layer effect properties for the given layer(s) without changing the
     * parent layer effect
     *
     * @param {ActionDescriptor} ref - Reference of layer(s) to update
     * @param {Array.<object>} propertyArray Array of DropShadow properties
     *
     * @return {PlayObject}
     */
    var _setExtendedDropShadows = function (ref, propertyArray) {
        assert(referenceOf(ref) === "layer", "setDropShadow is passed a non-layer reference");

        var descriptorArray = propertyArray.map(function (properties) {
            return _dropShadowDescriptor(properties);
        });

        return _extendedLayerEffectDescriptor(ref, "dropShadowMulti", descriptorArray, true);
    };

    /**
     * Update multiple inner shadow layer effect properties for the given layer(s)
     *
     * @param {ActionDescriptor} ref - Reference of layer(s) to update
     * @param {Array.<object>} propertyArray Array of InnerShadow properties
     *
     * @return {PlayObject}
     */
    var _setInnerShadows = function (ref, propertyArray) {
        assert(referenceOf(ref) === "layer", "setInnnerShadow is passed a non-layer reference");

        var descriptorArray = propertyArray.map(function (properties) {
            return _innerShadowDescriptor(properties);
        });

        return _layerEffectDescriptor(ref, "innerShadowMulti", descriptorArray, true);
    };

    /**
     * Update multiple inner shadow layer effect properties for the given layer(s) without changing the
     * parent layer effect
     *
     * @param {ActionDescriptor} ref - Reference of layer(s) to update
     * @param {Array.<object>} propertyArray Array of InnerShadow properties
     *
     * @return {PlayObject}
     */
    var _setExtendedInnerShadows = function (ref, propertyArray) {
        assert(referenceOf(ref) === "layer", "setInnnerShadow is passed a non-layer reference");

        var descriptorArray = propertyArray.map(function (properties) {
            return _innerShadowDescriptor(properties);
        });

        return _extendedLayerEffectDescriptor(ref, "innerShadowMulti", descriptorArray, true);
    };

    /**
     * Update the given type of layer effect properties for the given layer(s)
     *
     * @param {string} type - type of layer effect. currently "dropShadow" or "innerShadow"
     * @param {ActionDescriptor} ref - Reference of layer(s) to update
     * @param {Array.<object>} propertyArray Array of InnerShadow properties
     *
     * @return {PlayObject}
     */
    var setLayerEffect = function (type, ref, propertyArray) {
        if (type === "innerShadow") {
            return _setInnerShadows(ref, propertyArray);
        } else if (type === "dropShadow") {
            return _setDropShadows(ref, propertyArray);
        }
    };

    /**
     * Update the given type of layer effect properties for the given layer(s) without changing the
     * parent layer effect
     *
     * @param {string} type - type of layer effect. currently "dropShadow" or "innerShadow"
     * @param {ActionDescriptor} ref - Reference of layer(s) to update
     * @param {Array.<object>} propertyArray Array of InnerShadow properties
     *
     * @return {PlayObject}
     */
    var setExtendedLayerEffect = function (type, ref, propertyArray) {
        if (type === "innerShadow") {
            return _setExtendedInnerShadows(ref, propertyArray);
        } else if (type === "dropShadow") {
            return _setExtendedDropShadows(ref, propertyArray);
        }
    };

    exports.referenceBy = referenceBy;

    exports.setLayerEffect = setLayerEffect;
    exports.setExtendedLayerEffect = setExtendedLayerEffect;
});
<commit_msg>When deleting all effects, keep a hidden effect in Photoshop so that it won't break.<commit_after>/*
 * Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

define(function (require, exports) {
    "use strict";

    var _ = require("lodash");

    var PlayObject = require("../playObject"),
        referenceBy = require("./reference").wrapper("layer"),
        referenceOf = require("./reference").refersTo,
        inUnits = require("./unit"),
        color = require("./color"),
        assert = require("../util").assert;

    /**
     * Generically build a PlayObject for a layerEffect
     * The layerEffectValue parameter should be a fully constructed object that can be supplied to the "to._value"
     * property of the descriptor.
     *
     * @private
     * @param {ActionDescriptor} ref layer(s) reference
     * @param {string} layerEffectType type of layerEffect (example: dropShadow)
     * @param {object} layerEffectValue object that can be supplied for "to._value" in the descriptor
     * @param {boolean=} multi value that allows function to return the Multi Layer Effect friendly descriptor
     *
     * @return {PlayObject}
     */
    var _layerEffectDescriptor = function (ref, layerEffectType, layerEffectValue, multi) {
        var val = {};

        if (multi) {
            val[layerEffectType] = layerEffectValue;
        } else {
            val[layerEffectType] = {
                _obj: layerEffectType,
                _value: layerEffectValue
            };
        }

        return new PlayObject(
            "set",
            {
                "null": {
                    "_ref": [
                        {
                            "_property": "layerEffects",
                            "_ref": "property"
                        },
                        ref
                    ]
                },
                "to": {
                    "_obj": "layerEffects",
                    "_value": val
                }
            }
        );
    };

    /**
     * Generically build an PlayObject for a layerEffect which uses the useExtendedReference option
     * The layerEffectValue parameter should be a fully constructed object that can be supplied to the "to._value"
     * property of the descriptor.
     *
     * @private
     * @param {ActionDescriptor} ref layer(s) reference
     * @param {string} layerEffectType type of layerEffect (example: dropShadow)
     * @param {object} layerEffectValue object that can be supplied for "to._value" in the descriptor
     *
     * @return {PlayObject}
     */

    var _extendedLayerEffectDescriptor = function (ref, layerEffectType, layerEffectValue) {
        return new PlayObject(
            "set",
            {
                "null": {
                    "_ref": [
                        {
                            _ref: null,
                            "_property": layerEffectType
                        },
                        {
                            "_property": "layerEffects",
                            "_ref": "property"
                        },
                        ref
                    ]
                },
                "to": layerEffectValue
            },
            {
                useExtendedReference: true
            }
        );
    };
    /**
     * Helper Function to set blend mode correctly. We should have a blend mode object in the future
     *
     * @param {string} mode the blend mode
     * @return {object} the PS friendly blend mode object
     */
    var _blendMode = function (mode) {
        return {
            _enum: "blendMode",
            _value: mode
        };
    };

    /**
     * Parse Shadow JS properties and assign units to make them acceptable to PS
     *
     * The expected format of the properties object is like:
     * {enabled: true, color: {r: 255, g: 0, b: 0}, blur: 20}
     * Distance/positions values in pixels
     * Angles in degrees
     * Opacity percentage [0,100]
     *
     * @private
     * @param {object} properties intermediate object format using Photoshop names, but without units
     *
     * @return {object} PS friendly Properties
     */
    var _shadowProperties = function (properties) {
        var layerEffectPsProperties = {
            enabled: properties.enabled === undefined ? true : properties.enabled,
            useGlobalAngle: properties.useGlobalAngle === undefined ? true : properties.useGlobalAngle
        };

        if (_.isObject(properties.color)) {
            layerEffectPsProperties.color = color.colorObject(properties.color);
        }
        if (_.isNumber(properties.opacity)) {
            layerEffectPsProperties.opacity = inUnits.percent(properties.opacity);
        }
        if (_.isNumber(properties.chokeMatte)) {
            layerEffectPsProperties.chokeMatte = inUnits.pixels(properties.chokeMatte);
        }
        if (_.isNumber(properties.blur)) {
            layerEffectPsProperties.blur = inUnits.pixels(properties.blur);
        }
        if (_.isNumber(properties.localLightingAngle)) {
            layerEffectPsProperties.localLightingAngle = inUnits.degrees(properties.localLightingAngle);
        }
        if (_.isNumber(properties.distance)) {
            layerEffectPsProperties.distance = inUnits.pixels(properties.distance);
        }
        if (_.isString(properties.blendMode)) {
            layerEffectPsProperties.mode = _blendMode(properties.blendMode);
        }
        return layerEffectPsProperties;
    };

    /**
     * Return drop shadow descriptor for the given properties
     *
     * The expected format of the properties object is like:
     * {enabled: true, color: {r: 255, g: 0, b: 0}, blur: 20}
     * Distance/positions values in pixels
     * Angles in degrees
     * Opacity percentage [0,100]
     *
     * @private
     * @param {object} properties intermediate object format using Photoshop names, but without units
     *
     * @return {Descriptor}
     */

    var _dropShadowDescriptor = function (properties) {
        return {
            "_obj": "dropShadow",
            "_value": _shadowProperties(properties)
        };
    };

    /**
     * Return inner shadow descriptor for the given properties
     *
     * The expected format of the properties object is like:
     * {enabled: true, color: {r: 255, g: 0, b: 0}, blur: 20}
     * Distance/positions values in pixels
     * Angles in degrees
     * Opacity percentage [0,100]
     *
     * @private
     * @param {object} properties intermediate object format using Photoshop names, but without units
     *
     * @return {Descriptor}
     */

    var _innerShadowDescriptor = function (properties) {
        return {
            "_obj": "innerShadow",
            "_value": _shadowProperties(properties)
        };
    };
    /**
     * Update multiple drop shadow layer effect properties for the given layer(s)
     *
     * @param {ActionDescriptor} ref - Reference of layer(s) to update
     * @param {Array.<object>} propertyArray Array of DropShadow properties
     *
     * @return {PlayObject}
     */
    var _setDropShadows = function (ref, propertyArray) {
        assert(referenceOf(ref) === "layer", "setDropShadow is passed a non-layer reference");

        var descriptorArray = propertyArray.map(function (properties) {
            return _dropShadowDescriptor(properties);
        });

        return _layerEffectDescriptor(ref, "dropShadowMulti", descriptorArray, true);
    };

    /**
     * Update multiple drop shadow layer effect properties for the given layer(s) without changing the
     * parent layer effect
     *
     * @param {ActionDescriptor} ref - Reference of layer(s) to update
     * @param {Array.<object>} propertyArray Array of DropShadow properties
     *
     * @return {PlayObject}
     */
    var _setExtendedDropShadows = function (ref, propertyArray) {
        assert(referenceOf(ref) === "layer", "setDropShadow is passed a non-layer reference");

        var descriptorArray = propertyArray.map(function (properties) {
            return _dropShadowDescriptor(properties);
        });

        return _extendedLayerEffectDescriptor(ref, "dropShadowMulti", descriptorArray, true);
    };

    /**
     * Update multiple inner shadow layer effect properties for the given layer(s)
     *
     * @param {ActionDescriptor} ref - Reference of layer(s) to update
     * @param {Array.<object>} propertyArray Array of InnerShadow properties
     *
     * @return {PlayObject}
     */
    var _setInnerShadows = function (ref, propertyArray) {
        assert(referenceOf(ref) === "layer", "setInnnerShadow is passed a non-layer reference");

        var descriptorArray = propertyArray.map(function (properties) {
            return _innerShadowDescriptor(properties);
        });

        return _layerEffectDescriptor(ref, "innerShadowMulti", descriptorArray, true);
    };

    /**
     * Update multiple inner shadow layer effect properties for the given layer(s) without changing the
     * parent layer effect
     *
     * @param {ActionDescriptor} ref - Reference of layer(s) to update
     * @param {Array.<object>} propertyArray Array of InnerShadow properties
     *
     * @return {PlayObject}
     */
    var _setExtendedInnerShadows = function (ref, propertyArray) {
        assert(referenceOf(ref) === "layer", "setInnnerShadow is passed a non-layer reference");

        var descriptorArray = propertyArray.map(function (properties) {
            return _innerShadowDescriptor(properties);
        });

        return _extendedLayerEffectDescriptor(ref, "innerShadowMulti", descriptorArray, true);
    };

    /**
     * Update the given type of layer effect properties for the given layer(s)
     *
     * @param {string} type - type of layer effect. currently "dropShadow" or "innerShadow"
     * @param {ActionDescriptor} ref - Reference of layer(s) to update
     * @param {Array.<object>} propertyArray Array of InnerShadow properties
     *
     * @return {PlayObject}
     */
    var setLayerEffect = function (type, ref, propertyArray) {
        if (type === "innerShadow") {
            return _setInnerShadows(ref, propertyArray);
        } else if (type === "dropShadow") {
            return _setDropShadows(ref, propertyArray);
        }
    };

    var HIDDEN_LAYER_EFFECT_PROPERTIES = { "enabled": false, "present": false };
    /**
     * Update the given type of layer effect properties for the given layer(s) without changing the
     * parent layer effect
     *
     * @param {string} type - type of layer effect. currently "dropShadow" or "innerShadow"
     * @param {ActionDescriptor} ref - Reference of layer(s) to update
     * @param {Array.<object>} propertyArray Array of InnerShadow properties. Passing an emptry arrary
     * will remove all effects of the type.
     *
     * @return {PlayObject}
     */
    var setExtendedLayerEffect = function (type, ref, propertyArray) {
        if (propertyArray.length === 0) {
            // when deleting all effects, keep a hidden effect in Photoshop so that it won't break.
            propertyArray.push(HIDDEN_LAYER_EFFECT_PROPERTIES);
        }

        if (type === "innerShadow") {
            return _setExtendedInnerShadows(ref, propertyArray);
        } else if (type === "dropShadow") {
            return _setExtendedDropShadows(ref, propertyArray);
        }
    };

    exports.referenceBy = referenceBy;

    exports.setLayerEffect = setLayerEffect;
    exports.setExtendedLayerEffect = setExtendedLayerEffect;
});
<|endoftext|>


<commit_before>// Preferences, stored in chrome.storage

var M = module.exports = {};

var keyboard = require('./keyboard'),
    message = require('./message');

var firstMod = keyboard.modifiers.ALT,
    secondMod = keyboard.mac ? keyboard.modifiers.META : keyboard.modifiers.CTRL;

var defaults = {
    'modifier.cell': firstMod,
    'modifier.column': firstMod | secondMod,
    'modifier.row': 0,
    'modifier.table': 0,
    'modifier.extend': keyboard.modifiers.SHIFT,

    'capture.enabled': true,
    'capture.reset': false,

    'scroll.speed': 300,
    'scroll.acceleration': 30,

    'copy.format.enabled.richHTML': true,
    'copy.format.enabled.richHTMLCSS': true,
    'copy.format.enabled.textCSV': true,
    'copy.format.enabled.textCSVSwap': true,
    'copy.format.enabled.textHTML': true,
    'copy.format.enabled.textHTMLCSS': true,
    'copy.format.enabled.textTabs': true,
    'copy.format.enabled.textTabsSwap': true,

    'copy.format.default.richHTML': true,

    'infobox.enabled': true
};

var captureModes = [
    {
        id: 'zzz',
        name: 'Off'
    },
    {
        id: 'cell',
        name: 'Cells'
    },
    {
        id: 'column',
        name: 'Columns'
    },
    {
        id: 'row',
        name: 'Rows'
    },
    {
        id: 'table',
        name: 'Tables'
    }
];

var copyFormats = [
    {
        "id": "richHTMLCSS",
        "name": "As is",
        "desc": "Copy the table as seen on the screen (to insert into a Word document)"
    },
    {
        "id": "richHTML",
        "name": "Plain Table",
        "desc": "Copy the table without formatting"
    },
    {
        "id": "textTabs",
        "name": "Text",
        "desc": "Copy as tab-delimited text"
    },
    {
        "id": "textTabsSwap",
        "name": "Text+Swap",
        "desc": "Copy as tab-delimited text, swap columns and rows"
    },
    {
        "id": "textCSV",
        "name": "CSV",
        "desc": "Copy as comma-separated text"
    },
    {
        "id": "textCSVSwap",
        "name": "CSV+Swap",
        "desc": "Copy as comma-separated text, swap columns and rows"
    },
    {
        "id": "textHTMLCSS",
        "name": "HTML+CSS",
        "desc": "Copy as HTML source, retain formatting"
    },
    {
        "id": "textHTML",
        "name": "HTML",
        "desc": "Copy as HTML source, without formatting"
    },
];

var infoFunctions = [
    {
        id: 'count',
        name: 'Count',
    },
    {
        id: 'sum',
        name: 'Sum',
    },
    {
        id: 'avg',
        name: 'Average'
    },
    {
        id: 'min',
        name: 'Min value'
    },
    {
        id: 'max',
        name: 'Max value'
    }
];

var prefs = {};

M.load = function () {
    return new Promise(function (resolve) {
        chrome.storage.local.get(null, function (obj) {
            obj = obj || {};

            // from the previous version
            if('modKey' in obj && String(obj.modKey) === '1') {
                console.log('FOUND ALTERNATE MODKEY SETTING');
                obj['modifier.cell'] = secondMod;
                delete obj.modKey;
            }

            prefs = Object.assign({}, defaults, prefs, obj);
            console.log('PREFS LOAD', prefs);
            resolve(prefs);
        });
    });
};

M.save = function () {
    return new Promise(function (resolve) {
        chrome.storage.local.clear();
        chrome.storage.local.set(prefs, function () {
            console.log('PREFS SET', prefs);
            resolve(prefs);
        });
    });
};

M.setAll = function (obj) {
    prefs = Object.assign({}, prefs, obj);
    return M.save();
};

M.set = function (key, val) {
    prefs[key] = val;
    return M.save();
};

M.val = function (key) {
    return prefs[key];
};

M.int = function (key) {
    return Number(M.val(key)) || 0;
};

M.copyFormats = function () {
    return copyFormats.map(function (f) {
        f.enabled = !!M.val('copy.format.enabled.' + f.id);
        f.default = !!M.val('copy.format.default.' + f.id);
        return f;
    });
};

M.infoFunctions = function() {
    return infoFunctions;
};

M.captureModes = function() {
    return captureModes;
};
<commit_msg>changed default copy preference<commit_after>// Preferences, stored in chrome.storage

var M = module.exports = {};

var keyboard = require('./keyboard'),
    message = require('./message');

var firstMod = keyboard.modifiers.ALT,
    secondMod = keyboard.mac ? keyboard.modifiers.META : keyboard.modifiers.CTRL;

var defaults = {
    'modifier.cell': firstMod,
    'modifier.column': firstMod | secondMod,
    'modifier.row': 0,
    'modifier.table': 0,
    'modifier.extend': keyboard.modifiers.SHIFT,

    'capture.enabled': true,
    'capture.reset': false,

    'scroll.speed': 300,
    'scroll.acceleration': 30,

    'copy.format.enabled.richHTML': true,
    'copy.format.enabled.richHTMLCSS': true,
    'copy.format.enabled.textCSV': true,
    'copy.format.enabled.textCSVSwap': true,
    'copy.format.enabled.textHTML': true,
    'copy.format.enabled.textHTMLCSS': true,
    'copy.format.enabled.textTabs': true,
    'copy.format.enabled.textTabsSwap': true,

    'copy.format.default.richHTMLCSS': true,

    'infobox.enabled': true
};

var captureModes = [
    {
        id: 'zzz',
        name: 'Off'
    },
    {
        id: 'cell',
        name: 'Cells'
    },
    {
        id: 'column',
        name: 'Columns'
    },
    {
        id: 'row',
        name: 'Rows'
    },
    {
        id: 'table',
        name: 'Tables'
    }
];

var copyFormats = [
    {
        "id": "richHTMLCSS",
        "name": "As is",
        "desc": "Copy the table as seen on the screen (to insert into a Word document)"
    },
    {
        "id": "richHTML",
        "name": "Plain Table",
        "desc": "Copy the table without formatting"
    },
    {
        "id": "textTabs",
        "name": "Text",
        "desc": "Copy as tab-delimited text"
    },
    {
        "id": "textTabsSwap",
        "name": "Text+Swap",
        "desc": "Copy as tab-delimited text, swap columns and rows"
    },
    {
        "id": "textCSV",
        "name": "CSV",
        "desc": "Copy as comma-separated text"
    },
    {
        "id": "textCSVSwap",
        "name": "CSV+Swap",
        "desc": "Copy as comma-separated text, swap columns and rows"
    },
    {
        "id": "textHTMLCSS",
        "name": "HTML+CSS",
        "desc": "Copy as HTML source, retain formatting"
    },
    {
        "id": "textHTML",
        "name": "HTML",
        "desc": "Copy as HTML source, without formatting"
    },
];

var infoFunctions = [
    {
        id: 'count',
        name: 'Count',
    },
    {
        id: 'sum',
        name: 'Sum',
    },
    {
        id: 'avg',
        name: 'Average'
    },
    {
        id: 'min',
        name: 'Min value'
    },
    {
        id: 'max',
        name: 'Max value'
    }
];

var prefs = {};

M.load = function () {
    return new Promise(function (resolve) {
        chrome.storage.local.get(null, function (obj) {
            obj = obj || {};

            // from the previous version
            if('modKey' in obj && String(obj.modKey) === '1') {
                console.log('FOUND ALTERNATE MODKEY SETTING');
                obj['modifier.cell'] = secondMod;
                delete obj.modKey;
            }

            prefs = Object.assign({}, defaults, prefs, obj);
            console.log('PREFS LOAD', prefs);
            resolve(prefs);
        });
    });
};

M.save = function () {
    return new Promise(function (resolve) {
        chrome.storage.local.clear();
        chrome.storage.local.set(prefs, function () {
            console.log('PREFS SET', prefs);
            resolve(prefs);
        });
    });
};

M.setAll = function (obj) {
    prefs = Object.assign({}, prefs, obj);
    return M.save();
};

M.set = function (key, val) {
    prefs[key] = val;
    return M.save();
};

M.val = function (key) {
    return prefs[key];
};

M.int = function (key) {
    return Number(M.val(key)) || 0;
};

M.copyFormats = function () {
    return copyFormats.map(function (f) {
        f.enabled = !!M.val('copy.format.enabled.' + f.id);
        f.default = !!M.val('copy.format.default.' + f.id);
        return f;
    });
};

M.infoFunctions = function() {
    return infoFunctions;
};

M.captureModes = function() {
    return captureModes;
};
<|endoftext|>


<commit_before>IRIS.ModifierProvider = Class.extend({
    _modifierIns: {},
    //_entityAsset: {},
    _modifierOpts: {},
    init: function(opts) {
        if (IRIS._isObject(opts)) {
            for(var key in opts) {
                opts[key] = this._normalizeOpts(key, opts[key]);
                //this._registerEntityAssetRel(key,opts[key].entity);
                this._registerModifierOpts(key, opts[key]);
            }
        }
    },
    getModifier: function(id) {
        if (typeof this._modifierIns[id] !== 'undefined')
            return this._modifierIns[id];
        var opts = this.getModifierOpts(id);
        if (opts) {
            switch (opts.target) {
                default:
                    var oModifier = this._getModifier('id', opts);
            }
            /*var oModifier = new IRIS.Modifier({
                            id: id,
                            target: opts.target,
                            zone: opts.zone,
                            zoneOpts: opts.zoneOpts});*/
            this._modifierIns[id] = oModifier;
            return oModifier;
        }
        return false;
    },
    apply: function(oAsset, modifierIds) {
        for(var key in modifierIds) {
            if (!IRIS._isUndef(this._modifierOpts[modifierIds[key]])) {
                //TODO: implement concept of shared and private modifiers
                //IF shared we create an instance of a modifier bound to this provider
                var modifierIns = this._modifierIns[modifierIds[key]];
                if (IRIS._isUndef(modifierIns)) {
                    modifierIns = this._getModifierInstance(this._modifierOpts[modifierIds[key]]);
                    this._modifierIns[modifierIds[key]] = modifierIns;
                }
                if (modifierIns)
                    modifierIns.apply(oAsset);
            }
        }
    },
    getModifierOpts: function(id) {
        if (!IRIS._isUndef(this._modifierOpts[id]))
            return this._modifierOpts[id];
        return false;
    },
    _getModifierInstance: function(opts) {
        switch(opts.target) {
            case IRIS.MODIFIER_TARGET_POSITION:
                return new IRIS.ThreejsPositionModifier(opts);
            default:
                return false;
        }
    },
    _normalizeOpts: function(modifierId, opts) {
        if (typeof opts == 'object') {
            if (typeof opts.id == 'undefined')
                opts.id = modifierId;
        }
        return opts;
    },
    _registerModifierOpts: function(modifierId, opts) {
        this._modifierOpts[modifierId] = opts;
    }
});

IRIS.ctrl.modifierProvider = {};
IRIS.registerModifierProvider = function(modifierProviderClass, id) {
    IRIS.ctrl.modifierProvider[id] = modifierProviderClass;
};
<commit_msg>The provider executes modifiers by using it's id or handling an intance passed as reference.<commit_after>IRIS.ModifierProvider = Class.extend({
    _modifierIns: {},
    //_entityAsset: {},
    _modifierOpts: {},
    init: function(opts) {
        if (IRIS._isObject(opts)) {
            for(var key in opts) {
                opts[key] = this._normalizeOpts(key, opts[key]);
                //this._registerEntityAssetRel(key,opts[key].entity);
                this._registerModifierOpts(key, opts[key]);
            }
        }
    },
    getModifier: function(id) {
        if (typeof this._modifierIns[id] !== 'undefined')
            return this._modifierIns[id];
        var opts = this.getModifierOpts(id);
        if (opts) {
            switch (opts.target) {
                default:
                    var oModifier = this._getModifier('id', opts);
            }
            /*var oModifier = new IRIS.Modifier({
                            id: id,
                            target: opts.target,
                            zone: opts.zone,
                            zoneOpts: opts.zoneOpts});*/
            this._modifierIns[id] = oModifier;
            return oModifier;
        }
        return false;
    },
    apply: function(oAsset, modifierIds) {
        for(var key in modifierIds) {
            if (IRIS._isString(modifierIds[key])) {
                if (!IRIS._isUndef(this._modifierOpts[modifierIds[key]])) {
                    //TODO: implement concept of shared and private modifiers
                    //IF shared we create an instance of a modifier bound to this provider
                    var modifierIns = this._modifierIns[modifierIds[key]];
                    if (IRIS._isUndef(modifierIns)) {
                        modifierIns = this._getModifierInstance(this._modifierOpts[modifierIds[key]]);
                        this._modifierIns[modifierIds[key]] = modifierIns;
                    }
                    if (modifierIns)
                        modifierIns._apply(oAsset);
                }
            } else {
                modifierIds[key].apply(oAsset);
            }
        }
    },
    getModifierOpts: function(id) {
        if (!IRIS._isUndef(this._modifierOpts[id]))
            return this._modifierOpts[id];
        return false;
    },
    _getModifierInstance: function(opts) {
        switch(opts.target) {
            case IRIS.MODIFIER_TARGET_POSITION:
                return new IRIS.ThreejsPositionModifier(opts);
            default:
                return false;
        }
    },
    _normalizeOpts: function(modifierId, opts) {
        if (typeof opts == 'object') {
            if (typeof opts.id == 'undefined')
                opts.id = modifierId;
        }
        return opts;
    },
    _registerModifierOpts: function(modifierId, opts) {
        this._modifierOpts[modifierId] = opts;
    }
});

IRIS.ctrl.modifierProvider = {};
IRIS.registerModifierProvider = function(modifierProviderClass, id) {
    IRIS.ctrl.modifierProvider[id] = modifierProviderClass;
};
<|endoftext|>


<commit_before>/**
 * Created by 清月_荷雾 on 14-2-10.
 * author 清月_荷雾(441984145@qq.com)
 *        赤菁风铃(liuxuanzy@qq.com)
 * 一个内部元素可以自由移动的UIObject类
 */

var util = require("../util/util"),
    dom = require("../util/dom"),
    os = require("../util/os"),
    UIObject = require('./UIObject').UIObject,
    _transform = os.prefixStyle('transform'),
    _transition = {
        transitionTimingFunction: os.prefixStyle('transitionTimingFunction'),
        transitionDuration: os.prefixStyle('transitionDuration'),
        transitionDelay: os.prefixStyle('transitionDelay')
    };

/**
 * @constructor
 */
/**
 * 内部元素可以自由移动的UIObject类
 * @param [style] 添加在wrapper上的样式
 * @param [event] 是否触发滚动事件，为free时，将会忽略元素的准确位置
 * @param [type] 滚动类型
 * @param [move] 是否触发
 * move事件
 * @constructor
 */
function UIScroll(style, event, type, move) {
    UIObject.call(this);
    type = type || "vertical";
    this._horizontal = false;
    this._vertical = false;
    if (type === "horizontal" || type === "both") {
        this._horizontal = true;
    }
    if (type === "vertical" || type === "both") {
        this._vertical = true;
    }
    this._dom = this.wrapper = dom.createDom(util.format('

', style || ""));
    this.freeScroll = !event && os.nativeTouchScroll;
    this.emitEvent = event;
    this.emitMove = event && move;
    if (this.freeScroll) {
        this.wrapper.style.overflowY = this._horizontal ? "scroll" : "hidden";
        this.wrapper.style.overflowX = this._vertical ? "scroll" : "hidden";
        this.wrapper.style.webkitOverflowScrolling = "touch";
        return;
    }
    this.scroller = dom.createDom('

');
    this.wrapper.appendChild(this.scroller);
    this.x = 0;//水平滚动位置
    this.y = 0;//竖直滚动位置
    this._inited = false;
    var me = this;
    me.once("load", function () {
        me.scroller.style[_transition.transitionTimingFunction] = "cubic-bezier(0.1, 0.57, 0.1, 1)";
        me.bind(me.wrapper, "touchstart", me);
        me.bind(me.wrapper, "touchmove", me);
        me.bind(me.wrapper, "touchend", me);
        me.bind(me.scroller, "transitionend", me);
        me.bind(me.scroller, "webkitTransitionEnd", me);
        me.bind(me.scroller, "oTransitionEnd", me);
        me.bind(me.scroller, "MSTransitionEnd", me);
        me._inited = true;
        me.refresh();
    });
}

util.inherits(UIScroll, UIObject);

/**
 * 重写追加元素类
 */
UIScroll.prototype.append = function () {
    if (this.freeScroll) {
        UIObject.prototype.append.apply(this, arguments);
    } else {
        this._dom = this.scroller;
        UIObject.prototype.append.apply(this, arguments);
        if (this._inited) {
            this.refresh();
        }
        this._dom = this.wrapper;
    }
};

/**
 * 重写删除元素类
 */
UIScroll.prototype.remove = function () {
    if (this.freeScroll) {
        UIObject.prototype.remove.apply(this, arguments);
    } else {
        this._dom = this.scroller;
        UIObject.prototype.remove.apply(this, arguments);
        if (this._inited) {
            this.refresh();
        }
        this._dom = this.wrapper;
    }
};

/**
 * 滚动到制定位置
 * @param x 开始位置
 * @param y 结束位置
 * @param time 时间
 */
UIScroll.prototype.scrollTo = function (x, y, time) {
    this.isInTransition = time > 0;
    time = time || 0;
    this.scroller.style[_transition.transitionDuration] = (time || 0) + 'ms';
    this._translate(x, y);
};

/**
 * 重新初始化页面位置
 */
UIScroll.prototype.refresh = function () {
    var wrapperWidth = this.wrapper.clientWidth;
    var wrapperHeight = this.wrapper.clientHeight;
    var scrollerWidth = this.scroller.offsetWidth;
    var scrollerHeight = this.scroller.offsetHeight;
    this.maxScrollX = wrapperWidth - scrollerWidth;
    this.maxScrollY = wrapperHeight - scrollerHeight;
    this._horizontal = this._horizontal && this.maxScrollX < 0;
    this._vertical = this._vertical && this.maxScrollY < 0;
    if (!this._horizontal) {
        this.maxScrollX = 0;
    }
    if (!this._vertical) {
        this.maxScrollY = 0;
    }
    this._resetPosition();
};

/**
 * 事件回调
 * @private
 * @param e 异常事件
 */
UIScroll.prototype.handleEvent = function (e) {
    switch (e.type) {
        case 'touchstart':
            this._start(e);
            break;
        case 'touchmove':
            this._move(e);
            break;
        case 'touchend':
            this._end(e);
            break;
        case 'transitionend':
        case 'webkitTransitionEnd':
        case 'oTransitionEnd':
        case 'MSTransitionEnd':
            this._transitionEnd(e);
            break;
    }
};

/**
 * 动画结束事件
 * @private
 */
UIScroll.prototype._transitionEnd = function (e) {
    if (e.target !== this.scroller || !this.isInTransition) {
        return;
    }
    this.scroller.style[_transition.transitionDuration] = '0ms';
    if (!this._resetPosition(600)) {
        this.isInTransition = false;
        if (this.emitEvent) {
            this.emit("end", {x: this.x, y: this.y});
        }
    }
};

/**
 * 重置元素所在位置(对于元素不在预期的元素进去规范)
 * @param [time] 动画的时间
 * @returns {boolean}
 * @private
 */
UIScroll.prototype._resetPosition = function (time) {
    var x = this.x,
        y = this.y;
    time = time || 0;
    if (!this._horizontal || this.x > 0) {
        x = 0;
    } else if (this.x < this.maxScrollX) {
        x = this.maxScrollX;
    }
    if (!this._vertical || this.y > 0) {
        y = 0;
    } else if (this.y < this.maxScrollY) {
        y = this.maxScrollY;
    }
    if (x === this.x && y === this.y) {
        return false;
    }
    this.scrollTo(x, y, time);
    return true;
};

/**
 * 动画开始事件
 * @private
 */
UIScroll.prototype._start = function (e) {
    var point = e.touches ? e.touches[0] : e;
    this.moved = false;
    this.distX = 0;
    this.distY = 0;
    this.scroller.style[_transition.transitionDuration] = '0ms';
    if (this.isInTransition) {
        this.isInTransition = false;
        var matrix = window.getComputedStyle(dom, null),
            x, y;
        matrix = matrix[_transform].split(')')[0] || "";
        var matrix2 = matrix.split(', ');
        x = +(matrix2[12] || matrix2[4]);
        y = +(matrix2[13] || matrix2[5]);
        this._translate(Math.round(x), Math.round(y));
        this.emit("end", {x: this.x, y: this.y});
    }
    this.pointX = point.pageX;
    this.pointY = point.pageY;
    this.emit("start", {x: this.x, y: this.y});
};

/**
 * 动画过程事件
 * @private
 */
UIScroll.prototype._move = function (e) {
    var point = e.touches ? e.touches[0] : e,
        deltaX = point.pageX - this.pointX,
        deltaY = point.pageY - this.pointY,
        newX, newY,
        absDistX, absDistY;

    this.pointX = point.pageX;
    this.pointY = point.pageY;

    this.distX += deltaX;
    this.distY += deltaY;
    absDistX = Math.abs(this.distX);
    absDistY = Math.abs(this.distY);

    if (absDistX < 10 && absDistY < 10) {
        return;
    }
    deltaX = this._horizontal ? deltaX : 0;
    deltaY = this._vertical ? deltaY : 0;
    newX = this.x + deltaX;
    newY = this.y + deltaY;

    if (newX > 0 || newX < this.maxScrollX) {
        newX = this.x + deltaX / 3;
    }
    if (newY > 0 || newY < this.maxScrollY) {
        newY = this.y + deltaY / 3;
    }
    this.moved = true;
    this._translate(newX, newY);
    if (this.emitMove) {
        this.emit("move", {x: this.x, y: this.y});
    }
};

/**
 * 动画结束事件
 * @private
 */
UIScroll.prototype._end = function () {
    this.isInTransition = 0;
    if (this._resetPosition(600)) {
        return;
    }
    if (this.emitEvent && !this.moved) {
        this.emit("cancel");
    } else if (this.emitEvent) {
        this.emit("end", {x: this.x, y: this.y});
    }
};

UIScroll.prototype._translate = function (x, y) {
    this.scroller.style[_transform] = 'translate(' + x + 'px,' + y + 'px)';
    this.x = x;
    this.y = y;
};

exports.UIScroll = UIScroll;

<commit_msg>fix some error and improve to version 0.1.4<commit_after>/**
 * Created by 清月_荷雾 on 14-2-10.
 * author 清月_荷雾(441984145@qq.com)
 *        赤菁风铃(liuxuanzy@qq.com)
 * 一个内部元素可以自由移动的UIObject类
 */

var util = require("../util/util"),
    dom = require("../util/dom"),
    os = require("../util/os"),
    UIObject = require('./UIObject').UIObject,
    _transform = dom.prefixStyle('transform'),
    _transition = {
        transitionTimingFunction: dom.prefixStyle('transitionTimingFunction'),
        transitionDuration: dom.prefixStyle('transitionDuration'),
        transitionDelay: dom.prefixStyle('transitionDelay')
    };

/**
 * @constructor
 */
/**
 * 内部元素可以自由移动的UIObject类
 * @param [style] 添加在wrapper上的样式
 * @param [event] 是否触发滚动事件，为free时，将会忽略元素的准确位置
 * @param [type] 滚动类型
 * @param [move] 是否触发
 * move事件
 * @constructor
 */
function UIScroll(style, event, type, move) {
    UIObject.call(this);
    type = type || "vertical";
    this._horizontal = false;
    this._vertical = false;
    if (type === "horizontal" || type === "both") {
        this._horizontal = true;
    }
    if (type === "vertical" || type === "both") {
        this._vertical = true;
    }
    this._dom = this.wrapper = dom.createDom(util.format('

', style || ""));
    this.freeScroll = !event && os.os.nativeTouchScroll;
    this.emitEvent = event;
    this.emitMove = event && move;
    if (this.freeScroll) {
        this.wrapper.style.overflowY = this._horizontal ? "scroll" : "hidden";
        this.wrapper.style.overflowX = this._vertical ? "scroll" : "hidden";
        this.wrapper.style.webkitOverflowScrolling = "touch";
        return;
    }
    this.scroller = dom.createDom('

');
    this.wrapper.appendChild(this.scroller);
    this.x = 0;//水平滚动位置
    this.y = 0;//竖直滚动位置
    this._inited = false;
    var me = this;
    me.once("load", function () {
        me.scroller.style[_transition.transitionTimingFunction] = "cubic-bezier(0.1, 0.57, 0.1, 1)";
        me.bind(me.wrapper, "touchstart", me);
        me.bind(me.wrapper, "touchmove", me);
        me.bind(me.wrapper, "touchend", me);
        me.bind(me.scroller, "transitionend", me);
        me.bind(me.scroller, "webkitTransitionEnd", me);
        me.bind(me.scroller, "oTransitionEnd", me);
        me.bind(me.scroller, "MSTransitionEnd", me);
        me._inited = true;
        me.refresh();
    });
}

util.inherits(UIScroll, UIObject);

/**
 * 重写追加元素类
 */
UIScroll.prototype.append = function () {
    if (this.freeScroll) {
        UIObject.prototype.append.apply(this, arguments);
    } else {
        this._dom = this.scroller;
        UIObject.prototype.append.apply(this, arguments);
        if (this._inited) {
            this.refresh();
        }
        this._dom = this.wrapper;
    }
};

/**
 * 重写删除元素类
 */
UIScroll.prototype.remove = function () {
    if (this.freeScroll) {
        UIObject.prototype.remove.apply(this, arguments);
    } else {
        this._dom = this.scroller;
        UIObject.prototype.remove.apply(this, arguments);
        if (this._inited) {
            this.refresh();
        }
        this._dom = this.wrapper;
    }
};

/**
 * 滚动到制定位置
 * @param x 开始位置
 * @param y 结束位置
 * @param time 时间
 */
UIScroll.prototype.scrollTo = function (x, y, time) {
    this.isInTransition = time > 0;
    time = time || 0;
    this.scroller.style[_transition.transitionDuration] = (time || 0) + 'ms';
    this._translate(x, y);
};

/**
 * 重新初始化页面位置
 */
UIScroll.prototype.refresh = function () {
    var wrapperWidth = this.wrapper.clientWidth;
    var wrapperHeight = this.wrapper.clientHeight;
    var scrollerWidth = this.scroller.offsetWidth;
    var scrollerHeight = this.scroller.offsetHeight;
    this.maxScrollX = wrapperWidth - scrollerWidth;
    this.maxScrollY = wrapperHeight - scrollerHeight;
    this._horizontal = this._horizontal && this.maxScrollX < 0;
    this._vertical = this._vertical && this.maxScrollY < 0;
    if (!this._horizontal) {
        this.maxScrollX = 0;
    }
    if (!this._vertical) {
        this.maxScrollY = 0;
    }
    this._resetPosition();
};

/**
 * 事件回调
 * @private
 * @param e 异常事件
 */
UIScroll.prototype.handleEvent = function (e) {
    switch (e.type) {
        case 'touchstart':
            this._start(e);
            break;
        case 'touchmove':
            this._move(e);
            break;
        case 'touchend':
            this._end(e);
            break;
        case 'transitionend':
        case 'webkitTransitionEnd':
        case 'oTransitionEnd':
        case 'MSTransitionEnd':
            this._transitionEnd(e);
            break;
    }
};

/**
 * 动画结束事件
 * @private
 */
UIScroll.prototype._transitionEnd = function (e) {
    if (e.target !== this.scroller || !this.isInTransition) {
        return;
    }
    this.scroller.style[_transition.transitionDuration] = '0ms';
    if (!this._resetPosition(600)) {
        this.isInTransition = false;
        if (this.emitEvent) {
            this.emit("end", {x: this.x, y: this.y});
        }
    }
};

/**
 * 重置元素所在位置(对于元素不在预期的元素进去规范)
 * @param [time] 动画的时间
 * @returns {boolean}
 * @private
 */
UIScroll.prototype._resetPosition = function (time) {
    var x = this.x,
        y = this.y;
    time = time || 0;
    if (!this._horizontal || this.x > 0) {
        x = 0;
    } else if (this.x < this.maxScrollX) {
        x = this.maxScrollX;
    }
    if (!this._vertical || this.y > 0) {
        y = 0;
    } else if (this.y < this.maxScrollY) {
        y = this.maxScrollY;
    }
    if (x === this.x && y === this.y) {
        return false;
    }
    this.scrollTo(x, y, time);
    return true;
};

/**
 * 动画开始事件
 * @private
 */
UIScroll.prototype._start = function (e) {
    var point = e.touches ? e.touches[0] : e;
    this.moved = false;
    this.distX = 0;
    this.distY = 0;
    this.scroller.style[_transition.transitionDuration] = '0ms';
    if (this.isInTransition) {
        this.isInTransition = false;
        var matrix = window.getComputedStyle(dom, null),
            x, y;
        matrix = matrix[_transform].split(')')[0] || "";
        var matrix2 = matrix.split(', ');
        x = +(matrix2[12] || matrix2[4]);
        y = +(matrix2[13] || matrix2[5]);
        this._translate(Math.round(x), Math.round(y));
        this.emit("end", {x: this.x, y: this.y});
    }
    this.pointX = point.pageX;
    this.pointY = point.pageY;
    this.emit("start", {x: this.x, y: this.y});
};

/**
 * 动画过程事件
 * @private
 */
UIScroll.prototype._move = function (e) {
    var point = e.touches ? e.touches[0] : e,
        deltaX = point.pageX - this.pointX,
        deltaY = point.pageY - this.pointY,
        newX, newY,
        absDistX, absDistY;

    this.pointX = point.pageX;
    this.pointY = point.pageY;

    this.distX += deltaX;
    this.distY += deltaY;
    absDistX = Math.abs(this.distX);
    absDistY = Math.abs(this.distY);

    if (absDistX < 10 && absDistY < 10) {
        return;
    }
    deltaX = this._horizontal ? deltaX : 0;
    deltaY = this._vertical ? deltaY : 0;
    newX = this.x + deltaX;
    newY = this.y + deltaY;

    if (newX > 0 || newX < this.maxScrollX) {
        newX = this.x + deltaX / 3;
    }
    if (newY > 0 || newY < this.maxScrollY) {
        newY = this.y + deltaY / 3;
    }
    this.moved = true;
    this._translate(newX, newY);
    if (this.emitMove) {
        this.emit("move", {x: this.x, y: this.y});
    }
};

/**
 * 动画结束事件
 * @private
 */
UIScroll.prototype._end = function () {
    this.isInTransition = 0;
    if (this._resetPosition(600)) {
        return;
    }
    if (this.emitEvent && !this.moved) {
        this.emit("cancel");
    } else if (this.emitEvent) {
        this.emit("end", {x: this.x, y: this.y});
    }
};

UIScroll.prototype._translate = function (x, y) {
    this.scroller.style[_transform] = 'translate(' + x + 'px,' + y + 'px)';
    this.x = x;
    this.y = y;
};

exports.UIScroll = UIScroll;

<|endoftext|>


<commit_before>'use strict';

//dependencies
const _ = require('lodash');
const mongoose = require('mongoose');
const ServiceRequest = mongoose.model('ServiceRequest');

/**
 * ServiceRequest Controller
 *
 * @description :: Server-side logic for managing ServiceRequest.
 */
module.exports = {
  /**
   * @function
   * @name servicerequests.index()
   * @description display a list of all servicerequests
   * @param  {HttpRequest} request  a http request
   * @param  {HttpResponse} response a http response
   */
  index: function (request, response, next) {

    ServiceRequest
      .list(request, function (error, results) {
        if (error) {
          next(error);
        } else {
          response.ok(results);
        }
      });

  },

  /**
   * @function
   * @name servicerequests.create()
   * @description create a new servicerequest
   * @param  {HttpRequest} request  a http request
   * @param  {HttpResponse} response a http response
   */
  create: function (request, response, next) {
    //set operator if not exists
    let body = request.body;

    //ensure current party exists and is not an app
    const shouldSetOperator =
      (!body.operator && request.party && !request.party.isApp);

    //ensure service request contact method workspace
    const workspace =
      (_.get(body, 'method.workspace') ||
        _.get(request, 'party.relation.workspace'));
    body.method.workspace = workspace;

    if (shouldSetOperator) {
      body.operator = request.party;
    }

    ServiceRequest.create(body, function (error, serviceRequest) {
      if (error) {
        next(error);
      } else {
        response.created(serviceRequest);
      }
    });

  },

  /**
   * @function
   * @name servicerequests.show()
   * @description display a specific servicerequest
   * @param  {HttpRequest} request  a http request
   * @param  {HttpResponse} response a http response
   */
  show: function (request, response, next) {
    ServiceRequest
      .show(request, function (error, servicerequest) {
        if (error) {
          next(error);
        } else {
          response.ok(servicerequest);
        }
      });
  },

  /**
   * @function
   * @name servicerequests.update()
   * @description update a specific servicerequest
   * @param  {HttpRequest} request  a http request
   * @param  {HttpResponse} response a http response
   */
  update: function (request, response, next) {

    //ensure service request contact method workspace
    const workspace =
      (_.get(request, 'body.method.workspace') ||
        _.get(request, 'party.relation.workspace'));
    request.body = _.merge({}, request.body, { method: { workspace: workspace } });

    ServiceRequest
      .edit(request, function (error, servicerequest) {
        if (error) {
          next(error);
        } else {
          response.ok(servicerequest);
        }
      });
  },

  /**
   * @function
   * @name servicerequests.destroy()
   * @description delete a specific servicerequest
   * @param  {HttpRequest} request  a http request
   * @param  {HttpResponse} response a http response
   */
  destroy: function (request, response, next) {
    ServiceRequest
      .findByIdAndRemove(
        request.params.id,
        function (error, servicerequest) {
          if (error) {
            next(error);
          } else {
            response.ok(servicerequest);
          }
        });
  }

};
<commit_msg>ensure method source(workspace) set on update take.2<commit_after>'use strict';

//dependencies
const _ = require('lodash');
const mongoose = require('mongoose');
const ServiceRequest = mongoose.model('ServiceRequest');

/**
 * ServiceRequest Controller
 *
 * @description :: Server-side logic for managing ServiceRequest.
 */
module.exports = {
  /**
   * @function
   * @name servicerequests.index()
   * @description display a list of all servicerequests
   * @param  {HttpRequest} request  a http request
   * @param  {HttpResponse} response a http response
   */
  index: function (request, response, next) {

    ServiceRequest
      .list(request, function (error, results) {
        if (error) {
          next(error);
        } else {
          response.ok(results);
        }
      });

  },

  /**
   * @function
   * @name servicerequests.create()
   * @description create a new servicerequest
   * @param  {HttpRequest} request  a http request
   * @param  {HttpResponse} response a http response
   */
  create: function (request, response, next) {
    //set operator if not exists
    let body = request.body;

    //ensure current party exists and is not an app
    const shouldSetOperator =
      (!body.operator && request.party && !request.party.isApp);

    //ensure service request contact method workspace
    const workspace =
      (_.get(body, 'method.workspace') ||
        _.get(request, 'party.relation.workspace'));
    body.method.workspace = workspace;

    if (shouldSetOperator) {
      body.operator = request.party;
    }

    ServiceRequest.create(body, function (error, serviceRequest) {
      if (error) {
        next(error);
      } else {
        response.created(serviceRequest);
      }
    });

  },

  /**
   * @function
   * @name servicerequests.show()
   * @description display a specific servicerequest
   * @param  {HttpRequest} request  a http request
   * @param  {HttpResponse} response a http response
   */
  show: function (request, response, next) {
    ServiceRequest
      .show(request, function (error, servicerequest) {
        if (error) {
          next(error);
        } else {
          response.ok(servicerequest);
        }
      });
  },

  /**
   * @function
   * @name servicerequests.update()
   * @description update a specific servicerequest
   * @param  {HttpRequest} request  a http request
   * @param  {HttpResponse} response a http response
   */
  update: function (request, response, next) {

    //ensure service request contact method workspace
    const workspace =
      (_.get(request, 'body.method.workspace') ||
        _.get(request, 'body.operator.relation.workspace'));
    request.body = _.merge({}, request.body, { method: { workspace: workspace } });

    ServiceRequest
      .edit(request, function (error, servicerequest) {
        if (error) {
          next(error);
        } else {
          response.ok(servicerequest);
        }
      });
  },

  /**
   * @function
   * @name servicerequests.destroy()
   * @description delete a specific servicerequest
   * @param  {HttpRequest} request  a http request
   * @param  {HttpResponse} response a http response
   */
  destroy: function (request, response, next) {
    ServiceRequest
      .findByIdAndRemove(
        request.params.id,
        function (error, servicerequest) {
          if (error) {
            next(error);
          } else {
            response.ok(servicerequest);
          }
        });
  }

};
<|endoftext|>