<commit_before>"use strict";

var db       = require('../../models');
var generate = require('../../lib/generate');

var _ = require('lodash');

var sendPostRequest = function(context, path, data, done) {
  request
    .post(path)
    .type('form') // sets Content-Type: application/x-www-form-urlencoded
    .send(data)
    .end(function(err, res) {
      context.res = res;
      done(err);
    });
};

var resetDatabase = function(done) {
  db.sequelize.query('DELETE FROM PairingCodes').then(function() {
    return db.sequelize.query('DELETE FROM ServiceAccessTokens');
  })
  .then(function() {
    done();
  },
  function(error) {
    done(error);
  });
};

var createPairingCode = function(attributes, done) {
  var data = {
    ClientId:         attributes.clientId,
    device_code:      '8ecf4b2a0df2df7fd69df128e0ac4fcc',
    user_code:        '0a264',
    verification_uri: 'http://www.example.com/verify',
    verified:         attributes.verified
  };

  db.PairingCode
    .create(data)
    .success(function(pairingCode) {
      done();
    });
};

var verifyError = function(res, error) {
  expect(res.headers['content-type']).to.equal('application/json; charset=utf-8');
  expect(res.body).to.be.an('object');
  expect(res.body).to.have.property('error');
  expect(res.body.error).to.equal(error);
};

describe("POST /token", function() {
  before(function() {
    sinon.stub(generate, 'accessToken').returns('aed201ffb3362de42700a293bdebf694');
  });

  after(function() {
    generate.accessToken.restore();
  });

  context("Polling to obtain an access token", function() {
    context("with incorrect Content-Type", function() {
      before(function(done) {
        var self = this;

        var requestBody = {
          client_id:  '101',
          grant_type: 'authorization_code',
          code:       '8ecf4b2a0df2df7fd69df128e0ac4fcc'
        };

        request
          .post('/token')
          .type('json') // sets Content-Type: application/json
          .send(requestBody)
          .end(function(err, res) {
            self.res = res;
            done(err);
          });
      });

      it("should return status 400", function() {
        expect(this.res.statusCode).to.equal(400);
      });

      it("should return an invalid_request error", function() {
        verifyError(this.res, 'invalid_request');
      });
    });

    context("with missing client_id", function() {
      before(function(done) {
        var requestBody = {
          // client_id:  '101',
          grant_type: 'authorization_code',
          code:       '8ecf4b2a0df2df7fd69df128e0ac4fcc'
        };

        sendPostRequest(this, '/token', requestBody, done);
      });

      it("should return status 400", function() {
        expect(this.res.statusCode).to.equal(400);
      });

      it("should return an invalid_request error", function() {
        verifyError(this.res, 'invalid_request');
      });
    });

    context("with an invalid client_id", function() {
      before(function(done) {
        var requestBody = {
          client_id:  'unknown',
          grant_type: 'authorization_code',
          code:       '8ecf4b2a0df2df7fd69df128e0ac4fcc'
        };

        sendPostRequest(this, '/token', requestBody, done);
      });

      it("should return status 400", function() {
        expect(this.res.statusCode).to.equal(400);
      });

      it("should return an invalid_client error", function() {
        verifyError(this.res, 'invalid_client');
      });
    });

    context("with missing grant_type", function() {
      before(function(done) {
        var requestBody = {
          client_id:  '101',
          // grant_type: 'authorization_code',
          code:       '8ecf4b2a0df2df7fd69df128e0ac4fcc'
        };

        sendPostRequest(this, '/token', requestBody, done);
      });

      it("should return status 400", function() {
        expect(this.res.statusCode).to.equal(400);
      });

      it("should return an invalid_request error", function() {
        verifyError(this.res, 'invalid_request');
      });
    });

    context("with an invalid grant_type", function() {
      before(function(done) {
        var requestBody = {
          client_id:  '101',
          grant_type: 'unknown',
          code:       '8ecf4b2a0df2df7fd69df128e0ac4fcc'
        };

        sendPostRequest(this, '/token', requestBody, done);
      });

      it("should return status 400", function() {
        expect(this.res.statusCode).to.equal(400);
      });

      it("should return an unsupported_grant_type error", function() {
        verifyError(this.res, 'unsupported_grant_type');
      });
    });

    context("with a valid client_id", function() {
      context("when the authorization request is pending", function() {
        context("when the authorization code is valid", function() {
          before(resetDatabase);

          before(function(done) {
            createPairingCode({ clientId: 100, verified: false }, done);
          });

          before(function(done) {
            var requestBody = {
              client_id:  '100',
              grant_type: 'authorization_code',
              code:       '8ecf4b2a0df2df7fd69df128e0ac4fcc'
            };

            sendPostRequest(this, '/token', requestBody, done);
          });

          it("should return status 400", function() {
            expect(this.res.statusCode).to.equal(400);
          });

          it("should return an authorization_pending error", function() {
            verifyError(this.res, 'authorization_pending');
          });
        });

        context("when the authorization code is invalid", function() {
          before(resetDatabase);

          before(function(done) {
            createPairingCode({ clientId: 100, verified: false }, done);
          });

          before(function(done) {
            var requestBody = {
              client_id:  '100',
              grant_type: 'authorization_code',
              code:       'invalid'
            };

            sendPostRequest(this, '/token', requestBody, done);
          });

          it("should return status 400", function() {
            expect(this.res.statusCode).to.equal(400);
          });

          it("should return an invalid_client error", function() {
            verifyError(this.res, 'invalid_client');
          });
        });
      });

      // RFC 6749, section 5.1
      context("when the authorization request is successful", function() {
        context("when the authorization code is valid", function() {
          before(resetDatabase);

          before(function(done) {
            createPairingCode({ clientId: 101, verified: true }, done);
          });

          before(function(done) {
            var requestBody = {
              client_id:  '101',
              grant_type: 'authorization_code',
              code:       '8ecf4b2a0df2df7fd69df128e0ac4fcc'
            };

            sendPostRequest(this, '/token', requestBody, done);
          });

          it("should return status 200", function() {
            expect(this.res.statusCode).to.equal(200);
          });

          it("should return a Cache-Control: no-store header", function() {
            expect(this.res.headers).to.have.property('cache-control');
            expect(this.res.headers['cache-control']).to.equal('no-store');
          });

          it("should return a Pragma: no-cache header", function() {
            expect(this.res.headers).to.have.property('pragma');
            expect(this.res.headers['pragma']).to.equal('no-cache');
          });

          it("should return a JSON object", function() {
            expect(this.res.headers['content-type']).to.equal('application/json; charset=utf-8');
            expect(this.res.body).to.be.an('object');
          });

          describe("the response body", function() {
            it("should include a valid access token", function() {
              expect(this.res.body).to.have.property('token');
              expect(this.res.body.token).to.equal('aed201ffb3362de42700a293bdebf694');
            });

            it("should include the token type", function() {
              expect(this.res.body).to.have.property('token_type');
              expect(this.res.body.token_type).to.equal('bearer');
            });

            it("should include a valid refresh token"); // TODO: optional: refresh_token
            it("should include the lifetime of the access token"); // TODO: recommended: expires_in
            it("should include the scope of the access token"); // TODO: optional(?): scope
          });

          describe("the database", function() {
            before(function(done) {
              var self = this;

              db.ServiceAccessToken.findAll()
                .then(function(accessTokens) {
                  self.accessTokens = accessTokens;
                  return db.PairingCode.findAll();
                })
                .then(function(pairingCodes) {
                  self.pairingCodes = pairingCodes;
                  done();
                },
                function(error) {
                  done(error)
                });
            });

            it("should delete the pairing code", function() {
              expect(this.pairingCodes).to.be.ok;
              expect(this.pairingCodes).to.be.an('array');
              expect(this.pairingCodes.length).to.equal(0);
            });

            it("should contain a new access token", function() {
              expect(this.accessTokens).to.be.ok;
              expect(this.accessTokens).to.be.an('array');
              expect(this.accessTokens.length).to.equal(1);
            });

            describe("the access token", function() {
              it("should have correct value", function() {
                expect(this.accessTokens[0].token).to.equal('aed201ffb3362de42700a293bdebf694');
              });

              it("should be associated with the correct client device", function() {
                expect(this.accessTokens[0].ClientId).to.equal(101);
              });

              it("should be associated with the correct user");

              it("should be associated with the correct service provider");
            });
          });
        });

        context("when the authorization code is invalid", function() {
          before(resetDatabase);

          before(function(done) {
            createPairingCode({ clientId: 101, verified: true }, done);
          });

          before(function(done) {
            var requestBody = {
              client_id:  '101',
              grant_type: 'authorization_code',
              code:       'invalid'
            };

            sendPostRequest(this, '/token', requestBody, done);
          });

          it("should return status 400", function() {
            expect(this.res.statusCode).to.equal(400);
          });

          it("should return invalid_client error", function() {
            verifyError(this.res, 'invalid_client');
          });
        });

        context("with missing authorization code", function() {
          before(resetDatabase);

          before(function(done) {
            createPairingCode({ clientId: 101, verified: true }, done);
          });

          before(function(done) {
            var requestBody = {
              client_id:  '101',
              grant_type: 'authorization_code',
              // code:       '8ecf4b2a0df2df7fd69df128e0ac4fcc'
            };

            sendPostRequest(this, '/token', requestBody, done);
          });

          it("should return status 400", function() {
            expect(this.res.statusCode).to.equal(400);
          });

          it("should return invalid_request error", function() {
            verifyError(this.res, 'invalid_request');
          });
        });
      });
    });

    context("when the client polls too quickly", function() {
      it("should return status 400");
      it("should return slow_down error");
    });
  });
});

describe("generate.accessToken", function() {
  it("should generate access tokens valid according to RFC6750 section 2.1", function() {
    var accessToken = generate.accessToken();

    // b64token    = 1*( ALPHA / DIGIT /
    //       "-" / "." / "_" / "~" / "+" / "/" ) *"="
    expect(accessToken).to.match(/^[A-Za-z0-9\-._~+/]+=*$/);
  });
});
<commit_msg>Refactored<commit_after>"use strict";

var db       = require('../../models');
var generate = require('../../lib/generate');

var _ = require('lodash');

var sendPostRequest = function(context, path, options, done) {
  request
    .post(path)
    .type(options.type || 'form') // sets Content-Type: application/x-www-form-urlencoded
    .send(options.data)
    .end(function(err, res) {
      context.res = res;
      done(err);
    });
};

var resetDatabase = function(done) {
  db.sequelize.query('DELETE FROM PairingCodes').then(function() {
    return db.sequelize.query('DELETE FROM ServiceAccessTokens');
  })
  .then(function() {
    done();
  },
  function(error) {
    done(error);
  });
};

var createPairingCode = function(attributes, done) {
  var data = {
    ClientId:         attributes.clientId,
    device_code:      '8ecf4b2a0df2df7fd69df128e0ac4fcc',
    user_code:        '0a264',
    verification_uri: 'http://www.example.com/verify',
    verified:         attributes.verified
  };

  db.PairingCode
    .create(data)
    .success(function(pairingCode) {
      done();
    });
};

var verifyError = function(res, error) {
  expect(res.headers['content-type']).to.equal('application/json; charset=utf-8');
  expect(res.body).to.be.an('object');
  expect(res.body).to.have.property('error');
  expect(res.body.error).to.equal(error);
};

describe("POST /token", function() {
  before(function() {
    sinon.stub(generate, 'accessToken').returns('aed201ffb3362de42700a293bdebf694');
  });

  after(function() {
    generate.accessToken.restore();
  });

  context("Polling to obtain an access token", function() {
    context("with incorrect Content-Type", function() {
      before(function(done) {
        var requestBody = {
          client_id:  '101',
          grant_type: 'authorization_code',
          code:       '8ecf4b2a0df2df7fd69df128e0ac4fcc'
        };

        sendPostRequest(this, '/token', { type: 'json', data: requestBody }, done);
      });

      it("should return status 400", function() {
        expect(this.res.statusCode).to.equal(400);
      });

      it("should return an invalid_request error", function() {
        verifyError(this.res, 'invalid_request');
      });
    });

    context("with missing client_id", function() {
      before(function(done) {
        var requestBody = {
          // client_id:  '101',
          grant_type: 'authorization_code',
          code:       '8ecf4b2a0df2df7fd69df128e0ac4fcc'
        };

        sendPostRequest(this, '/token', requestBody, done);
      });

      it("should return status 400", function() {
        expect(this.res.statusCode).to.equal(400);
      });

      it("should return an invalid_request error", function() {
        verifyError(this.res, 'invalid_request');
      });
    });

    context("with an invalid client_id", function() {
      before(function(done) {
        var requestBody = {
          client_id:  'unknown',
          grant_type: 'authorization_code',
          code:       '8ecf4b2a0df2df7fd69df128e0ac4fcc'
        };

        sendPostRequest(this, '/token', { data: requestBody }, done);
      });

      it("should return status 400", function() {
        expect(this.res.statusCode).to.equal(400);
      });

      it("should return an invalid_client error", function() {
        verifyError(this.res, 'invalid_client');
      });
    });

    context("with missing grant_type", function() {
      before(function(done) {
        var requestBody = {
          client_id:  '101',
          // grant_type: 'authorization_code',
          code:       '8ecf4b2a0df2df7fd69df128e0ac4fcc'
        };

        sendPostRequest(this, '/token', requestBody, done);
      });

      it("should return status 400", function() {
        expect(this.res.statusCode).to.equal(400);
      });

      it("should return an invalid_request error", function() {
        verifyError(this.res, 'invalid_request');
      });
    });

    context("with an invalid grant_type", function() {
      before(function(done) {
        var requestBody = {
          client_id:  '101',
          grant_type: 'unknown',
          code:       '8ecf4b2a0df2df7fd69df128e0ac4fcc'
        };

        sendPostRequest(this, '/token', { data: requestBody }, done);
      });

      it("should return status 400", function() {
        expect(this.res.statusCode).to.equal(400);
      });

      it("should return an unsupported_grant_type error", function() {
        verifyError(this.res, 'unsupported_grant_type');
      });
    });

    context("with a valid client_id", function() {
      context("when the authorization request is pending", function() {
        context("when the authorization code is valid", function() {
          before(resetDatabase);

          before(function(done) {
            createPairingCode({ clientId: 100, verified: false }, done);
          });

          before(function(done) {
            var requestBody = {
              client_id:  '100',
              grant_type: 'authorization_code',
              code:       '8ecf4b2a0df2df7fd69df128e0ac4fcc'
            };

            sendPostRequest(this, '/token', { data: requestBody }, done);
          });

          it("should return status 400", function() {
            expect(this.res.statusCode).to.equal(400);
          });

          it("should return an authorization_pending error", function() {
            verifyError(this.res, 'authorization_pending');
          });
        });

        context("when the authorization code is invalid", function() {
          before(resetDatabase);

          before(function(done) {
            createPairingCode({ clientId: 100, verified: false }, done);
          });

          before(function(done) {
            var requestBody = {
              client_id:  '100',
              grant_type: 'authorization_code',
              code:       'invalid'
            };

            sendPostRequest(this, '/token', { data: requestBody }, done);
          });

          it("should return status 400", function() {
            expect(this.res.statusCode).to.equal(400);
          });

          it("should return an invalid_client error", function() {
            verifyError(this.res, 'invalid_client');
          });
        });
      });

      // RFC 6749, section 5.1
      context("when the authorization request is successful", function() {
        context("when the authorization code is valid", function() {
          before(resetDatabase);

          before(function(done) {
            createPairingCode({ clientId: 101, verified: true }, done);
          });

          before(function(done) {
            var requestBody = {
              client_id:  '101',
              grant_type: 'authorization_code',
              code:       '8ecf4b2a0df2df7fd69df128e0ac4fcc'
            };

            sendPostRequest(this, '/token', { data: requestBody }, done);
          });

          it("should return status 200", function() {
            expect(this.res.statusCode).to.equal(200);
          });

          it("should return a Cache-Control: no-store header", function() {
            expect(this.res.headers).to.have.property('cache-control');
            expect(this.res.headers['cache-control']).to.equal('no-store');
          });

          it("should return a Pragma: no-cache header", function() {
            expect(this.res.headers).to.have.property('pragma');
            expect(this.res.headers['pragma']).to.equal('no-cache');
          });

          it("should return a JSON object", function() {
            expect(this.res.headers['content-type']).to.equal('application/json; charset=utf-8');
            expect(this.res.body).to.be.an('object');
          });

          describe("the response body", function() {
            it("should include a valid access token", function() {
              expect(this.res.body).to.have.property('token');
              expect(this.res.body.token).to.equal('aed201ffb3362de42700a293bdebf694');
            });

            it("should include the token type", function() {
              expect(this.res.body).to.have.property('token_type');
              expect(this.res.body.token_type).to.equal('bearer');
            });

            it("should include a valid refresh token"); // TODO: optional: refresh_token
            it("should include the lifetime of the access token"); // TODO: recommended: expires_in
            it("should include the scope of the access token"); // TODO: optional(?): scope
          });

          describe("the database", function() {
            before(function(done) {
              var self = this;

              db.ServiceAccessToken.findAll()
                .then(function(accessTokens) {
                  self.accessTokens = accessTokens;
                  return db.PairingCode.findAll();
                })
                .then(function(pairingCodes) {
                  self.pairingCodes = pairingCodes;
                  done();
                },
                function(error) {
                  done(error)
                });
            });

            it("should delete the pairing code", function() {
              expect(this.pairingCodes).to.be.ok;
              expect(this.pairingCodes).to.be.an('array');
              expect(this.pairingCodes.length).to.equal(0);
            });

            it("should contain a new access token", function() {
              expect(this.accessTokens).to.be.ok;
              expect(this.accessTokens).to.be.an('array');
              expect(this.accessTokens.length).to.equal(1);
            });

            describe("the access token", function() {
              it("should have correct value", function() {
                expect(this.accessTokens[0].token).to.equal('aed201ffb3362de42700a293bdebf694');
              });

              it("should be associated with the correct client device", function() {
                expect(this.accessTokens[0].ClientId).to.equal(101);
              });

              it("should be associated with the correct user");

              it("should be associated with the correct service provider");
            });
          });
        });

        context("when the authorization code is invalid", function() {
          before(resetDatabase);

          before(function(done) {
            createPairingCode({ clientId: 101, verified: true }, done);
          });

          before(function(done) {
            var requestBody = {
              client_id:  '101',
              grant_type: 'authorization_code',
              code:       'invalid'
            };

            sendPostRequest(this, '/token', { data: requestBody }, done);
          });

          it("should return status 400", function() {
            expect(this.res.statusCode).to.equal(400);
          });

          it("should return invalid_client error", function() {
            verifyError(this.res, 'invalid_client');
          });
        });

        context("with missing authorization code", function() {
          before(resetDatabase);

          before(function(done) {
            createPairingCode({ clientId: 101, verified: true }, done);
          });

          before(function(done) {
            var requestBody = {
              client_id:  '101',
              grant_type: 'authorization_code',
              // code:       '8ecf4b2a0df2df7fd69df128e0ac4fcc'
            };

            sendPostRequest(this, '/token', { data: requestBody }, done);
          });

          it("should return status 400", function() {
            expect(this.res.statusCode).to.equal(400);
          });

          it("should return invalid_request error", function() {
            verifyError(this.res, 'invalid_request');
          });
        });
      });
    });

    context("when the client polls too quickly", function() {
      it("should return status 400");
      it("should return slow_down error");
    });
  });
});

describe("generate.accessToken", function() {
  it("should generate access tokens valid according to RFC6750 section 2.1", function() {
    var accessToken = generate.accessToken();

    // b64token    = 1*( ALPHA / DIGIT /
    //       "-" / "." / "_" / "~" / "+" / "/" ) *"="
    expect(accessToken).to.match(/^[A-Za-z0-9\-._~+/]+=*$/);
  });
});
<|endoftext|>


<commit_before>var demand = require('must'),
	di = require('../../lib/asyncdi');

var fn_basic = function() { return true; };
var fn_async = function(callback) { callback(null, true) };
var fn_one = function(one) { return true; };

describe('asyncdi', function() {
	describe('new', function() {
		it('must be an instance of Wrapper', function() {
			new di.Wrapper(fn_basic).must.be.an.instanceof(di.Wrapper);
		});
	});
	describe('()', function() {
		it('must be an instance of Wrapper', function() {
			di(fn_basic).must.be.an.instanceof(di.Wrapper);
		});
	});
	describe('fn_basic.isAsync', function() {
		it('must not be async', function() {
			demand(di(fn_basic).isAsync).not.be.true();
		});
	});
	describe('fn_async.isAsync', function() {
		it('must be async', function() {
			demand(di(fn_async).isAsync).be.true();
		});
	});
	describe('fn_basic.call(callback)', function() {
		it('must callback(null, true)', function(done) {
			di(fn_basic).call(function(err, val) {
				demand(err).be.null();
				demand(val).be.true();
				done();
			});
		});
	});
	describe('fn_basic.call()', function() {
		it('must return true', function() {
			di(fn_basic).call().must.be.true();
		});
	});
	describe('fn_async.call(callback)', function() {
		it('must callback(null, true)', function(done) {
			di(fn_async).call(function(err, val) {
				demand(err).be.null();
				demand(val).be.true();
				done();
			});
		});
	});
	describe('fn_one.requires', function() {
		it('must require `one`', function() {
			demand(di(fn_one).requires.one).be.true();
		});
	});
	describe('fn_one.requires', function() {
		it('must not require `two`', function() {
			demand(di(fn_one).requires.two).be.undefined();
		});
	});
})
<commit_msg>Improving asyncdi spec<commit_after>var demand = require('must'),
	di = require('../../lib/asyncdi');

var fn_basic = function() { return true; };
var fn_async = function(callback) { callback(null, true) };
var fn_one = function(one) { return true; };

describe('AsyncDI', function() {
	describe('new Wrapper', function() {
		it('must be an instance of Wrapper', function() {
			new di.Wrapper(fn_basic).must.be.an.instanceof(di.Wrapper);
		});
	});
	describe('()', function() {
		it('must be an instance of Wrapper', function() {
			di(fn_basic).must.be.an.instanceof(di.Wrapper);
		});
	});
	describe('fn_basic.isAsync', function() {
		it('must not be async', function() {
			demand(di(fn_basic).isAsync).not.be.true();
		});
	});
	describe('fn_async.isAsync', function() {
		it('must be async', function() {
			demand(di(fn_async).isAsync).be.true();
		});
	});
	describe('fn_basic.call(callback)', function() {
		it('must callback(null, true)', function(done) {
			di(fn_basic).call(function(err, val) {
				demand(err).be.null();
				demand(val).be.true();
				done();
			});
		});
	});
	describe('fn_basic.call()', function() {
		it('must return true', function() {
			di(fn_basic).call().must.be.true();
		});
	});
	describe('fn_async.call(callback)', function() {
		it('must callback(null, true)', function(done) {
			di(fn_async).call(function(err, val) {
				demand(err).be.null();
				demand(val).be.true();
				done();
			});
		});
	});
	describe('fn_one.requires', function() {
		it('must require `one`', function() {
			demand(di(fn_one).requires.one).be.true();
		});
	});
	describe('fn_one.requires', function() {
		it('must not require `two`', function() {
			demand(di(fn_one).requires.two).be.undefined();
		});
	});
})
<|endoftext|>


<commit_before>'use strict';

/* Services */

// Demonstrate how to register services
// In this case it is a simple value service.
angular.module('myApp.services', []).
  value('version', '0.1')

  .factory('usersplaces', function($rootScope, $http, placeName) {
    var cache = {};

    return function(part, user, fn) {
        var url = 'usersplaces/' + part + '/' + user;
        $http.get(url).success(function(data) {
            placeName(part, data.name);
            var placesTypes = data.placesTypes.filter(function(d){
                return d.places && d.places.length > 0;
            })
            cache[url] = placesTypes;
            fn(placesTypes);
        });
        return cache[url] || undefined;
    }
  })

  .factory('placeName', function($rootScope, $http) {
    var names = {
        'us' : 'USA',
        'world' : 'Svět',
    }

    return function(part, name) {
        if (name && !names[part]) {
            names[part] = name;
        }
        return names[part];
    }
  })

  .service('question', function($rootScope, $http, $cookies) {

    $http.defaults.headers.post['X-CSRFToken'] = $cookies.csrftoken;
    $http.defaults.headers.post['Content-Type'] =  'application/x-www-form-urlencoded'
      var qIndex = 0;
      var lastAnswerIndex = -1;
      var worldPart;
      function returnQuestion (fn){
            var q = questions[qIndex++];
            if(q) q.msResponseTime = - (new Date()).valueOf();
            fn(q);
      }
      var questions = []
      return {
          first: function(part, fn){
              worldPart = part
                $http.get('question/' + part).success(function(data) {
                    qIndex = 0;
                    lastAnswerIndex = -1
                    questions = data;
                    returnQuestion(fn);
                });
          },
          availableCount: function(part, fn){
              worldPart = part
                $http.get('question/' + part).success(function(data) {
                    fn(data.length);
                });
          },
          next: function(part, fn){
                returnQuestion(fn);
          },
          answer: function(question) {
                question.msResponseTime += (new Date()).valueOf();
                question.index = qIndex-1;
                questions[qIndex-1] = question;
                $http.post('question/' + worldPart, question).success(function(data) {
                    var newLastAnswerIndex = questions.length - data.length -1;
                    // if it is not a delayed response
                    if (lastAnswerIndex < newLastAnswerIndex) {
                        lastAnswerIndex = newLastAnswerIndex;
                        questions = questions.slice(0, lastAnswerIndex +1).concat(data);
                    }
                });

                return  100 * qIndex / questions.length;
          },
          summary: function() {
              var correctlyAnswered = questions.filter(function(q){
                      return q.code == q.answer;
                  })

              return {
                  correctlyAnsweredRatio : correctlyAnswered.length / questions.length,
                  questions : questions
              }
          }
      }

  })
<commit_msg>JavaScript: Practise summary showing incorrect states bug fixed<commit_after>'use strict';

/* Services */

// Demonstrate how to register services
// In this case it is a simple value service.
angular.module('myApp.services', []).
  value('version', '0.1')

  .factory('usersplaces', function($rootScope, $http, placeName) {
    var cache = {};

    return function(part, user, fn) {
        var url = 'usersplaces/' + part + '/' + user;
        $http.get(url).success(function(data) {
            placeName(part, data.name);
            var placesTypes = data.placesTypes.filter(function(d){
                return d.places && d.places.length > 0;
            })
            cache[url] = placesTypes;
            fn(placesTypes);
        });
        return cache[url] || undefined;
    }
  })

  .factory('placeName', function($rootScope, $http) {
    var names = {
        'us' : 'USA',
        'world' : 'Svět',
    }

    return function(part, name) {
        if (name && !names[part]) {
            names[part] = name;
        }
        return names[part];
    }
  })

  .service('question', function($rootScope, $http, $cookies) {

    $http.defaults.headers.post['X-CSRFToken'] = $cookies.csrftoken;
    $http.defaults.headers.post['Content-Type'] =  'application/x-www-form-urlencoded'
      var qIndex = 0;
      var lastAnswerIndex = -1;
      var worldPart;
      function returnQuestion (fn){
            var q = questions[qIndex++];
            if(q) q.msResponseTime = - (new Date()).valueOf();
            fn(q);
      }
      var questions = []
      var summary = []
      return {
          first: function(part, fn){
              worldPart = part;
              summary = [];
                $http.get('question/' + part).success(function(data) {
                    qIndex = 0;
                    lastAnswerIndex = -1;
                    questions = data;
                    returnQuestion(fn);
                });
          },
          availableCount: function(part, fn){
              worldPart = part
                $http.get('question/' + part).success(function(data) {
                    fn(data.length);
                });
          },
          next: function(part, fn){
                returnQuestion(fn);
          },
          answer: function(question) {
                question.msResponseTime += (new Date()).valueOf();
                question.index = qIndex-1;
                summary.push(question);
                $http.post('question/' + worldPart, question).success(function(data) {
                    var newLastAnswerIndex = questions.length - data.length -1;
                    // if it is not a delayed response
                    if (lastAnswerIndex < newLastAnswerIndex) {
                        lastAnswerIndex = newLastAnswerIndex;
                        questions = questions.slice(0, lastAnswerIndex +1).concat(data);
                    }
                });

                return  100 * qIndex / questions.length;
          },
          summary: function() {
              var correctlyAnswered = summary.filter(function(q){
                      return q.code == q.answer;
                  })

              return {
                  correctlyAnsweredRatio : correctlyAnswered.length / summary.length,
                  questions : summary
              }
          }
      }

  })
<|endoftext|>


<commit_before>var Immutable = require('immutable');
var _localStorage = require('./lib/localStorage');

var ImmutableStoreMixin = {
    state: Immutable.Map(),
    init: function() {
        // Update state with cached data
        this.setState(this._getCachedState(), false);
    },
    setState: function(nextState, triggerUpdate) {
        if (!nextState) {
            return null;
        }

    	var _targetState = this.state.merge(nextState);

    	if (_targetState !== this.state) {
    		this.state = _targetState;

            if (triggerUpdate !== false) {
                this.trigger();
                this._updateLocalStorage();
            }
    	}
    },
    get: function(key) {
		return this.state.get(key);
    },
    _updateLocalStorage: function() {
        if (!this.localStorageKey) {
            // Don't save state unless we need too
            return null;
        }

        var _stateString;

        if (this.stateToString) {
            // Custom conversion to string
            _stateString = this.stateToString(this.state);

            if (!_stateString) {
                var err = new Error('`stateToString()` must return a valid JSON string');
                console.warn(err.stack);
                return null;
            }
        }
        else {
            _stateString = JSON.stringify(this.state.toJS());
        }

        _localStorage.setItem(this.localStorageKey, _stateString);
    },
    _getCachedState: function() {
        if (!this.localStorageKey) {
            // Don't get state unless we need too
            return null;
        }

        var _stateString = _localStorage.getItem(this.localStorageKey);

        if (!_stateString || _stateString === '') {
            return null;
        }

        var _cachedState;

        if (this.stateFromString) {
            _cachedState = this.stateFromString(_stateString);

            if (!_cachedState) {
                var err = new Error('`stateFromString()` must return a Immutable.Map');
                console.warn(err.stack);
                return null;
            }
        }
        else {
            var _cachedJSON = JSON.parse(_stateString);
            _cachedState = Immutable.fromJS(_cachedJSON);
        }

        return _cachedState;
    }
};

module.exports = ImmutableStoreMixin;
<commit_msg>trigger callback on first get request<commit_after>var Immutable = require('immutable');
var _localStorage = require('./lib/localStorage');

var ImmutableStoreMixin = {
    state: Immutable.Map(),
    init: function() {
        // Update state with cached data
        this.setState(this._getCachedState(), false);
    },
    setState: function(nextState, triggerUpdate) {
        if (!nextState) {
            return null;
        }

    	var _targetState = this.state.merge(nextState);

    	if (_targetState !== this.state) {
    		this.state = _targetState;

            if (triggerUpdate !== false) {
                this.trigger();
                this._updateLocalStorage();
            }
    	}
    },
    get: function(key) {
        if (this.onFirstRequest && !this._ImmutableStoreMixinRequested) {
            this._ImmutableStoreMixinRequested = true;
            this.onFirstRequest();
        }

		return this.state.get(key);
    },
    _updateLocalStorage: function() {
        if (!this.localStorageKey) {
            // Don't save state unless we need too
            return null;
        }

        var _stateString;

        if (this.stateToString) {
            // Custom conversion to string
            _stateString = this.stateToString(this.state);

            if (!_stateString) {
                var err = new Error('`stateToString()` must return a valid JSON string');
                console.warn(err.stack);
                return null;
            }
        }
        else {
            _stateString = JSON.stringify(this.state.toJS());
        }

        _localStorage.setItem(this.localStorageKey, _stateString);
    },
    _getCachedState: function() {
        if (!this.localStorageKey) {
            // Don't get state unless we need too
            return null;
        }

        var _stateString = _localStorage.getItem(this.localStorageKey);

        if (!_stateString || _stateString === '') {
            return null;
        }

        var _cachedState;

        if (this.stateFromString) {
            _cachedState = this.stateFromString(_stateString);

            if (!_cachedState) {
                var err = new Error('`stateFromString()` must return a Immutable.Map');
                console.warn(err.stack);
                return null;
            }
        }
        else {
            var _cachedJSON = JSON.parse(_stateString);
            _cachedState = Immutable.fromJS(_cachedJSON);
        }

        return _cachedState;
    }
};

module.exports = ImmutableStoreMixin;
<|endoftext|>


<commit_before>$(document).ready(function(){

        /*
         * jQuery Accessible tab panel system, using ARIA
         * Website: http://a11y.nicolas-hoffmann.net/tabs/
         * License MIT: https://github.com/nico3333fr/jquery-accessible-tabs-aria/blob/master/LICENSE
         */
        // Store current URL hash.
        var hash = window.location.hash.replace( "#", "" );

        /* Tabs ------------------------------------------------------------------------------------------------------------ */
        $tabs = $( ".js-tabs" );

        if ( $tabs.length ) {

            $tab_list = $( ".js-tablist" );
            $tab_list.each( function () {
                var $this_tab_list = $( this ),
                    options = $this_tab_list.data(),
                    $tabs_prefix_classes = typeof options.tabsPrefixClass !== 'undefined' ? options.tabsPrefixClass + '-' : '',
                    $hx = typeof options.hx !== 'undefined' ? options.hx : '',
                    $existing_hx = typeof options.existingHx !== 'undefined' ? options.existingHx : '',
                    $this_tab_list_items = $this_tab_list.children( ".js-tablist__item" ),
                    $this_tab_list_links = $this_tab_list.find( ".js-tablist__link" );

                // roles init
                $this_tab_list.attr( "role", "tablist" );                   // ul
                $this_tab_list_items.attr( "role", "presentation" );        // li
                $this_tab_list_links.attr( "role", "tab" );                 // a

                // classes init
                $this_tab_list.addClass( $tabs_prefix_classes + 'tabs__list' );
                $this_tab_list_items.addClass( $tabs_prefix_classes + 'tabs__item' );
                $this_tab_list_links.addClass( $tabs_prefix_classes + 'tabs__link' );

                // controls/tabindex attributes
                $this_tab_list_links.each( function () {
                    var $this = $( this ),
                        $href = $this.attr( "href" ),
                        $controls = $( $href ),
                        $text = $this.html();

                    if ( $hx !== "" ) {
                       $controls.prepend('<' + $hx + ' class="invisible" tabindex="0">' + $text + '</' + $hx + '>');
                    }
                    if ( $existing_hx !== "" ) {
                       $controls.find($existing_hx + ':first-child').attr('tabindex',0);
                    }
                    if ( typeof $href !== "undefined" && $href !== "" && $href !== "#" ) {
                            $this.attr({
                                    "aria-controls": $href.replace( "#", "" ),
                                    "tabindex": -1,
                                    "aria-selected": "false"
                            });
                    }

                    $this.removeAttr("href");

                    } );
            } );

            /* Tabs content ---------------------------------------------------------------------------------------------------- */
            $( ".js-tabcontent" ).attr({
                    "role": "tabpanel",             // contents
                    "aria-hidden": "true"           // all hidden
                    //"tabindex": 0
            })
            .each( function() {
                    var $this = $( this ),
                        $this_id = $this.attr( "id" ),
                        $prefix_attribute = $("#label_" + $this_id ).parents('.js-tablist').attr( 'data-tabs-prefix-class' ),
                        $tabs_prefix_classes = typeof $prefix_attribute !== 'undefined' ? $prefix_attribute + '-' : '';
                    // label by link
                    $this.attr( "aria-labelledby", "label_" + $this_id );

                    $this.addClass ( $tabs_prefix_classes + 'tabs__content');
            });

            // search if hash is ON tabs
            if ( hash !== "" && $( "#" + hash + ".js-tabcontent" ).length !== 0 ) {
                    // display
                    $( "#" + hash + ".js-tabcontent" ).removeAttr( "aria-hidden" );
                    // selection menu
                    $( "#label_" + hash + ".js-tablist__link" ).attr({
                            "aria-selected": "true",
                            "tabindex": 0
                    });
            }
            // search if hash is IN tabs
            if ( hash !== "" && $( "#" + hash + ".js-tabcontent" ).length === 0 && $( "#" + hash ).parents( '.js-tabcontent' ).length ){
                var $this_hash = $( "#" + hash ),
                    $tab_content_parent = $this_hash.parents( '.js-tabcontent' ),
                    $tab_content_parent_id = $tab_content_parent.attr( 'id' );

                    $tab_content_parent.removeAttr( "aria-hidden" );
                    // selection menu
                    $( "#label_" + $tab_content_parent_id + ".js-tablist__link" ).attr({
                            "aria-selected": "true",
                            "tabindex": 0
                    });
            }

            // if no selected => select first
            $tabs.each( function() {
                    var $this = $( this ),
                        $tab_selected = $this.find( '.js-tablist__link[aria-selected="true"]' ),
                        $first_link = $this.find( ".js-tablist__link:first" ),
                        $first_content = $this.find( ".js-tabcontent:first" );

                    if ( $tab_selected.length === 0 ) {
                       $first_link.attr({
                             "aria-selected": "true",
                             "tabindex": 0
                       });
                       $first_content.removeAttr( "aria-hidden" );
                    }
            } );

            /* Events ---------------------------------------------------------------------------------------------------------- */
            /* click on a tab link */
            $( "body" ).on( "click", ".js-tablist__link", function( event ) {
                    var $this = $( this ),
                        $hash_to_update = $this.attr( "aria-controls" ),
                        $tab_content_linked = $( "#" + $this.attr( "aria-controls" ) ),
                        $parent = $this.parents( ".js-tabs" ),
                        $all_tab_links = $parent.find( ".js-tablist__link" ),
                        $all_tab_contents = $parent.find( ".js-tabcontent" );

                    // aria selected false on all links
                    $all_tab_links.attr({
                        "tabindex": -1,
                        "aria-selected": "false"
                        });

                    // add aria selected on $this
                    $this.attr({
                        "aria-selected": "true",
                        "tabindex": 0
                    });

                    // add aria-hidden on all tabs contents
                    $all_tab_contents.attr( "aria-hidden", "true" );

                    // remove aria-hidden on tab linked
                    $tab_content_linked.removeAttr( "aria-hidden" );

                    // add fragment (timeout for transitions)
                    setTimeout(function(){ history.pushState(null, null, location.pathname + location.search + '#' + $hash_to_update)}, 1000);

                    event.preventDefault();
            } )
            /* Key down in tabs */
            .on( "keydown", ".js-tablist", function( event ) {

                    var $parent = $(this).parents( '.js-tabs' ),
                        $activated = $parent.find( '.js-tablist__link[aria-selected="true"]' ).parent(),
                        $last_link = $parent.find( ".js-tablist__item:last-child .js-tablist__link" ),
                        $first_link = $parent.find( ".js-tablist__item:first-child .js-tablist__link" ),
                        $focus_on_tab_only = false;

                    // some event should be activated only if the focus is on tabs (not on tabpanel)
                    if ( $( document.activeElement ).is( $parent.find('.js-tablist__link') ) ){
                       $focus_on_tab_only = true;
                       }

                    // catch keyboard event only if focus is on tab
                    if ($focus_on_tab_only && !event.ctrlKey) {
                        // strike up or left in the tab
                        if ( event.keyCode == 37 || event.keyCode == 38 ) {
                                // if we are on first => activate last
                                if ( $activated.is( ".js-tablist__item:first-child" ) ) {
                                    $last_link.click().focus();
                                }
                                // else activate previous
                                else {
                                     $activated.prev().children( ".js-tablist__link" ).click().focus();
                                }
                                event.preventDefault();
                        }
                        // strike down or right in the tab
                        else if ( event.keyCode == 40 || event.keyCode == 39 ) {
                                // if we are on last => activate first
                                if ( $activated.is( ".js-tablist__item:last-child" ) ) {
                                    $first_link.click().focus();
                                }
                                // else activate next
                                else {
                                      $activated.next().children( ".js-tablist__link" ).click().focus();
                                     }
                                event.preventDefault();
                        }
                        else if ( event.keyCode == 36 ) {
                                // activate first tab
                                $first_link.click().focus();
                                event.preventDefault();
                        }
                        else if ( event.keyCode == 35 ) {
                                // activate last tab
                                $last_link.click().focus();
                                event.preventDefault();
                        }

                    }

            } )
            .on( "keydown", ".js-tabcontent", function( event ) {

                    var $this = $(this),
                        $selector_tab_to_focus = $this.attr('aria-labelledby'),
                        $tab_to_focus = $("#" + $selector_tab_to_focus),
                        $parent_item = $tab_to_focus.parent(),
                        $parent_list = $parent_item.parent();

                    // CTRL up/Left
                    if ( (event.keyCode == 37 || event.keyCode == 38) && event.ctrlKey ) {
                        $tab_to_focus.focus();
                        event.preventDefault();
                    }
                    // CTRL PageUp
                    if ( event.keyCode == 33 && event.ctrlKey ) {
                        $tab_to_focus.focus();

                        // if we are on first => activate last
                        if ( $parent_item.is( ".js-tablist__item:first-child" ) ) {
                           $parent_list.find( ".js-tablist__item:last-child .js-tablist__link" ).click().focus();
                        }
                        // else activate prev
                        else {
                             $parent_item.prev().children( ".js-tablist__link" ).click().focus();
                             }
                        event.preventDefault();
                    }
                    // CTRL PageDown
                    if ( event.keyCode == 34 && event.ctrlKey ) {
                        $tab_to_focus.focus();

                        // if we are on last => activate first
                        if ( $parent_item.is( ".js-tablist__item:last-child" ) ) {
                           $parent_list.find( ".js-tablist__item:first-child .js-tablist__link" ).click().focus();
                        }
                        // else activate next
                        else {
                             $parent_item.next().children( ".js-tablist__link" ).click().focus();
                             }
                        event.preventDefault();
                    }

            } )
            /* click on a tab link */
            .on( "click", ".js-link-to-tab", function( event ) {
                    var $this = $(this),
                         $tab_to_go = $($this.attr('href')),
                         $button_to_click = $( '#' + $tab_to_go.attr('aria-labelledby') );

                    // activate tabs
                    $button_to_click.click();
                    // give focus to the good button
                    setTimeout(function(){ $button_to_click.focus() }, 10);
            } );

        }

});
<commit_msg>Fixed Global namespace pollution<commit_after>$(document).ready(function(){

        /*
         * jQuery Accessible tab panel system, using ARIA
         * Website: http://a11y.nicolas-hoffmann.net/tabs/
         * License MIT: https://github.com/nico3333fr/jquery-accessible-tabs-aria/blob/master/LICENSE
         */
        // Store current URL hash.
        var hash = window.location.hash.replace( "#", "" );

        /* Tabs ------------------------------------------------------------------------------------------------------------ */
        var $tabs = $( ".js-tabs" );

        if ( $tabs.length ) {

            var $tab_list = $( ".js-tablist" );
            $tab_list.each( function () {
                var $this_tab_list = $( this ),
                    options = $this_tab_list.data(),
                    $tabs_prefix_classes = typeof options.tabsPrefixClass !== 'undefined' ? options.tabsPrefixClass + '-' : '',
                    $hx = typeof options.hx !== 'undefined' ? options.hx : '',
                    $existing_hx = typeof options.existingHx !== 'undefined' ? options.existingHx : '',
                    $this_tab_list_items = $this_tab_list.children( ".js-tablist__item" ),
                    $this_tab_list_links = $this_tab_list.find( ".js-tablist__link" );

                // roles init
                $this_tab_list.attr( "role", "tablist" );                   // ul
                $this_tab_list_items.attr( "role", "presentation" );        // li
                $this_tab_list_links.attr( "role", "tab" );                 // a

                // classes init
                $this_tab_list.addClass( $tabs_prefix_classes + 'tabs__list' );
                $this_tab_list_items.addClass( $tabs_prefix_classes + 'tabs__item' );
                $this_tab_list_links.addClass( $tabs_prefix_classes + 'tabs__link' );

                // controls/tabindex attributes
                $this_tab_list_links.each( function () {
                    var $this = $( this ),
                        $href = $this.attr( "href" ),
                        $controls = $( $href ),
                        $text = $this.html();

                    if ( $hx !== "" ) {
                       $controls.prepend('<' + $hx + ' class="invisible" tabindex="0">' + $text + '</' + $hx + '>');
                    }
                    if ( $existing_hx !== "" ) {
                       $controls.find($existing_hx + ':first-child').attr('tabindex',0);
                    }
                    if ( typeof $href !== "undefined" && $href !== "" && $href !== "#" ) {
                            $this.attr({
                                    "aria-controls": $href.replace( "#", "" ),
                                    "tabindex": -1,
                                    "aria-selected": "false"
                            });
                    }

                    $this.removeAttr("href");

                    } );
            } );

            /* Tabs content ---------------------------------------------------------------------------------------------------- */
            $( ".js-tabcontent" ).attr({
                    "role": "tabpanel",             // contents
                    "aria-hidden": "true"           // all hidden
                    //"tabindex": 0
            })
            .each( function() {
                    var $this = $( this ),
                        $this_id = $this.attr( "id" ),
                        $prefix_attribute = $("#label_" + $this_id ).parents('.js-tablist').attr( 'data-tabs-prefix-class' ),
                        $tabs_prefix_classes = typeof $prefix_attribute !== 'undefined' ? $prefix_attribute + '-' : '';
                    // label by link
                    $this.attr( "aria-labelledby", "label_" + $this_id );

                    $this.addClass ( $tabs_prefix_classes + 'tabs__content');
            });

            // search if hash is ON tabs
            if ( hash !== "" && $( "#" + hash + ".js-tabcontent" ).length !== 0 ) {
                    // display
                    $( "#" + hash + ".js-tabcontent" ).removeAttr( "aria-hidden" );
                    // selection menu
                    $( "#label_" + hash + ".js-tablist__link" ).attr({
                            "aria-selected": "true",
                            "tabindex": 0
                    });
            }
            // search if hash is IN tabs
            if ( hash !== "" && $( "#" + hash + ".js-tabcontent" ).length === 0 && $( "#" + hash ).parents( '.js-tabcontent' ).length ){
                var $this_hash = $( "#" + hash ),
                    $tab_content_parent = $this_hash.parents( '.js-tabcontent' ),
                    $tab_content_parent_id = $tab_content_parent.attr( 'id' );

                    $tab_content_parent.removeAttr( "aria-hidden" );
                    // selection menu
                    $( "#label_" + $tab_content_parent_id + ".js-tablist__link" ).attr({
                            "aria-selected": "true",
                            "tabindex": 0
                    });
            }

            // if no selected => select first
            $tabs.each( function() {
                    var $this = $( this ),
                        $tab_selected = $this.find( '.js-tablist__link[aria-selected="true"]' ),
                        $first_link = $this.find( ".js-tablist__link:first" ),
                        $first_content = $this.find( ".js-tabcontent:first" );

                    if ( $tab_selected.length === 0 ) {
                       $first_link.attr({
                             "aria-selected": "true",
                             "tabindex": 0
                       });
                       $first_content.removeAttr( "aria-hidden" );
                    }
            } );

            /* Events ---------------------------------------------------------------------------------------------------------- */
            /* click on a tab link */
            $( "body" ).on( "click", ".js-tablist__link", function( event ) {
                    var $this = $( this ),
                        $hash_to_update = $this.attr( "aria-controls" ),
                        $tab_content_linked = $( "#" + $this.attr( "aria-controls" ) ),
                        $parent = $this.parents( ".js-tabs" ),
                        $all_tab_links = $parent.find( ".js-tablist__link" ),
                        $all_tab_contents = $parent.find( ".js-tabcontent" );

                    // aria selected false on all links
                    $all_tab_links.attr({
                        "tabindex": -1,
                        "aria-selected": "false"
                        });

                    // add aria selected on $this
                    $this.attr({
                        "aria-selected": "true",
                        "tabindex": 0
                    });

                    // add aria-hidden on all tabs contents
                    $all_tab_contents.attr( "aria-hidden", "true" );

                    // remove aria-hidden on tab linked
                    $tab_content_linked.removeAttr( "aria-hidden" );

                    // add fragment (timeout for transitions)
                    setTimeout(function(){ history.pushState(null, null, location.pathname + location.search + '#' + $hash_to_update)}, 1000);

                    event.preventDefault();
            } )
            /* Key down in tabs */
            .on( "keydown", ".js-tablist", function( event ) {

                    var $parent = $(this).parents( '.js-tabs' ),
                        $activated = $parent.find( '.js-tablist__link[aria-selected="true"]' ).parent(),
                        $last_link = $parent.find( ".js-tablist__item:last-child .js-tablist__link" ),
                        $first_link = $parent.find( ".js-tablist__item:first-child .js-tablist__link" ),
                        $focus_on_tab_only = false;

                    // some event should be activated only if the focus is on tabs (not on tabpanel)
                    if ( $( document.activeElement ).is( $parent.find('.js-tablist__link') ) ){
                       $focus_on_tab_only = true;
                       }

                    // catch keyboard event only if focus is on tab
                    if ($focus_on_tab_only && !event.ctrlKey) {
                        // strike up or left in the tab
                        if ( event.keyCode == 37 || event.keyCode == 38 ) {
                                // if we are on first => activate last
                                if ( $activated.is( ".js-tablist__item:first-child" ) ) {
                                    $last_link.click().focus();
                                }
                                // else activate previous
                                else {
                                     $activated.prev().children( ".js-tablist__link" ).click().focus();
                                }
                                event.preventDefault();
                        }
                        // strike down or right in the tab
                        else if ( event.keyCode == 40 || event.keyCode == 39 ) {
                                // if we are on last => activate first
                                if ( $activated.is( ".js-tablist__item:last-child" ) ) {
                                    $first_link.click().focus();
                                }
                                // else activate next
                                else {
                                      $activated.next().children( ".js-tablist__link" ).click().focus();
                                     }
                                event.preventDefault();
                        }
                        else if ( event.keyCode == 36 ) {
                                // activate first tab
                                $first_link.click().focus();
                                event.preventDefault();
                        }
                        else if ( event.keyCode == 35 ) {
                                // activate last tab
                                $last_link.click().focus();
                                event.preventDefault();
                        }

                    }

            } )
            .on( "keydown", ".js-tabcontent", function( event ) {

                    var $this = $(this),
                        $selector_tab_to_focus = $this.attr('aria-labelledby'),
                        $tab_to_focus = $("#" + $selector_tab_to_focus),
                        $parent_item = $tab_to_focus.parent(),
                        $parent_list = $parent_item.parent();

                    // CTRL up/Left
                    if ( (event.keyCode == 37 || event.keyCode == 38) && event.ctrlKey ) {
                        $tab_to_focus.focus();
                        event.preventDefault();
                    }
                    // CTRL PageUp
                    if ( event.keyCode == 33 && event.ctrlKey ) {
                        $tab_to_focus.focus();

                        // if we are on first => activate last
                        if ( $parent_item.is( ".js-tablist__item:first-child" ) ) {
                           $parent_list.find( ".js-tablist__item:last-child .js-tablist__link" ).click().focus();
                        }
                        // else activate prev
                        else {
                             $parent_item.prev().children( ".js-tablist__link" ).click().focus();
                             }
                        event.preventDefault();
                    }
                    // CTRL PageDown
                    if ( event.keyCode == 34 && event.ctrlKey ) {
                        $tab_to_focus.focus();

                        // if we are on last => activate first
                        if ( $parent_item.is( ".js-tablist__item:last-child" ) ) {
                           $parent_list.find( ".js-tablist__item:first-child .js-tablist__link" ).click().focus();
                        }
                        // else activate next
                        else {
                             $parent_item.next().children( ".js-tablist__link" ).click().focus();
                             }
                        event.preventDefault();
                    }

            } )
            /* click on a tab link */
            .on( "click", ".js-link-to-tab", function( event ) {
                    var $this = $(this),
                         $tab_to_go = $($this.attr('href')),
                         $button_to_click = $( '#' + $tab_to_go.attr('aria-labelledby') );

                    // activate tabs
                    $button_to_click.click();
                    // give focus to the good button
                    setTimeout(function(){ $button_to_click.focus() }, 10);
            } );

        }

});
<|endoftext|>


<commit_before>/* ***** BEGIN LICENSE BLOCK *****
 * Distributed under the BSD license:
 *
 * Copyright (c) 2010, Ajax.org B.V.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Ajax.org B.V. nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ***** END LICENSE BLOCK ***** */

define(function(require, exports, module) {
"use strict";

var oop = require("./lib/oop");
var Range = require("./range").Range;
var Search = require("./search").Search;
var Document = require("./document").Document;

/**
 * @class Occur
 *
 * Finds all lines matching a search term in the current docuement and
 * displays them instead of the original document.
 *
 **/

/**
 *
 *
 * Creates a new `Occur` object.
 *
 * @constructor
 **/
function Occur() {
    // this.$options = {wrap: false, skipCurrent: false};
    // this.$keyboardHandler = new ISearchKbd(this);
}

oop.inherits(Occur, Search);

(function() {

    this.display = function(session, options) {
        this.$originalDoc = session.doc;
        var found = this.matchingLines(session, options),
            lines = found.map(function(foundLine) { return foundLine.content; }),
            occurDoc = new Document(lines);
        occurDoc.$occur = this;
        session.setDocument(occurDoc);
    }

    this.displayOriginal = function(session) {
        session.setDocument(this.$originalDoc);
    }

    this.matchingLines = function(session, options) {
        options = options || {};
        if (!session || !options.needle) return [];
        var search = new Search();
        search.set(options);
        var ranges = search.findAll(session);
        return ranges.map(function(range) {
            var row = range.start.row;
            return {row: row, content: session.getLine(row)};
        });
    }

}).call(Occur.prototype);

exports.Occur = Occur;

});
<commit_msg>[occur] highlighting occur doc<commit_after>/* ***** BEGIN LICENSE BLOCK *****
 * Distributed under the BSD license:
 *
 * Copyright (c) 2010, Ajax.org B.V.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Ajax.org B.V. nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ***** END LICENSE BLOCK ***** */

define(function(require, exports, module) {
"use strict";

var oop = require("./lib/oop");
var Range = require("./range").Range;
var Search = require("./search").Search;
var Document = require("./document").Document;

/**
 * @class Occur
 *
 * Finds all lines matching a search term in the current docuement and
 * displays them instead of the original document.
 *
 **/

/**
 *
 *
 * Creates a new `Occur` object.
 *
 * @constructor
 **/
function Occur() {
    // this.$options = {wrap: false, skipCurrent: false};
    // this.$keyboardHandler = new ISearchKbd(this);
}

oop.inherits(Occur, Search);

(function() {

    this.display = function(session, options) {
        this.$originalDoc = session.doc;
        var found = this.matchingLines(session, options),
            lines = found.map(function(foundLine) { return foundLine.content; }),
            occurDoc = new Document(lines);
        occurDoc.$occur = this;
        session.setDocument(occurDoc);
        session.highlight(null);
        session.highlight(options.re);
        session._emit('changeBackMarker');
    }

    this.displayOriginal = function(session) {
        session.setDocument(this.$originalDoc);
    }

    this.matchingLines = function(session, options) {
        options = options || {};
        if (!session || !options.needle) return [];
        var search = new Search();
        search.set(options);
        var ranges = search.findAll(session);
        return ranges.map(function(range) {
            var row = range.start.row;
            return {row: row, content: session.getLine(row)};
        });
    }

}).call(Occur.prototype);

exports.Occur = Occur;

});
<|endoftext|>


<commit_before>
var competition = require('./the_competitors.js'),

    valid       = require('testdata-valid-email'),
    invalid     = require('testdata-invalid-email');

var maxscore = 0;

function verify_one(X) {

    var result = { errors: [] },
        score  = 0;

    maxscore   = 0;

    valid.map(   function(V) { if ( X.test(V)) { ++score; } else { result.errors.push(V); } ++maxscore; } );
    invalid.map( function(I) { if (!X.test(I)) { ++score; } else { result.errors.push(I); } ++maxscore; } );

    result.name  = X.name;
    result.score = score;

    return result;

}

function verify(shortForm) {

    var result = competition.map( verify_one );

    if (shortForm || true) {
        for (var i in result) { delete result[i].errors; }
    }

    return result;

}

var res = verify();
res.sort(function(X,Y) { return X.score < Y.score; });

console.log('Of a possible ' + maxscore.toString() + ':');
res.map(function(X) {
  console.log('  ' + X.name + ': ' + X.score);
});<commit_msg>fix sorting; improve display more<commit_after>
var competition = require('./the_competitors.js'),

    valid       = require('testdata-valid-email'),
    invalid     = require('testdata-invalid-email');

var maxscore = 0;

function verify_one(X) {

    var result = { errors: [] },
        score  = 0;

    maxscore   = 0;

    valid.map(   function(V) { if ( X.test(V)) { ++score; } else { result.errors.push(V); } ++maxscore; } );
    invalid.map( function(I) { if (!X.test(I)) { ++score; } else { result.errors.push(I); } ++maxscore; } );

    result.name  = X.name;
    result.score = score;

    return result;

}

function verify(shortForm) {

    var result = competition.map( verify_one );

    if (shortForm || true) {
        for (var i in result) { delete result[i].errors; }
    }

    return result;

}

var res = verify().sort(function(X,Y) { return X.score < Y.score? 1 : (X.score > Y.score? -1 : 0); });

console.log('Of a possible ' + maxscore.toString() + ':');
res.map(function(X) {
  console.log('  ' + X.score + ' ' + X.name);
});<|endoftext|>


<commit_before>var tape = require("tape"),
    jsdom = require("jsdom"),
    d3 = Object.assign(require("../"), require("d3-selection"));

/*************************************
 ************ Components *************
 *************************************/

// Local state.
var spinnerCreated = 0,
    spinnerDestroyed = 0,
    spinnerTimerState = "",
    spinnerText = "",
    spinnerSetState,
    spinner = d3.component("div")
      .create(function (selection, setState){
        spinnerSetState = setState;
        spinnerCreated++;
        spinnerTimerState = "running";
        setState({
          timer: spinnerTimerState
        });
      })
      .render(function (selection, props, state){
        spinnerText = "Timer is " + state.timer;
        selection.text(spinnerText);
      })
      .destroy(function(state){
        spinnerDestroyed++;
      });

// For checking the default value of the state argument.
var stateValue,
    stateValueCheck = d3.component("div")
      .render(function (selection, props, state){
        stateValue = state;
      });

/*************************************
 ************** Tests ****************
 *************************************/
tape("Local state.", function(test) {
  var div = d3.select(jsdom.jsdom().body).append("div");

  // Create.
  div.call(spinner);
  test.equal(spinnerCreated, 1);
  test.equal(spinnerDestroyed, 0);
  test.equal(spinnerTimerState, "running");
  test.equal(spinnerText, "Timer is running");
  test.equal(div.html(), "
Timer is running
");

  // Re-render on setState().
  spinnerSetState({ timer: "running well"});
  test.equal(spinnerText, "Timer is running well");
  test.equal(div.html(), "
Timer is running well
");
  test.equal(spinnerCreated, 1);
  test.equal(spinnerDestroyed, 0);

  // Destroy.
  div.call(spinner, []);
  test.equal(spinnerCreated, 1);
  test.equal(spinnerDestroyed, 1);
  test.equal(spinnerText, "Timer is running well");
  test.equal(div.html(), "");

  test.end();
});

tape("State value default.", function(test) {
  var div = d3.select(jsdom.jsdom().body).append("div");
  div.call(stateValueCheck);
  test.equal(typeof stateValue, "object");
  test.equal(Object.keys(stateValue).length, 0);
  test.end();
});
<commit_msg>Reset counters in test to make it more readable<commit_after>var tape = require("tape"),
    jsdom = require("jsdom"),
    d3 = Object.assign(require("../"), require("d3-selection"));

/*************************************
 ************ Components *************
 *************************************/

// Local state.
var spinnerCreated,
    spinnerDestroyed,
    spinnerTimerState = "",
    spinnerText = "",
    spinnerSetState,
    spinner = d3.component("div")
      .create(function (selection, setState){
        spinnerSetState = setState;
        spinnerCreated++;
        spinnerTimerState = "running";
        setState({
          timer: spinnerTimerState
        });
      })
      .render(function (selection, props, state){
        spinnerText = "Timer is " + state.timer;
        selection.text(spinnerText);
      })
      .destroy(function(state){
        spinnerDestroyed++;
      });

// For checking the default value of the state argument.
var stateValue,
    stateValueCheck = d3.component("div")
      .render(function (selection, props, state){
        stateValue = state;
      });

/*************************************
 ************** Tests ****************
 *************************************/
tape("Local state.", function(test) {
  var div = d3.select(jsdom.jsdom().body).append("div");

  // Create.
  spinnerCreated = spinnerDestroyed = 0;
  div.call(spinner);
  test.equal(spinnerCreated, 1);
  test.equal(spinnerDestroyed, 0);
  test.equal(spinnerTimerState, "running");
  test.equal(spinnerText, "Timer is running");
  test.equal(div.html(), "
Timer is running
");

  // Re-render on setState().
  spinnerCreated = spinnerDestroyed = 0;
  spinnerSetState({ timer: "running well"});
  test.equal(spinnerText, "Timer is running well");
  test.equal(div.html(), "
Timer is running well
");
  test.equal(spinnerCreated, 0);
  test.equal(spinnerDestroyed, 0);

  // Destroy.
  spinnerCreated = spinnerDestroyed = 0;
  div.call(spinner, []);
  test.equal(spinnerCreated, 0);
  test.equal(spinnerDestroyed, 1);
  test.equal(spinnerText, "Timer is running well");
  test.equal(div.html(), "");

  test.end();
});

tape("State value default.", function(test) {
  var div = d3.select(jsdom.jsdom().body).append("div");
  div.call(stateValueCheck);
  test.equal(typeof stateValue, "object");
  test.equal(Object.keys(stateValue).length, 0);
  test.end();
});
<|endoftext|>