use standard to lint HTML too (#186)
This commit is contained in:
		
							parent
							
								
									ef80919269
								
							
						
					
					
						commit
						bfc3c46462
					
				
					 70 changed files with 214 additions and 210 deletions
				
			
		| 
						 | 
				
			
			@ -32,6 +32,7 @@ Lint:
 | 
			
		|||
Automatically fix most linting issues:
 | 
			
		||||
 | 
			
		||||
    npx standard --fix
 | 
			
		||||
    npx standard --fix --plugin html 'routes/**/*.html'
 | 
			
		||||
 | 
			
		||||
## Testing
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										9
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										9
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							| 
						 | 
				
			
			@ -3084,6 +3084,15 @@
 | 
			
		|||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "eslint-plugin-html": {
 | 
			
		||||
      "version": "4.0.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/eslint-plugin-html/-/eslint-plugin-html-4.0.3.tgz",
 | 
			
		||||
      "integrity": "sha512-ArFnlfQxwYSz/CP0zvk8Cy3MUhcDpT3o6jgO8eKD/b8ezcLVBrgkYzmMv+7S/ya+Yl9pN+Cz2tsgYp/zElkQzA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "htmlparser2": "3.9.2"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "eslint-plugin-import": {
 | 
			
		||||
      "version": "2.9.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.9.0.tgz",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,7 @@
 | 
			
		|||
  "description": "Alternative web client for Mastodon",
 | 
			
		||||
  "version": "0.2.2",
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "lint": "standard",
 | 
			
		||||
    "lint": "standard && standard --plugin html 'routes/**/*.html'",
 | 
			
		||||
    "dev": "run-s build-svg build-inline-script serve-dev",
 | 
			
		||||
    "serve-dev": "run-p --race build-sass-watch serve",
 | 
			
		||||
    "serve": "node server.js",
 | 
			
		||||
| 
						 | 
				
			
			@ -83,6 +83,7 @@
 | 
			
		|||
    "yargs": "11.0.0"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "eslint-plugin-html": "4.0.3",
 | 
			
		||||
    "now": "11.1.7",
 | 
			
		||||
    "standard": "11.0.1",
 | 
			
		||||
    "testcafe": "0.19.1"
 | 
			
		||||
| 
						 | 
				
			
			@ -117,7 +118,8 @@
 | 
			
		|||
      "atob",
 | 
			
		||||
      "btoa",
 | 
			
		||||
      "Blob",
 | 
			
		||||
      "Element"
 | 
			
		||||
      "Element",
 | 
			
		||||
      "Image"
 | 
			
		||||
    ],
 | 
			
		||||
    "ignore": [
 | 
			
		||||
      "dist",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,7 +33,7 @@
 | 
			
		|||
  import { toast } from '../_utils/toast'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    async oncreate() {
 | 
			
		||||
    async oncreate () {
 | 
			
		||||
      let { accountsFetcher } = this.get()
 | 
			
		||||
      try {
 | 
			
		||||
        // TODO: paginate
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -61,7 +61,7 @@
 | 
			
		|||
<script>
 | 
			
		||||
  export default {
 | 
			
		||||
    methods: {
 | 
			
		||||
      onGoBack(e) {
 | 
			
		||||
      onGoBack (e) {
 | 
			
		||||
        e.preventDefault()
 | 
			
		||||
        window.history.back()
 | 
			
		||||
      }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -105,7 +105,7 @@
 | 
			
		|||
  import { store } from '../_store/store'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      this.observe('animation', animation => {
 | 
			
		||||
        let reduceMotion = this.store.get()
 | 
			
		||||
        if (!animation || reduceMotion) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,19 +9,19 @@
 | 
			
		|||
  {{/if}}
 | 
			
		||||
</div>
 | 
			
		||||
<script>
 | 
			
		||||
	import Nav from './Nav.html';
 | 
			
		||||
  import Nav from './Nav.html'
 | 
			
		||||
  import { store } from '../_store/store'
 | 
			
		||||
  import InformationalFooter from './InformationalFooter.html'
 | 
			
		||||
 | 
			
		||||
  // Only focus the `.container` div on first load so it does not intefere 
 | 
			
		||||
  // Only focus the `.container` div on first load so it does not intefere
 | 
			
		||||
  // with other desired behaviours (e.g. you click a toot, you navigate from
 | 
			
		||||
  // a timeline view to a thread view, you press the back button, and now
 | 
			
		||||
  // you're still focused on the toot).
 | 
			
		||||
  let firstTime = true
 | 
			
		||||
 | 
			
		||||
	export default {
 | 
			
		||||
		components: {
 | 
			
		||||
			Nav,
 | 
			
		||||
  export default {
 | 
			
		||||
    components: {
 | 
			
		||||
      Nav,
 | 
			
		||||
      InformationalFooter
 | 
			
		||||
    },
 | 
			
		||||
    oncreate () {
 | 
			
		||||
| 
						 | 
				
			
			@ -31,5 +31,5 @@
 | 
			
		|||
      }
 | 
			
		||||
    },
 | 
			
		||||
    store: () => store
 | 
			
		||||
	}
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -21,11 +21,10 @@
 | 
			
		|||
  }
 | 
			
		||||
</style>
 | 
			
		||||
<script>
 | 
			
		||||
 | 
			
		||||
  import { mark, stop } from '../_utils/marks'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      mark('LazyImage oncreate()')
 | 
			
		||||
      let img = new Image()
 | 
			
		||||
      let { src } = this.get()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,7 @@
 | 
			
		|||
  let firstTime = true
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      firstTime = false
 | 
			
		||||
      requestAnimationFrame(() => {
 | 
			
		||||
        requestAnimationFrame(() => {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,7 +21,7 @@
 | 
			
		|||
  const SPINNER_DELAY = 700
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      setTimeout(() => {
 | 
			
		||||
        this.set({shown: true})
 | 
			
		||||
      }, SPINNER_DELAY)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -135,7 +135,7 @@
 | 
			
		|||
      }
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      onClick(e) {
 | 
			
		||||
      onClick (e) {
 | 
			
		||||
        let { selected } = this.get()
 | 
			
		||||
        if (!selected) {
 | 
			
		||||
          return
 | 
			
		||||
| 
						 | 
				
			
			@ -146,5 +146,4 @@
 | 
			
		|||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -43,7 +43,7 @@
 | 
			
		|||
 | 
			
		||||
  export default {
 | 
			
		||||
    methods: {
 | 
			
		||||
      onMouseOver(mouseOver) {
 | 
			
		||||
      onMouseOver (mouseOver) {
 | 
			
		||||
        this.set({playing: mouseOver})
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,7 +27,7 @@
 | 
			
		|||
  import { imgLoadError, mouseover } from '../_utils/events'
 | 
			
		||||
  export default {
 | 
			
		||||
    methods: {
 | 
			
		||||
      onMouseOver(mouseOver) {
 | 
			
		||||
      onMouseOver (mouseOver) {
 | 
			
		||||
        let { src, staticSrc } = this.get()
 | 
			
		||||
        this.refs.node.src = mouseOver ? src : staticSrc
 | 
			
		||||
      }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,7 +42,7 @@
 | 
			
		|||
    },
 | 
			
		||||
    computed: {
 | 
			
		||||
      hidePage: ($timelineInitialized, $timelinePreinitialized) => !$timelineInitialized && !$timelinePreinitialized,
 | 
			
		||||
      hideTimeline: ($timelineInitialized) => !$timelineInitialized,
 | 
			
		||||
      hideTimeline: ($timelineInitialized) => !$timelineInitialized
 | 
			
		||||
    },
 | 
			
		||||
    store: () => store,
 | 
			
		||||
    components: {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,7 +36,7 @@
 | 
			
		|||
    },
 | 
			
		||||
    computed: {
 | 
			
		||||
      hidePage: ($timelineInitialized, $timelinePreinitialized) => !$timelineInitialized && !$timelinePreinitialized,
 | 
			
		||||
      hideTimeline: ($timelineInitialized) => !$timelineInitialized,
 | 
			
		||||
      hideTimeline: ($timelineInitialized) => !$timelineInitialized
 | 
			
		||||
    },
 | 
			
		||||
    store: () => store,
 | 
			
		||||
    components: {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -67,10 +67,10 @@
 | 
			
		|||
    methods: {
 | 
			
		||||
      push,
 | 
			
		||||
      splice,
 | 
			
		||||
      say(text) {
 | 
			
		||||
      say (text) {
 | 
			
		||||
        this.push('messages', text)
 | 
			
		||||
      },
 | 
			
		||||
      onNewToast(text) {
 | 
			
		||||
      onNewToast (text) {
 | 
			
		||||
        this._queue = this._queue.then(() => {
 | 
			
		||||
          this.set({
 | 
			
		||||
            'text': text,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -73,7 +73,7 @@
 | 
			
		|||
      IconButton
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      onPinClick(e) {
 | 
			
		||||
      onPinClick (e) {
 | 
			
		||||
        e.preventDefault()
 | 
			
		||||
        let { currentInstance, pinnedPages } = this.store.get()
 | 
			
		||||
        let { href } = this.get()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -55,7 +55,7 @@
 | 
			
		|||
  const EMOJI_SEARCH_REGEX = new RegExp(`(?:\\s|^)(:[^:]{${MIN_PREFIX_LENGTH},})$`)
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      // perf improves for input responsiveness
 | 
			
		||||
      this.observe('composeSelectionStart', () => {
 | 
			
		||||
        scheduleIdleTask(() => {
 | 
			
		||||
| 
						 | 
				
			
			@ -94,7 +94,7 @@
 | 
			
		|||
          composeAutosuggestionSelected: 0,
 | 
			
		||||
          composeAutosuggestionSearchText: searchText,
 | 
			
		||||
          composeAutosuggestionSearchResults: results,
 | 
			
		||||
          composeAutosuggestionType: type,
 | 
			
		||||
          composeAutosuggestionType: type
 | 
			
		||||
        })
 | 
			
		||||
      })
 | 
			
		||||
      this.observe('shown', shown => {
 | 
			
		||||
| 
						 | 
				
			
			@ -103,7 +103,7 @@
 | 
			
		|||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      once: once,
 | 
			
		||||
      onClick(item) {
 | 
			
		||||
      onClick (item) {
 | 
			
		||||
        this.fire('autosuggestItemSelected')
 | 
			
		||||
        let { realm } = this.get()
 | 
			
		||||
        let { composeSelectionStart, composeAutosuggestionSearchText } = this.store.get()
 | 
			
		||||
| 
						 | 
				
			
			@ -114,16 +114,15 @@
 | 
			
		|||
        } else {
 | 
			
		||||
          /* no await */ insertEmojiAtPosition(realm, item, startIndex, endIndex)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      },
 | 
			
		||||
      async searchAccounts(searchText) {
 | 
			
		||||
      async searchAccounts (searchText) {
 | 
			
		||||
        searchText = searchText.substring(1)
 | 
			
		||||
        let { currentInstance } = this.store.get()
 | 
			
		||||
        let results = await searchAccountsByUsernameInDatabase(
 | 
			
		||||
          currentInstance, searchText, DATABASE_SEARCH_RESULTS_LIMIT)
 | 
			
		||||
        return results.slice(0, SEARCH_RESULTS_LIMIT)
 | 
			
		||||
      },
 | 
			
		||||
      searchEmoji(searchText) {
 | 
			
		||||
      searchEmoji (searchText) {
 | 
			
		||||
        searchText = searchText.toLowerCase().substring(1)
 | 
			
		||||
        let { currentCustomEmoji } = this.store.get()
 | 
			
		||||
        let results = currentCustomEmoji.filter(emoji => emoji.shortcode.toLowerCase().startsWith(searchText))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -117,7 +117,7 @@
 | 
			
		|||
  import { classname } from '../../_utils/classname'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      let { realm } = this.get()
 | 
			
		||||
      if (realm === 'home') {
 | 
			
		||||
        this.setupStickyObserver()
 | 
			
		||||
| 
						 | 
				
			
			@ -138,7 +138,7 @@
 | 
			
		|||
        setReplyVisibility(realm, replyVisibility)
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    ondestroy() {
 | 
			
		||||
    ondestroy () {
 | 
			
		||||
      this.teardownStickyObserver()
 | 
			
		||||
    },
 | 
			
		||||
    components: {
 | 
			
		||||
| 
						 | 
				
			
			@ -188,7 +188,7 @@
 | 
			
		|||
      slide
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      async onClickPostButton() {
 | 
			
		||||
      async onClickPostButton () {
 | 
			
		||||
        let { sticky } = this.get()
 | 
			
		||||
        if (sticky) {
 | 
			
		||||
          // when the button is sticky, we're scrolled down the home timeline,
 | 
			
		||||
| 
						 | 
				
			
			@ -197,10 +197,10 @@
 | 
			
		|||
          dialogs.showComposeDialog()
 | 
			
		||||
        } else {
 | 
			
		||||
          // else we're actually posting a new toot
 | 
			
		||||
          this.doPostStatus();
 | 
			
		||||
          this.doPostStatus()
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      doPostStatus() {
 | 
			
		||||
      doPostStatus () {
 | 
			
		||||
        let {
 | 
			
		||||
          text,
 | 
			
		||||
          media,
 | 
			
		||||
| 
						 | 
				
			
			@ -224,7 +224,7 @@
 | 
			
		|||
          sensitive, contentWarning, postPrivacyKey,
 | 
			
		||||
          mediaDescriptions, inReplyToUuid)
 | 
			
		||||
      },
 | 
			
		||||
      setupStickyObserver() {
 | 
			
		||||
      setupStickyObserver () {
 | 
			
		||||
        this.__stickyObserver = new IntersectionObserver(entries => {
 | 
			
		||||
          this.set({sticky: !entries[0].isIntersecting})
 | 
			
		||||
        })
 | 
			
		||||
| 
						 | 
				
			
			@ -243,7 +243,7 @@
 | 
			
		|||
          }
 | 
			
		||||
        }, {init: false})
 | 
			
		||||
      },
 | 
			
		||||
      teardownStickyObserver() {
 | 
			
		||||
      teardownStickyObserver () {
 | 
			
		||||
        if (this.__stickyObserver) {
 | 
			
		||||
          this.__stickyObserver.disconnect()
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,7 +19,7 @@
 | 
			
		|||
  import { scheduleIdleTask } from '../../_utils/scheduleIdleTask'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      this.setupSyncFromStore()
 | 
			
		||||
      this.setupSyncToStore()
 | 
			
		||||
    },
 | 
			
		||||
| 
						 | 
				
			
			@ -28,12 +28,12 @@
 | 
			
		|||
      rawText: ''
 | 
			
		||||
    }),
 | 
			
		||||
    methods: {
 | 
			
		||||
      setupSyncFromStore() {
 | 
			
		||||
      setupSyncFromStore () {
 | 
			
		||||
        this.observe('contentWarning', contentWarning => {
 | 
			
		||||
          this.set({rawText: contentWarning})
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      setupSyncToStore() {
 | 
			
		||||
      setupSyncToStore () {
 | 
			
		||||
        const saveText = debounce(() => scheduleIdleTask(() => this.store.save()), 1000)
 | 
			
		||||
 | 
			
		||||
        this.observe('rawText', rawText => {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,16 +37,16 @@
 | 
			
		|||
  import { clickSelectedAutosuggestionEmoji } from '../../_actions/emoji'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      this.setupSyncFromStore()
 | 
			
		||||
      this.setupSyncToStore()
 | 
			
		||||
      this.setupAutosize()
 | 
			
		||||
    },
 | 
			
		||||
    ondestroy() {
 | 
			
		||||
    ondestroy () {
 | 
			
		||||
      this.teardownAutosize()
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      setupSyncFromStore() {
 | 
			
		||||
      setupSyncFromStore () {
 | 
			
		||||
        let textarea = this.refs.textarea
 | 
			
		||||
        let firstTime = true
 | 
			
		||||
        this.observe('text', text => {
 | 
			
		||||
| 
						 | 
				
			
			@ -68,7 +68,7 @@
 | 
			
		|||
          }
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      setupSyncToStore() {
 | 
			
		||||
      setupSyncToStore () {
 | 
			
		||||
        const saveStore = debounce(() => scheduleIdleTask(() => this.store.save()), 1000)
 | 
			
		||||
 | 
			
		||||
        this.observe('rawText', rawText => {
 | 
			
		||||
| 
						 | 
				
			
			@ -79,7 +79,7 @@
 | 
			
		|||
          stop('observe rawText')
 | 
			
		||||
        }, {init: false})
 | 
			
		||||
      },
 | 
			
		||||
      setupAutosize() {
 | 
			
		||||
      setupAutosize () {
 | 
			
		||||
        let textarea = this.refs.textarea
 | 
			
		||||
        requestAnimationFrame(() => {
 | 
			
		||||
          mark('autosize()')
 | 
			
		||||
| 
						 | 
				
			
			@ -87,21 +87,21 @@
 | 
			
		|||
          stop('autosize()')
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      teardownAutosize() {
 | 
			
		||||
      teardownAutosize () {
 | 
			
		||||
        mark('autosize.destroy()')
 | 
			
		||||
        autosize.destroy(this.refs.textarea)
 | 
			
		||||
        stop('autosize.destroy()')
 | 
			
		||||
      },
 | 
			
		||||
      onBlur() {
 | 
			
		||||
      onBlur () {
 | 
			
		||||
        this.store.set({composeFocused: false})
 | 
			
		||||
      },
 | 
			
		||||
      onFocus() {
 | 
			
		||||
      onFocus () {
 | 
			
		||||
        this.store.set({composeFocused: true})
 | 
			
		||||
      },
 | 
			
		||||
      onSelectionChange(selectionStart) {
 | 
			
		||||
      onSelectionChange (selectionStart) {
 | 
			
		||||
        this.store.set({composeSelectionStart: selectionStart})
 | 
			
		||||
      },
 | 
			
		||||
      onKeydown(e) {
 | 
			
		||||
      onKeydown (e) {
 | 
			
		||||
        let { keyCode } = e
 | 
			
		||||
        // ctrl or cmd (on macs) was pressed; ctrl-enter means post a toot
 | 
			
		||||
        const ctrlPressed = e.getModifierState('Control') || e.getModifierState('Meta')
 | 
			
		||||
| 
						 | 
				
			
			@ -109,7 +109,7 @@
 | 
			
		|||
          case 9: // tab
 | 
			
		||||
            this.clickSelectedAutosuggestion(e)
 | 
			
		||||
            break
 | 
			
		||||
          case 13: //enter
 | 
			
		||||
          case 13: // enter
 | 
			
		||||
            const autosuggestionClicked = this.clickSelectedAutosuggestion(e)
 | 
			
		||||
            if (!autosuggestionClicked && ctrlPressed) {
 | 
			
		||||
              this.fire('postAction')
 | 
			
		||||
| 
						 | 
				
			
			@ -127,7 +127,7 @@
 | 
			
		|||
          default:
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      clickSelectedAutosuggestion(event) {
 | 
			
		||||
      clickSelectedAutosuggestion (event) {
 | 
			
		||||
        let {
 | 
			
		||||
          composeAutosuggestionShown,
 | 
			
		||||
          composeAutosuggestionType
 | 
			
		||||
| 
						 | 
				
			
			@ -145,7 +145,7 @@
 | 
			
		|||
        event.stopPropagation()
 | 
			
		||||
        return true
 | 
			
		||||
      },
 | 
			
		||||
      incrementAutosuggestSelected(increment, event) {
 | 
			
		||||
      incrementAutosuggestSelected (increment, event) {
 | 
			
		||||
        let {
 | 
			
		||||
          composeAutosuggestionShown,
 | 
			
		||||
          composeAutosuggestionSelected,
 | 
			
		||||
| 
						 | 
				
			
			@ -166,7 +166,7 @@
 | 
			
		|||
        event.preventDefault()
 | 
			
		||||
        event.stopPropagation()
 | 
			
		||||
      },
 | 
			
		||||
      clearAutosuggestions(event) {
 | 
			
		||||
      clearAutosuggestions (event) {
 | 
			
		||||
        let { composeAutosuggestionShown } = this.store.get()
 | 
			
		||||
        if (!composeAutosuggestionShown) {
 | 
			
		||||
          return
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,7 +24,7 @@
 | 
			
		|||
  import { scheduleIdleTask } from '../../_utils/scheduleIdleTask'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      let { lengthAsFraction } = this.get()
 | 
			
		||||
      this.set({lengthAsFractionDeferred: lengthAsFraction})
 | 
			
		||||
      // perf improvement for keyboard input latency
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,7 +22,7 @@
 | 
			
		|||
  import { scheduleIdleTask } from '../../_utils/scheduleIdleTask'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      let { lengthToDisplay } = this.get()
 | 
			
		||||
      this.set({lengthToDisplayDeferred: lengthToDisplay})
 | 
			
		||||
      // perf improvement for keyboard input latency
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -81,7 +81,7 @@
 | 
			
		|||
  import { scheduleIdleTask } from '../../_utils/scheduleIdleTask'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      this.setupSyncFromStore()
 | 
			
		||||
      this.setupSyncToStore()
 | 
			
		||||
    },
 | 
			
		||||
| 
						 | 
				
			
			@ -90,7 +90,7 @@
 | 
			
		|||
    }),
 | 
			
		||||
    store: () => store,
 | 
			
		||||
    methods: {
 | 
			
		||||
      setupSyncFromStore() {
 | 
			
		||||
      setupSyncFromStore () {
 | 
			
		||||
        this.observe('mediaDescriptions', mediaDescriptions => {
 | 
			
		||||
          mediaDescriptions = mediaDescriptions || []
 | 
			
		||||
          let { index, rawText } = this.get()
 | 
			
		||||
| 
						 | 
				
			
			@ -100,7 +100,7 @@
 | 
			
		|||
          }
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      setupSyncToStore() {
 | 
			
		||||
      setupSyncToStore () {
 | 
			
		||||
        const saveStore = debounce(() => scheduleIdleTask(() => this.store.save()), 1000)
 | 
			
		||||
 | 
			
		||||
        this.observe('rawText', rawText => {
 | 
			
		||||
| 
						 | 
				
			
			@ -118,7 +118,7 @@
 | 
			
		|||
          saveStore()
 | 
			
		||||
        }, {init: false})
 | 
			
		||||
      },
 | 
			
		||||
      onDeleteMedia() {
 | 
			
		||||
      onDeleteMedia () {
 | 
			
		||||
        let {
 | 
			
		||||
          realm,
 | 
			
		||||
          index
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -52,7 +52,7 @@
 | 
			
		|||
  import ComposeAutosuggest from './ComposeAutosuggest.html'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      if (process.env.NODE_ENV !== 'production') {
 | 
			
		||||
        window.__fakeFileInput = (file) => {
 | 
			
		||||
          this.onFileChange({
 | 
			
		||||
| 
						 | 
				
			
			@ -69,25 +69,25 @@
 | 
			
		|||
    },
 | 
			
		||||
    store: () => store,
 | 
			
		||||
    methods: {
 | 
			
		||||
      async onEmojiClick() {
 | 
			
		||||
      async onEmojiClick () {
 | 
			
		||||
        let dialogs = await importDialogs()
 | 
			
		||||
        let { realm } = this.get()
 | 
			
		||||
        dialogs.showEmojiDialog(realm)
 | 
			
		||||
      },
 | 
			
		||||
      onMediaClick() {
 | 
			
		||||
      onMediaClick () {
 | 
			
		||||
        this.refs.input.click()
 | 
			
		||||
      },
 | 
			
		||||
      onFileChange(e) {
 | 
			
		||||
      onFileChange (e) {
 | 
			
		||||
        let file = e.target.files[0]
 | 
			
		||||
        let { realm } = this.get()
 | 
			
		||||
        doMediaUpload(realm, file)
 | 
			
		||||
      },
 | 
			
		||||
      async onPostPrivacyClick() {
 | 
			
		||||
      async onPostPrivacyClick () {
 | 
			
		||||
        let dialogs = await importDialogs()
 | 
			
		||||
        let { realm } = this.get()
 | 
			
		||||
        dialogs.showPostPrivacyDialog(realm)
 | 
			
		||||
      },
 | 
			
		||||
      onContentWarningClick() {
 | 
			
		||||
      onContentWarningClick () {
 | 
			
		||||
        let { realm } = this.get()
 | 
			
		||||
        toggleContentWarningShown(realm)
 | 
			
		||||
      }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -55,8 +55,8 @@ export default {
 | 
			
		|||
    muteIcon: (muting) => muting ? '#fa-volume-up' : '#fa-volume-off',
 | 
			
		||||
    // end account data copypasta
 | 
			
		||||
    items: (blockLabel, blocking, blockIcon, muteLabel, muteIcon,
 | 
			
		||||
            followLabel, followIcon, following, followRequested,
 | 
			
		||||
            accountId, verifyCredentialsId, acct) => {
 | 
			
		||||
      followLabel, followIcon, following, followRequested,
 | 
			
		||||
      accountId, verifyCredentialsId, acct) => {
 | 
			
		||||
      let isUser = accountId === verifyCredentialsId
 | 
			
		||||
      return [
 | 
			
		||||
        !isUser && {
 | 
			
		||||
| 
						 | 
				
			
			@ -86,7 +86,7 @@ export default {
 | 
			
		|||
  methods: {
 | 
			
		||||
    show,
 | 
			
		||||
    close,
 | 
			
		||||
    onClick(item) {
 | 
			
		||||
    onClick (item) {
 | 
			
		||||
      switch (item.key) {
 | 
			
		||||
        case 'mention':
 | 
			
		||||
          return this.onMentionClicked()
 | 
			
		||||
| 
						 | 
				
			
			@ -98,7 +98,7 @@ export default {
 | 
			
		|||
          return this.onMuteClicked()
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    async onMentionClicked() {
 | 
			
		||||
    async onMentionClicked () {
 | 
			
		||||
      let { acct } = this.get()
 | 
			
		||||
      this.store.setComposeData('dialog', {
 | 
			
		||||
        text: `@${acct} `
 | 
			
		||||
| 
						 | 
				
			
			@ -107,17 +107,17 @@ export default {
 | 
			
		|||
      dialogs.showComposeDialog()
 | 
			
		||||
      this.close()
 | 
			
		||||
    },
 | 
			
		||||
    async onFollowClicked() {
 | 
			
		||||
    async onFollowClicked () {
 | 
			
		||||
      let { accountId, following } = this.get()
 | 
			
		||||
      this.close()
 | 
			
		||||
      await setAccountFollowed(accountId, !following, true)
 | 
			
		||||
    },
 | 
			
		||||
    async onBlockClicked() {
 | 
			
		||||
    async onBlockClicked () {
 | 
			
		||||
      let { accountId, blocking } = this.get()
 | 
			
		||||
      this.close()
 | 
			
		||||
      await setAccountBlocked(accountId, !blocking, true)
 | 
			
		||||
    },
 | 
			
		||||
    async onMuteClicked() {
 | 
			
		||||
    async onMuteClicked () {
 | 
			
		||||
      let { accountId, muting } = this.get()
 | 
			
		||||
      this.close()
 | 
			
		||||
      await setAccountMuted(accountId, !muting, true)
 | 
			
		||||
| 
						 | 
				
			
			@ -126,6 +126,6 @@ export default {
 | 
			
		|||
  components: {
 | 
			
		||||
    ModalDialog,
 | 
			
		||||
    GenericDialogList
 | 
			
		||||
  },
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -15,14 +15,14 @@
 | 
			
		|||
  import { close } from '../helpers/closeDialog'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      on('postedStatus', this, this.onPostedStatus)
 | 
			
		||||
      onCreateDialog.call(this)
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      show,
 | 
			
		||||
      close,
 | 
			
		||||
      onPostedStatus(realm) {
 | 
			
		||||
      onPostedStatus (realm) {
 | 
			
		||||
        if (realm !== 'dialog') {
 | 
			
		||||
          return
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,14 +40,14 @@
 | 
			
		|||
  import { oncreate as onCreateDialog } from '../helpers/onCreateDialog'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      on('destroyDialog', this, this.onDestroyDialog)
 | 
			
		||||
      onCreateDialog.call(this)
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      show,
 | 
			
		||||
      close,
 | 
			
		||||
      onDestroyDialog(thisId) {
 | 
			
		||||
      onDestroyDialog (thisId) {
 | 
			
		||||
        let {
 | 
			
		||||
          id,
 | 
			
		||||
          positiveResult,
 | 
			
		||||
| 
						 | 
				
			
			@ -67,11 +67,11 @@
 | 
			
		|||
          }
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      onPositive() {
 | 
			
		||||
      onPositive () {
 | 
			
		||||
        this.set({positiveResult: true})
 | 
			
		||||
        this.close()
 | 
			
		||||
      },
 | 
			
		||||
      onNegative() {
 | 
			
		||||
      onNegative () {
 | 
			
		||||
        this.close()
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -81,7 +81,7 @@
 | 
			
		|||
    methods: {
 | 
			
		||||
      show,
 | 
			
		||||
      close,
 | 
			
		||||
      onClickEmoji(emoji) {
 | 
			
		||||
      onClickEmoji (emoji) {
 | 
			
		||||
        let { realm } = this.get()
 | 
			
		||||
        insertEmoji(realm, emoji)
 | 
			
		||||
        this.close()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -127,7 +127,7 @@
 | 
			
		|||
  import { on, emit } from '../../../_utils/eventBus'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      let dialogElement = this.refs.node.parentElement
 | 
			
		||||
      this._a11yDialog = new A11yDialog(dialogElement)
 | 
			
		||||
      this._a11yDialog.on('hide', () => {
 | 
			
		||||
| 
						 | 
				
			
			@ -162,7 +162,7 @@
 | 
			
		|||
      }
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      showDialog(thisId) {
 | 
			
		||||
      showDialog (thisId) {
 | 
			
		||||
        let { id } = this.get()
 | 
			
		||||
        if (id !== thisId) {
 | 
			
		||||
          return
 | 
			
		||||
| 
						 | 
				
			
			@ -172,7 +172,7 @@
 | 
			
		|||
          this.set({ fadedIn: true })
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      closeDialog(thisId) {
 | 
			
		||||
      closeDialog (thisId) {
 | 
			
		||||
        let { id } = this.get()
 | 
			
		||||
        if (id !== thisId) {
 | 
			
		||||
          return
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,7 +29,7 @@
 | 
			
		|||
    methods: {
 | 
			
		||||
      show,
 | 
			
		||||
      close,
 | 
			
		||||
      onClick(item) {
 | 
			
		||||
      onClick (item) {
 | 
			
		||||
        let { realm } = this.get()
 | 
			
		||||
        setPostPrivacy(realm, item.key)
 | 
			
		||||
        this.close()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -53,8 +53,8 @@ export default {
 | 
			
		|||
    muteIcon: (muting) => muting ? '#fa-volume-up' : '#fa-volume-off',
 | 
			
		||||
    // end account data copypasta
 | 
			
		||||
    items: (blockLabel, blocking, blockIcon, muteLabel, muteIcon,
 | 
			
		||||
            followLabel, followIcon, following, followRequested,
 | 
			
		||||
            accountId, verifyCredentialsId) => {
 | 
			
		||||
      followLabel, followIcon, following, followRequested,
 | 
			
		||||
      accountId, verifyCredentialsId) => {
 | 
			
		||||
      let isUser = accountId === verifyCredentialsId
 | 
			
		||||
      return [
 | 
			
		||||
        isUser && {
 | 
			
		||||
| 
						 | 
				
			
			@ -89,7 +89,7 @@ export default {
 | 
			
		|||
  methods: {
 | 
			
		||||
    show,
 | 
			
		||||
    close,
 | 
			
		||||
    onClick(item) {
 | 
			
		||||
    onClick (item) {
 | 
			
		||||
      switch (item.key) {
 | 
			
		||||
        case 'delete':
 | 
			
		||||
          return this.onDeleteClicked()
 | 
			
		||||
| 
						 | 
				
			
			@ -101,22 +101,22 @@ export default {
 | 
			
		|||
          return this.onMuteClicked()
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    async onDeleteClicked() {
 | 
			
		||||
    async onDeleteClicked () {
 | 
			
		||||
      let { statusId } = this.get()
 | 
			
		||||
      this.close()
 | 
			
		||||
      await doDeleteStatus(statusId)
 | 
			
		||||
    },
 | 
			
		||||
    async onFollowClicked() {
 | 
			
		||||
    async onFollowClicked () {
 | 
			
		||||
      let { accountId, following } = this.get()
 | 
			
		||||
      this.close()
 | 
			
		||||
      await setAccountFollowed(accountId, !following, true)
 | 
			
		||||
    },
 | 
			
		||||
    async onBlockClicked() {
 | 
			
		||||
    async onBlockClicked () {
 | 
			
		||||
      let { accountId, blocking } = this.get()
 | 
			
		||||
      this.close()
 | 
			
		||||
      await setAccountBlocked(accountId, !blocking, true)
 | 
			
		||||
    },
 | 
			
		||||
    async onMuteClicked() {
 | 
			
		||||
    async onMuteClicked () {
 | 
			
		||||
      let { accountId, muting } = this.get()
 | 
			
		||||
      this.close()
 | 
			
		||||
      await setAccountMuted(accountId, !muting, true)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -120,7 +120,7 @@
 | 
			
		|||
      numFollowersDisplay: numFollowers => numberFormat.format(numFollowers)
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      async onMoreOptionsClick() {
 | 
			
		||||
      async onMoreOptionsClick () {
 | 
			
		||||
        let { account, relationship, verifyCredentials } = this.get()
 | 
			
		||||
        let dialogs = await importDialogs()
 | 
			
		||||
        dialogs.showAccountProfileOptionsDialog(account, relationship, verifyCredentials)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,7 +28,7 @@
 | 
			
		|||
 | 
			
		||||
  export default {
 | 
			
		||||
    methods: {
 | 
			
		||||
      async onFollowButtonClick(e) {
 | 
			
		||||
      async onFollowButtonClick (e) {
 | 
			
		||||
        e.preventDefault()
 | 
			
		||||
        e.stopPropagation()
 | 
			
		||||
        let {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,7 +39,7 @@
 | 
			
		|||
          note = `<p>${note}</p>`
 | 
			
		||||
        }
 | 
			
		||||
        return note
 | 
			
		||||
      },
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -19,14 +19,13 @@
 | 
			
		|||
  }
 | 
			
		||||
</style>
 | 
			
		||||
<script>
 | 
			
		||||
 | 
			
		||||
  import PseudoVirtualListLazyItem from './PseudoVirtualListLazyItem.html'
 | 
			
		||||
  import { getRectFromEntry } from '../../_utils/getRectFromEntry'
 | 
			
		||||
  import { mark, stop } from '../../_utils/marks'
 | 
			
		||||
  import { pseudoVirtualListStore } from './pseudoVirtualListStore'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      mark('PseudoVirtualList oncreate()')
 | 
			
		||||
      let { realm } = this.get()
 | 
			
		||||
      this.store.setCurrentRealm(realm)
 | 
			
		||||
| 
						 | 
				
			
			@ -57,7 +56,7 @@
 | 
			
		|||
      })
 | 
			
		||||
      stop('PseudoVirtualList oncreate()')
 | 
			
		||||
    },
 | 
			
		||||
    ondestroy() {
 | 
			
		||||
    ondestroy () {
 | 
			
		||||
      let { intersectionObserver } = this.get()
 | 
			
		||||
      if (intersectionObserver) {
 | 
			
		||||
        intersectionObserver.disconnect()
 | 
			
		||||
| 
						 | 
				
			
			@ -65,18 +64,18 @@
 | 
			
		|||
      this.store.setCurrentRealm(null)
 | 
			
		||||
    },
 | 
			
		||||
    helpers: {
 | 
			
		||||
      isIntersecting(key, $intersectionStates) {
 | 
			
		||||
      isIntersecting (key, $intersectionStates) {
 | 
			
		||||
        return !!($intersectionStates[key] && $intersectionStates[key].isIntersecting)
 | 
			
		||||
      },
 | 
			
		||||
      isCached(key, $intersectionStates) {
 | 
			
		||||
      isCached (key, $intersectionStates) {
 | 
			
		||||
        return !!($intersectionStates[key] && $intersectionStates[key].isCached)
 | 
			
		||||
      },
 | 
			
		||||
      getHeight(key, $intersectionStates) {
 | 
			
		||||
      getHeight (key, $intersectionStates) {
 | 
			
		||||
        return $intersectionStates[key] && $intersectionStates[key].height
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      scrollToPosition(element) {
 | 
			
		||||
      scrollToPosition (element) {
 | 
			
		||||
        let { scrolledToPosition } = this.get()
 | 
			
		||||
        if (scrolledToPosition) {
 | 
			
		||||
          return
 | 
			
		||||
| 
						 | 
				
			
			@ -87,7 +86,7 @@
 | 
			
		|||
          element.scrollIntoView(true)
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      onIntersection(entries) {
 | 
			
		||||
      onIntersection (entries) {
 | 
			
		||||
        mark('onIntersection')
 | 
			
		||||
        let newIntersectionStates = {}
 | 
			
		||||
        let { scrollToItem } = this.get()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,7 @@
 | 
			
		|||
  import { mark, stop } from '../../_utils/marks'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      this.observe('isIntersecting', isIntersecting => {
 | 
			
		||||
        if (isIntersecting) {
 | 
			
		||||
          mark('render')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,7 @@
 | 
			
		|||
  import { mark, stop } from '../../_utils/marks'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    async oncreate() {
 | 
			
		||||
    async oncreate () {
 | 
			
		||||
      // TODO: there appears to be a bug in {{#await}} that means we have to do this manually.
 | 
			
		||||
      // Some items may appear on top of other items because their offset is 0 and never updated.
 | 
			
		||||
      let { makeProps, key } = this.get()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,7 +22,7 @@
 | 
			
		|||
  }
 | 
			
		||||
</style>
 | 
			
		||||
<script>
 | 
			
		||||
  import SettingsNav from './SettingsNav.html';
 | 
			
		||||
  import SettingsNav from './SettingsNav.html'
 | 
			
		||||
  import FreeTextLayout from '../../_components/FreeTextLayout'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
| 
						 | 
				
			
			@ -30,5 +30,5 @@
 | 
			
		|||
      FreeTextLayout,
 | 
			
		||||
      SettingsNav
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -13,10 +13,10 @@
 | 
			
		|||
<script>
 | 
			
		||||
  export default {
 | 
			
		||||
    helpers: {
 | 
			
		||||
      getCurrentClass(page, name) {
 | 
			
		||||
        return page === name  ? "selected" : ""
 | 
			
		||||
      getCurrentClass (page, name) {
 | 
			
		||||
        return page === name ? 'selected' : ''
 | 
			
		||||
      },
 | 
			
		||||
      getAriaLabel(page, name, label) {
 | 
			
		||||
      getAriaLabel (page, name, label) {
 | 
			
		||||
        return page === name ? `${label} (current page)` : label
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -98,19 +98,18 @@
 | 
			
		|||
  }
 | 
			
		||||
</style>
 | 
			
		||||
<script>
 | 
			
		||||
  import { DEFAULT_MEDIA_WIDTH, DEFAULT_MEDIA_HEIGHT } from '../../_static/media'
 | 
			
		||||
  import { DEFAULT_MEDIA_WIDTH, DEFAULT_MEDIA_HEIGHT, ONE_TRANSPARENT_PIXEL } from '../../_static/media'
 | 
			
		||||
  import { importDialogs } from '../../_utils/asyncModules'
 | 
			
		||||
  import { mouseover } from '../../_utils/events'
 | 
			
		||||
  import NonAutoplayGifv from '../NonAutoplayGifv.html'
 | 
			
		||||
  import PlayVideoIcon from '../PlayVideoIcon.html'
 | 
			
		||||
  import { ONE_TRANSPARENT_PIXEL } from '../../_static/media'
 | 
			
		||||
  import { store } from '../../_store/store'
 | 
			
		||||
  import LazyImage from '../LazyImage.html'
 | 
			
		||||
  import AutoplayVideo from '../AutoplayVideo.html'
 | 
			
		||||
  import { registerClickDelegate } from '../../_utils/delegate'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      let { delegateKey } = this.get()
 | 
			
		||||
      registerClickDelegate(this, delegateKey, () => {
 | 
			
		||||
        let { media } = this.get()
 | 
			
		||||
| 
						 | 
				
			
			@ -139,13 +138,13 @@
 | 
			
		|||
      delegateKey: (media, uuid) => `media-${uuid}-${media.id}`
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      async onClickPlayVideoButton() {
 | 
			
		||||
      async onClickPlayVideoButton () {
 | 
			
		||||
        let { media, modalWidth, modalHeight } = this.get()
 | 
			
		||||
        let dialogs = await importDialogs()
 | 
			
		||||
        dialogs.showVideoDialog(media.preview_url, media.url,
 | 
			
		||||
          modalWidth, modalHeight, media.description)
 | 
			
		||||
      },
 | 
			
		||||
      async onClickShowImageButton() {
 | 
			
		||||
      async onClickShowImageButton () {
 | 
			
		||||
        let { media, modalWidth, modalHeight } = this.get()
 | 
			
		||||
        let dialogs = await importDialogs()
 | 
			
		||||
        dialogs.showImageDialog(media.preview_url, media.url, media.type,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,7 +38,7 @@
 | 
			
		|||
    computed: {
 | 
			
		||||
      maxMediaWidth: (mediaAttachments) => {
 | 
			
		||||
        return Math.max.apply(Math, mediaAttachments.map(media => {
 | 
			
		||||
          return media.meta && media.meta.small && typeof media.meta.small.width === 'number' ?  media.meta.small.width : DEFAULT_MEDIA_WIDTH
 | 
			
		||||
          return media.meta && media.meta.small && typeof media.meta.small.width === 'number' ? media.meta.small.width : DEFAULT_MEDIA_WIDTH
 | 
			
		||||
        }))
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,7 +46,7 @@
 | 
			
		|||
      statusId: (status) => status && status.id,
 | 
			
		||||
      uuid: ($currentInstance, timelineType, timelineValue, notificationId, statusId) => {
 | 
			
		||||
        return `${$currentInstance}/${timelineType}/${timelineValue}/${notificationId}/${statusId || ''}`
 | 
			
		||||
      },
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -122,7 +122,7 @@
 | 
			
		|||
  const isStatusArticle = node => node.classList.contains('status-article')
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      let { delegateKey, isStatusInOwnThread, showContent } = this.get()
 | 
			
		||||
      if (!isStatusInOwnThread) {
 | 
			
		||||
        // the whole <article> is clickable in this case
 | 
			
		||||
| 
						 | 
				
			
			@ -151,7 +151,7 @@
 | 
			
		|||
    },
 | 
			
		||||
    store: () => store,
 | 
			
		||||
    methods: {
 | 
			
		||||
      onClickOrKeydown(e) {
 | 
			
		||||
      onClickOrKeydown (e) {
 | 
			
		||||
        let { type, keyCode, target } = e
 | 
			
		||||
 | 
			
		||||
        let isClick = type === 'click'
 | 
			
		||||
| 
						 | 
				
			
			@ -202,18 +202,18 @@
 | 
			
		|||
      spoilerShown: ($spoilersShown, uuid) => !!$spoilersShown[uuid],
 | 
			
		||||
      replyShown: ($repliesShown, uuid) => !!$repliesShown[uuid],
 | 
			
		||||
      showMedia: (originalStatus, isStatusInNotification) => {
 | 
			
		||||
        return !isStatusInNotification
 | 
			
		||||
          && originalStatus.media_attachments
 | 
			
		||||
          && originalStatus.media_attachments.length
 | 
			
		||||
        return !isStatusInNotification &&
 | 
			
		||||
        originalStatus.media_attachments &&
 | 
			
		||||
        originalStatus.media_attachments.length
 | 
			
		||||
      },
 | 
			
		||||
      ariaLabel: (originalAccount, originalStatus, visibility) => {
 | 
			
		||||
        return (visibility === 'direct' ? 'Direct message' : 'Status') +
 | 
			
		||||
          ` by ${originalAccount.display_name || originalAccount.username}`
 | 
			
		||||
      },
 | 
			
		||||
      showHeader: (notification, status, timelineType) => {
 | 
			
		||||
        return (notification && (notification.type === 'reblog' || notification.type === 'favourite'))
 | 
			
		||||
          || status.reblog
 | 
			
		||||
          || timelineType === 'pinned'
 | 
			
		||||
        return (notification && (notification.type === 'reblog' || notification.type === 'favourite')) ||
 | 
			
		||||
        status.reblog ||
 | 
			
		||||
        timelineType === 'pinned'
 | 
			
		||||
      },
 | 
			
		||||
      className: (visibility, timelineType, isStatusInOwnThread) => {
 | 
			
		||||
        return classname(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,7 +25,7 @@
 | 
			
		|||
  const THROTTLE_DELAY = 150
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      on('postedStatus', this, this.onPostedStatus)
 | 
			
		||||
      this.setupRecalculateHeightListener()
 | 
			
		||||
    },
 | 
			
		||||
| 
						 | 
				
			
			@ -34,7 +34,7 @@
 | 
			
		|||
      composeData: ($currentComposeData, originalStatusId) => $currentComposeData[originalStatusId] || {}
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      onPostedStatus(realm) {
 | 
			
		||||
      onPostedStatus (realm) {
 | 
			
		||||
        let { originalStatusId } = this.get()
 | 
			
		||||
        if (realm !== originalStatusId) {
 | 
			
		||||
          return
 | 
			
		||||
| 
						 | 
				
			
			@ -47,7 +47,7 @@
 | 
			
		|||
          this.fire('recalculateHeight')
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      setupRecalculateHeightListener() {
 | 
			
		||||
      setupRecalculateHeightListener () {
 | 
			
		||||
        const recalc = () => requestAnimationFrame(() => this.fire('recalculateHeight'))
 | 
			
		||||
        // debounce AND throttle due to 333ms content warning animation
 | 
			
		||||
        const debounced = debounce(recalc, DEBOUNCE_DELAY)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -64,7 +64,7 @@
 | 
			
		|||
  import { emojifyText } from '../../_utils/emojifyText'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      this.hydrateContent()
 | 
			
		||||
    },
 | 
			
		||||
    store: () => store,
 | 
			
		||||
| 
						 | 
				
			
			@ -90,7 +90,7 @@
 | 
			
		|||
      }
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      hydrateContent() {
 | 
			
		||||
      hydrateContent () {
 | 
			
		||||
        if (!this.refs.node) {
 | 
			
		||||
          return
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -81,7 +81,6 @@
 | 
			
		|||
  }
 | 
			
		||||
</style>
 | 
			
		||||
<script>
 | 
			
		||||
 | 
			
		||||
  import Avatar from '../Avatar.html'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -129,7 +129,7 @@
 | 
			
		|||
  import { registerClickDelegate } from '../../_utils/delegate'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      let { delegateKey } = this.get()
 | 
			
		||||
      registerClickDelegate(this, delegateKey, () => this.onClickSensitiveMediaButton())
 | 
			
		||||
    },
 | 
			
		||||
| 
						 | 
				
			
			@ -141,10 +141,10 @@
 | 
			
		|||
      mediaAttachments: (originalStatus) => originalStatus.media_attachments,
 | 
			
		||||
      sensitiveShown: ($sensitivesShown, uuid) => !!$sensitivesShown[uuid],
 | 
			
		||||
      sensitive: (originalStatus, $markMediaAsSensitive) => originalStatus.sensitive || $markMediaAsSensitive,
 | 
			
		||||
      delegateKey: (uuid) => `sensitive-${uuid}`,
 | 
			
		||||
      delegateKey: (uuid) => `sensitive-${uuid}`
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      onClickSensitiveMediaButton() {
 | 
			
		||||
      onClickSensitiveMediaButton () {
 | 
			
		||||
        let { uuid } = this.get()
 | 
			
		||||
        let { sensitivesShown } = this.store.get()
 | 
			
		||||
        sensitivesShown[uuid] = !sensitivesShown[uuid]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -52,7 +52,7 @@
 | 
			
		|||
  import escapeHtml from 'escape-html'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      let { delegateKey } = this.get()
 | 
			
		||||
      registerClickDelegate(this, delegateKey, () => this.onClickSpoilerButton())
 | 
			
		||||
    },
 | 
			
		||||
| 
						 | 
				
			
			@ -67,7 +67,7 @@
 | 
			
		|||
      delegateKey: (uuid) => `spoiler-${uuid}`
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      onClickSpoilerButton() {
 | 
			
		||||
      onClickSpoilerButton () {
 | 
			
		||||
        requestAnimationFrame(() => {
 | 
			
		||||
          mark('clickSpoilerButton')
 | 
			
		||||
          let { uuid } = this.get()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -53,7 +53,7 @@
 | 
			
		|||
  import { on } from '../../_utils/eventBus'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      let {
 | 
			
		||||
        favoriteKey,
 | 
			
		||||
        reblogKey,
 | 
			
		||||
| 
						 | 
				
			
			@ -73,21 +73,21 @@
 | 
			
		|||
    },
 | 
			
		||||
    store: () => store,
 | 
			
		||||
    methods: {
 | 
			
		||||
      onFavoriteClick(e) {
 | 
			
		||||
      onFavoriteClick (e) {
 | 
			
		||||
        e.preventDefault()
 | 
			
		||||
        e.stopPropagation()
 | 
			
		||||
        let { originalStatusId, favorited } = this.get()
 | 
			
		||||
        /* no await */ setFavorited(originalStatusId, !favorited)
 | 
			
		||||
        this.set({animateFavorite: !favorited})
 | 
			
		||||
      },
 | 
			
		||||
      onReblogClick(e) {
 | 
			
		||||
      onReblogClick (e) {
 | 
			
		||||
        e.preventDefault()
 | 
			
		||||
        e.stopPropagation()
 | 
			
		||||
        let { originalStatusId, reblogged } = this.get()
 | 
			
		||||
        /* no await */ setReblogged(originalStatusId, !reblogged)
 | 
			
		||||
        this.set({animateReblog: !reblogged})
 | 
			
		||||
      },
 | 
			
		||||
      onReplyClick(e) {
 | 
			
		||||
      onReplyClick (e) {
 | 
			
		||||
        e.preventDefault()
 | 
			
		||||
        e.stopPropagation()
 | 
			
		||||
        requestAnimationFrame(() => {
 | 
			
		||||
| 
						 | 
				
			
			@ -98,7 +98,7 @@
 | 
			
		|||
          this.fire('recalculateHeight')
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      async onOptionsClick(e) {
 | 
			
		||||
      async onOptionsClick (e) {
 | 
			
		||||
        e.preventDefault()
 | 
			
		||||
        e.stopPropagation()
 | 
			
		||||
        let { originalStatusId, originalAccountId } = this.get()
 | 
			
		||||
| 
						 | 
				
			
			@ -107,7 +107,7 @@
 | 
			
		|||
        await updateRelationshipPromise
 | 
			
		||||
        dialogs.showStatusOptionsDialog(originalStatusId)
 | 
			
		||||
      },
 | 
			
		||||
      onPostedStatus(realm, inReplyToUuid) {
 | 
			
		||||
      onPostedStatus (realm, inReplyToUuid) {
 | 
			
		||||
        let {
 | 
			
		||||
          originalStatusId,
 | 
			
		||||
          uuid
 | 
			
		||||
| 
						 | 
				
			
			@ -166,7 +166,7 @@
 | 
			
		|||
      favoriteKey: (uuid) => `fav-${uuid}`,
 | 
			
		||||
      reblogKey: (uuid) => `reblog-${uuid}`,
 | 
			
		||||
      replyKey: (uuid) => `reply-${uuid}`,
 | 
			
		||||
      optionsKey: (uuid) => `options-${uuid}`,
 | 
			
		||||
      optionsKey: (uuid) => `options-${uuid}`
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -16,7 +16,7 @@
 | 
			
		|||
  import { store } from '../../_store/store'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      let { currentInstance } = this.store.get()
 | 
			
		||||
      let { timeline } = this.get()
 | 
			
		||||
      this.store.set({currentTimeline: timeline})
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@
 | 
			
		|||
<script>
 | 
			
		||||
  export default {
 | 
			
		||||
    methods: {
 | 
			
		||||
      onClick(event) {
 | 
			
		||||
      onClick (event) {
 | 
			
		||||
        let { onClick } = this.get()
 | 
			
		||||
        if (onClick) {
 | 
			
		||||
          onClick(event)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,7 @@
 | 
			
		|||
  import { updatePinnedStatusesForAccount } from '../../_actions/pinnedStatuses'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    async oncreate() {
 | 
			
		||||
    async oncreate () {
 | 
			
		||||
      let { accountId } = this.get()
 | 
			
		||||
      await updatePinnedStatusesForAccount(accountId)
 | 
			
		||||
    },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -63,14 +63,14 @@
 | 
			
		|||
  import { doubleRAF } from '../../_utils/doubleRAF'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      console.log('timeline oncreate()')
 | 
			
		||||
      this.setupFocus()
 | 
			
		||||
      setupTimeline()
 | 
			
		||||
      this.restoreFocus()
 | 
			
		||||
      this.setupStreaming()
 | 
			
		||||
    },
 | 
			
		||||
    ondestroy() {
 | 
			
		||||
    ondestroy () {
 | 
			
		||||
      console.log('ondestroy')
 | 
			
		||||
      this.teardownFocus()
 | 
			
		||||
    },
 | 
			
		||||
| 
						 | 
				
			
			@ -122,15 +122,13 @@
 | 
			
		|||
      },
 | 
			
		||||
      // for threads, it's simpler to just render all items as a pseudo-virtual list
 | 
			
		||||
      // due to need to scroll to the right item and thus calculate all item heights up-front
 | 
			
		||||
      virtual: (timelineType) => timelineType !=='status',
 | 
			
		||||
      scrollToItem: (timelineType, timelineValue, $firstTimelineItemId) => {
 | 
			
		||||
        // Scroll to the first item if this is a "status in own thread" timeline.
 | 
			
		||||
        // Don't scroll to the first item because it obscures the "back" button.
 | 
			
		||||
        return timelineType === 'status'
 | 
			
		||||
          && $firstTimelineItemId
 | 
			
		||||
          && timelineValue !== $firstTimelineItemId
 | 
			
		||||
          && timelineValue
 | 
			
		||||
      },
 | 
			
		||||
      virtual: (timelineType) => timelineType !== 'status',
 | 
			
		||||
      // Scroll to the first item if this is a "status in own thread" timeline.
 | 
			
		||||
      // Don't scroll to the first item because it obscures the "back" button.
 | 
			
		||||
      scrollToItem: (timelineType, timelineValue, $firstTimelineItemId) => (
 | 
			
		||||
        timelineType === 'status' && $firstTimelineItemId &&
 | 
			
		||||
        timelineValue !== $firstTimelineItemId && timelineValue
 | 
			
		||||
      ),
 | 
			
		||||
      itemIdsToAdd: ($itemIdsToAdd) => $itemIdsToAdd,
 | 
			
		||||
      headerProps: (itemIdsToAdd) => {
 | 
			
		||||
        return {
 | 
			
		||||
| 
						 | 
				
			
			@ -149,7 +147,7 @@
 | 
			
		|||
      blurWithCapture
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      initialize() {
 | 
			
		||||
      initialize () {
 | 
			
		||||
        let { initializeStarted } = this.get()
 | 
			
		||||
        if (initializeStarted) {
 | 
			
		||||
          return
 | 
			
		||||
| 
						 | 
				
			
			@ -162,10 +160,10 @@
 | 
			
		|||
          stop('initializeTimeline')
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      onScrollTopChanged(scrollTop) {
 | 
			
		||||
      onScrollTopChanged (scrollTop) {
 | 
			
		||||
        this.set({scrollTop: scrollTop})
 | 
			
		||||
      },
 | 
			
		||||
      onScrollToBottom() {
 | 
			
		||||
      onScrollToBottom () {
 | 
			
		||||
        let {
 | 
			
		||||
          timelineInitialized,
 | 
			
		||||
          runningUpdate
 | 
			
		||||
| 
						 | 
				
			
			@ -185,7 +183,7 @@
 | 
			
		|||
          timeline
 | 
			
		||||
        )
 | 
			
		||||
      },
 | 
			
		||||
      onScrollToTop() {
 | 
			
		||||
      onScrollToTop () {
 | 
			
		||||
        let { shouldShowHeader } = this.store.get()
 | 
			
		||||
        if (shouldShowHeader) {
 | 
			
		||||
          this.store.setForCurrentTimeline({
 | 
			
		||||
| 
						 | 
				
			
			@ -194,7 +192,7 @@
 | 
			
		|||
          })
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      setupStreaming() {
 | 
			
		||||
      setupStreaming () {
 | 
			
		||||
        let { currentInstance } = this.store.get()
 | 
			
		||||
        let { timeline } = this.get()
 | 
			
		||||
        let handleItemIdsToAdd = () => {
 | 
			
		||||
| 
						 | 
				
			
			@ -230,20 +228,20 @@
 | 
			
		|||
          scheduleIdleTask(handleItemIdsToAdd)
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      setupFocus() {
 | 
			
		||||
      setupFocus () {
 | 
			
		||||
        this.onPushState = this.onPushState.bind(this)
 | 
			
		||||
        this.store.setForCurrentTimeline({
 | 
			
		||||
          ignoreBlurEvents: false
 | 
			
		||||
        })
 | 
			
		||||
        window.addEventListener('pushState', this.onPushState)
 | 
			
		||||
      },
 | 
			
		||||
      teardownFocus() {
 | 
			
		||||
      teardownFocus () {
 | 
			
		||||
        window.removeEventListener('pushState', this.onPushState)
 | 
			
		||||
      },
 | 
			
		||||
      onPushState() {
 | 
			
		||||
      onPushState () {
 | 
			
		||||
        this.store.setForCurrentTimeline({ ignoreBlurEvents: true })
 | 
			
		||||
      },
 | 
			
		||||
      saveFocus(e) {
 | 
			
		||||
      saveFocus (e) {
 | 
			
		||||
        try {
 | 
			
		||||
          let { currentInstance } = this.store.get()
 | 
			
		||||
          let { timeline } = this.get()
 | 
			
		||||
| 
						 | 
				
			
			@ -263,7 +261,7 @@
 | 
			
		|||
          console.error('unable to save focus', err)
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      clearFocus() {
 | 
			
		||||
      clearFocus () {
 | 
			
		||||
        try {
 | 
			
		||||
          let { ignoreBlurEvents } = this.store.get()
 | 
			
		||||
          if (ignoreBlurEvents) {
 | 
			
		||||
| 
						 | 
				
			
			@ -279,7 +277,7 @@
 | 
			
		|||
          console.error('unable to clear focus', err)
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      restoreFocus() {
 | 
			
		||||
      restoreFocus () {
 | 
			
		||||
        let { lastFocusedElementSelector } = this.store.get()
 | 
			
		||||
        if (!lastFocusedElementSelector) {
 | 
			
		||||
          return
 | 
			
		||||
| 
						 | 
				
			
			@ -294,7 +292,7 @@
 | 
			
		|||
          })
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      onNoNeedToScroll() {
 | 
			
		||||
      onNoNeedToScroll () {
 | 
			
		||||
        // If the timeline doesn't need to scroll, then we can safely "preinitialize,"
 | 
			
		||||
        // i.e. render anything above the fold of the timeline. This avoids the affect
 | 
			
		||||
        // where the scrollable content appears to jump around if we need to scroll it.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -105,10 +105,10 @@
 | 
			
		|||
      },
 | 
			
		||||
      scrollTop: ($scrollTop) => $scrollTop,
 | 
			
		||||
      // TODO: bug in svelte store, shouldn't need to do this
 | 
			
		||||
      allVisibleItemsHaveHeight: ($allVisibleItemsHaveHeight) => $allVisibleItemsHaveHeight,
 | 
			
		||||
      allVisibleItemsHaveHeight: ($allVisibleItemsHaveHeight) => $allVisibleItemsHaveHeight
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      calculateListOffset() {
 | 
			
		||||
      calculateListOffset () {
 | 
			
		||||
        // TODO: better way to get the offset top?
 | 
			
		||||
        let node = this.refs.node
 | 
			
		||||
        if (!node) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,7 @@
 | 
			
		|||
  const SCROLL_EVENT_DELAY = 300
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      mark('onCreate VirtualListContainer')
 | 
			
		||||
      let {
 | 
			
		||||
        realm,
 | 
			
		||||
| 
						 | 
				
			
			@ -53,14 +53,14 @@
 | 
			
		|||
      }
 | 
			
		||||
      stop('onCreate VirtualListContainer')
 | 
			
		||||
    },
 | 
			
		||||
    ondestroy() {
 | 
			
		||||
    ondestroy () {
 | 
			
		||||
      this.teardownScroll()
 | 
			
		||||
      this.teardownFullscreen()
 | 
			
		||||
      this.store.setCurrentRealm(null)
 | 
			
		||||
    },
 | 
			
		||||
    store: () => virtualListStore,
 | 
			
		||||
    methods: {
 | 
			
		||||
      setupScroll(node) {
 | 
			
		||||
      setupScroll (node) {
 | 
			
		||||
        if (!node) {
 | 
			
		||||
          return
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -76,21 +76,21 @@
 | 
			
		|||
        })
 | 
			
		||||
        node.addEventListener('scroll', this.scrollListener)
 | 
			
		||||
      },
 | 
			
		||||
      teardownScroll() {
 | 
			
		||||
      teardownScroll () {
 | 
			
		||||
        let { containerQuery } = this.get()
 | 
			
		||||
        let node = document.querySelector(containerQuery)
 | 
			
		||||
        if (node) {
 | 
			
		||||
          node.removeEventListener('scroll', this.scrollListener)
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      setupFullscreen() {
 | 
			
		||||
      setupFullscreen () {
 | 
			
		||||
        this.onFullscreenChange = this.onFullscreenChange.bind(this)
 | 
			
		||||
        attachFullscreenListener(this.onFullscreenChange)
 | 
			
		||||
      },
 | 
			
		||||
      teardownFullscreen() {
 | 
			
		||||
      teardownFullscreen () {
 | 
			
		||||
        detachFullscreenListener(this.onFullscreenChange)
 | 
			
		||||
      },
 | 
			
		||||
      onScroll(event) {
 | 
			
		||||
      onScroll (event) {
 | 
			
		||||
        let { scrollTop, scrollHeight } = event.target
 | 
			
		||||
 | 
			
		||||
        // On mobile devices, this can make scrolling more responsive. On
 | 
			
		||||
| 
						 | 
				
			
			@ -104,7 +104,7 @@
 | 
			
		|||
          stop('onScroll -> setForRealm()')
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      onFullscreenChange() {
 | 
			
		||||
      onFullscreenChange () {
 | 
			
		||||
        mark('onFullscreenChange')
 | 
			
		||||
        console.log('is fullscreen? ', isFullscreen())
 | 
			
		||||
        this.set({ fullscreen: isFullscreen() })
 | 
			
		||||
| 
						 | 
				
			
			@ -115,5 +115,5 @@
 | 
			
		|||
      // TODO: bug in svelte/store – the observer in oncreate() never get removed without this hack
 | 
			
		||||
      allVisibleItemsHaveHeight: ($allVisibleItemsHaveHeight) => $allVisibleItemsHaveHeight
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -15,13 +15,13 @@
 | 
			
		|||
  import { AsyncLayout } from '../../_utils/AsyncLayout'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      const asyncLayout = new AsyncLayout(() => '__footer__')
 | 
			
		||||
      asyncLayout.observe('__footer__', this.refs.node, (rect) => {
 | 
			
		||||
        asyncLayout.disconnect()
 | 
			
		||||
        this.store.setForRealm({footerHeight: rect.height})
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    store: () => virtualListStore,
 | 
			
		||||
    store: () => virtualListStore
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -26,7 +26,7 @@
 | 
			
		|||
  import { doubleRAF } from '../../_utils/doubleRAF'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      this.observe('shown', shown => {
 | 
			
		||||
        if (shown) {
 | 
			
		||||
          this.doCalculateHeight()
 | 
			
		||||
| 
						 | 
				
			
			@ -38,7 +38,7 @@
 | 
			
		|||
    },
 | 
			
		||||
    store: () => virtualListStore,
 | 
			
		||||
    methods: {
 | 
			
		||||
      doCalculateHeight() {
 | 
			
		||||
      doCalculateHeight () {
 | 
			
		||||
        let { heightCalculated } = this.get()
 | 
			
		||||
        if (heightCalculated) { // only need to calculate once, it never changes
 | 
			
		||||
          return
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,7 +28,7 @@
 | 
			
		|||
  import { registerResizeListener, unregisterResizeListener } from '../../_utils/resize'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      let asyncLayout = new AsyncLayout(node => node.getAttribute('virtual-list-key'))
 | 
			
		||||
      let { key } = this.get()
 | 
			
		||||
      asyncLayout.observe(key, this.refs.node, (rect) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -39,7 +39,7 @@
 | 
			
		|||
      this.doRecalculateHeight = this.doRecalculateHeight.bind(this)
 | 
			
		||||
      registerResizeListener(this.doRecalculateHeight)
 | 
			
		||||
    },
 | 
			
		||||
    ondestroy() {
 | 
			
		||||
    ondestroy () {
 | 
			
		||||
      unregisterResizeListener(this.doRecalculateHeight)
 | 
			
		||||
    },
 | 
			
		||||
    store: () => virtualListStore,
 | 
			
		||||
| 
						 | 
				
			
			@ -47,7 +47,7 @@
 | 
			
		|||
      'shown': ($itemHeights, key) => $itemHeights[key] > 0
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      doRecalculateHeight() {
 | 
			
		||||
      doRecalculateHeight () {
 | 
			
		||||
        // Recalculate immediately because this is done on-demand, e.g.
 | 
			
		||||
        // when clicking the "More" button on a spoiler.
 | 
			
		||||
        let rect = this.refs.node.getBoundingClientRect()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,7 @@
 | 
			
		|||
  import { mark, stop } from '../../_utils/marks'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    async oncreate() {
 | 
			
		||||
    async oncreate () {
 | 
			
		||||
      // TODO: there appears to be a bug in {{#await}} that means we have to do this manually.
 | 
			
		||||
      // Some items may appear on top of other items because their offset is 0 and never updated.
 | 
			
		||||
      let { makeProps, key } = this.get()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,7 +29,7 @@
 | 
			
		|||
  import PinnedStatuses from '../../_components/timeline/PinnedStatuses.html'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      let { params } = this.get()
 | 
			
		||||
      let { accountId } = params
 | 
			
		||||
      clearProfileAndRelationship()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -95,7 +95,7 @@
 | 
			
		|||
  import { updateLists } from '../../_actions/lists'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    async oncreate() {
 | 
			
		||||
    async oncreate () {
 | 
			
		||||
      let { currentInstance } = this.store.get()
 | 
			
		||||
      if (currentInstance) {
 | 
			
		||||
        await updateLists()
 | 
			
		||||
| 
						 | 
				
			
			@ -111,5 +111,5 @@
 | 
			
		|||
    computed: {
 | 
			
		||||
      isLockedAccount: ($currentVerifyCredentials) => $currentVerifyCredentials && $currentVerifyCredentials.locked
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -8,11 +8,11 @@
 | 
			
		|||
  import { store } from '.././_store/store.js'
 | 
			
		||||
  import TimelineHomePage from '../_components/TimelineHomePage.html'
 | 
			
		||||
 | 
			
		||||
	export default {
 | 
			
		||||
		store: () => store,
 | 
			
		||||
		components: {
 | 
			
		||||
			NotLoggedInHome,
 | 
			
		||||
  export default {
 | 
			
		||||
    store: () => store,
 | 
			
		||||
    components: {
 | 
			
		||||
      NotLoggedInHome,
 | 
			
		||||
      TimelineHomePage
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -22,5 +22,5 @@
 | 
			
		|||
      HiddenFromSSR,
 | 
			
		||||
      TimelinePage
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -37,7 +37,7 @@
 | 
			
		|||
  import { updateVerifyCredentialsForInstance } from '.././_actions/instances'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    async oncreate() {
 | 
			
		||||
    async oncreate () {
 | 
			
		||||
      try {
 | 
			
		||||
        let { currentInstance } = this.store.get()
 | 
			
		||||
        await updateVerifyCredentialsForInstance(currentInstance)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,5 +27,5 @@
 | 
			
		|||
    data: () => ({
 | 
			
		||||
      version
 | 
			
		||||
    })
 | 
			
		||||
  };
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -42,5 +42,5 @@
 | 
			
		|||
      SettingsLayout
 | 
			
		||||
    },
 | 
			
		||||
    store: () => store
 | 
			
		||||
  };
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -19,5 +19,5 @@
 | 
			
		|||
      SettingsList,
 | 
			
		||||
      SettingsListItem
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -112,9 +112,9 @@
 | 
			
		|||
    },
 | 
			
		||||
    store: () => store,
 | 
			
		||||
    data: () => ({
 | 
			
		||||
      themes: themes,
 | 
			
		||||
      themes: themes
 | 
			
		||||
    }),
 | 
			
		||||
    async oncreate() {
 | 
			
		||||
    async oncreate () {
 | 
			
		||||
      let { instanceName } = this.get()
 | 
			
		||||
      await updateVerifyCredentialsForInstance(instanceName)
 | 
			
		||||
    },
 | 
			
		||||
| 
						 | 
				
			
			@ -124,23 +124,23 @@
 | 
			
		|||
      verifyCredentials: ($verifyCredentials, instanceName) => $verifyCredentials && $verifyCredentials[instanceName]
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      onThemeChange() {
 | 
			
		||||
      onThemeChange () {
 | 
			
		||||
        let { newTheme, instanceName } = this.get()
 | 
			
		||||
        changeTheme(instanceName,  newTheme)
 | 
			
		||||
        changeTheme(instanceName, newTheme)
 | 
			
		||||
      },
 | 
			
		||||
      onSwitchToThisInstance(e) {
 | 
			
		||||
      onSwitchToThisInstance (e) {
 | 
			
		||||
        e.preventDefault()
 | 
			
		||||
        let { instanceName } = this.get()
 | 
			
		||||
        switchToInstance(instanceName)
 | 
			
		||||
      },
 | 
			
		||||
      async onLogOut(e) {
 | 
			
		||||
      async onLogOut (e) {
 | 
			
		||||
        e.preventDefault()
 | 
			
		||||
        let { instanceName } = this.get()
 | 
			
		||||
 | 
			
		||||
        let dialogs = await importDialogs()
 | 
			
		||||
        dialogs.showConfirmationDialog({
 | 
			
		||||
          text: `Log out of ${instanceName}?`,
 | 
			
		||||
          onPositive() {
 | 
			
		||||
          onPositive () {
 | 
			
		||||
            logOutOfInstance(instanceName)
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -75,7 +75,7 @@
 | 
			
		|||
    },
 | 
			
		||||
    store: () => store,
 | 
			
		||||
    methods: {
 | 
			
		||||
      onSubmit(event) {
 | 
			
		||||
      onSubmit (event) {
 | 
			
		||||
        event.preventDefault()
 | 
			
		||||
        logInToInstance()
 | 
			
		||||
      }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue