<commit_before>var pg = require( 'pg' ),
	_ = require( 'underscore' ),
	dbgeo = require( 'dbgeo' ),
	db = require( './db' );

exports.topojson = function( req, res ) {
	var client = new pg.Client( db.conn );
	client.connect();

	var fields = req.params.fields ? req.params.fields.split( "," ) : [ "gid" ];
	fields.push( "ST_AsGeoJSON( geom ) AS geom" );

	var queryString = buildQuery( fields, req.params.table, req.params.where )
	client.query( queryString, function( error, result ) {
		dbgeo.parse({
		    "data": result.rows,
			"geometryColumn": "geom",
			"outputFormat": "topojson",
			"callback": function( error, result ) {
				if( error ) {
		    		    console.log( " --- error --- ", error);
				} else {
					res.send( result );
					client.end();
				}
		    }
		});
	});
}

exports.services = function( req, res ) {
	var client = new pg.Client( db.conn );
	client.connect();

	var services = [];

	var query = client.query( "SELECT organizations.* FROM neighborhoods INNER JOIN organization_lookup ON neighborhoods.id = neighborhood INNER JOIN organizations ON organizations.id = organization WHERE neighborhoods.id = '" + req.params.neighborhood + "'" );

	query.on( 'row', function( result ) {
		services.push( result );
	});

	query.on( 'end', function() {
		res.send( services );
		client.end();
	})
}

exports.names = function( req, res ) {
	var client = new pg.Client( db.conn );
	client.connect();

	var names = [];

	var fields = req.params.fields ? req.params.fields.split( "," ) : [ "id", "name" ];
	var where = "name IS NOT NULL";
	if( req.params.id ) where += " AND id = " + req.params.id;

	var queryString = buildQuery( fields, "neighborhoods", where );
	var query = client.query( queryString );

	query.on( 'row', function( result ) {
		names.push( result );
	})

	query.on( 'end', function() {
		res.send( names );
		client.end();
	});
}

exports.template = function( req, res ) {
	var client = new pg.Client( db.conn );
	client.connect();

	var template = JSON.parse( req.body.json ),
		id = req.body.id,
		html = '';

	load_part( template.shift() );

	function load_part( part ) {
		var data = [];
		var query = client.query( part.query + " WHERE id = " + id );
		query.on( 'row', function( result ) {
			data.push( result );
		});
		query.on( 'end', function() {
			if ( data.length ) {
				html += part.header;
				html += _.reduce( data, function( s1, row ) {
					if ( row.type ) {
						var type = row.type.trim();
						return s1 + _.reduce( part.style, function( s2, item ) {
							if ( item.data == type ) {
								return s2 + item.format.replace( /\|\|data\|\|/g, row[ item.data ] );
							}
							else {
								return ''
							}
						}, '' )
					}
					else {
						return s1 + _.reduce( part.style, function( s2, item ) {
							return s2 + item.format.replace( /\|\|data\|\|/g, row[ item.data ] );
						}, '' )
					}
				}, '' );
				html += part.footer;
			}

			if( template.length ) {
				load_part( template.shift() );
			}
			else {
				complete();
			}
		});
	}

	function complete() {
		res.send( html );
		client.end();
	}
}

function buildQuery( fields, table, where ) {
	var queryString = "SELECT";

	queryString = _.reduce( fields, function( memo, field, i ) {
		if( i > 0 ) memo += ",";
		return memo += " " + field;
	}, queryString );

	queryString += " FROM " + table;
	if( where ) queryString += " WHERE " + where;

	return queryString;
}
<commit_msg>Fixed return statement<commit_after>var pg = require( 'pg' ),
	_ = require( 'underscore' ),
	dbgeo = require( 'dbgeo' ),
	db = require( './db' );

exports.topojson = function( req, res ) {
	var client = new pg.Client( db.conn );
	client.connect();

	var fields = req.params.fields ? req.params.fields.split( "," ) : [ "gid" ];
	fields.push( "ST_AsGeoJSON( geom ) AS geom" );

	var queryString = buildQuery( fields, req.params.table, req.params.where )
	client.query( queryString, function( error, result ) {
		dbgeo.parse({
		    "data": result.rows,
			"geometryColumn": "geom",
			"outputFormat": "topojson",
			"callback": function( error, result ) {
				if( error ) {
		    		    console.log( " --- error --- ", error);
				} else {
					res.send( result );
					client.end();
				}
		    }
		});
	});
}

exports.services = function( req, res ) {
	var client = new pg.Client( db.conn );
	client.connect();

	var services = [];

	var query = client.query( "SELECT organizations.* FROM neighborhoods INNER JOIN organization_lookup ON neighborhoods.id = neighborhood INNER JOIN organizations ON organizations.id = organization WHERE neighborhoods.id = '" + req.params.neighborhood + "'" );

	query.on( 'row', function( result ) {
		services.push( result );
	});

	query.on( 'end', function() {
		res.send( services );
		client.end();
	})
}

exports.names = function( req, res ) {
	var client = new pg.Client( db.conn );
	client.connect();

	var names = [];

	var fields = req.params.fields ? req.params.fields.split( "," ) : [ "id", "name" ];
	var where = "name IS NOT NULL";
	if( req.params.id ) where += " AND id = " + req.params.id;

	var queryString = buildQuery( fields, "neighborhoods", where );
	var query = client.query( queryString );

	query.on( 'row', function( result ) {
		names.push( result );
	})

	query.on( 'end', function() {
		res.send( names );
		client.end();
	});
}

exports.template = function( req, res ) {
	var client = new pg.Client( db.conn );
	client.connect();

	var template = JSON.parse( req.body.json ),
		id = req.body.id,
		html = '';

	load_part( template.shift() );

	function load_part( part ) {
		var data = [];
		var query = client.query( part.query + " WHERE id = " + id );
		query.on( 'row', function( result ) {
			data.push( result );
		});
		query.on( 'end', function() {
			if ( data.length ) {
				html += part.header;
				html += _.reduce( data, function( s1, row ) {
					if ( row.type ) {
						var type = row.type.trim();
						return s1 + _.reduce( part.style, function( s2, item ) {
							if ( item.data == type ) {
								return s2 + item.format.replace( /\|\|data\|\|/g, row[ item.data ] );
							}
							else {
								return s2
							}
						}, '' )
					}
					else {
						return s1 + _.reduce( part.style, function( s2, item ) {
							return s2 + item.format.replace( /\|\|data\|\|/g, row[ item.data ] );
						}, '' )
					}
				}, '' );
				html += part.footer;
			}

			if( template.length ) {
				load_part( template.shift() );
			}
			else {
				complete();
			}
		});
	}

	function complete() {
		res.send( html );
		client.end();
	}
}

function buildQuery( fields, table, where ) {
	var queryString = "SELECT";

	queryString = _.reduce( fields, function( memo, field, i ) {
		if( i > 0 ) memo += ",";
		return memo += " " + field;
	}, queryString );

	queryString += " FROM " + table;
	if( where ) queryString += " WHERE " + where;

	return queryString;
}
<|endoftext|>


<commit_before>ServerEval = {
	results: function() {
		return ServerEval._collection.find({}, {
			sort: {
				eval_time: -1
			}
		});
	},
	eval: function(expr) {
		Meteor.call('serverEval/eval', expr);
	},
	clear: function() {
		Meteor.call('serverEval/clear');
	}
};

if (Meteor.isClient) {
	ServerEval._collection = new Meteor.Collection("eval-results");

	Meteor.subscribe("eval-results");
}

if (Meteor.isServer) {
	ServerEval._collection = new Meteor.Collection("eval-results", {
		connection: null
	});

	Meteor.publish("eval-results", function() {
		return ServerEval.results();
	});

	var prettyJSON = function(obj) {
		var cache = [];
		var json = JSON.stringify(obj, function(key, value) {
			if (_.isFunction(value)) {
				value = "[Function]";
			} else if (_.isObject(value)) {
				if (cache.indexOf(value) !== -1) {
					// Circular reference found, discard key
					return;
				}
				// Store value in our collection
				cache.push(value);
			}
			return value;
		});
		cache = null; // Enable garbage collection TODO investigate
		return json;
	};

	Meteor.methods({
		'serverEval/eval': function(expr) {
			if (!expr || expr.length === 0) return;
			var eval_time = Date.now();
			try {
				var result_raw = eval(expr);
				ServerEval._collection.insert({
					eval_time: eval_time,
					expr: expr,
					type: typeof result_raw,
					result: JSON.parse(prettyJSON(result_raw))
				});
			} catch (e) {
				ServerEval._collection.insert({
					eval_time: eval_time,
					expr: expr,
					error: true,
					result: e.toString()
				});
			}
		},
		'serverEval/clear': function() {
			ServerEval._collection.remove({});
		}
	});
}<commit_msg>add Function object properties to tree<commit_after>ServerEval = {
	results: function() {
		return ServerEval._collection.find({}, {
			sort: {
				eval_time: -1
			}
		});
	},
	eval: function(expr) {
		Meteor.call('serverEval/eval', expr);
	},
	clear: function() {
		Meteor.call('serverEval/clear');
	}
};

if (Meteor.isClient) {
	ServerEval._collection = new Meteor.Collection("eval-results");

	Meteor.subscribe("eval-results");
}

if (Meteor.isServer) {
	ServerEval._collection = new Meteor.Collection("eval-results", {
		connection: null
	});

	Meteor.publish("eval-results", function() {
		return ServerEval.results();
	});

	var prettyJSON = function(obj) {
		var cache = [];
		var json = JSON.stringify(obj, function(key, value) {
			var val = value;
			if (_.isObject(value)) {
				if (cache.indexOf(value) !== -1) {
					// Circular reference found, discard key
					return;
				}
				if (_.isFunction(value)) {
					val = _.extend({}, value);
					val.____TYPE____ = "[Function]";
				}
				// Store value in our collection
				cache.push(value);
			}
			return val;
		});
		cache = null; // Enable garbage collection TODO investigate
		return json;
	};

	Meteor.methods({
		'serverEval/eval': function(expr) {
			if (!expr || expr.length === 0) return;
			var eval_time = Date.now();
			try {
				var result_raw = eval(expr);
				//console.log(result_raw);
				ServerEval._collection.insert({
					eval_time: eval_time,
					expr: expr,
					type: typeof result_raw,
					result: JSON.parse(prettyJSON(result_raw))
				});
			} catch (e) {
				ServerEval._collection.insert({
					eval_time: eval_time,
					expr: expr,
					error: true,
					result: e.toString()
				});
			}
		},
		'serverEval/clear': function() {
			ServerEval._collection.remove({});
		}
	});
}<|endoftext|>


<commit_before>/*eslint dot-notation: "off"*/
/*eslint no-shadow: "off"*/

import {replace, when, reset} from '../../../../test-helper';

describe.only('the products controller', () => {
  let productsService;
  let ProductsController;
  let productsController;

  let makeProductsControllerWith = (productsService) => {
    ProductsController = require('./products.controller')['ProductsController'];
    return new ProductsController(productsService);
  };

  beforeEach(() => {
    productsService = require('./service/products-service').productsService();
    replace(productsService, 'fetch');
    when(productsService.fetch('/products.json')).thenResolve(['products']);
  });

  it('has no products', () => {
    productsController = makeProductsControllerWith(productsService);
    productsController.products.should.deepEqual([]);
  });

  it('fetches products from the server', () => {
    productsController = makeProductsControllerWith(productsService);

    return productsController.fetch('/products.json').then(() => {
      productsController.products.should.deepEqual(['products']);
    });
  });

  afterEach(() => reset());
});

<commit_msg>refactor specs<commit_after>/*eslint dot-notation: "off"*/
/*eslint no-shadow: "off"*/

import {replace, when, reset} from '../../../../test-helper';

describe.only('the products controller', () => {
  let productsService;
  let ProductsController;
  let productsController;

  let makeProductsControllerWith = (productsService) => {
    ProductsController = require('./products.controller')['ProductsController'];
    return new ProductsController(productsService);
  };

  beforeEach(() => {
    productsService = require('./service/products-service').productsService();
    replace(productsService, 'fetch');
  });

  it('has no products', () => {
    productsController = makeProductsControllerWith(productsService);
    productsController.products.should.deepEqual([]);
  });

  it('fetches products from the server', () => {
    when(productsService.fetch('/products.json')).thenResolve(['products']);
    productsController = makeProductsControllerWith(productsService);

    return productsController.fetch('/products.json').then(() => {
      productsController.products.should.deepEqual(['products']);
    });
  });

  afterEach(() => reset());
});

<|endoftext|>


<commit_before>var Graphite = require('graphite');
var Measured = require('measured');

var reportInterval = 5000;
var graphiteHost = process.env.GRAPHITE_HOST || null;
var graphitePort = process.env.GRAPHITE_PORT || 2003;
var envName = process.env.NODE_ENV || "unknown";
var processIdentifier = process.env.DYNO || "unknown-process";

var timer = null;
var graphite = null;
var data = Measured.createCollection('origami.polyfill.' + envName + '.' + processIdentifier);

if (graphiteHost) {
	graphite = Graphite.createClient('plaintext://'+graphiteHost+':'+graphitePort);
	timer = setInterval(function() {
		graphite.write(data.toJSON(), function(err) {
			if (err) {

				// Ignore timeouts
				if (err.code === 'ETIMEDOUT') return;

				console.error(err, err.stack);
				console.warn('Disabling graphite reporting due to error');
				clearTimeout(timer);
			}
		});
	}, reportInterval);
	timer.unref();
}

module.exports = data;
<commit_msg>Use the process ID rather than DYNO environment variable, this makes the metrics infrastructure agnostic.  You also get a nice effect of being able to see process restarts and lifetimes in your time series data.<commit_after>var Graphite = require('graphite');
var Measured = require('measured');

var reportInterval = 5000;
var graphiteHost = process.env.GRAPHITE_HOST || null;
var graphitePort = process.env.GRAPHITE_PORT || 2003;
var envName = process.env.NODE_ENV || "unknown";
var processIdentifier = 'pid-' + process.pid;

var timer = null;
var graphite = null;
var data = Measured.createCollection('origami.polyfill.' + envName + '.' + processIdentifier);

if (graphiteHost) {
	graphite = Graphite.createClient('plaintext://'+graphiteHost+':'+graphitePort);
	timer = setInterval(function() {
		graphite.write(data.toJSON(), function(err) {
			if (err) {

				// Ignore timeouts
				if (err.code === 'ETIMEDOUT') return;

				console.error(err, err.stack);
				console.warn('Disabling graphite reporting due to error');
				clearTimeout(timer);
			}
		});
	}, reportInterval);
	timer.unref();
}

module.exports = data;
<|endoftext|>


<commit_before>import React, {PropTypes, Component} from 'react'
import { connect } from 'react-redux'
import {Button, InputGroup, FormGroup, FormControl}
    from 'react-bootstrap'
import Helmet from 'react-helmet'
import {Page, ScrollView, View, LoaderText} from 'zanata-ui'
import { debounce, find } from 'lodash'
import Entry from './Entry'
import Pager from './Pager'
import { Notification } from '../../components'

import {
  initialLoad,
  handleDelete,
  handleUpdatePageSize,
  handleUpdateSort,
  handleUpdateSearch,
  pageSizeOption,
  sortOption
} from '../../actions/languages'

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

const loadingContainerTheme = {
  base: {
    ai: 'Ai(c)',
    flxg: 'Flxg(1)',
    jc: 'Jc(c)',
    w: 'W(100%)'
  }
}

class Languages extends Component {
  componentDidMount () {
    this.props.handleInitLoad()
  }

  render () {
    const {
      searchText,
      size,
      sort,
      page,
      results,
      totalCount,
      permission,
      user,
      loading,
      deleting,
      notification,
      handleDelete,
      handleOnUpdatePageSize,
      handleOnUpdateSort,
      handleOnUpdateSearch,
      handlePageChanged
    } = this.props

    // TODO: tweak for testing
    const totalPage = Math.floor(totalCount / size) +
   (totalCount % size > 0 ? 1 : 0)
  // const totalPage = 1

    return (
      <Page>
        {notification &&
        (<Notification severity={notification.severity}
          message={notification.message}
          details={notification.details}
          show={!!notification} />
        )
        }
        <Helmet title='Languages' />
        <ScrollView>
          <View theme={contentViewContainerTheme}>

                    Languages {!loading &&
                      {totalCount}}

                  {permission.canAddLocale &&
                    <Button className='btn-primary'>
                       Add new language
                    </Button>
                  }
                  {loading
                      ? <View theme={loadingContainerTheme}>
                        <LoaderText theme={{ base: { fz: 'Fz(ms1)' } }}
                          size='2' loading />
                      </View>
                      : (

                          <FormGroup>
                            <InputGroup>
                              <FormControl type='text'
                                defaultValue={searchText}
                                onChange={handleOnUpdateSearch} />
                              <InputGroup.Button>
                                <Button>

                                </Button>
                              </InputGroup.Button>
                            </InputGroup>
                          </FormGroup>

                          <FormControl componentClass='select'
                            className='pull-right' id='sort-options'
                            onChange={handleOnUpdateSort} value={sort.value}>
                            {sortOption.map(function (sort, i) {
                              return <option key={i} value={sort.value}>
                                {sort.display}</option>
                            })}
                          </FormControl>

                          Show
                          <FormControl inline componentClass='select'
                            onChange={handleOnUpdatePageSize} value={size}
                            id='page-size-options'>
                            {pageSizeOption.map(function (value, i) {
                              return <option key={i} value={value}>
                                {value}</option>
                            })}
                          </FormControl>

                          <Pager activePage={page} totalPage={totalPage}
                            handlePageChanged={handlePageChanged} />

)
                  }
                  {!loading &&

                            Language

                        {results.map(function (value, i) {
                          return <Entry key={i} locale={value}
                            userLanguageTeams={user.languageTeams}
                            permission={permission}
                            handleDelete={handleDelete}
                            isDeleting={deleting} />
                        })}

}

          </View>
        </ScrollView>
      </Page>
    )
  }
}

Languages.propTypes = {
  page: PropTypes.number,
  notification: PropTypes.object,
  permission: PropTypes.object,
  user: PropTypes.object,
  searchText: PropTypes.string,
  size: PropTypes.number,
  sort: PropTypes.object,
  results: PropTypes.array,
  totalCount: PropTypes.number,
  loading: PropTypes.bool,
  deleting: PropTypes.bool,
  handleInitLoad: PropTypes.func,
  handleDelete: PropTypes.func,
  handleOnUpdatePageSize: PropTypes.func,
  handleOnUpdateSort: PropTypes.func,
  handleOnUpdateSearch: PropTypes.func,
  handlePageChanged: PropTypes.func
}

const mapStateToProps = (state) => {
  let urlSort = state.routing.location.query.sort
  if (urlSort) {
    urlSort = find(sortOption, function (sort) {
      return sort.value === urlSort
    })
    if (!urlSort) {
      urlSort = sortOption[0]
    }
  } else {
    urlSort = sortOption[0]
  }

  const {
    locales,
    loading,
    permission,
    user,
    notification,
    deleting
  } = state.languages
  return {
    searchText: state.routing.location.query.search || '',
    page: parseInt(state.routing.location.query.page) || 1,
    size: parseInt(state.routing.location.query.size) || pageSizeOption[0],
    sort: urlSort,
    results: locales.results,
    totalCount: locales.totalCount,
    loading,
    permission,
    user,
    notification,
    deleting
  }
}

const mapDispatchToProps = (dispatch) => {
  const updateSearch = debounce((val) =>
    dispatch(handleUpdateSearch(val)), 200)

  return {
    handleInitLoad: () => {
      dispatch(initialLoad())
    },
    handleDelete: (localeId) => {
      dispatch(handleDelete(localeId))
    },
    handleOnUpdatePageSize: (event) => {
      dispatch(handleUpdatePageSize(event.target.value || ''))
    },
    handleOnUpdateSort: (event) => {
      dispatch(handleUpdateSort(event.target.value || ''))
    },
    handleOnUpdateSearch: (event) => {
      updateSearch(event.target.value || '')
    },
    handlePageChanged: (pageNum) => {
      console.info('update page here', pageNum)
    }
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(Languages)
<commit_msg>brought in pager.js code<commit_after>import React, {PropTypes, Component} from 'react'
import { connect } from 'react-redux'
import {Button, InputGroup, FormGroup, FormControl, Pagination}
    from 'react-bootstrap'
import Helmet from 'react-helmet'
import {Page, ScrollView, View, LoaderText} from 'zanata-ui'
import { debounce, find } from 'lodash'
import Entry from './Entry'
import { Notification } from '../../components'

import {
  initialLoad,
  handleDelete,
  handleUpdatePageSize,
  handleUpdateSort,
  handleUpdateSearch,
  pageSizeOption,
  sortOption
} from '../../actions/languages'

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

const loadingContainerTheme = {
  base: {
    ai: 'Ai(c)',
    flxg: 'Flxg(1)',
    jc: 'Jc(c)',
    w: 'W(100%)'
  }
}

class Languages extends Component {
  componentDidMount () {
    this.props.handleInitLoad()
  }

  render () {
    const {
      searchText,
      size,
      sort,
      page,
      results,
      totalCount,
      permission,
      user,
      loading,
      deleting,
      notification,
      handleDelete,
      handleOnUpdatePageSize,
      handleOnUpdateSort,
      handleOnUpdateSearch,
      handlePageChanged
    } = this.props

    // TODO: tweak for testing
    const totalPage = Math.floor(totalCount / size) +
   (totalCount % size > 0 ? 1 : 0)
  // const totalPage = 1

    return (
      <Page>
        {notification &&
        (<Notification severity={notification.severity}
          message={notification.message}
          details={notification.details}
          show={!!notification} />
        )
        }
        <Helmet title='Languages' />
        <ScrollView>
          <View theme={contentViewContainerTheme}>

                    Languages {!loading &&
                      {totalCount}}

                  {permission.canAddLocale &&
                    <Button className='btn-primary'>
                       Add new language
                    </Button>
                  }
                  {loading
                      ? <View theme={loadingContainerTheme}>
                        <LoaderText theme={{ base: { fz: 'Fz(ms1)' } }}
                          size='2' loading />
                      </View>
                      : (

                          <FormGroup>
                            <InputGroup>
                              <FormControl type='text'
                                defaultValue={searchText}
                                onChange={handleOnUpdateSearch} />
                              <InputGroup.Button>
                                <Button>

                                </Button>
                              </InputGroup.Button>
                            </InputGroup>
                          </FormGroup>

                          <FormControl componentClass='select'
                            className='pull-right' id='sort-options'
                            onChange={handleOnUpdateSort} value={sort.value}>
                            {sortOption.map(function (sort, i) {
                              return <option key={i} value={sort.value}>
                                {sort.display}</option>
                            })}
                          </FormControl>

                          Show
                          <FormControl inline componentClass='select'
                            onChange={handleOnUpdatePageSize} value={size}
                            id='page-size-options'>
                            {pageSizeOption.map(function (value, i) {
                              return <option key={i} value={value}>
                                {value}</option>
                            })}
                          </FormControl>

                          <Pagination
                            bsSize='medium'
                            items={totalPage}
                            activePage={page}
                            onSelect={handlePageChanged} />

)
                  }
                  {!loading &&

                            Language

                        {results.map(function (value, i) {
                          return <Entry key={i} locale={value}
                            userLanguageTeams={user.languageTeams}
                            permission={permission}
                            handleDelete={handleDelete}
                            isDeleting={deleting} />
                        })}

}

          </View>
        </ScrollView>
      </Page>
    )
  }
}

Languages.propTypes = {
  page: PropTypes.number,
  notification: PropTypes.object,
  permission: PropTypes.object,
  user: PropTypes.object,
  searchText: PropTypes.string,
  size: PropTypes.number,
  sort: PropTypes.object,
  results: PropTypes.array,
  totalCount: PropTypes.number,
  loading: PropTypes.bool,
  deleting: PropTypes.bool,
  handleInitLoad: PropTypes.func,
  handleDelete: PropTypes.func,
  handleOnUpdatePageSize: PropTypes.func,
  handleOnUpdateSort: PropTypes.func,
  handleOnUpdateSearch: PropTypes.func,
  handlePageChanged: PropTypes.func
}

const mapStateToProps = (state) => {
  let urlSort = state.routing.location.query.sort
  if (urlSort) {
    urlSort = find(sortOption, function (sort) {
      return sort.value === urlSort
    })
    if (!urlSort) {
      urlSort = sortOption[0]
    }
  } else {
    urlSort = sortOption[0]
  }

  const {
    locales,
    loading,
    permission,
    user,
    notification,
    deleting
  } = state.languages
  return {
    searchText: state.routing.location.query.search || '',
    page: parseInt(state.routing.location.query.page) || 1,
    size: parseInt(state.routing.location.query.size) || pageSizeOption[0],
    sort: urlSort,
    results: locales.results,
    totalCount: locales.totalCount,
    loading,
    permission,
    user,
    notification,
    deleting
  }
}

const mapDispatchToProps = (dispatch) => {
  const updateSearch = debounce((val) =>
    dispatch(handleUpdateSearch(val)), 200)

  return {
    handleInitLoad: () => {
      dispatch(initialLoad())
    },
    handleDelete: (localeId) => {
      dispatch(handleDelete(localeId))
    },
    handleOnUpdatePageSize: (event) => {
      dispatch(handleUpdatePageSize(event.target.value || ''))
    },
    handleOnUpdateSort: (event) => {
      dispatch(handleUpdateSort(event.target.value || ''))
    },
    handleOnUpdateSearch: (event) => {
      updateSearch(event.target.value || '')
    },
    handlePageChanged: (pageNum) => {
      console.info('update page here', pageNum)
    }
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(Languages)
<|endoftext|>


<commit_before>Slingshot.S3Storage = {

  accessId: "AWSAccessKeyId",
  secretKey: "AWSSecretAccessKey",

  directiveMatch: {
    bucket: String,
    bucketUrl: Match.OneOf(String, Function),

    region: Match.Where(function (region) {
      check(region, String);

      return /^[a-z]{2}-\w+-\d+$/.test(region);
    }),

    AWSAccessKeyId: String,
    AWSSecretAccessKey: String,

    acl: Match.Optional(Match.Where(function (acl) {
      check(acl, String);

      return [
          "private",
          "public-read",
          "public-read-write",
          "authenticated-read",
          "bucket-owner-read",
          "bucket-owner-full-control",
          "log-delivery-write"
        ].indexOf(acl) >= 0;
    })),

    key: Match.OneOf(String, Function),

    expire: Match.Where(function (expire) {
      check(expire, Number);

      return expire > 0;
    }),

    cacheControl: Match.Optional(String),
    contentDisposition: Match.Optional(Match.OneOf(String, Function, null))
  },

  directiveDefault: _.chain(Meteor.settings)
    .pick("AWSAccessKeyId", "AWSSecretAccessKey")
    .extend({
      bucket: Meteor.settings.S3Bucket,
      bucketUrl: function (bucket, region) {
        var bucketDomain = "s3-" + region + ".amazonaws.com";
        if (region === "us-east-1")
          bucketDomain = "s3.amazonaws.com";

        if (bucket.indexOf(".") !== -1)
          return "https://" + bucketDomain + "/" + bucket;

        return "https://" + bucket + "." + bucketDomain;
      },
      region: Meteor.settings.AWSRegion || "us-east-1",
      expire: 5 * 60 * 1000 //in 5 minutes
    })
    .value(),

  getContentDisposition: function (method, directive, file, meta) {
    var getContentDisposition = directive.contentDisposition;

    if (!_.isFunction(getContentDisposition)) {
      getContentDisposition = function () {
        var filename = file.name && encodeURIComponent(file.name);

        return directive.contentDisposition || filename &&
          "inline; filename=\"" + filename + "\"; filename*=utf-8''" +
          filename;
      };
    }

    return getContentDisposition.call(method, file, meta);
  },

  /**
   *
   * @param {{userId: String}} method
   * @param {Directive} directive
   * @param {FileInfo} file
   * @param {Object} [meta]
   *
   * @returns {UploadInstructions}
   */

  upload: function (method, directive, file, meta) {
    var policy = new Slingshot.StoragePolicy()
          .expireIn(directive.expire)
          .contentLength(0, Math.min(file.size, directive.maxSize || Infinity)),

        payload = {
          key: _.isFunction(directive.key) ?
            directive.key.call(method, file, meta) : directive.key,

          bucket: directive.bucket,

          "Content-Type": file.type,
          "acl": directive.acl,

          "Cache-Control": directive.cacheControl,
          "Content-Disposition": this.getContentDisposition(method, directive,
            file, meta)
        },

        bucketUrl = _.isFunction(directive.bucketUrl) ?
          directive.bucketUrl(directive.bucket, directive.region) :
          directive.bucketUrl,

        downloadUrl = [
          (directive.cdn || bucketUrl),
          payload.key
        ].map(function (part) {
            return part.replace(/\/+$/, '');
          }).join("/");

    this.applySignature(payload, policy, directive);

    return {
      upload: bucketUrl,
      download: downloadUrl,
      postData: [{
        name: "key",
        value: payload.key
      }].concat(_.chain(payload).omit("key").map(function (value, name) {
          return !_.isUndefined(value) && {
              name: name,
              value: value
            };
        }).compact().value())
    };
  },

  /** Applies signature an upload payload
   *
   * @param {Object} payload - Data to be upload along with file
   * @param {Slingshot.StoragePolicy} policy
   * @param {Directive} directive
   */

  applySignature: function (payload, policy, directive) {
    var now =  new Date(),
        today = now.getUTCFullYear() + formatNumber(now.getUTCMonth() + 1, 2) +
          formatNumber(now.getUTCDate(), 2),
        service = "s3";

    _.extend(payload, {
      "x-amz-algorithm": "AWS4-HMAC-SHA256",
      "x-amz-credential": [
        directive[this.accessId],
        today,
        directive.region,
        service,
        "aws4_request"
      ].join("/"),
      "x-amz-date": today + "T000000Z"
    });

    payload.policy = policy.match(payload).stringify();
    payload["x-amz-signature"] = this.signAwsV4(payload.policy,
      directive[this.secretKey], today, directive.region, service);
  },

  /** Generate a AWS Signature Version 4
   *
   * @param {String} policy - Base64 encoded policy to sign.
   * @param {String} secretKey - AWSSecretAccessKey
   * @param {String} date - Signature date (yyyymmdd)
   * @param {String} region - AWS Data-Center region
   * @param {String} service - type of service to use
   * @returns {String} hex encoded HMAC-256 signature
   */

  signAwsV4: function (policy, secretKey, date, region, service) {
    var dateKey = hmac256("AWS4" + secretKey, date),
        dateRegionKey = hmac256(dateKey, region),
        dateRegionServiceKey= hmac256(dateRegionKey, service),
        signingKey = hmac256(dateRegionServiceKey, "aws4_request");

    return hmac256(signingKey, policy, "hex");
  }
};

Slingshot.S3Storage.TempCredentials = _.defaults({

  directiveMatch: _.chain(Slingshot.S3Storage.directiveMatch)
    .omit("AWSAccessKeyId", "AWSSecretAccessKey")
    .extend({
      temporaryCredentials: Function
    })
    .value(),

  directiveDefault: _.omit(Slingshot.S3Storage.directiveDefault,
    "AWSAccessKeyId", "AWSSecretAccessKey"),

  applySignature: function (payload, policy, directive) {
    var credentials = directive.temporaryCredentials(directive.expire);

    check(credentials, Match.ObjectIncluding({
      AccessKeyId: Slingshot.S3Storage.directiveMatch.AWSAccessKeyId,
      SecretAccessKey: Slingshot.S3Storage.directiveMatch.AWSSecretAccessKey,
      SessionToken: String
    }));

    payload["x-amz-security-token"] = credentials.SessionToken;

    return Slingshot.S3Storage.applySignature
      .call(this, payload, policy, _.defaults({
        AWSAccessKeyId: credentials.AccessKeyId,
        AWSSecretAccessKey: credentials.SecretAccessKey
      }, directive));
  }
}, Slingshot.S3Storage);

function formatNumber(num, digits) {
  var string = String(num);

  return Array(digits - string.length + 1).join("0").concat(string);
}

var crypto = Npm.require("crypto");

function hmac256(key, data, encoding) {
  /* global Buffer: false */
  return crypto
    .createHmac("sha256", key)
    .update(new Buffer(data, "utf-8"))
    .digest(encoding);
}
<commit_msg>Update bucket domain for AWS beijing region.<commit_after>Slingshot.S3Storage = {

  accessId: "AWSAccessKeyId",
  secretKey: "AWSSecretAccessKey",

  directiveMatch: {
    bucket: String,
    bucketUrl: Match.OneOf(String, Function),

    region: Match.Where(function (region) {
      check(region, String);

      return /^[a-z]{2}-\w+-\d+$/.test(region);
    }),

    AWSAccessKeyId: String,
    AWSSecretAccessKey: String,

    acl: Match.Optional(Match.Where(function (acl) {
      check(acl, String);

      return [
          "private",
          "public-read",
          "public-read-write",
          "authenticated-read",
          "bucket-owner-read",
          "bucket-owner-full-control",
          "log-delivery-write"
        ].indexOf(acl) >= 0;
    })),

    key: Match.OneOf(String, Function),

    expire: Match.Where(function (expire) {
      check(expire, Number);

      return expire > 0;
    }),

    cacheControl: Match.Optional(String),
    contentDisposition: Match.Optional(Match.OneOf(String, Function, null))
  },

  directiveDefault: _.chain(Meteor.settings)
    .pick("AWSAccessKeyId", "AWSSecretAccessKey")
    .extend({
      bucket: Meteor.settings.S3Bucket,
      bucketUrl: function (bucket, region) {
        var bucketDomain = "s3-" + region + ".amazonaws.com";
        if (region === "us-east-1")
          bucketDomain = "s3.amazonaws.com";
        if (region === "cn-north-1")
          bucketDomain = "s3.cn-north-1.amazonaws.com.cn";

        if (bucket.indexOf(".") !== -1)
          return "https://" + bucketDomain + "/" + bucket;

        return "https://" + bucket + "." + bucketDomain;
      },
      region: Meteor.settings.AWSRegion || "us-east-1",
      expire: 5 * 60 * 1000 //in 5 minutes
    })
    .value(),

  getContentDisposition: function (method, directive, file, meta) {
    var getContentDisposition = directive.contentDisposition;

    if (!_.isFunction(getContentDisposition)) {
      getContentDisposition = function () {
        var filename = file.name && encodeURIComponent(file.name);

        return directive.contentDisposition || filename &&
          "inline; filename=\"" + filename + "\"; filename*=utf-8''" +
          filename;
      };
    }

    return getContentDisposition.call(method, file, meta);
  },

  /**
   *
   * @param {{userId: String}} method
   * @param {Directive} directive
   * @param {FileInfo} file
   * @param {Object} [meta]
   *
   * @returns {UploadInstructions}
   */

  upload: function (method, directive, file, meta) {
    var policy = new Slingshot.StoragePolicy()
          .expireIn(directive.expire)
          .contentLength(0, Math.min(file.size, directive.maxSize || Infinity)),

        payload = {
          key: _.isFunction(directive.key) ?
            directive.key.call(method, file, meta) : directive.key,

          bucket: directive.bucket,

          "Content-Type": file.type,
          "acl": directive.acl,

          "Cache-Control": directive.cacheControl,
          "Content-Disposition": this.getContentDisposition(method, directive,
            file, meta)
        },

        bucketUrl = _.isFunction(directive.bucketUrl) ?
          directive.bucketUrl(directive.bucket, directive.region) :
          directive.bucketUrl,

        downloadUrl = [
          (directive.cdn || bucketUrl),
          payload.key
        ].map(function (part) {
            return part.replace(/\/+$/, '');
          }).join("/");

    this.applySignature(payload, policy, directive);

    return {
      upload: bucketUrl,
      download: downloadUrl,
      postData: [{
        name: "key",
        value: payload.key
      }].concat(_.chain(payload).omit("key").map(function (value, name) {
          return !_.isUndefined(value) && {
              name: name,
              value: value
            };
        }).compact().value())
    };
  },

  /** Applies signature an upload payload
   *
   * @param {Object} payload - Data to be upload along with file
   * @param {Slingshot.StoragePolicy} policy
   * @param {Directive} directive
   */

  applySignature: function (payload, policy, directive) {
    var now =  new Date(),
        today = now.getUTCFullYear() + formatNumber(now.getUTCMonth() + 1, 2) +
          formatNumber(now.getUTCDate(), 2),
        service = "s3";

    _.extend(payload, {
      "x-amz-algorithm": "AWS4-HMAC-SHA256",
      "x-amz-credential": [
        directive[this.accessId],
        today,
        directive.region,
        service,
        "aws4_request"
      ].join("/"),
      "x-amz-date": today + "T000000Z"
    });

    payload.policy = policy.match(payload).stringify();
    payload["x-amz-signature"] = this.signAwsV4(payload.policy,
      directive[this.secretKey], today, directive.region, service);
  },

  /** Generate a AWS Signature Version 4
   *
   * @param {String} policy - Base64 encoded policy to sign.
   * @param {String} secretKey - AWSSecretAccessKey
   * @param {String} date - Signature date (yyyymmdd)
   * @param {String} region - AWS Data-Center region
   * @param {String} service - type of service to use
   * @returns {String} hex encoded HMAC-256 signature
   */

  signAwsV4: function (policy, secretKey, date, region, service) {
    var dateKey = hmac256("AWS4" + secretKey, date),
        dateRegionKey = hmac256(dateKey, region),
        dateRegionServiceKey= hmac256(dateRegionKey, service),
        signingKey = hmac256(dateRegionServiceKey, "aws4_request");

    return hmac256(signingKey, policy, "hex");
  }
};

Slingshot.S3Storage.TempCredentials = _.defaults({

  directiveMatch: _.chain(Slingshot.S3Storage.directiveMatch)
    .omit("AWSAccessKeyId", "AWSSecretAccessKey")
    .extend({
      temporaryCredentials: Function
    })
    .value(),

  directiveDefault: _.omit(Slingshot.S3Storage.directiveDefault,
    "AWSAccessKeyId", "AWSSecretAccessKey"),

  applySignature: function (payload, policy, directive) {
    var credentials = directive.temporaryCredentials(directive.expire);

    check(credentials, Match.ObjectIncluding({
      AccessKeyId: Slingshot.S3Storage.directiveMatch.AWSAccessKeyId,
      SecretAccessKey: Slingshot.S3Storage.directiveMatch.AWSSecretAccessKey,
      SessionToken: String
    }));

    payload["x-amz-security-token"] = credentials.SessionToken;

    return Slingshot.S3Storage.applySignature
      .call(this, payload, policy, _.defaults({
        AWSAccessKeyId: credentials.AccessKeyId,
        AWSSecretAccessKey: credentials.SecretAccessKey
      }, directive));
  }
}, Slingshot.S3Storage);

function formatNumber(num, digits) {
  var string = String(num);

  return Array(digits - string.length + 1).join("0").concat(string);
}

var crypto = Npm.require("crypto");

function hmac256(key, data, encoding) {
  /* global Buffer: false */
  return crypto
    .createHmac("sha256", key)
    .update(new Buffer(data, "utf-8"))
    .digest(encoding);
}
<|endoftext|>


<commit_before>var componentEdit = require('../controllers/component-edit'),
  componentEditName = 'component-edit',
  db = require('./edit/db'),
  dom = require('./dom'),
  ds = require('dollar-slice'),
  edit = require('./edit'),
  references = require('./references'),
  select = require('./select');

/**
 * Test if element is a component and not the toolbar.
 * @param {Element} el
 * @returns {boolean}
 */
function isComponent(el) {
  var ref = el instanceof Element && el.getAttribute(references.referenceAttribute),
    name = ref && references.getComponentNameFromReference(ref);

  return !!(name && name !== 'editor-toolbar');
}

/**
 * Returns an array of elements that are components from an el and its children.
 * @param {Element} el  Note: element must exist in the DOM so that querySelectorAll works.
 * @returns {array}
 */
function findComponents(el) {
  var children = [].slice.call(dom.findAll(el, '[' + references.referenceAttribute + ']')),
    selfAndChildren = [el].concat(children),
    components = selfAndChildren.filter(isComponent);

  return components;
}

/**
 * Adds selector to a component element. Is async because needs to get data.
 * @param {Element} el    The component element.
 * @returns {Promise|undefined}
 */
function addComponentSelector(el) {
  var ref = el.getAttribute(references.referenceAttribute);

  return edit.getData(ref)
    .catch(function (e) {
      // e.g. tried to get the schema of a component, and it 404'd
      if (e.message === '404') {
        return {}; // data is empty
      } else {
        return e; // something weird happened. don't eat the error
      }
    })
    .then(function (data) {
      var options = {
        ref: ref,
        path: el.getAttribute(references.editableAttribute),
        data: data
      };

      select.handler(el, options);
      return el;
    });
}

/**
 * Add handlers to all of the element and all of its children that are components.
 * @param {Element} el
 * @returns {Promise}
 */
function addComponentsHandlers(el) {
  ds.controller(componentEditName, componentEdit);
  // First, add the selectors.
  return Promise.all(findComponents(el).map(addComponentSelector))
    .then(function (els) {
      // Then, add controllers/decorators after all selectors have be added.
      return Promise.all(els.map(function (componentEl) {
        return ds.get(componentEditName, componentEl); // async because gets data for editable fields.
      }));
    });
}

/**
 * Reload component with latest HTML from the server.
 * @param {string} ref
 * @returns {Promise}
 */
function reloadComponent(ref) {
  return db.getHTML(ref)
    .then(function (el) {
      var currentEls = dom.findAll('[' + references.referenceAttribute + '="' + ref + '"]');

      switch (currentEls.length) {
        case 0: // Element was already removed from the DOM.
          break;
        case 1: // Normal case.
          dom.replaceElement(currentEls[0], el);
          return addComponentsHandlers(el);
        default: // Edge case (ref used multiple times on one page).
          window.location.reload();
      }
    });
}

exports.addComponentsHandlers = addComponentsHandlers;
exports.reloadComponent = reloadComponent;
<commit_msg>don't pass empty obj around<commit_after>var componentEdit = require('../controllers/component-edit'),
  componentEditName = 'component-edit',
  db = require('./edit/db'),
  dom = require('./dom'),
  ds = require('dollar-slice'),
  edit = require('./edit'),
  references = require('./references'),
  select = require('./select');

/**
 * Test if element is a component and not the toolbar.
 * @param {Element} el
 * @returns {boolean}
 */
function isComponent(el) {
  var ref = el instanceof Element && el.getAttribute(references.referenceAttribute),
    name = ref && references.getComponentNameFromReference(ref);

  return !!(name && name !== 'editor-toolbar');
}

/**
 * Returns an array of elements that are components from an el and its children.
 * @param {Element} el  Note: element must exist in the DOM so that querySelectorAll works.
 * @returns {array}
 */
function findComponents(el) {
  var children = [].slice.call(dom.findAll(el, '[' + references.referenceAttribute + ']')),
    selfAndChildren = [el].concat(children),
    components = selfAndChildren.filter(isComponent);

  return components;
}

/**
 * Adds selector to a component element. Is async because needs to get data.
 * @param {Element} el    The component element.
 * @returns {Promise|undefined}
 */
function addComponentSelector(el) {
  var ref = el.getAttribute(references.referenceAttribute);

  return edit.getData(ref)
    .catch(function (e) {
      // e.g. tried to get the schema of a component, and it 404'd
      if (e.message === '404') {
        return null; // data is empty
      } else {
        return e; // something weird happened. don't eat the error
      }
    })
    .then(function (data) {
      var options = {
        ref: ref,
        path: el.getAttribute(references.editableAttribute),
        data: data || {}
      };

      select.handler(el, options);
      return el;
    });
}

/**
 * Add handlers to all of the element and all of its children that are components.
 * @param {Element} el
 * @returns {Promise}
 */
function addComponentsHandlers(el) {
  ds.controller(componentEditName, componentEdit);
  // First, add the selectors.
  return Promise.all(findComponents(el).map(addComponentSelector))
    .then(function (els) {
      // Then, add controllers/decorators after all selectors have be added.
      return Promise.all(els.map(function (componentEl) {
        return ds.get(componentEditName, componentEl); // async because gets data for editable fields.
      }));
    });
}

/**
 * Reload component with latest HTML from the server.
 * @param {string} ref
 * @returns {Promise}
 */
function reloadComponent(ref) {
  return db.getHTML(ref)
    .then(function (el) {
      var currentEls = dom.findAll('[' + references.referenceAttribute + '="' + ref + '"]');

      switch (currentEls.length) {
        case 0: // Element was already removed from the DOM.
          break;
        case 1: // Normal case.
          dom.replaceElement(currentEls[0], el);
          return addComponentsHandlers(el);
        default: // Edge case (ref used multiple times on one page).
          window.location.reload();
      }
    });
}

exports.addComponentsHandlers = addComponentsHandlers;
exports.reloadComponent = reloadComponent;
<|endoftext|>


<commit_before>import WRISerializer from 'wri-json-api-serializer';

// utils
import { WRIAPI } from 'utils/axios';
import { logger } from 'utils/logs';

/**
 * Fetches widgets according to params.
 *
 * @param {Object} params - params sent to the API.
 * @param {Object} headers - headers used in the request
 * @param {boolean} _meta - flag indicating whether meta information should be
 * included in the response or not
 * @returns {Object[]} array of serialized widgets.
 */
export const fetchWidgets = (params = {}, headers = {}, _meta = false) => {
  logger.info('fetches widgets');
  return WRIAPI.get('widget', {
    headers: {
      ...WRIAPI.defaults.headers,
      // TO-DO: forces the API to not cache, this should be removed at some point
      'Upgrade-Insecure-Requests': 1,
      ...headers
    },
    params: {
      env: process.env.API_ENV,
      application: process.env.APPLICATIONS,
      ...params
    },
    transformResponse: [].concat(
      WRIAPI.defaults.transformResponse,
      (({ data, meta }) => ({ widgets: data, meta }))
    )
  })
    .then((response) => {
      const { status, statusText, data } = response;
      const { widgets, meta } = data;
      if (status >= 300) {
        logger.error('Error fetching widgets:', `${status}: ${statusText}`);
        throw new Error(statusText);
      }

      if (_meta) {
        return {
          widgets: WRISerializer({ data: widgets }),
          meta
        };
      }

      return WRISerializer({ data: widgets });
    })
    .catch((response) => {
      const { status, statusText } = response;

      logger.error(`Error fetching widgets: ${status}: ${statusText}`);
      throw new Error(`Error fetching widgets: ${status}: ${statusText}`);
    });
};

/**
 * fetches data for a specific widget.
 *
 * @param {String} id - widget id.
 * @param {Object} params - params sent to the API.
 * @returns {Object} serialized specified widget.
 */
export const fetchWidget = (id, params = {}) => {
  if (!id) throw Error('The widget id is mandatory to perform this request (fetchWidget).');
  logger.info(`Fetch widget: ${id}`);

  return WRIAPI.get(`widget/${id}`, {
    headers: {
      ...WRIAPI.defaults.headers,
      // TO-DO: forces the API to not cache, this should be removed at some point
      'Upgrade-Insecure-Requests': 1
    },
    params: {
      ...params,
      env: process.env.API_ENV,
      application: process.env.APPLICATIONS
    }
  })
    .then((response) => {
      const { status, statusText, data } = response;

      if (status >= 300) {
        if (status === 404) {
          logger.debug(`Widget '${id}' not found, ${status}: ${statusText}`);
        } else {
          logger.error(`Error fetching widget: ${id}: ${status}: ${statusText}`);
        }
        throw new Error(statusText);
      }
      return WRISerializer(data);
    })
    .catch(({ response }) => {
      const { status, statusText } = response;

      logger.error(`Error fetching widget ${id}: ${status}: ${statusText}`);
      throw new Error(`Error fetching widget ${id}: ${status}: ${statusText}`);
    });
};

/**
 * Deletes the specified widget.
 * This method requires authentication.
 *
 * @param {*} widgetId - widget ID to be deleted.
 * @param {string} datasetId - dataset ID the widget belongs to
 * @param {string} token - user's token.
 * @returns {Object} response.
 */
export const deleteWidget = (widgetId, datasetId, token) => {
  logger.info(`Delete widget: ${widgetId}`);

  return WRIAPI.delete(`dataset/${datasetId}/widget/${widgetId}`, {
    headers: {
      ...WRIAPI.defaults.headers,
      Authorization: token
    }
  })
    .then((response) => {
      const { status, statusText } = response;

      if (status >= 300) {
        if (status === 404) {
          logger.debug(`Widget '${widgetId}' not found, ${status}: ${statusText}`);
        } else {
          logger.error(`Error deleting widget: ${widgetId}: ${status}: ${statusText}`);
        }
        throw new Error(statusText);
      }
      return response;
    })
    .catch(({ response }) => {
      const { status, statusText } = response;

      logger.error(`Error deleting widget ${widgetId}: ${status}: ${statusText}`);
      throw new Error(`Error deleting widget ${widgetId}: ${status}: ${statusText}`);
    });
};

/**
 * Updates data for the widget provided.
 *
 * @param {Object} widget - widget data.
 * @param {string} token - user's token.
 * @returns {Object} serialized specified widget.
 */
export const updateWidget = (widget, token) => {
  logger.info(`Update widget: ${widget.id}`);
  return WRIAPI.patch(`widget/${widget.id}`, widget, { headers: { Authorization: token } })
    .then(response => WRISerializer(response.data))
    .catch(({ response }) => {
      const { status, statusText } = response;
      logger.error(`Error updating widget ${widget.id}: ${status}: ${statusText}`);
      throw new Error(`Error updating widget ${widget.id}: ${status}: ${statusText}`);
    });
};

/**
 * Creates a new widget.
 *
 * @param {Object} widget - widget data.
 * @param {string} datasetId - Dataset ID the widget belongs to.
 * @param {string} token - user's token.
 * @returns {Object} serialized widget.
 */
export const createWidget = (widget, datasetId, token) => {
  logger.info('Create widget');
  return WRIAPI.post(`dataset/${datasetId}/widget`,
    {
      application: process.env.APPLICATIONS,
      env: process.env.API_ENV,
      ...widget
    },
    { headers: { Authorization: token } })
    .then(response => WRISerializer(response.data))
    .catch(({ response }) => {
      const { status, statusText } = response;
      logger.error(`Error creating widget ${status}: ${statusText}`);
      throw new Error(`Error creating widget ${status}: ${statusText}`);
    });
};

/**
 * Fetches the metadata associated to the widget provided.
 *
 * @param {string} widgetId - widget data.
 * @param {string} datasetId - Dataset ID the widget belongs to.
 * @param {string} token - user's token.
 * @param {Object} params - request parameters.
 * @returns {Object} serialized widget metadata.
 */
export const fetchWidgetMetadata = (widgetId, datasetId, token, params = {}) => {
  logger.info(`Update widget metadata: ${widgetId}`);
  return WRIAPI.fetch(`dataset/${datasetId}/widget/${widgetId}/metadata`,
    {
      headers: { Authorization: token },
      params: {
        application: process.env.APPLICATIONS,
        env: process.env.API_ENV,
        ...params
      }
    })
    .then(response => WRISerializer(response.data))
    .catch(({ response }) => {
      const { status, statusText } = response;
      logger.error(`Error fetching widget metadata ${widgetId}: ${status}: ${statusText}`);
      throw new Error(`Error fetching widget metadata ${widgetId}: ${status}: ${statusText}`);
    });
};

/**
 * Updates the metadata for the widget provided.
 *
 * @param {Object} widget - widget data.
 * @param {string} datasetId - Dataset ID the widget belongs to.
 * @param {Object} metadata - metadata to be updated.
 * @param {string} token - user's token.
 * @returns {Object} serialized specified widget.
 */
export const updateWidgetMetadata = (widgetId, datasetId, metadata, token) => {
  logger.info(`Update widget metadata: ${widgetId}`);
  return WRIAPI.patch(`dataset/${datasetId}/widget/${widgetId}/metadata`,
    metadata,
    { headers: { Authorization: token } })
    .then(response => WRISerializer(response.data))
    .catch(({ response }) => {
      const { status, statusText } = response;
      logger.error(`Error updating widget metadata ${widgetId}: ${status}: ${statusText}`);
      throw new Error(`Error updating widget metadata ${widgetId}: ${status}: ${statusText}`);
    });
};

/**
 * Creates the metadata for the widget provided.
 *
 * @param {string} widgetId - widget id.
 * @param {string} datasetId - Dataset ID the widget belongs to.
 * @param {Object} metadata - metadata to be updated.
 * @param {string} token - user's token.
 * @returns {Object} serialized specified widget.
 */
export const createWidgetMetadata = (widgetId, datasetId, metadata, token) => {
  logger.info(`Update widget metadata: ${widgetId}`);
  return WRIAPI.post(`dataset/${datasetId}/widget/${widgetId}/metadata`,
    {
      ...metadata,
      application: process.env.APPLICATIONS,
      env: process.env.API_ENV
    },
    { headers: { Authorization: token } })
    .then(response => WRISerializer(response.data))
    .catch(({ response }) => {
      const { status, statusText } = response;
      logger.error(`Error creating widget metadata ${widgetId}: ${status}: ${statusText}`);
      throw new Error(`Error creating widget metadata ${widgetId}: ${status}: ${statusText}`);
    });
};

export default {
  fetchWidgets,
  fetchWidget,
  updateWidget,
  createWidget,
  fetchWidgetMetadata,
  updateWidgetMetadata,
  createWidgetMetadata,
  deleteWidget
};
<commit_msg>fix widget creation<commit_after>import WRISerializer from 'wri-json-api-serializer';

// utils
import { WRIAPI } from 'utils/axios';
import { logger } from 'utils/logs';

/**
 * Fetches widgets according to params.
 *
 * @param {Object} params - params sent to the API.
 * @param {Object} headers - headers used in the request
 * @param {boolean} _meta - flag indicating whether meta information should be
 * included in the response or not
 * @returns {Object[]} array of serialized widgets.
 */
export const fetchWidgets = (params = {}, headers = {}, _meta = false) => {
  logger.info('fetches widgets');
  return WRIAPI.get('widget', {
    headers: {
      ...WRIAPI.defaults.headers,
      // TO-DO: forces the API to not cache, this should be removed at some point
      'Upgrade-Insecure-Requests': 1,
      ...headers
    },
    params: {
      env: process.env.API_ENV,
      application: process.env.APPLICATIONS,
      ...params
    },
    transformResponse: [].concat(
      WRIAPI.defaults.transformResponse,
      (({ data, meta }) => ({ widgets: data, meta }))
    )
  })
    .then((response) => {
      const { status, statusText, data } = response;
      const { widgets, meta } = data;
      if (status >= 300) {
        logger.error('Error fetching widgets:', `${status}: ${statusText}`);
        throw new Error(statusText);
      }

      if (_meta) {
        return {
          widgets: WRISerializer({ data: widgets }),
          meta
        };
      }

      return WRISerializer({ data: widgets });
    })
    .catch((response) => {
      const { status, statusText } = response;

      logger.error(`Error fetching widgets: ${status}: ${statusText}`);
      throw new Error(`Error fetching widgets: ${status}: ${statusText}`);
    });
};

/**
 * fetches data for a specific widget.
 *
 * @param {String} id - widget id.
 * @param {Object} params - params sent to the API.
 * @returns {Object} serialized specified widget.
 */
export const fetchWidget = (id, params = {}) => {
  if (!id) throw Error('The widget id is mandatory to perform this request (fetchWidget).');
  logger.info(`Fetch widget: ${id}`);

  return WRIAPI.get(`widget/${id}`, {
    headers: {
      ...WRIAPI.defaults.headers,
      // TO-DO: forces the API to not cache, this should be removed at some point
      'Upgrade-Insecure-Requests': 1
    },
    params: {
      ...params,
      env: process.env.API_ENV,
      application: process.env.APPLICATIONS
    }
  })
    .then((response) => {
      const { status, statusText, data } = response;

      if (status >= 300) {
        if (status === 404) {
          logger.debug(`Widget '${id}' not found, ${status}: ${statusText}`);
        } else {
          logger.error(`Error fetching widget: ${id}: ${status}: ${statusText}`);
        }
        throw new Error(statusText);
      }
      return WRISerializer(data);
    })
    .catch(({ response }) => {
      const { status, statusText } = response;

      logger.error(`Error fetching widget ${id}: ${status}: ${statusText}`);
      throw new Error(`Error fetching widget ${id}: ${status}: ${statusText}`);
    });
};

/**
 * Deletes the specified widget.
 * This method requires authentication.
 *
 * @param {*} widgetId - widget ID to be deleted.
 * @param {string} datasetId - dataset ID the widget belongs to
 * @param {string} token - user's token.
 * @returns {Object} response.
 */
export const deleteWidget = (widgetId, datasetId, token) => {
  logger.info(`Delete widget: ${widgetId}`);

  return WRIAPI.delete(`dataset/${datasetId}/widget/${widgetId}`, {
    headers: {
      ...WRIAPI.defaults.headers,
      Authorization: token
    }
  })
    .then((response) => {
      const { status, statusText } = response;

      if (status >= 300) {
        if (status === 404) {
          logger.debug(`Widget '${widgetId}' not found, ${status}: ${statusText}`);
        } else {
          logger.error(`Error deleting widget: ${widgetId}: ${status}: ${statusText}`);
        }
        throw new Error(statusText);
      }
      return response;
    })
    .catch(({ response }) => {
      const { status, statusText } = response;

      logger.error(`Error deleting widget ${widgetId}: ${status}: ${statusText}`);
      throw new Error(`Error deleting widget ${widgetId}: ${status}: ${statusText}`);
    });
};

/**
 * Updates data for the widget provided.
 *
 * @param {Object} widget - widget data.
 * @param {string} token - user's token.
 * @returns {Object} serialized specified widget.
 */
export const updateWidget = (widget, token) => {
  logger.info(`Update widget: ${widget.id}`);
  return WRIAPI.patch(`widget/${widget.id}`, widget, { headers: { Authorization: token } })
    .then(response => WRISerializer(response.data))
    .catch(({ response }) => {
      const { status, statusText } = response;
      logger.error(`Error updating widget ${widget.id}: ${status}: ${statusText}`);
      throw new Error(`Error updating widget ${widget.id}: ${status}: ${statusText}`);
    });
};

/**
 * Creates a new widget.
 *
 * @param {Object} widget - widget data.
 * @param {string} datasetId - Dataset ID the widget belongs to.
 * @param {string} token - user's token.
 * @returns {Object} serialized widget.
 */
export const createWidget = (widget, datasetId, token) => {
  logger.info('Create widget');
  return WRIAPI.post(`dataset/${datasetId}/widget`,
    {
      application: process.env.APPLICATIONS.split(','),
      env: process.env.API_ENV,
      ...widget
    },
    { headers: { Authorization: token } })
    .then(response => WRISerializer(response.data))
    .catch(({ response }) => {
      const { status, statusText } = response;
      logger.error(`Error creating widget ${status}: ${statusText}`);
      throw new Error(`Error creating widget ${status}: ${statusText}`);
    });
};

/**
 * Fetches the metadata associated to the widget provided.
 *
 * @param {string} widgetId - widget data.
 * @param {string} datasetId - Dataset ID the widget belongs to.
 * @param {string} token - user's token.
 * @param {Object} params - request parameters.
 * @returns {Object} serialized widget metadata.
 */
export const fetchWidgetMetadata = (widgetId, datasetId, token, params = {}) => {
  logger.info(`Update widget metadata: ${widgetId}`);
  return WRIAPI.fetch(`dataset/${datasetId}/widget/${widgetId}/metadata`,
    {
      headers: { Authorization: token },
      params: {
        application: process.env.APPLICATIONS,
        env: process.env.API_ENV,
        ...params
      }
    })
    .then(response => WRISerializer(response.data))
    .catch(({ response }) => {
      const { status, statusText } = response;
      logger.error(`Error fetching widget metadata ${widgetId}: ${status}: ${statusText}`);
      throw new Error(`Error fetching widget metadata ${widgetId}: ${status}: ${statusText}`);
    });
};

/**
 * Updates the metadata for the widget provided.
 *
 * @param {Object} widget - widget data.
 * @param {string} datasetId - Dataset ID the widget belongs to.
 * @param {Object} metadata - metadata to be updated.
 * @param {string} token - user's token.
 * @returns {Object} serialized specified widget.
 */
export const updateWidgetMetadata = (widgetId, datasetId, metadata, token) => {
  logger.info(`Update widget metadata: ${widgetId}`);
  return WRIAPI.patch(`dataset/${datasetId}/widget/${widgetId}/metadata`,
    metadata,
    { headers: { Authorization: token } })
    .then(response => WRISerializer(response.data))
    .catch(({ response }) => {
      const { status, statusText } = response;
      logger.error(`Error updating widget metadata ${widgetId}: ${status}: ${statusText}`);
      throw new Error(`Error updating widget metadata ${widgetId}: ${status}: ${statusText}`);
    });
};

/**
 * Creates the metadata for the widget provided.
 *
 * @param {string} widgetId - widget id.
 * @param {string} datasetId - Dataset ID the widget belongs to.
 * @param {Object} metadata - metadata to be updated.
 * @param {string} token - user's token.
 * @returns {Object} serialized specified widget.
 */
export const createWidgetMetadata = (widgetId, datasetId, metadata, token) => {
  logger.info(`Update widget metadata: ${widgetId}`);
  return WRIAPI.post(`dataset/${datasetId}/widget/${widgetId}/metadata`,
    {
      ...metadata,
      application: process.env.APPLICATIONS,
      env: process.env.API_ENV
    },
    { headers: { Authorization: token } })
    .then(response => WRISerializer(response.data))
    .catch(({ response }) => {
      const { status, statusText } = response;
      logger.error(`Error creating widget metadata ${widgetId}: ${status}: ${statusText}`);
      throw new Error(`Error creating widget metadata ${widgetId}: ${status}: ${statusText}`);
    });
};

export default {
  fetchWidgets,
  fetchWidget,
  updateWidget,
  createWidget,
  fetchWidgetMetadata,
  updateWidgetMetadata,
  createWidgetMetadata,
  deleteWidget
};
<|endoftext|>


<commit_before>
exports.czdiscovery = {
	'enabled': true,
	'key' : 'http-api'
}

exports.elasticsearch = {
	index : 'agenda',
	hosts : [{
		'host' : '10.7.50.110',
		'port' : 9200
	}]
}

exports.server = {
	'host' : '%IP%',
	'port' : 3000
}

exports.redis = {
	'host' : '10.7.50.119',
	'port' : 6379,
	'keyTTL' : 3600,
	db : 0
}

<commit_msg>update settings.sample.js<commit_after>
exports.czdiscovery = {
	'enabled': true,
	'key' : 'http-api'
}

exports.elasticsearch = {
	index : 'agenda',
	hosts : [{
		'host' : '10.7.50.110',
		'port' : 9200
	}]
}

exports.server = {
	'host' : '%IP%',
	'port' : 3000
}

exports.redis = {
	'host' : '10.7.50.119',
	'port' : 6379,
	'keyTTL' : 3600,
	'db' : 0
}

<|endoftext|>


<commit_before>'use strict';

var App = require('../../src/chrome/background');

// a trivial example test
describe('Sample test', function() {

  App.initialize();

  it('Should have a test variable set to 7', function() {
    expect(App.testVariable).toEqual(7);
  });

});
<commit_msg>Add spy example test<commit_after>'use strict';

var App = require('../../src/chrome/background');

// a trivial example test
describe('Sample test', function() {

  beforeAll(function() {
    spyOn(window.chrome.runtime.onInstalled, 'addListener');

    App.initialize();
  });

  it('Should have a test variable set to 7', function() {
    expect(App.testVariable).toEqual(7);
  });

  it('should set up event listeners', function() {
    expect(window.chrome.runtime.onInstalled.addListener).toHaveBeenCalled();
  });
});
<|endoftext|>


<commit_before>var $ = require('jquery');
var Attribution = require('../../../../src/geo/ui/attribution/attribution-view');
var Map = require('../../../../src/geo/map');

describe('geo/ui/attribution', function () {
  beforeEach(function () {
    this.keyEsc = function () {
      var e = $.Event('keydown');
      e.keyCode = 27; // ESC
      $(document).trigger(e);
    };

    this.map = new Map();
    spyOn(this.map, 'bind').and.callThrough();

    this.view = new Attribution({
      map: this.map
    });
    this.view.render();
    this.$button = this.view.$('.js-button');
    this.$text = this.view.$('.js-text');
    this.viewHasClass = function (className) {
      return this.view.$el.hasClass(className);
    };
  });

  describe('render', function () {
    it('should render properly', function () {
      expect(this.$button.length).toBe(1);
      expect(this.$text.length).toBe(1);
    });

    it('should render when map attributions has changed', function () {
      spyOn(this.view, 'render');
      this.$button.click();
      this.map.trigger('change:attribution');
      expect(this.view.render).toHaveBeenCalled();
    });

    it('should add GMaps properly when provider is not Leaflet', function () {
      expect(this.viewHasClass('CDB-Attribution--gmaps')).toBeFalsy();
      this.map.set('provider', 'gmaps');
      this.view.render();
      expect(this.viewHasClass('CDB-Attribution--gmaps')).toBeTruthy();
    });
  });

  describe('when the attributions are displayed', function () {
    beforeEach(function () {
      this.$button.click();
    });

    it('should hide attributions text when js-button is clicked', function () {
      this.$button.click();
      expect(this.viewHasClass('is-active')).toBeFalsy();
    });

    it('should collapse the attributions when ESC is pressed', function () {
      this.keyEsc();
      expect(this.viewHasClass('is-active')).toBeFalsy();
    });

    it('should collapse the attributions when user clicks on the document', function () {
      $(document).trigger('click');
      expect(this.viewHasClass('is-active')).toBeFalsy();
    });
  });

  describe('when attributions are hidden', function () {
    beforeEach(function () {
      this.$button.click();
      this.keyEsc();
    });

    it('should show attributions text when js-button is clicked', function () {
      this.$button.click();
      expect(this.viewHasClass('is-active')).toBeTruthy();
    });

    it('should not respond to ESC', function () {
      expect(this.viewHasClass('is-active')).toBeFalsy();
      this.keyEsc();
      expect(this.viewHasClass('is-active')).toBeFalsy();
    });

    it('should not respond to clicks on the document', function () {
      expect(this.viewHasClass('is-active')).toBeFalsy();
      $(document).trigger('click');
      expect(this.viewHasClass('is-active')).toBeFalsy();
    });
  });
});
<commit_msg>Added tests checking that attributions first state is correct<commit_after>var $ = require('jquery');
var Attribution = require('../../../../src/geo/ui/attribution/attribution-view');
var Map = require('../../../../src/geo/map');

describe('geo/ui/attribution', function () {
  beforeEach(function () {
    this.keyEsc = function () {
      var e = $.Event('keydown');
      e.keyCode = 27; // ESC
      $(document).trigger(e);
    };

    this.map = new Map();
    spyOn(this.map, 'bind').and.callThrough();

    this.view = new Attribution({
      map: this.map
    });
    this.view.render();
    this.$button = this.view.$('.js-button');
    this.$text = this.view.$('.js-text');
    this.viewHasClass = function (className) {
      return this.view.$el.hasClass(className);
    };
  });

  describe('render', function () {
    it('should render properly', function () {
      expect(this.$button.length).toBe(1);
      expect(this.$text.length).toBe(1);
    });

    it('should render when map attributions has changed', function () {
      spyOn(this.view, 'render');
      this.$button.click();
      this.map.trigger('change:attribution');
      expect(this.view.render).toHaveBeenCalled();
    });

    it('should add GMaps properly when provider is not Leaflet', function () {
      expect(this.viewHasClass('CDB-Attribution--gmaps')).toBeFalsy();
      this.map.set('provider', 'gmaps');
      this.view.render();
      expect(this.viewHasClass('CDB-Attribution--gmaps')).toBeTruthy();
    });
  });

  describe('when the attributions are displayed', function () {
    beforeEach(function () {
      this.$button.click();
    });

    it('should have is-active class', function () {
      expect(this.viewHasClass('is-active')).toBeTruthy();
    });

    it('should hide attributions text when js-button is clicked', function () {
      this.$button.click();
      expect(this.viewHasClass('is-active')).toBeFalsy();
    });

    it('should collapse the attributions when ESC is pressed', function () {
      this.keyEsc();
      expect(this.viewHasClass('is-active')).toBeFalsy();
    });

    it('should collapse the attributions when user clicks on the document', function () {
      $(document).trigger('click');
      expect(this.viewHasClass('is-active')).toBeFalsy();
    });
  });

  describe('when attributions are hidden', function () {
    beforeEach(function () {
      this.$button.click();
      this.keyEsc();
    });

    it('shouldn\'t have is-active class', function () {
      expect(this.viewHasClass('is-active')).toBeFalsy();
    });

    it('should show attributions text when js-button is clicked', function () {
      this.$button.click();
      expect(this.viewHasClass('is-active')).toBeTruthy();
    });

    it('should not respond to ESC', function () {
      this.keyEsc();
      expect(this.viewHasClass('is-active')).toBeFalsy();
    });

    it('should not respond to clicks on the document', function () {
      $(document).trigger('click');
      expect(this.viewHasClass('is-active')).toBeFalsy();
    });
  });
});
<|endoftext|>


<commit_before>goog.provide('ol.test.style.IconImageCache');

describe('ol.style.IconImageCache', function() {
  var originalMaxCacheSize;

  beforeEach(function() {
    var cache = ol.style.IconImageCache.getInstance();
    cache.clear();
    originalMaxCacheSize = cache.maxCacheSize;
    cache.maxCacheSize_ = 4;
  });

  afterEach(function() {
    var cache = ol.style.IconImageCache.getInstance();
    cache.maxCacheSize_ = originalMaxCacheSize;
    cache.clear();
  });

  describe('#expire', function() {
    it('expires images when expected', function() {
      var cache = ol.style.IconImageCache.getInstance();

      var i, src, iconImage, key;

      for (i = 0; i < 4; ++i) {
        src = i + '';
        iconImage = new ol.style.IconImage_(src, null);
        cache.set(src, null, iconImage);
      }

      expect(cache.cacheSize_).to.eql(4);

      cache.expire();
      expect(cache.cacheSize_).to.eql(4);

      src = '4';
      iconImage = new ol.style.IconImage_(src, null);
      cache.set(src, null, iconImage);
      expect(cache.cacheSize_).to.eql(5);

      cache.expire(); // remove '0' and '4'
      expect(cache.cacheSize_).to.eql(3);

      src = '0';
      iconImage = new ol.style.IconImage_(src, null);
      goog.events.listen(iconImage, goog.events.EventType.CHANGE,
          goog.nullFunction, false);
      cache.set(src, null, iconImage);
      expect(cache.cacheSize_).to.eql(4);

      src = '4';
      iconImage = new ol.style.IconImage_(src, null);
      goog.events.listen(iconImage, goog.events.EventType.CHANGE,
          goog.nullFunction, false);
      cache.set(src, null, iconImage);
      expect(cache.cacheSize_).to.eql(5);

      // check that '0' and '4' are not removed from the cache
      cache.expire();
      key = ol.style.IconImageCache.getKey('0', null);
      expect(key in cache.cache_).to.be.ok();
      key = ol.style.IconImageCache.getKey('4', null);
      expect(key in cache.cache_).to.be.ok();

    });
  });
});

goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('ol.style.IconImageCache');
<commit_msg>Add ol.style.Icon tests for getAnchor and getOrigin<commit_after>goog.provide('ol.test.style.Icon');
goog.provide('ol.test.style.IconImageCache');

goog.require('ol.style.Icon');
goog.require('ol.style.IconAnchorUnits');
goog.require('ol.style.IconOrigin');

describe('ol.style.Icon', function() {
  var size = [36, 48];

  describe('#getAnchor', function() {
    var fractionAnchor = [0.25, 0.25];

    it('uses fractional units by default', function() {
      var iconStyle = new ol.style.Icon({
        src: 'test.png',
        size: size,
        anchor: fractionAnchor
      });
      expect(iconStyle.getAnchor()).to.eql([9, 12]);
    });

    it('uses pixels units', function() {
      var iconStyle = new ol.style.Icon({
        src: 'test.png',
        size: size,
        anchor: [2, 18],
        anchorXUnits: ol.style.IconAnchorUnits.PIXELS,
        anchorYUnits: ol.style.IconAnchorUnits.PIXELS
      });
      expect(iconStyle.getAnchor()).to.eql([2, 18]);
    });

    it('uses a bottom left anchor origin', function() {
      var iconStyle = new ol.style.Icon({
        src: 'test.png',
        size: size,
        anchor: fractionAnchor,
        anchorOrigin: ol.style.IconOrigin.BOTTOM_LEFT
      });
      expect(iconStyle.getAnchor()).to.eql([9, 36]);
    });

    it('uses a bottom right anchor origin', function() {
      var iconStyle = new ol.style.Icon({
        src: 'test.png',
        size: size,
        anchor: fractionAnchor,
        anchorOrigin: ol.style.IconOrigin.BOTTOM_RIGHT
      });
      expect(iconStyle.getAnchor()).to.eql([27, 36]);
    });

    it('uses a top right anchor origin', function() {
      var iconStyle = new ol.style.Icon({
        src: 'test.png',
        size: size,
        anchor: fractionAnchor,
        anchorOrigin: ol.style.IconOrigin.TOP_RIGHT
      });
      expect(iconStyle.getAnchor()).to.eql([27, 12]);
    });
  });

  describe('#getOrigin', function() {
    var offset = [16, 20];
    var imageSize = [144, 192];

    it('uses a top left offset origin (default)', function() {
      var iconStyle = new ol.style.Icon({
        src: 'test.png',
        size: size,
        offset: offset
      });
      expect(iconStyle.getOrigin()).to.eql([16, 20]);
    });

    it('uses a bottom left offset origin', function() {
      var iconStyle = new ol.style.Icon({
        src: 'test.png',
        size: size,
        offset: offset,
        offsetOrigin: ol.style.IconOrigin.BOTTOM_LEFT
      });
      iconStyle.iconImage_.size_ = imageSize;
      expect(iconStyle.getOrigin()).to.eql([16, 124]);
    });

    it('uses a bottom right offset origin', function() {
      var iconStyle = new ol.style.Icon({
        src: 'test.png',
        size: size,
        offset: offset,
        offsetOrigin: ol.style.IconOrigin.BOTTOM_RIGHT
      });
      iconStyle.iconImage_.size_ = imageSize;
      expect(iconStyle.getOrigin()).to.eql([92, 124]);
    });

    it('uses a top right offset origin', function() {
      var iconStyle = new ol.style.Icon({
        src: 'test.png',
        size: size,
        offset: offset,
        offsetOrigin: ol.style.IconOrigin.TOP_RIGHT
      });
      iconStyle.iconImage_.size_ = imageSize;
      expect(iconStyle.getOrigin()).to.eql([92, 20]);
    });
  });
});

describe('ol.style.IconImageCache', function() {
  var originalMaxCacheSize;

  beforeEach(function() {
    var cache = ol.style.IconImageCache.getInstance();
    cache.clear();
    originalMaxCacheSize = cache.maxCacheSize;
    cache.maxCacheSize_ = 4;
  });

  afterEach(function() {
    var cache = ol.style.IconImageCache.getInstance();
    cache.maxCacheSize_ = originalMaxCacheSize;
    cache.clear();
  });

  describe('#expire', function() {
    it('expires images when expected', function() {
      var cache = ol.style.IconImageCache.getInstance();

      var i, src, iconImage, key;

      for (i = 0; i < 4; ++i) {
        src = i + '';
        iconImage = new ol.style.IconImage_(src, null);
        cache.set(src, null, iconImage);
      }

      expect(cache.cacheSize_).to.eql(4);

      cache.expire();
      expect(cache.cacheSize_).to.eql(4);

      src = '4';
      iconImage = new ol.style.IconImage_(src, null);
      cache.set(src, null, iconImage);
      expect(cache.cacheSize_).to.eql(5);

      cache.expire(); // remove '0' and '4'
      expect(cache.cacheSize_).to.eql(3);

      src = '0';
      iconImage = new ol.style.IconImage_(src, null);
      goog.events.listen(iconImage, goog.events.EventType.CHANGE,
          goog.nullFunction, false);
      cache.set(src, null, iconImage);
      expect(cache.cacheSize_).to.eql(4);

      src = '4';
      iconImage = new ol.style.IconImage_(src, null);
      goog.events.listen(iconImage, goog.events.EventType.CHANGE,
          goog.nullFunction, false);
      cache.set(src, null, iconImage);
      expect(cache.cacheSize_).to.eql(5);

      // check that '0' and '4' are not removed from the cache
      cache.expire();
      key = ol.style.IconImageCache.getKey('0', null);
      expect(key in cache.cache_).to.be.ok();
      key = ol.style.IconImageCache.getKey('4', null);
      expect(key in cache.cache_).to.be.ok();

    });
  });
});

goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('ol.style.IconImageCache');
<|endoftext|>


<commit_before>'use strict';

import React from 'react';
import ReactDOM from 'react-dom';
import ConfiguredRadium from './ConfiguredRadium';
import baseStyles from './baseStyles';
import BurgerIcon from './BurgerIcon';
import CrossIcon from './CrossIcon';

export default (styles) => {

  return ConfiguredRadium(React.createClass({

    propTypes: {
      customBurgerIcon: React.PropTypes.element,
      customCrossIcon: React.PropTypes.element,
      id: React.PropTypes.string,
      isOpen: React.PropTypes.bool,
      noOverlay: React.PropTypes.bool,
      onStateChange: React.PropTypes.func,
      outerContainerId: React.PropTypes.string,
      pageWrapId: React.PropTypes.string,
      right: React.PropTypes.bool,
      styles: React.PropTypes.object,
      width: React.PropTypes.number
    },

    toggleMenu() {
      // Order important: handle wrappers before setting sidebar state.
      this.applyWrapperStyles();

      const newState = { isOpen: !this.state.isOpen };
      this.setState(newState, this.props.onStateChange.bind(null, newState));
    },

    // Applies component-specific styles to external wrapper elements.
    applyWrapperStyles() {
      if (styles.pageWrap && this.props.pageWrapId) {
        this.handleExternalWrapper(this.props.pageWrapId, styles.pageWrap, true);
      }

      if (styles.outerContainer && this.props.outerContainerId) {
        this.handleExternalWrapper(this.props.outerContainerId, styles.outerContainer, true);
      }
    },

    // Removes component-specific styles applied to external wrapper elements.
    clearWrapperStyles() {
      if (styles.pageWrap && this.props.pageWrapId) {
        this.handleExternalWrapper(this.props.pageWrapId, styles.pageWrap, false);
      }

      if (styles.outerContainer && this.props.outerContainerId) {
        this.handleExternalWrapper(this.props.outerContainerId, styles.outerContainer, false);
      }
    },

    // Sets or unsets styles on DOM elements outside the menu component.
    // This is necessary for correct page interaction with some of the menus.
    // Throws and returns if the required external elements don't exist,
    // which means any external page animations won't be applied.
    handleExternalWrapper(id, wrapperStyles, set) {
      const html = document.querySelector('html');
      const body = document.querySelector('body');
      const wrapper = document.getElementById(id);

      if (!wrapper) {
        console.error("Element with ID '" + id + "' not found");
        return;
      }

      const builtStyles = wrapperStyles(this.state.isOpen, this.props.width, this.props.right);

      for (const prop in builtStyles) {
        if (builtStyles.hasOwnProperty(prop)) {
          wrapper.style[prop] = set ? builtStyles[prop] : '';
        }
      }

      // Prevent any horizontal scroll.
      [html, body].forEach((element) => {
        element.style['overflow-x'] = set ? 'hidden' : '';
      });
    },

    // Builds styles incrementally for a given element.
    getStyles(el, index) {
      const propName = 'bm' + el.replace(el.charAt(0), el.charAt(0).toUpperCase());

      // Set base styles.
      let output = baseStyles[el] ? [baseStyles[el](this.state.isOpen, this.props.width, this.props.right)] : [];

      // Add animation-specific styles.
      if (styles[el]) {
        output.push(styles[el](this.state.isOpen, this.props.width, this.props.right, index + 1));
      }

      // Add custom styles.
      if (this.props.styles[propName]) {
        output.push(this.props.styles[propName]);
      }

      return output;
    },

    listenForClose(e) {
      e = e || window.event;

      if (this.state.isOpen && (e.key === 'Escape' || e.keyCode === 27)) {
        this.toggleMenu();
      }
    },

    getDefaultProps() {
      return {
        id: '',
        noOverlay: false,
        onStateChange: () => {},
        outerContainerId: '',
        pageWrapId: '',
        styles: {},
        width: 300
      };
    },

    getInitialState() {
      return { isOpen: false };
    },

    componentWillMount() {
      if (!styles) {
        throw new Error('No styles supplied');
      }

      // Warn if the selected menu requires external wrapper elements
      // but none were supplied.
      if (styles.pageWrap && !this.props.pageWrapId) {
        console.warn('No pageWrapId supplied');
      }

      if (styles.outerContainer && !this.props.outerContainerId) {
        console.warn('No outerContainerId supplied');
      }

      // Allow initial open state to be set by props.
      if (this.props.isOpen) {
        this.toggleMenu();
      }
    },

    componentDidMount() {
      window.onkeydown = this.listenForClose;
    },

    componentWillUnmount() {
      window.onkeydown = null;

      this.clearWrapperStyles();
    },

    componentDidUpdate() {
      if (styles.svg && this.isMounted()) {
        const morphShape = ReactDOM.findDOMNode(this, 'bm-morph-shape');
        let Snap, s, path;

        try {
          // This will throw with Webpack.
          Snap = require('snapsvg');
          s = Snap(morphShape);
          path = s.select('path');
        } catch (e) {
          console.warn('It looks like you might be using Webpack. Unfortunately, Elastic and Bubble are not currently supported with Webpack builds due to their Snap.svg dependency. See https://github.com/adobe-webplatform/Snap.svg/issues/341 for more info.');
          return;
        }

        if (this.state.isOpen) {
          // Animate SVG path.
          styles.svg.animate(path);
        } else {
          // Reset path (timeout ensures animation happens off screen).
          setTimeout(() => {
            path.attr('d', styles.svg.pathInitial);
          }, 300);
        }
      }
    },

    componentWillReceiveProps(nextProps) {
      if (typeof nextProps.isOpen !== 'undefined' && nextProps.isOpen !== this.state.isOpen) {
        this.toggleMenu();
      }
    },

    render() {
      let items, svg, overlay;

      // Add styles to user-defined menu items.
      if (this.props.children) {
        items = React.Children.map(this.props.children, (item, index) => {
          const extraProps = {
            key: index,
            style: this.getStyles('item', index)
          };
          return React.cloneElement(item, extraProps);
        });
      }

      // Add a morph shape for animations that use SVG.
      if (styles.svg) {
        svg = (

            <svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 100 800" preserveAspectRatio="none">
              <path d={ styles.svg.pathInitial }/>
            </svg>

        );
      }

      if (!this.props.noOverlay) {
        overlay =

;
      }

      return (

          { overlay }

            { svg }

                { items }

              <CrossIcon onClick={ this.toggleMenu } styles={ this.props.styles } customIcon={ this.props.customCrossIcon } />

          <BurgerIcon onClick={ this.toggleMenu } styles={ this.props.styles } customIcon={ this.props.customBurgerIcon } />

      );
    }
  }));
};
<commit_msg>Move item-generating function inside JSX<commit_after>'use strict';

import React from 'react';
import ReactDOM from 'react-dom';
import ConfiguredRadium from './ConfiguredRadium';
import baseStyles from './baseStyles';
import BurgerIcon from './BurgerIcon';
import CrossIcon from './CrossIcon';

export default (styles) => {

  return ConfiguredRadium(React.createClass({

    propTypes: {
      customBurgerIcon: React.PropTypes.element,
      customCrossIcon: React.PropTypes.element,
      id: React.PropTypes.string,
      isOpen: React.PropTypes.bool,
      noOverlay: React.PropTypes.bool,
      onStateChange: React.PropTypes.func,
      outerContainerId: React.PropTypes.string,
      pageWrapId: React.PropTypes.string,
      right: React.PropTypes.bool,
      styles: React.PropTypes.object,
      width: React.PropTypes.number
    },

    toggleMenu() {
      // Order important: handle wrappers before setting sidebar state.
      this.applyWrapperStyles();

      const newState = { isOpen: !this.state.isOpen };
      this.setState(newState, this.props.onStateChange.bind(null, newState));
    },

    // Applies component-specific styles to external wrapper elements.
    applyWrapperStyles() {
      if (styles.pageWrap && this.props.pageWrapId) {
        this.handleExternalWrapper(this.props.pageWrapId, styles.pageWrap, true);
      }

      if (styles.outerContainer && this.props.outerContainerId) {
        this.handleExternalWrapper(this.props.outerContainerId, styles.outerContainer, true);
      }
    },

    // Removes component-specific styles applied to external wrapper elements.
    clearWrapperStyles() {
      if (styles.pageWrap && this.props.pageWrapId) {
        this.handleExternalWrapper(this.props.pageWrapId, styles.pageWrap, false);
      }

      if (styles.outerContainer && this.props.outerContainerId) {
        this.handleExternalWrapper(this.props.outerContainerId, styles.outerContainer, false);
      }
    },

    // Sets or unsets styles on DOM elements outside the menu component.
    // This is necessary for correct page interaction with some of the menus.
    // Throws and returns if the required external elements don't exist,
    // which means any external page animations won't be applied.
    handleExternalWrapper(id, wrapperStyles, set) {
      const html = document.querySelector('html');
      const body = document.querySelector('body');
      const wrapper = document.getElementById(id);

      if (!wrapper) {
        console.error("Element with ID '" + id + "' not found");
        return;
      }

      const builtStyles = wrapperStyles(this.state.isOpen, this.props.width, this.props.right);

      for (const prop in builtStyles) {
        if (builtStyles.hasOwnProperty(prop)) {
          wrapper.style[prop] = set ? builtStyles[prop] : '';
        }
      }

      // Prevent any horizontal scroll.
      [html, body].forEach((element) => {
        element.style['overflow-x'] = set ? 'hidden' : '';
      });
    },

    // Builds styles incrementally for a given element.
    getStyles(el, index) {
      const propName = 'bm' + el.replace(el.charAt(0), el.charAt(0).toUpperCase());

      // Set base styles.
      let output = baseStyles[el] ? [baseStyles[el](this.state.isOpen, this.props.width, this.props.right)] : [];

      // Add animation-specific styles.
      if (styles[el]) {
        output.push(styles[el](this.state.isOpen, this.props.width, this.props.right, index + 1));
      }

      // Add custom styles.
      if (this.props.styles[propName]) {
        output.push(this.props.styles[propName]);
      }

      return output;
    },

    listenForClose(e) {
      e = e || window.event;

      if (this.state.isOpen && (e.key === 'Escape' || e.keyCode === 27)) {
        this.toggleMenu();
      }
    },

    getDefaultProps() {
      return {
        id: '',
        noOverlay: false,
        onStateChange: () => {},
        outerContainerId: '',
        pageWrapId: '',
        styles: {},
        width: 300
      };
    },

    getInitialState() {
      return { isOpen: false };
    },

    componentWillMount() {
      if (!styles) {
        throw new Error('No styles supplied');
      }

      // Warn if the selected menu requires external wrapper elements
      // but none were supplied.
      if (styles.pageWrap && !this.props.pageWrapId) {
        console.warn('No pageWrapId supplied');
      }

      if (styles.outerContainer && !this.props.outerContainerId) {
        console.warn('No outerContainerId supplied');
      }

      // Allow initial open state to be set by props.
      if (this.props.isOpen) {
        this.toggleMenu();
      }
    },

    componentDidMount() {
      window.onkeydown = this.listenForClose;
    },

    componentWillUnmount() {
      window.onkeydown = null;

      this.clearWrapperStyles();
    },

    componentDidUpdate() {
      if (styles.svg && this.isMounted()) {
        const morphShape = ReactDOM.findDOMNode(this, 'bm-morph-shape');
        let Snap, s, path;

        try {
          // This will throw with Webpack.
          Snap = require('snapsvg');
          s = Snap(morphShape);
          path = s.select('path');
        } catch (e) {
          console.warn('It looks like you might be using Webpack. Unfortunately, Elastic and Bubble are not currently supported with Webpack builds due to their Snap.svg dependency. See https://github.com/adobe-webplatform/Snap.svg/issues/341 for more info.');
          return;
        }

        if (this.state.isOpen) {
          // Animate SVG path.
          styles.svg.animate(path);
        } else {
          // Reset path (timeout ensures animation happens off screen).
          setTimeout(() => {
            path.attr('d', styles.svg.pathInitial);
          }, 300);
        }
      }
    },

    componentWillReceiveProps(nextProps) {
      if (typeof nextProps.isOpen !== 'undefined' && nextProps.isOpen !== this.state.isOpen) {
        this.toggleMenu();
      }
    },

    render() {
      let svg, overlay;

      // Add a morph shape for animations that use SVG.
      if (styles.svg) {
        svg = (

            <svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 100 800" preserveAspectRatio="none">
              <path d={styles.svg.pathInitial}/>
            </svg>

        );
      }

      if (!this.props.noOverlay) {
        overlay =

;
      }

      return (

          {overlay}

            {svg}

                {React.Children.map(this.props.children, (item, index) => {
                  const extraProps = {
                    key: index,
                    style: this.getStyles('item', index)
                  };
                  return React.cloneElement(item, extraProps);
                })}

              <CrossIcon onClick={this.toggleMenu} styles={this.props.styles} customIcon={this.props.customCrossIcon} />

          <BurgerIcon onClick={this.toggleMenu} styles={this.props.styles} customIcon={this.props.customBurgerIcon} />

      );
    }
  }));
};
<|endoftext|>