<commit_before>window.addEvent('domready',function(){
	SimpleTree = new Mif.Tree({
		container: $('tree_container'),
		grid: true,
		types: {
			folder:{
				openIcon: 'mif-tree-open-icon',
				closeIcon: 'mif-tree-close-icon'
			}
		},
		dfltType:'folder',
		height: 18
	})
	.load({
		url: '../assets/files/simpleTree.json'
	})
	.addEvent('load', function(){
		this.root.recursive(function(){
			this.toggle(null, false);
		});
	})
	.addEvent('select',function(node){
		$('log').adopt(new Element('li').set('html', node.name+' selected'));
	})
	.addEvent('unSelect', function(node){
		$('log').adopt(new Element('li').set('html', node.name+' unselected'));
	});
});<commit_msg>small demo fix<commit_after>window.addEvent('domready',function(){
	SimpleTree = new Mif.Tree({
		container: $('tree_container'),
		grid: true,
		types: {
			folder:{
				openIcon: 'mif-tree-open-icon',
				closeIcon: 'mif-tree-close-icon'
			}
		},
		dfltType:'folder',
		height: 18
	})
	.load({
		url: '../assets/files/simpleTree.json'
	})
	.addEvent('load', function(){
		this.root.recursive(function(){
			this.toggle();
		});
	})
	.addEvent('select',function(node){
		$('log').adopt(new Element('li').set('html', node.name+' selected'));
	})
	.addEvent('unSelect', function(node){
		$('log').adopt(new Element('li').set('html', node.name+' unselected'));
	});
});<|endoftext|>


<commit_before>'use strict';

require('../../setup');
var suite = new (require('benchmark')).Suite;
module.exports = suite;
var childproc = require('child_process');
var path = require('path');
var rewire = require('rewire');
var rpc = rewire('data/rpc');
var config = require('config');
var wait = require('wait.for');
var GameObject = require('model/GameObject');

// minimal GS configuration with one master and one worker process
var CONFIG = {net: {
	gameServers: {
		gs01: {host: '127.0.0.1', ports: [3000]},
	},
	rpc: {basePort: 7000},
}};
// dummy game object to call RPC functions on
var DUMMY_OBJ = new GameObject({
	tsid: 'LTESTOBJECT',
	add: function(a, b) { return a + b; },
});

var worker;

// called by the bench runner (i.e. only for the master process)
suite.asyncSetup = function(done) {
	// fork child process as worker/RPC server
	worker = childproc.fork(path.join(__filename));
	worker.send({cmd: 'init'});
	worker.on('message', function messageHandler() {
		// server is ready, initialize config and RPC channels for
		// ourself (master, RPC client)
		init(true, function masterReady() {
			done();
		});
	});
};

// message handler for the (worker/RPC client) child process
process.on('message', function(msg) {
	switch(msg.cmd) {
		case 'init':
			init(false);
			break;
		case 'shutdown':
			rpc.shutdown(function callback() {
				process.exit(0);
			});
			break;
	}
});

// initializes the process either as master (RPC client for the purpose of
// this benchmark) or worker (RPC server, started as a child process)
function init(isMaster, ready) {
	config.init(isMaster, CONFIG, isMaster ? {} : {gsid: 'gs01-01'});
	// mock the persistence layer (dirty as fuck, but we're only messing up
	// the rpc module for this particular process here)
	rpc.__set__('pers', {
		get: function() {
			return DUMMY_OBJ;
		},
	});
	// initialize RPC channels
	rpc.init(function callback(err) {
		if (err) throw err;
		if (isMaster) {
			// master -> start benchmark
			ready();
		}
		else {
			// worker -> signal parent process (benchmark suite) that we're ready
			process.send({type: 'ready'});
		}
	});
}

// cleanup/shutdown handler
suite.on('complete', function() {
	rpc.shutdown(function callback() {
		worker.send({cmd: 'shutdown'});
	});
});

suite.add('game object function call (w/ wait.for)', function(deferred) {
	wait.launchFiber(function rpcFiber() {
		rpc.sendObjRequest(DUMMY_OBJ, 'add', [1, 2]);
		deferred.resolve();
	});
}, {defer: true});

suite.add('game object function call (w/ callback)', function(deferred) {
	rpc.sendObjRequest(DUMMY_OBJ, 'add', [1, 2], function(err, res) {
		if (err) throw err;
		deferred.resolve();
	});
}, {defer: true});
<commit_msg>add missing config to fix rpc benchmark suite<commit_after>'use strict';

require('../../setup');
var suite = new (require('benchmark')).Suite;
module.exports = suite;
var childproc = require('child_process');
var path = require('path');
var rewire = require('rewire');
var rpc = rewire('data/rpc');
var config = require('config');
var wait = require('wait.for');
var GameObject = require('model/GameObject');

// minimal GS configuration with one master and one worker process
var CONFIG = {net: {
	gameServers: {
		gs01: {host: '127.0.0.1', ports: [3000]},
	},
	rpc: {basePort: 6000, timeout: 10000},
}};
// dummy game object to call RPC functions on
var DUMMY_OBJ = new GameObject({
	tsid: 'LTESTOBJECT',
	add: function(a, b) { return a + b; },
});

var worker;

// called by the bench runner (i.e. only for the master process)
suite.asyncSetup = function(done) {
	// fork child process as worker/RPC server
	worker = childproc.fork(path.join(__filename));
	worker.send({cmd: 'init'});
	worker.on('message', function messageHandler() {
		// server is ready, initialize config and RPC channels for
		// ourself (master, RPC client)
		init(true, function masterReady() {
			done();
		});
	});
};

// message handler for the (worker/RPC client) child process
process.on('message', function(msg) {
	switch(msg.cmd) {
		case 'init':
			init(false);
			break;
		case 'shutdown':
			rpc.shutdown(function callback() {
				process.exit(0);
			});
			break;
	}
});

// initializes the process either as master (RPC client for the purpose of
// this benchmark) or worker (RPC server, started as a child process)
function init(isMaster, ready) {
	config.init(isMaster, CONFIG, isMaster ? {} : {gsid: 'gs01-01'});
	// mock the persistence layer (dirty as fuck, but we're only messing up
	// the rpc module for this particular process here)
	rpc.__set__('pers', {
		get: function() {
			return DUMMY_OBJ;
		},
	});
	// initialize RPC channels
	rpc.init(function callback(err) {
		if (err) throw err;
		if (isMaster) {
			// master -> start benchmark
			ready();
		}
		else {
			// worker -> signal parent process (benchmark suite) that we're ready
			process.send({type: 'ready'});
		}
	});
}

// cleanup/shutdown handler
suite.on('complete', function() {
	rpc.shutdown(function callback() {
		worker.send({cmd: 'shutdown'});
	});
});

suite.add('game object function call (w/ wait.for)', function(deferred) {
	wait.launchFiber(function rpcFiber() {
		rpc.sendObjRequest(DUMMY_OBJ, 'add', [1, 2]);
		deferred.resolve();
	});
}, {defer: true});

suite.add('game object function call (w/ callback)', function(deferred) {
	rpc.sendObjRequest(DUMMY_OBJ, 'add', [1, 2], function(err, res) {
		if (err) throw err;
		deferred.resolve();
	});
}, {defer: true});
<|endoftext|>


<commit_before>NEWSBLUR.Views.StorySaveView = Backbone.View.extend({

    events: {
        "click .NB-feed-story-save" : "toggle_feed_story_save_dialog",
        "click .NB-sideoption-save-populate" : "populate_story_tags"
    },

    initialize: function() {
        this.model.story_save_view = this;
    },

    render: function() {
        return this.template({
            story: this.model,
            tags: this.existing_tags(),
            story_tags: this.unused_story_tags(),
            social_services: NEWSBLUR.assets.social_services,
            profile: NEWSBLUR.assets.user_profile
        });
    },

    existing_tags: function() {
        var tags = this.model.get('user_tags');

        if (!tags) {
            tags = this.folder_tags();
        }

        return tags || [];
    },

    template: _.template('\

\

\

\
                Add <%= Inflector.pluralize("story tag", story_tags.length, true) %>\

\

Tags
\

\
                <% _.each(tags, function(tag) { %>\

<%= tag %>
\
                <% }) %>\

\

\

\
    '),

    populate_story_tags: function() {
        var $populate = this.$('.NB-sideoption-save-populate');
        var $tag_input = this.$('.NB-sideoption-save-tag');
        var tags = this.model.get('story_tags');

        $populate.fadeOut(500);
        _.each(tags, function(tag) {
            $tag_input.tagit('createTag', tag);
        });

        this.toggle_feed_story_save_dialog({resize_open:true});
    },

    unused_story_tags: function() {
        var tags = _.reduce(this.model.get('user_tags') || [], function(m, t) {
            return _.without(m, t);
        }, this.model.get('story_tags'));
        return tags;
    },

    folder_tags: function() {
        var folder_tags = [];
        var feed_id = this.model.get('story_feed_id');
        var feed = NEWSBLUR.assets.get_feed(feed_id);
        if (feed) {
            folder_tags = feed.parent_folder_names();
        }
        return folder_tags;
    },

    all_tags: function() {
        var tags = [];
        var story_tags = this.model.get('story_tags') || [];
        var user_tags = this.model.get('user_tags') || [];
        var folder_tags = this.folder_tags();
        var all_tags = story_tags.concat(user_tags).concat(folder_tags);

        console.log(["all_tags", all_tags]);
        return all_tags;
    },

    toggle_feed_story_save_dialog: function(options) {
        options = options || {};
        var self = this;
        var feed_id = this.model.get('story_feed_id');
        var $sideoption = this.$('.NB-sideoption.NB-feed-story-save');
        var $save_wrapper = this.$('.NB-sideoption-save-wrapper');
        var $story_content = this.$('.NB-feed-story-content,.NB-story-content');
        var $tag_input = this.$('.NB-sideoption-save-tag');

        if (options.close ||
            ($sideoption.hasClass('NB-active') && !options.resize_open)) {
            // Close
            $save_wrapper.animate({
                'height': 0
            }, {
                'duration': 300,
                'easing': 'easeInOutQuint',
                'queue': false,
                'complete': _.bind(function() {
                    this.$('.NB-error').remove();
                    if (NEWSBLUR.app.story_list) {
                        NEWSBLUR.app.story_list.fetch_story_locations_in_feed_view();
                    }
                }, this)
            });
            $sideoption.removeClass('NB-active');
            if ($story_content.data('original_height')) {
                $story_content.animate({
                    'height': $story_content.data('original_height')
                }, {
                    'duration': 300,
                    'easing': 'easeInOutQuint',
                    'queue': false,
                    'complete': function() {
                        if (NEWSBLUR.app.story_list) {
                            NEWSBLUR.app.story_list.fetch_story_locations_in_feed_view();
                        }
                    }
                });
                $story_content.removeData('original_height');
            }
        } else {
            // Open/resize
            if (!options.resize_open) {
                this.$('.NB-error').remove();
            }
            $sideoption.addClass('NB-active');
            $tag_input.tagit({
                fieldName: "tags",
                availableTags: this.all_tags(),
                autocomplete: {delay: 0, minLength: 0},
                showAutocompleteOnFocus: false,
                removeConfirmation: true,
                caseSensitive: false,
                allowDuplicates: false,
                allowSpaces: true,
                readOnly: false,
                tagLimit: null,
                singleField: false,
                singleFieldDelimiter: ',',
                singleFieldNode: null,
                tabIndex: null,

                // Events
                afterTagAdded: function(event, ui) {
                    self.resize();
                },
                afterTagRemoved: function(event, ui) {
                    self.resize();
                }
            });
            $tag_input.tagit('addClassAutocomplete', 'NB-tagging-autocomplete');
            if (options.animate_scroll) {
                var $scroll_container = NEWSBLUR.reader.$s.$story_titles;
                if (_.contains(['split', 'full'], NEWSBLUR.assets.preference('story_layout'))) {
                    $scroll_container = this.model.latest_story_detail_view.$el.parent();
                }
                $scroll_container.stop().scrollTo(this.$el, {
                    duration: 600,
                    queue: false,
                    easing: 'easeInOutQuint',
                    offset: this.model.latest_story_detail_view.$el.height() -
                            $scroll_container.height()
                });
            }

            this.resize(options);
        }
    },

    resize: function(options) {
        options = options || {};
        var $sideoption_container = this.$('.NB-feed-story-sideoptions-container');
        var $save_wrapper = this.$('.NB-sideoption-save-wrapper');
        var $story_content = this.$('.NB-feed-story-content,.NB-story-content');
        var $story_wrapper = this.$('.NB-story-content-container');
        var $story_comments = this.$('.NB-feed-story-comments');
        var $tag_input = this.$('.NB-sideoption-save-tag');

        var $save_clone = $save_wrapper.clone();
        var dialog_height = $save_clone.css({
            'height': 'auto',
            'position': 'absolute',
            'visibility': 'hidden'
        }).appendTo($save_wrapper.parent()).height();
        $save_clone.remove();

        $save_wrapper.animate({
            'height': dialog_height
        }, {
            'duration': options.immediate ? 0 : 350,
            'easing': 'easeInOutQuint',
            'queue': false,
            'complete': _.bind(function() {
                if ($tag_input.length == 1) {
                    $tag_input.focus();
                }
                if (NEWSBLUR.app.story_list) {
                    NEWSBLUR.app.story_list.fetch_story_locations_in_feed_view();
                }

            }, this)
        });

        var sideoptions_height  = $sideoption_container.outerHeight(true);
        var wrapper_height      = $story_wrapper.height();
        var content_height      = $story_content.height();
        var content_outerheight = $story_content.outerHeight(true);
        var comments_height     = $story_comments.outerHeight(true);
        var container_offset    = $sideoption_container.length &&
                                  ($sideoption_container.position().top - 32);

        if (content_outerheight + comments_height < sideoptions_height) {
            $story_content.css('height', $sideoption_container.height());
            $story_content.animate({
                'height': sideoptions_height + dialog_height - comments_height
            }, {
                'duration': 350,
                'easing': 'easeInOutQuint',
                'queue': false,
                'complete': function() {
                    if (NEWSBLUR.app.story_list) {
                        NEWSBLUR.app.story_list.fetch_story_locations_in_feed_view();
                    }
                }
            }).data('original_height', content_height);
        } else if (sideoptions_height + dialog_height > wrapper_height) {
            $story_content.animate({
                'height': content_height + dialog_height - container_offset
            }, {
                'duration': 350,
                'easing': 'easeInOutQuint',
                'queue': false,
                'complete': function() {
                    if (NEWSBLUR.app.story_list) {
                        NEWSBLUR.app.story_list.fetch_story_locations_in_feed_view();
                    }
                }
            }).data('original_height', content_height);
        } else if (NEWSBLUR.app.story_list) {
            NEWSBLUR.app.story_list.fetch_story_locations_in_feed_view();
        }
    }

});<commit_msg>Logging heights.<commit_after>NEWSBLUR.Views.StorySaveView = Backbone.View.extend({

    events: {
        "click .NB-feed-story-save" : "toggle_feed_story_save_dialog",
        "click .NB-sideoption-save-populate" : "populate_story_tags"
    },

    initialize: function() {
        this.model.story_save_view = this;
    },

    render: function() {
        return this.template({
            story: this.model,
            tags: this.existing_tags(),
            story_tags: this.unused_story_tags(),
            social_services: NEWSBLUR.assets.social_services,
            profile: NEWSBLUR.assets.user_profile
        });
    },

    existing_tags: function() {
        var tags = this.model.get('user_tags');

        if (!tags) {
            tags = this.folder_tags();
        }

        return tags || [];
    },

    template: _.template('\

\

\

\
                Add <%= Inflector.pluralize("story tag", story_tags.length, true) %>\

\

Tags
\

\
                <% _.each(tags, function(tag) { %>\

<%= tag %>
\
                <% }) %>\

\

\

\
    '),

    populate_story_tags: function() {
        var $populate = this.$('.NB-sideoption-save-populate');
        var $tag_input = this.$('.NB-sideoption-save-tag');
        var tags = this.model.get('story_tags');

        $populate.fadeOut(500);
        _.each(tags, function(tag) {
            $tag_input.tagit('createTag', tag);
        });

        this.toggle_feed_story_save_dialog({resize_open:true});
    },

    unused_story_tags: function() {
        var tags = _.reduce(this.model.get('user_tags') || [], function(m, t) {
            return _.without(m, t);
        }, this.model.get('story_tags'));
        return tags;
    },

    folder_tags: function() {
        var folder_tags = [];
        var feed_id = this.model.get('story_feed_id');
        var feed = NEWSBLUR.assets.get_feed(feed_id);
        if (feed) {
            folder_tags = feed.parent_folder_names();
        }
        return folder_tags;
    },

    all_tags: function() {
        var tags = [];
        var story_tags = this.model.get('story_tags') || [];
        var user_tags = this.model.get('user_tags') || [];
        var folder_tags = this.folder_tags();
        var all_tags = story_tags.concat(user_tags).concat(folder_tags);

        console.log(["all_tags", all_tags]);
        return all_tags;
    },

    toggle_feed_story_save_dialog: function(options) {
        options = options || {};
        var self = this;
        var feed_id = this.model.get('story_feed_id');
        var $sideoption = this.$('.NB-sideoption.NB-feed-story-save');
        var $save_wrapper = this.$('.NB-sideoption-save-wrapper');
        var $story_content = this.$('.NB-feed-story-content,.NB-story-content');
        var $tag_input = this.$('.NB-sideoption-save-tag');

        if (options.close ||
            ($sideoption.hasClass('NB-active') && !options.resize_open)) {
            // Close
            $save_wrapper.animate({
                'height': 0
            }, {
                'duration': 300,
                'easing': 'easeInOutQuint',
                'queue': false,
                'complete': _.bind(function() {
                    this.$('.NB-error').remove();
                    if (NEWSBLUR.app.story_list) {
                        NEWSBLUR.app.story_list.fetch_story_locations_in_feed_view();
                    }
                }, this)
            });
            $sideoption.removeClass('NB-active');
            if ($story_content.data('original_height')) {
                $story_content.animate({
                    'height': $story_content.data('original_height')
                }, {
                    'duration': 300,
                    'easing': 'easeInOutQuint',
                    'queue': false,
                    'complete': function() {
                        if (NEWSBLUR.app.story_list) {
                            NEWSBLUR.app.story_list.fetch_story_locations_in_feed_view();
                        }
                    }
                });
                $story_content.removeData('original_height');
            }
        } else {
            // Open/resize
            if (!options.resize_open) {
                this.$('.NB-error').remove();
            }
            $sideoption.addClass('NB-active');
            $tag_input.tagit({
                fieldName: "tags",
                availableTags: this.all_tags(),
                autocomplete: {delay: 0, minLength: 0},
                showAutocompleteOnFocus: false,
                removeConfirmation: true,
                caseSensitive: false,
                allowDuplicates: false,
                allowSpaces: true,
                readOnly: false,
                tagLimit: null,
                singleField: false,
                singleFieldDelimiter: ',',
                singleFieldNode: null,
                tabIndex: null,

                // Events
                afterTagAdded: function(event, ui) {
                    self.resize();
                },
                afterTagRemoved: function(event, ui) {
                    self.resize();
                }
            });
            $tag_input.tagit('addClassAutocomplete', 'NB-tagging-autocomplete');
            if (options.animate_scroll) {
                var $scroll_container = NEWSBLUR.reader.$s.$story_titles;
                if (_.contains(['split', 'full'], NEWSBLUR.assets.preference('story_layout'))) {
                    $scroll_container = this.model.latest_story_detail_view.$el.parent();
                }
                $scroll_container.stop().scrollTo(this.$el, {
                    duration: 600,
                    queue: false,
                    easing: 'easeInOutQuint',
                    offset: this.model.latest_story_detail_view.$el.height() -
                            $scroll_container.height()
                });
            }

            this.resize(options);
        }
    },

    resize: function(options) {
        options = options || {};
        var $sideoption_container = this.$('.NB-feed-story-sideoptions-container');
        var $save_wrapper = this.$('.NB-sideoption-save-wrapper');
        var $story_content = this.$('.NB-feed-story-content,.NB-story-content');
        var $story_wrapper = this.$('.NB-story-content-container');
        var $story_comments = this.$('.NB-feed-story-comments');
        var $tag_input = this.$('.NB-sideoption-save-tag');

        var $save_clone = $save_wrapper.clone();
        var dialog_height = $save_clone.css({
            'height': 'auto',
            'position': 'absolute',
            'visibility': 'hidden'
        }).appendTo($save_wrapper.parent()).height();
        $save_clone.remove();

        $save_wrapper.animate({
            'height': dialog_height
        }, {
            'duration': options.immediate ? 0 : 350,
            'easing': 'easeInOutQuint',
            'queue': false,
            'complete': _.bind(function() {
                if ($tag_input.length == 1) {
                    $tag_input.focus();
                }
                if (NEWSBLUR.app.story_list) {
                    NEWSBLUR.app.story_list.fetch_story_locations_in_feed_view();
                }

            }, this)
        });

        var sideoptions_height  = $sideoption_container.outerHeight(true);
        var wrapper_height      = $story_wrapper.height();
        var content_height      = $story_content.height();
        var content_outerheight = $story_content.outerHeight(true);
        var comments_height     = $story_comments.outerHeight(true);
        var left_height         = content_outerheight + comments_height;
        var container_offset    = $sideoption_container.length &&
                                  ($sideoption_container.position().top - 32);

        console.log(["heights", dialog_height, sideoptions_height, wrapper_height, content_height, content_outerheight, comments_height, left_height, container_offset]);
        if (left_height < sideoptions_height) {
            $story_content.css('height', $sideoption_container.height());
            $story_content.animate({
                'height': sideoptions_height + dialog_height - comments_height
            }, {
                'duration': 350,
                'easing': 'easeInOutQuint',
                'queue': false,
                'complete': function() {
                    if (NEWSBLUR.app.story_list) {
                        NEWSBLUR.app.story_list.fetch_story_locations_in_feed_view();
                    }
                }
            }).data('original_height', content_height);
        } else if (sideoptions_height + dialog_height > wrapper_height) {
            $story_content.animate({
                'height': content_height + dialog_height - container_offset
            }, {
                'duration': 350,
                'easing': 'easeInOutQuint',
                'queue': false,
                'complete': function() {
                    if (NEWSBLUR.app.story_list) {
                        NEWSBLUR.app.story_list.fetch_story_locations_in_feed_view();
                    }
                }
            }).data('original_height', content_height);
        } else if (NEWSBLUR.app.story_list) {
            NEWSBLUR.app.story_list.fetch_story_locations_in_feed_view();
        }
    }

});<|endoftext|>


<commit_before>/* Copyright (C) 2017 Canonical Ltd. */
'use strict';

const React = require('react');

const ProfileHeader = require('./header');
const SvgIcon = require('../../svg-icon/svg-icon');

const jsTestUtils = require('../../../utils/component-test-utils');

describe('Profile Header', function() {
  let getUser;

  beforeEach(() => {
    getUser = sinon.stub().callsArgWith(1, null, {
      email: 'spinach@example.com',
      fullname: 'Geoffrey Spinach',
      gravatar_id: 'id123'
    });
  });

  it('can render', () => {
    const renderer = jsTestUtils.shallowRender(
      <ProfileHeader
        changeState={sinon.stub()}
        controllerIP={'1.2.3.4'}
        getUser={getUser}
        gisf={true}
        userInfo={{
          isCurrent: true,
          profile: 'spinach'
        }} />, true);
    const instance = renderer.getMountedInstance();
    // Triggering a componentWillMount before grabbing the rendered output so
    // that the getUser call will have returned and rendered the gravatar UI.
    // The following test tests the 'not yet returned' state.
    instance.componentWillMount();
    const output = renderer.getRenderOutput();
    const expected = (

            <SvgIcon
              name="close_16"
              size="20" />

                spinach

Geoffrey Spinach

spinach@example.com

                jaas

Home

About JAAS

    );
    expect(output).toEqualJSX(expected);
  });

  it('does not show controller info for other users', () => {
    const renderer = jsTestUtils.shallowRender(
      <ProfileHeader
        changeState={sinon.stub()}
        controllerIP={'1.2.3.4'}
        getUser={getUser}
        gisf={true}
        userInfo={{
          isCurrent: false,
          profile: 'notspinach'
        }} />, true);
    const instance = renderer.getMountedInstance();
    instance.componentWillMount();
    const output = renderer.getRenderOutput();
    const expected = (

            <SvgIcon
              name="close_16"
              size="20" />

                notspinach

Geoffrey Spinach

spinach@example.com

    );
    expect(output).toEqualJSX(expected);
  });

  it('displays a different link list for non-jaas', () => {
    const renderer = jsTestUtils.shallowRender(
      <ProfileHeader
        changeState={sinon.stub()}
        controllerIP={'1.2.3.4'}
        getUser={getUser}
        gisf={false}
        userInfo={{
          isCurrent: true,
          profile: 'spinach'
        }} />, true);
    const instance = renderer.getMountedInstance();
    // Triggering a componentWillMount before grabbing the rendered output so
    // that the getUser call will have returned and rendered the gravatar UI.
    // The following test tests the 'not yet returned' state.
    instance.componentWillMount();
    const output = renderer.getRenderOutput();
    const expected = (

            <SvgIcon
              name="close_16"
              size="20" />

                spinach

Geoffrey Spinach

spinach@example.com

                1.2.3.4

Juju Home

    );
    expect(output).toEqualJSX(expected);
  });

  it('displays a hidden gravatar until the user request has returned', () => {
    // For the test where it has returned successfully see the above tests.
    const output = jsTestUtils.shallowRender(
      <ProfileHeader
        changeState={sinon.stub()}
        getUser={() => {}}
        userInfo={{
          isCurrent: true,
          profile: 'spinach'
        }} />);
    assert.equal(
      output.props.children.props.children[1].props.className,
      'profile-header__avatar profile-header__avatar--default profile-header__avatar--hidden');
  });

  it('displays the fallback gravatar if the user request fails', () => {
    const renderer = jsTestUtils.shallowRender(
      <ProfileHeader
        changeState={sinon.stub()}
        getUser={(u, c) => c(null, null)}
        userInfo={{
          isCurrent: true,
          profile: 'spinach'
        }} />, true);
    renderer.getMountedInstance().componentWillMount();
    const output = renderer.getRenderOutput();
    const expected = (

      );
    expect(output.props.children.props.children[1]).toEqualJSX(expected);
  });

  it('can close the profile', () => {
    const changeState = sinon.stub();
    const output = jsTestUtils.shallowRender(
      <ProfileHeader
        changeState={changeState}
        getUser={getUser}
        userInfo={{
          isCurrent: true,
          profile: 'spinach'
        }} />);
    output.props.children.props.children[0].props.onClick();
    assert.equal(changeState.callCount, 1);
    assert.deepEqual(changeState.args[0][0], {
      hash: null,
      profile: null
    });
  });
});
<commit_msg>Add tests for the profile header tooltips.<commit_after>/* Copyright (C) 2017 Canonical Ltd. */
'use strict';

const React = require('react');

const ProfileHeader = require('./header');
const SvgIcon = require('../../svg-icon/svg-icon');

const jsTestUtils = require('../../../utils/component-test-utils');

describe('Profile Header', function() {
  let getUser;

  beforeEach(() => {
    getUser = sinon.stub().callsArgWith(1, null, {
      email: 'spinach@example.com',
      fullname: 'Geoffrey Spinach',
      gravatar_id: 'id123'
    });
  });

  it('can render', () => {
    const renderer = jsTestUtils.shallowRender(
      <ProfileHeader
        changeState={sinon.stub()}
        controllerIP={'1.2.3.4'}
        getUser={getUser}
        gisf={true}
        userInfo={{
          isCurrent: true,
          profile: 'spinach'
        }} />, true);
    const instance = renderer.getMountedInstance();
    // Triggering a componentWillMount before grabbing the rendered output so
    // that the getUser call will have returned and rendered the gravatar UI.
    // The following test tests the 'not yet returned' state.
    instance.componentWillMount();
    const output = renderer.getRenderOutput();
    const expected = (

            <SvgIcon
              name="close_16"
              size="20" />

                Edit your Gravatar

                spinach

                  Your Ubuntu One account details

Geoffrey Spinach

spinach@example.com

                jaas

Home

About JAAS

    );
    expect(output).toEqualJSX(expected);
  });

  it('can render correctly for the non-logged in user', () => {
    const renderer = jsTestUtils.shallowRender(
      <ProfileHeader
        changeState={sinon.stub()}
        controllerIP={'1.2.3.4'}
        getUser={getUser}
        gisf={true}
        userInfo={{
          isCurrent: false,
          profile: 'notspinach'
        }} />, true);
    const instance = renderer.getMountedInstance();
    instance.componentWillMount();
    const output = renderer.getRenderOutput();
    const expected = (

            <SvgIcon
              name="close_16"
              size="20" />

                notspinach

Geoffrey Spinach

spinach@example.com

    );
    expect(output).toEqualJSX(expected);
  });

  it('displays a different link list for non-jaas', () => {
    const renderer = jsTestUtils.shallowRender(
      <ProfileHeader
        changeState={sinon.stub()}
        controllerIP={'1.2.3.4'}
        getUser={getUser}
        gisf={false}
        userInfo={{
          isCurrent: true,
          profile: 'spinach'
        }} />, true);
    const instance = renderer.getMountedInstance();
    // Triggering a componentWillMount before grabbing the rendered output so
    // that the getUser call will have returned and rendered the gravatar UI.
    // The following test tests the 'not yet returned' state.
    instance.componentWillMount();
    const output = renderer.getRenderOutput();
    const expected = (

            1.2.3.4

Juju Home

    );
    expect(output.props.children.props.children[3]).toEqualJSX(expected);
  });

  it('displays a hidden gravatar until the user request has returned', () => {
    // For the test where it has returned successfully see the above tests.
    const output = jsTestUtils.shallowRender(
      <ProfileHeader
        changeState={sinon.stub()}
        getUser={() => {}}
        userInfo={{
          isCurrent: true,
          profile: 'spinach'
        }} />);
    assert.equal(
      output.props.children.props.children[1].props.className,
      'profile-header__avatar tooltip profile-header__avatar--default ' +
      'profile-header__avatar--hidden');
  });

  it('displays the fallback gravatar if the user request fails', () => {
    const renderer = jsTestUtils.shallowRender(
      <ProfileHeader
        changeState={sinon.stub()}
        getUser={(u, c) => c(null, null)}
        userInfo={{
          isCurrent: true,
          profile: 'spinach'
        }} />, true);
    renderer.getMountedInstance().componentWillMount();
    const output = renderer.getRenderOutput();
    const expected = (

            Edit your Gravatar

      );
    expect(output.props.children.props.children[1]).toEqualJSX(expected);
  });

  it('can close the profile', () => {
    const changeState = sinon.stub();
    const output = jsTestUtils.shallowRender(
      <ProfileHeader
        changeState={changeState}
        getUser={getUser}
        userInfo={{
          isCurrent: true,
          profile: 'spinach'
        }} />);
    output.props.children.props.children[0].props.onClick();
    assert.equal(changeState.callCount, 1);
    assert.deepEqual(changeState.args[0][0], {
      hash: null,
      profile: null
    });
  });
});
<|endoftext|>


<commit_before>// Amara, universalsubtitles.org
//
// Copyright (C) 2012 Participatory Culture Foundation
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see
// http://www.gnu.org/licenses/agpl-3.0.html.

goog.provide('unisubs.subtitle.SubtitleWidget');

/**
 * @constructor
 * @extends goog.ui.Component
 *
 * @param {unisubs.subtitle.EditableCaption} subtitle
 * @param {unisubs.subtitle.EditableCaptionSet} subtitleSet
 *
 *
 */
unisubs.subtitle.SubtitleWidget = function(subtitle,
                                           subtitleSet,
                                           editingFn,
                                           displayTimes,
                                           readOnly,
                                           displayParagraphMarker) {
    goog.ui.Component.call(this);
    this.subtitle_ = subtitle;
    this.subtitleSet_ = subtitleSet;
    this.editingFn_ = editingFn;
    this.displayTimes_ = displayTimes;
    this.keyHandler_ = null;
    this.timeSpinner_ = null;
    this.readOnly_ = readOnly;
    this.displayParagraphMarker_ = displayParagraphMarker;
    this.insertDeleteButtonsShowing_ = false;
};
goog.inherits(unisubs.subtitle.SubtitleWidget, goog.ui.Component);

unisubs.subtitle.SubtitleWidget.prototype.getContentElement = function() {
    return this.contentElement_;
};
unisubs.subtitle.SubtitleWidget.prototype.createDom = function() {
    var $d = goog.bind(this.getDomHelper().createDom, this.getDomHelper());
    if (!this.readOnly_) {
        this.deleteButton_ = this.createDeleteButton_($d);
        this.insertButton_ = this.createInsertButton_($d);
        this.paragraphMarkerButton_ = this.createParagraphMarkerButton_($d);
        this.updateParagraphMarkerButton_();
        goog.style.showElement(this.deleteButton_, false);
        goog.style.showElement(this.insertButton_, false);
        goog.style.showElement(this.paragraphMarkerButton_, false);
        this.contentElement_ = $d('span', 'unisubs-timestamp');

        this.setElementInternal(
            $d('li', null,
            this.contentElement_,
            this.titleElem_ =
            $d('span', {'className':'unisubs-title' + (this.subtitleSet_.languageIsRTL ? ' is-rtl' : '')},
                this.titleElemInner_ =
                $d('span')),
            this.deleteButton_,
            this.insertButton_,
            this.paragraphMarkerButton_
        ));

    } else {
        this.setElementInternal(
            $d('li', null,
            this.contentElement_,
            this.titleElem_ =
            $d('span', {'className':'unisubs-title'},
                this.titleElemInner_ =
                $d('span'))));
        this.contentElement_ = $d('span', 'unisubs-timestamp');
    }
    if (!this.displayTimes_) {
        goog.dom.classes.add(this.titleElem_, 'unisubs-title-notime');
        unisubs.style.showElement(this.contentElement_, false);
        var startTime = this.subtitleSet_.x.startTime(this.subtitle_.node);
        if (parseFloat(startTime) > -1) {
            var timeElement = $d('span', {'className': 'unisubs-timestamp-time-fixed'},
                                unisubs.formatTime(startTime));
            this.titleElem_.appendChild(timeElement);
        }
    }
    else {
        this.timeSpinner_ = new unisubs.Spinner(
            this.subtitle_.getStartTime(),
            goog.bind(this.subtitle_.getMinStartTime, this.subtitle_),
            goog.bind(this.subtitle_.getMaxStartTime, this.subtitle_),
            unisubs.formatTime);
        this.addChild(this.timeSpinner_, true);
    }
    this.textareaElem_ = null;
    this.keyHandler_ = null;
    this.docClickListener_ = null;
    this.updateValues_();
    this.showingTextarea_ = false;
    this.editing_ = false;
};
unisubs.subtitle.SubtitleWidget.prototype.createDeleteButton_ = function($d) {
    return $d('div', 'unisubs-sub-delete', ' ');
};
unisubs.subtitle.SubtitleWidget.prototype.createParagraphMarkerButton_ = function($d) {
    return $d('div', 'unisubs-sub-paragraph', ' ');

};
unisubs.subtitle.SubtitleWidget.prototype.createInsertButton_ = function($d) {
    return $d('div', 'unisubs-sub-insert', ' ');
};
unisubs.subtitle.SubtitleWidget.prototype.enterDocument = function() {
    unisubs.subtitle.SubtitleWidget.superClass_.enterDocument.call(this);
    var et = goog.events.EventType;

    if (!this.readOnly_) {
        this.getHandler().listen(this.deleteButton_, et.CLICK, this.deleteClicked_)
                         .listen(this.insertButton_, et.CLICK, this.insertClicked_)
                         .listen(this.paragraphMarkerButton_, et.CLICK, this.paragraphMarkerClicked_)
                         .listen(this.titleElem_, et.CLICK, this.clicked_)
                         .listen(this.getElement(),
                                [et.MOUSEOVER, et.MOUSEOUT],
                                this.mouseOverOut_)
                         .listen(this.subtitle_,
                                 unisubs.subtitle.EditableCaption.CHANGE,
                                 this.updateValues_);
    }

    if (this.timeSpinner_)
        this.getHandler().listen(
            this.timeSpinner_,
            goog.object.getValues(unisubs.Spinner.EventType),
            this.timeSpinnerListener_);
};
unisubs.subtitle.SubtitleWidget.prototype.setActive = function(active) {
    goog.dom.classes.enable(this.getElement(), 'active', active);
};
unisubs.subtitle.SubtitleWidget.prototype.deleteClicked_ = function(e) {
    this.subtitleSet_.deleteCaption(this.subtitle_);
};

unisubs.subtitle.SubtitleWidget.prototype.updateParagraphMarkerButton_ = function() {
    if (this.subtitleSet_.x.startOfParagraph(this.subtitle_)){
        goog.dom.classes.add(this.paragraphMarkerButton_, "selected")
    }else{

        goog.dom.classes.remove(this.paragraphMarkerButton_, "selected")
    }

}
unisubs.subtitle.SubtitleWidget.prototype.paragraphMarkerClicked_ = function(e) {
    e.stopPropagation();
    this.subtitle_.toggleStartOfParagraph();
    this.updateParagraphMarkerButton_();
};

unisubs.subtitle.SubtitleWidget.prototype.insertClicked_ = function(e) {
    e.stopPropagation();
    this.showInsertDeleteButtons_(false);
    this.subtitleSet_.insertCaption(this.subtitle_.getSubOrder());
};
unisubs.subtitle.SubtitleWidget.prototype.timeSpinnerListener_ =
    function(event)
{
    var et = unisubs.Spinner.EventType;
    if (event.type == et.ARROW_PRESSED)
        this.setEditing_(true, true);
    else if (event.type == et.VALUE_CHANGED) {
        this.subtitle_.setStartTime(event.value);
        this.setEditing_(false, true);
    }
};
unisubs.subtitle.SubtitleWidget.prototype.setEditing_ = function(editing, timeChanged) {
    this.editingFn_(editing, timeChanged, this);
    this.editing_ = editing;
    if (!editing)
        this.updateValues_();
};
/**
 *
 * @return {mirosub.subtitle.EditableCaption} The subtitle for this widget.
 */
unisubs.subtitle.SubtitleWidget.prototype.getSubtitle = function() {
    return this.subtitle_;
};
unisubs.subtitle.SubtitleWidget.prototype.mouseOverOut_ = function(e) {
    if (e.type == goog.events.EventType.MOUSEOVER &&
        !unisubs.subtitle.SubtitleWidget.editing_)
        this.showInsertDeleteButtons_(true);
    else if (e.type == goog.events.EventType.MOUSEOUT)
        this.showInsertDeleteButtons_(false);
};
unisubs.subtitle.SubtitleWidget.prototype.showInsertDeleteButtons_ =
    function(show)
{
    if (show == this.insertDeleteButtonsShowing_)
        return;
    this.insertDeleteButtonsShowing_ = show;

    if (!this.readOnly_) {
        goog.style.showElement(this.deleteButton_, show);
        goog.style.showElement(this.insertButton_, show);
        goog.style.showElement(this.paragraphMarkerButton_, show);
    }
};
unisubs.subtitle.SubtitleWidget.prototype.clicked_ = function(event) {
    if (this.showingTextarea_)
        return;
    if (unisubs.subtitle.SubtitleWidget.editing_) {
        unisubs.subtitle.SubtitleWidget.editing_.switchToView_();
        return;
    }
    this.switchToEditMode();
    event.stopPropagation();
    event.preventDefault();
};
unisubs.subtitle.SubtitleWidget.prototype.switchToEditMode = function() {
    this.showInsertDeleteButtons_(false);
    unisubs.subtitle.SubtitleWidget.editing_ = this;
    this.setEditing_(true, false);
    this.showingTextarea_ = true;
    this.docClickListener_ = new goog.events.EventHandler();
    var that = this;
    this.docClickListener_.listen(
        document, goog.events.EventType.CLICK,
        function(event) {
            if (event.target != that.textareaElem_) {
                that.switchToView_();
            }
        });
    goog.dom.removeNode(this.titleElemInner_);
    this.textareaElem_ = this.getDomHelper().createDom(
        'textarea', 'unisubs-subedit');
    goog.dom.append(this.titleElem_, this.textareaElem_);
    this.textareaElem_.value = this.subtitle_.getText();
    this.textareaElem_.focus();
    this.keyHandler_ = new goog.events.KeyHandler(this.textareaElem_);
    this.getHandler().listen(this.keyHandler_,
                             goog.events.KeyHandler.EventType.KEY,
                             this.handleKey_, false, this);

};
unisubs.subtitle.SubtitleWidget.prototype.handleKey_ = function(event) {
    if (event.keyCode == goog.events.KeyCodes.ENTER && !event.shiftKey) {
        this.switchToView_();
        event.stopPropagation();
        event.preventDefault();
    }
};
unisubs.subtitle.SubtitleWidget.prototype.switchToView_ = function() {
    if (!this.showingTextarea_)
        return;
    unisubs.subtitle.SubtitleWidget.editing_ = null;
    this.getHandler().unlisten(this.keyHandler_);
    this.disposeEventHandlers_();
    this.subtitle_.setText(this.textareaElem_.value);
    goog.dom.removeNode(this.textareaElem_);
    this.titleElem_.appendChild(this.titleElemInner_);
    this.showingTextarea_ = false;
    this.setEditing_(false, false);
};
unisubs.subtitle.SubtitleWidget.prototype.clearTimes = function() {
    unisubs.style.setVisibility(this.contentElement_, false);
};
unisubs.subtitle.SubtitleWidget.prototype.updateValues_ = function() {
    if (this.editing_)
        return;
    if (this.displayTimes_) {
        var time = this.subtitleSet_.x.startTime(this.subtitle_.node);
        this.contentElement_.style.visibility =
            time == -1 ? 'hidden' : 'visible';
        if (time != -1)
            this.timeSpinner_.setValue(time);
    }
    // FIXME: Sanitize / wrap to the right elements (<em>... etc)
    this.titleElemInner_.innerHTML  = goog.string.newLineToBr(this.subtitleSet_.x.content(this.subtitle_.node));

};
unisubs.subtitle.SubtitleWidget.prototype.disposeEventHandlers_ = function() {
    if (this.keyHandler_) {
        this.keyHandler_.dispose();
        this.keyHandler_ = null;
    }
    if (this.docClickListener_) {
        this.docClickListener_.dispose();
        this.docClickListener_ = null;
    }
};
unisubs.subtitle.SubtitleWidget.prototype.disposeInternal = function() {
    unisubs.subtitle.SubtitleWidget.superClass_.disposeInternal.call(this);
    this.disposeEventHandlers_();
};
<commit_msg>Fixed start of paragraph call<commit_after>// Amara, universalsubtitles.org
//
// Copyright (C) 2012 Participatory Culture Foundation
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see
// http://www.gnu.org/licenses/agpl-3.0.html.

goog.provide('unisubs.subtitle.SubtitleWidget');

/**
 * @constructor
 * @extends goog.ui.Component
 *
 * @param {unisubs.subtitle.EditableCaption} subtitle
 * @param {unisubs.subtitle.EditableCaptionSet} subtitleSet
 *
 *
 */
unisubs.subtitle.SubtitleWidget = function(subtitle,
                                           subtitleSet,
                                           editingFn,
                                           displayTimes,
                                           readOnly,
                                           displayParagraphMarker) {
    goog.ui.Component.call(this);
    this.subtitle_ = subtitle;
    this.subtitleSet_ = subtitleSet;
    this.editingFn_ = editingFn;
    this.displayTimes_ = displayTimes;
    this.keyHandler_ = null;
    this.timeSpinner_ = null;
    this.readOnly_ = readOnly;
    this.displayParagraphMarker_ = displayParagraphMarker;
    this.insertDeleteButtonsShowing_ = false;
};
goog.inherits(unisubs.subtitle.SubtitleWidget, goog.ui.Component);

unisubs.subtitle.SubtitleWidget.prototype.getContentElement = function() {
    return this.contentElement_;
};
unisubs.subtitle.SubtitleWidget.prototype.createDom = function() {
    var $d = goog.bind(this.getDomHelper().createDom, this.getDomHelper());
    if (!this.readOnly_) {
        this.deleteButton_ = this.createDeleteButton_($d);
        this.insertButton_ = this.createInsertButton_($d);
        this.paragraphMarkerButton_ = this.createParagraphMarkerButton_($d);
        this.updateParagraphMarkerButton_();
        goog.style.showElement(this.deleteButton_, false);
        goog.style.showElement(this.insertButton_, false);
        goog.style.showElement(this.paragraphMarkerButton_, false);
        this.contentElement_ = $d('span', 'unisubs-timestamp');

        this.setElementInternal(
            $d('li', null,
            this.contentElement_,
            this.titleElem_ =
            $d('span', {'className':'unisubs-title' + (this.subtitleSet_.languageIsRTL ? ' is-rtl' : '')},
                this.titleElemInner_ =
                $d('span')),
            this.deleteButton_,
            this.insertButton_,
            this.paragraphMarkerButton_
        ));

    } else {
        this.setElementInternal(
            $d('li', null,
            this.contentElement_,
            this.titleElem_ =
            $d('span', {'className':'unisubs-title'},
                this.titleElemInner_ =
                $d('span'))));
        this.contentElement_ = $d('span', 'unisubs-timestamp');
    }
    if (!this.displayTimes_) {
        goog.dom.classes.add(this.titleElem_, 'unisubs-title-notime');
        unisubs.style.showElement(this.contentElement_, false);
        var startTime = this.subtitleSet_.x.startTime(this.subtitle_.node);
        if (parseFloat(startTime) > -1) {
            var timeElement = $d('span', {'className': 'unisubs-timestamp-time-fixed'},
                                unisubs.formatTime(startTime));
            this.titleElem_.appendChild(timeElement);
        }
    }
    else {
        this.timeSpinner_ = new unisubs.Spinner(
            this.subtitle_.getStartTime(),
            goog.bind(this.subtitle_.getMinStartTime, this.subtitle_),
            goog.bind(this.subtitle_.getMaxStartTime, this.subtitle_),
            unisubs.formatTime);
        this.addChild(this.timeSpinner_, true);
    }
    this.textareaElem_ = null;
    this.keyHandler_ = null;
    this.docClickListener_ = null;
    this.updateValues_();
    this.showingTextarea_ = false;
    this.editing_ = false;
};
unisubs.subtitle.SubtitleWidget.prototype.createDeleteButton_ = function($d) {
    return $d('div', 'unisubs-sub-delete', ' ');
};
unisubs.subtitle.SubtitleWidget.prototype.createParagraphMarkerButton_ = function($d) {
    return $d('div', 'unisubs-sub-paragraph', ' ');

};
unisubs.subtitle.SubtitleWidget.prototype.createInsertButton_ = function($d) {
    return $d('div', 'unisubs-sub-insert', ' ');
};
unisubs.subtitle.SubtitleWidget.prototype.enterDocument = function() {
    unisubs.subtitle.SubtitleWidget.superClass_.enterDocument.call(this);
    var et = goog.events.EventType;

    if (!this.readOnly_) {
        this.getHandler().listen(this.deleteButton_, et.CLICK, this.deleteClicked_)
                         .listen(this.insertButton_, et.CLICK, this.insertClicked_)
                         .listen(this.paragraphMarkerButton_, et.CLICK, this.paragraphMarkerClicked_)
                         .listen(this.titleElem_, et.CLICK, this.clicked_)
                         .listen(this.getElement(),
                                [et.MOUSEOVER, et.MOUSEOUT],
                                this.mouseOverOut_)
                         .listen(this.subtitle_,
                                 unisubs.subtitle.EditableCaption.CHANGE,
                                 this.updateValues_);
    }

    if (this.timeSpinner_)
        this.getHandler().listen(
            this.timeSpinner_,
            goog.object.getValues(unisubs.Spinner.EventType),
            this.timeSpinnerListener_);
};
unisubs.subtitle.SubtitleWidget.prototype.setActive = function(active) {
    goog.dom.classes.enable(this.getElement(), 'active', active);
};
unisubs.subtitle.SubtitleWidget.prototype.deleteClicked_ = function(e) {
    this.subtitleSet_.deleteCaption(this.subtitle_);
};

unisubs.subtitle.SubtitleWidget.prototype.updateParagraphMarkerButton_ = function() {
    if (this.subtitleSet_.x.startOfParagraph(this.subtitle_.node)){
        goog.dom.classes.add(this.paragraphMarkerButton_, "selected")
    }else{

        goog.dom.classes.remove(this.paragraphMarkerButton_, "selected")
    }

}
unisubs.subtitle.SubtitleWidget.prototype.paragraphMarkerClicked_ = function(e) {
    e.stopPropagation();
    this.subtitle_.toggleStartOfParagraph();
    this.updateParagraphMarkerButton_();
};

unisubs.subtitle.SubtitleWidget.prototype.insertClicked_ = function(e) {
    e.stopPropagation();
    this.showInsertDeleteButtons_(false);
    this.subtitleSet_.insertCaption(this.subtitle_.getSubOrder());
};
unisubs.subtitle.SubtitleWidget.prototype.timeSpinnerListener_ =
    function(event)
{
    var et = unisubs.Spinner.EventType;
    if (event.type == et.ARROW_PRESSED)
        this.setEditing_(true, true);
    else if (event.type == et.VALUE_CHANGED) {
        this.subtitle_.setStartTime(event.value);
        this.setEditing_(false, true);
    }
};
unisubs.subtitle.SubtitleWidget.prototype.setEditing_ = function(editing, timeChanged) {
    this.editingFn_(editing, timeChanged, this);
    this.editing_ = editing;
    if (!editing)
        this.updateValues_();
};
/**
 *
 * @return {mirosub.subtitle.EditableCaption} The subtitle for this widget.
 */
unisubs.subtitle.SubtitleWidget.prototype.getSubtitle = function() {
    return this.subtitle_;
};
unisubs.subtitle.SubtitleWidget.prototype.mouseOverOut_ = function(e) {
    if (e.type == goog.events.EventType.MOUSEOVER &&
        !unisubs.subtitle.SubtitleWidget.editing_)
        this.showInsertDeleteButtons_(true);
    else if (e.type == goog.events.EventType.MOUSEOUT)
        this.showInsertDeleteButtons_(false);
};
unisubs.subtitle.SubtitleWidget.prototype.showInsertDeleteButtons_ =
    function(show)
{
    if (show == this.insertDeleteButtonsShowing_)
        return;
    this.insertDeleteButtonsShowing_ = show;

    if (!this.readOnly_) {
        goog.style.showElement(this.deleteButton_, show);
        goog.style.showElement(this.insertButton_, show);
        goog.style.showElement(this.paragraphMarkerButton_, show);
    }
};
unisubs.subtitle.SubtitleWidget.prototype.clicked_ = function(event) {
    if (this.showingTextarea_)
        return;
    if (unisubs.subtitle.SubtitleWidget.editing_) {
        unisubs.subtitle.SubtitleWidget.editing_.switchToView_();
        return;
    }
    this.switchToEditMode();
    event.stopPropagation();
    event.preventDefault();
};
unisubs.subtitle.SubtitleWidget.prototype.switchToEditMode = function() {
    this.showInsertDeleteButtons_(false);
    unisubs.subtitle.SubtitleWidget.editing_ = this;
    this.setEditing_(true, false);
    this.showingTextarea_ = true;
    this.docClickListener_ = new goog.events.EventHandler();
    var that = this;
    this.docClickListener_.listen(
        document, goog.events.EventType.CLICK,
        function(event) {
            if (event.target != that.textareaElem_) {
                that.switchToView_();
            }
        });
    goog.dom.removeNode(this.titleElemInner_);
    this.textareaElem_ = this.getDomHelper().createDom(
        'textarea', 'unisubs-subedit');
    goog.dom.append(this.titleElem_, this.textareaElem_);
    this.textareaElem_.value = this.subtitle_.getText();
    this.textareaElem_.focus();
    this.keyHandler_ = new goog.events.KeyHandler(this.textareaElem_);
    this.getHandler().listen(this.keyHandler_,
                             goog.events.KeyHandler.EventType.KEY,
                             this.handleKey_, false, this);

};
unisubs.subtitle.SubtitleWidget.prototype.handleKey_ = function(event) {
    if (event.keyCode == goog.events.KeyCodes.ENTER && !event.shiftKey) {
        this.switchToView_();
        event.stopPropagation();
        event.preventDefault();
    }
};
unisubs.subtitle.SubtitleWidget.prototype.switchToView_ = function() {
    if (!this.showingTextarea_)
        return;
    unisubs.subtitle.SubtitleWidget.editing_ = null;
    this.getHandler().unlisten(this.keyHandler_);
    this.disposeEventHandlers_();
    this.subtitle_.setText(this.textareaElem_.value);
    goog.dom.removeNode(this.textareaElem_);
    this.titleElem_.appendChild(this.titleElemInner_);
    this.showingTextarea_ = false;
    this.setEditing_(false, false);
};
unisubs.subtitle.SubtitleWidget.prototype.clearTimes = function() {
    unisubs.style.setVisibility(this.contentElement_, false);
};
unisubs.subtitle.SubtitleWidget.prototype.updateValues_ = function() {
    if (this.editing_)
        return;
    if (this.displayTimes_) {
        var time = this.subtitleSet_.x.startTime(this.subtitle_.node);
        this.contentElement_.style.visibility =
            time == -1 ? 'hidden' : 'visible';
        if (time != -1)
            this.timeSpinner_.setValue(time);
    }
    // FIXME: Sanitize / wrap to the right elements (<em>... etc)
    this.titleElemInner_.innerHTML  = goog.string.newLineToBr(this.subtitleSet_.x.content(this.subtitle_.node));

};
unisubs.subtitle.SubtitleWidget.prototype.disposeEventHandlers_ = function() {
    if (this.keyHandler_) {
        this.keyHandler_.dispose();
        this.keyHandler_ = null;
    }
    if (this.docClickListener_) {
        this.docClickListener_.dispose();
        this.docClickListener_ = null;
    }
};
unisubs.subtitle.SubtitleWidget.prototype.disposeInternal = function() {
    unisubs.subtitle.SubtitleWidget.superClass_.disposeInternal.call(this);
    this.disposeEventHandlers_();
};
<|endoftext|>


<commit_before>exports = module.exports = {};
/* Function(s) for comparing user's courses with degree requirements
 *
 */

/* Compares a user's taken courses with a degree's requirements and returns an
 * object containing lists of classes towards the degree and classes still
 * needed.
 *
 * @param courses An array containing all of courses a user has taken.
 * @param audit An object containing all the requirements of a degree.
 * @return An object containing a list of courses that meet degree requirements
 * and a list of requirements not known to have been met.
 */
exports.compareCoursesToAudit = function(courses, audit)
{
	let ret = {completed: {}, uncompleted: {}};

	for (let key in audit) {
		if (key === 'credits_min') {
			continue;
		}
		ret.completed[key] = [];
		ret.uncompleted[key] = {};
		for (let prop in audit[key]) {
			// Switch on type of info in requirement
			// eg. select_from, CS_XXXX, etc.
			let result = {};
			switch(true) {
			case /select_from.*/.test(prop):
				// TODO
				break;
			case /OR[0-9]+/.test(prop):
				result = checkOr(courses, audit[key][prop]);
				if( result.completed === true){
					ret.completed[key] = ret.completed[key].concat(result.completedItems);
				}else{
					ret.uncompleted[key][prop] = audit[key][prop];
				}
				break;
			case /AND[0-9]+/.test(prop):
				result = checkAnd(courses, audit[key][prop]);
				if( result.completed === true){
					ret.completed[key] = ret.completed[key].concat(result.completedItems);
				}else{
					ret.uncompleted[key][prop] = audit[key][prop];
				}
				break;
			case /[A-Z][A-Z]+_[0-9]{4}/.test(prop):
				if (checkExactCourse(courses, prop)) {
					ret.completed[key][prop] = audit[key][prop];
				} else {
					ret.uncompleted[key][prop] = audit[key][prop];
				}
				break;
			case /credits_min|min_credits/.test(prop):
				// TODO
				break;
			case /HASS/.test(prop):
				// TODO
				break;
			default:
				// TODO Something must have gone wrong
			}
		}
	}
	return ret;
};

function checkExactCourse(courses, course)
{
	//
	for (let courseI in courses) {
		if (courseI === course) {
			return true;
		}
	}
	return false;
};

//Returns ret, which has an attribute completed, which is true if
//the req is fufilled; completedItems is an array that contains the courses
//that fufilled it.
function checkOr(courses, or_obj){
	let ret = {
		completed:false,
		completedItems:[]
	};

	for(let or_course in or_obj){
		//Check if it's a nested AND or OR
		let result;
		switch(true){
		case /AND[0-9]+/.test(or_course):
			result = checkAnd(courses, or_obj[or_course]);
			if(result.completed === true){
				ret.completed = true;
				ret.completedItems = result.completedItems;
				return ret;
			}
			break;
		case (/OR[0-9]+/.test(or_course)):
			result = checkOr(courses, or_obj[or_course]);
			if(result.completed === true){
				ret.completed = true;
				ret.completedItems = result.completedItems;
				return ret;
			}
			break;
		default:
			for(let i = 0;i<courses.length;i++){
				if(courses[i].slugName === or_course){
					ret.completed = true;
					ret.completedItems = courses[i];
					return ret;
				}
			}
		}
	}
	return ret;
}
//Returns ret, which has an attribute completed, which is true if
//the req is fufilled; completedItems is an array that contains the courses
//that fufilled it.
function checkAnd(courses, and_obj){
	let ret = {
		completed:true,
		completedItems:[]
	};
	for(let and_course in and_obj){
		let result;
		//Check if it's a nested AND or OR
		switch(true){
		case /AND[0-9]+/.test(and_course):
			result = checkAnd(courses, and_obj[and_course]);
			if(!result.completed){
				ret.completed = false;
			}
			//merge the two arrays
			Array.prototype.push.apply(ret.completedItems, result.completedItems);
			break;
		case /OR[0-9]+/.test(and_course):
			result = checkOr(courses, and_obj[and_course]);
			if(!result){
				ret.completed = false;
			}
			//merge arrays
			Array.prototype.push.apply(ret.completedItems, result.completedItems);
			break;
		default:
			result = courses.find(function(element){
				return element.slugName === and_course;
			});
			if(result !== undefined){
				ret.completedItems.push(result);
			}else{
				ret.completed = false;
			}
		}
	}
	return ret;
}
<commit_msg>Changed auditLogic uncompleted to object; fixed match exact class<commit_after>exports = module.exports = {};
/* Function(s) for comparing user's courses with degree requirements
 *
 */

/* Compares a user's taken courses with a degree's requirements and returns an
 * object containing lists of classes towards the degree and classes still
 * needed.
 *
 * @param courses An array containing all of courses a user has taken.
 * @param audit An object containing all the requirements of a degree.
 * @return An object containing a list of courses that meet degree requirements
 * and a list of requirements not known to have been met.
 */
exports.compareCoursesToAudit = function(courses, audit)
{
	let ret = {completed: {}, uncompleted: {}};

	for (let key in audit) {
		if (key === 'credits_min') {
			continue;
		}
		ret.completed[key] = {};
		ret.uncompleted[key] = {};
		for (let prop in audit[key]) {
			// Switch on type of info in requirement
			// eg. select_from, CS_XXXX, etc.
			let result = {};
			switch(true) {
			case /select_from.*/.test(prop):
				// TODO
				break;
			case /OR[0-9]+/.test(prop):
				result = checkOr(courses, audit[key][prop]);
				if( result.completed === true){
					ret.completed[key][prop] = result.completedItems;
				}else{
					ret.uncompleted[key][prop] = audit[key][prop];
				}
				break;
			case /AND[0-9]+/.test(prop):
				result = checkAnd(courses, audit[key][prop]);
				if( result.completed === true){
					ret.completed[key][prop] = result.completedItems;
				}else{
					ret.uncompleted[key][prop] = audit[key][prop];
				}
				break;
			case /[A-Z][A-Z]+_[0-9]{4}/.test(prop):
				if (checkExactCourse(courses, prop)) {
					ret.completed[key][prop] = audit[key][prop];
				} else {
					ret.uncompleted[key][prop] = audit[key][prop];
				}
				break;
			case /credits_min|min_credits/.test(prop):
				// TODO
				break;
			case /HASS/.test(prop):
				// TODO
				break;
			default:
				// TODO Something must have gone wrong
			}
		}
	}
	return ret;
};

function checkExactCourse(courses, course)
{
	for (let courseI in courses) {
		if (courses[courseI].slugName === course) {
			return true;
		}
	}
	return false;
};

//Returns ret, which has an attribute completed, which is true if
//the req is fufilled; completedItems is an array that contains the courses
//that fufilled it.
function checkOr(courses, or_obj){
	let ret = {
		completed:false,
		completedItems:[]
	};

	for(let or_course in or_obj){
		//Check if it's a nested AND or OR
		let result;
		switch(true){
		case /AND[0-9]+/.test(or_course):
			result = checkAnd(courses, or_obj[or_course]);
			if(result.completed === true){
				ret.completed = true;
				ret.completedItems = result.completedItems;
				return ret;
			}
			break;
		case (/OR[0-9]+/.test(or_course)):
			result = checkOr(courses, or_obj[or_course]);
			if(result.completed === true){
				ret.completed = true;
				ret.completedItems = result.completedItems;
				return ret;
			}
			break;
		default:
			for(let i = 0;i<courses.length;i++){
				if(courses[i].slugName === or_course){
					ret.completed = true;
					ret.completedItems = courses[i];
					return ret;
				}
			}
		}
	}
	return ret;
}
//Returns ret, which has an attribute completed, which is true if
//the req is fufilled; completedItems is an array that contains the courses
//that fufilled it.
function checkAnd(courses, and_obj){
	let ret = {
		completed:true,
		completedItems:[]
	};
	for(let and_course in and_obj){
		let result;
		//Check if it's a nested AND or OR
		switch(true){
		case /AND[0-9]+/.test(and_course):
			result = checkAnd(courses, and_obj[and_course]);
			if(!result.completed){
				ret.completed = false;
			}
			//merge the two arrays
			Array.prototype.push.apply(ret.completedItems, result.completedItems);
			break;
		case /OR[0-9]+/.test(and_course):
			result = checkOr(courses, and_obj[and_course]);
			if(!result){
				ret.completed = false;
			}
			//merge arrays
			Array.prototype.push.apply(ret.completedItems, result.completedItems);
			break;
		default:
			result = courses.find(function(element){
				return element.slugName === and_course;
			});
			if(result !== undefined){
				ret.completedItems.push(result);
			}else{
				ret.completed = false;
			}
		}
	}
	return ret;
}
<|endoftext|>


<commit_before>var cdb = require('cartodb.js');
var createTextLabelsTabPane = require('../../components/tab-pane/create-text-labels-tab-pane');
var TabPaneTemplate = require('./layer-tab-pane.tpl');
var Header = require('./layer-header-view.js');
var AnalysesView = require('./layer-content-views/analyses-view');
var StyleView = require('../style/style-view');
var InfowindowsView = require('./layer-content-views/infowindows-view');
var ScrollView = require('../../components/scroll/scroll-view');

module.exports = cdb.core.View.extend({
  events: {
    'click .js-back': '_onClickBack'
  },

  initialize: function (opts) {
    if (!opts.layerDefinitionsCollection) throw new Error('layerDefinitionsCollection is required');
    if (!opts.layerDefinitionModel) throw new Error('layerDefinitionModel is required');
    if (!opts.stackLayoutModel) throw new Error('StackLayoutModel is required');
    if (!opts.modals) throw new Error('modals is required');
    if (!opts.configModel) throw new Error('configModel is required');
    if (!opts.editorModel) throw new Error('editorModel is required');
    if (!opts.analysis) throw new Error('analysis is required');

    this.layerDefinitionModel = opts.layerDefinitionModel;
    this.layerDefinitionsCollection = opts.layerDefinitionsCollection;
    this.stackLayoutModel = opts.stackLayoutModel;
    this.modals = opts.modals;
    this._configModel = opts.configModel;
    this._editorModel = opts.editorModel;
    this.analysis = opts.analysis;

    this._editorModel.on('change:edition', this._changeStyle, this);
    this.add_related_model(this._editorModel);
  },

  render: function () {
    this._unbindEvents();

    var self = this;
    var tabPaneTabs = [{
      label: _t('editor.layers.menu-tab-pane-labels.data'),
      name: 'data',
      selected: !this.options.selectedNode,
      createContentView: function () {
        return new cdb.core.View();
      }
    }, {
      label: _t('editor.layers.menu-tab-pane-labels.analyses'),
      name: 'analyses',
      selected: !!this.options.selectedNode,
      createContentView: function () {
        return new ScrollView({
          createContentView: function () {
            return new AnalysesView({
              className: 'Editor-content',
              layerDefinitionModel: self.layerDefinitionModel,
              modals: self.modals,
              analysis: self.analysis,
              selectedNode: self.options.selectedNode
            });
          }
        });
      }
    }, {
      label: _t('editor.layers.menu-tab-pane-labels.style'),
      name: 'style',
      createContentView: function () {
        var lastLayerNodeModel = self.layerDefinitionModel.getAnalysisDefinitionNodeModel();
        return new StyleView({
          className: 'Editor-content',
          analysisDefinitionsCollection: self.analysisDefinitionsCollection,
          querySchemaModel: lastLayerNodeModel.querySchemaModel,
          layerDefinitionsCollection: self.layerDefinitionsCollection,
          layerDefinitionModel: self.layerDefinitionModel,
          editorModel: self._editorModel,
          modals: self.modals
        });
      }
    }, {
      label: _t('editor.layers.menu-tab-pane-labels.infowindow'),
      name: 'infowindow',
      createContentView: function () {
        return new InfowindowsView({
          className: 'Editor-content',
          layerDefinitionModel: self.layerDefinitionModel,
          querySchemaModel: self.layerDefinitionModel.getAnalysisDefinitionNodeModel().querySchemaModel,
          configModel: self._configModel,
          editorModel: self._editorModel
        });
      }
    }, {
      label: _t('editor.layers.menu-tab-pane-labels.legends'),
      name: 'legends',
      createContentView: function () {
        return new cdb.core.View({
          className: 'Editor-content'
        });
      }
    }];

    var header = new Header({
      layerDefinitionModel: this.layerDefinitionModel,
      editorModel: this._editorModel
    });

    this.addView(header);
    this.$el.append(header.render().$el);

    var tabPaneOptions = {
      tabPaneOptions: {
        template: TabPaneTemplate,
        tabPaneItemOptions: {
          tagName: 'li',
          className: 'CDB-NavMenu-item'
        }
      },
      tabPaneItemLabelOptions: {
        tagName: 'button',
        className: 'CDB-NavMenu-link u-upperCase'
      }
    };

    this._layerTabPaneView = createTextLabelsTabPane(tabPaneTabs, tabPaneOptions);
    this._bindEvents();
    this.$el.append(this._layerTabPaneView.render().$el);
    this.addView(this._layerTabPaneView);
    return this;
  },

  _unbindEvents: function () {
    if (this._layerTabPaneView && this._layerTabPaneView.collection) {
      this._layerTabPaneView.collection.off('change:selected', this._quitEditing, this);
    }
  },

  _bindEvents: function () {
    this._layerTabPaneView.collection.on('change:selected', this._quitEditing, this);
    this.add_related_model(this._layerTabPaneView.collection);
  },

  _onClickBack: function () {
    this._quitEditing();
    this.stackLayoutModel.prevStep('layers');
  },

  _changeStyle: function () {
    this.$el.toggleClass('is-dark', this._editorModel.isEditing());
    this._layerTabPaneView.changeStyleMenu(this._editorModel);
  },

  _quitEditing: function () {
    if (this._layerTabPaneView.getSelectedTabPaneName() !== 'style') {
      this._editorModel.set({ edition: false });
    }
  }
});
<commit_msg>Fixed problem when get outs from layer-content-view<commit_after>var cdb = require('cartodb.js');
var createTextLabelsTabPane = require('../../components/tab-pane/create-text-labels-tab-pane');
var TabPaneTemplate = require('./layer-tab-pane.tpl');
var Header = require('./layer-header-view.js');
var AnalysesView = require('./layer-content-views/analyses-view');
var StyleView = require('../style/style-view');
var InfowindowsView = require('./layer-content-views/infowindows-view');
var ScrollView = require('../../components/scroll/scroll-view');

module.exports = cdb.core.View.extend({
  events: {
    'click .js-back': '_onClickBack'
  },

  initialize: function (opts) {
    if (!opts.layerDefinitionsCollection) throw new Error('layerDefinitionsCollection is required');
    if (!opts.layerDefinitionModel) throw new Error('layerDefinitionModel is required');
    if (!opts.stackLayoutModel) throw new Error('StackLayoutModel is required');
    if (!opts.modals) throw new Error('modals is required');
    if (!opts.configModel) throw new Error('configModel is required');
    if (!opts.editorModel) throw new Error('editorModel is required');
    if (!opts.analysis) throw new Error('analysis is required');

    this.layerDefinitionModel = opts.layerDefinitionModel;
    this.layerDefinitionsCollection = opts.layerDefinitionsCollection;
    this.stackLayoutModel = opts.stackLayoutModel;
    this.modals = opts.modals;
    this._configModel = opts.configModel;
    this._editorModel = opts.editorModel;
    this.analysis = opts.analysis;

    this._editorModel.on('change:edition', this._changeStyle, this);
    this.add_related_model(this._editorModel);
  },

  render: function () {
    this._unbindEvents();

    var self = this;
    var tabPaneTabs = [{
      label: _t('editor.layers.menu-tab-pane-labels.data'),
      name: 'data',
      selected: !this.options.selectedNode,
      createContentView: function () {
        return new cdb.core.View();
      }
    }, {
      label: _t('editor.layers.menu-tab-pane-labels.analyses'),
      name: 'analyses',
      selected: !!this.options.selectedNode,
      createContentView: function () {
        return new ScrollView({
          createContentView: function () {
            return new AnalysesView({
              className: 'Editor-content',
              layerDefinitionModel: self.layerDefinitionModel,
              modals: self.modals,
              analysis: self.analysis,
              selectedNode: self.options.selectedNode
            });
          }
        });
      }
    }, {
      label: _t('editor.layers.menu-tab-pane-labels.style'),
      name: 'style',
      createContentView: function () {
        var lastLayerNodeModel = self.layerDefinitionModel.getAnalysisDefinitionNodeModel();
        return new StyleView({
          className: 'Editor-content',
          analysisDefinitionsCollection: self.analysisDefinitionsCollection,
          querySchemaModel: lastLayerNodeModel.querySchemaModel,
          layerDefinitionsCollection: self.layerDefinitionsCollection,
          layerDefinitionModel: self.layerDefinitionModel,
          editorModel: self._editorModel,
          modals: self.modals
        });
      }
    }, {
      label: _t('editor.layers.menu-tab-pane-labels.infowindow'),
      name: 'infowindow',
      createContentView: function () {
        return new InfowindowsView({
          className: 'Editor-content',
          layerDefinitionModel: self.layerDefinitionModel,
          querySchemaModel: self.layerDefinitionModel.getAnalysisDefinitionNodeModel().querySchemaModel,
          configModel: self._configModel,
          editorModel: self._editorModel
        });
      }
    }, {
      label: _t('editor.layers.menu-tab-pane-labels.legends'),
      name: 'legends',
      createContentView: function () {
        return new cdb.core.View({
          className: 'Editor-content'
        });
      }
    }];

    var header = new Header({
      layerDefinitionModel: this.layerDefinitionModel,
      editorModel: this._editorModel
    });

    this.addView(header);
    this.$el.append(header.render().$el);

    var tabPaneOptions = {
      tabPaneOptions: {
        template: TabPaneTemplate,
        tabPaneItemOptions: {
          tagName: 'li',
          className: 'CDB-NavMenu-item'
        }
      },
      tabPaneItemLabelOptions: {
        tagName: 'button',
        className: 'CDB-NavMenu-link u-upperCase'
      }
    };

    this._layerTabPaneView = createTextLabelsTabPane(tabPaneTabs, tabPaneOptions);
    this._bindEvents();
    this.$el.append(this._layerTabPaneView.render().$el);
    this.addView(this._layerTabPaneView);
    return this;
  },

  _unbindEvents: function () {
    if (this._layerTabPaneView && this._layerTabPaneView.collection) {
      this._layerTabPaneView.collection.off('change:selected', this._quitEditing, this);
    }
  },

  _bindEvents: function () {
    this._layerTabPaneView.collection.on('change:selected', this._quitEditing, this);
    this.add_related_model(this._layerTabPaneView.collection);
  },

  _onClickBack: function () {
    this._editorModel.set({ edition: false });
    this.stackLayoutModel.prevStep('layers');
  },

  _changeStyle: function () {
    this.$el.toggleClass('is-dark', this._editorModel.isEditing());
    this._layerTabPaneView.changeStyleMenu(this._editorModel);
  },

  _quitEditing: function () {
    if (this._layerTabPaneView.getSelectedTabPaneName() !== 'style') {
      this._editorModel.set({ edition: false });
    }
  }
});
<|endoftext|>


<commit_before>var Backbone = require('backbone');
var QuerySchemaModel = require('../../../../javascripts/cartodb3/data/query-schema-model');
var QueryColumnModel = require('../../../../javascripts/cartodb3/data/query-column-model');
var QueryColumnsCollection = require('../../../../javascripts/cartodb3/data/query-columns-collection');

describe('data/query-columns-collection', function () {
  beforeEach(function () {
    this.configModel = new Backbone.Model();

    this.querySchemaModel = new QuerySchemaModel({}, {
      configModel: this.configModel
    });

    spyOn(QueryColumnsCollection.prototype, 'fetch');
    this.collection = new QueryColumnsCollection([], {
      querySchemaModel: this.querySchemaModel,
      configModel: this.configModel
    });
  });

  describe('url', function () {
    beforeEach(function () {
      this.configModel.set({
        base_url: ''
      });
      this.configModel.urlVersion = function () { return 'v1'; };
    });

    it('should not provide a valid url if tableName is not defined', function () {
      this.collection._tableName = '';
      expect(this.collection.url()).toBeFalsy();
      this.collection._tableName = 'comeon';
      expect(this.collection.url()).toBe('/api/v1/tables/comeon/columns');
    });
  });

  describe('binds', function () {
    it('should fetch query schema model when new column is added', function () {
      this.querySchemaModel.set('status', 'fetched');
      spyOn(this.querySchemaModel, 'fetch');
      this.collection.add(new Backbone.Model());
      expect(this.querySchemaModel.get('status')).toBe('unfetched');
      expect(this.querySchemaModel.fetch).toHaveBeenCalled();
    });

    it('should take query-schema when status changes to fetched', function () {
      spyOn(this.collection, 'reset').and.callThrough();
      this.querySchemaModel.columnsCollection.reset([
        {
          type: 'number',
          name: 'cartodb_id'
        }, {
          type: 'number',
          name: 'a_number'
        }, {
          type: 'string',
          name: 'texttt'
        }
      ]);

      this.querySchemaModel.set('status', 'fetched');
      expect(this.collection.reset).toHaveBeenCalled();
      expect(this.collection.size()).toBe(3);
    });
  });

  describe('addColumn', function () {
    it('should wait and parse a new column', function () {
      var options = {};
      QueryColumnModel.prototype.save = function (attrs, opts) {
        options = opts;
      };
      this.collection.addColumn();
      expect(options.wait).toBeTruthy();
      expect(options.parse).toBeTruthy();
    });
  });
});
<commit_msg>Added query columns specs<commit_after>var Backbone = require('backbone');
var QuerySchemaModel = require('../../../../javascripts/cartodb3/data/query-schema-model');
var QueryColumnModel = require('../../../../javascripts/cartodb3/data/query-column-model');
var QueryColumnsCollection = require('../../../../javascripts/cartodb3/data/query-columns-collection');

describe('data/query-columns-collection', function () {
  beforeEach(function () {
    this.configModel = new Backbone.Model();

    this.querySchemaModel = new QuerySchemaModel({}, {
      configModel: this.configModel
    });

    spyOn(QueryColumnsCollection.prototype, 'fetch');
    this.collection = new QueryColumnsCollection([], {
      querySchemaModel: this.querySchemaModel,
      configModel: this.configModel
    });
  });

  describe('url', function () {
    beforeEach(function () {
      this.configModel.set({
        base_url: ''
      });
      this.configModel.urlVersion = function () { return 'v1'; };
    });

    it('should not provide a valid url if tableName is not defined', function () {
      this.collection._tableName = '';
      expect(this.collection.url()).toBeFalsy();
      this.collection._tableName = 'comeon';
      expect(this.collection.url()).toBe('/api/v1/tables/comeon/columns');
    });
  });

  describe('binds', function () {
    it('should fetch query schema model when new column is added', function () {
      this.querySchemaModel.set('status', 'fetched');
      spyOn(this.querySchemaModel, 'fetch');
      this.collection.add(new Backbone.Model());
      expect(this.querySchemaModel.get('status')).toBe('unfetched');
      expect(this.querySchemaModel.fetch).toHaveBeenCalled();
    });

    it('should take query-schema when status changes to fetched', function () {
      spyOn(this.collection, 'reset').and.callThrough();
      this.querySchemaModel.columnsCollection.reset([
        {
          type: 'number',
          name: 'cartodb_id'
        }, {
          type: 'number',
          name: 'a_number'
        }, {
          type: 'string',
          name: 'texttt'
        }
      ]);

      this.querySchemaModel.set('status', 'fetched');
      expect(this.collection.reset).toHaveBeenCalled();
      expect(this.collection.size()).toBe(3);
    });
  });

  describe('addColumn', function () {
    it('should wait and not parse the new column', function () {
      var options = {};
      var attributes;
      QueryColumnModel.prototype.save = function (attrs, opts) {
        attributes = this.attributes;
        options = opts;
      };
      this.collection.addColumn();
      expect(attributes.isNew).toBeTruthy();
      expect(attributes.type).toBe('string');
      expect(attributes.name).toContain('column_');
      expect(options.wait).toBeTruthy();
      expect(options.parse).toBeFalsy();
    });
  });
});
<|endoftext|>


<commit_before>'use strict'

const EE = require('events').EventEmitter
const nes = require('nes')
const Histogram = require('native-hdr-histogram')
const histUtil = require('hdr-histogram-percentiles-obj')
const steed = require('steed')
const get = require('lodash.get')
const Client = nes.Client

function anger (opts) {
  if (opts.senders > opts.connections) {
    throw Error('Senders *are* connections, must be <= connections')
  }
  const tracker = new EE()
  const clients = new Array(opts.connections)
  const senders = new Array(opts.senders)
  const latencies = new Histogram(1, 10000, 5)
  const identifier = opts.identifier || 'id'
  const tail = opts.tail || false
  const expectedResponses = typeof opts.responses === 'number'
    ? opts.responses
    : opts.connections * opts.requests
  const map = new Map()
  const uidOf = typeof identifier === 'function'
    ? identifier
    : (payload) => get(payload, identifier)
  let auth = _noop
  if (opts.auth) auth = typeof opts.auth === 'function' ? opts.auth : function () { return opts.auth }

  for (let i = 0; i < clients.length; i++) {
    clients[i] = new Client(opts.url)
    clients[i]._angerIndex = i
    clients[i].sender = false
    if (i < opts.senders) {
      senders[i] = clients[i]
      clients[i].sender = true
    }
  }

  steed.each(clients, (client, done) => {
    client.connect({ auth: auth(client, client._angerIndex) }, done)
  }, (err) => {
    if (err) {
      tracker.emit('error', err)
      return
    }

    tracker.emit('connect')

    steed.each(clients, (client, done) => {
      client.subscribe(opts.subscription, handler, done)
    }, (err) => {
      if (err) {
        tracker.emit('error', err)
        return
      }

      tracker.emit('subscribe')
    })
  })

  tracker.on('subscribe', next)

  var totalResponses = 0
  var totalRequests = 0

  function handler (payload) {
    const mapObj = map.get(uidOf(payload))
    totalResponses++

    const startTime = mapObj.start
    const end = process.hrtime(startTime)
    const responseTime = end[0] * 1e3 + end[1] / 1e6
    latencies.record(responseTime)

    if (!--mapObj.expectedResponses) {
      tracker.emit('publish-events-recieved', uidOf(payload))

      if (!tail && totalResponses === expectedResponses) {
        complete()
      }

      return next(mapObj.sender)
    }
  }

  function next (sender) {
    if (totalRequests === opts.requests) return

    // begin emitting the requests if none have been emitted
    if (!totalRequests) {
      for (let i = 0; i < senders.length; i++) {
        triggerSender(senders[i])
      }
    }

    // if sender is passed in, trigger it
    if (sender) triggerSender(sender)
  }

  function triggerSender (sender) {
    const uid = opts.trigger(sender)
    if (++totalRequests === opts.requests && tail) setTimeout(complete, tail)
    map.set(uid, { start: process.hrtime(), sender: sender, expectedResponses: clients.length, id: uid })

    // emit trigger every time a client sends a message
    tracker.emit('trigger', uid)
  }

  function complete () {
    clients.forEach(disconnect)
    tracker.emit('end', {
      latency: histUtil.addPercentiles(latencies, histUtil.histAsObj(latencies)),
      requests: totalRequests,
      responses: totalResponses,
      connections: clients.length,
      senders: opts.senders
    })
  }

  function disconnect (client) {
    client.disconnect()
  }

  return tracker
}

function _noop () {}

module.exports = anger
<commit_msg>added getAuth function; put id and sender details into anger property<commit_after>'use strict'

const EE = require('events').EventEmitter
const nes = require('nes')
const Histogram = require('native-hdr-histogram')
const histUtil = require('hdr-histogram-percentiles-obj')
const steed = require('steed')
const get = require('lodash.get')
const Client = nes.Client

function anger (opts) {
  if (opts.senders > opts.connections) {
    throw Error('Senders *are* connections, must be <= connections')
  }
  const tracker = new EE()
  const clients = new Array(opts.connections)
  const senders = new Array(opts.senders)
  const latencies = new Histogram(1, 10000, 5)
  const identifier = opts.identifier || 'id'
  const tail = opts.tail || false
  const expectedResponses = typeof opts.responses === 'number'
    ? opts.responses
    : opts.connections * opts.requests
  const map = new Map()
  const uidOf = typeof identifier === 'function'
    ? identifier
    : (payload) => get(payload, identifier)
  const auth = getAuth(opts.auth)

  for (let i = 0; i < clients.length; i++) {
    clients[i] = new Client(opts.url)
    clients[i].anger = {
      id: i,
      sender: false
    }
    if (i < opts.senders) {
      senders[i] = clients[i]
      clients[i].anger.sender = true
    }
  }

  steed.each(clients, (client, done) => {
    client.connect({ auth: auth(client, client.anger.id) }, done)
  }, (err) => {
    if (err) {
      tracker.emit('error', err)
      return
    }

    tracker.emit('connect')

    steed.each(clients, (client, done) => {
      client.subscribe(opts.subscription, handler, done)
    }, (err) => {
      if (err) {
        tracker.emit('error', err)
        return
      }

      tracker.emit('subscribe')
    })
  })

  tracker.on('subscribe', next)

  var totalResponses = 0
  var totalRequests = 0

  function handler (payload) {
    const mapObj = map.get(uidOf(payload))
    totalResponses++

    const startTime = mapObj.start
    const end = process.hrtime(startTime)
    const responseTime = end[0] * 1e3 + end[1] / 1e6
    latencies.record(responseTime)

    if (!--mapObj.expectedResponses) {
      tracker.emit('publish-events-recieved', uidOf(payload))

      if (!tail && totalResponses === expectedResponses) {
        complete()
      }

      return next(mapObj.sender)
    }
  }

  function next (sender) {
    if (totalRequests === opts.requests) return

    // begin emitting the requests if none have been emitted
    if (!totalRequests) {
      for (let i = 0; i < senders.length; i++) {
        triggerSender(senders[i])
      }
    }

    // if sender is passed in, trigger it
    if (sender) triggerSender(sender)
  }

  function triggerSender (sender) {
    const uid = opts.trigger(sender)
    if (++totalRequests === opts.requests && tail) setTimeout(complete, tail)
    map.set(uid, { start: process.hrtime(), sender: sender, expectedResponses: clients.length, id: uid })

    // emit trigger every time a client sends a message
    tracker.emit('trigger', uid)
  }

  function complete () {
    clients.forEach(disconnect)
    tracker.emit('end', {
      latency: histUtil.addPercentiles(latencies, histUtil.histAsObj(latencies)),
      requests: totalRequests,
      responses: totalResponses,
      connections: clients.length,
      senders: opts.senders
    })
  }

  function disconnect (client) {
    client.disconnect()
  }

  return tracker
}

function _noop () {}

function getAuth (auth) {
  let ret = _noop
  if (auth) {
    if (typeof auth === 'function') {
      ret = auth
    } else {
      ret = function () { return auth }
    }
  }
  return ret
}

module.exports = anger
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

pref("extensions.set-default-columns@clear-code.com.columns", "threadCol,attachmentCol,flaggedCol,subjectCol,unreadButtonColHeader,senderCol,recipientCol,junkStatusCol,dateCol,locationCol");

<commit_msg>Set corresponder visible by default<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

pref("extensions.set-default-columns@clear-code.com.columns", "threadCol,attachmentCol,flaggedCol,subjectCol,unreadButtonColHeader,correspondentCol,junkStatusCol,dateCol,locationCol");

<|endoftext|>


<commit_before>import React from 'react';

import Analyzer from 'Parser/Core/Analyzer';
import Tab from 'Main/Tab';
import { formatPercentage, formatNumber } from 'common/format';
import StatisticBox, { STATISTIC_ORDER } from 'Main/StatisticBox';
import ResourceBreakdown from 'Parser/Core/Modules/ResourceTracker/ResourceBreakdown';
import FuryTracker from './FuryTracker';

import WastedFuryIcon from '../../images/dh_wasted_fury.jpg';

const furyIcon = 'inv_helm_leather_raiddemonhuntermythic_r_01';

class FuryDetails extends Analyzer {
  static dependencies = {
    furyTracker: FuryTracker,
  };

  get wastedFuryPercent() {
    return this.furyTracker.wasted / (this.furyTracker.wasted + this.furyTracker.generated);
  }

  get suggestionThresholds() {
    return {
      actual: this.wastedFuryPercent,
      isGreaterThan: {
        minor: 0.02,
        average: 0.05,
        major: 0.08,
      },
      style: 'percentage',
    };
  }

  suggestions(when) {
    when(this.suggestionThresholds).addSuggestion((suggest, actual, recommended) => {
      return suggest(`You wasted ${formatNumber(this.furyTracker.wasted)} Fury.`)
        .icon(furyIcon)
        .actual(`${formatPercentage(actual)}% Fury wasted`)
        .recommended(`Wasting less than ${formatPercentage(recommended)}% is recommended.`);
    });
  }

  statistic() {
    return (
      <StatisticBox
        icon={(
          <img
            src={WastedFuryIcon}
            alt="Wasted Fury"
          />
        )}
        value={formatNumber(this.furyTracker.wasted)}
        label="Fury Wasted"
        tooltip={`${formatPercentage(this.wastedFuryPercent)}% wasted`}
      />
    );
  }

  tab() {
    return {
      title: 'Fury Usage',
      url: 'fury-usage',
      render: () => (
        <Tab title="Fury usage breakdown">
          <ResourceBreakdown
            tracker={this.furyTracker}
            showSpenders={true}
          />
        </Tab>
      ),
    };
  }
  statisticOrder = STATISTIC_ORDER.CORE(4);
}

export default FuryDetails;
<commit_msg>increase fury suggestion tolerance<commit_after>import React from 'react';

import Analyzer from 'Parser/Core/Analyzer';
import Tab from 'Main/Tab';
import { formatPercentage, formatNumber } from 'common/format';
import StatisticBox, { STATISTIC_ORDER } from 'Main/StatisticBox';
import ResourceBreakdown from 'Parser/Core/Modules/ResourceTracker/ResourceBreakdown';
import FuryTracker from './FuryTracker';

import WastedFuryIcon from '../../images/dh_wasted_fury.jpg';

const furyIcon = 'inv_helm_leather_raiddemonhuntermythic_r_01';

class FuryDetails extends Analyzer {
  static dependencies = {
    furyTracker: FuryTracker,
  };

  get wastedFuryPercent() {
    return this.furyTracker.wasted / (this.furyTracker.wasted + this.furyTracker.generated);
  }

  get suggestionThresholds() {
    return {
      actual: this.wastedFuryPercent,
      isGreaterThan: {
        minor: 0.06,
        average: 0.10,
        major: 0.14,
      },
      style: 'percentage',
    };
  }

  suggestions(when) {
    when(this.suggestionThresholds).addSuggestion((suggest, actual, recommended) => {
      return suggest(`You wasted ${formatNumber(this.furyTracker.wasted)} Fury.`)
        .icon(furyIcon)
        .actual(`${formatPercentage(actual)}% Fury wasted`)
        .recommended(`<${formatPercentage(recommended)}% is recommended.`);
    });
  }

  statistic() {
    return (
      <StatisticBox
        icon={(
          <img
            src={WastedFuryIcon}
            alt="Wasted Fury"
          />
        )}
        value={formatNumber(this.furyTracker.wasted)}
        label="Fury Wasted"
        tooltip={`${formatPercentage(this.wastedFuryPercent)}% wasted`}
      />
    );
  }

  tab() {
    return {
      title: 'Fury Usage',
      url: 'fury-usage',
      render: () => (
        <Tab title="Fury usage breakdown">
          <ResourceBreakdown
            tracker={this.furyTracker}
            showSpenders={true}
          />
        </Tab>
      ),
    };
  }
  statisticOrder = STATISTIC_ORDER.CORE(4);
}

export default FuryDetails;
<|endoftext|>


<commit_before>const debugIt = require('debug')

module.exports = (opts = {}) => {
  const verbose = opts.verbose
  const namespace = opts.namespace || 'get-it'
  const defaultLogger = debugIt(namespace)
  const log = opts.log || defaultLogger
  const shortCircuit = log === defaultLogger && !debugIt.enabled(namespace)
  let requestId = 0

  return {
    processOptions: options => {
      options.requestId = options.requestId || ++requestId
      return options
    },

    onRequest: event => {
      // Short-circuit if not enabled, to save some CPU cycles with formatting stuff
      if (shortCircuit || !event) {
        return event
      }

      const options = event.options

      log('[%s] HTTP %s %s', options.requestId, options.method, options.url)

      if (verbose && options.body && typeof options.body === 'string') {
        log('[%s] Request body: %s', options.requestId, options.body)
      }

      if (verbose && options.headers) {
        log('[%s] Request headers: %s', options.requestId, JSON.stringify(options.headers, null, 2))
      }

      return event
    },

    onResponse: (res, context) => {
      // Short-circuit if not enabled, to save some CPU cycles with formatting stuff
      if (shortCircuit || !res) {
        return res
      }

      const reqId = context.options.requestId

      log('[%s] Response code: %s %s', reqId, res.statusCode, res.statusMessage)

      if (verbose && res.body) {
        log('[%s] Response body: %s', reqId, stringifyBody(res))
      }

      return res
    },

    onError: (err, context) => {
      log('[%s] ERROR: %s', context.options.requestId, err.message)
      return err
    }
  }
}

function stringifyBody(res) {
  const contentType = (res.headers['content-type'] || '').toLowerCase()
  const isJson = contentType.indexOf('application/json') !== -1
  return isJson ? tryFormat(res.body) : res.body
}

// Attempt pretty-formatting JSON
function tryFormat(body) {
  try {
    const parsed = typeof body === 'string' ? JSON.parse(body) : body
    return JSON.stringify(parsed, null, 2)
  } catch (err) {
    return body
  }
}
<commit_msg>Fix debug middleware from crashing on handled errors (fixes #4)<commit_after>const debugIt = require('debug')

module.exports = (opts = {}) => {
  const verbose = opts.verbose
  const namespace = opts.namespace || 'get-it'
  const defaultLogger = debugIt(namespace)
  const log = opts.log || defaultLogger
  const shortCircuit = log === defaultLogger && !debugIt.enabled(namespace)
  let requestId = 0

  return {
    processOptions: options => {
      options.requestId = options.requestId || ++requestId
      return options
    },

    onRequest: event => {
      // Short-circuit if not enabled, to save some CPU cycles with formatting stuff
      if (shortCircuit || !event) {
        return event
      }

      const options = event.options

      log('[%s] HTTP %s %s', options.requestId, options.method, options.url)

      if (verbose && options.body && typeof options.body === 'string') {
        log('[%s] Request body: %s', options.requestId, options.body)
      }

      if (verbose && options.headers) {
        log('[%s] Request headers: %s', options.requestId, JSON.stringify(options.headers, null, 2))
      }

      return event
    },

    onResponse: (res, context) => {
      // Short-circuit if not enabled, to save some CPU cycles with formatting stuff
      if (shortCircuit || !res) {
        return res
      }

      const reqId = context.options.requestId

      log('[%s] Response code: %s %s', reqId, res.statusCode, res.statusMessage)

      if (verbose && res.body) {
        log('[%s] Response body: %s', reqId, stringifyBody(res))
      }

      return res
    },

    onError: (err, context) => {
      const reqId = context.options.requestId
      if (!err) {
        log('[%s] Error encountered, but handled by an earlier middleware', reqId)
        return err
      }

      log('[%s] ERROR: %s', reqId, err.message)
      return err
    }
  }
}

function stringifyBody(res) {
  const contentType = (res.headers['content-type'] || '').toLowerCase()
  const isJson = contentType.indexOf('application/json') !== -1
  return isJson ? tryFormat(res.body) : res.body
}

// Attempt pretty-formatting JSON
function tryFormat(body) {
  try {
    const parsed = typeof body === 'string' ? JSON.parse(body) : body
    return JSON.stringify(parsed, null, 2)
  } catch (err) {
    return body
  }
}
<|endoftext|>