<commit_before>'use strict';
var d3 = require('d3');
require('d3-multiaxis-zoom')(d3);
var _ = require('lodash');
var utils = require('lightning-client-utils');
var TooltipPlugin = require('d3-tip');
TooltipPlugin(d3);

var margin = {
    top: 30,
    right: 20,
    bottom: 20,
    left: 45
};

var nestedExtent = function(data, map) {
    var max = d3.max(data, function(arr) {
        return d3.max(_.map(arr, map));
    });
    var min = d3.min(data, function(arr) {
        return d3.min(_.map(arr, map));
    });

    return [min, max];
};

var Line = function(selector, data, images, opts) {

    var defaults = {
        tooltips: false
    };

    opts = _.defaults(opts || {}, defaults);
    this.opts = opts;

    this.data = this._formatData(data);

    if(_.has(this.data, 'xaxis')) {
        margin.bottom = 57;
    }
    if(_.has(this.data, 'yaxis')) {
        margin.left = 70;
    }

    this.width = (opts.width || $(selector).width()) - margin.left - margin.right;
    this.height = Math.min(($(selector).height() || Infinity), (opts.height || (this.width * 0.6))) - margin.top - margin.bottom;

    this.selector = selector;
    this._init();
};

Line.prototype._init = function() {

    var data = this.data;
    var height = this.height;
    var width = this.width;
    var opts = this.opts;
    var selector = this.selector;
    var self = this;

    var series = data.series
    this.series = series;

    function setDefaultSize() {
        self.defaultSize = Math.max(Math.exp(2.5 - 0.005 * series[0].d.length), 1);
    }

    setDefaultSize()

    function setAxis() {

        var yDomain = nestedExtent(self.series.map(function(d) {return d.d}), function(d) {
            return d.y;
        });
        var xDomain = nestedExtent(self.series.map(function(d) {return d.d}), function(d) {
            return d.x;
        });

        var ySpread = Math.abs(yDomain[1] - yDomain[0]) || 1;
        var xSpread = Math.abs(xDomain[1] - xDomain[0]) || 1;

        self.x = d3.scale.linear()
            .domain([xDomain[0] - 0.05 * xSpread, xDomain[1] + 0.05 * xSpread])
            .range([0, width]);

        self.y = d3.scale.linear()
            .domain([yDomain[0] - 0.1 * ySpread, yDomain[1] + 0.1 * ySpread])
            .range([height, 0]);

        self.xAxis = d3.svg.axis()
            .scale(self.x)
            .orient('bottom')
            .ticks(5);

        self.yAxis = d3.svg.axis()
            .scale(self.y)
            .orient('left')
            .ticks(5);

        self.zoom = d3.behavior.zoom()
            .x(self.x)
            .y(self.y)
            .on('zoom', zoomed);

    }

    setAxis()

    this.line = d3.svg.line()
        .x(function (d) {
            return self.x(d.x);
        })
        .y(function (d) {
            return self.y(d.y);
        })

    var container = d3.select(selector)
        .append('div')
        .style('width', width + margin.left + margin.right + "px")
        .style('height', height + margin.top + margin.bottom + "px")

    var canvas = container
        .append('canvas')
        .attr('class', 'line-plot canvas')
        .attr('width', width)
        .attr('height', height)
        .style('margin', margin.top + 'px ' + margin.left + 'px')
        .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
        .call(self.zoom)

    var ctx = canvas
        .node().getContext("2d")

    var svg = container
        .append('svg:svg')
        .attr('class', 'line-plot svg')
        .attr('width', width + margin.left + margin.right)
        .attr('height', height + margin.top + margin.bottom)
        .append('svg:g')
        .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
        .call(self.zoom)

    svg.append('rect')
        .attr('width', width)
        .attr('height', height)
        .attr('class', 'line-plot rect');

    var makeXAxis = function () {
        return d3.svg.axis()
            .scale(self.x)
            .orient('bottom')
            .ticks(5);
    };

    var makeYAxis = function () {
        return d3.svg.axis()
            .scale(self.y)
            .orient('left')
            .ticks(5);
    };

    svg.append('svg:g')
        .attr('class', 'x axis')
        .attr('transform', 'translate(0, ' + height + ')')
        .call(this.xAxis);

    svg.append('g')
        .attr('class', 'y axis')
        .call(this.yAxis);

    svg.append('g')
        .attr('class', 'x grid')
        .attr('transform', 'translate(0,' + height + ')')
        .call(makeXAxis()
                .tickSize(-height, 0, 0)
                .tickFormat(''));

    svg.append('g')
        .attr('class', 'y grid')
        .call(makeYAxis()
                .tickSize(-width, 0, 0)
                .tickFormat(''));

    if(_.has(this.data, 'xaxis')) {
        var txt = this.data.xaxis;
        if(_.isArray(txt)) {
            txt = txt[0];
        }
        svg.append("text")
            .attr("class", "x label")
            .attr("text-anchor", "middle")
            .attr("x", width / 2)
            .attr("y", height + margin.bottom - 5)
            .text(txt);
    }
    if(_.has(this.data, 'yaxis')) {
        var txt = this.data.yaxis;
        if(_.isArray(txt)) {
            txt = txt[0];
        }

        svg.append("text")
            .attr("class", "y label")
            .attr("text-anchor", "middle")
            .attr("transform", "rotate(-90)")
            .attr("x", - height / 2)
            .attr("y", -50)
            .text(txt);
    }

    draw();

    function updateAxis() {

        svg.select('.x.axis').call(self.xAxis);
        svg.select('.y.axis').call(self.yAxis);
        svg.select('.x.grid')
            .call(makeXAxis()
                .tickSize(-height, 0, 0)
                .tickFormat(''));
        svg.select('.y.grid')
            .call(makeYAxis()
                    .tickSize(-width, 0, 0)
                    .tickFormat(''));
    }

    function zoomed() {
        redraw();
        updateAxis();
    }

    function redraw() {
        ctx.clearRect(0, 0, width + margin.left + margin.right, height + margin.top + margin.bottom);
        draw()
    }

    function draw() {

        ctx.globalAlpha = 0.9;

        _.forEach(self.series, function(s) {
            var t = s.d.length, d, i = 0;
            ctx.strokeStyle = s.c ? s.c : self.defaultSize;
            ctx.lineWidth = s.s ? s.s : self.defaultSize;
            ctx.lineJoin = 'round';
            ctx.beginPath();
            ctx.moveTo(self.x(s.d[0].x), self.y(s.d[0].y))
            while(++i < t) {
                ctx.lineTo(self.x(s.d[i].x), self.y(s.d[i].y));
            }
            ctx.stroke()
        })

    }

    this.svg = svg;
    this.canvas = canvas;
    this.zoomed = zoomed;
    this.updateAxis = updateAxis;
    this.setAxis = setAxis;
    this.setDefaultSize = setDefaultSize;
    this.series = series;
    this.redraw = redraw;

};

Line.prototype._formatData = function(data) {

    // parse the array data
    if(_.isArray(data.series[0])) {
        // handle case of mutliple series
        data.series = _.map(data.series, function(d) {
            return _.map(d, function(datum, i) {
                return {
                    x: data.index ? data.index[i] : i,
                    y: datum
                };
            });
        });
    } else {
        // handle a single series
        data.series = [_.map(data.series, function(d, i) {
            return {
                x: data.index ? data.index[i] : i,
                y: d
            };
        })];
    }

    // parse colors and sizes, and automatically fill colors
    // with our random colors if none provided
    var retColor = utils.getColorFromData(data);
    if (retColor.length == 0) {
        retColor = utils.getColors(data.series.length)
    }
    var retSize = data.size || []

    // embed properties in data array
    data.series = data.series.map(function(line, i) {
        var d = {'d': line, 'i': i}
        d.c = retColor.length > 1 ? retColor[i] : retColor[0]
        d.s = retSize.length > 1 ? retSize[i] : retSize[0]
        return d
    })

    return data;
};

module.exports = Line;

Line.prototype.updateData = function(data) {

    var self = this

    this.data = this._formatData(data);
    this.series = this.data.series;
    this.setDefaultSize()
    this.setAxis()
    this.canvas.call(self.zoom)
    this.updateAxis()
    this.redraw()

};<commit_msg>Tweaked size<commit_after>'use strict';
var d3 = require('d3');
require('d3-multiaxis-zoom')(d3);
var _ = require('lodash');
var utils = require('lightning-client-utils');
var TooltipPlugin = require('d3-tip');
TooltipPlugin(d3);

var margin = {
    top: 30,
    right: 20,
    bottom: 20,
    left: 45
};

var nestedExtent = function(data, map) {
    var max = d3.max(data, function(arr) {
        return d3.max(_.map(arr, map));
    });
    var min = d3.min(data, function(arr) {
        return d3.min(_.map(arr, map));
    });

    return [min, max];
};

var Line = function(selector, data, images, opts) {

    var defaults = {
        tooltips: false
    };

    opts = _.defaults(opts || {}, defaults);
    this.opts = opts;

    this.data = this._formatData(data);

    if(_.has(this.data, 'xaxis')) {
        margin.bottom = 57;
    }
    if(_.has(this.data, 'yaxis')) {
        margin.left = 70;
    }

    this.width = (opts.width || $(selector).width()) - margin.left - margin.right;
    this.height = Math.min(($(selector).height() || Infinity), (opts.height || (this.width * 0.6))) - margin.top - margin.bottom;

    this.selector = selector;
    this._init();
};

Line.prototype._init = function() {

    var data = this.data;
    var height = this.height;
    var width = this.width;
    var opts = this.opts;
    var selector = this.selector;
    var self = this;

    var series = data.series
    this.series = series;

    function setDefaultSize() {
        self.defaultSize = Math.max(Math.exp(2 - 0.003 * series[0].d.length), 1);
    }

    setDefaultSize()

    function setAxis() {

        var yDomain = nestedExtent(self.series.map(function(d) {return d.d}), function(d) {
            return d.y;
        });
        var xDomain = nestedExtent(self.series.map(function(d) {return d.d}), function(d) {
            return d.x;
        });

        var ySpread = Math.abs(yDomain[1] - yDomain[0]) || 1;
        var xSpread = Math.abs(xDomain[1] - xDomain[0]) || 1;

        self.x = d3.scale.linear()
            .domain([xDomain[0] - 0.05 * xSpread, xDomain[1] + 0.05 * xSpread])
            .range([0, width]);

        self.y = d3.scale.linear()
            .domain([yDomain[0] - 0.1 * ySpread, yDomain[1] + 0.1 * ySpread])
            .range([height, 0]);

        self.xAxis = d3.svg.axis()
            .scale(self.x)
            .orient('bottom')
            .ticks(5);

        self.yAxis = d3.svg.axis()
            .scale(self.y)
            .orient('left')
            .ticks(5);

        self.zoom = d3.behavior.zoom()
            .x(self.x)
            .y(self.y)
            .on('zoom', zoomed);

    }

    setAxis()

    this.line = d3.svg.line()
        .x(function (d) {
            return self.x(d.x);
        })
        .y(function (d) {
            return self.y(d.y);
        })

    var container = d3.select(selector)
        .append('div')
        .style('width', width + margin.left + margin.right + "px")
        .style('height', height + margin.top + margin.bottom + "px")

    var canvas = container
        .append('canvas')
        .attr('class', 'line-plot canvas')
        .attr('width', width)
        .attr('height', height)
        .style('margin', margin.top + 'px ' + margin.left + 'px')
        .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
        .call(self.zoom)

    var ctx = canvas
        .node().getContext("2d")

    var svg = container
        .append('svg:svg')
        .attr('class', 'line-plot svg')
        .attr('width', width + margin.left + margin.right)
        .attr('height', height + margin.top + margin.bottom)
        .append('svg:g')
        .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
        .call(self.zoom)

    svg.append('rect')
        .attr('width', width)
        .attr('height', height)
        .attr('class', 'line-plot rect');

    var makeXAxis = function () {
        return d3.svg.axis()
            .scale(self.x)
            .orient('bottom')
            .ticks(5);
    };

    var makeYAxis = function () {
        return d3.svg.axis()
            .scale(self.y)
            .orient('left')
            .ticks(5);
    };

    svg.append('svg:g')
        .attr('class', 'x axis')
        .attr('transform', 'translate(0, ' + height + ')')
        .call(this.xAxis);

    svg.append('g')
        .attr('class', 'y axis')
        .call(this.yAxis);

    svg.append('g')
        .attr('class', 'x grid')
        .attr('transform', 'translate(0,' + height + ')')
        .call(makeXAxis()
                .tickSize(-height, 0, 0)
                .tickFormat(''));

    svg.append('g')
        .attr('class', 'y grid')
        .call(makeYAxis()
                .tickSize(-width, 0, 0)
                .tickFormat(''));

    if(_.has(this.data, 'xaxis')) {
        var txt = this.data.xaxis;
        if(_.isArray(txt)) {
            txt = txt[0];
        }
        svg.append("text")
            .attr("class", "x label")
            .attr("text-anchor", "middle")
            .attr("x", width / 2)
            .attr("y", height + margin.bottom - 5)
            .text(txt);
    }
    if(_.has(this.data, 'yaxis')) {
        var txt = this.data.yaxis;
        if(_.isArray(txt)) {
            txt = txt[0];
        }

        svg.append("text")
            .attr("class", "y label")
            .attr("text-anchor", "middle")
            .attr("transform", "rotate(-90)")
            .attr("x", - height / 2)
            .attr("y", -50)
            .text(txt);
    }

    draw();

    function updateAxis() {

        svg.select('.x.axis').call(self.xAxis);
        svg.select('.y.axis').call(self.yAxis);
        svg.select('.x.grid')
            .call(makeXAxis()
                .tickSize(-height, 0, 0)
                .tickFormat(''));
        svg.select('.y.grid')
            .call(makeYAxis()
                    .tickSize(-width, 0, 0)
                    .tickFormat(''));
    }

    function zoomed() {
        redraw();
        updateAxis();
    }

    function redraw() {
        ctx.clearRect(0, 0, width + margin.left + margin.right, height + margin.top + margin.bottom);
        draw()
    }

    function draw() {

        ctx.globalAlpha = 0.9;

        _.forEach(self.series, function(s) {
            var t = s.d.length, d, i = 0;
            ctx.strokeStyle = s.c ? s.c : self.defaultSize;
            ctx.lineWidth = s.s ? s.s : self.defaultSize;
            ctx.lineJoin = 'round';
            ctx.beginPath();
            ctx.moveTo(self.x(s.d[0].x), self.y(s.d[0].y))
            while(++i < t) {
                ctx.lineTo(self.x(s.d[i].x), self.y(s.d[i].y));
            }
            ctx.stroke()
        })

    }

    this.svg = svg;
    this.canvas = canvas;
    this.zoomed = zoomed;
    this.updateAxis = updateAxis;
    this.setAxis = setAxis;
    this.setDefaultSize = setDefaultSize;
    this.series = series;
    this.redraw = redraw;

};

Line.prototype._formatData = function(data) {

    // parse the array data
    if(_.isArray(data.series[0])) {
        // handle case of mutliple series
        data.series = _.map(data.series, function(d) {
            return _.map(d, function(datum, i) {
                return {
                    x: data.index ? data.index[i] : i,
                    y: datum
                };
            });
        });
    } else {
        // handle a single series
        data.series = [_.map(data.series, function(d, i) {
            return {
                x: data.index ? data.index[i] : i,
                y: d
            };
        })];
    }

    // parse colors and sizes, and automatically fill colors
    // with our random colors if none provided
    var retColor = utils.getColorFromData(data);
    if (retColor.length == 0) {
        retColor = utils.getColors(data.series.length)
    }
    var retSize = data.size || []

    // embed properties in data array
    data.series = data.series.map(function(line, i) {
        var d = {'d': line, 'i': i}
        d.c = retColor.length > 1 ? retColor[i] : retColor[0]
        d.s = retSize.length > 1 ? retSize[i] : retSize[0]
        return d
    })

    return data;
};

module.exports = Line;

Line.prototype.updateData = function(data) {

    var self = this

    this.data = this._formatData(data);
    this.series = this.data.series;
    this.setDefaultSize()
    this.setAxis()
    this.canvas.call(self.zoom)
    this.updateAxis()
    this.redraw()

};<|endoftext|>


<commit_before>"use strict";

var directiveReplace     = require('../');
var es                   = require('event-stream');
var fs                   = require('fs');
var path                 = require('path');
var gutil                = require('gulp-util');
var expect               = require('chai').expect;
var mockery              = require('mockery');
var sinon                = require('sinon');

var getFile = function(filepath) {
    return new gutil.File({
        base: path.dirname(filepath),
        path: filepath,
        cwd: path.join(__dirname, 'test'),
        contents: fs.readFileSync(filepath)
    });
};

var getFileNull = function() {
    var filepath = __dirname;
    return new gutil.File({
        base: path.dirname(filepath),
        path: filepath,
        cwd: path.join(__dirname, 'test'),
        contents: null
    });
};

var getFileStream = function() {
    return new gutil.File({
        contents: es.readArray(['stream', 'with', 'those', 'contents'])
    });
};

var fixture = function(filepath) {
    return getFile(path.join('test', 'fixtures', filepath));
};

var expected = function(filepath) {
    return getFile(path.join('test', 'expected', filepath));
};

describe('gulp-directive-replace', function() {

    it('should throw an error when root path config is missing', function () {
        expect(function() {
            directiveReplace();
        }).to.throw('You should specify the templates root path.');
    });

    it('should throw a stream event error', function (cb) {

        var stream = directiveReplace({
            root: path.join(__dirname, 'fixtures')
        });

        stream.once('data', function(file) {
            expect(file.isStream()).to.be.true;
        });

        stream.once('error', function(error) {
            expect(error).to.be.instanceof(Error);
            expect(String(error.message).trim()).to.be.equal('Streaming not supported');
        });

        stream.once('end', cb);

        stream.write(getFileStream());

        stream.end();
    });

    it('should do nothing when file content is null', function (cb) {

        var stream = directiveReplace({
            root: path.join(__dirname, 'fixtures')
        });

        stream.once('data', function(file) {
            expect(file.isBuffer()).to.be.false;
            expect(file.contents).to.be.null;
        });

        stream.once('end', cb);

        stream.write(getFileNull());

        stream.end();
    });

    it('should do nothing when file content is empty', function (cb) {

        var stream = directiveReplace({
            root: path.join(__dirname, 'fixtures')
        });

        stream.once('data', function(file) {
            expect(file.isBuffer()).to.be.true;
            expect(String(file.contents).trim()).to.be.empty;
        });

        stream.once('end', cb);

        stream.write(fixture('example01.js'));

        stream.end();
    });

    it('should do nothing with templateUrl when file does not exist', function (cb) {

        var stream = directiveReplace({
            root: path.join(__dirname, 'fixtures')
        });

        stream.once('data', function(file) {
            expect(file.isBuffer()).to.be.true;
            expect(String(file.contents).trim()).to.be.equal(String(expected('example03.js').contents).trim());
        });

        stream.once('end', cb);

        stream.write(fixture('example03.js'));

        stream.end();
    });

    it('should replace the unique templateUrl found', function (cb) {

        var stream = directiveReplace({
            root: path.join(__dirname, 'fixtures')
        });

        stream.once('data', function(file) {
            expect(file.isBuffer()).to.be.true;
            expect(String(file.contents).trim()).to.be.equal(String(expected('example02.js').contents).trim());
        });

        stream.once('end', cb);

        stream.write(fixture('example02.js'));

        stream.end();
    });

    it('should replace one or more templateUrl found in a single and deeper level path', function (cb) {

        var stream = directiveReplace({
            root: path.join(__dirname, 'fixtures')
        });

        stream.once('data', function(file) {
            expect(file.isBuffer()).to.be.true;
            expect(String(file.contents).trim()).to.be.equal(String(expected('example04.js').contents).trim());
        });

        stream.once('end', cb);

        stream.write(fixture('example04.js'));

        stream.end();
    });

    it('should have a transformation function when it is provided on config', function (cb) {

        var stream = directiveReplace({
            root: path.join(__dirname, 'fixtures'),
            transform: function(basePath, template) {
                return template;
            }
        });

        stream.once('data', function(file) {
            expect(file.isBuffer()).to.be.true;
            expect(String(file.contents).trim()).to.be.equal(String(expected('example05.js').contents).trim());
        });

        stream.once('end', cb);

        stream.write(fixture('example05.js'));

        stream.end();
    });

    it('should pass minify options to html-minifier',  function(cb) {
        var minifyOpts = {
            collapseWhitespace: false,
            caseSensitive: false,
            maxLineLength: 12345
        };

        mockery.enable({
            warnOnReplace: false,
            warnOnUnregistered: false,
            useCleanCache: true
        });

        mockery.registerMock('html-minifier', {
            minify: function(content, opts) {
                expect(opts).to.be.eql(minifyOpts);
                return content;
            }
        });

        directiveReplace = require('../');

        var stream = directiveReplace({
            root: path.join(__dirname, 'fixtures'),
            minify: minifyOpts
        });

        stream.once('data', function(file) {
            expect(file.isBuffer()).to.be.true;
        });

        stream.once('end', cb);

        stream.write(fixture('example05.js'));

        stream.end();
    });
});<commit_msg>[CHANGE] Remove unused sinon module<commit_after>"use strict";

var directiveReplace     = require('../');
var es                   = require('event-stream');
var fs                   = require('fs');
var path                 = require('path');
var gutil                = require('gulp-util');
var expect               = require('chai').expect;
var mockery              = require('mockery');

var getFile = function(filepath) {
    return new gutil.File({
        base: path.dirname(filepath),
        path: filepath,
        cwd: path.join(__dirname, 'test'),
        contents: fs.readFileSync(filepath)
    });
};

var getFileNull = function() {
    var filepath = __dirname;
    return new gutil.File({
        base: path.dirname(filepath),
        path: filepath,
        cwd: path.join(__dirname, 'test'),
        contents: null
    });
};

var getFileStream = function() {
    return new gutil.File({
        contents: es.readArray(['stream', 'with', 'those', 'contents'])
    });
};

var fixture = function(filepath) {
    return getFile(path.join('test', 'fixtures', filepath));
};

var expected = function(filepath) {
    return getFile(path.join('test', 'expected', filepath));
};

describe('gulp-directive-replace', function() {

    it('should throw an error when root path config is missing', function () {
        expect(function() {
            directiveReplace();
        }).to.throw('You should specify the templates root path.');
    });

    it('should throw a stream event error', function (cb) {

        var stream = directiveReplace({
            root: path.join(__dirname, 'fixtures')
        });

        stream.once('data', function(file) {
            expect(file.isStream()).to.be.true;
        });

        stream.once('error', function(error) {
            expect(error).to.be.instanceof(Error);
            expect(String(error.message).trim()).to.be.equal('Streaming not supported');
        });

        stream.once('end', cb);

        stream.write(getFileStream());

        stream.end();
    });

    it('should do nothing when file content is null', function (cb) {

        var stream = directiveReplace({
            root: path.join(__dirname, 'fixtures')
        });

        stream.once('data', function(file) {
            expect(file.isBuffer()).to.be.false;
            expect(file.contents).to.be.null;
        });

        stream.once('end', cb);

        stream.write(getFileNull());

        stream.end();
    });

    it('should do nothing when file content is empty', function (cb) {

        var stream = directiveReplace({
            root: path.join(__dirname, 'fixtures')
        });

        stream.once('data', function(file) {
            expect(file.isBuffer()).to.be.true;
            expect(String(file.contents).trim()).to.be.empty;
        });

        stream.once('end', cb);

        stream.write(fixture('example01.js'));

        stream.end();
    });

    it('should do nothing with templateUrl when file does not exist', function (cb) {

        var stream = directiveReplace({
            root: path.join(__dirname, 'fixtures')
        });

        stream.once('data', function(file) {
            expect(file.isBuffer()).to.be.true;
            expect(String(file.contents).trim()).to.be.equal(String(expected('example03.js').contents).trim());
        });

        stream.once('end', cb);

        stream.write(fixture('example03.js'));

        stream.end();
    });

    it('should replace the unique templateUrl found', function (cb) {

        var stream = directiveReplace({
            root: path.join(__dirname, 'fixtures')
        });

        stream.once('data', function(file) {
            expect(file.isBuffer()).to.be.true;
            expect(String(file.contents).trim()).to.be.equal(String(expected('example02.js').contents).trim());
        });

        stream.once('end', cb);

        stream.write(fixture('example02.js'));

        stream.end();
    });

    it('should replace one or more templateUrl found in a single and deeper level path', function (cb) {

        var stream = directiveReplace({
            root: path.join(__dirname, 'fixtures')
        });

        stream.once('data', function(file) {
            expect(file.isBuffer()).to.be.true;
            expect(String(file.contents).trim()).to.be.equal(String(expected('example04.js').contents).trim());
        });

        stream.once('end', cb);

        stream.write(fixture('example04.js'));

        stream.end();
    });

    it('should have a transformation function when it is provided on config', function (cb) {

        var stream = directiveReplace({
            root: path.join(__dirname, 'fixtures'),
            transform: function(basePath, template) {
                return template;
            }
        });

        stream.once('data', function(file) {
            expect(file.isBuffer()).to.be.true;
            expect(String(file.contents).trim()).to.be.equal(String(expected('example05.js').contents).trim());
        });

        stream.once('end', cb);

        stream.write(fixture('example05.js'));

        stream.end();
    });

    it('should pass minify options to html-minifier',  function(cb) {
        var minifyOpts = {
            collapseWhitespace: false,
            caseSensitive: false,
            maxLineLength: 12345
        };

        mockery.enable({
            warnOnReplace: false,
            warnOnUnregistered: false,
            useCleanCache: true
        });

        mockery.registerMock('html-minifier', {
            minify: function(content, opts) {
                expect(opts).to.be.eql(minifyOpts);
                return content;
            }
        });

        directiveReplace = require('../');

        var stream = directiveReplace({
            root: path.join(__dirname, 'fixtures'),
            minify: minifyOpts
        });

        stream.once('data', function(file) {
            expect(file.isBuffer()).to.be.true;
        });

        stream.once('end', cb);

        stream.write(fixture('example05.js'));

        stream.end();
    });
});<|endoftext|>


<commit_before>/**
 * @copyright 2015, Robin Dietrich
 * @license AGPLv3 <http://www.gnu.org/licenses/agpl.html>
 */
define(function(require, exports, module) {
    var completeUtil = require("plugins/c9.ide.language/complete_util");
    var baseLanguageHandler = require('plugins/c9.ide.language/base_handler');
    var worker_util = require("plugins/c9.ide.language/worker_util");
    var _ = require("plugins/c9.nodeapi/lodash");

    var completer = module.exports = Object.create(baseLanguageHandler);
    var uId = 0;

    // caches last results
    var last_results = null;
    var last_pos = 0;

    // returns index of last full word
    function get_last_word_start(str) {
        var last = 0;
        for (var i = 0; i < str.length; ++i) {
            if (!str[i].match(/\w/)) {
                last = i+1;
            }
        }
        return last;
    }

    // takes care of initial plugin registration
    completer.init = function(callback) {
        callback();
    };

    // check if we handle the language
    completer.handlesLanguage = function(language) {
        return language === "c_cpp";
    };

    // do an initial parse to speed things up in the future
    completer.onDocumentOpen = function (path, doc, oldPath, callback) {
        completer.sender.emit("documentOpened", {path: path});
        callback();
    };

    // send closing info
    completer.onDocumentClose = function (path, callback) {
        completer.sender.emit("documentClosed", {path: path});
        callback();
    };

    // code completion
    completer.complete = function(doc, fullAst, pos, currentNode, callback) {
        // returns true if one strings is a subsequent match to another
        var filter_match = function (search, text) {
            var idx = 0;

            for (var i = 0; i < text.length; ++i) {
                if (idx == search.length)
                    return true;

                if (text[i] == search[idx])
                    ++idx;
            }

            return false;
        }

        // filter candidates based on entered text
        var filter_results = function (results, txt) {
            // match each results name to the subsequence
            var ret = [];

            if (txt.length)
                _.forEach(results, function(res) {
                    if (filter_match(txt, res.name))
                        ret.push(res);
                });
            else
                ret = results;

            // transform to c9 format
            var retConv = [];
            _.forEach(ret, function(res) {
                var r_meta = res.args.length ? "("+res.args.join(", ")+")" : null;

                retConv.push({
                    name: res.name, meta: r_meta, replaceText: res.name,
                    icon: null, priority: 100, doc: ""
                });
            });

            return retConv;
        };

        // create a unique numeric id to identify correct callback relationships
        var cId = ++uId;

        // match line to last full word
        var line = doc.getLine(pos.row);
        var wIdx = get_last_word_start(line.substr(0, pos.column));

        // pull back completion to the beginning if we have a full word start
        console.log(pos.column, wIdx);
        pos.column = wIdx;
        var wMatch = line.substr(wIdx);

        // check if we can use cached results
        if (last_results && last_pos.row == pos.row && last_pos.column == pos.column) {
            callback(last_results);
            return;
        }

        // cb when code completion is done
        completer.sender.on("completionResult", function tmp(event) {
            if (event.data.id != cId)
                return;

            // unregister this cb
            completer.sender.off("invokeCompletionReturn", tmp);

            last_results = filter_results(event.data.results, wMatch);
            last_pos = pos;

            // send results back
            callback(last_results);
        });

        // send completion data to the server
        completer.sender.emit("completion", {
            pos: pos,
            id: cId
        });
    };

    // do some code completion magic
    /*completer.complete = function(doc, fullAst, pos, currentNode, callback) {
        // create a unique numeric id to identify correct callback relationships
        var cId = ++uId;

        // wait for the result and invoke the complete.callback function
        completer.sender.on("invokeCompletionReturn", function invoTmp(ev) {
            if (ev.data.id != cId)
                return;

            // unregister this cb
            completer.sender.off("invokeCompletionReturn", invoTmp);

            var results = []; // results to return
            var line = doc.getLine(pos.row); // active line

            // match line to last full word
            var wIdx = get_last_word_start(line.substr(0, pos.column));
            var wMatch = false;

            if (wIdx < line.length) {
                // last index is within boundaries
                wMatch = line.substr(wIdx);
            }

            _.forEach(ev.data.results, function(result) {
                // variables used in the result
                var r_name, r_meta, r_replace, r_doc = "";
                var r_icon = null;
                var r_priority = 1005;

                switch(result.type) {
                    // struct, class, union, enum, enum member
                    case "enum_member":
                    case "def":
                        r_name = result.name;
                        r_doc = result.description;
                        r_replace = result.name;
                        r_icon = "package";
                        break;

                    // a single function, almost always emitted
                    case "function":
                        r_name = result.name + "(" + result.params.join(", ") + ")";
                        r_doc = result.return + " " + result.name + "(" + result.params.join(", ") + ")"
                        r_replace = result.name + "(";
                        r_icon = "method";
                        //r_meta = "(" + result.params.join(", ") + ")";
                        break;

                    // variable
                    case "variable":
                        r_name = result.name;
                        r_doc = result.return + " " + result.name;
                        r_replace = result.name;
                        r_icon = "property";
                        break;

                    // type definition
                    case "typedef":
                        //r_priority = 1004;
                        r_name = result.name;
                        r_replace = result.name;
                        break;

                    // class method
                    case "method":
                        r_name = result.name + "(" + result.params.join(", ") + ")";
                        r_doc = result.return + " " + result.name + "(" + result.params.join(", ") + ")"
                        r_replace = result.name + "(";
                        r_icon = "method";
                        //r_meta = "(" + result.params.join(", ") + ")";
                        break;

                    // class attribute
                    case "member":
                        r_name = result.name;
                        r_doc = result.return + " " + result.name;
                        r_replace = result.name;
                        r_icon = "property";
                        break;

                    // namespace
                    case "namespace":
                        r_name = result.name;
                        r_meta = "namespace";
                        r_replace = result.name + "::";
                        break;

                    // constructor
                    case "constructor":
                        r_name = result.name + "(" + result.params.join(", ") + ")";
                        r_doc = result.return + " " + result.name + "(" + result.params.join(", ") + ")"
                        r_replace = result.name;
                        r_icon = "package";
                        break;

                    // current argument in function
                    case "current":
                        r_priority = 1010;
                        r_name = result.name;
                        r_replace = result.name;
                        break;
                }

                if (!wMatch || r_name.substr(0, wMatch.length) == wMatch) {
                    // add result to list
                    results.push({
                        name: r_name, meta: r_meta, replaceText: r_replace,
                        icon: r_icon, priority: r_priority, doc: r_doc
                    });
                }
            });

            callback(results);
        });

        // send the completion data to the server
        completer.sender.emit("invokeCompletion", {
            pos: pos,
            id: cId
        });
    };*/
});
<commit_msg>Removed console.log<commit_after>/**
 * @copyright 2015, Robin Dietrich
 * @license AGPLv3 <http://www.gnu.org/licenses/agpl.html>
 */
define(function(require, exports, module) {
    var completeUtil = require("plugins/c9.ide.language/complete_util");
    var baseLanguageHandler = require('plugins/c9.ide.language/base_handler');
    var worker_util = require("plugins/c9.ide.language/worker_util");
    var _ = require("plugins/c9.nodeapi/lodash");

    var completer = module.exports = Object.create(baseLanguageHandler);
    var uId = 0;

    // caches last results
    var last_results = null;
    var last_pos = 0;

    // returns index of last full word
    function get_last_word_start(str) {
        var last = 0;
        for (var i = 0; i < str.length; ++i) {
            if (!str[i].match(/\w/)) {
                last = i+1;
            }
        }
        return last;
    }

    // takes care of initial plugin registration
    completer.init = function(callback) {
        callback();
    };

    // check if we handle the language
    completer.handlesLanguage = function(language) {
        return language === "c_cpp";
    };

    // do an initial parse to speed things up in the future
    completer.onDocumentOpen = function (path, doc, oldPath, callback) {
        completer.sender.emit("documentOpened", {path: path});
        callback();
    };

    // send closing info
    completer.onDocumentClose = function (path, callback) {
        completer.sender.emit("documentClosed", {path: path});
        callback();
    };

    // code completion
    completer.complete = function(doc, fullAst, pos, currentNode, callback) {
        // returns true if one strings is a subsequent match to another
        var filter_match = function (search, text) {
            var idx = 0;

            for (var i = 0; i < text.length; ++i) {
                if (idx == search.length)
                    return true;

                if (text[i] == search[idx])
                    ++idx;
            }

            return false;
        }

        // filter candidates based on entered text
        var filter_results = function (results, txt) {
            // match each results name to the subsequence
            var ret = [];

            if (txt.length)
                _.forEach(results, function(res) {
                    if (filter_match(txt, res.name))
                        ret.push(res);
                });
            else
                ret = results;

            // transform to c9 format
            var retConv = [];
            _.forEach(ret, function(res) {
                var r_meta = res.args.length ? "("+res.args.join(", ")+")" : null;

                retConv.push({
                    name: res.name, meta: r_meta, replaceText: res.name,
                    icon: null, priority: 100, doc: ""
                });
            });

            return retConv;
        };

        // create a unique numeric id to identify correct callback relationships
        var cId = ++uId;

        // match line to last full word
        var line = doc.getLine(pos.row);
        var wIdx = get_last_word_start(line.substr(0, pos.column));

        // pull back completion to the beginning if we have a full word start
        pos.column = wIdx;
        var wMatch = line.substr(wIdx);

        // check if we can use cached results
        if (last_results && last_pos.row == pos.row && last_pos.column == pos.column) {
            callback(last_results);
            return;
        }

        // cb when code completion is done
        completer.sender.on("completionResult", function tmp(event) {
            if (event.data.id != cId)
                return;

            // unregister this cb
            completer.sender.off("invokeCompletionReturn", tmp);

            last_results = filter_results(event.data.results, wMatch);
            last_pos = pos;

            // send results back
            callback(last_results);
        });

        // send completion data to the server
        completer.sender.emit("completion", {
            pos: pos,
            id: cId
        });
    };

    // do some code completion magic
    /*completer.complete = function(doc, fullAst, pos, currentNode, callback) {
        // create a unique numeric id to identify correct callback relationships
        var cId = ++uId;

        // wait for the result and invoke the complete.callback function
        completer.sender.on("invokeCompletionReturn", function invoTmp(ev) {
            if (ev.data.id != cId)
                return;

            // unregister this cb
            completer.sender.off("invokeCompletionReturn", invoTmp);

            var results = []; // results to return
            var line = doc.getLine(pos.row); // active line

            // match line to last full word
            var wIdx = get_last_word_start(line.substr(0, pos.column));
            var wMatch = false;

            if (wIdx < line.length) {
                // last index is within boundaries
                wMatch = line.substr(wIdx);
            }

            _.forEach(ev.data.results, function(result) {
                // variables used in the result
                var r_name, r_meta, r_replace, r_doc = "";
                var r_icon = null;
                var r_priority = 1005;

                switch(result.type) {
                    // struct, class, union, enum, enum member
                    case "enum_member":
                    case "def":
                        r_name = result.name;
                        r_doc = result.description;
                        r_replace = result.name;
                        r_icon = "package";
                        break;

                    // a single function, almost always emitted
                    case "function":
                        r_name = result.name + "(" + result.params.join(", ") + ")";
                        r_doc = result.return + " " + result.name + "(" + result.params.join(", ") + ")"
                        r_replace = result.name + "(";
                        r_icon = "method";
                        //r_meta = "(" + result.params.join(", ") + ")";
                        break;

                    // variable
                    case "variable":
                        r_name = result.name;
                        r_doc = result.return + " " + result.name;
                        r_replace = result.name;
                        r_icon = "property";
                        break;

                    // type definition
                    case "typedef":
                        //r_priority = 1004;
                        r_name = result.name;
                        r_replace = result.name;
                        break;

                    // class method
                    case "method":
                        r_name = result.name + "(" + result.params.join(", ") + ")";
                        r_doc = result.return + " " + result.name + "(" + result.params.join(", ") + ")"
                        r_replace = result.name + "(";
                        r_icon = "method";
                        //r_meta = "(" + result.params.join(", ") + ")";
                        break;

                    // class attribute
                    case "member":
                        r_name = result.name;
                        r_doc = result.return + " " + result.name;
                        r_replace = result.name;
                        r_icon = "property";
                        break;

                    // namespace
                    case "namespace":
                        r_name = result.name;
                        r_meta = "namespace";
                        r_replace = result.name + "::";
                        break;

                    // constructor
                    case "constructor":
                        r_name = result.name + "(" + result.params.join(", ") + ")";
                        r_doc = result.return + " " + result.name + "(" + result.params.join(", ") + ")"
                        r_replace = result.name;
                        r_icon = "package";
                        break;

                    // current argument in function
                    case "current":
                        r_priority = 1010;
                        r_name = result.name;
                        r_replace = result.name;
                        break;
                }

                if (!wMatch || r_name.substr(0, wMatch.length) == wMatch) {
                    // add result to list
                    results.push({
                        name: r_name, meta: r_meta, replaceText: r_replace,
                        icon: r_icon, priority: r_priority, doc: r_doc
                    });
                }
            });

            callback(results);
        });

        // send the completion data to the server
        completer.sender.emit("invokeCompletion", {
            pos: pos,
            id: cId
        });
    };*/
});
<|endoftext|>


<commit_before>'use babel';

MockDate = require('mockdate')

getDate = function(workspaceElement) {
  return workspaceElement.querySelector('.atom-clock-time').textContent
}

getTooltips = function(workspaceElement) {
  element = workspaceElement.querySelector('.atom-clock')
  return atom.tooltips.findTooltips(element)
}

getTooltipDate = function(workspaceElement) {
  tooltip = getTooltips(workspaceElement)[0]
  return tooltip.getTitle()
}

describe('Atom Clock', () => {

  let workspaceElement

  beforeEach(() => {
    workspaceElement = atom.views.getView(atom.workspace)
    jasmine.attachToDOM(workspaceElement)
    MockDate.set('1987-04-11 04:00')

    let statusBar
    let AtomClock

    waitsForPromise(() => atom.packages.activatePackage('status-bar').then((pack) => {
      statusBar = workspaceElement.querySelector('status-bar')
    }))

    waitsForPromise(() => atom.packages.activatePackage('atom-clock').then((clk) => {
      AtomClock = clk.mainModule
      AtomClock.consumeStatusBar(statusBar)
    }))

    waitsForPromise(() => atom.workspace.open())
  })

  afterEach(() => {
    MockDate.reset()
  })

  it('should not show the tooltip by default', () => {
    expect(getTooltips(workspaceElement)[0].enabled).toBe(false)
  })

  it('should show the tooltip when configured', () => {
    atom.config.set('atom-clock.showTooltip', true)
    expect(getTooltips(workspaceElement)[0].enabled).toBe(true)
  })

  it('should not show the clock icon by default', () => {
    icon = workspaceElement.querySelector('.atom-clock-icon.icon-clock')
    expect(icon).toBeNull()
  })

  it('should show the clock icon when configured', () => {
    atom.config.set('atom-clock.showClockIcon', true)
    icon = workspaceElement.querySelector('.atom-clock-icon.icon-clock')
    expect(icon).not.toBeNull()
  })

  it('should show the time with the default format', () => {
    date = getDate(workspaceElement)
    expect(date).toBe('4:00')
  })

  it('should show the time in the tooltip with the default format', () => {
    date = getTooltipDate(workspaceElement)
    expect(date.toLowerCase()).toBe('saturday, april 11, 1987 4:00 am')
  })

  it('should change the format of displayed time', () => {
    atom.config.set('atom-clock.dateFormat', 'H:mm:ss')
    date = getDate(workspaceElement)
    expect(date).toBe('4:00:00')

    atom.config.set('atom-clock.dateFormat', 'DD dddd YY H:mm')
    date = getDate(workspaceElement)
    expect(date.toLowerCase()).toBe('11 saturday 87 4:00')
  })

  it('should change the format of the displayed time in the tooltip', () => {
    atom.config.set('atom-clock.tooltipDateFormat', 'H:mm:ss')
    date = getTooltipDate(workspaceElement)
    expect(date).toBe('4:00:00')

    atom.config.set('atom-clock.tooltipDateFormat', 'DD dddd YY H:mm')
    date = getTooltipDate(workspaceElement)
    expect(date.toLowerCase()).toBe('11 saturday 87 4:00')
  })

  it('should change the clock content according with the locale', () => {
    atom.config.set('atom-clock.dateFormat', 'DD dddd YY H:mm')
    atom.config.set('atom-clock.locale', 'it')
    date = getDate(workspaceElement)
    expect(date.toLowerCase()).toBe('11 sabato 87 4:00')
  })

  it('should change the clock content in the tooltip according with the locale', () => {
    atom.config.set('atom-clock.tooltipDateFormat', 'DD dddd YY H:mm')
    atom.config.set('atom-clock.locale', 'it')
    date = getTooltipDate(workspaceElement)
    expect(date.toLowerCase()).toBe('11 sabato 87 4:00')
  })

  it('should change the whether UTC time is displayed', () => {
    atom.config.set('atom-clock.dateFormat', 'ZZ')

    atom.config.set('atom-clock.showUTC', true)
    date = getDate(workspaceElement)
    expect(date.toLowerCase()).toBe('+0000')
  })

  it('should change the whether UTC time is displayed in the tooltip', () => {
    atom.config.set('atom-clock.tooltipDateFormat', 'ZZ')

    atom.config.set('atom-clock.showUTC', true)
    date = getTooltipDate(workspaceElement)
    expect(date.toLowerCase()).toBe('+0000')
  })

})
<commit_msg>Modified UTC test again to actually test it properly<commit_after>'use babel';

MockDate = require('mockdate')

getDate = function(workspaceElement) {
  return workspaceElement.querySelector('.atom-clock-time').textContent
}

getTooltips = function(workspaceElement) {
  element = workspaceElement.querySelector('.atom-clock')
  return atom.tooltips.findTooltips(element)
}

getTooltipDate = function(workspaceElement) {
  tooltip = getTooltips(workspaceElement)[0]
  return tooltip.getTitle()
}

describe('Atom Clock', () => {

  let workspaceElement

  beforeEach(() => {
    workspaceElement = atom.views.getView(atom.workspace)
    jasmine.attachToDOM(workspaceElement)
    MockDate.set('1987-04-11 04:00', -300)

    let statusBar
    let AtomClock

    waitsForPromise(() => atom.packages.activatePackage('status-bar').then((pack) => {
      statusBar = workspaceElement.querySelector('status-bar')
    }))

    waitsForPromise(() => atom.packages.activatePackage('atom-clock').then((clk) => {
      AtomClock = clk.mainModule
      AtomClock.consumeStatusBar(statusBar)
    }))

    waitsForPromise(() => atom.workspace.open())
  })

  afterEach(() => {
    MockDate.reset()
  })

  it('should not show the tooltip by default', () => {
    expect(getTooltips(workspaceElement)[0].enabled).toBe(false)
  })

  it('should show the tooltip when configured', () => {
    atom.config.set('atom-clock.showTooltip', true)
    expect(getTooltips(workspaceElement)[0].enabled).toBe(true)
  })

  it('should not show the clock icon by default', () => {
    icon = workspaceElement.querySelector('.atom-clock-icon.icon-clock')
    expect(icon).toBeNull()
  })

  it('should show the clock icon when configured', () => {
    atom.config.set('atom-clock.showClockIcon', true)
    icon = workspaceElement.querySelector('.atom-clock-icon.icon-clock')
    expect(icon).not.toBeNull()
  })

  it('should show the time with the default format', () => {
    date = getDate(workspaceElement)
    expect(date).toBe('4:00')
  })

  it('should show the time in the tooltip with the default format', () => {
    date = getTooltipDate(workspaceElement)
    expect(date.toLowerCase()).toBe('saturday, april 11, 1987 4:00 am')
  })

  it('should change the format of displayed time', () => {
    atom.config.set('atom-clock.dateFormat', 'H:mm:ss')
    date = getDate(workspaceElement)
    expect(date).toBe('4:00:00')

    atom.config.set('atom-clock.dateFormat', 'DD dddd YY H:mm')
    date = getDate(workspaceElement)
    expect(date.toLowerCase()).toBe('11 saturday 87 4:00')
  })

  it('should change the format of the displayed time in the tooltip', () => {
    atom.config.set('atom-clock.tooltipDateFormat', 'H:mm:ss')
    date = getTooltipDate(workspaceElement)
    expect(date).toBe('4:00:00')

    atom.config.set('atom-clock.tooltipDateFormat', 'DD dddd YY H:mm')
    date = getTooltipDate(workspaceElement)
    expect(date.toLowerCase()).toBe('11 saturday 87 4:00')
  })

  it('should change the clock content according with the locale', () => {
    atom.config.set('atom-clock.dateFormat', 'DD dddd YY H:mm')
    atom.config.set('atom-clock.locale', 'it')
    date = getDate(workspaceElement)
    expect(date.toLowerCase()).toBe('11 sabato 87 4:00')
  })

  it('should change the clock content in the tooltip according with the locale', () => {
    atom.config.set('atom-clock.tooltipDateFormat', 'DD dddd YY H:mm')
    atom.config.set('atom-clock.locale', 'it')
    date = getTooltipDate(workspaceElement)
    expect(date.toLowerCase()).toBe('11 sabato 87 4:00')
  })

  it('should change the whether UTC time is displayed', () => {
    atom.config.set('atom-clock.dateFormat', 'ZZ')

    atom.config.set('atom-clock.showUTC', false)
    date = getDate(workspaceElement)
    expect(date.toLowerCase()).toBe('+0500')

    atom.config.set('atom-clock.showUTC', true)
    date = getDate(workspaceElement)
    expect(date.toLowerCase()).toBe('+0000')
  })

  it('should change the whether UTC time is displayed in the tooltip', () => {
    atom.config.set('atom-clock.tooltipDateFormat', 'ZZ')

    atom.config.set('atom-clock.showUTC', false)
    date = getTooltipDate(workspaceElement)
    expect(date.toLowerCase()).toBe('+0500')

    atom.config.set('atom-clock.showUTC', true)
    date = getTooltipDate(workspaceElement)
    expect(date.toLowerCase()).toBe('+0000')
  })

})
<|endoftext|>


<commit_before>'use strict';

var _            = require('underscore');
var http         = require('http');
var EventEmitter = require('events').EventEmitter;
var SyncMachine  = require('../lib/sync-machine');

var CHANGE = 'change',
    ERROR  = 'error';

var HttpStore = function() {};

_.extend(HttpStore, EventEmitter);
_.extend(HttpStore, SyncMachine);

HttpStore.prototype.getConfig = function() {
    if (this.config) {
        return this.config;
    }

    throw 'You must extend getConfig or set this.config with a hostname and port';
};

HttpStore.prototype._getRequestOptions = function(method, path)
{
    var config = this.getConfig();

    return {
        hostname : config.hostname,
        port     : config.port,
        method   : method,
        path     : path
    };
};

HttpStore.prototype.apiRequest = function(method, path, data, cb)
{
    this.beginSync();
    var options = this._getRequestOptions(method, path);

    var self = this;

    var req = http.request(options, function(response) {
        var responseText = '';

        response.on('data', function(chunk) {
            responseText += chunk;
        });

        response.on('end', function() {
            if (_.isFunction(cb)) {
                cb(false, JSON.parse(responseText));
            }

            this.finishSync();
            self.emit(CHANGE);
        });
    });

    req.on('error', function(e) {
        if (_.isFunction(cb)) {
            cb(e);
        }

        this.abortSync();
        self.emit(ERROR, e);
    });

    if (data) {
        req.write(JSON.stringify(data));
    }

    req.end();
};

module.exports = HttpStore;
<commit_msg>fix http store<commit_after>'use strict';

var _            = require('underscore');
var http         = require('http');
var BaseStore    = require('./base');
var SyncMachine  = require('../lib/sync-machine');

var CHANGE = 'change',
    ERROR  = 'error';

var HttpStore = function() {};

_.extend(HttpStore.prototype, BaseStore.prototype);
_.extend(HttpStore.prototype, SyncMachine.prototype);

HttpStore.prototype.getConfig = function() {
    if (this.config) {
        return this.config;
    }

    throw 'You must extend getConfig or set this.config with a hostname and port';
};

HttpStore.prototype._getRequestOptions = function(method, path)
{
    var config = this.getConfig();

    return {
        hostname : config.hostname,
        port     : config.port,
        method   : method,
        path     : path
    };
};

HttpStore.prototype.apiRequest = function(method, path, data, cb)
{
    this.beginSync();
    var options = this._getRequestOptions(method, path);

    var self = this;

    var req = http.request(options, function(response) {
        var responseText = '';

        response.on('data', function(chunk) {
            responseText += chunk;
        });

        response.on('end', function() {
            if (_.isFunction(cb)) {
                cb(false, JSON.parse(responseText));
            }

            this.finishSync();
            self.emit(CHANGE);
        });
    });

    req.on('error', function(e) {
        if (_.isFunction(cb)) {
            cb(e);
        }

        this.abortSync();
        self.emit(ERROR, e);
    });

    if (data) {
        req.write(JSON.stringify(data));
    }

    req.end();
};

module.exports = HttpStore;
<|endoftext|>


<commit_before>(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD
        define(['leaflet', 'mapbox-gl'], factory);
    } else if (typeof exports === 'object') {
        // Node, CommonJS-like
        module.exports = factory(require('leaflet'), require('mapbox-gl'));
    } else {
        // Browser globals (root is window)
        root.returnExports = factory(window.L, window.mapboxgl);
    }
}(this, function (L, mapboxgl) {
    L.MapboxGL = L.Layer.extend({
            options: {
            updateInterval: 32,
            // How much to extend the overlay view (relative to map size)
            // e.g. 0.1 would be 10% of map view in each direction
            padding: 0.1,
            // whether or not to register the mouse and keyboard
            // events on the mapbox overlay
            interactive: false,
            // set the tilepane as the default pane to draw gl tiles
            pane: 'tilePane'
        },

        initialize: function (options) {
            L.setOptions(this, options);

            if (options.accessToken) {
                mapboxgl.accessToken = options.accessToken;
            }

            // setup throttling the update event when panning
            this._throttledUpdate = L.Util.throttle(this._update, this.options.updateInterval, this);
        },

        onAdd: function (map) {
            if (!this._container) {
                this._initContainer();
            }

            var paneName = this.getPaneName();
            map.getPane(paneName).appendChild(this._container);

            this._initGL();

            this._offset = this._map.containerPointToLayerPoint([0, 0]);

            // work around https://github.com/mapbox/mapbox-gl-leaflet/issues/47
            if (map.options.zoomAnimation) {
                L.DomEvent.on(map._proxy, L.DomUtil.TRANSITION_END, this._transitionEnd, this);
            }
        },

        onRemove: function (map) {
            if (this._map._proxy && this._map.options.zoomAnimation) {
                L.DomEvent.off(this._map._proxy, L.DomUtil.TRANSITION_END, this._transitionEnd, this);
            }
            var paneName = this.getPaneName();
            map.getPane(paneName).removeChild(this._container);

            this._glMap.remove();
            this._glMap = null;
        },

        getEvents: function () {
            return {
                move: this._throttledUpdate, // sensibly throttle updating while panning
                zoomanim: this._animateZoom, // applys the zoom animation to the <canvas>
                zoom: this._pinchZoom, // animate every zoom event for smoother pinch-zooming
                zoomstart: this._zoomStart, // flag starting a zoom to disable panning
                zoomend: this._zoomEnd,
                resize: this._resize
            };
        },

        getMapboxMap: function () {
            return this._glMap;
        },

        getCanvas: function () {
            return this._glMap.getCanvas();
        },

        getSize: function () {
            return this._map.getSize().multiplyBy(1 + this.options.padding * 2);
        },

        getBounds: function () {
            var halfSize = this.getSize().multiplyBy(0.5);
            var center = this._map.latLngToContainerPoint(this._map.getCenter());
            return L.latLngBounds(
                this._map.containerPointToLatLng(center.subtract(halfSize)),
                this._map.containerPointToLatLng(center.add(halfSize))
            );
        },

        getContainer: function () {
            return this._container;
        },

        // returns the pane name set in options if it is a valid pane, defaults to tilePane
        getPaneName: function () {
            return this._map.getPane(this.options.pane) ? this.options.pane : 'tilePane';
        },

        _initContainer: function () {
            var container = this._container = L.DomUtil.create('div', 'leaflet-gl-layer');

            var size = this.getSize();
            var offset = this._map.getSize().multiplyBy(this.options.padding);
            container.style.width  = size.x + 'px';
            container.style.height = size.y + 'px';

            var topLeft = this._map.containerPointToLayerPoint([0, 0]).subtract(offset);

            L.DomUtil.setPosition(container, topLeft);
        },

        _initGL: function () {
            var center = this._map.getCenter();

            var options = L.extend({}, this.options, {
                container: this._container,
                center: [center.lng, center.lat],
                zoom: this._map.getZoom() - 1,
                attributionControl: false
            });

            this._glMap = new mapboxgl.Map(options);

            // allow GL base map to pan beyond min/max latitudes
            this._glMap.transform.latRange = null;

            if (this._glMap._canvas.canvas) {
                // older versions of mapbox-gl surfaced the canvas differently
                this._glMap._actualCanvas = this._glMap._canvas.canvas;
            } else {
                this._glMap._actualCanvas = this._glMap._canvas;
            }

            // treat child <canvas> element like L.ImageOverlay
            var canvas = this._glMap._actualCanvas;
            L.DomUtil.addClass(canvas, 'leaflet-image-layer');
            L.DomUtil.addClass(canvas, 'leaflet-zoom-animated');
            if (this.options.interactive) {
                L.DomUtil.addClass(canvas, 'leaflet-interactive');
            }
            if (this.options.className) {
                L.DomUtil.addClass(canvas, this.options.className);
            }
        },

        _update: function (e) {
            // update the offset so we can correct for it later when we zoom
            this._offset = this._map.containerPointToLayerPoint([0, 0]);

            if (this._zooming) {
                return;
            }

            var size = this.getSize(),
                container = this._container,
                gl = this._glMap,
                offset = this._map.getSize().multiplyBy(this.options.padding),
                topLeft = this._map.containerPointToLayerPoint([0, 0]).subtract(offset);

            L.DomUtil.setPosition(container, topLeft);

            var center = this._map.getCenter();

            // gl.setView([center.lat, center.lng], this._map.getZoom() - 1, 0);
            // calling setView directly causes sync issues because it uses requestAnimFrame

            var tr = gl.transform;
            tr.center = mapboxgl.LngLat.convert([center.lng, center.lat]);
            tr.zoom = this._map.getZoom() - 1;

            if (gl.transform.width !== size.x || gl.transform.height !== size.y) {
                container.style.width  = size.x + 'px';
                container.style.height = size.y + 'px';
                if (gl._resize !== null && gl._resize !== undefined){
                    gl._resize();
                } else {
                    gl.resize();
                }
            } else {
                // older versions of mapbox-gl surfaced update publicly
                if (gl._update !== null && gl._update !== undefined){
                    gl._update();
                } else {
                    gl.update();
                }
            }
        },

        // update the map constantly during a pinch zoom
        _pinchZoom: function (e) {
            this._glMap.jumpTo({
                zoom: this._map.getZoom() - 1,
                center: this._map.getCenter()
            });
        },

        // borrowed from L.ImageOverlay
        // https://github.com/Leaflet/Leaflet/blob/master/src/layer/ImageOverlay.js#L139-L144
        _animateZoom: function (e) {
            var scale = this._map.getZoomScale(e.zoom);
            var padding = this._map.getSize().multiplyBy(this.options.padding * scale);
            var viewHalf = this.getSize()._divideBy(2);
            // corrections for padding (scaled), adapted from
            // https://github.com/Leaflet/Leaflet/blob/master/src/map/Map.js#L1490-L1508
            var topLeft = this._map.project(e.center, e.zoom)
                ._subtract(viewHalf)
                ._add(this._map._getMapPanePos()
                .add(padding))._round();
            var offset = this._map.project(this._map.getBounds().getNorthWest(), e.zoom)
                ._subtract(topLeft);

            L.DomUtil.setTransform(
                this._glMap._actualCanvas,
                offset.subtract(this._offset),
                scale
            );
        },

        _zoomStart: function (e) {
            this._zooming = true;
        },

        _zoomEnd: function () {
            var scale = this._map.getZoomScale(this._map.getZoom()),
                offset = this._map._latLngToNewLayerPoint(
                    this._map.getBounds().getNorthWest(),
                    this._map.getZoom(),
                    this._map.getCenter()
                );

            L.DomUtil.setTransform(
                this._glMap._actualCanvas,
                offset.subtract(this._offset),
                scale
            );

            this._zooming = false;

            this._update();
        },

        _transitionEnd: function (e) {
            L.Util.requestAnimFrame(function () {
                var zoom = this._map.getZoom();
                var center = this._map.getCenter();
                var offset = this._map.latLngToContainerPoint(
                    this._map.getBounds().getNorthWest()
                );

                // reset the scale and offset
                L.DomUtil.setTransform(this._glMap._actualCanvas, offset, 1);

                // enable panning once the gl map is ready again
                this._glMap.once('moveend', L.Util.bind(function () {
                    this._zoomEnd();
                }, this));

                // update the map position
                this._glMap.jumpTo({
                    center: center,
                    zoom: zoom - 1
                });
            }, this);
        },

        _resize: function (e) {
            this._transitionEnd(e);
        }
    });

    L.mapboxGL = function (options) {
        return new L.MapboxGL(options);
    };

}));

<commit_msg>Fix offset issue (#130)<commit_after>(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD
        define(['leaflet', 'mapbox-gl'], factory);
    } else if (typeof exports === 'object') {
        // Node, CommonJS-like
        module.exports = factory(require('leaflet'), require('mapbox-gl'));
    } else {
        // Browser globals (root is window)
        root.returnExports = factory(window.L, window.mapboxgl);
    }
}(this, function (L, mapboxgl) {
    L.MapboxGL = L.Layer.extend({
            options: {
            updateInterval: 32,
            // How much to extend the overlay view (relative to map size)
            // e.g. 0.1 would be 10% of map view in each direction
            padding: 0.1,
            // whether or not to register the mouse and keyboard
            // events on the mapbox overlay
            interactive: false,
            // set the tilepane as the default pane to draw gl tiles
            pane: 'tilePane'
        },

        initialize: function (options) {
            L.setOptions(this, options);

            if (options.accessToken) {
                mapboxgl.accessToken = options.accessToken;
            }

            // setup throttling the update event when panning
            this._throttledUpdate = L.Util.throttle(this._update, this.options.updateInterval, this);
        },

        onAdd: function (map) {
            if (!this._container) {
                this._initContainer();
            }

            var paneName = this.getPaneName();
            map.getPane(paneName).appendChild(this._container);

            this._initGL();

            this._offset = this._map.containerPointToLayerPoint([0, 0]);

            // work around https://github.com/mapbox/mapbox-gl-leaflet/issues/47
            if (map.options.zoomAnimation) {
                L.DomEvent.on(map._proxy, L.DomUtil.TRANSITION_END, this._transitionEnd, this);
            }
        },

        onRemove: function (map) {
            if (this._map._proxy && this._map.options.zoomAnimation) {
                L.DomEvent.off(this._map._proxy, L.DomUtil.TRANSITION_END, this._transitionEnd, this);
            }
            var paneName = this.getPaneName();
            map.getPane(paneName).removeChild(this._container);

            this._glMap.remove();
            this._glMap = null;
        },

        getEvents: function () {
            return {
                move: this._throttledUpdate, // sensibly throttle updating while panning
                zoomanim: this._animateZoom, // applys the zoom animation to the <canvas>
                zoom: this._pinchZoom, // animate every zoom event for smoother pinch-zooming
                zoomstart: this._zoomStart, // flag starting a zoom to disable panning
                zoomend: this._zoomEnd,
                resize: this._resize
            };
        },

        getMapboxMap: function () {
            return this._glMap;
        },

        getCanvas: function () {
            return this._glMap.getCanvas();
        },

        getSize: function () {
            return this._map.getSize().multiplyBy(1 + this.options.padding * 2);
        },

        getBounds: function () {
            var halfSize = this.getSize().multiplyBy(0.5);
            var center = this._map.latLngToContainerPoint(this._map.getCenter());
            return L.latLngBounds(
                this._map.containerPointToLatLng(center.subtract(halfSize)),
                this._map.containerPointToLatLng(center.add(halfSize))
            );
        },

        getContainer: function () {
            return this._container;
        },

        // returns the pane name set in options if it is a valid pane, defaults to tilePane
        getPaneName: function () {
            return this._map.getPane(this.options.pane) ? this.options.pane : 'tilePane';
        },

        _initContainer: function () {
            var container = this._container = L.DomUtil.create('div', 'leaflet-gl-layer');

            var size = this.getSize();
            var offset = this._map.getSize().multiplyBy(this.options.padding);
            container.style.width  = size.x + 'px';
            container.style.height = size.y + 'px';

            var topLeft = this._map.containerPointToLayerPoint([0, 0]).subtract(offset);

            L.DomUtil.setPosition(container, topLeft);
        },

        _initGL: function () {
            var center = this._map.getCenter();

            var options = L.extend({}, this.options, {
                container: this._container,
                center: [center.lng, center.lat],
                zoom: this._map.getZoom() - 1,
                attributionControl: false
            });

            this._glMap = new mapboxgl.Map(options);

            // allow GL base map to pan beyond min/max latitudes
            this._glMap.transform.latRange = null;

            if (this._glMap._canvas.canvas) {
                // older versions of mapbox-gl surfaced the canvas differently
                this._glMap._actualCanvas = this._glMap._canvas.canvas;
            } else {
                this._glMap._actualCanvas = this._glMap._canvas;
            }

            // treat child <canvas> element like L.ImageOverlay
            var canvas = this._glMap._actualCanvas;
            L.DomUtil.addClass(canvas, 'leaflet-image-layer');
            L.DomUtil.addClass(canvas, 'leaflet-zoom-animated');
            if (this.options.interactive) {
                L.DomUtil.addClass(canvas, 'leaflet-interactive');
            }
            if (this.options.className) {
                L.DomUtil.addClass(canvas, this.options.className);
            }
        },

        _update: function (e) {
            // update the offset so we can correct for it later when we zoom
            this._offset = this._map.containerPointToLayerPoint([0, 0]);

            if (this._zooming) {
                return;
            }

            var size = this.getSize(),
                container = this._container,
                gl = this._glMap,
                offset = this._map.getSize().multiplyBy(this.options.padding),
                topLeft = this._map.containerPointToLayerPoint([0, 0]).subtract(offset);

            L.DomUtil.setPosition(container, topLeft);

            var center = this._map.getCenter();

            // gl.setView([center.lat, center.lng], this._map.getZoom() - 1, 0);
            // calling setView directly causes sync issues because it uses requestAnimFrame

            var tr = gl.transform;
            tr.center = mapboxgl.LngLat.convert([center.lng, center.lat]);
            tr.zoom = this._map.getZoom() - 1;

            if (gl.transform.width !== size.x || gl.transform.height !== size.y) {
                container.style.width  = size.x + 'px';
                container.style.height = size.y + 'px';
                if (gl._resize !== null && gl._resize !== undefined){
                    gl._resize();
                } else {
                    gl.resize();
                }
            } else {
                // older versions of mapbox-gl surfaced update publicly
                if (gl._update !== null && gl._update !== undefined){
                    gl._update();
                } else {
                    gl.update();
                }
            }
        },

        // update the map constantly during a pinch zoom
        _pinchZoom: function (e) {
            this._glMap.jumpTo({
                zoom: this._map.getZoom() - 1,
                center: this._map.getCenter()
            });
        },

        // borrowed from L.ImageOverlay
        // https://github.com/Leaflet/Leaflet/blob/master/src/layer/ImageOverlay.js#L139-L144
        _animateZoom: function (e) {
            var scale = this._map.getZoomScale(e.zoom);
            var padding = this._map.getSize().multiplyBy(this.options.padding * scale);
            var viewHalf = this.getSize()._divideBy(2);
            // corrections for padding (scaled), adapted from
            // https://github.com/Leaflet/Leaflet/blob/master/src/map/Map.js#L1490-L1508
            var topLeft = this._map.project(e.center, e.zoom)
                ._subtract(viewHalf)
                ._add(this._map._getMapPanePos()
                .add(padding))._round();
            var offset = this._map.project(this._map.getBounds().getNorthWest(), e.zoom)
                ._subtract(topLeft);

            L.DomUtil.setTransform(
                this._glMap._actualCanvas,
                offset.subtract(this._offset),
                scale
            );
        },

        _zoomStart: function (e) {
            this._zooming = true;
        },

        _zoomEnd: function () {
            var scale = this._map.getZoomScale(this._map.getZoom());

            L.DomUtil.setTransform(
                this._glMap._actualCanvas,
                // https://github.com/mapbox/mapbox-gl-leaflet/pull/130
                null,
                scale
            );

            this._zooming = false;

            this._update();
        },

        _transitionEnd: function (e) {
            L.Util.requestAnimFrame(function () {
                var zoom = this._map.getZoom();
                var center = this._map.getCenter();
                var offset = this._map.latLngToContainerPoint(
                    this._map.getBounds().getNorthWest()
                );

                // reset the scale and offset
                L.DomUtil.setTransform(this._glMap._actualCanvas, offset, 1);

                // enable panning once the gl map is ready again
                this._glMap.once('moveend', L.Util.bind(function () {
                    this._zoomEnd();
                }, this));

                // update the map position
                this._glMap.jumpTo({
                    center: center,
                    zoom: zoom - 1
                });
            }, this);
        },

        _resize: function (e) {
            this._transitionEnd(e);
        }
    });

    L.mapboxGL = function (options) {
        return new L.MapboxGL(options);
    };

}));

<|endoftext|>


<commit_before>/* global describe, it, before, beforeEach */

const Brave = require('../lib/brave')
const {urlInput, navigator, navigatorBookmarked, navigatorNotBookmarked, doneButton} = require('../lib/selectors')
const {getTargetAboutUrl} = require('../../js/lib/appUrlUtil')
const settings = require('../../js/constants/settings')
const {newTabMode} = require('../../app/common/constants/settingsEnums')
const aboutNewTabUrl = getTargetAboutUrl('about:newtab')

describe('about:newtab tests', function () {
  function * setup (client) {
    yield client
      .waitForUrl(Brave.newTabUrl)
      .waitForBrowserWindow()
      .waitForVisible(urlInput)
  }

  function * loadPageWithTracker (client) {
    const url = Brave.server.url('tracking.html')
    yield client
      .waitForDataFile('trackingProtection')
      .tabByIndex(0)
      .loadUrl(url)
  }

  function * loadPageWithAdblock (client) {
    const url = Brave.server.url('adblock.html')
    yield client
      .waitForDataFile('adblock')
      .tabByIndex(0)
      .loadUrl(url)

    waitForPageLoad(client)
  }

  function * reloadNewTab (client) {
    yield client
      .tabByIndex(0)
      .loadUrl(aboutNewTabUrl)
  }

  function * addDemoAboutPages (client) {
    yield client
      .addSite({ location: 'about:about' })
      .addSite({ location: 'about:adblock' })
      .addSite({ location: 'about:autofill' })
      .addSite({ location: 'about:blank' })
      .addSite({ location: 'about:bookmarks' })
      .addSite({ location: 'about:brave' })
      .addSite({ location: 'about:certerror' })
      .addSite({ location: 'about:config' })
      .addSite({ location: 'about:downloads' })
      .addSite({ location: 'about:error' })
      .addSite({ location: 'about:extensions' })
      .addSite({ location: 'about:flash' })
      .addSite({ location: 'about:history' })
      .addSite({ location: 'about:newtab' })
      .addSite({ location: 'about:passwords' })
      .addSite({ location: 'about:preferences' })
      .addSite({ location: 'about:safebrowsing' })
      .addSite({ location: 'about:styles' })
      .waitForExist('.tab[data-frame-key="1"]')
      .tabByIndex(0)
      .url(aboutNewTabUrl)
  }

  function * waitForPageLoad (client) {
    yield client
      .windowByUrl(Brave.browserWindowUrl)
      .waitForExist('.tab[data-frame-key="1"]')
      .tabByIndex(0)
  }

  describe('with NEWTAB_MODE === EMPTY_NEW_TAB', function () {
    Brave.beforeAll(this)

    before(function * () {
      yield this.app.client.changeSetting(settings.NEWTAB_MODE, newTabMode.EMPTY_NEW_TAB)
      yield reloadNewTab(this.app.client)
      yield setup(this.app.client)
    })

    it('returns an empty page', function * () {
      yield waitForPageLoad(this.app.client)

      yield this.app.client.waitForExist('.empty')
    })
  })

  describe('with NEWTAB_MODE === NEW_TAB_PAGE', function () {
    describe('page content', function () {
      Brave.beforeAll(this)

      before(function * () {
        yield setup(this.app.client)
      })

      it('displays a clock', function * () {
        yield waitForPageLoad(this.app.client)

        yield this.app.client
          .windowByUrl(Brave.browserWindowUrl)
          .waitForExist('.tab[data-frame-key="1"]')
          .tabByIndex(0)
          .waitForVisible('.clock .time')
          .waitUntil(function () {
            return this.getText('.clock .time')
              .then((clockTime) => {
                return !!clockTime.match(/^\d{1,2}.*\d{2}.*/)
              })
          })
      })

      // TODO(bsclifton):
      // - link check
      // has link to settings
      // has link to bookmarks
      // has link to history
    })

    describe('when displaying stats', function () {
      Brave.beforeEach(this)
      beforeEach(function * () {
        yield setup(this.app.client)
      })

      it('shows # trackers blocked', function * () {
        yield loadPageWithTracker(this.app.client)

        yield reloadNewTab(this.app.client)

        yield this.app.client
          .waitForVisible('.counter.trackers')
          .waitUntil(function () {
            return this.getText('.counter.trackers')
              .then((blocked) => {
                return blocked === '2'
              })
          })
      })

      // NOTE(bsclifton): this test can take 20+ seconds to run :(
      it('shows # ads blocked', function * () {
        yield loadPageWithAdblock(this.app.client)

        yield reloadNewTab(this.app.client)

        yield this.app.client
          .waitForVisible('.counter.ads')
          .waitUntil(function () {
            return this.getText('.counter.ads')
              .then((blocked) => {
                return blocked === '1'
              })
          })
      })

      // TODO(bsclifton):
      // upgrades
      // shows a time based on # blocked
    })

    describe('with the top sites tile area', function () {
      Brave.beforeEach(this)
      beforeEach(function * () {
        yield setup(this.app.client)
        yield this.app.client.clearAppData({browserHistory: true})
      })

      it('shows a preloaded list of sites if session has no entries yet', function * () {
        yield reloadNewTab(this.app.client)

        yield this.app.client
          .waitForVisible('.topSitesElementFavicon[href^="https://twitter.com/brave"]')
          .waitForVisible('.topSitesElementFavicon[href^="https://www.facebook.com/BraveSoftware"]')
          .waitForVisible('.topSitesElementFavicon[href^="https://www.youtube.com"]')
          .waitForVisible('.topSitesElementFavicon[href^="https://brave.com"]')
          .waitForVisible('.topSitesElementFavicon[href^="https://itunes.apple.com"]')
          .waitForVisible('.topSitesElementFavicon[href^="https://play.google.com/store"]')
      })

      it('shows sites that have been visited', function * () {
        yield loadPageWithTracker(this.app.client)

        yield reloadNewTab(this.app.client)

        yield this.app.client
          .waitForVisible('.topSitesElementFavicon')
      })

      it('lets you pin a tile (and shows the pinned icon afterwards)', function * () {
        yield loadPageWithTracker(this.app.client)

        yield reloadNewTab(this.app.client)

        yield this.app.client
          .waitForVisible('.topSitesElementFavicon')
          .moveToObject('.topSitesElement')
          .waitForVisible('.topSitesActionContainer')
          .click('.topSitesActionBtn')
          .moveToObject('.timeSaved')
          .waitForVisible('.pinnedTopSite')
      })

      it('doesn\'t show about pages on topSites grid', function * () {
        // Adding about pages shouldn't add them to topSites grid
        yield addDemoAboutPages(this.app.client)

        // Bookmarking an about:page should not add it to grid as well
        yield this.app.client
          .tabByUrl(aboutNewTabUrl)
          .windowParentByUrl(aboutNewTabUrl)
          .waitForVisible(navigator)
          .moveToObject(navigator)
          .waitForVisible(navigatorNotBookmarked)
          .click(navigatorNotBookmarked)
          .waitForVisible(doneButton)
          .click(doneButton)
          .moveToObject(navigator)
          .waitForVisible(navigatorBookmarked)

        yield reloadNewTab(this.app.client)

        yield this.app.client
          .waitForExist('.topSitesElementFavicon', 3000, true)
      })

      it('shows favicon image for topSites', function * () {
        const pageWithFavicon = Brave.server.url('favicon.html')

        yield this.app.client
          .tabByUrl(Brave.newTabUrl)
          .url(pageWithFavicon)
          .waitForUrl(pageWithFavicon)
          .windowParentByUrl(pageWithFavicon)

        yield reloadNewTab(this.app.client)

        yield this.app.client
          .waitForVisible('.topSitesElementFavicon img').should.eventually.be.true
      })

      it('replace topSites favicon images with a letter when no icon is found', function * () {
        const pageWithoutFavicon = Brave.server.url('page_favicon_not_found.html')

        yield this.app.client
          .tabByUrl(Brave.newTabUrl)
          .url(pageWithoutFavicon)
          .waitForUrl(pageWithoutFavicon)
          .windowParentByUrl(pageWithoutFavicon)

        yield reloadNewTab(this.app.client)

        yield this.app.client
          .waitForVisible('.topSitesElementFavicon')
          .getText('.topSitesElementFavicon').should.eventually.be.equal('F')
      })
    })
  })
})
<commit_msg>Fix "shows a preloaded list of sites if session has no entries yet" test Don't clear history on this case or preloaded list will not exist<commit_after>/* global describe, it, before, beforeEach */

const Brave = require('../lib/brave')
const {urlInput, navigator, navigatorBookmarked, navigatorNotBookmarked, doneButton} = require('../lib/selectors')
const {getTargetAboutUrl} = require('../../js/lib/appUrlUtil')
const settings = require('../../js/constants/settings')
const {newTabMode} = require('../../app/common/constants/settingsEnums')
const aboutNewTabUrl = getTargetAboutUrl('about:newtab')

describe('about:newtab tests', function () {
  function * setup (client) {
    yield client
      .waitForUrl(Brave.newTabUrl)
      .waitForBrowserWindow()
      .waitForVisible(urlInput)
  }

  function * loadPageWithTracker (client) {
    const url = Brave.server.url('tracking.html')
    yield client
      .waitForDataFile('trackingProtection')
      .tabByIndex(0)
      .loadUrl(url)
  }

  function * loadPageWithAdblock (client) {
    const url = Brave.server.url('adblock.html')
    yield client
      .waitForDataFile('adblock')
      .tabByIndex(0)
      .loadUrl(url)

    waitForPageLoad(client)
  }

  function * reloadNewTab (client) {
    yield client
      .tabByIndex(0)
      .loadUrl(aboutNewTabUrl)
  }

  function * addDemoAboutPages (client) {
    yield client
      .addSite({ location: 'about:about' })
      .addSite({ location: 'about:adblock' })
      .addSite({ location: 'about:autofill' })
      .addSite({ location: 'about:blank' })
      .addSite({ location: 'about:bookmarks' })
      .addSite({ location: 'about:brave' })
      .addSite({ location: 'about:certerror' })
      .addSite({ location: 'about:config' })
      .addSite({ location: 'about:downloads' })
      .addSite({ location: 'about:error' })
      .addSite({ location: 'about:extensions' })
      .addSite({ location: 'about:flash' })
      .addSite({ location: 'about:history' })
      .addSite({ location: 'about:newtab' })
      .addSite({ location: 'about:passwords' })
      .addSite({ location: 'about:preferences' })
      .addSite({ location: 'about:safebrowsing' })
      .addSite({ location: 'about:styles' })
      .waitForExist('.tab[data-frame-key="1"]')
      .tabByIndex(0)
      .url(aboutNewTabUrl)
  }

  function * waitForPageLoad (client) {
    yield client
      .windowByUrl(Brave.browserWindowUrl)
      .waitForExist('.tab[data-frame-key="1"]')
      .tabByIndex(0)
  }

  describe('with NEWTAB_MODE === EMPTY_NEW_TAB', function () {
    Brave.beforeAll(this)

    before(function * () {
      yield this.app.client.changeSetting(settings.NEWTAB_MODE, newTabMode.EMPTY_NEW_TAB)
      yield reloadNewTab(this.app.client)
      yield setup(this.app.client)
    })

    it('returns an empty page', function * () {
      yield waitForPageLoad(this.app.client)

      yield this.app.client.waitForExist('.empty')
    })
  })

  describe('with NEWTAB_MODE === NEW_TAB_PAGE', function () {
    describe('page content', function () {
      Brave.beforeAll(this)

      before(function * () {
        yield setup(this.app.client)
      })

      it('displays a clock', function * () {
        yield waitForPageLoad(this.app.client)

        yield this.app.client
          .windowByUrl(Brave.browserWindowUrl)
          .waitForExist('.tab[data-frame-key="1"]')
          .tabByIndex(0)
          .waitForVisible('.clock .time')
          .waitUntil(function () {
            return this.getText('.clock .time')
              .then((clockTime) => {
                return !!clockTime.match(/^\d{1,2}.*\d{2}.*/)
              })
          })
      })

      // TODO(bsclifton):
      // - link check
      // has link to settings
      // has link to bookmarks
      // has link to history
    })

    describe('when displaying stats', function () {
      Brave.beforeEach(this)
      beforeEach(function * () {
        yield setup(this.app.client)
      })

      it('shows # trackers blocked', function * () {
        yield loadPageWithTracker(this.app.client)

        yield reloadNewTab(this.app.client)

        yield this.app.client
          .waitForVisible('.counter.trackers')
          .waitUntil(function () {
            return this.getText('.counter.trackers')
              .then((blocked) => {
                return blocked === '2'
              })
          })
      })

      // NOTE(bsclifton): this test can take 20+ seconds to run :(
      it('shows # ads blocked', function * () {
        yield loadPageWithAdblock(this.app.client)

        yield reloadNewTab(this.app.client)

        yield this.app.client
          .waitForVisible('.counter.ads')
          .waitUntil(function () {
            return this.getText('.counter.ads')
              .then((blocked) => {
                return blocked === '1'
              })
          })
      })

      // TODO(bsclifton):
      // upgrades
      // shows a time based on # blocked
    })

    describe('with the top sites tile area', function () {
      Brave.beforeEach(this)
      beforeEach(function * () {
        yield setup(this.app.client)
      })

      it('shows a preloaded list of sites if session has no entries yet', function * () {
        yield reloadNewTab(this.app.client)

        yield this.app.client
          .waitForVisible('.topSitesElementFavicon[href^="https://twitter.com/brave"]')
          .waitForVisible('.topSitesElementFavicon[href^="https://www.facebook.com/BraveSoftware"]')
          .waitForVisible('.topSitesElementFavicon[href^="https://www.youtube.com"]')
          .waitForVisible('.topSitesElementFavicon[href^="https://brave.com"]')
          .waitForVisible('.topSitesElementFavicon[href^="https://itunes.apple.com"]')
          .waitForVisible('.topSitesElementFavicon[href^="https://play.google.com/store"]')
      })

      it('shows sites that have been visited', function * () {
        yield this.app.client.clearAppData({browserHistory: true})

        yield loadPageWithTracker(this.app.client)

        yield reloadNewTab(this.app.client)

        yield this.app.client
          .waitForVisible('.topSitesElementFavicon')
      })

      it('lets you pin a tile (and shows the pinned icon afterwards)', function * () {
        yield this.app.client.clearAppData({browserHistory: true})

        yield loadPageWithTracker(this.app.client)

        yield reloadNewTab(this.app.client)

        yield this.app.client
          .waitForVisible('.topSitesElementFavicon')
          .moveToObject('.topSitesElement')
          .waitForVisible('.topSitesActionContainer')
          .click('.topSitesActionBtn')
          .moveToObject('.timeSaved')
          .waitForVisible('.pinnedTopSite')
      })

      it('doesn\'t show about pages on topSites grid', function * () {
        yield this.app.client.clearAppData({browserHistory: true})

        // Adding about pages shouldn't add them to topSites grid
        yield addDemoAboutPages(this.app.client)

        // Bookmarking an about:page should not add it to grid as well
        yield this.app.client
          .tabByUrl(aboutNewTabUrl)
          .windowParentByUrl(aboutNewTabUrl)
          .waitForVisible(navigator)
          .moveToObject(navigator)
          .waitForVisible(navigatorNotBookmarked)
          .click(navigatorNotBookmarked)
          .waitForVisible(doneButton)
          .click(doneButton)
          .moveToObject(navigator)
          .waitForVisible(navigatorBookmarked)

        yield reloadNewTab(this.app.client)

        yield this.app.client
          .waitForExist('.topSitesElementFavicon', 3000, true)
      })

      it('shows favicon image for topSites', function * () {
        yield this.app.client.clearAppData({browserHistory: true})

        const pageWithFavicon = Brave.server.url('favicon.html')

        yield this.app.client
          .tabByUrl(Brave.newTabUrl)
          .url(pageWithFavicon)
          .waitForUrl(pageWithFavicon)
          .windowParentByUrl(pageWithFavicon)

        yield reloadNewTab(this.app.client)

        yield this.app.client
          .waitForVisible('.topSitesElementFavicon img').should.eventually.be.true
      })

      it('replace topSites favicon images with a letter when no icon is found', function * () {
        yield this.app.client.clearAppData({browserHistory: true})

        const pageWithoutFavicon = Brave.server.url('page_favicon_not_found.html')

        yield this.app.client
          .tabByUrl(Brave.newTabUrl)
          .url(pageWithoutFavicon)
          .waitForUrl(pageWithoutFavicon)
          .windowParentByUrl(pageWithoutFavicon)

        yield reloadNewTab(this.app.client)

        yield this.app.client
          .waitForVisible('.topSitesElementFavicon')
          .getText('.topSitesElementFavicon').should.eventually.be.equal('F')
      })
    })
  })
})
<|endoftext|>