forked from lavender/watch-party
		
	add unicode emoji autocomplete
This commit is contained in:
		
							parent
							
								
									c7efd725b3
								
							
						
					
					
						commit
						65212087e3
					
				
					 4 changed files with 41 additions and 24 deletions
				
			
		|  | @ -5,21 +5,19 @@ import { | ||||||
| } from "./watch-session.mjs?v=1e57e6"; | } from "./watch-session.mjs?v=1e57e6"; | ||||||
| import { emojify, emojis } from "./emojis.mjs?v=1e57e6"; | import { emojify, emojis } from "./emojis.mjs?v=1e57e6"; | ||||||
| 
 | 
 | ||||||
| function insertAtCursor(input, textToInsert) { | function setCaretPosition(elem, caretPos) { | ||||||
|   const isSuccess = document.execCommand("insertText", false, textToInsert); |         if(elem.createTextRange) { | ||||||
| 
 |             var range = elem.createTextRange(); | ||||||
|   // Firefox (non-standard method)
 |             range.move('character', caretPos); | ||||||
|   if (!isSuccess && typeof input.setRangeText === "function") { |             range.select(); | ||||||
|     const start = input.selectionStart; |         } else { | ||||||
|     input.setRangeText(textToInsert); |             if(elem.selectionStart) { | ||||||
|     // update cursor to be at the end of insertion
 |                 elem.focus(); | ||||||
|     input.selectionStart = input.selectionEnd = start + textToInsert.length; |                 elem.setSelectionRange(caretPos, caretPos); | ||||||
| 
 |             } | ||||||
|     // Notify any possible listeners of the change
 |             else | ||||||
|     const e = document.createEvent("UIEvent"); |                 elem.focus(); | ||||||
|     e.initEvent("input", true, false); |         } | ||||||
|     input.dispatchEvent(e); |  | ||||||
|   } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const setupChatboxEvents = (socket) => { | const setupChatboxEvents = (socket) => { | ||||||
|  | @ -53,22 +51,27 @@ const setupChatboxEvents = (socket) => { | ||||||
|     }; |     }; | ||||||
|     emojiAutocomplete.append( |     emojiAutocomplete.append( | ||||||
|       ...(await emojis) |       ...(await emojis) | ||||||
|         .filter((e) => e.toLowerCase().startsWith(search.toLowerCase())) |         .filter(([name]) => name.toLowerCase().startsWith(search.toLowerCase())) | ||||||
|         .map((name, i) => { |         .map(([name, replaceWith], i) => { | ||||||
|           const button = Object.assign(document.createElement("button"), { |           const button = Object.assign(document.createElement("button"), { | ||||||
|             className: "emoji-option" + (i === 0 ? " selected" : ""), |             className: "emoji-option" + (i === 0 ? " selected" : ""), | ||||||
|             onmousedown: (e) => e.preventDefault(), |             onmousedown: (e) => e.preventDefault(), | ||||||
|             onclick: () => |             onclick: () => { | ||||||
|               insertAtCursor(button, name.slice(match[2].length) + ": "), | 			  messageInput.value=prefix+replaceWith+" "+suffix; | ||||||
|  | 			  setCaretPosition(messageInput, (prefix+" "+replaceWith).length) | ||||||
|  | 			  }, | ||||||
|             onmouseover: () => select(button), |             onmouseover: () => select(button), | ||||||
|             onfocus: () => select(button), |             onfocus: () => select(button), | ||||||
|           }); |           }); | ||||||
|           button.append( |           button.append( | ||||||
|             Object.assign(new Image(), { |             (replaceWith[0]!==":"?Object.assign(document.createElement("span"), { | ||||||
|  |               textContent: replaceWith, | ||||||
|  |               className: "emoji", | ||||||
|  |             }):Object.assign(new Image(), { | ||||||
|               loading: "lazy", |               loading: "lazy", | ||||||
|               src: `/emojis/${name}.png`, |               src: `/emojis/${name}.png`, | ||||||
|               className: "emoji", |               className: "emoji", | ||||||
|             }), |             })), | ||||||
|             Object.assign(document.createElement("span"), { textContent: name }) |             Object.assign(document.createElement("span"), { textContent: name }) | ||||||
|           ); |           ); | ||||||
|           return button; |           return button; | ||||||
|  |  | ||||||
|  | @ -21,6 +21,10 @@ export async function emojify(text) { | ||||||
|   if (last < text.length) nodes.push(document.createTextNode(text.slice(last))); |   if (last < text.length) nodes.push(document.createTextNode(text.slice(last))); | ||||||
|   return nodes; |   return nodes; | ||||||
| } | } | ||||||
| export const emojis = fetch("/emojis") | export const emojis = Promise.all([ | ||||||
|   .then((e) => e.json()) |   fetch("/emojis") | ||||||
|   .then((e) => e.map((e) => e.slice(0, -4))); |     .then((e) => e.json()) | ||||||
|  |     .then((e) => e.map((e) => [e.slice(0, -4), ":"+e.slice(0, -4)+":"])), | ||||||
|  |   fetch('/emojis/unicode.json') | ||||||
|  |     .then((e) => e.json()) | ||||||
|  | ]).then(e=>e.flat(1)); | ||||||
|  | @ -287,6 +287,10 @@ button.small-button { | ||||||
|   width: 1.25rem; |   width: 1.25rem; | ||||||
|   height: 1.25rem; |   height: 1.25rem; | ||||||
|   margin: 0 0.5rem 0 0; |   margin: 0 0.5rem 0 0; | ||||||
|  |   font-size: 2.25ch; | ||||||
|  |   display: flex; | ||||||
|  |   align-items: center; | ||||||
|  |   justify-content: center; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .emoji-option.selected { | .emoji-option.selected { | ||||||
|  |  | ||||||
							
								
								
									
										6
									
								
								scripts/get_unicode_emojis.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										6
									
								
								scripts/get_unicode_emojis.sh
									
									
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,6 @@ | ||||||
|  | #!/bin/sh | ||||||
|  | 
 | ||||||
|  | # Get emoji folder | ||||||
|  | emojiFolder="$(readlink -f "$(dirname $0)/../frontend/emojis/")" | ||||||
|  | 
 | ||||||
|  | curl 'https://raw.githubusercontent.com/iamcal/emoji-data/master/emoji.json' | jq '. | map(. as $emoji | .short_names | map([., ($emoji.unified | split("-") | map(. | split("") | map(. as $nibble | (["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"] | index($nibble))) | reduce .[] as $item (0; (. * 16) + $item)) | map(if (. < 65536) then (.) else [55296 - 64 + (. / 1024 | floor), 56320 + (((. / 1024) - (. / 1024 | floor)) * 1024)] end) | flatten(1) | map(("\\u" + ("0000" + ({"str": "", "num": .} | until(.num < 1; {"str": (["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"][((.num / 16) - (.num / 16 | floor)) * 16] + .str), "num": (.num / 16) | floor})).str)[-4:])) | join("") | "\"" + . + "\"" | fromjson)])) | flatten(1)' --raw-output >"$emojiFolder/unicode.json" | ||||||
		Loading…
	
		Reference in a new issue