refactor: eslint config

This commit is contained in:
liwei 2020-06-06 21:19:53 +08:00
parent 558a56bad5
commit 60711fa74b
5 changed files with 421 additions and 209 deletions

198
frontend/.eslintrc.js Normal file
View File

@ -0,0 +1,198 @@
module.exports = {
root: true,
parserOptions: {
parser: 'babel-eslint',
sourceType: 'module'
},
env: {
browser: true,
node: true,
es6: true,
},
extends: ['plugin:vue/recommended', 'eslint:recommended'],
// add your custom rules here
//it is base on https://github.com/vuejs/eslint-config-vue
rules: {
"vue/max-attributes-per-line": [2, {
"singleline": 10,
"multiline": {
"max": 1,
"allowFirstLine": false
}
}],
"vue/singleline-html-element-content-newline": "off",
"vue/multiline-html-element-content-newline":"off",
"vue/name-property-casing": ["error", "PascalCase"],
"vue/no-v-html": "off",
'accessor-pairs': 2,
'arrow-spacing': [2, {
'before': true,
'after': true
}],
'block-spacing': [2, 'always'],
'brace-style': [2, '1tbs', {
'allowSingleLine': true
}],
'camelcase': [0, {
'properties': 'always'
}],
'comma-dangle': [2, 'never'],
'comma-spacing': [2, {
'before': false,
'after': true
}],
'comma-style': [2, 'last'],
'constructor-super': 2,
'curly': [2, 'multi-line'],
'dot-location': [2, 'property'],
'eol-last': 2,
'eqeqeq': ["error", "always", {"null": "ignore"}],
'generator-star-spacing': [2, {
'before': true,
'after': true
}],
'handle-callback-err': [2, '^(err|error)$'],
'indent': [2, 2, {
'SwitchCase': 1
}],
'jsx-quotes': [2, 'prefer-single'],
'key-spacing': [2, {
'beforeColon': false,
'afterColon': true
}],
'keyword-spacing': [2, {
'before': true,
'after': true
}],
'new-cap': [2, {
'newIsCap': true,
'capIsNew': false
}],
'new-parens': 2,
'no-array-constructor': 2,
'no-caller': 2,
'no-console': 'off',
'no-class-assign': 2,
'no-cond-assign': 2,
'no-const-assign': 2,
'no-control-regex': 0,
'no-delete-var': 2,
'no-dupe-args': 2,
'no-dupe-class-members': 2,
'no-dupe-keys': 2,
'no-duplicate-case': 2,
'no-empty-character-class': 2,
'no-empty-pattern': 2,
'no-eval': 2,
'no-ex-assign': 2,
'no-extend-native': 2,
'no-extra-bind': 2,
'no-extra-boolean-cast': 2,
'no-extra-parens': [2, 'functions'],
'no-fallthrough': 2,
'no-floating-decimal': 2,
'no-func-assign': 2,
'no-implied-eval': 2,
'no-inner-declarations': [2, 'functions'],
'no-invalid-regexp': 2,
'no-irregular-whitespace': 2,
'no-iterator': 2,
'no-label-var': 2,
'no-labels': [2, {
'allowLoop': false,
'allowSwitch': false
}],
'no-lone-blocks': 2,
'no-mixed-spaces-and-tabs': 2,
'no-multi-spaces': 2,
'no-multi-str': 2,
'no-multiple-empty-lines': [2, {
'max': 1
}],
'no-native-reassign': 2,
'no-negated-in-lhs': 2,
'no-new-object': 2,
'no-new-require': 2,
'no-new-symbol': 2,
'no-new-wrappers': 2,
'no-obj-calls': 2,
'no-octal': 2,
'no-octal-escape': 2,
'no-path-concat': 2,
'no-proto': 2,
'no-redeclare': 2,
'no-regex-spaces': 2,
'no-return-assign': [2, 'except-parens'],
'no-self-assign': 2,
'no-self-compare': 2,
'no-sequences': 2,
'no-shadow-restricted-names': 2,
'no-spaced-func': 2,
'no-sparse-arrays': 2,
'no-this-before-super': 2,
'no-throw-literal': 2,
'no-trailing-spaces': 2,
'no-undef': 2,
'no-undef-init': 2,
'no-unexpected-multiline': 2,
'no-unmodified-loop-condition': 2,
'no-unneeded-ternary': [2, {
'defaultAssignment': false
}],
'no-unreachable': 2,
'no-unsafe-finally': 2,
'no-unused-vars': [2, {
'vars': 'all',
'args': 'none'
}],
'no-useless-call': 2,
'no-useless-computed-key': 2,
'no-useless-constructor': 2,
'no-useless-escape': 0,
'no-whitespace-before-property': 2,
'no-with': 2,
'one-var': [2, {
'initialized': 'never'
}],
'operator-linebreak': [2, 'after', {
'overrides': {
'?': 'before',
':': 'before'
}
}],
'padded-blocks': [2, 'never'],
'quotes': [2, 'single', {
'avoidEscape': true,
'allowTemplateLiterals': true
}],
'semi': [2, 'never'],
'semi-spacing': [2, {
'before': false,
'after': true
}],
'space-before-blocks': [2, 'always'],
'space-before-function-paren': [2, 'never'],
'space-in-parens': [2, 'never'],
'space-infix-ops': 2,
'space-unary-ops': [2, {
'words': true,
'nonwords': false
}],
'spaced-comment': [2, 'always', {
'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
}],
'template-curly-spacing': [2, 'never'],
'use-isnan': 2,
'valid-typeof': 2,
'wrap-iife': [2, 'any'],
'yield-star-spacing': [2, 'both'],
'yoda': [2, 'never'],
'prefer-const': 2,
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
'object-curly-spacing': [2, 'always', {
objectsInObjects: false
}],
'array-bracket-spacing': [2, 'never']
}
}

View File

@ -4,41 +4,53 @@
<i class="material-icons">sentiment_dissatisfied</i>
<span>{{ $t('files.lonely') }}</span>
</h2>
<input style="display:none" type="file" id="upload-input" @change="uploadInput($event)" multiple>
<input id="upload-input" style="display:none" type="file" multiple @change="uploadInput($event)">
</div>
<div v-else id="listing"
<div
v-else
id="listing"
:class="user.viewMode"
@dragenter="dragEnter"
@dragend="dragEnd">
@dragend="dragEnd"
>
<div>
<div class="item header">
<div></div>
<div />
<div>
<p :class="{ active: nameSorted }" class="name"
<p
:class="{ active: nameSorted }"
class="name"
role="button"
tabindex="0"
@click="sort('name')"
:title="$t('files.sortByName')"
:aria-label="$t('files.sortByName')">
:aria-label="$t('files.sortByName')"
@click="sort('name')"
>
<span>{{ $t('files.name') }}</span>
<i class="material-icons">{{ nameIcon }}</i>
</p>
<p :class="{ active: sizeSorted }" class="size"
<p
:class="{ active: sizeSorted }"
class="size"
role="button"
tabindex="0"
@click="sort('size')"
:title="$t('files.sortBySize')"
:aria-label="$t('files.sortBySize')">
:aria-label="$t('files.sortBySize')"
@click="sort('size')"
>
<span>{{ $t('files.size') }}</span>
<i class="material-icons">{{ sizeIcon }}</i>
</p>
<p :class="{ active: modifiedSorted }" class="modified"
<p
:class="{ active: modifiedSorted }"
class="modified"
role="button"
tabindex="0"
@click="sort('modified')"
:title="$t('files.sortByLastModified')"
:aria-label="$t('files.sortByLastModified')">
:aria-label="$t('files.sortByLastModified')"
@click="sort('modified')"
>
<span>{{ $t('files.lastModified') }}</span>
<i class="material-icons">{{ modifiedIcon }}</i>
</p>
@ -48,37 +60,39 @@
<h2 v-if="req.numDirs > 0">{{ $t('files.folders') }}</h2>
<div v-if="req.numDirs > 0">
<item v-for="(item) in dirs"
<item
v-for="(item) in dirs"
:key="base64(item.name)"
v-bind:index="item.index"
v-bind:name="item.name"
v-bind:isDir="item.isDir"
v-bind:url="item.url"
v-bind:modified="item.modified"
v-bind:type="item.type"
v-bind:size="item.size">
</item>
:index="item.index"
:name="item.name"
:is-dir="item.isDir"
:url="item.url"
:modified="item.modified"
:type="item.type"
:size="item.size"
/>
</div>
<h2 v-if="req.numFiles > 0">{{ $t('files.files') }}</h2>
<div v-if="req.numFiles > 0">
<item v-for="(item) in files"
<item
v-for="(item) in files"
:key="base64(item.name)"
v-bind:index="item.index"
v-bind:name="item.name"
v-bind:isDir="item.isDir"
v-bind:url="item.url"
v-bind:modified="item.modified"
v-bind:type="item.type"
v-bind:size="item.size">
</item>
:index="item.index"
:name="item.name"
:is-dir="item.isDir"
:url="item.url"
:modified="item.modified"
:type="item.type"
:size="item.size"
/>
</div>
<input style="display:none" type="file" id="upload-input" @change="uploadInput($event)" multiple>
<input id="upload-input" style="display:none" type="file" multiple @change="uploadInput($event)">
<div :class="{ active: $store.state.multiple }" id="multiple-selection">
<div id="multiple-selection" :class="{ active: $store.state.multiple }">
<p>{{ $t('files.multipleSelectionEnabled') }}</p>
<div @click="$store.commit('multiple', false)" tabindex="0" role="button" :title="$t('files.clear')" :aria-label="$t('files.clear')" class="action">
<div tabindex="0" role="button" :title="$t('files.clear')" :aria-label="$t('files.clear')" class="action" @click="$store.commit('multiple', false)">
<i class="material-icons">clear</i>
</div>
</div>
@ -94,7 +108,7 @@ import buttons from '@/utils/buttons'
import url from '@/utils/url'
export default {
name: 'listing',
name: 'Listing',
components: { Item },
data: function() {
return {
@ -190,7 +204,7 @@ export default {
return
}
let key = String.fromCharCode(event.which).toLowerCase()
const key = String.fromCharCode(event.which).toLowerCase()
switch (key) {
case 'f':
@ -215,16 +229,16 @@ export default {
return
}
let items = []
const items = []
for (let i of this.selected) {
for (const i of this.selected) {
items.push({
from: this.req.items[i].url,
name: encodeURIComponent(this.req.items[i].name)
})
}
if (items.length == 0) {
if (items.length === 0) {
return
}
@ -238,9 +252,9 @@ export default {
return
}
let items = []
const items = []
for (let item of this.$store.state.clipboard.items) {
for (const item of this.$store.state.clipboard.items) {
const from = item.from.endsWith('/') ? item.from.slice(0, -1) : item.from
const to = this.$route.path + item.name
items.push({ from, to })
@ -264,7 +278,7 @@ export default {
resizeEvent() {
// Update the columns size based on the window width.
let columns = Math.floor(document.querySelector('main').offsetWidth / 300)
let items = css(['#listing.mosaic .item', '.mosaic#listing .item'])
const items = css(['#listing.mosaic .item', '.mosaic#listing .item'])
if (columns === 0) columns = 1
items.style.width = `calc(${100 / columns}% - 1em)`
},
@ -276,7 +290,7 @@ export default {
dragEnter() {
// When the user starts dragging an item, put every
// file on the listing with 50% opacity.
let items = document.getElementsByClassName('item')
const items = document.getElementsByClassName('item')
Array.from(items).forEach(file => {
file.style.opacity = 0.5
@ -289,8 +303,8 @@ export default {
event.preventDefault()
this.resetOpacity()
let dt = event.dataTransfer
let files = dt.files
const dt = event.dataTransfer
const files = dt.files
let el = event.target
if (files.length <= 0) return
@ -325,7 +339,7 @@ export default {
let conflict = false
for (let i = 0; i < files.length; i++) {
let res = items.findIndex(function hasConflict (element) {
const res = items.findIndex(function hasConflict(element) {
return (element.name === this)
}, files[i].name)
@ -353,7 +367,7 @@ export default {
this.checkConflict(event.currentTarget.files, this.req.items, '')
},
resetOpacity() {
let items = document.getElementsByClassName('item')
const items = document.getElementsByClassName('item')
Array.from(items).forEach(file => {
file.style.opacity = 1
@ -361,10 +375,10 @@ export default {
},
handleFiles(files, base, overwrite = false) {
buttons.loading('upload')
let promises = []
let progress = new Array(files.length).fill(0)
const promises = []
const progress = new Array(files.length).fill(0)
let onupload = (id) => (event) => {
const onupload = (id) => (event) => {
progress[id] = (event.loaded / event.total) * 100
let sum = 0
@ -376,12 +390,12 @@ export default {
}
for (let i = 0; i < files.length; i++) {
let file = files[i]
let filenameEncoded = url.encodeRFC5987ValueChars(file.name)
const file = files[i]
const filenameEncoded = url.encodeRFC5987ValueChars(file.name)
promises.push(api.post(this.$route.path + base + filenameEncoded, file, overwrite, onupload(i)))
}
let finish = () => {
const finish = () => {
buttons.success('upload')
this.$store.commit('setProgress', 0)
}

View File

@ -4,18 +4,18 @@
role="button"
tabindex="0"
draggable="true"
:data-dir="isDir"
:aria-label="name"
:aria-selected="isSelected"
@dragstart="dragStart"
@dragover="dragOver"
@drop="drop"
@click="click"
@dblclick="open"
@touchstart="touchstart"
:data-dir="isDir"
:aria-label="name"
:aria-selected="isSelected"
>
<div>
<img v-if="type==='image'" :src="compressUrl" />
<img v-if="type==='image'" :src="compressUrl">
<i v-else class="material-icons">{{ icon }}</i>
<!-- <i class="material-icons">{{ icon }}</i> -->
</div>
@ -34,146 +34,146 @@
</template>
<script>
import { mapMutations, mapGetters, mapState } from "vuex";
import { baseURL } from "@/utils/constants";
import filesize from "filesize";
import moment from "moment";
import { files as api } from "@/api";
import { mapMutations, mapGetters, mapState } from 'vuex'
import { baseURL } from '@/utils/constants'
import filesize from 'filesize'
import moment from 'moment'
import { files as api } from '@/api'
export default {
name: "item",
name: 'Item',
props: ['name', 'isDir', 'url', 'type', 'size', 'modified', 'index'],
data: function() {
return {
touches: 0
};
}
},
props: ["name", "isDir", "url", "type", "size", "modified", "index"],
computed: {
...mapState(["selected", "req", "jwt"]),
...mapGetters(["selectedCount"]),
...mapState(['selected', 'req', 'jwt']),
...mapGetters(['selectedCount']),
isSelected() {
return this.selected.indexOf(this.index) !== -1;
return this.selected.indexOf(this.index) !== -1
},
icon() {
if (this.isDir) return "folder";
if (this.type === "image") return "insert_photo";
if (this.type === "audio") return "volume_up";
if (this.type === "video") return "movie";
return "insert_drive_file";
if (this.isDir) return 'folder'
if (this.type === 'image') return 'insert_photo'
if (this.type === 'audio') return 'volume_up'
if (this.type === 'video') return 'movie'
return 'insert_drive_file'
},
canDrop() {
if (!this.isDir) return false;
if (!this.isDir) return false
for (let i of this.selected) {
for (const i of this.selected) {
if (this.req.items[i].url === this.url) {
return false;
return false
}
}
return true;
return true
},
compressUrl() {
const path = this.url.replace(/^\/files\//, "");
return `${baseURL}/api/compress/${path}?auth=${this.jwt}&inline=true`;
const path = this.url.replace(/^\/files\//, '')
return `${baseURL}/api/compress/${path}?auth=${this.jwt}&inline=true`
}
},
methods: {
...mapMutations(["addSelected", "removeSelected", "resetSelected"]),
...mapMutations(['addSelected', 'removeSelected', 'resetSelected']),
humanSize: function() {
return filesize(this.size);
return filesize(this.size)
},
humanTime: function() {
return moment(this.modified).fromNow();
return moment(this.modified).fromNow()
},
dragStart: function() {
if (this.selectedCount === 0) {
this.addSelected(this.index);
return;
this.addSelected(this.index)
return
}
if (!this.isSelected) {
this.resetSelected();
this.addSelected(this.index);
this.resetSelected()
this.addSelected(this.index)
}
},
dragOver: function(event) {
if (!this.canDrop) return;
if (!this.canDrop) return
event.preventDefault();
let el = event.target;
event.preventDefault()
let el = event.target
for (let i = 0; i < 5; i++) {
if (!el.classList.contains("item")) {
el = el.parentElement;
if (!el.classList.contains('item')) {
el = el.parentElement
}
}
el.style.opacity = 1;
el.style.opacity = 1
},
drop: function(event) {
if (!this.canDrop) return;
event.preventDefault();
if (!this.canDrop) return
event.preventDefault()
if (this.selectedCount === 0) return;
if (this.selectedCount === 0) return
let items = [];
const items = []
for (let i of this.selected) {
for (const i of this.selected) {
items.push({
from: this.req.items[i].url,
to: this.url + this.req.items[i].name
});
})
}
api
.move(items)
.then(() => {
this.$store.commit("setReload", true);
this.$store.commit('setReload', true)
})
.catch(this.$showError);
.catch(this.$showError)
},
click: function(event) {
if (this.selectedCount !== 0) event.preventDefault();
if (this.selectedCount !== 0) event.preventDefault()
if (this.$store.state.selected.indexOf(this.index) !== -1) {
this.removeSelected(this.index);
return;
this.removeSelected(this.index)
return
}
if (event.shiftKey) {
let fi = 0;
let la = 0;
let fi = 0
let la = 0
if (this.index > this.selected[0]) {
fi = this.selected[0] + 1;
la = this.index;
fi = this.selected[0] + 1
la = this.index
} else {
fi = this.index;
la = this.selected[0] - 1;
fi = this.index
la = this.selected[0] - 1
}
for (; fi <= la; fi++) {
this.addSelected(fi);
this.addSelected(fi)
}
return;
return
}
if (!event.ctrlKey && !this.$store.state.multiple) this.resetSelected();
this.addSelected(this.index);
if (!event.ctrlKey && !this.$store.state.multiple) this.resetSelected()
this.addSelected(this.index)
},
touchstart() {
setTimeout(() => {
this.touches = 0;
}, 300);
this.touches = 0
}, 300)
this.touches++;
this.touches++
if (this.touches > 1) {
this.open();
this.open()
}
},
open: function() {
this.$router.push({ path: this.url });
this.$router.push({ path: this.url })
}
}
}
};
</script>

View File

@ -2,57 +2,57 @@
<div id="previewer">
<div class="bar">
<button
@click="back"
id="close"
class="action"
:title="$t('files.closePreview')"
:aria-label="$t('files.closePreview')"
id="close"
@click="back"
>
<i class="material-icons">close</i>
</button>
<rename-button v-if="user.perm.rename"></rename-button>
<delete-button v-if="user.perm.delete"></delete-button>
<download-button v-if="user.perm.download"></download-button>
<info-button></info-button>
<rename-button v-if="user.perm.rename" />
<delete-button v-if="user.perm.delete" />
<download-button v-if="user.perm.download" />
<info-button />
</div>
<button
class="action"
@click="prev"
v-show="hasPrevious"
class="action"
:aria-label="$t('buttons.previous')"
:title="$t('buttons.previous')"
@click="prev"
>
<i class="material-icons">chevron_left</i>
</button>
<button
class="action"
@click="next"
v-show="hasNext"
class="action"
:aria-label="$t('buttons.next')"
:title="$t('buttons.next')"
@click="next"
>
<i class="material-icons">chevron_right</i>
</button>
<div class="preview">
<ExtendedImage v-if="req.type == 'image'" :src="raw"></ExtendedImage>
<audio v-else-if="req.type == 'audio'" :src="raw" autoplay controls></audio>
<ExtendedImage v-if="req.type == 'image'" :src="raw" />
<audio v-else-if="req.type == 'audio'" :src="raw" autoplay controls />
<video v-else-if="req.type == 'video'" :src="raw" autoplay controls>
<track
kind="captions"
v-for="(sub, index) in subtitles"
:key="index"
kind="captions"
:src="sub"
:label="'Subtitle ' + index"
:default="index === 0"
/>Sorry, your browser doesn't support embedded videos,
>Sorry, your browser doesn't support embedded videos,
but don't worry, you can
<a :href="download">download it</a>
and watch it with your favorite video player!
</video>
<object v-else-if="req.extension == '.pdf'" class="pdf" :data="raw"></object>
<object v-else-if="req.extension == '.pdf'" class="pdf" :data="raw" />
<a v-else-if="req.type == 'blob'" :href="download">
<h2 class="message">
{{ $t('buttons.download') }}
@ -64,20 +64,20 @@
</template>
<script>
import { mapState } from "vuex";
import url from "@/utils/url";
import { baseURL } from "@/utils/constants";
import { files as api } from "@/api";
import InfoButton from "@/components/buttons/Info";
import DeleteButton from "@/components/buttons/Delete";
import RenameButton from "@/components/buttons/Rename";
import DownloadButton from "@/components/buttons/Download";
import ExtendedImage from "./ExtendedImage";
import { mapState } from 'vuex'
import url from '@/utils/url'
import { baseURL } from '@/utils/constants'
import { files as api } from '@/api'
import InfoButton from '@/components/buttons/Info'
import DeleteButton from '@/components/buttons/Delete'
import RenameButton from '@/components/buttons/Rename'
import DownloadButton from '@/components/buttons/Download'
import ExtendedImage from './ExtendedImage'
const mediaTypes = ["image", "video", "audio", "blob"];
const mediaTypes = ['image', 'video', 'audio', 'blob']
export default {
name: "preview",
name: 'Preview',
components: {
InfoButton,
DeleteButton,
@ -87,103 +87,103 @@ export default {
},
data: function() {
return {
previousLink: "",
nextLink: "",
previousLink: '',
nextLink: '',
listing: null,
subtitles: []
};
}
},
computed: {
...mapState(["req", "user", "oldReq", "jwt"]),
...mapState(['req', 'user', 'oldReq', 'jwt']),
hasPrevious() {
return this.previousLink !== "";
return this.previousLink !== ''
},
hasNext() {
return this.nextLink !== "";
return this.nextLink !== ''
},
download() {
return `${baseURL}/api/raw${this.req.path}?auth=${this.jwt}`;
return `${baseURL}/api/raw${this.req.path}?auth=${this.jwt}`
},
compress() {
if (this.req.type === 'image') {
return `${baseURL}/api/compress${this.req.path}?auth=${this.jwt}`;
return `${baseURL}/api/compress${this.req.path}?auth=${this.jwt}`
} else {
return `${baseURL}/api/raw${this.req.path}?auth=${this.jwt}`;
return `${baseURL}/api/raw${this.req.path}?auth=${this.jwt}`
}
},
raw() {
return `${this.compress}&inline=true`;
return `${this.compress}&inline=true`
}
},
async mounted() {
window.addEventListener("keyup", this.key);
window.addEventListener('keyup', this.key)
if (this.req.subtitles) {
this.subtitles = this.req.subtitles.map(
sub => `${baseURL}/api/raw${sub}?auth=${this.jwt}&inline=true`
);
)
}
try {
if (this.oldReq.items) {
this.updateLinks(this.oldReq.items);
this.updateLinks(this.oldReq.items)
} else {
const path = url.removeLastDir(this.$route.path);
const res = await api.fetch(path);
this.updateLinks(res.items);
const path = url.removeLastDir(this.$route.path)
const res = await api.fetch(path)
this.updateLinks(res.items)
}
} catch (e) {
this.$showError(e);
this.$showError(e)
}
},
beforeDestroy() {
window.removeEventListener("keyup", this.key);
window.removeEventListener('keyup', this.key)
},
methods: {
back() {
let uri = url.removeLastDir(this.$route.path) + "/";
this.$router.push({ path: uri });
const uri = url.removeLastDir(this.$route.path) + '/'
this.$router.push({ path: uri })
},
prev() {
this.$router.push({ path: this.previousLink });
this.$router.push({ path: this.previousLink })
},
next() {
this.$router.push({ path: this.nextLink });
this.$router.push({ path: this.nextLink })
},
key(event) {
event.preventDefault();
event.preventDefault()
if (event.which === 13 || event.which === 39) {
// right arrow
if (this.hasNext) this.next();
if (this.hasNext) this.next()
} else if (event.which === 37) {
// left arrow
if (this.hasPrevious) this.prev();
if (this.hasPrevious) this.prev()
}
},
updateLinks(items) {
for (let i = 0; i < items.length; i++) {
if (items[i].name !== this.req.name) {
continue;
continue
}
for (let j = i - 1; j >= 0; j--) {
if (mediaTypes.includes(items[j].type)) {
this.previousLink = items[j].url;
break;
this.previousLink = items[j].url
break
}
}
for (let j = i + 1; j < items.length; j++) {
if (mediaTypes.includes(items[j].type)) {
this.nextLink = items[j].url;
break;
this.nextLink = items[j].url
break
}
}
return;
return
}
}
}
}
};
</script>