<commit_before>/*
 * Copyright 2016 EPAM Systems
 *
 *
 * This file is part of EPAM Report Portal.
 * https://github.com/reportportal/service-ui
 *
 * Report Portal is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Report Portal is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Report Portal.  If not, see <http://www.gnu.org/licenses/>.
 */
define(function (require) {
    'use strict';

    var $ = require('jquery');
    var _ = require('underscore');
    var Epoxy = require('backbone-epoxy');
    var LaunchSuiteStepItemModel = require('launches/common/LaunchSuiteStepItemModel');
    var LaunchSuiteDefectsView = require('launches/common/LaunchSuiteDefectsView');
    var ProductStatusLaunchName = require('newWidgets/widgets/productStatus/ProductStatusLaunchNameView');
    var ProductStatusFilterName = require('newWidgets/widgets/productStatus/ProductStatusFilterNameView');
    var ItemStartTimeView = require('launches/common/ItemStartTimeView');
    var Util = require('util');
    var Localization = require('localization');

    var ProductStatusView = Epoxy.View.extend({
        templateFilter: 'tpl-product-status-widget-row-filter',
        template: 'tpl-product-status-widget-row',
        className: 'product-status-widget-row rp-table-row',
        tagName: 'tr',

        initialize: function (headerData, cellData) {
            this.rendererViews = [];
            if (cellData.type === 'filter') {
                this.renderFilter(headerData, cellData.data);
            } else if (cellData.type === 'total') {
                this.renderTotal(headerData, cellData.data);
            } else {
                this.renderLaunch(headerData, cellData.data);
            }
        },
        renderFilter: function (headerData, data) {
            this.$el.html(Util.templates(this.templateFilter, {
                name: data.name,
                colspan: headerData.length
            }));
        },
        renderTotal: function (headerData, data) {
            var renderData = [];
            _.each(headerData, function (column) {
                var answer = {
                    type: column.text,
                    text: ''
                };
                switch (column.text) {
                case 'name':
                    answer.text = Localization.launchesHeaders.total;
                    break;
                case 'filter_name':
                    answer.text = Localization.launchesHeaders.total;
                    break;
                case 'total':
                    answer.text = data.total;
                    break;
                case 'passed':
                    answer.text = data.passed;
                    break;
                case 'failed':
                    answer.text = data.failed;
                    break;
                case 'skipped':
                    answer.text = data.skipped;
                    break;
                case 'product_bug':
                    answer.text = data.product_bug;
                    break;
                case 'auto_bug':
                    answer.text = data.automation_bug;
                    break;
                case 'system_issue':
                    answer.text = data.system_issue;
                    break;
                case 'to_investigate':
                    answer.text = data.to_investigate;
                    break;
                case 'passing_rate':
                    var count = 100;
                    if (parseInt(data.total, 10) !== 0) {
                        count = parseInt((data.passed / data.total) * 100, 10);
                    }
                    answer.text = count + '%';
                    if (count < 100) {
                        answer.text = '' + answer.text + '';
                    }
                    break;
                default:
                    answer.text = '';
                }
                renderData.push(answer);
            });
            this.$el.html(Util.templates(this.template, renderData));
        },
        renderLaunch: function (headerData, data) {
            var self = this;
            var afterFuncs = [];
            var renderData = [];
            this.launchModel = new LaunchSuiteStepItemModel(data);
            _.each(headerData, function (column) {
                renderData.push(self.getLaunchDataByColumn(data, column, afterFuncs));
            });
            this.$el.html(Util.templates(this.template, renderData));
            _.each(afterFuncs, function (func) {
                func.call(self);
            });
        },
        getLaunchDataByColumn: function (launchData, column, afterFuncs) {
            var columnKey = column.text;
            var answer = {
                type: columnKey,
                text: ''
            };
            if (column.type === 'basic') {
                switch (columnKey) {
                case 'name':
                    answer.text = '';
                    afterFuncs.push(function () {
                        this.rendererViews.push(new ProductStatusLaunchName({
                            model: this.launchModel,
                            el: $('[data-js-cell-name]', this.$el)
                        }));
                    });
                    break;
                case 'filter_name':
                    answer.text = '';
                    afterFuncs.push(function () {
                        this.rendererViews.push(new ProductStatusFilterName({
                            model: this.launchModel,
                            el: $('[data-js-cell-filter_name]', this.$el)
                        }));
                    });
                    break;
                case 'start_time':
                    answer.text = '';
                    afterFuncs.push(function () {
                        var view = new ItemStartTimeView({
                            model: this.launchModel
                        });
                        this.rendererViews.push(view);
                        $('[data-js-cell-start_time]', this.$el).html(view.$el);
                    });
                    break;
                case 'status':
                    answer.text = launchData.status;
                    break;
                case 'total':
                    answer.text = launchData.statistics.executions.total;
                    break;
                case 'passed':
                    answer.text = launchData.statistics.executions.passed;
                    break;
                case 'failed':
                    answer.text = launchData.statistics.executions.failed;
                    break;
                case 'skipped':
                    answer.text = launchData.statistics.executions.skipped;
                    break;
                case 'product_bug':
                    answer.text = '';
                    afterFuncs.push(function () {
                        this.rendererViews.push(new LaunchSuiteDefectsView({
                            model: this.launchModel,
                            el: $('[data-js-cell-product_bug]', this.$el),
                            type: 'product_bug',
                            clickable: false
                        }));
                    });
                    break;
                case 'auto_bug':
                    answer.text = '';
                    afterFuncs.push(function () {
                        this.rendererViews.push(new LaunchSuiteDefectsView({
                            model: this.launchModel,
                            el: $('[data-js-cell-auto_bug]', this.$el),
                            type: 'automation_bug',
                            clickable: false
                        }));
                    });
                    break;
                case 'system_issue':
                    answer.text = '';
                    afterFuncs.push(function () {
                        this.rendererViews.push(new LaunchSuiteDefectsView({
                            model: this.launchModel,
                            el: $('[data-js-cell-system_issue]', this.$el),
                            type: 'system_issue',
                            clickable: false
                        }));
                    });
                    break;
                case 'to_investigate':
                    answer.text = '' + launchData.statistics.defects.to_investigate.total + '';
                    break;
                case 'passing_rate':
                    var count = 100;
                    if (parseInt(launchData.statistics.executions.total, 10) !== 0) {
                        count = parseInt((launchData.statistics.executions.passed / launchData.statistics.executions.total) * 100, 10);
                    }
                    answer.text = count + '%';
                    if (count < 100) {
                        answer.text = '' + answer.text + '';
                    }
                    break;
                default:
                    answer.text = '';
                }
            } else if (column.type === 'custom') {
                var values = [];
                _.each(launchData.tags, function (tag) {
                    var re = new RegExp('^' + column.tag);
                    var value = tag.replace(re, '');
                    if (value !== tag) {
                        values.push(value);
                    }
                });
                answer.text = values.join(', ');
            }

            return answer;
        }
    });

    return ProductStatusView;
});
<commit_msg>add no defect column to product status widget<commit_after>/*
 * Copyright 2016 EPAM Systems
 *
 *
 * This file is part of EPAM Report Portal.
 * https://github.com/reportportal/service-ui
 *
 * Report Portal is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Report Portal is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Report Portal.  If not, see <http://www.gnu.org/licenses/>.
 */
define(function (require) {
    'use strict';

    var $ = require('jquery');
    var _ = require('underscore');
    var Epoxy = require('backbone-epoxy');
    var LaunchSuiteStepItemModel = require('launches/common/LaunchSuiteStepItemModel');
    var LaunchSuiteDefectsView = require('launches/common/LaunchSuiteDefectsView');
    var ProductStatusLaunchName = require('newWidgets/widgets/productStatus/ProductStatusLaunchNameView');
    var ProductStatusFilterName = require('newWidgets/widgets/productStatus/ProductStatusFilterNameView');
    var ItemStartTimeView = require('launches/common/ItemStartTimeView');
    var Util = require('util');
    var Localization = require('localization');

    var ProductStatusView = Epoxy.View.extend({
        templateFilter: 'tpl-product-status-widget-row-filter',
        template: 'tpl-product-status-widget-row',
        className: 'product-status-widget-row rp-table-row',
        tagName: 'tr',

        initialize: function (headerData, cellData) {
            this.rendererViews = [];
            if (cellData.type === 'filter') {
                this.renderFilter(headerData, cellData.data);
            } else if (cellData.type === 'total') {
                this.renderTotal(headerData, cellData.data);
            } else {
                this.renderLaunch(headerData, cellData.data);
            }
        },
        renderFilter: function (headerData, data) {
            this.$el.html(Util.templates(this.templateFilter, {
                name: data.name,
                colspan: headerData.length
            }));
        },
        renderTotal: function (headerData, data) {
            var renderData = [];
            _.each(headerData, function (column) {
                var answer = {
                    type: column.text,
                    text: ''
                };
                switch (column.text) {
                case 'name':
                    answer.text = Localization.launchesHeaders.total;
                    break;
                case 'filter_name':
                    answer.text = Localization.launchesHeaders.total;
                    break;
                case 'total':
                    answer.text = data.total;
                    break;
                case 'passed':
                    answer.text = data.passed;
                    break;
                case 'failed':
                    answer.text = data.failed;
                    break;
                case 'skipped':
                    answer.text = data.skipped;
                    break;
                case 'product_bug':
                    answer.text = data.product_bug;
                    break;
                case 'auto_bug':
                    answer.text = data.automation_bug;
                    break;
                case 'system_issue':
                    answer.text = data.system_issue;
                    break;
                case 'to_investigate':
                    answer.text = data.to_investigate;
                    break;
                case 'passing_rate':
                    var count = 100;
                    if (parseInt(data.total, 10) !== 0) {
                        count = parseInt((data.passed / data.total) * 100, 10);
                    }
                    answer.text = count + '%';
                    if (count < 100) {
                        answer.text = '' + answer.text + '';
                    }
                    break;
                default:
                    answer.text = '';
                }
                renderData.push(answer);
            });
            this.$el.html(Util.templates(this.template, renderData));
        },
        renderLaunch: function (headerData, data) {
            var self = this;
            var afterFuncs = [];
            var renderData = [];
            this.launchModel = new LaunchSuiteStepItemModel(data);
            _.each(headerData, function (column) {
                renderData.push(self.getLaunchDataByColumn(data, column, afterFuncs));
            });
            this.$el.html(Util.templates(this.template, renderData));
            _.each(afterFuncs, function (func) {
                func.call(self);
            });
        },
        getLaunchDataByColumn: function (launchData, column, afterFuncs) {
            var columnKey = column.text;
            var answer = {
                type: columnKey,
                text: ''
            };
            if (column.type === 'basic') {
                switch (columnKey) {
                case 'name':
                    answer.text = '';
                    afterFuncs.push(function () {
                        this.rendererViews.push(new ProductStatusLaunchName({
                            model: this.launchModel,
                            el: $('[data-js-cell-name]', this.$el)
                        }));
                    });
                    break;
                case 'filter_name':
                    answer.text = '';
                    afterFuncs.push(function () {
                        this.rendererViews.push(new ProductStatusFilterName({
                            model: this.launchModel,
                            el: $('[data-js-cell-filter_name]', this.$el)
                        }));
                    });
                    break;
                case 'start_time':
                    answer.text = '';
                    afterFuncs.push(function () {
                        var view = new ItemStartTimeView({
                            model: this.launchModel
                        });
                        this.rendererViews.push(view);
                        $('[data-js-cell-start_time]', this.$el).html(view.$el);
                    });
                    break;
                case 'status':
                    answer.text = launchData.status;
                    break;
                case 'total':
                    answer.text = launchData.statistics.executions.total;
                    break;
                case 'passed':
                    answer.text = launchData.statistics.executions.passed;
                    break;
                case 'failed':
                    answer.text = launchData.statistics.executions.failed;
                    break;
                case 'skipped':
                    answer.text = launchData.statistics.executions.skipped;
                    break;
                case 'product_bug':
                    answer.text = '';
                    afterFuncs.push(function () {
                        this.rendererViews.push(new LaunchSuiteDefectsView({
                            model: this.launchModel,
                            el: $('[data-js-cell-product_bug]', this.$el),
                            type: 'product_bug',
                            clickable: false
                        }));
                    });
                    break;
                case 'auto_bug':
                    answer.text = '';
                    afterFuncs.push(function () {
                        this.rendererViews.push(new LaunchSuiteDefectsView({
                            model: this.launchModel,
                            el: $('[data-js-cell-auto_bug]', this.$el),
                            type: 'automation_bug',
                            clickable: false
                        }));
                    });
                    break;
                case 'system_issue':
                    answer.text = '';
                    afterFuncs.push(function () {
                        this.rendererViews.push(new LaunchSuiteDefectsView({
                            model: this.launchModel,
                            el: $('[data-js-cell-system_issue]', this.$el),
                            type: 'system_issue',
                            clickable: false
                        }));
                    });
                    break;
                case 'no_defect':
                    answer.text = '';
                    afterFuncs.push(function () {
                        this.rendererViews.push(new LaunchSuiteDefectsView({
                            model: this.launchModel,
                            el: $('[data-js-cell-no_defect]', this.$el),
                            type: 'no_defect',
                            clickable: false
                        }));
                    });
                    break;
                case 'to_investigate':
                    answer.text = '' + launchData.statistics.defects.to_investigate.total + '';
                    break;
                case 'passing_rate':
                    var count = 100;
                    if (parseInt(launchData.statistics.executions.total, 10) !== 0) {
                        count = parseInt((launchData.statistics.executions.passed / launchData.statistics.executions.total) * 100, 10);
                    }
                    answer.text = count + '%';
                    if (count < 100) {
                        answer.text = '' + answer.text + '';
                    }
                    break;
                default:
                    answer.text = '';
                }
            } else if (column.type === 'custom') {
                var values = [];
                _.each(launchData.tags, function (tag) {
                    var re = new RegExp('^' + column.tag);
                    var value = tag.replace(re, '');
                    if (value !== tag) {
                        values.push(value);
                    }
                });
                answer.text = values.join(', ');
            }

            return answer;
        }
    });

    return ProductStatusView;
});
<|endoftext|>


<commit_before>'use strict';

require('../globals');

var util = require('../util'),
  setter = util.setter,
  getter = util.getter,
  time = require('./time');

var axis = module.exports = {};

axis.names = function(props) {
  return util.keys(util.keys(props).reduce(function(a, x) {
    var s = props[x].scale;
    if (s === X || s === Y) a[props[x].scale] = 1;
    return a;
  }, {}));
};

axis.defs = function(names, encoding, layout, stats, opt) {
  return names.reduce(function(a, name) {
    a.push(axis.def(name, encoding, layout, stats, opt));
    return a;
  }, []);
};

axis.def = function(name, encoding, layout, stats, opt) {
  var type = name;
  var isCol = name == COL, isRow = name == ROW;
  var rowOffset = axisTitleOffset(encoding, layout, Y) + 20,
    cellPadding = layout.cellPadding;

  if (isCol) type = 'x';
  if (isRow) type = 'y';

  var def = {
    type: type,
    scale: name
  };

  if (encoding.axis(name).grid) {
    def.grid = true;
    def.layer = 'back';

    if (isCol) {
      // set grid property -- put the lines on the right the cell
      setter(def, ['properties', 'grid'], {
        x: {
          offset: layout.cellWidth * (1+ cellPadding/2.0),
          // default value(s) -- vega doesn't do recursive merge
          scale: 'col'
        },
        y: {
          value: -layout.cellHeight * (cellPadding/2),
        },
        stroke: { value: encoding.config('cellGridColor') },
        opacity: { value: encoding.config('cellGridOpacity') }
      });
    } else if (isRow) {
      // set grid property -- put the lines on the top
      setter(def, ['properties', 'grid'], {
        y: {
          offset: -layout.cellHeight * (cellPadding/2),
          // default value(s) -- vega doesn't do recursive merge
          scale: 'row'
        },
        x: {
          value: rowOffset
        },
        x2: {
          offset: rowOffset + (layout.cellWidth * 0.05),
          // default value(s) -- vega doesn't do recursive merge
          group: 'mark.group.width',
          mult: 1
        },
        stroke: { value: encoding.config('cellGridColor') },
        opacity: { value: encoding.config('cellGridOpacity') }
      });
    } else {
      setter(def, ['properties', 'grid'], {
        stroke: { value: encoding.config('gridColor') },
        opacity: { value: encoding.config('gridOpacity') }
      });
    }
  }

  if (encoding.axis(name).title) {
    def = axis_title(def, name, encoding, layout, opt);
  }

  if (isRow || isCol) {
    setter(def, ['properties', 'ticks'], {
      opacity: {value: 0}
    });
    setter(def, ['properties', 'majorTicks'], {
      opacity: {value: 0}
    });
    setter(def, ['properties', 'axis'], {
      opacity: {value: 0}
    });
  }

  if (isCol) {
    def.orient = 'top';
  }

  if (isRow) {
    def.offset = rowOffset;
  }

  if (name == X) {
    if (encoding.has(Y) && encoding.isOrdinalScale(Y) && encoding.cardinality(Y, stats) > 30) {
      def.orient = 'top';
    }

    if (encoding.isDimension(X) || encoding.isType(X, T)) {
      setter(def, ['properties','labels'], {
        angle: {value: 270},
        align: {value: 'right'},
        baseline: {value: 'middle'}
      });
    } else { // Q
      def.ticks = 5;
    }
  }

  def = axis_labels(def, name, encoding, layout, opt);

  return def;
};

function axis_title(def, name, encoding, layout, opt) {
  // jshint unused:false

  var maxlength = null,
    fieldTitle = encoding.fieldTitle(name);
  if (name===X) {
    maxlength = layout.cellWidth / encoding.config('characterWidth');
  } else if (name === Y) {
    maxlength = layout.cellHeight / encoding.config('characterWidth');
  }

  def.title = maxlength ? util.truncate(fieldTitle, maxlength) : fieldTitle;

  if (name === ROW) {
    setter(def, ['properties','title'], {
      angle: {value: 0},
      align: {value: 'right'},
      baseline: {value: 'middle'},
      dy: {value: (-layout.height/2) -20}
    });
  }

  def.titleOffset = axisTitleOffset(encoding, layout, name);
  return def;
}

function axis_labels(def, name, encoding, layout, opt) {
  // jshint unused:false

  var fn;
  // add custom label for time type
  if (encoding.isType(name, T) && (fn = encoding.fn(name)) && (time.hasScale(fn))) {
    setter(def, ['properties','labels','text','scale'], 'time-'+ fn);
  }

  var textTemplatePath = ['properties','labels','text','template'];
  if (encoding.axis(name).format) {
    def.format = encoding.axis(name).format;
  } else if (encoding.isType(name, Q)) {
    setter(def, textTemplatePath, '{{data | number:\'.3s\'}}');
  } else if (encoding.isType(name, T)) {
    if (!encoding.fn(name)) {
      setter(def, textTemplatePath, '{{data | time:"%Y-%m-%d"}}');
    } else if (encoding.fn(name) === 'year') {
      setter(def, textTemplatePath, '{{data | number:"d"}}');
    }
  } else if (encoding.isType(name, [N, O]) && encoding.axis(name).maxLabelLength) {
    setter(def, textTemplatePath, '{{data | truncate:' + encoding.axis(name).maxLabelLength + '}}');
  }

  return def;
}

function axisTitleOffset(encoding, layout, name) {
  var value = encoding.axis(name).titleOffset;
  if (value) {
    return value;
  }
  switch (name) {
    case ROW: return 0;
    case COL: return 35;
  }
  return getter(layout, [name, 'axisTitleOffset']);
}
<commit_msg>fix axis<commit_after>'use strict';

require('../globals');

var util = require('../util'),
  setter = util.setter,
  getter = util.getter,
  time = require('./time');

var axis = module.exports = {};

axis.names = function(props) {
  return util.keys(util.keys(props).reduce(function(a, x) {
    var s = props[x].scale;
    if (s === X || s === Y) a[props[x].scale] = 1;
    return a;
  }, {}));
};

axis.defs = function(names, encoding, layout, stats, opt) {
  return names.reduce(function(a, name) {
    a.push(axis.def(name, encoding, layout, stats, opt));
    return a;
  }, []);
};

axis.def = function(name, encoding, layout, stats, opt) {
  var type = name;
  var isCol = name == COL, isRow = name == ROW;
  var rowOffset = axisTitleOffset(encoding, layout, Y) + 20,
    cellPadding = layout.cellPadding;

  if (isCol) type = 'x';
  if (isRow) type = 'y';

  var def = {
    type: type,
    scale: name
  };

  if (encoding.axis(name).grid) {
    def.grid = true;
    def.layer = 'back';

    if (isCol) {
      // set grid property -- put the lines on the right the cell
      setter(def, ['properties', 'grid'], {
        x: {
          offset: layout.cellWidth * (1+ cellPadding/2.0),
          // default value(s) -- vega doesn't do recursive merge
          scale: 'col'
        },
        y: {
          value: -layout.cellHeight * (cellPadding/2),
        },
        stroke: { value: encoding.config('cellGridColor') },
        opacity: { value: encoding.config('cellGridOpacity') }
      });
    } else if (isRow) {
      // set grid property -- put the lines on the top
      setter(def, ['properties', 'grid'], {
        y: {
          offset: -layout.cellHeight * (cellPadding/2),
          // default value(s) -- vega doesn't do recursive merge
          scale: 'row'
        },
        x: {
          value: rowOffset
        },
        x2: {
          offset: rowOffset + (layout.cellWidth * 0.05),
          // default value(s) -- vega doesn't do recursive merge
          group: 'mark.group.width',
          mult: 1
        },
        stroke: { value: encoding.config('cellGridColor') },
        opacity: { value: encoding.config('cellGridOpacity') }
      });
    } else {
      setter(def, ['properties', 'grid'], {
        stroke: { value: encoding.config('gridColor') },
        opacity: { value: encoding.config('gridOpacity') }
      });
    }
  }

  if (encoding.axis(name).title) {
    def = axis_title(def, name, encoding, layout, opt);
  }

  if (isRow || isCol) {
    setter(def, ['properties', 'ticks'], {
      opacity: {value: 0}
    });
    setter(def, ['properties', 'majorTicks'], {
      opacity: {value: 0}
    });
    setter(def, ['properties', 'axis'], {
      opacity: {value: 0}
    });
  }

  if (isCol) {
    def.orient = 'top';
  }

  if (isRow) {
    def.offset = rowOffset;
  }

  if (name == X) {
    if (encoding.has(Y) && encoding.isOrdinalScale(Y) && encoding.cardinality(Y, stats) > 30) {
      def.orient = 'top';
    }

    if (encoding.isDimension(X) || encoding.isType(X, T)) {
      setter(def, ['properties','labels'], {
        angle: {value: 270},
        align: {value: 'right'},
        baseline: {value: 'middle'}
      });
    } else { // Q
      def.ticks = 5;
    }
  }

  def = axis_labels(def, name, encoding, layout, opt);

  return def;
};

function axis_title(def, name, encoding, layout, opt) {
  // jshint unused:false

  var maxlength = null,
    fieldTitle = encoding.fieldTitle(name);
  if (name===X) {
    maxlength = layout.cellWidth / encoding.config('characterWidth');
  } else if (name === Y) {
    maxlength = layout.cellHeight / encoding.config('characterWidth');
  }

  def.title = maxlength ? util.truncate(fieldTitle, maxlength) : fieldTitle;

  if (name === ROW) {
    setter(def, ['properties','title'], {
      angle: {value: 0},
      align: {value: 'right'},
      baseline: {value: 'middle'},
      dy: {value: (-layout.height/2) -20}
    });
  }

  def.titleOffset = axisTitleOffset(encoding, layout, name);
  return def;
}

function axis_labels(def, name, encoding, layout, opt) {
  // jshint unused:false

  var fn;
  // add custom label for time type
  if (encoding.isType(name, T) && (fn = encoding.fn(name)) && (time.hasScale(fn))) {
    setter(def, ['properties','labels','text','scale'], 'time-'+ fn);
  }

  var textTemplatePath = ['properties','labels','text','template'];
  if (encoding.axis(name).format) {
    def.format = encoding.axis(name).format;
  } else if (encoding.isType(name, Q)) {
    setter(def, textTemplatePath, '{{data | number:\'.3s\'}}');
  } else if (encoding.isType(name, T)) {
    if (!encoding.fn(name)) {
      setter(def, textTemplatePath, '{{data | time:\'%Y-%m-%d\'}}');
    } else if (encoding.fn(name) === 'year') {
      setter(def, textTemplatePath, '{{data | number:\'d\'}}');
    }
  } else if (encoding.isType(name, [N, O]) && encoding.axis(name).maxLabelLength) {
    setter(def, textTemplatePath, '{{data | truncate:' + encoding.axis(name).maxLabelLength + '}}');
  }

  return def;
}

function axisTitleOffset(encoding, layout, name) {
  var value = encoding.axis(name).titleOffset;
  if (value) {
    return value;
  }
  switch (name) {
    case ROW: return 0;
    case COL: return 35;
  }
  return getter(layout, [name, 'axisTitleOffset']);
}
<|endoftext|>


<commit_before>// searchResults is an array
console.log(searchResults);

// group the results by category
var groupsByCategory = _.groupBy(searchResults, "category");

console.log(groupsByCategory);

// group the results by taxon
var groupsByTaxon = _.groupBy(searchResults, "taxon");

console.log(groupsByTaxon);

// isotope
// external js: isotope.pkgd.js

// init Isotope
var $grid = $('.grid').isotope({
  itemSelector: '.color-shape'
});

// store filter for each group
var filters = {};

$('.filters').on( 'click', '.button', function() {
  var $this = $(this);
  // get group key
  var $buttonGroup = $this.parents('.button-group');
  var filterGroup = $buttonGroup.attr('data-filter-group');
  // set filter for group
  filters[ filterGroup ] = $this.attr('data-filter');
  // combine filters
  var filterValue = concatValues( filters );
  // set filter for Isotope
  $grid.isotope({ filter: filterValue });
});

// change is-checked class on buttons
$('.button-group').each( function( i, buttonGroup ) {
  var $buttonGroup = $( buttonGroup );
  $buttonGroup.on( 'click', 'button', function() {
    $buttonGroup.find('.is-checked').removeClass('is-checked');
    $( this ).addClass('is-checked');
  });
});

// flatten object by concatting values
function concatValues( obj ) {
  var value = '';
  for ( var prop in obj ) {
    value += obj[ prop ];
  }
  return value;
}
<commit_msg>working demo of isotope<commit_after>// searchResults is an array
console.log(searchResults);

// group the results by category
var groupsByCategory = _.groupBy(searchResults, "category");

console.log(groupsByCategory);

// group the results by taxon
var groupsByTaxon = _.groupBy(searchResults, "taxon");

console.log(groupsByTaxon);

// isotope
// external js: isotope.pkgd.js

$( document ).ready(function() {

    // init Isotope
    var $grid = $('.grid').isotope({
      itemSelector: '.color-shape'
    });

    // store filter for each group
    var filters = {};

    $('.filters').on( 'click', '.search-results-button', function() {
      var $this = $(this);
      // get group key
      var $buttonGroup = $this.parents('.search-results-button-group');
      var filterGroup = $buttonGroup.attr('data-filter-group');
      // set filter for group
      filters[ filterGroup ] = $this.attr('data-filter');
      // combine filters
      var filterValue = concatValues( filters );
      // set filter for Isotope
      $grid.isotope({ filter: filterValue });
    });

    // change is-checked class on buttons
    $('.button-group').each( function( i, buttonGroup ) {
      var $buttonGroup = $( buttonGroup );
      $buttonGroup.on( 'click', 'button', function() {
        $buttonGroup.find('.is-checked').removeClass('is-checked');
        $( this ).addClass('is-checked');
      });
    });

    // flatten object by concatting values
    function concatValues( obj ) {
      var value = '';
      for ( var prop in obj ) {
        value += obj[ prop ];
      }
      return value;
    }

});

<|endoftext|>


<commit_before>const config = require('../../config');
const { formatInAppUrl } = require('../../ui/util/url');

async function redirectMiddleware(ctx, next) {
  const requestHost = ctx.host;
  const path = ctx.path;
  const url = ctx.url;
  // Getting err: too many redirects on some urls because of this
  // Need a better solution
  // const decodedUrl = decodeURIComponent(url);

  // if (decodedUrl !== url) {
  //   ctx.redirect(decodedUrl);
  //   return;
  // }

  if (path.endsWith('/') && path.length > 1) {
    ctx.redirect(url.replace(/\/$/, ''));
    return;
  }

  if (!path.startsWith('/$/') && path.match(/^([^@/:]+)\/([^:/]+)$/)) {
    ctx.redirect(url.replace(/^([^@/:]+)\/([^:/]+)(:(\/.*))/, '$1:$2')); // test against path, but use ctx.url to retain parameters
    return;
  }

  if (requestHost === 'open.lbry.com' || requestHost === 'open.lbry.io') {
    const openQuery = '?src=open';
    let redirectUrl = config.URL + formatInAppUrl(url, openQuery);

    if (redirectUrl.includes('?')) {
      redirectUrl = redirectUrl.replace('?', `${openQuery}&`);
    } else {
      redirectUrl += openQuery;
    }

    ctx.redirect(redirectUrl);
    return;
  }

  // No redirects needed
  await next();
}

module.exports = redirectMiddleware;
<commit_msg>remove unnecessary redirect in server<commit_after>const config = require('../../config');
const { formatInAppUrl } = require('../../ui/util/url');

async function redirectMiddleware(ctx, next) {
  const requestHost = ctx.host;
  const path = ctx.path;
  const url = ctx.url;

  // Getting err: too many redirects on some urls because of this
  // Need a better solution
  // const decodedUrl = decodeURIComponent(url);

  // if (decodedUrl !== url) {
  //   ctx.redirect(decodedUrl);
  //   return;
  // }

  if (!path.startsWith('/$/') && path.match(/^([^@/:]+)\/([^:/]+)$/)) {
    ctx.redirect(url.replace(/^([^@/:]+)\/([^:/]+)(:(\/.*))/, '$1:$2')); // test against path, but use ctx.url to retain parameters
    return;
  }

  if (requestHost === 'open.lbry.com' || requestHost === 'open.lbry.io') {
    const openQuery = '?src=open';
    let redirectUrl = config.URL + formatInAppUrl(url, openQuery);

    if (redirectUrl.includes('?')) {
      redirectUrl = redirectUrl.replace('?', `${openQuery}&`);
    } else {
      redirectUrl += openQuery;
    }

    ctx.redirect(redirectUrl);
    return;
  }

  // No redirects needed
  await next();
}

module.exports = redirectMiddleware;
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011-2012, Yahoo! Inc.  All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */
YUI.add('mojito-dispatcher-tests', function(Y, NAME) {

    var suite = new Y.Test.Suite(NAME),
        A = Y.Assert,
        dispatcher = Y.mojito.Dispatcher,
        store,
        command,
        adapter;

    suite.add(new Y.Test.Case({

        name: 'dispatch',

        'setUp': function() {
            store = {
                getAppConfig: function() {
                    return { yui: { dependencyCalculations: 'ondemand' } };
                },
                getStaticContext: function () {
                },
                getRoutes: function() {
                },
                validateContext: function() {
                },
                expandInstance: function(instance, context, cb) {
                    cb(null, {
                        type: instance.type,
                        id: 'xyz123',
                        instanceId: 'xyz123',
                        'controller-module': 'dispatch',
                        yui: {
                            config: {},
                            langs: [],
                            requires: [],
                            sorted: ['mojito', 'mojito-action-context'],
                            sortedPaths: {}
                        }
                    });
                }
            };

            command = {
                action: 'index',
                instance: {
                    type: 'M'
                },
                context: {
                    lang: 'klingon',
                    langs: 'klingon'
                }
            };

            adapter = {};
        },

        'tearDown': function() {
            store = null;
            command = null;
            adapter = null;
        },

        'test rpc with tunnel': function () {
            var tunnel,
                errorTriggered,
                tunnelCommand;

            tunnel = {
                rpc: function (c, a) {
                    tunnelCommand = c;
                }
            };
            errorTriggered = false;
            dispatcher.init(store, tunnel);
            dispatcher.rpc(command, {
                error: function () {
                    errorTriggered = true;
                }
            });
            A.isFalse(errorTriggered, 'if tunnel is set, it should not call adapter.error');
            A.areSame(command, tunnelCommand, 'delegate command to tunnel');
        },

        'test rpc without tunnel available': function () {
            var tunnel,
                errorTriggered,
                tunnelCommand;

            tunnel = null;
            errorTriggered = false;
            dispatcher.init(store, tunnel);
            dispatcher.rpc(command, {
                error: function () {
                    errorTriggered = true;
                }
            });
            A.isTrue(errorTriggered, 'if tunnel is not set, it should call adapter.error');
        },

        'test dispatch with command.rpc=1': function () {
            var tunnel,
                errorTriggered,
                tunnelCommand;

            tunnel = {
                rpc: function (c, a) {
                    tunnelCommand = c;
                }
            };
            command.rpc = 1;
            errorTriggered = false;
            dispatcher.init(store, tunnel);
            dispatcher.rpc(command, {
                error: function () {
                    errorTriggered = true;
                }
            });
            A.isFalse(errorTriggered, 'tunnel should be called');
            A.areSame(command, tunnelCommand, 'delegate command to tunnel');
        },

        'test dispatch with invalid mojit': function () {
            var tunnel,
                errorTriggered,
                tunnelCommand;

            tunnel = {
                rpc: function (c, a) {
                    tunnelCommand = c;
                }
            };
            errorTriggered = false;
            dispatcher.init(store, tunnel);
            // if the expandInstance calls with an error, the tunnel
            // should be tried.
            store.expandInstance = function (instance, context, callback) {
                callback({error: 1});
            };
            dispatcher.dispatch(command, {
                error: function () {
                    errorTriggered = true;
                }
            });
            A.isFalse(errorTriggered, 'tunnel should be called');
            A.areSame(command, tunnelCommand, 'delegate command to tunnel');
        },

        'test dispatch with valid controller': function () {
            var tunnel,
                errorTriggered,
                useCommand,
                acCommand,
                _createActionContext = dispatcher._createActionContext,
                _useController = dispatcher._useController;

            errorTriggered = false;
            dispatcher.init(store, tunnel);
            // if the expandInstance calls with an error, the tunnel
            // should be tried.
            store.expandInstance = function (instance, context, callback) {
                instance.controller = 'foo';
                Y.mojito.controllers[instance.controller] = {};
                callback(null, instance);
            };
            dispatcher._useController = function (c) {
                useCommand = c;
            };
            dispatcher._createActionContext = function (c) {
                acCommand = c;
            };
            dispatcher.dispatch(command, {
                error: function () {
                    errorTriggered = true;
                }
            });
            A.isFalse(errorTriggered, '_createActionContext should be called');
            A.areSame(command, acCommand, 'AC should be created based on the original command');

            // restoring references
            dispatcher._createActionContext = _createActionContext;
        },

        'test dispatch with invalid controller': function () {
            var tunnel,
                errorTriggered,
                useCommand,
                acCommand,
                _createActionContext = dispatcher._createActionContext,
                _useController = dispatcher._useController;

            errorTriggered = false;
            dispatcher.init(store, tunnel);
            // if the expandInstance calls with an error, the tunnel
            // should be tried.
            store.expandInstance = function (instance, context, callback) {
                instance.controller = 'foo';
                Y.mojito.controllers[instance.controller] = null;
                callback(null, instance);
            };
            dispatcher._useController = function (c) {
                useCommand = c;
            };
            dispatcher._createActionContext = function (c) {
                acCommand = c;
            };
            dispatcher.dispatch(command, {
                error: function () {
                    errorTriggered = true;
                }
            });
            A.isFalse(errorTriggered, '_useController should be called');
            A.areSame(command, useCommand, '_useController should be called based on the original command');

            // restoring references
            dispatcher._createActionContext = _createActionContext;
            dispatcher._useController = _useController;
        }

    }));

    Y.Test.Runner.add(suite);

}, '0.0.1', {requires: ['mojito-dispatcher']});
<commit_msg>better failures control in UT<commit_after>/*
 * Copyright (c) 2011-2012, Yahoo! Inc.  All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */
YUI.add('mojito-dispatcher-tests', function(Y, NAME) {

    var suite = new Y.Test.Suite(NAME),
        A = Y.Assert,
        dispatcher = Y.mojito.Dispatcher,
        store,
        command,
        adapter;

    suite.add(new Y.Test.Case({

        name: 'dispatch',

        'setUp': function() {
            store = {
                getAppConfig: function() {
                    return { yui: { dependencyCalculations: 'ondemand' } };
                },
                getStaticContext: function () {
                },
                getRoutes: function() {
                },
                validateContext: function() {
                },
                expandInstance: function(instance, context, cb) {
                    cb(null, {
                        type: instance.type,
                        id: 'xyz123',
                        instanceId: 'xyz123',
                        'controller-module': 'dispatch',
                        yui: {
                            config: {},
                            langs: [],
                            requires: [],
                            sorted: ['mojito', 'mojito-action-context'],
                            sortedPaths: {}
                        }
                    });
                }
            };

            command = {
                action: 'index',
                instance: {
                    type: 'M'
                },
                context: {
                    lang: 'klingon',
                    langs: 'klingon'
                }
            };

            adapter = {};
        },

        'tearDown': function() {
            store = null;
            command = null;
            adapter = null;
        },

        'test rpc with tunnel': function () {
            var tunnel,
                tunnelCommand;

            tunnel = {
                rpc: function (c, a) {
                    tunnelCommand = c;
                }
            };
            errorTriggered = false;
            dispatcher.init(store, tunnel);
            dispatcher.rpc(command, {
                error: function () {
                    A.fail('tunnel should be called instead');
                }
            });
            A.areSame(command, tunnelCommand, 'delegate command to tunnel');
        },

        'test rpc without tunnel available': function () {
            var tunnel,
                errorTriggered,
                tunnelCommand;

            tunnel = null;
            errorTriggered = false;
            dispatcher.init(store, tunnel);
            dispatcher.rpc(command, {
                error: function () {
                    errorTriggered = true;
                }
            });
            A.isTrue(errorTriggered, 'if tunnel is not set, it should call adapter.error');
        },

        'test dispatch with command.rpc=1': function () {
            var tunnel,
                tunnelCommand;

            tunnel = {
                rpc: function (c, a) {
                    tunnelCommand = c;
                }
            };
            command.rpc = 1;
            errorTriggered = false;
            dispatcher.init(store, tunnel);
            dispatcher.rpc(command, {
                error: function () {
                    A.fail('tunnel should be called instead');
                }
            });
            A.areSame(command, tunnelCommand, 'delegate command to tunnel');
        },

        'test dispatch with invalid mojit': function () {
            var tunnel,
                tunnelCommand;

            tunnel = {
                rpc: function (c, a) {
                    tunnelCommand = c;
                }
            };
            errorTriggered = false;
            dispatcher.init(store, tunnel);
            // if the expandInstance calls with an error, the tunnel
            // should be tried.
            store.expandInstance = function (instance, context, callback) {
                callback({error: 1});
            };
            dispatcher.dispatch(command, {
                error: function () {
                    A.fail('tunnel should be called instead');
                }
            });
            A.areSame(command, tunnelCommand, 'delegate command to tunnel');
        },

        'test dispatch with valid controller': function () {
            var tunnel,
                useCommand,
                acCommand,
                _createActionContext = dispatcher._createActionContext,
                _useController = dispatcher._useController;

            errorTriggered = false;
            dispatcher.init(store, tunnel);
            // if the expandInstance calls with an error, the tunnel
            // should be tried.
            store.expandInstance = function (instance, context, callback) {
                instance.controller = 'foo';
                Y.mojito.controllers[instance.controller] = {
                    fakeController: true
                };
                callback(null, instance);
            };
            dispatcher._useController = function (c) {
                A.fail('_createActionContext should be called instead');
            };
            dispatcher._createActionContext = function (c) {
                acCommand = c;
            };
            dispatcher.dispatch(command, {
                error: function () {
                    A.fail('_createActionContext should be called instead');
                }
            });
            A.areSame(command, acCommand, 'AC should be created based on the original command');

            // restoring references
            dispatcher._createActionContext = _createActionContext;
            dispatcher._useController = _useController;
        },

        'test dispatch with invalid controller': function () {
            var tunnel,
                useCommand,
                acCommand,
                _createActionContext = dispatcher._createActionContext,
                _useController = dispatcher._useController;

            errorTriggered = false;
            dispatcher.init(store, tunnel);
            // if the expandInstance calls with an error, the tunnel
            // should be tried.
            store.expandInstance = function (instance, context, callback) {
                instance.controller = 'foo';
                Y.mojito.controllers[instance.controller] = null;
                callback(null, instance);
            };
            dispatcher._useController = function (c) {
                useCommand = c;
            };
            dispatcher._createActionContext = function (c) {
                A.fail('_createActionContext should be called instead');
            };
            dispatcher.dispatch(command, {
                error: function () {
                    A.fail('_useController should be called instead');
                }
            });
            A.areSame(command, useCommand, '_useController should be called based on the original command');

            // restoring references
            dispatcher._createActionContext = _createActionContext;
            dispatcher._useController = _useController;
        }

    }));

    Y.Test.Runner.add(suite);

}, '0.0.1', {requires: ['mojito-dispatcher']});
<|endoftext|>


<commit_before>describe("edit feature fields dialog", function() {

  var view, model, table, row;
  beforeEach(function() {
    table = new cdb.admin.CartoDBTableMetadata({
      name: 'test',
      schema: [
        ['cartodb_id', 'number'],
        ['c1', 'string'],
        ['c2', 'number'],
        ['c3', 'boolean'],
        ['c4', 'date']
      ]
    });

    view = new cdb.admin.EditFeatureFields({
      model: new cdb.admin.Row({
        cartodb_id: '1',
        c1: 'jamon',
        c2: 10,
        c3: false,
        c4: '2012-10-10T10:10:10+02:00',
      }),
      table: table
    });
  });

  it("should render 4 fields", function() {
    view.render();
    expect(view.$('.wrapper > .field').size()).toBe(4);
  });

  it("should save the changes if edits a field correctly", function() {
    view.render();
    spyOn(view, 'hide');

    var $textarea = view.$el.find('textarea');

    $textarea
      .val('testing')
      .trigger(jQuery.Event( 'keydown', {
        ctrlKey: true,
        metaKey: true,
        keyCode: 13
      }));

    expect(view.hide).toHaveBeenCalled();
  })

  it('should render unknown column types as string', function() {
    table.set({'schema': [['cartodb_id', 'number'],['c1', 'who knows']] });
    view.model.set('c1', 'ay');

    view.render();
    expect(view.$('div.field:eq(0) label').text()).toBe('c1');
    expect(view.$('div.field:eq(0) textarea.string_field').length).toBe(1);
    expect(view.$('div.field:eq(0) textarea.string_field').text()).toBe('ay');
  })

  it("should not save the changes if edits a field badly", function() {
    view.render();

    spyOn(view, 'hide');
    spyOn(view, '_scrollToError');

    var $input = view.$el.find('input.number_field');

    $input
      .val('testing')
      .trigger(jQuery.Event( 'keyup' ));

    view._ok();

    expect(view._scrollToError).toHaveBeenCalled();
    expect(view.hide).not.toHaveBeenCalled();
  })
});
<commit_msg>Remove old edit fields metadata modal spec<commit_after><|endoftext|>


<commit_before>(function() {

"use strict";

var requestAnimationFrame =
   window.requestAnimationFrame
|| window.mozRequestAnimationFrame
|| window.webkitRequestAnimationFrame
|| window.ieRequestAnimationFrame;

// Utility function
var square = function square(x) {
  return x * x;
};

/**
 * @constructor
 */
var Engine = function Engine() {
  // A map from the various kinds of events to their observers
  this._listeners = {
    ":levelComplete": [],
    ":textShown": [],
    ":textHidden": []
  };

  // The balls
  this._balls = [];
  this._areas = [];
  this._previousFrameStamp = null;
  this._pad = new Pad();
  this._border = new Border();
  this._step = null;
  this._complete = false;
};

Engine.prototype = {
  /**
   * Call this to notify that the level is complete
   *
   * @param {boolean} victory If true, the player won, otherwise, the player lost
   */
  levelComplete: function levelComplete(victory) {
    console.log("Informing that level is complete");
    if (this._complete) {
      return;
    }
    this._step = function() { }; // Level is complete, nothing left to do
    this._complete = true;
    this._fireEvent(":levelComplete", {kind: "levelComplete", victory: victory});
  },

  // Handling events
  _fireEvent: function _fireEvent(key, event) {
    console.log("Informing observers of event", key);
    var set = this._listeners[key];
    if (!set) {
      console.error("Event key", key, "does not exist");
    }
    set.forEach(function(listener) {
      listener(event);
    });
  },
  addEventListener: function addEventListener(kind, listener) {
    var set = this._listeners[":" + kind];
    if (set == null) {
      throw new Error("Event kind " + kind + " does not exist");
    }
    if (set.indexOf(listener) == -1) {
      set.push(listener);
    }
  },
  removeEventListener: function removeEventListener(kind, listener) {
    var set = this._listeners[":" + kind];
    if (set == null) {
      throw new Error("Event kind " + kind + " does not exist");
    }
    var index = set.indexOf(listener);
    if (index != -1) {
      delete set[index];
    }
  },

  // Displaying text
  showText: function showText(text) {
    var eltText;
    var self = this;
    if (!this._eltText) {
      var eltBackground = document.getElementById("background");
      this._eltText = eltText = document.createElement("div");
    } else {
      eltText = this._eltText;
    }
    eltBackground.appendChild(eltText);
    eltText.textContent = text;
    eltText.classList.add("mayappear");
    eltText.classList.add("hidden");
    window.setTimeout(function() {
      eltText.classList.remove("hidden");
      eltText.classList.add("shown");
      eltText.addEventListener("transitionend", onshown);
      eltText.addEventListener("webkitTransitionEnd", onshown);
    });
    var onshown = function onshown() {
      eltText.removeEventListener("transitionend", onshown);
      eltText.removeEventListener("webkitTransitionEnd", onshown);
      self._fireEvent(":textShown", null);
    };
  },
  hideText: function hideText() {
    var eltText = this._eltText;
    if (!eltText) {
      return;
    }
    var self = this;
    eltText.classList.remove("shown");
    eltText.classList.add("hidden");
    var onhidden = function onhidden() {
      eltText.removeEventListener("transitionend", onhidden);
      eltText.removeEventListener("webkitTransitionEnd", onhidden);
      self._fireEvent(":textHidden", null);
    };
    eltText.addEventListener("transitionend", onhidden);
    eltText.addEventListener("webkitTransitionEnd", onhidden);
  },

  // Sprites
  /**
   * @return Ball
   */
  addBall: function addBall() {
    var ball = new Ball();
    this._balls.push(ball);
    return ball;
  },
  addArea: function addArea() {
    var area = new Area();
    this._areas.push(area);
    return area;
  },

  // Running the game (should be called by the level)
  run: function run(level) {
    var self = this;
    this._step = function() {
      Statistics.fps.begin();
      level.step(self);
      Statistics.fps.end();
      requestAnimationFrame(self._step);
    };
    var config = function config() {
      if (self._complete) {
        Config.removeEventListener("screenChanged", config);
        return;
      }
      console.log("Updating radius of just about everything");
      var radius = Math.min(Config.width, Config.height) / 2;
      self._pad.updateRadius(radius);
      self._balls.forEach(function (ball) {
        ball.updateRadius(radius);
      });
      self._areas.forEach(function (area) {
        area.updateRadius(radius);
      });
      self._border.updateRadius(radius);
    };
    Config.addEventListener("screenChanged", config);
    this._previousFrameStamp = Date.now();
    requestAnimationFrame(this._step);
  },

  // One step of the game (should be called by the level)
  step: function() {
    var now = Date.now();

    var midX = Config.width / 2;
    var midY = Config.height / 2;
    var delta = now - this._previousFrameStamp;

    var pad = this._pad;

    ////// Handle inputs
    if (Input.changed) {
      if (Input.mouseX == midX) {
        if (Input.mouseY >= midY) {
          pad.destRad = Math.PI / 2;
        } else {
          pad.destRad = - Math.PI / 2;
        }
      } else {
        var div = (Input.mouseY - midY) / (Input.mouseX - midX);
        if (Input.mouseX >= midX) {
          pad.destRad = Math.atan(div);
        } else {
          pad.destRad = Math.PI + Math.atan(div);
        }
      }
      Input.changed = false;
    }

    ////// Handle movements

    if (pad.destRad - pad.posRad < pad.posRad - pad.destRad) {
      pad.posRad = Math.min(pad.destRad, pad.posRad + 0.02 * delta);
    } else {
      pad.posRad = Math.max(pad.destRad, pad.posRad - 0.02 * delta);
    }

    for (var i = 0; i < this._balls.length; ++i) {
      var ball = this._balls[i];
      ball.x += ball.dx * ( ball.velocity * delta) ;
      ball.y += ball.dy * ( ball.velocity * delta) ;
    }

    ////// Handle display
    var ctx = canvasContext;
    // Clear and display game zone
    ctx.clearRect(0, 0, Config.width, Config.height);

    ctx.save();
    ctx.translate(midX, midY);
    var radius = Math.min(Config.width, Config.height) / 2;

    // Display center
    for (i = 0; i < this._areas.length; ++i) {
      this._areas[i].show(ctx);
    }

    // Display border
    this._border.show(ctx);

    // Display paddle
    var padX = this._pad.x = radius * Math.cos(this._pad.posRad);
    var padY = this._pad.y = radius * Math.sin(this._pad.posRad);
    ctx.beginPath();
    ctx.fillStyle = "white";
    ctx.strokeStyle = "white";
// FIXME Optimization: Pre-compute this as an image
    ctx.arc( padX, padY, this._pad.radiusPixels, 0, Math.PI * 2);
    ctx.fill();
    ctx.stroke();

    // Display ball
    for (i = 0; i < this._balls.length; ++i) {
      this._balls[i].show(ctx);
    }

    ////// Handle collisions
    var destructions = false;
    for (i = 0; i < this._balls.length; ++i) {
      ball = this._balls[i];
      // FIXME: Collision with the pad
      this._pad.handleCollision(ball);
      this._border.handleCollision(ball);
      for (var j = 0; j < this._areas.length; ++j) {
        var area = this._areas[j];
        area.handleCollision(ball);
        if (area.isDestroyed) {
          destructions = true;
        }
      }
      // FIXME: Collision with other balls
    }

    // FIXME: This won't scale if we have too many areas
    if (destructions) {
      var newAreas = [];
      for (j = 0; j < this._areas.length; ++j) {
        area = this._areas[j];
        if (!area.isDestroyed) {
          newAreas.push(area);
        }
      }
      this._areas = newAreas;
    }

    ctx.restore();

    this._previousFrameStamp = now;
  },

  getImage: function getImage() {
    return canvasContext.getImageData(0, 0, Config.width, Config.height);
  }
};

/**
 * @constructor
 */
var Sprite = function Sprite() {
  /**
   * The coordinates of the center of this object
   */
  this.x = 0;
  this.y = 0;

  /**
   * The radius
   */
  this.radiusPixels = 0;
  this.radiusPercent = null;

  this.fillStyle = null;
  this.strokeStyle = null;
  this.isBouncing = false;
  this.isAround = false;
  this.isDestructible = false;
  this.isDestroyed = false;
};
Sprite.prototype = {
  /**
   * If necessary, recompute the radius of the sprite
   * (used whenver the screen size changes)
   */
  updateRadius: function updateRadius(globalRadius) {
    console.log("Updating radius of", "" + this, globalRadius, this.radiusPercent);
    if (this.radiusPercent == null) {
      return;
    }
    this.radiusPixels = Math.floor(globalRadius * this.radiusPercent);
  },

  show: function show(ctx) {
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.radiusPixels, 0, Math.PI * 2);
    if (this.fillStyle) {
      ctx.fillStyle = this.fillStyle;
      ctx.fill();
    }
    if (this.strokeStyle) {
      ctx.strokeStyle = this.strokeStyle;
      ctx.stroke();
    }
  },

  /**
   * Detect collisions and, if necessary, bounce
   *
   * @param {boolean} inner If true, the ball is inside the object
   */
  handleCollision: function handleCollision(ball) {
    var axisX = this.x - ball.x;
    var axisY = this.y - ball.y;

    // Distance between centers
    var sqActualDistance = axisX * axisX + axisY * axisY;

    // The distance at which there is a collision
    var sqBounceDistance;
    var bounce;
    if (this.isAround) {
      sqBounceDistance = square(this.radiusPixels - ball.radiusPixels);
      bounce = sqBounceDistance <= sqActualDistance;
    } else {
      sqBounceDistance = square(this.radiusPixels + ball.radiusPixels);
      bounce = sqBounceDistance >= sqActualDistance;
      axisX = - axisX;
      axisY = - axisY;
    }
    if (bounce && this.isDestructible) {
      this.isDestroyed = true;
    }

    if (!bounce) {
      return false;
    }
    if (!this.isBouncing) {
      return true;
    }

    // Ok, we have a collision and we should bounce

    // Normalize axis
    var actualDistance = Math.sqrt(sqActualDistance);
    axisX /= actualDistance;
    axisY /= actualDistance;

    var symX = 2 * axisX - ball.dx;
    var symY = 2 * axisY - ball.dy;

    var symNorm = Math.sqrt(symX * symX + symY * symY);

    ball.dx = symX / symNorm;
    ball.dy = symY / symNorm;
    return true;
  },

  toString: function() {
    return "Sprite: " + this.name;
  },

  name: "unnamed sprite"
};

var Area = function Area() {
};
Area.prototype = {
  __proto__: Object.create(Sprite.prototype),
  name: "area"
};

var Ball = function Ball() {
  Sprite.call(this);
  this.dx = 0;
  this.dy = 1;
  this.velocity = 0.1;
  this.radiusPixels = 5;
  this.fillStyle = "white";
};
Ball.prototype = {
  __proto__: Object.create(Sprite.prototype),
  name: "ball"
};

var Pad = function Pad() {
  Sprite.call(this);
  this.posRad = Math.PI / 2;// Position in radians
  this.destRad = Math.PI / 2; // Destination in radians
  this.radiusPixels = 20;
  this.isBouncing = true;
};
Pad.prototype = {
  __proto__: Object.create(Sprite.prototype),
  name: "pad"
};

var Border = function Border() {
  Sprite.call(this);
  this.radiusPercent = 1;
  this.strokeStyle = "blue";
  this.isBouncing = true;
  this.isAround = true;
};
Border.prototype = {
  __proto__: Object.create(Sprite.prototype),
  name: "border",
};
if ("vibrate" in window.navigator) {
  Border.prototype.handleCollision = function handleCollision(ball) {
    if (Sprite.prototype.handleCollision.call(this, ball)) {
      window.navigator.vibrate(50);
      return true;
    }
    return false;
  };
}

var eltCanvas = document.getElementById("canvas");
var canvasContext = eltCanvas.getContext("2d");

var Input = {
  mouseX: 0,
  mouseY: 0,
  changed: false
};

var onmousemove = function onmousemove(event) {
  event.stopPropagation();
  Input.mouseX = event.clientX;
  Input.mouseY = event.clientY;
  Input.changed = true;
};

eltCanvas.addEventListener("mousemove", onmousemove);
document.getElementById("background").addEventListener("mousemove", onmousemove);

// Configure
var Circular;
if ("Circular" in window) {
  Circular = window.Circular;
} else {
  Circular = window.Circular = {};
}

var Config = window.Circular.Config;
Config.init(eltCanvas);

var Statistics = window.Circular.Statistics;

// Exports

Circular.Engine = Engine;

})();<commit_msg>[Refactor] Pad is now a regular sprite<commit_after>(function() {

"use strict";

var requestAnimationFrame =
   window.requestAnimationFrame
|| window.mozRequestAnimationFrame
|| window.webkitRequestAnimationFrame
|| window.ieRequestAnimationFrame;

// Utility function
var square = function square(x) {
  return x * x;
};

/**
 * @constructor
 */
var Engine = function Engine() {
  // A map from the various kinds of events to their observers
  this._listeners = {
    ":levelComplete": [],
    ":textShown": [],
    ":textHidden": []
  };

  // The balls
  this._balls = [];
  this._areas = [];
  this._previousFrameStamp = null;
  this._pad = new Pad();
  this._border = new Border();
  this._step = null;
  this._complete = false;
};

Engine.prototype = {
  /**
   * Call this to notify that the level is complete
   *
   * @param {boolean} victory If true, the player won, otherwise, the player lost
   */
  levelComplete: function levelComplete(victory) {
    console.log("Informing that level is complete");
    if (this._complete) {
      return;
    }
    this._step = function() { }; // Level is complete, nothing left to do
    this._complete = true;
    this._fireEvent(":levelComplete", {kind: "levelComplete", victory: victory});
  },

  // Handling events
  _fireEvent: function _fireEvent(key, event) {
    console.log("Informing observers of event", key);
    var set = this._listeners[key];
    if (!set) {
      console.error("Event key", key, "does not exist");
    }
    set.forEach(function(listener) {
      listener(event);
    });
  },
  addEventListener: function addEventListener(kind, listener) {
    var set = this._listeners[":" + kind];
    if (set == null) {
      throw new Error("Event kind " + kind + " does not exist");
    }
    if (set.indexOf(listener) == -1) {
      set.push(listener);
    }
  },
  removeEventListener: function removeEventListener(kind, listener) {
    var set = this._listeners[":" + kind];
    if (set == null) {
      throw new Error("Event kind " + kind + " does not exist");
    }
    var index = set.indexOf(listener);
    if (index != -1) {
      delete set[index];
    }
  },

  // Displaying text
  showText: function showText(text) {
    var eltText;
    var self = this;
    if (!this._eltText) {
      var eltBackground = document.getElementById("background");
      this._eltText = eltText = document.createElement("div");
    } else {
      eltText = this._eltText;
    }
    eltBackground.appendChild(eltText);
    eltText.textContent = text;
    eltText.classList.add("mayappear");
    eltText.classList.add("hidden");
    window.setTimeout(function() {
      eltText.classList.remove("hidden");
      eltText.classList.add("shown");
      eltText.addEventListener("transitionend", onshown);
      eltText.addEventListener("webkitTransitionEnd", onshown);
    });
    var onshown = function onshown() {
      eltText.removeEventListener("transitionend", onshown);
      eltText.removeEventListener("webkitTransitionEnd", onshown);
      self._fireEvent(":textShown", null);
    };
  },
  hideText: function hideText() {
    var eltText = this._eltText;
    if (!eltText) {
      return;
    }
    var self = this;
    eltText.classList.remove("shown");
    eltText.classList.add("hidden");
    var onhidden = function onhidden() {
      eltText.removeEventListener("transitionend", onhidden);
      eltText.removeEventListener("webkitTransitionEnd", onhidden);
      self._fireEvent(":textHidden", null);
    };
    eltText.addEventListener("transitionend", onhidden);
    eltText.addEventListener("webkitTransitionEnd", onhidden);
  },

  // Sprites
  /**
   * @return Ball
   */
  addBall: function addBall() {
    var ball = new Ball();
    this._balls.push(ball);
    return ball;
  },
  addArea: function addArea() {
    var area = new Area();
    this._areas.push(area);
    return area;
  },

  // Running the game (should be called by the level)
  run: function run(level) {
    var self = this;
    this._step = function() {
      Statistics.fps.begin();
      level.step(self);
      Statistics.fps.end();
      requestAnimationFrame(self._step);
    };
    var config = function config() {
      if (self._complete) {
        Config.removeEventListener("screenChanged", config);
        return;
      }
      console.log("Updating radius of just about everything");
      var radius = Math.min(Config.width, Config.height) / 2;
      self._pad.updateRadius(radius);
      self._balls.forEach(function (ball) {
        ball.updateRadius(radius);
      });
      self._areas.forEach(function (area) {
        area.updateRadius(radius);
      });
      self._border.updateRadius(radius);
    };
    Config.addEventListener("screenChanged", config);
    this._previousFrameStamp = Date.now();
    requestAnimationFrame(this._step);
  },

  // One step of the game (should be called by the level)
  step: function() {
    var now = Date.now();

    var midX = Config.width / 2;
    var midY = Config.height / 2;
    var radius = Math.min(Config.width, Config.height) / 2;

    var delta = now - this._previousFrameStamp;

    var pad = this._pad;

    ////// Handle inputs
    if (Input.changed) {
      if (Input.mouseX == midX) {
        if (Input.mouseY >= midY) {
          pad.destRad = Math.PI / 2;
        } else {
          pad.destRad = - Math.PI / 2;
        }
      } else {
        var div = (Input.mouseY - midY) / (Input.mouseX - midX);
        if (Input.mouseX >= midX) {
          pad.destRad = Math.atan(div);
        } else {
          pad.destRad = Math.PI + Math.atan(div);
        }
      }
      Input.changed = false;
    }

    ////// Handle movements

    if (pad.destRad - pad.posRad < pad.posRad - pad.destRad) {
      pad.posRad = Math.min(pad.destRad, pad.posRad + 0.01 * delta);
    } else {
      pad.posRad = Math.max(pad.destRad, pad.posRad - 0.01 * delta);
    }
    pad.x = radius * Math.cos(this._pad.posRad);
    pad.y = radius * Math.sin(this._pad.posRad);

    for (var i = 0; i < this._balls.length; ++i) {
      var ball = this._balls[i];
      ball.x += ball.dx * ( ball.velocity * delta) ;
      ball.y += ball.dy * ( ball.velocity * delta) ;
    }

    ////// Handle display
    var ctx = canvasContext;
    // Clear and display game zone
    ctx.clearRect(0, 0, Config.width, Config.height);

    ctx.save();
    ctx.translate(midX, midY);

    // Display center
    for (i = 0; i < this._areas.length; ++i) {
      this._areas[i].show(ctx);
    }

    // Display border
    this._border.show(ctx);

    // Display paddle
    this._pad.show(ctx);

    // Display ball
    for (i = 0; i < this._balls.length; ++i) {
      this._balls[i].show(ctx);
    }

    ////// Handle collisions
    var destructions = false;
    for (i = 0; i < this._balls.length; ++i) {
      var collisions = 0;
      ball = this._balls[i];
      // FIXME: Collision with the pad
      if (this._pad.handleCollision(ball)) collisions++;
      if (this._border.handleCollision(ball)) collisions++;
      for (var j = 0; j < this._areas.length; ++j) {
        var area = this._areas[j];
        if (area.handleCollision(ball)) collisions++;
        if (area.isDestroyed) {
          destructions = true;
        }
      }
      // FIXME: Collision with other balls

      // Increase speed progressively
      if (collisions > 0) {
        ball.velocity *= (1 + collisions / 20);
      }
    }

    // FIXME: This won't scale if we have too many areas
    if (destructions) {
      var newAreas = [];
      for (j = 0; j < this._areas.length; ++j) {
        area = this._areas[j];
        if (!area.isDestroyed) {
          newAreas.push(area);
        }
      }
      this._areas = newAreas;
    }

    ctx.restore();

    this._previousFrameStamp = now;
  },

  getImage: function getImage() {
    return canvasContext.getImageData(0, 0, Config.width, Config.height);
  }
};

/**
 * @constructor
 */
var Sprite = function Sprite() {
  /**
   * The coordinates of the center of this object
   */
  this.x = 0;
  this.y = 0;

  /**
   * The radius
   */
  this.radiusPixels = 0;
  this.radiusPercent = null;

  this.fillStyle = null;
  this.strokeStyle = null;
  this.isBouncing = false;
  this.isAround = false;
  this.isDestructible = false;
  this.isDestroyed = false;
};
Sprite.prototype = {
  /**
   * If necessary, recompute the radius of the sprite
   * (used whenver the screen size changes)
   */
  updateRadius: function updateRadius(globalRadius) {
    console.log("Updating radius of", "" + this, globalRadius, this.radiusPercent);
    if (this.radiusPercent == null) {
      return;
    }
    this.radiusPixels = Math.floor(globalRadius * this.radiusPercent);
  },

  show: function show(ctx) {
    if (this.name == "pad") {
      console.log("Showing pad", this.x, this.y, this.radiusPixels);
    }
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.radiusPixels, 0, Math.PI * 2);
    if (this.fillStyle) {
      ctx.fillStyle = this.fillStyle;
      ctx.fill();
    }
    if (this.strokeStyle) {
      ctx.strokeStyle = this.strokeStyle;
      ctx.stroke();
    }
  },

  /**
   * Detect collisions and, if necessary, bounce
   *
   * @param {boolean} inner If true, the ball is inside the object
   */
  handleCollision: function handleCollision(ball) {
    var axisX = this.x - ball.x;
    var axisY = this.y - ball.y;

    // Distance between centers
    var sqActualDistance = axisX * axisX + axisY * axisY;

    // The distance at which there is a collision
    var sqBounceDistance;
    var bounce;
    if (this.isAround) {
      sqBounceDistance = square(this.radiusPixels - ball.radiusPixels);
      bounce = sqBounceDistance <= sqActualDistance;
    } else {
      sqBounceDistance = square(this.radiusPixels + ball.radiusPixels);
      bounce = sqBounceDistance >= sqActualDistance;
      axisX = - axisX;
      axisY = - axisY;
    }
    if (bounce && this.isDestructible) {
      this.isDestroyed = true;
    }

    if (!bounce) {
      return false;
    }
    if (!this.isBouncing) {
      return true;
    }

    // Ok, we have a collision and we should bounce

    // Normalize axis
    var actualDistance = Math.sqrt(sqActualDistance);
    axisX /= actualDistance;
    axisY /= actualDistance;

    var symX = 2 * axisX - ball.dx;
    var symY = 2 * axisY - ball.dy;

    var symNorm = Math.sqrt(symX * symX + symY * symY);

    ball.dx = symX / symNorm;
    ball.dy = symY / symNorm;
    return true;
  },

  toString: function() {
    return "Sprite: " + this.name;
  },

  name: "unnamed sprite"
};

var Area = function Area() {
};
Area.prototype = {
  __proto__: Object.create(Sprite.prototype),
  name: "area"
};

var Ball = function Ball() {
  Sprite.call(this);
  this.dx = 0;
  this.dy = 1;
  this.velocity = 0.1;
  this.radiusPixels = 5;
  this.fillStyle = "white";
};
Ball.prototype = {
  __proto__: Object.create(Sprite.prototype),
  name: "ball"
};

var Pad = function Pad() {
  Sprite.call(this);
  this.posRad = Math.PI / 2;// Position in radians
  this.destRad = Math.PI / 2; // Destination in radians
  this.radiusPixels = 20;
  this.isBouncing = true;
  this.fillStyle = "white";
};
Pad.prototype = {
  __proto__: Object.create(Sprite.prototype),
  name: "pad"
};

var Border = function Border() {
  Sprite.call(this);
  this.radiusPercent = 1;
  this.strokeStyle = "blue";
  this.isBouncing = true;
  this.isAround = true;
};
Border.prototype = {
  __proto__: Object.create(Sprite.prototype),
  name: "border",
};
if ("vibrate" in window.navigator) {
  Border.prototype.handleCollision = function handleCollision(ball) {
    if (Sprite.prototype.handleCollision.call(this, ball)) {
      window.navigator.vibrate(50);
      return true;
    }
    return false;
  };
}

var eltCanvas = document.getElementById("canvas");
var canvasContext = eltCanvas.getContext("2d");

var Input = {
  mouseX: 0,
  mouseY: 0,
  changed: false
};

var onmousemove = function onmousemove(event) {
  event.stopPropagation();
  Input.mouseX = event.clientX;
  Input.mouseY = event.clientY;
  Input.changed = true;
};

eltCanvas.addEventListener("mousemove", onmousemove);
document.getElementById("background").addEventListener("mousemove", onmousemove);

// Configure
var Circular;
if ("Circular" in window) {
  Circular = window.Circular;
} else {
  Circular = window.Circular = {};
}

var Config = window.Circular.Config;
Config.init(eltCanvas);

var Statistics = window.Circular.Statistics;

// Exports

Circular.Engine = Engine;

})();<|endoftext|>


<commit_before>import isReturned from "./is-returned";

const rootElementFinder = {
  JSXElement(path, state) {
    const { jsx, crossedFunction } = state;

    // No need to traverse our JSX element.
    if (path === jsx) {
      path.skip();
      return;
    }

    const returned = isReturned(jsx);
    const otherIsReturned = isReturned(path);

    // We're looking for a root element, which must be returned by the function.
    if (otherIsReturned && (crossedFunction || !returned)) {
      state.root = false;
      path.stop();
    }
  },

  // Don't traverse into other functions, since they cannot contain the root.
  Function(path) {
    path.skip();
  }
};

// Detects if this JSX element is the root element.
// It is not the root if there is another root element in this
// or a higher function scope.
export default function isRootJSX(path) {
  let state = {
    root: true,
    crossedFunction: false,
    jsx: path
  };

  path.findParent((path) => {
    if (path.isJSXElement()) {
      state.root = false;
    } else if (path.isFunction() || path.isProgram()) {
      path.traverse(rootElementFinder, state);
      state.crossedFunction = true;
    }

    // End early if another JSXElement is found.
    return !state.root;
  });

  return state.root;
}
<commit_msg>Small fix<commit_after>import isReturned from "./is-returned";

const rootElementFinder = {
  JSXElement(path) {
    const { jsx, crossedFunction } = this;

    // No need to traverse our JSX element.
    if (path === jsx) {
      path.skip();
      return;
    }

    const returned = isReturned(jsx);
    const otherIsReturned = isReturned(path);

    // We're looking for a root element, which must be returned by the function.
    if (otherIsReturned && (crossedFunction || !returned)) {
      this.root = false;
      path.stop();
    }
  },

  // Don't traverse into other functions, since they cannot contain the root.
  Function(path) {
    path.skip();
  }
};

// Detects if this JSX element is the root element.
// It is not the root if there is another root element in this
// or a higher function scope.
export default function isRootJSX(path) {
  let state = {
    root: true,
    crossedFunction: false,
    jsx: path
  };

  path.findParent((path) => {
    if (path.isJSXElement()) {
      state.root = false;
    } else if (path.isFunction() || path.isProgram()) {
      path.traverse(rootElementFinder, state);
      state.crossedFunction = true;
    }

    // End early if another JSXElement is found.
    return !state.root;
  });

  return state.root;
}
<|endoftext|>


<commit_before>;(function () {

    // This file contains the code to define the graphics and then
    // renders them using data randomly generated by data.js.

    // Define graphics ...

    var scatterplot = gg({
        layers: [{ geometry: 'point', mapping: { x: 'd', y: 'r' } }]
    });

    var symmetric = gg({
        layers: [
            { geometry: 'line', mapping: { x: 'd', y: 'r' } },
        ],
        scales: [
            { type: 'linear', aesthetic: 'y', center: 0 }
        ]
    });

    var linechart = gg({
        layers: [
            { geometry: 'line', mapping: { x: 'd', y: 'r', group: 'subject', color: 'subject'} },
            { geometry: 'text', mapping: { x: 'd', y: 'r', }, text: '{d}, {r}', show: 'hover' }
        ],
        scales: [
            { aesthetic: 'color', type: 'color', range: ['#CFF09E', '#A8DBA8', '#79BD9A', '#3B8686'] }
        ]
    });

    var barchart = gg({
        layers: [
            { geometry: 'interval', mapping: { x: 'd', y: 'r' }, color: 'blue', width: 2 }
        ],
        scales: [
            { type: 'linear', aesthetic: 'y', min: 0 }
        ]
    });

    var histogram = gg({
        layers: [{
            geometry: 'interval',
            mapping: { x: 'group', y: 'count', color: 'group' },
            width: 20,
            statistic: { kind: 'sum', group: 'who', variable: 'purchases' }
        }],
        scales: [
            { type: 'categorical', aesthetic: 'x' },
            { type: 'linear', aesthetic: 'y', min: 0 }
        ]
    });

    var combined = gg({
        layers: [
            { geometry: 'point', mapping: { x: 'd', y: 'r' }, size: 3 },
            { geometry: 'line', mapping: { x: 'd', y: 'r' } }
            //{ geometry: 'interval', mapping: { x: 'd', y: 'r' }, width: 2 },
        ]
    });

    var semilog = gg({
        layers: [
            { geometry: 'point', mapping: { x: 'd', y: 'r' }, size: 3 },
            { geometry: 'line', mapping: { x: 'd', y: 'r' } }
        ],
        scales: [ { type: 'log', aesthetic: 'y', legend: 'whatever' },
                      { aesthetic: 'x', legend: 'foo' } ]
    });

    var heightHistogram = gg({
        layers: [
            {
                geometry: 'interval',
                mapping: { x: 'bin', y: 'count' },
                statistic: { kind: 'bin', variable: 'height', bins: 30 }
            }
        ],
        scales: [
            { type: 'categorical', aesthetic: 'x' },
            { type: 'linear', aesthetic: 'y', min: 0 }
        ]
    });

    var boxplot = gg({
        layers: [ {
            geometry: 'box',
            mapping: { x: 'group', y: false },
            statistic: { kind: 'box', group: 'grade', variable: 'value' }
        }],
        scales: [
            { type: 'categorical', aesthetic: 'x' }
        ]
    });

    var twoPopulations = gg({
        layers: [ {
            geometry: 'point',
            mapping: { x: 'intelligence', y: 'wisdom', color: 'group' },
            size: 2,
            alpha: 0.5
        }]
    });

    var quadrants = gg({
        layers: [
            {
                geometry: 'point',
                mapping: { x: 'x', y: 'y', size: 'size' }
            },
            { geometry: 'text', mapping: { x: 'x', y: 'y' }, text: '{name}: {size}',  show: 'hover' }
        ],
        scales: [ { aesthetic: 'size', range: [ 1, 5 ]} ]
    });

    var areachartSmooth = gg({
        layers: [ { geometry: 'area', mapping: { x: 'a', y: false, y0: 'top', y1: 'bottom' }, smooth: true } ]
    });

    var areachart = gg({
        layers: [ { geometry: 'area', mapping: { x: 'a', y: false, y0: 'top', y1: 'bottom' } } ]
    });

    // ... and render 'em

    var data = gg.sampleData;
    var div  = d3.select('#examples');
    var opts = { width: 300, height: 200, padding: 35 };

    linechart.renderer(div, opts)(data.upwardSubjects);
    combined.renderer(div, opts)(data.upward);
    barchart.renderer(div, opts)(_.map(data.upward, function (d) { return { d: d.d, r: Math.max(d.r, 0) }; }));
    quadrants.renderer(div, opts)(data.quadrants);
    histogram.renderer(div, opts)(data.purchases);
    semilog.renderer(div, opts)(data.semiLogData);
    heightHistogram.renderer(div, opts)(data.heightWeight);
    twoPopulations.renderer(div, opts)(data.twoPopulations);
    boxplot.renderer(div, opts)(data.forBoxPlots);
    symmetric.renderer(div, opts)(data.toBeCentered);
    areachartSmooth.renderer(div, opts)(data.upwardPairs);
    areachart.renderer(div, opts)(data.upwardPairs);

})();
<commit_msg>Change example code.<commit_after>;(function () {

    // This file contains the code to define the graphics and then
    // renders them using data randomly generated by data.js.

    var data = gg.sampleData;
    var div  = d3.select('#examples');
    var opts = { width: 300, height: 200, padding: 35 };

    // Define graphics ...

    function g (spec) { return gg(spec).renderer(div, opts); }

    var scatterplot = g({ layers: [{ geometry: 'point', mapping: { x: 'd', y: 'r' } }] });

    var symmetric = g({
        layers: [ { geometry: 'line', mapping: { x: 'd', y: 'r' } }, ],
        scales: [ { type: 'linear', aesthetic: 'y', center: 0 } ]
    });

    var linechart = g({
        layers: [
            { geometry: 'line', mapping: { x: 'd', y: 'r', group: 'subject', color: 'subject'} },
            { geometry: 'text', mapping: { x: 'd', y: 'r', }, text: '{d}, {r}', show: 'hover' }
        ],
        scales: [
            { aesthetic: 'color', type: 'color', range: ['#CFF09E', '#A8DBA8', '#79BD9A', '#3B8686'] }
        ]
    });

    var barchart = g({
        layers: [{ geometry: 'interval', mapping: { x: 'd', y: 'r' }, color: 'blue', width: 2 }],
        scales: [{ type: 'linear', aesthetic: 'y', min: 0 }]
    });

    var histogram = g({
        layers: [{
            geometry: 'interval',
            mapping: { x: 'group', y: 'count', color: 'group' },
            width: 20,
            statistic: { kind: 'sum', group: 'who', variable: 'purchases' }
        }],
        scales: [
            { type: 'categorical', aesthetic: 'x' },
            { type: 'linear', aesthetic: 'y', min: 0 }
        ]
    });

    var combined = g({
        layers: [
            { geometry: 'point', mapping: { x: 'd', y: 'r' }, size: 3 },
            { geometry: 'line', mapping: { x: 'd', y: 'r' } }
            //{ geometry: 'interval', mapping: { x: 'd', y: 'r' }, width: 2 },
        ]
    });

    var semilog = g({
        layers: [
            { geometry: 'point', mapping: { x: 'd', y: 'r' }, size: 3 },
            { geometry: 'line', mapping: { x: 'd', y: 'r' } }
        ],
        scales: [ { type: 'log', aesthetic: 'y', legend: 'whatever' },
                      { aesthetic: 'x', legend: 'foo' } ]
    });

    var heightHistogram = g({
        layers: [
            {
                geometry: 'interval',
                mapping: { x: 'bin', y: 'count' },
                statistic: { kind: 'bin', variable: 'height', bins: 30 }
            }
        ],
        scales: [
            { type: 'categorical', aesthetic: 'x' },
            { type: 'linear', aesthetic: 'y', min: 0 }
        ]
    });

    var boxplot = g({
        layers: [ {
            geometry: 'box',
            mapping: { x: 'group', y: false },
            statistic: { kind: 'box', group: 'grade', variable: 'value' }
        }],
        scales: [
            { type: 'categorical', aesthetic: 'x' }
        ]
    });

    var twoPopulations = g({
        layers: [ {
            geometry: 'point',
            mapping: { x: 'intelligence', y: 'wisdom', color: 'group' },
            size: 2,
            alpha: 0.5
        }]
    });

    var quadrants = g({
        layers: [
            {
                geometry: 'point',
                mapping: { x: 'x', y: 'y', size: 'size' }
            },
            { geometry: 'text', mapping: { x: 'x', y: 'y' }, text: '{name}: {size}',  show: 'hover' }
        ],
        scales: [ { aesthetic: 'size', range: [ 1, 5 ]} ]
    });

    var areachartSmooth = g({
        layers: [ { geometry: 'area', mapping: { x: 'a', y: false, y0: 'top', y1: 'bottom' }, smooth: true } ]
    });

    var areachart = g({ layers: [ { geometry: 'area', mapping: { x: 'a', y: false, y0: 'top', y1: 'bottom' } } ] });

    // ... and render 'em

    linechart(data.upwardSubjects);
    combined(data.upward);
    barchart(_.map(data.upward, function (d) { return { d: d.d, r: Math.max(d.r, 0) }; }));
    quadrants(data.quadrants);
    histogram(data.purchases);
    semilog(data.semiLogData);
    heightHistogram(data.heightWeight);
    twoPopulations(data.twoPopulations);
    boxplot(data.forBoxPlots);
    symmetric(data.toBeCentered);
    areachartSmooth(data.upwardPairs);
    areachart(data.upwardPairs);

})();
<|endoftext|>


<commit_before>
it("Should be able to add a class using #toggle", function() {
	var el = document.createElement("p");
	var classList = el.classList;
	classList.toggle("classA");
	expect(classList.contains("classA")).to.be(true);
});

it("Should be able to remove a class using #toggle and return false when indicating class is removed", function() {
	var el = document.createElement("p");
	var classList = el.classList;
	el.className = "classA";

	expect(classList.toggle("classA")).to.be(false);
	expect(classList.contains("classA")).to.be(false);
});

it("Should allow classes to be added using #add", function() {
	var el = document.createElement("p");
	var classList = el.classList;

	classList.add("classA");
	expect(classList.contains("classA")).to.be(true);
});

it("Should force add a class using toggle if the second argument is true", function() {
	var el = document.createElement("p");
	var classList = el.classList;
	classList.add("classA");
	classList.toggle("classA", true);
	expect(classList.contains("classA")).to.be(true);
});

it("Should be indexable", function() {
	var el = document.createElement("p");
	var classList = el.classList;
	el.className = "a b";

	// for old ie
	classList.toString();

	expect(classList[0]).to.be('a');
	expect(classList[1]).to.be('b');
});

it("Should be indexable using the #item method", function() {
	var el = document.createElement("p");
	var classList = el.classList;
	el.className = "a b";

	// for old ie
	classList.toString();

	expect(classList.item(0)).to.be('a');
	expect(classList.item(1)).to.be('b');
});

it("Should return the length using the #length method", function() {
	var el = document.createElement("p");
	var classList = el.classList;
	el.className = "a b";

	// for old ie
	classList.toString();

	expect(classList.length).to.be(2);
});

it("Should remove duplicate instances of class", function() {
	var el = document.createElement("p");
	var classList = el.classList;
	el.className = "a a a";

	classList.remove("a");
	expect(classList.contains("a")).to.be(false);
	expect(el.className).to.be("");
});
<commit_msg>Added failing test for classList on svg elements<commit_after>
it("Should be able to add a class using #toggle", function() {
	var el = document.createElement("p");
	var classList = el.classList;
	classList.toggle("classA");
	expect(classList.contains("classA")).to.be(true);
});

it("Should be able to remove a class using #toggle and return false when indicating class is removed", function() {
	var el = document.createElement("p");
	var classList = el.classList;
	el.className = "classA";

	expect(classList.toggle("classA")).to.be(false);
	expect(classList.contains("classA")).to.be(false);
});

it("Should allow classes to be added using #add", function() {
	var el = document.createElement("p");
	var classList = el.classList;

	classList.add("classA");
	expect(classList.contains("classA")).to.be(true);
});

it("Should force add a class using toggle if the second argument is true", function() {
	var el = document.createElement("p");
	var classList = el.classList;
	classList.add("classA");
	classList.toggle("classA", true);
	expect(classList.contains("classA")).to.be(true);
});

it("Should be indexable", function() {
	var el = document.createElement("p");
	var classList = el.classList;
	el.className = "a b";

	// for old ie
	classList.toString();

	expect(classList[0]).to.be('a');
	expect(classList[1]).to.be('b');
});

it("Should be indexable using the #item method", function() {
	var el = document.createElement("p");
	var classList = el.classList;
	el.className = "a b";

	// for old ie
	classList.toString();

	expect(classList.item(0)).to.be('a');
	expect(classList.item(1)).to.be('b');
});

it("Should return the length using the #length method", function() {
	var el = document.createElement("p");
	var classList = el.classList;
	el.className = "a b";

	// for old ie
	classList.toString();

	expect(classList.length).to.be(2);
});

it("Should remove duplicate instances of class", function() {
	var el = document.createElement("p");
	var classList = el.classList;
	el.className = "a a a";

	classList.remove("a");
	expect(classList.contains("a")).to.be(false);
	expect(el.className).to.be("");
});

it("Should work on svg elements", function() {
	var el = document.createElementNS("http://www.w3.org/2000/svg", "svg");
	var classList = el.classList;
	el.setAttribute('class', "a");

	classList.add("b");
	expect(classList.contains("b")).to.be(true);
	expect(el.className.baseVal).to.be("a b");
});
<|endoftext|>