<commit_before>"use strict";

let {forEach, find, findIndex} = require("lodash");

let can = require("../../shims/can"),
    $ = require("jquery"),
    element = require("../../lib/customElement");

let {conn} = require("../../lib/socketConn");

let {submitEntry} = require("../../models/chatlog");

let character = require("../../models/character"),
    user = require("../../models/user");

let inputs = [
  {name: "dialogue", template: require("./inputs/dialogue.mustache")},
  {name: "action", template: require("./inputs/action.mustache")},
  {name: "ooc", template: require("./inputs/ooc.mustache")},
  {name: "slug", template: require("./inputs/slug.mustache")},
  {name: "heading", template: require("./inputs/heading.mustache")}
];

/**
 * ChatInput Controller
 */
let ChatInput = element.define("chat-input", {
  style: require("./styles.styl"),
  template: require("./template.mustache"),
  events: {
    "form submit": sendMessage,
    "form keydown": keyPressed,
    "form textarea keydown": textAreaKeyPressed,
    "form textarea input": typingNotification,
    "form click": focusContent,
    "[name=type] change": typeSelectorChanged,
    "[name=actor] change": updateScopeActor,
    "[name=user] input": updateScopeUser,
    "{scope} type": typeChanged,
    "{scope} actor": updateActorDropdown,
    "{scope.characters} length": updateScopeActor,
    inserted: function(inp) {
      focusContent(inp);
      alignActionInput(inp);
      conn.state.bind("change", function(ev, newstate) {
        // TODO - figure out why .attr("user").id fails. CanJS bug.
        if (newstate === "open" && inp.scope.attr("user.id")) {
          window.setTimeout(function() {
            updateScopeUser(inp);
          }, 0);
        }
      });
      $(window).resize();
    }
  },
  attributes: {
    characters: { defaultMaker: character.list },
    actor: {},
    conn: { default: conn },
    user: {
      defaultMaker: function(scope) {
        user.current().then(function(usr) {
          scope.attr("user", usr);
        });
        return {};
      }
    },
    log: { type: "lookup", required: true, observe: false },
    type: { type: "string", default: inputs[0].name },
    inputs: { default: inputs },
    defaults: {
      internal: true,
      defaultMaker: function() {
        return Object.create(null);
      }
    }
  },
  helpers: {
    renderInput: renderInput,
    isSelected: isSelected
  }
});

/*
 * Chat message handling
 */
function sendMessage(chatInput, _el, event) {
  event.preventDefault();
  let formVals = can.deparam(chatInput.element.find("form").serialize());
  if (!formVals.content) { return; }
  formVals.actor = currentActor(chatInput).id;
  submitEntry(chatInput.scope.log, chatInput.scope.type, formVals);
  chatInput.scope.attr("user").attr("typing", false);
  chatInput.element.find("form")[0].reset();
}

/*
 * Actor management
 */
function currentActor(chatInput) {
  return chatInput.scope.attr("actor");
}

function updateScopeActor(chatInput) {
  chatInput.scope.attr(
    "actor", chatInput.element.find("[name=actor] :selected").data("actor"));
  alignActionInput(chatInput);
  $(window).resize();
}

function alignActionInput(chatInput) {
  let actionForm = chatInput.element.find("form.action");
  if (actionForm) {
    actionForm.find("[name=content]").css({
      "text-indent": actionForm.find("actor").width()
    });
  }
}

function updateActorDropdown(chatInput) {
  chatInput.element.find("[name=actor]").val(chatInput.scope.attr("actor").id);
}

/*
 * Cycle between input types
 */
const TAB = 9;
function keyPressed(chatInput, _el, event) {
  if (event.keyCode === TAB) {
    event.preventDefault();
    cycleInputType(chatInput, !event.shiftKey);
  }
}

function cycleInputType(chatInput, goForward) {
  let typeIndex = findIndex(inputs, {name: chatInput.scope.type});
  chatInput.scope.attr(
    "type",
    inputs[(typeIndex + (goForward ? 1 : inputs.length - 1)) %
           inputs.length].name);
  focusContent(chatInput);
}

function typeChanged(chatInput, scope) {
  let form = chatInput.element.find("form");
  chatInput.element.find("[name=type]").val(scope.type);
  chatInput.scope.attr("defaults", can.deparam(form.serialize()));
  forEach(chatInput.scope.defaults, function(v, k) {
    form.find("[name="+k+"]").val(v);
  });
  alignActionInput(chatInput);
  $(window).resize();
}

function typeSelectorChanged(chatInput, el) {
  chatInput.scope.attr("type", el.val());
}

/*
 * Special textareas
 */
const RET = 13;
function textAreaKeyPressed(chatInput, _el, event) {
  /*jshint validthis:true*/
  if (event.keyCode === RET && !event.shiftKey) {
    sendMessage.apply(this, arguments);
  }
}

function focusContent(chatInput) {
  chatInput.element.find("form [name=content]").focus();
}

function typingNotification(chatInput) {
  let user = chatInput.scope.attr("user");
  if (chatInput.element.find("form [name=content]").val().length) {
    user.attr("typing", true);
  } else {
    user.attr("typing", false);
  }
  user.save();
}

/*
 * Username management
 */
function updateScopeUser(chatInput) {
  if (conn.state() === "open") {
    let user = chatInput.scope.attr("user");
    user.attr("name", chatInput.element.find("[name=user]").val());
    user.save();
  }
}<commit_msg>Fixing up live binding of user name<commit_after>"use strict";

let {forEach, find, findIndex} = require("lodash");

let can = require("../../shims/can"),
    $ = require("jquery"),
    element = require("../../lib/customElement");

let {conn} = require("../../lib/socketConn");

let {submitEntry} = require("../../models/chatlog");

let character = require("../../models/character"),
    user = require("../../models/user");

let inputs = [
  {name: "dialogue", template: require("./inputs/dialogue.mustache")},
  {name: "action", template: require("./inputs/action.mustache")},
  {name: "ooc", template: require("./inputs/ooc.mustache")},
  {name: "slug", template: require("./inputs/slug.mustache")},
  {name: "heading", template: require("./inputs/heading.mustache")}
];

/**
 * ChatInput Controller
 */
let ChatInput = element.define("chat-input", {
  style: require("./styles.styl"),
  template: require("./template.mustache"),
  events: {
    "form submit": sendMessage,
    "form keydown": keyPressed,
    "form textarea keydown": textAreaKeyPressed,
    "form textarea input": typingNotification,
    "form click": focusContent,
    "[name=type] change": typeSelectorChanged,
    "[name=actor] change": updateScopeActor,
    "[name=user] input": updateScopeUser,
    "{scope} type": typeChanged,
    "{scope} actor": updateActorDropdown,
    "{scope.characters} length": updateScopeActor,
    inserted: function(inp) {
      focusContent(inp);
      alignActionInput(inp);
      conn.state.bind("change", function(ev, newstate) {
        // TODO - figure out why .attr("user").id fails. CanJS bug.
        if (newstate === "open" && inp.scope.attr("user.id")) {
          window.setTimeout(function() {
            updateScopeUser(inp);
          }, 0);
        }
      });
      $(window).resize();
    }
  },
  attributes: {
    characters: { defaultMaker: character.list },
    actor: {},
    conn: { default: conn },
    user: {
      defaultMaker: function(scope) {
        user.current().then(function(usr) {
          scope.attr("user", usr);
        });
        return {};
      }
    },
    log: { type: "lookup", required: true, observe: false },
    type: { type: "string", default: inputs[0].name },
    inputs: { default: inputs },
    defaults: {
      internal: true,
      defaultMaker: function() {
        return Object.create(null);
      }
    }
  },
  helpers: {
    renderInput: renderInput,
    isSelected: isSelected
  }
});

/*
 * Chat message handling
 */
function sendMessage(chatInput, _el, event) {
  event.preventDefault();
  let formVals = can.deparam(chatInput.element.find("form").serialize());
  if (!formVals.content) { return; }
  formVals.actor = currentActor(chatInput).id;
  submitEntry(chatInput.scope.log, chatInput.scope.type, formVals);
  chatInput.scope.attr("user").attr("typing", false);
  chatInput.element.find("form")[0].reset();
}

/*
 * Actor management
 */
function currentActor(chatInput) {
  return chatInput.scope.attr("actor");
}

function updateScopeActor(chatInput) {
  chatInput.scope.attr(
    "actor", chatInput.element.find("[name=actor] :selected").data("actor"));
  alignActionInput(chatInput);
  $(window).resize();
}

function alignActionInput(chatInput) {
  let actionForm = chatInput.element.find("form.action");
  if (actionForm) {
    actionForm.find("[name=content]").css({
      "text-indent": actionForm.find("actor").width()
    });
  }
}

function updateActorDropdown(chatInput) {
  chatInput.element.find("[name=actor]").val(chatInput.scope.attr("actor").id);
}

/*
 * Cycle between input types
 */
const TAB = 9;
function keyPressed(chatInput, _el, event) {
  if (event.keyCode === TAB) {
    event.preventDefault();
    cycleInputType(chatInput, !event.shiftKey);
  }
}

function cycleInputType(chatInput, goForward) {
  let typeIndex = findIndex(inputs, {name: chatInput.scope.type});
  chatInput.scope.attr(
    "type",
    inputs[(typeIndex + (goForward ? 1 : inputs.length - 1)) %
           inputs.length].name);
  focusContent(chatInput);
}

function typeChanged(chatInput, scope) {
  let form = chatInput.element.find("form");
  chatInput.element.find("[name=type]").val(scope.type);
  chatInput.scope.attr("defaults", can.deparam(form.serialize()));
  forEach(chatInput.scope.defaults, function(v, k) {
    form.find("[name="+k+"]").val(v);
  });
  alignActionInput(chatInput);
  $(window).resize();
}

function typeSelectorChanged(chatInput, el) {
  chatInput.scope.attr("type", el.val());
}

/*
 * Special textareas
 */
const RET = 13;
function textAreaKeyPressed(chatInput, _el, event) {
  /*jshint validthis:true*/
  if (event.keyCode === RET && !event.shiftKey) {
    sendMessage.apply(this, arguments);
  }
}

function focusContent(chatInput) {
  chatInput.element.find("form [name=content]").focus();
}

function typingNotification(chatInput) {
  let user = chatInput.scope.attr("user");
  if (chatInput.element.find("form [name=content]").val().length) {
    user.attr("typing", true);
  } else {
    user.attr("typing", false);
  }
  user.save();
}

/*
 * Username management
 */
function updateScopeUser(chatInput) {
  if (conn.state() === "open") {
    can.batch.start();
    let user = chatInput.scope.attr("user");
    user.attr("name", chatInput.element.find("[name=user]").val());
    user.save();
    can.batch.stop();
  }
}
{'fraction_non_alphanumeric': 0.1839102140903518, 'fraction_numerical': 0.0015090068848439121, 'mean_word_length': 3.706613404349756, 'pattern_counts': {'":': 24, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '517545', 'n_tokens_mistral': 3392, 'n_tokens_neox': 3400, 'n_words': 622}