<commit_before>$(function() {
  $('a[href*=#]:not([href=#])').click(function() {
    if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') || location.hostname == this.hostname) {

      var target = $(this.hash);
      target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
      if (target.length) {
        $('html,body').animate({
          scrollTop: target.offset().top
        }, 1000);
        return false;
      }
    }
  });

  $("#hmda-lar-fields tbody").each(function () {
    var $body = $(this);

    var ajax = $.ajax({
      url: "../static/hmda_lar.json",
      dataType: "json"
    });

    ajax.done(function (data) {
      var fields = data['fields'];
      var fieldNames = _(fields).keys().sort();

      _(fieldNames).each(function (fieldName) {
        var info = fields[fieldName];
        var $row = $("

");
        $row.
          append("" + fieldName + "	").
          append("" + info['description'] + "	").
          append("" + info['type'] + "	").
          append("" + (info['indexed'] ? "true" : "false") + "	");
        $body.append($row);
      });
    });
  });
});<commit_msg>Pointed to sam_registrations.json<commit_after>$(function() {
  $('a[href*=#]:not([href=#])').click(function() {
    if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') || location.hostname == this.hostname) {

      var target = $(this.hash);
      target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
      if (target.length) {
        $('html,body').animate({
          scrollTop: target.offset().top
        }, 1000);
        return false;
      }
    }
  });

  $("#hmda-lar-fields tbody").each(function () {
    var $body = $(this);

    var ajax = $.ajax({
      url: "../static/sam_registrations.json",
      dataType: "json"
    });

    ajax.done(function (data) {
      var fields = data['fields'];
      var fieldNames = _(fields).keys().sort();

      _(fieldNames).each(function (fieldName) {
        var info = fields[fieldName];
        var $row = $("

");
        $row.
          append("" + fieldName + "	").
          append("" + info['description'] + "	").
          append("" + info['type'] + "	").
          append("" + (info['indexed'] ? "true" : "false") + "	");
        $body.append($row);
      });
    });
  });
});
<|endoftext|>


<commit_before>/*
This file is part of Kronekeeper, a web based application for
recording and managing wiring frame records.

Copyright (C) 2016 NP Broadcast Limited

Kronekeeper is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Kronekeeper is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with Kronekeeper.  If not, see <http://www.gnu.org/licenses/>.

*/

require([
	'backbone',
        'jquery',
	'jqueryui'
], function (

) {
        'use strict';

	var Circuit_Model = Backbone.Model.extend({

		idAttribute: 'circuit_id',
		urlRoot: '/api/circuit',

		defaults: {
			block_id: null,
			circuit_id: null,
			designation: null,
			name: null,
			cable_reference: null,
			jumpers: []
		}

	});

	var Circuits_Collection = Backbone.Collection.extend({

		model: Circuit_Model,
		url: function() {
			return '/api/block/' + this.block_id;
		},

		initialize: function(args) {
			this.block_id = args.block_id;
		},

		parse: function(data) {
			return data.circuits;
		}
	});

	var Circuit_View = Backbone.View.extend({

		tagName: 'tr',
		className: 'circuit',

		events: {
			'click a.add_jumper' : 'add_jumper',
			'input .circuit_name input' : 'circuit_name_input',
			'change .circuit_name input' : 'circuit_name_change',
			'input .cable_reference input' : 'cable_reference_input',
			'change .cable_reference input' : 'cable_reference_change'
		},

		initialize: function() {
			this.listenTo(this.model, 'sync', this.model_synced);
		},

		template: _.template( $('#row_template').html() ),

		render: function() {
			var json = this.model.toJSON();
			json.jumper_text = json.jumpers.join('; ');
			this.$el.html(this.template(json));
			return this;
		},

		add_jumper: function(e) {
			console.log("Add jumper");
			console.log(e);
		},

		circuit_name_input: function(e) {
			this.highlight_change(e, 'name');
		},

		cable_reference_input: function(e) {
			this.highlight_change(e, 'cable_reference');
		},

		highlight_change: function(e, attribute_name) {
			if(e.target.value != this.model.attributes[attribute_name]) {
				e.target.parentNode.classList.add('change_pending');
			}
			else {
				e.target.parentNode.classList.remove('change_pending');
			}
		},

		circuit_name_change: function(e) {
			this.save_data({name: e.target.value});
		},

		cable_reference_change: function(e) {
			this.save_data({cable_reference: e.target.value});
		},

		save_data: function(data) {
			this.model.save(data, {
				patch: true,
				success: function(model, response, options) {
					console.log("circuit data saved");
				},
				error: function(model, xhr, options) {
					console.log("ERROR saving circuit data");
				}
			});
		},

		model_synced: function(model, response, options) {
			/* Clear field highlighting and flash green to indicate successful save */
			if('name' in response) {
				this.$el.find("td.circuit_name").removeClass('change_pending');
				this.$el.find("td.circuit_name").effect("highlight", {color: "#deffde"}, 500);
			};
			if('cable_reference' in response) {
				this.$el.find("td.cable_reference").removeClass('change_pending');
				this.$el.find("td.cable_reference").effect("highlight", {color: "#deffde"}, 500);
			};

		}

	});

	var Block_View = Backbone.View.extend({

		el: '#block_table_body',

		initialize: function() {
			this.listenTo(this.collection, 'reset', this.render);
		},

		render: function() {
			console.log("rendering Block_View");
			this.collection.each(function(model) {
				//console.log(model);
				var row = new Circuit_View({model: model});
				$('#block_table_body').append(row.render().$el);

			}, this);

			return this;
		}
	});

	var circuit_list = new Circuits_Collection({block_id: window.block_id});
	var view = new Block_View({collection: circuit_list});

	circuit_list.fetch({
		reset: true,
		success: function(collection, response, options) {
			console.log("fetched circuit list OK");
		},
		error: function(collection, response, options) {
			console.log("ERROR: failed to fetch circuit list");
		}
	});

	console.log("loaded block.js");

});

<commit_msg>Block display: pressing escape resets value of Circuit and Cable fields<commit_after>/*
This file is part of Kronekeeper, a web based application for
recording and managing wiring frame records.

Copyright (C) 2016 NP Broadcast Limited

Kronekeeper is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Kronekeeper is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with Kronekeeper.  If not, see <http://www.gnu.org/licenses/>.

*/

require([
	'backbone',
        'jquery',
	'jqueryui'
], function (

) {
        'use strict';

	var Circuit_Model = Backbone.Model.extend({

		idAttribute: 'circuit_id',
		urlRoot: '/api/circuit',

		defaults: {
			block_id: null,
			circuit_id: null,
			designation: null,
			name: null,
			cable_reference: null,
			jumpers: []
		}

	});

	var Circuits_Collection = Backbone.Collection.extend({

		model: Circuit_Model,
		url: function() {
			return '/api/block/' + this.block_id;
		},

		initialize: function(args) {
			this.block_id = args.block_id;
		},

		parse: function(data) {
			return data.circuits;
		}
	});

	var Circuit_View = Backbone.View.extend({

		tagName: 'tr',
		className: 'circuit',

		events: {
			'click a.add_jumper' : 'add_jumper',
			'input .circuit_name input' : 'circuit_name_input',
			'change .circuit_name input' : 'circuit_name_change',
			'keypress .circuit_name input' : 'circuit_name_keypress',
			'input .cable_reference input' : 'cable_reference_input',
			'change .cable_reference input' : 'cable_reference_change',
			'keypress .cable_reference input' : 'cable_reference_keypress',
		},

		initialize: function() {
			this.listenTo(this.model, 'sync', this.model_synced);
		},

		template: _.template( $('#row_template').html() ),

		render: function() {
			var json = this.model.toJSON();
			json.jumper_text = json.jumpers.join('; ');
			this.$el.html(this.template(json));
			return this;
		},

		add_jumper: function(e) {
			console.log("Add jumper");
			console.log(e);
		},

		circuit_name_keypress: function(e) {
			this.reset_on_escape_key(e, 'name');
		},

		cable_reference_keypress: function(e) {
			this.reset_on_escape_key(e, 'cable_reference');
		},

		reset_on_escape_key(e, attribute_name) {
			if(e.keyCode == 27) {
				e.target.value = this.model.attributes[attribute_name];
				e.target.parentNode.classList.remove('change_pending');
			}
		},

		circuit_name_input: function(e) {
			this.highlight_change(e, 'name');
		},

		cable_reference_input: function(e) {
			this.highlight_change(e, 'cable_reference');
		},

		highlight_change: function(e, attribute_name) {
			if(e.target.value != this.model.attributes[attribute_name]) {
				e.target.parentNode.classList.add('change_pending');
			}
			else {
				e.target.parentNode.classList.remove('change_pending');
			}
		},

		circuit_name_change: function(e) {
			this.save_data({name: e.target.value});
		},

		cable_reference_change: function(e) {
			this.save_data({cable_reference: e.target.value});
		},

		save_data: function(data) {
			this.model.save(data, {
				patch: true,
				success: function(model, response, options) {
					console.log("circuit data saved");
				},
				error: function(model, xhr, options) {
					console.log("ERROR saving circuit data");
				}
			});
		},

		model_synced: function(model, response, options) {
			/* Clear field highlighting and flash green to indicate successful save */
			if('name' in response) {
				this.$el.find("td.circuit_name").removeClass('change_pending');
				this.$el.find("td.circuit_name").effect("highlight", {color: "#deffde"}, 500);
			};
			if('cable_reference' in response) {
				this.$el.find("td.cable_reference").removeClass('change_pending');
				this.$el.find("td.cable_reference").effect("highlight", {color: "#deffde"}, 500);
			};

		}

	});

	var Block_View = Backbone.View.extend({

		el: '#block_table_body',

		initialize: function() {
			this.listenTo(this.collection, 'reset', this.render);
		},

		render: function() {
			console.log("rendering Block_View");
			this.collection.each(function(model) {
				//console.log(model);
				var row = new Circuit_View({model: model});
				$('#block_table_body').append(row.render().$el);

			}, this);

			return this;
		}
	});

	var circuit_list = new Circuits_Collection({block_id: window.block_id});
	var view = new Block_View({collection: circuit_list});

	circuit_list.fetch({
		reset: true,
		success: function(collection, response, options) {
			console.log("fetched circuit list OK");
		},
		error: function(collection, response, options) {
			console.log("ERROR: failed to fetch circuit list");
		}
	});

	console.log("loaded block.js");

});

<|endoftext|>


<commit_before>/*  this view should own everything on the page which has controls effecting its operation
   generate other views for the individual editors.
   The render here adds views for each update/handout by delegating to their collections but does not
   generate any html for the surrounding page.
*/
CMS.Views.CourseInfoEdit = Backbone.View.extend({
  // takes CMS.Models.CourseInfo as model
  tagName: 'div',

  render: function() {
    // instantiate the ClassInfoUpdateView and delegate the proper dom to it
    new CMS.Views.ClassInfoUpdateView({
        el: this.$('#course-update-view'),
        collection: this.model.get('updates')
    });

    new CMS.Views.ClassInfoHandoutsView({
        el: this.$('#course-handouts-view'),
        model: this.model.get('handouts')
    });
    return this;
  }
});

// ??? Programming style question: should each of these classes be in separate files?
CMS.Views.ClassInfoUpdateView = Backbone.View.extend({
    // collection is CourseUpdateCollection
    events: {
        "click .new-update-button" : "onNew",
        "click .save-button" : "onSave",
        "click .cancel-button" : "onCancel",
        "click .edit-button" : "onEdit",
        "click .delete-button" : "onDelete"
    },

    initialize: function() {
    	var self = this;
        // instantiates an editor template for each update in the collection
        window.templateLoader.loadRemoteTemplate("course_info_update",
        	// TODO Where should the template reside? how to use the static.url to create the path?
            "/static/client_templates/course_info_update.html",
            function (raw_template) {
        		self.template = _.template(raw_template);
        		self.render();
            }
        );
    },

    render: function () {
          // iterate over updates and create views for each using the template
          var updateEle = this.$el.find("#course-update-list");
          // remove and then add all children
          $(updateEle).empty();
          var self = this;
          this.collection.each(function (update) {
        	  var newEle = self.template({ updateModel : update });
              $(updateEle).append(newEle);
          });
          this.$el.find(".new-update-form").hide();
          this.$el.find('.date').datepicker({ 'dateFormat': 'MM d, yy' });
          return this;
    },

    onNew: function(event) {
        var self = this;
        // create new obj, insert into collection, and render this one ele overriding the hidden attr
        var newModel = new CMS.Models.CourseUpdate();
        this.collection.add(newModel, {at : 0});

        var $newForm = $(this.template({ updateModel : newModel }));

        var $textArea = $newForm.find(".new-update-content").first();
        if (this.$codeMirror == null ) {
            this.$codeMirror = CodeMirror.fromTextArea($textArea.get(0), {
                mode: "text/html",
                lineNumbers: true,
                lineWrapping: true,
            });
        }

        var updateEle = this.$el.find("#course-update-list");
        $(updateEle).prepend($newForm);
        $newForm.addClass('editing');
        this.$currentPost = $newForm.closest('li');

        window.$modalCover.show();
        window.$modalCover.bind('click', function() {
            self.closeEditor(self, true);
        });

        $('.date').datepicker('destroy');
        $('.date').datepicker({ 'dateFormat': 'MM d, yy' });
    },

    onSave: function(event) {
        var targetModel = this.eventModel(event);
        console.log(this.contentEntry(event).val());
        targetModel.set({ date : this.dateEntry(event).val(), content : this.$codeMirror.getValue() });
        // push change to display, hide the editor, submit the change
        this.closeEditor(this);
        targetModel.save();
    },

    onCancel: function(event) {
        // change editor contents back to model values and hide the editor
        $(this.editor(event)).hide();
        var targetModel = this.eventModel(event);
        this.closeEditor(this, !targetModel.id);
    },

    onEdit: function(event) {
        var self = this;
        this.$currentPost = $(event.target).closest('li');
        this.$currentPost.addClass('editing');

        $(this.editor(event)).show();
        var $textArea = this.$currentPost.find(".new-update-content").first();
        if (this.$codeMirror == null ) {
            this.$codeMirror = CodeMirror.fromTextArea($textArea.get(0), {
                mode: "text/html",
                lineNumbers: true,
                lineWrapping: true,
            });
        }

        window.$modalCover.show();
        var targetModel = this.eventModel(event);
        window.$modalCover.bind('click', function() {
            self.closeEditor(self);
        });
    },

    onDelete: function(event) {
        // TODO ask for confirmation
        // remove the dom element and delete the model
        var targetModel = this.eventModel(event);
        this.modelDom(event).remove();
        var cacheThis = this;
        targetModel.destroy({success : function (model, response) {
            cacheThis.collection.fetch({success : function() {cacheThis.render();}});
        }
        });
    },

    closeEditor: function(self, removePost) {
        var targetModel = self.collection.getByCid(self.$currentPost.attr('name'));

        if(removePost) {
            self.$currentPost.remove();
        }

        // close the modal and insert the appropriate data
        self.$currentPost.removeClass('editing');
        self.$currentPost.find('.date-display').html(targetModel.get('date'));
        self.$currentPost.find('.date').val(targetModel.get('date'));
        self.$currentPost.find('.update-contents').html(targetModel.get('content'));
        self.$currentPost.find('.new-update-content').val(targetModel.get('content'));
        self.$currentPost.find('form').hide();
        window.$modalCover.unbind('click');
        window.$modalCover.hide();
    },

    // Dereferencing from events to screen elements
    eventModel: function(event) {
        // not sure if it should be currentTarget or delegateTarget
        return this.collection.getByCid($(event.currentTarget).attr("name"));
    },

    modelDom: function(event) {
        return $(event.currentTarget).closest("li");
    },

    editor: function(event) {
    	var li = $(event.currentTarget).closest("li");
    	if (li) return $(li).find("form").first();
    },

    dateEntry: function(event) {
    	var li = $(event.currentTarget).closest("li");
    	if (li) return $(li).find(".date").first();
    },

    contentEntry: function(event) {
        return $(event.currentTarget).closest("li").find(".new-update-content").first();
    },

    dateDisplay: function(event) {
        return $(event.currentTarget).closest("li").find("#date-display").first();
    },

    contentDisplay: function(event) {
        return $(event.currentTarget).closest("li").find(".update-contents").first();
    }

});

// the handouts view is dumb right now; it needs tied to a model and all that jazz
CMS.Views.ClassInfoHandoutsView = Backbone.View.extend({
    // collection is CourseUpdateCollection
    events: {
        "click .save-button" : "onSave",
        "click .cancel-button" : "onCancel",
        "click .edit-button" : "onEdit"
    },

    initialize: function() {
        var self = this;
        this.model.fetch(
            {
                complete: function() {
                    window.templateLoader.loadRemoteTemplate("course_info_handouts",
                        "/static/client_templates/course_info_handouts.html",
                        function (raw_template) {
                            self.template = _.template(raw_template);
                            self.render();
                        }
                    );
                }
            }
        );
    },

    render: function () {
        var updateEle = this.$el;
        var self = this;
        this.$el.html(
            $(this.template( {
                model: this.model
                })
            )
        );
        this.$preview = this.$el.find('.handouts-content');
        this.$form = this.$el.find(".edit-handouts-form");
        this.$editor = this.$form.find('.handouts-content-editor');
        this.$form.hide();

        return this;
    },

    onEdit: function(event) {
        var self = this;
        this.$editor.val(this.$preview.html());
        this.$form.show();
        if (this.$codeMirror == null) {
            this.$codeMirror = CodeMirror.fromTextArea(this.$editor.get(0), {
                mode: "text/html",
                lineNumbers: true,
                lineWrapping: true,
            });
        }
        window.$modalCover.show();
        window.$modalCover.bind('click', function() {
            self.closeEditor(self);
        });
    },

    onSave: function(event) {
        this.model.set('data', this.$codeMirror.getValue());
        this.render();
        this.model.save();
        this.$form.hide();
        this.closeEditor(this);
    },

    onCancel: function(event) {
        this.$form.hide();
        this.closeEditor(this);
    },

    closeEditor: function(self) {
        this.$form.hide();
        window.$modalCover.unbind('click');
        window.$modalCover.hide();
    }
});<commit_msg>dispose of  when we close the editor<commit_after>/*  this view should own everything on the page which has controls effecting its operation
   generate other views for the individual editors.
   The render here adds views for each update/handout by delegating to their collections but does not
   generate any html for the surrounding page.
*/
CMS.Views.CourseInfoEdit = Backbone.View.extend({
  // takes CMS.Models.CourseInfo as model
  tagName: 'div',

  render: function() {
    // instantiate the ClassInfoUpdateView and delegate the proper dom to it
    new CMS.Views.ClassInfoUpdateView({
        el: this.$('#course-update-view'),
        collection: this.model.get('updates')
    });

    new CMS.Views.ClassInfoHandoutsView({
        el: this.$('#course-handouts-view'),
        model: this.model.get('handouts')
    });
    return this;
  }
});

// ??? Programming style question: should each of these classes be in separate files?
CMS.Views.ClassInfoUpdateView = Backbone.View.extend({
    // collection is CourseUpdateCollection
    events: {
        "click .new-update-button" : "onNew",
        "click .save-button" : "onSave",
        "click .cancel-button" : "onCancel",
        "click .edit-button" : "onEdit",
        "click .delete-button" : "onDelete"
    },

    initialize: function() {
    	var self = this;
        // instantiates an editor template for each update in the collection
        window.templateLoader.loadRemoteTemplate("course_info_update",
        	// TODO Where should the template reside? how to use the static.url to create the path?
            "/static/client_templates/course_info_update.html",
            function (raw_template) {
        		self.template = _.template(raw_template);
        		self.render();
            }
        );
    },

    render: function () {
          // iterate over updates and create views for each using the template
          var updateEle = this.$el.find("#course-update-list");
          // remove and then add all children
          $(updateEle).empty();
          var self = this;
          this.collection.each(function (update) {
        	  var newEle = self.template({ updateModel : update });
              $(updateEle).append(newEle);
          });
          this.$el.find(".new-update-form").hide();
          this.$el.find('.date').datepicker({ 'dateFormat': 'MM d, yy' });
          return this;
    },

    onNew: function(event) {
        var self = this;
        // create new obj, insert into collection, and render this one ele overriding the hidden attr
        var newModel = new CMS.Models.CourseUpdate();
        this.collection.add(newModel, {at : 0});

        var $newForm = $(this.template({ updateModel : newModel }));

        var $textArea = $newForm.find(".new-update-content").first();
        if (this.$codeMirror == null ) {
            this.$codeMirror = CodeMirror.fromTextArea($textArea.get(0), {
                mode: "text/html",
                lineNumbers: true,
                lineWrapping: true,
            });
        }

        var updateEle = this.$el.find("#course-update-list");
        $(updateEle).prepend($newForm);
        $newForm.addClass('editing');
        this.$currentPost = $newForm.closest('li');

        window.$modalCover.show();
        window.$modalCover.bind('click', function() {
            self.closeEditor(self, true);
        });

        $('.date').datepicker('destroy');
        $('.date').datepicker({ 'dateFormat': 'MM d, yy' });
    },

    onSave: function(event) {
        var targetModel = this.eventModel(event);
        console.log(this.contentEntry(event).val());
        targetModel.set({ date : this.dateEntry(event).val(), content : this.$codeMirror.getValue() });
        // push change to display, hide the editor, submit the change
        this.closeEditor(this);
        targetModel.save();
    },

    onCancel: function(event) {
        // change editor contents back to model values and hide the editor
        $(this.editor(event)).hide();
        var targetModel = this.eventModel(event);
        this.closeEditor(this, !targetModel.id);
    },

    onEdit: function(event) {
        var self = this;
        this.$currentPost = $(event.target).closest('li');
        this.$currentPost.addClass('editing');

        $(this.editor(event)).show();
        var $textArea = this.$currentPost.find(".new-update-content").first();
        if (this.$codeMirror == null ) {
            this.$codeMirror = CodeMirror.fromTextArea($textArea.get(0), {
                mode: "text/html",
                lineNumbers: true,
                lineWrapping: true,
            });
        }

        window.$modalCover.show();
        var targetModel = this.eventModel(event);
        window.$modalCover.bind('click', function() {
            self.closeEditor(self);
        });
    },

    onDelete: function(event) {
        // TODO ask for confirmation
        // remove the dom element and delete the model
        var targetModel = this.eventModel(event);
        this.modelDom(event).remove();
        var cacheThis = this;
        targetModel.destroy({success : function (model, response) {
            cacheThis.collection.fetch({success : function() {cacheThis.render();}});
        }
        });
    },

    closeEditor: function(self, removePost) {
        var targetModel = self.collection.getByCid(self.$currentPost.attr('name'));

        if(removePost) {
            self.$currentPost.remove();
        }

        // close the modal and insert the appropriate data
        self.$currentPost.removeClass('editing');
        self.$currentPost.find('.date-display').html(targetModel.get('date'));
        self.$currentPost.find('.date').val(targetModel.get('date'));
        self.$currentPost.find('.update-contents').html(targetModel.get('content'));
        self.$currentPost.find('.new-update-content').val(targetModel.get('content'));
        self.$currentPost.find('form').hide();
        window.$modalCover.unbind('click');
        window.$modalCover.hide();
        this.$codeMirror = null;
    },

    // Dereferencing from events to screen elements
    eventModel: function(event) {
        // not sure if it should be currentTarget or delegateTarget
        return this.collection.getByCid($(event.currentTarget).attr("name"));
    },

    modelDom: function(event) {
        return $(event.currentTarget).closest("li");
    },

    editor: function(event) {
    	var li = $(event.currentTarget).closest("li");
    	if (li) return $(li).find("form").first();
    },

    dateEntry: function(event) {
    	var li = $(event.currentTarget).closest("li");
    	if (li) return $(li).find(".date").first();
    },

    contentEntry: function(event) {
        return $(event.currentTarget).closest("li").find(".new-update-content").first();
    },

    dateDisplay: function(event) {
        return $(event.currentTarget).closest("li").find("#date-display").first();
    },

    contentDisplay: function(event) {
        return $(event.currentTarget).closest("li").find(".update-contents").first();
    }

});

// the handouts view is dumb right now; it needs tied to a model and all that jazz
CMS.Views.ClassInfoHandoutsView = Backbone.View.extend({
    // collection is CourseUpdateCollection
    events: {
        "click .save-button" : "onSave",
        "click .cancel-button" : "onCancel",
        "click .edit-button" : "onEdit"
    },

    initialize: function() {
        var self = this;
        this.model.fetch(
            {
                complete: function() {
                    window.templateLoader.loadRemoteTemplate("course_info_handouts",
                        "/static/client_templates/course_info_handouts.html",
                        function (raw_template) {
                            self.template = _.template(raw_template);
                            self.render();
                        }
                    );
                }
            }
        );
    },

    render: function () {
        var updateEle = this.$el;
        var self = this;
        this.$el.html(
            $(this.template( {
                model: this.model
                })
            )
        );
        this.$preview = this.$el.find('.handouts-content');
        this.$form = this.$el.find(".edit-handouts-form");
        this.$editor = this.$form.find('.handouts-content-editor');
        this.$form.hide();

        return this;
    },

    onEdit: function(event) {
        var self = this;
        this.$editor.val(this.$preview.html());
        this.$form.show();
        if (this.$codeMirror == null) {
            this.$codeMirror = CodeMirror.fromTextArea(this.$editor.get(0), {
                mode: "text/html",
                lineNumbers: true,
                lineWrapping: true,
            });
        }
        window.$modalCover.show();
        window.$modalCover.bind('click', function() {
            self.closeEditor(self);
        });
    },

    onSave: function(event) {
        this.model.set('data', this.$codeMirror.getValue());
        this.render();
        this.model.save();
        this.$form.hide();
        this.closeEditor(this);
    },

    onCancel: function(event) {
        this.$form.hide();
        this.closeEditor(this);
    },

    closeEditor: function(self) {
        this.$form.hide();
        window.$modalCover.unbind('click');
        window.$modalCover.hide();
        this.$codeMirror = null;
    }
});<|endoftext|>


<commit_before>$(function() {
  // Create Marquee
  $('#marquee ul').marquee({pauseOnHover: false});

  function updateClock() {
    // Update time and date
    $("#date").text( moment().format('dddd, MMMM D, YYYY') );
    $("#time").text( moment().format('h:mm:ss') );

    var lastFinishX;
    var scheduleFinished = true;

    $('#schedule ol li').each(function(index, element) {
      var startTime = $($(element).children()[0]).attr('datetime');
      var finishTime = $($(element).children()[1]).attr('datetime');

      var startTimeX = moment(startTime, "HH:mm:ss").format('X');
      var finishTimeX = moment(finishTime, "HH:mm:ss").format('X');

      var now = moment().format('X');

      // Highlight the current period
      if (startTimeX <= now && now < finishTimeX) {
        $(element).addClass('active');
      } else {
        $(element).removeClass('active');
      }

      // See if any periods have time left, otherwise it's closing time
      if (now < finishTimeX) {
        scheduleFinished = false;
      }

      // If our schedule is too big, collapse periods
      if ($('#schedule ol li').size() > 10) {
        $('#schedule').addClass('collapsing');
      } else {
        $('#schedule').removeClass('collapsing');
      }

      if (finishTimeX <= now && $('#schedule ol li').size() > 10) {
        $(element).filter(':visible').slideUp('slow');
      } else {
        $(element).show();
      }

      // Show a marker if we're in between periods
      if (lastFinishX <= now && now < startTimeX) {
        $(element).addClass('next');
      } else {
        $(element).removeClass('next');
      }

      var lastFinish = $($(element).children()[1]).attr('datetime');
      lastFinishX = moment(lastFinish, "HH:mm:ss").format('X');
    });

    // Check if schedule has finished
    if (scheduleFinished) {
      $('#wrapper').addClass('closingTime');
    } else {
      $('#wrapper').removeClass('closingTime');
    }

    setTimeout(updateClock, 1000);
  }

  updateClock();

  var socket = io();

  socket.on('refresh', function() {
    location.reload();
  });

  socket.on('error', function() {
    $('#connection-error').show();
  });

  socket.on('disconnect', function() {
    $('#connection-error').show();
  });

  socket.on('reconnect', function() {
    $('#connection-error').hide();
  });
});
<commit_msg>Reload from server, not cache<commit_after>$(function() {
  // Create Marquee
  $('#marquee ul').marquee({pauseOnHover: false});

  function updateClock() {
    // Update time and date
    $("#date").text( moment().format('dddd, MMMM D, YYYY') );
    $("#time").text( moment().format('h:mm:ss') );

    var lastFinishX;
    var scheduleFinished = true;

    $('#schedule ol li').each(function(index, element) {
      var startTime = $($(element).children()[0]).attr('datetime');
      var finishTime = $($(element).children()[1]).attr('datetime');

      var startTimeX = moment(startTime, "HH:mm:ss").format('X');
      var finishTimeX = moment(finishTime, "HH:mm:ss").format('X');

      var now = moment().format('X');

      // Highlight the current period
      if (startTimeX <= now && now < finishTimeX) {
        $(element).addClass('active');
      } else {
        $(element).removeClass('active');
      }

      // See if any periods have time left, otherwise it's closing time
      if (now < finishTimeX) {
        scheduleFinished = false;
      }

      // If our schedule is too big, collapse periods
      if ($('#schedule ol li').size() > 10) {
        $('#schedule').addClass('collapsing');
      } else {
        $('#schedule').removeClass('collapsing');
      }

      if (finishTimeX <= now && $('#schedule ol li').size() > 10) {
        $(element).filter(':visible').slideUp('slow');
      } else {
        $(element).show();
      }

      // Show a marker if we're in between periods
      if (lastFinishX <= now && now < startTimeX) {
        $(element).addClass('next');
      } else {
        $(element).removeClass('next');
      }

      var lastFinish = $($(element).children()[1]).attr('datetime');
      lastFinishX = moment(lastFinish, "HH:mm:ss").format('X');
    });

    // Check if schedule has finished
    if (scheduleFinished) {
      $('#wrapper').addClass('closingTime');
    } else {
      $('#wrapper').removeClass('closingTime');
    }

    setTimeout(updateClock, 1000);
  }

  updateClock();

  var socket = io();

  socket.on('refresh', function() {
    location.reload(true);
  });

  socket.on('error', function() {
    $('#connection-error').show();
  });

  socket.on('disconnect', function() {
    $('#connection-error').show();
  });

  socket.on('reconnect', function() {
    $('#connection-error').hide();
  });
});
<|endoftext|>


<commit_before>/*
* In a client-server architecture routes are resource address capability service nouns.
*/
fun.Router = Backbone.Router.extend({

    /*
     Seed server routes
    */
    routes: {
        "": "home",
        "home": "home",
        "contact": "contact",
        "landing": "landing",
        "settings": "settings"
    },

    initialize: function(){
        'use strict';
        // navigation bar
        fun.instances.navbar = new fun.views.navbar({
            el:"#fun-navbar"
        });

        // sub header
        fun.instances.subheader = new fun.views.subheader({
            el:"#fun-subheader"
        });

        // landing
        fun.instances.landing = new fun.views.landing({
            el:"#fun-landing"
        });

        // extra
        fun.instances.extra = new fun.views.extra({
            el:"#fun-extra"
        });

        // contact
        fun.instances.contact = new fun.views.contact({
            el:"#fun-contact"
        })

        // rooms
        fun.instances.rooms = new fun.views.rooms({
            el:"#fun-rooms"
        })

        // contact
        fun.instances.gallery = new fun.views.contact({
            el:"#fun-gallery"
        })

        // footer
        fun.instances.footer = new fun.views.footer({
            el:"#fun-footer"
        });
    },

    home: function(){
        'use strict';
        console.log('spawn some fun get account and context');

        // get account and context
        this.account = localStorage.getItem("username");
        this.context = sessionStorage.getItem("context");

        console.log(this.account, this.context);

        if (this.account === this.context){
            console.log('account same as context');
        } else {
            console.log('missing or different context');
        }

        if(fun.utils.loggedIn()){
            fun.utils.redirect(fun.conf.hash.dashboard);
        } else {
            fun.utils.redirect(fun.conf.hash.landing);
        }
        fun.instances.extra.render();
        fun.instances.footer.render();
    },

    landing: function(){
        'use strict';
        fun.utils.hideAll();
        fun.instances.navbar.render();
        fun.instances.landing.render();
        fun.instances.extra.render();
        fun.instances.footer.render();
    },

    contact: function(){
        'use strict';
        var contact = translate('contact');

        fun.utils.hideAll();
        fun.instances.navbar.render();
        //fun.instances.subheader.render(contact);
        fun.instances.contact.render();
        fun.instances.footer.render();
    },

    rooms: function(){
        'use strict';
        this.account = localStorage.getItem("username");
        var rooms = translate('settings');
        fun.utils.hideAll();
        fun.instances.navbar.render();
        fun.instances.subheader.render(rooms);
        fun.instances.rooms.render(this.account);
        fun.instances.footer.render();
    },

    gallery: function(){
        'use strict';
        this.account = localStorage.getItem("username");
        var gallery = translate('gallery');
        fun.utils.hideAll();
        fun.instances.navbar.render();
        fun.instances.subheader.render(rooms);
        fun.instances.gallery.render(this.account);
        fun.instances.footer.render();
    }
});

// init the shit out of this
$(function(){
    fun.instances.router = new fun.Router();
    Backbone.history.start();
});
<commit_msg>go random stuff<commit_after>/*
* In a client-server architecture routes are resource address capability service nouns.
*/
fun.Router = Backbone.Router.extend({

    /*
     Seed server routes
    */
    routes: {
        "": "home",
        "home": "home",
        "contact": "contact",
        "rooms": "rooms",
        "gallery": "gallery",
        "landing": "landing",
        "settings": "settings"
    },

    initialize: function(){
        'use strict';
        // navigation bar
        fun.instances.navbar = new fun.views.navbar({
            el:"#fun-navbar"
        });

        // sub header
        fun.instances.subheader = new fun.views.subheader({
            el:"#fun-subheader"
        });

        // landing
        fun.instances.landing = new fun.views.landing({
            el:"#fun-landing"
        });

        // extra
        fun.instances.extra = new fun.views.extra({
            el:"#fun-extra"
        });

        // contact
        fun.instances.contact = new fun.views.contact({
            el:"#fun-contact"
        })

        // rooms
        fun.instances.rooms = new fun.views.rooms({
            el:"#fun-rooms"
        })

        // contact
        fun.instances.gallery = new fun.views.contact({
            el:"#fun-gallery"
        })

        // footer
        fun.instances.footer = new fun.views.footer({
            el:"#fun-footer"
        });
    },

    home: function(){
        'use strict';
        console.log('spawn some fun get account and context');

        // get account and context
        this.account = localStorage.getItem("username");
        this.context = sessionStorage.getItem("context");

        console.log(this.account, this.context);

        if (this.account === this.context){
            console.log('account same as context');
        } else {
            console.log('missing or different context');
        }

        if(fun.utils.loggedIn()){
            fun.utils.redirect(fun.conf.hash.dashboard);
        } else {
            fun.utils.redirect(fun.conf.hash.landing);
        }
        fun.instances.extra.render();
        fun.instances.footer.render();
    },

    landing: function(){
        'use strict';
        fun.utils.hideAll();
        fun.instances.navbar.render();
        fun.instances.landing.render();
        fun.instances.extra.render();
        fun.instances.footer.render();
    },

    contact: function(){
        'use strict';
        var contact = translate('contact');

        fun.utils.hideAll();
        fun.instances.navbar.render();
        //fun.instances.subheader.render(contact);
        fun.instances.contact.render();
        fun.instances.footer.render();
    },

    rooms: function(){
        'use strict';
        var rooms = translate('rooms');
        fun.utils.hideAll();
        fun.instances.navbar.render();
        //fun.instances.subheader.render(rooms)
        fun.instances.rooms.render();
        fun.instances.footer.render();
    },

    gallery: function(){
        'use strict';
        var gallery = translate('gallery');
        fun.utils.hideAll();
        fun.instances.navbar.render();
        //fun.instances.subheader.render(gallery);
        fun.instances.gallery.render();
        fun.instances.footer.render();
    }
});

// init the shit out of this
$(function(){
    fun.instances.router = new fun.Router();
    Backbone.history.start();
});
<|endoftext|>


<commit_before>/*----------------------------------
        Table Tab Listeners
-----------------------------------*/
// Redraw the Subnet Table when shown
$('#navTabs a[href="#SubnetTab"]').on('shown.bs.tab', function(){
  if($.fn.DataTable.isDataTable('#SubnetTable')){$('#SubnetTable').DataTable().draw();}
});

/*----------------------------------
    Selection Table Constructors
-----------------------------------*/
// Build a Fresh Network Table
function buildNetworkTable(){
  $('#NetworkTable').DataTable().destroy();
  $('#NetworkTable').DataTable({
      "ajax": ($SCRIPT_ROOT + 'available_networks'),
      "bAutoWidth": false,
      "bPaginate": false,
      "bJQueryUI": false,
      "scrollCollapse": true,
      "dom": '<"NetworkTitle">ft',
      "order": [[0,'asc']],
      "scrollY": ($(window).height()/7),
      "select": true,
      "searching": true,
    });
  $("div.NetworkTitle").html('Network');
  return;
}

// Build a Fresh Ontology Table
function buildOntologyTable(network){
  $('#OntologyTable').DataTable().destroy();
  $('#OntologyTable').DataTable({
      "ajax": ($SCRIPT_ROOT + 'available_ontologies/' + network),
      "bAutoWidth": false,
      "bPaginate": false,
      "bJQueryUI": false,
      "dom": '<"OntologyTitle">ft',
      "initComplete": function(settings, json){
        if(json.data.length < 1){
          $('#GeneSelectTabs a[href="#TermGenesTab"]').tab('show');
        }
      },
      "language":{
        "emptyTable":"No ontologies available for this network. Please enter query genes in the \"Custom Gene List\" Tab."},
      "order": [[0,'asc']],
      "scrollCollapse": true,
      "scrollY": ($(window).height()/7),
      "select": true,
      "searching": true,
    });
  $("div.OntologyTitle").html('Ontology');
  return;
}

// Build a Fresh Term Table
function buildTermTable(ontology){
  $('#TermTable').DataTable().destroy();
  $('#TermTable').DataTable({
      "ajax": ($SCRIPT_ROOT + 'available_terms/' + ontology),
      "bAutoWidth": false,
      "bPaginate": false,
      "bJQueryUI": false,
      "dom": '<"TermTitle">frtip',
      "initComplete": function(settings, json){
        if(json.data.length < 1){
          $('#GeneSelectTabs a[href="#TermGenesTab"]').tab('show');
        }
      },
      "language":{
        "emptyTable":"No terms available for this ontology. Please enter query genes in the \"Custom Gene List\" Tab."},
      "order": [[0,'asc']],
      "scrollCollapse": true,
      "scrollY": ($(window).height()/4),
      "select": true,
      "searching": true,
    });
  $("div.TermTitle").html('Terms');
  return;
}

/*--------------------------------
      Gene Table Constructors
---------------------------------*/
function buildGeneTables(){
  // Enumerated column information!
  var cols = [
    {data: 'render', name:'rendered', title:'Vis'},
    {data: 'id', name:'id', title:'ID'},
    {data: 'alias', name:'alias', title:'Alias'},
    {data: 'fdr', name:'fdr', title:'FDR'},
    {data: 'cur_ldegree', name:'cur_ldegree', title:'Current Degree'},
    {data: 'ldegree', name:'ldegree', title:'Term Degree'},
    {data: 'gdegree', name:'gdegree', title:'Global Degree'},
    {data: 'chrom', name:'chrom', title:'Chrom'},
    {data: 'snp', name:'snp', title:'SNP'},
    {data: 'start', name:'start', title:'Start'},
    {data: 'end', name:'end', title:'End'},
    {data: 'numIntervening', name:'numIntervening', title:'Num Intervening'},
    {data: 'rankIntervening', name:'rankIntervening', title:'Rank Intervening'},
    {data: 'numSiblings', name:'numSiblings', title:'Num Siblings'},
    {data: 'windowSize', name:'windowSize', title:'Window Size', visible: false},
    {data: 'flankLimit', name:'flankLimit', title:'Flank Limit', visible: false},
    {data: 'annotations', name:'annotations', title:'Annotations'},
    //{data: 'parentNumIterations', name:'parentNumIterations', title: 'Num Parent Interactions'},
    //{data: 'parentAvgEffectSize', name:'parentAvgEffectSize', title: 'Avg Parent Effect Size'},
  ];

  /*--------------------------------
       Setup The Gene Table
  ---------------------------------*/
  // Get gene table data
  var geneData = [];
  Object.keys(geneDict).forEach(function(cur,idx,arr){geneData.push(geneDict[cur]['data']);});

  // Destroy the old tables, remove columns, remove listeners
  if($.fn.DataTable.isDataTable('#GeneTable')){
    $('#GeneTable').DataTable().destroy();
    $('#GeneTable').off().empty();
  }

  // Set up the main gene table
  var gene_table = $('#GeneTable').DataTable({
      "data": geneData,
      "deferRender": false,
      "dom": '<"GeneTitle">frtpB',
      "order": [[0,'dec'],[3,'asc'],[4,'dec']],
      "paging": true,
      "paginate": true,
      "rowId": 'id',
      "scrollCollapse": true,
      "scroller": {displayBuffer: 1500},
      "scrollX": "100%",
      "scrollY": ($(window).height()-275),
      "searching": true,
      "select": {"style": 'multi+shift'},
      "buttons": [
        {"extend": 'csv',"filename": 'genenetwork'},
        {"text": 'Graph Subnet', "action": makeSubnet},
        {"text": 'GWS', "action": gws},
        {"text": 'GO', "action": gont},
      ],
      "columns": cols,
    });

  // Set the inline titles on the tables
  $("div.GeneTitle").html('Gene Data');

  // Make certain columns invisible if there will be no useful data
  gene_table.columns(['snp:name', 'fdr:name', 'numIntervening:name', 'rankIntervening:name', 'numSiblings:name']).visible(isTerm);

  /*--------------------------------
       Setup The Subnet Table
  ---------------------------------*/
  // Destroy the old one if needed
  if($.fn.DataTable.isDataTable('#SubnetTable')){
    $('#SubnetTable').DataTable().destroy();
    $('#SubnetTable').off().empty();
  }

  // Set up the subnetwork gene table
  var sub_table = $('#SubnetTable').DataTable({
      "data": [],
      "dom": '<"SubnetTitle">frtpB',
      "order": [[0,'dec'],[3,'asc'],[4,'dec']],
      "paging": false,
      "paginate": false,
      "rowId": 'id',
      "scrollCollapse": true,
      "scrollX": "100%",
      "scrollY": $(window).height()-275,
      "searching": true,
      "select": {"style": 'multi+shift'},
      "buttons": [
        {"extend": 'csv',"filename": 'subnetwork'},
        {"text": 'Graph Subnet', "action": makeSubnet},
        {"text": 'GWS', "action": gws},
        {"text": 'GO', "action": gont},
      ],
      "columns": cols,
    });

  // Set the inline titles on the tables
  $("div.SubnetTitle").html('Subnet Data');

  // Make certain columns invisible if there will be no useful data
  sub_table.columns(['rendered:name']).visible(false);
  sub_table.columns(['snp:name', 'fdr:name', 'numIntervening:name', 'rankIntervening:name', 'numSiblings:name']).visible(isTerm);

  /*----------------------------------
       Setup The Table Listeners
  -----------------------------------*/
  // Set listener for pop effect of subnetwork table
  $('#SubnetTable tbody').on('mouseover','tr', function(evt){
    if(this['id'].length > 0){
      window.clearTimeout(popTimerID);
      popTimerID = window.setTimeout(function(id){
          cy.getElementById(id).flashClass('pop',750);
      }, 10, this['id']);
    }
  });

  // Handling a click on the two tables
  $('#GeneTable tbody').on('click','tr', function(evt){
    // If we are in the process of adding a gene, kill this request
    if(noAdd){
      $('#GeneTable').DataTable().row('#'+this['id']).deselect();
      window.alert('We\'re currently processing a previous add gene request, if you would like to add more than one at a time, please use the shift select method.');
      return;
    }

    // Otherwise update all the things
    if((evt.ctrlKey || evt.metaKey) && !(evt.shiftKey)){
      if($(evt.currentTarget).hasClass('selected')){
        $('#GeneTable').DataTable().row('#'+this['id']).deselect();}
      else{
        $('#GeneTable').DataTable().row('#'+this['id']).select();}
      window.open('http://www.maizegdb.org/gene_center/gene/'+this['id']);
    }
    else{geneSelect();}
  });
  $('#SubnetTable tbody').on('click','tr', function(evt){
    // If we are in the process of adding a gene, kill this request
    if(noAdd){
      $('#SubnetTable').DataTable().row('#'+this['id']).deselect();
      window.alert('We\'re currently processing a previous add gene request, if you would like to add more than one at a time, please use the shift select method.');
      return;
    }

    // Otherwise update all the things
    if((evt.ctrlKey || evt.metaKey) && !(evt.shiftKey)){
      if($(evt.currentTarget).hasClass('selected')){
        $('#SubnetTable').DataTable().row('#'+this['id']).deselect();}
      else{
        $('#SubnetTable').DataTable().row('#'+this['id']).select();}
      window.open('http://www.maizegdb.org/gene_center/gene/'+this['id']);
    }
    else{geneSelect();}
  });
}

/*---------------------------------------
      Run Enrichment Functions
---------------------------------------*/
function gws(e,dt,node,config){
  // Build the gene query list
  var geneList = dt.rows().ids();
  enrich(geneList,false);
}

function gont(e,dt,node,cofig){
  // Build the gene query list
  var geneList = dt.rows().ids();
  enrich(geneList,true);
}

/*---------------------------------------
      Gene and Subnet Table Updater
---------------------------------------*/
function updateSubnetTable(newGenes, newGenesSel){
  // Get the table api ref
  var tbl = $('#SubnetTable').DataTable();

  // Find the genes we must add and remove
  var oldGenes = new Set();
  tbl.rows().ids().each(function(cur){oldGenes.add(cur)});
  var toAdd = [...newGenes].filter(cur => !oldGenes.has(cur));
  var toSub = [...oldGenes].filter(cur => !newGenes.has(cur));

  // Get the data in the proper formats for adding and removing
  toAdd.forEach(function(cur,idx,arr){arr[idx] = geneDict[cur]['data'];});
  toSub.forEach(function(cur,idx,arr){arr[idx] = '#'+cur;});

  // Clear old data and add new
  if(toSub.length > 0){tbl.rows(toSub).remove();}
  tbl.rows.add(toAdd).draw();

  // Update the selections
  tbl.rows('.selected').deselect();
  tbl.rows(newGenesSel).select();
}
<commit_msg>Tweaked alighnment<commit_after>/*----------------------------------
        Table Tab Listeners
-----------------------------------*/
// Redraw the Subnet Table when shown
$('#navTabs a[href="#SubnetTab"]').on('shown.bs.tab', function(){
  if($.fn.DataTable.isDataTable('#SubnetTable')){$('#SubnetTable').DataTable().draw();}
});

/*----------------------------------
    Selection Table Constructors
-----------------------------------*/
// Build a Fresh Network Table
function buildNetworkTable(){
  $('#NetworkTable').DataTable().destroy();
  $('#NetworkTable').DataTable({
      "ajax": ($SCRIPT_ROOT + 'available_networks'),
      "bAutoWidth": false,
      "bPaginate": false,
      "bJQueryUI": false,
      "scrollCollapse": true,
      "dom": '<"NetworkTitle">ft',
      "order": [[0,'asc']],
      "scrollY": ($(window).height()/7),
      "select": true,
      "searching": true,
    });
  $("div.NetworkTitle").html('Network');
  return;
}

// Build a Fresh Ontology Table
function buildOntologyTable(network){
  $('#OntologyTable').DataTable().destroy();
  $('#OntologyTable').DataTable({
      "ajax": ($SCRIPT_ROOT + 'available_ontologies/' + network),
      "bAutoWidth": false,
      "bPaginate": false,
      "bJQueryUI": false,
      "dom": '<"OntologyTitle">ft',
      "initComplete": function(settings, json){
        if(json.data.length < 1){
          $('#GeneSelectTabs a[href="#TermGenesTab"]').tab('show');
        }
      },
      "language":{
        "emptyTable":"No ontologies available for this network. Please enter query genes in the \"Custom Gene List\" Tab."},
      "order": [[0,'asc']],
      "scrollCollapse": true,
      "scrollY": ($(window).height()/7),
      "select": true,
      "searching": true,
    });
  $("div.OntologyTitle").html('Ontology');
  return;
}

// Build a Fresh Term Table
function buildTermTable(ontology){
  $('#TermTable').DataTable().destroy();
  $('#TermTable').DataTable({
      "ajax": ($SCRIPT_ROOT + 'available_terms/' + ontology),
      "bAutoWidth": false,
      "bPaginate": false,
      "bJQueryUI": false,
      "dom": '<"TermTitle">frtip',
      "initComplete": function(settings, json){
        if(json.data.length < 1){
          $('#GeneSelectTabs a[href="#TermGenesTab"]').tab('show');
        }
      },
      "language":{
        "emptyTable":"No terms available for this ontology. Please enter query genes in the \"Custom Gene List\" Tab."},
      "order": [[0,'asc']],
      "scrollCollapse": true,
      "scrollY": ($(window).height()/4),
      "select": true,
      "searching": true,
    });
  $("div.TermTitle").html('Terms');
  return;
}

/*--------------------------------
      Gene Table Constructors
---------------------------------*/
function buildGeneTables(){
  // Enumerated column information!
  var cols = [
    {data: 'render', name:'rendered', title:'Vis'},
    {data: 'id', name:'id', title:'ID'},
    {data: 'alias', name:'alias', title:'Alias'},
    {data: 'fdr', name:'fdr', title:'FDR'},
    {data: 'cur_ldegree', name:'cur_ldegree', title:'Current Degree'},
    {data: 'ldegree', name:'ldegree', title:'Term Degree'},
    {data: 'gdegree', name:'gdegree', title:'Global Degree'},
    {data: 'chrom', name:'chrom', title:'Chrom'},
    {data: 'snp', name:'snp', title:'SNP'},
    {data: 'start', name:'start', title:'Start'},
    {data: 'end', name:'end', title:'End'},
    {data: 'numIntervening', name:'numIntervening', title:'Num Intervening'},
    {data: 'rankIntervening', name:'rankIntervening', title:'Rank Intervening'},
    {data: 'numSiblings', name:'numSiblings', title:'Num Siblings'},
    {data: 'windowSize', name:'windowSize', title:'Window Size', visible: false},
    {data: 'flankLimit', name:'flankLimit', title:'Flank Limit', visible: false},
    {data: 'annotations', name:'annotations', title:'Annotations'},
    //{data: 'parentNumIterations', name:'parentNumIterations', title: 'Num Parent Interactions'},
    //{data: 'parentAvgEffectSize', name:'parentAvgEffectSize', title: 'Avg Parent Effect Size'},
  ];

  /*--------------------------------
       Setup The Gene Table
  ---------------------------------*/
  // Get gene table data
  var geneData = [];
  Object.keys(geneDict).forEach(function(cur,idx,arr){geneData.push(geneDict[cur]['data']);});

  // Destroy the old tables, remove columns, remove listeners
  if($.fn.DataTable.isDataTable('#GeneTable')){
    $('#GeneTable').DataTable().destroy();
    $('#GeneTable').off().empty();
  }

  // Set up the main gene table
  var gene_table = $('#GeneTable').DataTable({
      "data": geneData,
      "deferRender": false,
      "dom": '<"GeneTitle">frtpB',
      "order": [[0,'dec'],[3,'asc'],[4,'dec']],
      "paging": true,
      "paginate": true,
      "rowId": 'id',
      "scrollCollapse": true,
      "scroller": {displayBuffer: 1500},
      "scrollX": "100%",
      "scrollY": $(window).height()-285,
      "searching": true,
      "select": {"style": 'multi+shift'},
      "buttons": [
        {"extend": 'csv',"filename": 'genenetwork'},
        {"text": 'Graph Subnet', "action": makeSubnet},
        {"text": 'GWS', "action": gws},
        {"text": 'GO', "action": gont},
      ],
      "columns": cols,
    });

  // Set the inline titles on the tables
  $("div.GeneTitle").html('Gene Data');

  // Make certain columns invisible if there will be no useful data
  gene_table.columns(['snp:name', 'fdr:name', 'numIntervening:name', 'rankIntervening:name', 'numSiblings:name']).visible(isTerm);

  /*--------------------------------
       Setup The Subnet Table
  ---------------------------------*/
  // Destroy the old one if needed
  if($.fn.DataTable.isDataTable('#SubnetTable')){
    $('#SubnetTable').DataTable().destroy();
    $('#SubnetTable').off().empty();
  }

  // Set up the subnetwork gene table
  var sub_table = $('#SubnetTable').DataTable({
      "data": [],
      "dom": '<"SubnetTitle">frtpB',
      "order": [[0,'dec'],[3,'asc'],[4,'dec']],
      "paging": false,
      "paginate": false,
      "rowId": 'id',
      "scrollCollapse": true,
      "scrollX": "100%",
      "scrollY": $(window).height()-285,
      "searching": true,
      "select": {"style": 'multi+shift'},
      "buttons": [
        {"extend": 'csv',"filename": 'subnetwork'},
        {"text": 'Graph Subnet', "action": makeSubnet},
        {"text": 'GWS', "action": gws},
        {"text": 'GO', "action": gont},
      ],
      "columns": cols,
    });

  // Set the inline titles on the tables
  $("div.SubnetTitle").html('Subnet Data');

  // Make certain columns invisible if there will be no useful data
  sub_table.columns(['rendered:name']).visible(false);
  sub_table.columns(['snp:name', 'fdr:name', 'numIntervening:name', 'rankIntervening:name', 'numSiblings:name']).visible(isTerm);

  /*----------------------------------
       Setup The Table Listeners
  -----------------------------------*/
  // Set listener for pop effect of subnetwork table
  $('#SubnetTable tbody').on('mouseover','tr', function(evt){
    if(this['id'].length > 0){
      window.clearTimeout(popTimerID);
      popTimerID = window.setTimeout(function(id){
          cy.getElementById(id).flashClass('pop',750);
      }, 10, this['id']);
    }
  });

  // Handling a click on the two tables
  $('#GeneTable tbody').on('click','tr', function(evt){
    // If we are in the process of adding a gene, kill this request
    if(noAdd){
      $('#GeneTable').DataTable().row('#'+this['id']).deselect();
      window.alert('We\'re currently processing a previous add gene request, if you would like to add more than one at a time, please use the shift select method.');
      return;
    }

    // Otherwise update all the things
    if((evt.ctrlKey || evt.metaKey) && !(evt.shiftKey)){
      if($(evt.currentTarget).hasClass('selected')){
        $('#GeneTable').DataTable().row('#'+this['id']).deselect();}
      else{
        $('#GeneTable').DataTable().row('#'+this['id']).select();}
      window.open('http://www.maizegdb.org/gene_center/gene/'+this['id']);
    }
    else{geneSelect();}
  });
  $('#SubnetTable tbody').on('click','tr', function(evt){
    // If we are in the process of adding a gene, kill this request
    if(noAdd){
      $('#SubnetTable').DataTable().row('#'+this['id']).deselect();
      window.alert('We\'re currently processing a previous add gene request, if you would like to add more than one at a time, please use the shift select method.');
      return;
    }

    // Otherwise update all the things
    if((evt.ctrlKey || evt.metaKey) && !(evt.shiftKey)){
      if($(evt.currentTarget).hasClass('selected')){
        $('#SubnetTable').DataTable().row('#'+this['id']).deselect();}
      else{
        $('#SubnetTable').DataTable().row('#'+this['id']).select();}
      window.open('http://www.maizegdb.org/gene_center/gene/'+this['id']);
    }
    else{geneSelect();}
  });
}

/*---------------------------------------
      Run Enrichment Functions
---------------------------------------*/
function gws(e,dt,node,config){
  // Build the gene query list
  var geneList = dt.rows().ids();
  enrich(geneList,false);
}

function gont(e,dt,node,cofig){
  // Build the gene query list
  var geneList = dt.rows().ids();
  enrich(geneList,true);
}

/*---------------------------------------
      Gene and Subnet Table Updater
---------------------------------------*/
function updateSubnetTable(newGenes, newGenesSel){
  // Get the table api ref
  var tbl = $('#SubnetTable').DataTable();

  // Find the genes we must add and remove
  var oldGenes = new Set();
  tbl.rows().ids().each(function(cur){oldGenes.add(cur)});
  var toAdd = [...newGenes].filter(cur => !oldGenes.has(cur));
  var toSub = [...oldGenes].filter(cur => !newGenes.has(cur));

  // Get the data in the proper formats for adding and removing
  toAdd.forEach(function(cur,idx,arr){arr[idx] = geneDict[cur]['data'];});
  toSub.forEach(function(cur,idx,arr){arr[idx] = '#'+cur;});

  // Clear old data and add new
  if(toSub.length > 0){tbl.rows(toSub).remove();}
  tbl.rows.add(toAdd).draw();

  // Update the selections
  tbl.rows('.selected').deselect();
  tbl.rows(newGenesSel).select();
}
<|endoftext|>


<commit_before>"use strict";
var socket;
var mapper;
function main() {
    socket = io();
    mapper = Mapper.init(document.getElementById('mapCard'));
    socket.on('connected', function (users) {
        socket.emit('subscribe', users[users.length-1]);
        console.log(users);
    });
    socket.on('newPacket', function (packet) {
        console.log(packet);
        mapper.addPackets([packet]);
        console.log(mapper._packets);
        mapper.render();
        var car = mapper.car;
        document.getElementById('songCard').innerText = car.song;
        document.getElementById('moodCard').innerText = Object.keys(car.mood).reduce(
            function(a, b) {
                return car.mood[a] > car.mood[b] ? a : b
            }
        );
    });

    socket.on('newPackets', function (packets) {
        console.log(packets);
        mapper.addPackets(packets);
        console.log(mapper._packets);
        mapper.render();
        var car = mapper.car;
        document.getElementById('songCard').innerText = car.song;
        document.getElementById('moodCard').innerText = Object.keys(car.mood).reduce(
            function(a, b) {
                return car.mood[a] > car.mood[b] ? a : b
            }
        );
    });
}
<commit_msg>Update crooz.js<commit_after>"use strict";
var socket;
var mapper;
function main() {
    socket = io();
    mapper = Mapper.init(document.getElementById('mapCard'));
    socket.on('connected', function (users) {
        socket.emit('subscribe', users
            .sort(function(a,b) {
                return new Date(b.tripId).getTime() - new Date(a.tripId).getTime()
            }[0])
        );
        console.log(users);
    });
    socket.on('newPacket', function (packet) {
        console.log(packet);
        mapper.addPackets([packet]);
        console.log(mapper._packets);
        mapper.render();
        var car = mapper.car;
        document.getElementById('songCard').innerText = car.song;
        document.getElementById('moodCard').innerText = Object.keys(car.mood).reduce(
            function(a, b) {
                return car.mood[a] > car.mood[b] ? a : b
            }
        );
    });

    socket.on('newPackets', function (packets) {
        console.log(packets);
        mapper.addPackets(packets);
        console.log(mapper._packets);
        mapper.render();
        var car = mapper.car;
        document.getElementById('songCard').innerText = car.song;
        document.getElementById('moodCard').innerText = Object.keys(car.mood).reduce(
            function(a, b) {
                return car.mood[a] > car.mood[b] ? a : b
            }
        );
    });
}
<|endoftext|>


<commit_before>//tributary and options are passed into this code
//tributary is the main object available in inlets
//options has some gauranteed elements:
//{
//  pluginId: a UUID that will also be the element id of a div
//}
//console.log(arguments);
//You are expected to return a plugin object with the following methods exposed:
//{
//  activate() { //initializes the plugin },
//  deactivate() { //cleans up after the plugin (removes itself) }
//}

var plugin = {};

if(!options) {
  options = {};
}
if(!options.pluginId) options.pluginId = tributary.newPluginId();

var el = document.getElementById(options.pluginId);
var config = tributary.__config__;

plugin.activate = function() {
  el = document.getElementById(options.pluginId);
  init();
  playButton();
  timeSlider();
  restartButton();

  config.on("change:play", playButton, this);
  config.on("change:loop", timeSlider, this);
  config.on("change:restart", restartButton, this);
  config.on("pause", onPlayPause, this);

  //Setup the ui for choosing the controls in the config div
  var configDiv = d3.select("#config-content");
  configDiv.node().appendChild(d3.select(el).select(".timecontrols").node());
  var timecontrols = d3.select(".timecontrols")
    .selectAll("button");

    timecontrols.datum(function() { return this.dataset; })
    timecontrols.filter(function(d) {
      return config.get(d.name);
    })
    .classed("active", true);

    timecontrols.on("click", function(d) {
      var tf = !config.get(d.name);
      d3.select(this).classed("active", tf);
      config.set(d.name, tf);
    });
}

plugin.deactivate = function() {
  el.innerHTML = "";

  //remove all the stuff we added to tributary
  destroy();
}

function onPlayPause() {
  var tc = d3.select(el).select(".time_controls");
  var pb = tc.select("button.play");
  if(!tributary.pause){
    pb.classed("playing", false);
    pb.text("Play");
  } else if(tributary.pause){
    pb.classed("playing", true);
    pb.text("Pause");
  }

  if(tributary.t < 1 || !tributary.loop) {
    tributary.pause = !tributary.pause;

    if(!tributary.pause) {
      //unpausing, so we setup our timer to run
      tributary.timer.then = new Date();
      tributary.timer.duration = (1 - tributary.t) * tributary.duration;
      tributary.timer.ctime = tributary.t;
    }
  }
}
function playButton() {
  //add/remove play button
  var tc = d3.select(el).select(".time_controls");
  if(config.get("play")) {
    //create the button
    var pb = tc.select("button.play")
    pb.style("display", "")

    pb.on("click", onPlayPause);
    onPlayPause();
  } else {
    //destroy the button
    tc.select("button.play").style("display", "none");
  }
}

function timeSlider() {
  tributary.loop = config.get("loop");
  var tc = d3.select(el).select(".time_controls");
  if(tributary.loop) {
    var ts = tc.select("input.time_slider");
    ts.style("display", "")

    //idk why jquery selections for on("change") works but d3 doesnt...
    ts.on('change', function() {
      tributary.t = parseFloat(this.value);//$('#slider').attr('value');
      if(tributary.pause){
        //only want to run code if we aren't already playing
        tributary.execute();
      }
    });
    config.on("tick", function(t) {
      ts.node().setAttribute("value", tributary.t);
      ts.node().value = tributary.t;
    });

    //TODO: generalize BV button to other displays
    if(config.get("display") === "svg") {
      var bv = tc.select("button.bv")
      bv.style("display", "");

      bv.on("click", function() {
        tributary.bv = !tributary.bv;
        tributary.events.trigger("execute");
      });
    }

  } else {
    tributary.bv = false;
    tc.select("input.time_slider").style("display", "none");
    tc.select("button.bv").style("display", "none");
  }

}

//RESTART BUTTON
//this restart button does something special. It calls the user defined init function, but it also
//makes it so that normal execution does not call the init function
function onRestart() {
  tributary.clear();
  tributary.initialize(tributary.g, tributary);
  if(tributary.init) {
    tributary.init(tributary.g);
  }
  tributary.execute();
  tributary.events.trigger("restart");
}
function restartButton() {
  var that = this;
  //console.log("play!", config.get("play"));
  //add/remove play button
  var tc = d3.select(el).select(".time_controls");
  if(config.get("restart")) {
    tributary.autoinit = false;
    //create the button
    var rb = tc.select("button.restart")
      .classed("button_on", true)
    rb.style("display", "")

    rb.on("click", onRestart);
    onRestart();
  } else {
    tributary.autoinit = true;
    //destroy the button
    tc.select("button.restart").style("display", "none");
  }
}

function init() {
  //time controls;
  tributary.loop = config.get("loop");

  //default parameters for this context
  tributary.pause = config.get("pause"); //pause is used to pause and unpause
  tributary.loop_type = config.get("loop_type"); //["off", "period", "pingpong"]
  tributary.bv = config.get("bv");
  tributary.nclones = config.get("nclones");
  tributary.clone_opacity = config.get("clone_opacity");
  tributary.duration = config.get("duration");
  tributary.ease = d3.ease(config.get("ease"));
  tributary.t = 0;
  tributary.dt = config.get("dt");
  tributary.reverse = false;

  //we need to save state of timer so when we pause/unpause or manually change slider
  //we can finish a transition
  tributary.timer = {
    then: new Date(),
    duration: tributary.duration,
    ctime: tributary.t
  };

  tributary.execute = function() {
    if(tributary.run !== undefined) {
      var t = tributary.t;
      if(tributary.loop) {
        t = tributary.ease(tributary.t);
      }
      tributary.run(tributary.g, t, 0);
    }
  }

  d3.timer(timerFunction);
  function timerFunction() {
    tributary.render();
    //if paused lets not execute
    if(tributary.pause) { return false; }
    if(tributary.__error__) { return false; }

    var now = new Date();
    var dtime = now - tributary.timer.then;
    var dt;

    //TODO: implement play button, should reset the timer
    if(tributary.loop) {
      if (tributary.reverse) {
        dt = tributary.timer.ctime * dtime / tributary.timer.duration * -1;
      } else {
        dt = (1 - tributary.timer.ctime) * dtime / tributary.timer.duration;
      }
      tributary.t = tributary.timer.ctime + dt;

      //once we reach 1, lets pause and stay there
      if(tributary.t >= 1 || tributary.t <= 0 || tributary.t === "NaN")
      {
        if(tributary.loop_type === "period") {
          tributary.t = 0;
          tributary.timer.then = new Date();
          tributary.timer.duration = tributary.duration;
          tributary.timer.ctime = tributary.t;
          tributary.reverse = false;
          //tributary.pause = false;
        } else if (tributary.loop_type === "pingpong") {
          //this sets tributary.t to 0 when we get to 0 and 1 when we get to 1 (because of the direction we were going)
          tributary.t = !tributary.reverse; //*1 casts the boolean to an int;
          tributary.timer.then = new Date();
          tributary.timer.duration = tributary.duration;
          tributary.timer.ctime = tributary.t;
          tributary.reverse = !tributary.reverse;
        }
        else {
          if (tributary.t !== 0)
          {
              tributary.t = 1;
              tributary.pause = true;
              tributary.__config__.trigger("pause");
          }
        }
      }
      //TODO: fix, look up 10 lines to pingpong
      //not sure why we get true and false for 1 and 0 when range hits the end
      if(tributary.t === true) { tributary.t = 1; }
      if(tributary.t === false) { tributary.t = 0; }
    } else {
      tributary.t += tributary.dt;
    }

    try {
      tributary.execute();
      tributary.__config__.trigger("noerror");
    } catch (err) {
      tributary.__config__.trigger("error", err);
    }
    tributary.__config__.trigger("tick", tributary.t);
  }

  //Clones
  tributary.events.on("prerender", function() {
    if(tributary.clones && config.get("display") === "svg") {
      $(tributary.clones.node()).empty();
    }
    if(tributary.bv) {
      makeClones();
    }
  });
}

function destroy() {
}

//TODO: make canvas clones
//This function
makeClones = function() {
  //create the clone and tributary g elements if they don't exist
  var svg = d3.select("#display").select("svg");
  tributary.clones = svg.selectAll("g.clones")
    .data([0]);
  tributary.clones
    .enter()
    .append("g").attr("class", "clones");
  tributary.g = svg.selectAll("g.delta")
    .data([0]);
  tributary.g
    .enter()
    .append("g").attr("class", "delta");

  //make n frames with lowered opacity
  var frames = d3.range(tributary.nclones);
  var gf = tributary.clones.selectAll("g.bvclone")
    .data(frames).enter()
    .append("g")
      .attr("class", "bvclone")
      .style("opacity", tributary.clone_opacity);

  gf.each(function(d, i) {
    var j = i+1;
    var frame = d3.select(this);
    tributary.init(frame, j);
    //tributary.run(i/tributary.nclones, frame, i);
    var t = tributary.ease(j/(tributary.nclones+1));
    tributary.run(frame, t, j);
  });
}

return plugin;

<commit_msg>cleanup a little more in the plugin<commit_after>//tributary and options are passed into this code
//tributary is the main object available in inlets
//options has some gauranteed elements:
//{
//  pluginId: a UUID that will also be the element id of a div
//}
//console.log(arguments);
//You are expected to return a plugin object with the following methods exposed:
//{
//  activate() { //initializes the plugin },
//  deactivate() { //cleans up after the plugin (removes itself) }
//}

var plugin = {};

if(!options) {
  options = {};
}
if(!options.pluginId) options.pluginId = tributary.newPluginId();

var el = document.getElementById(options.pluginId);
var config = tributary.__config__;

plugin.activate = function() {
  el = document.getElementById(options.pluginId);
  init();
  playButton();
  timeSlider();
  restartButton();

  config.on("change:play", playButton, this);
  config.on("change:loop", timeSlider, this);
  config.on("change:restart", restartButton, this);
  config.on("pause", onPlayPause, this);

  //Setup the ui for choosing the controls in the config div
  var configDiv = d3.select("#config-content");
  var timecontrolsDiv = configDiv.node().appendChild(d3.select(el).select(".timecontrols").node());
  var timecontrols = d3.select(timecontrolsDiv)
    .selectAll("button");

    timecontrols.datum(function() { return this.dataset; })
    timecontrols.filter(function(d) {
      return config.get(d.name);
    })
    .classed("active", true);

    timecontrols.on("click", function(d) {
      var tf = !config.get(d.name);
      d3.select(this).classed("active", tf);
      config.set(d.name, tf);
    });
}

plugin.deactivate = function() {
  el.innerHTML = "";

  tributary.pause = true;
  var configDiv = d3.select("#config-content");
  var timecontrolsDiv = configDiv.select(".timecontrols").remove();

  //remove all the stuff we added to tributary
  destroy();
}

function onPlayPause() {
  var tc = d3.select(el).select(".time_controls");
  var pb = tc.select("button.play");
  if(!tributary.pause){
    pb.classed("playing", false);
    pb.text("Play");
  } else if(tributary.pause){
    pb.classed("playing", true);
    pb.text("Pause");
  }

  if(tributary.t < 1 || !tributary.loop) {
    tributary.pause = !tributary.pause;

    if(!tributary.pause) {
      //unpausing, so we setup our timer to run
      tributary.timer.then = new Date();
      tributary.timer.duration = (1 - tributary.t) * tributary.duration;
      tributary.timer.ctime = tributary.t;
    }
  }
}
function playButton() {
  //add/remove play button
  var tc = d3.select(el).select(".time_controls");
  if(config.get("play")) {
    //create the button
    var pb = tc.select("button.play")
    pb.style("display", "")

    pb.on("click", onPlayPause);
    onPlayPause();
  } else {
    //destroy the button
    tc.select("button.play").style("display", "none");
  }
}

function timeSlider() {
  tributary.loop = config.get("loop");
  var tc = d3.select(el).select(".time_controls");
  if(tributary.loop) {
    var ts = tc.select("input.time_slider");
    ts.style("display", "")

    //idk why jquery selections for on("change") works but d3 doesnt...
    ts.on('change', function() {
      tributary.t = parseFloat(this.value);//$('#slider').attr('value');
      if(tributary.pause){
        //only want to run code if we aren't already playing
        tributary.execute();
      }
    });
    config.on("tick", function(t) {
      ts.node().setAttribute("value", tributary.t);
      ts.node().value = tributary.t;
    });

    //TODO: generalize BV button to other displays
    if(config.get("display") === "svg") {
      var bv = tc.select("button.bv")
      bv.style("display", "");

      bv.on("click", function() {
        tributary.bv = !tributary.bv;
        tributary.events.trigger("execute");
      });
    }

  } else {
    tributary.bv = false;
    tc.select("input.time_slider").style("display", "none");
    tc.select("button.bv").style("display", "none");
  }

}

//RESTART BUTTON
//this restart button does something special. It calls the user defined init function, but it also
//makes it so that normal execution does not call the init function
function onRestart() {
  tributary.clear();
  tributary.initialize(tributary.g, tributary);
  if(tributary.init) {
    tributary.init(tributary.g);
  }
  tributary.execute();
  tributary.events.trigger("restart");
}
function restartButton() {
  var that = this;
  //console.log("play!", config.get("play"));
  //add/remove play button
  var tc = d3.select(el).select(".time_controls");
  if(config.get("restart")) {
    tributary.autoinit = false;
    //create the button
    var rb = tc.select("button.restart")
      .classed("button_on", true)
    rb.style("display", "")

    rb.on("click", onRestart);
    onRestart();
  } else {
    tributary.autoinit = true;
    //destroy the button
    tc.select("button.restart").style("display", "none");
  }
}

function init() {
  //time controls;
  tributary.loop = config.get("loop");

  //default parameters for this context
  tributary.pause = config.get("pause"); //pause is used to pause and unpause
  tributary.loop_type = config.get("loop_type"); //["off", "period", "pingpong"]
  tributary.bv = config.get("bv");
  tributary.nclones = config.get("nclones");
  tributary.clone_opacity = config.get("clone_opacity");
  tributary.duration = config.get("duration");
  tributary.ease = d3.ease(config.get("ease"));
  tributary.t = 0;
  tributary.dt = config.get("dt");
  tributary.reverse = false;

  //we need to save state of timer so when we pause/unpause or manually change slider
  //we can finish a transition
  tributary.timer = {
    then: new Date(),
    duration: tributary.duration,
    ctime: tributary.t
  };

  tributary.execute = function() {
    if(tributary.run !== undefined) {
      var t = tributary.t;
      if(tributary.loop) {
        t = tributary.ease(tributary.t);
      }
      tributary.run(tributary.g, t, 0);
    }
  }

  d3.timer(timerFunction);
  function timerFunction() {
    tributary.render();
    //if paused lets not execute
    if(tributary.pause) { return false; }
    if(tributary.__error__) { return false; }

    var now = new Date();
    var dtime = now - tributary.timer.then;
    var dt;

    //TODO: implement play button, should reset the timer
    if(tributary.loop) {
      if (tributary.reverse) {
        dt = tributary.timer.ctime * dtime / tributary.timer.duration * -1;
      } else {
        dt = (1 - tributary.timer.ctime) * dtime / tributary.timer.duration;
      }
      tributary.t = tributary.timer.ctime + dt;

      //once we reach 1, lets pause and stay there
      if(tributary.t >= 1 || tributary.t <= 0 || tributary.t === "NaN")
      {
        if(tributary.loop_type === "period") {
          tributary.t = 0;
          tributary.timer.then = new Date();
          tributary.timer.duration = tributary.duration;
          tributary.timer.ctime = tributary.t;
          tributary.reverse = false;
          //tributary.pause = false;
        } else if (tributary.loop_type === "pingpong") {
          //this sets tributary.t to 0 when we get to 0 and 1 when we get to 1 (because of the direction we were going)
          tributary.t = !tributary.reverse; //*1 casts the boolean to an int;
          tributary.timer.then = new Date();
          tributary.timer.duration = tributary.duration;
          tributary.timer.ctime = tributary.t;
          tributary.reverse = !tributary.reverse;
        }
        else {
          if (tributary.t !== 0)
          {
              tributary.t = 1;
              tributary.pause = true;
              tributary.__config__.trigger("pause");
          }
        }
      }
      //TODO: fix, look up 10 lines to pingpong
      //not sure why we get true and false for 1 and 0 when range hits the end
      if(tributary.t === true) { tributary.t = 1; }
      if(tributary.t === false) { tributary.t = 0; }
    } else {
      tributary.t += tributary.dt;
    }

    try {
      tributary.execute();
      tributary.__config__.trigger("noerror");
    } catch (err) {
      tributary.__config__.trigger("error", err);
    }
    tributary.__config__.trigger("tick", tributary.t);
  }

  //Clones
  tributary.events.on("prerender", function() {
    if(tributary.clones && config.get("display") === "svg") {
      $(tributary.clones.node()).empty();
    }
    if(tributary.bv) {
      makeClones();
    }
  });
}

function destroy() {
}

//TODO: make canvas clones
//This function
makeClones = function() {
  //create the clone and tributary g elements if they don't exist
  var svg = d3.select("#display").select("svg");
  tributary.clones = svg.selectAll("g.clones")
    .data([0]);
  tributary.clones
    .enter()
    .append("g").attr("class", "clones");
  tributary.g = svg.selectAll("g.delta")
    .data([0]);
  tributary.g
    .enter()
    .append("g").attr("class", "delta");

  //make n frames with lowered opacity
  var frames = d3.range(tributary.nclones);
  var gf = tributary.clones.selectAll("g.bvclone")
    .data(frames).enter()
    .append("g")
      .attr("class", "bvclone")
      .style("opacity", tributary.clone_opacity);

  gf.each(function(d, i) {
    var j = i+1;
    var frame = d3.select(this);
    tributary.init(frame, j);
    //tributary.run(i/tributary.nclones, frame, i);
    var t = tributary.ease(j/(tributary.nclones+1));
    tributary.run(frame, t, j);
  });
}

return plugin;

<|endoftext|>