<commit_before>'use strict';

require('mocha');
require('should');
var assert = require('assert');
var Engines = require('..');
var engines = new Engines();
var engine = require('engine-handlebars');

describe('engines compile', function () {
  before(function () {
    engines = new Engines();
  });

  describe('.compile()', function () {
    it('should compile content with a cached engine: [handlebars].', function(done) {
      engines.setEngine('hbs', engine);
      var hbs = engines.getEngine('hbs');

      var settings = {
        partials: {
          'a': 'This is A: {{upper partials.a}} - {{lower helpers.a}}',
          'b': 'This is B: {{upper partials.b}} - {{lower helpers.b}}',
          'c': 'This is C: {{upper partials.c}} - {{lower helpers.c}}'
        },
        helpers: {
          'upper': function (str) { return str.toUpperCase(); },
          'lower': function (str) { return str.toLowerCase(); }
        }
      };

      var template = [
        '{{> a }}',
        '{{> b }}',
        '{{> c }}'
      ].join('\n\n');

      var context = {
        partials: {
          a: 'Partials Context A',
          b: 'Partials Context B',
          c: 'Partials Context C'
        },
        helpers: {
          a: 'Helpers Context A',
          b: 'Helpers Context B',
          c: 'Helpers Context C'
        }
      };

      var expected = [
        'This is A: PARTIALS CONTEXT A - helpers context a',
        'This is B: PARTIALS CONTEXT B - helpers context b',
        'This is C: PARTIALS CONTEXT C - helpers context c'
      ].join('\n');

      var fn = hbs.compile(template, settings);
      hbs.render(fn, context, function (err, content) {
        content.should.equal(expected);
        done();
      });
    });
  });

  it('should render content from a compiled string:', function() {
    var lodash = require('engine-lodash');
    var ctx = {name: 'Jon Schlinkert'};
    engines.setEngine('tmpl', lodash);

    var lodash = engines.getEngine('tmpl');
    var fn = lodash.compile('<%= name %>');
    assert(fn(ctx) === 'Jon Schlinkert');
  });

  it('should handle errors', function() {
    var lodash = require('engine-lodash');
    var ctx = {};
    engines.setEngine('tmpl', lodash);

    var lodash = engines.getEngine('tmpl');
    try {
      lodash.compile('<%= name %>', 'cause an error');
    } catch (err) {
      assert(err.message.indexOf('Cannot') !== -1);
      return;
    }
    throw new Error('Expected an error');
  });

  it('should handle async errors', function(cb) {
    var lodash = require('engine-lodash');
    engines.setEngine('tmpl', function (str, ctx, callback) {
      try {
        var fn = lodash.compile(str);
        var res = fn(ctx);
        return callback(null, res);
      } catch (err) {
        return callback(err);
      }
    });

    var tmpl = engines.getEngine('tmpl');
    var fn = tmpl.compile('<%= name %>');
    fn(function (err, res) {
      if (err) {
        assert.equal(err.message, 'name is not defined');
        return cb();
      }
      cb(new Error('Expected an error.'));
    });
  });

  it('should directly return a compiled function:', function() {
    var lodash = require('engine-lodash');
    var ctx = {name: 'Jon Schlinkert'};
    engines.setEngine('tmpl', lodash);

    var lodash = engines.getEngine('tmpl');
    var fn = lodash.compile('<%= name %>');
    fn = lodash.compile(fn);
    fn = lodash.compile(fn);
    fn = lodash.compile(fn);
    assert(fn(ctx) === 'Jon Schlinkert');
  });

  it('should allow the returned function to be async:', function(cb) {
    var lodash = require('engine-lodash');
    var ctx = {name: 'Jon Schlinkert'};
    engines.setEngine('tmpl', lodash);

    var lodash = engines.getEngine('tmpl');
    var fn = lodash.compile('<%= name %>');
    fn(ctx, function(err, res) {
      if (err) return cb(err);
      assert(res === 'Jon Schlinkert');
      cb();
    });
  });

  it('should allow the returned function to be async and not require a context:', function(cb) {
    var lodash = require('engine-lodash');
    engines.setEngine('tmpl', lodash);

    var lodash = engines.getEngine('tmpl');
    var fn = lodash.compile('No context required');
    fn(function(err, res) {
      if (err) return cb(err);
      assert(res === 'No context required');
      cb();
    });
  });

  it('should handle errors in sync render:', function(cb) {
    var lodash = require('engine-lodash');
    var ctx = {};
    engines.setEngine('tmpl', lodash);

    var lodash = engines.getEngine('tmpl');
    var fn = lodash.compile('<%= name %>');
    try {
      var res = fn(ctx);
      cb(new Error('expected an error'));
    } catch (err) {
      assert.equal(err.message, 'name is not defined');
      cb();
    }
  });

  it('should handle errors in async callback:', function(cb) {
    var lodash = require('engine-lodash');
    var ctx = {};
    engines.setEngine('tmpl', lodash);

    var lodash = engines.getEngine('tmpl');
    var fn = lodash.compile('<%= name %>');
    fn(ctx, function(err, res) {
      if (!err) return cb(new Error('expected an error'));
      assert(err.message === 'name is not defined');
      cb();
    });
  });
});
<commit_msg>update error message in test<commit_after>'use strict';

require('mocha');
require('should');
var assert = require('assert');
var Engines = require('..');
var engines = new Engines();
var engine = require('engine-handlebars');

describe('engines compile', function () {
  before(function () {
    engines = new Engines();
  });

  describe('.compile()', function () {
    it('should compile content with a cached engine: [handlebars].', function(done) {
      engines.setEngine('hbs', engine);
      var hbs = engines.getEngine('hbs');

      var settings = {
        partials: {
          'a': 'This is A: {{upper partials.a}} - {{lower helpers.a}}',
          'b': 'This is B: {{upper partials.b}} - {{lower helpers.b}}',
          'c': 'This is C: {{upper partials.c}} - {{lower helpers.c}}'
        },
        helpers: {
          'upper': function (str) { return str.toUpperCase(); },
          'lower': function (str) { return str.toLowerCase(); }
        }
      };

      var template = [
        '{{> a }}',
        '{{> b }}',
        '{{> c }}'
      ].join('\n\n');

      var context = {
        partials: {
          a: 'Partials Context A',
          b: 'Partials Context B',
          c: 'Partials Context C'
        },
        helpers: {
          a: 'Helpers Context A',
          b: 'Helpers Context B',
          c: 'Helpers Context C'
        }
      };

      var expected = [
        'This is A: PARTIALS CONTEXT A - helpers context a',
        'This is B: PARTIALS CONTEXT B - helpers context b',
        'This is C: PARTIALS CONTEXT C - helpers context c'
      ].join('\n');

      var fn = hbs.compile(template, settings);
      hbs.render(fn, context, function (err, content) {
        content.should.equal(expected);
        done();
      });
    });
  });

  it('should render content from a compiled string:', function() {
    var lodash = require('engine-lodash');
    var ctx = {name: 'Jon Schlinkert'};
    engines.setEngine('tmpl', lodash);

    var lodash = engines.getEngine('tmpl');
    var fn = lodash.compile('<%= name %>');
    assert(fn(ctx) === 'Jon Schlinkert');
  });

  it('should handle errors', function() {
    var lodash = require('engine-lodash');
    var ctx = {};
    engines.setEngine('tmpl', lodash);

    var lodash = engines.getEngine('tmpl');
    try {
      lodash.compile('<%= name %>', 'cause an error');
    } catch (err) {
      assert.equal(err.message, 'engine-cache "mergeHelpers" expected "options" to be an object.');
      return;
    }
    throw new Error('Expected an error');
  });

  it('should handle async errors', function(cb) {
    var lodash = require('engine-lodash');
    engines.setEngine('tmpl', function (str, ctx, callback) {
      try {
        var fn = lodash.compile(str);
        var res = fn(ctx);
        return callback(null, res);
      } catch (err) {
        return callback(err);
      }
    });

    var tmpl = engines.getEngine('tmpl');
    var fn = tmpl.compile('<%= name %>');
    fn(function (err, res) {
      if (err) {
        assert.equal(err.message, 'name is not defined');
        return cb();
      }
      cb(new Error('Expected an error.'));
    });
  });

  it('should directly return a compiled function:', function() {
    var lodash = require('engine-lodash');
    var ctx = {name: 'Jon Schlinkert'};
    engines.setEngine('tmpl', lodash);

    var lodash = engines.getEngine('tmpl');
    var fn = lodash.compile('<%= name %>');
    fn = lodash.compile(fn);
    fn = lodash.compile(fn);
    fn = lodash.compile(fn);
    assert(fn(ctx) === 'Jon Schlinkert');
  });

  it('should allow the returned function to be async:', function(cb) {
    var lodash = require('engine-lodash');
    var ctx = {name: 'Jon Schlinkert'};
    engines.setEngine('tmpl', lodash);

    var lodash = engines.getEngine('tmpl');
    var fn = lodash.compile('<%= name %>');
    fn(ctx, function(err, res) {
      if (err) return cb(err);
      assert(res === 'Jon Schlinkert');
      cb();
    });
  });

  it('should allow the returned function to be async and not require a context:', function(cb) {
    var lodash = require('engine-lodash');
    engines.setEngine('tmpl', lodash);

    var lodash = engines.getEngine('tmpl');
    var fn = lodash.compile('No context required');
    fn(function(err, res) {
      if (err) return cb(err);
      assert(res === 'No context required');
      cb();
    });
  });

  it('should handle errors in sync render:', function(cb) {
    var lodash = require('engine-lodash');
    var ctx = {};
    engines.setEngine('tmpl', lodash);

    var lodash = engines.getEngine('tmpl');
    var fn = lodash.compile('<%= name %>');
    try {
      var res = fn(ctx);
      cb(new Error('expected an error'));
    } catch (err) {
      assert.equal(err.message, 'name is not defined');
      cb();
    }
  });

  it('should handle errors in async callback:', function(cb) {
    var lodash = require('engine-lodash');
    var ctx = {};
    engines.setEngine('tmpl', lodash);

    var lodash = engines.getEngine('tmpl');
    var fn = lodash.compile('<%= name %>');
    fn(ctx, function(err, res) {
      if (!err) return cb(new Error('expected an error'));
      assert(err.message === 'name is not defined');
      cb();
    });
  });
});
<|endoftext|>


<commit_before>describe("Element methods", function () {
    var s;
    beforeEach(function () {
        s = Savage(100, 100);
    });
    afterEach(function () {
        s.remove();
    });

    /*
    DOM manipulation:
        - add/append
        - prepend
        - after
        - insertAfter
        - before
        - insertBefore
        - clone
        - parent
        - remove
    */
    it("Element.add (for Element)", function () {
        var rect = s.rect(10, 20, 30, 40);
        s.add(rect);
        expect(rect.node.parentNode).to.be(s.node);
        expect(s.node.lastChild).to.be(rect.node);
    });
    it("Element.add (for Set)", function () {
        var rect1 = s.rect(10, 20, 30, 40);
        var rect2 = s.rect(10, 20, 30, 40);
        var set = Savage.set(rect1, rect2);
        s.add(set);
        expect(rect1.node.parentNode).to.be(s.node);
        expect(rect2.node.parentNode).to.be(s.node);
    });
    it("Element.append (for Element)", function () {
        var rect = s.rect(10, 20, 30, 40);
        s.append(rect);
        expect(rect.node.parentNode).to.be(s.node);
        expect(s.node.lastChild).to.be(rect.node);
    });
    it("Element.append (for Set)", function () {
        var rect1 = s.rect(10, 20, 30, 40);
        var rect2 = s.rect(10, 20, 30, 40);
        var set = Savage.set(rect1, rect2);
        s.append(set);
        expect(rect1.node.parentNode).to.be(s.node);
        expect(rect2.node.parentNode).to.be(s.node);
    });
    it("Element.after", function() {
        var circle = s.circle(10, 20, 30);
        var rect = s.rect(10, 20, 30, 40);
        circle.after(rect);
        expect(circle.node.nextSibling).to.be(rect.node);
    });
    it("Element.prepend", function() {
        var rect = s.rect(10, 20, 30, 40);
        var circle = s.circle(10, 20, 30);
        var group = s.group();
        s.append(group);
        group.prepend(rect);
        expect(group.node.firstChild).to.be(rect.node);
        group.prepend(circle);
        expect(group.node.firstChild).to.be(circle.node);
    });
    it("Element.insertAfter", function() {
        var circle = s.circle(10, 20, 30);
        var rect = s.rect(10, 20, 30, 40);
        rect.insertAfter(circle);
        expect(circle.node.nextSibling).to.be(rect.node);
    });
    it("Element.before", function() {
        var circle = s.circle(10, 20, 30);
        var rect = s.rect(10, 20, 30, 40);
        circle.before(rect);
        expect(circle.node.previousSibling).to.be(rect.node);
    });
    it("Element.insertBefore", function() {
        var circle = s.circle(10, 20, 30);
        var rect = s.rect(10, 20, 30, 40);
        rect.insertBefore(circle);
        expect(circle.node.previousSibling).to.be(rect.node);
    });
    it("Element.clone", function() {
        var circle = s.circle(10, 20, 30);
        s.append(circle);
        var clone = circle.clone();
        expect(circle.node).not.to.be(clone.node);
        expect(circle.node.getAttribute("cx")).to.be("10");
        expect(circle.node.getAttribute("cy")).to.be("20");
        expect(circle.node.getAttribute("r")).to.be("30");
    });
    it("Element.parent", function() {
        var circle = s.circle(10, 20, 30);
        s.append(circle);
        var parent = circle.parent();
        expect(parent.node).to.be(s.node);
    });
    it("Element.remove", function() {
        var rect = s.rect(10, 20, 30, 40);
        expect(rect.node.parentNode).to.be(s.node);
        rect.remove();
        expect(rect.node.parentNode).to.be(null);
    });

    /*
    Set/get data:
        Element.attr()
        Element.data()
        Element.removeData()
        Element.asPX()
        Element.getBBox()

        // TODO:
        Element.getPointAtLength()
        Element.getSubpath()
        Element.getTotalLength()
    */

    it("Element.attr - get", function() {
        var circle = s.circle(10, 20, 30);
        var r = circle.attr("r");
        expect(r).to.be("30");
    });
    it("Element.attr - set string", function() {
        var circle = s.circle(10, 20, 30);
        circle.attr("r", 40);
        var r = circle.node.getAttribute("r");
        expect(r).to.be("40");
    });
    it("Element.attr - set object", function() {
        var circle = s.circle(10, 20, 30);
        circle.attr({
            cx: 1,
            cy: 2,
            r: 3
        });
        var cx = circle.node.getAttribute("cx");
        var cy = circle.node.getAttribute("cy");
        var r = circle.node.getAttribute("r");
        expect(cx).to.be("1");
        expect(cy).to.be("2");
        expect(r).to.be("3");
    });
    it("Element.data", function() {
        var circle = s.circle(10, 20, 30);
        circle.data("foo", "bar");
        var data = circle.data("foo");
        expect(data).to.be("bar");
        var myObject = {};
        circle.data("my-object", myObject);
        data = circle.data("my-object");
        expect(data).to.be(myObject);
    });
    it("Element.removeData", function() {
        var circle = s.circle(10, 20, 30);
        var myObject = {};
        circle.data("my-object", myObject);
        var data = circle.data("my-object");
        expect(data).to.be(myObject);
        circle.removeData("my-object");
        var data = circle.data("my-object");
        expect(data).to.be(null);
    });
    it("Element.asPX - from %", function() {
        s.attr({width: "200"}); // NOTE: This is only working with "200" as string, fails as number
        var rect = s.rect(0, 0, '100%', 10);
        var widthAsPx = rect.asPX("width");
        expect(widthAsPx).to.be(200);
    });
    it("Element.asPX - from em", function() {
        var rect = s.rect(0, 0, 10, '10em');
        var heightAsPx = rect.asPX("height");
        expect(heightAsPx).to.be(160); // assumes 1em = 16px, is this safe?
    });
    it("Element.getBBox", function() {
        var rect = s.rect(10, 20, 30, 40);
        var bbox = rect.getBBox();

        expect(bbox).to.eql({
            x: 10,
            y: 20,
            w: 30,
            width: 30,
            h: 40,
            height: 40,

            x2: 25,
            cy: 40,
            x2: (100 - 40),
            y2: (100 - 60)
        });
    });
});
<commit_msg>remove invalid test<commit_after>describe("Element methods", function () {
    var s;
    beforeEach(function () {
        s = Savage(100, 100);
    });
    afterEach(function () {
        s.remove();
    });

    /*
    DOM manipulation:
        - add/append
        - prepend
        - after
        - insertAfter
        - before
        - insertBefore
        - clone
        - parent
        - remove
    */
    it("Element.add (for Element)", function () {
        var rect = s.rect(10, 20, 30, 40);
        s.add(rect);
        expect(rect.node.parentNode).to.be(s.node);
        expect(s.node.lastChild).to.be(rect.node);
    });
    it("Element.add (for Set)", function () {
        var rect1 = s.rect(10, 20, 30, 40);
        var rect2 = s.rect(10, 20, 30, 40);
        var set = Savage.set(rect1, rect2);
        s.add(set);
        expect(rect1.node.parentNode).to.be(s.node);
        expect(rect2.node.parentNode).to.be(s.node);
    });
    it("Element.append (for Element)", function () {
        var rect = s.rect(10, 20, 30, 40);
        s.append(rect);
        expect(rect.node.parentNode).to.be(s.node);
        expect(s.node.lastChild).to.be(rect.node);
    });
    it("Element.append (for Set)", function () {
        var rect1 = s.rect(10, 20, 30, 40);
        var rect2 = s.rect(10, 20, 30, 40);
        var set = Savage.set(rect1, rect2);
        s.append(set);
        expect(rect1.node.parentNode).to.be(s.node);
        expect(rect2.node.parentNode).to.be(s.node);
    });
    it("Element.after", function() {
        var circle = s.circle(10, 20, 30);
        var rect = s.rect(10, 20, 30, 40);
        circle.after(rect);
        expect(circle.node.nextSibling).to.be(rect.node);
    });
    it("Element.prepend", function() {
        var rect = s.rect(10, 20, 30, 40);
        var circle = s.circle(10, 20, 30);
        var group = s.group();
        s.append(group);
        group.prepend(rect);
        expect(group.node.firstChild).to.be(rect.node);
        group.prepend(circle);
        expect(group.node.firstChild).to.be(circle.node);
    });
    it("Element.insertAfter", function() {
        var circle = s.circle(10, 20, 30);
        var rect = s.rect(10, 20, 30, 40);
        rect.insertAfter(circle);
        expect(circle.node.nextSibling).to.be(rect.node);
    });
    it("Element.before", function() {
        var circle = s.circle(10, 20, 30);
        var rect = s.rect(10, 20, 30, 40);
        circle.before(rect);
        expect(circle.node.previousSibling).to.be(rect.node);
    });
    it("Element.insertBefore", function() {
        var circle = s.circle(10, 20, 30);
        var rect = s.rect(10, 20, 30, 40);
        rect.insertBefore(circle);
        expect(circle.node.previousSibling).to.be(rect.node);
    });
    it("Element.clone", function() {
        var circle = s.circle(10, 20, 30);
        s.append(circle);
        var clone = circle.clone();
        expect(circle.node).not.to.be(clone.node);
        expect(circle.node.getAttribute("cx")).to.be("10");
        expect(circle.node.getAttribute("cy")).to.be("20");
        expect(circle.node.getAttribute("r")).to.be("30");
    });
    it("Element.parent", function() {
        var circle = s.circle(10, 20, 30);
        s.append(circle);
        var parent = circle.parent();
        expect(parent.node).to.be(s.node);
    });
    it("Element.remove", function() {
        var rect = s.rect(10, 20, 30, 40);
        expect(rect.node.parentNode).to.be(s.node);
        rect.remove();
        expect(rect.node.parentNode).to.be(null);
    });

    /*
    Set/get data:
        Element.attr()
        Element.data()
        Element.removeData()
        Element.asPX()
        Element.getBBox()

        // TODO:
        Element.getPointAtLength()
        Element.getSubpath()
        Element.getTotalLength()
    */

    it("Element.attr - get", function() {
        var circle = s.circle(10, 20, 30);
        var r = circle.attr("r");
        expect(r).to.be("30");
    });
    it("Element.attr - set", function() {
        var circle = s.circle(10, 20, 30);
        circle.attr({
            cx: 1,
            cy: 2,
            r: 3
        });
        var cx = circle.node.getAttribute("cx");
        var cy = circle.node.getAttribute("cy");
        var r = circle.node.getAttribute("r");
        expect(cx).to.be("1");
        expect(cy).to.be("2");
        expect(r).to.be("3");
    });
    it("Element.data", function() {
        var circle = s.circle(10, 20, 30);
        circle.data("foo", "bar");
        var data = circle.data("foo");
        expect(data).to.be("bar");
        var myObject = {};
        circle.data("my-object", myObject);
        data = circle.data("my-object");
        expect(data).to.be(myObject);
    });
    it("Element.removeData", function() {
        var circle = s.circle(10, 20, 30);
        var myObject = {};
        circle.data("my-object", myObject);
        var data = circle.data("my-object");
        expect(data).to.be(myObject);
        circle.removeData("my-object");
        var data = circle.data("my-object");
        expect(data).to.be(null);
    });
    it("Element.asPX - from %", function() {
        s.attr({width: "200"}); // NOTE: This is only working with "200" as string, fails as number
        var rect = s.rect(0, 0, '100%', 10);
        var widthAsPx = rect.asPX("width");
        expect(widthAsPx).to.be(200);
    });
    it("Element.asPX - from em", function() {
        var rect = s.rect(0, 0, 10, '10em');
        var heightAsPx = rect.asPX("height");
        expect(heightAsPx).to.be(160); // assumes 1em = 16px, is this safe?
    });
    it("Element.getBBox", function() {
        var rect = s.rect(10, 20, 30, 40);
        var bbox = rect.getBBox();

        expect(bbox).to.eql({
            x: 10,
            y: 20,
            w: 30,
            width: 30,
            h: 40,
            height: 40,

            x2: 25,
            cy: 40,
            x2: (100 - 40),
            y2: (100 - 60)
        });
    });
});
<|endoftext|>


<commit_before>/**
* Copyright 2012-2016, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var scatterPlot = require('../scatter/plot');

module.exports = function plot(ternary, data) {
    // mimic cartesian plotinfo
    var plotinfo = {
        x: function() { return ternary.xaxis; },
        y: function() { return ternary.yaxis; },
        plot: ternary.plotContainer
    };

    var calcdata = new Array(data.length),
        fullCalcdata = ternary.graphDiv.calcdata;

    for(var i = 0; i < fullCalcdata.length; i++) {
        var j = data.indexOf(fullCalcdata[i][0].trace);

        if(j === -1) continue;

        calcdata[j] = fullCalcdata[i];

        // while we're here and have references to both the Ternary object
        // and fullData, connect the two (for use by hover)
        data[j]._ternary = ternary;
    }

    scatterPlot(ternary.graphDiv, plotinfo, calcdata);
};
<commit_msg>remove nodes inside scatterlayer in scatterternary plot step<commit_after>/**
* Copyright 2012-2016, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var scatterPlot = require('../scatter/plot');

module.exports = function plot(ternary, data) {
    var plotContainer = ternary.plotContainer;

    // remove all nodes inside the scatter layer
    plotContainer.select('.scatterlayer').selectAll('*').remove();

    // mimic cartesian plotinfo
    var plotinfo = {
        x: function() { return ternary.xaxis; },
        y: function() { return ternary.yaxis; },
        plot: plotContainer
    };

    var calcdata = new Array(data.length),
        fullCalcdata = ternary.graphDiv.calcdata;

    for(var i = 0; i < fullCalcdata.length; i++) {
        var j = data.indexOf(fullCalcdata[i][0].trace);

        if(j === -1) continue;

        calcdata[j] = fullCalcdata[i];

        // while we're here and have references to both the Ternary object
        // and fullData, connect the two (for use by hover)
        data[j]._ternary = ternary;
    }

    scatterPlot(ternary.graphDiv, plotinfo, calcdata);
};
<|endoftext|>


<commit_before>var FacebookStrategy = require('passport-facebook').Strategy,
	LocalStrategy =   require('passport-local').Strategy;

var bcrypt =require('bcrypt');

var ddb = require('./dynamo_database').ddb;

exports.facebookStrategy = function (facebookAppId, facebookAppSecret) {
	return new FacebookStrategy({
			clientID: facebookAppId,
			clientSecret: facebookAppSecret,
			callbackURL: '/v1/auth/facebook/callback'
		},
		function(accessToken, refreshToken, profile, done) {
			console.log(profile);
			if(profile.emails == undefined)
							return done({error:"Profile não autorizou o email."});

			ddb.getItem('accounts', profile.emails[0].value, null, {}, function (err, user) {

				if(err){
					//console.log("Deu erro");
					return done(err);
				}else
				{
					if(!user)
					{
						user = {
							nome: profile.displayName,
							username: profile.emails[0].value,
							provider_id: profile.id,
							provider: 'facebook',
							dataNascimento: profile._json.birthday,
							sexo: profile._json.gender,
							exportFace: 0
						};

						if(profile.location != undefined)
							user.cidade = profile.location.id;

						if(profile._json.education != undefined){
							var max = 0;
							profile._json.education.forEach(function(item){
								var val;
								switch(item.type){
									case "High School": val = 1; break;
									case "College": val = 2; break;
									case "Graduate School": val = 3; break;
									default: val = 0;
								}
								if(val>max) max = val;
							});
							user.escolaridade = max;
						}

						ddb.putItem('accounts', user, {}, function (err) {
							if (!err) {
								//console.log("Criei usuário e to retornando ele.");
								return done(err, user);
							} else {
								//console.log("Erro ao criar usuário usuário.");
								console.log(err);
								return done(err);
							}
						});
					}
					else{
						if(user.exportFace == undefined){
							var newUser = {
								dataNascimento: {value: profile._json.birthday},
								sexo: {value: profile._json.gender},
								exportFace: {value: 0}
							};

							if(profile.location != undefined)
								newUser.cidade = {value: profile.location.id};

							if(profile._json.education != undefined){
								var max = 0;
								profile._json.education.forEach(function(item){
									var val;
									switch(item.type){
										case "High School": val = 1; break;
										case "College": val = 2; break;
										case "Graduate School": val = 3; break;
										default: val = 0;
									}
									if(val>max) max = val;
								});
								newUser.escolaridade = {value: max};
							}
						}
						return done(err, user);
					}
				}
			});
		}
	);
};
<commit_msg>Alterando o lugar onde atualiza os dados<commit_after>var FacebookStrategy = require('passport-facebook').Strategy,
	LocalStrategy =   require('passport-local').Strategy;

var bcrypt =require('bcrypt');

var ddb = require('./dynamo_database').ddb;

exports.facebookStrategy = function (facebookAppId, facebookAppSecret) {
	return new FacebookStrategy({
			clientID: facebookAppId,
			clientSecret: facebookAppSecret,
			callbackURL: '/v1/auth/facebook/callback'
		},
		function(accessToken, refreshToken, profile, done) {
			console.log(profile);
			if(profile.emails == undefined)
							return done({error:"Profile não autorizou o email."});

			ddb.getItem('accounts', profile.emails[0].value, null, {}, function (err, user) {

				if(err){
					//console.log("Deu erro");
					return done(err);
				}else
				{
					if(!user)
					{
						user = {
							nome: profile.displayName,
							username: profile.emails[0].value,
							provider_id: profile.id,
							provider: 'facebook',
							dataNascimento: profile._json.birthday,
							sexo: profile._json.gender,
							exportFace: 0
						};

						if(profile.location != undefined)
							user.cidade = profile.location.id;

						if(profile._json.education != undefined){
							var max = 0;
							profile._json.education.forEach(function(item){
								var val;
								switch(item.type){
									case "High School": val = 1; break;
									case "College": val = 2; break;
									case "Graduate School": val = 3; break;
									default: val = 0;
								}
								if(val>max) max = val;
							});
							user.escolaridade = max;
						}

						ddb.putItem('accounts', user, {}, function (err) {
							if (!err) {
								//console.log("Criei usuário e to retornando ele.");
								return done(err, user);
							} else {
								//console.log("Erro ao criar usuário usuário.");
								console.log(err);
								return done(err);
							}
						});
					}
					else{
						if(user.exportFace == undefined){
							var newUser = {
								dataNascimento: {value: profile._json.birthday},
								sexo: {value: profile._json.gender},
								exportFace: {value: 0}
							};

							if(profile.location != undefined)
								newUser.cidade = {value: profile.location.id};

							if(profile._json.education != undefined){
								var max = 0;
								profile._json.education.forEach(function(item){
									var val;
									switch(item.type){
										case "High School": val = 1; break;
										case "College": val = 2; break;
										case "Graduate School": val = 3; break;
										default: val = 0;
									}
									if(val>max) max = val;
								});
								newUser.escolaridade = {value: max};
							}

							ddb.updateItem('accounts', user.username, null, newUser, function (err, updatedUser) {
								if (!err) {
									console.log("Updated User");
								} else {
									console.log(err);
								}
							});
						}
						return done(err, user);
					}
				}
			});
		}
	);
};
<|endoftext|>


<commit_before>/*
 * Scripts to support charts on wiki article history.
 */

(function ($) {
    function init() {
        $('#show-chart').unbind('click');
        $('#show-chart').html(gettext('Loading...'));
        $('#show-chart').css('color', '#333333').css('cursor', 'auto').css('text-decoration', 'none');
        initChart();
    }

    function initChart() {
        var data, dateToRevID;
        $.ajax({
            type: "GET",
            url: $('#helpful-chart').data('url'),
            data: null,
            success: function (response) {
                data = response['data'];
                dateToRevID = response['date_to_rev_id'];
                dateTooltip = response['date_tooltip'];
                if(data.length > 0) {
                    $('#helpful-chart').show('fast', function () {
                        stockChart(data, dateToRevID, dateTooltip);
                        $('#helpful-chart').append('
' + gettext('Query took: ') + response['query'] + gettext(' seconds') + '
')
                    });
                }
                else {
                    $('#show-chart').html(gettext('No votes data'));
                    $('#show-chart').unbind('click');
                }
            },
            error: function () {
                $('#show-chart').html(gettext('Error loading chart'));
                $('#show-chart').unbind('click');
            }
        });
    }

    /*
     * stockChart()
     * Creates the StockChart object with the defined options.
     * Requires data and dateToRevID to be passed in, populated via AJAX.
     * The graph is drawn upon creation of the StockChart object.
     * Returns: nothing
     */
    function stockChart(data, dateToRevID, dateTooltip) {
        Highcharts.setOptions({
            lang: {
                months: [gettext('January'), gettext('February'), gettext('March'), gettext('April'), gettext('May'), gettext('June'), gettext('July'), gettext('August'), gettext('September'), gettext('October'), gettext('November'), gettext('December')],
                weekdays: [gettext('Sunday'), gettext('Monday'), gettext('Tuesday'), gettext('Wednesday'), gettext('Thursday'), gettext('Friday'), gettext('Saturday')],
                loading: gettext('Loading...'),
                rangeSelectorFrom: gettext('From'),
                rangeSelectorTo: gettext('To'),
                rangeSelectorZoom: gettext('Zoom'),
                resetZoom: gettext('Reset zoom'),
                resetZoomTitle: gettext('Reset zoom level 1:1')
            }
        });

        chart = new Highcharts.StockChart({
            chart: {
                renderTo: 'helpful-chart',
                spacingBottom: 40,
            },
            legend: {
                enabled: true,
                y: 40,
            },
            rangeSelector: {
                selected: 2,
                buttons: [{
                    type: 'month',
                    count: 1,
                    /* L10n: short for "1 month" */
                    text: gettext('1m')
                }, {
                    type: 'month',
                    count: 3,
                    /* L10n: short for "3 months" */
                    text: gettext('3m')
                }, {
                    type: 'month',
                    count: 6,
                    /* L10n: short for "6 months" */
                    text: gettext('6m')
                }, {
                    type: 'ytd',
                    /* L10n: short for "Year To Date" */
                    text: gettext('YTD')
                }, {
                    type: 'year',
                    count: 1,
                    /* L10n: short for "1 year" */
                    text: gettext('1y')
                }, {
                    type: 'all',
                    text: gettext('All')
                }],
                buttonTheme: {
                    width: null
                },
                inputStyle: {
                    fontSize: '10px'
                }
            },
            title: {
                text: gettext('Helpfulness Votes')
            },
            xAxis: {
                type: 'datetime',
                maxZoom: 14 * 24 * 3600000,  // fourteen days
                title: {
                    text: null
                }
            },
            yAxis: {
                title: {
                    text: gettext('Votes')
                }
            },
            tooltip: {
                style: {
                    width: 200
                },
                formatter: function(){
                    var x = this.x,
                        s;

                    if('key' in this) {
                        // revision/important date flag
                        s = ['' +
                            Highcharts.dateFormat('%b %e, %Y', x) +
                            '',
                            '' + this.point.text + '']
                    }
                    else {
                        // data point element
                        s = ['' +
                            Highcharts.dateFormat('%A, %b %e, %Y', x) +
                            '',
                            'Yes: ' + dateTooltip[x].yes + '',
                            'No: ' + dateTooltip[x].no + '',
                            'Percent: ' + dateTooltip[x].percent + '%'
                            ]
                    }
                    return s.join('
');
                },
                shared: true
            },
            credits: {
                enabled: false
            },
            plotOptions: {
                series: {
                    cursor: 'pointer',
                    point: {
                        events: {
                            mouseOver: function () {
                                $('#rev-list-' + dateToRevID[this.x]).addClass('graph-hover');
                            },
                            mouseOut: function () {
                                $('#rev-list-' + dateToRevID[this.x]).removeClass('graph-hover');
                            }
                        }
                    },
                    marker: {
                        lineWidth: 1
                    },
                    stickyTracking: true,
                }
            },
            series: data
        }, function () {
            $('#show-chart').hide();  // loading complete callback
        });
        chart.series[0].hide();
        chart.series[1].hide();
    }
    $('#show-chart').click(init);
}(jQuery));
<commit_msg>[Bug 681637] Localize Helpfulness Chart Hover Labels<commit_after>/*
 * Scripts to support charts on wiki article history.
 */

(function ($) {
    function init() {
        $('#show-chart').unbind('click');
        $('#show-chart').html(gettext('Loading...'));
        $('#show-chart').css('color', '#333333').css('cursor', 'auto').css('text-decoration', 'none');
        initChart();
    }

    function initChart() {
        var data, dateToRevID;
        $.ajax({
            type: "GET",
            url: $('#helpful-chart').data('url'),
            data: null,
            success: function (response) {
                data = response['data'];
                dateToRevID = response['date_to_rev_id'];
                dateTooltip = response['date_tooltip'];
                if(data.length > 0) {
                    $('#helpful-chart').show('fast', function () {
                        stockChart(data, dateToRevID, dateTooltip);
                        $('#helpful-chart').append('
' + gettext('Query took: ') + response['query'] + gettext(' seconds') + '
')
                    });
                }
                else {
                    $('#show-chart').html(gettext('No votes data'));
                    $('#show-chart').unbind('click');
                }
            },
            error: function () {
                $('#show-chart').html(gettext('Error loading chart'));
                $('#show-chart').unbind('click');
            }
        });
    }

    /*
     * stockChart()
     * Creates the StockChart object with the defined options.
     * Requires data and dateToRevID to be passed in, populated via AJAX.
     * The graph is drawn upon creation of the StockChart object.
     * Returns: nothing
     */
    function stockChart(data, dateToRevID, dateTooltip) {
        Highcharts.setOptions({
            lang: {
                months: [gettext('January'), gettext('February'), gettext('March'), gettext('April'), gettext('May'), gettext('June'), gettext('July'), gettext('August'), gettext('September'), gettext('October'), gettext('November'), gettext('December')],
                weekdays: [gettext('Sunday'), gettext('Monday'), gettext('Tuesday'), gettext('Wednesday'), gettext('Thursday'), gettext('Friday'), gettext('Saturday')],
                loading: gettext('Loading...'),
                rangeSelectorFrom: gettext('From'),
                rangeSelectorTo: gettext('To'),
                rangeSelectorZoom: gettext('Zoom'),
                resetZoom: gettext('Reset zoom'),
                resetZoomTitle: gettext('Reset zoom level 1:1')
            }
        });

        chart = new Highcharts.StockChart({
            chart: {
                renderTo: 'helpful-chart',
                spacingBottom: 40,
            },
            legend: {
                enabled: true,
                y: 40,
            },
            rangeSelector: {
                selected: 2,
                buttons: [{
                    type: 'month',
                    count: 1,
                    /* L10n: short for "1 month" */
                    text: gettext('1m')
                }, {
                    type: 'month',
                    count: 3,
                    /* L10n: short for "3 months" */
                    text: gettext('3m')
                }, {
                    type: 'month',
                    count: 6,
                    /* L10n: short for "6 months" */
                    text: gettext('6m')
                }, {
                    type: 'ytd',
                    /* L10n: short for "Year To Date" */
                    text: gettext('YTD')
                }, {
                    type: 'year',
                    count: 1,
                    /* L10n: short for "1 year" */
                    text: gettext('1y')
                }, {
                    type: 'all',
                    text: gettext('All')
                }],
                buttonTheme: {
                    width: null
                },
                inputStyle: {
                    fontSize: '10px'
                }
            },
            title: {
                text: gettext('Helpfulness Votes')
            },
            xAxis: {
                type: 'datetime',
                maxZoom: 14 * 24 * 3600000,  // fourteen days
                title: {
                    text: null
                }
            },
            yAxis: {
                title: {
                    text: gettext('Votes')
                }
            },
            tooltip: {
                style: {
                    width: 200
                },
                formatter: function(){
                    var x = this.x,
                        s;

                    if('key' in this) {
                        // revision/important date flag
                        s = ['' +
                            Highcharts.dateFormat('%b %e, %Y', x) +
                            '',
                            '' + this.point.text + '']
                    }
                    else {
                        // data point element
                        s = ['' +
                            Highcharts.dateFormat('%A, %b %e, %Y', x) +
                            '',
                            gettext('Yes') + ': ' + dateTooltip[x].yes + '',
                            gettext('No') + ': ' + dateTooltip[x].no + '',
                            gettext('Percent') + ': ' + dateTooltip[x].percent + '%'
                            ]
                    }
                    return s.join('
');
                },
                shared: true
            },
            credits: {
                enabled: false
            },
            plotOptions: {
                series: {
                    cursor: 'pointer',
                    point: {
                        events: {
                            mouseOver: function () {
                                $('#rev-list-' + dateToRevID[this.x]).addClass('graph-hover');
                            },
                            mouseOut: function () {
                                $('#rev-list-' + dateToRevID[this.x]).removeClass('graph-hover');
                            }
                        }
                    },
                    marker: {
                        lineWidth: 1
                    },
                    stickyTracking: true,
                }
            },
            series: data
        }, function () {
            $('#show-chart').hide();  // loading complete callback
        });
        chart.series[0].hide();
        chart.series[1].hide();
    }
    $('#show-chart').click(init);
}(jQuery));
<|endoftext|>


<commit_before>// is the captured node exempt from fragment loading?
function fragmentFilter(el) {
    var href = el.getAttribute('href') || el.getAttribute('action'),
        $el = $(el);
    return !href || href.substr(0,4) == 'http' ||
            href.substr(0,7) === 'mailto:' ||
            href.substr(0,11) === 'javascript:' ||
            href.substr(0,1) === '#' ||
            href.indexOf('/developers/') !== -1 ||
            href.indexOf('/ecosystem/') !== -1 ||
            href.indexOf('/statistics/') !== -1 ||
            href.indexOf('?modified=') !== -1 ||
            el.getAttribute('target') === '_blank' ||
            $el.hasClass('post') || $el.hasClass('sync');
}

(function(container, nodeFilter) {
    var threshold = 250,
        timeout = false,
        fragmentCache = {},
        cacheHash = '',
        reloadOnNext = false;

    if (z.capabilities.replaceState) {
        var $loading = $('
', {'class': 'loading-fragment overlay',
                                   'html': ''})
                        .prependTo($('body'));

        // Hijack <form> submission
        z.body.on('submit', 'form', function(e) {
            if (reloadOnNext) return;
            var form = $(this);
            var method = form.attr('method').toLowerCase();
            if (method === 'get') {
                e.preventDefault();
                hijackGET(form);
            } else if (method === 'post') {
                e.preventDefault();
                hijackPOST(form);
            }
            // Not GET or POST? Not interested.
        });

        z.page.ajaxSuccess(function(e, xhr, response) {
            // Do we have an instruction to clear a part of the fragment cache?
            var bust_flag = xhr.getResponseHeader('x-frag-bust');
            if (bust_flag) {

                // The `fcbust` header is a JSON-encoded list of strings.
                var decoded_prefixes = JSON.parse(bust_flag);

                for (var i = 0; i < decoded_prefixes.length; i++) {
                    var clear_prefix = decoded_prefixes[i];

                    // Delete all the matching cache entries.
                    _.each(fragmentCache, function(_, key) {
                        // If the prefix doesn't match the cache entry, skip it.
                        if (clear_prefix.length > key.length ||
                            key.substr(0, clear_prefix.length) !== clear_prefix) {
                            return;
                        }

                        delete fragmentCache[key];
                    });
                };
                console.log('fragment cache busted');
            }
        });

        function handleFragmentResponse(xhr, href) {
            var bust_flag = xhr.getResponseHeader('x-frag-bust');
            if (bust_flag && _.contains(JSON.parse(bust_flag), '/')) {
                synchronousLoad(xhr.getResponseHeader('x-uri') || href);
            }
        }

        function hijackGET(form) {
            var action = form.attr('action');
            //strip existing queryparams off the action.
            var link = document.createElement('a');
            link.href = action;
            var path = link.pathname + '?' + form.serialize();
            form.trigger('loadfragment', path);
        }

        function hijackPOST(form) {
            console.log('hijacking POST');
            startLoading();
            var action = form.attr('action') || window.location.href;
            var data = form.serialize();
            if (data) {
                data += '&_hijacked=true';
            } else {
                data = '_hijacked=true';
            }
            var href = action || window.location;
            $.ajax({
                type: 'POST',
                url: href,
                data: data
            }).done(function(response, textStatus, xhr) {
                // load up the response fragment!
                handleFragmentResponse(xhr, href);
                updateContent(response);
            }).fail(function(response) {
                form.trigger('notify', {
                    title: gettext('Error'),
                    msg: gettext('A server error has occurred.')
                });
                endLoading();
            });
        }

        // capture clicks in our target environment
        z.body.on('click', 'a', function(e) {
            if (reloadOnNext) return;
            var href = this.getAttribute('href');
            if (e.metaKey || e.ctrlKey || e.button !== 0) return;
            if (nodeFilter(this)) {
                return;
            }
            e.preventDefault();
            navigate({path: href});
        });

        // preserve scrollTop like a real boy
        function markScrollTop() {
            var path = window.location.pathname + window.location.search + window.location.hash;
            var state = {path: path, scrollTop: $(document).scrollTop()};
            console.log(format('setting the scrolltop for {0}', path));
            history.replaceState(state, false, path);
        }

        // start the loading indicator
        function startLoading() {
            container.trigger('startfragmentload');
            timeout = setTimeout(function() {
                $loading.addClass('show');
            }, threshold);
            loadTimer = new Date().getTime();
        }

        // end the loading timer and report timing
        function endLoading() {
            clearTimeout(timeout);
            _.delay(function() {
                $loading.removeClass('show');
            }, 400);
            stick.custom({
                'window.performance.timing.fragment.loaded':
                    (new Date()).getTime() - loadTimer
            });
        }

        // handle link clicking and state popping.
        function navigate(state, popped) {
            var href = state.path;
            startLoading();
            markScrollTop();
            getFragment(href).done(function(content) {
                updateContent(content, href, popped, {scrollTop: state.scrollTop});
            }).fail(function() {
                console.log('fetch error!');
                $(window).trigger('notify', {
                    title: gettext('Error'),
                    msg: gettext('There was an error loading the requested page.')});
            }).always(endLoading);
        }

        function getFragment(href) {
            var $def = $.Deferred();
            //caching!
            if (fragmentCache[href]) {
                console.log(format('cached {0}', href));
                $def.resolve(fragmentCache[href]);
            } else {
                console.log(format('fetching {0}', href));
                fetchFragment(href).done(function(d, textStatus, xhr) {
                    // Bail if this is not HTML.
                    if (xhr.getResponseHeader('content-type').indexOf('text/html') < 0) {
                        $def.reject();
                        return;
                    }
                    if (d.indexOf('') === -1) {
                        console.log('warning, fragment not properly served!');
                        return;
                    }
                    console.log('header is ' + xhr.getResponseHeader('date'));
                    console.log('caching fragment');
                    handleFragmentResponse(xhr, href);
                    $def.resolve(d);
                }).fail(function(e) {
                    $def.reject();
                });
            }
            return $def.promise();
        }

        function fetchFragment(href) {
            // Chrome doesn't obey the Vary header, so we need to keep the fragments
            // from getting cached with the page itself. Remove once Chrome bug #94369
            // has been resolved as fixed.
            var fetch_href = href;
            if (navigator.userAgent.indexOf('Chrome') > -1) {
                var chr_flag = '';

                // If we have a locale/region, we want to include those in the request
                // so Chrome does a hard reload of those pages when they change.
                var lang = $.cookie('lang');
                if (lang) {
                    chr_flag += lang;
                }
                var region = $.cookie('region');
                if (region) {
                    chr_flag += region;
                }

                if(chr_flag) {
                    chr_flag = '=' + encodeURIComponent(chr_flag);
                }

                fetch_href += (href.indexOf("?") > -1 ? '&' : '?') + 'frag' + chr_flag;
            }

            return $.get(fetch_href);
        }

        function synchronousLoad(href) {
            // TODO(potch): Save the user's navigation stack.
            window.location.href = href;
        }

        // pump content into our page, clean up after ourselves.
        function updateContent(content, href, popped, opts) {
            opts = opts || {};
            endLoading();

            container.html(content);
            var page = container.find('#page');
            if (!page.length) {
                throw "something has gone terribly wrong";
            }

            // scroll to the right spot.
            $('html, body').scrollTop(opts.scrollTop || 0);

            // Reset our lovelies.
            _.extend(z, {
                body: $(document.body),
                page: $('#container'),
                context: $('#page').data('context')
            });

            if (z.context.type === 'offline') {
                console.log('oh no!');
                return;
            }

            if (!href) {
                href = z.context.uri;
                console.log('whats the 411' + href);
            }

            if (z.context.cache === 'cache') {
                console.log('caching fragment');
                fragmentCache[href] = content;
            }

            // If we have new media, load the next fragment synchronously.
            if (z.context.hash != cacheHash) {
                reloadOnNext = true;
                container.trigger('fragmentpendingsync');
                console.log('performing synchronous load next navigation');
            }

            // Clear jQuery's data attribute cache for body.
            jQuery.cache[document.body[jQuery.expando]].data = null;

            // We so sneaky.
            document.title = z.context.title;

            var type = z.context.type;

            var newState = {
                path: href,
                type: type,
                title: z.context.title,
                scrollTop: $(document).scrollTop()
            };
            if (!popped) history.pushState(newState, false, href);

            container.trigger('fragmentloaded', [href, popped, newState]);
        }

        $(window).on('popstate', function(e) {
            var state = e.originalEvent.state;
            if (state) {
                navigate(state, true);
            }
        }).on('loadfragment', function(e, href) {
            if (href) navigate({path: href});
        }).on('refreshfragment', function(e) {
            var path = window.location.pathname + window.location.search + window.location.hash;
            if (fragmentCache[path]) {
                delete fragmentCache[path];
            }
            navigate({path: path});
        });

        $(window).on('updatecache', function() {
            console.log('event');
            updateCache();
        });

        function updateCache() {
            console.log('caching fragment');
            fragmentCache[window.location.pathname] = container.html();
        }

        $(function() {
            // Don't forget to update updateContent too, bro.
            var path = window.location.pathname + window.location.search + window.location.hash;
            var type = z.context.type;
            cacheHash = z.context.hash;
            var state = {
                path: path,
                type: type
            };
            history.replaceState(state, false, path);

            if (z.context.cache === 'cache') {
                updateCache();
            }
            container.trigger('fragmentloaded', [path, false, state]);
        });
        console.log("fragments enabled");
    } else {
        console.warn("fragments not enabled!!");
        $(function() {
            container.trigger('fragmentloaded');
        });
    }
})(z.page, fragmentFilter);
<commit_msg>rel=external links should not be fragment loaded (bug 823063)<commit_after>// is the captured node exempt from fragment loading?
function fragmentFilter(el) {
    var href = el.getAttribute('href') || el.getAttribute('action'),
        $el = $(el);
    return !href || href.substr(0,4) == 'http' ||
            href.substr(0,7) === 'mailto:' ||
            href.substr(0,11) === 'javascript:' ||
            href.substr(0,1) === '#' ||
            href.indexOf('/developers/') !== -1 ||
            href.indexOf('/ecosystem/') !== -1 ||
            href.indexOf('/statistics/') !== -1 ||
            href.indexOf('?modified=') !== -1 ||
            el.getAttribute('target') === '_blank' ||
            el.getAttribute('rel') === 'external' ||
            $el.hasClass('post') || $el.hasClass('sync');
}

(function(container, nodeFilter) {
    var threshold = 250,
        timeout = false,
        fragmentCache = {},
        cacheHash = '',
        reloadOnNext = false;

    if (z.capabilities.replaceState) {
        var $loading = $('
', {'class': 'loading-fragment overlay',
                                   'html': ''})
                        .prependTo($('body'));

        // Hijack <form> submission
        z.body.on('submit', 'form', function(e) {
            if (reloadOnNext) return;
            var form = $(this);
            var method = form.attr('method').toLowerCase();
            if (method === 'get') {
                e.preventDefault();
                hijackGET(form);
            } else if (method === 'post') {
                e.preventDefault();
                hijackPOST(form);
            }
            // Not GET or POST? Not interested.
        });

        z.page.ajaxSuccess(function(e, xhr, response) {
            // Do we have an instruction to clear a part of the fragment cache?
            var bust_flag = xhr.getResponseHeader('x-frag-bust');
            if (bust_flag) {

                // The `fcbust` header is a JSON-encoded list of strings.
                var decoded_prefixes = JSON.parse(bust_flag);

                for (var i = 0; i < decoded_prefixes.length; i++) {
                    var clear_prefix = decoded_prefixes[i];

                    // Delete all the matching cache entries.
                    _.each(fragmentCache, function(_, key) {
                        // If the prefix doesn't match the cache entry, skip it.
                        if (clear_prefix.length > key.length ||
                            key.substr(0, clear_prefix.length) !== clear_prefix) {
                            return;
                        }

                        delete fragmentCache[key];
                    });
                };
                console.log('fragment cache busted');
            }
        });

        function handleFragmentResponse(xhr, href) {
            var bust_flag = xhr.getResponseHeader('x-frag-bust');
            if (bust_flag && _.contains(JSON.parse(bust_flag), '/')) {
                synchronousLoad(xhr.getResponseHeader('x-uri') || href);
            }
        }

        function hijackGET(form) {
            var action = form.attr('action');
            //strip existing queryparams off the action.
            var link = document.createElement('a');
            link.href = action;
            var path = link.pathname + '?' + form.serialize();
            form.trigger('loadfragment', path);
        }

        function hijackPOST(form) {
            console.log('hijacking POST');
            startLoading();
            var action = form.attr('action') || window.location.href;
            var data = form.serialize();
            if (data) {
                data += '&_hijacked=true';
            } else {
                data = '_hijacked=true';
            }
            var href = action || window.location;
            $.ajax({
                type: 'POST',
                url: href,
                data: data
            }).done(function(response, textStatus, xhr) {
                // load up the response fragment!
                handleFragmentResponse(xhr, href);
                updateContent(response);
            }).fail(function(response) {
                form.trigger('notify', {
                    title: gettext('Error'),
                    msg: gettext('A server error has occurred.')
                });
                endLoading();
            });
        }

        // capture clicks in our target environment
        z.body.on('click', 'a', function(e) {
            if (reloadOnNext) return;
            var href = this.getAttribute('href');
            if (e.metaKey || e.ctrlKey || e.button !== 0) return;
            if (nodeFilter(this)) {
                return;
            }
            e.preventDefault();
            navigate({path: href});
        });

        // preserve scrollTop like a real boy
        function markScrollTop() {
            var path = window.location.pathname + window.location.search + window.location.hash;
            var state = {path: path, scrollTop: $(document).scrollTop()};
            console.log(format('setting the scrolltop for {0}', path));
            history.replaceState(state, false, path);
        }

        // start the loading indicator
        function startLoading() {
            container.trigger('startfragmentload');
            timeout = setTimeout(function() {
                $loading.addClass('show');
            }, threshold);
            loadTimer = new Date().getTime();
        }

        // end the loading timer and report timing
        function endLoading() {
            clearTimeout(timeout);
            _.delay(function() {
                $loading.removeClass('show');
            }, 400);
            stick.custom({
                'window.performance.timing.fragment.loaded':
                    (new Date()).getTime() - loadTimer
            });
        }

        // handle link clicking and state popping.
        function navigate(state, popped) {
            var href = state.path;
            startLoading();
            markScrollTop();
            getFragment(href).done(function(content) {
                updateContent(content, href, popped, {scrollTop: state.scrollTop});
            }).fail(function() {
                console.log('fetch error!');
                $(window).trigger('notify', {
                    title: gettext('Error'),
                    msg: gettext('There was an error loading the requested page.')});
            }).always(endLoading);
        }

        function getFragment(href) {
            var $def = $.Deferred();
            //caching!
            if (fragmentCache[href]) {
                console.log(format('cached {0}', href));
                $def.resolve(fragmentCache[href]);
            } else {
                console.log(format('fetching {0}', href));
                fetchFragment(href).done(function(d, textStatus, xhr) {
                    // Bail if this is not HTML.
                    if (xhr.getResponseHeader('content-type').indexOf('text/html') < 0) {
                        $def.reject();
                        return;
                    }
                    if (d.indexOf('') === -1) {
                        console.log('warning, fragment not properly served!');
                        return;
                    }
                    console.log('header is ' + xhr.getResponseHeader('date'));
                    console.log('caching fragment');
                    handleFragmentResponse(xhr, href);
                    $def.resolve(d);
                }).fail(function(e) {
                    $def.reject();
                });
            }
            return $def.promise();
        }

        function fetchFragment(href) {
            // Chrome doesn't obey the Vary header, so we need to keep the fragments
            // from getting cached with the page itself. Remove once Chrome bug #94369
            // has been resolved as fixed.
            var fetch_href = href;
            if (navigator.userAgent.indexOf('Chrome') > -1) {
                var chr_flag = '';

                // If we have a locale/region, we want to include those in the request
                // so Chrome does a hard reload of those pages when they change.
                var lang = $.cookie('lang');
                if (lang) {
                    chr_flag += lang;
                }
                var region = $.cookie('region');
                if (region) {
                    chr_flag += region;
                }

                if(chr_flag) {
                    chr_flag = '=' + encodeURIComponent(chr_flag);
                }

                fetch_href += (href.indexOf("?") > -1 ? '&' : '?') + 'frag' + chr_flag;
            }

            return $.get(fetch_href);
        }

        function synchronousLoad(href) {
            // TODO(potch): Save the user's navigation stack.
            window.location.href = href;
        }

        // pump content into our page, clean up after ourselves.
        function updateContent(content, href, popped, opts) {
            opts = opts || {};
            endLoading();

            container.html(content);
            var page = container.find('#page');
            if (!page.length) {
                throw "something has gone terribly wrong";
            }

            // scroll to the right spot.
            $('html, body').scrollTop(opts.scrollTop || 0);

            // Reset our lovelies.
            _.extend(z, {
                body: $(document.body),
                page: $('#container'),
                context: $('#page').data('context')
            });

            if (z.context.type === 'offline') {
                console.log('oh no!');
                return;
            }

            if (!href) {
                href = z.context.uri;
                console.log('whats the 411' + href);
            }

            if (z.context.cache === 'cache') {
                console.log('caching fragment');
                fragmentCache[href] = content;
            }

            // If we have new media, load the next fragment synchronously.
            if (z.context.hash != cacheHash) {
                reloadOnNext = true;
                container.trigger('fragmentpendingsync');
                console.log('performing synchronous load next navigation');
            }

            // Clear jQuery's data attribute cache for body.
            jQuery.cache[document.body[jQuery.expando]].data = null;

            // We so sneaky.
            document.title = z.context.title;

            var type = z.context.type;

            var newState = {
                path: href,
                type: type,
                title: z.context.title,
                scrollTop: $(document).scrollTop()
            };
            if (!popped) history.pushState(newState, false, href);

            container.trigger('fragmentloaded', [href, popped, newState]);
        }

        $(window).on('popstate', function(e) {
            var state = e.originalEvent.state;
            if (state) {
                navigate(state, true);
            }
        }).on('loadfragment', function(e, href) {
            if (href) navigate({path: href});
        }).on('refreshfragment', function(e) {
            var path = window.location.pathname + window.location.search + window.location.hash;
            if (fragmentCache[path]) {
                delete fragmentCache[path];
            }
            navigate({path: path});
        });

        $(window).on('updatecache', function() {
            console.log('event');
            updateCache();
        });

        function updateCache() {
            console.log('caching fragment');
            fragmentCache[window.location.pathname] = container.html();
        }

        $(function() {
            // Don't forget to update updateContent too, bro.
            var path = window.location.pathname + window.location.search + window.location.hash;
            var type = z.context.type;
            cacheHash = z.context.hash;
            var state = {
                path: path,
                type: type
            };
            history.replaceState(state, false, path);

            if (z.context.cache === 'cache') {
                updateCache();
            }
            container.trigger('fragmentloaded', [path, false, state]);
        });
        console.log("fragments enabled");
    } else {
        console.warn("fragments not enabled!!");
        $(function() {
            container.trigger('fragmentloaded');
        });
    }
})(z.page, fragmentFilter);
<|endoftext|>


<commit_before>$(document).ready(function() {
  $(".list--episodes, .list--queue").on("click", function(e) {
    var classList = e.target.classList;

    if (classList.contains("episode_button")) {
      var id = e.target.parentElement.parentElement.parentElement.dataset.id;
      var audioElem = document.querySelector(".audios [data-id='" + id + "']");

      if (classList.contains("episode_button--play")) {
        var $episodeElem = $(e.target).closest("cbus-episode");
        var $closestList = $(e.target).closest(".list");
        if ($closestList.hasClass("list--episodes")) { // from stream
          cbus.audio.setElement(audioElem);
          cbus.audio.play();
        } else { // from queue
          cbus.audio.playQueueItem($episodeElem.index());
        }
      } else if (classList.contains("episode_button--enqueue")) {
        cbus.audio.enqueue(audioElem);
      } else if (classList.contains("episode_button--remove-from-queue")) {
        cbus.audio.removeQueueItem($(e.target).closest("cbus-episode").index());
      } else if (classList.contains("episode_button--download")) {
        cbus.data.downloadEpisode(audioElem);
      } else if (classList.contains("episode_button--completed")) {
        cbus.data.toggleCompleted(audioElem.dataset.id);
      }
    } else if (classList.contains("episode_feed-title")) {
      var url = cbus.data.getEpisodeData({ id: $(e.target).closest("cbus-episode").attr("data-id") }).feedURL;
      cbus.broadcast.send("showPodcastDetail", {
        url: url
      });
    } else if (classList.contains("episode_info-button")) {
      var $episodeElem = $(e.target).closest("cbus-episode");
      console.log($episodeElem);
      if ($episodeElem.hasClass("info-open")) {
        console.log("has");
        $episodeElem.removeClass("info-open");
      } else {
        console.log("no has");
        $("cbus-episode").removeClass("info-open");
        $episodeElem.find(".episode_bottom").scrollTop(0);
        $episodeElem.addClass("info-open");
      }
    } else if (e.target.tagName === "A") {
      e.preventDefault();
      remote.shell.openExternal(e.target.href);
    }
  });

  /* search */

  let searchResultsElem = document.getElementsByClassName("explore_feeds--search-results")[0];
  document.querySelector(".explore_search input").addEventListener("keydown", function(e) {
    if (e.key === "Enter") {
      let query = this.value;

      if (query.length > 0) {
        searchResultsElem.innerHTML = "";

        let regexMatchResult = query.match(cbus.data.urlRegex);
        if (regexMatchResult && regexMatchResult[0] === query) {
          cbus.broadcast.send("showPodcastDetail", {
            url: query
          });
        } else {
          cbus.server.searchPodcasts(query, function(data) {
            if (data) {
              cbus.broadcast.send("got-search-results")
              for (let i = 0, l = data.length; i < l; i++) {
                searchResultsElem.appendChild(cbus.ui.makeFeedElem(data[i], i, true));
                cbus.data.feedsCache.push(data[i]);
              }
            }
          });

          searchResultsElem.classList.add("visible");
        }
      } else {
        searchResultsElem.classList.add("visible");
      }
    }
  });

  /* player controls */

  $(".player").on("click", function(e) {
    var classList = e.target.classList;
    if (classList.contains("player_button")) {
      if (classList.contains("player_button--backward")) {
        cbus.audio.jump(cbus.audio.DEFAULT_JUMP_AMOUNT_BACKWARD);
      } else if (classList.contains("player_button--forward")) {
        cbus.audio.jump(cbus.audio.DEFAULT_JUMP_AMOUNT_FORWARD);
      } else if (classList.contains("player_button--play")) {
        if (!cbus.audio.element) {
          if (cbus.audio.queue.length > 0) {
            cbus.audio.setElement(cbus.audio.queue[0]);
          }
          cbus.audio.play();
        } else if (cbus.audio.element.paused) {
          cbus.audio.play();
        } else {
          cbus.audio.pause();
        }
      } else if (classList.contains("player_button--next")) {
        cbus.audio.playQueueItem(0);
      }
    } else if (classList.contains("player_detail_tab")) {
      if (classList.contains("player_detail_tab--description")) {
          cbus.ui.setPlayerTab(0);
      } else if (classList.contains("player_detail_tab--chapters")) {
        cbus.ui.setPlayerTab(1);
      }
    } else if (classList.contains("player_detail_chapter")) {
      let chapters = cbus.data.getEpisodeData({ audioElement: cbus.audio.element }).chapters;
      cbus.audio.element.currentTime = chapters[Number(e.target.dataset.index)].time;
    } else if (classList.contains("player_detail_description_timelink")) {
      cbus.audio.element.currentTime = cbus.data.parseTimeString(e.target.textContent);
    }
  });

  $(".player_slider").on("input change", function() {
    var proportion = this.value / this.max;
    cbus.audio.element.currentTime = cbus.audio.element.duration * proportion;
  });

  cbus.ui.videoCanvasElement.addEventListener("dblclick", (e) => {
    cbus.ui.setFullscreen(!cbus.ui.browserWindow.isFullScreen());
  });

  /* header actions */

  $(".header_actions").on("click", function(e) {
    var classList = e.target.classList;
    if (classList.contains("header_action")) {
      if (classList.contains("header_action--refresh-episodes")) {
        cbus.data.update();
      }
    }
  });

  /* tabs */

  $("header nav a").on("click", function() {
    var targetId = this.dataset.target;
    cbus.ui.tabs.switch({ id: targetId });
  });

  /* update stream or load from cache */

  var storedEpisodes, lastAudioInfo, lastQueueInfos,
      lastAudioURL, lastAudioTime;

  localforageGetMulti([
    "cbus_feeds_qnp", "cbus_cache_episodes", "cbus_episodes_offline",
    "cbus-last-audio-info", "cbus-last-queue-infos", "cbus-last-audio-url",
    "cbus-last-audio-time", "cbus-last-queue-urls", "cbus_episode_progresses",
    "cbus_feeds", "cbus_episode_completed_statuses"
  ], function(r) {
    if (r.hasOwnProperty("cbus_cache_episodes")) {
      storedEpisodes = r["cbus_cache_episodes"];
    }
    if (r.hasOwnProperty("cbus_episodes_offline")) {
      cbus.data.episodesOffline = r["cbus_episodes_offline"] || [];
    }
    if (r.hasOwnProperty("cbus-last-audio-info")) {
      lastAudioInfo = r["cbus-last-audio-info"];
    }
    if (r.hasOwnProperty("cbus-last-queue-infos")) {
      lastQueueInfos = r["cbus-last-queue-infos"];
    }
    if (r.hasOwnProperty("cbus-last-audio-url")) {
      lastAudioURL = r["cbus-last-audio-url"];
    }
    if (r.hasOwnProperty("cbus-last-audio-time")) {
      lastAudioTime = r["cbus-last-audio-time"];
    }
    if (r.hasOwnProperty("cbus-last-queue-urls")) {
      lastQueueURLs = r["cbus-last-queue-urls"];
    }

    cbus.data.episodeProgresses = r["cbus_episode_progresses"] || [];
    cbus.data.episodeCompletedStatuses = r["cbus_episode_completed_statuses"] || [];
    cbus.data.feedsQNP = r["cbus_feeds_qnp"] || [];

    if (r["cbus_feeds"]) {
      cbus.data.feeds = r["cbus_feeds"].sort(cbus.const.podcastSort);
    } else {
      cbus.data.feeds = [];
    }
    for (let i = 0, l = cbus.data.feeds.length; i < l; i++) {
      cbus.data.feedsCache.push(cbus.data.feeds[i]);
    }
    if (cbus.data.feeds.length > 0) { // there are subscribed feeds
      cbus.ui.tabs.switch({ index: 0 }); // Home tab
    } else { // no subscribed feeds
      cbus.ui.tabs.switch({ index: 3 }); // Explore tab
    }
    cbus.ui.display("feeds");

    fs.readdir(path.join(cbus.data.USERDATA_PATH, "offline_episodes"), function(err, files) {
      for (let i = 0, l = cbus.data.episodesOffline.length; i < l; i++) {
        if (files.indexOf(sha1(cbus.data.episodesOffline[i])) === -1) { // both are arrays of strings
          let episodeURL = cbus.data.episodesOffline[i];
          cbus.data.episodesOffline.splice(i, 1)
          cbus.broadcast.send("offline_episodes_changed", {
            episodeURL: episodeURL
          });
        } else {
          console.log(files)
        }
      }
      localforage.setItem("cbus_episodes_offline", cbus.data.episodesOffline)
    })

    cbus.data.episodesUnsubbed = []

    if (storedEpisodes) {
      // store globally
      cbus.data.episodes = storedEpisodes.filter(function(episodeInfo) {
        var feedInfo = cbus.data.getFeedData({ url: episodeInfo.feedURL });
        if (!feedInfo || feedInfo.isUnsubscribed) { return false; }
        return true;
      });
      if (lastAudioInfo) {
        cbus.data.episodesUnsubbed.push(lastAudioInfo)
      }
      if (lastQueueInfos) {
        for (let episodeInfo of lastQueueInfos) {
          cbus.data.episodesUnsubbed.push(episodeInfo)
        }
      }
      cbus.data.updateMedias(); // make audio elems and add to DOM
      cbus.ui.display("episodes"); // display the episodes we already have

      if (lastAudioURL) {
        let elem = document.querySelector(`.audios [data-id='${lastAudioURL}']`);
        if (elem) {
          // cbus.audio.setElement(elem, true);
          cbus.audio.setElement(elem);
          if (lastAudioTime) {
            cbus.audio.element.currentTime = lastAudioTime;
            cbus.broadcast.send("audioTick", {
              currentTime: lastAudioTime,
              duration: cbus.data.getEpisodeData({ audioElement: cbus.audio.element }).length
            })
          }
        }
      }

      if (lastQueueURLs) {
        for (let i = 0, l = lastQueueURLs.length; i < l; i++) {
          cbus.audio.enqueue(document.querySelector(`.audios audio[data-id="${ lastQueueURLs[i] }"]`), true)
        }
      }
    }

    cbus.data.update(); // look for any new episodes (takes care of displaying and updateMedias-ing)
  });

  /* start loading popular podcasts */

  cbus.server.getPopularPodcasts((popularPodcastInfos) => {
    console.log(popularPodcastInfos)
    let popularPodcastsElem = document.getElementsByClassName("explore_feeds--popular")[0];
    for (let i = 0, l = popularPodcastInfos.length; i < l; i++) {
      popularPodcastsElem.appendChild(
        cbus.ui.makeFeedElem(popularPodcastInfos[i], i, true)
      );
      cbus.data.feedsCache.push(popularPodcastInfos[i]);
    }
  })

  cbus.broadcast.listen("toggleSubscribe", function(e) {
    console.log(e);

    var completeData = arrayFindByKey(cbus.data.feedsCache, { url: e.data.url })[0];
    var subscribed = !!arrayFindByKey(cbus.data.feeds, { url: e.data.url })[0]

    var direction;
    if (e.data.direction) {
      direction = e.data.direction;
    } else {
      if (subscribed) { // already subscribed
        direction = -1;
      } else { // not subscribed
        direction = 1;
      }
    }

    if (direction === -1) {
      cbus.data.unsubscribeFeed({ url: e.data.url }, true);
    } else {
      // complete required data
      var requiredKeys = ["image", "title", "url"];

      for (key of requiredKeys) {
        if (!e.data.hasOwnProperty(key)) {
          e.data[key] = completeData[key];
        }
      }

      cbus.data.subscribeFeed(e.data, true);
    }

    if (cbus.data.state.podcastDetailCurrentData.url === e.data.url) {
      if (direction === -1) {
        $(".podcast-detail_control--toggle-subscribe").removeClass("subscribed");
        console.log("removed subscribed class");
      } else {
        $(".podcast-detail_control--toggle-subscribe").addClass("subscribed");
        console.log("added subscribed class");
      }
    }
  });

  /* listen for audio change */

  cbus.broadcast.listen("audioChange", function(e) {
    var element = $("audio audio[data-id='" + e.data.id + "']");

    cbus.broadcast.send("audioTick", {
      currentTime: 0,
      duration: element.duration
    });

    cbus.ui.display("player", e.data);

    // /* extract accent color of feed image and apply to player */
    //
    // cbus.ui.colorify({
    //   image: e.data.feed.image,
    //   element: $(".player")
    // });
    // $(".player").addClass("light-colors");
  });

  /* update audio time */

  let playerTimeNowElem = document.getElementsByClassName("player_time--now")[0];
  let playerTimeTotalElem = document.getElementsByClassName("player_time--total")[0];
  let playerSliderElem = document.getElementsByClassName("player_slider")[0];

  cbus.broadcast.listen("audioTick", function(e) {
    /* slider */
    playerSliderElem.value = Math.round(1000 * e.data.currentTime / e.data.duration) || 0;

    /* time indicator */
    playerTimeNowElem.innerHTML = colonSeparateDuration(e.data.currentTime);
    playerTimeTotalElem.innerHTML = colonSeparateDuration(e.data.duration);

    /* record in localforage so we can resume next time */
    localforage.setItem("cbus-last-audio-time", e.data.currentTime);
  });

  /* open podcast detail when podcast name clicked in episode data */

  document.getElementsByClassName("player_detail_feed-title")[0].onclick = function() {
    cbus.broadcast.send("showPodcastDetail", {
      url: cbus.data.getEpisodeData({ audioElement: cbus.audio.element }).feedURL
    });
  };
});

/* shortly after startup, remove from episodesUnsubbed and feedsQNP episodes/feeds not in queue or now playing */
// setTimeout(function() {
//   var episodesStillNeededURLs = []
//   if (cbus.audio.element) {
//     episodesStillNeededURLs.push(cbus.data.getEpisodeData({audioElement: cbus.audio.element}).url)
//   }
// }, 10000)
<commit_msg>Cache jQuery element reference in list event handler<commit_after>$(document).ready(function() {
  $(".list--episodes, .list--queue").on("click", function(e) {
    var classList = e.target.classList;
    let $target = $(e.target);

    if (classList.contains("episode_button")) {
      var id = e.target.parentElement.parentElement.parentElement.dataset.id;
      var audioElem = document.querySelector(".audios [data-id='" + id + "']");

      if (classList.contains("episode_button--play")) {
        var $episodeElem = $target.closest("cbus-episode");
        var $closestList = $target.closest(".list");
        if ($closestList.hasClass("list--episodes")) { // from stream
          cbus.audio.setElement(audioElem);
          cbus.audio.play();
        } else { // from queue
          cbus.audio.playQueueItem($episodeElem.index());
        }
      } else if (classList.contains("episode_button--enqueue")) {
        cbus.audio.enqueue(audioElem);
      } else if (classList.contains("episode_button--remove-from-queue")) {
        cbus.audio.removeQueueItem($(e.target).closest("cbus-episode").index());
      } else if (classList.contains("episode_button--download")) {
        cbus.data.downloadEpisode(audioElem);
      } else if (classList.contains("episode_button--completed")) {
        cbus.data.toggleCompleted(audioElem.dataset.id);
      }
    } else if (classList.contains("episode_feed-title")) {
      var url = cbus.data.getEpisodeData({ id: $target.closest("cbus-episode").attr("data-id") }).feedURL;
      cbus.broadcast.send("showPodcastDetail", {
        url: url
      });
    } else if (classList.contains("episode_info-button")) {
      var $episodeElem = $target.closest("cbus-episode");
      console.log($episodeElem);
      if ($episodeElem.hasClass("info-open")) {
        console.log("has");
        $episodeElem.removeClass("info-open");
      } else {
        console.log("no has");
        $("cbus-episode").removeClass("info-open");
        $episodeElem.find(".episode_bottom").scrollTop(0);
        $episodeElem.addClass("info-open");
      }
    } else if (e.target.tagName === "A") {
      e.preventDefault();
      remote.shell.openExternal(e.target.href);
    }
  });

  /* search */

  let searchResultsElem = document.getElementsByClassName("explore_feeds--search-results")[0];
  document.querySelector(".explore_search input").addEventListener("keydown", function(e) {
    if (e.key === "Enter") {
      let query = this.value;

      if (query.length > 0) {
        searchResultsElem.innerHTML = "";

        let regexMatchResult = query.match(cbus.data.urlRegex);
        if (regexMatchResult && regexMatchResult[0] === query) {
          cbus.broadcast.send("showPodcastDetail", {
            url: query
          });
        } else {
          cbus.server.searchPodcasts(query, function(data) {
            if (data) {
              cbus.broadcast.send("got-search-results")
              for (let i = 0, l = data.length; i < l; i++) {
                searchResultsElem.appendChild(cbus.ui.makeFeedElem(data[i], i, true));
                cbus.data.feedsCache.push(data[i]);
              }
            }
          });

          searchResultsElem.classList.add("visible");
        }
      } else {
        searchResultsElem.classList.add("visible");
      }
    }
  });

  /* player controls */

  $(".player").on("click", function(e) {
    var classList = e.target.classList;
    if (classList.contains("player_button")) {
      if (classList.contains("player_button--backward")) {
        cbus.audio.jump(cbus.audio.DEFAULT_JUMP_AMOUNT_BACKWARD);
      } else if (classList.contains("player_button--forward")) {
        cbus.audio.jump(cbus.audio.DEFAULT_JUMP_AMOUNT_FORWARD);
      } else if (classList.contains("player_button--play")) {
        if (!cbus.audio.element) {
          if (cbus.audio.queue.length > 0) {
            cbus.audio.setElement(cbus.audio.queue[0]);
          }
          cbus.audio.play();
        } else if (cbus.audio.element.paused) {
          cbus.audio.play();
        } else {
          cbus.audio.pause();
        }
      } else if (classList.contains("player_button--next")) {
        cbus.audio.playQueueItem(0);
      }
    } else if (classList.contains("player_detail_tab")) {
      if (classList.contains("player_detail_tab--description")) {
          cbus.ui.setPlayerTab(0);
      } else if (classList.contains("player_detail_tab--chapters")) {
        cbus.ui.setPlayerTab(1);
      }
    } else if (classList.contains("player_detail_chapter")) {
      let chapters = cbus.data.getEpisodeData({ audioElement: cbus.audio.element }).chapters;
      cbus.audio.element.currentTime = chapters[Number(e.target.dataset.index)].time;
    } else if (classList.contains("player_detail_description_timelink")) {
      cbus.audio.element.currentTime = cbus.data.parseTimeString(e.target.textContent);
    }
  });

  $(".player_slider").on("input change", function() {
    var proportion = this.value / this.max;
    cbus.audio.element.currentTime = cbus.audio.element.duration * proportion;
  });

  cbus.ui.videoCanvasElement.addEventListener("dblclick", (e) => {
    cbus.ui.setFullscreen(!cbus.ui.browserWindow.isFullScreen());
  });

  /* header actions */

  $(".header_actions").on("click", function(e) {
    var classList = e.target.classList;
    if (classList.contains("header_action")) {
      if (classList.contains("header_action--refresh-episodes")) {
        cbus.data.update();
      }
    }
  });

  /* tabs */

  $("header nav a").on("click", function() {
    var targetId = this.dataset.target;
    cbus.ui.tabs.switch({ id: targetId });
  });

  /* update stream or load from cache */

  var storedEpisodes, lastAudioInfo, lastQueueInfos,
      lastAudioURL, lastAudioTime;

  localforageGetMulti([
    "cbus_feeds_qnp", "cbus_cache_episodes", "cbus_episodes_offline",
    "cbus-last-audio-info", "cbus-last-queue-infos", "cbus-last-audio-url",
    "cbus-last-audio-time", "cbus-last-queue-urls", "cbus_episode_progresses",
    "cbus_feeds", "cbus_episode_completed_statuses"
  ], function(r) {
    if (r.hasOwnProperty("cbus_cache_episodes")) {
      storedEpisodes = r["cbus_cache_episodes"];
    }
    if (r.hasOwnProperty("cbus_episodes_offline")) {
      cbus.data.episodesOffline = r["cbus_episodes_offline"] || [];
    }
    if (r.hasOwnProperty("cbus-last-audio-info")) {
      lastAudioInfo = r["cbus-last-audio-info"];
    }
    if (r.hasOwnProperty("cbus-last-queue-infos")) {
      lastQueueInfos = r["cbus-last-queue-infos"];
    }
    if (r.hasOwnProperty("cbus-last-audio-url")) {
      lastAudioURL = r["cbus-last-audio-url"];
    }
    if (r.hasOwnProperty("cbus-last-audio-time")) {
      lastAudioTime = r["cbus-last-audio-time"];
    }
    if (r.hasOwnProperty("cbus-last-queue-urls")) {
      lastQueueURLs = r["cbus-last-queue-urls"];
    }

    cbus.data.episodeProgresses = r["cbus_episode_progresses"] || [];
    cbus.data.episodeCompletedStatuses = r["cbus_episode_completed_statuses"] || [];
    cbus.data.feedsQNP = r["cbus_feeds_qnp"] || [];

    if (r["cbus_feeds"]) {
      cbus.data.feeds = r["cbus_feeds"].sort(cbus.const.podcastSort);
    } else {
      cbus.data.feeds = [];
    }
    for (let i = 0, l = cbus.data.feeds.length; i < l; i++) {
      cbus.data.feedsCache.push(cbus.data.feeds[i]);
    }
    if (cbus.data.feeds.length > 0) { // there are subscribed feeds
      cbus.ui.tabs.switch({ index: 0 }); // Home tab
    } else { // no subscribed feeds
      cbus.ui.tabs.switch({ index: 3 }); // Explore tab
    }
    cbus.ui.display("feeds");

    fs.readdir(path.join(cbus.data.USERDATA_PATH, "offline_episodes"), function(err, files) {
      for (let i = 0, l = cbus.data.episodesOffline.length; i < l; i++) {
        if (files.indexOf(sha1(cbus.data.episodesOffline[i])) === -1) { // both are arrays of strings
          let episodeURL = cbus.data.episodesOffline[i];
          cbus.data.episodesOffline.splice(i, 1)
          cbus.broadcast.send("offline_episodes_changed", {
            episodeURL: episodeURL
          });
        } else {
          console.log(files)
        }
      }
      localforage.setItem("cbus_episodes_offline", cbus.data.episodesOffline)
    })

    cbus.data.episodesUnsubbed = []

    if (storedEpisodes) {
      // store globally
      cbus.data.episodes = storedEpisodes.filter(function(episodeInfo) {
        var feedInfo = cbus.data.getFeedData({ url: episodeInfo.feedURL });
        if (!feedInfo || feedInfo.isUnsubscribed) { return false; }
        return true;
      });
      if (lastAudioInfo) {
        cbus.data.episodesUnsubbed.push(lastAudioInfo)
      }
      if (lastQueueInfos) {
        for (let episodeInfo of lastQueueInfos) {
          cbus.data.episodesUnsubbed.push(episodeInfo)
        }
      }
      cbus.data.updateMedias(); // make audio elems and add to DOM
      cbus.ui.display("episodes"); // display the episodes we already have

      if (lastAudioURL) {
        let elem = document.querySelector(`.audios [data-id='${lastAudioURL}']`);
        if (elem) {
          // cbus.audio.setElement(elem, true);
          cbus.audio.setElement(elem);
          if (lastAudioTime) {
            cbus.audio.element.currentTime = lastAudioTime;
            cbus.broadcast.send("audioTick", {
              currentTime: lastAudioTime,
              duration: cbus.data.getEpisodeData({ audioElement: cbus.audio.element }).length
            })
          }
        }
      }

      if (lastQueueURLs) {
        for (let i = 0, l = lastQueueURLs.length; i < l; i++) {
          cbus.audio.enqueue(document.querySelector(`.audios audio[data-id="${ lastQueueURLs[i] }"]`), true)
        }
      }
    }

    cbus.data.update(); // look for any new episodes (takes care of displaying and updateMedias-ing)
  });

  /* start loading popular podcasts */

  cbus.server.getPopularPodcasts((popularPodcastInfos) => {
    console.log(popularPodcastInfos)
    let popularPodcastsElem = document.getElementsByClassName("explore_feeds--popular")[0];
    for (let i = 0, l = popularPodcastInfos.length; i < l; i++) {
      popularPodcastsElem.appendChild(
        cbus.ui.makeFeedElem(popularPodcastInfos[i], i, true)
      );
      cbus.data.feedsCache.push(popularPodcastInfos[i]);
    }
  })

  cbus.broadcast.listen("toggleSubscribe", function(e) {
    console.log(e);

    var completeData = arrayFindByKey(cbus.data.feedsCache, { url: e.data.url })[0];
    var subscribed = !!arrayFindByKey(cbus.data.feeds, { url: e.data.url })[0]

    var direction;
    if (e.data.direction) {
      direction = e.data.direction;
    } else {
      if (subscribed) { // already subscribed
        direction = -1;
      } else { // not subscribed
        direction = 1;
      }
    }

    if (direction === -1) {
      cbus.data.unsubscribeFeed({ url: e.data.url }, true);
    } else {
      // complete required data
      var requiredKeys = ["image", "title", "url"];

      for (key of requiredKeys) {
        if (!e.data.hasOwnProperty(key)) {
          e.data[key] = completeData[key];
        }
      }

      cbus.data.subscribeFeed(e.data, true);
    }

    if (cbus.data.state.podcastDetailCurrentData.url === e.data.url) {
      if (direction === -1) {
        $(".podcast-detail_control--toggle-subscribe").removeClass("subscribed");
        console.log("removed subscribed class");
      } else {
        $(".podcast-detail_control--toggle-subscribe").addClass("subscribed");
        console.log("added subscribed class");
      }
    }
  });

  /* listen for audio change */

  cbus.broadcast.listen("audioChange", function(e) {
    var element = $("audio audio[data-id='" + e.data.id + "']");

    cbus.broadcast.send("audioTick", {
      currentTime: 0,
      duration: element.duration
    });

    cbus.ui.display("player", e.data);

    // /* extract accent color of feed image and apply to player */
    //
    // cbus.ui.colorify({
    //   image: e.data.feed.image,
    //   element: $(".player")
    // });
    // $(".player").addClass("light-colors");
  });

  /* update audio time */

  let playerTimeNowElem = document.getElementsByClassName("player_time--now")[0];
  let playerTimeTotalElem = document.getElementsByClassName("player_time--total")[0];
  let playerSliderElem = document.getElementsByClassName("player_slider")[0];

  cbus.broadcast.listen("audioTick", function(e) {
    /* slider */
    playerSliderElem.value = Math.round(1000 * e.data.currentTime / e.data.duration) || 0;

    /* time indicator */
    playerTimeNowElem.innerHTML = colonSeparateDuration(e.data.currentTime);
    playerTimeTotalElem.innerHTML = colonSeparateDuration(e.data.duration);

    /* record in localforage so we can resume next time */
    localforage.setItem("cbus-last-audio-time", e.data.currentTime);
  });

  /* open podcast detail when podcast name clicked in episode data */

  document.getElementsByClassName("player_detail_feed-title")[0].onclick = function() {
    cbus.broadcast.send("showPodcastDetail", {
      url: cbus.data.getEpisodeData({ audioElement: cbus.audio.element }).feedURL
    });
  };
});

/* shortly after startup, remove from episodesUnsubbed and feedsQNP episodes/feeds not in queue or now playing */
// setTimeout(function() {
//   var episodesStillNeededURLs = []
//   if (cbus.audio.element) {
//     episodesStillNeededURLs.push(cbus.data.getEpisodeData({audioElement: cbus.audio.element}).url)
//   }
// }, 10000)
<|endoftext|>