<commit_before>/*global angular*/
(function() {
  'use strict';

  angular
    .module('docsApp')
    .controller('DocumentController', DocumentController);

  DocumentController.$inject = [
    '$scope',
    '$location',
    '$routeParams',
    'FileUploader',
    'TokenService',
    'DateUtilsService',
    'ReceiverTypeService',
    'RespondentService',
    'StatusService',
    'DocumentService'
  ];

  function DocumentController(
      $scope,
      $location,
      $routeParams,
      FileUploader,
      TokenService,
      DateUtilsService,
      ReceiverTypeService,
      RespondentService,
      StatusService,
      DocumentService
    ) {
    var vm = this;
    var myDate = new Date();
    vm.uploader = new FileUploader();
    vm.currentUser = getCurrentUser();
    vm.id = '';
    vm.doc = {};
    vm.file = null;
    vm.item = {};
    vm.minDate = new Date(myDate.getFullYear() - 1, 12, 1);
    vm.maxDate = new Date(myDate.getFullYear() + 1, 0, 1);
    vm.receiverTypes = ReceiverTypeService.get();
    vm.respondents = RespondentService.get();
    vm.statusTypes = StatusService.get();
    vm.submit = submit;    vm.insertReturnPath = '';
    vm.returnPath = '/document/view/';
    vm.uploadPath = '/api/document/upload/';

    vm.uploader.onAfterAddingFile = function (item) {
      vm.item = item;
      vm.doc.url = item._file.name;
    }

    vm.uploader.onBeforeUploadItem = function (item) {
      item.url = vm.uploadPath + vm.id;
    }

    vm.uploader.onSuccessItem = function (item, response, status, headers) {
      console.log('Upload success!');
      console.log('item');
      console.log(item);
      console.log('response:');
      console.log(response);
    }

    vm.uploader.onCompleteAll = function () {
      console.log('All done');
      if (vm.id.length > 0) {
        $location.path(vm.returnPath + vm.id);
      }
    }

    function getCurrentUser() {
      var userToken = TokenService.getUserFromToken();
      return {
        name: userToken._doc.name,
        email: userToken._doc.email
      }
    }

    if ($routeParams.documentId) {
      DocumentService
        .query({documentId: $routeParams.documentId})
        .$promise
        .then(function success(response) {
          vm.doc = response;
          vm.doc.draftDate = new Date(vm.doc.draftDate);
          vm.doc.signDate = new Date(vm.doc.signDate);
          vm.doc.reception.receptionDate = new Date(vm.doc.reception.receptionDate);
          vm.doc.createdAt = new Date(vm.doc.createdAt);
          vm.doc.updatedAt = new Date();
        });
    } else {
      vm.doc = getBaseDoc();
    }

    function getBaseDoc() {
      var data = {
        number: '',
        status: '',
        receiver: {
          type: '',
          organization: '',
          name: ''
        },
        url: '',
        draftDate: new Date(),
        signDate: new Date(),
        entryUser: {
          name: '',
          email: ''
        },
        reception: {
          controlNumber:'',
          receptionDate: new Date(),
          office: '',
          receptionist: '',
          subject: ''
        },
        subject: '',
        content: '',
        createdAt: new Date(),
        updatedAt: new Date()
      };
      data.entryUser.name = vm.currentUser.name;
      data.entryUser.email = vm.currentUser.email;
      return data;
    };

    function flashMessage(message) {
      $mdDialog.show(
        $mdDialog.alert()
          .title('Atención')
          .textContent(message)
          .ariaLabel('Ventana de diálogo')
          .ok('Entendido')
      );
    }

    function isValidDoc() {
      if (!vm.doc) {
        flashMessage('Documento incompleto');
        return false
      }
      if (!vm.doc.receiver.organization) {
        flashMessage('Debe agregar una Dependencia');
        return false;
      }
      if (!vm.doc.receiver.name) {
        flashMessage('Debe agregar un encargado');
        return false;
      }
      if (!DateUtilsService.isValidDate(vm.doc.draftDate)) {
        flashMessage('Fecha de elaboración inválida');
        return false;
      }
      return true;
    }

    function submit() {
      if (isValidDoc()) {
        if (!vm.doc._id) {
          DocumentService
            .save(JSON.stringify(vm.doc))
            .$promise
            .then(function success(response) {
                if (response.success) {
                  vm.id = response.message;
                   vm.item.upload();
                }
                return response;
              }, function error(response) {
                if (response.status === 404) {
                  return 'Recurso no encontrado';
                } else {
                  return 'Error no especificado';
                }
              }
            );
        } else {
          DocumentService
            .update(JSON.stringify(vm.doc))
            .$promise
            .then(function success(response) {
                if (response.success) {
                  vm.id = response.message;
                  if (vm.item._file.name !== vm.doc.url) {
                    vm.item.upload();
                  } else {
                    $location.path(vm.returnPath + vm.id);
                  }
                }
                return response;
              }, function error(response) {
                if (response.status === 404) {
                  return 'Recurso no encontrado';
                } else {
                  return 'Error no especificado';
                }
              }
            );
        }
      } else {
        flashMessage('Error al guardar el documento');
      }
    }
  }
})();
<commit_msg>Minor fixes<commit_after>/*global angular*/
(function() {
  'use strict';

  angular
    .module('docsApp')
    .controller('DocumentController', DocumentController);

  DocumentController.$inject = [
    '$scope',
    '$location',
    '$routeParams',
    '$mdDialog',
    'FileUploader',
    'TokenService',
    'DateUtilsService',
    'ReceiverTypeService',
    'RespondentService',
    'StatusService',
    'DocumentService'
  ];

  function DocumentController(
      $scope,
      $location,
      $routeParams,
      $mdDialog,
      FileUploader,
      TokenService,
      DateUtilsService,
      ReceiverTypeService,
      RespondentService,
      StatusService,
      DocumentService
    ) {
    var vm = this;
    var myDate = new Date();
    vm.uploader = new FileUploader();
    vm.currentUser = getCurrentUser();
    vm.id = '';
    vm.doc = {};
    vm.file = null;
    vm.item = {};
    vm.minDate = new Date(myDate.getFullYear() - 1, 12, 1);
    vm.maxDate = new Date(myDate.getFullYear() + 1, 0, 1);
    vm.receiverTypes = ReceiverTypeService.get();
    vm.respondents = RespondentService.get();
    vm.statusTypes = StatusService.get();
    vm.submit = submit;    vm.insertReturnPath = '';
    vm.returnPath = '/document/view/';
    vm.uploadPath = '/api/document/upload/';

    vm.uploader.onAfterAddingFile = function (item) {
      vm.item = item;
      vm.doc.url = item._file.name;
    }

    vm.uploader.onBeforeUploadItem = function (item) {
      item.url = vm.uploadPath + vm.id;
    }

    vm.uploader.onSuccessItem = function (item, response, status, headers) {
      console.log('Upload success!');
      console.log('item');
      console.log(item);
      console.log('response:');
      console.log(response);
    }

    vm.uploader.onCompleteAll = function () {
      console.log('All done');
      if (vm.id.length > 0) {
        $location.path(vm.returnPath + vm.id);
      }
    }

    function getCurrentUser() {
      var userToken = TokenService.getUserFromToken();
      return {
        name: userToken._doc.name,
        email: userToken._doc.email
      }
    }

    if ($routeParams.documentId) {
      DocumentService
        .query({documentId: $routeParams.documentId})
        .$promise
        .then(function success(response) {
          vm.doc = response;
          vm.doc.draftDate = new Date(vm.doc.draftDate);
          vm.doc.signDate = new Date(vm.doc.signDate);
          vm.doc.reception.receptionDate = new Date(vm.doc.reception.receptionDate);
          vm.doc.createdAt = new Date(vm.doc.createdAt);
          vm.doc.updatedAt = new Date();
        });
    } else {
      vm.doc = getBaseDoc();
    }

    function getBaseDoc() {
      var data = {
        number: 'Sin número',
        status: '',
        receiver: {
          type: '',
          organization: '',
          name: ''
        },
        url: '',
        draftDate: new Date(),
        signDate: new Date(),
        entryUser: {
          name: '',
          email: ''
        },
        reception: {
          controlNumber:'',
          receptionDate: new Date(),
          office: '',
          receptionist: '',
          subject: ''
        },
        subject: '',
        content: '',
        createdAt: new Date(),
        updatedAt: new Date()
      };
      data.entryUser.name = vm.currentUser.name;
      data.entryUser.email = vm.currentUser.email;
      return data;
    };

    function flashMessage(message) {
      $mdDialog.show(
        $mdDialog.alert()
          .title('Atención')
          .textContent(message)
          .ariaLabel('Ventana de diálogo')
          .ok('Entendido')
      );
    }

    function isValidDoc() {
      if (!vm.doc) {
        flashMessage('Documento incompleto');
        return false
      }
      if (!vm.doc.receiver.organization) {
        flashMessage('Debe agregar una Dependencia');
        return false;
      }
      if (!vm.doc.receiver.name) {
        flashMessage('Debe agregar un encargado');
        return false;
      }
      if (!DateUtilsService.isValidDate(vm.doc.draftDate)) {
        flashMessage('Fecha de elaboración inválida');
        return false;
      }
      return true;
    }

    function submit() {
      if (isValidDoc()) {
        if (!vm.doc._id) {
          DocumentService
            .save(JSON.stringify(vm.doc))
            .$promise
            .then(function success(response) {
                if (response.success) {
                  vm.id = response.message;
                   vm.item.upload();
                }
                return response;
              }, function error(response) {
                if (response.status === 404) {
                  return 'Recurso no encontrado';
                } else {
                  return 'Error no especificado';
                }
              }
            );
        } else {
          DocumentService
            .update(JSON.stringify(vm.doc))
            .$promise
            .then(function success(response) {
                if (response.success) {
                  vm.id = response.message;
                  if (vm.item._file.name !== vm.doc.url) {
                    vm.item.upload();
                  } else {
                    $location.path(vm.returnPath + vm.id);
                  }
                }
                return response;
              }, function error(response) {
                if (response.status === 404) {
                  return 'Recurso no encontrado';
                } else {
                  return 'Error no especificado';
                }
              }
            );
        }
      } else {
        // flashMessage('Error al guardar el documento');
      }
    }
  }
})();
<|endoftext|>


<commit_before>var NanoEvents = require('nanoevents')
var assign = require('object-assign')

var SyncError = require('./sync-error')

var connectMessages = require('./messages/connect')
var errorMessages = require('./messages/error')
var pingMessages = require('./messages/ping')
var syncMessages = require('./messages/sync')

var validate = require('./validate')

var BEFORE_AUTH = ['connect', 'connected', 'error']

function syncMappedEvent (sync, action, meta) {
  if (sync.options.outMap) {
    sync.options.outMap(action, meta).then(function (changed) {
      sync.sendSync(changed[0], changed[1])
    })
  } else {
    sync.sendSync(action, meta)
  }
}

/**
 * Base methods for synchronization nodes. Client and server nodes
 * are based on this module.
 *
 * @param {string|number} nodeId Unique current machine name.
 * @param {Log} log Logux log instance to be synchronized.
 * @param {Connection} connection Connection to remote node.
 * @param {object} [options] Synchronization options.
 * @param {object} [options.credentials] Client credentials.
 *                                       For example, access token.
 * @param {authCallback} [options.auth] Function to check client credentials.
 * @param {boolean} [options.fixTime=false] Detect difference between client
 *                                          and server and fix time
 *                                          in synchronized actions.
 * @param {number} [options.timeout=0] Timeout in milliseconds to wait answer
 *                                     before disconnect.
 * @param {number} [options.ping=0] Milliseconds since last message to test
 *                                  connection by sending ping.
 * @param {filter} [options.inFilter] Function to filter actions
 *                                    from remote node. Best place
 *                                    for access control.
 * @param {mapper} [options.inMap] Map function to change remote node’s action
 *                                 before put it to current log.
 * @param {filter} [options.outFilter] Filter function to select actions
 *                                     to synchronization.
 * @param {mapper} [options.outMap] Map function to change action
 *                                  before sending it to remote client.
 * @param {string} [options.subprotocol] Application subprotocol version
 *                                       in SemVer format.
 *
 * @abstract
 * @class
 */
function BaseSync (nodeId, log, connection, options) {
  /**
   * Unique current machine name.
   * @type {string|number}
   *
   * @example
   * console.log(sync.localNodeId + ' is started')
   */
  this.localNodeId = nodeId
  /**
   * Log for synchronization.
   * @type {Log}
   */
  this.log = log
  /**
   * Connection used to communicate to remote node.
   * @type {Connection}
   */
  this.connection = connection
  /**
   * Synchronization options.
   * @type {object}
   */
  this.options = options || { }

  if (this.options.ping && !this.options.timeout) {
    throw new Error('You must set timeout option to use ping')
  }

  /**
   * Is synchronization in process.
   * @type {boolean}
   *
   * @example
   * sync.on('disconnect', () => {
   *   sync.connected //=> false
   * })
   */
  this.connected = false

  /**
   * Did we finish remote node authentication.
   * @type {boolean}
   */
  this.authenticated = false
  this.authenticating = false
  this.unauthenticated = []

  this.timeFix = 0
  this.syncing = 0
  this.received = { }

  /**
   * Latest current log `added` time, which was successfully synchronized.
   * It will be saves in log store.
   * @type {number}
   */
  this.lastSent = 0
  /**
   * Latest remote node’s log `added` time, which was successfully synchronized.
   * It will be saves in log store.
   * @type {number}
   */
  this.lastReceived = 0

  /**
   * Current synchronization state.
   *
   * * `disconnected`: no connection, but no new actions to synchronization.
   * * `wait`: new actions for synchronization but there is no connection.
   * * `connecting`: connection was established and we wait for node answer.
   * * `sending`: new actions was sent, waiting for answer.
   * * `synchronized`: all actions was synchronized and we keep connection.
   *
   * @type {"disconnected"|"wait"|"connecting"|"sending"|"synchronized"}
   *
   * @example
   * sync.on('state', () => {
   *   if (sync.state === 'wait' && sync.state === 'sending') {
   *     console.log('Do not close browser')
   *   }
   * })
   */
  this.state = 'disconnected'

  this.emitter = new NanoEvents()
  this.timeouts = []
  this.throwsError = true

  this.unbind = []
  var sync = this
  this.unbind.push(log.on('add', function (action, meta) {
    sync.onAdd(action, meta)
  }))
  this.unbind.push(connection.on('connecting', function () {
    sync.onConnecting()
  }))
  this.unbind.push(connection.on('connect', function () {
    sync.onConnect()
  }))
  this.unbind.push(connection.on('message', function (message) {
    sync.onMessage(message)
  }))
  this.unbind.push(connection.on('error', function (error) {
    if (error.message === 'Wrong message format') {
      sync.sendError(new SyncError(sync, 'wrong-format', error.received))
    } else {
      sync.error(error)
    }
    sync.connection.disconnect('error')
  }))
  this.unbind.push(connection.on('disconnect', function () {
    sync.onDisconnect()
  }))

  this.lastAddedCache = 0
  this.initializing = this.initialize()
}

BaseSync.prototype = {

  /**
   * Unique name of remote machine.
   * It is undefined until nodes handshake.
   *
   * @type {string|number|undefined}
   *
   * @example
   * console.log('Connected to ' + sync.remoteNodeId)
   */
  remoteNodeId: undefined,

  /**
   * Array with major and minor versions of used protocol.
   * @type {Version}
   *
   * @example
   * if (tool.sync.localProtocol[0] !== 1) {
   *   throw new Error('Unsupported Logux protocol')
   * }
   */
  localProtocol: [0, 1],

  /**
   * Array with major and minor versions of remote node protocol.
   * @type {Version|undefined}
   *
   * @example
   * if (sync.remoteProtocol[1] >= 5) {
   *   useNewAPI()
   * } else {
   *   useOldAPI()
   * }
   */
  remoteProtocol: undefined,

  /**
   * Remote node’s application subprotocol version in SemVer format.
   *
   * It is undefined until nodes handshake. If remote node will not send
   * on handshake its subprotocol, it will be set to `0.0.0`.
   *
   * @type {string|undefined}
   *
   * @example
   * if (semver.satisfies(sync.remoteSubprotocol, '>= 5.0.0') {
   *   useNewAPI()
   * } else {
   *   useOldAPI()
   * }
   */
  remoteSubprotocol: undefined,

  /**
   * Subscribe for synchronization events. It implements nanoevents API.
   * Supported events:
   *
   * * `state`: synchronization state was changed.
   * * `connect`: custom check before node authentication. You can throw
   *              a {@link SyncError} to send error to remote node.
   * * `clientError`: when error was sent to remote node.
   *
   * @param {"state"|"connect"|"clientError"} event The event name.
   * @param {listener} listener The listener function.
   *
   * @return {function} Unbind listener from event.
   *
   * @example
   * sync.on('clientError', error => {
   *   logError(error)
   * })
   */
  on: function on (event, listener) {
    return this.emitter.on(event, listener)
  },

  /**
   * Add one-time listener for synchronization events.
   * See {@link BaseSync#on} for supported events.
   *
   * @param {"state"|"connect"|"clientError"} event The event name.
   * @param {listener} listener The listener function.
   *
   * @return {function} Unbind listener from event.
   *
   * @example
   * sync.once('clientError', () => {
   *   everythingFine = false
   * })
   */
  once: function once (event, listener) {
    return this.emitter.once(event, listener)
  },

  /**
   * Disable throwing a error on error message and create error listener.
   *
   * @param {errorListener} listener The listener function.
   *
   * @return {undefined}
   *
   * @example
   * sync.catch(error => {
   *   console.error(error)
   * })
   */
  catch: function (listener) {
    this.throwsError = false
    this.on('error', listener)
  },

  /**
   * Return Promise until {@link BaseSync#state} will be changed
   * to specific value.
   *
   * @param {string} state The expected synchronization state value.
   *
   * @return {Promise} Promise until specific state.
   *
   * @example
   * sync.waitFor('synchronized').then(() => {
   *   console.log('Everything is synchronized')
   * })
   */
  waitFor: function (state) {
    var sync = this
    return new Promise(function (resolve) {
      var unbind = sync.on('state', function () {
        if (sync.state === state) {
          unbind()
          resolve()
        }
      })
    })
  },

  /**
   * Shut down the connection and unsubscribe from log events.
   *
   * @return {undefined}
   *
   * @example
   * connection.on('disconnect', () => {
   *   server.destroy()
   * })
   */
  destroy: function destroy () {
    if (this.connection.destroy) {
      this.connection.destroy()
    } else if (this.connected) {
      this.connection.disconnect('destroy')
    }
    for (var i = 0; i < this.unbind.length; i++) {
      this.unbind[i]()
    }
  },

  send: function send (msg) {
    if (this.connected) {
      this.delayPing()
      this.connection.send(msg)
    } else {
      var json = JSON.stringify(msg)
      throw new Error('Could not send ' + json + ' to disconnected connection')
    }
  },

  onConnecting: function onConnecting () {
    this.setState('connecting')
  },

  onConnect: function onConnect () {
    this.delayPing()
    this.connected = true
  },

  onDisconnect: function onDisconnect () {
    this.endTimeout()
    if (this.pingTimeout) clearTimeout(this.pingTimeout)
    this.connected = false

    if (this.lastAddedCache > this.lastSent) {
      this.setState('wait')
    } else {
      this.setState('disconnected')
    }
  },

  onMessage: function onMessage (msg) {
    this.delayPing()

    if (!validate(this, msg)) return
    var name = msg[0]

    if (!this.authenticated && BEFORE_AUTH.indexOf(name) === -1) {
      if (this.authenticating) {
        this.unauthenticated.push(msg)
      } else {
        this.sendError(new SyncError(this, 'missed-auth', JSON.stringify(msg)))
      }
      return
    }

    var args = new Array(msg.length - 1)
    for (var i = 1; i < msg.length; i++) {
      args[i - 1] = msg[i]
    }
    this[name + 'Message'].apply(this, args)
  },

  onAdd: function onAdd (action, meta) {
    if (!this.connected) {
      this.setState('wait')
      return
    }
    if (this.lastAddedCache < meta.added) {
      this.lastAddedCache = meta.added
    }

    if (this.received[meta.id.join('\t')]) {
      delete this.received[meta.id.join('\t')]
      return
    }

    if (this.options.outFilter) {
      var sync = this
      this.options.outFilter(action, meta).then(function (result) {
        if (result) syncMappedEvent(sync, action, meta)
      })
    } else {
      syncMappedEvent(this, action, meta)
    }
  },

  syncError: function syncError (type, options, received) {
    var err = new SyncError(this, type, options, received)
    this.error(err)
  },

  error: function error (err) {
    this.emitter.emit('error', err)
    if (this.throwsError) {
      throw err
    }
  },

  setState: function setState (state) {
    if (this.state !== state) {
      this.state = state
      this.emitter.emit('state')
    }
  },

  startTimeout: function startTimeout () {
    if (!this.options.timeout) return

    var ms = this.options.timeout
    var sync = this
    var timeout = setTimeout(function () {
      if (sync.connected) sync.connection.disconnect('timeout')
      sync.syncError('timeout', ms)
    }, ms)

    this.timeouts.push(timeout)
  },

  endTimeout: function endTimeout () {
    if (this.timeouts.length > 0) {
      clearTimeout(this.timeouts.shift())
    }
  },

  delayPing: function delayPing () {
    if (!this.options.ping) return
    if (this.pingTimeout) clearTimeout(this.pingTimeout)

    var sync = this
    this.pingTimeout = setTimeout(function () {
      if (sync.connected) sync.sendPing()
    }, this.options.ping)
  },

  syncSince: function syncSince (lastSynced) {
    var data = []
    var sync = this
    this.log.each({ order: 'added' }, function (action, meta) {
      if (meta.added <= lastSynced) {
        return false
      } else {
        data.push(action, meta)
        return true
      }
    }).then(function () {
      if (!sync.connected) return
      if (data.length > 0) {
        sync.sendSync.apply(sync, data)
      } else {
        sync.setState('synchronized')
      }
    })
  },

  setLastSent: function setLastSent (value) {
    if (this.lastSent < value) this.lastSent = value
    this.log.store.setLastSynced({ sent: value })
  },

  setLastReceived: function setLastReceived (value) {
    if (this.lastReceived < value) this.lastReceived = value
    this.log.store.setLastSynced({ received: value })
  },

  now: function now () {
    return Date.now()
  },

  initialize: function initialize () {
    var sync = this
    return Promise.all([
      this.log.store.getLastSynced(),
      this.log.store.getLastAdded()
    ]).then(function (result) {
      sync.lastSent = result[0].sent
      sync.lastReceived = result[0].received
      sync.lastAddedCache = result[1]

      if (sync.lastAddedCache > sync.lastSent) sync.setState('wait')
      if (sync.connection.connected) sync.onConnect()
    })
  }

}

BaseSync.prototype = assign(BaseSync.prototype,
  errorMessages, connectMessages, pingMessages, syncMessages)

module.exports = BaseSync

/**
 * Logux protocol version.
 *
 * @typedef {number[]} Version
 */

/**
 * @callback errorListener
 * @param {string} error The error description.
 */

/**
 * @callback authCallback
 * @param {object} credentials Remote node credentials.
 * @param {string} nodeId Unique ID of remote sync instance.
 * @return {Promise} Promise with boolean value.
 */

/**
 * @callback filter
 * @param {Action} action New action from log.
 * @param {Meta} meta New action metadata.
 * @return {Promise} Promise with `true` if action should be synchronized
 *                   with remote log.
 */

/**
 * @callback mapper
 * @param {Action} action New action from log.
 * @param {Meta} meta New action metadata.
 * @return {Promise} Promise with array of changed action and changed metadata.
 */
<commit_msg>Add error event to JSDoc<commit_after>var NanoEvents = require('nanoevents')
var assign = require('object-assign')

var SyncError = require('./sync-error')

var connectMessages = require('./messages/connect')
var errorMessages = require('./messages/error')
var pingMessages = require('./messages/ping')
var syncMessages = require('./messages/sync')

var validate = require('./validate')

var BEFORE_AUTH = ['connect', 'connected', 'error']

function syncMappedEvent (sync, action, meta) {
  if (sync.options.outMap) {
    sync.options.outMap(action, meta).then(function (changed) {
      sync.sendSync(changed[0], changed[1])
    })
  } else {
    sync.sendSync(action, meta)
  }
}

/**
 * Base methods for synchronization nodes. Client and server nodes
 * are based on this module.
 *
 * @param {string|number} nodeId Unique current machine name.
 * @param {Log} log Logux log instance to be synchronized.
 * @param {Connection} connection Connection to remote node.
 * @param {object} [options] Synchronization options.
 * @param {object} [options.credentials] Client credentials.
 *                                       For example, access token.
 * @param {authCallback} [options.auth] Function to check client credentials.
 * @param {boolean} [options.fixTime=false] Detect difference between client
 *                                          and server and fix time
 *                                          in synchronized actions.
 * @param {number} [options.timeout=0] Timeout in milliseconds to wait answer
 *                                     before disconnect.
 * @param {number} [options.ping=0] Milliseconds since last message to test
 *                                  connection by sending ping.
 * @param {filter} [options.inFilter] Function to filter actions
 *                                    from remote node. Best place
 *                                    for access control.
 * @param {mapper} [options.inMap] Map function to change remote node’s action
 *                                 before put it to current log.
 * @param {filter} [options.outFilter] Filter function to select actions
 *                                     to synchronization.
 * @param {mapper} [options.outMap] Map function to change action
 *                                  before sending it to remote client.
 * @param {string} [options.subprotocol] Application subprotocol version
 *                                       in SemVer format.
 *
 * @abstract
 * @class
 */
function BaseSync (nodeId, log, connection, options) {
  /**
   * Unique current machine name.
   * @type {string|number}
   *
   * @example
   * console.log(sync.localNodeId + ' is started')
   */
  this.localNodeId = nodeId
  /**
   * Log for synchronization.
   * @type {Log}
   */
  this.log = log
  /**
   * Connection used to communicate to remote node.
   * @type {Connection}
   */
  this.connection = connection
  /**
   * Synchronization options.
   * @type {object}
   */
  this.options = options || { }

  if (this.options.ping && !this.options.timeout) {
    throw new Error('You must set timeout option to use ping')
  }

  /**
   * Is synchronization in process.
   * @type {boolean}
   *
   * @example
   * sync.on('disconnect', () => {
   *   sync.connected //=> false
   * })
   */
  this.connected = false

  /**
   * Did we finish remote node authentication.
   * @type {boolean}
   */
  this.authenticated = false
  this.authenticating = false
  this.unauthenticated = []

  this.timeFix = 0
  this.syncing = 0
  this.received = { }

  /**
   * Latest current log `added` time, which was successfully synchronized.
   * It will be saves in log store.
   * @type {number}
   */
  this.lastSent = 0
  /**
   * Latest remote node’s log `added` time, which was successfully synchronized.
   * It will be saves in log store.
   * @type {number}
   */
  this.lastReceived = 0

  /**
   * Current synchronization state.
   *
   * * `disconnected`: no connection, but no new actions to synchronization.
   * * `wait`: new actions for synchronization but there is no connection.
   * * `connecting`: connection was established and we wait for node answer.
   * * `sending`: new actions was sent, waiting for answer.
   * * `synchronized`: all actions was synchronized and we keep connection.
   *
   * @type {"disconnected"|"wait"|"connecting"|"sending"|"synchronized"}
   *
   * @example
   * sync.on('state', () => {
   *   if (sync.state === 'wait' && sync.state === 'sending') {
   *     console.log('Do not close browser')
   *   }
   * })
   */
  this.state = 'disconnected'

  this.emitter = new NanoEvents()
  this.timeouts = []
  this.throwsError = true

  this.unbind = []
  var sync = this
  this.unbind.push(log.on('add', function (action, meta) {
    sync.onAdd(action, meta)
  }))
  this.unbind.push(connection.on('connecting', function () {
    sync.onConnecting()
  }))
  this.unbind.push(connection.on('connect', function () {
    sync.onConnect()
  }))
  this.unbind.push(connection.on('message', function (message) {
    sync.onMessage(message)
  }))
  this.unbind.push(connection.on('error', function (error) {
    if (error.message === 'Wrong message format') {
      sync.sendError(new SyncError(sync, 'wrong-format', error.received))
    } else {
      sync.error(error)
    }
    sync.connection.disconnect('error')
  }))
  this.unbind.push(connection.on('disconnect', function () {
    sync.onDisconnect()
  }))

  this.lastAddedCache = 0
  this.initializing = this.initialize()
}

BaseSync.prototype = {

  /**
   * Unique name of remote machine.
   * It is undefined until nodes handshake.
   *
   * @type {string|number|undefined}
   *
   * @example
   * console.log('Connected to ' + sync.remoteNodeId)
   */
  remoteNodeId: undefined,

  /**
   * Array with major and minor versions of used protocol.
   * @type {Version}
   *
   * @example
   * if (tool.sync.localProtocol[0] !== 1) {
   *   throw new Error('Unsupported Logux protocol')
   * }
   */
  localProtocol: [0, 1],

  /**
   * Array with major and minor versions of remote node protocol.
   * @type {Version|undefined}
   *
   * @example
   * if (sync.remoteProtocol[1] >= 5) {
   *   useNewAPI()
   * } else {
   *   useOldAPI()
   * }
   */
  remoteProtocol: undefined,

  /**
   * Remote node’s application subprotocol version in SemVer format.
   *
   * It is undefined until nodes handshake. If remote node will not send
   * on handshake its subprotocol, it will be set to `0.0.0`.
   *
   * @type {string|undefined}
   *
   * @example
   * if (semver.satisfies(sync.remoteSubprotocol, '>= 5.0.0') {
   *   useNewAPI()
   * } else {
   *   useOldAPI()
   * }
   */
  remoteSubprotocol: undefined,

  /**
   * Subscribe for synchronization events. It implements nanoevents API.
   * Supported events:
   *
   * * `state`: synchronization state was changed.
   * * `connect`: custom check before node authentication. You can throw
   *              a {@link SyncError} to send error to remote node.
   * * `error`: synchronization error was raised.
   * * `clientError`: when error was sent to remote node.
   *
   * @param {"state"|"connect"|"error"|"clientError"} event The event name.
   * @param {listener} listener The listener function.
   *
   * @return {function} Unbind listener from event.
   *
   * @example
   * sync.on('clientError', error => {
   *   logError(error)
   * })
   */
  on: function on (event, listener) {
    return this.emitter.on(event, listener)
  },

  /**
   * Add one-time listener for synchronization events.
   * See {@link BaseSync#on} for supported events.
   *
   * @param {"state"|"connect"|"error"|"clientError"} event The event name.
   * @param {listener} listener The listener function.
   *
   * @return {function} Unbind listener from event.
   *
   * @example
   * sync.once('clientError', () => {
   *   everythingFine = false
   * })
   */
  once: function once (event, listener) {
    return this.emitter.once(event, listener)
  },

  /**
   * Disable throwing a error on error message and create error listener.
   *
   * @param {errorListener} listener The listener function.
   *
   * @return {undefined}
   *
   * @example
   * sync.catch(error => {
   *   console.error(error)
   * })
   */
  catch: function (listener) {
    this.throwsError = false
    this.on('error', listener)
  },

  /**
   * Return Promise until {@link BaseSync#state} will be changed
   * to specific value.
   *
   * @param {string} state The expected synchronization state value.
   *
   * @return {Promise} Promise until specific state.
   *
   * @example
   * sync.waitFor('synchronized').then(() => {
   *   console.log('Everything is synchronized')
   * })
   */
  waitFor: function (state) {
    var sync = this
    return new Promise(function (resolve) {
      var unbind = sync.on('state', function () {
        if (sync.state === state) {
          unbind()
          resolve()
        }
      })
    })
  },

  /**
   * Shut down the connection and unsubscribe from log events.
   *
   * @return {undefined}
   *
   * @example
   * connection.on('disconnect', () => {
   *   server.destroy()
   * })
   */
  destroy: function destroy () {
    if (this.connection.destroy) {
      this.connection.destroy()
    } else if (this.connected) {
      this.connection.disconnect('destroy')
    }
    for (var i = 0; i < this.unbind.length; i++) {
      this.unbind[i]()
    }
  },

  send: function send (msg) {
    if (this.connected) {
      this.delayPing()
      this.connection.send(msg)
    } else {
      var json = JSON.stringify(msg)
      throw new Error('Could not send ' + json + ' to disconnected connection')
    }
  },

  onConnecting: function onConnecting () {
    this.setState('connecting')
  },

  onConnect: function onConnect () {
    this.delayPing()
    this.connected = true
  },

  onDisconnect: function onDisconnect () {
    this.endTimeout()
    if (this.pingTimeout) clearTimeout(this.pingTimeout)
    this.connected = false

    if (this.lastAddedCache > this.lastSent) {
      this.setState('wait')
    } else {
      this.setState('disconnected')
    }
  },

  onMessage: function onMessage (msg) {
    this.delayPing()

    if (!validate(this, msg)) return
    var name = msg[0]

    if (!this.authenticated && BEFORE_AUTH.indexOf(name) === -1) {
      if (this.authenticating) {
        this.unauthenticated.push(msg)
      } else {
        this.sendError(new SyncError(this, 'missed-auth', JSON.stringify(msg)))
      }
      return
    }

    var args = new Array(msg.length - 1)
    for (var i = 1; i < msg.length; i++) {
      args[i - 1] = msg[i]
    }
    this[name + 'Message'].apply(this, args)
  },

  onAdd: function onAdd (action, meta) {
    if (!this.connected) {
      this.setState('wait')
      return
    }
    if (this.lastAddedCache < meta.added) {
      this.lastAddedCache = meta.added
    }

    if (this.received[meta.id.join('\t')]) {
      delete this.received[meta.id.join('\t')]
      return
    }

    if (this.options.outFilter) {
      var sync = this
      this.options.outFilter(action, meta).then(function (result) {
        if (result) syncMappedEvent(sync, action, meta)
      })
    } else {
      syncMappedEvent(this, action, meta)
    }
  },

  syncError: function syncError (type, options, received) {
    var err = new SyncError(this, type, options, received)
    this.error(err)
  },

  error: function error (err) {
    this.emitter.emit('error', err)
    if (this.throwsError) {
      throw err
    }
  },

  setState: function setState (state) {
    if (this.state !== state) {
      this.state = state
      this.emitter.emit('state')
    }
  },

  startTimeout: function startTimeout () {
    if (!this.options.timeout) return

    var ms = this.options.timeout
    var sync = this
    var timeout = setTimeout(function () {
      if (sync.connected) sync.connection.disconnect('timeout')
      sync.syncError('timeout', ms)
    }, ms)

    this.timeouts.push(timeout)
  },

  endTimeout: function endTimeout () {
    if (this.timeouts.length > 0) {
      clearTimeout(this.timeouts.shift())
    }
  },

  delayPing: function delayPing () {
    if (!this.options.ping) return
    if (this.pingTimeout) clearTimeout(this.pingTimeout)

    var sync = this
    this.pingTimeout = setTimeout(function () {
      if (sync.connected) sync.sendPing()
    }, this.options.ping)
  },

  syncSince: function syncSince (lastSynced) {
    var data = []
    var sync = this
    this.log.each({ order: 'added' }, function (action, meta) {
      if (meta.added <= lastSynced) {
        return false
      } else {
        data.push(action, meta)
        return true
      }
    }).then(function () {
      if (!sync.connected) return
      if (data.length > 0) {
        sync.sendSync.apply(sync, data)
      } else {
        sync.setState('synchronized')
      }
    })
  },

  setLastSent: function setLastSent (value) {
    if (this.lastSent < value) this.lastSent = value
    this.log.store.setLastSynced({ sent: value })
  },

  setLastReceived: function setLastReceived (value) {
    if (this.lastReceived < value) this.lastReceived = value
    this.log.store.setLastSynced({ received: value })
  },

  now: function now () {
    return Date.now()
  },

  initialize: function initialize () {
    var sync = this
    return Promise.all([
      this.log.store.getLastSynced(),
      this.log.store.getLastAdded()
    ]).then(function (result) {
      sync.lastSent = result[0].sent
      sync.lastReceived = result[0].received
      sync.lastAddedCache = result[1]

      if (sync.lastAddedCache > sync.lastSent) sync.setState('wait')
      if (sync.connection.connected) sync.onConnect()
    })
  }

}

BaseSync.prototype = assign(BaseSync.prototype,
  errorMessages, connectMessages, pingMessages, syncMessages)

module.exports = BaseSync

/**
 * Logux protocol version.
 *
 * @typedef {number[]} Version
 */

/**
 * @callback errorListener
 * @param {string} error The error description.
 */

/**
 * @callback authCallback
 * @param {object} credentials Remote node credentials.
 * @param {string} nodeId Unique ID of remote sync instance.
 * @return {Promise} Promise with boolean value.
 */

/**
 * @callback filter
 * @param {Action} action New action from log.
 * @param {Meta} meta New action metadata.
 * @return {Promise} Promise with `true` if action should be synchronized
 *                   with remote log.
 */

/**
 * @callback mapper
 * @param {Action} action New action from log.
 * @param {Meta} meta New action metadata.
 * @return {Promise} Promise with array of changed action and changed metadata.
 */
<|endoftext|>


<commit_before>// actions
let actionCache = {}

const isObject = (item) => typeof item === 'object' && !Array.isArray(item) && item !== null
const toSpaces = (key) => key.replace(/(?:^|\.?)([A-Z])/g, (x, y) => ' ' + y.toLowerCase()).replace(/^ /, '')

export function createAction (type, payloadCreator) {
  if (actionCache[type]) {
    return actionCache[type]
  }

  const action = (...payloadArgs) => ({
    type: type,
    payload: typeof payloadCreator === 'function'
      ? payloadCreator(...payloadArgs)
      : isObject(payloadCreator)
        ? payloadCreator
        : { value: payloadCreator }
  })
  action.toString = () => type

  actionCache[type] = action

  return action
}

export function createActions (input, output) {
  if (!input.actions) {
    return
  }

  const path = output.path
  const payloadCreators = input.actions(input)

  // remove scenes from path
  const pathString = (path[0] === 'scenes' ? path.slice(1) : path).join('.')

  Object.keys(payloadCreators).forEach(key => {
    const type = `${toSpaces(key)} (${pathString})`
    output.actions[key] = createAction(type, payloadCreators[key])
  })
}
<commit_msg>export action type creator<commit_after>// actions
let actionCache = {}

const isObject = (item) => typeof item === 'object' && !Array.isArray(item) && item !== null
const toSpaces = (key) => key.replace(/(?:^|\.?)([A-Z])/g, (x, y) => ' ' + y.toLowerCase()).replace(/^ /, '')

export function createActionType (key, path) {
  // remove 'scenes.' from the path
  const pathString = (path[0] === 'scenes' ? path.slice(1) : path).join('.')
  return `${toSpaces(key)} (${pathString})`
}

export function createAction (type, payloadCreator) {
  if (actionCache[type]) {
    return actionCache[type]
  }

  const action = (...payloadArgs) => ({
    type: type,
    payload: typeof payloadCreator === 'function'
      ? payloadCreator(...payloadArgs)
      : isObject(payloadCreator)
        ? payloadCreator
        : { value: payloadCreator }
  })
  action.toString = () => type

  actionCache[type] = action

  return action
}

export function createActions (input, output) {
  if (!input.actions) {
    return
  }

  const path = output.path
  const payloadCreators = input.actions(input)

  Object.keys(payloadCreators).forEach(key => {
    output.actions[key] = createAction(createActionType(key, path), payloadCreators[key])
  })
}
<|endoftext|>


<commit_before>require(["jquery", "jquery.gridster"], function($, gridster) {
  var g = $("#notebook-panels");
  var scrollWidth = 15;
  var w = ($(document.body).width() - scrollWidth) * (3.0 / 12);
  var m = 10;
  var nbCols = 2;
  var b = (w - (2 * nbCols)*10)/2

  var ul = $("#notebook-panels .gridster > ul");

  var site = $("#site");
  var nb = $("#notebook");
  var sb = $("#sidebar");
  var hh = $("#header").height();
  function sticky_relocate() {
    if (nb.is(":visible")) {
      var t = nb.offset().top;
      if (t < 0) {
        sb.css("top", (Math.abs(t)+hh)+"px");
      } else if (t < hh) {
        sb.css("top", (hh-t)+"px");
      } else {
        sb.css("top", "20px");
      }
    }
  }

  site.scroll(sticky_relocate);

  ul.gridster({
    max_cols: nbCols,
    widget_margins: [m, m],
    widget_base_dimensions: [b, 250],
    max_sizex: 2,
    helper: 'clone',
    resize: {
      enabled: true
    }
  });
});

require(["jquery", "underscore", "base/js/events", "knockout"], function($, _, events, ko) {
  // http://lions-mark.com/jquery/scrollTo/
  $.fn.scrollTo = function( target, options, callback ){
    if(typeof options == 'function' && arguments.length == 2){ callback = options; options = target; }
    var settings = $.extend({
      scrollTarget  : target,
      offsetTop     : 50,
      duration      : 500,
      easing        : 'swing'
    }, options);
    return this.each(function(){
      var scrollPane = $(this);
      var scrollTarget = (typeof settings.scrollTarget == "number") ? settings.scrollTarget : $(settings.scrollTarget);
      var scrollY = (typeof scrollTarget == "number") ? scrollTarget : scrollTarget.offset().top + scrollPane.scrollTop() - parseInt(settings.offsetTop);
      scrollPane.animate({scrollTop : scrollY }, parseInt(settings.duration), settings.easing, function(){
        if (typeof callback == 'function') { callback.call(this); }
      });
    });
  };

  var td = $("#termDefinitions");
  if (!td.find("table").length) {
    function viewModel() {
      var self = this;
      self.definitions = {};
      self.definitions.data = ko.observableArray([]);
      self.clearDefinitions = function() {
        self.definitions.data.remove(function(e) { return true });
      };
      self.addDefinition = function(def) {
        self.definitions.data.remove(function(e) { return e.name == def.name;});
        self.definitions.data.push(def);
      };
      self.hightlightCell = function() {
        var cell = $("div.cell[data-cell-id='"+this.cell+"']");
        cell.addClass("alert alert-info");

        $('#site').scrollTo(cell, { duration: 300, offsetTop: 200 });

        setTimeout(function() {
          cell.removeClass("alert alert-info")
        }, 800);
      };
    };
    var model = new viewModel();

    var tbl = $('
'+
      '
'+
      '
Name	Type
'+
      '
'+
      '
'+
      '
'+
      '            	'+
      '            	'+
      '
'+
      '
'+
      '
')

    ko.applyBindings(model, tbl.get(0));
    td.append(tbl);

    events.on('kernel_restarting.Kernel', function(e, c) {
      // clear sidebar on kernel restart
      // reset term definitions
      model.clearDefinitions();
      // clear old progressbar & link to spark UI
      $('#spark-ui-link-container, #all-jobs-progress-bar').html('');
    });

    events.on('kernel_ready.Kernel', function(e, c) {
      var kernel = c.kernel;
      console.log("kernel", kernel);

      kernel.events.on("new.Definition", function(e, c) {
        console.log("new def", c);
        if (c.term || c.type) {
          model.addDefinition({name: c.term || c.type, type: c.tpe, cell: c.cell});
        }
      });
    });
  }
});
<commit_msg>Fix sidebar so notebook doesnt scroll forever<commit_after>require(["jquery", "jquery.gridster"], function($, gridster) {
  var g = $("#notebook-panels");
  var scrollWidth = 15;
  var w = ($(document.body).width() - scrollWidth) * (3.0 / 12);
  var m = 10;
  var nbCols = 2;
  var b = (w - (2 * nbCols)*10)/2

  var ul = $("#notebook-panels .gridster > ul");

  var site = $("#site");
  var nb = $("#notebook");
  var sb = $("#sidebar");
  var hh = $("#header").height();
  function sticky_relocate() {
    if (nb.is(":visible")) {
      var t = nb.offset().top;
      if (t < 0) {
        // allow to scroll the part of notebook which don't fit into window
        // otherwise the sidebar would make the window scrollable forever
        var maxOffset = Math.max(hh + nb.height() - $(window).height(), 0);
        var offset = Math.min(maxOffset, Math.abs(t) + hh);
        sb.css("top", offset+"px");
      } else if (t < hh) {
        sb.css("top", (hh-t)+"px");
      } else {
        sb.css("top", "20px");
      }
    }
  }

  site.scroll(sticky_relocate);

  ul.gridster({
    max_cols: nbCols,
    widget_margins: [m, m],
    widget_base_dimensions: [b, 250],
    max_sizex: 2,
    helper: 'clone',
    resize: {
      enabled: true
    }
  });
});

require(["jquery", "underscore", "base/js/events", "knockout"], function($, _, events, ko) {
  // http://lions-mark.com/jquery/scrollTo/
  $.fn.scrollTo = function( target, options, callback ){
    if(typeof options == 'function' && arguments.length == 2){ callback = options; options = target; }
    var settings = $.extend({
      scrollTarget  : target,
      offsetTop     : 50,
      duration      : 500,
      easing        : 'swing'
    }, options);
    return this.each(function(){
      var scrollPane = $(this);
      var scrollTarget = (typeof settings.scrollTarget == "number") ? settings.scrollTarget : $(settings.scrollTarget);
      var scrollY = (typeof scrollTarget == "number") ? scrollTarget : scrollTarget.offset().top + scrollPane.scrollTop() - parseInt(settings.offsetTop);
      scrollPane.animate({scrollTop : scrollY }, parseInt(settings.duration), settings.easing, function(){
        if (typeof callback == 'function') { callback.call(this); }
      });
    });
  };

  var td = $("#termDefinitions");
  if (!td.find("table").length) {
    function viewModel() {
      var self = this;
      self.definitions = {};
      self.definitions.data = ko.observableArray([]);
      self.clearDefinitions = function() {
        self.definitions.data.remove(function(e) { return true });
      };
      self.addDefinition = function(def) {
        self.definitions.data.remove(function(e) { return e.name == def.name;});
        self.definitions.data.push(def);
      };
      self.hightlightCell = function() {
        var cell = $("div.cell[data-cell-id='"+this.cell+"']");
        cell.addClass("alert alert-info");

        $('#site').scrollTo(cell, { duration: 300, offsetTop: 200 });

        setTimeout(function() {
          cell.removeClass("alert alert-info")
        }, 800);
      };
    };
    var model = new viewModel();

    var tbl = $('
'+
      '
'+
      '
Name	Type
'+
      '
'+
      '
'+
      '
'+
      '            	'+
      '            	'+
      '
'+
      '
'+
      '
')

    ko.applyBindings(model, tbl.get(0));
    td.append(tbl);

    events.on('kernel_restarting.Kernel', function(e, c) {
      // clear sidebar on kernel restart
      // reset term definitions
      model.clearDefinitions();
      // clear old progressbar & link to spark UI
      $('#spark-ui-link-container, #all-jobs-progress-bar').html('');
    });

    events.on('kernel_ready.Kernel', function(e, c) {
      var kernel = c.kernel;
      console.log("kernel", kernel);

      kernel.events.on("new.Definition", function(e, c) {
        console.log("new def", c);
        if (c.term || c.type) {
          model.addDefinition({name: c.term || c.type, type: c.tpe, cell: c.cell});
        }
      });
    });
  }
});
<|endoftext|>


<commit_before>'use strict';

angular.module('myApp').controller('ViewEventCtrl',
  ['$scope', '$http', 'BASE_MAP', 'currentUserService', 'myApiService', 'ErrorService',
  function ($scope, $http, BASE_MAP, currentUserService, myApiService, ErrorService) {
    var event = _myInit.event;
    console.log("Event", event);

    $scope.event = event;

    $scope.map = _.extend(BASE_MAP, {
      center: {
        latitude: event.place.latitude,
        longitude: event.place.longitude
      },
      zoom: 16
    });

    function init() {
      var curUserId = currentUserService.userId;
      var isPart = _.find(event.participants, function(partId) {
        return partId === curUserId;
      });
      changeParticipation(isPart);
    }

    function changeParticipation(isPart) {
      if (isPart) {
        $scope.isPart = true;
      } else {
        $scope.isPart = false;
      }
    }

    $scope.participate = function() {
      var $partBtn = $('#partBtn');
      $partBtn.attr('disabled', 'disabled');

      var params = {eventId: event._id, act: $scope.isPart ? 'remove' : 'add'};
      $http({method: 'POST', url: myApiService.buildUrl('/events/participation'), params: params}).
        success(function(data, status, headers, config) {
          $partBtn.removeAttr('disabled');  // FIXME controller shouldn't modify DOM. It's directive's responsibility
          changeParticipation(data.status === 'added');
          $http({method: 'GET', url: myApiService.buildUrl('/events/findById'), params: {id: $scope.event._id}}).
            success(function(res) {
              $scope.event = res.event;
            });
        }).
        error(function(data, status, headers, config) {
          $partBtn.removeAttr('disabled');
          changeParticipation(false);
          var msg = 'Не удалось принять участие. Повторите попытку позже. ' + (data.error ? data.error : data);
          console.error(msg, data);
          ErrorService.alert(msg);
        });
    };

    init();
  }]);<commit_msg>Refactor boilerplate.<commit_after>'use strict';

angular.module('myApp').controller('ViewEventCtrl',
  ['$scope', '$http', 'BASE_MAP', 'currentUserService', 'myApiService', 'ErrorService',
  function ($scope, $http, BASE_MAP, currentUserService, myApiService, ErrorService) {
    var event = _myInit.event;
    console.log("Event", event);

    $scope.event = event;

    $scope.map = _.extend(BASE_MAP, {
      center: {
        latitude: event.place.latitude,
        longitude: event.place.longitude
      },
      zoom: 16
    });

    function init() {
      var curUserId = currentUserService.userId;
      var isPart = _.find(event.participants, function(partId) {
        return partId === curUserId;
      });
      changeParticipation(isPart);
    }

    function changeParticipation(isPart) {
      $scope.isPart = isPart;
    }

    $scope.participate = function() {
      var $partBtn = $('#partBtn');
      $partBtn.attr('disabled', 'disabled');

      var params = {eventId: event._id, act: $scope.isPart ? 'remove' : 'add'};
      $http({method: 'POST', url: myApiService.buildUrl('/events/participation'), params: params}).
        success(function(data, status, headers, config) {
          $partBtn.removeAttr('disabled');  // FIXME controller shouldn't modify DOM. It's directive's responsibility
          changeParticipation(data.status === 'added');
          $http({method: 'GET', url: myApiService.buildUrl('/events/findById'), params: {id: $scope.event._id}}).
            success(function(res) {
              $scope.event = res.event;
            });
        }).
        error(function(data, status, headers, config) {
          $partBtn.removeAttr('disabled');
          changeParticipation(false);
          var msg = 'Не удалось принять участие. Повторите попытку позже. ' + (data.error ? data.error : data);
          console.error(msg, data);
          ErrorService.alert(msg);
        });
    };

    init();
  }]);<|endoftext|>


<commit_before>import React from "react";
import {PropTypes as T} from 'prop-types';
import {Grid, Row, Col} from 'react-bootstrap';
import IconButton from 'material-ui/IconButton';
import Close from 'material-ui/svg-icons/action/highlight-off';
import Checkbox from 'material-ui/Checkbox';
import {RadioButton, RadioButtonGroup} from 'material-ui/RadioButton';
import ActionFavorite from 'material-ui/svg-icons/action/favorite';
import ActionFavoriteBorder from 'material-ui/svg-icons/action/favorite-border';
import TextField from 'material-ui/TextField';
import StringSimilarity from 'string-similarity';
import RaisedButton from 'material-ui/RaisedButton';
import Swal from 'sweetalert';

const colors = [
  'Red',
  'Orange',
  'Yellow',
  'Green',
  'Blue',
  'Purple',
  'Black',
  'White',
];

const styles = {
  buttonClose : {
    position: 'absolute',
    top: '0',
    right: '0',
    margin: '15px',
    height: '100px',
    width: '100px'
  },
  iconClose : {
    color: 'white',
    height: '80px',
    width: '80px'
  },
  checkbox: {
    color: 'white',
    width: 'auto'
  },
  checkboxLabel: {
    color: 'white',
    width: 'auto'
  },
  checkboxIcon: {
    color: 'white'
  }
};

export default class PokeSearch extends React.PureComponent {
    constructor(props) {
        super(props);
    }

    getPokemonsByQuery = (arr, pokemonName) => {
        return arr.filter(pokemon => StringSimilarity.compareTwoStrings(pokemon.name, pokemonName) > 0.5);
    }

    getPokemonsByFilter = (arr) => {
        let pokemonsByFilter = [];

        arr.forEach(
            (pokemon) => {
                if(pokemon.type) {
                    pokemon.type.forEach(
                        (pokemonType) => {
                            if(this.props.pokesearch.searchedParams.pokemonType.length !== 0) {
                                this.props.pokesearch.searchedParams.pokemonType.forEach(
                                    (searchedParamsType) => {
                                        if(pokemonType.nom_type === searchedParamsType && pokemonsByFilter.indexOf(pokemon) === -1) {
                                            pokemonsByFilter.push(pokemon);
                                        }
                                    }
                                )
                            }
                        }
                    )
                }
            }
        )

        return pokemonsByFilter;
    }

    renderTypes(thisP, thisK) {
        return (

              <Checkbox
                checkedIcon={<ActionFavorite />}
                uncheckedIcon={<ActionFavoriteBorder style={{fill: 'white'}} />}
                label={thisP.name_type}
                labelStyle={{
                    backgroundColor: thisP.color,
                    width: 'auto',
                    color: 'white',
                    borderBottomLeftRadius: '10px',
                    borderTopRightRadius: '10px',
                    fontSize: '11px',
                    minWidth: '80px',
                    textAlign: 'center'
                }}
                onCheck={
                    (event, isInputChecked) => {
                        if(isInputChecked) {
                            if(this.props.pokesearch.searchedParams.pokemonType.indexOf(thisP.name_type) === -1) {
                                this.props.setSearchedType(thisP.name_type);
                            }
                        } else {
                                this.props.removeSearchedParamsType(thisP.name_type);
                        }
                    }
                }
                iconStyle={styles.checkboxIcon}
                style={styles.checkbox}
              />

        )
    }

    render () {
        return (

            <IconButton onClick={this.props.toggleSearch} style={styles.buttonClose} iconStyle={styles.iconClose} children={<Close/>}/>
            <Grid>
              <Row>
                <Col md={12} className="search-content">

Tape le nom dun Pokémon et appuies sur entrée

                  <input
                      onChange={(event) => {
                        if(event.target.value) {
                          this.props.setSearchedQuery(event.target.value);
                        } else {
                          this.props.resetSearchedParams();
                        }
                      }}
                      className="search-input"
                      type="text"
                      placeholder="Rechercher"
                  />

                      Types :
                      {
                          (this.props.types.all.map((thisP, thisKey) => this.renderTypes(thisP, thisKey)))
                      }

                      <RaisedButton
                        target="_blank"
                        label="Go!"
                        style={{margin: '15px'}}
                        labelColor="#ffffff"
                        onTouchTap={
                            () => {
                                if(this.props.pokesearch.searchedParams.pokemonType && this.props.pokesearch.searchedParams.query === null) {
                                    this.props.setSearchedPokemons(this.getPokemonsByFilter(this.props.pokemons.all));
                                }

                                if(this.props.pokesearch.searchedParams.pokemonType.length === 0 && this.props.pokesearch.searchedParams.query) {
                                    this.props.setSearchedPokemons(this.getPokemonsByQuery(this.props.pokemons.all, this.props.pokesearch.searchedParams.query));
                                }

                                if(this.props.pokesearch.searchedParams.pokemonType.length !== 0 && this.props.pokesearch.searchedParams.query) {
                                    this.props.setSearchedPokemons(this.getPokemonsByFilter(this.getPokemonsByQuery(this.props.pokemons.all, this.props.pokesearch.searchedParams.query)));
                                }
                                if(this.props.pokesearch.searchedParams.pokemonType.length === 0 && this.props.pokesearch.searchedParams.query === null) {
                                    Swal("Oops...", "Vous n'avez rien renseigné dans la recherche!", "error");
                                } else {
                                    this.props.closeSearch();
                                }
                            }
                        }
                        backgroundColor="#a4c639"
                      />

                </Col>
              </Row>
            </Grid>

        )
    }
}
<commit_msg>change message for UX<commit_after>import React from "react";
import {PropTypes as T} from 'prop-types';
import {Grid, Row, Col} from 'react-bootstrap';
import IconButton from 'material-ui/IconButton';
import Close from 'material-ui/svg-icons/action/highlight-off';
import Checkbox from 'material-ui/Checkbox';
import {RadioButton, RadioButtonGroup} from 'material-ui/RadioButton';
import ActionFavorite from 'material-ui/svg-icons/action/favorite';
import ActionFavoriteBorder from 'material-ui/svg-icons/action/favorite-border';
import TextField from 'material-ui/TextField';
import StringSimilarity from 'string-similarity';
import RaisedButton from 'material-ui/RaisedButton';
import Swal from 'sweetalert';

const colors = [
  'Red',
  'Orange',
  'Yellow',
  'Green',
  'Blue',
  'Purple',
  'Black',
  'White',
];

const styles = {
  buttonClose : {
    position: 'absolute',
    top: '0',
    right: '0',
    margin: '15px',
    height: '100px',
    width: '100px'
  },
  iconClose : {
    color: 'white',
    height: '80px',
    width: '80px'
  },
  checkbox: {
    color: 'white',
    width: 'auto'
  },
  checkboxLabel: {
    color: 'white',
    width: 'auto'
  },
  checkboxIcon: {
    color: 'white'
  }
};

export default class PokeSearch extends React.PureComponent {
    constructor(props) {
        super(props);
    }

    getPokemonsByQuery = (arr, pokemonName) => {
        return arr.filter(pokemon => StringSimilarity.compareTwoStrings(pokemon.name, pokemonName) > 0.5);
    }

    getPokemonsByFilter = (arr) => {
        let pokemonsByFilter = [];

        arr.forEach(
            (pokemon) => {
                if(pokemon.type) {
                    pokemon.type.forEach(
                        (pokemonType) => {
                            if(this.props.pokesearch.searchedParams.pokemonType.length !== 0) {
                                this.props.pokesearch.searchedParams.pokemonType.forEach(
                                    (searchedParamsType) => {
                                        if(pokemonType.nom_type === searchedParamsType && pokemonsByFilter.indexOf(pokemon) === -1) {
                                            pokemonsByFilter.push(pokemon);
                                        }
                                    }
                                )
                            }
                        }
                    )
                }
            }
        )

        return pokemonsByFilter;
    }

    renderTypes(thisP, thisK) {
        return (

              <Checkbox
                checkedIcon={<ActionFavorite />}
                uncheckedIcon={<ActionFavoriteBorder style={{fill: 'white'}} />}
                label={thisP.name_type}
                labelStyle={{
                    backgroundColor: thisP.color,
                    width: 'auto',
                    color: 'white',
                    borderBottomLeftRadius: '10px',
                    borderTopRightRadius: '10px',
                    fontSize: '11px',
                    minWidth: '80px',
                    textAlign: 'center'
                }}
                onCheck={
                    (event, isInputChecked) => {
                        if(isInputChecked) {
                            if(this.props.pokesearch.searchedParams.pokemonType.indexOf(thisP.name_type) === -1) {
                                this.props.setSearchedType(thisP.name_type);
                            }
                        } else {
                                this.props.removeSearchedParamsType(thisP.name_type);
                        }
                    }
                }
                iconStyle={styles.checkboxIcon}
                style={styles.checkbox}
              />

        )
    }

    render () {
        return (

            <IconButton onClick={this.props.toggleSearch} style={styles.buttonClose} iconStyle={styles.iconClose} children={<Close/>}/>
            <Grid>
              <Row>
                <Col md={12} className="search-content">

Tape le nom d'un Pokémon et clique sur Go!

                  <input
                      onChange={(event) => {
                        if(event.target.value) {
                          this.props.setSearchedQuery(event.target.value);
                        } else {
                          this.props.resetSearchedParams();
                        }
                      }}
                      className="search-input"
                      type="text"
                      placeholder="Rechercher"
                  />

                      Types :
                      {
                          (this.props.types.all.map((thisP, thisKey) => this.renderTypes(thisP, thisKey)))
                      }

                      <RaisedButton
                        target="_blank"
                        label="Go!"
                        style={{margin: '15px'}}
                        labelColor="#ffffff"
                        onTouchTap={
                            () => {
                                if(this.props.pokesearch.searchedParams.pokemonType && this.props.pokesearch.searchedParams.query === null) {
                                    this.props.setSearchedPokemons(this.getPokemonsByFilter(this.props.pokemons.all));
                                }

                                if(this.props.pokesearch.searchedParams.pokemonType.length === 0 && this.props.pokesearch.searchedParams.query) {
                                    this.props.setSearchedPokemons(this.getPokemonsByQuery(this.props.pokemons.all, this.props.pokesearch.searchedParams.query));
                                }

                                if(this.props.pokesearch.searchedParams.pokemonType.length !== 0 && this.props.pokesearch.searchedParams.query) {
                                    this.props.setSearchedPokemons(this.getPokemonsByFilter(this.getPokemonsByQuery(this.props.pokemons.all, this.props.pokesearch.searchedParams.query)));
                                }
                                if(this.props.pokesearch.searchedParams.pokemonType.length === 0 && this.props.pokesearch.searchedParams.query === null) {
                                    Swal("Oops...", "Vous n'avez rien renseigné dans la recherche!", "error");
                                } else {
                                    this.props.closeSearch();
                                }
                            }
                        }
                        backgroundColor="#a4c639"
                      />

                </Col>
              </Row>
            </Grid>

        )
    }
}
<|endoftext|>


<commit_before>/* global app:true, io:false */

var socket;
var myname;
var clock_socket;
var currenttime;
var selected_block_time;

var width = 900,
	height = 300,
	cellWidth = 60,
	cellHeight = 58, // cell size
	gapWidth = 12,
	gapHeight = 16,
	Dy = 80;

var hour = d3.time.format("%I"),
	minute = d3.time.format("%M"),
	month = d3.time.format("%b"),
	weekday = d3.time.format("%a"),
	date = d3.time.format("%d"),
	ampm = d3.time.format("%p"),
	format = d3.time.format("%b/%d %H:%M%p");

(function() {
  'use strict';

  var clockbar = $('#clock_bar');
  var myClock;
  function myTimer(){
		// >>>>>> socket: look clock
		clock_socket.emit('lookclock');
  }
  clock_socket = io.connect('http://171.65.102.132:3006');

  clock_socket.on('server_clock', function(data){
  	var str = data.split(":");
  	if(str[1]=='00'){
  		if((str[0]=="2")||(str[0]=="5")) {
  			callBlocks(currenttime);
  		}
  	}
  	if(str[0]=="0"){
  		clockbar.html(""+data+"");
  	}
  	else{
  		clockbar.html(""+data+"");
  	}
  });

  clock_socket.on('connect', function() {
	console.log("Clock connected!");
	myClock=setInterval(function(){myTimer()},500);
  });

  clock_socket.on('disconnect', function() {
	console.log('clock lost');
  });

  var blockdata = [];
  var infobox;
  var previewbox;

  var callBlocks = function(ticket){
	// +- 1 hour blocks range
	var beginT = d3.time.hour.floor(ticket);
	beginT = d3.time.hour.offset(beginT, -1);
	var endT = d3.time.hour.offset(beginT, 3);
	console.log(beginT);
	console.log(endT);
	socket.emit('/timeline/#callblocks', { begintime: beginT, endtime: endT});
	}

  var draw = function(blockdata){
    document.getElementById("btn_close").style.display="none"
    d3.select("svg")
       .remove();
	var tip = d3.tip()
		.attr('class', 'd3-tip')
		.direction('e')
		.offset([0,10])
		.html(function(d) {
			return "time: "+d.time;
		});

	var svg = d3.select("#d3Area").append("svg")
		.attr("width", width)
		.attr("height", height)
		.append("g")
		.attr("transform", "translate(4, 4)");

	svg.call(tip);

	var block = svg.selectAll(".block")
		.data(blockdata)
	.enter().append("g")
		.attr("class", "block")
		.attr("transform", function (d,i)
		{
			//var dx = (i-i%12)/12*(cellWidth+gapWidth);
			//var dy =  i%12 * (cellHeight+gapHeight);
			var dx = i%12 * (cellWidth+gapWidth);
			var dy = (i-i%12)/12*(cellHeight+gapHeight);
			return "translate(" + dx + ","+ dy + ")";
		})
		.on('mouseover', tip.show)
		.on('mouseout', tip.hide);

	block.append("rect")
		.attr("class", function (d)
		{
			var class_name;
			if (d.username==myname){
				class_name="my-block";
			}else{
				class_name="not-my-block";
			}

			if (d.past=="1"){
				class_name=class_name+" block-past";
			}else{
				if (d.current=="1"){
					class_name=class_name+" block-current";
				}else{
					class_name=class_name+" block-future"
				}
			}

			return class_name;
		})
		.attr("width", cellWidth)
		.attr("height", cellHeight)
		.attr("locked", function (d){
			if (d.lock=="1"){
				return true;
			}else{
				return false
			}
		})
		.attr("mine", function (d){
			if (d.username==myname){
				return true;
			}else{
				return false
			}
		})
		.attr("past", function (d){
			if (d.past=="1"){
				return true;
			}else{
				return false
			}
		})
		.attr("current", function (d){
			if (d.current=="1"){
				return true;
			}else{
				return false
			}
		})
		.on('mouseover', tip.show)
		.on('mouseout', tip.hide)
		.on('click', mouseclick);

	block.append("text")
		.attr("class", function (d)
		{
			var class_name;
			if (d.username==myname){
				class_name="my-block-name";
			}else{
				class_name="not-my-block-name";
			}
			return class_name;
		})
		.attr("x",10)
		.attr("y",14)
		.attr("dy", ".3em")
		.text(function(d) {
			var h = d.time.getHours();
			var ampm = (h<12 ? "a":"p");
			//h=("0" + h%12).slice(-2);
			h=(h%12);
			if(h==0){h="12";}
			var m = d.time.getMinutes();
			m=("0" + m).slice(-2);
			return h+":"+m+ampm;
		})
		.on('mouseover', tip.show)
		.on('mouseout', tip.hide);
  }

  function mouseclick(d,i){
	document.getElementById("btn_enter").disabled = true;
    document.getElementById("btn_access").disabled = true;
    document.getElementById("btn_reserve").disabled = true;
    document.getElementById("btn_pattern").disabled = true;

  	// reset to default layout
  	d3.selectAll(".block rect").transition().duration(1000)
  		.attr("width", cellWidth)
  		.attr("height", cellHeight);

  	d3.selectAll(".block").transition().duration(1000)
  		.attr("transform", function (d,i)
		{
			var dx = i%12 * (cellWidth+gapWidth);
			var dy = Dy+(i-i%12)/12*(cellHeight+gapHeight);
			return "translate(" + dx + ","+ dy + ")";
		});

  	var data;
	d3.select(this.parentNode).transition().duration(1000)
		.attr("transform", function (d)
		{
			data = d;
			var dx = i%12 * (cellWidth+gapWidth);
			var dy = 0;
			return "translate(" + dx + ","+ dy + ")";
		});
	d3.select(this.parentNode).transition().duration(1000)
		.attr("transform", function (d)
		{
			data = d;
			var dx = i%12 * (cellWidth+gapWidth);
			var dy = 8;
			return "translate(" + dx + ","+ dy + ")";
		});
	// expand the selected block*/
  	//d3.select(this).transition().duration(1000)
    //    .attr("width", (cellWidth+gapWidth)*4)
    //    .attr("height", (cellHeight+gapHeight)/2);

    // switch(this.getAttribute("class"))
//     {
//     	case "block-locked":
//     		document.getElementById("btn_enter").disabled = true;
//     		document.getElementById("btn_access").disabled = false;
//     		document.getElementById("btn_reserve").disabled = true;
//     		document.getElementById("btn_pattern").disabled = true;
//     		break;
//     	case "block-current":
//     		document.getElementById("btn_enter").disabled = false;
//     		document.getElementById("btn_access").disabled = true;
//     		document.getElementById("btn_reserve").disabled = true;
//     		document.getElementById("btn_pattern").disabled = true;
//     		break;
//     	case "block-default":
//     		document.getElementById("btn_enter").disabled = true;
//     		document.getElementById("btn_access").disabled = true;
//     		document.getElementById("btn_reserve").disabled = false;
//     		document.getElementById("btn_pattern").disabled = false;
//     		break;
//     }
	console.log(this.getAttribute("class"));
	console.log(this.getAttribute("mine"));
	console.log(this.getAttribute("past"));
	console.log(this.getAttribute("locked"));
	if(this.getAttribute("mine")==true) {
		if(this.getAttribute("past")==true) {
			document.getElementById("btn_enter").disabled = true;
    		document.getElementById("btn_access").disabled = false;
    		document.getElementById("btn_reserve").disabled = true;
    		document.getElementById("btn_pattern").disabled = true;
		}else{
			if(this.getAttribute("current")) {
				document.getElementById("btn_enter").disabled = false;
    			document.getElementById("btn_access").disabled = true;
    			document.getElementById("btn_reserve").disabled = true;
    			document.getElementById("btn_pattern").disabled = true;
			}else{
				document.getElementById("btn_enter").disabled = true;
    			document.getElementById("btn_access").disabled = true;
    			document.getElementById("btn_reserve").disabled = true;
    			document.getElementById("btn_pattern").disabled = false;
			}
		}
	}else{
		if(this.getAttribute("locked")==true) {
			console.log("this is locked block");
		}else{
			document.getElementById("btn_enter").disabled = true;
    		document.getElementById("btn_access").disabled = true;
    		document.getElementById("btn_reserve").disabled = false;
    		document.getElementById("btn_pattern").disabled = true;
		}
	}

	preloader();

    // preloading for block preview
    function preloader()
	{
		if(data.image<0){
			document.getElementById("btn_close").style.display="none";
			previewbox.html("[no preview]");
			writeInfo();
		}
		else
		{
			getPreview("http://171.65.102.132:3001/"+data.image, function(image) {
            	previewbox.html(image);
            	writeInfo();
            });
        }

    	function getPreview(path, callback) {
    		document.getElementById("btn_close").style.display="block";
            var image = new Image;
            image.id = "img_preview";
            image.src = path;
            image.setAttribute("class","img-responsive img-thumbnail");
            image.setAttribute("alt","Responsive image");
            image.onload = function() {
                callback(image);
            };
        }
	}

	// write block info to infobox
    function writeInfo(){
		var strInfo;
		strInfo = ""+data.time+"";
		strInfo = concatNewline(strInfo,"block time:"+data.blocktime);
		if(data.user_id<0){
			strInfo = concatNewline(strInfo,"[not claimed]");
		}else{
			strInfo = concatNewline(strInfo,"owner: "+data.username);
		}
		infobox.html(strInfo);
    }
    selected_block_time = data.blocktime;
  }

  function concatNewline(str0,str1){
	var strHTML = str0.concat("
");
	strHTML = strHTML.concat(str1);
  	return strHTML
  }

  var addChatMessage = function(data) {
    $('
', { text: data }).appendTo('#date_picker');
    $("#date_picker").animate({ scrollTop: $('#date_picker')[0].scrollHeight}, 500);
  };

  socket = io.connect();
  socket.on('connect', function(){
  	socket.emit('/timeline/#join');
  });

  socket.on('/timeline/#postblocks', function(data){
  	blockdata = [];
  	var num_ele = 9;
	for (var i=0;i<=data.length/num_ele;i++){
		var block = new Object();
		block.id = i;

		var d = new Date(0);
		d.setTime(data[i*num_ele]);
		block.time = d;

		block.lock = data[i*num_ele+1];
		block.username = data[i*num_ele+2];
		block.exp_id = data[i*num_ele+3];
		block.pattern_id = data[i*num_ele+4];
		block.past = data[i*num_ele+5];
		block.admin = data[i*num_ele+6];
		block.current = data[i*num_ele+7];
		block.image = data[i*num_ele+8];
		block.blocktime = data[i*num_ele];

		blockdata.push(block);
	}
	blockdata.length = blockdata.length-2;
	console.dir(blockdata);
	draw(blockdata);
  });

  socket.on('/timeline/#newUser', function(user) {
    myname=user;
    currenttime = new Date();
  	callBlocks(currenttime);
  	console.log('>>> timeline connected');
  });

  socket.on('/timeline/#doneRequest', function(msg) {
  	console.log(msg);
  	callBlocks(currenttime);
  });

  socket.on('message', function (message) {
  	console.log(message);
  });

  socket.on('disconnect', function() {
	console.log('>>> timeline disconnected');
  });

  app = app || {};

  app.Blocks = Backbone.Model.extend({
    url: '/account/timeline/',
    defaults: {
      userid: '',
      timestamp: ''
    }
  });

  app.BlocksView = Backbone.View.extend({
    el: '#blocks_nav',
    template: _.template( $('#tmpl-blocks_nav').html() ),
    events: {
      'click .btn-prev': 'reqPrev',
      'click .btn-now': 'reqNow',
      'click .btn-next': 'reqNext'
    },
    initialize: function() {
      this.model = new app.Blocks();
      this.listenTo(this.model, 'sync', this.render);
      this.render();
    },
    render: function() {
      this.$el.html(this.template( this.model.attributes));
    },
    reqPrev: function() {
      currenttime.setHours(currenttime.getHours() - 1);
      callBlocks(currenttime);
    },
    reqNow: function() {
      currenttime = new Date();
      callBlocks(currenttime);
    },
    reqNext: function() {
      currenttime.setHours(currenttime.getHours() + 1);
      callBlocks(currenttime);
    }
  });

  app.MenuView = Backbone.View.extend({
    el: '#info_menu',
    template: _.template( $('#tmpl-info_menu').html() ),
    events: {
      'click .btn-reserve': 'reqReserve',
      'click .btn-pattern': 'reqSetPattern',
      'click .btn-enter': 'reqEnterFreeform',
      'click .btn-access': 'reqDataAccess'
    },
    initialize: function() {
      this.model = new app.Blocks();
      this.listenTo(this.model, 'sync', this.render);
      this.render();
      document.getElementById("btn_enter").disabled = true;
      document.getElementById("btn_access").disabled = true;
      document.getElementById("btn_reserve").disabled = true;
      document.getElementById("btn_pattern").disabled = true;
      infobox = $('#info_box');
      previewbox = $('#preview_box');
    },
    render: function() {
      this.$el.html(this.template( this.model.attributes));
    },
    reqReserve: function() {
    	console.log("Sent request: Reserve a Block "+selected_block_time);
    	// >>>>>> socket: reserve block
    	socket.emit('/timeline/#reserveblock', { targettime: selected_block_time});

    },
    reqSetPattern: function() {
    	console.log("Sent request: Set Pattern");
    },
    reqDataAccess: function() {
    	console.log("Sent request: Data Access");
    },
    reqEnterFreeform: function() {
    	console.log("Sent request: Enter");
    }
  });

  $(document).ready(function() {
    app.blocksView = new app.BlocksView();
    app.menuView = new app.MenuView();
  });

  $('#d3Area').scroll(function() {
    $('#blockArea').css('top', $(this).scrollTop());
  });

  $('#btn_close').click(function(){
    $('#img_preview').css('display','none');
    document.getElementById("btn_close").style.display="none";
  });

}());
<commit_msg>style block class update<commit_after>/* global app:true, io:false */

var socket;
var myname;
var clock_socket;
var currenttime;
var selected_block_time;

var width = 900,
	height = 300,
	cellWidth = 60,
	cellHeight = 58, // cell size
	gapWidth = 12,
	gapHeight = 16,
	Dy = 80;

var hour = d3.time.format("%I"),
	minute = d3.time.format("%M"),
	month = d3.time.format("%b"),
	weekday = d3.time.format("%a"),
	date = d3.time.format("%d"),
	ampm = d3.time.format("%p"),
	format = d3.time.format("%b/%d %H:%M%p");

(function() {
  'use strict';

  var clockbar = $('#clock_bar');
  var myClock;
  function myTimer(){
		// >>>>>> socket: look clock
		clock_socket.emit('lookclock');
  }
  clock_socket = io.connect('http://171.65.102.132:3006');

  clock_socket.on('server_clock', function(data){
  	var str = data.split(":");
  	if(str[1]=='00'){
  		if((str[0]=="2")||(str[0]=="5")) {
  			callBlocks(currenttime);
  		}
  	}
  	if(str[0]=="0"){
  		clockbar.html(""+data+"");
  	}
  	else{
  		clockbar.html(""+data+"");
  	}
  });

  clock_socket.on('connect', function() {
	console.log("Clock connected!");
	myClock=setInterval(function(){myTimer()},500);
  });

  clock_socket.on('disconnect', function() {
	console.log('clock lost');
  });

  var blockdata = [];
  var infobox;
  var previewbox;

  var callBlocks = function(ticket){
	// +- 1 hour blocks range
	var beginT = d3.time.hour.floor(ticket);
	beginT = d3.time.hour.offset(beginT, -1);
	var endT = d3.time.hour.offset(beginT, 3);
	console.log(beginT);
	console.log(endT);
	socket.emit('/timeline/#callblocks', { begintime: beginT, endtime: endT});
	}

  var draw = function(blockdata){
    document.getElementById("btn_close").style.display="none"
    d3.select("svg")
       .remove();
	var tip = d3.tip()
		.attr('class', 'd3-tip')
		.direction('e')
		.offset([0,10])
		.html(function(d) {
			return "time: "+d.time;
		});

	var svg = d3.select("#d3Area").append("svg")
		.attr("width", width)
		.attr("height", height)
		.append("g")
		.attr("transform", "translate(4, 4)");

	svg.call(tip);

	var block = svg.selectAll(".block")
		.data(blockdata)
	.enter().append("g")
		.attr("class", "block")
		.attr("transform", function (d,i)
		{
			//var dx = (i-i%12)/12*(cellWidth+gapWidth);
			//var dy =  i%12 * (cellHeight+gapHeight);
			var dx = i%12 * (cellWidth+gapWidth);
			var dy = (i-i%12)/12*(cellHeight+gapHeight);
			return "translate(" + dx + ","+ dy + ")";
		})
		.on('mouseover', tip.show)
		.on('mouseout', tip.hide);

	block.append("rect")
		.attr("class", function (d)
		{
			var class_name;
			if (d.username==myname){
				class_name="my-block";
			}else{
				class_name="not-my-block";
			}

			if (d.past=="1"){
				class_name=class_name+" block-past";
			}else{
				if (d.current=="1"){
					class_name=class_name+" block-current";
				}else{
					class_name=class_name+" block-future"
				}
			}

			return class_name;
		})
		.attr("width", cellWidth)
		.attr("height", cellHeight)
		.attr("locked", function (d){
			if (d.lock=="1"){
				return true;
			}else{
				return false
			}
		})
		.attr("mine", function (d){
			if (d.username==myname){
				return true;
			}else{
				return false
			}
		})
		.attr("past", function (d){
			if (d.past=="1"){
				return true;
			}else{
				return false
			}
		})
		.attr("current", function (d){
			if (d.current=="1"){
				return true;
			}else{
				return false
			}
		})
		.on('mouseover', tip.show)
		.on('mouseout', tip.hide)
		.on('click', mouseclick);

	block.append("text")
		.attr("class", function (d)
		{
			var class_name;
			if (d.username==myname){
				class_name="my-block-name";
			}else{
				class_name="not-my-block-name";
			}
			return class_name;
		})
		.attr("x",10)
		.attr("y",14)
		.attr("dy", ".3em")
		.text(function(d) {
			var h = d.time.getHours();
			var ampm = (h<12 ? "a":"p");
			//h=("0" + h%12).slice(-2);
			h=(h%12);
			if(h==0){h="12";}
			var m = d.time.getMinutes();
			m=("0" + m).slice(-2);
			return h+":"+m+ampm;
		})
		.on('mouseover', tip.show)
		.on('mouseout', tip.hide);
  }

  function mouseclick(d,i){
	document.getElementById("btn_enter").disabled = true;
    document.getElementById("btn_access").disabled = true;
    document.getElementById("btn_reserve").disabled = true;
    document.getElementById("btn_pattern").disabled = true;

  	// reset to default layout
  	d3.selectAll(".block rect").transition().duration(1000)
  		.attr("width", cellWidth)
  		.attr("height", cellHeight);

  	d3.selectAll(".block").transition().duration(1000)
  		.attr("transform", function (d,i)
		{
			var dx = i%12 * (cellWidth+gapWidth);
			var dy = Dy+(i-i%12)/12*(cellHeight+gapHeight);
			return "translate(" + dx + ","+ dy + ")";
		});

  	var data;
	d3.select(this.parentNode).transition().duration(1000)
		.attr("transform", function (d)
		{
			data = d;
			var dx = i%12 * (cellWidth+gapWidth);
			var dy = 0;
			return "translate(" + dx + ","+ dy + ")";
		});
	d3.select(this.parentNode).transition().duration(1000)
		.attr("transform", function (d)
		{
			data = d;
			var dx = i%12 * (cellWidth+gapWidth);
			var dy = 8;
			return "translate(" + dx + ","+ dy + ")";
		});

	console.log(this.getAttribute("class"));
	console.log(this.getAttribute("mine"));
	console.log(this.getAttribute("past"));
	console.log(this.getAttribute("locked"));

	if(this.getAttribute("mine")){
		console.log("MINE!!!");
		if(this.getAttribute("past")){
			console.log("from the past");
			document.getElementById("btn_access").disabled = false;
		}else{
			if(this.getAttribute("current")){
				console.log("current block");
				document.getElementById("btn_enter").disabled = false;
			}else{
				console.log("into the future");
				document.getElementById("btn_pattern").disabled = false;
			}
		}
	}else{
		if(this.getAttribute("locked")){
			console.log("this is locked block");
		}else{
			document.getElementById("btn_reserve").disabled = false;
		}
	}

	preloader();

    // preloading for block preview
    function preloader()
	{
		if(data.image<0){
			document.getElementById("btn_close").style.display="none";
			previewbox.html("[no preview]");
			writeInfo();
		}
		else
		{
			getPreview("http://171.65.102.132:3001/"+data.image, function(image) {
            	previewbox.html(image);
            	writeInfo();
            });
        }

    	function getPreview(path, callback) {
    		document.getElementById("btn_close").style.display="block";
            var image = new Image;
            image.id = "img_preview";
            image.src = path;
            image.setAttribute("class","img-responsive img-thumbnail");
            image.setAttribute("alt","Responsive image");
            image.onload = function() {
                callback(image);
            };
        }
	}

	// write block info to infobox
    function writeInfo(){
		var strInfo;
		strInfo = ""+data.time+"";
		strInfo = concatNewline(strInfo,"block time:"+data.blocktime);
		if(data.user_id<0){
			strInfo = concatNewline(strInfo,"[not claimed]");
		}else{
			strInfo = concatNewline(strInfo,"owner: "+data.username);
		}
		infobox.html(strInfo);
    }
    selected_block_time = data.blocktime;
  }

  function concatNewline(str0,str1){
	var strHTML = str0.concat("
");
	strHTML = strHTML.concat(str1);
  	return strHTML
  }

  var addChatMessage = function(data) {
    $('
', { text: data }).appendTo('#date_picker');
    $("#date_picker").animate({ scrollTop: $('#date_picker')[0].scrollHeight}, 500);
  };

  socket = io.connect();
  socket.on('connect', function(){
  	socket.emit('/timeline/#join');
  });

  socket.on('/timeline/#postblocks', function(data){
  	blockdata = [];
  	var num_ele = 9;
	for (var i=0;i<=data.length/num_ele;i++){
		var block = new Object();
		block.id = i;

		var d = new Date(0);
		d.setTime(data[i*num_ele]);
		block.time = d;

		block.lock = data[i*num_ele+1];
		block.username = data[i*num_ele+2];
		block.exp_id = data[i*num_ele+3];
		block.pattern_id = data[i*num_ele+4];
		block.past = data[i*num_ele+5];
		block.admin = data[i*num_ele+6];
		block.current = data[i*num_ele+7];
		block.image = data[i*num_ele+8];
		block.blocktime = data[i*num_ele];

		blockdata.push(block);
	}
	blockdata.length = blockdata.length-2;
	console.dir(blockdata);
	draw(blockdata);
  });

  socket.on('/timeline/#newUser', function(user) {
    myname=user;
    currenttime = new Date();
  	callBlocks(currenttime);
  	console.log('>>> timeline connected');
  });

  socket.on('/timeline/#doneRequest', function(msg) {
  	console.log(msg);
  	callBlocks(currenttime);
  });

  socket.on('message', function (message) {
  	console.log(message);
  });

  socket.on('disconnect', function() {
	console.log('>>> timeline disconnected');
  });

  app = app || {};

  app.Blocks = Backbone.Model.extend({
    url: '/account/timeline/',
    defaults: {
      userid: '',
      timestamp: ''
    }
  });

  app.BlocksView = Backbone.View.extend({
    el: '#blocks_nav',
    template: _.template( $('#tmpl-blocks_nav').html() ),
    events: {
      'click .btn-prev': 'reqPrev',
      'click .btn-now': 'reqNow',
      'click .btn-next': 'reqNext'
    },
    initialize: function() {
      this.model = new app.Blocks();
      this.listenTo(this.model, 'sync', this.render);
      this.render();
    },
    render: function() {
      this.$el.html(this.template( this.model.attributes));
    },
    reqPrev: function() {
      currenttime.setHours(currenttime.getHours() - 1);
      callBlocks(currenttime);
    },
    reqNow: function() {
      currenttime = new Date();
      callBlocks(currenttime);
    },
    reqNext: function() {
      currenttime.setHours(currenttime.getHours() + 1);
      callBlocks(currenttime);
    }
  });

  app.MenuView = Backbone.View.extend({
    el: '#info_menu',
    template: _.template( $('#tmpl-info_menu').html() ),
    events: {
      'click .btn-reserve': 'reqReserve',
      'click .btn-pattern': 'reqSetPattern',
      'click .btn-enter': 'reqEnterFreeform',
      'click .btn-access': 'reqDataAccess'
    },
    initialize: function() {
      this.model = new app.Blocks();
      this.listenTo(this.model, 'sync', this.render);
      this.render();
      document.getElementById("btn_enter").disabled = true;
      document.getElementById("btn_access").disabled = true;
      document.getElementById("btn_reserve").disabled = true;
      document.getElementById("btn_pattern").disabled = true;
      infobox = $('#info_box');
      previewbox = $('#preview_box');
    },
    render: function() {
      this.$el.html(this.template( this.model.attributes));
    },
    reqReserve: function() {
    	console.log("Sent request: Reserve a Block "+selected_block_time);
    	// >>>>>> socket: reserve block
    	socket.emit('/timeline/#reserveblock', { targettime: selected_block_time});

    },
    reqSetPattern: function() {
    	console.log("Sent request: Set Pattern");
    },
    reqDataAccess: function() {
    	console.log("Sent request: Data Access");
    },
    reqEnterFreeform: function() {
    	console.log("Sent request: Enter");
    }
  });

  $(document).ready(function() {
    app.blocksView = new app.BlocksView();
    app.menuView = new app.MenuView();
  });

  $('#d3Area').scroll(function() {
    $('#blockArea').css('top', $(this).scrollTop());
  });

  $('#btn_close').click(function(){
    $('#img_preview').css('display','none');
    document.getElementById("btn_close").style.display="none";
  });

}());
<|endoftext|>


<commit_before>function getModule(React) {

    function bemJsonToReact(json, curBlock) {
        if(json) {
            if(Array.isArray(json)) {
                return json.map(function(item) {
                    return bemJsonToReact(item, curBlock);
                });
            }

            if(json.elem) {
                if(!json.tag) {
                    throw Error('Specify tag');
                }

                json.className = buildBemClassName((json.block || curBlock) + '__' + json.elem, json.mods, json.mix);
                return React.createElement(json.tag, json, bemJsonToReact(json.children));
            }

            if(json.block) {
                return React.createElement(json.block, json);
            }
        }

        return json;
    }

    function buildBemClassName(bemEntity, mods, mix) {
        var res = bemEntity;

        for(var modName in mods) {
            mods[modName] &&
                (res += ' ' + bemEntity + '_' + modName +
                    (mods[modName] === true? '' : '_' + mods[modName]));
        }

        if(mix) {
            var i = 0,
                mixItem;
            while(mixItem = mix[i++]) {
                if(!mixItem.block || !mixItem.elem) {
                    throw Error('Specify both block and elem in mix');
                }

                res += ' ' + buildBemClassName(mixItem.block + '__' + mixItem.elem, mixItem.mods);
            }
        }

        return res;
    }

    var bemMixin = {
            render : function() {
                var json = this.renderToBemJson();

                if(!json.block) {
                    throw Error('Specify block');
                }

                if(!json.tag) {
                    throw Error('Specify tag');
                }

                json.className = buildBemClassName(json.block, json.mods, this.props.mix);

                return React.createElement(
                    json.tag,
                    json,
                    bemJsonToReact(json.children, json.block));
            }
        },
        exports = {
            createClass : function(spec) {
                spec.mixins?
                    spec.mixins.unshift(bemMixin) :
                    spec.mixins = [bemMixin];

                return React.createClass(spec);
            },

            unmountComponentAtNode : function(container) {
                return React.unmountComponentAtNode(container);
            }
        };

    ['render', 'renderToString', 'renderToStaticMarkup'].forEach(function(method) {
        var reactMethod = React[method];
        exports[method] = function(element) {
            if(!element || !element.block) {
                throw Error(method + ': invalid bem component json');
            }

            element = React.createElement(element.block, element);
            return reactMethod.apply(React, arguments);
        };
    });

    return exports;
}

if(typeof module === 'object' && typeof module.exports === 'object') {
    module.exports = getModule(require('react'));
}
else {
    var BemReact = getModule(React);
}
<commit_msg>move delimiters to constants<commit_after>function getModule(React) {

    var MOD_DELIM = '_',
        ELEM_DELIM = '__';

    function bemJsonToReact(json, curBlock) {
        if(json) {
            if(Array.isArray(json)) {
                return json.map(function(item) {
                    return bemJsonToReact(item, curBlock);
                });
            }

            if(json.elem) {
                if(!json.tag) {
                    throw Error('Specify tag');
                }

                json.className = buildBemClassName((json.block || curBlock) + ELEM_DELIM + json.elem, json.mods, json.mix);
                return React.createElement(json.tag, json, bemJsonToReact(json.children));
            }

            if(json.block) {
                return React.createElement(json.block, json);
            }
        }

        return json;
    }

    function buildBemClassName(bemEntity, mods, mix) {
        var res = bemEntity;

        for(var modName in mods) {
            mods[modName] &&
                (res += ' ' + bemEntity + MOD_DELIM + modName +
                    (mods[modName] === true? '' : MOD_DELIM + mods[modName]));
        }

        if(mix) {
            var i = 0,
                mixItem;
            while(mixItem = mix[i++]) {
                if(!mixItem.block || !mixItem.elem) {
                    throw Error('Specify both block and elem in mix');
                }

                res += ' ' + buildBemClassName(mixItem.block + ELEM_DELIM + mixItem.elem, mixItem.mods);
            }
        }

        return res;
    }

    var bemMixin = {
            render : function() {
                var json = this.renderToBemJson();

                if(!json.block) {
                    throw Error('Specify block');
                }

                if(!json.tag) {
                    throw Error('Specify tag');
                }

                json.className = buildBemClassName(json.block, json.mods, this.props.mix);

                return React.createElement(
                    json.tag,
                    json,
                    bemJsonToReact(json.children, json.block));
            }
        },
        exports = {
            createClass : function(spec) {
                spec.mixins?
                    spec.mixins.unshift(bemMixin) :
                    spec.mixins = [bemMixin];

                return React.createClass(spec);
            },

            unmountComponentAtNode : function(container) {
                return React.unmountComponentAtNode(container);
            }
        };

    ['render', 'renderToString', 'renderToStaticMarkup'].forEach(function(method) {
        var reactMethod = React[method];
        exports[method] = function(element) {
            if(!element || !element.block) {
                throw Error(method + ': invalid bem component json');
            }

            element = React.createElement(element.block, element);
            return reactMethod.apply(React, arguments);
        };
    });

    return exports;
}

if(typeof module === 'object' && typeof module.exports === 'object') {
    module.exports = getModule(require('react'));
}
else {
    var BemReact = getModule(React);
}
<|endoftext|>