<commit_before>/**
 * backbone-relational-views.js 0.1.1
 * (c) 2013 Santanu Basu
 *
 * Dependencies:
 *
 * Backbone (https://github.com/documentcloud/backbone)
 * Underscore (https://github.com/jashkenas/underscore/)
 * Backbone-Relational (https://github.com/PaulUithol/Backbone-relational)
 */

define([
    "backbone",
    "underscore",
    "jquery"
], function (bb, us, $) {

    /*
    Sample spec: [{path:"a.b"}, {path:"c", order:-1}]
    Currently, this builder only handles direct paths into simple objects, dotted notation does not traverse relationships
    */
    var buildModelComparator = function (spec) {
        for (var i = 0; i<spec.length; i++) {
            var rule = spec[i];
            rule.get = eval("(function(o) { return o.attributes." + rule.path + ";})");
            if (us.isUndefined(rule.order)) {
                rule.order = 1;
            }
        }
        return function (a, b) {
            var udefa = us.isUndefined(a);
            var udefb = us.isUndefined(b);
            if (udefa&&!udefb) {
                return 1;
            }
            else if (udefb&&!udefa) {
                return -1;
            }
            else if (udefa&&udefb) {
                return 0;
            }
            for (var i = 0; i<spec.length; i++) {
                var rule = spec[i];
                if (rule.get(a)<rule.get(b)) {
                    return rule.order;
                }
                else if (rule.get(a)>rule.get(b)) {
                    return -rule.order;
                }
            }
            return 0;
        }
    };

    bb.RelationalView = bb.View.extend({
        defaultConfig: {
            subviewConfigs: {}
        },
        initialize: function (options) {
            options = $.extend(true, {
                render:true,
                subviews:{}
            }, options);
            if (!this.model) {
                this.model = new bb.RelationalModel();
            }
            this.config = this.normalizeConfig($.extend(true, {}, this.defaultConfig, us.pick(options, ["template", "getTemplate", "getEl", "subviewConfigs"])));
            this.subviews = {};
            this.viewState = {};
            this.createSubviews();
            for (var key in options.subviews) {
                this.setSubview(key, options.subviews[key]);
            }
            this.setupEventHandlers();
            if (options.render) {
                this.render();
            }
        },
        getModelId:function(model) {
            return "id" in model?model.id:model.cid;
        },
        setupEventHandlers:function() {
            var thiz = this;
            var batchRender = (function(thiz) {
                var batched = false;
                function render() {
                    if (batched) {
                        thiz.render();
                        batched = false;
                    }
                }
                return function() {
                    batched = true;
                    us.defer(render);
                }
            })(this);
            this.listenTo(this.model, "change", function (model, options) {
                batchRender();
            });
            this.model.getRelations().forEach(function(relation) {
                if (relation instanceof bb.HasMany) {
                    thiz.listenTo(thiz.model.get(relation.key), "sort", function (model, collection, options) {
                        batchRender();
                    });
                    thiz.listenTo(thiz.model.get(relation.key), "relational:add", function (model, collection, options) {
                        var index = collection.indexOf(model);
                        this.createCollectionSubview(relation.key, index, model);
                        batchRender();
                    });
                    thiz.listenTo(thiz.model.get(relation.key), "relational:remove", function (model, collection, options) {
                        this.deleteCollectionSubview(relation.key, this.getModelId(model), options.index);
                        batchRender();
                    });
                    thiz.listenTo(thiz.model.get(relation.key), "sort", function (model, collection, options) {
                        batchRender();
                    });
                }
                else {
                    thiz.listenTo(thiz.model, "relational:change:"+relation.key, function (model, options) {
                        var oldModel = model._previousAttributes[relation.key];
                        var newModel = model.attributes[relation.key];
                        if (oldModel===newModel) {
                            return;
                        }
                        if (oldModel!=null) {
                            this.deleteDirectSubview(relation.key)
                        }
                        if (newModel!=null) {
                            this.createDirectSubview(relation.key, newModel)
                        }
                        batchRender();
                    });
                }
            });
        },
        normalizeSubviewConfig: function (config) {
            var normalizedConfig = $.extend(true, {}, config);
            if (normalizedConfig.viewType) {
                if (!(normalizedConfig.viewType.prototype instanceof bb.RelationalView)) {
                    console.warn("A viewType was defined for a subview config, but it is not a RelationalView, reverting to using RelationalView as the viewType.");
                    normalizedConfig.viewType = bb.RelationalView;
                }
            }
            else {
                normalizedConfig.viewType = bb.RelationalView;
            }
            if (us.isUndefined(normalizedConfig.getViewType)) {
                normalizedConfig.getViewType = function() {
                    return normalizedConfig.viewType;
                };
            }
            return normalizedConfig;
        },
        normalizeConfig: function (config) {
            var thiz = this;
            var normalizedConfig = $.extend(true, {}, config);
            for (var key in normalizedConfig.subviewConfigs) {
                normalizedConfig.subviewConfigs[key] = this.normalizeSubviewConfig(normalizedConfig.subviewConfigs[key]);
            }
            if (us.isUndefined(normalizedConfig.template)) {
                normalizedConfig.template = function (it) {
                    return "";
                };
            }
            if (us.isUndefined(normalizedConfig.getTemplate)) {
                normalizedConfig.getTemplate = function () {
                    return normalizedConfig.template;
                };
            }
            if (us.isUndefined(normalizedConfig.getEl)) {
                normalizedConfig.getEl = function () {
                    return thiz.$el;
                };
            }
            return normalizedConfig;
        },
        destroy: function () {
            this.$el.empty();
            this.stopListening();
            this.undelegateEvents();
            for (var key in this.subviews) {
                var value = this.subviews[key];
                if (value instanceof bb.RelationalView) {
                    var subview = value;
                    subview.destroy();
                }
                else {
                    for (var subviewKey in value) {
                        value[subviewKey].destroy();
                    }
                }
            }
        },
        createSubviews: function () {
            for (var key in this.model.attributes) {
                var value = this.model.attributes[key];
                if (us.isUndefined(value)||us.isNull(value)) {
                    continue;
                }
                var relation = this.model.getRelation(key);
                if (us.isUndefined(relation)) {
                    continue;
                }
                if (relation instanceof bb.HasMany) {
                    var collection = value;
                    this.subviews[key] = {};
                    for (var i = 0; i<collection.models.length; i++) {
                        var model = collection.at(i);
                        this.createCollectionSubview(key, i, model);
                    }
                }
                else {
                    this.createDirectSubview(key, value);
                }
            }
        },
        createDirectSubview: function(key, model) {
            if (key in this.subviews) {
                console.warn("Cannot create a direct subview for key " + key + " because one already exists.");
                return;
            }
            var subview = this.subviews[key];
            if (!(key in this.config.subviewConfigs)) {
                return;
            }
            var subviewConfig = this.config.subviewConfigs[key];
            var viewType = subviewConfig.getViewType.call(this, model);
            subview = new viewType({
                model:model,
                template:subviewConfig.template,
                getTemplate:subviewConfig.getTemplate
            });
            this.subviews[key] = subview;
        },
        createCollectionSubview: function(key, index, model) {
            if (!(key in this.config.subviewConfigs)) {
                return;
            }
            var subviewConfig = this.config.subviewConfigs[key];
            var viewType = subviewConfig.getViewType.call(this, model, index);
            var subview = new viewType({
                model: model,
                template:subviewConfig.template,
                getTemplate:subviewConfig.getTemplate
            });
            var modelId = this.getModelId(model);
            this.subviews[key][modelId] = subview;

        },
        deleteDirectSubview: function (key) {
            var subview = this.subviews[key];
            if (subview) {
                subview.destroy();
                delete this.subviews[key];
            }
        },
        deleteCollectionSubview: function (key, modelId) {
            var subviews = this.subviews[key];
            if (subviews) {
                var subview = subviews[modelId];
                delete subviews[modelId];
                if (subview) {
                    subview.destroy();
                }
            }
        },
        setSubview:function(key, subview) {
            if (key in this.config.subviewConfigs) {
                console.warn("You are manually setting a subview on key \""+key+"\" but a subview configuration already exists for this key.  Your subview may be overwritten as a result of model state changes.");
            }
            if (key in this.subviews) {
                this.subviews[key].remove();
            }
            this.subviews[key] = subview;
            if (this.model.has(key)) {
                console.warn("You are manually setting a subview on key \""+key+"\" but a submodel already exists for this key.  This submodel will be overwritten by the model of the subview.");
            }
            this.model.set(key, subview.model, {
                silent:true
            });
        },
        deferredPostRender: function() {
            var thiz = this;
            us.defer(function () {
                thiz.postRender();
            });
        },
        postRender: function () {
        },
        preRender: function () {
        },
        render: function () {
            var thiz = this;
            this.preRender();
            var proxyAttributes = $.extend({}, this.model.attributes, this.viewState);
            for (var key in proxyAttributes) {
                var attribute = proxyAttributes[key];
                var markup = "
";
                if (attribute instanceof bb.Model) {
                    proxyAttributes[key] = markup;
                }
                else if (attribute instanceof bb.Collection) {
                    proxyAttributes[key] = attribute.map(function(model, index) {
                        return "
";
                    });
                }
            }

            proxyAttributes.this = this;
            var template = this.config.getTemplate.call(this, this.model);
            var $proxyEl = $(template(proxyAttributes));
            $proxyEl.attr("modelId", this.getModelId(this.model));

            for (var key in this.subviews) {
                var value = this.subviews[key];
                if (value instanceof bb.RelationalView) {
                    var subview = value;
                    subview.$el.attr("dataKey", key);
                    $proxyEl.find("div[dataKey=\"" + key + "\"]").replaceWith(subview.$el);
                }
                else {
                    var subviews = value;
                    var submodelCollection = this.model.get(key);
                    $proxyEl.find("div[dataKey=\"" + key + "\"]").replaceWith(function(index) {
                        var submodel = submodelCollection.at(index);
                        return subviews[thiz.getModelId(submodel)].$el;
                    })
                }
            }

            var $oldEl = this.config.getEl();
            this.setElement($proxyEl);
            $oldEl.replaceWith($proxyEl);

            this.deferredPostRender();
            return this;
        }
    });

    return {
        buildComparator: buildModelComparator,
        RelationalView: bb.RelationalView
    }

});
<commit_msg>View event listener setup hook, invoked on render<commit_after>/**
 * backbone-relational-views.js 0.1.1
 * (c) 2013 Santanu Basu
 *
 * Dependencies:
 *
 * Backbone (https://github.com/documentcloud/backbone)
 * Underscore (https://github.com/jashkenas/underscore/)
 * Backbone-Relational (https://github.com/PaulUithol/Backbone-relational)
 */

define([
    "backbone",
    "underscore",
    "jquery"
], function (bb, us, $) {

    /*
    Sample spec: [{path:"a.b"}, {path:"c", order:-1}]
    Currently, this builder only handles direct paths into simple objects, dotted notation does not traverse relationships
    */
    var buildModelComparator = function (spec) {
        for (var i = 0; i<spec.length; i++) {
            var rule = spec[i];
            rule.get = eval("(function(o) { return o.attributes." + rule.path + ";})");
            if (us.isUndefined(rule.order)) {
                rule.order = 1;
            }
        }
        return function (a, b) {
            var udefa = us.isUndefined(a);
            var udefb = us.isUndefined(b);
            if (udefa&&!udefb) {
                return 1;
            }
            else if (udefb&&!udefa) {
                return -1;
            }
            else if (udefa&&udefb) {
                return 0;
            }
            for (var i = 0; i<spec.length; i++) {
                var rule = spec[i];
                if (rule.get(a)<rule.get(b)) {
                    return rule.order;
                }
                else if (rule.get(a)>rule.get(b)) {
                    return -rule.order;
                }
            }
            return 0;
        }
    };

    bb.RelationalView = bb.View.extend({
        defaultConfig: {
            subviewConfigs: {}
        },
        initialize: function (options) {
            options = $.extend(true, {
                render:true,
                subviews:{}
            }, options);
            if (!this.model) {
                this.model = new bb.RelationalModel();
            }
            this.config = this.normalizeConfig($.extend(true, {}, this.defaultConfig, us.pick(options, ["template", "getTemplate", "getEl", "subviewConfigs"])));
            this.subviews = {};
            this.viewState = $.extend(true, {}, options.viewState);
            this.createSubviews();
            for (var key in options.subviews) {
                this.setSubview(key, options.subviews[key]);
            }
            this.setupModelEventHandlers();
            if (options.render) {
                this.render();
            }
        },
        getModelId:function(model) {
            return "id" in model?model.id:model.cid;
        },
        setupModelEventHandlers:function() {
            var thiz = this;
            var batchRender = (function(thiz) {
                var batched = false;
                function render() {
                    if (batched) {
                        thiz.render();
                        batched = false;
                    }
                }
                return function() {
                    batched = true;
                    us.defer(render);
                }
            })(this);
            this.listenTo(this.model, "change", function (model, options) {
                batchRender();
            });
            this.model.getRelations().forEach(function(relation) {
                if (relation instanceof bb.HasMany) {
                    thiz.listenTo(thiz.model.get(relation.key), "sort", function (model, collection, options) {
                        batchRender();
                    });
                    thiz.listenTo(thiz.model.get(relation.key), "relational:add", function (model, collection, options) {
                        var index = collection.indexOf(model);
                        this.createCollectionSubview(relation.key, index, model);
                        batchRender();
                    });
                    thiz.listenTo(thiz.model.get(relation.key), "relational:remove", function (model, collection, options) {
                        this.deleteCollectionSubview(relation.key, this.getModelId(model), options.index);
                        batchRender();
                    });
                    thiz.listenTo(thiz.model.get(relation.key), "sort", function (model, collection, options) {
                        batchRender();
                    });
                }
                else {
                    thiz.listenTo(thiz.model, "relational:change:"+relation.key, function (model, options) {
                        var oldModel = model._previousAttributes[relation.key];
                        var newModel = model.attributes[relation.key];
                        if (oldModel===newModel) {
                            return;
                        }
                        if (oldModel!=null) {
                            this.deleteDirectSubview(relation.key)
                        }
                        if (newModel!=null) {
                            this.createDirectSubview(relation.key, newModel)
                        }
                        batchRender();
                    });
                }
            });
        },
        normalizeSubviewConfig: function (config) {
            var normalizedConfig = $.extend(true, {}, config);
            if (normalizedConfig.viewType) {
                if (!(normalizedConfig.viewType.prototype instanceof bb.RelationalView)) {
                    console.warn("A viewType was defined for a subview config, but it is not a RelationalView, reverting to using RelationalView as the viewType.");
                    normalizedConfig.viewType = bb.RelationalView;
                }
            }
            else {
                normalizedConfig.viewType = bb.RelationalView;
            }
            if (us.isUndefined(normalizedConfig.getViewType)) {
                normalizedConfig.getViewType = function() {
                    return normalizedConfig.viewType;
                };
            }
            return normalizedConfig;
        },
        normalizeConfig: function (config) {
            var thiz = this;
            var normalizedConfig = $.extend(true, {}, config);
            for (var key in normalizedConfig.subviewConfigs) {
                normalizedConfig.subviewConfigs[key] = this.normalizeSubviewConfig(normalizedConfig.subviewConfigs[key]);
            }
            if (us.isUndefined(normalizedConfig.template)) {
                normalizedConfig.template = function (it) {
                    return "";
                };
            }
            if (us.isUndefined(normalizedConfig.getTemplate)) {
                normalizedConfig.getTemplate = function () {
                    return normalizedConfig.template;
                };
            }
            if (us.isUndefined(normalizedConfig.getEl)) {
                normalizedConfig.getEl = function () {
                    return thiz.$el;
                };
            }
            return normalizedConfig;
        },
        forAllSubviews:function(f) {
            for (var key in this.subviews) {
                var value = this.subviews[key];
                if (value instanceof bb.RelationalView) {
                    var subview = value;
                    f(key, subview);
                }
                else {
                    for (var subviewKey in value) {
                        f(subviewKey, value[subviewKey]);
                    }
                }
            }
        },
        destroy: function () {
            this.$el.empty();
            this.stopListening();
            this.undelegateEvents();
            this.forAllSubviews(function(key, view) {
                view.destroy();
            })
        },
        createSubviews: function () {
            for (var key in this.model.attributes) {
                var value = this.model.attributes[key];
                if (us.isUndefined(value)||us.isNull(value)) {
                    continue;
                }
                var relation = this.model.getRelation(key);
                if (us.isUndefined(relation)) {
                    continue;
                }
                if (relation instanceof bb.HasMany) {
                    var collection = value;
                    this.subviews[key] = {};
                    for (var i = 0; i<collection.models.length; i++) {
                        var model = collection.at(i);
                        this.createCollectionSubview(key, i, model);
                    }
                }
                else {
                    this.createDirectSubview(key, value);
                }
            }
        },
        createDirectSubview: function(key, model) {
            if (key in this.subviews) {
                console.warn("Cannot create a direct subview for key " + key + " because one already exists.");
                return;
            }
            var subview = this.subviews[key];
            if (!(key in this.config.subviewConfigs)) {
                return;
            }
            var subviewConfig = this.config.subviewConfigs[key];
            var viewType = subviewConfig.getViewType.call(this, model);
            subview = new viewType({
                model:model,
                template:subviewConfig.template,
                getTemplate:subviewConfig.getTemplate
            });
            this.subviews[key] = subview;
        },
        createCollectionSubview: function(key, index, model) {
            if (!(key in this.config.subviewConfigs)) {
                return;
            }
            var subviewConfig = this.config.subviewConfigs[key];
            var viewType = subviewConfig.getViewType.call(this, model, index);
            var subview = new viewType({
                model: model,
                template:subviewConfig.template,
                getTemplate:subviewConfig.getTemplate
            });
            var modelId = this.getModelId(model);
            this.subviews[key][modelId] = subview;

        },
        deleteDirectSubview: function (key) {
            var subview = this.subviews[key];
            if (subview) {
                subview.destroy();
                delete this.subviews[key];
            }
        },
        deleteCollectionSubview: function (key, modelId) {
            var subviews = this.subviews[key];
            if (subviews) {
                var subview = subviews[modelId];
                delete subviews[modelId];
                if (subview) {
                    subview.destroy();
                }
            }
        },
        setSubview:function(key, subview) {
            if (key in this.config.subviewConfigs) {
                console.warn("You are manually setting a subview on key \""+key+"\" but a subview configuration already exists for this key.  Your subview may be overwritten as a result of model state changes.");
            }
            if (key in this.subviews) {
                this.subviews[key].remove();
            }
            this.subviews[key] = subview;
            if (this.model.has(key)) {
                console.warn("You are manually setting a subview on key \""+key+"\" but a submodel already exists for this key.  This submodel will be overwritten by the model of the subview.");
            }
            this.model.set(key, subview.model, {
                silent:true
            });
        },
        deferredPostRender: function() {
            var thiz = this;
            us.defer(function () {
                thiz.postRender();
                thiz.setupAllEventHandlers();
            });
        },
        postRender: function () {
        },
        preRender: function () {
        },
        setupEventHandlers:function() {
            this.delegateEvents();
        },
        setupAllEventHandlers:function() {
            this.forAllSubviews(function(key, view) {
                view.setupAllEventHandlers();
            })
            this.setupEventHandlers();
        },
        render: function () {
            var thiz = this;
            this.preRender();
            var proxyAttributes = $.extend({}, this.model.attributes, this.viewState);
            for (var key in proxyAttributes) {
                var attribute = proxyAttributes[key];
                var markup = "
";
                if (attribute instanceof bb.Model) {
                    proxyAttributes[key] = markup;
                }
                else if (attribute instanceof bb.Collection) {
                    proxyAttributes[key] = attribute.map(function(model, index) {
                        return "
";
                    });
                }
            }

            proxyAttributes.this = this;
            var template = this.config.getTemplate.call(this, this.model);
            var $proxyEl = $(template(proxyAttributes));
            $proxyEl.attr("modelId", this.getModelId(this.model));

            for (var key in this.subviews) {
                var value = this.subviews[key];
                if (value instanceof bb.RelationalView) {
                    var subview = value;
                    subview.$el.attr("dataKey", key);
                    $proxyEl.find("div[dataKey=\"" + key + "\"]").replaceWith(subview.$el);
                }
                else {
                    var subviews = value;
                    var submodelCollection = this.model.get(key);
                    $proxyEl.find("div[dataKey=\"" + key + "\"]").replaceWith(function(index) {
                        var submodel = submodelCollection.at(index);
                        return subviews[thiz.getModelId(submodel)].$el;
                    })
                }
            }

            var $oldEl = this.config.getEl();
            this.setElement($proxyEl);
            $oldEl.replaceWith($proxyEl);

            this.deferredPostRender();
            return this;
        }
    });

    return {
        buildComparator: buildModelComparator,
        RelationalView: bb.RelationalView
    }

});
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2016, salesforce.com, inc.
 * All rights reserved.
 * Licensed under the BSD 3-Clause license.
 * For full license text, see LICENSE.txt file in the repo root or
 * https://opensource.org/licenses/BSD-3-Clause
 */

/**
 * tests/db/model/aspect/find.js
 */
'use strict'; // eslint-disable-line strict
const expect = require('chai').expect;
const tu = require('../../../testUtils');
const u = require('./utils');
const Aspect = tu.db.Aspect;
const Op = require('sequelize').Op;

describe('tests/db/model/aspect/find.js >', () => {
  before((done) => {
    u.createMedium()
    .then(() => {
      Aspect.create({
        name: 'luke',
        timeout: '1s',
        isPublished: true,
        tags: ['jedi', 'boring'],
      });
      Aspect.create({
        name: 'leia',
        timeout: '1m',
        isPublished: true,
        tags: ['princess', 'jedi'],
      });
    })
    .then(() => done())
    .catch(done);
  });

  after(u.forceDelete);

  describe('find by name >', () => {
    it('find by name, found', (done) => {
      Aspect.findOne({ where: { name: u.name } })
      .then((o) => expect(o).to.have.property('name', u.name))
      .then(() => done())
      .catch(done);
    });

    it('find by name, not found', (done) => {
      Aspect.findOne({ where: { name: 'x' } })
      .then((o) => expect(o).to.be.null)
      .then(() => done())
      .catch(done);
    });
  });

  it('find by tag, found', (done) => {
    Aspect.findAll({
      where: { tags: { [Op.contains]: ['jedi'] } },
    })
    .then((o) => expect(o).to.have.lengthOf(2))
    .then(() => Aspect.findAll({
      where: { tags: { [Op.contains]: ['boring'] } },
    }))
    .then((o) => expect(o).to.have.lengthOf(1))
    .then(() => Aspect.findAll({
      where: { tags: { [Op.contains]: ['father'] } },
    }))
    .then((o) => expect(o).to.be.empty)
    .then(() => done())
    .catch(done);
  });

  it('tags and related links in default scope', (done) => {
    Aspect.findAll()
    .then((o) => {
      for (let i = 0; i < o.length; i++) {
        const el = o[i];
        if (el.get({ plain: true }).tags === undefined) {
          throw new Error('expecting "tags" attribute');
        }

        if (el.get({ plain: true }).relatedLinks === undefined) {
          throw new Error('expecting "relatedLinks" attribute');
        }
      }

      done();
    })
    .catch(done);
  });

  it('returns correct profile access field name', (done) => {
    expect(Aspect.getProfileAccessField()).to.equal('aspectAccess');
    done();
  });
});
<commit_msg>flapper fix (#874)<commit_after>/**
 * Copyright (c) 2016, salesforce.com, inc.
 * All rights reserved.
 * Licensed under the BSD 3-Clause license.
 * For full license text, see LICENSE.txt file in the repo root or
 * https://opensource.org/licenses/BSD-3-Clause
 */

/**
 * tests/db/model/aspect/find.js
 */
'use strict'; // eslint-disable-line strict
const expect = require('chai').expect;
const tu = require('../../../testUtils');
const u = require('./utils');
const Aspect = tu.db.Aspect;
const Op = require('sequelize').Op;

describe('tests/db/model/aspect/find.js >', () => {
  before((done) => {
    u.createMedium()
    .then(() => Aspect.create({
      name: 'luke',
      timeout: '1s',
      isPublished: true,
      tags: ['jedi', 'boring'],
    }))
    .then(() => Aspect.create({
      name: 'leia',
      timeout: '1m',
      isPublished: true,
      tags: ['princess', 'jedi'],
    }))
    .then(() => done())
    .catch(done);
  });

  after(u.forceDelete);

  describe('find by name >', () => {
    it('find by name, found', (done) => {
      Aspect.findOne({ where: { name: u.name } })
      .then((o) => expect(o).to.have.property('name', u.name))
      .then(() => done())
      .catch(done);
    });

    it('find by name, not found', (done) => {
      Aspect.findOne({ where: { name: 'x' } })
      .then((o) => expect(o).to.be.null)
      .then(() => done())
      .catch(done);
    });
  });

  it('find by tag, found', (done) => {
    Aspect.findAll({
      where: { tags: { [Op.contains]: ['jedi'] } },
    })
    .then((o) => expect(o).to.have.lengthOf(2))
    .then(() => Aspect.findAll({
      where: { tags: { [Op.contains]: ['boring'] } },
    }))
    .then((o) => expect(o).to.have.lengthOf(1))
    .then(() => Aspect.findAll({
      where: { tags: { [Op.contains]: ['father'] } },
    }))
    .then((o) => expect(o).to.be.empty)
    .then(() => done())
    .catch(done);
  });

  it('tags and related links in default scope', (done) => {
    Aspect.findAll()
    .then((o) => {
      for (let i = 0; i < o.length; i++) {
        const el = o[i];
        if (el.get({ plain: true }).tags === undefined) {
          throw new Error('expecting "tags" attribute');
        }

        if (el.get({ plain: true }).relatedLinks === undefined) {
          throw new Error('expecting "relatedLinks" attribute');
        }
      }

      done();
    })
    .catch(done);
  });

  it('returns correct profile access field name', (done) => {
    expect(Aspect.getProfileAccessField()).to.equal('aspectAccess');
    done();
  });
});
<|endoftext|>


<commit_before>
function getCurrentTabUrl(callback) {
  var queryInfo = {
    active: true,
    currentWindow: true
  };

  chrome.tabs.query(queryInfo, function(tabs) {
    var tab = tabs[0];
    var url = tab.url;
    callback(url, tab);
  });
}

// Doing sick nasty raw-ish ajax request
function sendRequest(url, method, body, callback, errorCallback) {
  var x = new XMLHttpRequest();
  x.open(method, url);
    x.setRequestHeader('Accept', 'application/json');
    x.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
  x.onreadystatechange = function() {
    if (x.readyState == 4) {
      if (x.status >= 200 && x.status < 300) {
        callback(x);
      } else {
        errorCallback(x);
      }
    }
  }
  x.onerror = function() {
    errorCallback('Network error.');
  };
  if (body) {
    console.log("Sending body");
    x.send(JSON.stringify(body));
  } else {
    console.log("Sending no body");
    x.send();
  }
}

function renderStatus(statusText) {
  document.getElementById('status').innerHTML = statusText;
}

function renderBuilds(buildsHTML) {
  document.getElementById('builds').innerHTML = buildsHTML;
}

var githubPullRequestUrl = null;
var owner = null;
var repo = null;
var pull = null;

document.addEventListener('DOMContentLoaded', function() {
  getCurrentTabUrl(function(url, tab) {

    githubPullRequestUrl = url;

    var el = document.createElement('a');
    el.href = url;
    var parts = el.pathname.split("/");

    console.log("parts", parts);

    if (parts.length >= 3) {
      owner = parts[1];
      repo = parts[2];

      console.log("owner b", owner);
      console.log("repo b", repo);

      setTimeout(function() {
        chrome.tabs.sendMessage(tab.id, {}, showListOfBuilds);
      }, 500);
    } else {
      console.log("doesn't any github anything")
    }

    // Verify that we are on a github pull request with regex on URL
    if (parts.length >= 5 && parts[3] === "pull") {
      pull = parts[4];

      console.log("owner", owner);
      console.log("repo", repo);
      console.log("pull", pull);

      var button = "<button id='kickOffButton'>Make build for PR " + pull + "</button>"
      var textfield = "<input id='parameters' type='text' placeholder='Build params as JSON (optional)'></intput"
      renderStatus(button + textfield);

      document.getElementById('kickOffButton').addEventListener('click', function () {
        document.getElementById('kickOffButton').disabled = true;
        var parameters = document.getElementById("parameters").value
        chrome.tabs.sendMessage(tab.id, { parameters: parameters }, doStuffWithDOM);
      });

    } else {
      renderStatus('Cannot create a build from this page');
    }

  });
});

function showListOfBuilds(message) {

  renderBuilds("Loading list of recent CircleCI builds...");

  var branch = message.branch

  var circleToken = null;

  chrome.storage.sync.get({
    config: '',
  }, function(items) {
    var config = items.config || "{}";
    var obj = JSON.parse(config);
    var circleToken = obj[owner + "/" + repo];
    if (!circleToken) {
      renderStatus("No CircleCI API token found for: " + owner + "/" + repo);
      return;
    }

    /*
     * Look for current builds
     */
    var circleURL = "https://circleci.com/api/v1/project/" + owner + "/" + repo + "?shallow=true&offset=0&limit=30&circle-token=" + circleToken;
    if (branch) {
      circleURL = "https://circleci.com/api/v1/project/" + owner + "/" + repo +"/tree/" + branch + "?shallow=true&offset=0&limit=30&circle-token=" + circleToken;
    }
    sendRequest(circleURL, 'GET', null, function(response) {

      var buildsForThisPR = []

      var obj = JSON.parse(response.responseText);
      for (var key in obj) {
        var build = obj[key]
        var pullRequestUrls = build["pull_request_urls"];

        var indexOfPR = pullRequestUrls.indexOf(githubPullRequestUrl)
        if (indexOfPR > -1 || pull === null) {
          buildsForThisPR.push(build)
        }
      }

      var listeners = [];

      var buildsHTML = ""

      buildsHTML += "

";
      buildsHTML += "
Build	Branch	Log	Status	Outcome	Action
"
      for (var key in obj) {
        var build = obj[key]

        var status = build["status"];
        var startTime = build["start_time"];
        var outcome = build["outcome"];
        var buildUrl = build["build_url"];
        var buildNum = build["build_num"];
        var pullRequestUrls = build["pull_request_urls"];
        var subject = build["subject"];
        var buildBranch = build["branch"];

        if (outcome === null) {
          outcome = "running";
        }

        var viewButtonID = "btn-view-" + buildNum
        var cancelButtonID = "btn-cancel-" + buildNum

        buildsHTML += "
";
        buildsHTML += "" + buildNum + "	";
        buildsHTML += "" + buildBranch + "	";
        buildsHTML += "" + subject + "	";
        buildsHTML += "" + status + "	";
        buildsHTML += "" + outcome + "	";
        if (outcome === "running") {
          buildsHTML += "<button id='" + viewButtonID + "' type='button' text='View'>View</button>	";
          buildsHTML += "<button id='" + cancelButtonID + "' type='button' text='Cancel'>Cancel</button>	";
        } else {
          buildsHTML += "<button id='" + viewButtonID + "' type='button' text='View')'>View</button>	";
          buildsHTML += "";
        }
        buildsHTML += "
";

      }
      buildsHTML += "

";
      renderBuilds(buildsHTML);

      setTimeout(function() {
        for (var key in obj) {
          (function() {
            var build = obj[key]
            var buildNum = build["build_num"];

            var viewButtonID = "btn-view-" + buildNum
            var cancelButtonID = "btn-cancel-" + buildNum

            var viewBtn = document.getElementById(viewButtonID);
            var cancelBtn = document.getElementById(cancelButtonID);

            if (viewBtn) {
              viewBtn.addEventListener('click', function() {
                openCircleBuild(build);
              });
            }

            if (cancelBtn) {
              cancelBtn.addEventListener('click', function(event) {
                cancelCircleBuild(build, event.target)
              });
            }
          }());

        }
      }, 250);

    }, function(errorMessage) {

    });

  });

}

function openCircleBuild(build) {
  var buildUrl = build["build_url"];
  chrome.tabs.create({ url: buildUrl });
}

function cancelCircleBuild(build, element) {

  element.disabled = true

  var buildUrl = build["build_url"];
  var owner = build["username"];
  var repo = build["reponame"];
  var branch = build["branch"];
  var buildNum = build["build_num"];

  var circleToken = null;

  chrome.storage.sync.get({
    config: '',
  }, function(items) {
    var config = items.config || "{}";
    var obj = JSON.parse(config);
    var circleToken = obj[owner + "/" + repo];
    if (!circleToken) {
      renderStatus("No CircleCI API token found for: " + owner + "/" + repo);
      return;
    }

    var circleURL = "https://circleci.com/api/v1/project/" + owner + "/" + repo +"/" + buildNum + "/cancel?circle-token=" + circleToken;
    sendRequest(circleURL, 'POST', null, function(response) {

      setTimeout(function() {
        getCurrentTabUrl(function(url, tab) {
          chrome.tabs.sendMessage(tab.id, {}, showListOfBuilds);
        });
      }, 500);

    });

  });

}

/* A function creator for callbacks */
function doStuffWithDOM(message) {

  var branch = message.branch

  var customParameters = {};
  try {
    customParameters = JSON.parse(message.parameters);
  } catch (e) {

  }

  var circleToken = null;

  chrome.storage.sync.get({
    config: '',
  }, function(items) {
    var config = items.config || "{}";
    var obj = JSON.parse(config);
    var circleToken = obj[owner + "/" + repo];
    if (!circleToken) {
      renderStatus("No CircleCI API token found for: " + owner + "/" + repo);
      return;
    }

    var circleURL = "https://circleci.com/api/v1/project/" + owner + "/" + repo +"/tree/" + branch + "?circle-token=" + circleToken;

    // Create the build parameters for the repo
    var buildParameters = {
      OWNER: owner,
      REPO: repo,
      PULL: pull,
      BRANCH: branch
    }

    // Merge the build parameters with the cudstom parameters that we need to send in the request
    for (var attrname in customParameters) { buildParameters[attrname] = customParameters[attrname]; }
    var body = {
      build_parameters: buildParameters
    };

    // Send the parameterized build to CicleCI
    sendRequest(circleURL, 'POST', body, function(response) {
      renderStatus('Stated build for - ' + owner + "/" + repo +"/tree/" + branch);

      var obj = JSON.parse(response.responseText);
      var buildUrl = obj['build_url'];
      chrome.tabs.create({ url: buildUrl });
    }, function(errorMessage) {
      renderStatus('Error :( - ' + errorMessage);
    });

  });

}
<commit_msg>Removed logs<commit_after>
function getCurrentTabUrl(callback) {
  var queryInfo = {
    active: true,
    currentWindow: true
  };

  chrome.tabs.query(queryInfo, function(tabs) {
    var tab = tabs[0];
    var url = tab.url;
    callback(url, tab);
  });
}

// Doing sick nasty raw-ish ajax request
function sendRequest(url, method, body, callback, errorCallback) {
  var x = new XMLHttpRequest();
  x.open(method, url);
    x.setRequestHeader('Accept', 'application/json');
    x.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
  x.onreadystatechange = function() {
    if (x.readyState == 4) {
      if (x.status >= 200 && x.status < 300) {
        callback(x);
      } else {
        errorCallback(x);
      }
    }
  }
  x.onerror = function() {
    errorCallback('Network error.');
  };
  if (body) {
    x.send(JSON.stringify(body));
  } else {
    x.send();
  }
}

function renderStatus(statusText) {
  document.getElementById('status').innerHTML = statusText;
}

function renderBuilds(buildsHTML) {
  document.getElementById('builds').innerHTML = buildsHTML;
}

var githubPullRequestUrl = null;
var owner = null;
var repo = null;
var pull = null;

document.addEventListener('DOMContentLoaded', function() {
  getCurrentTabUrl(function(url, tab) {

    githubPullRequestUrl = url;

    var el = document.createElement('a');
    el.href = url;
    var parts = el.pathname.split("/");

    if (parts.length >= 3) {
      owner = parts[1];
      repo = parts[2];

      setTimeout(function() {
        chrome.tabs.sendMessage(tab.id, {}, showListOfBuilds);
      }, 500);
    }

    // Verify that we are on a github pull request with regex on URL
    if (parts.length >= 5 && parts[3] === "pull") {
      pull = parts[4];

      var button = "<button id='kickOffButton'>Make build for PR " + pull + "</button>"
      var textfield = "<input id='parameters' type='text' placeholder='Build params as JSON (optional)'></intput"
      renderStatus(button + textfield);

      document.getElementById('kickOffButton').addEventListener('click', function () {
        document.getElementById('kickOffButton').disabled = true;
        var parameters = document.getElementById("parameters").value
        chrome.tabs.sendMessage(tab.id, { parameters: parameters }, doStuffWithDOM);
      });

    } else {
      renderStatus('Cannot create a build from this page');
    }

  });
});

function showListOfBuilds(message) {

  renderBuilds("Loading list of recent CircleCI builds...");

  var branch = message.branch

  var circleToken = null;

  chrome.storage.sync.get({
    config: '',
  }, function(items) {
    var config = items.config || "{}";
    var obj = JSON.parse(config);
    var circleToken = obj[owner + "/" + repo];
    if (!circleToken) {
      renderStatus("No CircleCI API token found for: " + owner + "/" + repo);
      return;
    }

    /*
     * Look for current builds
     */
    var circleURL = "https://circleci.com/api/v1/project/" + owner + "/" + repo + "?shallow=true&offset=0&limit=30&circle-token=" + circleToken;
    if (branch) {
      circleURL = "https://circleci.com/api/v1/project/" + owner + "/" + repo +"/tree/" + branch + "?shallow=true&offset=0&limit=30&circle-token=" + circleToken;
    }
    sendRequest(circleURL, 'GET', null, function(response) {

      var buildsForThisPR = []

      var obj = JSON.parse(response.responseText);
      for (var key in obj) {
        var build = obj[key]
        var pullRequestUrls = build["pull_request_urls"];

        var indexOfPR = pullRequestUrls.indexOf(githubPullRequestUrl)
        if (indexOfPR > -1 || pull === null) {
          buildsForThisPR.push(build)
        }
      }

      var listeners = [];

      var buildsHTML = ""

      buildsHTML += "

";
      buildsHTML += "
Build	Branch	Log	Status	Outcome	Action
"
      for (var key in obj) {
        var build = obj[key]

        var status = build["status"];
        var startTime = build["start_time"];
        var outcome = build["outcome"];
        var buildUrl = build["build_url"];
        var buildNum = build["build_num"];
        var pullRequestUrls = build["pull_request_urls"];
        var subject = build["subject"];
        var buildBranch = build["branch"];

        if (outcome === null) {
          outcome = "running";
        }

        var viewButtonID = "btn-view-" + buildNum
        var cancelButtonID = "btn-cancel-" + buildNum

        buildsHTML += "
";
        buildsHTML += "" + buildNum + "	";
        buildsHTML += "" + buildBranch + "	";
        buildsHTML += "" + subject + "	";
        buildsHTML += "" + status + "	";
        buildsHTML += "" + outcome + "	";
        if (outcome === "running") {
          buildsHTML += "<button id='" + viewButtonID + "' type='button' text='View'>View</button>	";
          buildsHTML += "<button id='" + cancelButtonID + "' type='button' text='Cancel'>Cancel</button>	";
        } else {
          buildsHTML += "<button id='" + viewButtonID + "' type='button' text='View')'>View</button>	";
          buildsHTML += "";
        }
        buildsHTML += "
";

      }
      buildsHTML += "

";
      renderBuilds(buildsHTML);

      setTimeout(function() {
        for (var key in obj) {
          (function() {
            var build = obj[key]
            var buildNum = build["build_num"];

            var viewButtonID = "btn-view-" + buildNum
            var cancelButtonID = "btn-cancel-" + buildNum

            var viewBtn = document.getElementById(viewButtonID);
            var cancelBtn = document.getElementById(cancelButtonID);

            if (viewBtn) {
              viewBtn.addEventListener('click', function() {
                openCircleBuild(build);
              });
            }

            if (cancelBtn) {
              cancelBtn.addEventListener('click', function(event) {
                cancelCircleBuild(build, event.target)
              });
            }
          }());

        }
      }, 250);

    }, function(errorMessage) {

    });

  });

}

function openCircleBuild(build) {
  var buildUrl = build["build_url"];
  chrome.tabs.create({ url: buildUrl });
}

function cancelCircleBuild(build, element) {

  element.disabled = true

  var buildUrl = build["build_url"];
  var owner = build["username"];
  var repo = build["reponame"];
  var branch = build["branch"];
  var buildNum = build["build_num"];

  var circleToken = null;

  chrome.storage.sync.get({
    config: '',
  }, function(items) {
    var config = items.config || "{}";
    var obj = JSON.parse(config);
    var circleToken = obj[owner + "/" + repo];
    if (!circleToken) {
      renderStatus("No CircleCI API token found for: " + owner + "/" + repo);
      return;
    }

    var circleURL = "https://circleci.com/api/v1/project/" + owner + "/" + repo +"/" + buildNum + "/cancel?circle-token=" + circleToken;
    sendRequest(circleURL, 'POST', null, function(response) {

      setTimeout(function() {
        getCurrentTabUrl(function(url, tab) {
          chrome.tabs.sendMessage(tab.id, {}, showListOfBuilds);
        });
      }, 500);

    });

  });

}

/* A function creator for callbacks */
function doStuffWithDOM(message) {

  var branch = message.branch

  var customParameters = {};
  try {
    customParameters = JSON.parse(message.parameters);
  } catch (e) {

  }

  var circleToken = null;

  chrome.storage.sync.get({
    config: '',
  }, function(items) {
    var config = items.config || "{}";
    var obj = JSON.parse(config);
    var circleToken = obj[owner + "/" + repo];
    if (!circleToken) {
      renderStatus("No CircleCI API token found for: " + owner + "/" + repo);
      return;
    }

    var circleURL = "https://circleci.com/api/v1/project/" + owner + "/" + repo +"/tree/" + branch + "?circle-token=" + circleToken;

    // Create the build parameters for the repo
    var buildParameters = {
      OWNER: owner,
      REPO: repo,
      PULL: pull,
      BRANCH: branch
    }

    // Merge the build parameters with the cudstom parameters that we need to send in the request
    for (var attrname in customParameters) { buildParameters[attrname] = customParameters[attrname]; }
    var body = {
      build_parameters: buildParameters
    };

    // Send the parameterized build to CicleCI
    sendRequest(circleURL, 'POST', body, function(response) {
      renderStatus('Stated build for - ' + owner + "/" + repo +"/tree/" + branch);

      var obj = JSON.parse(response.responseText);
      var buildUrl = obj['build_url'];
      chrome.tabs.create({ url: buildUrl });
    }, function(errorMessage) {
      renderStatus('Error :( - ' + errorMessage);
    });

  });

}
<|endoftext|>


<commit_before>/*
 * Copyright 2015 brutusin.org
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * @author Ignacio del Valle Alles idelvall@brutusin.org
 */
if ("undefined" == typeof BrutusinForms) {
    throw new Error("brutusin-json-forms-bootstrap.js requires brutusin-json-forms.js");
}

BrutusinForms.decorator = function (element) {
    if (element.tagName) {
        var tagName = element.tagName.toLowerCase();
        if (tagName === "input" && element.type !== "checkbox" || tagName === "textarea") {
            element.className += " form-control";
        } else if (tagName === "select") {
            element.className += " chosen-select form-control";
        } else if (tagName === "button") {
            element.className += "btn btn-primary  btn-xs";
        } else if (tagName === "form") {
            element.className += " form-inline";
        }
    }
    if (element.title) {
        element.setAttribute("data-toggle", "tooltip");
    }
};

BrutusinForms.postRender = function (bf) {
    $('[data-toggle="tooltip"]').tooltip();
};<commit_msg>Issue #4 solved<commit_after>/*
 * Copyright 2015 brutusin.org
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * @author Ignacio del Valle Alles idelvall@brutusin.org
 */
if ("undefined" == typeof BrutusinForms) {
    throw new Error("brutusin-json-forms-bootstrap.js requires brutusin-json-forms.js");
}

BrutusinForms.decorator = function (element) {
    if (element.tagName) {
        var tagName = element.tagName.toLowerCase();
        if (tagName === "input" && element.type !== "checkbox" || tagName === "textarea") {
            element.className += " form-control";
        } else if (tagName === "select") {
            element.className += " chosen-select form-control";
        } else if (tagName === "button") {
            element.className += "btn btn-primary  btn-xs";
        } else if (tagName === "form") {
            element.className += " form-inline";
        }
    }
    if (element.title) {
        element.setAttribute("data-toggle", "tooltip");
        $(element).tooltip({
            container: 'body'
        });
    }
};<|endoftext|>


<commit_before>HOST = null; // localhost
PORT = 8001;

// when the daemon started
var starttime = (new Date()).getTime();

var mem = process.memoryUsage();
// every 10 seconds poll for the memory.
setInterval(function () {
  mem = process.memoryUsage();
}, 10*1000);

var fu = require("../../common/fu"),
    Breeze = require("./Breeze/Breeze"),
    ChatJS = require("./ChatJS/Channel"),
    sys = require("sys"),
    url = require("url"),
    qs = require("querystring");

var SESSION_TIMEOUT = 60 * 1000;

// [room_name] => array(sessions)
var rooms = {};
var sessions = {};

function joinRoom (room_name, nick) {
  if (room_name.length > 50) return null;
  if (/[^\w_\-^!]/.exec(room_name)) return null;
  if (nick.length > 50) return null;
  if (/[^\w_\-^!]/.exec(nick)) return null;

  // Does the room exist?
  if (typeof rooms[room_name] == 'undefined') {
    // No. Create it.

    sys.puts('Creating a room: '+room_name);

    var channel = new ChatJS.Channel(room_name);

    var room = {
      room_name: room_name,
      channel: channel,
      sessions: []
    };

    rooms[room_name] = room;
  }

  // Is the user already in the room?
  if (!rooms[room_name].sessions[nick]) {
    // No, join the room.
    rooms[room_name].sessions[nick] = createSession(nick, rooms[room_name].channel);

  } else {
    return null;
  }

  return rooms[room_name];
}

function createSession (nick, channel) {
  // TODO: name length
  if (nick.length > 50) return null;
  if (/[^\w_\-^!]/.exec(nick)) return null;

  for (var i in sessions) {
    var session = sessions[i];
    if (session && session.nick === nick) return null;
  }

  var session = {
    nick: nick,
    timestamp: new Date(),

    poke: function () {
      session.timestamp = new Date();
    },

    destroy: function () {
      channel.appendMessage(session.nick, "part");
      delete sessions[session.nick];
    }
  };

  sessions[session.nick] = session;
  return session;
}

// interval to kill off old sessions
setInterval(function () {
  var now = new Date();
  for (var id in sessions) {
    if (!sessions.hasOwnProperty(id)) continue;
    var session = sessions[id];

    if (now - session.timestamp > SESSION_TIMEOUT) {
      session.destroy();
    }
  }
}, 1000);

fu.listen(Number(process.env.PORT || PORT), HOST);

fu.get("/", fu.staticHandler("www/index.html"));
fu.get("/style.css", fu.staticHandler("www/css/style.css"));
fu.get("/client.js", fu.staticHandler("www/js/client.js"));
fu.get("/jquery.js", fu.staticHandler("www/jquery.js"));

fu.get("/who", function (req, res) {
  sys.puts('serv: who');
  sys.puts(' - req: '+req);
  sys.puts(' - res: '+res);
  var room_name = qs.parse(url.parse(req.url).query).room;
  var nicks = [];
  for (var id in rooms[room_name].sessions) {
    if (!sessions.hasOwnProperty(id)) continue;
    var session = sessions[id];
    nicks.push(session.nick);
  }
  res.simpleJSON(200, { nicks: nicks
                      , rss: mem.rss
                      });
});

fu.get("/join", function (req, res) {
  sys.puts('serv: join');
  sys.puts(' - query: '+url.parse(req.url).query);

  // Gets the room name from the URL (a GET request).
  var room_name = qs.parse(url.parse(req.url).query).room;
  if (room_name == null || room_name.length == 0) {
    res.simpleJSON(400, {error: "Bad room name."});
    return;
  }

  // TODO: Something more fun.
  var user_name = 'anon'+Math.floor(Math.random()*1000000000000);
  var room = joinRoom(room_name, user_name);
  if (room == null) {
    res.simpleJSON(400, {error: "There's already a user with your name in the room."});
    return;
  }

  sys.puts("connection: " + room_name + "@" + res.connection.remoteAddress);

  room.channel.appendMessage(user_name, "join");
  res.simpleJSON(200, { nick: user_name
                      , room: room_name
                      , rss: mem.rss
                      , starttime: starttime
                      });
});

fu.get("/part", function (req, res) {
  sys.puts('serv: part');
  var id = qs.parse(url.parse(req.url).query).nick;
  var session;
  if (id && sessions[id]) {
    session = sessions[id];
    session.destroy();
  }
  res.simpleJSON(200, { rss: mem.rss });
});

fu.get("/recv", function (req, res) {
  sys.puts('serv: recv');
  if (!qs.parse(url.parse(req.url).query).since) {
    res.simpleJSON(400, { error: "Must supply since parameter" });
    return;
  }
  var id = qs.parse(url.parse(req.url).query).nick;
  var room_name = qs.parse(url.parse(req.url).query).room;
  var session;
  if (id && sessions[id]) {
    session = sessions[id];
    session.poke();
  }

  var since = parseInt(qs.parse(url.parse(req.url).query).since, 10);

  sys.puts(room_name);

  var room = rooms[room_name];
  room.channel.query(since, function (messages) {
    if (session) session.poke();
    res.simpleJSON(200, { messages: messages, rss: mem.rss });
  });
});

fu.get("/nick", function (req, res) {
  sys.puts('serv: nick');
  var nick = qs.parse(url.parse(req.url).query).nick;
  var new_nick = qs.parse(url.parse(req.url).query).new_nick;
  var room_name = qs.parse(url.parse(req.url).query).room;

  sys.puts('old name: '+nick);
  sys.puts('new name: '+new_nick);

  if (new_nick.length > 50 || /[^\w_\-^!]/.exec(new_nick)) {
    res.simpleJSON(400, { error: "Invalid nickname" });
    return;
  }

  var session = sessions[nick];
  if (!session || !new_nick) {
    res.simpleJSON(400, { error: "No such session id" });
    return;
  }

  session.nick = new_nick;

  delete sessions[nick];
  sessions[new_nick] = session;

  session.poke();

  var room = rooms[room_name];
  room.channel.appendMessage(nick, "nick", new_nick);
  res.simpleJSON(200, { rss: mem.rss });
});

fu.get("/send", function (req, res) {
  sys.puts('serv: send');
  var id = qs.parse(url.parse(req.url).query).nick;
  var room_name = qs.parse(url.parse(req.url).query).room;
  var text = qs.parse(url.parse(req.url).query).text;

  sys.puts(id);

  var session = sessions[id];
  if (!session || !text) {
    res.simpleJSON(400, { error: "No such session id" });
    return;
  }

  session.poke();

  var room = rooms[room_name];
  room.channel.appendMessage(session.nick, "msg", text);
  res.simpleJSON(200, { rss: mem.rss });
});
<commit_msg>No global session object.<commit_after>HOST = null; // localhost
PORT = 8001;

// when the daemon started
var starttime = (new Date()).getTime();

var mem = process.memoryUsage();
// every 10 seconds poll for the memory.
setInterval(function () {
  mem = process.memoryUsage();
}, 10*1000);

var fu = require("../../common/fu"),
    Breeze = require("./Breeze/Breeze"),
    ChatJS = require("./ChatJS/Channel"),
    sys = require("sys"),
    url = require("url"),
    qs = require("querystring");

var SESSION_TIMEOUT = 60 * 1000;

// [room_name] => array(sessions)
var rooms = {};

function joinRoom (room_name, nick) {
  if (room_name.length > 50) return null;
  if (/[^\w_\-^!]/.exec(room_name)) return null;
  if (nick.length > 50) return null;
  if (/[^\w_\-^!]/.exec(nick)) return null;

  // Does the room exist?
  if (typeof rooms[room_name] == 'undefined') {
    // No. Create it.

    sys.puts('Creating a room: '+room_name);

    var channel = new ChatJS.Channel(room_name);

    var room = {
      room_name: room_name,
      channel: channel,
      sessions: []
    };

    rooms[room_name] = room;

    // interval to kill off old sessions
    setInterval(function () {
      var now = new Date();
      for (var id in this.sessions) {
        if (!this.sessions.hasOwnProperty(id)) continue;
        var session = this.sessions[id];

        if (now - session.timestamp > SESSION_TIMEOUT) {
          session.destroy();
        }
      }
    }.bind(room), 1000);
  }

  // Is the user already in the room?
  if (!rooms[room_name].sessions[nick]) {
    // No, join the room.
    rooms[room_name].sessions[nick] = createSession(nick, rooms[room_name]);

  } else {
    return null;
  }

  return rooms[room_name];
}

function createSession (nick, room) {
  // TODO: name length
  if (nick.length > 50) return null;
  if (/[^\w_\-^!]/.exec(nick)) return null;

  for (var i in room.sessions) {
    var session = room.sessions[i];
    if (session && session.nick === nick) return null;
  }

  var session = {
    nick: nick,
    timestamp: new Date(),

    poke: function () {
      session.timestamp = new Date();
    },

    destroy: function () {
      room.channel.appendMessage(session.nick, "part");
      delete room.sessions[session.nick];
    }
  };

  return session;
}

fu.listen(Number(process.env.PORT || PORT), HOST);

fu.get("/", fu.staticHandler("www/index.html"));
fu.get("/style.css", fu.staticHandler("www/css/style.css"));
fu.get("/client.js", fu.staticHandler("www/js/client.js"));
fu.get("/jquery.js", fu.staticHandler("www/jquery.js"));

fu.get("/who", function (req, res) {
  sys.puts('serv: who');
  sys.puts(' - req: '+req);
  sys.puts(' - res: '+res);
  var room_name = qs.parse(url.parse(req.url).query).room;
  var nicks = [];
  for (var id in rooms[room_name].sessions) {
    if (!rooms[room_name].sessions.hasOwnProperty(id)) continue;
    var session = rooms[room_name].sessions[id];
    nicks.push(session.nick);
  }
  res.simpleJSON(200, { nicks: nicks
                      , rss: mem.rss
                      });
});

fu.get("/join", function (req, res) {
  sys.puts('serv: join');
  sys.puts(' - query: '+url.parse(req.url).query);

  // Gets the room name from the URL (a GET request).
  var room_name = qs.parse(url.parse(req.url).query).room;
  if (room_name == null || room_name.length == 0) {
    res.simpleJSON(400, {error: "Bad room name."});
    return;
  }

  // TODO: Something more fun.
  var user_name = 'anon'+Math.floor(Math.random()*1000000000000);
  var room = joinRoom(room_name, user_name);
  if (room == null) {
    res.simpleJSON(400, {error: "There's already a user with your name in the room."});
    return;
  }

  sys.puts("connection: " + room_name + "@" + res.connection.remoteAddress);

  room.channel.appendMessage(user_name, "join");
  res.simpleJSON(200, { nick: user_name
                      , room: room_name
                      , rss: mem.rss
                      , starttime: starttime
                      });
});

fu.get("/part", function (req, res) {
  sys.puts('serv: part');
  var id = qs.parse(url.parse(req.url).query).nick;
  var room_name = qs.parse(url.parse(req.url).query).room;
  var room = rooms[room_name];
  var session;
  if (id && room.sessions[id]) {
    session = room.sessions[id];
    session.destroy();
  }
  res.simpleJSON(200, { rss: mem.rss });
});

fu.get("/recv", function (req, res) {
  sys.puts('serv: recv');
  if (!qs.parse(url.parse(req.url).query).since) {
    res.simpleJSON(400, { error: "Must supply since parameter" });
    return;
  }
  var id = qs.parse(url.parse(req.url).query).nick;
  var room_name = qs.parse(url.parse(req.url).query).room;
  var room = rooms[room_name];
  var session;
  if (id && room.sessions[id]) {
    session = room.sessions[id];
    session.poke();
  }

  var since = parseInt(qs.parse(url.parse(req.url).query).since, 10);

  sys.puts(room_name);

  room.channel.query(since, function (messages) {
    if (session) session.poke();
    res.simpleJSON(200, { messages: messages, rss: mem.rss });
  });
});

fu.get("/nick", function (req, res) {
  sys.puts('serv: nick');
  var nick = qs.parse(url.parse(req.url).query).nick;
  var new_nick = qs.parse(url.parse(req.url).query).new_nick;
  var room_name = qs.parse(url.parse(req.url).query).room;
  var room = rooms[room_name];

  sys.puts('old name: '+nick);
  sys.puts('new name: '+new_nick);

  if (new_nick.length > 50 || /[^\w_\-^!]/.exec(new_nick)) {
    res.simpleJSON(400, { error: "Invalid nickname" });
    return;
  }

  var session = room.sessions[nick];
  if (!session || !new_nick) {
    res.simpleJSON(400, { error: "No such session id" });
    return;
  }

  session.nick = new_nick;

  delete room.sessions[nick];
  room.sessions[new_nick] = session;

  session.poke();

  room.channel.appendMessage(nick, "nick", new_nick);
  res.simpleJSON(200, { rss: mem.rss });
});

fu.get("/send", function (req, res) {
  sys.puts('serv: send');
  var id = qs.parse(url.parse(req.url).query).nick;
  var room_name = qs.parse(url.parse(req.url).query).room;
  var text = qs.parse(url.parse(req.url).query).text;
  var room = rooms[room_name];

  sys.puts(id);

  var session = room.sessions[id];
  if (!session || !text) {
    res.simpleJSON(400, { error: "No such session id" });
    return;
  }

  session.poke();

  room.channel.appendMessage(session.nick, "msg", text);
  res.simpleJSON(200, { rss: mem.rss });
});
<|endoftext|>


<commit_before>var _ = require('underscore');
var ASTRewriter = require('./ast-rewriter');
var ASTPrinter  = require('./ast-printer');

/*
 * Compiles juttle options & filter ASTs to influx select queries.
 */
var Compiler = function() {
    this.rewriter = new ASTRewriter();
    this.printer  = new ASTPrinter();
}

/*
 * select_stmt = "SELECT" fields from_clause [ into_clause *] [ where_clause ]
 *               [ group_by_clause *] [ order_by_clause ] [ limit_clause ]
 *               [ offset_clause *] [ slimit_clause *] [ soffset_clause *]
 * Constructs marked with * are not supported.
 */
Compiler.prototype.build = function(options, filter_opts) {
    options = options || {};
    filter_opts = filter_opts || {};

    return _.compact([
        this._buildSelect(options, filter_opts),
        this._buildFrom(options, filter_opts),
        this._buildWhere(options, filter_opts),
        this._buildOrderBy(options, filter_opts),
        this._buildLimit(options, filter_opts),
        this._buildOffset(options, filter_opts),
    ]).join(' ');
}

Compiler.prototype._buildSelect = function(options, filter_opts) {
    var fields = options.fields || '*';

    if (_.isArray(fields)) { fields = fields.join(',') }

    return ['SELECT', fields].join(' ');
};

Compiler.prototype._buildWhere = function(options, filter_opts) {
    var root = filter_opts.filter_ast;

    if (root) {
        return ['WHERE', this.printer.visit(this.rewriter.visit(root))].join(' ');
    } else {
        return null;
    }
}

Compiler.prototype._buildFrom = function(options, filter_ast) {
    var measurements = options.measurements || '/.*/';

    if (_.isArray(measurements)) { measurements = measurements.join(','); }

    return ['FROM', measurements].join(' ');
}

Compiler.prototype._buildLimit = function(options, filter_ast) {
    if (options.limit) {
        return ['LIMIT', options.limit].join(' ');
    } else {
        return null;
    }
}

Compiler.prototype._buildOffset = function(options, filter_ast) {
    if (options.offset) {
        return ['OFFSET', options.offset].join(' ');
    } else {
        return null;
    }
}

Compiler.prototype._buildOrderBy = function(options, filter_ast) {
    return null;
};

/*
Compiler.prototype._isMeasurement = function(str) {
    return this._isMeasurementName(str) || this._is
};

Compiler.prototype._isIdentifier = function(str) {
    return this._isUnquotedIdentifier || this._isQuotedIdentifier;
};

Compiler.prototype._isUnquotedIdentifier = function(str) {
    return true;
};

Compiler.prototype._isQuotedIdentifier = function(str) {
    return true;
};
*/

module.exports = Compiler;
<commit_msg>Remove unimplemented code<commit_after>var _ = require('underscore');
var ASTRewriter = require('./ast-rewriter');
var ASTPrinter  = require('./ast-printer');

/*
 * Compiles juttle options & filter ASTs to influx select queries.
 */
var Compiler = function() {
    this.rewriter = new ASTRewriter();
    this.printer  = new ASTPrinter();
}

/*
 * select_stmt = "SELECT" fields from_clause [ into_clause *] [ where_clause ]
 *               [ group_by_clause *] [ order_by_clause ] [ limit_clause ]
 *               [ offset_clause *] [ slimit_clause *] [ soffset_clause *]
 * Constructs marked with * are not supported.
 */
Compiler.prototype.build = function(options, filter_opts) {
    options = options || {};
    filter_opts = filter_opts || {};

    return _.compact([
        this._buildSelect(options, filter_opts),
        this._buildFrom(options, filter_opts),
        this._buildWhere(options, filter_opts),
        this._buildOrderBy(options, filter_opts),
        this._buildLimit(options, filter_opts),
        this._buildOffset(options, filter_opts),
    ]).join(' ');
}

Compiler.prototype._buildSelect = function(options, filter_opts) {
    var fields = options.fields || '*';

    if (_.isArray(fields)) { fields = fields.join(',') }

    return ['SELECT', fields].join(' ');
};

Compiler.prototype._buildWhere = function(options, filter_opts) {
    var root = filter_opts.filter_ast;

    if (root) {
        return ['WHERE', this.printer.visit(this.rewriter.visit(root))].join(' ');
    } else {
        return null;
    }
}

Compiler.prototype._buildFrom = function(options, filter_ast) {
    var measurements = options.measurements || '/.*/';

    if (_.isArray(measurements)) { measurements = measurements.join(','); }

    return ['FROM', measurements].join(' ');
}

Compiler.prototype._buildLimit = function(options, filter_ast) {
    if (options.limit) {
        return ['LIMIT', options.limit].join(' ');
    } else {
        return null;
    }
}

Compiler.prototype._buildOffset = function(options, filter_ast) {
    if (options.offset) {
        return ['OFFSET', options.offset].join(' ');
    } else {
        return null;
    }
}

Compiler.prototype._buildOrderBy = function(options, filter_ast) {
    // FIXME
};

module.exports = Compiler;
<|endoftext|>


<commit_before>/*globals CoreCircsim */

sc_require('models/procedure');

CoreCircsim.Procedure.FIXTURES = [

{
  // GUID Must be a unique string for each procedure!
  guid: '1',
  title: "Decrease Ra",
  isComplete: false,
  cols: ["DR", "RR", "SS"],
  rows: ["IS", "CVP", "SV", "HR", "CO", "Ra", "MAP"],
  initialVariable: 5,
  initialVariableDirection: 1,
  answerKeys: [1,2],
  relationshipKeys: [{
    equation: [4, 2, 3],
    errors: [[2, 1, 1], [2, 1, 0], [2, 0, 0], [2, 0, 1], [1, 2, 2], [1, 2, 0], [1, 0, 0], [1, 0, 2], [0, 2, 2], [0, 2, 0], [0, 1, 1], [0, 1, 0], [0, 0, 2], [0, 0, 1]],
    errorMessage: "Err message 1"
  },
  {
    equation: [6, 4, 5],
    errors: [[2, 1, 1], [2, 1, 0], [2, 0, 0], [2, 0, 1], [1, 2, 2], [1, 2, 0], [1, 0, 0], [1, 0, 2], [0, 2, 2], [0, 2, 0], [0, 1, 1], [0, 1, 0], [0, 0, 2], [0, 0, 1]],
    errorMessage: "Err message 2"
  }]
}];
<commit_msg>Rethinking how to do the relationship evaluations...<commit_after>/*globals CoreCircsim */

sc_require('models/procedure');

CoreCircsim.Procedure.FIXTURES = [

{
  // GUID Must be a unique string for each procedure!
  guid: '1',
  title: "Decrease Ra",
  isComplete: false,
  cols: ["DR", "RR", "SS"],
  rows: ["IS", "CVP", "SV", "HR", "CO", "Ra", "MAP"],
  initialVariable: 5,
  initialVariableDirection: 1,
  answerKeys: [1,2],
  relationshipEvaluationIntro: "You will now be evaluated for your relationship accuracy.",
  relationshipEvaluations: [{
    equation: [4, 2, 3],
    errorMessage: "Err message 1",
    isComplete: false
  },
  {
    equation: [6, 4, 5],
    errorMessage: "Err message 2",
    isComplete: false
  }]
}];

<|endoftext|>


<commit_before>cdb.admin.overlays.Text = cdb.core.View.extend({

  className: "text overlay",

  template_name: 'table/views/overlays/text',

  events: {

    "mouseup":           "_onMouseUp",
    "mousedown":         "_onMouseDown",

    "mouseenter .text":  "_onMouseEnter",
    "mouseleave .text":  "_onMouseLeave",

    "click .close":      "_close",
    "click .content":    "_click",
    "dblclick .content": "_dblClick",

    "keyup .text":       "_onKeyUp",
    "click .text":       "_killEvent",
    "paste .text":       "_onPaste"

  },

  initialize: function() {

    _.bindAll(this, "_click", "_close", "_dblClick", "_onChangeMode", "_onKeyDown", "_putOnTop");

    // Bind ESC key
    $(document).bind('keydown', this._onKeyDown);

    this.template = this.getTemplate(this.template_name);

    this._setupModels();

  },

  _killEvent: function(e) {

    e && e.preventDefault();
    e && e.stopPropagation();

  },

  // Setup the internal and custom model
  _setupModels: function() {

    var extra = this.model.get("extra");

    this.model.set({ text: extra.text }, { silent: true });

    // Binding
    this.model.bind('change:text',    this._setText,    this);
    this.model.bind('change:style',   this._applyStyle, this);
    this.model.bind('change:display', this._onChangeDisplay, this);
    this.model.bind('change:extra',   this._onChangeExtra, this);

    // Internal model to store the editing state
    this.editModel = new cdb.core.Model({ mode: "" });
    this.editModel.bind('change:mode', this._onChangeMode, this);

    this.add_related_model(this.editModel);

  },

  // Element events
  _onKeyUp: function(e) {

    var self = this;

    var temp      = "";
    var domString = "";

    if (this.timeout)       clearTimeout(this.timeout);
    if (this.keyUpTimeout)  clearTimeout(this.keyUpTimeout);
    if (this.savingTimeout) clearTimeout(this.savingTimeout);

    var value = this.$text.html();

    if (cdb.Utils.stripHTML(value) == "") {

      this.keyUpTimeout = setTimeout(function() {

        self.model.set({ text: "" }, { silent: true });
        self._close();

      }, 600);

    } else {

      this.model.set({ text: value }, { silent: true });

      if (!this.$el.hasClass("hover") && this.$text.text()) {
        this.savingTimeout = setTimeout(function() {

          self._disableEditingMode();

        }, 500);
      }
    }

  },

  _dblClick: function(e) {

    this._killEvent(e);

  },

  _click: function(e) {

    this._killEvent(e);

    this._putOnTop();

    var isLink = e.target.hasAttribute("href");

    if (!isLink) {
      cdb.god.trigger("closeDialogs");
    }

  },

  _onKeyDown: function(e) {

    if (e.keyCode === 27) {
      this.editModel.set("mode", "");
    }

  },

  _onPaste: function(e) {

    var self = this;

    setTimeout(function() {

      var text = cdb.Utils.stripHTML(self.model.get("text"));
      self.model.set("text", text)

    }, 200);

  },

  _onMouseUp: function(e) {

    // Prevents entering in the edit mode when clicking the edit button
    if (!$(e.target).parents(".overlay_text").length && !$(e.target).hasClass("overlay_text")) {
      return;
    }

    cdb.god.trigger("closeDialogs");

    var extra = this.model.get("extra");

    var x     = this.model.get("x");
    var y     = this.model.get("y");

    var oldX  = this.$el.position().left;
    var oldY  = this.$el.position().top;

    var portraitDirection  = extra.portraitDirection;
    var landscapeDirection = extra.landscapeDirection;

    if (y == 0 && portraitDirection == "bottom") oldY = y;
    if (x == 0 && landscapeDirection == "right") oldX = x;

    // If we didn't move the overlay
    if (oldX === x && y === oldY || x == 0 && landscapeDirection == "right" && y === oldY || y == 0 && portraitDirection == "bottom" && oldX === x) {

      this.dropdown.hide();
      this.editModel.set("mode", "editable");

      return;

    }

    var x = this.$el.position().left;
    var y = this.$el.position().top;

    // Default positions
    extra.portraitDirection  = "top";
    extra.landscapeDirection = "left";

    // Let's see where did we put our overlay…
    var rightSticked  = x + this.$el.width()  >= $(".cartodb-map").width();
    var bottomSticked = y + this.$el.height() >= $(".cartodb-map").height();

    if (bottomSticked) { // we sticked the overlay to the bottom of the screen

      y = 0;

      this.$el.css({ bottom: 0, top: "auto" });

      extra.portraitDirection = "bottom";

    }

    if (rightSticked) { // we sticked the overlay to the right side

      x = 0;

      this.$el.css({ right: 0, left: "auto" });

      extra.landscapeDirection = "right";

    }

    this.model.set({ extra: extra }, { silent: true});
    this.model.set({ x: x, y: y });

    this.model.save();

  },

  _onMouseDown: function() { },

  _onMouseEnter: function() {

    this.$el.addClass("hover");
    if (this.editModel.get("mode") == "editable") {
      if (this.timeout) clearTimeout(this.timeout);
    }

  },

  _onMouseLeave: function() {
    this.$el.removeClass("hover");

    var self = this;

    if (this.editModel.get("mode") == "editable") {

      this.timeout = setTimeout(function() {

        self.editModel.set("mode", "");

      }, 250);
    }

  },

  show: function(animated) {

    this.$el.show();

    if (true) this.$el.addClass('animated bounceIn');

  },

  hide: function(callback) {

    var self = this;

    this.$el
    .removeClass('animated bounceIn')
    .addClass('animated bounceOut');

    callback && callback();

    // Give it some time to complete the animation
    setTimeout(function() {
      self.clean();
    }, 550);

  },

  _close: function(e) {

    this._killEvent(e);

    var self = this;

    this.dropdown.hide();
    this.dropdown.clean();

    this.hide(function() {
      self.trigger("remove", self);
    });

  },

  _onChangeDisplay: function() {

    var display = this.model.get("display");

    if (display) {
      this.show();
    } else {
      this.$el.hide();
    }

  },

  _onChangeExtra: function() {

    var extra  = this.model.get("extra");
    extra.text = this.model.get("text");

    this.model.set({ extra: extra }, { silent: true });

  },

  /*
   * Applies style to the content of the widget
   */

  _applyStyle: function() {

    var style      = this.model.get("style");

    var boxColor   = style["box-color"];
    var boxOpacity = style["box-opacity"];
    var boxWidth   = style["box-width"];
    var fontFamily = style["font-family-name"];

    this.$text.css(style);
    this.$text.css("font-size", style["font-size"] + "px");

    var rgbaCol = 'rgba(' + parseInt(boxColor.slice(-6,-4),16)
    + ',' + parseInt(boxColor.slice(-4,-2),16)
    + ',' + parseInt(boxColor.slice(-2),16)
    +', ' + boxOpacity + ' )';

    this.$el.css("background-color", rgbaCol);
    this.$el.css("max-width", boxWidth);

    var fontFamilyClass = "";

    if      (fontFamily  == "DejaVu Sans Book") fontFamilyClass = "dejavu";
    else if (fontFamily  == "unifont Medium")   fontFamilyClass = "unifont";
    else if (fontFamily  == "Open Sans")        fontFamilyClass = "open_sans";

    this.$el.css("width", "auto");

    this.$el
    .removeClass("dejavu")
    .removeClass("unifont")
    .removeClass("open_sans");

    this.$el.addClass(fontFamilyClass);

  },

  _onChangeMode: function() {

    var mode = this.editModel.get("mode");

    if (mode == "editable") {

      this._enableEditingMode();

    } else {

      this._disableEditingMode();

    }

  },

  _enableEditingMode: function() {

    var text = this.model.get("text");

    this.$el
    .addClass("editable")
    .addClass("disabled");

    this.$text.attr("contenteditable", true).focus();

    this.$el.css("width", "auto");

    var self = this;

    setTimeout(function() {
      self.$text.html(text);
    }, 100)

  },

  _disableEditingMode: function() {

    var text = this._transformToMarkdown(this.model.get("text"));

    this.editModel.set("mode", "");

    if (text) {

      this.$text.html(text);

      this.$el
      .removeClass("editable")
      .removeClass("disabled");

      this.$text.attr("contenteditable", false);
      this.$el.css("width", "auto");

      var self = this;

      setTimeout(function() {
        var width = self.$el.width();
        self.$el.css("width", width);
      }, 300);

      this.model.save();

    }

  },

  _setText: function() {

    var text          = this.model.get("text");
    var rendered_text = this._transformToMarkdown(text);

    var extra = this.model.get("extra");

    extra.text          = text;
    extra.rendered_text = rendered_text

    this.model.set({ extra: extra }, { silent: true });

    if (rendered_text) this.$text.html(rendered_text);

  },

  _transformToMarkdown: function(text) {

    text = markdown.toHTML(text)

    text = text.replace(/</g, "<");
    text = text.replace(/>/g, ">");
    text = text.replace(/<p>/g, "");
    text = text.replace(/&nbsp;/g, " ");
    text = text.replace(/<\/p>/g, "");

    return text;

  },

  _addDropdown: function() {

    var device            = this.model.get("device");
    var horizontal_offset = 26;
    var vertical_offset   = 24;

    if (device === "mobile") {
      vertical_offset -= $("header").height() + 12;
    }

    this.dropdown = new cdb.admin.WidgetPropertiesDropdown({
      tick: "left",
      target: this.$el.find(".edit"),
      model: this.model,
      offset_mode: device === 'mobile' ? "offset" : "position",
      horizontal_position: "left",
      horizontal_offset: horizontal_offset,
      vertical_offset: vertical_offset,
      template_base: 'table/views/overlays/properties_dropdown',
      form_data: [{
        name: 'Text Align',
        form: {
          'text-align':      { type: 'text_align', value: 'left' },
        }
      }, {
        name: 'Text Style',
        form: {
          'font-size':  { type: 'simple_number', value: 12, min: 5, max: 50, inc: 2 },
          'color':      { type: 'color', value: '#FFF' },
        }

      }, {
        name: 'Font',
        form: {
          'font-family-name': {
            type: 'select',
            value: "Helvetica",
            extra: ["Helvetica", "DejaVu Sans Book", "unifont Medium", "Open Sans"]
          }
        }
      }, {

        name: 'Box Style',
        form: {
          'box-color':  { type: 'color', value: '#000' },
          'box-opacity':  { type: 'simple_opacity', value: .7, min:0, max:1, inc: .1 },
        }

      }, {
        name: 'Max Width',
        form: {
          'box-width':  { type: 'simple_number', value: 300, min: 50, max: 2000, inc: 10 },
        }

      }]
    });

    this._bindDropdown();

    var self = this;

    this.dropdown.on("saved", function() {
      self.dropdown.move(true);
    });

    if (this.model.get("device") == "mobile") {
      $(".map").append(this.dropdown.render().el);
    } else {
      this.$el.append(this.dropdown.render().el);
    }

  },

  _bindDropdown: function() {

    this.dropdown.bind("onDropdownShown", function() {
      this.$el.addClass("open");

      this._putOnTop();

    }, this);

    this.dropdown.bind("onDropdownHidden", function() {
      this.$el.removeClass("open");
    }, this);

    cdb.god.bind("closeDialogs", this.dropdown.hide, this.dropdown);

  },

  _putOnTop: function() {

    $(".overlay").css("z-index", 999);
    this.$el.css("z-index", 2001);

  },

  _place: function() {

    var landscapeDirection = this.model.get("extra").landscapeDirection;
    var portraitDirection  = this.model.get("extra").portraitDirection;

    if (portraitDirection == 'bottom') {

      this.$el.offset({
        top: this.model.get("y")
      });

      this.$el.css({
        top: "auto",
        bottom: this.model.get("y")
      });

    } else {
      this.$el.offset({
        top: this.model.get("y")
      });
    }

    if (landscapeDirection == 'right') {

      this.$el.offset({
        left: this.model.get("x")
      });

      this.$el.css({
        left: "auto",
        right: this.model.get("x")
      });

    } else {
      this.$el.offset({
        left: this.model.get("x")
      });
    }

  },

  render: function() {

    this._place();

    this.$el.append(this.template(this.model.attributes));

    this.$text = this.$el.find(".content div.text");

    var text = this._transformToMarkdown(this.model.get("text"));

    this.$text.html(text);

    this._applyStyle();
    this._onChangeExtra();
    this._addDropdown();

    return this;

  }

});
<commit_msg>update overlay to use the droid sans font<commit_after>cdb.admin.overlays.Text = cdb.core.View.extend({

  className: "text overlay",

  template_name: 'table/views/overlays/text',

  events: {

    "mouseup":           "_onMouseUp",
    "mousedown":         "_onMouseDown",

    "mouseenter .text":  "_onMouseEnter",
    "mouseleave .text":  "_onMouseLeave",

    "click .close":      "_close",
    "click .content":    "_click",
    "dblclick .content": "_dblClick",

    "keyup .text":       "_onKeyUp",
    "click .text":       "_killEvent",
    "paste .text":       "_onPaste"

  },

  initialize: function() {

    _.bindAll(this, "_click", "_close", "_dblClick", "_onChangeMode", "_onKeyDown", "_putOnTop");

    // Bind ESC key
    $(document).bind('keydown', this._onKeyDown);

    this.template = this.getTemplate(this.template_name);

    this._setupModels();

  },

  _killEvent: function(e) {

    e && e.preventDefault();
    e && e.stopPropagation();

  },

  // Setup the internal and custom model
  _setupModels: function() {

    var extra = this.model.get("extra");

    this.model.set({ text: extra.text }, { silent: true });

    // Binding
    this.model.bind('change:text',    this._setText,    this);
    this.model.bind('change:style',   this._applyStyle, this);
    this.model.bind('change:display', this._onChangeDisplay, this);
    this.model.bind('change:extra',   this._onChangeExtra, this);

    // Internal model to store the editing state
    this.editModel = new cdb.core.Model({ mode: "" });
    this.editModel.bind('change:mode', this._onChangeMode, this);

    this.add_related_model(this.editModel);

  },

  // Element events
  _onKeyUp: function(e) {

    var self = this;

    var temp      = "";
    var domString = "";

    if (this.timeout)       clearTimeout(this.timeout);
    if (this.keyUpTimeout)  clearTimeout(this.keyUpTimeout);
    if (this.savingTimeout) clearTimeout(this.savingTimeout);

    var value = this.$text.html();

    if (cdb.Utils.stripHTML(value) == "") {

      this.keyUpTimeout = setTimeout(function() {

        self.model.set({ text: "" }, { silent: true });
        self._close();

      }, 600);

    } else {

      this.model.set({ text: value }, { silent: true });

      if (!this.$el.hasClass("hover") && this.$text.text()) {
        this.savingTimeout = setTimeout(function() {

          self._disableEditingMode();

        }, 500);
      }
    }

  },

  _dblClick: function(e) {

    this._killEvent(e);

  },

  _click: function(e) {

    this._killEvent(e);

    this._putOnTop();

    var isLink = e.target.hasAttribute("href");

    if (!isLink) {
      cdb.god.trigger("closeDialogs");
    }

  },

  _onKeyDown: function(e) {

    if (e.keyCode === 27) {
      this.editModel.set("mode", "");
    }

  },

  _onPaste: function(e) {

    var self = this;

    setTimeout(function() {

      var text = cdb.Utils.stripHTML(self.model.get("text"));
      self.model.set("text", text)

    }, 200);

  },

  _onMouseUp: function(e) {

    // Prevents entering in the edit mode when clicking the edit button
    if (!$(e.target).parents(".overlay_text").length && !$(e.target).hasClass("overlay_text")) {
      return;
    }

    cdb.god.trigger("closeDialogs");

    var extra = this.model.get("extra");

    var x     = this.model.get("x");
    var y     = this.model.get("y");

    var oldX  = this.$el.position().left;
    var oldY  = this.$el.position().top;

    var portraitDirection  = extra.portraitDirection;
    var landscapeDirection = extra.landscapeDirection;

    if (y == 0 && portraitDirection == "bottom") oldY = y;
    if (x == 0 && landscapeDirection == "right") oldX = x;

    // If we didn't move the overlay
    if (oldX === x && y === oldY || x == 0 && landscapeDirection == "right" && y === oldY || y == 0 && portraitDirection == "bottom" && oldX === x) {

      this.dropdown.hide();
      this.editModel.set("mode", "editable");

      return;

    }

    var x = this.$el.position().left;
    var y = this.$el.position().top;

    // Default positions
    extra.portraitDirection  = "top";
    extra.landscapeDirection = "left";

    // Let's see where did we put our overlay…
    var rightSticked  = x + this.$el.width()  >= $(".cartodb-map").width();
    var bottomSticked = y + this.$el.height() >= $(".cartodb-map").height();

    if (bottomSticked) { // we sticked the overlay to the bottom of the screen

      y = 0;

      this.$el.css({ bottom: 0, top: "auto" });

      extra.portraitDirection = "bottom";

    }

    if (rightSticked) { // we sticked the overlay to the right side

      x = 0;

      this.$el.css({ right: 0, left: "auto" });

      extra.landscapeDirection = "right";

    }

    this.model.set({ extra: extra }, { silent: true});
    this.model.set({ x: x, y: y });

    this.model.save();

  },

  _onMouseDown: function() { },

  _onMouseEnter: function() {

    this.$el.addClass("hover");
    if (this.editModel.get("mode") == "editable") {
      if (this.timeout) clearTimeout(this.timeout);
    }

  },

  _onMouseLeave: function() {
    this.$el.removeClass("hover");

    var self = this;

    if (this.editModel.get("mode") == "editable") {

      this.timeout = setTimeout(function() {

        self.editModel.set("mode", "");

      }, 250);
    }

  },

  show: function(animated) {

    this.$el.show();

    if (true) this.$el.addClass('animated bounceIn');

  },

  hide: function(callback) {

    var self = this;

    this.$el
    .removeClass('animated bounceIn')
    .addClass('animated bounceOut');

    callback && callback();

    // Give it some time to complete the animation
    setTimeout(function() {
      self.clean();
    }, 550);

  },

  _close: function(e) {

    this._killEvent(e);

    var self = this;

    this.dropdown.hide();
    this.dropdown.clean();

    this.hide(function() {
      self.trigger("remove", self);
    });

  },

  _onChangeDisplay: function() {

    var display = this.model.get("display");

    if (display) {
      this.show();
    } else {
      this.$el.hide();
    }

  },

  _onChangeExtra: function() {

    var extra  = this.model.get("extra");
    extra.text = this.model.get("text");

    this.model.set({ extra: extra }, { silent: true });

  },

  /*
   * Applies style to the content of the widget
   */

  _applyStyle: function() {

    var style      = this.model.get("style");

    var boxColor   = style["box-color"];
    var boxOpacity = style["box-opacity"];
    var boxWidth   = style["box-width"];
    var fontFamily = style["font-family-name"];

    this.$text.css(style);
    this.$text.css("font-size", style["font-size"] + "px");

    var rgbaCol = 'rgba(' + parseInt(boxColor.slice(-6,-4),16)
    + ',' + parseInt(boxColor.slice(-4,-2),16)
    + ',' + parseInt(boxColor.slice(-2),16)
    +', ' + boxOpacity + ' )';

    this.$el.css("background-color", rgbaCol);
    this.$el.css("max-width", boxWidth);

    var fontFamilyClass = "";

    if      (fontFamily  == "Droid Sans") fontFamilyClass = "droid";
    else if (fontFamily  == "Vollkorn")   fontFamilyClass = "vollkorn";
    else if (fontFamily  == "Open Sans")  fontFamilyClass = "open_sans";
    else if (fontFamily  == "Roboto")     fontFamilyClass = "roboto";

    this.$el.css("width", "auto");

    this.$el
    .removeClass("droid")
    .removeClass("vollkorn")
    .removeClass("roboto")
    .removeClass("open_sans");

    this.$el.addClass(fontFamilyClass);

  },

  _onChangeMode: function() {

    var mode = this.editModel.get("mode");

    if (mode == "editable") {

      this._enableEditingMode();

    } else {

      this._disableEditingMode();

    }

  },

  _enableEditingMode: function() {

    var text = this.model.get("text");

    this.$el
    .addClass("editable")
    .addClass("disabled");

    this.$text.attr("contenteditable", true).focus();

    this.$el.css("width", "auto");

    var self = this;

    setTimeout(function() {
      self.$text.html(text);
    }, 100)

  },

  _disableEditingMode: function() {

    var text = this._transformToMarkdown(this.model.get("text"));

    this.editModel.set("mode", "");

    if (text) {

      this.$text.html(text);

      this.$el
      .removeClass("editable")
      .removeClass("disabled");

      this.$text.attr("contenteditable", false);
      this.$el.css("width", "auto");

      var self = this;

      setTimeout(function() {
        var width = self.$el.width();
        self.$el.css("width", width);
      }, 300);

      this.model.save();

    }

  },

  _setText: function() {

    var text          = this.model.get("text");
    var rendered_text = this._transformToMarkdown(text);

    var extra = this.model.get("extra");

    extra.text          = text;
    extra.rendered_text = rendered_text

    this.model.set({ extra: extra }, { silent: true });

    if (rendered_text) this.$text.html(rendered_text);

  },

  _transformToMarkdown: function(text) {

    text = markdown.toHTML(text)

    text = text.replace(/</g, "<");
    text = text.replace(/>/g, ">");
    text = text.replace(/<p>/g, "");
    text = text.replace(/&nbsp;/g, " ");
    text = text.replace(/<\/p>/g, "");

    return text;

  },

  _addDropdown: function() {

    var device            = this.model.get("device");
    var horizontal_offset = 26;
    var vertical_offset   = 24;

    if (device === "mobile") {
      vertical_offset -= $("header").height() + 12;
    }

    this.dropdown = new cdb.admin.WidgetPropertiesDropdown({
      tick: "left",
      target: this.$el.find(".edit"),
      model: this.model,
      offset_mode: device === 'mobile' ? "offset" : "position",
      horizontal_position: "left",
      horizontal_offset: horizontal_offset,
      vertical_offset: vertical_offset,
      template_base: 'table/views/overlays/properties_dropdown',
      form_data: [{
        name: 'Text Align',
        form: {
          'text-align':      { type: 'text_align', value: 'left' },
        }
      }, {
        name: 'Text Style',
        form: {
          'font-size':  { type: 'simple_number', value: 12, min: 5, max: 50, inc: 2 },
          'color':      { type: 'color', value: '#FFF' },
        }

      }, {
        name: 'Font',
        form: {
          'font-family-name': {
            type: 'select',
            value: "Helvetica",
            extra: ["Helvetica", "Droid Sans", "Vollkorn", "Roboto", "Open Sans"]
          }
        }
      }, {

        name: 'Box Style',
        form: {
          'box-color':  { type: 'color', value: '#000' },
          'box-opacity':  { type: 'simple_opacity', value: .7, min:0, max:1, inc: .1 },
        }

      }, {
        name: 'Max Width',
        form: {
          'box-width':  { type: 'simple_number', value: 300, min: 50, max: 2000, inc: 10 },
        }

      }]
    });

    this._bindDropdown();

    var self = this;

    this.dropdown.on("saved", function() {
      self.dropdown.move(true);
    });

    if (this.model.get("device") == "mobile") {
      $(".map").append(this.dropdown.render().el);
    } else {
      this.$el.append(this.dropdown.render().el);
    }

  },

  _bindDropdown: function() {

    this.dropdown.bind("onDropdownShown", function() {
      this.$el.addClass("open");

      this._putOnTop();

    }, this);

    this.dropdown.bind("onDropdownHidden", function() {
      this.$el.removeClass("open");
    }, this);

    cdb.god.bind("closeDialogs", this.dropdown.hide, this.dropdown);

  },

  _putOnTop: function() {

    $(".overlay").css("z-index", 999);
    this.$el.css("z-index", 2001);

  },

  _place: function() {

    var landscapeDirection = this.model.get("extra").landscapeDirection;
    var portraitDirection  = this.model.get("extra").portraitDirection;

    if (portraitDirection == 'bottom') {

      this.$el.offset({
        top: this.model.get("y")
      });

      this.$el.css({
        top: "auto",
        bottom: this.model.get("y")
      });

    } else {
      this.$el.offset({
        top: this.model.get("y")
      });
    }

    if (landscapeDirection == 'right') {

      this.$el.offset({
        left: this.model.get("x")
      });

      this.$el.css({
        left: "auto",
        right: this.model.get("x")
      });

    } else {
      this.$el.offset({
        left: this.model.get("x")
      });
    }

  },

  render: function() {

    this._place();

    this.$el.append(this.template(this.model.attributes));

    this.$text = this.$el.find(".content div.text");

    var text = this._transformToMarkdown(this.model.get("text"));

    this.$text.html(text);

    this._applyStyle();
    this._onChangeExtra();
    this._addDropdown();

    return this;

  }

});
<|endoftext|>