<commit_before>/**

 Copyright 2016, Cloud Compass Computing, Inc.

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.

 */
var https = require('https');
var github = require('octonode');
var url = require('url');
var querystring = require('querystring');

function parse_link_header(header) {
  if (header.length === 0) {
    throw new Error("input must not be of zero length");
  }

  // Split parts by comma
  var parts = header.split(',');
  var links = {};
  // Parse each part into a named link
  for (var i = 0; i < parts.length; i++) {
    var section = parts[i].split(';');
    if (section.length !== 2) {
      throw new Error("section could not be split on ';'");
    }
    var url = section[0].replace(/<(.*)>/, '$1').trim();
    var name = section[1].replace(/rel="(.*)"/, '$1').trim();
    links[name] = url;
  }
  return links;
}

module.exports = {

  // used to populate friendly name before creation of a Service model instance
  getAccount: function (service, cb) {
    var client = github.client(service.token);
    var ghme = client.me();
    ghme.info(function (error, data) {
      if (error != null) {
        cb(null, error);
      } else {
        cb(data.login);
      }
    });
  },

  // automates github webhook creation on creation of Module model instance
  createWebhook: function (module, cb) {
    if (!_.has(module, 'config.full_name')) return cb("Repository name not provided");

    var serviceId = _.has(module.service, 'id') ? module.service.id : module.service;

    Service.findOne({id: serviceId}).exec(function (err, service) {
      if (err) return cb(err);
      if (service == undefined) return cb('Invalid parent service');

      var client = github.client(service.token);
      var ghrepo = client.repo(module.config.full_name);
      var evts = [];
      switch (module.type) {
        case 'repo':
          evts = ["push", "create", "delete", "member"];
          break;
        case 'issues':
          evts = ['issues'];
          break;
      }

      sails.log.info('adding webhook', module.project, service.token, module.config.full_name, evts);
      // sails.log.info(ghrepo.collaborators(cb));
      ghrepo.hook({
        name: "web",
        active: true,
        events: evts,
        config: {
          url: process.env.SB_WEBHOOK_BASE_URL || sails.config.url.hooks + "/payload/" + module.project,
          content_type: "json"
        }
      }, cb);
    });

  },

  // constructs Event model instance for PayloadController
  createEvent: function (req, cb) {
    // sails.log.info('creating event', req.body);
    var event = {};
    event.platform = 'github';
    event.event_type = req.headers['x-github-event'];
    event.actor_name = req.body.sender.login;
    event.target_name = req.body.repository.name;
    event.target_url = req.body.repository.url;
    event.project = req.param('projectId');

    switch (event.event_type) {
      case 'push':
        event.source_url = req.body.compare;
        event.event_action = 'pushed ' + '' + req.body.commits.length + ' ' + 'commits' + ' to';
        break;
      case 'issues':
        event.source_url = req.body.issue.html_url;
        event.event_action = req.body.action + ' an issue on';
        break;
      case 'ping':
        event.event_action = 'pinged from';
        break;
    }
    return event;
  },

  // exposed to client in ServiceController
  getRepos: function (serviceID, cb) {

    var issues = [];
    var client = github.client();

    var pager = function (err, data, headers) {
      if (data) {
        issues = issues.concat(data);
      }

      if (headers.link) {
        var linkHeaders = parse_link_header(headers.link);
        if (linkHeaders && linkHeaders.next) {
          //parse out next page from link header format like https://api.github.com/user/repos?page=50&per_page=100
          var nextPageNumber = querystring.parse(url.parse(linkHeaders.next).query).page;

          getRepoPage(client, nextPageNumber, pager)
        } else {
          sails.log.debug("Returning repos to caller...");
          cb(err, issues, headers);
        }
      }
    };

    function getRepoPage(client, page, pager) {
      sails.log.debug("Retrieving repo page ", page);
      var ghme = client.me();
      ghme.repos({
        page: page,
        per_page: 100
      }, pager);
    }

    Service.findOne({id: serviceID})
      .exec(function (err, service) {
        if (service) {
          client = github.client(service.token);
          getRepoPage(client, 1, pager);
        } else {
          sails.log.error('could not retrieve repos', err);
        }
      });
  },

  // exposed to client in VCSController
  getCommits: function (widgetId, cb) {
    Widget.findOne({id: widgetId}).populate('module')
      .exec(function (err, widget) {
        if (widget) {
          // sails.log.debug('finding first module:', widget.modules[0].id);
          Module.findOne({id: widget.module.id}).populate('service')
            .exec(function (err, module) {
              if (module) {
                var client = github.client(module.service.token);
                var ghrepo = client.repo(module.config.full_name);
                ghrepo.commits(cb);
              } else {
                sails.log.error('could not retrieve module', err);
              }
            });
        } else {
          sails.log.error('could not retrieve widget', err);
        }
      });
  },
  // exposed to client in VCSController
  getIssues: function (widgetId, cb) {
    sails.log.debug('finding widget:', widgetId);
    Widget.findOne({id: widgetId}).populate('module')
      .exec(function (err, widget) {
        if (widget) {
          // sails.log.debug('finding first module:', widget.modules);
          Module.findOne({id: widget.module.id}).populate('service')
            .exec(function (err, module) {
              if (module) {
                var client = github.client(module.service.token);
                var ghrepo = client.repo(module.config.full_name);
                ghrepo.issues(cb);
              } else {
                sails.log.error('could not retrieve module', err);
              }
            });
        } else {
          sails.log.error('could not retrieve widget', err);
        }
      });
  }

};
/**
 * Created by tiffa on 2016-05-06.
 */
<commit_msg>- fixing webhook configuration logic<commit_after>/**

 Copyright 2016, Cloud Compass Computing, Inc.

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.

 */
var https = require('https');
var github = require('octonode');
var url = require('url');
var querystring = require('querystring');

function parse_link_header(header) {
  if (header.length === 0) {
    throw new Error("input must not be of zero length");
  }

  // Split parts by comma
  var parts = header.split(',');
  var links = {};
  // Parse each part into a named link
  for (var i = 0; i < parts.length; i++) {
    var section = parts[i].split(';');
    if (section.length !== 2) {
      throw new Error("section could not be split on ';'");
    }
    var url = section[0].replace(/<(.*)>/, '$1').trim();
    var name = section[1].replace(/rel="(.*)"/, '$1').trim();
    links[name] = url;
  }
  return links;
}

module.exports = {

  // used to populate friendly name before creation of a Service model instance
  getAccount: function (service, cb) {
    var client = github.client(service.token);
    var ghme = client.me();
    ghme.info(function (error, data) {
      if (error != null) {
        cb(null, error);
      } else {
        cb(data.login);
      }
    });
  },

  // automates github webhook creation on creation of Module model instance
  createWebhook: function (module, cb) {
    if (!_.has(module, 'config.full_name')) return cb("Repository name not provided");

    var serviceId = _.has(module.service, 'id') ? module.service.id : module.service;

    Service.findOne({id: serviceId}).exec(function (err, service) {
      if (err) return cb(err);
      if (service == undefined) return cb('Invalid parent service');

      var client = github.client(service.token);
      var ghrepo = client.repo(module.config.full_name);
      var evts = [];
      switch (module.type) {
        case 'repo':
          evts = ["push", "create", "delete", "member"];
          break;
        case 'issues':
          evts = ['issues'];
          break;
      }

      var webhookURL = (process.env.SB_WEBHOOK_BASE_URL || sails.config.url.hooks ) + "/payload/" + module.project;

      sails.log.info('adding webhook', module.config.full_name, webhookURL, evts);

      ghrepo.hook({
        name: "web",
        active: true,
        events: evts,
        config: {
          url: webhookURL,
          content_type: "json"
        }
      }, cb);
    });

  },

  // constructs Event model instance for PayloadController
  createEvent: function (req, cb) {
    // sails.log.info('creating event', req.body);
    var event = {};
    event.platform = 'github';
    event.event_type = req.headers['x-github-event'];
    event.actor_name = req.body.sender.login;
    event.target_name = req.body.repository.name;
    event.target_url = req.body.repository.url;
    event.project = req.param('projectId');

    switch (event.event_type) {
      case 'push':
        event.source_url = req.body.compare;
        event.event_action = 'pushed ' + '' + req.body.commits.length + ' ' + 'commits' + ' to';
        break;
      case 'issues':
        event.source_url = req.body.issue.html_url;
        event.event_action = req.body.action + ' an issue on';
        break;
      case 'ping':
        event.event_action = 'pinged from';
        break;
    }
    return event;
  },

  // exposed to client in ServiceController
  getRepos: function (serviceID, cb) {

    var issues = [];
    var client = github.client();

    var pager = function (err, data, headers) {
      if (data) {
        issues = issues.concat(data);
      }

      if (headers.link) {
        var linkHeaders = parse_link_header(headers.link);
        if (linkHeaders && linkHeaders.next) {
          //parse out next page from link header format like https://api.github.com/user/repos?page=50&per_page=100
          var nextPageNumber = querystring.parse(url.parse(linkHeaders.next).query).page;

          getRepoPage(client, nextPageNumber, pager)
        } else {
          sails.log.debug("Returning repos to caller...");
          cb(err, issues, headers);
        }
      }
    };

    function getRepoPage(client, page, pager) {
      sails.log.debug("Retrieving repo page ", page);
      var ghme = client.me();
      ghme.repos({
        page: page,
        per_page: 100
      }, pager);
    }

    Service.findOne({id: serviceID})
      .exec(function (err, service) {
        if (service) {
          client = github.client(service.token);
          getRepoPage(client, 1, pager);
        } else {
          sails.log.error('could not retrieve repos', err);
        }
      });
  },

  // exposed to client in VCSController
  getCommits: function (widgetId, cb) {
    Widget.findOne({id: widgetId}).populate('module')
      .exec(function (err, widget) {
        if (widget) {
          // sails.log.debug('finding first module:', widget.modules[0].id);
          Module.findOne({id: widget.module.id}).populate('service')
            .exec(function (err, module) {
              if (module) {
                var client = github.client(module.service.token);
                var ghrepo = client.repo(module.config.full_name);
                ghrepo.commits(cb);
              } else {
                sails.log.error('could not retrieve module', err);
              }
            });
        } else {
          sails.log.error('could not retrieve widget', err);
        }
      });
  },
  // exposed to client in VCSController
  getIssues: function (widgetId, cb) {
    sails.log.debug('finding widget:', widgetId);
    Widget.findOne({id: widgetId}).populate('module')
      .exec(function (err, widget) {
        if (widget) {
          // sails.log.debug('finding first module:', widget.modules);
          Module.findOne({id: widget.module.id}).populate('service')
            .exec(function (err, module) {
              if (module) {
                var client = github.client(module.service.token);
                var ghrepo = client.repo(module.config.full_name);
                ghrepo.issues(cb);
              } else {
                sails.log.error('could not retrieve module', err);
              }
            });
        } else {
          sails.log.error('could not retrieve widget', err);
        }
      });
  }

};
/**
 * Created by tiffa on 2016-05-06.
 */
<|endoftext|>


<commit_before>girderTest.importPlugin('candela');

girderTest.startApp();

$(function () {
    describe('Test the candela UI.', function () {
        it('register a user', girderTest.createUser(
            'johndoe', 'john.doe@email.com', 'John', 'Doe', 'password!'
        ));

        it('visits the configuration page', function () {
            girderTest.waitForLoad();

            waitsFor(function () {
                return $('a.g-nav-link[g-target="admin"]:visible').length > 0;
            }, 'admin nav link to appear');

            runs(function () {
                $('a.g-nav-link[g-target="admin"]').click();
            });

            waitsFor(function () {
                return $('.g-plugins-config').length > 0;
            }, 'navigate to admin page');

            runs(function () {
                $('.g-plugins-config').click();
            });

            waitsFor(function () {
                return $('.g-plugin-config-link[g-route="plugins/candela/config"]').length > 0;
            }, 'navigate to plugins page');

            runs(function () {
                $('.g-plugin-config-link[g-route="plugins/candela/config"]').click();
            });

            waitsFor(function () {
                return $('.g-config-breadcrumb-container').length > 0;
            }, 'navigate to candela plugin config page');

            runs(function () {
                expect($('.g-default-layout').children().eq(1).find('a').attr('href')).toBe('http://candela.readthedocs.io/');
            });
        });

        it('uploads the data file', function () {
            runs(function () {
                expect($('#g-user-action-menu.open').length).toBe(0);
                $('.g-user-text>a:first').click();
            });
            girderTest.waitForLoad();

            runs(function () {
                expect($('#g-user-action-menu.open').length).toBe(1);
                $('a.g-my-folders').click();
            });
            girderTest.waitForLoad();

            runs(function () {
                $('a.g-folder-list-link:last').click();
            });
            girderTest.waitForLoad();

            waitsFor(function () {
                return $('ol.breadcrumb>li.active').text() === 'Public' &&
                       $('.g-empty-parent-message:visible').length === 1;
            }, 'descending into Public folder');

            girderTest.binaryUpload('clients/web/test/testFile.csv');

            runs(function () {
                $('.g-item-list-link:first').click();
            });
        });

        it('sets up candela inputs and renders the visualization', function () {
            waitsFor(function () {
                return $('.g-item-candela-component').length === 1;
            }, 'the candela component selector to appear');

            runs(function () {
                expect($('.g-item-candela-component option').length).toBeGreaterThan(18);
                $('.g-item-candela-component').val('BarChart').change();
            });

            waitsFor(function () {
                var inputs = $('.g-candela-inputs-container').children().eq(1).children().children();
                return inputs.length === 6;
            }, 'the bar chart options to be available');

            runs(function () {
                var inputs = $('.g-candela-inputs-container').children().eq(1).children().children();
                expect(inputs.eq(0).find('label').text()).toBe('Width');
                expect(inputs.eq(1).find('label').text()).toBe('Height');
                expect(inputs.eq(2).find('label').text()).toBe('x');
                var values = [];
                for (var i = 0; i < 4; i += 1) {
                    values.push(inputs.eq(2).find('option').eq(i).text());
                }
                values.sort();
                expect(values).toEqual(['(none)', 'a_b', 'c', 'id']);
                expect(inputs.eq(3).find('label').text()).toBe('y');
                expect(inputs.eq(4).find('label').text()).toBe('color');
                expect(inputs.eq(5).find('label').text()).toBe('hover');
                $('.g-candela-update-vis').click();
            });

            waitsFor(function () {
                return $('.g-candela-vis').find('canvas').length === 1;
            }, 'the vis canvas to be drawn');

            runs(function () {
                $('.g-item-candela-component').val('TreeHeatmap').change();
            });

            waitsFor(function () {
                var inputs = $('.g-candela-inputs-container').children().eq(1).children().children();
                return inputs.length === 9;
            }, 'the visualization type to change to TreeHeatmap');

            runs(function () {
                var inputs = $('.g-candela-inputs-container').children().eq(1).children().children();
                expect(inputs.eq(2).find('label').text()).toBe('Identifier column');
                expect(inputs.eq(3).find('label').text()).toBe('Color scale');
                expect(inputs.eq(3).find('option').eq(1).text()).toBe('row');
            });

            runs(function () {
                $('.g-item-candela-component').val('BulletChart').change();
            });

            waitsFor(function () {
                var inputs = $('.g-candela-inputs-container').children().eq(1).children().children();
                return inputs.length === 5;
            }, 'the visualization type to change to BulletChart');

            runs(function () {
                var inputs = $('.g-candela-inputs-container').children().eq(1).children().children();
                expect(inputs.eq(3).find('label').text()).toBe('title');
                expect(inputs.eq(4).find('label').text()).toBe('subtitle');
            });
        });

        it('uploads a bad data file', function () {
            runs(function () {
                expect($('#g-user-action-menu.open').length).toBe(0);
                $('.g-user-text>a:first').click();
            });
            girderTest.waitForLoad();

            runs(function () {
                expect($('#g-user-action-menu.open').length).toBe(1);
                $('a.g-my-folders').click();
            });
            girderTest.waitForLoad();

            runs(function () {
                $('a.g-folder-list-link:last').click();
            });
            girderTest.waitForLoad();

            waitsFor(function () {
                return $('ol.breadcrumb>li.active').text() === 'Public' &&
                       $('.g-item-list-link').length === 1;
            }, 'descending into Public folder');

            girderTest.binaryUpload('clients/web/test/testFileBad.csv');

            runs(function () {
                $('.g-item-list-link').eq(1).click();
            });

            waitsFor(function () {
                return $('.alert-danger').length === 1;
            }, 'the error message to appear');

            runs(function () {
                expect($('.alert-danger').text()).toContain('An error occurred while attempting to read and parse the data file.');
            });
        });
    });
});
<commit_msg>Use girderTest.startApp to start the app in testing<commit_after>girderTest.importPlugin('candela');
girderTest.startApp();

$(function () {
    describe('Test the candela UI.', function () {
        it('register a user', girderTest.createUser(
            'johndoe', 'john.doe@email.com', 'John', 'Doe', 'password!'
        ));

        it('visits the configuration page', function () {
            girderTest.waitForLoad();

            waitsFor(function () {
                return $('a.g-nav-link[g-target="admin"]:visible').length > 0;
            }, 'admin nav link to appear');

            runs(function () {
                $('a.g-nav-link[g-target="admin"]').click();
            });

            waitsFor(function () {
                return $('.g-plugins-config').length > 0;
            }, 'navigate to admin page');

            runs(function () {
                $('.g-plugins-config').click();
            });

            waitsFor(function () {
                return $('.g-plugin-config-link[g-route="plugins/candela/config"]').length > 0;
            }, 'navigate to plugins page');

            runs(function () {
                $('.g-plugin-config-link[g-route="plugins/candela/config"]').click();
            });

            waitsFor(function () {
                return $('.g-config-breadcrumb-container').length > 0;
            }, 'navigate to candela plugin config page');

            runs(function () {
                expect($('.g-default-layout').children().eq(1).find('a').attr('href')).toBe('http://candela.readthedocs.io/');
            });
        });

        it('uploads the data file', function () {
            runs(function () {
                expect($('#g-user-action-menu.open').length).toBe(0);
                $('.g-user-text>a:first').click();
            });
            girderTest.waitForLoad();

            runs(function () {
                expect($('#g-user-action-menu.open').length).toBe(1);
                $('a.g-my-folders').click();
            });
            girderTest.waitForLoad();

            runs(function () {
                $('a.g-folder-list-link:last').click();
            });
            girderTest.waitForLoad();

            waitsFor(function () {
                return $('ol.breadcrumb>li.active').text() === 'Public' &&
                       $('.g-empty-parent-message:visible').length === 1;
            }, 'descending into Public folder');

            girderTest.binaryUpload('clients/web/test/testFile.csv');

            runs(function () {
                $('.g-item-list-link:first').click();
            });
        });

        it('sets up candela inputs and renders the visualization', function () {
            waitsFor(function () {
                return $('.g-item-candela-component').length === 1;
            }, 'the candela component selector to appear');

            runs(function () {
                expect($('.g-item-candela-component option').length).toBeGreaterThan(18);
                $('.g-item-candela-component').val('BarChart').change();
            });

            waitsFor(function () {
                var inputs = $('.g-candela-inputs-container').children().eq(1).children().children();
                return inputs.length === 6;
            }, 'the bar chart options to be available');

            runs(function () {
                var inputs = $('.g-candela-inputs-container').children().eq(1).children().children();
                expect(inputs.eq(0).find('label').text()).toBe('Width');
                expect(inputs.eq(1).find('label').text()).toBe('Height');
                expect(inputs.eq(2).find('label').text()).toBe('x');
                var values = [];
                for (var i = 0; i < 4; i += 1) {
                    values.push(inputs.eq(2).find('option').eq(i).text());
                }
                values.sort();
                expect(values).toEqual(['(none)', 'a_b', 'c', 'id']);
                expect(inputs.eq(3).find('label').text()).toBe('y');
                expect(inputs.eq(4).find('label').text()).toBe('color');
                expect(inputs.eq(5).find('label').text()).toBe('hover');
                $('.g-candela-update-vis').click();
            });

            waitsFor(function () {
                return $('.g-candela-vis').find('canvas').length === 1;
            }, 'the vis canvas to be drawn');

            runs(function () {
                $('.g-item-candela-component').val('TreeHeatmap').change();
            });

            waitsFor(function () {
                var inputs = $('.g-candela-inputs-container').children().eq(1).children().children();
                return inputs.length === 9;
            }, 'the visualization type to change to TreeHeatmap');

            runs(function () {
                var inputs = $('.g-candela-inputs-container').children().eq(1).children().children();
                expect(inputs.eq(2).find('label').text()).toBe('Identifier column');
                expect(inputs.eq(3).find('label').text()).toBe('Color scale');
                expect(inputs.eq(3).find('option').eq(1).text()).toBe('row');
            });

            runs(function () {
                $('.g-item-candela-component').val('BulletChart').change();
            });

            waitsFor(function () {
                var inputs = $('.g-candela-inputs-container').children().eq(1).children().children();
                return inputs.length === 5;
            }, 'the visualization type to change to BulletChart');

            runs(function () {
                var inputs = $('.g-candela-inputs-container').children().eq(1).children().children();
                expect(inputs.eq(3).find('label').text()).toBe('title');
                expect(inputs.eq(4).find('label').text()).toBe('subtitle');
            });
        });

        it('uploads a bad data file', function () {
            runs(function () {
                expect($('#g-user-action-menu.open').length).toBe(0);
                $('.g-user-text>a:first').click();
            });
            girderTest.waitForLoad();

            runs(function () {
                expect($('#g-user-action-menu.open').length).toBe(1);
                $('a.g-my-folders').click();
            });
            girderTest.waitForLoad();

            runs(function () {
                $('a.g-folder-list-link:last').click();
            });
            girderTest.waitForLoad();

            waitsFor(function () {
                return $('ol.breadcrumb>li.active').text() === 'Public' &&
                       $('.g-item-list-link').length === 1;
            }, 'descending into Public folder');

            girderTest.binaryUpload('clients/web/test/testFileBad.csv');

            runs(function () {
                $('.g-item-list-link').eq(1).click();
            });

            waitsFor(function () {
                return $('.alert-danger').length === 1;
            }, 'the error message to appear');

            runs(function () {
                expect($('.alert-danger').text()).toContain('An error occurred while attempting to read and parse the data file.');
            });
        });
    });
});
<|endoftext|>


<commit_before>girderTest.importPlugin('candela');
girderTest.startApp();

describe('Test the candela UI.', function () {
    it('register a user', girderTest.createUser(
        'johndoe', 'john.doe@email.com', 'John', 'Doe', 'password!'
    ));

    it('uploads the data file', function () {
        runs(function () {
            expect($('#g-user-action-menu.open').length).toBe(0);
            $('.g-user-text>a:first').click();
            expect($('#g-user-action-menu.open').length).toBe(1);
            $('a.g-my-folders').click();
        });

        waitsFor(function () {
            return $('a.g-folder-list-link').length === 2;
        }, 'Public and Private folders to appear');

        runs(function () {
            $('a.g-folder-list-link:contains("Public")').click();
        });
        girderTest.waitForLoad();

        waitsFor(function () {
            return $('ol.breadcrumb>li.active').text() === 'Public' &&
                   $('.g-empty-parent-message:visible').length === 1;
        }, 'descending into Public folder');

        girderTest.binaryUpload('clients/web/test/testFile.csv');

        runs(function () {
            $('.g-item-list-link:first').click();
        });
    });

    it('sets up candela inputs and renders the visualization', function () {
        waitsFor(function () {
            return $('.g-item-candela-component').length === 1;
        }, 'the candela component selector to appear');

        runs(function () {
            expect($('.g-item-candela-component option').length).toBeGreaterThan(5);
            $('.g-item-candela-component').val('BarChart').change();
        });

        waitsFor(function () {
            var inputs = $('.g-candela-inputs-container').children().eq(1).children().children();
            return inputs.length > 3;
        }, 'the bar chart options to be available');

        runs(function () {
            var inputs = $('.g-candela-inputs-container').children().eq(1).children().children();
            expect(inputs.eq(0).find('label').text()).toBe('Width');
            expect(inputs.eq(1).find('label').text()).toBe('Height');
            expect(inputs.eq(2).find('label').text()).toBe('X');
            var values = [];
            for (var i = 0; i < 4; i += 1) {
                values.push(inputs.eq(2).find('option').eq(i).text());
            }
            values.sort();
            expect(values).toEqual(['(none)', 'a_b', 'c', 'id']);
            $('.g-candela-update-vis').click();
        });

        waitsFor(function () {
            return $('.g-candela-vis').find('canvas').length === 1;
        }, 'the vis canvas to be drawn');

        runs(function () {
            $('.g-item-candela-component').val('TreeHeatmap').change();
        });

        waitsFor(function () {
            var inputs = $('.g-candela-inputs-container').children().eq(1).children().children();
            return inputs.length === 9;
        }, 'the visualization type to change to TreeHeatmap');

        runs(function () {
            var inputs = $('.g-candela-inputs-container').children().eq(1).children().children();
            expect(inputs.eq(2).find('label').text()).toBe('Identifier column');
            expect(inputs.eq(3).find('label').text()).toBe('Color scale');
            expect(inputs.eq(3).find('option').eq(1).text()).toBe('row');
        });

        runs(function () {
            $('.g-item-candela-component').val('Histogram').change();
        });

        waitsFor(function () {
            var inputs = $('.g-candela-inputs-container').children().eq(1).children().children();
            return inputs.length > 3;
        }, 'the visualization type to change to BulletChart');

        runs(function () {
            var inputs = $('.g-candela-inputs-container').children().eq(1).children().children();
            expect(inputs.eq(2).find('label').text()).toBe('X');
        });
    });

    // This test is skipped because this failure mode no longer exists with the
    // updated Candela plugin backing technologies. Specifically, d3-dsv is used
    // for parsing, and that module happily accepts any stream of bytes and will
    // simply parse what it gets, even if that is a zip file or a PNG image or
    // anything else.
    xit('uploads a bad data file', function () {
        runs(function () {
            expect($('#g-user-action-menu.open').length).toBe(0);
            $('.g-user-text>a:first').click();
        });
        waitsFor(function () {
            return $('#g-user-action-menu.open').length === 1;
        }, 'menu to open');

        runs(function () {
            $('a.g-my-folders').click();
        });
        waitsFor(function () {
            return $('.g-folder-list-link').length > 0;
        }, 'user folder list to load');

        runs(function () {
            $('a.g-folder-list-link:contains("Public")').click();
        });
        girderTest.waitForLoad();
        waitsFor(function () {
            return $('ol.breadcrumb>li.active').text() === 'Public' &&
                   $('.g-item-list-link').length === 1;
        }, 'descending into Public folder');

        girderTest.binaryUpload('clients/web/test/testFileBad.csv');

        runs(function () {
            $('.g-item-list-link').eq(1).click();
        });

        waitsFor(function () {
            return $('.alert-danger').length === 1;
        }, 'the error message to appear');

        runs(function () {
            expect($('.alert-danger').text()).toContain('An error occurred while attempting to read and parse the data file.');
        });
    });
});
<commit_msg>Refactor client build for new style plugins<commit_after>girderTest.importPlugin('candela');
girderTest.startApp();

describe('Test the candela UI.', function () {
    it('register a user', girderTest.createUser(
        'johndoe', 'john.doe@email.com', 'John', 'Doe', 'password!'
    ));

    it('uploads the data file', function () {
        runs(function () {
            expect($('#g-user-action-menu.open').length).toBe(0);
            $('.g-user-text>a:first').click();
            expect($('#g-user-action-menu.open').length).toBe(1);
            $('a.g-my-folders').click();
        });

        waitsFor(function () {
            return $('a.g-folder-list-link').length === 2;
        }, 'Public and Private folders to appear');

        runs(function () {
            $('a.g-folder-list-link:contains("Public")').click();
        });
        girderTest.waitForLoad();

        waitsFor(function () {
            return $('ol.breadcrumb>li.active').text() === 'Public' &&
                   $('.g-empty-parent-message:visible').length === 1;
        }, 'descending into Public folder');

        girderTest.binaryUpload('girder/web_client/test/testFile.csv');

        runs(function () {
            $('.g-item-list-link:first').click();
        });
    });

    it('sets up candela inputs and renders the visualization', function () {
        waitsFor(function () {
            return $('.g-item-candela-component').length === 1;
        }, 'the candela component selector to appear');

        runs(function () {
            expect($('.g-item-candela-component option').length).toBeGreaterThan(5);
            $('.g-item-candela-component').val('BarChart').change();
        });

        waitsFor(function () {
            var inputs = $('.g-candela-inputs-container').children().eq(1).children().children();
            return inputs.length > 3;
        }, 'the bar chart options to be available');

        runs(function () {
            var inputs = $('.g-candela-inputs-container').children().eq(1).children().children();
            expect(inputs.eq(0).find('label').text()).toBe('Width');
            expect(inputs.eq(1).find('label').text()).toBe('Height');
            expect(inputs.eq(2).find('label').text()).toBe('X');
            var values = [];
            for (var i = 0; i < 4; i += 1) {
                values.push(inputs.eq(2).find('option').eq(i).text());
            }
            values.sort();
            expect(values).toEqual(['(none)', 'a_b', 'c', 'id']);
            $('.g-candela-update-vis').click();
        });

        waitsFor(function () {
            return $('.g-candela-vis').find('canvas').length === 1;
        }, 'the vis canvas to be drawn');

        runs(function () {
            $('.g-item-candela-component').val('TreeHeatmap').change();
        });

        waitsFor(function () {
            var inputs = $('.g-candela-inputs-container').children().eq(1).children().children();
            return inputs.length === 9;
        }, 'the visualization type to change to TreeHeatmap');

        runs(function () {
            var inputs = $('.g-candela-inputs-container').children().eq(1).children().children();
            expect(inputs.eq(2).find('label').text()).toBe('Identifier column');
            expect(inputs.eq(3).find('label').text()).toBe('Color scale');
            expect(inputs.eq(3).find('option').eq(1).text()).toBe('row');
        });

        runs(function () {
            $('.g-item-candela-component').val('Histogram').change();
        });

        waitsFor(function () {
            var inputs = $('.g-candela-inputs-container').children().eq(1).children().children();
            return inputs.length > 3;
        }, 'the visualization type to change to BulletChart');

        runs(function () {
            var inputs = $('.g-candela-inputs-container').children().eq(1).children().children();
            expect(inputs.eq(2).find('label').text()).toBe('X');
        });
    });

    // This test is skipped because this failure mode no longer exists with the
    // updated Candela plugin backing technologies. Specifically, d3-dsv is used
    // for parsing, and that module happily accepts any stream of bytes and will
    // simply parse what it gets, even if that is a zip file or a PNG image or
    // anything else.
    xit('uploads a bad data file', function () {
        runs(function () {
            expect($('#g-user-action-menu.open').length).toBe(0);
            $('.g-user-text>a:first').click();
        });
        waitsFor(function () {
            return $('#g-user-action-menu.open').length === 1;
        }, 'menu to open');

        runs(function () {
            $('a.g-my-folders').click();
        });
        waitsFor(function () {
            return $('.g-folder-list-link').length > 0;
        }, 'user folder list to load');

        runs(function () {
            $('a.g-folder-list-link:contains("Public")').click();
        });
        girderTest.waitForLoad();
        waitsFor(function () {
            return $('ol.breadcrumb>li.active').text() === 'Public' &&
                   $('.g-item-list-link').length === 1;
        }, 'descending into Public folder');

        girderTest.binaryUpload('girder/web_client/test/testFileBad.csv');

        runs(function () {
            $('.g-item-list-link').eq(1).click();
        });

        waitsFor(function () {
            return $('.alert-danger').length === 1;
        }, 'the error message to appear');

        runs(function () {
            expect($('.alert-danger').text()).toContain('An error occurred while attempting to read and parse the data file.');
        });
    });
});
<|endoftext|>


<commit_before>$.fn.SleepyTable = $.fn.SleepyTable || {};
$.fn.SleepyTable.plugins = $.fn.SleepyTable.plugins || {};
(function ($, undefined) {

	//Constants
	PLACEHOLDER    = '!-placeholder-!',

	$.fn.SleepyTable.plugins.filter =  {
		//Public - Modifiable
		debug: false,
		/*
		 * Options per column for sorting, keys are index of header columns.
		 * - enabled - Bool - If sorting should be enabled or not on this table.
		 * Example: filterOptions: {0: {enabled: false}}
		 * Example: filterOptions: {2: {type: select, source: [url]}}
		 * Example: filterOptions: {1: {placeholder: [text]}}
		 */
		columnOptions    : {},
		sleepTime        : 700,
		filterTimer      : null,

		cssFilterRow     : 'sleepytable-filter-row',
		cssFilterDisabled: 'sleepytable-filter-disabled',

		$filterRow       : null,
		$filterHeaders   : [],

		publicMethods : ['set'],

		init : function(tableObj) {
			var config = tableObj.config,
				$thead,
				$filterRow,
				$th,
				thisPlugin = this;

			if (config.$headers.length !== 0) {
				$thead = config.$element.find('thead').first();
				$thead.find('tr.'+this.cssFilterRow).remove();
				$filterRow = $('

').addClass(this.cssFilterRow);

				var filterPlugin = this;
				config.$headers.each(function(i, elem) {
					$th = $('	');
					if (filterPlugin.columnOptions[i] == undefined) filterPlugin.columnOptions[i] = {};
					if (filterPlugin.columnOptions[i].enabled !== false) {
						if (filterPlugin.columnOptions[i] && filterPlugin.columnOptions[i].type && filterPlugin.columnOptions[i].type.toLowerCase() == 'select') {
							$th.html('<select placeholder="Choose a filter"></select>');
							var $select;
							if (filterPlugin.columnOptions[i].source) {
								//AJAX select box
								$select = $th.find('select');

								$select.html('<option value="'+PLACEHOLDER+'">Loading Options...</option>');

								config.ajaxTransport.call(null, {
									url: filterPlugin.columnOptions[i].source,
									dataType: filterPlugin.columnOptions[i].dataType,
									data: filterPlugin.columnOptions[i].data,
									type: filterPlugin.columnOptions[i].httpMethod || 'GET',
									traditional: config.traditionalSerialization,
									context: {
										columnId: i,
										$table: config.$element,
										$element: $select,
										path: filterPlugin.columnOptions[i].options,
										placeholder: filterPlugin.columnOptions[i].placeholder,
										value: filterPlugin.columnOptions[i].value,
										getDynamicPath: filterPlugin.getDynamicPath,
										debug: filterPlugin.debug
									},
									success: function (data) {
										var pathParts = this.path.split("[]"),
											elements =  eval('data.'+pathParts[0]),
											i,
											display,
											options = '';
										if(this.debug) tableObj.debug('Filter value: ' + this.columnId + " to " + this.value);
										for (i in elements) {
											display = eval('data.'+this.getDynamicPath(this.path, i));
											if (display !== undefined) {
												options += '<option value="'+i+'">'+display.toString()+'</option>';
											}
										}
										this.$element.find('option').html(this.placeholder||'Choose filter...');
										this.$element.append(options);
										if (this.value != undefined) {
											if(this.debug) tableObj.debug('Filter AJAX, calling filterSet ' + this.columnId + " to " + this.value);
											this.$table.SleepyTable('plugin.filter.set', this.columnId, this.value);
										}
									},
									error: function (jqXHR, textStatus, errorThrown) {
										this.$element.attr('disabled', true).empty();
									}
								});
							}
							else if (filterPlugin.columnOptions[i].options) {
								//Select box with pre-configured options
								$select = $th.find('select');
								$select.html('<option value="'+PLACEHOLDER+'">'+(filterPlugin.columnOptions[i].placeholder||'Select Filter...')+'</option>');
								for (var j in filterPlugin.columnOptions[i].options) {
									$select.append('<option value="'+j+'">'+filterPlugin.columnOptions[i].options[j]+'</option>');
								}
							}
						}
						else {
							var placeholderText = '';
							if (filterPlugin.columnOptions[i] && filterPlugin.columnOptions[i].placeholder) {
								placeholderText = filterPlugin.columnOptions[i].placeholder
							}
							var valueText = '';
							if (filterPlugin.columnOptions[i] && filterPlugin.columnOptions[i].value !== undefined) {
								valueText = filterPlugin.columnOptions[i].value;
							}
							else {
								filterPlugin.columnOptions[i].value = '';
							}
							$th.html('<input type="search" placeholder="'+placeholderText+'" value="'+valueText+'" />');
						}
					}
					else {
						$th.html('<input type="search" class="'+this.cssFilterDisabled+'" disabled="disabled"></input>');
					}
					$filterRow.append($th);
					$th.find(' > select')
						.off('change.SleepyTable.plugin.filter')
						.on('change.SleepyTable.plugin.filter', function(event) {
							config.$element.SleepyTable('plugin.filter.set', i, $(this).val());
						});
					$th.find(' > input')
						.off('keyup.SleepyTable.plugin.filter, change.SleepyTable.plugin.filter')
						.on('keyup.SleepyTable.plugin.filter, change.SleepyTable.plugin.filter', function(event) {
							if(this.filterTimer != null) {
								clearTimeout(this.filterTimer);
								this.filterTimer = null;
							}
							if(filterPlugin.debug) tableObj.debug('Setting value to: '+$(this).val());
							var value = $(this).val();
							this.filterTimer = setTimeout(
								function() {
									if(filterPlugin.debug) tableObj.debug('Timout running with: '+ value);
									config.$element.SleepyTable('plugin.filter.set', i, value);
									this.filterTimer = null;
									config.$element.SleepyTable(
										'plugin.history.filterChange', thisPlugin.getFetchParams(tableObj, {}, true)
									);

								}
							, filterPlugin.sleepTime);
						});
				});
				$thead.append($filterRow);
				this.$filterHeaders = $filterRow.find('th');
				this.$filterHeaders.each(function(i) {
					if (filterPlugin.columnOptions[i].value !== undefined) {
						config.$element.SleepyTable('plugin.filter.set', i, filterPlugin.columnOptions[i].value, false);
					}
				});
			}
		},

		headersChanged: function (tableObj, headers) {
			this.init(tableObj);
		},

		getFetchParams : function(tableObj, data, columnIdValueMode) {
			var config = tableObj.config,
				filterPlugin;

			if(data == undefined) {
				data = {};
			}
			if(columnIdValueMode == undefined) {
				columnIdValueMode = false;
			}

			if(this.debug) {
				tableObj.debug('Filter: ');
				tableObj.debug('filterOptions: ');
				tableObj.debug(this.columnOptions);
			}

			filterPlugin = this;
			if(this.$filterHeaders.length) {
				this.$filterHeaders.each(function(columnId) {
					var $header = $(config.$headers[columnId]);
					value = filterPlugin.columnOptions[columnId].value;
					if (value != PLACEHOLDER && value != '' && value != undefined) {
						if (filterPlugin.columnOptions[columnId] && filterPlugin.columnOptions[columnId].varName !== undefined) {
							varName = filterPlugin.columnOptions[columnId].varName
						}
						//Check element for data-var-name
						else if ($header.data('varFilter') !== undefined) {
							varName = $header.data('varFilter');
						}
						//Use data-src
						else if ($header.data('src') !== undefined) {
							var dataParts = $header.data('src').split('[]');
							varName = dataParts.pop();
							if (varName.charAt(0) == '.') varName = varName.substr(1);
						}
						else {
							//Throw error, don't know how to sort this column.
						}
						if(columnIdValueMode) {
							data[columnId] = value;
						}
						else {
							data[varName] = value;
						}
					}
				});
			}
			return data;
		},

		set: function(tableObj, columnId, value, updateData) {
			if(this.debug) tableObj.debug('Filter Plugin: Setting '+columnId+' to '+value);
			var config = tableObj.config;

			if (this.columnOptions[columnId] == undefined) this.columnOptions[columnId] = {};
			if (this.columnOptions[columnId].value == undefined) this.columnOptions[columnId].value = '';

			if(typeof(this.columnOptions[columnId].translation) == 'function') {
				this.columnOptions[columnId].value = this.columnOptions[columnId].translation(value);
			}
			else {
				this.columnOptions[columnId].value = value;
			}

			$(this.$filterHeaders[columnId]).children().val(value);

			if (updateData !== false) {
				config.$element.SleepyTable('clearPages');
			}
		},

		//Helpers
		getDynamicPath : function(path, index) {
			var splitSrc = path.split("[]");
			return splitSrc[0]+'['+index+']'+splitSrc[1];
		}
	}
})(jQuery);

<commit_msg>MOD - Added filter options for remotely populating filter select boxes to choose the option value.<commit_after>$.fn.SleepyTable = $.fn.SleepyTable || {};
$.fn.SleepyTable.plugins = $.fn.SleepyTable.plugins || {};
(function ($, undefined) {

	//Constants
	PLACEHOLDER    = '!-placeholder-!',

	$.fn.SleepyTable.plugins.filter =  {
		//Public - Modifiable
		debug: false,
		/*
		 * Options per column for sorting, keys are index of header columns.
		 * - enabled - Bool - If sorting should be enabled or not on this table.
		 * Example: filterOptions: {0: {enabled: false}}
		 * Example: filterOptions: {2: {type: select, source: [url]}}
		 * Example: filterOptions: {1: {placeholder: [text]}},
		 * Example: filterOptions: {1: {source: [url], dataType: json, optionValueField: "id"}} - Use the value of optionValueField as value for the option element.
		 */
		columnOptions    : {},
		sleepTime        : 700,
		filterTimer      : null,

		cssFilterRow     : 'sleepytable-filter-row',
		cssFilterDisabled: 'sleepytable-filter-disabled',

		$filterRow       : null,
		$filterHeaders   : [],

		publicMethods : ['set'],

		init : function(tableObj) {
			var config = tableObj.config,
				$thead,
				$filterRow,
				$th,
				thisPlugin = this;

			if (config.$headers.length !== 0) {
				$thead = config.$element.find('thead').first();
				$thead.find('tr.'+this.cssFilterRow).remove();
				$filterRow = $('

').addClass(this.cssFilterRow);

				var filterPlugin = this;
				config.$headers.each(function(i, elem) {
					$th = $('	');
					if (filterPlugin.columnOptions[i] == undefined) filterPlugin.columnOptions[i] = {};
					if (filterPlugin.columnOptions[i].enabled !== false) {
						if (filterPlugin.columnOptions[i] && filterPlugin.columnOptions[i].type && filterPlugin.columnOptions[i].type.toLowerCase() == 'select') {
							$th.html('<select placeholder="Choose a filter"></select>');
							var $select;
							if (filterPlugin.columnOptions[i].source) {
								//AJAX select box
								$select = $th.find('select');

								$select.html('<option value="'+PLACEHOLDER+'">Loading Options...</option>');

								config.ajaxTransport.call(null, {
									url: filterPlugin.columnOptions[i].source,
									dataType: filterPlugin.columnOptions[i].dataType,
									data: filterPlugin.columnOptions[i].data,
									type: filterPlugin.columnOptions[i].httpMethod || 'GET',
									traditional: config.traditionalSerialization,
									context: {
										columnId: i,
										$table: config.$element,
										$element: $select,
										path: filterPlugin.columnOptions[i].options,
										placeholder: filterPlugin.columnOptions[i].placeholder,
										value: filterPlugin.columnOptions[i].value,
										optionValueField: filterPlugin.columnOptions[i].optionValueField,
										getDynamicPath: filterPlugin.getDynamicPath,
										debug: filterPlugin.debug
									},
									success: function (data) {
										var pathParts = this.path.split("[]"),
											elements =  eval('data.'+pathParts[0]),
											i,
											display,
											options = '',
											optionsValue = '';
										if(this.debug) tableObj.debug('Filter value: ' + this.columnId + " to " + this.value);
										for (i in elements) {
											display = eval('data.'+this.getDynamicPath(this.path, i));
											if (display !== undefined) {
												if(this.optionValueField != undefined) {
													optionsValue = eval('data.'+this.getDynamicPath(this.optionValueField, i));
													options += '<option value="'+optionsValue+'">'+display.toString()+'</option>';
												}
												else {
													options += '<option value="'+i+'">'+display.toString()+'</option>';
												}
											}
										}
										this.$element.find('option').html(this.placeholder||'Choose filter...');
										this.$element.append(options);
										if (this.value != undefined) {
											if(this.debug) tableObj.debug('Filter AJAX, calling filterSet ' + this.columnId + " to " + this.value);
											this.$table.SleepyTable('plugin.filter.set', this.columnId, this.value);
										}
									},
									error: function (jqXHR, textStatus, errorThrown) {
										this.$element.attr('disabled', true).empty();
									}
								});
							}
							else if (filterPlugin.columnOptions[i].options) {
								//Select box with pre-configured options
								$select = $th.find('select');
								$select.html('<option value="'+PLACEHOLDER+'">'+(filterPlugin.columnOptions[i].placeholder||'Select Filter...')+'</option>');
								for (var j in filterPlugin.columnOptions[i].options) {
									$select.append('<option value="'+j+'">'+filterPlugin.columnOptions[i].options[j]+'</option>');
								}
							}
						}
						else {
							var placeholderText = '';
							if (filterPlugin.columnOptions[i] && filterPlugin.columnOptions[i].placeholder) {
								placeholderText = filterPlugin.columnOptions[i].placeholder
							}
							var valueText = '';
							if (filterPlugin.columnOptions[i] && filterPlugin.columnOptions[i].value !== undefined) {
								valueText = filterPlugin.columnOptions[i].value;
							}
							else {
								filterPlugin.columnOptions[i].value = '';
							}
							$th.html('<input type="search" placeholder="'+placeholderText+'" value="'+valueText+'" />');
						}
					}
					else {
						$th.html('<input type="search" class="'+this.cssFilterDisabled+'" disabled="disabled"></input>');
					}
					$filterRow.append($th);
					$th.find(' > select')
						.off('change.SleepyTable.plugin.filter')
						.on('change.SleepyTable.plugin.filter', function(event) {
							config.$element.SleepyTable('plugin.filter.set', i, $(this).val());
						});
					$th.find(' > input')
						.off('keyup.SleepyTable.plugin.filter, change.SleepyTable.plugin.filter')
						.on('keyup.SleepyTable.plugin.filter, change.SleepyTable.plugin.filter', function(event) {
							if(this.filterTimer != null) {
								clearTimeout(this.filterTimer);
								this.filterTimer = null;
							}
							if(filterPlugin.debug) tableObj.debug('Setting value to: '+$(this).val());
							var value = $(this).val();
							this.filterTimer = setTimeout(
								function() {
									if(filterPlugin.debug) tableObj.debug('Timout running with: '+ value);
									config.$element.SleepyTable('plugin.filter.set', i, value);
									this.filterTimer = null;
									config.$element.SleepyTable(
										'plugin.history.filterChange', thisPlugin.getFetchParams(tableObj, {}, true)
									);

								}
							, filterPlugin.sleepTime);
						});
				});
				$thead.append($filterRow);
				this.$filterHeaders = $filterRow.find('th');
				this.$filterHeaders.each(function(i) {
					if (filterPlugin.columnOptions[i].value !== undefined) {
						config.$element.SleepyTable('plugin.filter.set', i, filterPlugin.columnOptions[i].value, false);
					}
				});
			}
		},

		headersChanged: function (tableObj, headers) {
			this.init(tableObj);
		},

		getFetchParams : function(tableObj, data, columnIdValueMode) {
			var config = tableObj.config,
				filterPlugin;

			if(data == undefined) {
				data = {};
			}
			if(columnIdValueMode == undefined) {
				columnIdValueMode = false;
			}

			if(this.debug) {
				tableObj.debug('Filter: ');
				tableObj.debug('filterOptions: ');
				tableObj.debug(this.columnOptions);
			}

			filterPlugin = this;
			if(this.$filterHeaders.length) {
				this.$filterHeaders.each(function(columnId) {
					var $header = $(config.$headers[columnId]);
					value = filterPlugin.columnOptions[columnId].value;
					if (value != PLACEHOLDER && value != '' && value != undefined) {
						if (filterPlugin.columnOptions[columnId] && filterPlugin.columnOptions[columnId].varName !== undefined) {
							varName = filterPlugin.columnOptions[columnId].varName
						}
						//Check element for data-var-name
						else if ($header.data('varFilter') !== undefined) {
							varName = $header.data('varFilter');
						}
						//Use data-src
						else if ($header.data('src') !== undefined) {
							var dataParts = $header.data('src').split('[]');
							varName = dataParts.pop();
							if (varName.charAt(0) == '.') varName = varName.substr(1);
						}
						else {
							//Throw error, don't know how to sort this column.
						}
						if(columnIdValueMode) {
							data[columnId] = value;
						}
						else {
							data[varName] = value;
						}
					}
				});
			}
			return data;
		},

		set: function(tableObj, columnId, value, updateData) {
			if(this.debug) tableObj.debug('Filter Plugin: Setting '+columnId+' to '+value);
			var config = tableObj.config;

			if (this.columnOptions[columnId] == undefined) this.columnOptions[columnId] = {};
			if (this.columnOptions[columnId].value == undefined) this.columnOptions[columnId].value = '';

			if(typeof(this.columnOptions[columnId].translation) == 'function') {
				this.columnOptions[columnId].value = this.columnOptions[columnId].translation(value);
			}
			else {
				this.columnOptions[columnId].value = value;
			}

			$(this.$filterHeaders[columnId]).children().val(value);

			if (updateData !== false) {
				config.$element.SleepyTable('clearPages');
			}
		},

		//Helpers
		getDynamicPath : function(path, index) {
			var splitSrc = path.split("[]");
			return splitSrc[0]+'['+index+']'+splitSrc[1];
		}
	}
})(jQuery);

<|endoftext|>


<commit_before>(function () {
    var dayBefore = function (date) {
        var previous = new Date(date);
        previous.setDate(date.getDate() - 1);

        return previous;
    };

    var dayAfter = function (date) {
        var next = new Date(date);
        next.setDate(date.getDate() + 1);

        return next;
    };

    var xOfDay = function (d) { return chartBasis.getX()(d.day); },
        yOfPoints = function (d) { return chartBasis.getY()(d.points);},
        id = function (val) { return val;},
        formatDate = d3.time.format('%Y-%m-%d').parse;

    var chartBasis = (function () {
        var dimensions,
            graphs = {},
            barCharts = {},
            sprintDays,
            maxPoints,

            svg,

            x, y,

            MAX_TICKS = 35;

        var setSVG = function (svgElementID) {
            svg = d3.select(svgElementID)
                .append('svg')
                    .attr('width', dimensions.width + dimensions.margin.left + dimensions.margin.right)
                    .attr('height', dimensions.height + dimensions.margin.top + dimensions.margin.bottom)
                .append('g')
                    .attr('id', 'graphs')
                    .attr('transform', 'translate(' + dimensions.margin.left + ',' + dimensions.margin.top + ')');
        };

        var addAxes = function () {
            var xAxis = d3.svg.axis().scale(x)
                .orient('bottom')
                .ticks(
                    Math.min(sprintDays.length, MAX_TICKS)
                )
                .tickFormat(d3.time.format('%b %e'));

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

            svg.append('g')
                .attr('class', 'x axis')
                .attr('transform', 'translate(0,' + dimensions.height + ')')
                .call(xAxis)
                .selectAll('text') // aligns the labels on the x-axis for the rotation
                    .style('text-anchor', 'end')
                    .attr('dx', '-.8em')
                    .attr('dy', '.15em');

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

        var loadLabels = function (index) {
            var $labelsTable = $('#graph-labels tbody');

            for (var name in graphs) {
                $labelsTable.append(graphs[name].getLabelHTML(index));
            }
        }

        var showDataPointsLabel = function (position, index) {
            $('#graph-labels').show().css({
                left: position[0] + 20,
                top: position[1] + 30
            });
            loadLabels(index);
        };

        var resetHoverEffects = function () {
            svg.selectAll('.data-point')
                .attr('class', 'data-point');
            svg.selectAll('.x.axis .tick text')
                .style('font-weight', 'normal');
            $('#graph-labels').hide().find('tbody').html('');
        };

        var bisect = d3.bisector(id).left;

        var highlightDataPoints = function (index) {
            svg.selectAll('.data-point:nth-child(' + (index + 1) + ')')
                .attr('class', 'data-point selected');
            svg.select('.x.axis .tick:nth-child(' + (index + 1) + ') text')
                .style('font-weight', 'bold');
        };

        var highlightAtMouse = function () {
            return function () {
                var mouse = d3.mouse(this),
                    xNearMouse = x.invert(mouse[0] - (dimensions.width / sprintDays.length) / 2),
                    indexAtX = bisect(sprintDays, xNearMouse);

                resetHoverEffects();
                highlightDataPoints(indexAtX, xNearMouse);
                showDataPointsLabel(mouse, indexAtX);
            };
        };

        var addHoverOverlay = function () {
            return svg.append('rect')
                .attr('id', 'burndown-overlay')
                .attr('width', dimensions.width)
                .attr('height', dimensions.height)
                .on('mouseout', resetHoverEffects);
        };

        var addHoverEffects = function () {
            var overlay = addHoverOverlay();

            overlay.on('mousemove', highlightAtMouse());
            overlay.on('mouseout', resetHoverEffects);
        };

        var setDomain = function () {
            x = d3.time.scale().range([0, dimensions.width]);
            y = d3.scale.linear().range([dimensions.height, 0]);

            x.domain(d3.extent(sprintDays, id));
            y.domain([0, maxPoints]);
        };

        var renderGraphs = function () {
            for (var name in graphs) {
                graphs[name].render();
            }
        };

        var renderBarCharts = function () {
            for (var name in barCharts) {
                barCharts[name].render();
            }
        };

        return {
            /**
             * @param {Date[]} days - List of days in the sprint
             * @param {int} max - The maximal total number of story points in the sprint
             */
            init: function (days, max) {
                sprintDays = days;
                maxPoints = max;
            },

            /**
             * @param {Graph[]} lineGraphs - Graphs to be rendered in the chart
             */
            addGraphs: function (lineGraphs) {
                graphs = lineGraphs;
            },

            /**
             * @param {BarChart[]} bars - BarCharts to be displayed on the bottom of the chart
             */
            addBarCharts: function (bars) {
                barCharts = bars;
            },

            /**
             * @param {string} id - The ID of the element where the burndown chart will be shown
             * @param {Object} chartDimensions - An object containing height, width, margin.top, margin.right, margin.bottom, margin.left
             */
            render: function (id, chartDimensions) {
                dimensions = chartDimensions;

                setSVG(id);
                setDomain();

                addAxes();
                renderBarCharts();
                renderGraphs();
                addHoverEffects();
            },

            /**
             * @returns Returns the d3 function which translates a date to a point in the chart
             */
            getX: function () {
                return x;
            },

            /**
             * @returns Returns the d3 function which translates a number of story points to a point in the chart
             */
            getY: function () {
                return y;
            }
        };
    })();

    var graphsData = function () {
        var remainingPointsPerDay,
            pointsClosedBeforeSprint,
            sprintData,
            totalPoints;

        var calculateActualProgressData = function (closedPerDay) {
            return [{ // adding another "day" so that the progress of the first day is not hidden
                day: dayBefore(closedPerDay[0].date),
                points: totalPoints - pointsClosedBeforeSprint
            }].concat(closedPerDay.map(function (day) {
                return {
                    day: day.date,
                    points: totalPoints - day.points
                };
            }));
        };

        var isWeekend = function (date) {
            return date.getDay() % 6 === 0;
        };

        var countWeekendDays = function (data) {
            var count = 0;

            data.forEach(function (data, i) {
                if (isWeekend(data.day) && i !== 0) count++;
            });

            return count;
        };

        var prepareData = function (data) {
            return data.map(function (d) {
                d.date = formatDate(d.date);

                return d;
            })
        };

        var calculatePointsClosedPerDay = function (totalPoints, remainingPointsPerDay) {
            var previous = totalPoints;

            return remainingPointsPerDay.map(function (remaining) {
                var closedThatDay = previous - remaining.points;
                previous = remaining.points;

                return {
                    day: remaining.day,
                    points: closedThatDay
                };
            });
        };

        return {
            /**
             * @param {Object} closedPerDate - An object with date strings as its keys and number of closed points as values
             * @param {number} closedBeforeSprint - Number of story points that were closed before the sprint start
             */
            init: function (closedPerDate, closedBeforeSprint) {
                totalPoints = closedPerDate[0].scope;
                pointsClosedBeforeSprint = closedBeforeSprint;
                sprintData = prepareData(closedPerDate);
                remainingPointsPerDay = calculateActualProgressData(sprintData);
            },

            /**
             * @returns {number} Total number of story points in this sprint
             */
            getTotalPoints: function () {
                return totalPoints;
            },

            /**
             * The data represented by the line in the burndown chart.
             * It returns a list of the days of the sprint as well as the number of unclosed points at that day.
             * @returns {Object[]} List of Objects of the form { day: 'yyyy-mm-dd', points: numberOfRemainingPoints }
             */
            getBurndownData: function () {
                return remainingPointsPerDay;
            },

            /**
             * The data represented by bar charts in the diagram.
             * It returns a list of the days of the sprint as well as the number of points closed on that day.
             * @returns {Object[]} List of Objects of the form { day: 'yyyy-mm-dd', points: numberOfClosedPoints }
             */
            getPointsClosedPerDay: function () {
                return calculatePointsClosedPerDay(totalPoints, remainingPointsPerDay);
            },

            /**
             * The data represented by the dashed green line.
             * It contains the days of the sprint as well as the ideal number of points (= total points / (number of days - weekend days)) to be closed on a day.
             * @returns {Object[]}
             */
            getIdealGraphData: function () {
                var averagePointsPerDay = totalPoints / (remainingPointsPerDay.length - countWeekendDays(remainingPointsPerDay) - 1),
                    idealData = [],
                    remaining = totalPoints;

                remainingPointsPerDay.forEach(function (day) {
                    idealData.push({ day: day.day, points: remaining });
                    if (!isWeekend(dayAfter(day.day))) remaining -= averagePointsPerDay;
                });

                return idealData;
            },

            /**
             * @returns {Date[]}
             */
            getDaysInSprint: function () {
                return [ // adding another "day" so that the progress of the first day is not hidden
                    dayBefore(sprintData[0].date)
                ].concat(sprintData.map(function (day) {
                    return day.date;
                }));
            },

            /**
             * @returns {int} - Maximal total number of points in the sprint
             */
            getMaxPoints: function () {
                return d3.max(sprintData, function (day) { return day.scope; });
            },

            /**
             * @returns {Object[]} - Returns line chart data for the scope line
             */
            getScopeLine: function () {
                return [{ // adding another "day" so that the progress of the first day is not hidden
                    day: dayBefore(sprintData[0].date),
                    points: sprintData[0].scope
                }].concat(sprintData.map(function (day) {
                    return {
                        day: day.date,
                        points: day.scope
                    };
                }));
            },

            /**
             * @returns {Object[]} - Returns line chart data for the burnup chart
             */
            getBurnupData: function () {
                return [{ // adding another "day" so that the progress of the first day is not hidden
                    day: dayBefore(sprintData[0].date),
                    points: pointsClosedBeforeSprint
                }].concat(sprintData.map(function (day) {
                    return {
                        day: day.date,
                        points: pointsClosedBeforeSprint + day.points
                    };
                }));
            }
        };
    }();

    /**
     * Objects containing data for line charts which can be rendered.
     * @param {Object[]} data
     * @param {string} id - Its CSS id
     * @param {string} label - Description text for the graph which will show in the label that appears when hovering
     * @constructor
     */
    var Graph = function(data, id, label) {
        this.data = data;
        this.id = id;
        this.label = label;

        this.line = d3.svg.line()
            .x(xOfDay)
            .y(yOfPoints);

        this.addDataPoints = function () {
            this.plane.append('g')
                .attr('id', id + '-data-points')
                .selectAll('.data-point')
                .data(data)
                .enter()
                .append('circle')
                    .attr('class', 'data-point')
                    .attr('r', 4)
                    .attr('cx', xOfDay)
                    .attr('cy', yOfPoints);
        };
    };

    Graph.prototype = {
        constructor: Graph,

        /**
         * @param i - The data list index that the mouse is hovering
         * @returns {string} - The label HTML
         */
        getLabelHTML: function (i) {
            return '
'
                + '' + this.label + '	'
                + ''
                + Math.round(this.data[Math.min(this.data.length - 1, i)].points)
                + '	'
                + '
';
        },

        /**
         * Renders the graph on the chart
         */
        render: function () {
            this.plane = d3.select('#graphs');

            this.plane.append('path')
                .attr('class', 'graph ' + this.id)
                .attr('d', this.line(this.data));

            this.addDataPoints()
        }
    };

    /**
     * Same as Graph but also renders graph areas under the line.
     * ProgressGraph will be limited to dates <= today.
     * @param data
     * @param id
     * @param label
     * @constructor
     */
    var ProgressGraph = function (data, id, label) {
        data = data.filter(function (d) {
            var $snapshotDate = $('#snapshot-date'),
                filterDate = $snapshotDate.length > 0 ? Date.parse($snapshotDate.text()) : new Date();

            return d.day <= filterDate;
        });

        Graph.call(this, data, id, label);

        this.addGraphArea = function () {
            this.plane.append('path')
                .datum(this.data)
                .attr('class', 'graph-area')
                .attr('d', d3.svg.area()
                    .x(xOfDay)
                    .y0(chartBasis.getY()(0))
                    .y1(yOfPoints));
        }
    }

    ProgressGraph.prototype = new Graph;
    ProgressGraph.prototype.render = function () {
        Graph.prototype.render.call(this);
        this.addGraphArea();
    };

    /**
     * Objects that contain data for bars that will be rendered at the bottom of the chart
     * @param data
     * @param id
     * @param label
     * @constructor
     */
    var BarChart = function (data, id, label) {
        this.data = data;
        this.id = id;
        this.label = label;
    };

    BarChart.prototype = {
        constructor: BarChart,

        /**
         * Renders the bar charts inside the burndown/burnup chart
         */
        render: function () {
            d3.select('#graphs').selectAll(this.id)
                .data(this.data)
                .enter().append('line')
                    .attr('class', 'daily-points')
                    .attr('x1', xOfDay)
                    .attr('y1', chartBasis.getY()(0))
                    .attr('x2', xOfDay)
                    .attr('y2', yOfPoints);
        }
    };

    var $chartData = $('#chart-data');
    graphsData.init(
        $.parseJSON($chartData.text()),
        +$chartData.data('before')
    );

    chartBasis.init(graphsData.getDaysInSprint(), graphsData.getMaxPoints());
    chartBasis.addGraphs({
        burnup: new ProgressGraph(graphsData.getBurnupData(), 'burn-up', 'Completed'),
        scope: new Graph(graphsData.getScopeLine(), 'scope', 'Scope'),
        burndown: new ProgressGraph(graphsData.getBurndownData(), 'actual', 'Remaining '),
        ideal: new Graph(graphsData.getIdealGraphData(), 'ideal', 'Ideal')
    });
    chartBasis.addBarCharts({
        closedPerDay: new BarChart(graphsData.getPointsClosedPerDay(), 'daily-points', 'Closed')
    });
    chartBasis.render(
        '#burndown',
        {
            height: 400,
            width: 600,

            margin: { top: 10, right: 10, bottom: 50, left: 30 }
        }
    );
})();
<commit_msg>Change id to cssID.<commit_after>(function () {
    var dayBefore = function (date) {
        var previous = new Date(date);
        previous.setDate(date.getDate() - 1);

        return previous;
    };

    var dayAfter = function (date) {
        var next = new Date(date);
        next.setDate(date.getDate() + 1);

        return next;
    };

    var xOfDay = function (d) { return chartBasis.getX()(d.day); },
        yOfPoints = function (d) { return chartBasis.getY()(d.points);},
        id = function (val) { return val;},
        formatDate = d3.time.format('%Y-%m-%d').parse;

    var chartBasis = (function () {
        var dimensions,
            graphs = {},
            barCharts = {},
            sprintDays,
            maxPoints,

            svg,

            x, y,

            MAX_TICKS = 35;

        var setSVG = function (svgElementID) {
            svg = d3.select(svgElementID)
                .append('svg')
                    .attr('width', dimensions.width + dimensions.margin.left + dimensions.margin.right)
                    .attr('height', dimensions.height + dimensions.margin.top + dimensions.margin.bottom)
                .append('g')
                    .attr('id', 'graphs')
                    .attr('transform', 'translate(' + dimensions.margin.left + ',' + dimensions.margin.top + ')');
        };

        var addAxes = function () {
            var xAxis = d3.svg.axis().scale(x)
                .orient('bottom')
                .ticks(
                    Math.min(sprintDays.length, MAX_TICKS)
                )
                .tickFormat(d3.time.format('%b %e'));

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

            svg.append('g')
                .attr('class', 'x axis')
                .attr('transform', 'translate(0,' + dimensions.height + ')')
                .call(xAxis)
                .selectAll('text') // aligns the labels on the x-axis for the rotation
                    .style('text-anchor', 'end')
                    .attr('dx', '-.8em')
                    .attr('dy', '.15em');

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

        var loadLabels = function (index) {
            var $labelsTable = $('#graph-labels tbody');

            for (var name in graphs) {
                $labelsTable.append(graphs[name].getLabelHTML(index));
            }
        }

        var showDataPointsLabel = function (position, index) {
            $('#graph-labels').show().css({
                left: position[0] + 20,
                top: position[1] + 30
            });
            loadLabels(index);
        };

        var resetHoverEffects = function () {
            svg.selectAll('.data-point')
                .attr('class', 'data-point');
            svg.selectAll('.x.axis .tick text')
                .style('font-weight', 'normal');
            $('#graph-labels').hide().find('tbody').html('');
        };

        var bisect = d3.bisector(id).left;

        var highlightDataPoints = function (index) {
            svg.selectAll('.data-point:nth-child(' + (index + 1) + ')')
                .attr('class', 'data-point selected');
            svg.select('.x.axis .tick:nth-child(' + (index + 1) + ') text')
                .style('font-weight', 'bold');
        };

        var highlightAtMouse = function () {
            return function () {
                var mouse = d3.mouse(this),
                    xNearMouse = x.invert(mouse[0] - (dimensions.width / sprintDays.length) / 2),
                    indexAtX = bisect(sprintDays, xNearMouse);

                resetHoverEffects();
                highlightDataPoints(indexAtX, xNearMouse);
                showDataPointsLabel(mouse, indexAtX);
            };
        };

        var addHoverOverlay = function () {
            return svg.append('rect')
                .attr('id', 'burndown-overlay')
                .attr('width', dimensions.width)
                .attr('height', dimensions.height)
                .on('mouseout', resetHoverEffects);
        };

        var addHoverEffects = function () {
            var overlay = addHoverOverlay();

            overlay.on('mousemove', highlightAtMouse());
            overlay.on('mouseout', resetHoverEffects);
        };

        var setDomain = function () {
            x = d3.time.scale().range([0, dimensions.width]);
            y = d3.scale.linear().range([dimensions.height, 0]);

            x.domain(d3.extent(sprintDays, id));
            y.domain([0, maxPoints]);
        };

        var renderGraphs = function () {
            for (var name in graphs) {
                graphs[name].render();
            }
        };

        var renderBarCharts = function () {
            for (var name in barCharts) {
                barCharts[name].render();
            }
        };

        return {
            /**
             * @param {Date[]} days - List of days in the sprint
             * @param {int} max - The maximal total number of story points in the sprint
             */
            init: function (days, max) {
                sprintDays = days;
                maxPoints = max;
            },

            /**
             * @param {Graph[]} lineGraphs - Graphs to be rendered in the chart
             */
            addGraphs: function (lineGraphs) {
                graphs = lineGraphs;
            },

            /**
             * @param {BarChart[]} bars - BarCharts to be displayed on the bottom of the chart
             */
            addBarCharts: function (bars) {
                barCharts = bars;
            },

            /**
             * @param {string} id - The ID of the element where the burndown chart will be shown
             * @param {Object} chartDimensions - An object containing height, width, margin.top, margin.right, margin.bottom, margin.left
             */
            render: function (id, chartDimensions) {
                dimensions = chartDimensions;

                setSVG(id);
                setDomain();

                addAxes();
                renderBarCharts();
                renderGraphs();
                addHoverEffects();
            },

            /**
             * @returns Returns the d3 function which translates a date to a point in the chart
             */
            getX: function () {
                return x;
            },

            /**
             * @returns Returns the d3 function which translates a number of story points to a point in the chart
             */
            getY: function () {
                return y;
            }
        };
    })();

    var graphsData = function () {
        var remainingPointsPerDay,
            pointsClosedBeforeSprint,
            sprintData,
            totalPoints;

        var calculateActualProgressData = function (closedPerDay) {
            return [{ // adding another "day" so that the progress of the first day is not hidden
                day: dayBefore(closedPerDay[0].date),
                points: totalPoints - pointsClosedBeforeSprint
            }].concat(closedPerDay.map(function (day) {
                return {
                    day: day.date,
                    points: totalPoints - day.points
                };
            }));
        };

        var isWeekend = function (date) {
            return date.getDay() % 6 === 0;
        };

        var countWeekendDays = function (data) {
            var count = 0;

            data.forEach(function (data, i) {
                if (isWeekend(data.day) && i !== 0) count++;
            });

            return count;
        };

        var prepareData = function (data) {
            return data.map(function (d) {
                d.date = formatDate(d.date);

                return d;
            })
        };

        var calculatePointsClosedPerDay = function (totalPoints, remainingPointsPerDay) {
            var previous = totalPoints;

            return remainingPointsPerDay.map(function (remaining) {
                var closedThatDay = previous - remaining.points;
                previous = remaining.points;

                return {
                    day: remaining.day,
                    points: closedThatDay
                };
            });
        };

        return {
            /**
             * @param {Object} closedPerDate - An object with date strings as its keys and number of closed points as values
             * @param {number} closedBeforeSprint - Number of story points that were closed before the sprint start
             */
            init: function (closedPerDate, closedBeforeSprint) {
                totalPoints = closedPerDate[0].scope;
                pointsClosedBeforeSprint = closedBeforeSprint;
                sprintData = prepareData(closedPerDate);
                remainingPointsPerDay = calculateActualProgressData(sprintData);
            },

            /**
             * @returns {number} Total number of story points in this sprint
             */
            getTotalPoints: function () {
                return totalPoints;
            },

            /**
             * The data represented by the line in the burndown chart.
             * It returns a list of the days of the sprint as well as the number of unclosed points at that day.
             * @returns {Object[]} List of Objects of the form { day: 'yyyy-mm-dd', points: numberOfRemainingPoints }
             */
            getBurndownData: function () {
                return remainingPointsPerDay;
            },

            /**
             * The data represented by bar charts in the diagram.
             * It returns a list of the days of the sprint as well as the number of points closed on that day.
             * @returns {Object[]} List of Objects of the form { day: 'yyyy-mm-dd', points: numberOfClosedPoints }
             */
            getPointsClosedPerDay: function () {
                return calculatePointsClosedPerDay(totalPoints, remainingPointsPerDay);
            },

            /**
             * The data represented by the dashed green line.
             * It contains the days of the sprint as well as the ideal number of points (= total points / (number of days - weekend days)) to be closed on a day.
             * @returns {Object[]}
             */
            getIdealGraphData: function () {
                var averagePointsPerDay = totalPoints / (remainingPointsPerDay.length - countWeekendDays(remainingPointsPerDay) - 1),
                    idealData = [],
                    remaining = totalPoints;

                remainingPointsPerDay.forEach(function (day) {
                    idealData.push({ day: day.day, points: remaining });
                    if (!isWeekend(dayAfter(day.day))) remaining -= averagePointsPerDay;
                });

                return idealData;
            },

            /**
             * @returns {Date[]}
             */
            getDaysInSprint: function () {
                return [ // adding another "day" so that the progress of the first day is not hidden
                    dayBefore(sprintData[0].date)
                ].concat(sprintData.map(function (day) {
                    return day.date;
                }));
            },

            /**
             * @returns {int} - Maximal total number of points in the sprint
             */
            getMaxPoints: function () {
                return d3.max(sprintData, function (day) { return day.scope; });
            },

            /**
             * @returns {Object[]} - Returns line chart data for the scope line
             */
            getScopeLine: function () {
                return [{ // adding another "day" so that the progress of the first day is not hidden
                    day: dayBefore(sprintData[0].date),
                    points: sprintData[0].scope
                }].concat(sprintData.map(function (day) {
                    return {
                        day: day.date,
                        points: day.scope
                    };
                }));
            },

            /**
             * @returns {Object[]} - Returns line chart data for the burnup chart
             */
            getBurnupData: function () {
                return [{ // adding another "day" so that the progress of the first day is not hidden
                    day: dayBefore(sprintData[0].date),
                    points: pointsClosedBeforeSprint
                }].concat(sprintData.map(function (day) {
                    return {
                        day: day.date,
                        points: pointsClosedBeforeSprint + day.points
                    };
                }));
            }
        };
    }();

    /**
     * Objects containing data for line charts which can be rendered.
     * @param {Object[]} data
     * @param {string} cssID - Its CSS identifier (used as class or id)
     * @param {string} label - Description text for the graph which will show in the label that appears when hovering
     * @constructor
     */
    var Graph = function(data, cssID, label) {
        this.data = data;
        this.cssID = cssID;
        this.label = label;

        this.line = d3.svg.line()
            .x(xOfDay)
            .y(yOfPoints);

        this.addDataPoints = function () {
            this.plane.append('g')
                .attr('id', cssID + '-data-points')
                .selectAll('.data-point')
                .data(data)
                .enter()
                .append('circle')
                    .attr('class', 'data-point')
                    .attr('r', 4)
                    .attr('cx', xOfDay)
                    .attr('cy', yOfPoints);
        };
    };

    Graph.prototype = {
        constructor: Graph,

        /**
         * @param i - The data list index that the mouse is hovering
         * @returns {string} - The label HTML
         */
        getLabelHTML: function (i) {
            return '
'
                + '' + this.label + '	'
                + ''
                + Math.round(this.data[Math.min(this.data.length - 1, i)].points)
                + '	'
                + '
';
        },

        /**
         * Renders the graph on the chart
         */
        render: function () {
            this.plane = d3.select('#graphs');

            this.plane.append('path')
                .attr('class', 'graph ' + this.cssID)
                .attr('d', this.line(this.data));

            this.addDataPoints()
        }
    };

    /**
     * Same as Graph but also renders graph areas under the line.
     * ProgressGraph will be limited to dates <= today.
     * @param data
     * @param id
     * @param label
     * @constructor
     */
    var ProgressGraph = function (data, cssID, label) {
        data = data.filter(function (d) {
            var $snapshotDate = $('#snapshot-date'),
                filterDate = $snapshotDate.length > 0 ? Date.parse($snapshotDate.text()) : new Date();

            return d.day <= filterDate;
        });

        Graph.call(this, data, cssID, label);

        this.addGraphArea = function () {
            this.plane.append('path')
                .datum(this.data)
                .attr('class', 'graph-area')
                .attr('d', d3.svg.area()
                    .x(xOfDay)
                    .y0(chartBasis.getY()(0))
                    .y1(yOfPoints));
        }
    }

    ProgressGraph.prototype = new Graph;
    ProgressGraph.prototype.render = function () {
        Graph.prototype.render.call(this);
        this.addGraphArea();
    };

    /**
     * Objects that contain data for bars that will be rendered at the bottom of the chart
     * @param data
     * @param id
     * @param label
     * @constructor
     */
    var BarChart = function (data, cssID, label) {
        this.data = data;
        this.cssID = cssID;
        this.label = label;
    };

    BarChart.prototype = {
        constructor: BarChart,

        /**
         * Renders the bar charts inside the burndown/burnup chart
         */
        render: function () {
            d3.select('#graphs').selectAll(this.cssID)
                .data(this.data)
                .enter().append('line')
                    .attr('class', 'daily-points')
                    .attr('x1', xOfDay)
                    .attr('y1', chartBasis.getY()(0))
                    .attr('x2', xOfDay)
                    .attr('y2', yOfPoints);
        }
    };

    var $chartData = $('#chart-data');
    graphsData.init(
        $.parseJSON($chartData.text()),
        +$chartData.data('before')
    );

    chartBasis.init(graphsData.getDaysInSprint(), graphsData.getMaxPoints());
    chartBasis.addGraphs({
        burnup: new ProgressGraph(graphsData.getBurnupData(), 'burn-up', 'Completed'),
        scope: new Graph(graphsData.getScopeLine(), 'scope', 'Scope'),
        burndown: new ProgressGraph(graphsData.getBurndownData(), 'actual', 'Remaining '),
        ideal: new Graph(graphsData.getIdealGraphData(), 'ideal', 'Ideal')
    });
    chartBasis.addBarCharts({
        closedPerDay: new BarChart(graphsData.getPointsClosedPerDay(), 'daily-points', 'Closed')
    });
    chartBasis.render(
        '#burndown',
        {
            height: 400,
            width: 600,

            margin: { top: 10, right: 10, bottom: 50, left: 30 }
        }
    );
})();
<|endoftext|>


<commit_before>/*global $,document,console*/
/*global FastClick*/

/* initialize FastClick */
$(function () {
	FastClick.attach(document.body);
});

/* config jQM */
$(document).on("mobileinit", function () {
	console.log("jQuery Mobile initialized");
	$.mobile.loader.prototype.options.text = "LOADING";
	$.mobile.loader.prototype.options.textVisible = true;
	$.mobile.loader.prototype.options.textonly = true;
});<commit_msg>remove custom jqm loader style<commit_after>/*global $,document,console*/
/*global FastClick*/

/* initialize FastClick */
$(function () {
    FastClick.attach(document.body);
});

/* config jQM */
$(document).on("mobileinit", function () {
    // jqm config
});<|endoftext|>


<commit_before>AE.SESSION_TIME_OUT_WARNING=10 * 60 ; //timeout duration in seconds
AE.SESSION_TIME_OUT_WAIT= 1 * 60;
AE.SESSION_TIMED_OUT = false;
AE.SESSION_TIMER_ID;
AE.SESSION_TIME_OUT_ENABLED = true;
//----------------------------------------------------------------------------------------------------------------
// INITIALIZE THE TIMER
Event.observe(window, 'load', function(){
	if(AE.SESSION_TIME_OUT_ENABLED){
		resetLogoutTimer();
	}
});

Event.observe(window, 'mousemove', function(){
	if(AE.SESSION_TIME_OUT_ENABLED){
		resetLogoutTimer();
	}

});

//----------------------------------------------------------------------------------------------------------------
// reset the timer
function resetLogoutTimer() {
  if(AE.SESSION_TIMER_ID){
	  window.clearTimeout(AE.SESSION_TIMER_ID);
	 // $('logout_warning').hide();
  }
  AE.SESSION_TIMER_ID = logoutWarning.delay(AE.SESSION_TIME_OUT_WARNING);
}

//----------------------------------------------------------------------------------------------------------------
//shows the warning box
function logoutWarning() {
  var warnDiv = new Window({className: "alphacube", width:580, height:190, zIndex: 100, resizable: true, recenterAuto:true, draggable:true});
  warnWindow.setContent('logout_warning');
  warnWindow.showCenter(true);
  warnWindow.show();
  AE.SESSION_TIMER_ID = timeoutSession.delay(AE.SESSION_TIME_OUT_WAIT);
}
function timeoutSession() {
	AE.SESSION_TIMED_OUT = true;
}

// ----------------------------------------------------------------------------------------------------------------
function logOutOKClicked(url){
	Windows.closeAll();
	if(AE.SESSION_TIMED_OUT) window.location=url;
}

<commit_msg>removing the close <commit_after>AE.SESSION_TIME_OUT_WARNING=10 * 60 ; //timeout duration in seconds
AE.SESSION_TIME_OUT_WAIT= 1 * 60;
AE.SESSION_TIMED_OUT = false;
AE.SESSION_TIMER_ID;
AE.SESSION_TIME_OUT_ENABLED = true;
//----------------------------------------------------------------------------------------------------------------
// INITIALIZE THE TIMER
Event.observe(window, 'load', function(){
	if(AE.SESSION_TIME_OUT_ENABLED){
		resetLogoutTimer();
	}
});

Event.observe(window, 'mousemove', function(){
	if(AE.SESSION_TIME_OUT_ENABLED){
		resetLogoutTimer();
	}

});

//----------------------------------------------------------------------------------------------------------------
// reset the timer
function resetLogoutTimer() {
  if(AE.SESSION_TIMER_ID){
	  window.clearTimeout(AE.SESSION_TIMER_ID);
	 // $('logout_warning').hide();
  }
  AE.SESSION_TIMER_ID = logoutWarning.delay(AE.SESSION_TIME_OUT_WARNING);
}

//----------------------------------------------------------------------------------------------------------------
//shows the warning box
function logoutWarning() {
  var warnDiv = new Window({className: "alphacube", width:580, height:190, zIndex: 100, resizable: true, recenterAuto:true, draggable:true, closable:false});
  warnWindow.setContent('logout_warning');
  warnWindow.showCenter(true);
  warnWindow.show();
  AE.SESSION_TIMER_ID = timeoutSession.delay(AE.SESSION_TIME_OUT_WAIT);
}
function timeoutSession() {
	AE.SESSION_TIMED_OUT = true;
}

// ----------------------------------------------------------------------------------------------------------------
function logOutOKClicked(url){
	Windows.closeAll();
	if(AE.SESSION_TIMED_OUT) window.location=url;
}

<|endoftext|>


<commit_before>import * as R from 'ramda'
import * as React from 'react'

import { PreviewData } from '../types'
import * as utils from './utils'
import * as Json from './Json'
import * as Voila from './Voila'

export const detect = R.pipe(utils.stripCompression, utils.extIs('.ipynb'))

function NotebookLoader({ handle, children }) {
  const data = utils.usePreview({ type: 'ipynb', handle })
  const processed = utils.useProcessing(data.result, (json) =>
    PreviewData.Notebook({
      preview: json.html,
      note: json.info.note,
      warnings: json.info.warnings,
    }),
  )
  return children(utils.useErrorHandling(processed, { handle, retry: data.fetch }))
}

export const Loader = function WrappedNotebookLoader({ handle, children, options }) {
  switch (options.mode) {
    case 'voila':
      return <Voila.Loader {...{ handle, children }} />
    case 'json':
      return <Json.Loader {...{ handle, children }} />
    default:
      return <NotebookLoader {...{ handle, children }} />
  }
}
<commit_msg>Fix Notebook to JSON crash (#3063)<commit_after>import * as R from 'ramda'
import * as React from 'react'

import { PreviewData } from '../types'
import * as utils from './utils'
import * as Json from './Json'
import * as Voila from './Voila'

export const detect = R.pipe(utils.stripCompression, utils.extIs('.ipynb'))

function NotebookLoader({ handle, children }) {
  const data = utils.usePreview({ type: 'ipynb', handle })
  const processed = utils.useProcessing(data.result, (json) =>
    PreviewData.Notebook({
      preview: json.html,
      note: json.info.note,
      warnings: json.info.warnings,
    }),
  )
  return children(utils.useErrorHandling(processed, { handle, retry: data.fetch }))
}

export const Loader = function WrappedNotebookLoader({ handle, children, options }) {
  switch (options.mode) {
    case 'voila':
      return <Voila.Loader {...{ handle, children }} />
    case 'json':
      return <Json.Loader {...{ handle, children, options }} />
    default:
      return <NotebookLoader {...{ handle, children }} />
  }
}
<|endoftext|>