<commit_before>let style = document.createElement("style");
document.head.appendChild(style);
style.sheet.insertRule(`
  dlib-guiinput {
    display: flex;
    position: relative;
    font-family: monospace;
    font-size: 12px;
    align-items: center;
    height: 20px;
  }
`, 0);
style.sheet.insertRule(`
  dlib-guiinput * {
    outline: none;
  }
`, 0);
style.sheet.insertRule(`
  dlib-guiinput label, dlib-guiinput input, dlib-guiinput select, dlib-gui textarea {
    display: flex;
    font-family: inherit;
    justify-content: center;
    align-items: center;
    width: 100%;
    margin: 0 5px;
  }
`, 0);
style.sheet.insertRule(`
  dlib-guiinput label {
    flex: 1;
    min-width: 25%;
  }
`, 0);
style.sheet.insertRule(`
  dlib-guiinput label span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
`, 0);
style.sheet.insertRule(`
  dlib-guiinput button.clear {
    cursor: pointer;
    font-family: inherit;
    -webkit-appearance: none;
    border: none;
    font-size: 1em;
    padding: 0 5px;
    box-sizing: border-box;
    background: transparent;
    color: inherit;
  }
`, 0);
style.sheet.insertRule(`
  dlib-guiinput input, dlib-guiinput select, dlib-gui textarea {
    flex: 5;
  }
`, 0);
style.sheet.insertRule(`
  dlib-guiinput input.range {
    flex: 2;
  }
`, 0);
style.sheet.insertRule(`
  dlib-guiinput input[type="range"] {
    flex: 3.5;
  }
`, 0);
style.sheet.insertRule(`
  dlib-guiinput input.color {
    flex: 3.5;
  }
`, 0);

const roundToStep = (number, step) => {
  return (Math.round(number * (1 / step)) / (1 / step));
}

export default class GUIInput extends HTMLElement {
  constructor () {
    super();

    this._object = null;
    this._key = "";
    this._type = "";
    this._label = "";

    this._inputs = [];
    this._options = [];
    this._step = 0.01;
    this._min = 0;
    this._max = Infinity;

    this._initialValue = undefined;

    this._onChangeBinded = this._onChange.bind(this);
    this._onClearBinded = this._onClear.bind(this);
  }

  set value(value) {
    this.object[this.key] = value;
    this.update();
  }

  get value() {
    return this.object[this.key];
  }

  set object(value) {
    this._object = value;
    this._updateHTML();
  }

  get object() {
    return this._object;
  }

  set key(value) {
    this._key = value;
    this._updateHTML();
  }

  get key() {
    return this._key;
  }

  set type(value) {
    this._type = value;
    this._updateHTML();
  }

  get type() {
    return this._type;
  }

  set label(value) {
    this._label = value;
    this._updateHTML();
  }

  get label() {
    return this._label;
  }

  set step(value) {
    this._step = value;
    for (let input of this._inputs) {
      input.step = this._step;
    }
    this.min = this.min;
    this.max = this.max;
  }

  get step() {
    return this._step;
  }

  set min(value) {
    this._min = roundToStep(value, this.step);
    for (let input of this._inputs) {
      input.min = this._min;
    }
  }

  get min() {
    return this._min;
  }

  set max(value) {
    this._max = roundToStep(value, this.step);
    for (let input of this._inputs) {
      input.max = this._max;
    }
  }

  get max() {
    return this._max;
  }

  set options(value) {
    this._options = value;
    if(!this._inputs[0] || this._inputs[0].tagName !== "SELECT") {
      return;
    }

    let html = "";
    for (let option of this._options) {
      html += `<option selected="${option === this.value}" value="${option}">${option}</option>`;
    }
    this._inputs[0].innerHTML = html;
  }

  get options() {
    return this._options;
  }

  update() {
    if(this.type === "button") {
      return;
    }

    let changed = false;
    for (let input of this._inputs) {
      let key;
      switch (input.type) {
        case "checkbox":
          key = "checked";
          break;
        case "number":
          key = "valueAsNumber";
          break;
        default:
          key = "value";
          break;
      }

      if(this.value !== input[key]) {
        input[key] = this.value;
        changed = true;
      }
    }

    if(changed) {
      this.dispatchEvent(new Event("change"));
    }
  }

  _onChange(e) {
    let value;

    if(e.target instanceof HTMLInputElement && e.target.type === "checkbox") {
      this.value = e.target.checked;
    } else if(e.target.type === "range" || e.target.type === "number") {
      if(e.target.valueAsNumber === undefined) {
        return;
      }
      this.value = e.target.valueAsNumber;
    } else if(e.target.type === "button") {
      this.value();
    } else if(e.target.type === "color") {
      if(e.type === "change") {
        this.value = e.target.value;
      }
    } else {
      this.value = e.target.value;
    }
  }

  _onClear() {
    this.value = this._initialValue;
  }

  _updateHTML() {
    if(!this.object || !this.key || !this.type) {
      return;
    }

    if(this._initialValue === undefined) {
      this._initialValue = this.value;
    }

    this.removeEventListener("input", this._onChangeBinded);
    this.removeEventListener("change", this._onChangeBinded);
    this.removeEventListener("click", this._onChangeBinded);
    if(this.querySelector(".clear")) {
      this.querySelector(".clear").removeEventListener("click", this._onClearBinded);
    }

    // TODO: Update with ShadowDOM when cross-browser

    this.innerHTML = `
      ${this.label}
      ${this.type === "select" ? "<select></select>" : (this.type === "text" ? `<textarea rows="1"></textarea>` : `<input type="${this.type}"/>`)}
      ${this.type === "range" ? "<input class=\"range\" type=\"number\"/>" : ""}
      ${this.type === "color" ? "<input class=\"color\" type=\"text\"/>" : ""}
      <button class="clear">✕</button>
    `;

    this._inputs = Array.from(this.querySelectorAll("input, select, textarea"));

    if(this.type === "range") {
      let nextDecimal = Math.pow(10, Math.abs(parseInt(this.value)).toString().length);
      this.max = this.max !== Infinity ? this.max : (this.value < 0 ? 0 : (Math.abs(this.value) < 1 ? 1 : nextDecimal));
      this.min = this.min || (this.value >= 0 ? 0 : (Math.abs(this.value) < 1 ? -1 : -nextDecimal));
    } else if(this.type === "button") {
      this._inputs[0].value = this.label;
    } else if(this.type === "select") {
      this.options = this.options;
    }

    this.step = this.step;

    this.querySelector(".clear").addEventListener("click", this._onClearBinded);
    if(this.type === "button") {
      this.addEventListener("click", this._onChangeBinded);
    } else {
      this.addEventListener("input", this._onChangeBinded);
      this.addEventListener("change", this._onChangeBinded);
    }

    this.update();
  }
}

window.customElements.define("dlib-guiinput", GUIInput);
<commit_msg>fix gui select input<commit_after>let style = document.createElement("style");
document.head.appendChild(style);
style.sheet.insertRule(`
  dlib-guiinput {
    display: flex;
    position: relative;
    font-family: monospace;
    font-size: 12px;
    align-items: center;
    height: 20px;
  }
`, 0);
style.sheet.insertRule(`
  dlib-guiinput * {
    outline: none;
  }
`, 0);
style.sheet.insertRule(`
  dlib-guiinput label, dlib-guiinput input, dlib-guiinput select, dlib-gui textarea {
    display: flex;
    font-family: inherit;
    justify-content: center;
    align-items: center;
    width: 100%;
    margin: 0 5px;
  }
`, 0);
style.sheet.insertRule(`
  dlib-guiinput label {
    flex: 1;
    min-width: 25%;
  }
`, 0);
style.sheet.insertRule(`
  dlib-guiinput label span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
`, 0);
style.sheet.insertRule(`
  dlib-guiinput button.clear {
    cursor: pointer;
    font-family: inherit;
    -webkit-appearance: none;
    border: none;
    font-size: 1em;
    padding: 0 5px;
    box-sizing: border-box;
    background: transparent;
    color: inherit;
  }
`, 0);
style.sheet.insertRule(`
  dlib-guiinput input, dlib-guiinput select, dlib-gui textarea {
    flex: 5;
  }
`, 0);
style.sheet.insertRule(`
  dlib-guiinput input.range {
    flex: 2;
  }
`, 0);
style.sheet.insertRule(`
  dlib-guiinput input[type="range"] {
    flex: 3.5;
  }
`, 0);
style.sheet.insertRule(`
  dlib-guiinput input.color {
    flex: 3.5;
  }
`, 0);

const roundToStep = (number, step) => {
  return (Math.round(number * (1 / step)) / (1 / step));
}

export default class GUIInput extends HTMLElement {
  constructor () {
    super();

    this._object = null;
    this._key = "";
    this._type = "";
    this._label = "";

    this._inputs = [];
    this._options = [];
    this._step = 0.01;
    this._min = 0;
    this._max = Infinity;

    this._initialValue = undefined;

    this._onChangeBinded = this._onChange.bind(this);
    this._onClearBinded = this._onClear.bind(this);
  }

  set value(value) {
    this.object[this.key] = value;
    this.update();
  }

  get value() {
    return this.object[this.key];
  }

  set object(value) {
    this._object = value;
    this._updateHTML();
  }

  get object() {
    return this._object;
  }

  set key(value) {
    this._key = value;
    this._updateHTML();
  }

  get key() {
    return this._key;
  }

  set type(value) {
    this._type = value;
    this._updateHTML();
  }

  get type() {
    return this._type;
  }

  set label(value) {
    this._label = value;
    this._updateHTML();
  }

  get label() {
    return this._label;
  }

  set step(value) {
    this._step = value;
    for (let input of this._inputs) {
      input.step = this._step;
    }
    this.min = this.min;
    this.max = this.max;
  }

  get step() {
    return this._step;
  }

  set min(value) {
    this._min = roundToStep(value, this.step);
    for (let input of this._inputs) {
      input.min = this._min;
    }
  }

  get min() {
    return this._min;
  }

  set max(value) {
    this._max = roundToStep(value, this.step);
    for (let input of this._inputs) {
      input.max = this._max;
    }
  }

  get max() {
    return this._max;
  }

  set options(value) {
    this._options = value;
    if(!this._inputs[0] || this._inputs[0].tagName !== "SELECT") {
      return;
    }

    let html = "";
    for (let option of this._options) {
      html += `<option selected="${option === this.value}" value="${option}">${option}</option>`;
    }
    this._inputs[0].innerHTML = html;
  }

  get options() {
    return this._options;
  }

  update() {
    if(this.type === "button") {
      return;
    }

    let changed = false;
    for (let input of this._inputs) {
      let key;
      let value = this.value;
      switch (input.type) {
        case "checkbox":
          key = "checked";
          break;
        case "number":
          key = "valueAsNumber";
          break;
        case "select-one":
          key = "value";
          value = value.toString();
          break;
        default:
          key = "value";
          break;
      }

      if(value !== input[key]) {
        input[key] = value;
        changed = true;
      }
    }

    if(changed) {
      this.dispatchEvent(new Event("change"));
    }
  }

  _onChange(e) {
    let value;

    if(e.target instanceof HTMLInputElement && e.target.type === "checkbox") {
      this.value = e.target.checked;
    } else if(e.target.type === "range" || e.target.type === "number") {
      if(e.target.valueAsNumber === undefined) {
        return;
      }
      this.value = e.target.valueAsNumber;
    } else if(e.target.type === "button") {
      this.value();
    } else if(e.target.type === "color") {
      if(e.type === "change") {
        this.value = e.target.value;
      }
    } else {
      this.value = e.target.value;
    }
  }

  _onClear() {
    this.value = this._initialValue;
  }

  _updateHTML() {
    if(!this.object || !this.key || !this.type) {
      return;
    }

    if(this._initialValue === undefined) {
      this._initialValue = this.value;
    }

    this.removeEventListener("input", this._onChangeBinded);
    this.removeEventListener("change", this._onChangeBinded);
    this.removeEventListener("click", this._onChangeBinded);
    if(this.querySelector(".clear")) {
      this.querySelector(".clear").removeEventListener("click", this._onClearBinded);
    }

    // TODO: Update with ShadowDOM when cross-browser

    this.innerHTML = `
      ${this.label}
      ${this.type === "select" ? "<select></select>" : (this.type === "text" ? `<textarea rows="1"></textarea>` : `<input type="${this.type}"/>`)}
      ${this.type === "range" ? "<input class=\"range\" type=\"number\"/>" : ""}
      ${this.type === "color" ? "<input class=\"color\" type=\"text\"/>" : ""}
      <button class="clear">✕</button>
    `;

    this._inputs = Array.from(this.querySelectorAll("input, select, textarea"));

    if(this.type === "range") {
      let nextDecimal = Math.pow(10, Math.abs(parseInt(this.value)).toString().length);
      this.max = this.max !== Infinity ? this.max : (this.value < 0 ? 0 : (Math.abs(this.value) < 1 ? 1 : nextDecimal));
      this.min = this.min || (this.value >= 0 ? 0 : (Math.abs(this.value) < 1 ? -1 : -nextDecimal));
    } else if(this.type === "button") {
      this._inputs[0].value = this.label;
    } else if(this.type === "select") {
      this.options = this.options;
    }

    this.step = this.step;

    this.querySelector(".clear").addEventListener("click", this._onClearBinded);
    if(this.type === "button") {
      this.addEventListener("click", this._onChangeBinded);
    } else {
      this.addEventListener("input", this._onChangeBinded);
      this.addEventListener("change", this._onChangeBinded);
    }

    this.update();
  }
}

window.customElements.define("dlib-guiinput", GUIInput);
<|endoftext|>


<commit_before>// This code opens the share or survey link in a new pop-up window.
// Since it's opened in a new window the GA event can be sent
// afterwards.

(function () {
  $.each(['.share-link', '#take-survey'], function(_, cssSelector) {
    $(cssSelector).on('click.open', function(e) {
      var label = this.id, url = this.href, width, height;
      var windowFeatures = {
        '#take-survey': 'chrome,width=800,height=600',
        '.share-link': 'chrome,width=600,height=300'
      }[cssSelector]
      e.preventDefault();
      window.open(url, label + ' window', windowFeatures);
      ga('send', 'event', {
        'eventCategory': cssSelector.substring(1),
        'eventAction': 'click',
        'eventLabel': label
      });
    });
  });
})();

// process form submits without leaving the page
(function () {
  $.each(['.inplace-form'], function(_, cssSelector) {
    var form = $(this);
    /* There doesn't seem to be any particularly nice way of finding
       which submit button was clicked from jQuery's submit event.
       One way is to create a hidden input element with the submit
       button's name and value on clicking of that button, suggested
       here: http://stackoverflow.com/a/11271850/223092 */
    form.find(':submit').click(function (e) {
      if ($(this).attr('name')) {
        $(form).append(
          $('<input type="hidden">').attr({
            name: $(this).attr('name'),
            value: $(this).attr('value')
          })
        );
      }
    });
    $(cssSelector).on('submit', function(e) {
      var data = $(this).serialize(),
        url = this.action,
        panel = $(this).parent()[0],
        thanks = $('#' + panel.id + 'thanks');
      e.preventDefault();
      /* If this is the "support" form, make sure that the constituency
         field is set, or give an error: */
      if ($(this).attr('id') == 'support') {
        if (!$(this).find('select[name="constituencies"]').val()) {
          alert('You must select a constituency first');
          return;
        }
      }
      /* We'll post the form as an AJAX request in the background, so
         set the 'thanks' field to indicate that it's being
         submitted */
      $(panel).hide();
      $(thanks).text('Submitting your response...')
      $(thanks).show();
      $.ajax({
        url: url,
        type: 'POST',
        data: data
      }).done(function () {
        $(thanks).text('Thank-you for your input');
      }).fail(function () {
        $(thanks).text('Submission failed; you can try again');
        $(panel).show();
      });
      if (navigator.userAgent.indexOf('Opera Mini') > -1) {
        $(document).scrollTop(thanks.offsetTop);
      }
    });
  });
})();

// Opera Mini specific fix for video scaling
(function () {
  $.each(['.embedded-video'], function(_, cssSelector) {
    if (navigator.userAgent.indexOf('Opera Mini') > -1) {
      $(cssSelector).find('.ratio-img').hide();
    }
  });
})();
<commit_msg>Fix the Javascript-enhanced form submission<commit_after>// This code opens the share or survey link in a new pop-up window.
// Since it's opened in a new window the GA event can be sent
// afterwards.

(function () {
  $.each(['.share-link', '#take-survey'], function(_, cssSelector) {
    $(cssSelector).on('click.open', function(e) {
      var label = this.id, url = this.href, width, height;
      var windowFeatures = {
        '#take-survey': 'chrome,width=800,height=600',
        '.share-link': 'chrome,width=600,height=300'
      }[cssSelector]
      e.preventDefault();
      window.open(url, label + ' window', windowFeatures);
      ga('send', 'event', {
        'eventCategory': cssSelector.substring(1),
        'eventAction': 'click',
        'eventLabel': label
      });
    });
  });
})();

// process form submits without leaving the page
(function () {
  $('.inplace-form').each(function (i) {
    var form = $(this);
    /* There doesn't seem to be any particularly nice way of finding
       which submit button was clicked from jQuery's submit event.
       One way is to create a hidden input element with the submit
       button's name and value on clicking of that button, suggested
       here: http://stackoverflow.com/a/11271850/223092 */
    form.find(':submit').click(function (e) {
      if ($(this).attr('name')) {
        $(form).append(
          $('<input type="hidden">').attr({
            name: $(this).attr('name'),
            value: $(this).attr('value')
          })
        );
      }
    });
    form.on('submit', function(e) {
      var data = $(this).serialize(),
        url = this.action,
        panel = $(this).parent()[0],
        thanks = $('#' + panel.id + 'thanks');
      e.preventDefault();
      /* If this is the "support" form, make sure that the constituency
         field is set, or give an error: */
      if ($(this).attr('id') == 'support') {
        if (!$(this).find('select[name="constituencies"]').val()) {
          alert('You must select a constituency first');
          return;
        }
      }
      /* We'll post the form as an AJAX request in the background, so
         set the 'thanks' field to indicate that it's being
         submitted */
      $(panel).hide();
      $(thanks).text('Submitting your response...')
      $(thanks).show();
      $.ajax({
        url: url,
        type: 'POST',
        data: data
      }).done(function () {
        $(thanks).text('Thank-you for your input');
      }).fail(function () {
        $(thanks).text('Submission failed; you can try again');
        $(panel).show();
      });
      if (navigator.userAgent.indexOf('Opera Mini') > -1) {
        $(document).scrollTop(thanks.offsetTop);
      }
    });
  });
})();

// Opera Mini specific fix for video scaling
(function () {
  $.each(['.embedded-video'], function(_, cssSelector) {
    if (navigator.userAgent.indexOf('Opera Mini') > -1) {
      $(cssSelector).find('.ratio-img').hide();
    }
  });
})();
<|endoftext|>


<commit_before>var chessground = require('chessground');
var layout = require('../../layout');
var widgets = require('../../_commonWidgets');
var menu = require('../../menu');
var clock = require('../clock');
var renderPromotion = require('../promotion').view;
var utils = require('../../../utils');
var i18n = require('../../../i18n');
var button = require('./button');
var game = require('../game');
var ground = require('../ground');
var gameStatus = require('../status');
var replayView = require('../replay/replayView');
var renderChat = require('../chat').view;
var renderCorrespondenceClock = require('../correspondenceClock/correspondenceView');

function compact(x) {
  if (Object.prototype.toString.call(x) === '[object Array]') {
    var elems = x.filter(function(n) {
      return n !== undefined;
    });
    return elems.length > 0 ? elems : null;
  }
  return x;
}

function ratingDiff(player) {
  if (typeof player.ratingDiff === 'undefined') return null;
  if (player.ratingDiff === 0) return m('span.rp.null', 0);
  if (player.ratingDiff > 0) return m('span.rp.up', ' +' + player.ratingDiff);
  if (player.ratingDiff < 0) return m('span.rp.down', ' ' + player.ratingDiff);
}

function renderMaterial(material) {
  var children = [];
  for (var role in material) {
    var piece = m('div.' + role);
    var count = material[role];
    var content;
    if (count === 1) content = piece;
    else {
      content = [];
      for (var i = 0; i < count; i++) content.push(piece);
    }
    children.push(m('div.tomb', content));
  }
  return children;
}

function renderCheckCount(ctrl, color) {
  var player = color === ctrl.data.player.color ? ctrl.data.opponent : ctrl.data.player;
  if (typeof player.checks !== 'undefined') return m('div.checks', player.checks);
}

function renderAntagonist(ctrl, player, material) {
  return m('section.antagonist', [
    m('div.vertical_align', [
      m('div.infos', [
        m('h2', utils.playerName(player)),
        m('div', [
          player.user ? m('h3.rating', [
            player.rating,
            ratingDiff(player)
          ]) : null,
          renderCheckCount(ctrl, player.color),
          renderMaterial(material)
        ])
      ]),
      ctrl.clock ? clock.view(ctrl.clock, player.color, ctrl.isClockRunning() ? ctrl.data.game.player : null) : (
        ctrl.data.correspondence ? renderCorrespondenceClock(
          ctrl.correspondenceClock, i18n, player.color, ctrl.data.game.player
        ) : null
      )
    ])
  ]);
}

function renderGameRunningActions(ctrl) {
  var d = ctrl.data;
  var answerButtons = compact([
    button.cancelDrawOffer(ctrl),
    button.answerOpponentDrawOffer(ctrl),
    button.cancelTakebackProposition(ctrl),
    button.answerOpponentTakebackProposition(ctrl), (game.mandatory(d) && game.nbMoves(d, d.player.color) === 0) ? m('div.text[data-icon=j]',
      ctrl.trans('youHaveNbSecondsToMakeYourFirstMove', 30)
    ) : null
  ]);
  return [
    m('div.actions', [
      button.moretime(ctrl),
      button.standard(ctrl, game.abortable, 'L', 'abortGame', 'abort'),
      button.standard(ctrl, game.takebackable, 'i', 'proposeATakeback', 'takeback-yes'),
      button.standard(ctrl, game.drawable, '2', 'offerDraw', 'draw-yes'),
      button.standard(ctrl, game.resignable, 'b', 'resign', 'resign'),
      button.forceResign(ctrl),
      button.threefoldClaimDraw(ctrl),
      m('br'), m('br'), button.backToGame(ctrl)
    ]),
    m('div.answers', answerButtons)
  ];
}

function renderGameEndedActions(ctrl) {
  var result;
  if (gameStatus.finished(ctrl.data)) switch (ctrl.data.game.winner) {
    case 'white':
      result = '1-0';
      break;
    case 'black':
      result = '0-1';
      break;
    default:
      result = '½-½';
  }
  var winner = game.getPlayer(ctrl.data, ctrl.data.game.winner);
  var status = gameStatus.toLabel(ctrl.data) +
    (winner ? '. ' + i18n(winner.color === 'white' ? 'whiteIsVictorious' : 'blackIsVictorious') + '.' : '');
  var buttons = ctrl.vm.redirecting ? null : (
    button.joinRematch(ctrl) ||
    button.answerOpponentRematch(ctrl) ||
    button.cancelRematch(ctrl) ||
    [button.rematch(ctrl), m('br'), m('br'), button.backToGame(ctrl)]
  );
  return [
    m('div.result', [result, m('br'), m('br'), status]),
    m('div.control.buttons', buttons)
  ];
}

function renderPlayerActions(ctrl) {
  return m('div.overlay.overlay_scale', {
    class: utils.classSet({
      open: ctrl.vm.showingActions
    })
  }, [
    m('button.overlay_close.fa.fa-close', {
      config: utils.ontouchend(ctrl.hideActions)
    }),
    m('div#player_controls.overlay_content', game.playable(ctrl.data) ?
      renderGameRunningActions(ctrl) : renderGameEndedActions(ctrl)
    )
  ]);
}

function renderGameButtons(ctrl) {
  var actions = [
    m('button#open_player_controls.game_action.fa.fa-ellipsis-h', {
      class: utils.classSet({
        'answer_required': ctrl.data.opponent.proposingTakeback ||
          ctrl.data.opponent.offeringDraw ||
          game.forceResignable(ctrl.data)
      }),
      config: utils.ontouchend(ctrl.showActions)
    }),
    ctrl.chat ? m('button#open_chat.game_action[data-icon=c]', {
      class: utils.classSet({
        unread: ctrl.chat.unread
      }),
      config: utils.ontouchend(ctrl.chat.open || utils.noop)
    }) : m('button.game_action.empty[data-icon=c]'),
    replayView.renderButtons(ctrl.replay)
  ];
  return m('section#game_actions', actions);
}

var loader = m('div.loader_circles',
  [1, 2, 3].map(function(i) {
    return m('div.circle_' + i);
  })
);

module.exports = function(ctrl) {

  var material = chessground.board.getMaterialDiff(ctrl.chessground.data);

  function footer() {
    var els = [
      renderAntagonist(ctrl, ctrl.data.player, material[ctrl.data.player.color]),
      renderGameButtons(ctrl),
      renderPlayerActions(ctrl)
    ];
    if (ctrl.chat) els.push(renderChat(ctrl.chat));

    return els;
  }

  function header() {
    return [
      m('nav', [
        widgets.menuButton(),
        widgets.gameButton(),
        ctrl.vm.connectedWS ? m('h1.playing', ctrl.title) : m('h1.reconnecting', [
          i18n('reconnecting'),
          loader
        ])
      ]),
      renderAntagonist(ctrl, ctrl.data.opponent, material[ctrl.data.opponent.color])
    ];
  }

  function board() {
    var x = utils.getViewportDims().vw;
    return m('section.board_wrapper', {
      style: {
        height: x + 'px'
      }
    }, [
      m('div', {
        class: 'board grey merida ' + ctrl.data.game.variant.key
      }, chessground.view(ctrl.chessground), renderPromotion(ctrl))
    ]);
  }

  function renderMenu() {
    return menu.view(utils.partialƒ(ground.applySettings, ctrl.chessground));
  }

  return layout.board(header, board, footer, renderMenu, null, ctrl.data.player.color);
};

module.exports.renderMaterial = renderMaterial;
<commit_msg>Back to game button below all<commit_after>var chessground = require('chessground');
var layout = require('../../layout');
var widgets = require('../../_commonWidgets');
var menu = require('../../menu');
var clock = require('../clock');
var renderPromotion = require('../promotion').view;
var utils = require('../../../utils');
var i18n = require('../../../i18n');
var button = require('./button');
var game = require('../game');
var ground = require('../ground');
var gameStatus = require('../status');
var replayView = require('../replay/replayView');
var renderChat = require('../chat').view;
var renderCorrespondenceClock = require('../correspondenceClock/correspondenceView');

function compact(x) {
  if (Object.prototype.toString.call(x) === '[object Array]') {
    var elems = x.filter(function(n) {
      return n !== undefined;
    });
    return elems.length > 0 ? elems : null;
  }
  return x;
}

function ratingDiff(player) {
  if (typeof player.ratingDiff === 'undefined') return null;
  if (player.ratingDiff === 0) return m('span.rp.null', 0);
  if (player.ratingDiff > 0) return m('span.rp.up', ' +' + player.ratingDiff);
  if (player.ratingDiff < 0) return m('span.rp.down', ' ' + player.ratingDiff);
}

function renderMaterial(material) {
  var children = [];
  for (var role in material) {
    var piece = m('div.' + role);
    var count = material[role];
    var content;
    if (count === 1) content = piece;
    else {
      content = [];
      for (var i = 0; i < count; i++) content.push(piece);
    }
    children.push(m('div.tomb', content));
  }
  return children;
}

function renderCheckCount(ctrl, color) {
  var player = color === ctrl.data.player.color ? ctrl.data.opponent : ctrl.data.player;
  if (typeof player.checks !== 'undefined') return m('div.checks', player.checks);
}

function renderAntagonist(ctrl, player, material) {
  return m('section.antagonist', [
    m('div.vertical_align', [
      m('div.infos', [
        m('h2', utils.playerName(player)),
        m('div', [
          player.user ? m('h3.rating', [
            player.rating,
            ratingDiff(player)
          ]) : null,
          renderCheckCount(ctrl, player.color),
          renderMaterial(material)
        ])
      ]),
      ctrl.clock ? clock.view(ctrl.clock, player.color, ctrl.isClockRunning() ? ctrl.data.game.player : null) : (
        ctrl.data.correspondence ? renderCorrespondenceClock(
          ctrl.correspondenceClock, i18n, player.color, ctrl.data.game.player
        ) : null
      )
    ])
  ]);
}

function renderGameRunningActions(ctrl) {
  var d = ctrl.data;
  var answerButtons = compact([
    button.cancelDrawOffer(ctrl),
    button.answerOpponentDrawOffer(ctrl),
    button.cancelTakebackProposition(ctrl),
    button.answerOpponentTakebackProposition(ctrl), (game.mandatory(d) && game.nbMoves(d, d.player.color) === 0) ? m('div.text[data-icon=j]',
      ctrl.trans('youHaveNbSecondsToMakeYourFirstMove', 30)
    ) : null
  ]);
  return [
    m('div.actions', [
      button.moretime(ctrl),
      button.standard(ctrl, game.abortable, 'L', 'abortGame', 'abort'),
      button.standard(ctrl, game.takebackable, 'i', 'proposeATakeback', 'takeback-yes'),
      button.standard(ctrl, game.drawable, '2', 'offerDraw', 'draw-yes'),
      button.standard(ctrl, game.resignable, 'b', 'resign', 'resign'),
      button.forceResign(ctrl),
      button.threefoldClaimDraw(ctrl),
    ]),
    m('div.answers', answerButtons),
    m('br'), m('br'), button.backToGame(ctrl)
  ];
}

function renderGameEndedActions(ctrl) {
  var result;
  if (gameStatus.finished(ctrl.data)) switch (ctrl.data.game.winner) {
    case 'white':
      result = '1-0';
      break;
    case 'black':
      result = '0-1';
      break;
    default:
      result = '½-½';
  }
  var winner = game.getPlayer(ctrl.data, ctrl.data.game.winner);
  var status = gameStatus.toLabel(ctrl.data) +
    (winner ? '. ' + i18n(winner.color === 'white' ? 'whiteIsVictorious' : 'blackIsVictorious') + '.' : '');
  var buttons = ctrl.vm.redirecting ? null : (
    button.joinRematch(ctrl) ||
    button.answerOpponentRematch(ctrl) ||
    button.cancelRematch(ctrl) ||
    [button.rematch(ctrl), m('br'), m('br'), button.backToGame(ctrl)]
  );
  return [
    m('div.result', [result, m('br'), m('br'), status]),
    m('div.control.buttons', buttons)
  ];
}

function renderPlayerActions(ctrl) {
  return m('div.overlay.overlay_scale', {
    class: utils.classSet({
      open: ctrl.vm.showingActions
    })
  }, [
    m('button.overlay_close.fa.fa-close', {
      config: utils.ontouchend(ctrl.hideActions)
    }),
    m('div#player_controls.overlay_content', game.playable(ctrl.data) ?
      renderGameRunningActions(ctrl) : renderGameEndedActions(ctrl)
    )
  ]);
}

function renderGameButtons(ctrl) {
  var actions = [
    m('button#open_player_controls.game_action.fa.fa-ellipsis-h', {
      class: utils.classSet({
        'answer_required': ctrl.data.opponent.proposingTakeback ||
          ctrl.data.opponent.offeringDraw ||
          game.forceResignable(ctrl.data)
      }),
      config: utils.ontouchend(ctrl.showActions)
    }),
    ctrl.chat ? m('button#open_chat.game_action[data-icon=c]', {
      class: utils.classSet({
        unread: ctrl.chat.unread
      }),
      config: utils.ontouchend(ctrl.chat.open || utils.noop)
    }) : m('button.game_action.empty[data-icon=c]'),
    replayView.renderButtons(ctrl.replay)
  ];
  return m('section#game_actions', actions);
}

var loader = m('div.loader_circles',
  [1, 2, 3].map(function(i) {
    return m('div.circle_' + i);
  })
);

module.exports = function(ctrl) {

  var material = chessground.board.getMaterialDiff(ctrl.chessground.data);

  function footer() {
    var els = [
      renderAntagonist(ctrl, ctrl.data.player, material[ctrl.data.player.color]),
      renderGameButtons(ctrl),
      renderPlayerActions(ctrl)
    ];
    if (ctrl.chat) els.push(renderChat(ctrl.chat));

    return els;
  }

  function header() {
    return [
      m('nav', [
        widgets.menuButton(),
        widgets.gameButton(),
        ctrl.vm.connectedWS ? m('h1.playing', ctrl.title) : m('h1.reconnecting', [
          i18n('reconnecting'),
          loader
        ])
      ]),
      renderAntagonist(ctrl, ctrl.data.opponent, material[ctrl.data.opponent.color])
    ];
  }

  function board() {
    var x = utils.getViewportDims().vw;
    return m('section.board_wrapper', {
      style: {
        height: x + 'px'
      }
    }, [
      m('div', {
        class: 'board grey merida ' + ctrl.data.game.variant.key
      }, chessground.view(ctrl.chessground), renderPromotion(ctrl))
    ]);
  }

  function renderMenu() {
    return menu.view(utils.partialƒ(ground.applySettings, ctrl.chessground));
  }

  return layout.board(header, board, footer, renderMenu, null, ctrl.data.player.color);
};

module.exports.renderMaterial = renderMaterial;
<|endoftext|>


<commit_before>import UX from '../../../src/screens/task/ux';
import Reading from '../../../src/screens/task/reading';
import { TestRouter, Factory, FakeWindow, ld, TimeMock, C } from '../../helpers';

describe('Reading Tasks Screen', () => {
  let props, history;
  TimeMock.setTo('2017-10-14T12:00:00.000Z');

  beforeEach(() => {
    const task = Factory.studentTask({ type: 'reading' });
    task.tasksMap = { course: Factory.course() }
    history = new TestRouter({
      push: (url) => {
        props.ux.goToStepId(ld.last(url.split('/')), false);
      },
    }).history;
    props = {
      windowImpl: new FakeWindow(),
      ux: new UX({
        stepId: task.steps[0].id,
        task, history,
        course: Factory.course(),
      }),
    };
  });

  it('matches snapshot', () => {
    expect(<C><Reading {...props} /></C>).toMatchSnapshot();
  });

  it('render as loading', () => {
    props.ux.goToStepId(3);
    props.ux.currentStep.api.reset();
    expect(props.ux.currentStep.needsFetched).toBeTruthy();
    const r = mount(<C><Reading {...props} /></C>);
    expect(r).toHaveRendered('ContentLoader');
    r.unmount();
  });

  it('renders content', () => {
    const r = mount(<C><Reading {...props} /></C>);

    r.unmount();
  });

  it('renders value props', () => {
    props.ux.task.steps[1].formats = ['free-response', 'multiple-choice'];
    props.ux._stepId = props.ux.steps.find(s=>s.type === 'two-step-intro').id;
    const r = mount(<C><Reading {...props} /></C>);
    expect(props.ux.currentStep.type).toEqual('two-step-intro');
    expect(r).toHaveRendered('TwoStepValueProp');
    r.unmount();
  });

  it('pages through steps', () => {
    const pr = mount(<C><Reading {...props} /></C>);
    expect(pr).toHaveRendered('a.paging-control.prev')
    expect(pr).toHaveRendered('a.paging-control.next');
    pr.find('a.paging-control.next').simulate('click');
    pr.find('a.paging-control.next').simulate('click');
    pr.unmount();
  });

});
<commit_msg>fix reading spec<commit_after>import UX from '../../../src/screens/task/ux';
import Reading from '../../../src/screens/task/reading';
import { TestRouter, Factory, FakeWindow, ld, TimeMock, C } from '../../helpers';

describe('Reading Tasks Screen', () => {
  let props, history;
  TimeMock.setTo('2017-10-14T12:00:00.000Z');

  beforeEach(() => {
    const task = Factory.studentTask({ type: 'reading' });
    task.tasksMap = { course: Factory.course() }
    history = new TestRouter({
      push: (url) => {
        props.ux.goToStepId(ld.last(url.split('/')), false);
      },
    }).history;
    props = {
      windowImpl: new FakeWindow(),
      ux: new UX({
        stepId: task.steps[0].id,
        task, history,
        course: Factory.course(),
      }),
    };
  });

  it('matches snapshot', () => {
    expect(<C><Reading {...props} /></C>).toMatchSnapshot();
  });

  it('render as loading', () => {
    props.ux.goToStepId(3);
    props.ux.currentStep.api.reset();
    expect(props.ux.currentStep.needsFetched).toBeTruthy();
    const r = mount(<C><Reading {...props} /></C>);
    expect(r).toHaveRendered('ContentLoader');
    r.unmount();
  });

  it('renders content', () => {
    const r = mount(<C><Reading {...props} /></C>);

    r.unmount();
  });

  it('renders value props', () => {
    props.ux.task.steps[1].formats = ['free-response', 'multiple-choice'];
    props.ux._stepId = props.ux.steps.find(s=>s.type === 'two-step-intro').id;
    const r = mount(<C><Reading {...props} /></C>);
    expect(props.ux.currentStep.type).toEqual('two-step-intro');
    expect(r).toHaveRendered('TwoStepValueProp');
    r.unmount();
  });

  it('pages through steps', () => {
    const pr = mount(<C><Reading {...props} /></C>);
    expect(pr).toHaveRendered('a.paging-control.prev')
    expect(pr).toHaveRendered('a.paging-control.next');
    pr.find('a.paging-control.next').first().simulate('click');
    pr.find('a.paging-control.next').first().simulate('click');
    pr.unmount();
  });

});
<|endoftext|>


<commit_before>import { React, PropTypes, styled, observer } from 'vendor';
import { colors, fonts } from '../../theme';
import { Button } from 'react-bootstrap';
import { Field, ErrorMessage } from 'formik';

const FormWrapper = styled.div`
  max-width: 1200px;
  margin: 6rem auto;
`;

const Header = styled.div`
  background: ${props => props.templateColors.background};
  border-left: 8px solid ${props => props.templateColors.border};
  background-color: ${props => props.templateColors.background};
  font-size: 1.8rem;
  font-weight: bold;
  padding: 1.5rem 3.2rem;
  display: flex;
`;

const HeaderStep = styled.div`
  font-size: 1.2rem;
  margin-right: 2.4rem;
`;

const BodyWrapper = styled.div`
  border: 1px solid ${colors.neutral.pale};
  border-top-width: 0;
  border-radius: 0 0 2px 2px;
  background: #fff;
`;

const Body = styled.div`
  padding: 4rem;
`;

const Footer = styled.div`
  position: fixed;
  z-index: 1030;
  bottom: 0;
  left: 0;
  right: 0;
  width: 100%;
  padding: .8rem 2.4rem;
  background: ${colors.neutral.bright};
  box-shadow: 0 -1px 2px rgba(0,0,0,0.19);
`;

const FooterInner = styled.div`
  max-width: 1200px;
  margin: 0 auto;
  display: flex;
  justify-content: space-between;
`;

const Row = styled.div`
  margin: 2.4rem 0;
`;

const SplitRow = styled.div`
  display: flex;
  margin-bottom: 2.4rem;
  > * {
    flex-basis: 50%;
  }
`;

const Setting = styled.div`
  margin-bottom: 0.5rem;
`;

const Label = styled.label`
  font-weight: bold;
`;

const HintText = styled.div`
  color: ${colors.neutral.dark};
  ${fonts.faces.light};
`;

const StyledTextInput = styled(Field).attrs({
  type: 'text',
})`
  padding: 0.8rem 1rem;
  border-radius: 4px;
  border: 1px solid ${colors.forms.borders.light};
  font-size: 1.4rem;

  &:focus {
    border-color: ${colors.forms.borders.focus};
    box-shadow: 0 0 4px 0 ${colors.forms.borders.focusShadow};
  }

  &::placeholder {
    font-size: inherit;
  }
`;

const TextInputWrapper = styled.div`
  display: flex;
  flex-direction: column;
`;

const TextInputError = styled.div`
  color: red;
  margin: 1rem 0;
`;

const TextInput = (props) => (
  <TextInputWrapper>
    <StyledTextInput {...props} />
    <ErrorMessage name={props.name} render={msg => <TextInputError>{msg}</TextInputError>} />
  </TextInputWrapper>
);
TextInput.propTypes = {
  name: PropTypes.string.isRequired,
};

const AltButton = styled(Button)`
  &.btn.btn-plain {
    background-color: ${colors.neutral.white};
    color: ${colors.neutral.dark};
    border: 1px solid ${colors.neutral.pale};
    padding: 1rem 2rem;
    min-width: 10rem;
  }
`;

const PrimaryButton = styled(Button)`
  &.btn {
    padding: 1rem 2rem;
  }
`;

const AssignmentBuilder = observer(({ ux, children, title }) => {
  return (
    <>
      <FormWrapper>
        <Header className="heading" templateColors={colors.templates[ux.plan.type]}>
          <HeaderStep>
            STEP {ux.steps.number}
          </HeaderStep>
          {title}
        </Header>
        <BodyWrapper>
          {children}
        </BodyWrapper>
      </FormWrapper>
      <Footer className="controls">
        <FooterInner>
          {!ux.steps.canGoBackward && <AltButton variant="plain">Cancel</AltButton>}
          {ux.steps.canGoBackward && <AltButton variant="plain" onClick={ux.steps.goBackward}>Back</AltButton>}
          <PrimaryButton
            variant="primary"
            disabled={!ux.steps.canGoForward}
            onClick={ux.steps.goForward}
          >
            Save & Continue
          </PrimaryButton>
        </FooterInner>
      </Footer>
    </>
  );
});

AssignmentBuilder.propTypes = {
  ux: PropTypes.object.isRequired,
  children: PropTypes.node.isRequired,
  title: PropTypes.string.isRequired,
};

export { AssignmentBuilder, Row, SplitRow, HintText, Label, TextInput, Setting, Body };
<commit_msg>scroll to top when builder loads<commit_after>import { React, PropTypes, styled, observer } from 'vendor';
import { ScrollToTop } from 'shared';
import { colors, fonts } from '../../theme';
import { Button } from 'react-bootstrap';
import { Field, ErrorMessage } from 'formik';

const FormWrapper = styled.div`
  max-width: 1200px;
  margin: 6rem auto;
`;

const Header = styled.div`
  background: ${props => props.templateColors.background};
  border-left: 8px solid ${props => props.templateColors.border};
  background-color: ${props => props.templateColors.background};
  font-size: 1.8rem;
  font-weight: bold;
  padding: 1.5rem 3.2rem;
  display: flex;
`;

const HeaderStep = styled.div`
  font-size: 1.2rem;
  margin-right: 2.4rem;
`;

const BodyWrapper = styled.div`
  border: 1px solid ${colors.neutral.pale};
  border-top-width: 0;
  border-radius: 0 0 2px 2px;
  background: #fff;
`;

const Body = styled.div`
  padding: 4rem;
`;

const Footer = styled.div`
  position: fixed;
  z-index: 1030;
  bottom: 0;
  left: 0;
  right: 0;
  width: 100%;
  padding: .8rem 2.4rem;
  background: ${colors.neutral.bright};
  box-shadow: 0 -1px 2px rgba(0,0,0,0.19);
`;

const FooterInner = styled.div`
  max-width: 1200px;
  margin: 0 auto;
  display: flex;
  justify-content: space-between;
`;

const Row = styled.div`
  margin: 2.4rem 0;
`;

const SplitRow = styled.div`
  display: flex;
  margin-bottom: 2.4rem;
  > * {
    flex-basis: 50%;
  }
`;

const Setting = styled.div`
  margin-bottom: 0.5rem;
`;

const Label = styled.label`
  font-weight: bold;
`;

const HintText = styled.div`
  color: ${colors.neutral.dark};
  ${fonts.faces.light};
`;

const StyledTextInput = styled(Field).attrs({
  type: 'text',
})`
  padding: 0.8rem 1rem;
  border-radius: 4px;
  border: 1px solid ${colors.forms.borders.light};
  font-size: 1.4rem;

  &:focus {
    border-color: ${colors.forms.borders.focus};
    box-shadow: 0 0 4px 0 ${colors.forms.borders.focusShadow};
  }

  &::placeholder {
    font-size: inherit;
  }
`;

const TextInputWrapper = styled.div`
  display: flex;
  flex-direction: column;
`;

const TextInputError = styled.div`
  color: red;
  margin: 1rem 0;
`;

const TextInput = (props) => (
  <TextInputWrapper>
    <StyledTextInput {...props} />
    <ErrorMessage name={props.name} render={msg => <TextInputError>{msg}</TextInputError>} />
  </TextInputWrapper>
);
TextInput.propTypes = {
  name: PropTypes.string.isRequired,
};

const AltButton = styled(Button)`
  &.btn.btn-plain {
    background-color: ${colors.neutral.white};
    color: ${colors.neutral.dark};
    border: 1px solid ${colors.neutral.pale};
    padding: 1rem 2rem;
    min-width: 10rem;
  }
`;

const PrimaryButton = styled(Button)`
  &.btn {
    padding: 1rem 2rem;
  }
`;

const AssignmentBuilder = observer(({ ux, children, title }) => {
  return (
    <ScrollToTop>
      <FormWrapper>
        <Header className="heading" templateColors={colors.templates[ux.plan.type]}>
          <HeaderStep>
            STEP {ux.steps.number}
          </HeaderStep>
          {title}
        </Header>
        <BodyWrapper>
          {children}
        </BodyWrapper>
      </FormWrapper>
      <Footer className="controls">
        <FooterInner>
          {!ux.steps.canGoBackward && <AltButton variant="plain">Cancel</AltButton>}
          {ux.steps.canGoBackward && <AltButton variant="plain" onClick={ux.steps.goBackward}>Back</AltButton>}
          <PrimaryButton
            variant="primary"
            disabled={!ux.steps.canGoForward}
            onClick={ux.steps.goForward}
          >
            Save & Continue
          </PrimaryButton>
        </FooterInner>
      </Footer>
    </ScrollToTop>
  );
});

AssignmentBuilder.propTypes = {
  ux: PropTypes.object.isRequired,
  children: PropTypes.node.isRequired,
  title: PropTypes.string.isRequired,
};

export { AssignmentBuilder, Row, SplitRow, HintText, Label, TextInput, Setting, Body };
<|endoftext|>


<commit_before>/**
 * OpenEyes
 *
 * (C) Moorfields Eye Hospital NHS Foundation Trust, 2008-2011
 * (C) OpenEyes Foundation, 2011-2013
 * This file is part of OpenEyes.
 * OpenEyes is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
 * OpenEyes is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License along with OpenEyes in a file titled COPYING. If not, see <http://www.gnu.org/licenses/>.
 *
 * @package OpenEyes
 * @link http://www.openeyes.org.uk
 * @author OpenEyes <info@openeyes.org.uk>
 * @copyright Copyright (c) 2008-2011, Moorfields Eye Hospital NHS Foundation Trust
 * @copyright Copyright (c) 2011-2013, OpenEyes Foundation
 * @license http://www.gnu.org/licenses/gpl-3.0.html The GNU General Public License V3.0
 */

/**
 *  HOW TO USE

 Intit the search by calling the
 OpenEyes.UI.Search.init( $('#patient_merge_search') );
 and pass the input DOM
 Clik on one item in the autocomplete list will redirect to the patien's summery page like:  /patient/view/19942

 To override the default functionality

 Set the ajax URL to be called (default: /patient/ajaxSearch ):

 OpenEyes.UI.Search.setSourceURL('/patientMergeRequest/search');

 To override the jquery autocomplete defaults:

 use the OpenEyes.UI.Search.getElement() to get back the input DOM with jquery autocomple

 _renderItem:
 OpenEyes.UI.Search.getElement().data('autocomplete')._renderItem = function (ul, item) {
        return $("

")
          .data("item.autocomplete", item)
          .append("" + item.first_name + " " + item.last_name + "")
          .appendTo(ul);
    };

 select:
 OpenEyes.UI.Search.getElement().autocomplete('option', 'select', function(event, ui){
        alert(ui.item.id);
    });

 close:
 OpenEyes.UI.Search.getElement().autocomplete('option', 'close', function(event, ui){
        console.log(event, ui);
    });

 *
 *
 */

(function (exports) {
    /**
     * OpenEyes UI namespace
     * @namespace OpenEyes.UI
     * @memberOf OpenEyes
     */

    var autocompleteSource = '/patient/ajaxSearch';
    var $searchInput;

    /**
     * Render an item
     *
     * @param ul
     * @param item
     * @returns {*|jQuery}
     */
    var renderItem = function (ul, item) {
        ul.addClass("z-index-1000 patient-ajax-list");
        return $("

")
          .data("item.autocomplete", item)
          .append("" + item.first_name + " " + item.last_name + "" + " (" + item.age + ")" + "Male" + "
" + item.nhsnum + "

Hospital No.: " + item.hos_num + "
Date of birth: " + item.dob + "")
          .appendTo(ul);
    };

    /**
     * Init the search
     */
    function initAutocomplete() {
        $searchInput.autocomplete({
            minLength: 0,
            delay: 700,
            source: function (request, response) {
                $.getJSON(autocompleteSource, {
                    term: request.term,
                    ajax: 'ajax'
                }, response);
            },
            search: function () {
                $('.loader').show();
            },
            select: function(event, ui){
                window.location.href = "/patient/view/" + ui.item.id;
            },
            response: function (event, ui) {
                $('.loader').hide();
                if (ui.content.length === 0) {
                    $('.no-result-patients').slideDown();
                } else {
                    $('.no-result-patients').slideUp();
                }
            }
        });

        if ($searchInput !== 'undefined' && $searchInput.length) {
            $searchInput.data("autocomplete")._renderItem = renderItem;
        }
    }

    exports.Search = {
        init: function ($input) {
            $searchInput = $input;
            initAutocomplete();
        },
        setSourceURL: function(url){
            autocompleteSource = url;
        },
        setRenderItem: function(renderItem){
            $searchInput.data("autocomplete")._renderItem = renderItem;
        },
        getElement: function(){
            return $searchInput;
        }
    };
}(this.OpenEyes.UI));<commit_msg>Fixes issues with no results and multiple searches<commit_after>/**
 * OpenEyes
 *
 * (C) Moorfields Eye Hospital NHS Foundation Trust, 2008-2011
 * (C) OpenEyes Foundation, 2011-2013
 * This file is part of OpenEyes.
 * OpenEyes is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
 * OpenEyes is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License along with OpenEyes in a file titled COPYING. If not, see <http://www.gnu.org/licenses/>.
 *
 * @package OpenEyes
 * @link http://www.openeyes.org.uk
 * @author OpenEyes <info@openeyes.org.uk>
 * @copyright Copyright (c) 2008-2011, Moorfields Eye Hospital NHS Foundation Trust
 * @copyright Copyright (c) 2011-2013, OpenEyes Foundation
 * @license http://www.gnu.org/licenses/gpl-3.0.html The GNU General Public License V3.0
 */

/**
 *  HOW TO USE

 Intit the search by calling the
 OpenEyes.UI.Search.init( $('#patient_merge_search') );
 and pass the input DOM
 Clik on one item in the autocomplete list will redirect to the patien's summery page like:  /patient/view/19942

 To override the default functionality

 Set the ajax URL to be called (default: /patient/ajaxSearch ):

 OpenEyes.UI.Search.setSourceURL('/patientMergeRequest/search');

 To override the jquery autocomplete defaults:

 use the OpenEyes.UI.Search.getElement() to get back the input DOM with jquery autocomple

 _renderItem:
 OpenEyes.UI.Search.getElement().data('autocomplete')._renderItem = function (ul, item) {
        return $("

")
          .data("item.autocomplete", item)
          .append("" + item.first_name + " " + item.last_name + "")
          .appendTo(ul);
    };

 select:
 OpenEyes.UI.Search.getElement().autocomplete('option', 'select', function(event, ui){
        alert(ui.item.id);
    });

 close:
 OpenEyes.UI.Search.getElement().autocomplete('option', 'close', function(event, ui){
        console.log(event, ui);
    });

 *
 *
 */

(function (exports) {
    /**
     * OpenEyes UI namespace
     * @namespace OpenEyes.UI
     * @memberOf OpenEyes
     */

    var autocompleteSource = '/patient/ajaxSearch';
    var $searchInput;

    /**
     * Render an item
     *
     * @param ul
     * @param item
     * @returns {*|jQuery}
     */
    var renderItem = function (ul, item) {
        ul.addClass("z-index-1000 patient-ajax-list");
        return $("

")
          .data("item.autocomplete", item)
          .append("" + item.first_name + " " + item.last_name + "" + " (" + item.age + ")" + "Male" + "
" + item.nhsnum + "

Hospital No.: " + item.hos_num + "
Date of birth: " + item.dob + "")
          .appendTo(ul);
    };

    /**
     * Init the search
     */
    function initAutocomplete($input) {
      $input.autocomplete({
            minLength: 0,
            delay: 700,
            source: function (request, response) {
                $.getJSON(autocompleteSource, {
                    term: request.term,
                    ajax: 'ajax'
                }, response);
            },
            search: function () {
                $('.loader').show();
            },
            select: function(event, ui){
                window.location.href = "/patient/view/" + ui.item.id;
            },
            response: function (event, ui) {
                $('.loader').hide();
                if (ui.content.length === 0) {
                  $input.siblings('.no-result-patients').slideDown();
                } else {
                  $input.siblings('.no-result-patients').slideUp();
                }
            }
        });

        if ($input !== 'undefined' && $input.length) {
          $input.data("autocomplete")._renderItem = renderItem;
        }
    }

    exports.Search = {
        init: function ($input) {
            $searchInput = $input;
            initAutocomplete($input);

            return exports.Search;
        },
        setSourceURL: function(url){
            autocompleteSource = url;
        },
        setRenderItem: function(renderItem){
            $searchInput.data("autocomplete")._renderItem = renderItem;
        },
        getElement: function(){
            return $searchInput;
        }
    };
}(this.OpenEyes.UI));<|endoftext|>


<commit_before>/*
 * This is purely for the Android 1.5/1.6 HTML 5 Storage
 * I was hoping that Android 2.0 would deprecate this, but given the fact that
 * most manufacturers ship with Android 1.5 and do not do OTA Updates, this is required
 */

var DroidDB = function()
{
  this.txQueue = [];
}

DroidDB.prototype.addResult = function(rawdata, tx_id)
{
  eval("var data = " + rawdata);
  var tx = this.txQueue[tx_id];
  tx.resultSet.push(data);
}

DroidDB.prototype.completeQuery = function(tx_id)
{
  var tx = this.txQueue[tx_id];
  var r = new result();
  r.rows.resultSet = tx.resultSet;
  r.rows.length = tx.resultSet.length;
  tx.win(r);
}

DroidDB.prototype.fail = function(reason, tx_id)
{
  var tx = this.txQueue[tx_id];
  tx.fail(reason);
}

var DatabaseShell = function()
{

}

DatabaseShell.prototype.transaction = function(process)
{
  tx = new Tx();
  process(tx);
}

var Tx = function()
{
  droiddb.txQueue.push(this);
  this.id = droiddb.txQueue.length - 1;
  this.resultSet = [];
}

Tx.prototype.executeSql = function(query, params, win, fail)
{
  droidStorage.executeSql(query, params, this.id);
  tx.win = win;
  tx.fail = fail;
}

var result = function()
{
  this.rows = new Rows();
}

var Rows = function()
{
  this.resultSet = [];
  this.length = 0;
}

Rows.prototype.item = function(row_id)
{
  return this.resultSet[id];
}

var dbSetup = function(name, version, display_name, size)
{
    droidStorage.openDatabase(name, version, display_name, size)
    db_object = new DatabaseShell();
    return db_object;
}

PhoneGap.addConstructor(function() {
  if (typeof navigator.openDatabase == "undefined")
  {
    navigator.openDatabase = window.openDatabase = dbSetup;
  window.droiddb = new DroidDB();
  }
});

<commit_msg>Attempt to fix the HTML 5 storage<commit_after>/*
 * This is purely for the Android 1.5/1.6 HTML 5 Storage
 * I was hoping that Android 2.0 would deprecate this, but given the fact that
 * most manufacturers ship with Android 1.5 and do not do OTA Updates, this is required
 */

var DroidDB = function()
{
  this.txQueue = [];
}

DroidDB.prototype.addResult = function(rawdata, tx_id)
{
  eval("var data = " + rawdata);
  var tx = this.txQueue[tx_id];
  tx.resultSet.push(data);
}

DroidDB.prototype.completeQuery = function(tx_id)
{
  var tx = this.txQueue[tx_id];
  var r = new result();
  r.rows.resultSet = tx.resultSet;
  r.rows.length = tx.resultSet.length;
  tx.win(r);
}

DroidDB.prototype.fail = function(reason, tx_id)
{
  var tx = this.txQueue[tx_id];
  tx.fail(reason);
}

var DatabaseShell = function()
{

}

DatabaseShell.prototype.transaction = function(process)
{
  tx = new Tx();
  process(tx);
}

var Tx = function()
{
  droiddb.txQueue.push(this);
  this.id = droiddb.txQueue.length - 1;
  this.resultSet = [];
}

Tx.prototype.executeSql = function(query, params, win, fail)
{
  droidStorage.executeSql(query, params, this.id);
  tx.win = win;
  tx.fail = fail;
}

var result = function()
{
  this.rows = new Rows();
}

var Rows = function()
{
  this.resultSet = [];
  this.length = 0;
}

Rows.prototype.item = function(row_id)
{
  return this.resultSet[id];
}

var dbSetup = function(name, version, display_name, size)
{
    droidStorage.openDatabase(name, version, display_name, size)
    db_object = new DatabaseShell();
    return db_object;
}

PhoneGap.addConstructor(function() {
  if (typeof window.openDatabase == "undefined")
  {
    navigator.openDatabase = window.openDatabase = dbSetup;
    window.droiddb = new DroidDB();
  }
});

<|endoftext|>


<commit_before>import { SEARCH_URL, AUTOCOMPLETE_URL } from 'constants';
import { SHOW_TOOLTIP, HIDE_TOOLTIP, TOGGLE_FOCUS, SEARCH_REQUEST,
  SEARCH_SUCCESS, SEARCH_FAILURE, UPDATE_SEARCH_INPUT, SEARCH_APPEND,
  AUTOCOMPLETE_REQUEST, AUTOCOMPLETE_SUCCESS, AUTOCOMPLETE_FAILURE } from './actionTypes';
import makeActionCreator from './makeActionCreator';
import mockAutocomplete from '../utils/mockAutocomplete';

export const showSearchTooltip = makeActionCreator(SHOW_TOOLTIP);
export const hideSearchTooltip = makeActionCreator(HIDE_TOOLTIP);
export const toggleFocus = makeActionCreator(TOGGLE_FOCUS);

const searchRequest = makeActionCreator(SEARCH_REQUEST);
const searchSuccess = makeActionCreator(SEARCH_SUCCESS, 'data');
const searchFailure = makeActionCreator(SEARCH_FAILURE, 'error');
const searchAppend = makeActionCreator(SEARCH_APPEND);

export const updateSearchInput = makeActionCreator(UPDATE_SEARCH_INPUT, 'input');

let pageIndex = 0;

const getResults = serializedQuery => new Promise((resolve, reject) => {
  const baseSearchURL = SEARCH_URL[window.catalogue];
  const searchUrl = `${baseSearchURL}?${serializedQuery}`;
  fetch(searchUrl)
    .then(response => response.json())
    .then(parsedResponse => resolve(parsedResponse))
    .catch(error => reject(error));
});

const serializeQuery = (query, selectedData) => {
  const encode = encodeURIComponent; // short-hand
  let serializedQuery = (query) ? `recording=${encode(query)}` : '';
  Object.keys(selectedData).forEach((category) => {
    if (selectedData[category].length) {
      const categoryEntries = selectedData[category].reduce((curStr, entry, index) => {
        if (index === selectedData[category].length - 1) {
          return curStr + encode(entry);
        }
        return `${curStr}${encode(entry)}+`;
      }, '');
      serializedQuery += `&${encode(category)}=${categoryEntries}`;
    }
  });
  if (pageIndex) {
    serializedQuery += `&page=${pageIndex}`;
  }
  return serializedQuery;
};

export const getSearchResults = () => (dispatch, getStore) => {
  pageIndex = 0;
  const state = getStore();
  const query = state.search.input;
  const { selectedData } = state.filtersData;
  const serializedQuery = serializeQuery(query, selectedData);
  dispatch(searchRequest());
  getResults(serializedQuery).then(
    data => dispatch(searchSuccess(data)),
    error => dispatch(searchFailure(error)));
};

export const getMoreResults = () => (dispatch) => {
  pageIndex += 1;
  dispatch(searchAppend());
  setTimeout(() => {
    getResults(pageIndex).then(data => dispatch(searchSuccess(data)),
    error => dispatch(searchFailure(error)));
  }, 1000);
};

export const getAutocompleteList = input => (dispatch) => {
  const autocompleteURL = AUTOCOMPLETE_URL[window.catalogue];
  if (!autocompleteURL) {
    return;
  }
  dispatch({ type: AUTOCOMPLETE_REQUEST });
  mockAutocomplete(input).then(datalist => dispatch({ type: AUTOCOMPLETE_SUCCESS, datalist }));
};
<commit_msg>Use 1 as initial page index<commit_after>import { SEARCH_URL, AUTOCOMPLETE_URL } from 'constants';
import { SHOW_TOOLTIP, HIDE_TOOLTIP, TOGGLE_FOCUS, SEARCH_REQUEST,
  SEARCH_SUCCESS, SEARCH_FAILURE, UPDATE_SEARCH_INPUT, SEARCH_APPEND,
  AUTOCOMPLETE_REQUEST, AUTOCOMPLETE_SUCCESS, AUTOCOMPLETE_FAILURE } from './actionTypes';
import makeActionCreator from './makeActionCreator';
import mockAutocomplete from '../utils/mockAutocomplete';

export const showSearchTooltip = makeActionCreator(SHOW_TOOLTIP);
export const hideSearchTooltip = makeActionCreator(HIDE_TOOLTIP);
export const toggleFocus = makeActionCreator(TOGGLE_FOCUS);

const searchRequest = makeActionCreator(SEARCH_REQUEST);
const searchSuccess = makeActionCreator(SEARCH_SUCCESS, 'data');
const searchFailure = makeActionCreator(SEARCH_FAILURE, 'error');
const searchAppend = makeActionCreator(SEARCH_APPEND);

export const updateSearchInput = makeActionCreator(UPDATE_SEARCH_INPUT, 'input');

let pageIndex = 1;

const getResults = serializedQuery => new Promise((resolve, reject) => {
  const baseSearchURL = SEARCH_URL[window.catalogue];
  const searchUrl = `${baseSearchURL}?${serializedQuery}`;
  fetch(searchUrl)
    .then(response => response.json())
    .then(parsedResponse => resolve(parsedResponse))
    .catch(error => reject(error));
});

const serializeQuery = (query, selectedData) => {
  const encode = encodeURIComponent; // short-hand
  let serializedQuery = (query) ? `recording=${encode(query)}` : '';
  Object.keys(selectedData).forEach((category) => {
    if (selectedData[category].length) {
      const categoryEntries = selectedData[category].reduce((curStr, entry, index) => {
        if (index === selectedData[category].length - 1) {
          return curStr + encode(entry);
        }
        return `${curStr}${encode(entry)}+`;
      }, '');
      serializedQuery += `&${encode(category)}=${categoryEntries}`;
    }
  });
  if (pageIndex - 1 !== 0) {
    serializedQuery += `&page=${pageIndex}`;
  }
  return serializedQuery;
};

export const getSearchResults = () => (dispatch, getStore) => {
  pageIndex = 1;
  const state = getStore();
  const query = state.search.input;
  const { selectedData } = state.filtersData;
  const serializedQuery = serializeQuery(query, selectedData);
  dispatch(searchRequest());
  getResults(serializedQuery).then(
    data => dispatch(searchSuccess(data)),
    error => dispatch(searchFailure(error)));
};

export const getMoreResults = () => (dispatch) => {
  pageIndex += 1;
  dispatch(searchAppend());
  setTimeout(() => {
    getResults(pageIndex).then(data => dispatch(searchSuccess(data)),
    error => dispatch(searchFailure(error)));
  }, 1000);
};

export const getAutocompleteList = input => (dispatch) => {
  const autocompleteURL = AUTOCOMPLETE_URL[window.catalogue];
  if (!autocompleteURL) {
    return;
  }
  dispatch({ type: AUTOCOMPLETE_REQUEST });
  mockAutocomplete(input).then(datalist => dispatch({ type: AUTOCOMPLETE_SUCCESS, datalist }));
};
<|endoftext|>


<commit_before>function gmmktime () {
    // http://kevin.vanzonneveld.net
    // +   original by: Brett Zamir (http://brett-zamir.me)
    // +   derived from: mktime
    // *     example 1: gmmktime(14, 10, 2, 2, 1, 2008);
    // *     returns 1: 1201875002

    var no=0, i = 0, ma=0, mb=0, d = new Date(), dn = new Date(), argv = arguments, argc = argv.length;

    var dateManip = {
        0: function (tt){ return d.setUTCHours(tt); },
        1: function (tt){ return d.setUTCMinutes(tt); },
        2: function (tt){ var set = d.setUTCSeconds(tt); mb = d.getUTCDate() - dn.getUTCDate(); return set;},
        3: function (tt){ var set = d.setUTCMonth(parseInt(tt, 10)-1); ma = d.getUTCFullYear() - dn.getUTCFullYear(); return set;},
        4: function (tt){ return d.setUTCDate(tt+mb);},
        5: function (tt){
            if (tt >= 0 && tt <= 69) {
                tt += 2000;
            }
            else if (tt >= 70 && tt <= 100) {
                tt += 1900;
            }
            return d.setUTCFullYear(tt+ma);
        }
        // 7th argument (for DST) is deprecated
    };

    for (i = 0; i < argc; i++){
        no = parseInt(argv[i]*1, 10);
        if (isNaN(no)) {
            return false;
        } else {
            // arg is number, let's manipulate date object
            if (!dateManip[i](no)){
                // failed
                return false;
            }
        }
    }
    for (i = argc; i < 6; i++) {
        switch (i) {
            case 0:
                no = dn.getUTCHours();
                break;
            case 1:
                no = dn.getUTCMinutes();
                break;
            case 2:
                no = dn.getUTCSeconds();
                break;
            case 3:
                no = dn.getUTCMonth()+1;
                break;
            case 4:
                no = dn.getUTCDate();
                break;
            case 5:
                no = dn.getUTCFullYear();
                break;
        }
        dateManip[i](no);
    }

    return Math.floor(d.getTime()/1000);
}
<commit_msg>Editing via github.com. Updating to reflect changes made to mktime. Added negative time example.<commit_after>function gmmktime() {
    // http://kevin.vanzonneveld.net
    // +   original by: Brett Zamir (http://brett-zamir.me)
    // +   derived from: mktime
    // *     example 1: gmmktime(14, 10, 2, 2, 1, 2008);
    // *     returns 1: 1201875002
    // *     example 2: gmmktime(0, 0, -1, 1, 1, 1970);
    // *     returns 2: -1

    var d = new Date(), r = arguments, i = 0,
        e = ['Hours', 'Minutes', 'Seconds', 'Month', 'Date', 'FullYear'];

    for (i = 0; i < e.length; i++) {
        if (typeof r[i] === 'undefined') {
            r[i] = d['getUTC' + e[i]]();
            r[i] += (i === 3); // +1 to fix JS months.
        } else {
            r[i] = parseInt(r[i], 10);
            if (isNaN(r[i])) {
                return false;
            }
        }
    }

    // Map years 0-69 to 2000-2069 and years 70-100 to 1970-2000.
    r[5] += (r[5] >= 0 ? (r[5] <= 69 ? 2e3 : (r[5] <= 100 ? 1900 : 0)) : 0);

    // Set year, month (-1 to fix JS months), and date.
    // !This must come before the call to setHours!
    d.setUTCFullYear(r[5], r[3] - 1, r[4]);

    // Set hours, minutes, and seconds.
    d.setUTCHours(r[0], r[1], r[2]);

    // Divide milliseconds by 1000 to return seconds and drop decimal.
    // Add 1 second if negative or it'll be off from PHP by 1 second.
    return (d.getTime() / 1e3 >> 0) - (d.getTime() < 0);
}<|endoftext|>


<commit_before>/**********************************************
 * Module for communication with the dice
 *
 **********************************************/
var diceServiceUUID = "00000000000000000000000000001812";
var diceRollCharacteristicUUID = "00000000000000000000000000002ac5";
var diceCommandCharacteristicUUID = "00000000000000000000000000002a9f";

var r = {
  commands: {
    COMMAND_REGISTER: 1,
    COMMAND_REGISTER_ACK: 2,
    COMMAND_LED_ON: 3,
    COMMAND_LED_OFF: 4
  },
  dice: [],
  noble: null,
  maxDice: 4,
  diceMapping: {},

  sendCommand: function(did, command) {
    if(r.diceMapping[did] != null) {
      var payload = new Buffer(1);
      payload.writeUInt8(command, 0);
      r.diceMapping[did].write(payload, true, function(e) {
        if(e) {
          console.log(e);
        }
      });
    }
  },

  init: function(rollHandler) {
    /**
     * Initialize the BLE system
     */
    r.noble = require('noble');
    r.noble.on('stateChange', function(state) {
      console.log('State changed to: ' + state);
      if(state === 'poweredOn') {
        r.noble.startScanning([diceServiceUUID], false);
      } else {
        r.noble.stopScanning();
      }
    });

    r.noble.on('discover', function(p) {
      var ad = p.advertisement;
      var name = ad.localName;
      var uuid = ad.serviceUuids;

      console.log('Found peripheral: ' + name);
      r.diceMapping[uuid] = name;
      p.on('disconnect', function() {
        console.log('Disconnected from: ' + p);
        r.noble.startScanning();
      });

      p.connect(function(e) {
        p.discoverServices([diceServiceUUID], function(e, services) {
          services.forEach(function(service) {
            console.log('Found service: ' + service.uuid);
            service.discoverCharacteristics([], function(e, characteristics) {
              characteristics.forEach(function(c) {
                if(c.uuid === diceRollCharacteristicUUID) {
                  c.on('read', function(data, isNotification) {
                    var did = data[0] >> 4;
                    var value = data[0] & 0xf;
                    rollHandler(did, value);
                  });
                  c.notify(true, function(e) {
                    console.log('Listening for rolls');
                  });
                }
                else if(c.uuid = diceCommandCharacteristicUUID) {
                  c.on('read', function(data, isNotification) {
                    var did = data[0] >> 4;
                    var value = data[0] & 0xf;
                    if(value == r.commands.COMMAND_REGISTER) {
                      r.diceMapping[did] = c;
                      r.sendCommand(did, r.commands.COMMAND_REGISTER_ACK);
                      console.log('Registered dice #' + did);
                    }
                  });
                  c.notify(true, function(e) {
                    if(e) {
                      console.log(e);
                    }
                  });
                }
              });
            });
          });
        });
      });
    });
  }
};

module.exports = r;
<commit_msg>Add buzz command<commit_after>/**********************************************
 * Module for communication with the dice
 *
 **********************************************/
var diceServiceUUID = "00000000000000000000000000001812";
var diceRollCharacteristicUUID = "00000000000000000000000000002ac5";
var diceCommandCharacteristicUUID = "00000000000000000000000000002a9f";

var r = {
  commands: {
    COMMAND_REGISTER: 1,
    COMMAND_REGISTER_ACK: 2,
    COMMAND_LED_ON: 3,
    COMMAND_LED_OFF: 4,
    COMMAND_BUZZ: 5
  },
  dice: [],
  noble: null,
  maxDice: 4,
  diceMapping: {},

  sendCommand: function(did, command) {
    if(r.diceMapping[did] != null) {
      var payload = new Buffer(1);
      payload.writeUInt8(command, 0);
      r.diceMapping[did].write(payload, true, function(e) {
        if(e) {
          console.log(e);
        }
      });
    }
  },

  init: function(rollHandler) {
    /**
     * Initialize the BLE system
     */
    r.noble = require('noble');
    r.noble.on('stateChange', function(state) {
      console.log('State changed to: ' + state);
      if(state === 'poweredOn') {
        r.noble.startScanning([diceServiceUUID], false);
      } else {
        r.noble.stopScanning();
      }
    });

    r.noble.on('discover', function(p) {
      var ad = p.advertisement;
      var name = ad.localName;
      var uuid = ad.serviceUuids;

      console.log('Found peripheral: ' + name);
      r.diceMapping[uuid] = name;
      p.on('disconnect', function() {
        console.log('Disconnected from: ' + p);
        r.noble.startScanning();
      });

      p.connect(function(e) {
        p.discoverServices([diceServiceUUID], function(e, services) {
          services.forEach(function(service) {
            console.log('Found service: ' + service.uuid);
            service.discoverCharacteristics([], function(e, characteristics) {
              characteristics.forEach(function(c) {
                if(c.uuid === diceRollCharacteristicUUID) {
                  c.on('read', function(data, isNotification) {
                    var did = data[0] >> 4;
                    var value = data[0] & 0xf;
                    rollHandler(did, value);
                  });
                  c.notify(true, function(e) {
                    console.log('Listening for rolls');
                  });
                }
                else if(c.uuid = diceCommandCharacteristicUUID) {
                  c.on('read', function(data, isNotification) {
                    var did = data[0] >> 4;
                    var value = data[0] & 0xf;
                    if(value == r.commands.COMMAND_REGISTER) {
                      r.diceMapping[did] = c;
                      r.sendCommand(did, r.commands.COMMAND_REGISTER_ACK);
                      console.log('Registered dice #' + did);
                    }
                  });
                  c.notify(true, function(e) {
                    if(e) {
                      console.log(e);
                    }
                  });
                }
              });
            });
          });
        });
      });
    });
  }
};

module.exports = r;
<|endoftext|>


<commit_before>class HomeController {
  constructor($state, socketService, userService) {
    this.$state = $state;
    this.socket = socketService;
    this.userService = userService;

    this._setup();
  }

  createRoom() {
    this.socket.emit('create-room', null, data => {
      if (data.roomId)
        this.$state.go('room', { roomId: data.roomId});
    });
  }

  joinRoom(roomId) {
    console.log(roomId);
  }

  _setup() {
    this.socket.emit('home', null, data => {
      this.rooms = data.rooms;
      this.users = data.users;
    });

    this.socket.on('user:connect', data => {
      this.users.push(data.user);
    });

    this.socket.on('user:disconnect', data => {
      this.users.splice(this.users.indexOf(data.user));
    });

    this.socket.on('user:create-room', data => {
      this.rooms = data.rooms;
    });
  }
}

HomeController.$inject = ['$state', 'socketService', 'userService'];

export { HomeController };
<commit_msg>joinRoom method now changes state to room with supplied roomId.<commit_after>class HomeController {
  constructor($state, socketService, userService) {
    this.$state = $state;
    this.socket = socketService;
    this.userService = userService;

    this._setup();
  }

  createRoom() {
    this.socket.emit('create-room', null, data => {
      if (data.roomId)
        this.$state.go('room', { roomId: data.roomId});
    });
  }

  joinRoom(roomId) {
    this.$state.go('room', { roomId });
  }

  _setup() {
    this.socket.emit('home', null, data => {
      this.rooms = data.rooms;
      this.users = data.users;
    });

    this.socket.on('user:connect', data => {
      this.users.push(data.user);
    });

    this.socket.on('user:disconnect', data => {
      this.users.splice(this.users.indexOf(data.user));
    });

    this.socket.on('user:create-room', data => {
      this.rooms = data.rooms;
    });
  }
}

HomeController.$inject = ['$state', 'socketService', 'userService'];

export { HomeController };
<|endoftext|>


<commit_before>import gulp from 'gulp'
import babelify from 'babelify'
import browserSync from 'browser-sync'
import browserify from 'browserify'
import browserifyShim from 'browserify-shim'
import rename from 'gulp-rename'
import stylus from 'gulp-stylus'
import concat from 'gulp-concat'
import jade from 'gulp-jade'
import es from 'event-stream'
import rimraf from 'rimraf'
import ghPages from 'gulp-gh-pages'
import autoprefixer from 'gulp-autoprefixer'
import sourcemaps from 'gulp-sourcemaps'
import imagemin from 'gulp-imagemin'
import watch from 'gulp-watch'
import uglify from 'gulp-uglify'
import resrc from 'gulp-resrc'
import condition from 'gulp-if'
import header from 'gulp-header'
import plumber from 'gulp-plumber'
import source from 'vinyl-source-stream'
import ngAnnotate from 'gulp-ng-annotate'
import gutil from 'gulp-util'
import eslint from 'gulp-eslint'

const PRODUCTION = process.env.NODE_ENV && process.env.NODE_ENV.toLowerCase() === 'production';
const DIST = './dist'

gulp.task('es6', () => {
    return browserify('./src/js/main.js', {
        transform: ['babelify', 'require-globify', 'browserify-shim'],
        debug: !PRODUCTION
    })
    .bundle()
    // this must to listen error event, can't use plumber
    // use gutil and console to pretty error output
    .on('error', err => gutil.log(err.message) & console.log(err.codeFrame))
    .pipe(plumber())
    .pipe(source('app.js'))
    .pipe(ngAnnotate())
    .pipe(condition(PRODUCTION, uglify()))
    .pipe(rename('app.js'))
    .pipe(condition(PRODUCTION, header('// Made by XGHeaven\n')))
    .pipe(gulp.dest( DIST + '/js/'))
    .pipe(browserSync.stream())
})

gulp.task('stylus', () => {
    let opts = {
        compress: PRODUCTION
    }

    return gulp
    .src('./src/stylus/**/*.styl')
    .pipe(plumber())
    .pipe(condition(PRODUCTION, sourcemaps.init()))
    .pipe(stylus(opts))
    .pipe(condition(PRODUCTION, sourcemaps.write()))
    .pipe(concat('app.css'))
    .pipe(autoprefixer({
        browsers: 'last 2 versions'
    }))
    .pipe(condition(PRODUCTION, header('/* Made by XGHeaven */\n')))
    .pipe(gulp.dest('./dist/css/'))
    .pipe(browserSync.stream())
})

gulp.task('image', () => {
    return gulp.src('./src/image/**/*.*')
    .pipe(imagemin({
        progressive: true
    }))
    .pipe(gulp.dest(DIST + '/image'))
})

gulp.task('cdn', () => {
    const jsFiles = [
        'angular/angular',
        'angular-animate/angular-animate',
        'angular-aria/angular-aria',
        'angular-material/angular-material',
        'angular-ui-router/release/angular-ui-router',
        'angular-sanitize/angular-sanitize',
        'angular-messages/angular-messages',
        'angular-hotkeys/build/hotkeys',
        'ngstorage/ngStorage',
        'marked/marked'
        ].map(addMin('.js'))
    const cssFiles = [
        'angular-material/angular-material',
        'angular-material/angular-material.layouts',
        'bootstrap/dist/css/bootstrap',
        'font-awesome/css/font-awesome',
        'angular-hotkeys/build/hotkeys'
        ].map(addMin('.css')).concat([
            './node_modules/highlight.js/styles/default.css'
        ])

    const fontFiles = [
        'bootstrap/dist/fonts/*.*',
        'font-awesome/fonts/*.*'
    ].map(f => './node_modules/' + f)

    gulp.src(jsFiles).pipe(gulp.dest(DIST + '/js/'))
    gulp.src(cssFiles).pipe(gulp.dest(DIST + '/css/'))
    gulp.src(fontFiles).pipe(gulp.dest(DIST + '/fonts/'))

    function addMin(suffix) {
        return function(file) {
            return './node_modules/' + file + '.min' + suffix;
        }
    }
})

gulp.task('clean', () => {
    rimraf.sync(DIST)
})

gulp.task('view', () => {
  gulp.run(['html', 'pug'])
})

gulp.task('html', () => {
  return es.merge(
    gulp.src('./src/view/**/*.html', {base: 'src'}),
    gulp.src('./src/*.html')
  ).pipe(gulp.dest(DIST))
  .pipe(browserSync.stream())
})

gulp.task('pug', () => {
  return gulp
  .src('./src/view/**/*.jade', {base: 'src'})
  .pipe(plumber())
  .pipe(jade())
  .pipe(gulp.dest(DIST))
  .pipe(browserSync.stream())
})

gulp.task('build', ['clean', 'es6', 'stylus', 'view', 'cdn', 'image'])

gulp.task('watch', () => {
    // gulp run is deprecated before 4.0
    watch('./src/js/**/*.js', () => gulp.run(['es6']))
    watch('./src/stylus/**/*.styl', () => gulp.run(['stylus']))
    watch('./src/**/*.jade', () => gulp.run(['pug']))
    watch('./src/**/*.html', () => gulp.run(['html']))
    watch('./src/image/**/*', () => gulp.run(['image']))
})

gulp.task('reload', () => {
    browserSync.reload()
})

gulp.task('server', ['build'], () => {
    browserSync.init({
        server: {
            baseDir: DIST
        },
        ui: false,
        port: 8000
    })
})

function lint() {
  return gulp
  .src('src/**/*.js')
  .pipe(eslint())
  .pipe(eslint.format())
  .pipe(eslint.failAfterError())
}

gulp.task('lint', lint)

gulp.task('predeploy', () => {
    return gulp.src('CNAME').pipe(gulp.dest(DIST))
})

gulp.task('lintBeforeDeploy', ['build', 'predeploy'], lint)

gulp.task('deploy', ['lintBeforeDeploy'], () => {
    return gulp.src(DIST + '/**/*').pipe(ghPages())
})

gulp.task('default', ['clean', 'build', 'server', 'watch'])
<commit_msg>fix: uglify file warning after source('app.js'), change to 'src/js/app.js'<commit_after>import gulp from 'gulp'
import babelify from 'babelify'
import browserSync from 'browser-sync'
import browserify from 'browserify'
import browserifyShim from 'browserify-shim'
import rename from 'gulp-rename'
import stylus from 'gulp-stylus'
import concat from 'gulp-concat'
import jade from 'gulp-jade'
import es from 'event-stream'
import rimraf from 'rimraf'
import ghPages from 'gulp-gh-pages'
import autoprefixer from 'gulp-autoprefixer'
import sourcemaps from 'gulp-sourcemaps'
import imagemin from 'gulp-imagemin'
import watch from 'gulp-watch'
import uglify from 'gulp-uglify'
import resrc from 'gulp-resrc'
import condition from 'gulp-if'
import header from 'gulp-header'
import plumber from 'gulp-plumber'
import source from 'vinyl-source-stream'
import ngAnnotate from 'gulp-ng-annotate'
import gutil from 'gulp-util'
import eslint from 'gulp-eslint'

const PRODUCTION = process.env.NODE_ENV && process.env.NODE_ENV.toLowerCase() === 'production';
const DIST = './dist'

gulp.task('es6', () => {
    return browserify('./src/js/main.js', {
        transform: ['babelify', 'require-globify', 'browserify-shim'],
        debug: !PRODUCTION
    })
    .bundle()
    // this must to listen error event, can't use plumber
    // use gutil and console to pretty error output
    .on('error', err => gutil.log(err.message) & console.log(err.codeFrame))
    .pipe(plumber())
    .pipe(source('src/js/app.js'))
    .pipe(ngAnnotate())
    .pipe(condition(PRODUCTION, uglify()))
    .pipe(rename('app.js'))
    .pipe(condition(PRODUCTION, header('// Made by XGHeaven\n')))
    .pipe(gulp.dest( DIST + '/js/'))
    .pipe(browserSync.stream())
})

gulp.task('stylus', () => {
    let opts = {
        compress: PRODUCTION
    }

    return gulp
    .src('./src/stylus/**/*.styl')
    .pipe(plumber())
    .pipe(condition(PRODUCTION, sourcemaps.init()))
    .pipe(stylus(opts))
    .pipe(condition(PRODUCTION, sourcemaps.write()))
    .pipe(concat('app.css'))
    .pipe(autoprefixer({
        browsers: 'last 2 versions'
    }))
    .pipe(condition(PRODUCTION, header('/* Made by XGHeaven */\n')))
    .pipe(gulp.dest('./dist/css/'))
    .pipe(browserSync.stream())
})

gulp.task('image', () => {
    return gulp.src('./src/image/**/*.*')
    .pipe(imagemin({
        progressive: true
    }))
    .pipe(gulp.dest(DIST + '/image'))
})

gulp.task('cdn', () => {
    const jsFiles = [
        'angular/angular',
        'angular-animate/angular-animate',
        'angular-aria/angular-aria',
        'angular-material/angular-material',
        'angular-ui-router/release/angular-ui-router',
        'angular-sanitize/angular-sanitize',
        'angular-messages/angular-messages',
        'angular-hotkeys/build/hotkeys',
        'ngstorage/ngStorage',
        'marked/marked'
        ].map(addMin('.js'))
    const cssFiles = [
        'angular-material/angular-material',
        'angular-material/angular-material.layouts',
        'bootstrap/dist/css/bootstrap',
        'font-awesome/css/font-awesome',
        'angular-hotkeys/build/hotkeys'
        ].map(addMin('.css')).concat([
            './node_modules/highlight.js/styles/default.css'
        ])

    const fontFiles = [
        'bootstrap/dist/fonts/*.*',
        'font-awesome/fonts/*.*'
    ].map(f => './node_modules/' + f)

    gulp.src(jsFiles).pipe(gulp.dest(DIST + '/js/'))
    gulp.src(cssFiles).pipe(gulp.dest(DIST + '/css/'))
    gulp.src(fontFiles).pipe(gulp.dest(DIST + '/fonts/'))

    function addMin(suffix) {
        return function(file) {
            return './node_modules/' + file + '.min' + suffix;
        }
    }
})

gulp.task('clean', () => {
    rimraf.sync(DIST)
})

gulp.task('view', () => {
  gulp.run(['html', 'pug'])
})

gulp.task('html', () => {
  return es.merge(
    gulp.src('./src/view/**/*.html', {base: 'src'}),
    gulp.src('./src/*.html')
  ).pipe(gulp.dest(DIST))
  .pipe(browserSync.stream())
})

gulp.task('pug', () => {
  return gulp
  .src('./src/view/**/*.jade', {base: 'src'})
  .pipe(plumber())
  .pipe(jade())
  .pipe(gulp.dest(DIST))
  .pipe(browserSync.stream())
})

gulp.task('build', ['clean', 'es6', 'stylus', 'view', 'cdn', 'image'])

gulp.task('watch', () => {
    // gulp run is deprecated before 4.0
    watch('./src/js/**/*.js', () => gulp.run(['es6']))
    watch('./src/stylus/**/*.styl', () => gulp.run(['stylus']))
    watch('./src/**/*.jade', () => gulp.run(['pug']))
    watch('./src/**/*.html', () => gulp.run(['html']))
    watch('./src/image/**/*', () => gulp.run(['image']))
})

gulp.task('reload', () => {
    browserSync.reload()
})

gulp.task('server', ['build'], () => {
    browserSync.init({
        server: {
            baseDir: DIST
        },
        ui: false,
        port: 8000
    })
})

function lint() {
  return gulp
  .src('src/**/*.js')
  .pipe(eslint())
  .pipe(eslint.format())
  .pipe(eslint.failAfterError())
}

gulp.task('lint', lint)

gulp.task('predeploy', () => {
    return gulp.src('CNAME').pipe(gulp.dest(DIST))
})

gulp.task('lintBeforeDeploy', ['build', 'predeploy'], lint)

gulp.task('deploy', ['lintBeforeDeploy'], () => {
    return gulp.src(DIST + '/**/*').pipe(ghPages())
})

gulp.task('default', ['clean', 'build', 'server', 'watch'])
<|endoftext|>