1
0

msgInput.js 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. /**
  2. * @param {string} servicename
  3. * @return {Element}
  4. **/
  5. function createSlashAutocompleteHeader(servicename) {
  6. var lh = document.createElement("lh");
  7. lh.textContent = servicename;
  8. lh.className = R.klass.commands.header;
  9. return lh;
  10. }
  11. /**
  12. * @param {Command|{names: Array<string>!, desc: string!, usage: string!,category: string!, exec: Function!}|string} cmd
  13. * @param {Element=} imgSpan
  14. * @return {Element}
  15. **/
  16. function createSlashAutocompleteDom(cmd, imgSpan) {
  17. var li = document.createElement("li")
  18. ,name = document.createElement("span")
  19. name.className = R.klass.commands.name;
  20. if (typeof cmd === "string") {
  21. if (imgSpan) {
  22. li.appendChild(imgSpan);
  23. }
  24. name.textContent = cmd;
  25. li.appendChild(name);
  26. } else {
  27. var usage = document.createElement("span")
  28. ,desc = document.createElement("span");
  29. name.textContent = cmd.name;
  30. usage.textContent = cmd.usage;
  31. desc.textContent = cmd.desc;
  32. usage.className = R.klass.commands.usage;
  33. desc.className = R.klass.commands.desc;
  34. li.appendChild(name);
  35. li.appendChild(usage);
  36. li.appendChild(desc);
  37. }
  38. li.dataset.input = name.textContent;
  39. li.className = R.klass.commands.item;
  40. return li;
  41. }
  42. function autoComplete(inputDom) {
  43. var now = Date.now(),
  44. slashDom = document.getElementById(R.id.message.slashComplete);
  45. if (slashDom.dataset.cursor)
  46. delete slashDom.dataset.cursor;
  47. var /** @type {Array<Chatter|Room|Command|{names: Array<string>!, desc: string!, usage: string!, category: string!, exec: Function!}|{name: string, provider: string, emojiSpan: Element}>} */
  48. commands = [],
  49. input = inputDom.value;
  50. if (inputDom.value[0] === '/') {
  51. var endCmd = input.indexOf(' '),
  52. inputFinished = endCmd !== -1;
  53. endCmd = endCmd === -1 ? input.length : endCmd;
  54. var inputCmd = input.substr(0, endCmd);
  55. if (inputFinished) {
  56. var currentClientCmd = CLIENT_COMMANDS.getCommand(inputCmd);
  57. if (currentClientCmd)
  58. commands.push(currentClientCmd);
  59. } else {
  60. commands = CLIENT_COMMANDS.getCommandsStartingWith(inputCmd);
  61. slashDom.dataset.cursor = JSON.stringify([0, inputDom.selectionEnd]);
  62. }
  63. var availableCommands = (SELECTED_CONTEXT ? SELECTED_CONTEXT.getChatContext().commands.data : {});
  64. for (var currentCmdId in availableCommands) {
  65. var currentCmd = availableCommands[currentCmdId];
  66. if ((!inputFinished && currentCmd.name.substr(0, endCmd) === inputCmd) ||
  67. (inputFinished && currentCmd.name === inputCmd))
  68. commands.push(currentCmd);
  69. }
  70. }
  71. commands.sort(function(a, b) {
  72. return a.category.localeCompare(b.category) || a.name.localeCompare(b.name);
  73. });
  74. if (!commands.length && inputDom.selectionStart === inputDom.selectionEnd && inputDom.selectionStart) {
  75. var start = inputDom.selectionStart,
  76. end = inputDom.selectionEnd;
  77. for (; start && inputDom.value[start -1] !== ' '; start--) {}
  78. for (var valueLen = inputDom.value.length; end < valueLen && inputDom.value[end] !== ' '; end++) {}
  79. if (start !== end && end -start -1 > 0) {
  80. if (inputDom.value[start] === '#') {
  81. var channels = SELECTED_CONTEXT.getChatContext().channels,
  82. inputStr = inputDom.value.substr(start +1, end -start -1);
  83. for (var i in channels) {
  84. if (channels[i].name.length >= inputStr.length && channels[i].name.substr(0, inputStr.length) === inputStr)
  85. commands.push(channels[i]);
  86. }
  87. } else if (inputDom.value[start] === '@') {
  88. var users = SELECTED_ROOM instanceof PrivateMessageRoom ? SELECTED_CONTEXT.getChatContext().users : SELECTED_ROOM.users,
  89. inputStr = inputDom.value.substr(start +1, end -start -1);
  90. for (var i in users) {
  91. var userName = users[i].getName();
  92. if (userName.length >= inputStr.length && userName.substr(0, inputStr.length) === inputStr)
  93. commands.push(users[i]);
  94. }
  95. } else if (inputDom.value[start] === ':' && window['searchEmojis']) {
  96. var inputCmd = inputDom.value.substr(start +1, end -start -1),
  97. emojiList = window['searchEmojis'](inputCmd);
  98. for (var emojiCode in emojiList) {
  99. var domEmoji = window['makeEmoji'](emojiCode, false),
  100. domParent = document.createElement("span");
  101. domParent.appendChild(domEmoji);
  102. domParent.className = R.klass.emoji.small;
  103. commands.push({
  104. name: ':' +emojiCode +':',
  105. emojiSpan: domParent,
  106. provider: CURRENT_EMOJI_PROVIDER.name
  107. });
  108. }
  109. for (var i in SELECTED_CONTEXT.getChatContext().emojis.data) {
  110. if (i.length >= inputCmd.length && i.substr(0, inputCmd.length) === inputCmd) {
  111. var emojiSpan = document.createElement("span");
  112. emojiSpan.className = R.klass.emoji.small;
  113. emojiSpan.appendChild(makeEmojiDom(i));
  114. commands.push({
  115. name: ':' +i +':',
  116. emojiSpan: emojiSpan,
  117. provider: "custom"
  118. });
  119. }
  120. }
  121. }
  122. if (commands.length)
  123. slashDom.dataset.cursor = JSON.stringify([start, end]);
  124. }
  125. }
  126. slashDom.textContent = '';
  127. if (commands.length) {
  128. var slashFrag = document.createDocumentFragment(),
  129. prevService;
  130. for (var i =0, nbCmd = commands.length; i < nbCmd; i++) {
  131. var command = commands[i];
  132. if (command instanceof Chatter) {
  133. if (!prevService) {
  134. prevService = true;
  135. slashFrag.appendChild(createSlashAutocompleteHeader(locale.members));
  136. }
  137. var span = document.createElement("span");
  138. span.className = R.klass.commands.userIcon;
  139. span.style.backgroundImage = "url(\"" +command.getSmallIcon() +"\")";
  140. slashFrag.appendChild(createSlashAutocompleteDom('@' +command.getName(), span));
  141. } else if (command instanceof Room) {
  142. if (!prevService) {
  143. prevService = true;
  144. slashFrag.appendChild(createSlashAutocompleteHeader(locale.channels));
  145. }
  146. slashFrag.appendChild(createSlashAutocompleteDom('#' +command.name));
  147. } else if (command.emojiSpan) {
  148. if (prevService !== command.provider) {
  149. prevService = command.provider;
  150. slashFrag.appendChild(createSlashAutocompleteHeader(command.provider));
  151. }
  152. slashFrag.appendChild(createSlashAutocompleteDom(command.name, command.emojiSpan));
  153. } else {
  154. if (prevService !== command.category) {
  155. prevService = command.category;
  156. slashFrag.appendChild(createSlashAutocompleteHeader(command.category));
  157. }
  158. slashFrag.appendChild(createSlashAutocompleteDom(command));
  159. }
  160. }
  161. slashDom.appendChild(slashFrag);
  162. }
  163. }
  164. function focusInput() {
  165. document.getElementById(R.id.message.input).focus();
  166. }
  167. function initMsgInput() {
  168. var lastKeyDown = 0,
  169. input = document.getElementById(R.id.message.input);
  170. input.addEventListener('input', function() {
  171. if (SELECTED_ROOM) {
  172. var now = Date.now();
  173. if (lastKeyDown + 3000 < now && (SELECTED_CONTEXT.getChatContext().self.presence || (SELECTED_ROOM instanceof PrivateMessageRoom))) {
  174. sendTyping(SELECTED_ROOM);
  175. lastKeyDown = now;
  176. }
  177. autoComplete(this);
  178. }
  179. });
  180. /*
  181. input.addEventListener("keydown", function(e) {
  182. /** @const *
  183. var TAB_KEY = 9;
  184. if (e.keyCode === TAB_KEY) {
  185. e.preventDefault();
  186. console.log("COUGHT");
  187. return false;
  188. }
  189. });
  190. */
  191. document.getElementById(R.id.message.slashComplete).addEventListener("click", function(e) {
  192. if (SELECTED_ROOM) {
  193. var target = e.target;
  194. var cursor = this.dataset.cursor;
  195. if (cursor) {
  196. cursor = JSON.parse(cursor);
  197. while (target && target !== this) {
  198. if (target.dataset.input) {
  199. var inputElement = document.getElementById(R.id.message.input),
  200. toAdd = target.dataset.input;
  201. if (inputElement.value.length <= cursor[1])
  202. toAdd += ' ';
  203. inputElement.value = inputElement.value.substr(0, cursor[0]) +toAdd +inputElement.value.substr(cursor[1]);
  204. inputElement.selectionStart = inputElement.selectionEnd = cursor[0] +toAdd.length;
  205. autoComplete(inputElement);
  206. inputElement.focus();
  207. break;
  208. }
  209. target = target.parentElement;
  210. }
  211. }
  212. }
  213. });
  214. }