<commit_before>/**
 * NodeChange.js
 *
 * Copyright, Moxiecode Systems AB
 * Released under LGPL License.
 *
 * License: http://www.tinymce.com/license
 * Contributing: http://www.tinymce.com/contributing
 */

/**
 * This class handles the nodechange event dispatching both manual and though selection change events.
 *
 * @class tinymce.NodeChange
 * @private
 */
define("tinymce/NodeChange", [
	"tinymce/dom/RangeUtils"
], function(RangeUtils) {
	return function(editor) {
		var lastRng, lastPath = [];

		/**
		 * Returns true/false if the current element path has been changed or not.
		 *
		 * @private
		 * @return {Boolean} True if the element path is the same false if it's not.
		 */
		function isSameElementPath(startElm) {
			var i, currentPath;

			currentPath = editor.$(startElm).parentsUntil(editor.getBody());
			if (currentPath.length === lastPath.length) {
				for (i = currentPath.length; i >= 0; i--) {
					if (currentPath[i] !== lastPath[i]) {
						break;
					}
				}

				if (i === -1) {
					lastPath = currentPath;
					return true;
				}
			}

			lastPath = currentPath;

			return false;
		}

		// Gecko doesn't support the "selectionchange" event
		if (!('onselectionchange' in editor.getDoc())) {
			editor.on('NodeChange Click MouseUp KeyUp', function() {
				var nativeRng, fakeRng;

				// Since DOM Ranges mutate on modification
				// of the DOM we need to clone it's contents
				nativeRng = editor.selection.getRng();
				fakeRng = {
					startContainer: nativeRng.startContainer,
					startOffset: nativeRng.startOffset,
					endContainer: nativeRng.endContainer,
					endOffset: nativeRng.endOffset
				};

				if (!RangeUtils.compareRanges(fakeRng, lastRng)) {
					editor.fire('SelectionChange');
				}

				lastRng = fakeRng;
			});
		}

		editor.on('SelectionChange', function() {
			var startElm = editor.selection.getStart();

			// Selection change might fire when focus is lost so check if the start is still within the body
			if (!isSameElementPath(startElm) && editor.dom.isChildOf(startElm, editor.getBody())) {
				editor.nodeChanged({selectionChange: true});
			}
		});

		/**
		 * Distpaches out a onNodeChange event to all observers. This method should be called when you
		 * need to update the UI states or element path etc.
		 *
		 * @method nodeChanged
		 * @param {Object} args Optional args to pass to NodeChange event handlers.
		 */
		this.nodeChanged = function(args) {
			var selection = editor.selection, node, parents, root;

			// Fix for bug #1896577 it seems that this can not be fired while the editor is loading
			if (editor.initialized && !editor.settings.disable_nodechange && !editor.settings.readonly) {
				// Get start node
				root = editor.getBody();
				node = selection.getStart() || root;
				node = node.ownerDocument != editor.getDoc() ? editor.getBody() : node;

				// Edge case for
|

				if (node.nodeName == 'IMG' && selection.isCollapsed()) {
					node = node.parentNode;
				}

				// Get parents and add them to object
				parents = [];
				editor.dom.getParent(node, function(node) {
					if (node === root) {
						return true;
					}

					parents.push(node);
				});

				args = args || {};
				args.element = node;
				args.parents = parents;

				editor.fire('NodeChange', args);
			}
		};
	};
});
<commit_msg>Fixed issue with Gecko not updating the selection properly.<commit_after>/**
 * NodeChange.js
 *
 * Copyright, Moxiecode Systems AB
 * Released under LGPL License.
 *
 * License: http://www.tinymce.com/license
 * Contributing: http://www.tinymce.com/contributing
 */

/**
 * This class handles the nodechange event dispatching both manual and though selection change events.
 *
 * @class tinymce.NodeChange
 * @private
 */
define("tinymce/NodeChange", [
	"tinymce/dom/RangeUtils"
], function(RangeUtils) {
	return function(editor) {
		var lastRng, lastPath = [];

		/**
		 * Returns true/false if the current element path has been changed or not.
		 *
		 * @private
		 * @return {Boolean} True if the element path is the same false if it's not.
		 */
		function isSameElementPath(startElm) {
			var i, currentPath;

			currentPath = editor.$(startElm).parentsUntil(editor.getBody());
			if (currentPath.length === lastPath.length) {
				for (i = currentPath.length; i >= 0; i--) {
					if (currentPath[i] !== lastPath[i]) {
						break;
					}
				}

				if (i === -1) {
					lastPath = currentPath;
					return true;
				}
			}

			lastPath = currentPath;

			return false;
		}

		// Gecko doesn't support the "selectionchange" event
		if (!('onselectionchange' in editor.getDoc())) {
			editor.on('NodeChange Click MouseUp KeyUp', function(e) {
				var nativeRng, fakeRng;

				// Since DOM Ranges mutate on modification
				// of the DOM we need to clone it's contents
				nativeRng = editor.selection.getRng();
				fakeRng = {
					startContainer: nativeRng.startContainer,
					startOffset: nativeRng.startOffset,
					endContainer: nativeRng.endContainer,
					endOffset: nativeRng.endOffset
				};

				// Always treat nodechange as a selectionchange since applying
				// formatting to the current range wouldn't update the range but it's parent
				if (e.type == 'nodechange' || !RangeUtils.compareRanges(fakeRng, lastRng)) {
					editor.fire('SelectionChange');
				}

				lastRng = fakeRng;
			});
		}

		editor.on('SelectionChange', function() {
			var startElm = editor.selection.getStart();

			// Selection change might fire when focus is lost so check if the start is still within the body
			if (!isSameElementPath(startElm) && editor.dom.isChildOf(startElm, editor.getBody())) {
				editor.nodeChanged({selectionChange: true});
			}
		});

		/**
		 * Distpaches out a onNodeChange event to all observers. This method should be called when you
		 * need to update the UI states or element path etc.
		 *
		 * @method nodeChanged
		 * @param {Object} args Optional args to pass to NodeChange event handlers.
		 */
		this.nodeChanged = function(args) {
			var selection = editor.selection, node, parents, root;

			// Fix for bug #1896577 it seems that this can not be fired while the editor is loading
			if (editor.initialized && !editor.settings.disable_nodechange && !editor.settings.readonly) {
				// Get start node
				root = editor.getBody();
				node = selection.getStart() || root;
				node = node.ownerDocument != editor.getDoc() ? editor.getBody() : node;

				// Edge case for
|

				if (node.nodeName == 'IMG' && selection.isCollapsed()) {
					node = node.parentNode;
				}

				// Get parents and add them to object
				parents = [];
				editor.dom.getParent(node, function(node) {
					if (node === root) {
						return true;
					}

					parents.push(node);
				});

				args = args || {};
				args.element = node;
				args.parents = parents;

				editor.fire('NodeChange', args);
			}
		};
	};
});
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import Radium from 'radium'

import colors from '../../styles/colors'

import { Text } from '../../components'

const styles = {
  color: colors.gray,
  fontStyle: 'italic',
}

class Subtitle extends Component {
  render() {
    return (

{this.props.children}

    )
  }
}

export default Radium(Subtitle)
<commit_msg>Remove unneeded Text import<commit_after>import React, { Component } from 'react'
import Radium from 'radium'

import colors from '../../styles/colors'

const styles = {
  color: colors.gray,
  fontStyle: 'italic',
}

class Subtitle extends Component {
  render() {
    return (

{this.props.children}

    )
  }
}

export default Radium(Subtitle)
<|endoftext|>


<commit_before>define(['logger', 'tracker', 'underscore', 'jquery', 'backbone', 'view/sss/UserView', 'chap-timeline', 'data/timeline/TimelineData', 'view/timeline/ClusterHelper', 'voc'],
    function(Logger, tracker, _, $, Backbone, UserView, Timeline, TimelineData, EntitiesHelper, Voc){
    return Backbone.View.extend({
        LOG: Logger.get('TimelineView'),
        waitingForLastOne : 0,
        events: {
            'bnp:zoomCluster' : 'expand', //@unused UI removed
            'bnp:expanded' : 'redraw',
            'bnp:unexpanded' : 'redraw'
        },
        initialize: function() {
            var that = this;
            if (!this.model ) {
                throw Error("no timeline model provided");
            }

            this.timeAttr = this.model.get(Voc.timeAttr);
            if( this.timeAttr.isEntity ) this.timeAttr = this.timeAttr.getSubject();
            this.timeAttr = this.model.vie.namespaces.uri(this.timeAttr);
            this.expandMarginPercent = 10;

            this.entitiesHelper = new EntitiesHelper(
                this.timeAttr,
                this.options.EntityView,
                this.options.ClusterView
            );

            this.user = this.model.get(Voc.belongsToUser);
            this.waitingForLastOne = 0;

            if (!this.options.timeline) {
                throw Error("no timeline configuration provided");
            }

            // TODO: resolve this hack: only fire on start change to avoid double execution
            this.model.on('change:' + this.model.vie.namespaces.uri(Voc.start), this.rearrangeVisibleArea, this);
            this.user.on('change:' + this.model.vie.namespaces.uri(Voc.hasUserEvent), this.changeEntitySet, this);

            this.LOG.debug('TimelineView initialized');

            // Deal with window resize
            // Redraw timeline when resize ends or pauses
            var timer;
            $(window).on('resize', function() {
                if ( timer ) {
                    clearTimeout(timer);
                }

                timer = setTimeout(function() {
                    that.LOG.debug('Resize timeout called');
                    timer = null;
                    that.redraw();
                }, 500);
            });
        },
        changeEntitySet: function(model, set, options) {
            this.LOG.debug('changeEntitySet', set);
            set = set || [];
            if( !_.isArray(set)) set = [set];
            var previous = Backbone.Model.prototype.previous.call(this.user,
                this.model.vie.namespaces.uri(Voc.hasUserEvent)) || [];
            if( !_.isArray(previous)) previous = [previous];
            this.LOG.debug('previous', previous);
            var that = this;
            var added = _.difference(set, previous);
            this.LOG.debug('added', added);
            this.addEntities(added);

            var deleted = _.difference(previous, set);
            _.each(deleted, function(a){
                a = that.model.vie.entities.get(a);
                var entity = a.get(Voc.hasResource);
                // TODO don't remove entity if referenced by another user event
                that.removeEntity(entity);
            });
        },
        rearrangeVisibleArea: function(model, collection, options ) {
            this.LOG.debug("rearrangeVisibleArea", options && options.by);
            if (options.by && options.by === this ) return;

            var startTime = new Date(this.model.get(Voc.start));
            var endTime = new Date(this.model.get(Voc.end));
            if( !startTime || !endTime )  return;
            this.LOG.debug('startTime', startTime);
            this.LOG.debug('endTime', endTime);
            var range = this.timeline.getVisibleChartRange();
            this.timeline.setVisibleChartRange( startTime, endTime);
            this.reclusterByRangeChange(
                    new Date(range.start), new Date(range.end),
                    startTime, endTime);
        },
        addEntities: function(entities) {
            var that = this;
            var lastOne;
            var initRange = !this.model.get(Voc.start) && !this.model.get(Voc.end);
            this.LOG.debug("initRange", initRange, this.model.get(Voc.start), this.model.get(Voc.end));
            var readyEntities = [];
            _.each(entities, function(ue) {
                if( !ue.isEntity ) ue = that.model.vie.entities.get(ue);
                var entity = ue.get(Voc.hasResource);
                that.addEntity(entity);
                if( !initRange ) return;

                that.waitingForLastOne++;
                if( !entity.get(that.timeAttr) ) {
                    entity.once("change:"+that.timeAttr, that.checkLastOne, that);
                    return;
                }
                readyEntities.push(entity);
                that.LOG.debug('addEntities', entity, that.waitingForLastOne);
            });
            _.each(readyEntities, function(entity) {
                that.checkLastOne(entity);
            });
        },
        checkLastOne: function(entity) {
            this.waitingForLastOne--;
            this.LOG.debug('checkLastOne', entity, this.waitingForLastOne);
            if( !this.lastOne || this.lastOne.get(this.timeAttr) < entity.get(this.timeAttr) ) {
                this.lastOne = entity;
            }
            if( this.waitingForLastOne == 0 ) {
                this.browseTo(this.lastOne);
            }

        },
        addEntity: function(entity, collection, options) {
            if( this.entitiesHelper.contains(entity) ) {
                return false;
            }
            this.entitiesHelper.addEntityView(entity, this.timeAttr);
            this.listenTo(entity, 'change:' + entity.vie.namespaces.uri(this.timeAttr), this.changeEntity);
            return true;

        },
        changeEntity: function(entity, options ) {
            this.LOG.debug("coll changeEntity");
            this.entitiesHelper.changeEntityView(entity, this.timeAttr);
        },
        removeEntity: function(entity, collection, options) {
            this.entitiesHelper.removeEntityView(entity, this.timeAttr);
        },
        render: function() {
            if( this.timeline ) {
                this.timeline.redraw();
                return this;
            }

            this.$el.empty();

            this.renderUser();
            this.renderTimeline();
            this.renderDatepicker();

            var view = this;
            // add entities which are already contained
            var userevents = this.user.get(Voc.hasUserEvent) || [];
            if( !_.isArray(userevents)) userevents = [userevents];
            this.addEntities(userevents);
            return this;
        },
        renderUser: function () {
            //@unused This functionality has been disabled for now
            return false;
            if( this.user && this.user.isEntity) {
                var par = $('
');
                this.userDOM = $('
');
                par.append(this.userDOM);
                this.$el.append(par);

                // Instantiate User View
                this.userView = new UserView({
                    model:this.user,
                    el: this.userDOM
                });
                this.userView.render();
            }

            this.LOG.debug('this.user of timeline', this.user.getSubject());

        },
        renderTimeline: function() {
            // Instantiate our timeline object.
            this.timelineDOM = document.createElement('div');
            this.timelineDOM.setAttribute('class', 'timeline');
            this.$el.append(this.timelineDOM);
            this.timeline = new Timeline(this.timelineDOM);
            this.LOG.debug("draw timeline", this.model.get(Voc.start), this.model.get(Voc.end));
            var start = this.model.get(Voc.start);
            var end = this.model.get(Voc.end);
            if( !start ) {
                start = new Date();
                start.setDate(start.getDate() -1 );
            }
            if( !end ) {
                end = new Date();
                end.setDate(end.getDate() +1);
            }
            this.timeline.draw( [{
                    'start' : new Date(), // add a dummy event to force rendering
                    'content' : "x"
                }], _.extend(this.options.timeline, {
                'start' : start,
                'end' : end,
                'min' : new Date('2013-01-01'),
                'max' : new Date( ( ( new Date() ).getFullYear() + 1 ) + '-07-01' ),
                'zoomMin' : 28800000, // 8 hours
                'zoomMax' : 31556940000 // 1 year
            }));
            this.timeline.deleteItem(0); // remove dummy node
            this.LOG.debug('timeline', this.timeline);

            this.entitiesHelper.setTimeline(this.timeline, this.timelineDOM);

            var view = this;
            // bind timeline's internal events to model
            links.events.addListener(this.timeline, 'rangechanged', function(range){
                view.LOG.debug('caught rangechanged: '+ range.start + ' - ' + range.end);
                var vals = {};
                vals[Voc.start] = range.start;
                vals[Voc.end] = range.end;
                view.reclusterByRangeChange(
                    new Date(view.model.get(Voc.start)), new Date(view.model.get(Voc.end)),
                    new Date(range.start), new Date(range.end));

                view.model.save(vals, { 'by' : view, 'calledBy' : 'renderTimeline' });
            });
        },
        renderDatepicker: function() {
            var that = this;

            this.$el.prepend('
Jump To Date: <input type="text" name="jumpToDate" val="" />
');
            this.$el.find('input[name="jumpToDate"]')
                .datepicker({
                  minDate : that.timeline.options.min,
                  maxDate : that.timeline.options.max,
                  changeMonth: true,
                  changeYear: true,
                  showOn : 'button',
                  buttonImage : 'img/calendar.png',
                  buttonImageOnly : true,
                  buttonText : 'Jump To Date',
                  onSelect: function(dateText, ui) {
                      var date = new Date(dateText);
                      that.LOG.debug('Jump To Date Selected', dateText, ui, date);
                      that.browseToDate(date);

                      tracker.info(tracker.EXECUTEJUMPTODATEBUTTON, tracker.TIMELINEAREA, null, date.getTime());
                   }
                });
            this.$el.find('input[name="jumpToDate"]')
                .parent()
                .find('img.ui-datepicker-trigger')
                .on('click', function() {
                    tracker.info(tracker.CLICKJUMPTODATEBUTTON, tracker.TIMELINEAREA);
                });
        },
        reclusterByRangeChange: function(prev_start, prev_end, start, end) {
            var prev_range = prev_end - prev_start;
            var range = end - start;

            if( prev_range != range ) {
                this.entitiesHelper.clusterByRange(start, end);
            }
        },
        datesEqual: function(item, entity) {
            return new Date(item.start).toUTCString() ==
                new Date(entity.get(this.timeAttr)).toUTCString();
        },
        getSelectedItem: function() {
            return this.timeline.getSelection()[0].row;
        },
        browseToDate: function(date) {
            this.LOG.debug("browseToDate called with date", date);
            var range = this.timeline.getVisibleChartRange();
            var diff = range.end - range.start;
                vals = {},
                start = new Date(parseInt(date.getTime() - diff / 2)),
                end = new Date(parseInt(date.getTime() + diff / 2));

            vals[Voc.start] = start;
            vals[Voc.end] = end;
            this.model.save(vals, { 'by' : this, 'calledBy' : 'browseToDate' });
            this.LOG.debug("start", start, "end", end);
            this.timeline.setVisibleChartRange(start, end, true);
        },
        browseTo: function(entity) {
            // wait for the time attribute if not set yet
            if( !entity.get(this.timeAttr) ) {
                entity.once('change:' + this.timeAttr, this.browseTo, this);
                return;
            }
            this.LOG.debug("browseTo called with entity", entity, JSON.stringify(entity.attributes));

            var entityDate = new Date(entity.get(this.timeAttr));

            this.browseToDate(entityDate);
        },
        //@unused UI removed
        expand: function(e) {
            this.LOG.debug('clickCluster event', e);
            var entities = e.cluster.get('entities');
            var minmax = this.minmax(entities);
            this.LOG.debug('minamx', minmax);

            var range = minmax['max'] - minmax['min'];
            var start = minmax['min'] - range/this.expandMarginPercent;
            var end = minmax['max'] + range/this.expandMarginPercent;

            var vals = {};
            vals[Voc.start] = new Date(start);
            vals[Voc.end] = new Date(end);

            this.LOG.debug('expand', 'start', vals[Voc.start], 'end', vals[Voc.end]);

            this.timeline.setVisibleChartRange( start, end);
            this.reclusterByRangeChange(
                    new Date(this.model.get(Voc.start)), new Date(this.model.get(Voc.end)),
                    vals[Voc.start], vals[Voc.end]
                );
            this.model.save(vals, { 'by' : this, 'calledBy' : 'expand' });
        },
        minmax: function(entities) {
            var min, max;
            var that = this;
            _.each(entities, function(entity) {
                var time = entity.get(that.timeAttr);
                if( min === undefined || time < min ) min = time;
                if( max === undefined || time > min ) max = time;
            });
            return {
                'min' : min,
                'max' : max
            };
        },
        redraw: function(e) {
            this.LOG.debug('clickCluster', e);
            this.timeline.redraw();
            if ( e && e.clusterView ) {
                if ( e.type === 'bnp:expanded' ) {
                    e.clusterView.$el.parent().parent().css('z-index', '150');
                } else if ( e.type === 'bnp:unexpanded' ) {
                    e.clusterView.$el.parent().parent().css('z-index', '');
                }
            }
        }

    });
});
<commit_msg>Moved timeline options into separate setOptions call.<commit_after>define(['logger', 'tracker', 'underscore', 'jquery', 'backbone', 'view/sss/UserView', 'chap-timeline', 'data/timeline/TimelineData', 'view/timeline/ClusterHelper', 'voc'],
    function(Logger, tracker, _, $, Backbone, UserView, Timeline, TimelineData, EntitiesHelper, Voc){
    return Backbone.View.extend({
        LOG: Logger.get('TimelineView'),
        waitingForLastOne : 0,
        events: {
            'bnp:zoomCluster' : 'expand', //@unused UI removed
            'bnp:expanded' : 'redraw',
            'bnp:unexpanded' : 'redraw'
        },
        initialize: function() {
            var that = this;
            if (!this.model ) {
                throw Error("no timeline model provided");
            }

            this.timeAttr = this.model.get(Voc.timeAttr);
            if( this.timeAttr.isEntity ) this.timeAttr = this.timeAttr.getSubject();
            this.timeAttr = this.model.vie.namespaces.uri(this.timeAttr);
            this.expandMarginPercent = 10;

            this.entitiesHelper = new EntitiesHelper(
                this.timeAttr,
                this.options.EntityView,
                this.options.ClusterView
            );

            this.user = this.model.get(Voc.belongsToUser);
            this.waitingForLastOne = 0;

            if (!this.options.timeline) {
                throw Error("no timeline configuration provided");
            }

            // TODO: resolve this hack: only fire on start change to avoid double execution
            this.model.on('change:' + this.model.vie.namespaces.uri(Voc.start), this.rearrangeVisibleArea, this);
            this.user.on('change:' + this.model.vie.namespaces.uri(Voc.hasUserEvent), this.changeEntitySet, this);

            this.LOG.debug('TimelineView initialized');

            // Deal with window resize
            // Redraw timeline when resize ends or pauses
            var timer;
            $(window).on('resize', function() {
                if ( timer ) {
                    clearTimeout(timer);
                }

                timer = setTimeout(function() {
                    that.LOG.debug('Resize timeout called');
                    timer = null;
                    that.redraw();
                }, 500);
            });
        },
        changeEntitySet: function(model, set, options) {
            this.LOG.debug('changeEntitySet', set);
            set = set || [];
            if( !_.isArray(set)) set = [set];
            var previous = Backbone.Model.prototype.previous.call(this.user,
                this.model.vie.namespaces.uri(Voc.hasUserEvent)) || [];
            if( !_.isArray(previous)) previous = [previous];
            this.LOG.debug('previous', previous);
            var that = this;
            var added = _.difference(set, previous);
            this.LOG.debug('added', added);
            this.addEntities(added);

            var deleted = _.difference(previous, set);
            _.each(deleted, function(a){
                a = that.model.vie.entities.get(a);
                var entity = a.get(Voc.hasResource);
                // TODO don't remove entity if referenced by another user event
                that.removeEntity(entity);
            });
        },
        rearrangeVisibleArea: function(model, collection, options ) {
            this.LOG.debug("rearrangeVisibleArea", options && options.by);
            if (options.by && options.by === this ) return;

            var startTime = new Date(this.model.get(Voc.start));
            var endTime = new Date(this.model.get(Voc.end));
            if( !startTime || !endTime )  return;
            this.LOG.debug('startTime', startTime);
            this.LOG.debug('endTime', endTime);
            var range = this.timeline.getVisibleChartRange();
            this.timeline.setVisibleChartRange( startTime, endTime);
            this.reclusterByRangeChange(
                    new Date(range.start), new Date(range.end),
                    startTime, endTime);
        },
        addEntities: function(entities) {
            var that = this;
            var lastOne;
            var initRange = !this.model.get(Voc.start) && !this.model.get(Voc.end);
            this.LOG.debug("initRange", initRange, this.model.get(Voc.start), this.model.get(Voc.end));
            var readyEntities = [];
            _.each(entities, function(ue) {
                if( !ue.isEntity ) ue = that.model.vie.entities.get(ue);
                var entity = ue.get(Voc.hasResource);
                that.addEntity(entity);
                if( !initRange ) return;

                that.waitingForLastOne++;
                if( !entity.get(that.timeAttr) ) {
                    entity.once("change:"+that.timeAttr, that.checkLastOne, that);
                    return;
                }
                readyEntities.push(entity);
                that.LOG.debug('addEntities', entity, that.waitingForLastOne);
            });
            _.each(readyEntities, function(entity) {
                that.checkLastOne(entity);
            });
        },
        checkLastOne: function(entity) {
            this.waitingForLastOne--;
            this.LOG.debug('checkLastOne', entity, this.waitingForLastOne);
            if( !this.lastOne || this.lastOne.get(this.timeAttr) < entity.get(this.timeAttr) ) {
                this.lastOne = entity;
            }
            if( this.waitingForLastOne == 0 ) {
                this.browseTo(this.lastOne);
            }

        },
        addEntity: function(entity, collection, options) {
            if( this.entitiesHelper.contains(entity) ) {
                return false;
            }
            this.entitiesHelper.addEntityView(entity, this.timeAttr);
            this.listenTo(entity, 'change:' + entity.vie.namespaces.uri(this.timeAttr), this.changeEntity);
            return true;

        },
        changeEntity: function(entity, options ) {
            this.LOG.debug("coll changeEntity");
            this.entitiesHelper.changeEntityView(entity, this.timeAttr);
        },
        removeEntity: function(entity, collection, options) {
            this.entitiesHelper.removeEntityView(entity, this.timeAttr);
        },
        render: function() {
            if( this.timeline ) {
                this.timeline.redraw();
                return this;
            }

            this.$el.empty();

            this.renderUser();
            this.renderTimeline();
            this.renderDatepicker();

            var view = this;
            // add entities which are already contained
            var userevents = this.user.get(Voc.hasUserEvent) || [];
            if( !_.isArray(userevents)) userevents = [userevents];
            this.addEntities(userevents);
            return this;
        },
        renderUser: function () {
            //@unused This functionality has been disabled for now
            return false;
            if( this.user && this.user.isEntity) {
                var par = $('
');
                this.userDOM = $('
');
                par.append(this.userDOM);
                this.$el.append(par);

                // Instantiate User View
                this.userView = new UserView({
                    model:this.user,
                    el: this.userDOM
                });
                this.userView.render();
            }

            this.LOG.debug('this.user of timeline', this.user.getSubject());

        },
        renderTimeline: function() {
            // Instantiate our timeline object.
            this.timelineDOM = document.createElement('div');
            this.timelineDOM.setAttribute('class', 'timeline');
            this.$el.append(this.timelineDOM);
            this.timeline = new Timeline(this.timelineDOM);
            this.LOG.debug("draw timeline", this.model.get(Voc.start), this.model.get(Voc.end));
            var start = this.model.get(Voc.start);
            var end = this.model.get(Voc.end);
            if( !start ) {
                start = new Date();
                start.setDate(start.getDate() -1 );
            }
            if( !end ) {
                end = new Date();
                end.setDate(end.getDate() +1);
            }
            this.timeline.setOptions(_.extend(this.options.timeline, {
                'start' : start,
                'end' : end,
                'min' : new Date('2013-01-01'),
                'max' : new Date( ( ( new Date() ).getFullYear() + 1 ) + '-07-01' ),
                'zoomMin' : 28800000, // 8 hours
                'zoomMax' : 31556940000 // 1 year
            }));
            this.timeline.draw( [{
                    'start' : new Date(), // add a dummy event to force rendering
                    'content' : "x"
                }] );
            this.timeline.deleteItem(0); // remove dummy node
            this.LOG.debug('timeline', this.timeline);

            this.entitiesHelper.setTimeline(this.timeline, this.timelineDOM);

            var view = this;
            // bind timeline's internal events to model
            links.events.addListener(this.timeline, 'rangechanged', function(range){
                view.LOG.debug('caught rangechanged: '+ range.start + ' - ' + range.end);
                var vals = {};
                vals[Voc.start] = range.start;
                vals[Voc.end] = range.end;
                view.reclusterByRangeChange(
                    new Date(view.model.get(Voc.start)), new Date(view.model.get(Voc.end)),
                    new Date(range.start), new Date(range.end));

                view.model.save(vals, { 'by' : view, 'calledBy' : 'renderTimeline' });
            });
        },
        renderDatepicker: function() {
            var that = this;

            this.$el.prepend('
Jump To Date: <input type="text" name="jumpToDate" val="" />
');
            this.$el.find('input[name="jumpToDate"]')
                .datepicker({
                  minDate : that.timeline.options.min,
                  maxDate : that.timeline.options.max,
                  changeMonth: true,
                  changeYear: true,
                  showOn : 'button',
                  buttonImage : 'img/calendar.png',
                  buttonImageOnly : true,
                  buttonText : 'Jump To Date',
                  onSelect: function(dateText, ui) {
                      var date = new Date(dateText);
                      that.LOG.debug('Jump To Date Selected', dateText, ui, date);
                      that.browseToDate(date);

                      tracker.info(tracker.EXECUTEJUMPTODATEBUTTON, tracker.TIMELINEAREA, null, date.getTime());
                   }
                });
            this.$el.find('input[name="jumpToDate"]')
                .parent()
                .find('img.ui-datepicker-trigger')
                .on('click', function() {
                    tracker.info(tracker.CLICKJUMPTODATEBUTTON, tracker.TIMELINEAREA);
                });
        },
        reclusterByRangeChange: function(prev_start, prev_end, start, end) {
            var prev_range = prev_end - prev_start;
            var range = end - start;

            if( prev_range != range ) {
                this.entitiesHelper.clusterByRange(start, end);
            }
        },
        datesEqual: function(item, entity) {
            return new Date(item.start).toUTCString() ==
                new Date(entity.get(this.timeAttr)).toUTCString();
        },
        getSelectedItem: function() {
            return this.timeline.getSelection()[0].row;
        },
        browseToDate: function(date) {
            this.LOG.debug("browseToDate called with date", date);
            var range = this.timeline.getVisibleChartRange();
            var diff = range.end - range.start;
                vals = {},
                start = new Date(parseInt(date.getTime() - diff / 2)),
                end = new Date(parseInt(date.getTime() + diff / 2));

            vals[Voc.start] = start;
            vals[Voc.end] = end;
            this.model.save(vals, { 'by' : this, 'calledBy' : 'browseToDate' });
            this.LOG.debug("start", start, "end", end);
            this.timeline.setVisibleChartRange(start, end, true);
        },
        browseTo: function(entity) {
            // wait for the time attribute if not set yet
            if( !entity.get(this.timeAttr) ) {
                entity.once('change:' + this.timeAttr, this.browseTo, this);
                return;
            }
            this.LOG.debug("browseTo called with entity", entity, JSON.stringify(entity.attributes));

            var entityDate = new Date(entity.get(this.timeAttr));

            this.browseToDate(entityDate);
        },
        //@unused UI removed
        expand: function(e) {
            this.LOG.debug('clickCluster event', e);
            var entities = e.cluster.get('entities');
            var minmax = this.minmax(entities);
            this.LOG.debug('minamx', minmax);

            var range = minmax['max'] - minmax['min'];
            var start = minmax['min'] - range/this.expandMarginPercent;
            var end = minmax['max'] + range/this.expandMarginPercent;

            var vals = {};
            vals[Voc.start] = new Date(start);
            vals[Voc.end] = new Date(end);

            this.LOG.debug('expand', 'start', vals[Voc.start], 'end', vals[Voc.end]);

            this.timeline.setVisibleChartRange( start, end);
            this.reclusterByRangeChange(
                    new Date(this.model.get(Voc.start)), new Date(this.model.get(Voc.end)),
                    vals[Voc.start], vals[Voc.end]
                );
            this.model.save(vals, { 'by' : this, 'calledBy' : 'expand' });
        },
        minmax: function(entities) {
            var min, max;
            var that = this;
            _.each(entities, function(entity) {
                var time = entity.get(that.timeAttr);
                if( min === undefined || time < min ) min = time;
                if( max === undefined || time > min ) max = time;
            });
            return {
                'min' : min,
                'max' : max
            };
        },
        redraw: function(e) {
            this.LOG.debug('clickCluster', e);
            this.timeline.redraw();
            if ( e && e.clusterView ) {
                if ( e.type === 'bnp:expanded' ) {
                    e.clusterView.$el.parent().parent().css('z-index', '150');
                } else if ( e.type === 'bnp:unexpanded' ) {
                    e.clusterView.$el.parent().parent().css('z-index', '');
                }
            }
        }

    });
});
<|endoftext|>


<commit_before>export default {
  space: [0, 4, 8, 16, 32, 64, 128, 256, 512],
  fonts: {
    body: "aktiv-grotesk-extended, sans-serif",
    heading: "inherit",
    monospace: "Menlo, monospace",
  },
  fontSizes: [12, 14, 16, 20, 24, 32, 48, 64, 96],
  fontWeights: {
    body: 400,
    heading: 500,
    bold: 700,
  },
  lineHeights: {
    body: 1.5,
    heading: 1.125,
  },
  sizes: {
    largeContainer: 1320,
    container: 1200,
  },
  colors: {
    text: "#000",
    background: "#fff",
    primary: "#07c",
    secondary: "#30c",
    muted: "#f6f6f6",
    green: "#219653",
    purple: "#FA00FF",
    yellow: "#F8B03D",
    orange: "#F17A5D",
    violet: "#9473B0",
    blue: "#79CDE0",
    cinderella: "#FCE8DE",
  },
  borders: {
    primary: "3px solid #000000",
  },
  forms: {
    input: {
      fontFamily: "body",
      bg: "blue",
      border: "primary",
      borderWidth: 4,
    },
    textarea: {
      fontFamily: "body",
      bg: "blue",
      border: "primary",
      borderWidth: 4,
    },
    select: {
      fontFamily: "body",
      bg: "blue",
      border: "primary",
      borderWidth: 4,
      option: {
        fontSize: 3,
        padding: 3,
        backgroundColor: "white",
      },
    },
  },
  buttons: {
    primary: {
      position: "relative",
      padding: [2, 3],

      fontSize: [0, 2],
      fontFamily: "body",
      fontWeight: "heading",

      color: "#000",
      borderWidth: ["3px", "4px"],
      borderStyle: "solid",
      borderColor: "#000",
      backgroundColor: "yellow",
    },
    white: {
      variant: "buttons.primary",
      background: "#fff",
    },
  },
  links: {
    header: {
      color: "white",
      fontSize: 5,
      textDecoration: "none",
      "&:hover": {
        borderBottom: "2px solid white",
      },
    },
    button: {
      position: "relative",
      px: 3,
      fontSize: 2,
      height: 50,
      lineHeight: "43px",
      display: "inline-block",
      height: 50,
      fontFamily: "body",
      fontWeight: "heading",

      color: "#000",
      textDecoration: "none",
      textTransform: "uppercase",
    },
  },
  text: {
    caps: {
      textTransform: "uppercase",
    },
    header: {
      variant: "text.caps",
      fontSize: 2,
      fontWeight: "bold",
      mt: 20,
      mb: 3,
    },
    prefooter: {
      fontWeight: "bold",
      color: "violet",
    },
    heading: {
      fontFamily: "heading",
      fontWeight: "heading",
      lineHeight: "heading",
    },
    marquee: {
      variant: "text.caps",
      fontSize: 5,
      whiteSpace: "nowrap",
    },
    label: {
      textTransform: "uppercase",
      fontWeight: "bold",
      fontSize: 3,
      color: "orange",
      mb: 2,
    },
    labelDescription: {
      mb: 3,
      maxWidth: 850,
    },
  },
  styles: {
    root: {
      fontFamily: "body",
      lineHeight: "body",
      fontWeight: "body",
    },
    h1: {
      color: "text",
      fontFamily: "heading",
      lineHeight: "heading",
      fontWeight: "heading",
      mb: "1em",
      fontSize: 5,
    },
    h2: {
      color: "text",
      fontFamily: "heading",
      lineHeight: "heading",
      fontWeight: "heading",
      mb: "1em",
      fontSize: 4,
    },
    h3: {
      color: "text",
      fontFamily: "heading",
      lineHeight: "heading",
      fontWeight: "heading",
      mb: "1em",
      fontSize: 3,
    },
    h4: {
      color: "text",
      fontFamily: "heading",
      lineHeight: "heading",
      fontWeight: "heading",
      mb: "1em",
      fontSize: 2,
    },
    h5: {
      color: "text",
      fontFamily: "heading",
      lineHeight: "heading",
      fontWeight: "heading",
      mb: "1em",
      fontSize: 1,
    },
    h6: {
      color: "text",
      fontFamily: "heading",
      lineHeight: "heading",
      fontWeight: "heading",
      mb: "1em",
      fontSize: 0,
    },
    p: {
      color: "text",
      fontFamily: "body",
      fontWeight: "body",
      lineHeight: "body",
      mb: "1em",
    },
    a: {
      color: "primary",
    },
    pre: {
      fontFamily: "monospace",
      overflowX: "auto",
      code: {
        color: "inherit",
      },
    },
    code: {
      fontFamily: "monospace",
      fontSize: "inherit",
    },
    table: {
      width: "100%",
      borderCollapse: "separate",
      borderSpacing: 0,
    },
    th: {
      textAlign: "left",
      borderBottomStyle: "solid",
    },
    td: {
      textAlign: "left",
      borderBottomStyle: "solid",
    },
    img: {
      maxWidth: "100%",
    },
  },
  zIndices: {
    header: "10",
  },
};
<commit_msg>Make menu zIndex higher to fix overlaps<commit_after>export default {
  space: [0, 4, 8, 16, 32, 64, 128, 256, 512],
  fonts: {
    body: "aktiv-grotesk-extended, sans-serif",
    heading: "inherit",
    monospace: "Menlo, monospace",
  },
  fontSizes: [12, 14, 16, 20, 24, 32, 48, 64, 96],
  fontWeights: {
    body: 400,
    heading: 500,
    bold: 700,
  },
  lineHeights: {
    body: 1.5,
    heading: 1.125,
  },
  sizes: {
    largeContainer: 1320,
    container: 1200,
  },
  colors: {
    text: "#000",
    background: "#fff",
    primary: "#07c",
    secondary: "#30c",
    muted: "#f6f6f6",
    green: "#219653",
    purple: "#FA00FF",
    yellow: "#F8B03D",
    orange: "#F17A5D",
    violet: "#9473B0",
    blue: "#79CDE0",
    cinderella: "#FCE8DE",
  },
  borders: {
    primary: "3px solid #000000",
  },
  forms: {
    input: {
      fontFamily: "body",
      bg: "blue",
      border: "primary",
      borderWidth: 4,
    },
    textarea: {
      fontFamily: "body",
      bg: "blue",
      border: "primary",
      borderWidth: 4,
    },
    select: {
      fontFamily: "body",
      bg: "blue",
      border: "primary",
      borderWidth: 4,
      option: {
        fontSize: 3,
        padding: 3,
        backgroundColor: "white",
      },
    },
  },
  buttons: {
    primary: {
      position: "relative",
      padding: [2, 3],

      fontSize: [0, 2],
      fontFamily: "body",
      fontWeight: "heading",

      color: "#000",
      borderWidth: ["3px", "4px"],
      borderStyle: "solid",
      borderColor: "#000",
      backgroundColor: "yellow",
    },
    white: {
      variant: "buttons.primary",
      background: "#fff",
    },
  },
  links: {
    header: {
      color: "white",
      fontSize: 5,
      textDecoration: "none",
      "&:hover": {
        borderBottom: "2px solid white",
      },
    },
    button: {
      position: "relative",
      px: 3,
      fontSize: 2,
      height: 50,
      lineHeight: "43px",
      display: "inline-block",
      height: 50,
      fontFamily: "body",
      fontWeight: "heading",

      color: "#000",
      textDecoration: "none",
      textTransform: "uppercase",
    },
  },
  text: {
    caps: {
      textTransform: "uppercase",
    },
    header: {
      variant: "text.caps",
      fontSize: 2,
      fontWeight: "bold",
      mt: 20,
      mb: 3,
    },
    prefooter: {
      fontWeight: "bold",
      color: "violet",
    },
    heading: {
      fontFamily: "heading",
      fontWeight: "heading",
      lineHeight: "heading",
    },
    marquee: {
      variant: "text.caps",
      fontSize: 5,
      whiteSpace: "nowrap",
    },
    label: {
      textTransform: "uppercase",
      fontWeight: "bold",
      fontSize: 3,
      color: "orange",
      mb: 2,
    },
    labelDescription: {
      mb: 3,
      maxWidth: 850,
    },
  },
  styles: {
    root: {
      fontFamily: "body",
      lineHeight: "body",
      fontWeight: "body",
    },
    h1: {
      color: "text",
      fontFamily: "heading",
      lineHeight: "heading",
      fontWeight: "heading",
      mb: "1em",
      fontSize: 5,
    },
    h2: {
      color: "text",
      fontFamily: "heading",
      lineHeight: "heading",
      fontWeight: "heading",
      mb: "1em",
      fontSize: 4,
    },
    h3: {
      color: "text",
      fontFamily: "heading",
      lineHeight: "heading",
      fontWeight: "heading",
      mb: "1em",
      fontSize: 3,
    },
    h4: {
      color: "text",
      fontFamily: "heading",
      lineHeight: "heading",
      fontWeight: "heading",
      mb: "1em",
      fontSize: 2,
    },
    h5: {
      color: "text",
      fontFamily: "heading",
      lineHeight: "heading",
      fontWeight: "heading",
      mb: "1em",
      fontSize: 1,
    },
    h6: {
      color: "text",
      fontFamily: "heading",
      lineHeight: "heading",
      fontWeight: "heading",
      mb: "1em",
      fontSize: 0,
    },
    p: {
      color: "text",
      fontFamily: "body",
      fontWeight: "body",
      lineHeight: "body",
      mb: "1em",
    },
    a: {
      color: "primary",
    },
    pre: {
      fontFamily: "monospace",
      overflowX: "auto",
      code: {
        color: "inherit",
      },
    },
    code: {
      fontFamily: "monospace",
      fontSize: "inherit",
    },
    table: {
      width: "100%",
      borderCollapse: "separate",
      borderSpacing: 0,
    },
    th: {
      textAlign: "left",
      borderBottomStyle: "solid",
    },
    td: {
      textAlign: "left",
      borderBottomStyle: "solid",
    },
    img: {
      maxWidth: "100%",
    },
  },
  zIndices: {
    header: "11",
  },
};
<|endoftext|>


<commit_before>import React from 'react';
import autoBind from 'react-autobind';
import bem from '../bem';

/*
Properties:
- checked <boolean>
- onChange <function>: required
- label <string>
*/
class Checkbox extends React.Component {
  constructor(props){
    if (typeof props.onChange !== 'function') {
      throw new Error('onChange callback missing!');
    }
    super(props);
    autoBind(this);
  }

  onChange(evt) {
    this.props.onChange(evt.currentTarget.checked);
  }

  render() {
    return (
      <bem.Checkbox>
        <bem.Checkbox__wrapper>
          <bem.Checkbox__input
            type='checkbox'
            name={this.props.name}
            id={this.props.id}
            onChange={this.onChange}
            checked={this.props.checked}
          />

          {this.props.label &&
            <bem.Checkbox__label htmlFor={this.props.id}>
              {this.props.label}
            </bem.Checkbox__label>
          }
        </bem.Checkbox__wrapper>
      </bem.Checkbox>
    );
  }
}

export default Checkbox;
<commit_msg>add disabled option for Checkbox component<commit_after>import React from 'react';
import autoBind from 'react-autobind';
import bem from '../bem';

/*
Properties:
- checked <boolean>
- disabled <boolean>
- onChange <function>: required
- label <string>
*/
class Checkbox extends React.Component {
  constructor(props){
    if (typeof props.onChange !== 'function') {
      throw new Error('onChange callback missing!');
    }
    super(props);
    autoBind(this);
  }

  onChange(evt) {
    this.props.onChange(evt.currentTarget.checked);
  }

  render() {
    return (
      <bem.Checkbox>
        <bem.Checkbox__wrapper>
          <bem.Checkbox__input
            type='checkbox'
            name={this.props.name}
            id={this.props.id}
            onChange={this.onChange}
            checked={this.props.checked}
            disabled={this.props.disabled}
          />

          {this.props.label &&
            <bem.Checkbox__label htmlFor={this.props.id}>
              {this.props.label}
            </bem.Checkbox__label>
          }
        </bem.Checkbox__wrapper>
      </bem.Checkbox>
    );
  }
}

export default Checkbox;
<|endoftext|>


<commit_before>/* @flow */

import Base from "./Base";
import Table from "./Table";

import type { FieldId, Field as FieldObject } from "metabase/meta/types/Field";
import type { TableId } from "metabase/meta/types/Table";

import { isDate, isNumeric, isBoolean, isString, isSummable, isCategory, isDimension, isMetric, getIconForField } from "metabase/lib/schema_metadata";
import { isPK } from "metabase/lib/types";

export default class Field extends Base {
    static type = "fields";
    static schema = {};

    _object: FieldObject;

    id: FieldId;
    display_name: string;
    table_id: TableId;
    fk_target_field_id: FieldId;

    base_type: string;
    special_type: string;

    table(): Table {
        const table = this._entity(Table, this.table_id);
        if (table == null) {
            throw new Error("Couldn't get the table for this field");
        }
        return table;
    }

    target() {
        return this._entity(Field, this.fk_target_field_id);
    }

    isDate()      { return isDate(this._object); }
    isNumeric()   { return isNumeric(this._object); }
    isBoolean()   { return isBoolean(this._object); }
    isString()    { return isString(this._object); }
    isSummable()  { return isSummable(this._object); }
    isCategory()  { return isCategory(this._object); }
    isMetric()    { return isMetric(this._object); }
    isDimension() { return isDimension(this._object); }
    isID()        { return isPK(this.special_type); }

    values(): Array<string> {
        let values = this._object.values;
        // https://github.com/metabase/metabase/issues/3417
        if (Array.isArray(values)) {
            return values;
        } else if (values && Array.isArray(values.values)) {
            return values.values;
        } else {
            return [];
        }
    }

    icon() {
        return getIconForField(this._object);
    }
}
<commit_msg>FKs are IDs too! Resolves #4193<commit_after>/* @flow */

import Base from "./Base";
import Table from "./Table";

import type { FieldId, Field as FieldObject } from "metabase/meta/types/Field";
import type { TableId } from "metabase/meta/types/Table";

import { isDate, isNumeric, isBoolean, isString, isSummable, isCategory, isDimension, isMetric, getIconForField } from "metabase/lib/schema_metadata";
import { isPK, isFK } from "metabase/lib/types";

export default class Field extends Base {
    static type = "fields";
    static schema = {};

    _object: FieldObject;

    id: FieldId;
    display_name: string;
    table_id: TableId;
    fk_target_field_id: FieldId;

    base_type: string;
    special_type: string;

    table(): Table {
        const table = this._entity(Table, this.table_id);
        if (table == null) {
            throw new Error("Couldn't get the table for this field");
        }
        return table;
    }

    target() {
        return this._entity(Field, this.fk_target_field_id);
    }

    isDate()      { return isDate(this._object); }
    isNumeric()   { return isNumeric(this._object); }
    isBoolean()   { return isBoolean(this._object); }
    isString()    { return isString(this._object); }
    isSummable()  { return isSummable(this._object); }
    isCategory()  { return isCategory(this._object); }
    isMetric()    { return isMetric(this._object); }
    isDimension() { return isDimension(this._object); }
    isID()        { return isPK(this.special_type) || isFK(this.special_type); }
    isPK()        { return isPK(this.special_type); }
    isFK()        { return isFK(this.special_type); }

    values(): Array<string> {
        let values = this._object.values;
        // https://github.com/metabase/metabase/issues/3417
        if (Array.isArray(values)) {
            return values;
        } else if (values && Array.isArray(values.values)) {
            return values.values;
        } else {
            return [];
        }
    }

    icon() {
        return getIconForField(this._object);
    }
}
<|endoftext|>


<commit_before>var tree = require("../tree"),
    Visitor = require("./visitor");

var CSSVisitorUtils = function(context) {
    this._visitor = new Visitor(this);
    this._context = context;
};

CSSVisitorUtils.prototype = {
    containsSilentNonBlockedChild: function(bodyRules) {
        var rule;
        if (bodyRules == null) {
            return false;
        }
        for (var r = 0; r < bodyRules.length; r++) {
            rule = bodyRules[r];
            if (rule.isSilent && rule.isSilent(this._context) && !rule.blocksVisibility()) {
                //the atrule contains something that was referenced (likely by extend)
                //therefore it needs to be shown in output too
                return true;
            }
        }
        return false;
    },

    keepOnlyVisibleChilds: function(owner) {
        if (owner == null || owner.rules == null) {
            return ;
        }

        owner.rules = owner.rules.filter(function(thing) {
            return thing.isVisible();
        }
        );
    },

    isEmpty: function(owner) {
        if (owner == null || owner.rules == null) {
            return true;
        }
        return owner.rules.length === 0;
    },

    hasVisibleSelector: function(rulesetNode) {
        if (rulesetNode == null || rulesetNode.paths == null) {
            return false;
        }
        return rulesetNode.paths.length > 0;
    },

    resolveVisibility: function (node, originalRules) {
        if (!node.blocksVisibility()) {
            if (this.isEmpty(node) && !this.containsSilentNonBlockedChild(originalRules)) {
                return ;
            }

            return node;
        }

        var compiledRulesBody = node.rules[0];
        this.keepOnlyVisibleChilds(compiledRulesBody);

        if (this.isEmpty(compiledRulesBody)) {
            return ;
        }

        node.ensureVisibility();
        node.removeVisibilityBlock();

        return node;
    },

    isVisibleRuleset: function(rulesetNode) {
        if (rulesetNode.firstRoot) {
            return true;
        }

        if (this.isEmpty(rulesetNode)) {
            return false;
        }

        if (!rulesetNode.root && !this.hasVisibleSelector(rulesetNode)) {
            return false;
        }

        return true;
    }

};

var ToCSSVisitor = function(context) {
    this._visitor = new Visitor(this);
    this._context = context;
    this.utils = new CSSVisitorUtils(context);
};

ToCSSVisitor.prototype = {
    isReplacing: true,
    run: function (root) {
        return this._visitor.visit(root);
    },

    visitDeclaration: function (declNode, visitArgs) {
        if (declNode.blocksVisibility() || declNode.variable) {
            return;
        }
        return declNode;
    },

    visitMixinDefinition: function (mixinNode, visitArgs) {
        // mixin definitions do not get eval'd - this means they keep state
        // so we have to clear that state here so it isn't used if toCSS is called twice
        mixinNode.frames = [];
    },

    visitExtend: function (extendNode, visitArgs) {
    },

    visitComment: function (commentNode, visitArgs) {
        if (commentNode.blocksVisibility() || commentNode.isSilent(this._context)) {
            return;
        }
        return commentNode;
    },

    visitMedia: function(mediaNode, visitArgs) {
        var originalRules = mediaNode.rules[0].rules;
        mediaNode.accept(this._visitor);
        visitArgs.visitDeeper = false;

        return this.utils.resolveVisibility(mediaNode, originalRules);
    },

    visitImport: function (importNode, visitArgs) {
        if (importNode.blocksVisibility()) {
            return ;
        }
        return importNode;
    },

    visitAtRule: function(atRuleNode, visitArgs) {
        if (atRuleNode.rules && atRuleNode.rules.length) {
            return this.visitAtRuleWithBody(atRuleNode, visitArgs);
        } else {
            return this.visitAtRuleWithoutBody(atRuleNode, visitArgs);
        }
    },

    visitAtRuleWithBody: function(atRuleNode, visitArgs) {
        //if there is only one nested ruleset and that one has no path, then it is
        //just fake ruleset
        function hasFakeRuleset(atRuleNode) {
            var bodyRules = atRuleNode.rules;
            return bodyRules.length === 1 && (!bodyRules[0].paths || bodyRules[0].paths.length === 0);
        }
        function getBodyRules(atRuleNode) {
            var nodeRules = atRuleNode.rules;
            if (hasFakeRuleset(atRuleNode)) {
                return nodeRules[0].rules;
            }

            return nodeRules;
        }
        //it is still true that it is only one ruleset in array
        //this is last such moment
        //process childs
        var originalRules = getBodyRules(atRuleNode);
        atRuleNode.accept(this._visitor);
        visitArgs.visitDeeper = false;

        if (!this.utils.isEmpty(atRuleNode)) {
            this._mergeRules(atRuleNode.rules[0].rules);
        }

        return this.utils.resolveVisibility(atRuleNode, originalRules);
    },

    visitAtRuleWithoutBody: function(atRuleNode, visitArgs) {
        if (atRuleNode.blocksVisibility()) {
            return;
        }

        if (atRuleNode.name === "@charset") {
            // Only output the debug info together with subsequent @charset definitions
            // a comment (or @media statement) before the actual @charset atrule would
            // be considered illegal css as it has to be on the first line
            if (this.charset) {
                if (atRuleNode.debugInfo) {
                    var comment = new tree.Comment("/* " + atRuleNode.toCSS(this._context).replace(/\n/g, "") + " */\n");
                    comment.debugInfo = atRuleNode.debugInfo;
                    return this._visitor.visit(comment);
                }
                return;
            }
            this.charset = true;
        }

        return atRuleNode;
    },

    checkValidNodes: function(rules, isRoot) {
        if (!rules) {
            return;
        }

        for (var i = 0; i < rules.length; i++) {
            var ruleNode = rules[i];
            if (isRoot && ruleNode instanceof tree.Declaration && !ruleNode.variable) {
                throw { message: "Properties must be inside selector blocks. They cannot be in the root",
                    index: ruleNode.getIndex(), filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename};
            }
            if (ruleNode instanceof tree.Call) {
                throw { message: "Function '" + ruleNode.name + "' is undefined",
                    index: ruleNode.getIndex(), filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename};
            }
            if (ruleNode.type && !ruleNode.allowRoot) {
                throw { message: ruleNode.type + " node returned by a function is not valid here",
                    index: ruleNode.getIndex(), filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename};
            }
        }
    },

    visitRuleset: function (rulesetNode, visitArgs) {
        //at this point rulesets are nested into each other
        var rule, rulesets = [];

        this.checkValidNodes(rulesetNode.rules, rulesetNode.firstRoot);

        if (!rulesetNode.root) {
            //remove invisible paths
            this._compileRulesetPaths(rulesetNode);

            // remove rulesets from this ruleset body and compile them separately
            var nodeRules = rulesetNode.rules, nodeRuleCnt = nodeRules ? nodeRules.length : 0;
            for (var i = 0; i < nodeRuleCnt; ) {
                rule = nodeRules[i];
                if (rule && rule.rules) {
                    // visit because we are moving them out from being a child
                    rulesets.push(this._visitor.visit(rule));
                    nodeRules.splice(i, 1);
                    nodeRuleCnt--;
                    continue;
                }
                i++;
            }
            // accept the visitor to remove rules and refactor itself
            // then we can decide nogw whether we want it or not
            // compile body
            if (nodeRuleCnt > 0) {
                rulesetNode.accept(this._visitor);
            } else {
                rulesetNode.rules = null;
            }
            visitArgs.visitDeeper = false;

        } else { //if (! rulesetNode.root) {
            rulesetNode.accept(this._visitor);
            visitArgs.visitDeeper = false;
        }

        if (rulesetNode.rules) {
            this._mergeRules(rulesetNode.rules);
            this._removeDuplicateRules(rulesetNode.rules);
        }

        //now decide whether we keep the ruleset
        if (this.utils.isVisibleRuleset(rulesetNode)) {
            rulesetNode.ensureVisibility();
            rulesets.splice(0, 0, rulesetNode);
        }

        if (rulesets.length === 1) {
            return rulesets[0];
        }
        return rulesets;
    },

    _compileRulesetPaths: function(rulesetNode) {
        if (rulesetNode.paths) {
            rulesetNode.paths = rulesetNode.paths
                .filter(function(p) {
                    var i;
                    if (p[0].elements[0].combinator.value === ' ') {
                        p[0].elements[0].combinator = new(tree.Combinator)('');
                    }
                    for (i = 0; i < p.length; i++) {
                        if (p[i].isVisible() && p[i].getIsOutput()) {
                            return true;
                        }
                    }
                    return false;
                });
        }
    },

    _removeDuplicateRules: function(rules) {
        if (!rules) { return; }

        // remove duplicates
        var ruleCache = {},
            ruleList, rule, i;

        for (i = rules.length - 1; i >= 0 ; i--) {
            rule = rules[i];
            if (rule instanceof tree.Declaration) {
                if (!ruleCache[rule.name]) {
                    ruleCache[rule.name] = rule;
                } else {
                    ruleList = ruleCache[rule.name];
                    if (ruleList instanceof tree.Declaration) {
                        ruleList = ruleCache[rule.name] = [ruleCache[rule.name].toCSS(this._context)];
                    }
                    var ruleCSS = rule.toCSS(this._context);
                    if (ruleList.indexOf(ruleCSS) !== -1) {
                        rules.splice(i, 1);
                    } else {
                        ruleList.push(ruleCSS);
                    }
                }
            }
        }
    },

    _mergeRules: function(rules) {
        if (!rules) {
            return;
        }

        var groups    = {},
            groupsArr = [];

        for (var i = 0; i < rules.length; i++) {
            var rule = rules[i];
            if (rule.merge) {
                var key = rule.name;
                groups[key] ? rules.splice(i--, 1) :
                    groupsArr.push(groups[key] = []);
                groups[key].push(rule);
            }
        }

        groupsArr.forEach(function(group) {
            if (group.length > 0) {
                var result = group[0],
                    space  = [],
                    comma  = [new tree.Expression(space)];
                group.forEach(function(rule) {
                    if ((rule.merge === '+') && (space.length > 0)) {
                        comma.push(new tree.Expression(space = []));
                    }
                    space.push(rule.value);
                    result.important = result.important || rule.important;
                });
                result.value = new tree.Value(comma);
            }
        });
    },

    visitAnonymous: function(anonymousNode, visitArgs) {
        if (anonymousNode.blocksVisibility()) {
            return ;
        }
        anonymousNode.accept(this._visitor);
        return anonymousNode;
    }
};

module.exports = ToCSSVisitor;
<commit_msg>clean to-css-visitor.js (eslint etc.)<commit_after>var tree = require("../tree"),
    Visitor = require("./visitor");

var CSSVisitorUtils = function(context) {
    this._visitor = new Visitor(this);
    this._context = context;
};

CSSVisitorUtils.prototype = {
    containsSilentNonBlockedChild: function(bodyRules) {
        var rule;
        if (!bodyRules) {
            return false;
        }
        for (var r = 0; r < bodyRules.length; r++) {
            rule = bodyRules[r];
            if (rule.isSilent && rule.isSilent(this._context) && !rule.blocksVisibility()) {
                //the atrule contains something that was referenced (likely by extend)
                //therefore it needs to be shown in output too
                return true;
            }
        }
        return false;
    },

    keepOnlyVisibleChilds: function(owner) {
        if (owner && owner.rules) {
            owner.rules = owner.rules.filter(function(thing) {
                return thing.isVisible();
            });
        }
    },

    isEmpty: function(owner) {
        return (owner && owner.rules)
            ? (owner.rules.length === 0) : true;
    },

    hasVisibleSelector: function(rulesetNode) {
        return (rulesetNode && rulesetNode.paths)
            ? (rulesetNode.paths.length > 0) : false;
    },

    resolveVisibility: function (node, originalRules) {
        if (!node.blocksVisibility()) {
            if (this.isEmpty(node) && !this.containsSilentNonBlockedChild(originalRules)) {
                return ;
            }

            return node;
        }

        var compiledRulesBody = node.rules[0];
        this.keepOnlyVisibleChilds(compiledRulesBody);

        if (this.isEmpty(compiledRulesBody)) {
            return ;
        }

        node.ensureVisibility();
        node.removeVisibilityBlock();

        return node;
    },

    isVisibleRuleset: function(rulesetNode) {
        if (rulesetNode.firstRoot) {
            return true;
        }

        if (this.isEmpty(rulesetNode)) {
            return false;
        }

        if (!rulesetNode.root && !this.hasVisibleSelector(rulesetNode)) {
            return false;
        }

        return true;
    }

};

var ToCSSVisitor = function(context) {
    this._visitor = new Visitor(this);
    this._context = context;
    this.utils = new CSSVisitorUtils(context);
};

ToCSSVisitor.prototype = {
    isReplacing: true,
    run: function (root) {
        return this._visitor.visit(root);
    },

    visitDeclaration: function (declNode, visitArgs) {
        if (declNode.blocksVisibility() || declNode.variable) {
            return;
        }
        return declNode;
    },

    visitMixinDefinition: function (mixinNode, visitArgs) {
        // mixin definitions do not get eval'd - this means they keep state
        // so we have to clear that state here so it isn't used if toCSS is called twice
        mixinNode.frames = [];
    },

    visitExtend: function (extendNode, visitArgs) {
    },

    visitComment: function (commentNode, visitArgs) {
        if (commentNode.blocksVisibility() || commentNode.isSilent(this._context)) {
            return;
        }
        return commentNode;
    },

    visitMedia: function(mediaNode, visitArgs) {
        var originalRules = mediaNode.rules[0].rules;
        mediaNode.accept(this._visitor);
        visitArgs.visitDeeper = false;

        return this.utils.resolveVisibility(mediaNode, originalRules);
    },

    visitImport: function (importNode, visitArgs) {
        if (importNode.blocksVisibility()) {
            return ;
        }
        return importNode;
    },

    visitAtRule: function(atRuleNode, visitArgs) {
        if (atRuleNode.rules && atRuleNode.rules.length) {
            return this.visitAtRuleWithBody(atRuleNode, visitArgs);
        } else {
            return this.visitAtRuleWithoutBody(atRuleNode, visitArgs);
        }
    },

    visitAtRuleWithBody: function(atRuleNode, visitArgs) {
        //if there is only one nested ruleset and that one has no path, then it is
        //just fake ruleset
        function hasFakeRuleset(atRuleNode) {
            var bodyRules = atRuleNode.rules;
            return bodyRules.length === 1 && (!bodyRules[0].paths || bodyRules[0].paths.length === 0);
        }
        function getBodyRules(atRuleNode) {
            var nodeRules = atRuleNode.rules;
            if (hasFakeRuleset(atRuleNode)) {
                return nodeRules[0].rules;
            }

            return nodeRules;
        }
        //it is still true that it is only one ruleset in array
        //this is last such moment
        //process childs
        var originalRules = getBodyRules(atRuleNode);
        atRuleNode.accept(this._visitor);
        visitArgs.visitDeeper = false;

        if (!this.utils.isEmpty(atRuleNode)) {
            this._mergeRules(atRuleNode.rules[0].rules);
        }

        return this.utils.resolveVisibility(atRuleNode, originalRules);
    },

    visitAtRuleWithoutBody: function(atRuleNode, visitArgs) {
        if (atRuleNode.blocksVisibility()) {
            return;
        }

        if (atRuleNode.name === "@charset") {
            // Only output the debug info together with subsequent @charset definitions
            // a comment (or @media statement) before the actual @charset atrule would
            // be considered illegal css as it has to be on the first line
            if (this.charset) {
                if (atRuleNode.debugInfo) {
                    var comment = new tree.Comment("/* " + atRuleNode.toCSS(this._context).replace(/\n/g, "") + " */\n");
                    comment.debugInfo = atRuleNode.debugInfo;
                    return this._visitor.visit(comment);
                }
                return;
            }
            this.charset = true;
        }

        return atRuleNode;
    },

    checkValidNodes: function(rules, isRoot) {
        if (!rules) {
            return;
        }

        for (var i = 0; i < rules.length; i++) {
            var ruleNode = rules[i];
            if (isRoot && ruleNode instanceof tree.Declaration && !ruleNode.variable) {
                throw { message: "Properties must be inside selector blocks. They cannot be in the root",
                    index: ruleNode.getIndex(), filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename};
            }
            if (ruleNode instanceof tree.Call) {
                throw { message: "Function '" + ruleNode.name + "' is undefined",
                    index: ruleNode.getIndex(), filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename};
            }
            if (ruleNode.type && !ruleNode.allowRoot) {
                throw { message: ruleNode.type + " node returned by a function is not valid here",
                    index: ruleNode.getIndex(), filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename};
            }
        }
    },

    visitRuleset: function (rulesetNode, visitArgs) {
        //at this point rulesets are nested into each other
        var rule, rulesets = [];

        this.checkValidNodes(rulesetNode.rules, rulesetNode.firstRoot);

        if (!rulesetNode.root) {
            //remove invisible paths
            this._compileRulesetPaths(rulesetNode);

            // remove rulesets from this ruleset body and compile them separately
            var nodeRules = rulesetNode.rules, nodeRuleCnt = nodeRules ? nodeRules.length : 0;
            for (var i = 0; i < nodeRuleCnt; ) {
                rule = nodeRules[i];
                if (rule && rule.rules) {
                    // visit because we are moving them out from being a child
                    rulesets.push(this._visitor.visit(rule));
                    nodeRules.splice(i, 1);
                    nodeRuleCnt--;
                    continue;
                }
                i++;
            }
            // accept the visitor to remove rules and refactor itself
            // then we can decide nogw whether we want it or not
            // compile body
            if (nodeRuleCnt > 0) {
                rulesetNode.accept(this._visitor);
            } else {
                rulesetNode.rules = null;
            }
            visitArgs.visitDeeper = false;

        } else { //if (! rulesetNode.root) {
            rulesetNode.accept(this._visitor);
            visitArgs.visitDeeper = false;
        }

        if (rulesetNode.rules) {
            this._mergeRules(rulesetNode.rules);
            this._removeDuplicateRules(rulesetNode.rules);
        }

        //now decide whether we keep the ruleset
        if (this.utils.isVisibleRuleset(rulesetNode)) {
            rulesetNode.ensureVisibility();
            rulesets.splice(0, 0, rulesetNode);
        }

        if (rulesets.length === 1) {
            return rulesets[0];
        }
        return rulesets;
    },

    _compileRulesetPaths: function(rulesetNode) {
        if (rulesetNode.paths) {
            rulesetNode.paths = rulesetNode.paths
                .filter(function(p) {
                    var i;
                    if (p[0].elements[0].combinator.value === ' ') {
                        p[0].elements[0].combinator = new(tree.Combinator)('');
                    }
                    for (i = 0; i < p.length; i++) {
                        if (p[i].isVisible() && p[i].getIsOutput()) {
                            return true;
                        }
                    }
                    return false;
                });
        }
    },

    _removeDuplicateRules: function(rules) {
        if (!rules) { return; }

        // remove duplicates
        var ruleCache = {},
            ruleList, rule, i;

        for (i = rules.length - 1; i >= 0 ; i--) {
            rule = rules[i];
            if (rule instanceof tree.Declaration) {
                if (!ruleCache[rule.name]) {
                    ruleCache[rule.name] = rule;
                } else {
                    ruleList = ruleCache[rule.name];
                    if (ruleList instanceof tree.Declaration) {
                        ruleList = ruleCache[rule.name] = [ruleCache[rule.name].toCSS(this._context)];
                    }
                    var ruleCSS = rule.toCSS(this._context);
                    if (ruleList.indexOf(ruleCSS) !== -1) {
                        rules.splice(i, 1);
                    } else {
                        ruleList.push(ruleCSS);
                    }
                }
            }
        }
    },

    _mergeRules: function(rules) {
        if (!rules) {
            return;
        }

        var groups    = {},
            groupsArr = [];

        for (var i = 0; i < rules.length; i++) {
            var rule = rules[i];
            if (rule.merge) {
                var key = rule.name;
                groups[key] ? rules.splice(i--, 1) :
                    groupsArr.push(groups[key] = []);
                groups[key].push(rule);
            }
        }

        groupsArr.forEach(function(group) {
            if (group.length > 0) {
                var result = group[0],
                    space  = [],
                    comma  = [new tree.Expression(space)];
                group.forEach(function(rule) {
                    if ((rule.merge === '+') && (space.length > 0)) {
                        comma.push(new tree.Expression(space = []));
                    }
                    space.push(rule.value);
                    result.important = result.important || rule.important;
                });
                result.value = new tree.Value(comma);
            }
        });
    },

    visitAnonymous: function(anonymousNode, visitArgs) {
        if (anonymousNode.blocksVisibility()) {
            return ;
        }
        anonymousNode.accept(this._visitor);
        return anonymousNode;
    }
};

module.exports = ToCSSVisitor;
<|endoftext|>


<commit_before>// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html

module.exports = function (config) {
  config.set({
    basePath: '',
    frameworks: ['jasmine', '@angular-devkit/build-angular'],
    plugins: [
      require('karma-jasmine'),
      require('karma-chrome-launcher'),
      require('karma-jasmine-html-reporter'),
      require('karma-coverage-istanbul-reporter'),
      require('@angular-devkit/build-angular/plugins/karma')
    ],
    client: {
      clearContext: false // leave Jasmine Spec Runner output visible in browser
    },
    coverageIstanbulReporter: {
      dir: require('path').join(__dirname, '../../coverage'),
      reports: ['html', 'lcovonly'],
      fixWebpackSourcePaths: true
    },
    reporters: ['progress', 'kjhtml'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ['Chrome'],

    //--- Custom Config for Travis CI ---
    customLaunchers: {
      ChromeNoSandbox: {
        base: 'Chrome',
        flags: ['--no-sandbox']
      }
    },
    //---

    singleRun: false
  });
};
<commit_msg>Using ChromeHeadless and automatically switch to it in CI<commit_after>// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html

module.exports = function (config) {
  config.set({
    basePath: '',
    frameworks: ['jasmine', '@angular-devkit/build-angular'],
    plugins: [
      require('karma-jasmine'),
      require('karma-chrome-launcher'),
      require('karma-jasmine-html-reporter'),
      require('karma-coverage-istanbul-reporter'),
      require('@angular-devkit/build-angular/plugins/karma')
    ],
    client: {
      clearContext: false // leave Jasmine Spec Runner output visible in browser
    },
    coverageIstanbulReporter: {
      dir: require('path').join(__dirname, '../../coverage'),
      reports: ['html', 'lcovonly'],
      fixWebpackSourcePaths: true
    },
    reporters: ['progress', 'kjhtml'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: process.env.CI
      ? ['ChromeCi']
      : ['ChromeNoSandbox'],

    //--- Custom Config for Travis CI ---
    customLaunchers: {
      ChromeCi: {
        base: 'ChromeHeadless',
        flags: [
          '--no-sandbox'
        ]
      },
      ChromeNoSandbox: {
        base: 'Chrome',
        flags: ['--no-sandbox']
      }
    },
    //---

    singleRun: false
  });
};
<|endoftext|>


<commit_before>'use strict';

const loopback = require('loopback');
const boot = require('loopback-boot');
const logger = require('./services/winston-config')();

const app = module.exports = loopback();

app.start = function () {
  // start the web server
  return app.listen(function () {
    app.emit('started');
    const baseUrl = app.get('url').replace(/\/$/, '');
    logger.log('Web server listening at: %s', baseUrl); //eslint-disable-line no-console
    if (app.get('loopback-component-explorer')) {
      const explorerPath = app.get('loopback-component-explorer').mountPath;
      logger.log('Browse your REST API at %s%s', baseUrl, explorerPath); //eslint-disable-line
    }
  });
};

// Bootstrap the application, configure models, datasources and middleware.
// Sub-apps like REST API are mounted via boot scripts.
boot(app, __dirname, function (err) {
  if (err) {throw err;}

  // start the server if `$ node server.js`
  if (require.main === module) {
    app.start();
  }
});
<commit_msg>Remove useless eslint-disable-line<commit_after>'use strict';

const loopback = require('loopback');
const boot = require('loopback-boot');
const logger = require('./services/winston-config')();

const app = module.exports = loopback();

app.start = function () {
  // start the web server
  return app.listen(function () {
    app.emit('started');
    const baseUrl = app.get('url').replace(/\/$/, '');
    logger.log('Web server listening at: %s', baseUrl);
    if (app.get('loopback-component-explorer')) {
      const explorerPath = app.get('loopback-component-explorer').mountPath;
      logger.log('Browse your REST API at %s%s', baseUrl, explorerPath);
    }
  });
};

// Bootstrap the application, configure models, datasources and middleware.
// Sub-apps like REST API are mounted via boot scripts.
boot(app, __dirname, function (err) {
  if (err) {throw err;}

  // start the server if `$ node server.js`
  if (require.main === module) {
    app.start();
  }
});
<|endoftext|>


<commit_before><commit_msg>Multi process recomputation<commit_after><|endoftext|>


<commit_before>import ExportsStorage from '../ExportsStorage';

let subject;

beforeEach(() => {
  subject = new ExportsStorage(process.cwd());
  return subject.init(':memory:');
});

afterEach(() => subject.close());

it('can add default exports', () =>
  subject.upsert({
    name: 'Foo',
    pathToFile: './lib/ExportsStorage.js',
    isDefault: true,
  }).then(() =>
    subject.get('Foo').then((rows) => {
      expect(rows.length).toEqual(1);
      expect(rows[0].path).toEqual('./lib/ExportsStorage.js');
      expect(rows[0].name).toEqual('default');
    })
  ));

it('can add non-default exports', () =>
  subject.upsert({
    name: 'Bar',
    pathToFile: './lib/ExportsStorage.js',
    isDefault: false,
  }).then(() =>
    subject.get('Bar').then((rows) => {
      expect(rows.length).toEqual(1);
      expect(rows[0].path).toEqual('./lib/ExportsStorage.js');
      expect(rows[0].name).toEqual('Bar');
    })
  ));

it('updates existing entries', () =>
  subject.upsert({
    name: 'Bar',
    pathToFile: './lib/ExportsStorage.js',
    isDefault: false,
  }).then(() =>
    subject.upsert({
      name: 'bar',
      pathToFile: './lib/ExportsStorage.js',
      isDefault: false,
    }).then(() =>
      subject.get('Bar').then((rows) => {
        expect(rows.length).toEqual(1);
        expect(rows[0].path).toEqual('./lib/ExportsStorage.js');
        expect(rows[0].name).toEqual('bar');
      })
    )
  ));

it('can remove entries', () =>
  subject.upsert({
    name: 'Bar',
    pathToFile: './lib/ExportsStorage.js',
    isDefault: false,
  }).then(() =>
    subject.remove('./lib/ExportsStorage.js').then(() =>
      subject.get('Bar').then((rows) => {
        expect(rows.length).toEqual(0);
      })
    )
  ));

it('removes old entries on update', () =>
  subject.update({
    names: ['foo', 'Bar'],
    defaultName: 'bazgraz',
    pathToFile: './bazgraz.js',
  }).then(() =>
    subject.get('Bar').then((rows) => {
      expect(rows.length).toEqual(1);
      return subject.update({
        names: ['foo'],
        defaultName: 'bazgraz',
        pathToFile: './bazgraz.js',
      }).then(() =>
        subject.get('Bar').then((rows) => {
          expect(rows.length).toEqual(0);
        }));
    })
  ));

it('can check a lot of files if they need updating', () => {
  const files = [];
  for (let i = 0; i < 1000; i++) {
    files.push({ path: `./foo-${i}.js`, mtime: i });
  }
  return subject.needsUpdate(files);
});
<commit_msg>Fix ExportStorage test<commit_after>import ExportsStorage from '../ExportsStorage';

let subject;

beforeEach(() => {
  subject = new ExportsStorage(process.cwd());
  return subject.init(':memory:');
});

afterEach(() => subject.close());

it('can add default exports', () =>
  subject.upsert({
    name: 'Foo',
    pathToFile: './lib/ExportsStorage.js',
    isDefault: true,
  }).then(() =>
    subject.get('Foo').then((rows) => {
      expect(rows.length).toEqual(1);
      expect(rows[0].path).toEqual('./lib/ExportsStorage.js');
      expect(rows[0].name).toEqual('default');
    })
  ));

it('can add non-default exports', () =>
  subject.upsert({
    name: 'Bar',
    pathToFile: './lib/ExportsStorage.js',
    isDefault: false,
  }).then(() =>
    subject.get('Bar').then((rows) => {
      expect(rows.length).toEqual(1);
      expect(rows[0].path).toEqual('./lib/ExportsStorage.js');
      expect(rows[0].name).toEqual('Bar');
    })
  ));

it('updates existing entries', () =>
  subject.upsert({
    name: 'Bar',
    pathToFile: './lib/ExportsStorage.js',
    isDefault: false,
  }).then(() =>
    subject.upsert({
      name: 'bar',
      pathToFile: './lib/ExportsStorage.js',
      isDefault: false,
    }).then(() =>
      subject.get('Bar').then((rows) => {
        expect(rows.length).toEqual(1);
        expect(rows[0].path).toEqual('./lib/ExportsStorage.js');
        expect(rows[0].name).toEqual('bar');
      })
    )
  ));

it('can remove entries', () =>
  subject.upsert({
    name: 'Bar',
    pathToFile: './lib/ExportsStorage.js',
    isDefault: false,
  }).then(() =>
    subject.remove('./lib/ExportsStorage.js').then(() =>
      subject.get('Bar').then((rows) => {
        expect(rows.length).toEqual(0);
      })
    )
  ));

it('removes old entries on update', () =>
  subject.update({
    names: ['foo', 'Bar'],
    defaultNames: ['bazgraz'],
    pathToFile: './bazgraz.js',
  }).then(() =>
    subject.get('Bar').then((rows) => {
      expect(rows.length).toEqual(1);
      return subject.update({
        names: ['foo'],
        defaultNames: ['bazgraz'],
        pathToFile: './bazgraz.js',
      }).then(() =>
        subject.get('Bar').then((rows) => {
          expect(rows.length).toEqual(0);
        }));
    })
  ));

it('can check a lot of files if they need updating', () => {
  const files = [];
  for (let i = 0; i < 1000; i++) {
    files.push({ path: `./foo-${i}.js`, mtime: i });
  }
  return subject.needsUpdate(files);
});
<|endoftext|>


<commit_before>/*global require, __dirname */

var WEB = __dirname + '/../web';

var rjs = (function () {
    var requirejs = require('requirejs');

    return {
        optimize: function (config, callback) {
            requirejs.optimize(config, function () {
                if (typeof callback === 'function') {
                    callback();
                }
            });
        },

        convert: function (input, output) {
            var cmd = '"' + process.execPath + '" node_modules/requirejs/bin/r.js -convert "' + input + '" "' + output + '"';

            require('child_process').execSync(cmd);
        }
    };
}());

var extend = (function () {
    var slice = Array.prototype.slice;

    return function (target) {
        var i, length, object, key,
            objects = slice.call(arguments, 1);

        for (i = 0, length = objects.length; i < length; ++i) {
            object = objects[i];

            for (key in object) {
                if (object.hasOwnProperty(key)) {
                    target[key] = object[key];
                }
            }
        }

        return target;
    };
}());

var build = (function () {
    var baseConfig, mainConfig;

    baseConfig = {
        baseUrl: WEB + '/js',
        findNestedDependencies: false,
        preserveLicenseComments: false
    };

    mainConfig = require(WEB + '/js/config')({
        build: true
    });

    return function (name, config) {
        if (name instanceof Array) {
            var i, length;

            for (i = 0, length = name.length; i < length; ++i) {
                build(name[i], config);
            }
        } else {
            rjs.optimize(extend({
                name: name,
                out: WEB + '/js/dist/' + name + '.min.js'
            }, baseConfig, mainConfig, config), function () {
                console.log('module ' + name + ' builded');
            });
        }
    };
}());

var uglify = (function () {
    var UglifyJS = require('uglify-js'),
        fs = require('fs');

    return function (relativePath, out) {
        var absolutePath = WEB + '/' + relativePath,
            result = UglifyJS.minify([absolutePath]);

        if (out) {
            out = WEB + '/' + out;
        } else {
            out = absolutePath.replace(/\.js$/, '.min.js');
        }

        fs.writeFile(out, result.code, function () {
            console.log('file ' + relativePath + ' uglified');
        });
    };
}());

rjs.convert('web/vendor/phpjs/src', 'web/vendor/phpjs/requirejs');

build('athorrent', {
    include: ['bootstrap']
});

build(['files', 'torrents', 'sharings', 'users'], {
    exclude: ['athorrent']
});

uglify('js/config.js', 'js/dist/config.min.js');
uglify('vendor/requirejs/require.js');
<commit_msg>search.js need to be build<commit_after>/*global require, __dirname */

var WEB = __dirname + '/../web';

var rjs = (function () {
    var requirejs = require('requirejs');

    return {
        optimize: function (config, callback) {
            requirejs.optimize(config, function () {
                if (typeof callback === 'function') {
                    callback();
                }
            });
        },

        convert: function (input, output) {
            var cmd = '"' + process.execPath + '" node_modules/requirejs/bin/r.js -convert "' + input + '" "' + output + '"';

            require('child_process').execSync(cmd);
        }
    };
}());

var extend = (function () {
    var slice = Array.prototype.slice;

    return function (target) {
        var i, length, object, key,
            objects = slice.call(arguments, 1);

        for (i = 0, length = objects.length; i < length; ++i) {
            object = objects[i];

            for (key in object) {
                if (object.hasOwnProperty(key)) {
                    target[key] = object[key];
                }
            }
        }

        return target;
    };
}());

var build = (function () {
    var baseConfig, mainConfig;

    baseConfig = {
        baseUrl: WEB + '/js',
        findNestedDependencies: false,
        preserveLicenseComments: false
    };

    mainConfig = require(WEB + '/js/config')({
        build: true
    });

    return function (name, config) {
        if (name instanceof Array) {
            var i, length;

            for (i = 0, length = name.length; i < length; ++i) {
                build(name[i], config);
            }
        } else {
            rjs.optimize(extend({
                name: name,
                out: WEB + '/js/dist/' + name + '.min.js'
            }, baseConfig, mainConfig, config), function () {
                console.log('module ' + name + ' builded');
            });
        }
    };
}());

var uglify = (function () {
    var UglifyJS = require('uglify-js'),
        fs = require('fs');

    return function (relativePath, out) {
        var absolutePath = WEB + '/' + relativePath,
            result = UglifyJS.minify([absolutePath]);

        if (out) {
            out = WEB + '/' + out;
        } else {
            out = absolutePath.replace(/\.js$/, '.min.js');
        }

        fs.writeFile(out, result.code, function () {
            console.log('file ' + relativePath + ' uglified');
        });
    };
}());

rjs.convert('web/vendor/phpjs/src', 'web/vendor/phpjs/requirejs');

build('athorrent', {
    include: ['bootstrap']
});

build(['files', 'search', 'torrents', 'sharings', 'users'], {
    exclude: ['athorrent']
});

uglify('js/config.js', 'js/dist/config.min.js');
uglify('vendor/requirejs/require.js');
<|endoftext|>