use standard to lint HTML too (#186)

This commit is contained in:
Nolan Lawson 2018-04-19 21:38:01 -07:00 committed by GitHub
parent ef80919269
commit bfc3c46462
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
70 changed files with 214 additions and 210 deletions

View File

@ -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
View File

@ -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",

View File

@ -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",

View File

@ -33,7 +33,7 @@
import { toast } from '../_utils/toast'
export default {
async oncreate() {
async oncreate () {
let { accountsFetcher } = this.get()
try {
// TODO: paginate

View File

@ -61,7 +61,7 @@
<script>
export default {
methods: {
onGoBack(e) {
onGoBack (e) {
e.preventDefault()
window.history.back()
}

View File

@ -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) {

View File

@ -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>

View File

@ -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()

View File

@ -11,7 +11,7 @@
let firstTime = true
export default {
oncreate() {
oncreate () {
firstTime = false
requestAnimationFrame(() => {
requestAnimationFrame(() => {

View File

@ -21,7 +21,7 @@
const SPINNER_DELAY = 700
export default {
oncreate() {
oncreate () {
setTimeout(() => {
this.set({shown: true})
}, SPINNER_DELAY)

View File

@ -135,7 +135,7 @@
}
},
methods: {
onClick(e) {
onClick (e) {
let { selected } = this.get()
if (!selected) {
return
@ -146,5 +146,4 @@
}
}
}
</script>

View File

@ -43,7 +43,7 @@
export default {
methods: {
onMouseOver(mouseOver) {
onMouseOver (mouseOver) {
this.set({playing: mouseOver})
}
},

View File

@ -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
}

View File

@ -42,7 +42,7 @@
},
computed: {
hidePage: ($timelineInitialized, $timelinePreinitialized) => !$timelineInitialized && !$timelinePreinitialized,
hideTimeline: ($timelineInitialized) => !$timelineInitialized,
hideTimeline: ($timelineInitialized) => !$timelineInitialized
},
store: () => store,
components: {

View File

@ -36,7 +36,7 @@
},
computed: {
hidePage: ($timelineInitialized, $timelinePreinitialized) => !$timelineInitialized && !$timelinePreinitialized,
hideTimeline: ($timelineInitialized) => !$timelineInitialized,
hideTimeline: ($timelineInitialized) => !$timelineInitialized
},
store: () => store,
components: {

View File

@ -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,

View File

@ -73,7 +73,7 @@
IconButton
},
methods: {
onPinClick(e) {
onPinClick (e) {
e.preventDefault()
let { currentInstance, pinnedPages } = this.store.get()
let { href } = this.get()

View File

@ -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))

View File

@ -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()
}

View File

@ -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 => {

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)
}

View File

@ -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>

View File

@ -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
}

View File

@ -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()
}
},

View File

@ -81,7 +81,7 @@
methods: {
show,
close,
onClickEmoji(emoji) {
onClickEmoji (emoji) {
let { realm } = this.get()
insertEmoji(realm, emoji)
this.close()

View File

@ -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

View File

@ -29,7 +29,7 @@
methods: {
show,
close,
onClick(item) {
onClick (item) {
let { realm } = this.get()
setPostPrivacy(realm, item.key)
this.close()

View File

@ -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)

View File

@ -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)

View File

@ -28,7 +28,7 @@
export default {
methods: {
async onFollowButtonClick(e) {
async onFollowButtonClick (e) {
e.preventDefault()
e.stopPropagation()
let {

View File

@ -39,7 +39,7 @@
note = `<p>${note}</p>`
}
return note
},
}
}
}
</script>

View File

@ -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()

View File

@ -16,7 +16,7 @@
import { mark, stop } from '../../_utils/marks'
export default {
oncreate() {
oncreate () {
this.observe('isIntersecting', isIntersecting => {
if (isIntersecting) {
mark('render')

View File

@ -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()

View File

@ -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>

View File

@ -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
}
}

View File

@ -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,

View File

@ -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
}))
}
},

View File

@ -46,7 +46,7 @@
statusId: (status) => status && status.id,
uuid: ($currentInstance, timelineType, timelineValue, notificationId, statusId) => {
return `${$currentInstance}/${timelineType}/${timelineValue}/${notificationId}/${statusId || ''}`
},
}
}
}
</script>

View File

@ -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(

View File

@ -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)

View File

@ -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
}

View File

@ -81,7 +81,6 @@
}
</style>
<script>
import Avatar from '../Avatar.html'
export default {

View File

@ -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]

View File

@ -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()

View File

@ -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>

View File

@ -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})

View File

@ -14,7 +14,7 @@
<script>
export default {
methods: {
onClick(event) {
onClick (event) {
let { onClick } = this.get()
if (onClick) {
onClick(event)

View File

@ -16,7 +16,7 @@
import { updatePinnedStatusesForAccount } from '../../_actions/pinnedStatuses'
export default {
async oncreate() {
async oncreate () {
let { accountId } = this.get()
await updatePinnedStatusesForAccount(accountId)
},

View File

@ -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.

View File

@ -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) {

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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()

View File

@ -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()

View File

@ -29,7 +29,7 @@
import PinnedStatuses from '../../_components/timeline/PinnedStatuses.html'
export default {
oncreate() {
oncreate () {
let { params } = this.get()
let { accountId } = params
clearProfileAndRelationship()

View File

@ -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>

View File

@ -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>

View File

@ -22,5 +22,5 @@
HiddenFromSSR,
TimelinePage
}
};
}
</script>

View File

@ -37,7 +37,7 @@
import { updateVerifyCredentialsForInstance } from '.././_actions/instances'
export default {
async oncreate() {
async oncreate () {
try {
let { currentInstance } = this.store.get()
await updateVerifyCredentialsForInstance(currentInstance)

View File

@ -27,5 +27,5 @@
data: () => ({
version
})
};
}
</script>

View File

@ -42,5 +42,5 @@
SettingsLayout
},
store: () => store
};
}
</script>

View File

@ -19,5 +19,5 @@
SettingsList,
SettingsListItem
}
};
}
</script>

View File

@ -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)
}
})

View File

@ -75,7 +75,7 @@
},
store: () => store,
methods: {
onSubmit(event) {
onSubmit (event) {
event.preventDefault()
logInToInstance()
}