<commit_before>var
  should = require('should'),
  EventEmitter = require('events'),
  rewire = require('rewire'),
  Backend = rewire('../../lib/service/Backend'),
  sinon = require('sinon'),
  PendingRequest = require.main.require('lib/store/PendingRequest');

describe('Test: service/Backend', function () {
  var
    sandbox,
    dummyContext = {
      dummy: 'context',
      clientConnectionStore: {
        getByConnectionId: () => {}
      },
      pluginStore: {
        getByProtocol: () => {}
      },
      backendHandler: {
        removeBackend: () => {}
      }
    },
    dummyTimeout = 1234,
    dummyAddress = 'aDummyAddress',
    spyConsoleError,
    spyConsoleLog,
    spyNinvoke;

  before(() => {
    sandbox = sinon.sandbox.create();
  });

  beforeEach(() => {
    spyConsoleError = sandbox.spy();
    spyConsoleLog = sandbox.spy();
    spyNinvoke = sandbox.spy();
    Backend.__set__('console', {log: spyConsoleLog, error: spyConsoleError});
    Backend.__set__('q', {ninvoke: spyNinvoke});
  });

  afterEach(() => {
    sandbox.restore();
  });

  it('method Constructor must initiate properly and plug good listeners to events', () => {
    var
      backend,
      dummySocket = new EventEmitter(),
      onConnectionCloseStub = sandbox.stub(Backend.prototype, 'onConnectionClose'),
      onConnectionErrorStub = sandbox.stub(Backend.prototype, 'onConnectionError'),
      onMessageStub = sandbox.stub(Backend.prototype, 'onMessage'),
      messageRoomsStub = sandbox
        .stub(Backend.prototype, 'initializeMessageRooms')
        .returns({});

    dummySocket.upgradeReq = {
      connection: {
        remoteAddress: dummyAddress
      }
    };

    backend = new Backend(dummySocket, dummyContext, dummyTimeout);

    backend.socket.emit('close');
    backend.socket.emit('error');
    backend.socket.emit('message');

    should(onConnectionCloseStub.calledOnce).be.true();
    should(onConnectionErrorStub.calledOnce).be.true();
    should(messageRoomsStub.calledOnce).be.true();
    should(onMessageStub.calledOnce).be.true();
    should(backend.backendRequestStore).be.instanceOf(PendingRequest);
    should(backend.httpPort).be.eql(null);
    should(backend.httpPortCallback).be.eql(null);
    should(backend.onMessageRooms).be.an.Object();
  });

  describe('method onMessage', () => {
    it('onMessage must throw an error if JSON.parse does not do what is expected', () => {
      var
        backend = initBackend(dummyContext),
        badMessage = 'unexpected',
        error = 'SyntaxError: Unexpected token u';

      backend.onMessage(badMessage);

      should(spyConsoleError.calledWith(`Bad message received from the backend : ${badMessage}; Reason : ${error}`)).be.true();
    });

    it('message room "response" must call the promise resolution if message is ok', () => {
      var
        backend = initBackend(dummyContext),
        goodResponse = {
          room: 'response',
          data: {
            requestId: 'aRequestId',
            response: 'aResponse'
          }
        },
        goodResponseMessage = JSON.stringify(goodResponse),
        requestExistsStub,
        requestGetStub,
        requestRemoveStub,
        resolveSpy;

      requestExistsStub = sandbox
        .stub(backend.backendRequestStore, 'existsByRequestId')
        .returns(true);
      resolveSpy = sandbox.spy();
      requestGetStub = sandbox
        .stub(backend.backendRequestStore, 'getByRequestId')
        .returns({
          promise: {
            resolve: resolveSpy
          }
        });
      requestRemoveStub = sandbox.stub(backend.backendRequestStore, 'removeByRequestId');

      backend.onMessage(goodResponseMessage);

      should(requestExistsStub.calledOnce).be.true();
      should(requestExistsStub.calledWith('aRequestId')).be.true();
      should(resolveSpy.calledOnce).be.true();
      should(requestGetStub.calledOnce).be.true();
      should(requestGetStub.calledWith('aRequestId')).be.true();
      should(requestRemoveStub.calledOnce).be.true();
      should(requestRemoveStub.calledWith('aRequestId')).be.true();
    });

    it('message room "response" should do nothing if request is unknown', () => {
      var
        backend = initBackend(dummyContext),
        unexistingResponse = {
          room: 'response',
          data: {
            requestId: 'aRequestId',
            response: 'aResponse'
          }
        },
        unexistingResponseMessage = JSON.stringify(unexistingResponse),
        requestExistsStub,
        requestGetStub,
        requestRemoveStub;

      requestExistsStub = sandbox
        .stub(backend.backendRequestStore, 'existsByRequestId')
        .returns(false);
      requestGetStub = sandbox.stub(backend.backendRequestStore, 'getByRequestId');
      requestRemoveStub = sandbox.stub(backend.backendRequestStore, 'removeByRequestId');

      backend.onMessage(unexistingResponseMessage);

      should(requestExistsStub.calledOnce).be.true();
      should(requestExistsStub.calledWith('aRequestId')).be.true();
      should(requestGetStub.callCount).be.eql(0);
      should(requestRemoveStub.callCount).be.eql(0);
    });

    it('message room "joinChannel" must call joinChannel if everything is ok', () => {
      var
        backend = initBackend(dummyContext),
        join = {
          room: 'joinChannel',
          data: {
            id: 'anId',
            some: 'data'
          }
        },
        joinMessage = JSON.stringify(join),
        connectionGetStub,
        pluginGetStub,
        joinChannelSpy;

      connectionGetStub = sandbox
        .stub(backend.context.clientConnectionStore, 'getByConnectionId')
        .returns({
          type: 'aType'
        });

      joinChannelSpy = sandbox.spy();

      pluginGetStub = sandbox
        .stub(backend.context.pluginStore, 'getByProtocol')
        .returns({
          joinChannel: joinChannelSpy
        });

      backend.onMessage(joinMessage);

      should(connectionGetStub.calledOnce).be.true();
      should(connectionGetStub.calledWith('anId')).be.true();
      should(pluginGetStub.calledOnce).be.true();
      should(pluginGetStub.calledWith('aType')).be.true();
      should(joinChannelSpy.calledOnce).be.true();
      should(joinChannelSpy.calledWith(join.data)).be.true();
    });

    it('message room "joinChannel" must do nothing if client type can not be determined', () => {
      var
        backend = initBackend(dummyContext),
        join = {
          room: 'joinChannel',
          data: {
            id: 'anId',
            some: 'data'
          }
        },
        joinMessage = JSON.stringify(join),
        connectionGetStub,
        pluginGetStub;

      connectionGetStub = sandbox
        .stub(backend.context.clientConnectionStore, 'getByConnectionId')
        .returns({});
      pluginGetStub = sandbox.stub(backend.context.pluginStore, 'getByProtocol');

      backend.onMessage(joinMessage);

      should(connectionGetStub.calledOnce).be.true();
      should(connectionGetStub.calledWith('anId')).be.true();
      should(pluginGetStub.callCount).be.eql(0);
    });

    it('message room "leaveChannel" must call leaveChannel if everything is ok', () => {
      var
        backend = initBackend(dummyContext),
        leave = {
          room: 'leaveChannel',
          data: {
            id: 'anId',
            some: 'data'
          }
        },
        leaveMessage = JSON.stringify(leave),
        connectionGetStub,
        pluginGetStub,
        leaveChannelSpy;

      connectionGetStub = sandbox
        .stub(backend.context.clientConnectionStore, 'getByConnectionId')
        .returns({
          type: 'aType'
        });

      leaveChannelSpy = sandbox.spy();

      pluginGetStub = sandbox
        .stub(backend.context.pluginStore, 'getByProtocol')
        .returns({
          leaveChannel: leaveChannelSpy
        });

      backend.onMessage(leaveMessage);

      should(connectionGetStub.calledOnce).be.true();
      should(connectionGetStub.calledWith('anId')).be.true();
      should(pluginGetStub.calledOnce).be.true();
      should(pluginGetStub.calledWith('aType')).be.true();
      should(leaveChannelSpy.calledOnce).be.true();
      should(leaveChannelSpy.calledWith(leave.data)).be.true();
    });

    it('message room "leaveChannel" must do nothing if client type can not be determined', () => {
      var
        backend = initBackend(dummyContext),
        leave = {
          room: 'leaveChannel',
          data: {
            id: 'anId',
            some: 'data'
          }
        },
        leaveMessage = JSON.stringify(leave),
        connectionGetStub,
        pluginGetStub;

      connectionGetStub = sandbox
        .stub(backend.context.clientConnectionStore, 'getByConnectionId')
        .returns({});
      pluginGetStub = sandbox.stub(backend.context.pluginStore, 'getByProtocol');

      backend.onMessage(leaveMessage);

      should(connectionGetStub.calledOnce).be.true();
      should(connectionGetStub.calledWith('anId')).be.true();
      should(pluginGetStub.callCount).be.eql(0);
    });

    it('message room "notify" must call notify if everything is ok', () => {
      var
        backend = initBackend(dummyContext),
        notify = {
          room: 'notify',
          data: {
            id: 'anId',
            some: 'data'
          }
        },
        notifyMessage = JSON.stringify(notify),
        connectionGetStub,
        pluginGetStub,
        notifySpy;

      connectionGetStub = sandbox
        .stub(backend.context.clientConnectionStore, 'getByConnectionId')
        .returns({
          type: 'aType'
        });

      notifySpy = sandbox.spy();

      pluginGetStub = sandbox
        .stub(backend.context.pluginStore, 'getByProtocol')
        .returns({
          notify: notifySpy
        });

      backend.onMessage(notifyMessage);

      should(connectionGetStub.calledOnce).be.true();
      should(connectionGetStub.calledWith('anId')).be.true();
      should(pluginGetStub.calledOnce).be.true();
      should(pluginGetStub.calledWith('aType')).be.true();
      should(notifySpy.calledOnce).be.true();
      should(notifySpy.calledWith(notify.data)).be.true();
    });

    it('message room "notify" must do nothing if client type can not be determined', () => {
      var
        backend = initBackend(dummyContext),
        notify = {
          room: 'notify',
          data: {
            id: 'anId',
            some: 'data'
          }
        },
        notifyMessage = JSON.stringify(notify),
        connectionGetStub,
        pluginGetStub;

      connectionGetStub = sandbox
        .stub(backend.context.clientConnectionStore, 'getByConnectionId')
        .returns({});
      pluginGetStub = sandbox.stub(backend.context.pluginStore, 'getByProtocol');

      backend.onMessage(notifyMessage);

      should(connectionGetStub.calledOnce).be.true();
      should(connectionGetStub.calledWith('anId')).be.true();
      should(pluginGetStub.callCount).be.eql(0);
    });

    it('message room broadcast must broadcast message to all plugins', () => {
      var
        spyPluginBroadcast = sandbox.spy(),
        pluginContext = {
          pluginStore: {
            plugins: {
              aPlugin: {
                broadcast: spyPluginBroadcast
              }
            }
          }
        },
        backend = initBackend(pluginContext),
        broadcast = {
          room: 'broadcast',
          data: {
            some: 'data'
          }
        },
        broadcastMessage = JSON.stringify(broadcast);

      backend.onMessage(broadcastMessage);

      should(spyPluginBroadcast.calledOnce).be.true();
      should(spyPluginBroadcast.calledWith(broadcast.data)).be.true();
    });

    it('message room httpPortInitialization must set the httpPort', () => {
      var
        backend = initBackend(dummyContext),
        httpPort = {
          room: 'httpPortInitialization',
          data: {
            httpPort: 1234
          }
        },
        httpPortMessage = JSON.stringify(httpPort);

      backend.onMessage(httpPortMessage);

      should(spyConsoleLog.calledOnce).be.true();
      should(spyConsoleLog.calledWith(`Backend HTTP port of ${dummyAddress} received : 1234`)).be.true();
      should(backend.httpPort).be.eql(1234);
    });

    it('message room httpPortInitialization must set the httpPort and call callback if set and unset it', () => {
      var
        backend = initBackend(dummyContext),
        httpPort = {
          room: 'httpPortInitialization',
          data: {
            httpPort: 1234
          }
        },
        httpPortMessage = JSON.stringify(httpPort),
        httpPortCallback = sandbox.spy();

      backend.httpPortCallback = httpPortCallback;

      backend.onMessage(httpPortMessage);

      should(spyConsoleLog.calledOnce).be.true();
      should(spyConsoleLog.calledWith(`Backend HTTP port of ${dummyAddress} received : 1234`)).be.true();
      should(backend.httpPort).be.eql(1234);
      should(backend.httpPortCallback).be.eql(null);
      should(httpPortCallback.calledOnce).be.true();
    });

    it('unexpected message room should write a message in console error', () => {
      var
        backend = initBackend(dummyContext),
        unexpected = {
          room: 'unexpected'
        },
        unexpectedMessage = JSON.stringify(unexpected);

      backend.onMessage(unexpectedMessage);

      should(spyConsoleError.calledWith('Unknown message type unexpected')).be.true();
    });
  });

  it('method onConnectionClose', () => {
    var
      backend = initBackend(dummyContext),
      getAllStub,
      removeBackendStub,
      removeRequestStub,
      spyPromiseReject = sandbox.spy();

    getAllStub = sandbox
      .stub(backend.backendRequestStore, 'getAll')
      .returns({
        aRequestId: {
          promise: {
            reject: spyPromiseReject
          }
        },
        anotherRequestId: {
          promise: {
            reject: spyPromiseReject
          }
        }
      });

    removeBackendStub = sandbox.stub(backend.context.backendHandler, 'removeBackend');
    removeRequestStub = sandbox.stub(backend.backendRequestStore, 'removeByRequestId');

    backend.onConnectionClose();

    should(spyConsoleLog.calledOnce).be.true();
    should(spyConsoleLog.calledWith(`Connection with backend ${dummyAddress} closed.`)).be.true();
    should(getAllStub.calledOnce).be.true();
    should(removeBackendStub.calledOnce).be.true();
    should(removeBackendStub.calledWith(backend)).be.true();
    should(spyPromiseReject.calledTwice).be.true();
    should(removeRequestStub.calledTwice).be.true();
    should(removeRequestStub.calledWith('aRequestId')).be.true();
    should(removeRequestStub.calledWith('anotherRequestId')).be.true();
  });

  it('method onConnectionError', () => {
    var
      backend = initBackend(dummyContext),
      getAllStub,
      removeBackendStub,
      removeRequestStub,
      spyPromiseReject = sandbox.spy(),
      error = new Error('an Error');

    getAllStub = sandbox
      .stub(backend.backendRequestStore, 'getAll')
      .returns({
        aRequestId: {
          promise: {
            reject: spyPromiseReject
          }
        },
        anotherRequestId: {
          promise: {
            reject: spyPromiseReject
          }
        }
      });

    removeBackendStub = sandbox.stub(backend.context.backendHandler, 'removeBackend');
    removeRequestStub = sandbox.stub(backend.backendRequestStore, 'removeByRequestId');

    backend.onConnectionError(error);

    should(spyConsoleError.calledOnce).be.true();
    should(spyConsoleError.calledWith(`Connection with backend ${dummyAddress} was in error; Reason :`, error)).be.true();
    should(getAllStub.calledOnce).be.true();
    should(removeBackendStub.calledOnce).be.true();
    should(removeBackendStub.calledWith(backend)).be.true();
    should(spyPromiseReject.calledTwice).be.true();
    should(removeRequestStub.calledTwice).be.true();
    should(removeRequestStub.calledWith('aRequestId')).be.true();
    should(removeRequestStub.calledWith('anotherRequestId')).be.true();
  });

  it('method send', () => {
    var
      backend = initBackend(dummyContext),
      addStub,
      pendingItem = {
        message: 'a message'
      };

    addStub = sandbox.stub(backend.backendRequestStore, 'add');
    backend.socket.send = sandbox.spy();

    backend.send(pendingItem);

    should(addStub.calledOnce).be.true();
    should(addStub.calledWith(pendingItem)).be.true();
    should(backend.socket.send.calledOnce).be.true();
    should(backend.socket.send.calledWith(JSON.stringify(pendingItem.message))).be.true();
  });

  it('method sendRaw', () => {
    var backend = initBackend(dummyContext);

    backend.sendRaw('a message');

    should(spyNinvoke.calledOnce).be.true();
    should(spyNinvoke.calledWith(backend.socket, 'send', 'a message')).be.true();
  });

  function initBackend (context) {
    var dummySocket = new EventEmitter();

    dummySocket.upgradeReq = {
      connection: {
        remoteAddress: dummyAddress
      }
    };

    return new Backend(dummySocket, context, dummyTimeout);
  }
});<commit_msg>add test on undefined message.room<commit_after>var
  should = require('should'),
  EventEmitter = require('events'),
  rewire = require('rewire'),
  Backend = rewire('../../lib/service/Backend'),
  sinon = require('sinon'),
  PendingRequest = require.main.require('lib/store/PendingRequest');

describe('Test: service/Backend', function () {
  var
    sandbox,
    dummyContext = {
      dummy: 'context',
      clientConnectionStore: {
        getByConnectionId: () => {}
      },
      pluginStore: {
        getByProtocol: () => {}
      },
      backendHandler: {
        removeBackend: () => {}
      }
    },
    dummyTimeout = 1234,
    dummyAddress = 'aDummyAddress',
    spyConsoleError,
    spyConsoleLog,
    spyNinvoke;

  before(() => {
    sandbox = sinon.sandbox.create();
  });

  beforeEach(() => {
    spyConsoleError = sandbox.spy();
    spyConsoleLog = sandbox.spy();
    spyNinvoke = sandbox.spy();
    Backend.__set__('console', {log: spyConsoleLog, error: spyConsoleError});
    Backend.__set__('q', {ninvoke: spyNinvoke});
  });

  afterEach(() => {
    sandbox.restore();
  });

  it('method Constructor must initiate properly and plug good listeners to events', () => {
    var
      backend,
      dummySocket = new EventEmitter(),
      onConnectionCloseStub = sandbox.stub(Backend.prototype, 'onConnectionClose'),
      onConnectionErrorStub = sandbox.stub(Backend.prototype, 'onConnectionError'),
      onMessageStub = sandbox.stub(Backend.prototype, 'onMessage'),
      messageRoomsStub = sandbox
        .stub(Backend.prototype, 'initializeMessageRooms')
        .returns({});

    dummySocket.upgradeReq = {
      connection: {
        remoteAddress: dummyAddress
      }
    };

    backend = new Backend(dummySocket, dummyContext, dummyTimeout);

    backend.socket.emit('close');
    backend.socket.emit('error');
    backend.socket.emit('message');

    should(onConnectionCloseStub.calledOnce).be.true();
    should(onConnectionErrorStub.calledOnce).be.true();
    should(messageRoomsStub.calledOnce).be.true();
    should(onMessageStub.calledOnce).be.true();
    should(backend.backendRequestStore).be.instanceOf(PendingRequest);
    should(backend.httpPort).be.eql(null);
    should(backend.httpPortCallback).be.eql(null);
    should(backend.onMessageRooms).be.an.Object();
  });

  describe('method onMessage', () => {
    it('onMessage must write a console error if the message contains no room', () => {
      var
        backend = initBackend(dummyContext),
        badMessage = {
          no: 'room'
        },
        badMessageString = JSON.stringify(badMessage),
        error = 'SyntaxError: Unexpected token u';

      backend.onMessage(badMessageString);

      should(spyConsoleError.calledWith(`Room is not specified in message: ${badMessageString}`)).be.true();
    });

    it('onMessage must write a console error if JSON.parse does not do what is expected', () => {
      var
        backend = initBackend(dummyContext),
        badMessage = 'unexpected',
        error = 'SyntaxError: Unexpected token u';

      backend.onMessage(badMessage);

      should(spyConsoleError.calledWith(`Bad message received from the backend : ${badMessage}; Reason : ${error}`)).be.true();
    });

    it('message room "response" must call the promise resolution if message is ok', () => {
      var
        backend = initBackend(dummyContext),
        goodResponse = {
          room: 'response',
          data: {
            requestId: 'aRequestId',
            response: 'aResponse'
          }
        },
        goodResponseMessage = JSON.stringify(goodResponse),
        requestExistsStub,
        requestGetStub,
        requestRemoveStub,
        resolveSpy;

      requestExistsStub = sandbox
        .stub(backend.backendRequestStore, 'existsByRequestId')
        .returns(true);
      resolveSpy = sandbox.spy();
      requestGetStub = sandbox
        .stub(backend.backendRequestStore, 'getByRequestId')
        .returns({
          promise: {
            resolve: resolveSpy
          }
        });
      requestRemoveStub = sandbox.stub(backend.backendRequestStore, 'removeByRequestId');

      backend.onMessage(goodResponseMessage);

      should(requestExistsStub.calledOnce).be.true();
      should(requestExistsStub.calledWith('aRequestId')).be.true();
      should(resolveSpy.calledOnce).be.true();
      should(requestGetStub.calledOnce).be.true();
      should(requestGetStub.calledWith('aRequestId')).be.true();
      should(requestRemoveStub.calledOnce).be.true();
      should(requestRemoveStub.calledWith('aRequestId')).be.true();
    });

    it('message room "response" should do nothing if request is unknown', () => {
      var
        backend = initBackend(dummyContext),
        unexistingResponse = {
          room: 'response',
          data: {
            requestId: 'aRequestId',
            response: 'aResponse'
          }
        },
        unexistingResponseMessage = JSON.stringify(unexistingResponse),
        requestExistsStub,
        requestGetStub,
        requestRemoveStub;

      requestExistsStub = sandbox
        .stub(backend.backendRequestStore, 'existsByRequestId')
        .returns(false);
      requestGetStub = sandbox.stub(backend.backendRequestStore, 'getByRequestId');
      requestRemoveStub = sandbox.stub(backend.backendRequestStore, 'removeByRequestId');

      backend.onMessage(unexistingResponseMessage);

      should(requestExistsStub.calledOnce).be.true();
      should(requestExistsStub.calledWith('aRequestId')).be.true();
      should(requestGetStub.callCount).be.eql(0);
      should(requestRemoveStub.callCount).be.eql(0);
    });

    it('message room "joinChannel" must call joinChannel if everything is ok', () => {
      var
        backend = initBackend(dummyContext),
        join = {
          room: 'joinChannel',
          data: {
            id: 'anId',
            some: 'data'
          }
        },
        joinMessage = JSON.stringify(join),
        connectionGetStub,
        pluginGetStub,
        joinChannelSpy;

      connectionGetStub = sandbox
        .stub(backend.context.clientConnectionStore, 'getByConnectionId')
        .returns({
          type: 'aType'
        });

      joinChannelSpy = sandbox.spy();

      pluginGetStub = sandbox
        .stub(backend.context.pluginStore, 'getByProtocol')
        .returns({
          joinChannel: joinChannelSpy
        });

      backend.onMessage(joinMessage);

      should(connectionGetStub.calledOnce).be.true();
      should(connectionGetStub.calledWith('anId')).be.true();
      should(pluginGetStub.calledOnce).be.true();
      should(pluginGetStub.calledWith('aType')).be.true();
      should(joinChannelSpy.calledOnce).be.true();
      should(joinChannelSpy.calledWith(join.data)).be.true();
    });

    it('message room "joinChannel" must do nothing if client type can not be determined', () => {
      var
        backend = initBackend(dummyContext),
        join = {
          room: 'joinChannel',
          data: {
            id: 'anId',
            some: 'data'
          }
        },
        joinMessage = JSON.stringify(join),
        connectionGetStub,
        pluginGetStub;

      connectionGetStub = sandbox
        .stub(backend.context.clientConnectionStore, 'getByConnectionId')
        .returns({});
      pluginGetStub = sandbox.stub(backend.context.pluginStore, 'getByProtocol');

      backend.onMessage(joinMessage);

      should(connectionGetStub.calledOnce).be.true();
      should(connectionGetStub.calledWith('anId')).be.true();
      should(pluginGetStub.callCount).be.eql(0);
    });

    it('message room "leaveChannel" must call leaveChannel if everything is ok', () => {
      var
        backend = initBackend(dummyContext),
        leave = {
          room: 'leaveChannel',
          data: {
            id: 'anId',
            some: 'data'
          }
        },
        leaveMessage = JSON.stringify(leave),
        connectionGetStub,
        pluginGetStub,
        leaveChannelSpy;

      connectionGetStub = sandbox
        .stub(backend.context.clientConnectionStore, 'getByConnectionId')
        .returns({
          type: 'aType'
        });

      leaveChannelSpy = sandbox.spy();

      pluginGetStub = sandbox
        .stub(backend.context.pluginStore, 'getByProtocol')
        .returns({
          leaveChannel: leaveChannelSpy
        });

      backend.onMessage(leaveMessage);

      should(connectionGetStub.calledOnce).be.true();
      should(connectionGetStub.calledWith('anId')).be.true();
      should(pluginGetStub.calledOnce).be.true();
      should(pluginGetStub.calledWith('aType')).be.true();
      should(leaveChannelSpy.calledOnce).be.true();
      should(leaveChannelSpy.calledWith(leave.data)).be.true();
    });

    it('message room "leaveChannel" must do nothing if client type can not be determined', () => {
      var
        backend = initBackend(dummyContext),
        leave = {
          room: 'leaveChannel',
          data: {
            id: 'anId',
            some: 'data'
          }
        },
        leaveMessage = JSON.stringify(leave),
        connectionGetStub,
        pluginGetStub;

      connectionGetStub = sandbox
        .stub(backend.context.clientConnectionStore, 'getByConnectionId')
        .returns({});
      pluginGetStub = sandbox.stub(backend.context.pluginStore, 'getByProtocol');

      backend.onMessage(leaveMessage);

      should(connectionGetStub.calledOnce).be.true();
      should(connectionGetStub.calledWith('anId')).be.true();
      should(pluginGetStub.callCount).be.eql(0);
    });

    it('message room "notify" must call notify if everything is ok', () => {
      var
        backend = initBackend(dummyContext),
        notify = {
          room: 'notify',
          data: {
            id: 'anId',
            some: 'data'
          }
        },
        notifyMessage = JSON.stringify(notify),
        connectionGetStub,
        pluginGetStub,
        notifySpy;

      connectionGetStub = sandbox
        .stub(backend.context.clientConnectionStore, 'getByConnectionId')
        .returns({
          type: 'aType'
        });

      notifySpy = sandbox.spy();

      pluginGetStub = sandbox
        .stub(backend.context.pluginStore, 'getByProtocol')
        .returns({
          notify: notifySpy
        });

      backend.onMessage(notifyMessage);

      should(connectionGetStub.calledOnce).be.true();
      should(connectionGetStub.calledWith('anId')).be.true();
      should(pluginGetStub.calledOnce).be.true();
      should(pluginGetStub.calledWith('aType')).be.true();
      should(notifySpy.calledOnce).be.true();
      should(notifySpy.calledWith(notify.data)).be.true();
    });

    it('message room "notify" must do nothing if client type can not be determined', () => {
      var
        backend = initBackend(dummyContext),
        notify = {
          room: 'notify',
          data: {
            id: 'anId',
            some: 'data'
          }
        },
        notifyMessage = JSON.stringify(notify),
        connectionGetStub,
        pluginGetStub;

      connectionGetStub = sandbox
        .stub(backend.context.clientConnectionStore, 'getByConnectionId')
        .returns({});
      pluginGetStub = sandbox.stub(backend.context.pluginStore, 'getByProtocol');

      backend.onMessage(notifyMessage);

      should(connectionGetStub.calledOnce).be.true();
      should(connectionGetStub.calledWith('anId')).be.true();
      should(pluginGetStub.callCount).be.eql(0);
    });

    it('message room broadcast must broadcast message to all plugins', () => {
      var
        spyPluginBroadcast = sandbox.spy(),
        pluginContext = {
          pluginStore: {
            plugins: {
              aPlugin: {
                broadcast: spyPluginBroadcast
              }
            }
          }
        },
        backend = initBackend(pluginContext),
        broadcast = {
          room: 'broadcast',
          data: {
            some: 'data'
          }
        },
        broadcastMessage = JSON.stringify(broadcast);

      backend.onMessage(broadcastMessage);

      should(spyPluginBroadcast.calledOnce).be.true();
      should(spyPluginBroadcast.calledWith(broadcast.data)).be.true();
    });

    it('message room httpPortInitialization must set the httpPort', () => {
      var
        backend = initBackend(dummyContext),
        httpPort = {
          room: 'httpPortInitialization',
          data: {
            httpPort: 1234
          }
        },
        httpPortMessage = JSON.stringify(httpPort);

      backend.onMessage(httpPortMessage);

      should(spyConsoleLog.calledOnce).be.true();
      should(spyConsoleLog.calledWith(`Backend HTTP port of ${dummyAddress} received : 1234`)).be.true();
      should(backend.httpPort).be.eql(1234);
    });

    it('message room httpPortInitialization must set the httpPort and call callback if set and unset it', () => {
      var
        backend = initBackend(dummyContext),
        httpPort = {
          room: 'httpPortInitialization',
          data: {
            httpPort: 1234
          }
        },
        httpPortMessage = JSON.stringify(httpPort),
        httpPortCallback = sandbox.spy();

      backend.httpPortCallback = httpPortCallback;

      backend.onMessage(httpPortMessage);

      should(spyConsoleLog.calledOnce).be.true();
      should(spyConsoleLog.calledWith(`Backend HTTP port of ${dummyAddress} received : 1234`)).be.true();
      should(backend.httpPort).be.eql(1234);
      should(backend.httpPortCallback).be.eql(null);
      should(httpPortCallback.calledOnce).be.true();
    });

    it('unexpected message room should write a message in console error', () => {
      var
        backend = initBackend(dummyContext),
        unexpected = {
          room: 'unexpected'
        },
        unexpectedMessage = JSON.stringify(unexpected);

      backend.onMessage(unexpectedMessage);

      should(spyConsoleError.calledWith('Unknown message type unexpected')).be.true();
    });
  });

  it('method onConnectionClose', () => {
    var
      backend = initBackend(dummyContext),
      getAllStub,
      removeBackendStub,
      removeRequestStub,
      spyPromiseReject = sandbox.spy();

    getAllStub = sandbox
      .stub(backend.backendRequestStore, 'getAll')
      .returns({
        aRequestId: {
          promise: {
            reject: spyPromiseReject
          }
        },
        anotherRequestId: {
          promise: {
            reject: spyPromiseReject
          }
        }
      });

    removeBackendStub = sandbox.stub(backend.context.backendHandler, 'removeBackend');
    removeRequestStub = sandbox.stub(backend.backendRequestStore, 'removeByRequestId');

    backend.onConnectionClose();

    should(spyConsoleLog.calledOnce).be.true();
    should(spyConsoleLog.calledWith(`Connection with backend ${dummyAddress} closed.`)).be.true();
    should(getAllStub.calledOnce).be.true();
    should(removeBackendStub.calledOnce).be.true();
    should(removeBackendStub.calledWith(backend)).be.true();
    should(spyPromiseReject.calledTwice).be.true();
    should(removeRequestStub.calledTwice).be.true();
    should(removeRequestStub.calledWith('aRequestId')).be.true();
    should(removeRequestStub.calledWith('anotherRequestId')).be.true();
  });

  it('method onConnectionError', () => {
    var
      backend = initBackend(dummyContext),
      getAllStub,
      removeBackendStub,
      removeRequestStub,
      spyPromiseReject = sandbox.spy(),
      error = new Error('an Error');

    getAllStub = sandbox
      .stub(backend.backendRequestStore, 'getAll')
      .returns({
        aRequestId: {
          promise: {
            reject: spyPromiseReject
          }
        },
        anotherRequestId: {
          promise: {
            reject: spyPromiseReject
          }
        }
      });

    removeBackendStub = sandbox.stub(backend.context.backendHandler, 'removeBackend');
    removeRequestStub = sandbox.stub(backend.backendRequestStore, 'removeByRequestId');

    backend.onConnectionError(error);

    should(spyConsoleError.calledOnce).be.true();
    should(spyConsoleError.calledWith(`Connection with backend ${dummyAddress} was in error; Reason :`, error)).be.true();
    should(getAllStub.calledOnce).be.true();
    should(removeBackendStub.calledOnce).be.true();
    should(removeBackendStub.calledWith(backend)).be.true();
    should(spyPromiseReject.calledTwice).be.true();
    should(removeRequestStub.calledTwice).be.true();
    should(removeRequestStub.calledWith('aRequestId')).be.true();
    should(removeRequestStub.calledWith('anotherRequestId')).be.true();
  });

  it('method send', () => {
    var
      backend = initBackend(dummyContext),
      addStub,
      pendingItem = {
        message: 'a message'
      };

    addStub = sandbox.stub(backend.backendRequestStore, 'add');
    backend.socket.send = sandbox.spy();

    backend.send(pendingItem);

    should(addStub.calledOnce).be.true();
    should(addStub.calledWith(pendingItem)).be.true();
    should(backend.socket.send.calledOnce).be.true();
    should(backend.socket.send.calledWith(JSON.stringify(pendingItem.message))).be.true();
  });

  it('method sendRaw', () => {
    var backend = initBackend(dummyContext);

    backend.sendRaw('a message');

    should(spyNinvoke.calledOnce).be.true();
    should(spyNinvoke.calledWith(backend.socket, 'send', 'a message')).be.true();
  });

  function initBackend (context) {
    var dummySocket = new EventEmitter();

    dummySocket.upgradeReq = {
      connection: {
        remoteAddress: dummyAddress
      }
    };

    return new Backend(dummySocket, context, dummyTimeout);
  }
});<|endoftext|>


<commit_before>/* File: profils.js
 *
 * Copyright (c) 2014
 * Centre National d’Enseignement à Distance (Cned), Boulevard Nicephore Niepce, 86360 CHASSENEUIL-DU-POITOU, France
 * (direction-innovation@cned.fr)
 *
 * GNU Affero General Public License (AGPL) version 3.0 or later version
 *
 * This file is part of a program which is free software: you can
 * redistribute it and/or modify it under the terms of the
 * GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with this program.
 * If not, see <http://www.gnu.org/licenses/>.
 *
 */

'use strict';
/*exported utils */

var utils = require('./utils'),
	request = require('supertest'),
	express = require('express'),
	helpersService = require('../../../api/helpers/helpers'),
	app = express();

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

	it('Service:helpers', function(done) {
		this.timeout(10000);
		setTimeout(done, 10000);

		app.post('/sendMail', function(req, res) {
			req.body = {

				to: 'destinataire@test.com',
				content: 'test content',
				encoded: 'test encoded'

			};
			helpersService.sendMail(req, res);
		});
		request(app).post('/sendMail').expect(200, done);
	});
});<commit_msg>fixer le titre de l'entête CNED<commit_after>/* File: helpers.js
 *
 * Copyright (c) 2014
 * Centre National d’Enseignement à Distance (Cned), Boulevard Nicephore Niepce, 86360 CHASSENEUIL-DU-POITOU, France
 * (direction-innovation@cned.fr)
 *
 * GNU Affero General Public License (AGPL) version 3.0 or later version
 *
 * This file is part of a program which is free software: you can
 * redistribute it and/or modify it under the terms of the
 * GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with this program.
 * If not, see <http://www.gnu.org/licenses/>.
 *
 */

'use strict';
/*exported utils */

var utils = require('./utils'),
	request = require('supertest'),
	express = require('express'),
	helpersService = require('../../../api/helpers/helpers'),
	app = express();

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

	it('Service:helpers', function(done) {
		this.timeout(10000);
		setTimeout(done, 10000);

		app.post('/sendMail', function(req, res) {
			req.body = {

				to: 'destinataire@test.com',
				content: 'test content',
				encoded: 'test encoded'

			};
			helpersService.sendMail(req, res);
		});
		request(app).post('/sendMail').expect(200, done);
	});
});<|endoftext|>


<commit_before>'use strict';
describe('tink-pagination-angular', function() {

  beforeEach(module('tink.pagination'));

  var bodyEl = $('body'), sandboxEl;
  var $compile, $templateCache, scope;

  // beforeEach(module('tink'));

  beforeEach(inject(function (_$rootScope_, _$compile_, _$templateCache_) {
    scope = _$rootScope_.$new();
    $compile = _$compile_;
    $templateCache = _$templateCache_;
    bodyEl.html('');
    sandboxEl = $('<div>').attr('id', 'sandbox').appendTo(bodyEl);

    var template = $templateCache.get('src/templates/pagination.html');
    $templateCache.put('templates/pagination.html',template);
  }));

  afterEach(function() {
    scope.$destroy();
    sandboxEl.remove();
  });

  function compileDirective(template, locals) {
    template = templates[template];
    angular.extend(scope, angular.copy(template.scope || templates['default'].scope), locals);
    var element = $(template.element).appendTo(sandboxEl);
    element = $compile(element)(scope);
    scope.$digest();
    return jQuery(element[0]);
  }

  var templates = {
    'default': {
      scope: {nums:1,numpp:5,totalitems:100},
      element: '<tink-pagination  tink-current-page="nums" tink-change="changed(page,perPage,next)" tink-total-items="totalitems" tink-items-per-page="numpp"></tink-pagination>'
    }
  };

  describe('default', function() {
    it('should run this basic setup',function(){
      var element = compileDirective('default');
      console.log(element);
    });
  });

});<commit_msg>added test for perPage<commit_after>'use strict';
describe('tink-pagination-angular', function() {

  beforeEach(module('ngAnimate'));
  beforeEach(module('ngAnimateMock'));
  beforeEach(module('ngSanitize'));
  beforeEach(module('tink.pagination'));
  beforeEach(module('templates'));

  var bodyEl = $('body'), sandboxEl;
  var $compile, $templateCache, scope;

  // beforeEach(module('tink'));

  beforeEach(inject(function (_$rootScope_, _$compile_, _$templateCache_) {
    scope = _$rootScope_.$new();
    $compile = _$compile_;
    $templateCache = _$templateCache_;

    var template = $templateCache.get('src/templates/pagination.html');
    $templateCache.put('templates/pagination.html',template);

    bodyEl.html('');
    sandboxEl = $('<div>').attr('id', 'sandbox').appendTo(bodyEl);
  }));

  afterEach(function() {
    scope.$destroy();
    sandboxEl.remove();
  });

  function compileDirective(template, locals) {
    template = templates[template];
    angular.extend(scope, angular.copy(template.scope || templates['default'].scope), locals);
    var element = $(template.element).appendTo(sandboxEl);
    element = $compile(element)(scope);
    scope.$digest();
    return jQuery(element[0]);
  }

  var templates = {
    'default': {
      scope: {nums:1,numpp:5,totalitems:100,tinkItemsPerPageValues:undefined},
      element: '<tink-pagination tink-items-per-page-values="tinkItemsPerPageValues" tink-current-page="nums" tink-change="changed(page,perPage,next)" tink-total-items="totalitems" tink-items-per-page="numpp"></tink-pagination>'
    }
  };

  describe('Current page', function() {

    it('default',function(){

    });

  });

  describe('perPage', function() {
    it('default',function(){
      var element = compileDirective('default');
      var options = element.find('div.select option');
      var array = []
      for(var i=0;i<options.length;i++){
        array.push(parseInt($(options.get(i)).html()))
      }
      expect(array).toEqual([5,10,20,30]);
    });

    it('change the values',function(){
      var element = compileDirective('default',{nums:1,numpp:5,totalitems:100,tinkItemsPerPageValues:[5,15,30,50]});
      var options = element.find('div.select option');
      var array = []
      for(var i=0;i<options.length;i++){
        array.push(parseInt($(options.get(i)).html()))
      }
      expect(array).toEqual([5,15,30,50]);
    });
  });

});<|endoftext|>


<commit_before>xdescribe('just check storage service basic API', function() {
  var storage;

  beforeEach(function () {
    module('storage');
  });

  beforeEach(function () {
    inject(function (_storage_) {
      storage = _storage_;
    });
  });

  it('Storage set/get should cooperate well', function () {
    storage.set('story', 'love is color blind');
    expect(storage.get('story')).toEqual('love is color blind');
  });

  it('Storage remove method should work right', function () {
    storage.set('story', 'love is color blind');
    storage.remove("love");
    expect(storage.get("love")).toBeNull();
  });

  it('Storage clear method should work right', function () {
    storage.set('story', 'love is color blind');
    storage.set('content', 'forever girl');
    storage.clear();
    expect(storage.get('love')).toBeNull();
    expect(storage.get('content')).toBeNull();
  });

  it('Storage getSize method should work right', function () {
    storage.set('story', 'love is color blind');
    storage.set('content', 'forever girl');
    expect(storage.getSize()).toEqual(2);
    storage.clear();
  });

  it('Storage getByIndex method should work right', function () {
    storage.set('story', 'love is color blind');
    storage.set('content', 'forever girl');
    expect(storage.getByIndex(0)).toEqual('forever girl');
    expect(storage.getByIndex(1)).toEqual('love is color blind');
    storage.clear();
  });
});
<commit_msg>modify operate seperate module<commit_after>xdescribe('just check storage service basic API', function() {
  var storageOperate;

  beforeEach(function () {
    module('storage.operate');
  });

  beforeEach(function () {
    inject(function (_storageOperate_) {
      storageOperate = _storageOperate_;
    });
  });

  it('Storage set/get should cooperate well', function () {
    storageOperate.set('story', 'love is color blind');
    expect(storageOperate.get('story')).toEqual('love is color blind');
  });

  it('Storage remove method should work right', function () {
    storageOperate.set('story', 'love is color blind');
    storageOperate.remove("love");
    expect(storageOperate.get("love")).toBeNull();
  });

  it('Storage clear method should work right', function () {
    storageOperate.set('story', 'love is color blind');
    storageOperate.set('content', 'forever girl');
    storageOperate.clear();
    expect(storageOperate.get('love')).toBeNull();
    expect(storageOperate.get('content')).toBeNull();
  });

  it('Storage getSize method should work right', function () {
    storageOperate.set('story', 'love is color blind');
    storageOperate.set('content', 'forever girl');
    expect(storageOperate.getSize()).toEqual(2);
    storageOperate.clear();
  });

  it('Storage getByIndex method should work right', function () {
    storageOperate.set('story', 'love is color blind');
    storageOperate.set('content', 'forever girl');
    expect(storageOperate.getByIndex(0)).toEqual('forever girl');
    expect(storageOperate.getByIndex(1)).toEqual('love is color blind');
    storageOperate.clear();
  });
});
<|endoftext|>


<commit_before>//
// This file is licensed under the MIT X11 open source license.
// http://www.opensource.org/licenses/mit-license.php
//
// Authors: Aaron Bockover <abockover@novell.com>
//
// Copyright 2009 Novell, Inc.
//

function __MoonshineWmpPluginBindInstance (control) {
    MtkScreenBinder.BindScreen (control);
    new MoonshinePluginPlayer (control);
}

function MoonshinePluginPlayer (control) {

    this.MoonshinePlayer = new MoonshinePlayer;
    this.WmpControl = control.GetHost ();

    // properties we wish to override for setting media location
    this.MediaSourceProperties = [ "src", "source", "filename", "url" ];

    this.MapWmpAttributes = function () {
        for (var i = 0; i < this.WmpControl.attributes.length; i++) {
            var attr = this.WmpControl.attributes[i];
            this.MapWmpAttribute (attr.name, attr.value);
        }

        var params = this.WmpControl.childNodes;
        if (params) {
            for (var i = 0, n = params.length; i < n; i++) {
                if (params[i] instanceof HTMLParamElement) {
                    this.MapWmpAttribute (params[i].name, params[i].value);
                }
            }
        }
    },

    this.MapWmpAttribute = function (name, value) {
        function to_bool (x) {
            return x.toLowerCase () == "true";
        }

        var param = name.toLowerCase ();
        switch (param) {
            case "background":
            case "bgcolor":      this.MoonshinePlayer.Background = value; break;
            case "showcontrols": this.MoonshinePlayer.ControlsVisible = to_bool (value); break;
            case "autostart":    this.MoonshinePlayer.AutoPlay = to_bool (value); break;
            case "loop":         this.MoonshinePlayer.LoopPlayback = to_bool (value); break;
        }

        for (var j = 0; j < this.MediaSourceProperties.length; j++) {
            if (this.MediaSourceProperties[j] == param) {
                this.MoonshinePlayer.Source = value;
                break;
            }
        }
    };

    this.ImplementWmpApi = function () {
        this.WmpControl["controls"] = new MoonshinePluginPlayerWmpControls (this.MoonshinePlayer);

        var self = this;
        var properties = this.MediaSourceProperties;
        for (var p in properties) {
            delete this.WmpControl[properties[p]];
            this.WmpControl.__defineSetter__ (properties[p], function (s) self.MoonshinePlayer.Source = s);
            this.WmpControl.__defineGetter__ (properties[p], function () self.MoonshinePlayer.Source);
        }
    };

    this.MapWmpAttributes ();
    this.ImplementWmpApi ();
}

<commit_msg>Patch from Chris Toshok fixing the full screen button not responding properly to the changed event<commit_after>//
// This file is licensed under the MIT X11 open source license.
// http://www.opensource.org/licenses/mit-license.php
//
// Authors: Aaron Bockover <abockover@novell.com>
//
// Copyright 2009 Novell, Inc.
//

function __MoonshineWmpPluginBindInstance (control) {
    MtkScreenBinder.BindScreen (control);
    new MoonshinePluginPlayer (control);
}

function MoonshinePluginPlayer (control) {

    this.MoonshinePlayer = new MoonshinePlayer;
    this.WmpControl = control.GetHost ();

    this.WmpControl.ReloadMediaSource = delegate (this, function () {
        var source = this.MoonshinePlayer.Source;
        this.MoonshinePlayer.Source = null;
        this.MoonshinePlayer.Source = source;
    });

    // properties we wish to override for setting media location
    this.MediaSourceProperties = [ "src", "source", "filename", "url" ];

    this.MapWmpAttributes = function () {
        for (var i = 0; i < this.WmpControl.attributes.length; i++) {
            var attr = this.WmpControl.attributes[i];
            this.MapWmpAttribute (attr.name, attr.value);
        }

        var params = this.WmpControl.childNodes;
        if (params) {
            for (var i = 0, n = params.length; i < n; i++) {
                if (params[i] instanceof HTMLParamElement) {
                    this.MapWmpAttribute (params[i].name, params[i].value);
                }
            }
        }
    },

    this.MapWmpAttribute = function (name, value) {
        function to_bool (x) {
            return x.toLowerCase () == "true";
        }

        var param = name.toLowerCase ();
        switch (param) {
            case "background":
            case "bgcolor":      this.MoonshinePlayer.Background = value; break;
            case "showcontrols": this.MoonshinePlayer.ControlsVisible = to_bool (value); break;
            case "autostart":    this.MoonshinePlayer.AutoPlay = to_bool (value); break;
            case "loop":         this.MoonshinePlayer.LoopPlayback = to_bool (value); break;
        }

        for (var j = 0; j < this.MediaSourceProperties.length; j++) {
            if (this.MediaSourceProperties[j] == param) {
                this.MoonshinePlayer.Source = value;
                break;
            }
        }
    };

    this.ImplementWmpApi = function () {
        this.WmpControl["controls"] = new MoonshinePluginPlayerWmpControls (this.MoonshinePlayer);

        var self = this;
        var properties = this.MediaSourceProperties;
        for (var p in properties) {
            delete this.WmpControl[properties[p]];
            this.WmpControl.__defineSetter__ (properties[p], function (s) self.MoonshinePlayer.Source = s);
            this.WmpControl.__defineGetter__ (properties[p], function () self.MoonshinePlayer.Source);
        }
    };

    this.MapWmpAttributes ();
    this.ImplementWmpApi ();
}

<|endoftext|>


<commit_before>import 'codemirror/lib/codemirror.css'
import 'codemirror/addon/dialog/dialog.css'
import 'codemirror/addon/search/matchesonscrollbar.css'

import CodeMirror from 'codemirror'
import 'codemirror/mode/markdown/markdown.js'
import 'codemirror/addon/scroll/scrollpastend.js'
import 'codemirror/keymap/vim.js'
import 'codemirror/keymap/emacs.js'
import 'codemirror/keymap/sublime.js'
import 'codemirror/addon/search/search.js'
import 'codemirror/addon/search/searchcursor.js'
import 'codemirror/addon/search/jump-to-line.js'
import 'codemirror/addon/dialog/dialog.js'
import 'codemirror/addon/search/match-highlighter.js'
import 'codemirror/addon/search/matchesonscrollbar.js'
import 'codemirror/addon/selection/active-line.js'

import { syncPreview } from './sync_scroll'

// load all the themes
export const themes = ['3024-day', '3024-night', 'abcdef', 'ambiance-mobile', 'ambiance', 'base16-dark', 'base16-light', 'bespin', 'blackboard', 'cobalt', 'colorforth', 'dracula', 'duotone-dark', 'duotone-light', 'eclipse', 'elegant', 'erlang-dark', 'hopscotch', 'icecoder', 'isotope', 'lesser-dark', 'liquibyte', 'material', 'mbo', 'mdn-like', 'midnight', 'monokai', 'neat', 'neo', 'night', 'panda-syntax', 'paraiso-dark', 'paraiso-light', 'pastel-on-dark', 'railscasts', 'rubyblue', 'seti', 'solarized', 'the-matrix', 'tomorrow-night-bright', 'tomorrow-night-eighties', 'ttcn', 'twilight', 'vibrant-ink', 'xq-dark', 'xq-light', 'yeti', 'zenburn']
themes.forEach((theme) => {
  require(`codemirror/theme/${theme}.css`)
})

const mac = CodeMirror.keyMap['default'] === CodeMirror.keyMap.macDefault
const ctrl = mac ? 'Cmd' : 'Ctrl'

const editor = CodeMirror.fromTextArea(document.getElementById('editor'), {
  lineNumbers: true,
  mode: 'markdown',
  theme: 'blackboard',
  lineWrapping: true,
  scrollPastEnd: true,
  autofocus: true,
  styleActiveLine: { nonEmpty: true },
  tabSize: 8,
  indentUnit: 4
})

editor.on('scroll', (instance) => {
  syncPreview()
})

// custom keyboard shortcuts
const extraKeys = { 'Alt-F': 'findPersistent' }
extraKeys[`${ctrl}-B`] = (cm) => {
  document.querySelector('i.fa-bold').click()
}
extraKeys[`${ctrl}-I`] = (cm) => {
  document.querySelector('i.fa-italic').click()
}
extraKeys[`${ctrl}-U`] = (cm) => {
  document.querySelector('i.fa-underline').click()
}
extraKeys[`${ctrl}-,`] = (cm) => {
  document.querySelector('i.fa-cog').click()
}
extraKeys['Tab'] = (cm) => {
  cm.execCommand('indentMore')
}
editor.setOption('extraKeys', extraKeys)

// default implementation of vim commands
CodeMirror.Vim.defineEx('w', 'w', (cm, input) => {
  console.log('write')
})
CodeMirror.Vim.defineEx('q', 'q', (cm, input) => {
  if (input.input === 'q') {
    console.log('quit')
  } else if (input.input === 'q!') {
    console.log('force quit')
  }
})
CodeMirror.Vim.defineEx('wq', 'wq', (cm, input) => {
  console.log('write then quit')
})

// custom commands
CodeMirror.commands.toUpperCase = (cm) => {
  cm.replaceSelection(cm.getSelection().toUpperCase())
}
CodeMirror.commands.toLowerCase = (cm) => {
  cm.replaceSelection(cm.getSelection().toLowerCase())
}

export default editor
<commit_msg>Make CodeMirror modes correct and complete<commit_after>import 'codemirror/lib/codemirror.css'
import 'codemirror/addon/dialog/dialog.css'
import 'codemirror/addon/search/matchesonscrollbar.css'

import CodeMirror from 'codemirror'

import 'codemirror/mode/gfm/gfm.js'
import 'codemirror/mode/javascript/javascript.js'
import 'codemirror/mode/clike/clike.js'
import 'codemirror/mode/python/python.js'
import 'codemirror/mode/css/css.js'
import 'codemirror/mode/php/php.js'
import 'codemirror/mode/ruby/ruby.js'
import 'codemirror/mode/shell/shell.js'
import 'codemirror/mode/r/r.js'
import 'codemirror/mode/go/go.js'
import 'codemirror/mode/perl/perl.js'
import 'codemirror/mode/coffeescript/coffeescript.js'
import 'codemirror/mode/swift/swift.js'
import 'codemirror/mode/commonlisp/commonlisp.js'
import 'codemirror/mode/haskell/haskell.js'
import 'codemirror/mode/lua/lua.js'
import 'codemirror/mode/clojure/clojure.js'
import 'codemirror/mode/groovy/groovy.js'
import 'codemirror/mode/rust/rust.js'
import 'codemirror/mode/powershell/powershell.js'

import 'codemirror/addon/scroll/scrollpastend.js'
import 'codemirror/keymap/vim.js'
import 'codemirror/keymap/emacs.js'
import 'codemirror/keymap/sublime.js'
import 'codemirror/addon/search/search.js'
import 'codemirror/addon/search/searchcursor.js'
import 'codemirror/addon/search/jump-to-line.js'
import 'codemirror/addon/dialog/dialog.js'
import 'codemirror/addon/search/match-highlighter.js'
import 'codemirror/addon/search/matchesonscrollbar.js'
import 'codemirror/addon/selection/active-line.js'

import { syncPreview } from './sync_scroll'

// load all the themes
export const themes = ['3024-day', '3024-night', 'abcdef', 'ambiance-mobile', 'ambiance', 'base16-dark', 'base16-light', 'bespin', 'blackboard', 'cobalt', 'colorforth', 'dracula', 'duotone-dark', 'duotone-light', 'eclipse', 'elegant', 'erlang-dark', 'hopscotch', 'icecoder', 'isotope', 'lesser-dark', 'liquibyte', 'material', 'mbo', 'mdn-like', 'midnight', 'monokai', 'neat', 'neo', 'night', 'panda-syntax', 'paraiso-dark', 'paraiso-light', 'pastel-on-dark', 'railscasts', 'rubyblue', 'seti', 'solarized', 'the-matrix', 'tomorrow-night-bright', 'tomorrow-night-eighties', 'ttcn', 'twilight', 'vibrant-ink', 'xq-dark', 'xq-light', 'yeti', 'zenburn']
themes.forEach((theme) => {
  require(`codemirror/theme/${theme}.css`)
})

const mac = CodeMirror.keyMap['default'] === CodeMirror.keyMap.macDefault
const ctrl = mac ? 'Cmd' : 'Ctrl'

const editor = CodeMirror.fromTextArea(document.getElementById('editor'), {
  lineNumbers: true,
  mode: 'gfm',
  theme: 'blackboard',
  lineWrapping: true,
  scrollPastEnd: true,
  autofocus: true,
  styleActiveLine: { nonEmpty: true },
  tabSize: 8,
  indentUnit: 4
})

editor.on('scroll', (instance) => {
  syncPreview()
})

// custom keyboard shortcuts
const extraKeys = { 'Alt-F': 'findPersistent' }
extraKeys[`${ctrl}-B`] = (cm) => {
  document.querySelector('i.fa-bold').click()
}
extraKeys[`${ctrl}-I`] = (cm) => {
  document.querySelector('i.fa-italic').click()
}
extraKeys[`${ctrl}-U`] = (cm) => {
  document.querySelector('i.fa-underline').click()
}
extraKeys[`${ctrl}-,`] = (cm) => {
  document.querySelector('i.fa-cog').click()
}
extraKeys['Tab'] = (cm) => {
  cm.execCommand('indentMore')
}
editor.setOption('extraKeys', extraKeys)

// default implementation of vim commands
CodeMirror.Vim.defineEx('w', 'w', (cm, input) => {
  console.log('write')
})
CodeMirror.Vim.defineEx('q', 'q', (cm, input) => {
  if (input.input === 'q') {
    console.log('quit')
  } else if (input.input === 'q!') {
    console.log('force quit')
  }
})
CodeMirror.Vim.defineEx('wq', 'wq', (cm, input) => {
  console.log('write then quit')
})

// custom commands
CodeMirror.commands.toUpperCase = (cm) => {
  cm.replaceSelection(cm.getSelection().toUpperCase())
}
CodeMirror.commands.toLowerCase = (cm) => {
  cm.replaceSelection(cm.getSelection().toLowerCase())
}

export default editor
<|endoftext|>


<commit_before>"use strict";

/*
 * Sir Trevor Editor
 * --
 * Represents one Sir Trevor editor instance (with multiple blocks)
 * Each block references this instance.
 * BlockTypes are global however.
 */

var _ = require('./lodash');
var $ = require('jquery');
var config = require('./config');
var utils = require('./utils');

var Events = require('./events');
var EventBus = require('./event-bus');
var FormEvents = require('./form-events');
var BlockControls = require('./block-controls');
var BlockManager = require('./block-manager');
var FloatingBlockControls = require('./floating-block-controls');
var FormatBar = require('./format-bar');
var EditorStore = require('./extensions/editor-store');
var ErrorHandler = require('./error-handler');

var Editor = function(options) {
  this.initialize(options);
};

Object.assign(Editor.prototype, require('./function-bind'), require('./events'), {

  bound: ['onFormSubmit', 'hideAllTheThings', 'changeBlockPosition',
    'removeBlockDragOver', 'renderBlock', 'resetBlockControls',
    'blockLimitReached'],

  events: {
    'block:reorder:dragend': 'removeBlockDragOver',
    'block:content:dropped': 'removeBlockDragOver'
  },

  initialize: function(options) {
    utils.log("Init SirTrevor.Editor");

    this.options = Object.assign({}, config.defaults, options || {});
    this.ID = _.uniqueId('st-editor-');

    if (!this._ensureAndSetElements()) { return false; }

    if(!_.isUndefined(this.options.onEditorRender) &&
       _.isFunction(this.options.onEditorRender)) {
      this.onEditorRender = this.options.onEditorRender;
    }

    // Mediated events for *this* Editor instance
    this.mediator = Object.assign({}, Events);

    this._bindFunctions();

    config.instances.push(this);

    this.build();

    FormEvents.bindFormSubmit(this.$form);
  },

  /*
   * Build the Editor instance.
   * Check to see if we've been passed JSON already, and if not try and
   * create a default block.
   * If we have JSON then we need to build all of our blocks from this.
   */
  build: function() {
    this.$el.hide();

    this.errorHandler = new ErrorHandler(this.$outer, this.mediator, this.options.errorsContainer);
    this.store = new EditorStore(this.$el.val(), this.mediator);
    this.block_manager = new BlockManager(this.options, this.ID, this.mediator);
    this.block_controls = new BlockControls(this.block_manager.blockTypes, this.mediator);
    this.fl_block_controls = new FloatingBlockControls(this.$wrapper, this.ID, this.mediator);
    this.formatBar = new FormatBar(this.options.formatBar, this.mediator);

    this.mediator.on('block:changePosition', this.changeBlockPosition);
    this.mediator.on('block-controls:reset', this.resetBlockControls);
    this.mediator.on('block:limitReached', this.blockLimitReached);
    this.mediator.on('block:render', this.renderBlock);

    this.dataStore = "Please use store.retrieve();";

    this._setEvents();

    this.$wrapper.prepend(this.fl_block_controls.render().$el);
    $(document.body).append(this.formatBar.render().$el);
    this.$outer.append(this.block_controls.render().$el);

    $(window).bind('click', this.hideAllTheThings);

    this.createBlocks();
    this.$wrapper.addClass('st-ready');

    if(!_.isUndefined(this.onEditorRender)) {
      this.onEditorRender();
    }
  },

  createBlocks: function() {
    var store = this.store.retrieve();

    if (store.data.length > 0) {
      store.data.forEach(function(block) {
        this.mediator.trigger('block:create', block.type, block.data);
      }, this);
    } else if (this.options.defaultType !== false) {
      this.mediator.trigger('block:create', this.options.defaultType, {});
    }
  },

  destroy: function() {
    // Destroy the rendered sub views
    this.formatBar.destroy();
    this.fl_block_controls.destroy();
    this.block_controls.destroy();

    // Destroy all blocks
    this.blocks.forEach(function(block) {
      this.mediator.trigger('block:remove', this.block.blockID);
    }, this);

    // Stop listening to events
    this.mediator.stopListening();
    this.stopListening();

    // Remove instance
    config.instances = config.instances.filter(function(instance) {
      return instance.ID !== this.ID;
    }, this);

    // Clear the store
    this.store.reset();
    this.$outer.replaceWith(this.$el.detach());
  },

  reinitialize: function(options) {
    this.destroy();
    this.initialize(options || this.options);
  },

  resetBlockControls: function() {
    this.block_controls.renderInContainer(this.$wrapper);
    this.block_controls.hide();
  },

  blockLimitReached: function(toggle) {
    this.$wrapper.toggleClass('st--block-limit-reached', toggle);
  },

  _setEvents: function() {
    Object.keys(this.events).forEach(function(type) {
      EventBus.on(type, this[this.events[type]], this);
    }, this);
  },

  hideAllTheThings: function(e) {
    this.block_controls.hide();
    this.formatBar.hide();
  },

  store: function(method, options){
    utils.log("The store method has been removed, please call store[methodName]");
    return this.store[method].call(this, options || {});
  },

  renderBlock: function(block) {
    this._renderInPosition(block.render().$el);
    this.hideAllTheThings();
    // this.scrollTo(block.$el);

    block.trigger("onRender");
  },

  scrollTo: function(element) {
    $('html, body').animate({ scrollTop: element.position().top }, 300, "linear");
  },

  removeBlockDragOver: function() {
    this.$outer.find('.st-drag-over').removeClass('st-drag-over');
  },

  changeBlockPosition: function($block, selectedPosition) {
    selectedPosition = selectedPosition - 1;

    var blockPosition = this.getBlockPosition($block),
    $blockBy = this.$wrapper.find('.st-block').eq(selectedPosition);

    var where = (blockPosition > selectedPosition) ? "Before" : "After";

    if($blockBy && $blockBy.attr('id') !== $block.attr('id')) {
      this.hideAllTheThings();
      $block["insert" + where]($blockBy);
      this.scrollTo($block);
    }
  },

  _renderInPosition: function(block) {
    if (this.block_controls.currentContainer) {
      this.block_controls.currentContainer.after(block);
    } else {
      this.$wrapper.append(block);
    }
  },

  validateAndSaveBlock: function(block, shouldValidate) {
    if ((!config.skipValidation || shouldValidate) && !block.valid()) {
      this.mediator.trigger('errors:add', { text: _.result(block, 'validationFailMsg') });
      utils.log("Block " + block.blockID + " failed validation");
      return;
    }

    var blockData = block.getData();
    utils.log("Adding data for block " + block.blockID + " to block store:",
              blockData);
    this.store.addData(blockData);
  },

  /*
   * Handle a form submission of this Editor instance.
   * Validate all of our blocks, and serialise all data onto the JSON objects
   */
  onFormSubmit: function(shouldValidate) {
    // if undefined or null or anything other than false - treat as true
    shouldValidate = (shouldValidate === false) ? false : true;

    utils.log("Handling form submission for Editor " + this.ID);

    this.mediator.trigger('errors:reset');
    this.store.reset();

    this.validateBlocks(shouldValidate);
    this.block_manager.validateBlockTypesExist(shouldValidate);

    this.mediator.trigger('errors:render');
    this.$el.val(this.store.toString());

    return this.errorHandler.errors.length;
  },

  validateBlocks: function(shouldValidate) {
    var self = this;
    this.$wrapper.find('.st-block').each(function(idx, block) {
      var _block = self.block_manager.findBlockById($(block).attr('id'));
      if (!_.isUndefined(_block)) {
        self.validateAndSaveBlock(_block, shouldValidate);
      }
    });
  },

  findBlockById: function(block_id) {
    return this.block_manager.findBlockById(block_id);
  },

  getBlocksByType: function(block_type) {
    return this.block_manager.getBlocksByType(block_type);
  },

  getBlocksByIDs: function(block_ids) {
    return this.block_manager.getBlocksByIDs(block_ids);
  },

  getBlockPosition: function($block) {
    return this.$wrapper.find('.st-block').index($block);
  },

  _ensureAndSetElements: function() {
    if(_.isUndefined(this.options.el) || _.isEmpty(this.options.el)) {
      utils.log("You must provide an el");
      return false;
    }

    this.$el = this.options.el;
    this.el = this.options.el[0];
    this.$form = this.$el.parents('form');

    var $outer = $("<div>").attr({ 'id': this.ID, 'class': 'st-outer', 'dropzone': 'copy link move' });
    var $wrapper = $("<div>").attr({ 'class': 'st-blocks' });

    // Wrap our element in lots of containers *eww*
    this.$el.wrap($outer).wrap($wrapper);

    this.$outer = this.$form.find('#' + this.ID);
    this.$wrapper = this.$outer.find('.st-blocks');

    return true;
  }

});

module.exports = Editor;

<commit_msg>should submit an empty string if data store empty<commit_after>"use strict";

/*
 * Sir Trevor Editor
 * --
 * Represents one Sir Trevor editor instance (with multiple blocks)
 * Each block references this instance.
 * BlockTypes are global however.
 */

var _ = require('./lodash');
var $ = require('jquery');
var config = require('./config');
var utils = require('./utils');

var Events = require('./events');
var EventBus = require('./event-bus');
var FormEvents = require('./form-events');
var BlockControls = require('./block-controls');
var BlockManager = require('./block-manager');
var FloatingBlockControls = require('./floating-block-controls');
var FormatBar = require('./format-bar');
var EditorStore = require('./extensions/editor-store');
var ErrorHandler = require('./error-handler');

var Editor = function(options) {
  this.initialize(options);
};

Object.assign(Editor.prototype, require('./function-bind'), require('./events'), {

  bound: ['onFormSubmit', 'hideAllTheThings', 'changeBlockPosition',
    'removeBlockDragOver', 'renderBlock', 'resetBlockControls',
    'blockLimitReached'],

  events: {
    'block:reorder:dragend': 'removeBlockDragOver',
    'block:content:dropped': 'removeBlockDragOver'
  },

  initialize: function(options) {
    utils.log("Init SirTrevor.Editor");

    this.options = Object.assign({}, config.defaults, options || {});
    this.ID = _.uniqueId('st-editor-');

    if (!this._ensureAndSetElements()) { return false; }

    if(!_.isUndefined(this.options.onEditorRender) &&
       _.isFunction(this.options.onEditorRender)) {
      this.onEditorRender = this.options.onEditorRender;
    }

    // Mediated events for *this* Editor instance
    this.mediator = Object.assign({}, Events);

    this._bindFunctions();

    config.instances.push(this);

    this.build();

    FormEvents.bindFormSubmit(this.$form);
  },

  /*
   * Build the Editor instance.
   * Check to see if we've been passed JSON already, and if not try and
   * create a default block.
   * If we have JSON then we need to build all of our blocks from this.
   */
  build: function() {
    this.$el.hide();

    this.errorHandler = new ErrorHandler(this.$outer, this.mediator, this.options.errorsContainer);
    this.store = new EditorStore(this.$el.val(), this.mediator);
    this.block_manager = new BlockManager(this.options, this.ID, this.mediator);
    this.block_controls = new BlockControls(this.block_manager.blockTypes, this.mediator);
    this.fl_block_controls = new FloatingBlockControls(this.$wrapper, this.ID, this.mediator);
    this.formatBar = new FormatBar(this.options.formatBar, this.mediator);

    this.mediator.on('block:changePosition', this.changeBlockPosition);
    this.mediator.on('block-controls:reset', this.resetBlockControls);
    this.mediator.on('block:limitReached', this.blockLimitReached);
    this.mediator.on('block:render', this.renderBlock);

    this.dataStore = "Please use store.retrieve();";

    this._setEvents();

    this.$wrapper.prepend(this.fl_block_controls.render().$el);
    $(document.body).append(this.formatBar.render().$el);
    this.$outer.append(this.block_controls.render().$el);

    $(window).bind('click', this.hideAllTheThings);

    this.createBlocks();
    this.$wrapper.addClass('st-ready');

    if(!_.isUndefined(this.onEditorRender)) {
      this.onEditorRender();
    }
  },

  createBlocks: function() {
    var store = this.store.retrieve();

    if (store.data.length > 0) {
      store.data.forEach(function(block) {
        this.mediator.trigger('block:create', block.type, block.data);
      }, this);
    } else if (this.options.defaultType !== false) {
      this.mediator.trigger('block:create', this.options.defaultType, {});
    }
  },

  destroy: function() {
    // Destroy the rendered sub views
    this.formatBar.destroy();
    this.fl_block_controls.destroy();
    this.block_controls.destroy();

    // Destroy all blocks
    this.blocks.forEach(function(block) {
      this.mediator.trigger('block:remove', this.block.blockID);
    }, this);

    // Stop listening to events
    this.mediator.stopListening();
    this.stopListening();

    // Remove instance
    config.instances = config.instances.filter(function(instance) {
      return instance.ID !== this.ID;
    }, this);

    // Clear the store
    this.store.reset();
    this.$outer.replaceWith(this.$el.detach());
  },

  reinitialize: function(options) {
    this.destroy();
    this.initialize(options || this.options);
  },

  resetBlockControls: function() {
    this.block_controls.renderInContainer(this.$wrapper);
    this.block_controls.hide();
  },

  blockLimitReached: function(toggle) {
    this.$wrapper.toggleClass('st--block-limit-reached', toggle);
  },

  _setEvents: function() {
    Object.keys(this.events).forEach(function(type) {
      EventBus.on(type, this[this.events[type]], this);
    }, this);
  },

  hideAllTheThings: function(e) {
    this.block_controls.hide();
    this.formatBar.hide();
  },

  store: function(method, options){
    utils.log("The store method has been removed, please call store[methodName]");
    return this.store[method].call(this, options || {});
  },

  renderBlock: function(block) {
    this._renderInPosition(block.render().$el);
    this.hideAllTheThings();
    // this.scrollTo(block.$el);

    block.trigger("onRender");
  },

  scrollTo: function(element) {
    $('html, body').animate({ scrollTop: element.position().top }, 300, "linear");
  },

  removeBlockDragOver: function() {
    this.$outer.find('.st-drag-over').removeClass('st-drag-over');
  },

  changeBlockPosition: function($block, selectedPosition) {
    selectedPosition = selectedPosition - 1;

    var blockPosition = this.getBlockPosition($block),
    $blockBy = this.$wrapper.find('.st-block').eq(selectedPosition);

    var where = (blockPosition > selectedPosition) ? "Before" : "After";

    if($blockBy && $blockBy.attr('id') !== $block.attr('id')) {
      this.hideAllTheThings();
      $block["insert" + where]($blockBy);
      this.scrollTo($block);
    }
  },

  _renderInPosition: function(block) {
    if (this.block_controls.currentContainer) {
      this.block_controls.currentContainer.after(block);
    } else {
      this.$wrapper.append(block);
    }
  },

  validateAndSaveBlock: function(block, shouldValidate) {
    if ((!config.skipValidation || shouldValidate) && !block.valid()) {
      this.mediator.trigger('errors:add', { text: _.result(block, 'validationFailMsg') });
      utils.log("Block " + block.blockID + " failed validation");
      return;
    }

    var blockData = block.getData();
    utils.log("Adding data for block " + block.blockID + " to block store:",
              blockData);
    this.store.addData(blockData);
  },

  /*
   * Handle a form submission of this Editor instance.
   * Validate all of our blocks, and serialise all data onto the JSON objects
   */
  onFormSubmit: function(shouldValidate) {
    // if undefined or null or anything other than false - treat as true
    shouldValidate = (shouldValidate === false) ? false : true;

    utils.log("Handling form submission for Editor " + this.ID);

    this.mediator.trigger('errors:reset');
    this.store.reset();

    this.validateBlocks(shouldValidate);
    this.block_manager.validateBlockTypesExist(shouldValidate);

    this.mediator.trigger('errors:render');

    // If there is nothing in the store, the textarea should be submitted empty
    if (_.isEmpty(this.store.store.data)) {
        this.$el.val('');
    }
    else {
        this.$el.val(this.store.toString());
    }

    return this.errorHandler.errors.length;
  },

  validateBlocks: function(shouldValidate) {
    var self = this;
    this.$wrapper.find('.st-block').each(function(idx, block) {
      var _block = self.block_manager.findBlockById($(block).attr('id'));
      if (!_.isUndefined(_block)) {
        self.validateAndSaveBlock(_block, shouldValidate);
      }
    });
  },

  findBlockById: function(block_id) {
    return this.block_manager.findBlockById(block_id);
  },

  getBlocksByType: function(block_type) {
    return this.block_manager.getBlocksByType(block_type);
  },

  getBlocksByIDs: function(block_ids) {
    return this.block_manager.getBlocksByIDs(block_ids);
  },

  getBlockPosition: function($block) {
    return this.$wrapper.find('.st-block').index($block);
  },

  _ensureAndSetElements: function() {
    if(_.isUndefined(this.options.el) || _.isEmpty(this.options.el)) {
      utils.log("You must provide an el");
      return false;
    }

    this.$el = this.options.el;
    this.el = this.options.el[0];
    this.$form = this.$el.parents('form');

    var $outer = $("<div>").attr({ 'id': this.ID, 'class': 'st-outer', 'dropzone': 'copy link move' });
    var $wrapper = $("<div>").attr({ 'class': 'st-blocks' });

    // Wrap our element in lots of containers *eww*
    this.$el.wrap($outer).wrap($wrapper);

    this.$outer = this.$form.find('#' + this.ID);
    this.$wrapper = this.$outer.find('.st-blocks');

    return true;
  }

});

module.exports = Editor;

<|endoftext|>


<commit_before>function FullScreen(editor, args)
{
  this.editor = editor;
  editor._superclean_on = false;
  cfg = editor.config;

  cfg.registerButton
  ( 'fullscreen',
    this._lc("Maximize/Minimize Editor"),
    [_editor_url + cfg.imgURL + 'ed_buttons_main.gif',8,0], true,
      function(e, objname, obj)
      {
        e._fullScreen();
        if(e._isFullScreen)
        {
          obj.swapImage([_editor_url + cfg.imgURL + 'ed_buttons_main.gif',9,0]);
        }
        else
        {
          obj.swapImage([_editor_url + cfg.imgURL + 'ed_buttons_main.gif',8,0]);
        }
      }
  );

  // See if we can find 'popupeditor' and replace it with fullscreen
  cfg.addToolbarElement("fullscreen", "popupeditor", 0);
}

FullScreen._pluginInfo =
{
  name     : "FullScreen",
  version  : "1.0",
  developer: "James Sleeman",
  developer_url: "http://www.gogo.co.nz/",
  c_owner      : "Gogo Internet Services",
  license      : "htmlArea",
  sponsor      : "Gogo Internet Services",
  sponsor_url  : "http://www.gogo.co.nz/"
};

FullScreen.prototype._lc = function(string) {
    return HTMLArea._lc(string, 'FullScreen');
}

/** fullScreen makes an editor take up the full window space (and resizes when the browser is resized)
 *  the principle is the same as the "popupwindow" functionality in the original htmlArea, except
 *  this one doesn't popup a window (it just uses to positioning hackery) so it's much more reliable
 *  and much faster to switch between
 */

HTMLArea.prototype._fullScreen = function()
{
  var e = this;
  function sizeItUp()
  {
    if(!e._isFullScreen || e._sizing) return false;
    e._sizing = true;
    // Width & Height of window
    var x,y;
    if (window.innerHeight) // all except Explorer
    {
      x = window.innerWidth;
      y = window.innerHeight;
    }
    else if (document.documentElement && document.documentElement.clientHeight)
      // Explorer 6 Strict Mode
    {
      x = document.documentElement.clientWidth;
      y = document.documentElement.clientHeight;
    }
    else if (document.body) // other Explorers
    {
      x = document.body.clientWidth;
      y = document.body.clientHeight;
    }

    e.sizeEditor(x + 'px',y + 'px',true,true);
    e._sizing = false;
  }

  function sizeItDown()
  {
    if(e._isFullScreen || e._sizing) return false;
    e._sizing = true;
    e.initSize();
    e._sizing = false;
  }

  /** It's not possible to reliably get scroll events, particularly when we are hiding the scrollbars
   *   so we just reset the scroll ever so often while in fullscreen mode
   */
  function resetScroll()
  {
    if(e._isFullScreen)
    {
      window.scroll(0,0);
      window.setTimeout(resetScroll,150);
    }
  }

  if(typeof this._isFullScreen == 'undefined')
  {
    this._isFullScreen = false;
    if(e.target != e._iframe)
    {
      HTMLArea._addEvent(window, 'resize', sizeItUp);
    }
  }

  // Gecko has a bug where if you change position/display on a
  // designMode iframe that designMode dies.
  if(HTMLArea.is_gecko)
  {
    this.deactivateEditor();
  }

  if(this._isFullScreen)
  {
    // Unmaximize
    this._htmlArea.style.position = '';
    try
    {
      if(HTMLArea.is_ie)
      {
        var bod = document.getElementsByTagName('html');
      }
      else
      {
        var bod = document.getElementsByTagName('body');
      }
      bod[0].style.overflow='';
    }
    catch(e)
    {
      // Nutthin
    }
    this._isFullScreen = false;
    sizeItDown();

    window.scroll(this._unScroll.x, this._unScroll.y);
  }
  else
  {

    // Get the current Scroll Positions
    this._unScroll =
    {
     x:(window.pageXOffset)?(window.pageXOffset):(document.documentElement)?document.documentElement.scrollLeft:document.body.scrollLeft,
     y:(window.pageYOffset)?(window.pageYOffset):(document.documentElement)?document.documentElement.scrollTop:document.body.scrollTop
    };

    // Maximize
    window.scroll
    this._htmlArea.style.position = 'absolute';
    this._htmlArea.style.zIndex   = 9999;
    this._htmlArea.style.left     = 0;
    this._htmlArea.style.top      = 0;
    this._isFullScreen = true;
    resetScroll();

    try
    {
      if(HTMLArea.is_ie)
      {
        var bod = document.getElementsByTagName('html');
      }
      else
      {
        var bod = document.getElementsByTagName('body');
      }
      bod[0].style.overflow='hidden';
    }
    catch(e)
    {
      // Nutthin
    }

    sizeItUp();
  }

  if(HTMLArea.is_gecko)
  {
    this.activateEditor();
  }
  this.focusEditor();
}<commit_msg>Fix for fullscreen when the editor is enclosed in relative/absolute  positioned elements.<commit_after>function FullScreen(editor, args)
{
  this.editor = editor;
  editor._superclean_on = false;
  cfg = editor.config;

  cfg.registerButton
  ( 'fullscreen',
    this._lc("Maximize/Minimize Editor"),
    [_editor_url + cfg.imgURL + 'ed_buttons_main.gif',8,0], true,
      function(e, objname, obj)
      {
        e._fullScreen();
        if(e._isFullScreen)
        {
          obj.swapImage([_editor_url + cfg.imgURL + 'ed_buttons_main.gif',9,0]);
        }
        else
        {
          obj.swapImage([_editor_url + cfg.imgURL + 'ed_buttons_main.gif',8,0]);
        }
      }
  );

  // See if we can find 'popupeditor' and replace it with fullscreen
  cfg.addToolbarElement("fullscreen", "popupeditor", 0);
}

FullScreen._pluginInfo =
{
  name     : "FullScreen",
  version  : "1.0",
  developer: "James Sleeman",
  developer_url: "http://www.gogo.co.nz/",
  c_owner      : "Gogo Internet Services",
  license      : "htmlArea",
  sponsor      : "Gogo Internet Services",
  sponsor_url  : "http://www.gogo.co.nz/"
};

FullScreen.prototype._lc = function(string) {
    return HTMLArea._lc(string, 'FullScreen');
}

/** fullScreen makes an editor take up the full window space (and resizes when the browser is resized)
 *  the principle is the same as the "popupwindow" functionality in the original htmlArea, except
 *  this one doesn't popup a window (it just uses to positioning hackery) so it's much more reliable
 *  and much faster to switch between
 */

HTMLArea.prototype._fullScreen = function()
{
  var e = this;
  function sizeItUp()
  {
    if(!e._isFullScreen || e._sizing) return false;
    e._sizing = true;
    // Width & Height of window
    var x,y;
    if (window.innerHeight) // all except Explorer
    {
      x = window.innerWidth;
      y = window.innerHeight;
    }
    else if (document.documentElement && document.documentElement.clientHeight)
      // Explorer 6 Strict Mode
    {
      x = document.documentElement.clientWidth;
      y = document.documentElement.clientHeight;
    }
    else if (document.body) // other Explorers
    {
      x = document.body.clientWidth;
      y = document.body.clientHeight;
    }

    e.sizeEditor(x + 'px',y + 'px',true,true);
    e._sizing = false;
  }

  function sizeItDown()
  {
    if(e._isFullScreen || e._sizing) return false;
    e._sizing = true;
    e.initSize();
    e._sizing = false;
  }

  /** It's not possible to reliably get scroll events, particularly when we are hiding the scrollbars
   *   so we just reset the scroll ever so often while in fullscreen mode
   */
  function resetScroll()
  {
    if(e._isFullScreen)
    {
      window.scroll(0,0);
      window.setTimeout(resetScroll,150);
    }
  }

  if(typeof this._isFullScreen == 'undefined')
  {
    this._isFullScreen = false;
    if(e.target != e._iframe)
    {
      HTMLArea._addEvent(window, 'resize', sizeItUp);
    }
  }

  // Gecko has a bug where if you change position/display on a
  // designMode iframe that designMode dies.
  if(HTMLArea.is_gecko)
  {
    this.deactivateEditor();
  }

  if(this._isFullScreen)
  {
    // Unmaximize
    this._htmlArea.style.position = '';
    try
    {
      if(HTMLArea.is_ie)
      {
        var bod = document.getElementsByTagName('html');
      }
      else
      {
        var bod = document.getElementsByTagName('body');
      }
      bod[0].style.overflow='';
    }
    catch(e)
    {
      // Nutthin
    }
    this._isFullScreen = false;
    sizeItDown();

    // Restore all ancestor positions
    var ancestor = this._htmlArea;
    while((ancestor = ancestor.parentNode) && ancestor.style)
    {
      ancestor.style.position = ancestor._xinha_fullScreenOldPosition;
      ancestor._xinha_fullScreenOldPosition = null;
    }

    window.scroll(this._unScroll.x, this._unScroll.y);
  }
  else
  {

    // Get the current Scroll Positions
    this._unScroll =
    {
     x:(window.pageXOffset)?(window.pageXOffset):(document.documentElement)?document.documentElement.scrollLeft:document.body.scrollLeft,
     y:(window.pageYOffset)?(window.pageYOffset):(document.documentElement)?document.documentElement.scrollTop:document.body.scrollTop
    };

    // Make all ancestors position = static
    var ancestor = this._htmlArea;
    while((ancestor = ancestor.parentNode) && ancestor.style)
    {
      ancestor._xinha_fullScreenOldPosition = ancestor.style.position;
      ancestor.style.position = 'static';
    }

    // Maximize
    window.scroll(0,0);
    this._htmlArea.style.position = 'absolute';
    this._htmlArea.style.zIndex   = 9999;
    this._htmlArea.style.left     = 0;
    this._htmlArea.style.top      = 0;
    this._isFullScreen = true;
    resetScroll();

    try
    {
      if(HTMLArea.is_ie)
      {
        var bod = document.getElementsByTagName('html');
      }
      else
      {
        var bod = document.getElementsByTagName('body');
      }
      bod[0].style.overflow='hidden';
    }
    catch(e)
    {
      // Nutthin
    }

    sizeItUp();
  }

  if(HTMLArea.is_gecko)
  {
    this.activateEditor();
  }
  this.focusEditor();
}<|endoftext|>


<commit_before>suite('time and date', function() {

    var result;
    var today = new Date();

    suite('p5.prototype.day', function() {
      var day = p5.prototype.day;
      var dd = today.getDate();
      suite('day()', function() {
        test('should be a function', function() {
            assert.ok(day);
            assert.typeOf(day, 'function');
        });
        test('should return todays date', function() {
            result = day();
            assert.equal(result, dd);
        });
      });
    });

    suite('p5.prototype.month', function() {
      var month = p5.prototype.month;
      var mm = today.getMonth() + 1;
      suite('month()', function() {
        test('should be a function', function() {
            assert.ok(month);
            assert.typeOf(month, 'function');
        });
        test('should return todays date', function() {
            result = month();
            assert.equal(result, mm);
        });
      });
    });

});<commit_msg>time and date tests<commit_after>suite('time and date', function() {

    var result;
    var startTime = new Date().getTime();

    suite('p5.prototype.year', function() {
      var year = p5.prototype.year;
      suite('year()', function() {
        test('should be a function', function() {
            assert.ok(year);
            assert.typeOf(year, 'function');
        });
        test('should return this year', function() {
            result = year();
            var jsYear = new Date().getFullYear();
            assert.equal(result, jsYear);
        });
      });
    });

    suite('p5.prototype.day', function() {
      var day = p5.prototype.day;
      suite('day()', function() {
        test('should be a function', function() {
            assert.ok(day);
            assert.typeOf(day, 'function');
        });
        test('should return todays day', function() {
            var jsDay = new Date().getDate();
            result = day();
            assert.equal(result, jsDay);
        });
      });
    });

    suite('p5.prototype.month', function() {
      var month = p5.prototype.month;
      suite('month()', function() {
        test('should be a function', function() {
            assert.ok(month);
            assert.typeOf(month, 'function');
        });
        test('should return today\'s month', function() {
            result = month();
            var jsMonth = new Date().getMonth() + 1;
            assert.equal(result, jsMonth);
        });
      });
    });

    suite('p5.prototype.hour', function() {
      var hour = p5.prototype.hour;
      suite('hour()', function() {
        test('should be a function', function() {
            assert.ok(hour);
            assert.typeOf(hour, 'function');
        });
        test('should return this hour', function() {
            var jsHour = new Date().getHours();
            result = hour();
            assert.equal(result, jsHour);
        });
      });
    });

    suite('p5.prototype.second', function() {
      var second = p5.prototype.second;
      suite('second()', function() {
        test('should be a function', function() {
            assert.ok(second);
            assert.typeOf(second, 'function');
        });
        test('should return this second', function() {
            var jsSecond = new Date().getSeconds();
            result = second();
            assert.equal(result, jsSecond); //(Math.abs(jsSecond - result), '==', 0, 'everything is ok'); // in my testing, found this might be off by 1 second
        });
      });
    });

    suite('p5.prototype.minute', function() {
      var minute = p5.prototype.minute;
      suite('minute()', function() {
        test('should be a function', function() {
            assert.ok(minute);
            assert.typeOf(minute, 'function');
        });
        test('should return a number that is this minute', function() {
            var jsMinute = new Date().getMinutes();
            result = minute();
            assert.isNumber(result);
            assert.isNumber(jsMinute);
            assert.equal(result, jsMinute);
        });
      });
    });

    suite('p5.prototype.millis', function() {
      var runningTime = 1000;
      var p5mock = {_startTime: new Date().getTime() - runningTime};
      var millis = p5.prototype.millis;
      var result = millis.call(p5mock);
      suite('millis()', function() {
        test('should be a function', function() {
            assert.ok(millis);
            assert.typeOf(millis, 'function');
        });
        test('result should be a number', function() {
            assert.isNumber(result);
        });
        test('result should be ' + runningTime, function() {
            assert.operator(result, '==', runningTime, 'everything is ok');
        });
         test('result should be > newResult', function() {
            var newResult = millis.call(p5mock);
            assert.operator(newResult, '>', result, 'everything is ok');
        });
      });
    });

});<|endoftext|>


<commit_before>var errors = require('../../../src/getstream').errors,
    expect = require('expect.js'),
    Promise = require('../../../src/lib/promise'),
    td = require('testdouble'),
    mocks = require('../utils/mocks'),
    beforeEachFn = require('../utils/hooks').beforeEach,
    signing = signing || require('../../../src/lib/signing');

describe('[UNIT] Stream Client Batch (Node)', function() {

    beforeEach(beforeEachFn);

    afterEach(function() {
        td.reset();
    });

    function replaceMSR() {
        var msr = td.function();
        td.replace(this.client, 'makeSignedRequest', msr);
        return msr;
    }

    it('#addToMany', function() {
        expect(this.client.addToMany).to.be.a(Function);

        var msr = replaceMSR.call(this);

        var activity = { actor: 'matthisk', object: 0, verb: 'tweet' };
        var feeds = ['global:feed', 'global:feed2'];

        this.client.addToMany(activity, feeds);

        td.verify(msr({
            url: 'feed/add_to_many/',
            body: {
                activity: activity,
                feeds: feeds
            }
        }, undefined));
    });

    it('#followMany', function() {
        expect(this.client.followMany).to.be.a(Function);

        var msr = replaceMSR.call(this);

        var follows = [];
        var cb = function() {};

        this.client.followMany(follows, 10, cb);

        td.verify(msr({
            url: 'follow_many/',
            body: follows,
            qs: {
                'activity_copy_limit': 10
            }
        }, cb));
    });

    it('#followMany', function() {
        expect(this.client.followMany).to.be.a(Function);

        var msr = replaceMSR.call(this);

        var follows = [];
        var cb = function() {};

        this.client.followMany(follows, cb);

        td.verify(msr({
            url: 'follow_many/',
            body: follows,
            qs: { }
        }, cb));
    });

    it('#makeSignedRequest', function() {
        var self = this;
        td.replace(this.client, 'apiSecret', '');

        function throws() {
            self.client.makeSignedRequest({});
        }

        expect(throws).to.throwException(function(err) {
            expect(err).to.be.a(errors.SiteError);
        });
    });

    it('#makeSignedRequest', function() {
        var p = this.client.makeSignedRequest({});

        expect(p).to.be.a(Promise);
    });

});<commit_msg>Tests: Add test that should fail because of #102<commit_after>var errors = require('../../../src/getstream').errors,
    expect = require('expect.js'),
    Promise = require('../../../src/lib/promise'),
    td = require('testdouble'),
    mocks = require('../utils/mocks'),
    beforeEachFn = require('../utils/hooks').beforeEach,
    signing = signing || require('../../../src/lib/signing');

describe('[UNIT] Stream Client Batch (Node)', function() {

    beforeEach(beforeEachFn);

    afterEach(function() {
        td.reset();
    });

    function replaceMSR() {
        var msr = td.function();
        td.replace(this.client, 'makeSignedRequest', msr);
        return msr;
    }

    it('#addToMany', function() {
        expect(this.client.addToMany).to.be.a(Function);

        var msr = replaceMSR.call(this);

        var activity = { actor: 'matthisk', object: 0, verb: 'tweet' };
        var feeds = ['global:feed', 'global:feed2'];

        this.client.addToMany(activity, feeds);

        td.verify(msr({
            url: 'feed/add_to_many/',
            body: {
                activity: activity,
                feeds: feeds
            }
        }, undefined));
    });

    it('#followMany', function() {
        expect(this.client.followMany).to.be.a(Function);

        var msr = replaceMSR.call(this);

        var follows = [];
        var cb = function() {};

        this.client.followMany(follows, 10, cb);

        td.verify(msr({
            url: 'follow_many/',
            body: follows,
            qs: {
                'activity_copy_limit': 10
            }
        }, cb));
    });

    it('#followMany', function() {
        expect(this.client.followMany).to.be.a(Function);

        var msr = replaceMSR.call(this);

        var follows = [];
        var cb = function() {};

        this.client.followMany(follows, cb);

        td.verify(msr({
            url: 'follow_many/',
            body: follows,
            qs: { }
        }, cb));
    });

    it('#followMany', function() {
        expect(this.client.followMany).to.be.a(Function);

        var msr = replaceMSR.call(this);

        var follows = [];
        var cb = function() {};

        this.client.followMany(follows, 0, cb);

        td.verify(msr({
            url: 'follow_many/',
            body: follows,
            qs: {
                'activity_copy_limit': 0
            }
        }, cb));
    });

    it('#makeSignedRequest', function() {
        var self = this;
        td.replace(this.client, 'apiSecret', '');

        function throws() {
            self.client.makeSignedRequest({});
        }

        expect(throws).to.throwException(function(err) {
            expect(err).to.be.a(errors.SiteError);
        });
    });

    it('#makeSignedRequest', function() {
        var p = this.client.makeSignedRequest({});

        expect(p).to.be.a(Promise);
    });

});
<|endoftext|>


<commit_before>Draw.rect = function(x, y, w, h) {
  Canvas.context.beginPath();
  switch(Draw.currentRectMode) {
    case CORNER: Canvas.context.fillRect(x, y, w, h);
                 Canvas.context.strokeRect(x, y, w, h); break;
    case CORNERS: Canvas.context.fillRect(x, y, w - x, h - y);
                 Canvas.context.strokeRect(x, y, w - x, h - y); break;
    case RADIUS: Canvas.context.fillRect(x + w/2, y + h/2, w * 2, h * 2);
                 Canvas.context.strokeRect(x + w/2, y + h/2, w * 2, h * 2); break;
    case CENTER: Canvas.context.fillRect(x + w/2, y + h/2, w, h);
                 Canvas.context.strokeRect(x + w/2, y + h/2, w, h); break;
  }
  Canvas.context.fill();
  Canvas.context.stroke();
};
<commit_msg>Update rect.js<commit_after>Draw.rect = function(x, y, w, h, tl, tr, br, bl) {
  var realX = x,
      realY = y,
      realW = w,
      realH = h;

  switch(Draw.currentRectMode) {
    case CORNERS: realW = w - x;
                  realH = h - y; break;
    case RADIUS: realX = x + w/2;
                 realY = y + h/2;
                 realW = w * 2;
                 realH = h * 2; break;
    case CENTER: realX = x - w/2;
                 realY = y - h/2; break;
  }

  tl = tl || 0;
  tr = tr || tl;
  br = br || tl;
  bl = bl || tl;

  ctx.beginPath();
  ctx.moveTo(realX + tl, realY);
  ctx.lineTo(realX + realW - tr, realY);
  ctx.quadraticCurveTo(realX + realW, realY, realX + realW, realY + tr);
  ctx.lineTo(realX + realW, realY + realH - br);
  ctx.quadraticCurveTo(realX + realW, realY + realH, realX + realW - br, realY + realH);
  ctx.lineTo(realX + bl, realY + realH);
  ctx.quadraticCurveTo(x, realY + realH, realX, realY + realH - bl);
  ctx.lineTo(realX, realY + tl);
  ctx.quadraticCurveTo(realX, realY, realX + tl, realY);
  ctx.closePath();

  ctx.fill();
  ctx.stroke();
};
<|endoftext|>