176 lines
		
	
	
		
			No EOL
		
	
	
		
			5.4 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			176 lines
		
	
	
		
			No EOL
		
	
	
		
			5.4 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
| <textarea
 | |
|   class="compose-box-input"
 | |
|   placeholder="What's on your mind?"
 | |
|   ref:textarea
 | |
|   bind:value=rawText
 | |
|   on:blur="onBlur()"
 | |
|   on:focus="onFocus()"
 | |
|   on:selectionChange="onSelectionChange(event)"
 | |
|   on:keydown="onKeydown(event)"
 | |
| ></textarea>
 | |
| <style>
 | |
|   .compose-box-input {
 | |
|     grid-area: input;
 | |
|     margin: 10px 0 0 5px;
 | |
|     padding: 10px;
 | |
|     border: 1px solid var(--input-border);
 | |
|     min-height: 75px;
 | |
|     resize: none;
 | |
|     overflow: hidden;
 | |
|     word-wrap: break-word;
 | |
|     /* Text must be at least 16px or else iOS Safari zooms in */
 | |
|     font-size: 1.2em;
 | |
|     /* Hack to make Edge stretch the element all the way to the right.
 | |
|      * Also desktop Safari makes the gauge stretch too far to the right without it.
 | |
|      */
 | |
|     width: calc(100% - 5px);
 | |
|   }
 | |
| </style>
 | |
| <script>
 | |
|   import { store } from '../../_store/store'
 | |
|   import { autosize } from '../../_utils/autosize'
 | |
|   import { scheduleIdleTask } from '../../_utils/scheduleIdleTask'
 | |
|   import debounce from 'lodash-es/debounce'
 | |
|   import { mark, stop } from '../../_utils/marks'
 | |
|   import { selectionChange } from '../../_utils/events'
 | |
|   import { clickSelectedAutosuggestionUsername } from '../../_actions/compose'
 | |
|   import { clickSelectedAutosuggestionEmoji } from '../../_actions/emoji'
 | |
| 
 | |
|   export default {
 | |
|     oncreate() {
 | |
|       this.setupSyncFromStore()
 | |
|       this.setupSyncToStore()
 | |
|       this.setupAutosize()
 | |
|     },
 | |
|     ondestroy() {
 | |
|       this.teardownAutosize()
 | |
|     },
 | |
|     methods: {
 | |
|       setupSyncFromStore() {
 | |
|         let textarea = this.refs.textarea
 | |
|         let firstTime = true
 | |
|         this.observe('text', text => {
 | |
|           if (this.get('rawText') !== text) {
 | |
|             this.set({rawText: text})
 | |
|             // this next autosize is required to resize after
 | |
|             // the user clicks the "toot" button
 | |
|             mark('autosize.update()')
 | |
|             autosize.update(textarea)
 | |
|             stop('autosize.update()')
 | |
|           }
 | |
|           if (firstTime) {
 | |
|             firstTime = false
 | |
|             if (this.get('autoFocus')) {
 | |
|               requestAnimationFrame(() => textarea.focus())
 | |
|             }
 | |
|           }
 | |
|         })
 | |
|       },
 | |
|       setupSyncToStore() {
 | |
|         const saveText = debounce(() => scheduleIdleTask(() => this.store.save()), 1000)
 | |
| 
 | |
|         this.observe('rawText', rawText => {
 | |
|           mark('observe rawText')
 | |
|           let realm = this.get('realm')
 | |
|           this.store.setComposeData(realm, {text: rawText})
 | |
|           saveText()
 | |
|           stop('observe rawText')
 | |
|         }, {init: false})
 | |
|       },
 | |
|       setupAutosize() {
 | |
|         let textarea = this.refs.textarea
 | |
|         requestAnimationFrame(() => {
 | |
|           mark('autosize()')
 | |
|           autosize(textarea)
 | |
|           stop('autosize()')
 | |
|         })
 | |
|       },
 | |
|       teardownAutosize() {
 | |
|         mark('autosize.destroy()')
 | |
|         autosize.destroy(this.refs.textarea)
 | |
|         stop('autosize.destroy()')
 | |
|       },
 | |
|       onBlur() {
 | |
|         this.store.set({composeFocused: false})
 | |
|       },
 | |
|       onFocus() {
 | |
|         this.store.set({composeFocused: true})
 | |
|       },
 | |
|       onSelectionChange(selectionStart) {
 | |
|         this.store.set({composeSelectionStart: selectionStart})
 | |
|       },
 | |
|       onKeydown(e) {
 | |
|         let { keyCode } = e
 | |
|         switch (keyCode) {
 | |
|           case 9: // tab
 | |
|           case 13: //enter
 | |
|             this.clickSelectedAutosuggestion(e)
 | |
|             break
 | |
|           case 38: // up
 | |
|             this.incrementAutosuggestSelected(-1, e)
 | |
|             break
 | |
|           case 40: // down
 | |
|             this.incrementAutosuggestSelected(1, e)
 | |
|             break
 | |
|           case 27: // escape
 | |
|             this.clearAutosuggestions(e)
 | |
|             break
 | |
|           default:
 | |
|         }
 | |
|       },
 | |
|       clickSelectedAutosuggestion(event) {
 | |
|         let autosuggestionShown = this.store.get('composeAutosuggestionShown')
 | |
|         if (!autosuggestionShown) {
 | |
|           return
 | |
|         }
 | |
|         let type = this.store.get('composeAutosuggestionType')
 | |
|         if (type === 'account') {
 | |
|           /* no await */ clickSelectedAutosuggestionUsername(this.get('realm'))
 | |
|         } else { // emoji
 | |
|           /* no await */ clickSelectedAutosuggestionEmoji(this.get('realm'))
 | |
|         }
 | |
|         event.preventDefault()
 | |
|         event.stopPropagation()
 | |
|       },
 | |
|       incrementAutosuggestSelected(increment, event) {
 | |
|         let autosuggestionShown = this.store.get('composeAutosuggestionShown')
 | |
|         if (!autosuggestionShown) {
 | |
|           return
 | |
|         }
 | |
|         let selected = this.store.get('composeAutosuggestionSelected') || 0
 | |
|         let searchResults = this.store.get('composeAutosuggestionSearchResults') || []
 | |
|         selected += increment
 | |
|         if (selected >= 0) {
 | |
|           selected = selected % searchResults.length
 | |
|         } else {
 | |
|           selected = searchResults.length + selected
 | |
|         }
 | |
|         this.store.set({composeAutosuggestionSelected: selected})
 | |
|         event.preventDefault()
 | |
|         event.stopPropagation()
 | |
|       },
 | |
|       clearAutosuggestions(event) {
 | |
|         let autosuggestionShown = this.store.get('composeAutosuggestionShown')
 | |
|         if (!autosuggestionShown) {
 | |
|           return
 | |
|         }
 | |
|         this.store.set({
 | |
|           composeAutosuggestionSearchResults: [],
 | |
|           composeAutosuggestionSelected: 0
 | |
|         })
 | |
|         event.preventDefault()
 | |
|         event.stopPropagation()
 | |
|       }
 | |
|     },
 | |
|     store: () => store,
 | |
|     data: () => ({
 | |
|       rawText: ''
 | |
|     }),
 | |
|     computed: {
 | |
|       postedStatusForRealm: ($postedStatusForRealm) => $postedStatusForRealm
 | |
|     },
 | |
|     events: {
 | |
|       selectionChange
 | |
|     }
 | |
|   }
 | |
| </script> |