<commit_before>/* jshint expr:true */

/* The intent is for this to only add unit tests to this file going forward.
 *
 * XXX Before long, we're going to want to create a home for backend functional
 * tests, and move many of the tests that current live in this file there.
 */

var EventEmitter = require( "events" ).EventEmitter;

var chai = require("chai");
var expect = chai.expect;
var sinon = require("sinon");
var https = require("https");

require("../../server/server");
var presence = require("../../server/presence");
var logger = require("../../server/logger");

describe("presence", function() {

  var sandbox;
  var api = presence.api;
  var users = presence._users;

  beforeEach(function() {
    sandbox = sinon.sandbox.create();
  });

  afterEach(function() {
    users.forEach(function(user) {
      users.remove(user.nick);
    });
    sandbox.restore();
  });

  describe("api", function() {

    // XXX: this method is private but critical. That's why we have
    // test coverage for it. In the future we might pull it out into a
    // separate object as a way to separate concerns.
    describe("#_verifyAssertion", function() {

      var oldEnv;

      before(function() {
        oldEnv = process.env.NODE_ENV;
        process.env.NODE_ENV = "development";
      });

      after(function() {
        process.env.NODE_ENV = oldEnv;
      });

      it("should send a secure http request to the verifier service",
        function() {
          var request = {write: function() {}, end: function() {}};
          var options = {
            host: "verifier.login.persona.org",
            path: "/verify",
            method: "POST"
          };
          sandbox.stub(https, "request").returns(request);
          api._verifyAssertion("fake assertion data", function() {});

          sinon.assert.calledOnce(https.request);
          sinon.assert.calledWith(https.request, sinon.match(options));
        });

      it("should trigger without error if the assertion is valid",
        function() {
          var assertionCallback = sinon.spy();
          var response = new EventEmitter();
          var request = {write: function() {}, end: function() {}};
          var answer = {
            status: "okay",
            email: "john.doe@mozilla.com"
          };
          response.setEncoding = function() {};

          sandbox.stub(https, "request", function(options, callback) {
            callback(response);
            return request;
          });
          api._verifyAssertion("fake assertion data", assertionCallback);

          response.emit("data", JSON.stringify(answer));
          response.emit("end");

          sinon.assert.calledOnce(assertionCallback);
          sinon.assert.calledWithExactly(
            assertionCallback, null, answer.email);
        });

      it("should trigger with an error if the assertion is invalid",
        function() {
          var assertionCallback = sinon.spy();
          var response = new EventEmitter();
          var request = {write: function() {}, end: function() {}};
          var answer = {
            status: "not okay",
            reason: "invalid assertion"
          };
          response.setEncoding = function() {};

          sandbox.stub(https, "request", function(options, callback) {
            callback(response);
            return request;
          });
          api._verifyAssertion("fake assertion data", assertionCallback);

          response.emit("data", JSON.stringify(answer));
          response.emit("end");

          sinon.assert.calledOnce(assertionCallback);
          sinon.assert.calledWithExactly(
            assertionCallback, answer.reason);
        });
    });

    describe("#signin", function() {

      it("should add a new user to the user list and return the nick",
        function(done) {
          var req = {body: {assertion: "fake assertion"}};
          var res = {send: sinon.spy()};
          var answer = JSON.stringify({nick: "foo"});
          sandbox.stub(presence.api, "_verifyAssertion", function(a, c) {
            c(null, "foo");

            expect(users.get("foo")).to.not.equal(undefined);

            sinon.assert.calledOnce(res.send);
            sinon.assert.calledWithExactly(res.send, 200, answer);
            done();
          });

          api.signin(req, res);
        });

      it("should return a 400 if the assertion was invalid", function(done) {
        var req = {body: {assertion: "fake assertion"}};
        var res = {send: sinon.spy()};
        var answer = JSON.stringify({error: "invalid assertion"});
        sandbox.stub(presence.api, "_verifyAssertion", function(a, c) {
          c("invalid assertion");

          expect(users.get("foo")).to.equal(undefined);

          sinon.assert.calledOnce(res.send);
          sinon.assert.calledWithExactly(res.send, 400, answer);
          done();
        });

        api.signin(req, res);
      });

    });

    describe("#signout", function() {

      it("should remove the user from the user list", function() {
        var req = {body: {nick: "foo"}};
        var res = {send: sinon.spy()};

        users.add("foo");
        api.signout(req, res);
        expect(users.get("foo")).to.equal(undefined);

        sinon.assert.calledOnce(res.send);
        sinon.assert.calledWith(res.send, 200);
      });

    });

    describe("#stream", function() {

      it("should send an empty list of events", function(done) {
        var user = users.add("foo").get("foo");
        var req = {body: {nick: "foo"}};
        var res = {send: function(code, data) {
          expect(code).to.equal(200);
          expect(data).to.equal(JSON.stringify([]));
          done();
        }};
        sandbox.stub(user, "present").returns(true);

        api.stream(req, res);
      });

      it("should send a list of events", function(done) {
        var user = users.add("foo").get("foo");
        var event = {some: "data"};
        var req = {body: {nick: "foo"}};
        var res = {send: function(code, data) {
          expect(code).to.equal(200);
          expect(data).to.equal(JSON.stringify([event]));
          done();
        }};
        sandbox.stub(user, "present").returns(true);

        api.stream(req, res);
        user.send(event);
      });

      it("should fail if no nick is provided", function() {
        var req = {body: {}};
        var res = {send: sinon.spy()};

        api.stream(req, res);

        sinon.assert.calledOnce(res.send);
        sinon.assert.calledWithExactly(res.send, 400, JSON.stringify({}));
      });

    });

    describe("#callOffer", function() {

      it("should forward the event to the peer after swapping the nick",
        function() {
          var req = {body: {data: {peer: "bar"}, nick: "foo"}};
          var res = {send: function() {}};
          var forwardedEvent = {peer: "foo"};
          var bar = users.add("foo").add("bar").get("bar");
          sandbox.stub(bar, "send");

          api.callOffer(req, res);

          sinon.assert.calledOnce(bar.send);
          sinon.assert.calledWith(
            bar.send, {"incoming_call": forwardedEvent});
        });

      it("should warn on handling offers to unknown users", function() {
        sandbox.stub(logger, "warn");
        var req = {body: {data: {peer: "bar"}}};
        var res = {send: function() {}};

        api.callOffer(req, res);

        sinon.assert.calledOnce(logger.warn);
      });

    });

    describe("#callAccepted", function() {

      it("should forward the event to the peer after swapping the nick",
        function() {
          var req = {body: {data: {peer: "bar"}, nick: "foo"}};
          var res = {send: function() {}};
          var forwardedEvent = {peer: "foo"};
          var bar = users.add("foo").add("bar").get("bar");
          sandbox.stub(bar, "send");

          api.callAccepted(req, res);

          sinon.assert.calledOnce(bar.send);
          sinon.assert.calledWith(
            bar.send, {"call_accepted": forwardedEvent});
        });

      it("should warn on handling answers to unknown users", function() {
        sandbox.stub(logger, "warn");
        var req = {body: {data: {peer: "bar"}}};
        var res = {send: function() {}};

        api.callAccepted(req, res);

        sinon.assert.calledOnce(logger.warn);
      });
    });

    describe("#callHangup", function() {

      it("should forward the event to the peer after swapping the nick",
        function() {
          var req = {body: {data: {peer: "bar"}, nick: "foo"}};
          var res = {send: function() {}};
          var forwardedEvent = {peer: "foo"};
          var bar = users.add("foo").add("bar").get("bar");
          sandbox.stub(bar, "send");

          api.callHangup(req, res);

          sinon.assert.calledOnce(bar.send);
          sinon.assert.calledWith(
            bar.send, {"call_hangup": forwardedEvent});
        });

      it("should warn on handling hangups to unknown users", function() {
        sandbox.stub(logger, "warn");
        var req = {body: {data: {peer: "bar"}}};
        var res = {send: function() {}};

        api.callHangup(req, res);

        sinon.assert.calledOnce(logger.warn);
      });
    });

    describe("#presenceRequest", function() {

      it("should send the list of present users to the given user",
        function() {
          var req = {body: {nick: "foo"}};
          var res = {send: sinon.spy()};
          var foo = users.add("foo").get("foo");
          var bar = users.add("bar").get("bar");
          sandbox.stub(users, "present").returns([bar]);
          sandbox.stub(foo, "send");

          api.presenceRequest(req, res);

          sinon.assert.calledOnce(foo.send);
          sinon.assert.calledWithExactly(foo.send, {users: [bar.toJSON()]});
        });

    });
  });
});
<commit_msg>Server: add a test for /stream<commit_after>/* jshint expr:true */

/* The intent is for this to only add unit tests to this file going forward.
 *
 * XXX Before long, we're going to want to create a home for backend functional
 * tests, and move many of the tests that current live in this file there.
 */

var EventEmitter = require( "events" ).EventEmitter;

var chai = require("chai");
var expect = chai.expect;
var sinon = require("sinon");
var https = require("https");

require("../../server/server");
var presence = require("../../server/presence");
var logger = require("../../server/logger");

describe("presence", function() {

  var sandbox;
  var api = presence.api;
  var users = presence._users;

  beforeEach(function() {
    sandbox = sinon.sandbox.create();
  });

  afterEach(function() {
    users.forEach(function(user) {
      users.remove(user.nick);
    });
    sandbox.restore();
  });

  describe("api", function() {

    // XXX: this method is private but critical. That's why we have
    // test coverage for it. In the future we might pull it out into a
    // separate object as a way to separate concerns.
    describe("#_verifyAssertion", function() {

      var oldEnv;

      before(function() {
        oldEnv = process.env.NODE_ENV;
        process.env.NODE_ENV = "development";
      });

      after(function() {
        process.env.NODE_ENV = oldEnv;
      });

      it("should send a secure http request to the verifier service",
        function() {
          var request = {write: function() {}, end: function() {}};
          var options = {
            host: "verifier.login.persona.org",
            path: "/verify",
            method: "POST"
          };
          sandbox.stub(https, "request").returns(request);
          api._verifyAssertion("fake assertion data", function() {});

          sinon.assert.calledOnce(https.request);
          sinon.assert.calledWith(https.request, sinon.match(options));
        });

      it("should trigger without error if the assertion is valid",
        function() {
          var assertionCallback = sinon.spy();
          var response = new EventEmitter();
          var request = {write: function() {}, end: function() {}};
          var answer = {
            status: "okay",
            email: "john.doe@mozilla.com"
          };
          response.setEncoding = function() {};

          sandbox.stub(https, "request", function(options, callback) {
            callback(response);
            return request;
          });
          api._verifyAssertion("fake assertion data", assertionCallback);

          response.emit("data", JSON.stringify(answer));
          response.emit("end");

          sinon.assert.calledOnce(assertionCallback);
          sinon.assert.calledWithExactly(
            assertionCallback, null, answer.email);
        });

      it("should trigger with an error if the assertion is invalid",
        function() {
          var assertionCallback = sinon.spy();
          var response = new EventEmitter();
          var request = {write: function() {}, end: function() {}};
          var answer = {
            status: "not okay",
            reason: "invalid assertion"
          };
          response.setEncoding = function() {};

          sandbox.stub(https, "request", function(options, callback) {
            callback(response);
            return request;
          });
          api._verifyAssertion("fake assertion data", assertionCallback);

          response.emit("data", JSON.stringify(answer));
          response.emit("end");

          sinon.assert.calledOnce(assertionCallback);
          sinon.assert.calledWithExactly(
            assertionCallback, answer.reason);
        });
    });

    describe("#signin", function() {

      it("should add a new user to the user list and return the nick",
        function(done) {
          var req = {body: {assertion: "fake assertion"}};
          var res = {send: sinon.spy()};
          var answer = JSON.stringify({nick: "foo"});
          sandbox.stub(presence.api, "_verifyAssertion", function(a, c) {
            c(null, "foo");

            expect(users.get("foo")).to.not.equal(undefined);

            sinon.assert.calledOnce(res.send);
            sinon.assert.calledWithExactly(res.send, 200, answer);
            done();
          });

          api.signin(req, res);
        });

      it("should return a 400 if the assertion was invalid", function(done) {
        var req = {body: {assertion: "fake assertion"}};
        var res = {send: sinon.spy()};
        var answer = JSON.stringify({error: "invalid assertion"});
        sandbox.stub(presence.api, "_verifyAssertion", function(a, c) {
          c("invalid assertion");

          expect(users.get("foo")).to.equal(undefined);

          sinon.assert.calledOnce(res.send);
          sinon.assert.calledWithExactly(res.send, 400, answer);
          done();
        });

        api.signin(req, res);
      });

    });

    describe("#signout", function() {

      it("should remove the user from the user list", function() {
        var req = {body: {nick: "foo"}};
        var res = {send: sinon.spy()};

        users.add("foo");
        api.signout(req, res);
        expect(users.get("foo")).to.equal(undefined);

        sinon.assert.calledOnce(res.send);
        sinon.assert.calledWith(res.send, 200);
      });

    });

    describe("#stream", function() {

      it("should send to all the present users an new one joined", function() {
        var foo = users.add("foo").get("foo");
        var bar = users.add("bar").get("bar");
        var xoo = users.add("xoo").get("xoo");
        var oof = users.add("oof").get("oof");
        var req = {body: {nick: "foo"}};
        var res = {send: function() {}};
        sandbox.stub(bar, "present").returns(true);
        sandbox.stub(xoo, "present").returns(true);
        sandbox.stub(bar, "send").returns(true);
        sandbox.stub(xoo, "send").returns(true);
        sandbox.stub(oof, "send").returns(true);

        api.stream(req, res);

        sinon.assert.calledOnce(bar.send);
        sinon.assert.calledWith(bar.send, {userJoined: "foo"});
        sinon.assert.calledOnce(xoo.send);
        sinon.assert.calledWith(xoo.send, {userJoined: "foo"});
        sinon.assert.notCalled(oof.send);
      });

      it("should send an empty list of events", function(done) {
        var user = users.add("foo").get("foo");
        var req = {body: {nick: "foo"}};
        var res = {send: function(code, data) {
          expect(code).to.equal(200);
          expect(data).to.equal(JSON.stringify([]));
          done();
        }};
        sandbox.stub(user, "present").returns(true);

        api.stream(req, res);
      });

      it("should send a list of events", function(done) {
        var user = users.add("foo").get("foo");
        var event = {some: "data"};
        var req = {body: {nick: "foo"}};
        var res = {send: function(code, data) {
          expect(code).to.equal(200);
          expect(data).to.equal(JSON.stringify([event]));
          done();
        }};
        sandbox.stub(user, "present").returns(true);

        api.stream(req, res);
        user.send(event);
      });

      it("should fail if no nick is provided", function() {
        var req = {body: {}};
        var res = {send: sinon.spy()};

        api.stream(req, res);

        sinon.assert.calledOnce(res.send);
        sinon.assert.calledWithExactly(res.send, 400, JSON.stringify({}));
      });

    });

    describe("#callOffer", function() {

      it("should forward the event to the peer after swapping the nick",
        function() {
          var req = {body: {data: {peer: "bar"}, nick: "foo"}};
          var res = {send: function() {}};
          var forwardedEvent = {peer: "foo"};
          var bar = users.add("foo").add("bar").get("bar");
          sandbox.stub(bar, "send");

          api.callOffer(req, res);

          sinon.assert.calledOnce(bar.send);
          sinon.assert.calledWith(
            bar.send, {"incoming_call": forwardedEvent});
        });

      it("should warn on handling offers to unknown users", function() {
        sandbox.stub(logger, "warn");
        var req = {body: {data: {peer: "bar"}}};
        var res = {send: function() {}};

        api.callOffer(req, res);

        sinon.assert.calledOnce(logger.warn);
      });

    });

    describe("#callAccepted", function() {

      it("should forward the event to the peer after swapping the nick",
        function() {
          var req = {body: {data: {peer: "bar"}, nick: "foo"}};
          var res = {send: function() {}};
          var forwardedEvent = {peer: "foo"};
          var bar = users.add("foo").add("bar").get("bar");
          sandbox.stub(bar, "send");

          api.callAccepted(req, res);

          sinon.assert.calledOnce(bar.send);
          sinon.assert.calledWith(
            bar.send, {"call_accepted": forwardedEvent});
        });

      it("should warn on handling answers to unknown users", function() {
        sandbox.stub(logger, "warn");
        var req = {body: {data: {peer: "bar"}}};
        var res = {send: function() {}};

        api.callAccepted(req, res);

        sinon.assert.calledOnce(logger.warn);
      });
    });

    describe("#callHangup", function() {

      it("should forward the event to the peer after swapping the nick",
        function() {
          var req = {body: {data: {peer: "bar"}, nick: "foo"}};
          var res = {send: function() {}};
          var forwardedEvent = {peer: "foo"};
          var bar = users.add("foo").add("bar").get("bar");
          sandbox.stub(bar, "send");

          api.callHangup(req, res);

          sinon.assert.calledOnce(bar.send);
          sinon.assert.calledWith(
            bar.send, {"call_hangup": forwardedEvent});
        });

      it("should warn on handling hangups to unknown users", function() {
        sandbox.stub(logger, "warn");
        var req = {body: {data: {peer: "bar"}}};
        var res = {send: function() {}};

        api.callHangup(req, res);

        sinon.assert.calledOnce(logger.warn);
      });
    });

    describe("#presenceRequest", function() {

      it("should send the list of present users to the given user",
        function() {
          var req = {body: {nick: "foo"}};
          var res = {send: sinon.spy()};
          var foo = users.add("foo").get("foo");
          var bar = users.add("bar").get("bar");
          sandbox.stub(users, "present").returns([bar]);
          sandbox.stub(foo, "send");

          api.presenceRequest(req, res);

          sinon.assert.calledOnce(foo.send);
          sinon.assert.calledWithExactly(foo.send, {users: [bar.toJSON()]});
        });

    });
  });
});
<|endoftext|>


<commit_before>'use strict';

describeComponent('lib/flight-yql', function () {

  // Initialize the component and attach it to the DOM
  beforeEach(function () {
    setupComponent();
  });

  it('should be defined', function () {
    expect(this.component).toBeDefined();
  });

  it('should have the base uri set correctly for yql', function() {
    var expected = 'https://query.yahooapis.com/v1/public/yql';

    expect(this.component.attr.baseUri).toEqual(expected);
  });

  it('should set default options for request as method GET', function() {
    var expected = 'GET';

    expect(this.component.options.method).toEqual(expected);
  });

  it('should set the default headers of request to form encoded header',
     function() {
    var expected =  {'Content-type': 'application/x-www-form-urlencoded'};

    expect(this.component.options.headers).toEqual(expected);
  });

  describe('query()', function() {
    var server;

    beforeEach(function() {
      server = sinon.fakeServer.create();
    });

    afterEach(function() {
      server.restore();
    });

    it('should throw an error if there is no query passed in', function() {
      var expected = new Error(this.component.attr.ERROR_NO_QUERY),
          self = this;
      expect(function() {
        self.component.query();
      }).toThrow(expected);
    });
    it('should throw an error if the query is not a string', function() {
      var expected = new Error(this.component.attr.ERROR_MALFORMED_QUERY),
          self = this;

      expect(function() {
        self.component.query({});
      }).toThrow(expected);

      expect(function() {
        self.component.query([]);
      }).toThrow(expected);

      expect(function() {
        self.component.query(1);
      }).toThrow(expected);

      expect(function() {
        self.component.query(true);
      }).toThrow(expected);
    });
    it('should throw an error if callback is not a function', function() {
      var expected = new Error(this.component.attr.ERROR_CB_NOT_A_FUNCTION),
          self = this;

      expect(function() {
        self.component.query('hello', 'world');
      }).toThrow(expected);
    });
    it('should return a jquery deferred', function() {
      var actual = this.component.query('hello', function(){});

      expect(actual.then).toBeDefined();
    });
    it('should always make a GET request by default', function() {
      this.component.query('a', function(){});

      expect(server.requests[0]).toBeDefined();
      expect(server.requests[0].method).toEqual('GET');
    });
    it('should set the format attribute to JSON by default', function() {
      this.component.query('a', function(){});

      expect(server.requests[0]).toBeDefined();
      expect(server.requests[0].url.search('format=JSON')).toBeTruthy();
    });
    it('should set the q attribute to the query passed in', function() {
      this.component.query('a', function(){});

      expect(server.requests[0]).toBeDefined();
      expect(server.requests[0].url.search('q=a')).toBeTruthy();
    });
  });
});
<commit_msg>Broke test removed unused one<commit_after>'use strict';

describeComponent('lib/flight-yql', function () {

  // Initialize the component and attach it to the DOM
  beforeEach(function () {
    setupComponent();
  });

  it('should be defined', function () {
    expect(this.component).toBeDefined();
  });

  it('should have the base uri set correctly for yql', function() {
    var expected = 'https://query.yahooapis.com/v1/public/yql';

    expect(this.component.attr.baseUri).toEqual(expected);
  });

  it('should set the default headers of request to form encoded header',
     function() {
    var expected =  {'Content-type': 'application/x-www-form-urlencoded'};

    expect(this.component.options.headers).toEqual(expected);
  });

  describe('query()', function() {
    var server;

    beforeEach(function() {
      server = sinon.fakeServer.create();
    });

    afterEach(function() {
      server.restore();
    });

    it('should throw an error if there is no query passed in', function() {
      var expected = new Error(this.component.attr.ERROR_NO_QUERY),
          self = this;
      expect(function() {
        self.component.query();
      }).toThrow(expected);
    });
    it('should throw an error if the query is not a string', function() {
      var expected = new Error(this.component.attr.ERROR_MALFORMED_QUERY),
          self = this;

      expect(function() {
        self.component.query({});
      }).toThrow(expected);

      expect(function() {
        self.component.query([]);
      }).toThrow(expected);

      expect(function() {
        self.component.query(1);
      }).toThrow(expected);

      expect(function() {
        self.component.query(true);
      }).toThrow(expected);
    });
    it('should throw an error if callback is not a function', function() {
      var expected = new Error(this.component.attr.ERROR_CB_NOT_A_FUNCTION),
          self = this;

      expect(function() {
        self.component.query('hello', 'world');
      }).toThrow(expected);
    });
    it('should return a jquery deferred', function() {
      var actual = this.component.query('hello', function(){});

      expect(actual.then).toBeDefined();
    });
    it('should always make a GET request by default', function() {
      this.component.query('a', function(){});

      expect(server.requests[0]).toBeDefined();
      expect(server.requests[0].method).toEqual('GET');
    });
    it('should set the format attribute to JSON by default', function() {
      this.component.query('a', function(){});

      expect(server.requests[0]).toBeDefined();
      expect(server.requests[0].url.search('format=JSON')).toBeTruthy();
    });
    it('should set the q attribute to the query passed in', function() {
      this.component.query('a', function(){});

      expect(server.requests[0]).toBeDefined();
      expect(server.requests[0].url.search('q=a')).toBeTruthy();
    });
  });
});
<|endoftext|>


<commit_before>/*jshint white: false, strict: false, plusplus: false, onevar: false,
  nomen: false */
/*global define: false, console: false, window: false, setTimeout: false */

define( function ( require ) {

    var Event = require( './event' );

    /* Entity
     *
     * An entity is a collection of entity components under a single globally unique identifier.
     */

    return function( engine ) {

        var Entity = function( options ) {

            options = options || {};
            var that = this;

            // Members

            var _guid = window.guid();                 // Globally-unique ID
            Object.defineProperty( this, 'id', {
                get: function() {
                    return _guid;
                }
            });

            var _name = options.name || null;           // Name string
            Object.defineProperty( this, 'name', {
                get: function() {
                    return _name;
                }
            });

            var _parent = options.parent || null;       // Parent entity, or null if no parent
            Object.defineProperty( this, 'parent', {
                get: function() {
                    return _parent;
                },
                set: function( value ) {
                    if( value != this && value != _parent ) {
                        var previous = _parent;
                        _parent = value;
                        onParentChanged({
                            previous: previous,
                            current: value
                        });
                    }
                }
            });

            var _manager = options.manager || null;     // Component manager
            Object.defineProperty( this, 'manager', {
                get: function() {
                    return _manager;
                },
                set: function( value ) {
                    _manager = value;
                }
            });

            var _size = 0;
            Object.defineProperty( this, 'size', {
                get: function() {
                    return _size;
                }
            });

            var _components = {};       // Dictionary of components, indexed by component type

            // Methods

            // Add a component and return the previous component of the same type, or null.
            this.add = function( component ) {
                var previousComponent = that.remove( component.type );
                component.owner = that;
                _components[component.type] = component;
                ++ _size;
                onComponentAdded( component );
                return previousComponent || null;
            };

            // Remove a component and return it, or null.
            this.remove = function( type ) {
                var previousComponent;
                if( _components.hasOwnProperty( type ) ) {
                    previousComponent = _components[type];
                    delete _components[type];
                    previousComponent.owner = null;
                    -- _size;
                    onComponentRemoved( previousComponent );
                }
                return previousComponent || null;
            };

            // Find the first occurence of a component with a given type and return it, or null.
            this.find = function( type ) {
                if( !_components.hasOwnProperty( type ) )
                    return null;

                return _components[type];
            };

            // Return true if this entity has a component with a given type, or false.
            this.contains = function( type ) {
                return _components.hasOwnProperty( type );
            };

            // Events

            var _parentChanged = new Event();
            Object.defineProperty( this, 'parentChanged', {
                get: function() {
                    return _parentChanged;
                }
            });
            var onParentChanged = function( options ) {
                if( _parentChanged ) {
                    _parentChanged( options );
                }
            };

            var _managerChanged = new Event();
            Object.defineProperty( this, 'managerChanged', {
                get: function() {
                    return _managerChanged;
                }
            });
            var onManagerChanged = function( options ) {
                if( _managerChanged ) {
                    _managerChanged( options );
                }
            };

            var _childAdded = new Event();
            Object.defineProperty( this, 'childAdded', {
                get: function() {
                    return _childAdded;
                }
            });
            var onChildAdded = function( options ) {
                if( _childAdded ) {
                    _childAdded( options );
                }
            };

            var _childRemoved = new Event();
            Object.defineProperty( this, 'childRemoved', {
                get: function() {
                    return _childRemoved;
                }
            });
            var onChildRemoved = function( options ) {
                if( _childRemoved ) {
                    _childRemoved( options );
                }
            };

            var _componentAdded = new Event();
            Object.defineProperty( this, 'componentAdded', {
                get: function() {
                    return _componentAdded;
                }
            });
            var onComponentAdded = function( component ) {
                if( _componentAdded ) {
                    _componentAdded( component );
                }
            };

            var _componentRemoved = new Event();
            Object.defineProperty( this, 'componentRemoved', {
                get: function() {
                    return _componentRemoved;
                }
            });
            var onComponentRemoved = function( component ) {
                if( _componentRemoved ) {
                    _componentRemoved( component );
                }
            };

        };

        return Entity;

    };

});
<commit_msg>Event triggers and handlers for addChild and removeChild.<commit_after>/*jshint white: false, strict: false, plusplus: false, onevar: false,
  nomen: false */
/*global define: false, console: false, window: false, setTimeout: false */

define( function ( require ) {

    var Event = require( './event' );

    /* Entity
     *
     * An entity is a collection of entity components under a single globally unique identifier.
     */

    return function( engine ) {

        var Entity = function( options ) {

            options = options || {};
            var that = this;

            // Members

            var _guid = window.guid();                 // Globally-unique ID
            Object.defineProperty( this, 'id', {
                get: function() {
                    return _guid;
                }
            });

            var _name = options.name || null;           // Name string
            Object.defineProperty( this, 'name', {
                get: function() {
                    return _name;
                }
            });

            var _parent = options.parent || null;       // Parent entity, or null if no parent
            Object.defineProperty( this, 'parent', {
                get: function() {
                    return _parent;
                },
                set: function( value ) {
                    if( value != this && value != _parent ) {
                        if( _parent ) {
                            parent.childRemoved( this );
                        }

                        var previous = _parent;
                        _parent = value;
                        onParentChanged({
                            previous: previous,
                            current: value
                        });

                        if( _parent ) {
                            parent.childAdded( this );
                        }
                    }
                }
            });

            var _children = {};

            var _manager = options.manager || null;     // Component manager
            Object.defineProperty( this, 'manager', {
                get: function() {
                    return _manager;
                },
                set: function( value ) {
                    _manager = value;
                }
            });

            var _size = 0;
            Object.defineProperty( this, 'size', {
                get: function() {
                    return _size;
                }
            });

            var _components = {};       // Dictionary of components, indexed by component type

            // Methods

            // Add a component and return the previous component of the same type, or null.
            this.add = function( component ) {
                var previousComponent = that.remove( component.type );
                component.owner = that;
                _components[component.type] = component;
                ++ _size;
                onComponentAdded( component );
                return previousComponent || null;
            };

            // Remove a component and return it, or null.
            this.remove = function( type ) {
                var previousComponent;
                if( _components.hasOwnProperty( type ) ) {
                    previousComponent = _components[type];
                    delete _components[type];
                    previousComponent.owner = null;
                    -- _size;
                    onComponentRemoved( previousComponent );
                }
                return previousComponent || null;
            };

            // Find the first occurence of a component with a given type and return it, or null.
            this.find = function( type ) {
                if( !_components.hasOwnProperty( type ) )
                    return null;

                return _components[type];
            };

            // Return true if this entity has a component with a given type, or false.
            this.contains = function( type ) {
                return _components.hasOwnProperty( type );
            };

            // Events

            var _parentChanged = new Event();
            Object.defineProperty( this, 'parentChanged', {
                get: function() {
                    return _parentChanged;
                }
            });
            var onParentChanged = function( options ) {
                if( _parentChanged ) {
                    _parentChanged( options );
                }
            };

            var _managerChanged = new Event();
            Object.defineProperty( this, 'managerChanged', {
                get: function() {
                    return _managerChanged;
                }
            });
            var onManagerChanged = function( options ) {
                if( _managerChanged ) {
                    _managerChanged( options );
                }
            };

            var _childAdded = new Event();
            Object.defineProperty( this, 'childAdded', {
                get: function() {
                    return _childAdded;
                }
            });
            var onChildAdded = function( options ) {
                if( _childAdded ) {
                    _childAdded( options );
                }
            };

            var _childRemoved = new Event();
            Object.defineProperty( this, 'childRemoved', {
                get: function() {
                    return _childRemoved;
                }
            });
            var onChildRemoved = function( options ) {
                if( _childRemoved ) {
                    _childRemoved( options );
                }
            };

            var _componentAdded = new Event();
            Object.defineProperty( this, 'componentAdded', {
                get: function() {
                    return _componentAdded;
                }
            });
            var onComponentAdded = function( component ) {
                if( _componentAdded ) {
                    _componentAdded( component );
                }
            };

            var _componentRemoved = new Event();
            Object.defineProperty( this, 'componentRemoved', {
                get: function() {
                    return _componentRemoved;
                }
            });
            var onComponentRemoved = function( component ) {
                if( _componentRemoved ) {
                    _componentRemoved( component );
                }
            };

            // Event handlers

            var handleChildAdded = function( child ) {
                _children[child.id] = child;
            };
            childAdded.subscribe( handleChildAdded );

            var handleChildRemoved = function( child ) {
                delete _children[child.id];
            };
            childRemoved.subscribe( handleChildRemoved );

        };

        return Entity;

    };

});
<|endoftext|>


<commit_before>/**
 * @name pc.events
 * @namespace
 * @description Extend any normal object with events
 *
 * @example var o = {};
 * o = pc.extend(o, pc.events);
 *
 * // attach event
 * o.on("event_name", function() {
 *   alert('event_name fired');
 * }, this);
 *
 * // fire event
 * o.fire("event_name");
 *
 * // detach all events from object
 * o.off('event_name');
 */
pc.events = function () {

    var Events = {
        /**
        * @function
        * @name pc.events.attach
        * @description Attach event methods 'on', 'off', 'fire' and 'hasEvent' to the target object
        * @param  {Object} target The object to add events to.
        * @return {Object} The target object
        */
        attach: function (target) {
            var ev = pc.events;
            target.on = ev.on;
            target.off = ev.off;
            target.fire = ev.fire;
            target.once = ev.once;
            target.hasEvent = ev.hasEvent;
            target.bind = ev.on;
            target.unbind = ev.off;
            return target;
        },

        /**
         * @function
         * @name pc.events.on
         * @description Attach an event handler to an event
         * @param {String} name Name of the event to bind the callback to
         * @param {Function} callback Function that is called when event is fired
         * @param {Object} [scope] Object to use as 'this' when the event is fired, defaults to current this
         * @example var o = {};
         * pc.events.attach(o);
         * o.on('event_name', function (a, b) {
         *   console.log(a + b);
         * });
         * o.fire('event_name', 1, 2); // prints 3 to the console
         */
        on: function (name, callback, scope) {
            if(pc.type(name) != "string") {
                throw new TypeError("Event name must be a string");
            }
            var callbacks = this._callbacks || (this._callbacks = {});
            var events = callbacks[name] || (callbacks[name] = []);
            events.push({
                callback: callback,
                scope: scope || this
            });

            return this;
        },

        /**
         * @function
         * @name pc.events.off
         * @description Detach an event handler from an event. If callback is not provided then all callbacks are unbound from the event,
         * if scope is not provided then all events with the callback will be unbound.
         * @param {String} name Name of the event to unbind
         * @param {Function} [callback] Function to be unbound
         * @param {Object} [scope] Scope that was used as the this when the event is fired
         * @example
         * var handler = function () {
         * };
         * var o = {};
         * pc.events.attach(o);
         * o.on('event_name', handler);
         *
         * o.off('event_name'); // Remove all events called 'event_name'
         * o.off('event_name', handler); // Remove all handler functions, called 'event_name'
         * o.off('event_name', handler, this); // Remove all hander functions, called 'event_name' with scope this
         */
        off: function (name, callback, scope) {
            var callbacks = this._callbacks;
            var events;
            var index;

            if (!callbacks) {
                return; // no callbacks at all
            }

            if (!callback) {
                // Clear all callbacks
                callbacks[name] = [];
            } else {
                events = callbacks[name];
                if (!events) {
                    return this;
                }

                for (index = 0; index < events.length; index++) {
                    if (events[index].callback === callback) {
                        if (!scope || (scope === events[index].scope)) {
                            events.splice(index, 1);
                            index--;
                        }
                    }
                }
            }

            return this;
        },

        /**
         * @function
         * @name pc.events.fire
         * @description Fire an event, all additional arguments are passed on to the event listener
         * @param {Object} name Name of event to fire
         * @param {*} [...] Arguments that are passed to the event handler
         * @example
         * var o = {};
         * pc.events.attach(o);
         * o.on('event_name', function (msg) {
         *   alert('event_name fired: ' + msg);
         * });
         * o.fire('event_name', 'This is the message');
         */
        fire: function (name) {
            var index;
            var length;
            var args;
            var callbacks;

            if (this._callbacks && this._callbacks[name]) {
                length = this._callbacks[name].length;
                if (length) {
                    if (arguments.length > 1) {
                        args = new Array(arguments.length-1);
                        for (index = 1; index < arguments.length; index++) {
                            args[index-1] = arguments[index];
                        }
                    }

                    callbacks = this._callbacks[name].slice(); // clone list so that deleting inside callbacks works
                    var originalIndex = 0;
                    for(index = 0; index < length; ++index) {
                        var scope = callbacks[index].scope;
                        callbacks[index].callback.apply(scope, args);
                        if (callbacks[index].callback.once) {
                            this._callbacks[name].splice(originalIndex, 1);
                        } else {
                            originalIndex++;
                        }
                    }
                }
            }

            return this;
        },

        once: function (name, callback, scope) {
            callback.once = true;
            this.on(name, callback, scope);
        },

        /**
        * @function
        * @name pc.events.hasEvent
        * @description Test if there are any handlers bound to an event name
        * @param {String} name The name of the event to test
        * @example
        * var o = {};
        * pc.events.attach(o); // add events to o
        * o.on('event_name', function () {}); // bind an event to 'event_name'
        * o.hasEvent('event_name'); // returns true
        */
        hasEvent: function (name) {
            return (this._callbacks !== undefined && this._callbacks[name] !== undefined && this._callbacks[name].length > 0);
        }
    };

    // For compatibility
    Events.bind = Events.on;
    Events.unbind = Events.off;

    return Events;
} ();
<commit_msg>Optimise event.fire by limiting argument length.<commit_after>/**
 * @name pc.events
 * @namespace
 * @description Extend any normal object with events
 *
 * @example var o = {};
 * o = pc.extend(o, pc.events);
 *
 * // attach event
 * o.on("event_name", function() {
 *   alert('event_name fired');
 * }, this);
 *
 * // fire event
 * o.fire("event_name");
 *
 * // detach all events from object
 * o.off('event_name');
 */
pc.events = function () {

    var Events = {
        /**
        * @function
        * @name pc.events.attach
        * @description Attach event methods 'on', 'off', 'fire' and 'hasEvent' to the target object
        * @param  {Object} target The object to add events to.
        * @return {Object} The target object
        */
        attach: function (target) {
            var ev = pc.events;
            target.on = ev.on;
            target.off = ev.off;
            target.fire = ev.fire;
            target.once = ev.once;
            target.hasEvent = ev.hasEvent;
            target.bind = ev.on;
            target.unbind = ev.off;
            return target;
        },

        /**
         * @function
         * @name pc.events.on
         * @description Attach an event handler to an event
         * @param {String} name Name of the event to bind the callback to
         * @param {Function} callback Function that is called when event is fired. Note the callback is limited to 8 arguments.
         * @param {Object} [scope] Object to use as 'this' when the event is fired, defaults to current this
         * @example var o = {};
         * pc.events.attach(o);
         * o.on('event_name', function (a, b) {
         *   console.log(a + b);
         * });
         * o.fire('event_name', 1, 2); // prints 3 to the console
         */
        on: function (name, callback, scope) {
            if(pc.type(name) != "string") {
                throw new TypeError("Event name must be a string");
            }
            var callbacks = this._callbacks || (this._callbacks = {});
            var events = callbacks[name] || (callbacks[name] = []);
            events.push({
                callback: callback,
                scope: scope || this
            });

            return this;
        },

        /**
         * @function
         * @name pc.events.off
         * @description Detach an event handler from an event. If callback is not provided then all callbacks are unbound from the event,
         * if scope is not provided then all events with the callback will be unbound.
         * @param {String} name Name of the event to unbind
         * @param {Function} [callback] Function to be unbound
         * @param {Object} [scope] Scope that was used as the this when the event is fired
         * @example
         * var handler = function () {
         * };
         * var o = {};
         * pc.events.attach(o);
         * o.on('event_name', handler);
         *
         * o.off('event_name'); // Remove all events called 'event_name'
         * o.off('event_name', handler); // Remove all handler functions, called 'event_name'
         * o.off('event_name', handler, this); // Remove all hander functions, called 'event_name' with scope this
         */
        off: function (name, callback, scope) {
            var callbacks = this._callbacks;
            var events;
            var index;

            if (!callbacks) {
                return; // no callbacks at all
            }

            if (!callback) {
                // Clear all callbacks
                callbacks[name] = [];
            } else {
                events = callbacks[name];
                if (!events) {
                    return this;
                }

                for (index = 0; index < events.length; index++) {
                    if (events[index].callback === callback) {
                        if (!scope || (scope === events[index].scope)) {
                            events.splice(index, 1);
                            index--;
                        }
                    }
                }
            }

            return this;
        },

        /**
         * @function
         * @name pc.events.fire
         * @description Fire an event, all additional arguments are passed on to the event listener
         * @param {Object} name Name of event to fire
         * @param {*} [...] Arguments that are passed to the event handler
         * @example
         * var o = {};
         * pc.events.attach(o);
         * o.on('event_name', function (msg) {
         *   alert('event_name fired: ' + msg);
         * });
         * o.fire('event_name', 'This is the message');
         */
        fire: function (name) {
            var index;
            var length;
            var args;
            var callbacks;

            if (this._callbacks && this._callbacks[name]) {
                length = this._callbacks[name].length;
                if (length) {
                    callbacks = this._callbacks[name].slice(); // clone list so that deleting inside callbacks works
                    var originalIndex = 0;
                    for(index = 0; index < length; ++index) {
                        var scope = callbacks[index].scope;
                        callbacks[index].callback.call(scope, arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7], arguments[8]);
                        if (callbacks[index].callback.once) {
                            this._callbacks[name].splice(originalIndex, 1);
                        } else {
                            originalIndex++;
                        }
                    }
                }
            }

            return this;
        },

        once: function (name, callback, scope) {
            callback.once = true;
            this.on(name, callback, scope);
        },

        /**
        * @function
        * @name pc.events.hasEvent
        * @description Test if there are any handlers bound to an event name
        * @param {String} name The name of the event to test
        * @example
        * var o = {};
        * pc.events.attach(o); // add events to o
        * o.on('event_name', function () {}); // bind an event to 'event_name'
        * o.hasEvent('event_name'); // returns true
        */
        hasEvent: function (name) {
            return (this._callbacks !== undefined && this._callbacks[name] !== undefined && this._callbacks[name].length > 0);
        }
    };

    // For compatibility
    Events.bind = Events.on;
    Events.unbind = Events.off;

    return Events;
} ();
<|endoftext|>


<commit_before>'use strict';

describe('Service: Poller', function () {

  // load the service's module
  beforeEach(module('awsinstancesManagerApp'));

  // instantiate service
  var Poller;
  beforeEach(inject(function (_Poller_) {
    Poller = _Poller_;
  }));

  it('should do something', function () {
    expect(!!Poller).toBe(true);
  });

});
<commit_msg>Misc bug fixes and optimisations<commit_after><|endoftext|>


<commit_before>import EventEmitter from 'eventemitter2'
import store from '../store/store'
import { actions } from '../store/actions'
import * as selectors from '../store/selectors'

const events = new EventEmitter()
store.subscribe(handleEvent)

const authenticated = (state) => state.globals.authenticated

function handleEvent () {
  const state = store.getState()
  const data = selectors.captureSelector(state)
  if (authenticated(state)) {
    events.emit('ready')
  }
  if (selectors.documentCaptured(state)) {
    events.emit('documentCapture', data)
  }
  if (selectors.faceCaptured(state)) {
    events.emit('faceCapture', data)
  }
  if (selectors.allCaptured(state)) {
    events.emit('complete', data)
  }
}

events.getCaptures = () => captureSelector(store.getState())

export default events
<commit_msg>fixed exception by referencing the correct object<commit_after>import EventEmitter from 'eventemitter2'
import store from '../store/store'
import { actions } from '../store/actions'
import * as selectors from '../store/selectors'

const events = new EventEmitter()
store.subscribe(handleEvent)

const authenticated = (state) => state.globals.authenticated

function handleEvent () {
  const state = store.getState()
  const data = selectors.captureSelector(state)
  if (authenticated(state)) {
    events.emit('ready')
  }
  if (selectors.documentCaptured(state)) {
    events.emit('documentCapture', data)
  }
  if (selectors.faceCaptured(state)) {
    events.emit('faceCapture', data)
  }
  if (selectors.allCaptured(state)) {
    events.emit('complete', data)
  }
}

events.getCaptures = () => selectors.captureSelector(store.getState())

export default events
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 Google Inc., authors, and contributors <see AUTHORS file>
 * Licensed under http://www.apache.org/licenses/LICENSE-2.0 <see LICENSE file>
 * Created By:
 * Maintained By:
 */

//require can.jquery-all

(function(can) {

can.Model.Cacheable("CMS.Models.Program", {
  root_object : "program"
  , root_collection : "programs"
  , findAll : "/api/programs?company_controls_first=true"
  , findOne : "/api/programs/{id}"
  , create : "POST /api/programs"
  , init : function() {
    this.validatePresenceOf("title");
    this._super.apply(this, arguments);
  }
}, {});

can.Model.Cacheable("CMS.Models.Directive", {
  root_object : "directive"
  , root_collection : "directives"
  , findAll : "/api/directives"
  , findOne : "/api/directives/{id}"
  , create : "POST /api/directives"
}, {
  init : function() {
    this._super && this._super.apply(this, arguments);
    var that = this;
    this.attr("descendant_sections", can.compute(function() {
      return that.attr("sections").concat(can.reduce(that.sections, function(a, b) {
        return a.concat(can.makeArray(b.descendant_sections()));
      }, []));
    }));
    this.attr("descendant_sections_count", can.compute(function() {
      return that.attr("descendant_sections")().length;
    }));
  }
  , lowercase_kind : function() { return this.kind.toLowerCase(); }

});

CMS.Models.Directive("CMS.Models.Regulation", {
  findAll : "/api/directives?meta_kind=regulation"
  , create : {
    type : "POST"
    , url : "/api/directives"
    , data : {
      kind : "regulation"
    }
  }
}, {});

CMS.Models.Directive("CMS.Models.Policy", {
  findAll : "/api/directives?meta_kind=policy"
  , create : {
    type : "POST"
    , url : "/api/directives"
    , data : {
      kind : "policy"
    }
  }
}, {});

CMS.Models.Directive("CMS.Models.Contract", {
  findAll : "/api/directives?meta_kind=contract"
  , create : {
    type : "POST"
    , url : "/api/directives"
    , data : {
      kind : "contract"
    }
  }
}, {});

can.Model.Cacheable("CMS.Models.OrgGroup", {
  root_object : "org_group"
  , root_collection : "org_groups"
  , findAll : "/api/org_groups"
  , create : "POST /api/org_groups"
}, {});

can.Model.Cacheable("CMS.Models.Project", {
  root_object : "project"
  , root_collection : "projects"
  , findAll : "/api/projects"
  , create : "POST /api/projects"
}, {});

can.Model.Cacheable("CMS.Models.Facility", {
  root_object : "facility"
  , root_collection : "facilities"
  , findAll : "/api/facilities"
  , create : "POST /api/facilities"
}, {});

can.Model.Cacheable("CMS.Models.Product", {
  root_object : "product"
  , root_collection : "products"
  , findAll : "/api/products"
  , create : "POST /api/products"
}, {});

can.Model.Cacheable("CMS.Models.DataAsset", {
  root_object : "data_asset"
  , root_collection : "data_assets"
  , findAll : "/api/data_assets"
  , create : "POST /api/data_assets"
}, {});

can.Model.Cacheable("CMS.Models.Market", {
  root_object : "market"
  , root_collection : "markets"
  , findAll : "/api/markets"
  , create : "POST /api/markets"
}, {});

can.Model.Cacheable("CMS.Models.RiskyAttribute", {
  root_object : "risky_attribute"
  , root_collection : "risky_attributes"
  , findAll : "/api/risky_attributes"
  , create : "POST /api/risky_attributes"
}, {});

can.Model.Cacheable("CMS.Models.Risk", {
  root_object : "risk"
  , root_collection : "risks"
  , findAll : function(params) {
    var root_object =  this.root_object
    , root_collection = this.root_collection;
    return $.ajax({
      url : "/api/risks"
      , type : "get"
      , data : params
      , dataType : "json"
    }).then(function(risks) {
      if(risks[root_collection + "_collection"]) {
        risks = risks[root_collection + "_collection"];
      }
      if(risks[root_collection]) {
        risks = risks[root_collection];
      }

      can.each(risks, function(r) {
        if(r[root_object]) {
          r = r[root_object];
        }
        if(r.hasOwnProperty("trigger")) {
          r.risk_trigger = r.trigger;
          delete r.trigger;
        }
      });
      return risks;
    });
  }
  , create : function(params) {
    params.trigger = params.risk_trigger;
    return $.ajax({
      type : "POST"
      , url : "/api/risks"
      , data : params
      , dataType : "json"
    });
  }
}, {});

can.Model.Cacheable("CMS.Models.Help", {
  root_object : "help"
  , root_collection : "helps"
  , findAll : "GET /api/help"
  , findOne : "GET /api/help/{id}"
  , update : "PUT /api/help/{id}"
  , create : "POST /api/help"
}, {});

})(this.can);<commit_msg>Story 49871709: Separating directive types according to new API on dashboard<commit_after>/*
 * Copyright (C) 2013 Google Inc., authors, and contributors <see AUTHORS file>
 * Licensed under http://www.apache.org/licenses/LICENSE-2.0 <see LICENSE file>
 * Created By:
 * Maintained By:
 */

//require can.jquery-all

(function(can) {

can.Model.Cacheable("CMS.Models.Program", {
  root_object : "program"
  , root_collection : "programs"
  , findAll : "/api/programs?company_controls_first=true"
  , findOne : "/api/programs/{id}"
  , create : "POST /api/programs"
  , init : function() {
    this.validatePresenceOf("title");
    this._super.apply(this, arguments);
  }
}, {});

can.Model.Cacheable("CMS.Models.Directive", {
  root_object : "directive"
  , root_collection : "directives"
  , findAll : "/api/directives"
  , findOne : "/api/directives/{id}"
  , create : "POST /api/directives"
}, {
  init : function() {
    this._super && this._super.apply(this, arguments);
    var that = this;
    this.attr("descendant_sections", can.compute(function() {
      return that.attr("sections").concat(can.reduce(that.sections, function(a, b) {
        return a.concat(can.makeArray(b.descendant_sections()));
      }, []));
    }));
    this.attr("descendant_sections_count", can.compute(function() {
      return that.attr("descendant_sections")().length;
    }));
  }
  , lowercase_kind : function() { return this.kind.toLowerCase(); }

});

CMS.Models.Directive("CMS.Models.Regulation", {
  findAll : "/api/directives?kind=Regulation"
  , create : {
    type : "POST"
    , url : "/api/directives"
    , data : {
      kind : "regulation"
    }
  }
}, {});

CMS.Models.Directive("CMS.Models.Policy", {
  findAll : "/api/directives?kind=Company+Policy"
  , create : {
    type : "POST"
    , url : "/api/directives"
    , data : {
      kind : "policy"
    }
  }
}, {});

CMS.Models.Directive("CMS.Models.Contract", {
  findAll : "/api/directives?kind=Contract"
  , create : {
    type : "POST"
    , url : "/api/directives"
    , data : {
      kind : "contract"
    }
  }
}, {});

can.Model.Cacheable("CMS.Models.OrgGroup", {
  root_object : "org_group"
  , root_collection : "org_groups"
  , findAll : "/api/org_groups"
  , create : "POST /api/org_groups"
}, {});

can.Model.Cacheable("CMS.Models.Project", {
  root_object : "project"
  , root_collection : "projects"
  , findAll : "/api/projects"
  , create : "POST /api/projects"
}, {});

can.Model.Cacheable("CMS.Models.Facility", {
  root_object : "facility"
  , root_collection : "facilities"
  , findAll : "/api/facilities"
  , create : "POST /api/facilities"
}, {});

can.Model.Cacheable("CMS.Models.Product", {
  root_object : "product"
  , root_collection : "products"
  , findAll : "/api/products"
  , create : "POST /api/products"
}, {});

can.Model.Cacheable("CMS.Models.DataAsset", {
  root_object : "data_asset"
  , root_collection : "data_assets"
  , findAll : "/api/data_assets"
  , create : "POST /api/data_assets"
}, {});

can.Model.Cacheable("CMS.Models.Market", {
  root_object : "market"
  , root_collection : "markets"
  , findAll : "/api/markets"
  , create : "POST /api/markets"
}, {});

can.Model.Cacheable("CMS.Models.RiskyAttribute", {
  root_object : "risky_attribute"
  , root_collection : "risky_attributes"
  , findAll : "/api/risky_attributes"
  , create : "POST /api/risky_attributes"
}, {});

can.Model.Cacheable("CMS.Models.Risk", {
  root_object : "risk"
  , root_collection : "risks"
  , findAll : function(params) {
    var root_object =  this.root_object
    , root_collection = this.root_collection;
    return $.ajax({
      url : "/api/risks"
      , type : "get"
      , data : params
      , dataType : "json"
    }).then(function(risks) {
      if(risks[root_collection + "_collection"]) {
        risks = risks[root_collection + "_collection"];
      }
      if(risks[root_collection]) {
        risks = risks[root_collection];
      }

      can.each(risks, function(r) {
        if(r[root_object]) {
          r = r[root_object];
        }
        if(r.hasOwnProperty("trigger")) {
          r.risk_trigger = r.trigger;
          delete r.trigger;
        }
      });
      return risks;
    });
  }
  , create : function(params) {
    params.trigger = params.risk_trigger;
    return $.ajax({
      type : "POST"
      , url : "/api/risks"
      , data : params
      , dataType : "json"
    });
  }
}, {});

can.Model.Cacheable("CMS.Models.Help", {
  root_object : "help"
  , root_collection : "helps"
  , findAll : "GET /api/help"
  , findOne : "GET /api/help/{id}"
  , update : "PUT /api/help/{id}"
  , create : "POST /api/help"
}, {});

})(this.can);<|endoftext|>


<commit_before>function delay(callback, duration) {
	// If tooltip has displayed, start hide timer
	if(duration > 0) {
		return setTimeout(
			$.proxy(callback, this), duration
		);
	}
	else{ callback.call(this); }
}

function showMethod(event) {
	if(this.tooltip.hasClass(CLASS_DISABLED)) { return FALSE; }

	// Clear hide timers
	clearTimeout(this.timers.show);
	clearTimeout(this.timers.hide);

	// Start show timer
	this.timers.show = delay.call(this,
		function() { this.toggle(TRUE, event); },
		this.options.show.delay
	);
}

function hideMethod(event) {
	if(this.tooltip.hasClass(CLASS_DISABLED)) { return FALSE; }

	// Check if new target was actually the tooltip element
	var relatedTarget = $(event.relatedTarget),
		ontoTooltip = relatedTarget.closest(SELECTOR)[0] === this.tooltip[0],
		ontoTarget = relatedTarget[0] === this.options.show.target[0];

	// Clear timers and stop animation queue
	clearTimeout(this.timers.show);
	clearTimeout(this.timers.hide);

	// Prevent hiding if tooltip is fixed and event target is the tooltip.
	// Or if mouse positioning is enabled and cursor momentarily overlaps
	if(this !== relatedTarget[0] &&
		(this.options.position.target === 'mouse' && ontoTooltip) ||
		(this.options.hide.fixed && (
			(/mouse(out|leave|move)/).test(event.type) && (ontoTooltip || ontoTarget))
		))
	{
		try {
			event.preventDefault();
			event.stopImmediatePropagation();
		} catch(e) {}

		return;
	}

	// If tooltip has displayed, start hide timer
	this.timers.hide = delay.call(this,
		function() { this.toggle(FALSE, event); },
		this.options.hide.delay,
		this
	);
}

function inactiveMethod(event) {
	if(this.tooltip.hasClass(CLASS_DISABLED) || !this.options.hide.inactive) { return FALSE; }

	// Clear timer
	clearTimeout(this.timers.inactive);

	this.timers.inactive = delay.call(this,
		function(){ this.hide(event); },
		this.options.hide.inactive
	);
}

function repositionMethod(event) {
	if(this.rendered && this.tooltip[0].offsetWidth > 0) { this.reposition(event); }
}

// Store mouse coordinates
PROTOTYPE._storeMouse = function(event) {
	(this.mouse = $.event.fix(event)).type = 'mousemove';
};

// Bind events
PROTOTYPE._bind = function(targets, events, method, suffix, context) {
	var ns = '.' + this._id + (suffix ? '-'+suffix : '');
	events.length && $(targets).bind(
		(events.split ? events : events.join(ns + ' ')) + ns,
		$.proxy(method, context || this)
	);
};
PROTOTYPE._unbind = function(targets, suffix) {
	$(targets).unbind('.' + this._id + (suffix ? '-'+suffix : ''));
};

// Apply common event handlers using delegate (avoids excessive .bind calls!)
var ns = '.'+NAMESPACE;
function delegate(selector, events, method) {
	$(document.body).delegate(selector,
		(events.split ? events : events.join(ns + ' ')) + ns,
		function() {
			var api = QTIP.api[ $.attr(this, ATTR_ID) ];
			api && !api.disabled && method.apply(api, arguments);
		}
	);
}

$(function() {
	delegate(SELECTOR, ['mouseenter', 'mouseleave'], function(event) {
		var state = event.type === 'mouseenter',
			tooltip = $(event.currentTarget),
			target = $(event.relatedTarget || event.target),
			options = this.options;

		// On mouseenter...
		if(state) {
			// Focus the tooltip on mouseenter (z-index stacking)
			this.focus(event);

			// Clear hide timer on tooltip hover to prevent it from closing
			tooltip.hasClass(CLASS_FIXED) && !tooltip.hasClass(CLASS_DISABLED) && clearTimeout(this.timers.hide);
		}

		// On mouseleave...
		else {
			// Hide when we leave the tooltip and not onto the show target (if a hide event is set)
			if(options.position.target === 'mouse' && options.hide.event &&
				options.show.target && !target.closest(options.show.target[0]).length) {
				this.hide(event);
			}
		}

		// Add hover class
		tooltip.toggleClass(CLASS_HOVER, state);
	});

	// Define events which reset the 'inactive' event handler
	delegate('['+ATTR_ID+']', INACTIVE_EVENTS, inactiveMethod);
});

// Event trigger
PROTOTYPE._trigger = function(type, args, event) {
	var callback = $.Event('tooltip'+type);
	callback.originalEvent = (event && $.extend({}, event)) || this.cache.event || NULL;

	this.triggering = type;
	this.tooltip.trigger(callback, [this].concat(args || []));
	this.triggering = FALSE;

	return !callback.isDefaultPrevented();
};

PROTOTYPE._bindEvents = function(showEvents, hideEvents, showTargets, hideTargets, showMethod, hideMethod) {
	// Get tasrgets that lye within both
	var similarTargets = showTargets.filter( hideTargets ).add( hideTargets.filter(showTargets) ),
		toggleEvents = [];

	// If hide and show targets are the same...
	if(similarTargets.length) {

		// Filter identical show/hide events
		$.each(hideEvents, function(i, type) {
			var showIndex = $.inArray(type, showEvents);

			// Both events are identical, remove from both hide and show events
			// and append to toggleEvents
			showIndex > -1 && toggleEvents.push( showEvents.splice( showIndex, 1 )[0] );
		});

		// Toggle events are special case of identical show/hide events, which happen in sequence
		if(toggleEvents.length) {
			// Bind toggle events to the similar targets
			this._bind(similarTargets, toggleEvents, function(event) {
				var state = this.rendered ? this.tooltip[0].offsetWidth > 0 : false;
				(state ? hideMethod : showMethod).call(this, event);
			});

			// Remove the similar targets from the regular show/hide bindings
			showTargets = showTargets.not(similarTargets);
			hideTargets = hideTargets.not(similarTargets);
		}
	}

	// Apply show/hide/toggle events
	this._bind(showTargets, showEvents, showMethod);
	this._bind(hideTargets, hideEvents, hideMethod);
};

PROTOTYPE._assignInitialEvents = function(event) {
	var options = this.options,
		showTarget = options.show.target,
		hideTarget = options.hide.target,
		showEvents = options.show.event ? $.trim('' + options.show.event).split(' ') : [],
		hideEvents = options.hide.event ? $.trim('' + options.hide.event).split(' ') : [];

	/*
	 * Make sure hoverIntent functions properly by using mouseleave as a hide event if
	 * mouseenter/mouseout is used for show.event, even if it isn't in the users options.
	 */
	if(/mouse(over|enter)/i.test(options.show.event) && !/mouse(out|leave)/i.test(options.hide.event)) {
		hideEvents.push('mouseleave');
	}

	/*
	 * Also make sure initial mouse targetting works correctly by caching mousemove coords
	 * on show targets before the tooltip has rendered. Also set onTarget when triggered to
	 * keep mouse tracking working.
	 */
	this._bind(showTarget, 'mousemove', function(event) {
		this._storeMouse(event);
		this.cache.onTarget = TRUE;
	});

	// Define hoverIntent function
	function hoverIntent(event) {
		// Only continue if tooltip isn't disabled
		if(this.disabled || this.destroyed) { return FALSE; }

		// Cache the event data
		this.cache.event = $.event.fix(event);
		this.cache.target = event ? $(event.target) : [undefined];

		// Start the event sequence
		clearTimeout(this.timers.show);
		this.timers.show = delay.call(this,
			function() { this.render(typeof event === 'object' || options.show.ready); },
			options.show.delay
		);
	}

	// Filter and bind events
	this._bindEvents(showEvents, hideEvents, showTarget, hideTarget, hoverIntent, function() {
		clearTimeout(this.timers.show);
	});

	// Prerendering is enabled, create tooltip now
	if(options.show.ready || options.prerender) { hoverIntent.call(this, event); }
};

// Event assignment method
PROTOTYPE._assignEvents = function() {
	var self = this,
		options = this.options,
		posOptions = options.position,

		tooltip = this.tooltip,
		showTarget = options.show.target,
		hideTarget = options.hide.target,
		containerTarget = posOptions.container,
		viewportTarget = posOptions.viewport,
		documentTarget = $(document),
		bodyTarget = $(document.body),
		windowTarget = $(window),

		showEvents = options.show.event ? $.trim('' + options.show.event).split(' ') : [],
		hideEvents = options.hide.event ? $.trim('' + options.hide.event).split(' ') : [];

	// Assign passed event callbacks
	$.each(options.events, function(name, callback) {
		self._bind(tooltip, name === 'toggle' ? ['tooltipshow','tooltiphide'] : ['tooltip'+name], callback, null, tooltip);
	});

	// Hide tooltips when leaving current window/frame (but not select/option elements)
	if(/mouse(out|leave)/i.test(options.hide.event) && options.hide.leave === 'window') {
		this._bind(documentTarget, ['mouseout', 'blur'], function(event) {
			if(!/select|option/.test(event.target.nodeName) && !event.relatedTarget) {
				this.hide(event);
			}
		});
	}

	// Enable hide.fixed by adding appropriate class
	if(options.hide.fixed) {
		hideTarget = hideTarget.add( tooltip.addClass(CLASS_FIXED) );
	}

	/*
	 * Make sure hoverIntent functions properly by using mouseleave to clear show timer if
	 * mouseenter/mouseout is used for show.event, even if it isn't in the users options.
	 */
	else if(/mouse(over|enter)/i.test(options.show.event)) {
		this._bind(hideTarget, 'mouseleave', function() {
			clearTimeout(this.timers.show);
		});
	}

	// Hide tooltip on document mousedown if unfocus events are enabled
	if(('' + options.hide.event).indexOf('unfocus') > -1) {
		this._bind(containerTarget.closest('html'), ['mousedown', 'touchstart'], function(event) {
			var elem = $(event.target),
				enabled = this.rendered && !this.tooltip.hasClass(CLASS_DISABLED) && this.tooltip[0].offsetWidth > 0,
				isAncestor = elem.parents(SELECTOR).filter(this.tooltip[0]).length > 0;

			if(elem[0] !== this.target[0] && elem[0] !== this.tooltip[0] && !isAncestor &&
				!this.target.has(elem[0]).length && enabled
			) {
				this.hide(event);
			}
		});
	}

	// Check if the tooltip hides when inactive
	if('number' === typeof options.hide.inactive) {
		// Bind inactive method to show target(s) as a custom event
		this._bind(showTarget, 'qtip-'+this.id+'-inactive', inactiveMethod);

		// Define events which reset the 'inactive' event handler
		this._bind(hideTarget.add(tooltip), QTIP.inactiveEvents, inactiveMethod, '-inactive');
	}

	// Filter and bind events
	this._bindEvents(showEvents, hideEvents, showTarget, hideTarget, showMethod, hideMethod);

	// Mouse movement bindings
	this._bind(showTarget.add(tooltip), 'mousemove', function(event) {
		// Check if the tooltip hides when mouse is moved a certain distance
		if('number' === typeof options.hide.distance) {
			var origin = this.cache.origin || {},
				limit = this.options.hide.distance,
				abs = Math.abs;

			// Check if the movement has gone beyond the limit, and hide it if so
			if(abs(event.pageX - origin.pageX) >= limit || abs(event.pageY - origin.pageY) >= limit) {
				this.hide(event);
			}
		}

		// Cache mousemove coords on show targets
		this._storeMouse(event);
	});

	// Mouse positioning events
	if(posOptions.target === 'mouse') {
		// If mouse adjustment is on...
		if(posOptions.adjust.mouse) {
			// Apply a mouseleave event so we don't get problems with overlapping
			if(options.hide.event) {
				// Track if we're on the target or not
				this._bind(showTarget, ['mouseenter', 'mouseleave'], function(event) {
					this.cache.onTarget = event.type === 'mouseenter';
				});
			}

			// Update tooltip position on mousemove
			this._bind(documentTarget, 'mousemove', function(event) {
				// Update the tooltip position only if the tooltip is visible and adjustment is enabled
				if(this.rendered && this.cache.onTarget && !this.tooltip.hasClass(CLASS_DISABLED) && this.tooltip[0].offsetWidth > 0) {
					this.reposition(event);
				}
			});
		}
	}

	// Adjust positions of the tooltip on window resize if enabled
	if(posOptions.adjust.resize || viewportTarget.length) {
		this._bind( $.event.special.resize ? viewportTarget : windowTarget, 'resize', repositionMethod );
	}

	// Adjust tooltip position on scroll of the window or viewport element if present
	if(posOptions.adjust.scroll) {
		this._bind( windowTarget.add(posOptions.container), 'scroll', repositionMethod );
	}
};

// Un-assignment method
PROTOTYPE._unassignEvents = function() {
	var targets = [
		this.options.show.target[0],
		this.options.hide.target[0],
		this.rendered && this.tooltip[0],
		this.options.position.container[0],
		this.options.position.viewport[0],
		this.options.position.container.closest('html')[0], // unfocus
		window,
		document
	];

	this._unbind($([]).pushStack( $.grep(targets, function(i) {
		return typeof i === 'object';
	})));
};

<commit_msg>Added existence checks to support using the destroy method while the the tooltip is being created<commit_after>function delay(callback, duration) {
	// If tooltip has displayed, start hide timer
	if(duration > 0) {
		return setTimeout(
			$.proxy(callback, this), duration
		);
	}
	else{ callback.call(this); }
}

function showMethod(event) {
	if(this.tooltip.hasClass(CLASS_DISABLED)) { return FALSE; }

	// Clear hide timers
	clearTimeout(this.timers.show);
	clearTimeout(this.timers.hide);

	// Start show timer
	this.timers.show = delay.call(this,
		function() { this.toggle(TRUE, event); },
		this.options.show.delay
	);
}

function hideMethod(event) {
	if(this.tooltip.hasClass(CLASS_DISABLED) || this.destroyed) { return FALSE; }

	// Check if new target was actually the tooltip element
	var relatedTarget = $(event.relatedTarget),
		ontoTooltip = relatedTarget.closest(SELECTOR)[0] === this.tooltip[0],
		ontoTarget = relatedTarget[0] === this.options.show.target[0];

	// Clear timers and stop animation queue
	clearTimeout(this.timers.show);
	clearTimeout(this.timers.hide);

	// Prevent hiding if tooltip is fixed and event target is the tooltip.
	// Or if mouse positioning is enabled and cursor momentarily overlaps
	if(this !== relatedTarget[0] &&
		(this.options.position.target === 'mouse' && ontoTooltip) ||
		(this.options.hide.fixed && (
			(/mouse(out|leave|move)/).test(event.type) && (ontoTooltip || ontoTarget))
		))
	{
		try {
			event.preventDefault();
			event.stopImmediatePropagation();
		} catch(e) {}

		return;
	}

	// If tooltip has displayed, start hide timer
	this.timers.hide = delay.call(this,
		function() { this.toggle(FALSE, event); },
		this.options.hide.delay,
		this
	);
}

function inactiveMethod(event) {
	if(this.tooltip.hasClass(CLASS_DISABLED) || !this.options.hide.inactive) { return FALSE; }

	// Clear timer
	clearTimeout(this.timers.inactive);

	this.timers.inactive = delay.call(this,
		function(){ this.hide(event); },
		this.options.hide.inactive
	);
}

function repositionMethod(event) {
	if(this.rendered && this.tooltip[0].offsetWidth > 0) { this.reposition(event); }
}

// Store mouse coordinates
PROTOTYPE._storeMouse = function(event) {
	(this.mouse = $.event.fix(event)).type = 'mousemove';
};

// Bind events
PROTOTYPE._bind = function(targets, events, method, suffix, context) {
	var ns = '.' + this._id + (suffix ? '-'+suffix : '');
	events.length && $(targets).bind(
		(events.split ? events : events.join(ns + ' ')) + ns,
		$.proxy(method, context || this)
	);
};
PROTOTYPE._unbind = function(targets, suffix) {
	$(targets).unbind('.' + this._id + (suffix ? '-'+suffix : ''));
};

// Apply common event handlers using delegate (avoids excessive .bind calls!)
var ns = '.'+NAMESPACE;
function delegate(selector, events, method) {
	$(document.body).delegate(selector,
		(events.split ? events : events.join(ns + ' ')) + ns,
		function() {
			var api = QTIP.api[ $.attr(this, ATTR_ID) ];
			api && !api.disabled && method.apply(api, arguments);
		}
	);
}

$(function() {
	delegate(SELECTOR, ['mouseenter', 'mouseleave'], function(event) {
		var state = event.type === 'mouseenter',
			tooltip = $(event.currentTarget),
			target = $(event.relatedTarget || event.target),
			options = this.options;

		// On mouseenter...
		if(state) {
			// Focus the tooltip on mouseenter (z-index stacking)
			this.focus(event);

			// Clear hide timer on tooltip hover to prevent it from closing
			tooltip.hasClass(CLASS_FIXED) && !tooltip.hasClass(CLASS_DISABLED) && clearTimeout(this.timers.hide);
		}

		// On mouseleave...
		else {
			// Hide when we leave the tooltip and not onto the show target (if a hide event is set)
			if(options.position.target === 'mouse' && options.hide.event &&
				options.show.target && !target.closest(options.show.target[0]).length) {
				this.hide(event);
			}
		}

		// Add hover class
		tooltip.toggleClass(CLASS_HOVER, state);
	});

	// Define events which reset the 'inactive' event handler
	delegate('['+ATTR_ID+']', INACTIVE_EVENTS, inactiveMethod);
});

// Event trigger
PROTOTYPE._trigger = function(type, args, event) {
	var callback = $.Event('tooltip'+type);
	callback.originalEvent = (event && $.extend({}, event)) || this.cache.event || NULL;

	this.triggering = type;
	this.tooltip.trigger(callback, [this].concat(args || []));
	this.triggering = FALSE;

	return !callback.isDefaultPrevented();
};

PROTOTYPE._bindEvents = function(showEvents, hideEvents, showTargets, hideTargets, showMethod, hideMethod) {
	// Get tasrgets that lye within both
	var similarTargets = showTargets.filter( hideTargets ).add( hideTargets.filter(showTargets) ),
		toggleEvents = [];

	// If hide and show targets are the same...
	if(similarTargets.length) {

		// Filter identical show/hide events
		$.each(hideEvents, function(i, type) {
			var showIndex = $.inArray(type, showEvents);

			// Both events are identical, remove from both hide and show events
			// and append to toggleEvents
			showIndex > -1 && toggleEvents.push( showEvents.splice( showIndex, 1 )[0] );
		});

		// Toggle events are special case of identical show/hide events, which happen in sequence
		if(toggleEvents.length) {
			// Bind toggle events to the similar targets
			this._bind(similarTargets, toggleEvents, function(event) {
				var state = this.rendered ? this.tooltip[0].offsetWidth > 0 : false;
				(state ? hideMethod : showMethod).call(this, event);
			});

			// Remove the similar targets from the regular show/hide bindings
			showTargets = showTargets.not(similarTargets);
			hideTargets = hideTargets.not(similarTargets);
		}
	}

	// Apply show/hide/toggle events
	this._bind(showTargets, showEvents, showMethod);
	this._bind(hideTargets, hideEvents, hideMethod);
};

PROTOTYPE._assignInitialEvents = function(event) {
	var options = this.options,
		showTarget = options.show.target,
		hideTarget = options.hide.target,
		showEvents = options.show.event ? $.trim('' + options.show.event).split(' ') : [],
		hideEvents = options.hide.event ? $.trim('' + options.hide.event).split(' ') : [];

	/*
	 * Make sure hoverIntent functions properly by using mouseleave as a hide event if
	 * mouseenter/mouseout is used for show.event, even if it isn't in the users options.
	 */
	if(/mouse(over|enter)/i.test(options.show.event) && !/mouse(out|leave)/i.test(options.hide.event)) {
		hideEvents.push('mouseleave');
	}

	/*
	 * Also make sure initial mouse targetting works correctly by caching mousemove coords
	 * on show targets before the tooltip has rendered. Also set onTarget when triggered to
	 * keep mouse tracking working.
	 */
	this._bind(showTarget, 'mousemove', function(event) {
		this._storeMouse(event);
		this.cache.onTarget = TRUE;
	});

	// Define hoverIntent function
	function hoverIntent(event) {
		// Only continue if tooltip isn't disabled
		if(this.disabled || this.destroyed) { return FALSE; }

		// Cache the event data
		this.cache.event = $.event.fix(event);
		this.cache.target = event ? $(event.target) : [undefined];

		// Start the event sequence
		clearTimeout(this.timers.show);
		this.timers.show = delay.call(this,
			function() { this.render(typeof event === 'object' || options.show.ready); },
			options.show.delay
		);
	}

	// Filter and bind events
	this._bindEvents(showEvents, hideEvents, showTarget, hideTarget, hoverIntent, function() {
		if(!this.timers) { return FALSE; }
		clearTimeout(this.timers.show);
	});

	// Prerendering is enabled, create tooltip now
	if(options.show.ready || options.prerender) { hoverIntent.call(this, event); }
};

// Event assignment method
PROTOTYPE._assignEvents = function() {
	var self = this,
		options = this.options,
		posOptions = options.position,

		tooltip = this.tooltip,
		showTarget = options.show.target,
		hideTarget = options.hide.target,
		containerTarget = posOptions.container,
		viewportTarget = posOptions.viewport,
		documentTarget = $(document),
		bodyTarget = $(document.body),
		windowTarget = $(window),

		showEvents = options.show.event ? $.trim('' + options.show.event).split(' ') : [],
		hideEvents = options.hide.event ? $.trim('' + options.hide.event).split(' ') : [];

	// Assign passed event callbacks
	$.each(options.events, function(name, callback) {
		self._bind(tooltip, name === 'toggle' ? ['tooltipshow','tooltiphide'] : ['tooltip'+name], callback, null, tooltip);
	});

	// Hide tooltips when leaving current window/frame (but not select/option elements)
	if(/mouse(out|leave)/i.test(options.hide.event) && options.hide.leave === 'window') {
		this._bind(documentTarget, ['mouseout', 'blur'], function(event) {
			if(!/select|option/.test(event.target.nodeName) && !event.relatedTarget) {
				this.hide(event);
			}
		});
	}

	// Enable hide.fixed by adding appropriate class
	if(options.hide.fixed) {
		hideTarget = hideTarget.add( tooltip.addClass(CLASS_FIXED) );
	}

	/*
	 * Make sure hoverIntent functions properly by using mouseleave to clear show timer if
	 * mouseenter/mouseout is used for show.event, even if it isn't in the users options.
	 */
	else if(/mouse(over|enter)/i.test(options.show.event)) {
		this._bind(hideTarget, 'mouseleave', function() {
			clearTimeout(this.timers.show);
		});
	}

	// Hide tooltip on document mousedown if unfocus events are enabled
	if(('' + options.hide.event).indexOf('unfocus') > -1) {
		this._bind(containerTarget.closest('html'), ['mousedown', 'touchstart'], function(event) {
			var elem = $(event.target),
				enabled = this.rendered && !this.tooltip.hasClass(CLASS_DISABLED) && this.tooltip[0].offsetWidth > 0,
				isAncestor = elem.parents(SELECTOR).filter(this.tooltip[0]).length > 0;

			if(elem[0] !== this.target[0] && elem[0] !== this.tooltip[0] && !isAncestor &&
				!this.target.has(elem[0]).length && enabled
			) {
				this.hide(event);
			}
		});
	}

	// Check if the tooltip hides when inactive
	if('number' === typeof options.hide.inactive) {
		// Bind inactive method to show target(s) as a custom event
		this._bind(showTarget, 'qtip-'+this.id+'-inactive', inactiveMethod);

		// Define events which reset the 'inactive' event handler
		this._bind(hideTarget.add(tooltip), QTIP.inactiveEvents, inactiveMethod, '-inactive');
	}

	// Filter and bind events
	this._bindEvents(showEvents, hideEvents, showTarget, hideTarget, showMethod, hideMethod);

	// Mouse movement bindings
	this._bind(showTarget.add(tooltip), 'mousemove', function(event) {
		// Check if the tooltip hides when mouse is moved a certain distance
		if('number' === typeof options.hide.distance) {
			var origin = this.cache.origin || {},
				limit = this.options.hide.distance,
				abs = Math.abs;

			// Check if the movement has gone beyond the limit, and hide it if so
			if(abs(event.pageX - origin.pageX) >= limit || abs(event.pageY - origin.pageY) >= limit) {
				this.hide(event);
			}
		}

		// Cache mousemove coords on show targets
		this._storeMouse(event);
	});

	// Mouse positioning events
	if(posOptions.target === 'mouse') {
		// If mouse adjustment is on...
		if(posOptions.adjust.mouse) {
			// Apply a mouseleave event so we don't get problems with overlapping
			if(options.hide.event) {
				// Track if we're on the target or not
				this._bind(showTarget, ['mouseenter', 'mouseleave'], function(event) {
					if(!this.cache) {return FALSE; }
					this.cache.onTarget = event.type === 'mouseenter';
				});
			}

			// Update tooltip position on mousemove
			this._bind(documentTarget, 'mousemove', function(event) {
				// Update the tooltip position only if the tooltip is visible and adjustment is enabled
				if(this.rendered && this.cache.onTarget && !this.tooltip.hasClass(CLASS_DISABLED) && this.tooltip[0].offsetWidth > 0) {
					this.reposition(event);
				}
			});
		}
	}

	// Adjust positions of the tooltip on window resize if enabled
	if(posOptions.adjust.resize || viewportTarget.length) {
		this._bind( $.event.special.resize ? viewportTarget : windowTarget, 'resize', repositionMethod );
	}

	// Adjust tooltip position on scroll of the window or viewport element if present
	if(posOptions.adjust.scroll) {
		this._bind( windowTarget.add(posOptions.container), 'scroll', repositionMethod );
	}
};

// Un-assignment method
PROTOTYPE._unassignEvents = function() {
	var targets = [
		this.options.show.target[0],
		this.options.hide.target[0],
		this.rendered && this.tooltip[0],
		this.options.position.container[0],
		this.options.position.viewport[0],
		this.options.position.container.closest('html')[0], // unfocus
		window,
		document
	];

	this._unbind($([]).pushStack( $.grep(targets, function(i) {
		return typeof i === 'object';
	})));
};

<|endoftext|>


<commit_before>/**
 * jQuery UI custom widget: data range.
 * Author:
 *   Soichiro Miki
 * Depends:
 *   jquery-ui-1.8.x.js with Datepicker widget (or newer)
 *   layout.css
 */

$.widget('ui.daterange', {
	options: {
		dash: ' — ',
		icon: 'images/calendar_view_month.png'
	},

	_types: [
		{label: 'all', from: '', to: '' },
		{label: 'today', from: 'today', to: 'today', stripe: true },
		{label: 'yesterday', from: 'yesterday', to: 'yesterday', stripe: true},
		{label: 'last 1 week', from: '1 week ago', to: 'today' },
		{label: 'last 1 month', from: '1 month ago', to: 'today'},
		{label: 'last 3 months', from: '3 months ago', to: 'today'},
		{label: 'last 6 months', from: '6 months ago', to: 'today'},
		{label: 'last 1 year', from: '-1year', to: 'today' },
		{label: 'custom...', custom: true, stripe: true }
	],

	_create: function()
	{
		var self = this;
		var root = this.element.empty().addClass('ui-daterange')

		var datePickerOpts = {
			buttonText: 'select',
			buttonImage: self.options.icon,
			buttonImageOnly: true,
			showOn: 'button',
			constrainInput: false,
			dateFormat: 'yy-mm-dd',
			changeMonth: true,
			changeYear: true
		};

		var refresh = function()
		{
			var selected = $('option:selected', kindSelect);
			var info = selected.data('info');
			from.val(info.from);
			to.val(info.to);
			if (info.custom)
			{
				$.each([from, to], function() {
					$(this).removeAttr('disabled')
					.datepicker('enable')
					.datepicker('option', {maxDate: '', minDate: ''});
				});
			}
			else
			{
				$.each([from, to], function() {
					$(this).attr('disabled', 'disabled').datepicker('disable');
				});
			}
		};

		var kindSelect = $('<select>')
		.addClass('ui-daterange-kind')
		.appendTo(root);
		kindSelect.change(refresh);
		for (var i = 0; i < self._types.length; i++)
		{
			var item = self._types[i];
			var opt = $('<option>')
			.data('info', item)
			.append(item.label)
			.appendTo(kindSelect);
			if (item.stripe)
				opt.addClass('ui-daterange-stripe')
		}

		var customField = $('<span>')
		.addClass('ui-daterange-custom')
		.appendTo(root);

		// 'FROM' field
		var from = $('<input type="text">')
		.addClass('ui-daterange-from')
		.appendTo(customField)
		.datepicker(datePickerOpts)
		.datepicker('option', 'onSelect', function(text, inst) {
			to.datepicker('option', 'minDate', from.val());
		});
		if (this.options.fromName)
			from.attr('name', this.options.fromName);

		// ' - '
		customField.append(self.options.dash);

		// 'TO' field
		var to = $('<input type="text">')
		.addClass('ui-daterange-to')
		.appendTo(customField)
		.datepicker(datePickerOpts)
		.datepicker('option', 'onSelect', function(text, inst) {
			from.datepicker('option', 'maxDate', to.val());
		});
		if (this.options.toName)
			to.attr('name', this.options.toName);

		refresh();
	},

	_setOptions: function(key, value, animated)
	{
		$.Widget.prototype._setOption.apply(this, arguments);
	}
});<commit_msg>Daterange: Implement date calc on JavaScript<commit_after>/**
 * jQuery UI custom widget: data range.
 * Author:
 *   Soichiro Miki
 * Depends:
 *   jquery-ui-1.8.x.js with Datepicker widget (or newer)
 *   layout.css
 */

$.widget('ui.daterange', {
	options: {
		dash: ' — ',
		icon: 'images/calendar_view_month.png',
		dateFormat: 'yy-mm-dd'
	},

	_types: [
		{label: 'all', from: '', to: '' },
		{label: 'today', from: '0', to: '0', stripe: true },
		{label: 'yesterday', from: '-1d', to: '-1d', stripe: true},
		{label: 'last 1 week', from: '-7d', to: '0' },
		{label: 'last 1 month', from: '-1m', to: '0'},
		{label: 'last 3 months', from: '-3m', to: '0'},
		{label: 'last 6 months', from: '-6m', to: '0'},
		{label: 'last 1 year', from: '-12m', to: '0' },
		{label: 'custom...', custom: true, stripe: true }
	],

	_create: function()
	{
		var self = this;
		var root = this.element.empty().addClass('ui-daterange')

		var datePickerOpts = {
			buttonText: 'select',
			buttonImage: self.options.icon,
			buttonImageOnly: true,
			showOn: 'button',
			constrainInput: false,
			dateFormat: this.options.dateFormat,
			changeMonth: true,
			changeYear: true
		};

		var refresh = function()
		{
			var selected = $('option:selected', kindSelect);
			var info = selected.data('info');
			if (info.custom)
			{
				$.each([from, to], function() {
					$(this).removeAttr('disabled')
					.datepicker('enable')
					.datepicker('option', {maxDate: '', minDate: ''});
				});
			}
			else
			{
				$.each([[from, info.from], [to, info.to]], function() {
					var target = $(this[0]);
					var value = this[1];
					if (value)
					{
						target.val(self._format(self._calcDateDiff(value)));
					}
					else
						target.val('');
					target.attr('disabled', 'disabled').datepicker('disable');
				});
			}
		};

		var kindSelect = $('<select>')
		.addClass('ui-daterange-kind')
		.appendTo(root);
		kindSelect.change(refresh);
		for (var i = 0; i < self._types.length; i++)
		{
			var item = self._types[i];
			var opt = $('<option>')
			.data('info', item)
			.attr('value', item.label)
			.append(item.label)
			.appendTo(kindSelect);
			if (item.stripe)
				opt.addClass('ui-daterange-stripe')
		}

		var customField = $('<span>')
		.addClass('ui-daterange-custom')
		.appendTo(root);

		// 'FROM' field
		var from = $('<input type="text">')
		.addClass('ui-daterange-from')
		.appendTo(customField)
		.datepicker(datePickerOpts)
		.datepicker('option', 'onSelect', function(text, inst) {
			to.datepicker('option', 'minDate', from.val());
		});
		if (this.options.fromName)
			from.attr('name', this.options.fromName);

		// ' - '
		customField.append(self.options.dash);

		// 'TO' field
		var to = $('<input type="text">')
		.addClass('ui-daterange-to')
		.appendTo(customField)
		.datepicker(datePickerOpts)
		.datepicker('option', 'onSelect', function(text, inst) {
			from.datepicker('option', 'maxDate', to.val());
		});
		if (this.options.toName)
			to.attr('name', this.options.toName);

		refresh();
	},

	_calcDateDiff: function(diff, from)
	{
		var m = diff.match(/^(\-?)(\d+)([dwmy]?)$/);
		if (!m) return null;

		var dt = new Date();
		if (from instanceof Date) dt = from;
		if (m[3] == 'd' || m[3] == 'w' || !m[3])
		{
			var days = m[3] == 'w' ? m[2] * 7 : m[2];
			if (m[1]) days = -days;
			dt.setTime(dt.getTime() + 86400000 * days);
			return dt;
		}
		else
		{
			var months = m[3] == 'y' ? m[2] * 12 : m[2];
			if (m[1]) months = -months;
			var year = dt.getFullYear();
			var month = dt.getMonth() + parseInt(months);
			var date = dt.getDate();
			// round date in such a way that '1 month before 2011/Mar/30' is
			// 2011/Feb/28
			var lastDayOfTargetMonth = new Date(year, month + 1, 0).getDate();
			if (date > lastDayOfTargetMonth) date = lastDayOfTargetMonth;
			return new Date(year, month, date);
		}
	},

	_format: function(date)
	{
		return $.datepicker.formatDate(this.options.dateFormat, date);
	},

	_setOptions: function(key, value, animated)
	{
		$.Widget.prototype._setOption.apply(this, arguments);
	}
});<|endoftext|>