This commit is contained in:
		
				commit
				
					
						14a2714c1e
					
				
			
		
					 2 changed files with 99 additions and 0 deletions
				
			
		| 
						 | 
					@ -62,12 +62,14 @@ import {
 | 
				
			||||||
  matchStrikethrough,
 | 
					  matchStrikethrough,
 | 
				
			||||||
} from '../quill/formatting/matchers';
 | 
					} from '../quill/formatting/matchers';
 | 
				
			||||||
import { missingCaseError } from '../util/missingCaseError';
 | 
					import { missingCaseError } from '../util/missingCaseError';
 | 
				
			||||||
 | 
					import { AutoSubstituteAsciiEmojis } from '../quill/auto-substitute-ascii-emojis';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Quill.register('formats/emoji', EmojiBlot);
 | 
					Quill.register('formats/emoji', EmojiBlot);
 | 
				
			||||||
Quill.register('formats/mention', MentionBlot);
 | 
					Quill.register('formats/mention', MentionBlot);
 | 
				
			||||||
Quill.register('formats/block', DirectionalBlot);
 | 
					Quill.register('formats/block', DirectionalBlot);
 | 
				
			||||||
Quill.register('formats/monospace', MonospaceBlot);
 | 
					Quill.register('formats/monospace', MonospaceBlot);
 | 
				
			||||||
Quill.register('formats/spoiler', SpoilerBlot);
 | 
					Quill.register('formats/spoiler', SpoilerBlot);
 | 
				
			||||||
 | 
					Quill.register('modules/autoSubstituteAsciiEmojis', AutoSubstituteAsciiEmojis);
 | 
				
			||||||
Quill.register('modules/emojiCompletion', EmojiCompletion);
 | 
					Quill.register('modules/emojiCompletion', EmojiCompletion);
 | 
				
			||||||
Quill.register('modules/mentionCompletion', MentionCompletion);
 | 
					Quill.register('modules/mentionCompletion', MentionCompletion);
 | 
				
			||||||
Quill.register('modules/formattingMenu', FormattingMenu);
 | 
					Quill.register('modules/formattingMenu', FormattingMenu);
 | 
				
			||||||
| 
						 | 
					@ -729,6 +731,7 @@ export function CompositionInput(props: Props): React.ReactElement {
 | 
				
			||||||
                callbacksRef.current.onPickEmoji(emoji),
 | 
					                callbacksRef.current.onPickEmoji(emoji),
 | 
				
			||||||
              skinTone,
 | 
					              skinTone,
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
 | 
					            autoSubstituteAsciiEmojis: true,
 | 
				
			||||||
            formattingMenu: {
 | 
					            formattingMenu: {
 | 
				
			||||||
              i18n,
 | 
					              i18n,
 | 
				
			||||||
              isMenuEnabled: isFormattingEnabled,
 | 
					              isMenuEnabled: isFormattingEnabled,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										96
									
								
								ts/quill/auto-substitute-ascii-emojis/index.tsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								ts/quill/auto-substitute-ascii-emojis/index.tsx
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,96 @@
 | 
				
			||||||
 | 
					// Copyright 2020 Signal Messenger, LLC
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: AGPL-3.0-only
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import type Quill from 'quill';
 | 
				
			||||||
 | 
					import Delta from 'quill-delta';
 | 
				
			||||||
 | 
					import _ from 'lodash';
 | 
				
			||||||
 | 
					import type { EmojiData } from '../../components/emoji/lib';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  convertShortName,
 | 
				
			||||||
 | 
					  convertShortNameToData,
 | 
				
			||||||
 | 
					} from '../../components/emoji/lib';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type AutoSubstituteAsciiEmojisOptions = {
 | 
				
			||||||
 | 
					  skinTone: number;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const emojiMap: Record<string, string> = {
 | 
				
			||||||
 | 
					  ':)': 'slightly_smiling_face',
 | 
				
			||||||
 | 
					  ':-)': 'slightly_smiling_face',
 | 
				
			||||||
 | 
					  ':(': 'slightly_frowning_face',
 | 
				
			||||||
 | 
					  ':-(': 'slightly_frowning_face',
 | 
				
			||||||
 | 
					  ':D': 'smiley',
 | 
				
			||||||
 | 
					  ':-D': 'smiley',
 | 
				
			||||||
 | 
					  ':*': 'kissing',
 | 
				
			||||||
 | 
					  ':-*': 'kissing',
 | 
				
			||||||
 | 
					  ':P': 'stuck_out_tongue',
 | 
				
			||||||
 | 
					  ':-P': 'stuck_out_tongue',
 | 
				
			||||||
 | 
					  ';P': 'stuck_out_tongue_winking_eye',
 | 
				
			||||||
 | 
					  ';-P': 'stuck_out_tongue_winking_eye',
 | 
				
			||||||
 | 
					  'D:': 'anguished',
 | 
				
			||||||
 | 
					  "D-':": 'anguished',
 | 
				
			||||||
 | 
					  ':O': 'open_mouth',
 | 
				
			||||||
 | 
					  ':-O': 'open_mouth',
 | 
				
			||||||
 | 
					  ":'(": 'cry',
 | 
				
			||||||
 | 
					  ":'-(": 'cry',
 | 
				
			||||||
 | 
					  ':/': 'confused',
 | 
				
			||||||
 | 
					  ':-/': 'confused',
 | 
				
			||||||
 | 
					  ';)': 'wink',
 | 
				
			||||||
 | 
					  ';-)': 'wink',
 | 
				
			||||||
 | 
					  '(Y)': '+1',
 | 
				
			||||||
 | 
					  '(N)': '-1',
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class AutoSubstituteAsciiEmojis {
 | 
				
			||||||
 | 
					  options: AutoSubstituteAsciiEmojisOptions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  quill: Quill;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  constructor(quill: Quill, options: AutoSubstituteAsciiEmojisOptions) {
 | 
				
			||||||
 | 
					    this.options = options;
 | 
				
			||||||
 | 
					    this.quill = quill;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.quill.on(
 | 
				
			||||||
 | 
					      'text-change',
 | 
				
			||||||
 | 
					      _.debounce(() => this.onTextChange(), 100)
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  onTextChange(): void {
 | 
				
			||||||
 | 
					    const range = this.quill.getSelection();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!range) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const [blot, index] = this.quill.getLeaf(range.index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (blot !== undefined && blot.text !== undefined) {
 | 
				
			||||||
 | 
					      const blotText: string = blot.text;
 | 
				
			||||||
 | 
					      Object.entries(emojiMap).some(([textEmoji, emojiName]) => {
 | 
				
			||||||
 | 
					        if (blotText.substring(0, index).endsWith(textEmoji)) {
 | 
				
			||||||
 | 
					          const emojiData = convertShortNameToData(
 | 
				
			||||||
 | 
					            emojiName,
 | 
				
			||||||
 | 
					            this.options.skinTone
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					          if (emojiData) {
 | 
				
			||||||
 | 
					            this.insertEmoji(
 | 
				
			||||||
 | 
					              emojiData,
 | 
				
			||||||
 | 
					              range.index - textEmoji.length,
 | 
				
			||||||
 | 
					              textEmoji.length
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  insertEmoji(emojiData: EmojiData, index: number, range: number): void {
 | 
				
			||||||
 | 
					    const emoji = convertShortName(emojiData.short_name, this.options.skinTone);
 | 
				
			||||||
 | 
					    const delta = new Delta().retain(index).delete(range).insert({ emoji });
 | 
				
			||||||
 | 
					    this.quill.updateContents(delta, 'user');
 | 
				
			||||||
 | 
					    this.quill.setSelection(index + 1, 0);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue