<commit_before>import { expect } from 'chai';
import { search } from '../src';

const {
  multipleColumns, singleColumn,
  strategies: { infix, prefix }, _columnMatches, matches
} = search;

describe('search.multipleColumns', function () {
  it('matches all', function () {
    const query = { demo: 'foo' };
    const data = [{ demo: 'foobar' }, { demo: 'foofoo' }];
    const result = multipleColumns({
      data,
      query,
      columns: [
        { cell: { property: 'demo' } }
      ]
    });

    expect(result).to.deep.equal(data);
  });

  it('matches some', function () {
    const query = { demo: 'foo' };
    const match = { demo: 'foobar' };
    const data = [match, { demo: 'zappa' }];
    const result = multipleColumns({
      data,
      query,
      columns: [
        { cell: { property: 'demo' } }
      ]
    });

    expect(result).to.deep.equal([match]);
  });

  it('does not match from other column', function () {
    const query = { demo: 'foo' };
    const match = { demo: 'foobar' };
    const data = [match, { demo: 'bar', another: 'foobar' }];
    const result = multipleColumns({
      data,
      query,
      columns: [
        { cell: { property: 'demo' } },
        { cell: { property: 'another' } }
      ]
    });

    expect(result).to.deep.equal([match]);
  });

  it('matches none', function () {
    const query = { demo: 'foo' };
    const data = [{ demo: 'barbar' }, { demo: 'zappa' }];
    const result = multipleColumns({
      data,
      query,
      columns: [
        { cell: { property: 'demo' } }
      ]
    });

    expect(result).to.deep.equal([]);
  });

  it('returns all data without a query', function () {
    const data = [{ demo: 'foobar' }, { demo: 'zappa' }];
    const result = multipleColumns({
      data,
      columns: [
        { cell: { property: 'demo' } }
      ]
    });

    expect(result).to.deep.equal(data);
  });
});

describe('search.singleColumn', function () {
  it('matches searched column', function () {
    const query = 'foo';
    const data = [{ demo: 'foobar' }];
    const result = singleColumn({
      data,
      query,
      columns: [
        { cell: { property: 'demo' } }
      ],
      searchColumn: 'demo'
    });

    expect(result).to.deep.equal(data);
  });

  it('matches some', function () {
    const query = 'foo';
    const data = { demo: 'foobar' };
    const result = singleColumn({
      data: [
        data,
        { demo: 'zapzap' }
      ],
      query,
      columns: [
        { cell: { property: 'demo' } }
      ]
    });

    expect(result).to.deep.equal([data]);
  });

  it('matches none', function () {
    const query = 'foo';
    const data = { demo: 'zapzap' };
    const result = singleColumn({
      data: [
        data
      ],
      query,
      columns: [
        { cell: { property: 'demo' } }
      ]
    });

    expect(result).to.deep.equal([]);
  });

  it('matches against all columns', function () {
    const query = 'foo';
    const data = [{ demo: 'foobar' }];
    const result = singleColumn({
      data,
      query,
      columns: [
        { cell: { property: 'demo' } }
      ],
      searchColumn: 'all'
    });

    expect(result).to.deep.equal(data);
  });

  it('matches against all columns by default', function () {
    const query = 'foo';
    const data = [{ demo: 'foobar' }];
    const result = singleColumn({
      data,
      query,
      columns: [
        { cell: { property: 'demo' } }
      ],
      searchColumn: 'all'
    });

    expect(result).to.deep.equal(data);
  });

  it('returns all data without a query', function () {
    const data = [{ demo: 'foobar' }];
    const result = singleColumn({
      data,
      columns: [
        { cell: { property: 'demo' } }
      ]
    });

    expect(result).to.deep.equal(data);
  });
});

describe('search._columnMatches', function () {
  it('returns matching query', function () {
    const query = 'foo';
    const result = _columnMatches({
      query,
      column: { cell: { property: 'demo' } },
      row: { demo: 'foobar' }
    });

    expect(result).to.equal(true);
  });

  it('does not return missing query', function () {
    const query = 'zoo';
    const result = _columnMatches({
      query,
      column: { cell: { property: 'demo' } },
      row: { demo: 'foobar' }
    });

    expect(result).to.equal(false);
  });

  it('accepts alternative strategy', function () {
    const query = 'oba';
    const result = _columnMatches({
      query,
      column: { cell: { property: 'demo' } },
      row: { demo: 'foobar' },
      strategy: prefix
    });

    expect(result).to.equal(false);
  });

  it('accepts alternative transform', function () {
    const query = 'oba';
    const result = _columnMatches({
      query,
      column: { cell: { property: 'demo' } },
      row: { demo: 'foobar' },
      transform: v => v
    });

    expect(result).to.equal(true);
  });

  it('parses nested property', function () {
    const query = 'foo';
    const result = _columnMatches({
      query,
      column: { cell: { property: 'demo.another' } },
      row: { demo: { another: 'foobar' } }
    });

    expect(result).to.equal(true);
  });

  it('formats property', function () {
    const query = 'foo';
    const result = _columnMatches({
      query,
      column: { cell: { property: 'demo', resolve: a => a.toUpperCase() } },
      row: { demo: 'foobar' },
      transform: v => v
    });

    expect(result).to.equal(false);
  });

  it('is not visible without a valid value', function () {
    const query = 'foo';
    const result = _columnMatches({
      query,
      column: { cell: { property: 'demo' } },
      row: { demo: ['bar'] },
      transform: v => v
    });

    expect(result).to.equal(false);
  });

  it('is not visible with undefined', function () {
    const query = 'foo';
    const result = _columnMatches({
      query,
      column: { cell: { property: 'demo' } },
      row: { demo: undefined },
      transform: v => v
    });

    expect(result).to.equal(false);
  });
});

describe('search.matches', function () {
  it('matches infix by default', function () {
    const query = 'oba';
    const result = matches({
      value: 'foobar',
      query
    });
    const expected = [
      {
        startIndex: 2,
        length: query.length
      }
    ];

    expect(result).to.deep.equal(expected);
  });

  it('matches case-insensitively by default', function () {
    const query = 'foo';
    const result = matches({
      value: 'FOOBAR',
      query
    });
    const expected = [
      {
        startIndex: 0,
        length: query.length
      }
    ];

    expect(result).to.deep.equal(expected);
  });

  it('allows changing strategy', function () {
    const query = 'foo';
    const result = matches({
      value: 'foobar',
      query,
      strategy: prefix
    });
    const expected = [
      {
        startIndex: 0,
        length: query.length
      }
    ];

    expect(result).to.deep.equal(expected);
  });

  it('allows changing transform', function () {
    const query = 'foo';
    const result = matches({
      value: 'FOOBAR',
      query,
      transform: a => a
    });
    const expected = [];

    expect(result).to.deep.equal(expected);
  });

  it('does not crash without parameters', function () {
    const result = matches();

    expect(result).to.deep.equal({});
  });
});

describe('search.strategies.infix', function () {
  it('matches correctly', function () {
    const queryTerm = 'light';
    const text = 'enlighten';

    const predicate = infix(queryTerm);
    const expected = [
      {
        startIndex: 2,
        length: queryTerm.length
      }
    ];

    expect(predicate.evaluate(text)).to.equal(true);
    expect(predicate.matches(text)).to.deep.equal(expected);
  });

  it('matches multiple correctly', function () {
    const queryTerm = 'oub';
    const text = 'double trouble';

    const predicate = infix(queryTerm);
    const expected = [
      {
        startIndex: 1,
        length: queryTerm.length
      },
      {
        startIndex: 9,
        length: queryTerm.length
      }
    ];

    expect(predicate.evaluate(text)).to.equal(true);
    expect(predicate.matches(text)).to.deep.equal(expected);
  });

  it('does not match', function () {
    const queryTerm = 'light';
    const text = 'dark';

    const predicate = infix(queryTerm);

    expect(predicate.evaluate(text)).to.equal(false);
    expect(predicate.matches(text)).to.be.empty;
  });
});

describe('search.strategies.prefix', function () {
  it('matches correctly', function () {
    const queryTerm = 'lay';
    const text = 'layout';

    const predicate = prefix(queryTerm);
    const expected = [{
      startIndex: 0,
      length: queryTerm.length
    }];

    expect(predicate.evaluate(text)).to.equal(true);
    expect(predicate.matches(text)).to.deep.equal(expected);
  });

  it('does not match', function () {
    const queryTerm = 'lay';
    const text = 'outlay';

    const predicate = prefix(queryTerm);

    expect(predicate.evaluate(text)).to.equal(false);
    expect(predicate.matches(text)).to.be.empty;
  });
});
<commit_msg>search - Add a test to verify that `resolve` was called correctly<commit_after>import { expect } from 'chai';
import { search } from '../src';

const {
  multipleColumns, singleColumn,
  strategies: { infix, prefix }, _columnMatches, matches
} = search;

describe('search.multipleColumns', function () {
  it('matches all', function () {
    const query = { demo: 'foo' };
    const data = [{ demo: 'foobar' }, { demo: 'foofoo' }];
    const result = multipleColumns({
      data,
      query,
      columns: [
        { cell: { property: 'demo' } }
      ]
    });

    expect(result).to.deep.equal(data);
  });

  it('matches some', function () {
    const query = { demo: 'foo' };
    const match = { demo: 'foobar' };
    const data = [match, { demo: 'zappa' }];
    const result = multipleColumns({
      data,
      query,
      columns: [
        { cell: { property: 'demo' } }
      ]
    });

    expect(result).to.deep.equal([match]);
  });

  it('does not match from other column', function () {
    const query = { demo: 'foo' };
    const match = { demo: 'foobar' };
    const data = [match, { demo: 'bar', another: 'foobar' }];
    const result = multipleColumns({
      data,
      query,
      columns: [
        { cell: { property: 'demo' } },
        { cell: { property: 'another' } }
      ]
    });

    expect(result).to.deep.equal([match]);
  });

  it('matches none', function () {
    const query = { demo: 'foo' };
    const data = [{ demo: 'barbar' }, { demo: 'zappa' }];
    const result = multipleColumns({
      data,
      query,
      columns: [
        { cell: { property: 'demo' } }
      ]
    });

    expect(result).to.deep.equal([]);
  });

  it('returns all data without a query', function () {
    const data = [{ demo: 'foobar' }, { demo: 'zappa' }];
    const result = multipleColumns({
      data,
      columns: [
        { cell: { property: 'demo' } }
      ]
    });

    expect(result).to.deep.equal(data);
  });
});

describe('search.singleColumn', function () {
  it('matches searched column', function () {
    const query = 'foo';
    const data = [{ demo: 'foobar' }];
    const result = singleColumn({
      data,
      query,
      columns: [
        { cell: { property: 'demo' } }
      ],
      searchColumn: 'demo'
    });

    expect(result).to.deep.equal(data);
  });

  it('matches some', function () {
    const query = 'foo';
    const data = { demo: 'foobar' };
    const result = singleColumn({
      data: [
        data,
        { demo: 'zapzap' }
      ],
      query,
      columns: [
        { cell: { property: 'demo' } }
      ]
    });

    expect(result).to.deep.equal([data]);
  });

  it('matches none', function () {
    const query = 'foo';
    const data = { demo: 'zapzap' };
    const result = singleColumn({
      data: [
        data
      ],
      query,
      columns: [
        { cell: { property: 'demo' } }
      ]
    });

    expect(result).to.deep.equal([]);
  });

  it('matches against all columns', function () {
    const query = 'foo';
    const data = [{ demo: 'foobar' }];
    const result = singleColumn({
      data,
      query,
      columns: [
        { cell: { property: 'demo' } }
      ],
      searchColumn: 'all'
    });

    expect(result).to.deep.equal(data);
  });

  it('matches against all columns by default', function () {
    const query = 'foo';
    const data = [{ demo: 'foobar' }];
    const result = singleColumn({
      data,
      query,
      columns: [
        { cell: { property: 'demo' } }
      ],
      searchColumn: 'all'
    });

    expect(result).to.deep.equal(data);
  });

  it('returns all data without a query', function () {
    const data = [{ demo: 'foobar' }];
    const result = singleColumn({
      data,
      columns: [
        { cell: { property: 'demo' } }
      ]
    });

    expect(result).to.deep.equal(data);
  });
});

describe('search._columnMatches', function () {
  it('returns matching query', function () {
    const query = 'foo';
    const result = _columnMatches({
      query,
      column: { cell: { property: 'demo' } },
      row: { demo: 'foobar' }
    });

    expect(result).to.equal(true);
  });

  it('does not return missing query', function () {
    const query = 'zoo';
    const result = _columnMatches({
      query,
      column: { cell: { property: 'demo' } },
      row: { demo: 'foobar' }
    });

    expect(result).to.equal(false);
  });

  it('accepts alternative strategy', function () {
    const query = 'oba';
    const result = _columnMatches({
      query,
      column: { cell: { property: 'demo' } },
      row: { demo: 'foobar' },
      strategy: prefix
    });

    expect(result).to.equal(false);
  });

  it('accepts alternative transform', function () {
    const query = 'oba';
    const result = _columnMatches({
      query,
      column: { cell: { property: 'demo' } },
      row: { demo: 'foobar' },
      transform: v => v
    });

    expect(result).to.equal(true);
  });

  it('parses nested property', function () {
    const query = 'foo';
    const result = _columnMatches({
      query,
      column: { cell: { property: 'demo.another' } },
      row: { demo: { another: 'foobar' } }
    });

    expect(result).to.equal(true);
  });

  it('formats property', function () {
    const query = 'foo';
    const result = _columnMatches({
      query,
      column: { cell: { property: 'demo', resolve: a => a.toUpperCase() } },
      row: { demo: 'foobar' },
      transform: v => v
    });

    expect(result).to.equal(false);
  });

  it('formats with all parameters', function () {
    const property = 'demo';
    const row = { demo: 'foobar' };
    let receivedCellData;
    let receivedProperty;
    const result = _columnMatches({
      query: 'foo',
      column: {
        cell: {
          property,
          resolve: (a, { cellData, property }) => {
            receivedCellData = cellData;
            receivedProperty = property;

            return a;
          }
        }
      },
      row,
      transform: v => v
    });

    expect(row).to.equal(receivedCellData);
    expect(property).to.equal(receivedProperty);
  });

  it('is not visible without a valid value', function () {
    const query = 'foo';
    const result = _columnMatches({
      query,
      column: { cell: { property: 'demo' } },
      row: { demo: ['bar'] },
      transform: v => v
    });

    expect(result).to.equal(false);
  });

  it('is not visible with undefined', function () {
    const query = 'foo';
    const result = _columnMatches({
      query,
      column: { cell: { property: 'demo' } },
      row: { demo: undefined },
      transform: v => v
    });

    expect(result).to.equal(false);
  });
});

describe('search.matches', function () {
  it('matches infix by default', function () {
    const query = 'oba';
    const result = matches({
      value: 'foobar',
      query
    });
    const expected = [
      {
        startIndex: 2,
        length: query.length
      }
    ];

    expect(result).to.deep.equal(expected);
  });

  it('matches case-insensitively by default', function () {
    const query = 'foo';
    const result = matches({
      value: 'FOOBAR',
      query
    });
    const expected = [
      {
        startIndex: 0,
        length: query.length
      }
    ];

    expect(result).to.deep.equal(expected);
  });

  it('allows changing strategy', function () {
    const query = 'foo';
    const result = matches({
      value: 'foobar',
      query,
      strategy: prefix
    });
    const expected = [
      {
        startIndex: 0,
        length: query.length
      }
    ];

    expect(result).to.deep.equal(expected);
  });

  it('allows changing transform', function () {
    const query = 'foo';
    const result = matches({
      value: 'FOOBAR',
      query,
      transform: a => a
    });
    const expected = [];

    expect(result).to.deep.equal(expected);
  });

  it('does not crash without parameters', function () {
    const result = matches();

    expect(result).to.deep.equal({});
  });
});

describe('search.strategies.infix', function () {
  it('matches correctly', function () {
    const queryTerm = 'light';
    const text = 'enlighten';

    const predicate = infix(queryTerm);
    const expected = [
      {
        startIndex: 2,
        length: queryTerm.length
      }
    ];

    expect(predicate.evaluate(text)).to.equal(true);
    expect(predicate.matches(text)).to.deep.equal(expected);
  });

  it('matches multiple correctly', function () {
    const queryTerm = 'oub';
    const text = 'double trouble';

    const predicate = infix(queryTerm);
    const expected = [
      {
        startIndex: 1,
        length: queryTerm.length
      },
      {
        startIndex: 9,
        length: queryTerm.length
      }
    ];

    expect(predicate.evaluate(text)).to.equal(true);
    expect(predicate.matches(text)).to.deep.equal(expected);
  });

  it('does not match', function () {
    const queryTerm = 'light';
    const text = 'dark';

    const predicate = infix(queryTerm);

    expect(predicate.evaluate(text)).to.equal(false);
    expect(predicate.matches(text)).to.be.empty;
  });
});

describe('search.strategies.prefix', function () {
  it('matches correctly', function () {
    const queryTerm = 'lay';
    const text = 'layout';

    const predicate = prefix(queryTerm);
    const expected = [{
      startIndex: 0,
      length: queryTerm.length
    }];

    expect(predicate.evaluate(text)).to.equal(true);
    expect(predicate.matches(text)).to.deep.equal(expected);
  });

  it('does not match', function () {
    const queryTerm = 'lay';
    const text = 'outlay';

    const predicate = prefix(queryTerm);

    expect(predicate.evaluate(text)).to.equal(false);
    expect(predicate.matches(text)).to.be.empty;
  });
});
<|endoftext|>


<commit_before>
//positioning settings
var width = 740;
var height = 3500;
var pad = { left: 10, right: 0, top: 60, bottom: 10 };
var vertSpace = 45;
var xName = 20;

var xPrct = 520;
var xChange = 640;
var xNumF = 260;
var xTotal = 380;

var rectW = 80;
var rectH = 35;
var yHeader = 20;
var ySubHead = 40;

//define scales
var scaleRB6 = ['rgb(178,24,43)','rgb(239,138,98)','rgb(253,219,199)','rgb(209,229,240)','rgb(103,169,207)','rgb(33,102,172)'];
var colors = d3.scale.quantize().domain([30, 0]).range(scaleRB6);
var sizeNumF = d3.scale.linear().domain([10, 100]).range([11, 30]);
var sizeTotal = d3.scale.linear().domain([50, 500]).range([11, 30]);
var changeH = d3.scale.linear().domain([0, 13]).range([0, 18]);
var prctBar = d3.scale.linear().domain([0, 32]).range([0, 25]);

//create container elements
var svg = d3.select(".top25").append("svg")
            .attr("width", width + pad.left + pad.right)
            .attr("height", height + pad.top + pad.bottom);

//create header (background) tiles
var headerTiles = svg.append("g").attr("class", "headerTile").attr("transform", "translate(" + pad.left + ",0)");
var activeTile = headerTiles.append("rect").attr({x: xPrct-60, y: 7, width: 120, height: 43, class: "prct"}).style("fill", "#eee").on("click", rankPrct);
headerTiles.append("rect").attr({x: xChange-60, y: 7, width: 120, height: 43, fill: "white", class: "change"}).on("click", rankChange);
headerTiles.append("rect").attr({x: xNumF-45, y: 7, width: 90, height: 43, fill: "white", class: "numF"}).on("click", rankNumF);
headerTiles.append("rect").attr({x: xTotal-45, y: 7, width: 90, height: 43, fill: "white", class: "total"}).on("click", rankTotal);
headerTiles.selectAll("rect").style("cursor", "pointer");

//create header text
var header = svg.append("g").attr("class", "header").attr("transform", "translate(" + pad.left + "," + yHeader + ")");
header.append("text").text("Sci. Majors").attr("x", xPrct).on("click", rankPrct);
header.append("text").text("Researchers").attr("x", xChange).on("click", rankChange);
header.append("text").text("Explicit").attr("x", xNumF).on("click", rankNumF);
header.append("text").text("Implicit").attr("x", xTotal).on("click", rankTotal);
var subHead = svg.append("g").attr("class", "subHead").attr("transform", "translate(" + pad.left + "," + ySubHead + ")");
subHead.append("text").text("% Women").attr("x", xPrct).on("click", rankPrct);
subHead.append("text").text("% Women").attr("x", xChange).on("click", rankChange);
subHead.append("text").text("Stereotypes").attr("x", xNumF).on("click", rankNumF);
subHead.append("text").text("Stereotypes").attr("x", xTotal).on("click", rankTotal);
header.selectAll("text").style("cursor", "pointer");
subHead.selectAll("text").style("cursor", "pointer");
//event handlers for resorting the rows
function rankPrct() {
  activeTile.style("fill", "white");
  activeTile = d3.select(".headerTile .prct");
  activeTile.style("fill", "#eee");
  d3.selectAll("g.row")
    .transition().duration(800)
    .attr("transform", function(d) { return "translate(0," + vertSpace*(+d.rank - 0.5) + ")"; });
}
function rankChange() {
  activeTile.style("fill", "white");
  activeTile = d3.select(".headerTile .change");
  activeTile.style("fill", "#eee");
  d3.selectAll("g.row")
    .transition().duration(800)
    .attr("transform", function(d) { return "translate(0," + vertSpace*(+d.rankChange - 0.5) + ")"; });
}
function rankNumF() {
  activeTile.style("fill", "white");
  activeTile = d3.select(".headerTile .numF");
  activeTile.style("fill", "#eee");
  d3.selectAll("g.row")
    .transition().duration(800)
    .attr("transform", function(d) { return "translate(0," + vertSpace*(+d.rankNumF - 0.5) + ")"; });
}
function rankTotal() {
  activeTile.style("fill", "white");
  activeTile = d3.select(".headerTile .total");
  activeTile.style("fill", "#eee");
  d3.selectAll("g.row")
    .transition().duration(800)
    .attr("transform", function(d) { return "translate(0," + vertSpace*(+d.rankTotal - 0.5) + ")"; });
}

//create header line and content SVG group
svg.append("line").attr({ x1: 0, x2: width, y1: 2, y2: 2}).style({"stroke-width": 2, stroke: "#222"});
svg.append("line").attr({ x1: 0, x2: width, y1: pad.top-5, y2: pad.top-5}).style({"stroke-width": 2, stroke: "#222"});
var g = svg.append("g").attr("transform", "translate(" + pad.left + ", " + pad.top + ")");

//load data...
d3.csv("data/top25.csv", function(data) {

  ///////////////////////////////
  //  FIXED POSITION ELEMENTS  //
  ///////////////////////////////

  //add lines in between
  g.selectAll("line.sep").data(data).enter().append("line")
    .attr({ x1: -pad.left, x2: width-pad.left, class: "sep"})
    .attr("y1", function(d) { return vertSpace*d.rank; })
    .attr("y2", function(d) { return vertSpace*d.rank; })
    .style({"stroke-width": 0.5, stroke: "#888"});

  //ranking text
  g.selectAll("text.rank").data(data).enter().append("text")
    .attr("class", "rank")
    .text(function(d) { return d.rank + "."; })
    .attr("y", function(d) { return vertSpace*(d.rank - 0.5); })
    .attr("x", 5);

  /////////////////////////////////
  //  DYNAMIC POSITION ELEMENTS  //
  /////////////////////////////////

  //add grouping elements
  var rows = g.selectAll(".rows")
              .data(data).enter()
              .append("g")
              .attr("class", "row")
              .attr("transform", function(d) {
                return "translate(0," + vertSpace*(+d.rank - 0.5) + ")";
              });

  //for each school...
  rows.each(function(d) {

    //get a D3 selection of the g SVG element
    var s = d3.select(this);

    //school name
    s.append("text")
      .attr("class", "name")
      .text(function(d) { return d.abbrev; })
      .attr("x", xName);

    //percent women text
    s.append("text")
      .attr("class", "prct")
      .text(function(d) { return d.prctStr; })
      .attr("x", xPrct)
      .style("fill", "#333")
      .style("font-size", 25);

    //change percent text
    s.append("text")
      .attr("class", "change")
      .text(function(d) { return d.changeStr; })
      .attr("x", xChange)
      .style("font-size", 25);

    //number women text
    s.append("text")
      .attr("class", "numF")
      .text(function(d) { return d.numF; })
      .attr("x", xNumF)
      .style("font-size", 25);
      //.style("font-size", function(d) { return sizeNumF(d.numF); });

    //total number text
    s.append("text")
      .attr("class", "total")
      .text(function(d) { return d.total; })
      .attr("x", xTotal)
      .style("font-size", 25);
      //.style("font-size", function(d) { return sizeTotal(d.total); });

  });

});
<commit_msg>Update top25.js<commit_after>
//positioning settings
var width = 740;
var height = 3200;
var pad = { left: 10, right: 0, top: 60, bottom: 10 };
var vertSpace = 45;
var xName = 20;

var xPrct = 520;
var xChange = 640;
var xNumF = 260;
var xTotal = 380;

var rectW = 80;
var rectH = 35;
var yHeader = 20;
var ySubHead = 40;

//define scales
var sizeNumF = d3.scale.linear().domain([10, 100]).range([11, 30]);
var sizeTotal = d3.scale.linear().domain([50, 500]).range([11, 30]);
var changeH = d3.scale.linear().domain([0, 13]).range([0, 18]);
var prctBar = d3.scale.linear().domain([0, 32]).range([0, 25]);

//create container elements
var svg = d3.select(".top25").append("svg")
            .attr("width", width + pad.left + pad.right)
            .attr("height", height + pad.top + pad.bottom);

//create header (background) tiles
var headerTiles = svg.append("g").attr("class", "headerTile").attr("transform", "translate(" + pad.left + ",0)");
var activeTile = headerTiles.append("rect").attr({x: xNumF-45, y: 7, width: 90, height: 43, fill: "white", class: "numF"}).on("click", rankNumF);
headerTiles.append("rect").attr({x: xTotal-45, y: 7, width: 90, height: 43, fill: "white", class: "total"}).on("click", rankTotal);
headerTiles.append("rect").attr({x: xPrct-60, y: 7, height: 43, width: 120, class: "prct"}).style("fill", "#eee").on("click", rankPrct);
headerTiles.append("rect").attr({x: xChange-60, y: 7, width: 120, height: 43, fill: "white", class: "change"}).on("click", rankChange);
headerTiles.selectAll("rect").style("cursor", "pointer");

//create header text
var header = svg.append("g").attr("class", "header").attr("transform", "translate(" + pad.left + "," + yHeader + ")");
header.append("text").text("Sci. Majors").attr("x", xPrct).on("click", rankPrct);
header.append("text").text("Researchers").attr("x", xChange).on("click", rankChange);
header.append("text").text("Explicit").attr("x", xNumF).on("click", rankNumF);
header.append("text").text("Implicit").attr("x", xTotal).on("click", rankTotal);
var subHead = svg.append("g").attr("class", "subHead").attr("transform", "translate(" + pad.left + "," + ySubHead + ")");
subHead.append("text").text("% Women").attr("x", xPrct).on("click", rankPrct);
subHead.append("text").text("% Women").attr("x", xChange).on("click", rankChange);
subHead.append("text").text("Stereotypes").attr("x", xNumF).on("click", rankNumF);
subHead.append("text").text("Stereotypes").attr("x", xTotal).on("click", rankTotal);
header.selectAll("text").style("cursor", "pointer");
subHead.selectAll("text").style("cursor", "pointer");
//event handlers for resorting the rows
function rankPrct() {
  activeTile.style("fill", "white");
  activeTile = d3.select(".headerTile .prct");
  activeTile.style("fill", "#eee");
  d3.selectAll("g.row")
    .transition().duration(800)
    .attr("transform", function(d) { return "translate(0," + vertSpace*(+d.rank - 0.5) + ")"; });
}
function rankChange() {
  activeTile.style("fill", "white");
  activeTile = d3.select(".headerTile .change");
  activeTile.style("fill", "#eee");
  d3.selectAll("g.row")
    .transition().duration(800)
    .attr("transform", function(d) { return "translate(0," + vertSpace*(+d.rankChange - 0.5) + ")"; });
}
function rankNumF() {
  activeTile.style("fill", "white");
  activeTile = d3.select(".headerTile .numF");
  activeTile.style("fill", "#eee");
  d3.selectAll("g.row")
    .transition().duration(800)
    .attr("transform", function(d) { return "translate(0," + vertSpace*(+d.rankNumF - 0.5) + ")"; });
}
function rankTotal() {
  activeTile.style("fill", "white");
  activeTile = d3.select(".headerTile .total");
  activeTile.style("fill", "#eee");
  d3.selectAll("g.row")
    .transition().duration(800)
    .attr("transform", function(d) { return "translate(0," + vertSpace*(+d.rankTotal - 0.5) + ")"; });
}

//create header line and content SVG group
svg.append("line").attr({ x1: 0, x2: width, y1: 2, y2: 2}).style({"stroke-width": 2, stroke: "#222"});
svg.append("line").attr({ x1: 0, x2: width, y1: pad.top-5, y2: pad.top-5}).style({"stroke-width": 2, stroke: "#222"});
var g = svg.append("g").attr("transform", "translate(" + pad.left + ", " + pad.top + ")");

//load data...
d3.csv("data/top25.csv", function(data) {

  ///////////////////////////////
  //  FIXED POSITION ELEMENTS  //
  ///////////////////////////////

  //add lines in between
  g.selectAll("line.sep").data(data).enter().append("line")
    .attr({ x1: -pad.left, x2: width-pad.left, class: "sep"})
    .attr("y1", function(d) { return vertSpace*d.rank; })
    .attr("y2", function(d) { return vertSpace*d.rank; })
    .style({"stroke-width": 0.5, stroke: "#888"});

  //ranking text
  g.selectAll("text.rank").data(data).enter().append("text")
    .attr("class", "rank")
    .text(function(d) { return d.rank + "."; })
    .attr("y", function(d) { return vertSpace*(d.rank - 0.5); })
    .attr("x", 5);

  /////////////////////////////////
  //  DYNAMIC POSITION ELEMENTS  //
  /////////////////////////////////

  //add grouping elements
  var rows = g.selectAll(".rows")
              .data(data).enter()
              .append("g")
              .attr("class", "row")
              .attr("transform", function(d) {
                return "translate(0," + vertSpace*(+d.rank - 0.5) + ")";
              });

  //for each school...
  rows.each(function(d) {

    //get a D3 selection of the g SVG element
    var s = d3.select(this);

    //school name
    s.append("text")
      .attr("class", "name")
      .text(function(d) { return d.abbrev; })
      .attr("x", xName);

    //percent women text
    s.append("text")
      .attr("class", "prct")
      .text(function(d) { return d.prctStr; })
      .attr("x", xPrct)
      .style("fill", "#333")
      .style("font-size", 25);

    //change percent text
    s.append("text")
      .attr("class", "change")
      .text(function(d) { return d.changeStr; })
      .attr("x", xChange)
      .style("font-size", 25);

    //number women text
    s.append("text")
      .attr("class", "numF")
      .text(function(d) { return d.numF; })
      .attr("x", xNumF)
      .style("font-size", 25);
      //.style("font-size", function(d) { return sizeNumF(d.numF); });

    //total number text
    s.append("text")
      .attr("class", "total")
      .text(function(d) { return d.total; })
      .attr("x", xTotal)
      .style("font-size", 25);
      //.style("font-size", function(d) { return sizeTotal(d.total); });

  });

});
<|endoftext|>


<commit_before>module.exports = {

	//---------------------------------------------------------------------
	// Action Name
	//
	// This is the name of the action displayed in the editor.
	//---------------------------------------------------------------------

	name: "Store Game Server Info",

	//---------------------------------------------------------------------
	// Action Section
	//
	// This is the section the action will fall into.
	//---------------------------------------------------------------------

	section: "Other Stuff",

	//---------------------------------------------------------------------
	// Action Subtitle
	//
	// This function generates the subtitle displayed next to the name.
	//---------------------------------------------------------------------

	subtitle: function(data) {
		const info = ['Server Name', 'Map', 'Number of players', 'Max Players', 'Server Tags', 'Is server has password?'];
		return `${info[parseInt(data.info)]}`;
	},

	//---------------------------------------------------------------------
		 // DBM Mods Manager Variables (Optional but nice to have!)
		 //
		 // These are variables that DBM Mods Manager uses to show information
		 // about the mods for people to see in the list.
		 //---------------------------------------------------------------------

		 // Who made the mod (If not set, defaults to "DBM Mods")
		 author: "NetLuis",

		 // The version of the mod (Defaults to 1.0.0)
		 version: "1.9.1",

		 // A short description to show on the mod line for this mod (Must be on a single line)
		 short_description: "Stores Game Server Information.",

		 long_description: "Y",

		 // If it depends on any other mods by name, ex: WrexMODS if the mod uses something from WrexMods

		 //---------------------------------------------------------------------

	//---------------------------------------------------------------------
	// Action Storage Function
	//
	// Stores the relevant variable info for the editor.
	//---------------------------------------------------------------------

	variableStorage: function(data, varType) {
		const type = parseInt(data.storage);
		if(type !== varType) return;
		const info = parseInt(data.info);
		let dataType = 'Unknown Type';
		switch(info) {
			case 0:
				dataType = "Server Name";
				break;
			case 1:
				dataType = "Map";
				break;
			case 2:
				dataType = "Number";
				break;
			case 3:
				dataType = "Number";
				break;
			case 4:
				dataType = "Server Tags";
				break;
			case 5:
				dataType = "Boolean";
				break;
		}
		return ([data.varName, dataType]);
	},

	//---------------------------------------------------------------------
	// Action Fields
	//
	// These are the fields for the action. These fields are customized
	// by creating elements with corresponding IDs in the HTML. These
	// are also the names of the fields stored in the action's JSON data.
	//---------------------------------------------------------------------

	fields: ["serverip", "gametype", "info", "storage", "varName"],

	//---------------------------------------------------------------------
	// Command HTML
	//
	// This function returns a string containing the HTML used for
	// editting actions.
	//
	// The "isEvent" parameter will be true if this action is being used
	// for an event. Due to their nature, events lack certain information,
	// so edit the HTML to reflect this.
	//
	// The "data" parameter stores constants for select elements to use.
	// Each is an array: index 0 for commands, index 1 for events.
	// The names are: sendTargets, members, roles, channels,
	//                messages, servers, variables
	//---------------------------------------------------------------------

	html: function(isEvent, data) {
		return `

            <embedleftline style="background-color: #2b9696;"></embedleftline>

	    Mod Info:
Made by ${this.author}

	    ${this.short_description}
Version: ${this.version}

		Server IP:Port or Domain:

		<textarea id="serverip" rows="2" placeholder="csgo.example.com" style="width: 95%; font-family: monospace; white-space: nowrap; resize: none;"></textarea>

	 	Game Type:

	 	<textarea id="gametype" rows="2" placeholder="Write Game Type. You can find Game Type of your game below." style="width: 95%; font-family: monospace; white-space: nowrap; resize: none;"></textarea>

		Source Info:

		<select id="info" class="round">
			<option value="0" selected>Server Name</option>
			<option value="1">Map</option>
			<option value="2">Number of players in the server</option>
			<option value="3">Max Players</option>
			<option value="4">Server Tags</option>
			<option value="5">Is server has password?</option>
				</select>

			Store In:

			<select id="storage" class="round" onchange="glob.variableChange(this, 'varNameContainer')">
				${data.variables[1]}
			</select>

			Variable Name:

			<input id="varName" class="round" type="text">

			You can see supported games from here.
Also you can see what you need to write to "Game Type" by clicking here.

        `
	},

	//---------------------------------------------------------------------
	// Action Editor Init Code
	//
	// When the HTML is first applied to the action editor, this code
	// is also run. This helps add modifications or setup reactionary
	// functions for the DOM elements.
	//---------------------------------------------------------------------

	init: function() {
		const {glob, document} = this;

		glob.variableChange(document.getElementById('storage'), 'varNameContainer');
	},

	//---------------------------------------------------------------------
	// Action Bot Function
	//
	// This is the function for the action within the Bot's Action class.
	// Keep in mind event calls won't have access to the "msg" parameter,
	// so be sure to provide checks for variable existance.
	//---------------------------------------------------------------------

	action: function(cache) {
		const _this = this // To fix error
        const data = cache.actions[cache.index];
		const info = parseInt(data.info);
		const gametype = _this.evalMessage(data.gametype, cache);
		const host = _this.evalMessage(data.serverip, cache)

        // Main code:
		const WrexMODS = _this.getWrexMods(); // as always.
		WrexMODS.CheckAndInstallNodeModule('game-server-query');
		const query = WrexMODS.require('game-server-query');

		query (
            {
            type: `${gametype}`,
            host: `${host}`
            },
            function(state) {
                if(state.error){
              console.log("[Store Game Server Info Mod] Server is offline.");
            }
                else {
                    switch (info) {
                        case 0:
                            result = state.name;
                            break;
                        case 1:
                            result = state.map;
                            break;
                        case 2:
                            result = state.raw.numplayers;
                            break;
                        case 3:
                            result = state.maxplayers;
                            break;
                        case 4:
                            result = state.raw.tags;
                            break;
                        case 5:
                            result = state.password
                            break;
                        default:
                            break;
                    }

            if (result !== undefined) {
				const storage = parseInt(data.storage);
				const varName2 = _this.evalMessage(data.varName, cache);
				_this.storeValue(result, storage, varName2, cache);
				_this.callNextAction(cache);
			} else {
				_this.callNextAction(cache);
			}
		}
		}
        )
	},
	//---------------------------------------------------------------------
	// Action Bot Mod
	//
	// Upon initialization of the bot, this code is run. Using the bot's
	// DBM namespace, one can add/modify existing functions if necessary.
	// In order to reduce conflictions between mods, be sure to alias
	// functions you wish to overwrite.
	//---------------------------------------------------------------------

	mod: function(DBM) {}

	}; // End of module
<commit_msg>Update game_server_MOD.js<commit_after>module.exports = {

	//---------------------------------------------------------------------
	// Action Name
	//
	// This is the name of the action displayed in the editor.
	//---------------------------------------------------------------------

	name: "Store Game Server Info",

	//---------------------------------------------------------------------
	// Action Section
	//
	// This is the section the action will fall into.
	//---------------------------------------------------------------------

	section: "Other Stuff",

	//---------------------------------------------------------------------
	// Action Subtitle
	//
	// This function generates the subtitle displayed next to the name.
	//---------------------------------------------------------------------

	subtitle: function(data) {
		const info = ['Server Name', 'Map', 'Number of players', 'Max Players', 'Server Tags', 'Is server has password?'];
		return `${info[parseInt(data.info)]}`;
	},

	//---------------------------------------------------------------------
		 // DBM Mods Manager Variables (Optional but nice to have!)
		 //
		 // These are variables that DBM Mods Manager uses to show information
		 // about the mods for people to see in the list.
		 //---------------------------------------------------------------------

		 // Who made the mod (If not set, defaults to "DBM Mods")
		 author: "NetLuis",

		 // The version of the mod (Defaults to 1.0.0)
		 version: "1.9.1", //Added in 1.9.1

		 // A short description to show on the mod line for this mod (Must be on a single line)
		 short_description: "Stores Game Server Information.",

		 long_description: "Y",

		 // If it depends on any other mods by name, ex: WrexMODS if the mod uses something from WrexMods

		 //---------------------------------------------------------------------

	//---------------------------------------------------------------------
	// Action Storage Function
	//
	// Stores the relevant variable info for the editor.
	//---------------------------------------------------------------------

	variableStorage: function(data, varType) {
		const type = parseInt(data.storage);
		if(type !== varType) return;
		const info = parseInt(data.info);
		let dataType = 'Unknown Type';
		switch(info) {
			case 0:
				dataType = "Server Name";
				break;
			case 1:
				dataType = "Map";
				break;
			case 2:
				dataType = "Number";
				break;
			case 3:
				dataType = "Number";
				break;
			case 4:
				dataType = "Server Tags";
				break;
			case 5:
				dataType = "Boolean";
				break;
		}
		return ([data.varName, dataType]);
	},

	//---------------------------------------------------------------------
	// Action Fields
	//
	// These are the fields for the action. These fields are customized
	// by creating elements with corresponding IDs in the HTML. These
	// are also the names of the fields stored in the action's JSON data.
	//---------------------------------------------------------------------

	fields: ["serverip", "gametype", "info", "storage", "varName"],

	//---------------------------------------------------------------------
	// Command HTML
	//
	// This function returns a string containing the HTML used for
	// editting actions.
	//
	// The "isEvent" parameter will be true if this action is being used
	// for an event. Due to their nature, events lack certain information,
	// so edit the HTML to reflect this.
	//
	// The "data" parameter stores constants for select elements to use.
	// Each is an array: index 0 for commands, index 1 for events.
	// The names are: sendTargets, members, roles, channels,
	//                messages, servers, variables
	//---------------------------------------------------------------------

	html: function(isEvent, data) {
		return `

            <embedleftline style="background-color: #2b9696;"></embedleftline>

	    Mod Info:
Made by ${this.author}

	    ${this.short_description}
Version: ${this.version}

		Server IP:Port or Domain:

		<textarea id="serverip" rows="2" placeholder="csgo.example.com" style="width: 95%; font-family: monospace; white-space: nowrap; resize: none;"></textarea>

	 	Game Type:

	 	<textarea id="gametype" rows="2" placeholder="Write Game Type. You can find Game Type of your game below." style="width: 95%; font-family: monospace; white-space: nowrap; resize: none;"></textarea>

		Source Info:

		<select id="info" class="round">
			<option value="0" selected>Server Name</option>
			<option value="1">Map</option>
			<option value="2">Number of players in the server</option>
			<option value="3">Max Players</option>
			<option value="4">Server Tags</option>
			<option value="5">Is server has password?</option>
				</select>

			Store In:

			<select id="storage" class="round" onchange="glob.variableChange(this, 'varNameContainer')">
				${data.variables[1]}
			</select>

			Variable Name:

			<input id="varName" class="round" type="text">

			You can see supported games from here.
Also you can see what you need to write to "Game Type" by clicking here.

        `
	},

	//---------------------------------------------------------------------
	// Action Editor Init Code
	//
	// When the HTML is first applied to the action editor, this code
	// is also run. This helps add modifications or setup reactionary
	// functions for the DOM elements.
	//---------------------------------------------------------------------

	init: function() {
		const {glob, document} = this;

		glob.variableChange(document.getElementById('storage'), 'varNameContainer');
	},

	//---------------------------------------------------------------------
	// Action Bot Function
	//
	// This is the function for the action within the Bot's Action class.
	// Keep in mind event calls won't have access to the "msg" parameter,
	// so be sure to provide checks for variable existance.
	//---------------------------------------------------------------------

	action: function(cache) {
		const _this = this // To fix error
        const data = cache.actions[cache.index];
		const info = parseInt(data.info);
		const gametype = _this.evalMessage(data.gametype, cache);
		const host = _this.evalMessage(data.serverip, cache)

        // Main code:
		const WrexMODS = _this.getWrexMods(); // as always.
		WrexMODS.CheckAndInstallNodeModule('game-server-query');
		const query = WrexMODS.require('game-server-query');

		query (
            {
            type: `${gametype}`,
            host: `${host}`
            },
            function(state) {
                if(state.error){
              console.log("[Store Game Server Info Mod] Server is offline.");
            }
                else {
                    switch (info) {
                        case 0:
                            result = state.name;
                            break;
                        case 1:
                            result = state.map;
                            break;
                        case 2:
                            result = state.raw.numplayers;
                            break;
                        case 3:
                            result = state.maxplayers;
                            break;
                        case 4:
                            result = state.raw.tags;
                            break;
                        case 5:
                            result = state.password
                            break;
                        default:
                            break;
                    }

            if (result !== undefined) {
				const storage = parseInt(data.storage);
				const varName2 = _this.evalMessage(data.varName, cache);
				_this.storeValue(result, storage, varName2, cache);
				_this.callNextAction(cache);
			} else {
				_this.callNextAction(cache);
			}
		}
		}
        )
	},
	//---------------------------------------------------------------------
	// Action Bot Mod
	//
	// Upon initialization of the bot, this code is run. Using the bot's
	// DBM namespace, one can add/modify existing functions if necessary.
	// In order to reduce conflictions between mods, be sure to alias
	// functions you wish to overwrite.
	//---------------------------------------------------------------------

	mod: function(DBM) {}

	}; // End of module
<|endoftext|>


<commit_before>var capture = function(){
    var replace_all = function(str, find, replace) { return str.replace(new RegExp(find, 'g'), replace); };
    var esc = function (text) { return replace_all(replace_all(replace_all(encodeURIComponent(text),"[(]",escape("(")),"[)]",escape(")")),"[']",escape("'")); };
    var selection = window.getSelection().toString();

    var uri = 'org-protocol://';
    if (selection != "")
    {
	uri += 'capture:/p/';
    }
    else
    {
	uri += 'capture:/L/'
    };

    uri += encodeURIComponent(location.href) + '/' +
	encodeURIComponent(document.title) ;

    if (selection != "") { uri += '/' + esc(selection); };

    console.log("Capturing the following URI with org-protocol:", uri);

    location.href=uri;
};

capture();
<commit_msg>Escape special characters in page title<commit_after>var capture = function(){
    var replace_all = function(str, find, replace) { return str.replace(new RegExp(find, 'g'), replace); };
    var esc = function (text) { return replace_all(replace_all(replace_all(encodeURIComponent(text),"[(]",escape("(")),"[)]",escape(")")),"[']",escape("'")); };
    var selection = window.getSelection().toString();

    var uri = 'org-protocol://';
    if (selection != "")
    {
	uri += 'capture:/p/';
    }
    else
    {
	uri += 'capture:/L/'
    };

    uri += encodeURIComponent(location.href) + '/' +
	esc(document.title) ;

    if (selection != "") { uri += '/' + esc(selection); };

    console.log("Capturing the following URI with org-protocol:", uri);

    location.href=uri;
};

capture();
<|endoftext|>


<commit_before>/*
 ---

 name: Parametrics

 script: Parametrics.js

 description: MUI - Initializes the GUI Parametrics property sliders.

 copyright: (c) 2010 Contributors in (/AUTHORS.txt).

 license: MIT-style license in (/MIT-LICENSE.txt).

 note:
 This documentation is taken directly from the javascript source files. It is built using Natural Docs.

 requires:
 - Core/Element
 - Core/Class
 - Core/Options
 - Core/Events
 - MUI
 - MUI.Core

 provides: [MUI.Parametrics]

 ...
 */

MUI.append({

	addRadiusSlider: function(){
		if ($('radiusSliderarea')){
			var windowOptions = MUI.Windows.options;
			var sliderFirst = true;
			var mochaSlide = new Slider('radiusSliderarea', 'radiusSliderknob', {
				steps: 14,
				offset: 0,
				onChange: function(pos){
					$('radiusUpdatevalue').set('html', pos);
					// Change default corner radius of the original class
					windowOptions.cornerRadius = pos;
					MUI.Window.implement({ options: windowOptions });
					// Don't redraw windows the first time the slider is initialized
					if (sliderFirst){
						sliderFirst = false;
						return;
					}
					// Change corner radius of all active classes and their windows
					MUI.each(function(instance){
						if (instance.className != 'MUI.Window') return;
						instance.options.cornerRadius = pos;
						instance.redraw();
					}.bind(this));
				}.bind(this)
			}).set(windowOptions.cornerRadius);
		}
	},

	addShadowSlider: function(){
		if ($('shadowSliderarea')){
			var windowOptions = MUI.Windows.options;
			var sliderFirst = true;
			var mochaSlide = new Slider('shadowSliderarea', 'shadowSliderknob', {
				range: [1, 10],
				offset: 0,
				onChange: function(pos){
					$('shadowUpdatevalue').set('html', pos);
					// Change default shadow width of the original class
					windowOptions.shadowBlur = pos;
					MUI.Window.implement({ options: windowOptions });
					// Don't redraw windows the first time the slider is initialized
					if (sliderFirst){
						sliderFirst = false;
						return;
					}
					// Change shadow width of all active classes and their windows
					MUI.each(function(instance){
						if (instance.className != 'MUI.Window') return;
						var oldShadowBlur = instance.options.shadowBlur;
						instance.options.shadowBlur = pos;

						if (!instance.useCSS3){
							instance.el.windowEl.setStyles({
								'top': instance.el.windowEl.getStyle('top').toInt() - (instance.options.shadowBlur - oldShadowBlur),
								'left': instance.el.windowEl.getStyle('left').toInt() - (instance.options.shadowBlur - oldShadowBlur)
							});
						}

						instance.redraw();
					}.bind(this));
				}.bind(this),
				onComplete: function(){
					MUI.each(function(instance){
						if (instance.className != 'MUI.Window') return;
						if (instance.options.resizable){
							instance._adjustHandles();
						}
					});
				}
			}).set(windowOptions.shadowBlur);
		}
	},

	addOffsetXSlider: function(){
		if ($('offsetXSliderarea')){
			var windowOptions = MUI.Windows.options;
			var sliderFirst = true;
			var mochaSlide = new Slider('offsetXSliderarea', 'offsetXSliderknob', {
				range: [-5, 5],
				offset: 0,
				initialStep: 0,
				onChange: function(pos){
				console.log(pos);
					$('offsetXUpdatevalue').set('text', pos);
					windowOptions.shadowOffset.x = pos;
					MUI.Window.implement({ options: windowOptions });
					// Don't redraw windows the first time the slider is initialized
					if (sliderFirst){
						sliderFirst = false;
						return;
					}
					// Change shadow position of all active classes and their windows
					MUI.each(function(instance){
						if (instance.className != 'MUI.Window') return;
						var oldOffsetX = instance.options.shadowOffset.x;
						instance.options.shadowOffset.x = pos;
						if (!instance.useCSS3) instance.el.windowEl.setStyle('left', instance.el.windowEl.getStyle('left').toInt() - (oldOffsetX - pos));
						instance.redraw();
					}.bind(this));
				}.bind(this),
				onComplete: function(){
					MUI.each(function(instance){
						if (instance.className != 'MUI.Window') return;
						if (instance.options.resizable){
							instance._adjustHandles();
						}
					});
				}
			}).set(windowOptions.shadowOffset.x);
		}
	},

	addOffsetYSlider: function(){
		if ($('offsetYSliderarea')){
			var windowOptions = MUI.Windows.options;
			var sliderFirst = true;
			var mochaSlide = new Slider('offsetYSliderarea', 'offsetYSliderknob', {
				range: [-5, 5],
				offset: 0,
				onChange: function(pos){
					$('offsetYUpdatevalue').set('text', pos);
					windowOptions.shadowOffset.y = pos;
					MUI.Window.implement({ options: windowOptions });
					// Don't redraw windows the first time the slider is initialized
					if (sliderFirst){
						sliderFirst = false;
						return;
					}
					// Change shadow position of all active classes and their windows
					MUI.each(function(instance){
						if (instance.className != 'MUI.Window') return;
						var oldOffsetY = instance.options.shadowOffset.y;
						instance.options.shadowOffset.y = pos;
						if (!instance.useCSS3) instance.el.windowEl.setStyle('top', instance.el.windowEl.getStyle('top').toInt() - (oldOffsetY - pos));
						instance.redraw();
					}.bind(this));
				}.bind(this),
				onComplete: function(){
					MUI.each(function(instance){
						if (instance.className != 'MUI.Window') return;
						if (instance.options.resizable){
							instance._adjustHandles();
						}
					});
				}
			}).set(windowOptions.shadowOffset.y);
		}
	}

});
<commit_msg>forgot to remove console.log<commit_after>/*
 ---

 name: Parametrics

 script: Parametrics.js

 description: MUI - Initializes the GUI Parametrics property sliders.

 copyright: (c) 2010 Contributors in (/AUTHORS.txt).

 license: MIT-style license in (/MIT-LICENSE.txt).

 note:
 This documentation is taken directly from the javascript source files. It is built using Natural Docs.

 requires:
 - Core/Element
 - Core/Class
 - Core/Options
 - Core/Events
 - MUI
 - MUI.Core

 provides: [MUI.Parametrics]

 ...
 */

MUI.append({

	addRadiusSlider: function(){
		if ($('radiusSliderarea')){
			var windowOptions = MUI.Windows.options;
			var sliderFirst = true;
			var mochaSlide = new Slider('radiusSliderarea', 'radiusSliderknob', {
				steps: 14,
				offset: 0,
				onChange: function(pos){
					$('radiusUpdatevalue').set('html', pos);
					// Change default corner radius of the original class
					windowOptions.cornerRadius = pos;
					MUI.Window.implement({ options: windowOptions });
					// Don't redraw windows the first time the slider is initialized
					if (sliderFirst){
						sliderFirst = false;
						return;
					}
					// Change corner radius of all active classes and their windows
					MUI.each(function(instance){
						if (instance.className != 'MUI.Window') return;
						instance.options.cornerRadius = pos;
						instance.redraw();
					}.bind(this));
				}.bind(this)
			}).set(windowOptions.cornerRadius);
		}
	},

	addShadowSlider: function(){
		if ($('shadowSliderarea')){
			var windowOptions = MUI.Windows.options;
			var sliderFirst = true;
			var mochaSlide = new Slider('shadowSliderarea', 'shadowSliderknob', {
				range: [1, 10],
				offset: 0,
				onChange: function(pos){
					$('shadowUpdatevalue').set('html', pos);
					// Change default shadow width of the original class
					windowOptions.shadowBlur = pos;
					MUI.Window.implement({ options: windowOptions });
					// Don't redraw windows the first time the slider is initialized
					if (sliderFirst){
						sliderFirst = false;
						return;
					}
					// Change shadow width of all active classes and their windows
					MUI.each(function(instance){
						if (instance.className != 'MUI.Window') return;
						var oldShadowBlur = instance.options.shadowBlur;
						instance.options.shadowBlur = pos;

						if (!instance.useCSS3){
							instance.el.windowEl.setStyles({
								'top': instance.el.windowEl.getStyle('top').toInt() - (instance.options.shadowBlur - oldShadowBlur),
								'left': instance.el.windowEl.getStyle('left').toInt() - (instance.options.shadowBlur - oldShadowBlur)
							});
						}

						instance.redraw();
					}.bind(this));
				}.bind(this),
				onComplete: function(){
					MUI.each(function(instance){
						if (instance.className != 'MUI.Window') return;
						if (instance.options.resizable){
							instance._adjustHandles();
						}
					});
				}
			}).set(windowOptions.shadowBlur);
		}
	},

	addOffsetXSlider: function(){
		if ($('offsetXSliderarea')){
			var windowOptions = MUI.Windows.options;
			var sliderFirst = true;
			var mochaSlide = new Slider('offsetXSliderarea', 'offsetXSliderknob', {
				range: [-5, 5],
				offset: 0,
				initialStep: 0,
				onChange: function(pos){
					$('offsetXUpdatevalue').set('text', pos);
					windowOptions.shadowOffset.x = pos;
					MUI.Window.implement({ options: windowOptions });
					// Don't redraw windows the first time the slider is initialized
					if (sliderFirst){
						sliderFirst = false;
						return;
					}
					// Change shadow position of all active classes and their windows
					MUI.each(function(instance){
						if (instance.className != 'MUI.Window') return;
						var oldOffsetX = instance.options.shadowOffset.x;
						instance.options.shadowOffset.x = pos;
						if (!instance.useCSS3) instance.el.windowEl.setStyle('left', instance.el.windowEl.getStyle('left').toInt() - (oldOffsetX - pos));
						instance.redraw();
					}.bind(this));
				}.bind(this),
				onComplete: function(){
					MUI.each(function(instance){
						if (instance.className != 'MUI.Window') return;
						if (instance.options.resizable){
							instance._adjustHandles();
						}
					});
				}
			}).set(windowOptions.shadowOffset.x);
		}
	},

	addOffsetYSlider: function(){
		if ($('offsetYSliderarea')){
			var windowOptions = MUI.Windows.options;
			var sliderFirst = true;
			var mochaSlide = new Slider('offsetYSliderarea', 'offsetYSliderknob', {
				range: [-5, 5],
				offset: 0,
				onChange: function(pos){
					$('offsetYUpdatevalue').set('text', pos);
					windowOptions.shadowOffset.y = pos;
					MUI.Window.implement({ options: windowOptions });
					// Don't redraw windows the first time the slider is initialized
					if (sliderFirst){
						sliderFirst = false;
						return;
					}
					// Change shadow position of all active classes and their windows
					MUI.each(function(instance){
						if (instance.className != 'MUI.Window') return;
						var oldOffsetY = instance.options.shadowOffset.y;
						instance.options.shadowOffset.y = pos;
						if (!instance.useCSS3) instance.el.windowEl.setStyle('top', instance.el.windowEl.getStyle('top').toInt() - (oldOffsetY - pos));
						instance.redraw();
					}.bind(this));
				}.bind(this),
				onComplete: function(){
					MUI.each(function(instance){
						if (instance.className != 'MUI.Window') return;
						if (instance.options.resizable){
							instance._adjustHandles();
						}
					});
				}
			}).set(windowOptions.shadowOffset.y);
		}
	}

});
<|endoftext|>


<commit_before>// Copyright (c) 2012 Jonathan Penn (http://cocoamanifest.net/)

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

var kPortraitString = "portrait"
var kLandscapeString = "landscape"

var kMaxDimension4inch = 568;
var kMaxDimension4point7inch = 667;
var kMaxDimension5point5inch = 736;

// rectMaxSizeMatchesPhoneWithMaxDimensionForOrientation(rect, maxDimension, orientation)
//
// Returns whether the given rect matches a given max dimension in a particular orientation.
//
// `rect` is the rectangle representing the image size you want to check
// `maxDimension` is the size of the longest side of the screen on a given device
// `orientation` is...well...duh!
//
function rectMaxSizeMatchesPhoneWithMaxDimensionForOrientation(rect, maxDimension, orientation) {
  return (orientation == kPortraitString && rect.size.height == maxDimension) || (orientation == kLandscapeString && rect.size.width == maxDimension)
}

// captureLocalizedScreenshot(name)
//
// Tells the local target to take a screen shot and names the file after the
// state of the simulator like so:
//
//   [model]___[orientation]___[name].png
//
// `model` is the model of the device (iphone, iphone5, ipad)
// `orientation` is...well...duh!
// `name` is what you passed in to the function
//
// Screenshots are saved along with the trace results in UI Automation. See
// `run_screenshooter.sh` for examples on how to pull those images out and put
// them wherever you want.
//
function captureLocalizedScreenshot(name) {
  var target = UIATarget.localTarget();
  var model = target.model();
  var rect = target.rect();

  var orientation = kPortraitString;
  if (rect.size.height < rect.size.width) {
    orientation = kLandscapeString;
  }

  if (model.match(/iPhone/)) {
    if (rectMaxSizeMatchesPhoneWithMaxDimensionForOrientation(rect, kMaxDimension4inch, orientation)) {
      model = "iOS-4-in";
    }
    else if (rectMaxSizeMatchesPhoneWithMaxDimensionForOrientation(rect, kMaxDimension4point7inch, orientation)) {
      model = "iOS-4.7-in";
    }
    else if (rectMaxSizeMatchesPhoneWithMaxDimensionForOrientation(rect, kMaxDimension5point5inch, orientation)) {
      model = "iOS-5.5-in";
    }
    else {
      model = "iOS-3.5-in";
    }
  } else {
    model = "iOS-iPad";
  }

  var parts = [model, orientation, name];
  target.captureScreenWithName(parts.join("___"));
}
<commit_msg>Update for iPad Pro<commit_after>// Copyright (c) 2012 Jonathan Penn (http://cocoamanifest.net/)

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

var kPortraitString = "portrait"
var kLandscapeString = "landscape"

var kMaxDimension4inch = 568;
var kMaxDimension4point7inch = 667;
var kMaxDimension5point5inch = 736;
var kMaxDimensioniPadPro = 1366;

// rectMaxSizeMatchesPhoneWithMaxDimensionForOrientation(rect, maxDimension, orientation)
//
// Returns whether the given rect matches a given max dimension in a particular orientation.
//
// `rect` is the rectangle representing the image size you want to check
// `maxDimension` is the size of the longest side of the screen on a given device
// `orientation` is...well...duh!
//
function rectMaxSizeMatchesPhoneWithMaxDimensionForOrientation(rect, maxDimension, orientation) {
  return (orientation == kPortraitString && rect.size.height == maxDimension) || (orientation == kLandscapeString && rect.size.width == maxDimension)
}

// captureLocalizedScreenshot(name)
//
// Tells the local target to take a screen shot and names the file after the
// state of the simulator like so:
//
//   [model]___[orientation]___[name].png
//
// `model` is the model of the device (iphone, iphone5, ipad)
// `orientation` is...well...duh!
// `name` is what you passed in to the function
//
// Screenshots are saved along with the trace results in UI Automation. See
// `run_screenshooter.sh` for examples on how to pull those images out and put
// them wherever you want.
//
function captureLocalizedScreenshot(name) {
  var target = UIATarget.localTarget();
  var model = target.model();
  var rect = target.rect();

  var orientation = kPortraitString;
  if (rect.size.height < rect.size.width) {
    orientation = kLandscapeString;
  }

  if (model.match(/iPhone/)) {
    if (rectMaxSizeMatchesPhoneWithMaxDimensionForOrientation(rect, kMaxDimension4inch, orientation)) {
      model = "iOS-4-in";
    }
    else if (rectMaxSizeMatchesPhoneWithMaxDimensionForOrientation(rect, kMaxDimension4point7inch, orientation)) {
      model = "iOS-4.7-in";
    }
    else if (rectMaxSizeMatchesPhoneWithMaxDimensionForOrientation(rect, kMaxDimension5point5inch, orientation)) {
      model = "iOS-5.5-in";
    }
    else {
      model = "iOS-3.5-in";
    }
  } else {
    if (rectMaxSizeMatchesPhoneWithMaxDimensionForOrientation(rect, kMaxDimensioniPadPro, orientation)) {
      model = "iOS-iPad-Pro";
    } else {
      model = "iOS-iPad";
    }
  }

  var parts = [model, orientation, name];
  target.captureScreenWithName(parts.join("___"));
}
<|endoftext|>


<commit_before>var page = require('webpage').create(),
    async = require('./async.js'),
    downloadLink;

function errorFn(msg, trace) {
  // Log the error and trace
  console.log('wat');
  // trace.forEach(function(item) {
  //     console.error('  ', item.file, ':', item.line);
  // });

  // Leave with a bad exit code
  phantom.exit(1);
}
phantom.onError = errorFn;
page.onError = errorFn;

// Run a check function every 100 ms
function waitFor(checkFn, cb) {
  throw new Error('hai');
  if (checkFn()) {
    cb();
  } else {
    setTimeout(function waitForFn () {
      waitFor(checkFn, cb);
    }, 100);
  }
}

function openIcoMoon(cb) {
  // Open IcoMoon
  page.open('http://icomoon.io/app-old', function (status) {
    // If the status was 'fail', callback with an error
    var err = null;
    if (status === 'fail') {
      err = new Error('IcoMoon app "http://icomoon.io/app-old" could not be opened.');
    }
    cb(err);
  });
}
function waitForLoading(cb) {
  // Wait for loading to complete
  waitFor(function () {
    return page.evaluate(function () {
      return !document.getElementById('loading');
    });
  }, cb);
}

// In series
async.series([
  // On first open, cache bust
  openIcoMoon,
  waitForLoading,
  function clearCache (cb) {
    // Clear out indexedDB and localStorage
    page.evaluate(function () {
      if (window.indexedDB) {
        indexedDB.deleteDatabase('IDBWrapper-storage');
      }

      if (window.localStorage) {
        localStorage.clear();
      }
    });

    // Callback
    cb();
  },
  // Re-open page with busted cache
  openIcoMoon,
  waitForLoading,
  function uploadImages (cb) {
    // Submit many images (need a file path for all our images)
    var fs = require('fs'),
        filesPath = phantom.args[0],
        filesJSON = fs.read(filesPath),
        files = JSON.parse(filesJSON);
    page.uploadFile('#files', files);

    // Continue
    waitFor(function () {
      var itemsCreated = page.evaluate(function () {
        return $('#imported').find('.checkbox-icon').length;
      });
      return itemsCreated === files.length;
    }, cb);
  },
  function moveToDownloadScreen (cb) {
    // Move to the downlod screen
    page.evaluate(function () {
      // Select our images
      $('#imported').find('.checkbox-icon').click();

      // "Click" the 'Next' link
      window.location.hash = 'font';
    });

    // Wait for the next screen to load
    waitFor(function () {
      return page.evaluate(function () {
        return $('#saveFont').length;
      });
    }, cb);
  },
  function exportFont (cb) {
    // Save any zip redirect requests
    page.onNavigationRequested = function (url) {
      if (url.indexOf('.zip') > -1) {
        downloadLink = url;
      }
    };

    // Click the download link
    page.evaluate(function () {
      $('#saveFont').click();
    });

    // Wait for the redirect request to our zip
    waitFor(function () {
      return downloadLink;
    }, cb);
  }
], function output (err) {
  // // DEV: Take a screenshot for progress
  // page.render('app.png');

  // If there was an error, log it
  if (err) {
    console.error(err);
    phantom.exit(1);
  } else {
  // Otherwise, output the download link for the next module
    console.log(downloadLink);
    phantom.exit(0);
  }
});
<commit_msg>stderr is logging properly<commit_after>var page = require('webpage').create(),
    async = require('./async.js'),
    downloadLink;

function errorFn(msg, trace) {
  // Log the error and trace
  var system = require('system');
  system.stderr.write('What\'s up?');
  // trace.forEach(function(item) {
  //     console.error('  ', item.file, ':', item.line);
  // });

  // Leave with a bad exit code
  phantom.exit(1);
}
phantom.onError = errorFn;
page.onError = errorFn;

// Run a check function every 100 ms
function waitFor(checkFn, cb) {
  throw new Error('hai');
  if (checkFn()) {
    cb();
  } else {
    setTimeout(function waitForFn () {
      waitFor(checkFn, cb);
    }, 100);
  }
}

function openIcoMoon(cb) {
  // Open IcoMoon
  page.open('http://icomoon.io/app-old', function (status) {
    // If the status was 'fail', callback with an error
    var err = null;
    if (status === 'fail') {
      err = new Error('IcoMoon app "http://icomoon.io/app-old" could not be opened.');
    }
    cb(err);
  });
}
function waitForLoading(cb) {
  // Wait for loading to complete
  waitFor(function () {
    return page.evaluate(function () {
      return !document.getElementById('loading');
    });
  }, cb);
}

// In series
async.series([
  // On first open, cache bust
  openIcoMoon,
  waitForLoading,
  function clearCache (cb) {
    // Clear out indexedDB and localStorage
    page.evaluate(function () {
      if (window.indexedDB) {
        indexedDB.deleteDatabase('IDBWrapper-storage');
      }

      if (window.localStorage) {
        localStorage.clear();
      }
    });

    // Callback
    cb();
  },
  // Re-open page with busted cache
  openIcoMoon,
  waitForLoading,
  function uploadImages (cb) {
    // Submit many images (need a file path for all our images)
    var fs = require('fs'),
        filesPath = phantom.args[0],
        filesJSON = fs.read(filesPath),
        files = JSON.parse(filesJSON);
    page.uploadFile('#files', files);

    // Continue
    waitFor(function () {
      var itemsCreated = page.evaluate(function () {
        return $('#imported').find('.checkbox-icon').length;
      });
      return itemsCreated === files.length;
    }, cb);
  },
  function moveToDownloadScreen (cb) {
    // Move to the downlod screen
    page.evaluate(function () {
      // Select our images
      $('#imported').find('.checkbox-icon').click();

      // "Click" the 'Next' link
      window.location.hash = 'font';
    });

    // Wait for the next screen to load
    waitFor(function () {
      return page.evaluate(function () {
        return $('#saveFont').length;
      });
    }, cb);
  },
  function exportFont (cb) {
    // Save any zip redirect requests
    page.onNavigationRequested = function (url) {
      if (url.indexOf('.zip') > -1) {
        downloadLink = url;
      }
    };

    // Click the download link
    page.evaluate(function () {
      $('#saveFont').click();
    });

    // Wait for the redirect request to our zip
    waitFor(function () {
      return downloadLink;
    }, cb);
  }
], function output (err) {
  // // DEV: Take a screenshot for progress
  // page.render('app.png');

  // If there was an error, log it
  if (err) {
    console.error(err);
    phantom.exit(1);
  } else {
  // Otherwise, output the download link for the next module
    console.log(downloadLink);
    phantom.exit(0);
  }
});
<|endoftext|>


<commit_before>// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt

frappe.ui.form.NewTimeline = class {
	constructor(opts) {
		Object.assign(this, opts);
		this.doc_info = this.frm && this.frm.get_docinfo() || {};
		this.make();
	}

	make() {
		this.timeline_wrapper = $(`<div class="new-timeline">`);
		this.parent.replaceWith(this.timeline_wrapper);
		this.timeline_items = [];
		this.render_timeline_items();
	}

	refresh() {

	}

	add_action_button() {

	}

	render_timeline_items() {
		this.prepare_timeline_contents();

		this.timeline_items.sort((item1, item2) => new Date(item2.creation) - new Date(item1.creation));
		this.timeline_items.forEach(item => {
			this.timeline_wrapper.append(this.get_timeline_item(item));
		});
	}

	prepare_timeline_contents() {
		this.timeline_items.push(...this.get_view_timeline_contents());
		this.timeline_items.push(...this.get_communication_timeline_contents());
		this.timeline_items.push(...this.get_comment_timeline_contents());
		this.timeline_items.push(...this.get_energy_point_timeline_contents());
		// shared
		// milestones
		// versions
		// attachments
	}

	get_timeline_item(item) {
		const timeline_item = $(`

					${frappe.utils.icon(item.icon, 'md')}

		`);
		timeline_item.find('.timeline-content').append(item.content);
		if (!item.hide_timestamp) {
			timeline_item.find('.timeline-content').append(`<div>${comment_when(item.creation)}</div>`);
		}
		return timeline_item;
	}

	get_view_timeline_contents() {
		let view_timeline_contents = [];
		(this.doc_info.views || []).forEach(view => {
			let view_content = `

						${__("{0} viewed", [frappe.user.full_name(view.owner).bold()])}

			`;
			view_timeline_contents.push({
				icon: 'view',
				creation: view.creation,
				content: view_content,
			});
		});
		return view_timeline_contents;
	}

	get_communication_timeline_contents() {
		let communication_timeline_contents = [];
		(this.doc_info.communications|| []).forEach(communication => {
			let communication_content =  $(frappe.render_template('timeline_email', { doc: communication }));
			this.setup_reply(communication_content);
			communication_content.find(".timeline-email-content").append(communication.content);
			communication_timeline_contents.push({
				icon: 'mail',
				creation: communication.creation,
				card: true,
				content: this.get_communication_content(communication),
			});
		});
		return communication_timeline_contents;
	}

	get_comment_timeline_contents() {
		let comment_timeline_contents = [];
		(this.doc_info.comments || []).forEach(comment => {
			comment_timeline_contents.push({
				icon: 'mail',
				creation: comment.creation,
				content: comment.content,
			});
		});
		return comment_timeline_contents;
	}

	get_version_timeline_contents() {
		let version_timeline_contents = [];
		(this.doc_info.versions || []).forEach(version => {
			version_timeline_contents.push({
				icon: 'mail',
				creation: version.creation,
				content: version.content,
			});
		});
		return version_timeline_contents;
	}

	get_energy_point_timeline_contents() {
		let energy_point_timeline_contents = [];
		(this.doc_info.energy_point_logs || []).forEach(log => {
			energy_point_timeline_contents.push({
				icon: 'review',
				creation: log.creation,
				content: frappe.energy_points.format_form_log(log)
			});
		});
		return energy_point_timeline_contents;
	}

	setup_reply(communication_box) {
		let actions = communication_box.find('.actions');
		let reply = $(`<a class="reply">${frappe.utils.icon('reply', 'md')}</a>`).click(e => {
			console.log(e);
		});
		let reply_all = $(`<a class="reply-all">${frappe.utils.icon('reply-all', 'md')}</a>`).click(e => {
			console.log(e);
		});
		actions.append(reply);
		actions.append(reply_all);
	}
};<commit_msg>fix: Update timeline render code<commit_after>// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt

frappe.ui.form.NewTimeline = class {
	constructor(opts) {
		Object.assign(this, opts);
		this.doc_info = this.frm && this.frm.get_docinfo() || {};
		this.make();
	}

	make() {
		this.timeline_wrapper = $(`<div class="new-timeline">`);
		this.parent.replaceWith(this.timeline_wrapper);
		this.timeline_items = [];
		this.render_timeline_items();
	}

	refresh() {
		this.render_timeline_items();
	}

	add_action_button() {

	}

	render_timeline_items() {
		this.timeline_wrapper.empty();
		this.timeline_items = [];
		this.prepare_timeline_contents();

		this.timeline_items.sort((item1, item2) => new Date(item1.creation) - new Date(item2.creation));
		this.timeline_items.forEach(this.add_timeline_item.bind(this));
	}

	prepare_timeline_contents() {
		this.timeline_items.push(...this.get_view_timeline_contents());
		this.timeline_items.push(...this.get_communication_timeline_contents());
		this.timeline_items.push(...this.get_comment_timeline_contents());
		this.timeline_items.push(...this.get_energy_point_timeline_contents());
		// shared
		// milestones
		// versions
		// attachments
	}

	add_timeline_item(item) {
		let timeline_item = this.get_timeline_item(item);
		this.timeline_wrapper.prepend(timeline_item);
		return timeline_item;
	}

	get_timeline_item(item) {
		const timeline_item = $(`

					${frappe.utils.icon(item.icon, 'md')}

		`);
		timeline_item.find('.timeline-content').append(item.content);
		if (!item.hide_timestamp) {
			timeline_item.find('.timeline-content').append(`<div>${comment_when(item.creation)}</div>`);
		}
		return timeline_item;
	}

	get_view_timeline_contents() {
		let view_timeline_contents = [];
		(this.doc_info.views || []).forEach(view => {
			let view_content = `

						${__("{0} viewed", [frappe.user.full_name(view.owner).bold()])}

			`;
			view_timeline_contents.push({
				icon: 'view',
				creation: view.creation,
				content: view_content,
			});
		});
		return view_timeline_contents;
	}

	get_communication_timeline_contents() {
		let communication_timeline_contents = [];
		(this.doc_info.communications|| []).forEach(communication => {
			let communication_content =  $(frappe.render_template('timeline_email', { doc: communication }));
			this.setup_reply(communication_content);
			communication_content.find(".timeline-email-content").append(communication.content);
			communication_timeline_contents.push({
				icon: 'mail',
				creation: communication.creation,
				card: true,
				content: communication_content,
			});
		});
		return communication_timeline_contents;
	}

	get_comment_timeline_contents() {
		let comment_timeline_contents = [];
		(this.doc_info.comments || []).forEach(comment => {
			comment_timeline_contents.push({
				icon: 'mail',
				creation: comment.creation,
				content: comment.content,
			});
		});
		return comment_timeline_contents;
	}

	get_version_timeline_contents() {
		let version_timeline_contents = [];
		(this.doc_info.versions || []).forEach(version => {
			version_timeline_contents.push({
				icon: 'mail',
				creation: version.creation,
				content: version.content,
			});
		});
		return version_timeline_contents;
	}

	get_energy_point_timeline_contents() {
		let energy_point_timeline_contents = [];
		(this.doc_info.energy_point_logs || []).forEach(log => {
			energy_point_timeline_contents.push({
				icon: 'review',
				creation: log.creation,
				content: frappe.energy_points.format_form_log(log)
			});
		});
		return energy_point_timeline_contents;
	}

	setup_reply(communication_box) {
		let actions = communication_box.find('.actions');
		let reply = $(`<a class="reply">${frappe.utils.icon('reply', 'md')}</a>`).click(e => {
			console.log(e);
		});
		let reply_all = $(`<a class="reply-all">${frappe.utils.icon('reply-all', 'md')}</a>`).click(e => {
			console.log(e);
		});
		actions.append(reply);
		actions.append(reply_all);
	}
};<|endoftext|>