<commit_before>//----------------------------------------------------------------------------
//  Copyright (C) 2013 The IPython Development Team
//
//  Distributed under the terms of the BSD License.  The full license is in
//  the file COPYING, distributed as part of this software.
//----------------------------------------------------------------------------

//============================================================================
// Base Widget Model and View classes
//============================================================================

/**
 * @module IPython
 * @namespace IPython
 **/

define(["notebook/js/widgetmanager",
        "underscore",
        "backbone"],
function(widget_manager, underscore, backbone){

    var WidgetModel = Backbone.Model.extend({
        constructor: function (widget_manager, model_id, comm) {
            // Construcctor
            //
            // Creates a WidgetModel instance.
            //
            // Parameters
            // ----------
            // widget_manager : WidgetManager instance
            // model_id : string
            //      An ID unique to this model.
            // comm : Comm instance (optional)
            this.widget_manager = widget_manager;
            this.pending_msgs = 0;
            this.msg_throttle = 2;
            this.msg_buffer = null;
            this.key_value_lock = null;
            this.id = model_id;
            this.views = [];

            if (comm !== undefined) {
                // Remember comm associated with the model.
                this.comm = comm;
                comm.model = this;

                // Hook comm messages up to model.
                comm.on_close($.proxy(this._handle_comm_closed, this));
                comm.on_msg($.proxy(this._handle_comm_msg, this));
            }
            return Backbone.Model.apply(this);
        },

        send: function (content, callbacks) {
            // Send a custom msg over the comm.
            if (this.comm !== undefined) {
                var data = {method: 'custom', custom_content: content};
                this.comm.send(data, callbacks);
            }
        },

        _handle_comm_closed: function (msg) {
            // Handle when a widget is closed.
            this.trigger('comm:close');
            delete this.comm.model; // Delete ref so GC will collect widget model.
            delete this.comm;
            delete this.model_id; // Delete id from model so widget manager cleans up.
            // TODO: Handle deletion, like this.destroy(), and delete views, etc.
        },

        _handle_comm_msg: function (msg) {
            // Handle incoming comm msg.
            var method = msg.content.data.method;
            switch (method) {
                case 'update':
                    this.apply_update(msg.content.data.state);
                    break;
                case 'custom':
                    this.trigger('msg:custom', msg.content.data.custom_content);
                    break;
                case 'display':
                    this.widget_manager.display_view(msg.parent_header.msg_id, this);
                    break;
            }
        },

        apply_update: function (state) {
            // Handle when a widget is updated via the python side.
            for (var key in state) {
                if (state.hasOwnProperty(key)) {
                    var value = state[key];
                    this.key_value_lock = [key, value];
                    try {
                        this.set(key, this._unpack_models(value));
                    } finally {
                        this.key_value_lock = null;
                    }
                }
            }
            //TODO: are there callbacks that make sense in this case?  If so, attach them here as an option
            this.save();
        },

        _handle_status: function (msg, callbacks) {
            // Handle status msgs.

            // execution_state : ('busy', 'idle', 'starting')
            if (this.comm !== undefined) {
                if (msg.content.execution_state ==='idle') {
                    // Send buffer if this message caused another message to be
                    // throttled.
                    if (this.msg_buffer !== null &&
                        this.msg_throttle === this.pending_msgs) {
                        var data = {method: 'backbone', sync_method: 'update', sync_data: this.msg_buffer};
                        this.comm.send(data, callbacks);
                        this.msg_buffer = null;
                    } else {
                        --this.pending_msgs;
                    }
                }
            }
        },

        _handle_sync: function (method, options) {
            // Custom syncronization logic.
            var model_json = this.toJSON();
            var attr;

            // Only send updated state if the state hasn't been changed
            // during an update.
            if (this.comm !== undefined) {
                if (this.pending_msgs >= this.msg_throttle) {
                    // The throttle has been exceeded, buffer the current msg so
                    // it can be sent once the kernel has finished processing
                    // some of the existing messages.
                    if (this.msg_buffer === null) {
                        this.msg_buffer = $.extend({}, model_json); // Copy
                    }
                    for (attr in options.attrs) {
                        var value = this._pack_models(options.attrs[attr]);
                        if (this.key_value_lock === null || attr !== this.key_value_lock[0] || value !== this.key_value_lock[1]) {
                            this.msg_buffer[attr] = value;
                        }
                    }

                } else {
                    // We haven't exceeded the throttle, send the message like
                    // normal.  If this is a patch operation, just send the
                    // changes.
                    var send_json = model_json;
                    send_json = {};
                    for (attr in options.attrs) {
                        var value = this._pack_models(options.attrs[attr]);
                        if (this.key_value_lock === null || attr !== this.key_value_lock[0] || value !== this.key_value_lock[1]) {
                            send_json[attr] = value;
                        }
                    }

                    var is_empty = true;
                    for (var prop in send_json) if (send_json.hasOwnProperty(prop)) is_empty = false;
                    if (!is_empty) {
                        ++this.pending_msgs;
                        var data = {method: 'backbone', sync_data: send_json};
                        this.comm.send(data, options.callbacks);
                    }
                }
            }

            // Since the comm is a one-way communication, assume the message
            // arrived.
            return model_json;
        },

        _pack_models: function(value) {
            // Replace models with model ids recursively.
            if (value instanceof Backbone.Model) {
                return value.id;
            } else if (value instanceof Object) {
                var packed = {};
                for (var key in value) {
                    packed[key] = this._pack_models(value[key]);
                }
                return packed;
            } else {
                return value;
            }
        },

        _unpack_models: function(value) {
            // Replace model ids with models recursively.
            if (value instanceof Object) {
                var unpacked = {};
                for (var key in value) {
                    unpacked[key] = this._unpack_models(value[key]);
                }
                return unpacked;
            } else {
                var model = this.widget_manager.get_model(value);
                if (model !== null) {
                    return model;
                } else {
                    return value;
                }
            }
        },

    });
    widget_manager.register_widget_model('WidgetModel', WidgetModel);

    var WidgetView = Backbone.View.extend({
        initialize: function(parameters) {
            // Public constructor.
            this.model.on('change',this.update,this);
            this.options = parameters.options;
            this.child_views = [];
            this.model.views.push(this);
        },

        update: function(){
            // Triggered on model change.
            //
            // Update view to be consistent with this.model
        },

        create_child_view: function(child_model, options) {
            // Create and return a child view.
            //
            // -given a model and (optionally) a view name if the view name is
            // not given, it defaults to the model's default view attribute.

            // TODO: this is hacky, and makes the view depend on this cell attribute and widget manager behavior
	        // it would be great to have the widget manager add the cell metadata
	        // to the subview without having to add it here.
	        options = options || {};
            options.cell = this.options.cell;
            var child_view = this.model.widget_manager.create_view(child_model, options);
            this.child_views[child_model.id] = child_view;
            return child_view;
        },

        delete_child_view: function(child_model, options) {
            // Delete a child view that was previously created using create_child_view.
            var view = this.child_views[child_model.id];
            delete this.child_views[child_model.id];
            view.remove();
        },

        do_diff: function(old_list, new_list, removed_callback, added_callback) {
            // Difference a changed list and call remove and add callbacks for
            // each removed and added item in the new list.
            //
            // Parameters
            // ----------
            // old_list : array
            // new_list : array
            // removed_callback : Callback(item)
            //      Callback that is called for each item removed.
            // added_callback : Callback(item)
            //      Callback that is called for each item added.

            // removed items
            _.each(_.difference(old_list, new_list), function(item, index, list) {
                removed_callback(item);
            }, this);

            // added items
            _.each(_.difference(new_list, old_list), function(item, index, list) {
                added_callback(item);
            }, this);
        },

        callbacks: function(){
            // Create msg callbacks for a comm msg.
            return this.model.widget_manager.callbacks(this);
        },

        render: function(){
            // Render the view.
            //
            // By default, this is only called the first time the view is created
        },

        send: function (content) {
            // Send a custom msg associated with this view.
            this.model.send(content, this.callbacks());
        },

        touch: function () {
            // Associate recent model changes with this notebook.
            this.model.save(this.model.changedAttributes(), {patch: true, callbacks: this.callbacks()});
        },

    });

    var DOMWidgetView = WidgetView.extend({
        initialize: function (options) {
            // Public constructor

            // In the future we may want to make changes more granular
            // (e.g., trigger on visible:change).
            this.model.on('change', this.update, this);
            this.model.on('msg:custom', this.on_msg, this);
            DOMWidgetView.__super__.initialize.apply(this, arguments);
        },

        on_msg: function(msg) {
            // Handle DOM specific msgs.
            switch(msg.msg_type) {
                case 'add_class':
                    this.add_class(msg.selector, msg.class_list);
                    break;
                case 'remove_class':
                    this.remove_class(msg.selector, msg.class_list);
                    break;
            }
        },

        add_class: function (selector, class_list) {
            // Add a DOM class to an element.
            this._get_selector_element(selector).addClass(class_list);
        },

        remove_class: function (selector, class_list) {
            // Remove a DOM class from an element.
            this._get_selector_element(selector).removeClass(class_list);
        },

        update: function () {
            // Update the contents of this view
            //
            // Called when the model is changed.  The model may have been
            // changed by another view or by a state update from the back-end.
            //      The very first update seems to happen before the element is
            // finished rendering so we use setTimeout to give the element time
            // to render
            var e = this.$el;
            var visible = this.model.get('visible');
            setTimeout(function() {e.toggle(visible)},0);

            var css = this.model.get('_css');
            if (css === undefined) {return;}
            for (var selector in css) {
                if (css.hasOwnProperty(selector)) {
                    // Apply the css traits to all elements that match the selector.
                    var elements = this._get_selector_element(selector);
                    if (elements.length > 0) {
                        var css_traits = css[selector];
                        for (var css_key in css_traits) {
                            if (css_traits.hasOwnProperty(css_key)) {
                                elements.css(css_key, css_traits[css_key]);
                            }
                        }
                    }
                }
            }
        },

        _get_selector_element: function (selector) {
            // Get the elements via the css selector.

            // If the selector is blank, apply the style to the $el_to_style
            // element.  If the $el_to_style element is not defined, use apply
            // the style to the view's element.
            var elements;
            if (selector === undefined || selector === null || selector === '') {
                if (this.$el_to_style === undefined) {
                    elements = this.$el;
                } else {
                    elements = this.$el_to_style;
                }
            } else {
                elements = this.$el.find(selector);
            }
            return elements;
        },
    });

    IPython.WidgetModel = WidgetModel;
    IPython.WidgetView = WidgetView;
    IPython.DOMWidgetView = DOMWidgetView;

    // Pass through widget_manager instance (probably not a good practice).
    return widget_manager;
});
<commit_msg>make the saving to python a method of the model, called with callbacks<commit_after>//----------------------------------------------------------------------------
//  Copyright (C) 2013 The IPython Development Team
//
//  Distributed under the terms of the BSD License.  The full license is in
//  the file COPYING, distributed as part of this software.
//----------------------------------------------------------------------------

//============================================================================
// Base Widget Model and View classes
//============================================================================

/**
 * @module IPython
 * @namespace IPython
 **/

define(["notebook/js/widgetmanager",
        "underscore",
        "backbone"],
function(widget_manager, underscore, backbone){

    var WidgetModel = Backbone.Model.extend({
        constructor: function (widget_manager, model_id, comm) {
            // Construcctor
            //
            // Creates a WidgetModel instance.
            //
            // Parameters
            // ----------
            // widget_manager : WidgetManager instance
            // model_id : string
            //      An ID unique to this model.
            // comm : Comm instance (optional)
            this.widget_manager = widget_manager;
            this.pending_msgs = 0;
            this.msg_throttle = 2;
            this.msg_buffer = null;
            this.key_value_lock = null;
            this.id = model_id;
            this.views = [];

            if (comm !== undefined) {
                // Remember comm associated with the model.
                this.comm = comm;
                comm.model = this;

                // Hook comm messages up to model.
                comm.on_close($.proxy(this._handle_comm_closed, this));
                comm.on_msg($.proxy(this._handle_comm_msg, this));
            }
            return Backbone.Model.apply(this);
        },

        send: function (content, callbacks) {
            // Send a custom msg over the comm.
            if (this.comm !== undefined) {
                var data = {method: 'custom', custom_content: content};
                this.comm.send(data, callbacks);
            }
        },

        _handle_comm_closed: function (msg) {
            // Handle when a widget is closed.
            this.trigger('comm:close');
            delete this.comm.model; // Delete ref so GC will collect widget model.
            delete this.comm;
            delete this.model_id; // Delete id from model so widget manager cleans up.
            // TODO: Handle deletion, like this.destroy(), and delete views, etc.
        },

        _handle_comm_msg: function (msg) {
            // Handle incoming comm msg.
            var method = msg.content.data.method;
            switch (method) {
                case 'update':
                    this.apply_update(msg.content.data.state);
                    break;
                case 'custom':
                    this.trigger('msg:custom', msg.content.data.custom_content);
                    break;
                case 'display':
                    this.widget_manager.display_view(msg.parent_header.msg_id, this);
                    break;
            }
        },

        apply_update: function (state) {
            // Handle when a widget is updated via the python side.
            for (var key in state) {
                if (state.hasOwnProperty(key)) {
                    var value = state[key];
                    this.key_value_lock = [key, value];
                    try {
                        this.set(key, this._unpack_models(value));
                    } finally {
                        this.key_value_lock = null;
                    }
                }
            }
            //TODO: are there callbacks that make sense in this case?  If so, attach them here as an option
            this.save();
        },

        _handle_status: function (msg, callbacks) {
            // Handle status msgs.

            // execution_state : ('busy', 'idle', 'starting')
            if (this.comm !== undefined) {
                if (msg.content.execution_state ==='idle') {
                    // Send buffer if this message caused another message to be
                    // throttled.
                    if (this.msg_buffer !== null &&
                        this.msg_throttle === this.pending_msgs) {
                        var data = {method: 'backbone', sync_method: 'update', sync_data: this.msg_buffer};
                        this.comm.send(data, callbacks);
                        this.msg_buffer = null;
                    } else {
                        --this.pending_msgs;
                    }
                }
            }
        },

        _handle_sync: function (method, options) {
            // Custom syncronization logic.
            var model_json = this.toJSON();
            var attr;

            // Only send updated state if the state hasn't been changed
            // during an update.
            if (this.comm !== undefined) {
                if (this.pending_msgs >= this.msg_throttle) {
                    // The throttle has been exceeded, buffer the current msg so
                    // it can be sent once the kernel has finished processing
                    // some of the existing messages.
                    if (this.msg_buffer === null) {
                        this.msg_buffer = $.extend({}, model_json); // Copy
                    }
                    for (attr in options.attrs) {
                        var value = this._pack_models(options.attrs[attr]);
                        if (this.key_value_lock === null || attr !== this.key_value_lock[0] || value !== this.key_value_lock[1]) {
                            this.msg_buffer[attr] = value;
                        }
                    }

                } else {
                    // We haven't exceeded the throttle, send the message like
                    // normal.  If this is a patch operation, just send the
                    // changes.
                    var send_json = model_json;
                    send_json = {};
                    for (attr in options.attrs) {
                        var value = this._pack_models(options.attrs[attr]);
                        if (this.key_value_lock === null || attr !== this.key_value_lock[0] || value !== this.key_value_lock[1]) {
                            send_json[attr] = value;
                        }
                    }

                    var is_empty = true;
                    for (var prop in send_json) if (send_json.hasOwnProperty(prop)) is_empty = false;
                    if (!is_empty) {
                        ++this.pending_msgs;
                        var data = {method: 'backbone', sync_data: send_json};
                        this.comm.send(data, options.callbacks);
                    }
                }
            }

            // Since the comm is a one-way communication, assume the message
            // arrived.
            return model_json;
        },

        push: function(callbacks) {
			// Push this model's state to the back-end
			//
			// This invokes a Backbone.Sync.
            this.save(this.changedAttributes(), {patch: true, callbacks: callbacks});
        },

        _pack_models: function(value) {
            // Replace models with model ids recursively.
            if (value instanceof Backbone.Model) {
                return value.id;
            } else if (value instanceof Object) {
                var packed = {};
                for (var key in value) {
                    packed[key] = this._pack_models(value[key]);
                }
                return packed;
            } else {
                return value;
            }
        },

        _unpack_models: function(value) {
            // Replace model ids with models recursively.
            if (value instanceof Object) {
                var unpacked = {};
                for (var key in value) {
                    unpacked[key] = this._unpack_models(value[key]);
                }
                return unpacked;
            } else {
                var model = this.widget_manager.get_model(value);
                if (model !== null) {
                    return model;
                } else {
                    return value;
                }
            }
        },

    });
    widget_manager.register_widget_model('WidgetModel', WidgetModel);

    var WidgetView = Backbone.View.extend({
        initialize: function(parameters) {
            // Public constructor.
            this.model.on('change',this.update,this);
            this.options = parameters.options;
            this.child_views = [];
            this.model.views.push(this);
        },

        update: function(){
            // Triggered on model change.
            //
            // Update view to be consistent with this.model
        },

        create_child_view: function(child_model, options) {
            // Create and return a child view.
            //
            // -given a model and (optionally) a view name if the view name is
            // not given, it defaults to the model's default view attribute.

            // TODO: this is hacky, and makes the view depend on this cell attribute and widget manager behavior
	        // it would be great to have the widget manager add the cell metadata
	        // to the subview without having to add it here.
	        options = options || {};
            options.cell = this.options.cell;
            var child_view = this.model.widget_manager.create_view(child_model, options);
            this.child_views[child_model.id] = child_view;
            return child_view;
        },

        delete_child_view: function(child_model, options) {
            // Delete a child view that was previously created using create_child_view.
            var view = this.child_views[child_model.id];
            delete this.child_views[child_model.id];
            view.remove();
        },

        do_diff: function(old_list, new_list, removed_callback, added_callback) {
            // Difference a changed list and call remove and add callbacks for
            // each removed and added item in the new list.
            //
            // Parameters
            // ----------
            // old_list : array
            // new_list : array
            // removed_callback : Callback(item)
            //      Callback that is called for each item removed.
            // added_callback : Callback(item)
            //      Callback that is called for each item added.

            // removed items
            _.each(_.difference(old_list, new_list), function(item, index, list) {
                removed_callback(item);
            }, this);

            // added items
            _.each(_.difference(new_list, old_list), function(item, index, list) {
                added_callback(item);
            }, this);
        },

        callbacks: function(){
            // Create msg callbacks for a comm msg.
            return this.model.widget_manager.callbacks(this);
        },

        render: function(){
            // Render the view.
            //
            // By default, this is only called the first time the view is created
        },

        send: function (content) {
            // Send a custom msg associated with this view.
            this.model.send(content, this.callbacks());
        },

        touch: function () {
            this.model.push(this.callbacks());
        },

    });

    var DOMWidgetView = WidgetView.extend({
        initialize: function (options) {
            // Public constructor

            // In the future we may want to make changes more granular
            // (e.g., trigger on visible:change).
            this.model.on('change', this.update, this);
            this.model.on('msg:custom', this.on_msg, this);
            DOMWidgetView.__super__.initialize.apply(this, arguments);
        },

        on_msg: function(msg) {
            // Handle DOM specific msgs.
            switch(msg.msg_type) {
                case 'add_class':
                    this.add_class(msg.selector, msg.class_list);
                    break;
                case 'remove_class':
                    this.remove_class(msg.selector, msg.class_list);
                    break;
            }
        },

        add_class: function (selector, class_list) {
            // Add a DOM class to an element.
            this._get_selector_element(selector).addClass(class_list);
        },

        remove_class: function (selector, class_list) {
            // Remove a DOM class from an element.
            this._get_selector_element(selector).removeClass(class_list);
        },

        update: function () {
            // Update the contents of this view
            //
            // Called when the model is changed.  The model may have been
            // changed by another view or by a state update from the back-end.
            //      The very first update seems to happen before the element is
            // finished rendering so we use setTimeout to give the element time
            // to render
            var e = this.$el;
            var visible = this.model.get('visible');
            setTimeout(function() {e.toggle(visible)},0);

            var css = this.model.get('_css');
            if (css === undefined) {return;}
            for (var selector in css) {
                if (css.hasOwnProperty(selector)) {
                    // Apply the css traits to all elements that match the selector.
                    var elements = this._get_selector_element(selector);
                    if (elements.length > 0) {
                        var css_traits = css[selector];
                        for (var css_key in css_traits) {
                            if (css_traits.hasOwnProperty(css_key)) {
                                elements.css(css_key, css_traits[css_key]);
                            }
                        }
                    }
                }
            }
        },

        _get_selector_element: function (selector) {
            // Get the elements via the css selector.

            // If the selector is blank, apply the style to the $el_to_style
            // element.  If the $el_to_style element is not defined, use apply
            // the style to the view's element.
            var elements;
            if (selector === undefined || selector === null || selector === '') {
                if (this.$el_to_style === undefined) {
                    elements = this.$el;
                } else {
                    elements = this.$el_to_style;
                }
            } else {
                elements = this.$el.find(selector);
            }
            return elements;
        },
    });

    IPython.WidgetModel = WidgetModel;
    IPython.WidgetView = WidgetView;
    IPython.DOMWidgetView = DOMWidgetView;

    // Pass through widget_manager instance (probably not a good practice).
    return widget_manager;
});
<|endoftext|>


<commit_before>App.LoadingWidgetView = Em.View.extend({
  template: Ember.Handlebars.compile('Loading{{view._ticker}}'),

  tickerChar: '.',
  tickerLength: 3,

  _ticker: '',
  _timeoutId: null,

  didInsertElement: function(){
    this.set('_timeoutId', setInterval(
      Em.$.proxy(this.tick, this),
      750
    ));
  },

  tick: function(){
    if (this.get('isDestroyed') || this.get('isDestroying')){
      return this.clear();
    }

    var state = (this.get('_ticker').length + 1) % (this.get('tickerLength') + 1),
        ticker = Array(state + 1).join(this.get('tickerChar'));

    this.set('_ticker', ticker);
  },

  willRemoveElement: Em.aliasMethod('clear'),

  clear: function(){
    if (!Em.isNone(this.get('_timeoutId')))
      return clearInterval(this.get('_timeoutId'));
  }
});
<commit_msg>Use the RunLoop/Backburner<commit_after>App.LoadingWidgetView = Em.View.extend({
  template: Ember.Handlebars.compile('Loading{{view._ticker}}'),

  tickerChar: '.',
  tickerLength: 3,

  _ticker: '',

  didInsertElement: Em.aliasMethod('schedule'),
  schedule: function(){
    Ember.run.later(this,
      Em.$.proxy(this.tick, this),
      750
    );
  },

  tick: function(){
    if (this.get('isDestroyed') || this.get('isDestroying')){ return; }

    var _ticker = this.get('_ticker'),
        tickerLength = this.get('tickerLength'),
        tickerChar = this.get('tickerChar'),

        state = (_ticker.length + 1) % (tickerLength + 1),
        ticker = Array(state + 1).join(tickerChar);

    this.set('_ticker', ticker);
    this.schedule();
  },
});
<|endoftext|>


<commit_before>(function(window, $) {
  "use strict";

  /* globals jQuery, dashboardConfig, StatsProcessor, BubbleChart, DetailTable, BarChart, ServiceList, ServiceListView */

  var DashboardOptions;

  /**
   * Dashboard options
   * @typedef {{
   *  bubble_chart_el: HTMLElement|jQuery,
   *  detail_table_el: HTMLElement|jQuery,
   *  modal_handler: ModalHandler,
   *  stats_realtime_endpoint: String
   * }}
   */
  DashboardOptions = {
    bubble_chart_el: null,
    detail_table_el: null,
    modal_handler: null,
    stats_realtime_endpoint: null
  };

  /**
   * Dashboard constructor
   * It is the magic glue between the various graphs, the data and the network updates.
   *
   * @param {DashboardOptions} options
   * @constructor
   */
  var Dashboard = function Dashboard(options) {
    var self = this;
    var $body = $('body');

    /**
     * Reference to the barchart object
     * @type {BarChart}
     */
    self.barChart = null;

    /**
     * Reference to the stats processor  object
     * @type {StatsProcessor}
     */
    self.statsProcessor = null;

    /**
     * Reference to the bubble chart object
     * @type {BubbleChart}
     */
    self.bubbleChart = null;

    /**
     * Reference to the detail table object
     * @type {DetailTable}
     */
    self.detailTable = null;

    /**
     * Reference to the services list object
     * @type {ServiceList}
     */
    self.serviceList = null;

    /**
     * Reference to the services list view object
     * @type {ServiceListView}
     */
    self.serviceListView = null;

    /**
     * Reference to the URL manager object
     * @type {URLManager}
     */
    self.urlManager = null;

    /**
     * Reference to the modal handler object
     * @type {ModalHandler}
     */
    self.modalHandler = options.modal_handler;

    self.$bubbleChartEl = options.bubble_chart_el;
    self.$detailTableEl = options.detail_table_el;

    $body.on('radioItemClick', function (evt){ self.showDetailPanelForChannel(evt.item); });
    $body.on('peakButtonClick', function (evt) { self.showPeakData(evt); });

    var initialServicesToDisplay = Dashboard.INITIAL_SERVICES_TO_DISPLAY;

    // If URL contains a service list then use that for initial services
    self.urlManager = new UrlManager({ key: 'services', delim: ',' });
    if (self.urlManager.hasItems()) {
      initialServicesToDisplay = self.urlManager.items();
    }

    options.initialServicesToDisplay = initialServicesToDisplay;

    self._initServices(initialServicesToDisplay)
        .then(function () {
          self._initStatsProcessor(options);
        });

  };

  Dashboard.INITIAL_SERVICES_TO_DISPLAY = dashboardConfig.initialServices || [];

  /**
   * Initialize the stats processor, grab some initial data and feed the graph layout
   *
   * @param {DashboardOptions} options
   * @private
   */
  Dashboard.prototype._initStatsProcessor = function _initStatsProcessor(options){
    var self = this;

    self.statsProcessor = new StatsProcessor({
      filterServices: options.initialServicesToDisplay,
      endpoint: options.stats_realtime_endpoint
    });

    // Get the Stats objects for the view and augment
    // then with programme data from an external API
    // This is asyncronous and when all the data has
    // been augmented, run initWithData
    self.statsProcessor
        .initialData()
        .then(function () {
          return self._latestStatsObjectsWithProgrammeInfo();
        })
        .then(function (latest) {
          self.initWithData(latest);
        });

    $(self.statsProcessor).on("update", function () {
      self._latestStatsObjectsWithProgrammeInfo().
          then(
            function (latest) {
              self.update(latest);
            }
          );
    });
  };

  /**
   * Fetches all the latest Stats objects and augments them
   * with programme info.
   *
   * Returns a Promise that resolves with the array of
   * augmented latest Stats objects
   *
   * @private
   */
  Dashboard.prototype._latestStatsObjectsWithProgrammeInfo = function latestStatsObjectsWithProgrammeInfo() {
    var self     = this,
        deferred = $.Deferred(),
        latest = self.statsProcessor.latest(),
        promises;

    // For each Stats object in the latest array,
    // run the method that augments with remote programme data
    promises = latest.map(self._augmentStatsWithProgrammeData);

    // When all the Stats objects in the `latest`
    // array augmented, we resolve the promise
    // and pass the latest array through
    $.when.apply(null, promises)
     .then(
      function () {
        deferred.resolve(latest);
      });

    // return the promise so the caller
    // can listen using `then` for the
    // stats objects to be augmented
    return deferred.promise();
  };

  /**
   * Augments a Stats with programme data from an external API.
   * Note: The Stats object is modified directly so any references
   *       to it will gain the programme data
   *
   * @private
   * @param {<Stats>} stats Stats object to be augmented
   * @returns {<jQuery.Deferred>} A promise that resolves when the
                                  Stat object has been augmented.
   */
  Dashboard.prototype._augmentStatsWithProgrammeData = function _augmentStatsWithProgrammeData(stats){
    var deferred = $.Deferred();
    var self = this;
    var now = new Date();
    var time_now = now.toISOString();
    var channel = stats.channel_name;

    var url =  "http://dev.notu.be/2014/05/on_tv/?start_time="+time_now+"&service_key="+channel;

    var jqxhr =  $.getJSON(url)
                  .done(function(data) {
                    if(data["response"]["docs"][0]){
                      var prog = {
                        id: data["response"]["docs"][0]["pid"],
                        title: data["response"]["docs"][0]["title"],
                        subtitle: data["response"]["docs"][0]["title"],
                        service_id: data["response"]["docs"][0]["service_key"],
                        start: data["response"]["docs"][0]["start_time"],
                        end: data["response"]["docs"][0]["end_time"],
                        image: data["response"]["docs"][0]["image_url"]
                      };
                      stats.programme = prog;
                      deferred.resolve(stats);
                    }
                  });

    return deferred.promise();
  };

  /**
   * Initializes services handling.
   * It let the ability to the user to choose the displayed channels on both bubble and detail graph
   *
   * @private
   * @param {Array.<string>} initialServicesToDisplay Service ids to be displayed
   */
  Dashboard.prototype._initServices = function _initServices(initialServicesToDisplay){
    var self = this,
        deferred = $.Deferred();

    // List of all available services
    self.serviceList = new ServiceList(initialServicesToDisplay);

    // View to allow user to select which services they want
    self.serviceListView = new ServiceListView('#services-list ul');

    // Connect the list with the view
    self.serviceList
        .services()
        .then(function (services) {
          self.serviceListView.render(services);
          self.updateBookmark();

          // Link to the Stats class so that Stats objects
          // can be linked to their parent services
          Stats.serviceList = self.serviceList;

          // All done, notify anything waiting for
          // our promise to resolve
          deferred.resolve();
        });

    $(self.serviceList).on('serviceStateChanged', function (evt) {
      self.updateService(evt.service, evt.service.isSelected);
      self.updateBookmark();
    });

    return deferred.promise();
  };

  /**
   * Initialize the dashboard with fresh data.
   * Past this point, all further inbound data may arrive from Websocket connection
   *
   * @param {Array.<Stats>} latest
   */
  Dashboard.prototype.initWithData = function initWithData(latest) {
    this.bubbleChart = new BubbleChart(this.$bubbleChartEl, latest);
    this.detailTable = new DetailTable(this.$detailTableEl, latest);
  };

  /**
   * Updates the dashboard with new data.
   * Everything is automatically redrawn on screen.
   *
   * @api
   * @param {array} latest
   */
  Dashboard.prototype.update = function update(latest) {
    this.bubbleChart.update(latest);
    this.detailTable.update(latest);

    if (this.modalHandler.isVisible( $('#stats') )){
      var serviceId  = this.barChart.getCurrentServiceId(),
          lastUpdate = this.statsProcessor.lastUpdateReceivedForService(serviceId);

      this.barChart.appendGraphData(lastUpdate);
      this.barChart.updateGraph();
    }
  };

  /**
   * Shorthand to alter the displayed services on screen
   *
   * @api
   * @param {Service} service
   */
  Dashboard.prototype.updateService = function updateService(service) {
    if (service.isSelected) {
      this.statsProcessor.addService(service.id);
    } else {
      this.statsProcessor.removeService(service.id);
    }
  };

  /**
   * Update bookmarkable link to the current services
   *
   * @api
   */
  Dashboard.prototype.updateBookmark = function updateBookmark() {
    this.serviceList.selectedServices().then(function (services) {
      var ids = services.map(function (s) { return s.id; }).join(','),
          url = '?services=' + ids;
      $('.bookmark').attr('href', url);
    });
  };

  /**
   * Once a bubble or channel detail row is clicked, we display a detailed view with an historical view
   *
   * @api
   * @param {Stats} item
   */
  Dashboard.prototype.showDetailPanelForChannel = function showDetailPanelForChannel(item) {
    var self = this;

    //jshint devel:true
    console.log('showDetailPanelForChannel', item);

    if (!this.barChart) {
      this.barChart = new BarChart();
      this.barChart.setup({
        mediums: Object.keys(item.audience.platforms),
        programme_uri: dashboardConfig.programmeUri,
        programme_picture_uri: dashboardConfig.programmePictureUri
      });
    }

    this.barChart.updateHeadline(item);
    this.modalHandler.load( $('#stats') );

    this.statsProcessor.historicalByService(item.channel).then(function(response){
      var service_data = self.statsProcessor.parseUpdates(response.stations)[ item.channel ];

      // Swap the last data item form the server with
      // that one passed in as it will have programme
      // data
      //sometimess there's no historical data, this helps
      if(!service_data){
        console.log("No service data yet for "+item.channel+" continuing anyway");
      }else{
        service_data[service_data.length - 1] = item;
        self.barChart.update(service_data);
        self.barChart.updateGraph();
      }

      setTimeout(function(){
        self.modalHandler.loaded( $('#stats') );
      }, 1000 );
    });
  };

  /**
   * Shorthand to display the detailed++ chart.
   * Suppose you already have displayed the channel detailed view.
   *
   * @todo move that in the barchart as it's a bit unrelated to the dashboard (legacy code related)
   * @param {MouseEvent=} event
   */
  Dashboard.prototype.showPeakData = function showPeakData(event) {
    // jshint unused:vars
    this.barChart.showFluxChart();
  };

  /*
   Exporting
   */
  window['Dashboard'] = Dashboard;

}(window, jQuery));
<commit_msg>Removed dependency on dev.notu.be server<commit_after>(function(window, $) {
  "use strict";

  /* globals jQuery, dashboardConfig, StatsProcessor, BubbleChart, DetailTable, BarChart, ServiceList, ServiceListView */

  var DashboardOptions;

  /**
   * Dashboard options
   * @typedef {{
   *  bubble_chart_el: HTMLElement|jQuery,
   *  detail_table_el: HTMLElement|jQuery,
   *  modal_handler: ModalHandler,
   *  stats_realtime_endpoint: String
   * }}
   */
  DashboardOptions = {
    bubble_chart_el: null,
    detail_table_el: null,
    modal_handler: null,
    stats_realtime_endpoint: null
  };

  /**
   * Dashboard constructor
   * It is the magic glue between the various graphs, the data and the network updates.
   *
   * @param {DashboardOptions} options
   * @constructor
   */
  var Dashboard = function Dashboard(options) {
    var self = this;
    var $body = $('body');

    /**
     * Reference to the barchart object
     * @type {BarChart}
     */
    self.barChart = null;

    /**
     * Reference to the stats processor  object
     * @type {StatsProcessor}
     */
    self.statsProcessor = null;

    /**
     * Reference to the bubble chart object
     * @type {BubbleChart}
     */
    self.bubbleChart = null;

    /**
     * Reference to the detail table object
     * @type {DetailTable}
     */
    self.detailTable = null;

    /**
     * Reference to the services list object
     * @type {ServiceList}
     */
    self.serviceList = null;

    /**
     * Reference to the services list view object
     * @type {ServiceListView}
     */
    self.serviceListView = null;

    /**
     * Reference to the URL manager object
     * @type {URLManager}
     */
    self.urlManager = null;

    /**
     * Reference to the modal handler object
     * @type {ModalHandler}
     */
    self.modalHandler = options.modal_handler;

    self.$bubbleChartEl = options.bubble_chart_el;
    self.$detailTableEl = options.detail_table_el;

    $body.on('radioItemClick', function (evt){ self.showDetailPanelForChannel(evt.item); });
    $body.on('peakButtonClick', function (evt) { self.showPeakData(evt); });

    var initialServicesToDisplay = Dashboard.INITIAL_SERVICES_TO_DISPLAY;

    // If URL contains a service list then use that for initial services
    self.urlManager = new UrlManager({ key: 'services', delim: ',' });
    if (self.urlManager.hasItems()) {
      initialServicesToDisplay = self.urlManager.items();
    }

    options.initialServicesToDisplay = initialServicesToDisplay;

    self._initServices(initialServicesToDisplay)
        .then(function () {
          self._initStatsProcessor(options);
        });

  };

  Dashboard.INITIAL_SERVICES_TO_DISPLAY = dashboardConfig.initialServices || [];

  /**
   * Initialize the stats processor, grab some initial data and feed the graph layout
   *
   * @param {DashboardOptions} options
   * @private
   */
  Dashboard.prototype._initStatsProcessor = function _initStatsProcessor(options){
    var self = this;

    self.statsProcessor = new StatsProcessor({
      filterServices: options.initialServicesToDisplay,
      endpoint: options.stats_realtime_endpoint
    });

    // Get the Stats objects for the view and augment
    // them with programme data from an external API.
    // This is asynchronous and when all the data has
    // been augmented, run initWithData.
    self.statsProcessor
        .initialData()
        .then(function () {
          return self._latestStatsObjectsWithProgrammeInfo();
        })
        .then(function (latest) {
          self.initWithData(latest);
        });

    $(self.statsProcessor).on("update", function () {
      self._latestStatsObjectsWithProgrammeInfo().
          then(
            function (latest) {
              self.update(latest);
            }
          );
    });
  };

  /**
   * Fetches all the latest Stats objects and augments them
   * with programme info.
   *
   * Returns a Promise that resolves with the array of
   * augmented latest Stats objects
   *
   * @private
   */
  Dashboard.prototype._latestStatsObjectsWithProgrammeInfo = function latestStatsObjectsWithProgrammeInfo() {
    var self     = this,
        deferred = $.Deferred(),
        latest = self.statsProcessor.latest(),
        promises;

    return deferred.resolve(latest);

    /* This code is commented out because the dev.notu.be server is not
       available.

    // For each Stats object in the latest array,
    // run the method that augments with remote programme data
    promises = latest.map(self._augmentStatsWithProgrammeData);

    // When all the Stats objects in the `latest`
    // array augmented, we resolve the promise
    // and pass the latest array through
    $.when.apply(null, promises)
     .then(
      function () {
        deferred.resolve(latest);
      });

    // return the promise so the caller
    // can listen using `then` for the
    // stats objects to be augmented
    return deferred.promise();
    */
  };

  /**
   * Augments a Stats with programme data from an external API.
   * Note: The Stats object is modified directly so any references
   *       to it will gain the programme data
   *
   * @private
   * @param {<Stats>} stats Stats object to be augmented
   * @returns {<jQuery.Deferred>} A promise that resolves when the
                                  Stat object has been augmented.
   */
  Dashboard.prototype._augmentStatsWithProgrammeData = function _augmentStatsWithProgrammeData(stats){
    var deferred = $.Deferred();
    var self = this;
    var now = new Date();
    var time_now = now.toISOString();
    var channel = stats.channel_name;

    var url =  "http://dev.notu.be/2014/05/on_tv/?start_time="+time_now+"&service_key="+channel;

    var jqxhr =  $.getJSON(url)
                  .done(function(data) {
                    if(data["response"]["docs"][0]){
                      var prog = {
                        id: data["response"]["docs"][0]["pid"],
                        title: data["response"]["docs"][0]["title"],
                        subtitle: data["response"]["docs"][0]["title"],
                        service_id: data["response"]["docs"][0]["service_key"],
                        start: data["response"]["docs"][0]["start_time"],
                        end: data["response"]["docs"][0]["end_time"],
                        image: data["response"]["docs"][0]["image_url"]
                      };
                      stats.programme = prog;
                      deferred.resolve(stats);
                    }
                  });

    return deferred.promise();
  };

  /**
   * Initializes services handling.
   * It let the ability to the user to choose the displayed channels on both bubble and detail graph
   *
   * @private
   * @param {Array.<string>} initialServicesToDisplay Service ids to be displayed
   */
  Dashboard.prototype._initServices = function _initServices(initialServicesToDisplay){
    var self = this,
        deferred = $.Deferred();

    // List of all available services
    self.serviceList = new ServiceList(initialServicesToDisplay);

    // View to allow user to select which services they want
    self.serviceListView = new ServiceListView('#services-list ul');

    // Connect the list with the view
    self.serviceList
        .services()
        .then(function (services) {
          self.serviceListView.render(services);
          self.updateBookmark();

          // Link to the Stats class so that Stats objects
          // can be linked to their parent services
          Stats.serviceList = self.serviceList;

          // All done, notify anything waiting for
          // our promise to resolve
          deferred.resolve();
        });

    $(self.serviceList).on('serviceStateChanged', function (evt) {
      self.updateService(evt.service, evt.service.isSelected);
      self.updateBookmark();
    });

    return deferred.promise();
  };

  /**
   * Initialize the dashboard with fresh data.
   * Past this point, all further inbound data may arrive from Websocket connection
   *
   * @param {Array.<Stats>} latest
   */
  Dashboard.prototype.initWithData = function initWithData(latest) {
    this.bubbleChart = new BubbleChart(this.$bubbleChartEl, latest);
    this.detailTable = new DetailTable(this.$detailTableEl, latest);
  };

  /**
   * Updates the dashboard with new data.
   * Everything is automatically redrawn on screen.
   *
   * @api
   * @param {array} latest
   */
  Dashboard.prototype.update = function update(latest) {
    this.bubbleChart.update(latest);
    this.detailTable.update(latest);

    if (this.modalHandler.isVisible( $('#stats') )){
      var serviceId  = this.barChart.getCurrentServiceId(),
          lastUpdate = this.statsProcessor.lastUpdateReceivedForService(serviceId);

      this.barChart.appendGraphData(lastUpdate);
      this.barChart.updateGraph();
    }
  };

  /**
   * Shorthand to alter the displayed services on screen
   *
   * @api
   * @param {Service} service
   */
  Dashboard.prototype.updateService = function updateService(service) {
    if (service.isSelected) {
      this.statsProcessor.addService(service.id);
    } else {
      this.statsProcessor.removeService(service.id);
    }
  };

  /**
   * Update bookmarkable link to the current services
   *
   * @api
   */
  Dashboard.prototype.updateBookmark = function updateBookmark() {
    this.serviceList.selectedServices().then(function (services) {
      var ids = services.map(function (s) { return s.id; }).join(','),
          url = '?services=' + ids;
      $('.bookmark').attr('href', url);
    });
  };

  /**
   * Once a bubble or channel detail row is clicked, we display a detailed view with an historical view
   *
   * @api
   * @param {Stats} item
   */
  Dashboard.prototype.showDetailPanelForChannel = function showDetailPanelForChannel(item) {
    var self = this;

    //jshint devel:true
    console.log('showDetailPanelForChannel', item);

    if (!this.barChart) {
      this.barChart = new BarChart();
      this.barChart.setup({
        mediums: Object.keys(item.audience.platforms),
        programme_uri: dashboardConfig.programmeUri,
        programme_picture_uri: dashboardConfig.programmePictureUri
      });
    }

    this.barChart.updateHeadline(item);
    this.modalHandler.load( $('#stats') );

    this.statsProcessor.historicalByService(item.channel).then(function(response){
      var service_data = self.statsProcessor.parseUpdates(response.stations)[ item.channel ];

      // Swap the last data item form the server with
      // that one passed in as it will have programme
      // data
      //sometimess there's no historical data, this helps
      if(!service_data){
        console.log("No service data yet for "+item.channel+" continuing anyway");
      }else{
        service_data[service_data.length - 1] = item;
        self.barChart.update(service_data);
        self.barChart.updateGraph();
      }

      setTimeout(function(){
        self.modalHandler.loaded( $('#stats') );
      }, 1000 );
    });
  };

  /**
   * Shorthand to display the detailed++ chart.
   * Suppose you already have displayed the channel detailed view.
   *
   * @todo move that in the barchart as it's a bit unrelated to the dashboard (legacy code related)
   * @param {MouseEvent=} event
   */
  Dashboard.prototype.showPeakData = function showPeakData(event) {
    // jshint unused:vars
    this.barChart.showFluxChart();
  };

  /*
   Exporting
   */
  window['Dashboard'] = Dashboard;

}(window, jQuery));
<|endoftext|>


<commit_before>/**
 * bobcat_embed_switch_tab: manipulate styles to change tabs to tab_id
 *
 * @param tab_id    id of tab to change to
 * @param key       unique key to allow for multiple embeds
 */
function bobcat_embed_switch_tab(tab_id,key) {
	// Hide all tabpanels for this key
	var bobcat_tabpanels = document.getElementsByClassName(`bobcat_embed_tab_content_${key}`);
	var bobcat_previously_selected_tabpanel;
	for (var i=0;i<bobcat_tabpanels.length;i++) {
		bobcat_previously_selected_tabpanel = bobcat_tabpanels[i];
		bobcat_previously_selected_tabpanel.style.display = 'none';
		bobcat_previously_selected_tabpanel.setAttribute('aria-hidden', 'true');
	}
	// Unselect previous tab
	var bobcat_previously_selected_tab = document.getElementsByClassName(`bobcat_embed_tabs_selected_${key}`)[0];
	bobcat_previously_selected_tab.classList.remove('bobcat_embed_tabs_selected', `bobcat_embed_tabs_selected_${key}`);
	bobcat_previously_selected_tab.setAttribute('aria-selected', 'false');
	// Select current tab
	var bobcat_selected_tab = document.getElementById(tab_id);
	bobcat_selected_tab.classList.add('bobcat_embed_tabs_selected',`bobcat_embed_tabs_selected_${key}`);
	bobcat_selected_tab.setAttribute('aria-selected', 'true');
	// Show new tabpanel
	var bobcat_seleced_tabpanel = document.getElementById(`bobcat_embed_tab_content_${tab_id}`);
	bobcat_seleced_tabpanel.style.display = 'block';
	bobcat_seleced_tabpanel.setAttribute('aria-hidden', 'false');
}
<commit_msg>Removed ticks and added back regular stirng interpolation for IE<commit_after>/**
 * bobcat_embed_switch_tab: manipulate styles to change tabs to tab_id
 *
 * @param tab_id    id of tab to change to
 * @param key       unique key to allow for multiple embeds
 */
function bobcat_embed_switch_tab(tab_id,key) {
	// Hide all tabpanels for this key
	var bobcat_tabpanels = document.getElementsByClassName('bobcat_embed_tab_content_' + key);
	var bobcat_previously_selected_tabpanel;
	for (var i=0;i<bobcat_tabpanels.length;i++) {
		bobcat_previously_selected_tabpanel = bobcat_tabpanels[i];
		bobcat_previously_selected_tabpanel.style.display = 'none';
		bobcat_previously_selected_tabpanel.setAttribute('aria-hidden', 'true');
	}
	// Unselect previous tab
	var bobcat_previously_selected_tab = document.getElementsByClassName('bobcat_embed_tabs_selected_' + key)[0];
	bobcat_previously_selected_tab.classList.remove('bobcat_embed_tabs_selected', 'bobcat_embed_tabs_selected_' + key);
	bobcat_previously_selected_tab.setAttribute('aria-selected', 'false');
	// Select current tab
	var bobcat_selected_tab = document.getElementById(tab_id);
	bobcat_selected_tab.classList.add('bobcat_embed_tabs_selected','bobcat_embed_tabs_selected_' + key);
	bobcat_selected_tab.setAttribute('aria-selected', 'true');
	// Show new tabpanel
	var bobcat_seleced_tabpanel = document.getElementById('bobcat_embed_tab_content_' + tab_id);
	bobcat_seleced_tabpanel.style.display = 'block';
	bobcat_seleced_tabpanel.setAttribute('aria-hidden', 'false');
}
<|endoftext|>


<commit_before>/* jshint node:true */
/* global require, it, before, beforeEach, describe */

'use strict';
var should = require('should'),
    inquirer = require('inquirer'),
    gulp = require('gulp'),
    mockGulpDest = require('mock-gulp-dest')(gulp);

require('../slushfile');

/**
 * Mock inquirer prompt
 */

function mockPrompt(answers) {
    inquirer.prompt = function (prompts, done) {

        [].concat(prompts).forEach(function (prompt) {
            if (!(prompt.name in answers)) {
                answers[prompt.name] = prompt.default;
            }
        });

        done(answers);
    };
}

describe('slush-ng-app', function() {
    before(function () {
        process.chdir(__dirname);
        process.argv.push('--skip-install');
    });

    describe('default generator', function () {
        beforeEach(function () {
            mockPrompt({
                moveon: true
            });
        });

        it('should put all project files in current working directory', function (done) {
            gulp.start('default').once('stop', function () {
                mockGulpDest.cwd().should.equal(__dirname);
                mockGulpDest.basePath().should.equal(__dirname);
                done();
            });
        });

        it('should create expected files', function (done) {
            gulp.start('default').once('stop', function () {
                mockGulpDest.assertDestContains([
                    '.bowerrc',
                    '.editorconfig',
                    '.gitignore',
                    '.jshintrc',
                    '.travis.yml',
                    'bower.json',
                    'gulpfile.js',
                    'package.json',
                    'LICENSE',
                    'README.md',
                    'app/index.html',
                    'app/index-async.html',
                    'app/img/.gitkeep',
                    'app/css/main.css',
                    'app/css/app.css',
                    'app/js/app.js',
                    'app/js/controllers.js',
                    'app/js/directives.js',
                    'app/js/filters.js',
                    'app/js/services.js',
                    'app/partials/partial1.html',
                    'app/partials/partial2.html',
                    'test/karma.conf.js',
                    'test/protractor-conf.js',
                    'test/e2e/scenarios.js',
                    'test/unit/controllersSpec.js',
                    'test/unit/directivesSpec.js',
                    'test/unit/filtersSpec.js',
                    'test/unit/servicesSpec.js'
                ]);

                done();
            });
        });
    });
});
<commit_msg>Update tests.<commit_after>/* jshint node:true */
/* global require, it, before, beforeEach, describe */

'use strict';
var should = require('should'),
    inquirer = require('inquirer'),
    gulp = require('gulp'),
    mockGulpDest = require('mock-gulp-dest')(gulp);

require('../slushfile');

/**
 * Mock inquirer prompt
 */

function mockPrompt(answers) {
    inquirer.prompt = function (prompts, done) {

        [].concat(prompts).forEach(function (prompt) {
            if (!(prompt.name in answers)) {
                answers[prompt.name] = prompt.default;
            }
        });

        done(answers);
    };
}

describe('slush-ng-app', function() {
    before(function () {
        process.chdir(__dirname);
        process.argv.push('--skip-install');
    });

    describe('default generator', function () {
        beforeEach(function () {
            mockPrompt({
                moveon: true
            });
        });

        it('should put all project files in current working directory', function (done) {
            gulp.start('default').once('stop', function () {
                mockGulpDest.cwd().should.equal(__dirname);
                mockGulpDest.basePath().should.equal(__dirname);
                done();
            });
        });

        it('should create expected files', function (done) {
            gulp.start('default').once('stop', function () {
                mockGulpDest.assertDestContains([
                    '.bowerrc',
                    '.editorconfig',
                    '.gitignore',
                    '.jshintrc',
                    '.travis.yml',
                    'bower.json',
                    'gulpfile.js',
                    'package.json',
                    'LICENSE',
                    'README.md',
                    'app/index.html',
                    'app/index-async.html',
                    'app/img/.gitkeep',
                    'app/css/main.css',
                    'app/css/app.css',
                    'app/js/app.js',
                    'app/components/version/interpolate-filter_test.js',
                    'app/components/version/interpolate-filter.js',
                    'app/components/version/version_test.js',
                    'app/components/version/version-directive_test.js',
                    'app/components/version/version-directive.js',
                    'app/components/version/version.js',
                    'app/view1/view1.html',
                    'app/view1/view1.js',
                    'app/view1/view1_test.js',
                    'app/view2/view2.html',
                    'app/view2/view2.js',
                    'app/view2/view2_test.js',
                    'test/karma.conf.js',
                    'test/e2e-tests/protractor.conf.js',
                    'test/e2e-tests/scenarios.js'
                ]);

                done();
            });
        });
    });
});
<|endoftext|>


<commit_before>// Test the widget framework.
casper.notebook_test(function () {
    var index;

    this.then(function () {

        // Check if the WidgetManager class is defined.
        this.test.assert(this.evaluate(function() {
            return IPython.WidgetManager != undefined;
        }), 'WidgetManager class is defined');
    });

    index = this.append_cell(
        'from IPython.html import widgets\n' +
        'from IPython.display import display, clear_output\n' +
        'print("Success")');
    this.execute_cell_then(index);

    this.wait(500); // Wait for require.js async callbacks to load dependencies.

    this.then(function () {
        // Check if the widget manager has been instanciated.
        this.test.assert(this.evaluate(function() {
            return IPython.widget_manager != undefined;
        }), 'Notebook widget manager instanciated');
    });

    throttle_index = this.append_cell(
        'import time\n' +
        'textbox = widgets.TextBoxWidget()\n' +
        'display(textbox)\n'+
        'textbox.add_class("my-throttle-textbox")\n' +
        'def handle_change(name, old, new):\n' +
        '    print(len(new))\n' +
        '    time.sleep(0.5)\n' +
        'textbox.on_trait_change(handle_change)\n' +
        'print("Success")');
    this.execute_cell_then(throttle_index, function(index){
        this.test.assert(this.get_output_cell(index).text == 'Success\n',
            'Test throttling cell executed with correct output');

        this.test.assert(this.cell_element_exists(index,
            '.widget-area .widget-subarea'),
            'Widget subarea exists.');

        this.test.assert(this.cell_element_exists(index,
            '.my-throttle-textbox'), 'Textbox exists.');

        // Send 20 characters
        this.sendKeys('.my-throttle-textbox', '....................');
    });

    this.wait(2000); // Wait for clicks to execute in kernel

    this.then(function(){
        var resume = true;
        var i = 0;
        while (resume) {
            i++;
            var output = this.get_output_cell(throttle_index, i);
            if (output === undefined || output === null) {
                resume = false;
                i--;
            }
        }

        // Only 4 outputs should have printed, but because of timing, sometimes
        // 5 outputs will print.  All we need to do is verify num outputs <= 5
        // because that is much less than 20.
        this.test.assert(i <= 5, 'Messages throttled.');

        // We also need to verify that the last state sent was correct.
        var last_state = this.get_output_cell(throttle_index, i).text;
        this.test.assert(last_state == "20\n", "Last state sent when throttling.");
    })
});
<commit_msg>Fixed widget_manager instance test.<commit_after>// Test the widget framework.
casper.notebook_test(function () {
    var index;

    this.then(function () {

        // Check if the WidgetManager class is defined.
        this.test.assert(this.evaluate(function() {
            return IPython.WidgetManager != undefined;
        }), 'WidgetManager class is defined');
    });

    index = this.append_cell(
        'from IPython.html import widgets\n' +
        'from IPython.display import display, clear_output\n' +
        'print("Success")');
    this.execute_cell_then(index);

    this.wait(500); // Wait for require.js async callbacks to load dependencies.

    this.then(function () {
        // Check if the widget manager has been instanciated.
        this.test.assert(this.evaluate(function() {
            return IPython.notebook.kernel.widget_manager != undefined;
        }), 'Notebook widget manager instanciated');
    });

    throttle_index = this.append_cell(
        'import time\n' +
        'textbox = widgets.TextBoxWidget()\n' +
        'display(textbox)\n'+
        'textbox.add_class("my-throttle-textbox")\n' +
        'def handle_change(name, old, new):\n' +
        '    print(len(new))\n' +
        '    time.sleep(0.5)\n' +
        'textbox.on_trait_change(handle_change)\n' +
        'print("Success")');
    this.execute_cell_then(throttle_index, function(index){
        this.test.assert(this.get_output_cell(index).text == 'Success\n',
            'Test throttling cell executed with correct output');

        this.test.assert(this.cell_element_exists(index,
            '.widget-area .widget-subarea'),
            'Widget subarea exists.');

        this.test.assert(this.cell_element_exists(index,
            '.my-throttle-textbox'), 'Textbox exists.');

        // Send 20 characters
        this.sendKeys('.my-throttle-textbox', '....................');
    });

    this.wait(2000); // Wait for clicks to execute in kernel

    this.then(function(){
        var resume = true;
        var i = 0;
        while (resume) {
            i++;
            var output = this.get_output_cell(throttle_index, i);
            if (output === undefined || output === null) {
                resume = false;
                i--;
            }
        }

        // Only 4 outputs should have printed, but because of timing, sometimes
        // 5 outputs will print.  All we need to do is verify num outputs <= 5
        // because that is much less than 20.
        this.test.assert(i <= 5, 'Messages throttled.');

        // We also need to verify that the last state sent was correct.
        var last_state = this.get_output_cell(throttle_index, i).text;
        this.test.assert(last_state == "20\n", "Last state sent when throttling.");
    });
});
<|endoftext|>


<commit_before>const User = require('./models/user');
const Project = require('./models/project');

function projectSetup(app, csrfProtection) {
  app.get('/projects', csrfProtection, (req, res) => {
    var query = Project.find({}).sort('-saved');
    var readLanguages = (req.query.readLanguages || '').split(',');
    var writeLanguages = (req.query.writeLanguages || '').split(',');
    if ((!readLanguages && !writeLanguages) && req.user) {
      readLanguages = req.user.readLanguages;
      writeLanguages = req.user.writeLanguages;
    }

    if (readLanguages) {
      query = query.find({ fromLanguages: { $in: readLanguages } });
    }
    if (writeLanguages) {
      query = query.find({ toLanguage: { $in: writeLanguages } });
    }

    query.exec( (err, projects) => {
      if (err) {
        return res.json(err);
      }

      var rows = [];
      while (projects.length) {
        rows.push(projects.splice(0, 3));
      }

      res.render('projects', {
        user: req.user,
        rows: rows
      });
    });
  });

  app.get('/projects/new', csrfProtection, (req, res) => {
    if (!req.user) {
      return res.redirect('/login');
    }
    res.render('new-project', {
      csrfToken: req.csrfToken()
    });
  });

  app.post('/projects/new', csrfProtection, (req, res) => {
    if (!req.user) {
      return res.redirect('/login');
    }
    var p = new Project({
      founding_user_id: req.user._id,
      founding_user_osm_id: req.user.osm_id,
      fromLanguages: req.body.fromLanguages,
      toLanguage: req.body.toLanguage,
      directions: req.body.directions,
      saved: new Date(),
      lat: req.body.lat,
      lng: req.body.lng,
      zoom: req.body.zoom
    });
    p.save((err) => {
      if (err) {
        return res.json(err);
      }
      res.redirect('/projects/' + p._id);
    });
  });

  app.get('/projects/:id', csrfProtection, (req, res) => {
    Project.findById(req.params.id, (err, project) => {
      if (err) {
        return res.json(err);
      }
      res.render('naming', {
        lat: project.lat,
        lng: project.lng,
        zoom: project.zoom,
        fromLanguages: project.fromLanguages,
        toLanguage: project.toLanguage,
        csrfToken: req.csrfToken()
      });
    });
  });
}

module.exports = projectSetup;
<commit_msg>test issue with project filter<commit_after>const User = require('./models/user');
const Project = require('./models/project');

function projectSetup(app, csrfProtection) {
  app.get('/projects', csrfProtection, (req, res) => {
    var query = Project.find({}).sort('-saved');
    var readLanguages = (req.query.readLanguages || '').split(',');
    var writeLanguages = (req.query.writeLanguages || '').split(',');
    if ((!readLanguages && !writeLanguages) && req.user) {
      readLanguages = req.user.readLanguages;
      writeLanguages = req.user.writeLanguages;
    }

/*
    if (readLanguages) {
      query = query.find({ fromLanguages: { $in: readLanguages } });
    }
    if (writeLanguages) {
      query = query.find({ toLanguage: { $in: writeLanguages } });
    }
    */

    query.exec( (err, projects) => {
      if (err) {
        return res.json(err);
      }

      var rows = [];
      while (projects.length) {
        rows.push(projects.splice(0, 3));
      }

      res.render('projects', {
        user: req.user,
        rows: rows
      });
    });
  });

  app.get('/projects/new', csrfProtection, (req, res) => {
    if (!req.user) {
      return res.redirect('/login');
    }
    res.render('new-project', {
      csrfToken: req.csrfToken()
    });
  });

  app.post('/projects/new', csrfProtection, (req, res) => {
    if (!req.user) {
      return res.redirect('/login');
    }
    var p = new Project({
      founding_user_id: req.user._id,
      founding_user_osm_id: req.user.osm_id,
      fromLanguages: req.body.fromLanguages,
      toLanguage: req.body.toLanguage,
      directions: req.body.directions,
      saved: new Date(),
      lat: req.body.lat,
      lng: req.body.lng,
      zoom: req.body.zoom
    });
    p.save((err) => {
      if (err) {
        return res.json(err);
      }
      res.redirect('/projects/' + p._id);
    });
  });

  app.get('/projects/:id', csrfProtection, (req, res) => {
    Project.findById(req.params.id, (err, project) => {
      if (err) {
        return res.json(err);
      }
      res.render('naming', {
        lat: project.lat,
        lng: project.lng,
        zoom: project.zoom,
        fromLanguages: project.fromLanguages,
        toLanguage: project.toLanguage,
        csrfToken: req.csrfToken()
      });
    });
  });
}

module.exports = projectSetup;
<|endoftext|>


<commit_before>/**
 * Trelloviz
 * Copyright 2012 Martin W. Kirst
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

/**
 * Sample usage: <input type="text" data-bind="colorPicker:color" />
 */

if (typeof ko != 'undefined') {
  ko.bindingHandlers.colorPicker = {
    init:function (element, valueAccessor, allBindingsAccessor, viewModel) {
      var value = valueAccessor();
      $(element).val(ko.utils.unwrapObservable(value));
      $(element).colorPicker({onColorChange: function(elementId, newColorValue) {
        value(newColorValue);
      }});
    },
    update:function (element, valueAccessor, allBindingsAccessor, viewModel) {
      $(element).val(ko.utils.unwrapObservable(valueAccessor()));
    }
  }
}

<commit_msg>shelf - testing observable array elements<commit_after>/**
 * Trelloviz
 * Copyright 2012 Martin W. Kirst
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

/**
 * Sample usage: <input type="text" data-bind="colorPicker:color" />
 */

if (typeof ko != 'undefined') {
  ko.bindingHandlers.colorPicker = {
    init:function (element, valueAccessor, allBindingsAccessor, viewModel) {
      var value = valueAccessor();
      $(element).val(ko.utils.unwrapObservable(value));
      $(element).colorPicker({onColorChange:function (elementId, newColorValue) {
        value(newColorValue);
      }});
    },
    update:function (element, valueAccessor, allBindingsAccessor, viewModel) {
      $(element).val(ko.utils.unwrapObservable(valueAccessor()));
    }
  }
}

ko.extenders.logChange = function(target, option) {
  target.subscribe(function(newValue) {
    console.log(option + ": " + newValue);
  });
  return target;
};
<|endoftext|>


<commit_before>#!/usr/bin/env node
/* Copyright 2015, Yahoo Inc.
   Copyrights licensed under the MIT License.
   See the accompanying LICENSE file for terms. */

var fs = require('fs');
var path = require('path');
var spawn = require('child_process').spawn;

var packagesdir = path.join(__dirname, '../packages');
var examplesdir = path.join(__dirname, '../examples');
var rootdir = path.join(__dirname, '..');

npm(['install'], rootdir, function() {
    var async = require('async');
    var linkedModules = [];
    var linkedDeps = {};

    async.reduce([packagesdir, examplesdir], [],
    function(packages, dir, doneDir){
        fs.readdir(dir, function(err, subdirs) {
            subdirs = subdirs.map(function(subdir) {
                return path.join(dir, subdir);
            });
            doneDir(err, packages.concat(subdirs));
        });
    },
    function linkPackages(err, packages){
        var doAgain = [];

        async.eachSeries(packages, function(file, donePackage) {
            var pkgpath = path.join(file, 'package.json');
            if (!fs.existsSync(pkgpath)) {
                return donePackage();
            }

            var pkg = require(pkgpath);

            var deps = Object.keys(pkg.dependencies||{})
                .concat(Object.keys(pkg.devDependencies||{}));

            var depsToLink = deps.filter(function(dep) {
                if (/mendel/.test(dep) && !linkedDeps[file+':'+dep]) {
                    return true;
                }
                return false;
            });
            var waitFor = depsToLink.filter(function(dep) {
                return -1 == linkedModules.indexOf(dep);
            });

            if (waitFor.length) {
                doAgain.push(file);
                return donePackage();
            } else if(depsToLink.length) {
                return async.eachSeries(depsToLink, function(dep, depDone) {
                    console.log('local link', dep, 'to', pkg.name, '...');
                    npm(['link', dep], file, function() {
                        linkedDeps[file+':'+dep] = true;
                        depDone();
                    });
                }, function() {
                    doAgain.push(file);
                    donePackage();
                });
            }

            console.log('local install', pkg.name, '...');
            npm('install', file, function() {
                if (/packages/.test(file)) {
                    console.log('local link', pkg.name, '...');
                    npm('link', file, function() {
                        linkedModules.push(pkg.name);
                        donePackage();
                    });
                } else {
                    linkedModules.push(pkg.name);
                    donePackage();
                }
            });
        }, function() {
            if (doAgain.length) {
                linkPackages(null, doAgain);
            }
        });
    });

});

function npm(cmd, dir, cb) {
    if (!Array.isArray(cmd)) cmd = [cmd];
    var npmp = spawn('npm', cmd, {cwd: dir, stdio: 'inherit'});
    npmp.on('exit', cb);
}
<commit_msg>Fix linkall script for npm 5+<commit_after>#!/usr/bin/env node
/* Copyright 2015, Yahoo Inc.
   Copyrights licensed under the MIT License.
   See the accompanying LICENSE file for terms. */

var fs = require('fs');
var path = require('path');
var spawn = require('child_process').spawn;

var packagesdir = path.join(__dirname, '../packages');
var examplesdir = path.join(__dirname, '../examples');
var rootdir = path.join(__dirname, '..');

npm(['install'], rootdir, function() {
    var async = require('async');
    var linkedModules = [];
    var linkedDeps = {};
    var installed = [];

    async.reduce([packagesdir, examplesdir], [],
    function(packages, dir, doneDir){
        fs.readdir(dir, function(err, subdirs) {
            subdirs = subdirs.map(function(subdir) {
                return path.join(dir, subdir);
            });
            doneDir(err, packages.concat(subdirs));
        });
    },
    function linkPackages(err, packages){
        var doAgain = [];

        async.eachSeries(packages, function(file, donePackage) {
            var pkgpath = path.join(file, 'package.json');
            if (!fs.existsSync(pkgpath)) {
                return donePackage();
            }

            var pkg = require(pkgpath);

            var deps = Object.keys(pkg.dependencies||{})
                .concat(Object.keys(pkg.devDependencies||{}));

            var depsToLink = deps.filter(function(dep) {
                if (/mendel/.test(dep) && !linkedDeps[file+':'+dep]) {
                    return true;
                }
                return false;
            });
            var waitFor = depsToLink.filter(function(dep) {
                return -1 == linkedModules.indexOf(dep);
            });

            if (waitFor.length) {
                doAgain.push(file);
                return donePackage();
            }

            if (installed.indexOf(file) === -1) {
                installed.push(file);
                doAgain.push(file);
                console.log('local install', pkg.name, '...');
                return npm('install', file, function() {
                    if (/packages/.test(file)) {
                        console.log('local link', pkg.name, '...');
                        npm('link', file, function() {
                            linkedModules.push(pkg.name);
                            donePackage();
                        });
                    } else {
                        linkedModules.push(pkg.name);
                        donePackage();
                    }
                });
            }

            if(depsToLink.length) {
                async.eachSeries(depsToLink, function(dep, depDone) {
                    console.log('local link', dep, 'to', pkg.name, '...');
                    npm(['link', dep], file, function() {
                        linkedDeps[file+':'+dep] = true;
                        depDone();
                    });
                }, function() {
                    doAgain.push(file);
                    donePackage();
                });
            } else {
                donePackage();
            }
        }, function() {
            if (doAgain.length) {
                linkPackages(null, doAgain);
            }
        });
    });

});

function npm(cmd, dir, cb) {
    if (!Array.isArray(cmd)) cmd = [cmd];
    var npmp = spawn('npm', cmd, {cwd: dir, stdio: 'inherit'});
    npmp.on('exit', cb);
}
<|endoftext|>


<commit_before>"use strict";

let MapDataController = function() {
  let self = {
    dataDropdownList: null,

    toggleButton: null,
    mapDataPanel: null,
    resetButton: null
  };

  function setDataDropdown(id) {
    self.dataDropdownList = d3.select(id);
  }

  function setupDataPanel(buttonID, listWrapperID) {
    self.mapDataPanel = d3.select(listWrapperID)
      .style("pointer-events", "none")
      .style("opacity", 0)
      .style("height", window.innerHeight - d3.select(".navbar").node().clientHeight + "px");

    self.toggleButton = d3.select(buttonID).classed("open", false)
      .on("click", function(d) {
        let open = !d3.select(this).classed("open");
        d3.select(this).classed("open", open);

        d3.select(this).select(".glyphicon").attr("class", open ? "glyphicon glyphicon-arrow-up" : "glyphicon glyphicon-arrow-down");

        self.mapDataPanel
          .style("pointer-events", open ? "all" : "none")
          .style("opacity", open ? 1 : 0);
      });
  }

  function attachResetOverlayButton(id) {
    self.resetButton = d3.select(id)
      .on("click", resetOverlay);
  }

  function resetOverlay() {
    App.views.map.drawChoropleth();
    console.log("Reset Overlay");
  }

  function populateDropdown(categories) {
    // populate census data dropdown
    self.mapDataPanel.select("#mapSettings").selectAll(".censusType")
      .data(Object.keys(categories))
      .enter().append("div")
      .attr("class", "panel panel-default censusType")
      .each(function(c1) {
        let panel = d3.select(this);

        // create link within tab
        panel.append("div")
          .attr("class", "panel-heading")
          .attr("data-toggle", "collapse")
          .attr("href", "#" + _.kebabCase("main_" + c1))
          .html(_.capitalize(_.startCase(c1)));

        // create tab content div for this t1 category
        let panelBody = panel.append("div")
          .attr("class", "panel-collapse collapse")
          .attr("id", _.kebabCase("main_" + c1))
          .append("div")
          .attr("class", "panel-body");

        panelBody.selectAll(".censusSubtype")
          .data(categories[c1])
          .enter().append("div")
          .attr("class", "row censusSubtype")
          .datum(function(c2) {
            return {
              mainType: c1,
              subType: c2
            };
          })
          .attr("id", d => _.kebabCase("sub_" + d.subType))
          .each(function(d) {
            let row = d3.select(this);

            row.append("span")
              .html(function(d) {
                return d.subType;
              });

            let btnGroup = row.append("div")
              .attr("class", "btn-group");

            btnGroup.append("button")
              .attr("class", "btn btn-success")
              .text("Chart")
              .on("click", chartButtonClick);

            btnGroup.append("button")
              .attr("class", "btn btn-success")
              .text("Map")
              .on("click", mapButtonClick);
          });
      });
  }

  function mapButtonClick(d) {
    // d3.event.stopPropagation(); // prevent menu close on link click

    // toggle whether or not it is selected
    console.log(d);

    let reducedData = App.models.censusData.getSubsetGeoJSON(d);
    App.views.map.drawChoropleth(reducedData);
  }

  function chartButtonClick(d) {
    console.log("Create chart for", d);
    App.views.chartList.addPropertyChart(d);
  }

  return {
    setupDataPanel,
    attachResetOverlayButton,

    populateDropdown
  }
}
<commit_msg>Button click in map data controller successfully removes chart, just needs to be connected in the other direction<commit_after>"use strict";

let MapDataController = function() {
  let self = {
    dataDropdownList: null,

    toggleButton: null,
    mapDataPanel: null,
    resetButton: null
  };

  function setDataDropdown(id) {
    self.dataDropdownList = d3.select(id);
  }

  function setupDataPanel(buttonID, listWrapperID) {
    self.mapDataPanel = d3.select(listWrapperID)
      .style("pointer-events", "none")
      .style("opacity", 0)
      .style("height", window.innerHeight - d3.select(".navbar").node().clientHeight + "px");

    self.toggleButton = d3.select(buttonID).classed("open", false)
      .on("click", function(d) {
        let open = !d3.select(this).classed("open");
        d3.select(this).classed("open", open);

        d3.select(this).select(".glyphicon").attr("class", open ? "glyphicon glyphicon-arrow-up" : "glyphicon glyphicon-arrow-down");

        self.mapDataPanel
          .style("pointer-events", open ? "all" : "none")
          .style("opacity", open ? 1 : 0);
      });
  }

  function attachResetOverlayButton(id) {
    self.resetButton = d3.select(id)
      .on("click", resetOverlay);
  }

  function resetOverlay() {
    App.views.map.drawChoropleth();
    console.log("Reset Overlay");
  }

  function populateDropdown(categories) {
    // populate census data dropdown
    self.mapDataPanel.select("#mapSettings").selectAll(".censusType")
      .data(Object.keys(categories))
      .enter().append("div")
      .attr("class", "panel panel-default censusType")
      .each(function(c1) {
        let panel = d3.select(this);

        // create link within tab
        panel.append("div")
          .attr("class", "panel-heading")
          .attr("data-toggle", "collapse")
          .attr("href", "#" + _.kebabCase("main_" + c1))
          .html(_.capitalize(_.startCase(c1)));

        // create tab content div for this t1 category
        let panelBody = panel.append("div")
          .attr("class", "panel-collapse collapse")
          .attr("id", _.kebabCase("main_" + c1))
          .append("div")
          .attr("class", "panel-body");

        panelBody.selectAll(".censusSubtype")
          .data(categories[c1])
          .enter().append("div")
          .attr("class", "row censusSubtype")
          .datum(function(c2) {
            return {
              mainType: c1,
              subType: c2
            };
          })
          .attr("id", d => _.kebabCase("sub_" + d.subType))
          .each(function(d) {
            let row = d3.select(this);

            row.append("span")
              .html(function(d) {
                return d.subType;
              });

            let btnGroup = row.append("div")
              .attr("class", "btn-group");

            btnGroup.append("button")
              .attr("class", "btn btn-success chartButton")
              .text("Chart")
              .on("click", chartButtonClick);

            btnGroup.append("button")
              .attr("class", "btn btn-success mapButton")
              .text("Map")
              .on("click", mapButtonClick);
          });
      });
  }

  function mapButtonClick(d) {
    // d3.event.stopPropagation(); // prevent menu close on link click

    // toggle whether or not it is selected
    console.log(d);

    let reducedData = App.models.censusData.getSubsetGeoJSON(d);
    App.views.map.drawChoropleth(reducedData);
  }

  function chartButtonClick(d) {
    console.log("Create chart for", d);
    // chart exists already
    if (d3.select(this).classed("btn-danger")) {
      removeChart.call(this, d);
      App.views.chartList.removePropertyChart(d);
    } else {
      addChart.call(this, d);
      App.views.chartList.addPropertyChart(d);
    }
  }

  function addChart(d) {
    d3.select(this).attr("class", "btn btn-danger chartButton");
  }

  function removeChart(d) {
    d3.select(this).attr("class", "btn btn-success chartButton");
  }

  function removeChartFromList(propertyTypes) {
    d3.selectAll("#" + _.kebabCase("main_" + propertyTypes.mainType)).selectAll("#" + _.kebabCase("sub_" + propertyTypes.subType))
    .select(".chartButton")
      .each(removeChart);
  }

  return {
    setupDataPanel,
    attachResetOverlayButton,

    populateDropdown,
    removeChartFromList
  };
}
<|endoftext|>


<commit_before>var Fibonacci = React.createClass({
  getInitialState: function() {
    return {sequence: 1, value: 0};
  },

  handleSequenceChange: function(e) {
    this.setState({sequence: e.target.value})
  },

  handleSubmit: function(e) {
    e.preventDefault();
    $.get(this.props.url + "/" + this.state.sequence, function(dataJsonString, status, jqXHR){
      var data = JSON.parse(dataJsonString);
      this.setState({value: data.fibNumber})
    }.bind(this));
  },

  render: function() {
    return (

Fibonacci

Compute some fibonacci numbers.

        <form className="form-inline" onSubmit={this.handleSubmit}>
          <input type="number" className="form-control" min="1" max="1250"
            onChange={this.handleSequenceChange}
            value={this.state.sequence} />
          <input type="submit" className="btn btn-primary" value="Ok" />
        </form>

{this.state.value}

    );
  }
});

ReactDOM.render(
  <Fibonacci url="fib" />,
  document.getElementById('react-node')
);
<commit_msg>track fib sequence history<commit_after>var App = React.createClass({
  getInitialState: function() {
    return {
      /** The current sequence number */
      sequence: 1,
      /** The current Fibonacci number */
      value: 0,
      /** The history of sequence and Fibonaccie numbers */
      history: [{x: 1, y: 0}]
    };
  },

  handleSequenceChange: function(e) {
    this.setState({sequence: e.target.value})
  },

  handleSubmit: function(e) {
    e.preventDefault();
    $.get(this.props.url + "/" + this.state.sequence, function(dataJsonString, status, jqXHR){
      var data = JSON.parse(dataJsonString);
      var newHistory = this.state.history.concat({x: data.sequenceNumber, y: data.fibNumber});
      this.setState({
          value: data.fibNumber,
          history: newHistory
        });
    }.bind(this));
  },

  render: function() {
    return (

Fibonacci

Compute some fibonacci numbers.

        <form className="form-inline" onSubmit={this.handleSubmit}>
          <input type="number" className="form-control" min="1" max="1250"
            onChange={this.handleSequenceChange}
            value={this.state.sequence} />
          <input type="submit" className="btn btn-primary" value="Ok" />
        </form>

{this.state.value}

        <Plot coordinates={this.state.history} />

    );
  }
});

var Coordinate = React.createClass({
  render: function() {
    return
({this.props.x}, {this.props.y})
;
  }
});

var Plot = React.createClass({
  /**
   * Simply render all the coordinates contained in the state as <Coordinates />
   */
  render: function() {
    var coordinateNodes = this.props.coordinates
      .sort( (c1, c2) => c1.x - c2.x )
      .map(function(coordinate) {
        return <Coordinate x={coordinate.x} y={coordinate.y} key={coordinate.x} />
    });
    return
 {coordinateNodes}

  }
});

ReactDOM.render(
  <App url="fib" />,
  document.getElementById('react-node')
);
<|endoftext|>


<commit_before>E2.plugins["triangle_modulator"] = function(core, node) {
	var self = this;

	this.desc = 'Triangle oscilator. A time value incrementing by one per second will yield a 1Hz output signal.';
	this.input_slots = [ { name: 'time', dt: core.datatypes.FLOAT, desc: 'The current time in seconds.', def: 0 } ];
	this.output_slots = [ { name: 'value', dt: core.datatypes.FLOAT, desc: 'Emits ((0.5 - |(time % 1.0) - 0.5|) - 0.25) * 4.', def: 0 } ];

	this.reset = function()
	{
		self.time = 0.0;
		self.result = 0.0;
	};

	this.update_input = function(slot, data)
	{
		self.time = data;
	};

	this.update_state = function(delta_t)
	{
		self.result = ((0.5 - Math.abs(self.time % 1.0 - 0.5)) - 0.25) * 4.0;

	};

	this.update_output = function(slot)
	{
		return self.result;
	};
};
<commit_msg>Refactored the triangle modulator to use prototype.<commit_after>E2.p = E2.plugins["triangle_modulator"] = function(core, node)
{
	this.desc = 'Triangle oscilator. A time value incrementing by one per second will yield a 1Hz output signal.';

	this.input_slots = [
		{ name: 'time', dt: core.datatypes.FLOAT, desc: 'The current time in seconds.', def: 0 }
	];

	this.output_slots = [
		{ name: 'value', dt: core.datatypes.FLOAT, desc: 'Emits ((0.5 - |(time % 1.0) - 0.5|) - 0.25) * 4.', def: 0 }
	];
};

E2.p.prototype.reset = function()
{
	this.time = 0.0;
	this.result = 0.0;
};

E2.p.prototype.update_input = function(slot, data)
{
	this.time = data;
};

E2.p.prototype.update_state = function(delta_t)
{
	this.result = ((0.5 - Math.abs(this.time % 1.0 - 0.5)) - 0.25) * 4.0;

};

E2.p.prototype.update_output = function(slot)
{
	return this.result;
};
<|endoftext|>