<commit_before>'use strict';

const checkUtils = require('./check-utils'),
      WebSocket  = require('ws');

/**
 * Factory function, create an object instance.
 *
 * WebSocket connection to a ViSense system WebSocket API.
 *
 * @param {object}  socketAddress ViSense system socket address.
 * @param {boolean} useSsl        Flag to indicate whether or not to use SSL.
 * @param {string}  apiPath       ViSense API path (e.g. '/api/v2/data/main/count/preset0').
 * @param {string}  sessionToken  Authentication session token.
 *
 * @returns {object} WebSocketConnection object instance.
 *
 * @throws When invalid function parameters are provided.
 */
function WebSocketConnection(socketAddress, useSsl, apiPath, sessionToken) {

  // Validate function parameters.
  checkUtils.checkSocketAddress(socketAddress);
  if (!checkUtils.isDefinedBoolean(useSsl)) {
    throw new Error('Parameter \'useSsl\' invalid');
  }

  checkUtils.checkSessionToken(sessionToken);

  if (  !checkUtils.isDefinedString(apiPath)
     || (apiPath.length === 0)) {
    throw Error('Parameter \'apiPath: ""\' is invalid or empty');
  }

  // Private class members.
  let _webSocket = null;
  const _url = (useSsl ? 'wss://' : 'ws://') + socketAddress.ip + ':' + socketAddress.port + apiPath + '?X-AUTHENTICATION-TOKEN=' + sessionToken;

  const _reset = () => {
    _webSocket.removeAllListeners('open');
    _webSocket.removeAllListeners('close');
    _webSocket.removeAllListeners('message');
    _webSocket.removeAllListeners('error');
    _webSocket = null;
  }

  // Class prototype.
  let WebSocketConnectionProto = {
    /**
     * Open a WebSocket connection.
     *
     * @returns {object} Promise with the open call. The callback prototypes are:
     *                    - resolve()
     *                    - reject({string} error message)
     */
    open() {
      if (_webSocket !== null) {
        throw Error('WebSocket still in use not closed (properly)');
      }

      return new Promise((resolve, reject) => {
        _webSocket = new WebSocket(_url, { rejectUnauthorized: false });

        const onClose = () => {
          reject('WebSocket was closed');
        };

        const onError = (error) => {
          reject(error.message);
        };

        _webSocket.on('open', () => {
          _webSocket.removeEventListener('close', onClose);
          _webSocket.removeEventListener('error', onError);
          resolve();
        });

        _webSocket.on('close', onClose);
        _webSocket.on('error', onError);
      });
    },

    /**
     * Send a query to the WebSocket.
     *
     * @param {string} query   Query string.
     * @param {string} onData  Callback to be executed on data. Prototype:
     *                          - onData({string} data) -> {bool}
     *                         The onData callback should return 'true' upon stream end,
     *                          false if the connection must be preserved. If the onData
     *                          callback is not provided, the returned promise from send
     *                          will instantaneously resolve at first data. If the
     *                          onData callback is not provided, and no data arrives, the
     *                          promise will resolve after a timeout period.
     * @param {number} timeout Timeout in [milliseconds]. The promise will be resolved if
     *                          this timeout is reached.
     *
     * @returns {object} Promise with the query call. The callback prototypes are:
     *                    - resolve()
     *                    - reject({string} error message)
     *
     * @throws An error when the WebSocket connection was closed prior to the query.
     */
    send(query, onDataCallback, timeout) {
      if (_webSocket.readyState !== 1) {
        throw Error('WebSocket not opened (yet)');
      }

      return new Promise((resolve, reject) => {
        let timer = null;

        const onMessage = (data) => {
          if (  (typeof onDataCallback === 'undefined')
             || onDataCallback(data)) {
            removeEventListeners();
            clearTimeout(timer);
            resolve();
          }
        };

        const onClose = () => {
          clearTimeout(timer);
          removeEventListeners();
          reject('WebSocket was closed');
        };

        const onError = (error) => {
          clearTimeout(timer);
          removeEventListeners();
          reject(error.Message);
        };

        const removeEventListeners = () => {
          if (_webSocket != null) {
            _webSocket.removeEventListener('message', onMessage);
            _webSocket.removeEventListener('close', onClose);
            _webSocket.removeEventListener('error', onError);
          }
        };

        _webSocket.send(query, { mask: true }, (error) => {
          if (typeof error !== 'undefined') {
            reject(error.message);
          }
        });

        _webSocket.on('message', onMessage);
        _webSocket.on('close',   onClose);
        _webSocket.on('error',   onError);

        if (typeof onDataCallback === 'undefined') {
          // Resolve query without handler callback or data after a grace period.
          timer = setTimeout(() => {
            removeEventListeners();
            resolve();
          }, 200);
        } else if (  (typeof timeout !== 'undefined')
                  && (typeof timeout === 'number')) {
          // Resolve query after a grace period if a timeout is specified.
          timer = setTimeout(() => {
            removeEventListeners();
            resolve();
          }, timeout);
        }
      });
    },

    /**
     * Close the WebSocket connection.
     *
     * @returns {object} Promise with the close call. The callback prototypes are:
     *                    - resolve()
     *                    - reject({string} error message)
     */
    close() {
      if (!_webSocket) {
        throw Error('WebSocket is not opened');
      }

      return new Promise((resolve, reject) => {
        _webSocket.on('close', () => {
          _reset();
          resolve();
        });

        _webSocket.on('error', (error) => {
          reject(error.message);
        });

        _webSocket.close();
      });
    }
  };

  return Object.assign(Object.create(WebSocketConnectionProto));
}

module.exports = WebSocketConnection;
<commit_msg>FIX: Right order of calls.<commit_after>'use strict';

const checkUtils = require('./check-utils'),
      WebSocket  = require('ws');

/**
 * Factory function, create an object instance.
 *
 * WebSocket connection to a ViSense system WebSocket API.
 *
 * @param {object}  socketAddress ViSense system socket address.
 * @param {boolean} useSsl        Flag to indicate whether or not to use SSL.
 * @param {string}  apiPath       ViSense API path (e.g. '/api/v2/data/main/count/preset0').
 * @param {string}  sessionToken  Authentication session token.
 *
 * @returns {object} WebSocketConnection object instance.
 *
 * @throws When invalid function parameters are provided.
 */
function WebSocketConnection(socketAddress, useSsl, apiPath, sessionToken) {

  // Validate function parameters.
  checkUtils.checkSocketAddress(socketAddress);
  if (!checkUtils.isDefinedBoolean(useSsl)) {
    throw new Error('Parameter \'useSsl\' invalid');
  }

  checkUtils.checkSessionToken(sessionToken);

  if (  !checkUtils.isDefinedString(apiPath)
     || (apiPath.length === 0)) {
    throw Error('Parameter \'apiPath: ""\' is invalid or empty');
  }

  // Private class members.
  let _webSocket = null;
  const _url = (useSsl ? 'wss://' : 'ws://') + socketAddress.ip + ':' + socketAddress.port + apiPath + '?X-AUTHENTICATION-TOKEN=' + sessionToken;

  const _reset = () => {
    _webSocket.removeAllListeners('open');
    _webSocket.removeAllListeners('close');
    _webSocket.removeAllListeners('message');
    _webSocket.removeAllListeners('error');
    _webSocket = null;
  }

  // Class prototype.
  let WebSocketConnectionProto = {
    /**
     * Open a WebSocket connection.
     *
     * @returns {object} Promise with the open call. The callback prototypes are:
     *                    - resolve()
     *                    - reject({string} error message)
     */
    open() {
      if (_webSocket !== null) {
        throw Error('WebSocket still in use not closed (properly)');
      }

      return new Promise((resolve, reject) => {
        _webSocket = new WebSocket(_url, { rejectUnauthorized: false });

        const onClose = () => {
          reject('WebSocket was closed');
        };

        const onError = (error) => {
          reject(error.message);
        };

        _webSocket.on('open', () => {
          _webSocket.removeEventListener('close', onClose);
          _webSocket.removeEventListener('error', onError);
          resolve();
        });

        _webSocket.on('close', onClose);
        _webSocket.on('error', onError);
      });
    },

    /**
     * Send a query to the WebSocket.
     *
     * @param {string} query   Query string.
     * @param {string} onData  Callback to be executed on data. Prototype:
     *                          - onData({string} data) -> {bool}
     *                         The onData callback should return 'true' upon stream end,
     *                          false if the connection must be preserved. If the onData
     *                          callback is not provided, the returned promise from send
     *                          will instantaneously resolve at first data. If the
     *                          onData callback is not provided, and no data arrives, the
     *                          promise will resolve after a timeout period.
     * @param {number} timeout Timeout in [milliseconds]. The promise will be resolved if
     *                          this timeout is reached.
     *
     * @returns {object} Promise with the query call. The callback prototypes are:
     *                    - resolve()
     *                    - reject({string} error message)
     *
     * @throws An error when the WebSocket connection was closed prior to the query.
     */
    send(query, onDataCallback, timeout) {
      if (_webSocket.readyState !== 1) {
        throw Error('WebSocket not opened (yet)');
      }

      return new Promise((resolve, reject) => {
        let timer = null;

        const onMessage = (data) => {
          if (  (typeof onDataCallback === 'undefined')
             || onDataCallback(data)) {
            removeEventListeners();
            clearTimeout(timer);
            resolve();
          }
        };

        const onClose = () => {
          clearTimeout(timer);
          removeEventListeners();
          reject('WebSocket was closed');
        };

        const onError = (error) => {
          clearTimeout(timer);
          removeEventListeners();
          reject(error.Message);
        };

        const removeEventListeners = () => {
          if (_webSocket != null) {
            _webSocket.removeEventListener('message', onMessage);
            _webSocket.removeEventListener('close', onClose);
            _webSocket.removeEventListener('error', onError);
          }
        };

        _webSocket.on('message', onMessage);
        _webSocket.on('close',   onClose);
        _webSocket.on('error',   onError);

        _webSocket.send(query, { mask: true }, (error) => {
          if (typeof error !== 'undefined') {
            reject(error.message);
          }
        });

        if (typeof onDataCallback === 'undefined') {
          // Resolve query without handler callback or data after a grace period.
          timer = setTimeout(() => {
            removeEventListeners();
            resolve();
          }, 200);
        } else if (  (typeof timeout !== 'undefined')
                  && (typeof timeout === 'number')) {
          // Resolve query after a grace period if a timeout is specified.
          timer = setTimeout(() => {
            removeEventListeners();
            resolve();
          }, timeout);
        }
      });
    },

    /**
     * Close the WebSocket connection.
     *
     * @returns {object} Promise with the close call. The callback prototypes are:
     *                    - resolve()
     *                    - reject({string} error message)
     */
    close() {
      if (!_webSocket) {
        throw Error('WebSocket is not opened');
      }

      return new Promise((resolve, reject) => {
        _webSocket.on('close', () => {
          _reset();
          resolve();
        });

        _webSocket.on('error', (error) => {
          reject(error.message);
        });

        _webSocket.close();
      });
    }
  };

  return Object.assign(Object.create(WebSocketConnectionProto));
}

module.exports = WebSocketConnection;
<|endoftext|>


<commit_before>angular.module('mean.system')
  .factory('game', ['socket', '$timeout', function (socket, $timeout) {

  var game = {
    id: null,
    players: [],
    playerIndex: 0,
    winningCard: -1,
    winningCardPlayer: -1,
    gameWinner: -1,
    table: [],
    czar: null,
    playerMinLimit: 3,
    playerMaxLimit: 6,
    pointLimit: null,
    state: null,
    round: 0,
    time: 0,
    curQuestion: null,
    notification: null,
    timeLimits: {},
    joinOverride: false
  };

  var notificationQueue = [];
  var timeout = false;
  var self = this;
  var joinOverrideTimeout = 0;

  var addToNotificationQueue = function(msg) {
    notificationQueue.push(msg);
    if (!timeout) { // Start a cycle if there isn't one
      setNotification();
    }
  };
  var setNotification = function() {
    if (notificationQueue.length === 0) { // If notificationQueue is empty, stop
      clearInterval(timeout);
      timeout = false;
      game.notification = '';
    } else {
      game.notification = notificationQueue.shift(); // Show a notification and check again in a bit
      timeout = $timeout(setNotification, 1300);
    }
  };

  var timeSetViaUpdate = false;
  var decrementTime = function() {
    if (game.time > 0 && !timeSetViaUpdate) {
      game.time--;
    } else {
      timeSetViaUpdate = false;
    }
    $timeout(decrementTime, 950);
  };

  socket.on('id', function(data) {
    game.id = data.id;
  });

  socket.on('prepareGame', function(data) {
    game.playerMinLimit = data.playerMinLimit;
    game.playerMaxLimit = data.playerMaxLimit;
    game.pointLimit = data.pointLimit;
    game.timeLimits = data.timeLimits;
  });

  socket.on('gameUpdate', function(data) {
    // console.log(data);
    game.joinOverride = false;
    clearTimeout(game.joinOverrideTimeout);

    var i;
    // Cache the index of the player in the players array
    for (i = 0; i < data.players.length; i++) {
      if (game.id === data.players[i].socketID) {
        game.playerIndex = i;
      }
    }

    var newState = (data.state !== game.state);

    //Handle updating game.time
    if (data.round !== game.round) {
      game.time = game.timeLimits.stateChoosing - 1;
      timeSetViaUpdate = true;
    } else if (newState && data.state === 'waiting for czar to decide') {
      game.time = game.timeLimits.stateJudging - 1;
      timeSetViaUpdate = true;
    } else if (newState && data.state === 'winner has been chosen') {
      game.time = game.timeLimits.stateResults - 1;
      timeSetViaUpdate = true;
    }

    // Set these properties on each update
    game.round = data.round;
    game.winningCard = data.winningCard;
    game.winningCardPlayer = data.winningCardPlayer;
    game.winnerAutopicked = data.winnerAutopicked;
    game.gameWinner = data.gameWinner;
    game.pointLimit = data.pointLimit;

    // Handle updating game.table
    if (data.table.length === 0) {
      game.table = [];
    } else {
      // All players represented in game.table
      var playersPicked = {};
      for (i = 0; i < game.table.length; i++) {
        playersPicked[game.table[i].player] = true;
      }
      // Only add new player's picks to game.table
      for (i = 0; i < data.table.length; i++) {
        if (!playersPicked[data.table[i].player]) {
          game.table.push(data.table[i]);
        }
      }
    }

    if (game.state !== 'waiting for players to pick') {
      game.players = data.players;
    }

    if (newState || game.curQuestion !== data.curQuestion) {
      game.state = data.state;
    }

    if (data.state === 'waiting for players to pick') {
      game.czar = data.czar;
      game.curQuestion = data.curQuestion;

      // Set notifications only when entering state
      if (newState) {
        if (game.czar === game.playerIndex) {
          addToNotificationQueue('You\'re the Card Czar! Players are choosing answers...');
        } else if (game.curQuestion.numAnswers === 1) {
          addToNotificationQueue('Select an answer!');
        } else {
          addToNotificationQueue('Select TWO answers!');
        }
      }

    } else if (data.state === 'winner has been chosen') {
      game.curQuestion = data.curQuestion;
    } else if (data.state === 'awaiting players') {
      joinOverrideTimeout = $timeout(function() {
        game.joinOverride = true;
      }, 15000);
    } else if (data.state === 'game dissolved' || data.state === 'game ended') {
      console.log('game dissolved or ended');
      game.players[game.playerIndex].hand = [];
    }
  });

  socket.on('notification', function(data) {
    addToNotificationQueue(data.notification);
  });

  game.joinGame = function(mode) {
    mode = mode || 'joinGame';
    var userID = !!window.user ? user._id : 'unauthenticated';
    socket.emit(mode,{userID: userID});
  };

  game.startGame = function() {
    socket.emit('startGame');
  };

  game.leaveGame = function() {
    socket.emit('leaveGame');
  };

  game.pickCards = function(cards) {
    socket.emit('pickCards',{cards: cards});
  };

  game.pickWinning = function(card) {
    socket.emit('pickWinning',{card: card.id});
  };

  decrementTime();

  return game;
}]);
<commit_msg>Fixed issue with answers not being spliced into question when czar clicks twice<commit_after>angular.module('mean.system')
  .factory('game', ['socket', '$timeout', function (socket, $timeout) {

  var game = {
    id: null,
    players: [],
    playerIndex: 0,
    winningCard: -1,
    winningCardPlayer: -1,
    gameWinner: -1,
    table: [],
    czar: null,
    playerMinLimit: 3,
    playerMaxLimit: 6,
    pointLimit: null,
    state: null,
    round: 0,
    time: 0,
    curQuestion: null,
    notification: null,
    timeLimits: {},
    joinOverride: false
  };

  var notificationQueue = [];
  var timeout = false;
  var self = this;
  var joinOverrideTimeout = 0;

  var addToNotificationQueue = function(msg) {
    notificationQueue.push(msg);
    if (!timeout) { // Start a cycle if there isn't one
      setNotification();
    }
  };
  var setNotification = function() {
    if (notificationQueue.length === 0) { // If notificationQueue is empty, stop
      clearInterval(timeout);
      timeout = false;
      game.notification = '';
    } else {
      game.notification = notificationQueue.shift(); // Show a notification and check again in a bit
      timeout = $timeout(setNotification, 1300);
    }
  };

  var timeSetViaUpdate = false;
  var decrementTime = function() {
    if (game.time > 0 && !timeSetViaUpdate) {
      game.time--;
    } else {
      timeSetViaUpdate = false;
    }
    $timeout(decrementTime, 950);
  };

  socket.on('id', function(data) {
    game.id = data.id;
  });

  socket.on('prepareGame', function(data) {
    game.playerMinLimit = data.playerMinLimit;
    game.playerMaxLimit = data.playerMaxLimit;
    game.pointLimit = data.pointLimit;
    game.timeLimits = data.timeLimits;
  });

  socket.on('gameUpdate', function(data) {
    // console.log(data);
    game.joinOverride = false;
    clearTimeout(game.joinOverrideTimeout);

    var i;
    // Cache the index of the player in the players array
    for (i = 0; i < data.players.length; i++) {
      if (game.id === data.players[i].socketID) {
        game.playerIndex = i;
      }
    }

    var newState = (data.state !== game.state);

    //Handle updating game.time
    if (data.round !== game.round) {
      game.time = game.timeLimits.stateChoosing - 1;
      timeSetViaUpdate = true;
    } else if (newState && data.state === 'waiting for czar to decide') {
      game.time = game.timeLimits.stateJudging - 1;
      timeSetViaUpdate = true;
    } else if (newState && data.state === 'winner has been chosen') {
      game.time = game.timeLimits.stateResults - 1;
      timeSetViaUpdate = true;
    }

    // Set these properties on each update
    game.round = data.round;
    game.winningCard = data.winningCard;
    game.winningCardPlayer = data.winningCardPlayer;
    game.winnerAutopicked = data.winnerAutopicked;
    game.gameWinner = data.gameWinner;
    game.pointLimit = data.pointLimit;

    // Handle updating game.table
    if (data.table.length === 0) {
      game.table = [];
    } else {
      // All players represented in game.table
      var playersPicked = {};
      for (i = 0; i < game.table.length; i++) {
        playersPicked[game.table[i].player] = true;
      }
      // Only add new player's picks to game.table
      for (i = 0; i < data.table.length; i++) {
        if (!playersPicked[data.table[i].player]) {
          game.table.push(data.table[i]);
        }
      }
    }

    if (game.state !== 'waiting for players to pick') {
      game.players = data.players;
    }

    if (newState || game.curQuestion !== data.curQuestion) {
      game.state = data.state;
    }

    if (data.state === 'waiting for players to pick') {
      game.czar = data.czar;
      game.curQuestion = data.curQuestion;

      // Set notifications only when entering state
      if (newState) {
        if (game.czar === game.playerIndex) {
          addToNotificationQueue('You\'re the Card Czar! Players are choosing answers...');
        } else if (game.curQuestion.numAnswers === 1) {
          addToNotificationQueue('Select an answer!');
        } else {
          addToNotificationQueue('Select TWO answers!');
        }
      }

    } else if (data.state === 'winner has been chosen' && data.state !== game.state) {
      game.curQuestion = data.curQuestion;
    } else if (data.state === 'awaiting players') {
      joinOverrideTimeout = $timeout(function() {
        game.joinOverride = true;
      }, 15000);
    } else if (data.state === 'game dissolved' || data.state === 'game ended') {
      console.log('game dissolved or ended');
      game.players[game.playerIndex].hand = [];
    }
  });

  socket.on('notification', function(data) {
    addToNotificationQueue(data.notification);
  });

  game.joinGame = function(mode) {
    mode = mode || 'joinGame';
    var userID = !!window.user ? user._id : 'unauthenticated';
    socket.emit(mode,{userID: userID});
  };

  game.startGame = function() {
    socket.emit('startGame');
  };

  game.leaveGame = function() {
    socket.emit('leaveGame');
  };

  game.pickCards = function(cards) {
    socket.emit('pickCards',{cards: cards});
  };

  game.pickWinning = function(card) {
    socket.emit('pickWinning',{card: card.id});
  };

  decrementTime();

  return game;
}]);
<|endoftext|>


<commit_before>App.FormView = Backbone.View.extend({

  tagName: 'form',

  templateName: 'form',

  events: {
    'click .submit': 'onSubmit'
  },

  initialize: function initialize(options) {
    var name = options.name;
    this.fields =  {};
    this.options = options;
    this.template = getTmpl(this.templateName);

    this.onRender = options.onRender || noop;
    this.onSuccess = options.onSuccess || noop;
    this.onError = options.onError || noop;

    if(this.collection) {
      this.collection.on('sync', function(collection, resp, options) {
        if(!options.previousModels) {
          App.router.navigate(name, {trigger: true});
        }
      });

      this.collection.on('error', function() {
        console.error(this);
      });
    }

    if(this.model) {
      this.model.on('sync', this.onSuccess, this);
      this.model.on('error', this.onError, this);
    }

    this.render();
    this.onRender();
    this.build();
  },

  text: function Text(name, attributes) {
    return $('<textarea/>', _.extend({name: name}, attributes));
  },

  string: function String(name, attributes) {
    return $('<input/>', _.extend({type: 'text', name: name}, attributes));
  },

  boolean: function Boolean(name, attributes) {
    return $('<input/>', _.extend({type: 'checkbox', name: name}, attributes));
  },

  render: function render() {
    var html = this.template({'name': this.options.name});
    this.$el.html(html);
    this.trigger('render');
  },

  build: function build() {
    var p, label, widget;
    var container = this.$el.find('.fields');

    _.each(this.options.fields, function(options, name) {
      p = $('

');
      label = $('', {'for': name}).html(options.label + ':');
      widget = this[options.type](name, options.attributes || {});

      p.append(label, widget);
      container.append(p);

      this.fields[name] = widget;
    }, this);
  },

  addWidget: function addWidget(el) {2
    this.$el.find('.form-widgets').append(el);
  },

  getField: function getField(key) {
    return this.$el.find('[name="' + key + '"]');
  },

  serialize: function serialize() {
    var v, type, data = {};
    _.each(this.fields, function(widget, key) {
      type = widget.attr('type');
      if(type === 'checkbox') {
        v = widget.prop('checked');
      } else {
        v = widget.val();
      }
      data[key] = v;
    });
    return  data;
  },

  unload: function unload() {
    this.model = null;
    this.el.reset();
  },

  load: function load(id) {
    var model = this.model = this.collection.get(id);
    _.each(model.attributes, function(value, key) {
      var field = this.getField(key);
      if(typeof value === 'boolean') {
        field.prop('checked', value);
      } else {
        field.val(value);
      }
    }, this);
    this.trigger('load', model);
  },

  onSubmit: function onSubmit() {
    var data = this.serialize();
    if(!this.model) {
      this.model = this.collection.create(data);
    } else {
      this.model.save(data);
    }
    return false;
  }

});<commit_msg>Added a saved event<commit_after>App.FormView = Backbone.View.extend({

  tagName: 'form',

  templateName: 'form',

  events: {
    'click .submit': 'onSubmit'
  },

  initialize: function initialize(options) {
    this.fields =  {};
    this.options = options;
    this.template = getTmpl(this.templateName);

    this.onRender = options.onRender || noop;
    this.onError = options.onError || noop;

    if(this.collection) {
      this.collection.on('sync', function() {this.trigger('success', this.collection)}, this);
      this.collection.on('error', this.onError, this);
    }

    if(this.model) {
      this.model.on('sync', function() {this.trigger('success', this.model)}, this);
      this.model.on('error', this.onError, this);
    }

    this.render();
    this.onRender();
    this.build();
  },

  text: function Text(name, attributes) {
    return $('<textarea/>', _.extend({name: name}, attributes));
  },

  string: function String(name, attributes) {
    return $('<input/>', _.extend({type: 'text', name: name}, attributes));
  },

  boolean: function Boolean(name, attributes) {
    return $('<input/>', _.extend({type: 'checkbox', name: name}, attributes));
  },

  render: function render() {
    var html = this.template({'name': this.options.name});
    this.$el.html(html);
    this.trigger('render');
  },

  build: function build() {
    var p, label, widget;
    var container = this.$el.find('.fields');

    _.each(this.options.fields, function(options, name) {
      p = $('

');
      label = $('', {'for': name}).html(options.label + ':');
      widget = this[options.type](name, options.attributes || {});

      p.append(label, widget);
      container.append(p);

      this.fields[name] = widget;
    }, this);
  },

  addWidget: function addWidget(el) {
    this.$el.find('.form-widgets').append(el);
  },

  getField: function getField(key) {
    return this.$el.find('[name="' + key + '"]');
  },

  serialize: function serialize() {
    var v, type, data = {};
    _.each(this.fields, function(widget, key) {
      type = widget.attr('type');
      if(type === 'checkbox') {
        v = widget.prop('checked');
      } else {
        v = widget.val();
      }
      data[key] = v;
    });
    return  data;
  },

  unload: function unload() {
    this.model = null;
    this.el.reset();
    this.trigger('unload');
  },

  load: function load(id) {
    var model = this.model = this.collection.get(id);
    _.each(model.attributes, function(value, key) {
      var field = this.getField(key);
      if(typeof value === 'boolean') {
        field.prop('checked', value);
      } else {
        field.val(value);
      }
    }, this);
    this.trigger('load', model);
  },

  onSubmit: function onSubmit() {
    var data = this.serialize();
    if(!this.model) {
      this.model = this.collection.create(data);
    } else {
      this.model.save(data);
    }
    this.model.once('sync', function() {
      alert('Saved!');
      this.trigger('saved', this.model);
    }, this);
    return false;
  }

});<|endoftext|>


<commit_before>
import Marionette from 'backbone.marionette';
import LoginModalView from './loginModal';
import ThemeCollection from 'collection/theme';
import ThemeThumbList from 'ui/themeThumbList';
import SearchInput from 'ui/form/searchInput';
import template from 'templates/homeRoot.ejs';

export default Marionette.LayoutView.extend({
    template,

    behaviors: {
        l20n: {},
    },

    ui: {
        createThemeButton: '.create_theme_btn',
        scrollTarget: '.scroll_target',
        searchResults: '#rg_search_results',
        noResultPlaceholder: '.no_result',
        charactersLeftPlaceholder: '.characters_left',
        charactersLeftPlaceholderText: '.characters_left .text',
    },

    regions: {
        searchInput: '.rg_search_input',
        searchResults: '#rg_search_results',
    },

    events: {
        'click @ui.createThemeButton': 'onClickCreateTheme',
    },

    initialize(options) {
        this._app = options.app;
        this._window = this._app.getWindow();
        this._document = this._app.getDocument();

        this.resetThemeCollection();
    },

    onRender() {
        this._searchInput = new SearchInput({
            placeholder: document.l10n.getSync('searchATheme'),
        });

        this.getRegion('searchInput').show( this._searchInput );

        this._searchInput.on('empty', this.resetThemeCollection, this);
        this._searchInput.on('notEnoughCharacters', this.showCharactersLeftPlaceholder, this);
        this._searchInput.on('search', this.fetchSearchedThemes, this);
        this._searchInput.on('focus', this._scrollToSearchInput, this);
        this._searchInput.on('keyup', this._scrollToSearchInput, this);
        this._searchInput.setFocus();

        this.getRegion('searchResults').show(
            new ThemeThumbList({
                collection: this.collection,
            })
        );
    },

    _scrollToSearchInput() {
        window.requestAnimationFrame(() => {
            this.ui.scrollTarget[0].scrollIntoView({ behavior: 'smooth' });
        });
    },

    onClickCreateTheme() {
        if (this._app.isLogged()) {
            window.location.replace('/create_theme');
        }
        else {
            this.displayLoginModal();
        }
    },

    fetchSearchedThemes(searchString) {
        this.collection.fetch({
            reset: true,
            merge: false,
            data: {
                q: searchString,
                hasLayer: true,
            },
            success: (collection, response, options) => {
                this.onThemesFetchSuccess(collection, response, options);
                this._searchInput.trigger('search:success');
            },
            error: (collection, response, options) => {
                this.onThemesFetchError(collection, response, options);
                this._searchInput.trigger('search:error');
            },
        });
    },

    onThemesFetchSuccess(collection) {
        if (collection.models.length === 0) {
            this.showNoResultPlaceholder();
        }
        else {
            this.showResults();
        }
    },

    onThemesFetchError() {
        this.showNoResultPlaceholder();
    },

    resetThemeCollection() {
        this.collection = new ThemeCollection();

        if (MAPCONTRIB.highlightList) {
            this.collection.add(
                JSON.parse(unescape( MAPCONTRIB.highlightList ))
            );
        }

        this.render();
        this.showResults();
    },

    displayLoginModal() {
        new LoginModalView({
            authSuccessCallback: '/create_theme',
            authFailCallback: '/',
        }).open();
    },

    showCharactersLeftPlaceholder(searchString) {
        this._scrollToSearchInput();

        const charactersLeft = 3 - searchString.length;

        this.ui.charactersLeftPlaceholderText.html(
            document.l10n.getSync(
                'home_charactersLeft',
                { n: charactersLeft }
            )
        );

        this.ui.noResultPlaceholder.addClass('hide');
        this.ui.searchResults.addClass('hide');
        this.ui.charactersLeftPlaceholder.removeClass('hide');
    },

    showNoResultPlaceholder() {
        this._scrollToSearchInput();

        this.ui.searchResults.addClass('hide');
        this.ui.charactersLeftPlaceholder.addClass('hide');
        this.ui.noResultPlaceholder.removeClass('hide');
    },

    showResults() {
        this._scrollToSearchInput();

        this.ui.noResultPlaceholder.addClass('hide');
        this.ui.charactersLeftPlaceholder.addClass('hide');
        this.ui.searchResults.removeClass('hide');
    },

    hidePlaceholders() {
        this.ui.charactersLeftPlaceholder.addClass('hide');
        this.ui.noResultPlaceholder.addClass('hide');
    },
});
<commit_msg>Don't scroll by default on the home page<commit_after>
import Marionette from 'backbone.marionette';
import LoginModalView from './loginModal';
import ThemeCollection from 'collection/theme';
import ThemeThumbList from 'ui/themeThumbList';
import SearchInput from 'ui/form/searchInput';
import template from 'templates/homeRoot.ejs';

export default Marionette.LayoutView.extend({
    template,

    behaviors: {
        l20n: {},
    },

    ui: {
        createThemeButton: '.create_theme_btn',
        scrollTarget: '.scroll_target',
        searchResults: '#rg_search_results',
        noResultPlaceholder: '.no_result',
        charactersLeftPlaceholder: '.characters_left',
        charactersLeftPlaceholderText: '.characters_left .text',
    },

    regions: {
        searchInput: '.rg_search_input',
        searchResults: '#rg_search_results',
    },

    events: {
        'click @ui.createThemeButton': 'onClickCreateTheme',
    },

    initialize(options) {
        this._app = options.app;
        this._window = this._app.getWindow();
        this._document = this._app.getDocument();

        this.resetThemeCollection();
    },

    onRender() {
        this._searchInput = new SearchInput({
            placeholder: document.l10n.getSync('searchATheme'),
        });

        this.getRegion('searchInput').show( this._searchInput );

        this._searchInput.on('empty', this.resetThemeCollection, this);
        this._searchInput.on('notEnoughCharacters', this.showCharactersLeftPlaceholder, this);
        this._searchInput.on('search', this.fetchSearchedThemes, this);
        this._searchInput.on('focus', this._scrollToSearchInput, this);
        this._searchInput.on('keyup', this._scrollToSearchInput, this);
        this._searchInput.setFocus();

        this.getRegion('searchResults').show(
            new ThemeThumbList({
                collection: this.collection,
            })
        );
    },

    _scrollToSearchInput() {
        window.requestAnimationFrame(() => {
            this.ui.scrollTarget[0].scrollIntoView({ behavior: 'smooth' });
        });
    },

    onClickCreateTheme() {
        if (this._app.isLogged()) {
            window.location.replace('/create_theme');
        }
        else {
            this.displayLoginModal();
        }
    },

    fetchSearchedThemes(searchString) {
        this.collection.fetch({
            reset: true,
            merge: false,
            data: {
                q: searchString,
                hasLayer: true,
            },
            success: (collection, response, options) => {
                this.onThemesFetchSuccess(collection, response, options);
                this._searchInput.trigger('search:success');
                this._scrollToSearchInput();
            },
            error: (collection, response, options) => {
                this.onThemesFetchError(collection, response, options);
                this._searchInput.trigger('search:error');
            },
        });
    },

    onThemesFetchSuccess(collection) {
        if (collection.models.length === 0) {
            this.showNoResultPlaceholder();
        }
        else {
            this.showResults();
        }
    },

    onThemesFetchError() {
        this.showNoResultPlaceholder();
    },

    resetThemeCollection() {
        this.collection = new ThemeCollection();

        if (MAPCONTRIB.highlightList) {
            this.collection.add(
                JSON.parse(unescape( MAPCONTRIB.highlightList ))
            );
        }

        this.render();
        this.showResults();
    },

    displayLoginModal() {
        new LoginModalView({
            authSuccessCallback: '/create_theme',
            authFailCallback: '/',
        }).open();
    },

    showCharactersLeftPlaceholder(searchString) {
        this._scrollToSearchInput();

        const charactersLeft = 3 - searchString.length;

        this.ui.charactersLeftPlaceholderText.html(
            document.l10n.getSync(
                'home_charactersLeft',
                { n: charactersLeft }
            )
        );

        this.ui.noResultPlaceholder.addClass('hide');
        this.ui.searchResults.addClass('hide');
        this.ui.charactersLeftPlaceholder.removeClass('hide');
    },

    showNoResultPlaceholder() {
        this._scrollToSearchInput();

        this.ui.searchResults.addClass('hide');
        this.ui.charactersLeftPlaceholder.addClass('hide');
        this.ui.noResultPlaceholder.removeClass('hide');
    },

    showResults() {
        this.ui.noResultPlaceholder.addClass('hide');
        this.ui.charactersLeftPlaceholder.addClass('hide');
        this.ui.searchResults.removeClass('hide');
    },

    hidePlaceholders() {
        this.ui.charactersLeftPlaceholder.addClass('hide');
        this.ui.noResultPlaceholder.addClass('hide');
    },
});
<|endoftext|>


<commit_before>define(['marionette', 'backgrid', 'views/table', 'views/filter',
  'collections/componenttypes',
  'modules/projects/views/addto',
  'utils/table',
  'templates/samples/proteinlist.html'],
  function(Marionette, Backgrid, TableView, FilterView, ComponentTypes, AddToProjectView, table, Template) {

  var ClickableRow = table.ClickableRow.extend({
    event: 'proteins:view',
    argument: 'PROTEINID',
    cookie: true,
  })

  return Marionette.LayoutView.extend({
    className: 'content',
    template: Template,
    regions: { 'wrap': '.wrapper', type: '.type' },
    // ui: {
    //   add: 'a.add',
    // },

    clickableRow: ClickableRow,
    showFilter: true,

    title: 'Protein',
    url: 'protein',

    templateHelpers: function() {
        var validOnly = app.options.get('valid_components')
        return {
          title: this.getOption('title'),
          url: this.getOption('url'),
          CAN_CREATE: ((validOnly && app.staff) || !validOnly) && (app.proposal && app.proposal.get('ACTIVE') == 1),
        }
    },

    columns: [
        { name: 'NAME', label: 'Name', cell: 'string', editable: false },
        { name: 'ACRONYM', label: 'Acronym', cell: 'string', editable: false },
        { name: 'MOLECULARMASS', label: 'Mass', cell: 'string', editable: false },
        { name: 'HASSEQ', label: 'Sequence', cell: 'string', editable: false },
        { name: 'PDBS', label: 'PDBs', cell: 'string', editable: false },
        { name: 'COMPONENTTYPE', label: 'Type', cell: 'string', editable: false },
        { name: 'CONCENTRATIONTYPE', label: 'Unit', cell: 'string', editable: false },
        { name: 'SCOUNT', label: 'Samples', cell: 'string', editable: false },
        { name: 'DCOUNT', label: 'Data Collections', cell: 'string', editable: false },
        { name: 'SAFETYLEVEL', label: 'Risk Rating', cell: table.SafetyCell, editable: false },
        { name: ' ', cell: table.ProjectCell, itemname: 'ACRONYM', itemid: 'PROTEINID', itemtype:'protein', editable: false },
    ],

    hiddenColumns: [2,3,5],

    selectModel: function(m, checked) {
        console.log('model seleted in grid')
        m.set({ isGridSelected: checked })
    },

    initialize: function(options) {
      if (app.mobile()) {
        _.each(this.getOption('hiddenColumns'), function(v) {
            this.getOption('columns')[v].renderable = false
        }, this)
      }

      var cols = this.getOption('columns').slice(0)
      if (options.selectable) {
          cols.unshift({ label: '', cell: 'select-row', headerCell: 'select-all', editable: false })
          this.options.clickableRow = Backgrid.Row
          this.listenTo(this.collection, 'backgrid:selected', this.selectModel, this)
      }

      var self = this
      this.table = new TableView({ collection: options.collection, columns: cols, tableClass: 'proposals', filter: 's', search: options.params && options.params.s, loading: true,
        backgrid: {
          row: this.getOption('clickableRow'),
          emptyText: function() {
            return self.collection.fetched ? 'No '+self.getOption('title')+'s found' : 'Retrieving '+self.getOption('title')+'s'
          }
        }, noPageUrl: options.noPageUrl, noSearchUrl: options.noSearchUrl })

      this.types = new ComponentTypes()
      this.tr = this.types.fetch()
    },

    onRender: function() {
      // if (app.proposal && app.proposal.get('ACTIVE') != 1) this.ui.add.hide()

      this.wrap.show(this.table)
      if (this.getOption('showFilter')) this.tr.done(this.showFilter.bind(this))
    },

    showFilter: function() {
        this.ty = new FilterView({
            url: !this.getOption('noFilterUrl'),
            collection: this.getOption('collection'),
            value: this.getOption('params') && this.getOption('params').ty,
            name: 'type',
            filters: this.types.map(function(m) { return { id: m.get('COMPONENTTYPEID'), name: m.get('NAME') } })
        })
        this.type.show(this.ty)
    },

    onShow: function() {
      this.table.focusSearch()
    },
  })

})
<commit_msg>AddToProjectView is not required in proteinlist.js<commit_after>define(['marionette', 'backgrid', 'views/table', 'views/filter',
  'collections/componenttypes',
  'utils/table',
  'templates/samples/proteinlist.html'],
  function(Marionette, Backgrid, TableView, FilterView, ComponentTypes, table, Template) {

  var ClickableRow = table.ClickableRow.extend({
    event: 'proteins:view',
    argument: 'PROTEINID',
    cookie: true,
  })

  return Marionette.LayoutView.extend({
    className: 'content',
    template: Template,
    regions: { 'wrap': '.wrapper', type: '.type' },
    // ui: {
    //   add: 'a.add',
    // },

    clickableRow: ClickableRow,
    showFilter: true,

    title: 'Protein',
    url: 'protein',

    templateHelpers: function() {
        var validOnly = app.options.get('valid_components')
        return {
          title: this.getOption('title'),
          url: this.getOption('url'),
          CAN_CREATE: ((validOnly && app.staff) || !validOnly) && (app.proposal && app.proposal.get('ACTIVE') == 1),
        }
    },

    columns: [
        { name: 'NAME', label: 'Name', cell: 'string', editable: false },
        { name: 'ACRONYM', label: 'Acronym', cell: 'string', editable: false },
        { name: 'MOLECULARMASS', label: 'Mass', cell: 'string', editable: false },
        { name: 'HASSEQ', label: 'Sequence', cell: 'string', editable: false },
        { name: 'PDBS', label: 'PDBs', cell: 'string', editable: false },
        { name: 'COMPONENTTYPE', label: 'Type', cell: 'string', editable: false },
        { name: 'CONCENTRATIONTYPE', label: 'Unit', cell: 'string', editable: false },
        { name: 'SCOUNT', label: 'Samples', cell: 'string', editable: false },
        { name: 'DCOUNT', label: 'Data Collections', cell: 'string', editable: false },
        { name: 'SAFETYLEVEL', label: 'Risk Rating', cell: table.SafetyCell, editable: false },
        { name: ' ', cell: table.ProjectCell, itemname: 'ACRONYM', itemid: 'PROTEINID', itemtype:'protein', editable: false },
    ],

    hiddenColumns: [2,3,5],

    selectModel: function(m, checked) {
        console.log('model seleted in grid')
        m.set({ isGridSelected: checked })
    },

    initialize: function(options) {
      if (app.mobile()) {
        _.each(this.getOption('hiddenColumns'), function(v) {
            this.getOption('columns')[v].renderable = false
        }, this)
      }

      var cols = this.getOption('columns').slice(0)
      if (options.selectable) {
          cols.unshift({ label: '', cell: 'select-row', headerCell: 'select-all', editable: false })
          this.options.clickableRow = Backgrid.Row
          this.listenTo(this.collection, 'backgrid:selected', this.selectModel, this)
      }

      var self = this
      this.table = new TableView({ collection: options.collection, columns: cols, tableClass: 'proposals', filter: 's', search: options.params && options.params.s, loading: true,
        backgrid: {
          row: this.getOption('clickableRow'),
          emptyText: function() {
            return self.collection.fetched ? 'No '+self.getOption('title')+'s found' : 'Retrieving '+self.getOption('title')+'s'
          }
        }, noPageUrl: options.noPageUrl, noSearchUrl: options.noSearchUrl })

      this.types = new ComponentTypes()
      this.tr = this.types.fetch()
    },

    onRender: function() {
      // if (app.proposal && app.proposal.get('ACTIVE') != 1) this.ui.add.hide()

      this.wrap.show(this.table)
      if (this.getOption('showFilter')) this.tr.done(this.showFilter.bind(this))
    },

    showFilter: function() {
        this.ty = new FilterView({
            url: !this.getOption('noFilterUrl'),
            collection: this.getOption('collection'),
            value: this.getOption('params') && this.getOption('params').ty,
            name: 'type',
            filters: this.types.map(function(m) { return { id: m.get('COMPONENTTYPEID'), name: m.get('NAME') } })
        })
        this.type.show(this.ty)
    },

    onShow: function() {
      this.table.focusSearch()
    },
  })

})
<|endoftext|>


<commit_before>var g_blog;

function displayBlog2HTML(blog,callback) {
  var menuHTML,blogHTML;

  Handlebars.registerHelper("encodeText", function (str) {
    return str.replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """).replace(/\n/g,"
");
  });

  function getBoth() {
    if (menuHTML && blogHTML) {
      callback(menuHTML + blogHTML);
    }
  }

  getTemplateSource("menu",function (source) {
    menuHTML = source;
    getBoth()
  });

  getTemplateSource("blog",function(source) {
    var template = Handlebars.compile(source);
    console.log(blog);
    blogHTML = template(blog);
    getBoth();
  });
}

function displayBlog(blog) {
  displayBlog2HTML(blog,function (html) {
    document.getElementById("main").innerHTML = html;
  });
}

function loadBlogFromServer(blogID) {
  req = {
    type: "blog",
    action: "load",
    blogID: blogID
  };
  datastore(req, function (res) {
    if (res.success) {
      var blog = new Blog("","","");
      blog.loadObject(res.blog);
      g_blog = blog;
      displayBlog(blog);
    } else {
      error(res.data);
    }
  });
}

function editBlogTitle() {
  g_blog.editBlogTitle = true;
  displayBlog(g_blog);
}

function saveBlogTitleChange() {
  var title = getBlogTitle();
  if (title != g_blog.title && g_blogList.hasTitle(title)) {
    alert("Another blog already has this title: " + title);
    return
  }
  g_blog.editTitle(getBlogTitle());
  g_blog.editBlogTitle = false;
  displayBlog(g_blog);
  var req = {
    "type": "blogInfo",
    "action": "save",
    "blogInfo": new BlogInfo(g_blog.blogID,g_blog.blogID, g_blog.title,g_blog.userID)
  }
  datastore(req, function (res) {
    if (!res.success) {
      error(res.error);
    }
  });
}

function cancelBlogTitleChange() {
  g_blog.editBlogTitle = false;
  displayBlog(g_blog);
}

function addPost() {
  var domID = g_blog.getDOMID()
  g_blog.addPost(new Post(domID,"","","",new Date(),g_blog.blogID,g_blog.userID));
  g_blog.editPost(domID);
  displayBlog(g_blog);
}

function getPost() {
  var dateOnly = document.getElementById("postdateonly").value
  var timeOnly = document.getElementById("posttimeonly").value
  var date = new Date(dateOnly + " " + timeOnly)
  return {
    domID: document.getElementById("postdomid").value,
    postID: document.getElementById("postpostid").value,
    title: document.getElementById("posttitle").value,
    text: document.getElementById("posttext").value,
    date: date,
    blogID: document.getElementById("postblogid").value,
    userID: document.getElementById("postuserid").value,
    dateOnly: dateOnly,
    timeOnly: timeOnly
  };
}

function getBlogTitle() {
  return document.getElementById("blogtitle").value
}

function savePostChanges(domID) {
  var values = getPost();
  var post = new Post(values.domID,values.postID,values.title,values.text,values.date,values.blogID,values.userID);
  g_blog.stopEditingPost(domID);
  if (post.postID) {
    g_blog.savePost(domID,post);
    displayBlog(g_blog);
    req = {
      type: "post",
      action: "save",
      post: post
    }
    datastore(req,function (res) {
      if (!res.success) {
        error(res.error);
      }
    });
  } else {
    g_blog.savePost(domID,post);
    displayBlog(g_blog);
    req = {
      type: "post",
      action: "create",
      post: post
    }
    datastore(req,function (res) {
      if (res.success) {
        g_blog.updatePostID(domID,res.postID)
        displayBlog(g_blog);
      } else {
        error(res.error);
      }
    });
  }
}

function cancelPostChanges(domID) {
  var values = getPost();
  var post = g_blog.getPost(domID);
  if (post.postID) {
    g_blog.stopEditingPost(domID);
  } else {
    g_blog.deletePost(domID);
  }
  displayBlog(g_blog);
}

function editPost(domID) {
  g_blog.editPost(domID);
  displayBlog(g_blog);
}

function deletePost(domID) {
  post = g_blog.deletePost(domID);
  displayBlog(g_blog);
  req = {
    type: "post",
    action: "delete",
    postID: post.postID
  }
  datastore(req,function (res) {
    if (res.success) {
    } else {
      error(res.error);
    }
  });
}
<commit_msg>fix error<commit_after>var g_blog;

function displayBlog2HTML(blog,callback) {
  var menuHTML,blogHTML;

  Handlebars.registerHelper("encodeText", function (str) {
    return str.replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """).replace(/\n/g,"
");
  });

  function getBoth() {
    if (menuHTML && blogHTML) {
      callback(menuHTML + blogHTML);
    }
  }

  getTemplateSource("menu",function (source) {
    menuHTML = source;
    getBoth()
  });

  getTemplateSource("blog",function(source) {
    var template = Handlebars.compile(source);
    console.log(blog);
    blogHTML = template(blog);
    getBoth();
  });
}

function displayBlog(blog) {
  displayBlog2HTML(blog,function (html) {
    document.getElementById("main").innerHTML = html;
  });
}

function loadBlogFromServer(blogID) {
  req = {
    type: "blog",
    action: "load",
    blogID: blogID
  };
  datastore(req, function (res) {
    if (res.success) {
      var blog = new Blog("","","");
      blog.loadObject(res.blog);
      g_blog = blog;
      displayBlog(blog);
    } else {
      error(res.error);
    }
  });
}

function editBlogTitle() {
  g_blog.editBlogTitle = true;
  displayBlog(g_blog);
}

function saveBlogTitleChange() {
  var title = getBlogTitle();
  if (title != g_blog.title && g_blogList.hasTitle(title)) {
    alert("Another blog already has this title: " + title);
    return
  }
  g_blog.editTitle(getBlogTitle());
  g_blog.editBlogTitle = false;
  displayBlog(g_blog);
  var req = {
    "type": "blogInfo",
    "action": "save",
    "blogInfo": new BlogInfo(g_blog.blogID,g_blog.blogID, g_blog.title,g_blog.userID)
  }
  datastore(req, function (res) {
    if (!res.success) {
      error(res.error);
    }
  });
}

function cancelBlogTitleChange() {
  g_blog.editBlogTitle = false;
  displayBlog(g_blog);
}

function addPost() {
  var domID = g_blog.getDOMID()
  g_blog.addPost(new Post(domID,"","","",new Date(),g_blog.blogID,g_blog.userID));
  g_blog.editPost(domID);
  displayBlog(g_blog);
}

function getPost() {
  var dateOnly = document.getElementById("postdateonly").value
  var timeOnly = document.getElementById("posttimeonly").value
  var date = new Date(dateOnly + " " + timeOnly)
  return {
    domID: document.getElementById("postdomid").value,
    postID: document.getElementById("postpostid").value,
    title: document.getElementById("posttitle").value,
    text: document.getElementById("posttext").value,
    date: date,
    blogID: document.getElementById("postblogid").value,
    userID: document.getElementById("postuserid").value,
    dateOnly: dateOnly,
    timeOnly: timeOnly
  };
}

function getBlogTitle() {
  return document.getElementById("blogtitle").value
}

function savePostChanges(domID) {
  var values = getPost();
  var post = new Post(values.domID,values.postID,values.title,values.text,values.date,values.blogID,values.userID);
  g_blog.stopEditingPost(domID);
  if (post.postID) {
    g_blog.savePost(domID,post);
    displayBlog(g_blog);
    req = {
      type: "post",
      action: "save",
      post: post
    }
    datastore(req,function (res) {
      if (!res.success) {
        error(res.error);
      }
    });
  } else {
    g_blog.savePost(domID,post);
    displayBlog(g_blog);
    req = {
      type: "post",
      action: "create",
      post: post
    }
    datastore(req,function (res) {
      if (res.success) {
        g_blog.updatePostID(domID,res.postID)
        displayBlog(g_blog);
      } else {
        error(res.error);
      }
    });
  }
}

function cancelPostChanges(domID) {
  var values = getPost();
  var post = g_blog.getPost(domID);
  if (post.postID) {
    g_blog.stopEditingPost(domID);
  } else {
    g_blog.deletePost(domID);
  }
  displayBlog(g_blog);
}

function editPost(domID) {
  g_blog.editPost(domID);
  displayBlog(g_blog);
}

function deletePost(domID) {
  post = g_blog.deletePost(domID);
  displayBlog(g_blog);
  req = {
    type: "post",
    action: "delete",
    postID: post.postID
  }
  datastore(req,function (res) {
    if (res.success) {
    } else {
      error(res.error);
    }
  });
}
<|endoftext|>


<commit_before>(function() {
  var app = angular.module('discores', ['ngRoute']);

  app.config(['$routeProvider', function($routeProvider) {
    $routeProvider
      .when('/courses', {
        templateUrl: '/views/courses.html',
        controller: 'CourseCtrl',
        controllerAs: 'courseCtrl'
      })
      .when('/players/:playerId/games', {
        templateUrl:'views/player-games.html',
        controller: 'PlayerGamesCtrl',
        controllerAs: 'playerGamesCtrl'
      })
      .when('/players', {
        templateUrl: '/views/players.html',
        controller: 'PlayerCtrl',
        controllerAs: 'playerCtrl'
      })
      .when('/game/results/:gameId', {
        templateUrl: 'views/game-results.html',
        controller: 'ResultsCtrl',
        controllerAs: 'resultsCtrl'
      })
      .when('/game/:gameId/:holeNumber', {
        templateUrl: 'views/play-game.html',
        controller: 'PlayCtrl',
        controllerAs: 'playCtrl'
      })
      .when('/game', {
        templateUrl: '/views/create-game.html',
        controller: 'GameCtrl',
        controllerAs: 'gameCtrl'
      })
      .otherwise({
        redirectTo: '/game'
      });
  }]);

  app.controller('ResultsCtrl', ['$scope', '$http', '$routeParams', function($scope, $http, $routeParams) {
    var self = this;
    self.game = null;
    self.holes = [];
    self.playersScores = [];

    $http.get('/api/game/' + $routeParams.gameId)
      .success(function(g) {
        self.game = g;

        for (var i = 0; i < self.game.course.numberOfHoles; i++) {
          self.holes.push(i + 1);
        }

        self.game.players.forEach(function(p) {
          var sum = self.game.scores[p.id].reduce(function(sum, h) {
            sum += h;
            return sum;
          }, 0);

          var result = '';
          if (sum === self.game.course.par) {
            result = 'E';
          } else {
            result = 0 - (self.game.course.par - sum);
          }

          self.playersScores.push({
            'name': p.name,
            'scores': self.game.scores[p.id],
            'result': result
          })
        });
      });
  }]);

  app.controller('PlayCtrl', ['$scope', '$http', '$routeParams', '$location', function($scope, $http, $routeParams, $location) {
    var self = this;

    self.game = null;
    self.holeNumber = $routeParams.holeNumber;
    self.holeScores = {};
    self.nextHoleBtnLabel = self.holeNumber != 18 ? 'Next Hole' : 'Finish Game';

    self.prevHole = function() {
      var prevHole = self.holeNumber - 1;
      $location.path('/game/' + self.game.id + '/' + prevHole);
    };

    self.nextHole = function() {
      if (self.holeNumber < 1) {
        alert('Oh no! Invalid URL. Current hole is less than 1. Go Go Hole 1.');
        $location.path('/game/' + self.game.id + '/' + 1);
      }

      // Save the current hole
      self.game.players.forEach(function(p) {
        self.game.scores[p.id][self.holeNumber-1] = self.holeScores[p.id];
      });

      $http.post('/api/game/update', self.game)
        .success(function(game) {
          self.holeNumber++;
          if (self.holeNumber > self.game.course.numberOfHoles) {
            $location.path('/game/results/' + game.id + '/');
          } else {
            $location.path('/game/' + game.id + '/' + self.holeNumber);
          }
        })
        .error(function(e) {
          alert('Uh oh! Error moving to next hole :(');
        });
    };

    $http.get('/api/game/' + $routeParams.gameId)
      .success(function(g) {
        self.game = g;

        self.game.players.forEach(function(p) {
          self.holeScores[p.id] = self.game.scores[p.id][self.holeNumber-1] || 0;
        });
      });
  }]);

  app.controller('PlayerGamesCtrl', ['$scope', '$http', '$routeParams', function ($scope, $http, $routeParams) {
    var self = this;

    self.games = [];
    self.playerId = $routeParams.playerId;
    self.playerNameLabel = null;

    $http.get('/api/players/' + self.playerId)
      .success(function(data) {
        self.playerNameLabel = data.name + "'s Games";
      });

    $http.get('/api/players/' + self.playerId + '/games/')
      .success(function(data) {
        self.games = data.map(function(g) {
          var sum = g.scores[self.playerId].reduce(function(sum, h) {
            sum += h;
            return sum;
          }, 0);
          g.myResult = 0 - (g.course.par - sum);
          return g;
        });
      });

  }]);

  app.controller('GameCtrl', ['$scope', '$http', '$routeParams', '$location', function ($scope, $http, $routeParams, $location) {
    var self = this;

    $scope.$parent.tab = 0;

    self.allCourses = [];
    self.allPlayers = [];
    self.selectedCourse = null;
    self.selectedPlayers = [];
    self.newPlayer = null;

    self.startGame = function() {
      if (!self.selectedPlayers.length || !self.selectedCourse) {
        return;
      }

      var courseName = self.selectedCourse.name;
      var playersNames = _.pluck(self.selectedPlayers, 'name').join(',');
      console.log('Starting game at ' + courseName + ' with ' + playersNames);

      // Begin the game and change the view
      var newGame = {
        course: self.selectedCourse,
        players: self.selectedPlayers
      };

      $http.post('/api/game', newGame)
        .success(function(game) {
          // Change window location
          $location.path('/game/' + game.id + '/' + 1);
        })
        .error(function(e) {
          alert('Whoops! Error beginning game');
        });
    };

    self.addPlayer = function() {
      for (var i = 0; i < self.selectedPlayers.length; i++) {
        if (self.selectedPlayers[i].id === self.newPlayer.id) {
          alert('Player already added');
          return;
        }
      }

      self.selectedPlayers.push(self.newPlayer);
      self.newPlayer = null;
    }

    self.removePlayer = function(player) {
      if (!player) return;

      self.selectedPlayers = self.selectedPlayers.filter(function(p) {
        return p.id !== player.id;
      });
    }

    $http.get('/api/players')
      .success(function(data) {
        self.allPlayers.length = 0;
        data.forEach(function(p) {
          self.allPlayers.push(p);
        });
      });

    $http.get('/api/courses')
      .success(function(data) {
        self.allCourses.length = 0;
        data.forEach(function(c) {
          self.allCourses.push(c);
        });
      });
  }]);

  app.controller('CourseCtrl', ['$scope', '$http', '$routeParams', function($scope, $http, $routeParams) {
    var self = this;

    $scope.$parent.tab = 1;

    self.courses = [];

    self.newName = '';
    self.newPar = '';
    self.newNumberOfHoles = '';

    self.save = function() {
      if (!self.newName || self.newPar < 1 || self.newNumberOfHoles < 1) {
        return;
      }

      var courseToSave = {
        'name': self.newName,
        'par': self.newPar,
        'numberOfHoles': self.newNumberOfHoles
      };

      $http.post('/api/courses', courseToSave)
        .success(function() {
          self.courses.push(courseToSave);
        })
        .error(function(e) {
          alert('OH NOES!');
        });
    };

    $http.get('/api/courses')
      .success(function(data) {
        self.courses.length = 0;
        data.forEach(function(c) {
          self.courses.push(c);
        });
      });
  }]);

  app.controller('PlayerCtrl', ['$scope', '$http', '$routeParams', function ($scope, $http, $routeParams) {
    var self = this;

    $scope.$parent.tab = 2;

    self.players = [];

    self.newPlayerName = '';

    self.save = function() {
      if (!self.newPlayerName) return;

      var playerToSave = { 'name': self.newPlayerName };
      $http.post('/api/players', playerToSave)
        .success(function() {
          self.players.push(playerToSave);
        })
        .error(function(e) {
          alert('OH NOES - Something went wrong');
        });

      self.newPlayerName = '';
    };

    $http.get('/api/players')
      .success(function(data) {
        self.players.length = 0;
        data.forEach(function(p) {
          self.players.push(p);
        });
      });
  }]);
})();
<commit_msg>Updating so if course played during game is anything other than 17 holes, the label will still read 'Finish Game' rather than 'Next Hole'<commit_after>(function() {
  var app = angular.module('discores', ['ngRoute']);

  app.config(['$routeProvider', function($routeProvider) {
    $routeProvider
      .when('/courses', {
        templateUrl: '/views/courses.html',
        controller: 'CourseCtrl',
        controllerAs: 'courseCtrl'
      })
      .when('/players/:playerId/games', {
        templateUrl:'views/player-games.html',
        controller: 'PlayerGamesCtrl',
        controllerAs: 'playerGamesCtrl'
      })
      .when('/players', {
        templateUrl: '/views/players.html',
        controller: 'PlayerCtrl',
        controllerAs: 'playerCtrl'
      })
      .when('/game/results/:gameId', {
        templateUrl: 'views/game-results.html',
        controller: 'ResultsCtrl',
        controllerAs: 'resultsCtrl'
      })
      .when('/game/:gameId/:holeNumber', {
        templateUrl: 'views/play-game.html',
        controller: 'PlayCtrl',
        controllerAs: 'playCtrl'
      })
      .when('/game', {
        templateUrl: '/views/create-game.html',
        controller: 'GameCtrl',
        controllerAs: 'gameCtrl'
      })
      .otherwise({
        redirectTo: '/game'
      });
  }]);

  app.controller('ResultsCtrl', ['$scope', '$http', '$routeParams', function($scope, $http, $routeParams) {
    var self = this;
    self.game = null;
    self.holes = [];
    self.playersScores = [];

    $http.get('/api/game/' + $routeParams.gameId)
      .success(function(g) {
        self.game = g;

        for (var i = 0; i < self.game.course.numberOfHoles; i++) {
          self.holes.push(i + 1);
        }

        self.game.players.forEach(function(p) {
          var sum = self.game.scores[p.id].reduce(function(sum, h) {
            sum += h;
            return sum;
          }, 0);

          var result = '';
          if (sum === self.game.course.par) {
            result = 'E';
          } else {
            result = 0 - (self.game.course.par - sum);
          }

          self.playersScores.push({
            'name': p.name,
            'scores': self.game.scores[p.id],
            'result': result
          })
        });
      });
  }]);

  app.controller('PlayCtrl', ['$scope', '$http', '$routeParams', '$location', function($scope, $http, $routeParams, $location) {
    var self = this;

    self.game = null;
    self.holeNumber = $routeParams.holeNumber;
    self.holeScores = {};
    self.nextHoleBtnLabel = 'Next Hole';

    self.prevHole = function() {
      var prevHole = self.holeNumber - 1;
      $location.path('/game/' + self.game.id + '/' + prevHole);
    };

    self.nextHole = function() {
      if (self.holeNumber < 1) {
        alert('Oh no! Invalid URL. Current hole is less than 1. Go Go Hole 1.');
        $location.path('/game/' + self.game.id + '/' + 1);
      }

      // Save the current hole
      self.game.players.forEach(function(p) {
        self.game.scores[p.id][self.holeNumber-1] = self.holeScores[p.id];
      });

      $http.post('/api/game/update', self.game)
        .success(function(game) {
          self.holeNumber++;
          if (self.holeNumber > self.game.course.numberOfHoles) {
            $location.path('/game/results/' + game.id + '/');
          } else {
            $location.path('/game/' + game.id + '/' + self.holeNumber);
          }
        })
        .error(function(e) {
          alert('Uh oh! Error moving to next hole :(');
        });
    };

    $http.get('/api/game/' + $routeParams.gameId)
      .success(function(g) {
        self.game = g;

        if (self.game.course.numberOfHoles == self.holeNumber) {
          self.nextHoleBtnLabel = 'Finish Game';
        }

        self.game.players.forEach(function(p) {
          self.holeScores[p.id] = self.game.scores[p.id][self.holeNumber-1] || 0;
        });
      });
  }]);

  app.controller('PlayerGamesCtrl', ['$scope', '$http', '$routeParams', function ($scope, $http, $routeParams) {
    var self = this;

    self.games = [];
    self.playerId = $routeParams.playerId;
    self.playerNameLabel = null;

    $http.get('/api/players/' + self.playerId)
      .success(function(data) {
        self.playerNameLabel = data.name + "'s Games";
      });

    $http.get('/api/players/' + self.playerId + '/games/')
      .success(function(data) {
        self.games = data.map(function(g) {
          var sum = g.scores[self.playerId].reduce(function(sum, h) {
            sum += h;
            return sum;
          }, 0);
          g.myResult = 0 - (g.course.par - sum);
          return g;
        });
      });

  }]);

  app.controller('GameCtrl', ['$scope', '$http', '$routeParams', '$location', function ($scope, $http, $routeParams, $location) {
    var self = this;

    $scope.$parent.tab = 0;

    self.allCourses = [];
    self.allPlayers = [];
    self.selectedCourse = null;
    self.selectedPlayers = [];
    self.newPlayer = null;

    self.startGame = function() {
      if (!self.selectedPlayers.length || !self.selectedCourse) {
        return;
      }

      var courseName = self.selectedCourse.name;
      var playersNames = _.pluck(self.selectedPlayers, 'name').join(',');
      console.log('Starting game at ' + courseName + ' with ' + playersNames);

      // Begin the game and change the view
      var newGame = {
        course: self.selectedCourse,
        players: self.selectedPlayers
      };

      $http.post('/api/game', newGame)
        .success(function(game) {
          // Change window location
          $location.path('/game/' + game.id + '/' + 1);
        })
        .error(function(e) {
          alert('Whoops! Error beginning game');
        });
    };

    self.addPlayer = function() {
      for (var i = 0; i < self.selectedPlayers.length; i++) {
        if (self.selectedPlayers[i].id === self.newPlayer.id) {
          alert('Player already added');
          return;
        }
      }

      self.selectedPlayers.push(self.newPlayer);
      self.newPlayer = null;
    }

    self.removePlayer = function(player) {
      if (!player) return;

      self.selectedPlayers = self.selectedPlayers.filter(function(p) {
        return p.id !== player.id;
      });
    }

    $http.get('/api/players')
      .success(function(data) {
        self.allPlayers.length = 0;
        data.forEach(function(p) {
          self.allPlayers.push(p);
        });
      });

    $http.get('/api/courses')
      .success(function(data) {
        self.allCourses.length = 0;
        data.forEach(function(c) {
          self.allCourses.push(c);
        });
      });
  }]);

  app.controller('CourseCtrl', ['$scope', '$http', '$routeParams', function($scope, $http, $routeParams) {
    var self = this;

    $scope.$parent.tab = 1;

    self.courses = [];

    self.newName = '';
    self.newPar = '';
    self.newNumberOfHoles = '';

    self.save = function() {
      if (!self.newName || self.newPar < 1 || self.newNumberOfHoles < 1) {
        return;
      }

      var courseToSave = {
        'name': self.newName,
        'par': self.newPar,
        'numberOfHoles': self.newNumberOfHoles
      };

      $http.post('/api/courses', courseToSave)
        .success(function() {
          self.courses.push(courseToSave);
        })
        .error(function(e) {
          alert('OH NOES!');
        });
    };

    $http.get('/api/courses')
      .success(function(data) {
        self.courses.length = 0;
        data.forEach(function(c) {
          self.courses.push(c);
        });
      });
  }]);

  app.controller('PlayerCtrl', ['$scope', '$http', '$routeParams', function ($scope, $http, $routeParams) {
    var self = this;

    $scope.$parent.tab = 2;

    self.players = [];

    self.newPlayerName = '';

    self.save = function() {
      if (!self.newPlayerName) return;

      var playerToSave = { 'name': self.newPlayerName };
      $http.post('/api/players', playerToSave)
        .success(function() {
          self.players.push(playerToSave);
        })
        .error(function(e) {
          alert('OH NOES - Something went wrong');
        });

      self.newPlayerName = '';
    };

    $http.get('/api/players')
      .success(function(data) {
        self.players.length = 0;
        data.forEach(function(p) {
          self.players.push(p);
        });
      });
  }]);
})();
<|endoftext|>


<commit_before>import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
import { Tracker } from 'meteor/tracker';
import { _ } from 'meteor/underscore';
import { $ } from 'meteor/jquery';
import { OHIF } from 'meteor/ohif:core';

/*
 * input: controls a select2 component
 */
OHIF.mixins.select2 = new OHIF.Mixin({
    dependencies: 'select',
    composition: {
        onCreated() {
            const instance = Template.instance();
            const { component, data } = instance;

            // Controls select2 initialization
            instance.isInitialized = false;

            // Set the custom focus flag
            component.isCustomFocus = true;

            const valueMethod = component.value;
            component.value = value => {
                if (_.isUndefined(value) && !instance.isInitialized) {
                    if (!_.isUndefined(instance.data.value)) return instance.data.value;
                    if (!_.isUndefined(component.defaultValue)) return component.defaultValue;
                    return;
                }

                return valueMethod(value);
            };

            // Utility function to get the dropdown jQuery element
            instance.getDropdownContainerElement = () => {
                const $select2 = component.$element.nextAll('.select2:first');
                const containerId = $select2.find('.select2-selection').attr('aria-owns');
                return $(`#${containerId}`).closest('.select2-container');
            };

            // Check if this select will include a placeholder
            const placeholder = data.options && data.options.placeholder;
            if (placeholder) {
                instance.autorun(() => {
                    // Get the option items
                    let items = data.items;

                    // Check if the items are reactive and get them if true
                    const isReactive = items instanceof ReactiveVar;
                    if (isReactive) {
                        items = items.get();
                    }

                    // Check if there is already an empty option on items list
                    if (!_.findWhere(items, { value: '' })) {
                        // Clone the current items
                        const newItems = _.clone(items) || [];
                        newItems.unshift({
                            label: placeholder,
                            value: ''
                        });

                        // Set the new items list including the empty option
                        if (isReactive) {
                            data.items.set(newItems);
                        } else {
                            data.items = newItems;
                        }
                    }
                });
            }
        },

        onRendered() {
            const instance = Template.instance();
            const { component, data } = instance;

            // Destroy and re-create the select2 instance
            instance.rebuildSelect2 = () => {
                // Destroy the select2 instance if exists and re-create it
                if (component.select2Instance) {
                    component.select2Instance.destroy();
                }

                // Clone the options and check if the select2 should be initialized inside a modal
                const options = _.clone(data.options);
                const $closestModal = component.$element.closest('.modal');
                if ($closestModal.length) {
                    options.dropdownParent = $closestModal;
                }

                // Apply the select2 to the component
                component.$element.select2(options);

                // Store the select2 instance to allow its further destruction
                component.select2Instance = component.$element.data('select2');

                // Get the focusable elements
                const elements = [];
                const $select2 = component.$element.nextAll('.select2:first');
                const $select2Selection = $select2.find('.select2-selection');
                elements.push(component.$element[0]);
                elements.push($select2Selection[0]);

                // Attach focus and blur handlers to focusable elements
                $(elements).on('focus', event => {
                    instance.isFocused = true;
                    if (event.target === event.currentTarget) {
                        // Show the state message on elements focus
                        component.toggleMessage(true);
                    }
                }).on('blur', event => {
                    instance.isFocused = false;
                    if (event.target === event.currentTarget) {
                        // Hide the state message on elements blur
                        component.toggleMessage(false);
                    }
                });

                // Redirect keydown events from input to the select2 selection handler
                component.$element.on('keydown ', event => {
                    event.preventDefault();
                    $select2.find('.select2-selection').trigger(event);
                });

                // Keep focus on element if ESC was pressed
                $select2.on('keydown ', event => {
                    if (event.which === 27) {
                        instance.component.$element.focus();
                    }
                });

                // Handle dropdown opening when focusing the selection element
                $select2Selection.on('keydown ', event => {
                    const skipKeys = new Set([8, 9, 12, 16, 17, 18, 20, 27, 46, 91, 93]);
                    const functionKeysRegex = /F[0-9]([0-9])?$/;
                    const isFunctionKey = functionKeysRegex.test(event.key);
                    if (skipKeys.has(event.which) || isFunctionKey) {
                        return;
                    }

                    event.preventDefault();
                    event.stopPropagation();

                    // Open the select2 dropdown
                    instance.component.$element.select2('open');

                    // Check if the pressed key will produce a character
                    const searchSelector = '.select2-search__field';
                    const $search = component.select2Instance.$dropdown.find(searchSelector);
                    const isChar = OHIF.ui.isCharacterKeyPress(event);
                    const char = event.key;
                    if ($search.length && isChar && char.length === 1) {
                        // Event needs to be triggered twice to work properly with this plugin
                        $search.val(char).trigger('input').trigger('input');
                    }
                });

                // Set select2 as initialized
                instance.isInitialized = true;
            };

            instance.autorun(() => {
                // Run this computation every time the reactive items suffer any changes
                const isReactive = data.items instanceof ReactiveVar;
                if (isReactive) {
                    data.items.dep.depend();
                }

                if (isReactive) {
                    // Keep the current value of the component
                    const currentValue = component.value();
                    const wasFocused = instance.isFocused;

                    Tracker.afterFlush(() => {
                        component.$element.val(currentValue);
                        instance.rebuildSelect2();

                        if (wasFocused) {
                            component.$element.focus();
                        }
                    });
                } else {
                    instance.rebuildSelect2();
                }
            });
        },

        events: {
            // Focus element when selecting a value
            'select2:select'(event, instance) {
                instance.component.$element.focus();
            },

            // Focus the element when closing the dropdown container using ESC key
            'select2:open'(event, instance) {
                const { minimumResultsForSearch } = instance.data.options;
                if (minimumResultsForSearch === Infinity || minimumResultsForSearch === -1) return;
                const $container = instance.getDropdownContainerElement();

                if (!instance.data.wrapText) {
                    $container.addClass('select2-container-nowrap');
                }

                const $searchInput = $container.find('.select2-search__field');
                $searchInput.on('keydown.focusOnFinish', event => {
                    const keys = new Set([9, 13, 27]);
                    if (keys.has(event.which)) {
                        $searchInput.off('keydown.focusOnFinish');
                        instance.component.$element.focus();
                    }
                });
            }
        },

        onDestroyed() {
            const instance = Template.instance();
            const { component } = instance;

            // Destroy the select2 instance to remove unwanted DOM elements
            if (component.select2Instance) {
                component.select2Instance.destroy();
            }
        }
    }
});
<commit_msg>fix(select2): Stop adding inputSelect placeholder for multiple=true input selects<commit_after>import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
import { Tracker } from 'meteor/tracker';
import { _ } from 'meteor/underscore';
import { $ } from 'meteor/jquery';
import { OHIF } from 'meteor/ohif:core';

/*
 * input: controls a select2 component
 */
OHIF.mixins.select2 = new OHIF.Mixin({
    dependencies: 'select',
    composition: {
        onCreated() {
            const instance = Template.instance();
            const { component, data } = instance;

            // Controls select2 initialization
            instance.isInitialized = false;

            // Set the custom focus flag
            component.isCustomFocus = true;

            const valueMethod = component.value;
            component.value = value => {
                if (_.isUndefined(value) && !instance.isInitialized) {
                    if (!_.isUndefined(instance.data.value)) return instance.data.value;
                    if (!_.isUndefined(component.defaultValue)) return component.defaultValue;
                    return;
                }

                return valueMethod(value);
            };

            // Utility function to get the dropdown jQuery element
            instance.getDropdownContainerElement = () => {
                const $select2 = component.$element.nextAll('.select2:first');
                const containerId = $select2.find('.select2-selection').attr('aria-owns');
                return $(`#${containerId}`).closest('.select2-container');
            };

            // Check if this select will include a placeholder
            const placeholder = data.options && data.options.placeholder;
            if (placeholder) {
                instance.autorun(() => {
                    // Get the option items
                    let items = data.items;

                    // Check if the items are reactive and get them if true
                    const isReactive = items instanceof ReactiveVar;
                    if (isReactive) {
                        items = items.get();
                    }

                    // Check if there is already an empty option on items list
                    // Note: If this is a multi-select input. Do not add a placeholder
                    const isMultiple = instance.data.options && instance.data.options.multiple;
                    if (!_.findWhere(items, { value: '' }) && isMultiple === false) {
                        // Clone the current items
                        const newItems = _.clone(items) || [];
                        newItems.unshift({
                            label: placeholder,
                            value: ''
                        });

                        // Set the new items list including the empty option
                        if (isReactive) {
                            data.items.set(newItems);
                        } else {
                            data.items = newItems;
                        }
                    }
                });
            }
        },

        onRendered() {
            const instance = Template.instance();
            const { component, data } = instance;

            // Destroy and re-create the select2 instance
            instance.rebuildSelect2 = () => {
                // Destroy the select2 instance if exists and re-create it
                if (component.select2Instance) {
                    component.select2Instance.destroy();
                }

                // Clone the options and check if the select2 should be initialized inside a modal
                const options = _.clone(data.options);
                const $closestModal = component.$element.closest('.modal');
                if ($closestModal.length) {
                    options.dropdownParent = $closestModal;
                }

                // Apply the select2 to the component
                component.$element.select2(options);

                // Store the select2 instance to allow its further destruction
                component.select2Instance = component.$element.data('select2');

                // Get the focusable elements
                const elements = [];
                const $select2 = component.$element.nextAll('.select2:first');
                const $select2Selection = $select2.find('.select2-selection');
                elements.push(component.$element[0]);
                elements.push($select2Selection[0]);

                // Attach focus and blur handlers to focusable elements
                $(elements).on('focus', event => {
                    instance.isFocused = true;
                    if (event.target === event.currentTarget) {
                        // Show the state message on elements focus
                        component.toggleMessage(true);
                    }
                }).on('blur', event => {
                    instance.isFocused = false;
                    if (event.target === event.currentTarget) {
                        // Hide the state message on elements blur
                        component.toggleMessage(false);
                    }
                });

                // Redirect keydown events from input to the select2 selection handler
                component.$element.on('keydown ', event => {
                    event.preventDefault();
                    $select2.find('.select2-selection').trigger(event);
                });

                // Keep focus on element if ESC was pressed
                $select2.on('keydown ', event => {
                    if (event.which === 27) {
                        instance.component.$element.focus();
                    }
                });

                // Handle dropdown opening when focusing the selection element
                $select2Selection.on('keydown ', event => {
                    const skipKeys = new Set([8, 9, 12, 16, 17, 18, 20, 27, 46, 91, 93]);
                    const functionKeysRegex = /F[0-9]([0-9])?$/;
                    const isFunctionKey = functionKeysRegex.test(event.key);
                    if (skipKeys.has(event.which) || isFunctionKey) {
                        return;
                    }

                    event.preventDefault();
                    event.stopPropagation();

                    // Open the select2 dropdown
                    instance.component.$element.select2('open');

                    // Check if the pressed key will produce a character
                    const searchSelector = '.select2-search__field';
                    const $search = component.select2Instance.$dropdown.find(searchSelector);
                    const isChar = OHIF.ui.isCharacterKeyPress(event);
                    const char = event.key;
                    if ($search.length && isChar && char.length === 1) {
                        // Event needs to be triggered twice to work properly with this plugin
                        $search.val(char).trigger('input').trigger('input');
                    }
                });

                // Set select2 as initialized
                instance.isInitialized = true;
            };

            instance.autorun(() => {
                // Run this computation every time the reactive items suffer any changes
                const isReactive = data.items instanceof ReactiveVar;
                if (isReactive) {
                    data.items.dep.depend();
                }

                if (isReactive) {
                    // Keep the current value of the component
                    const currentValue = component.value();
                    const wasFocused = instance.isFocused;

                    Tracker.afterFlush(() => {
                        component.$element.val(currentValue);
                        instance.rebuildSelect2();

                        if (wasFocused) {
                            component.$element.focus();
                        }
                    });
                } else {
                    instance.rebuildSelect2();
                }
            });
        },

        events: {
            // Focus element when selecting a value
            'select2:select'(event, instance) {
                instance.component.$element.focus();
            },

            // Focus the element when closing the dropdown container using ESC key
            'select2:open'(event, instance) {
                const { minimumResultsForSearch } = instance.data.options;
                if (minimumResultsForSearch === Infinity || minimumResultsForSearch === -1) return;
                const $container = instance.getDropdownContainerElement();

                if (!instance.data.wrapText) {
                    $container.addClass('select2-container-nowrap');
                }

                const $searchInput = $container.find('.select2-search__field');
                $searchInput.on('keydown.focusOnFinish', event => {
                    const keys = new Set([9, 13, 27]);
                    if (keys.has(event.which)) {
                        $searchInput.off('keydown.focusOnFinish');
                        instance.component.$element.focus();
                    }
                });
            }
        },

        onDestroyed() {
            const instance = Template.instance();
            const { component } = instance;

            // Destroy the select2 instance to remove unwanted DOM elements
            if (component.select2Instance) {
                component.select2Instance.destroy();
            }
        }
    }
});
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { observer } from 'mobx-react';
import CommandButton from './component/CommandButton';
import logo from './logo.svg';
import './App.css';

@observer
export default class App extends Component {
  constructor(props) {
    super(props);
    this.handleInputChange = this.handleInputChange.bind(this);
    this.handleCityChange = this.handleCityChange.bind(this);
  }

  handleInputChange(event) {
    const target = event.target;
    const value = target.value;
    const name = target.name;
    this.props.viewModel[name] = value;
  }

  handleCityChange(event) {
    const value = event.target.value;
    this.props.viewModel.Local.City = value;
  }

  render() {
    const vm = this.props.viewModel;
    return (

Welcome to Neutronium-Mobx-React

        <form>

            Name
            <input id="name" name="Name" placeholder="Name" className="form-control" value={vm.Name} onChange={this.handleInputChange} />

            Last Name
            <input id="Last" name="LastName" placeholder="Last Name" className="form-control" value={vm.LastName} onChange={this.handleInputChange} />

            City
            <input id="City" placeholder="City" className="form-control" value={vm.Local.City} onChange={this.handleCityChange} />

        </form>

          {vm.Count}

          {vm.Skills.map((object, i) =>
{object.Name} - {object.Type}
)}

        <CommandButton command={vm.Command} name="Command"></CommandButton>

        <CommandButton command={vm.ChangeSkill} name="Change Skill"></CommandButton>

    );
  }
}
<commit_msg>Adding radio button<commit_after>import React, { Component } from 'react';
import { observer } from 'mobx-react';
import CommandButton from './component/CommandButton';
import logo from './logo.svg';
import './App.css';

@observer
export default class App extends Component {
  constructor(props) {
    super(props);
    this.handleInputChange = this.handleInputChange.bind(this);
    this.handleCityChange = this.handleCityChange.bind(this);
  }

  handleInputChange(event) {
    const target = event.target;
    const value = target.value;
    const name = target.name;
    this.props.viewModel[name] = value;
  }

  handleCityChange(event) {
    const value = event.target.value;
    this.props.viewModel.Local.City = value;
  }

  handleOptionChange(option, event){
    this.props.viewModel.PersonalState = option;
  }

  render() {
    const vm = this.props.viewModel;
    return (

Welcome to Neutronium-Mobx-React

        <form>

            Name
            <input id="name" name="Name" placeholder="Name" className="form-control" value={vm.Name} onChange={this.handleInputChange} />

            Last Name
            <input id="Last" name="LastName" placeholder="Last Name" className="form-control" value={vm.LastName} onChange={this.handleInputChange} />

            City
            <input id="City" placeholder="City" className="form-control" value={vm.Local.City} onChange={this.handleCityChange} />

            Age {vm.Age} years
            <input type="range" id="Age" name="Age" className="form-control" value={vm.Age} onChange={this.handleInputChange} />

            State: {vm.PersonalState.displayName}

              {vm.States.map((state, i) => <input type="radio" value={state} checked={state.intValue===vm.PersonalState.intValue} onChange={this.handleOptionChange.bind(this,state)}/> {state.displayName})}

        </form>

          {vm.Count}

          {vm.Skills.map((object, i) =>
{object.Name} - {object.Type}
)}

        <CommandButton command={vm.Command} name="Command"></CommandButton>

        <CommandButton command={vm.ChangeSkill} name="Change Skill"></CommandButton>

    );
  }
}
<|endoftext|>


<commit_before>var db = require('../dbAccess.js')

this.info = {
  aliases: [
    'Notes',
    'Message'
  ],
  helpInfo: {
    show: true,
    category: 'ACCF',
    name: 'Template',
    usage: 'temp [template]',
    desc: 'Templates a template'
  }
}

this.Command = function (data) {
  try {
    if (data.args.length === 0) {
      let usr = data.user
      let usrinfo = db.getUserInfo(usr.id)
      if (usrinfo.Note != null) {
        return usr.username + "'s Note is: `" + usrinfo.Note + '`'
      } else {
        return ' ' + usr.username + ' has not set a Note yet'
      }
    } else if (data.message.mentions.users.first() == null && data.args.length > 0) {
      db.setUserInfo(data.user.id, {'Note': data.args.join('')})
      return ' Your Note is now `' + data.args.join(' ') + '`'
    } else if (data.message.mentions.users.first() != null && data.args.length === 1) {
      let usr = data.message.mentions.users.first()
      let usrinfo = db.getUserInfo(usr.id)
      if (usrinfo.Note != null) {
        return usr.username + "'s Note is: `" + usrinfo.Note + '`'
      } else {
        return ' ' + usr.username + ' has not set a Note yet'
      }
    } else {
      return 'Usage: `!note [note]` or `!note [mention]`'
    }
  } catch (e) {
    return ' ' + data.user.username + ' has not set a Note yet'
  }
}
<commit_msg>Fixed whitespaces that causes !note to not whitespaced correctly.<commit_after>var db = require('../dbAccess.js')

this.info = {
  aliases: [
    'Notes',
    'Message'
  ],
  helpInfo: {
    show: true,
    category: 'ACCF',
    name: 'Template',
    usage: 'temp [template]',
    desc: 'Templates a template'
  }
}

this.Command = function (data) {
  try {
    if (data.args.length === 0) {
      let usr = data.user
      let usrinfo = db.getUserInfo(usr.id)
      if (usrinfo.Note != null) {
        return usr.username + "'s Note is: `" + usrinfo.Note + '`'
      } else {
        return ' ' + usr.username + ' has not set a Note yet'
      }
    } else if (data.message.mentions.users.first() == null && data.args.length > 0) {
      db.setUserInfo(data.user.id, {'Note': data.args.join(' ')})
      return ' Your Note is now `' + data.args.join(' ') + '`'
    } else if (data.message.mentions.users.first() != null && data.args.length === 1) {
      let usr = data.message.mentions.users.first()
      let usrinfo = db.getUserInfo(usr.id)
      if (usrinfo.Note != null) {
        return usr.username + "'s Note is: `" + usrinfo.Note + '`'
      } else {
        return ' ' + usr.username + ' has not set a Note yet'
      }
    } else {
      return 'Usage: `!note [note]` or `!note [mention]`'
    }
  } catch (e) {
    return ' ' + data.user.username + ' has not set a Note yet'
  }
}
<|endoftext|>