Fix linter, fix files by linter rules.

Fix backup file.
This commit is contained in:
2019-03-17 11:20:24 +07:00
parent 056e31d218
commit b611c49904
35 changed files with 957 additions and 812 deletions

View File

@@ -1,27 +1,39 @@
module.exports = { module.exports = {
root: true, root: true,
env: { env: {
node: true node: true
}, },
'extends': [ parserOptions: {
'plugin:vue/essential', parser: 'babel-eslint',
'eslint:recommended', sourceType: 'module',
'airbnb' },
], plugins: [
rules: { 'vue'
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', ],
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', extends: [
'indent': ['error', 4, { 'SwitchCase': 1 }], 'plugin:vue/essential',
'max-len': ['error', { 'code': 120 }], 'eslint:recommended',
'class-methods-use-this': 'off', ],
'object-curly-newline': ['error', { 'consistent': true }], rules: {
'comma-dangle': ['error', { 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'functions': 'never', 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'arrays': 'always-multiline', 'indent': ['error', 4, { 'SwitchCase': 1 }],
'objects': 'always-multiline' 'max-len': ['error', { 'code': 120 }],
}] 'class-methods-use-this': 'off',
}, 'object-curly-newline': ['error', { 'consistent': true }],
parserOptions: { 'comma-dangle': ['error', {
parser: 'babel-eslint' 'functions': 'never',
} 'arrays': 'always-multiline',
} 'objects': 'always-multiline'
}],
'import/extensions': false,
},
settings: {
'import/resolver': {
node: {
extensions: ['.js', '.jsx', '.vue'],
},
},
},
};

View File

@@ -57,16 +57,6 @@
"id": "bsdasdad123", "id": "bsdasdad123",
"title": "kapitel 1", "title": "kapitel 1",
"youtubeId": "bsdasdad1" "youtubeId": "bsdasdad1"
},
{
"id": "bsdasdad124",
"title": "kapitel 2",
"youtubeId": "bsdasdad2"
},
{
"id": "bsdasdad125",
"title": "kapitel 3",
"youtubeId": "bsdasdad3"
} }
], ],
"description": "Третья глава первой книги о Гарри Поттере", "description": "Третья глава первой книги о Гарри Поттере",
@@ -151,7 +141,7 @@
}, },
"articlePartId": "k2", "articlePartId": "k2",
"youtubeId": "hHW1oY26kxQ", "youtubeId": "hHW1oY26kxQ",
"articleTitle": "Harry Potter und Stein der Weisen - 2", "articleTitle": "Harry Potter und Stein der Weisen - 1",
"__collections__": {} "__collections__": {}
}, },
"hp1k3": { "hp1k3": {
@@ -170,7 +160,26 @@
"words": {}, "words": {},
"articlePartId": "k3", "articlePartId": "k3",
"youtubeId": "hHW1oY26kxQ", "youtubeId": "hHW1oY26kxQ",
"articleTitle": "Harry Potter und Stein der Weisen - 3", "articleTitle": "Harry Potter und Stein der Weisen - 1",
"__collections__": {}
},
"hp2k1": {
"content": [
{
"sentences": [
{
"origText": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"transText": "Бла21-бла-бла"
}
]
}
],
"articleId": "hp2",
"partTitle": "kapitel 1",
"words": {},
"articlePartId": "k1",
"youtubeId": "hHW1oY26kxQ",
"articleTitle": "Harry Potter und Stein der Weisen - 2",
"__collections__": {} "__collections__": {}
} }
} }

View File

@@ -28,7 +28,8 @@
"@vue/cli-service": "^3.4.0", "@vue/cli-service": "^3.4.0",
"babel-eslint": "^10.0.1", "babel-eslint": "^10.0.1",
"eslint": "^5.8.0", "eslint": "^5.8.0",
"eslint-config-airbnb": "^17.1.0", "eslint-config-airbnb-base": "^13.1.0",
"eslint-plugin-import": "^2.16.0",
"eslint-plugin-jsx-a11y": "^6.2.1", "eslint-plugin-jsx-a11y": "^6.2.1",
"eslint-plugin-vue": "^5.0.0", "eslint-plugin-vue": "^5.0.0",
"stylus": "^0.54.5", "stylus": "^0.54.5",

View File

@@ -1,23 +1,23 @@
<template> <template>
<v-app> <v-app>
<app-header></app-header> <app-header></app-header>
<v-content> <v-content>
<router-view /> <router-view />
</v-content> </v-content>
<app-footer></app-footer> <app-footer></app-footer>
</v-app> </v-app>
</template> </template>
<script> <script>
import AppHeader from '@/components/AppHeader'; import AppHeader from '@/components/AppHeader';
import AppFooter from '@/components/AppFooter'; import AppFooter from '@/components/AppFooter';
export default { export default {
components: { components: {
AppHeader, AppHeader,
AppFooter, AppFooter,
} },
}; };
</script> </script>

View File

@@ -10,9 +10,9 @@
<script> <script>
export default { export default {
computed: { computed: {
year: () => new Date().getFullYear(), year: () => new Date().getFullYear(),
}, },
}; };
</script> </script>

View File

@@ -13,7 +13,8 @@
<v-list-tile-title v-text="item.title"></v-list-tile-title> <v-list-tile-title v-text="item.title"></v-list-tile-title>
</v-list-tile-content> </v-list-tile-content>
</v-list-tile> </v-list-tile>
<v-list-tile @click.prevent="signOut" v-if="isUserAuthentificated">
<v-list-tile @click.prevent="signOut" v-if="isUserAuthenticated">
<v-list-tile-action> <v-list-tile-action>
<v-icon left v-html="'exit_to_app'"></v-icon> <v-icon left v-html="'exit_to_app'"></v-icon>
</v-list-tile-action> </v-list-tile-action>
@@ -24,7 +25,7 @@
</v-list> </v-list>
</v-navigation-drawer> </v-navigation-drawer>
<v-toolbar app dark class="primary"> <v-toolbar app dark class="primary">
<v-toolbar-side-icon @click.stop="drawer = !drawer;" class="hidden-md-and-up"></v-toolbar-side-icon> <v-toolbar-side-icon @click.stop="drawer = !drawer" class="hidden-md-and-up"></v-toolbar-side-icon>
<router-link to="/" tag="span" style="cursor: pointer;"> <router-link to="/" tag="span" style="cursor: pointer;">
<v-toolbar-title v-text="'Dannc Ich Lerne Deutsch'"></v-toolbar-title> <v-toolbar-title v-text="'Dannc Ich Lerne Deutsch'"></v-toolbar-title>
</router-link> </router-link>
@@ -32,9 +33,9 @@
<v-toolbar-items class="hidden-sm-and-down"> <v-toolbar-items class="hidden-sm-and-down">
<v-btn v-for="(item, i) in menuItems" flat :key="`menuitem-${i}`" :to="item.route"> <v-btn v-for="(item, i) in menuItems" flat :key="`menuitem-${i}`" :to="item.route">
<v-icon left v-html="item.icon"></v-icon> <v-icon left v-html="item.icon"></v-icon>
{{item.title}} {{ item.title }}
</v-btn> </v-btn>
<v-btn flat @click.prevent="signOut" v-if="isUserAuthentificated"> <v-btn flat @click.prevent="signOut" v-if="isUserAuthenticated">
<v-icon left v-html="'exit_to_app'"></v-icon> <v-icon left v-html="'exit_to_app'"></v-icon>
Выйти Выйти
</v-btn> </v-btn>
@@ -44,49 +45,30 @@
</template> </template>
<script> <script>
export default { export default {
data() { data() {
return { return {
drawer: false, drawer: false,
}; };
}, },
methods: { methods: {
signOut() { signOut() {
this.$confirm('Вы точно хотите выйти?').then(res => { this.$confirm('Вы точно хотите выйти?').then(res => {
if (res) { if (res) {
this.$store.dispatch('signOut'); this.$store.dispatch('signOut');
}
});
},
changeLocation(to) {
this.$router.push(to);
}
},
computed: {
isUserAuthentificated() {
return this.$store.getters.isUserAuthentificated;
},
menuItems() {
if (this.isUserAuthentificated) {
return [
{
icon: 'visibility',
title: 'Статьи',
route: '/articles',
},
{
icon: 'extension',
title: 'Учить слова',
route: '/words',
},
{
icon: 'account_circle',
title: 'Мой профиль',
route: '/profile',
},
];
} }
});
},
changeLocation(to) {
this.$router.push(to);
},
},
computed: {
isUserAuthenticated() {
return this.$store.getters.isUserAuthenticated;
},
menuItems() {
if (this.isUserAuthenticated) {
return [ return [
{ {
icon: 'visibility', icon: 'visibility',
@@ -94,19 +76,38 @@
route: '/articles', route: '/articles',
}, },
{ {
icon: 'input', icon: 'extension',
title: 'Войти', title: 'Учить слова',
route: '/sign_in', route: '/words',
}, },
{ {
icon: 'lock_open', icon: 'account_circle',
title: 'Регистрация', title: 'Мой профиль',
route: '/sign_up', route: '/profile',
}, },
]; ];
}, }
return [
{
icon: 'visibility',
title: 'Статьи',
route: '/articles',
},
{
icon: 'input',
title: 'Войти',
route: '/sign_in',
},
{
icon: 'lock_open',
title: 'Регистрация',
route: '/sign_up',
},
];
}, },
}; },
};
</script> </script>
<style scoped> <style scoped>

View File

@@ -36,13 +36,25 @@
<v-layout row> <v-layout row>
<v-flex xs12> <v-flex xs12>
<v-card-actions> <v-card-actions>
<!-- <v-rating v-model="article.rating" color="yellow" readonly dense half-increments></v-rating> <!-- <v-rating
v-model="article.rating"
color="yellow"
readonly
dense
half-increments
>
</v-rating>
<div class="ml-1"> <div class="ml-1">
<span>{{ article.rating }}</span> <span>{{ article.rating }}</span>
<span>({{ article.ratingsCount }})</span> <span>({{ article.ratingsCount }})</span>
</div> --> </div> -->
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn v-if="!expandDetails" class="primary" flat :to="{ name: 'article', params: { articleId: article.id } }"> <v-btn
v-if="!expandDetails"
:to="{ name: 'article', params: { articleId: article.id } }"
class="primary"
flat
>
Открыть Открыть
</v-btn> </v-btn>
<v-btn v-if="expandDetails && canAddArticle(article.id)" <v-btn v-if="expandDetails && canAddArticle(article.id)"
@@ -64,48 +76,48 @@
</template> </template>
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import YoutubeButton from '@/components/Article/YoutubeButton'; import YoutubeButton from '@/components/Article/YoutubeButton';
import { getArticleLevel, declOfNum } from '@/utils'; import { getArticleLevel, declOfNum } from '@/utils';
export default { export default {
props: { props: {
article: { article: {
type: Object, type: Object,
required: true, required: true,
},
expandDetails: {
type: Boolean,
default: false,
},
}, },
computed: { expandDetails: {
partsDescription() { type: Boolean,
const partsCount = this.article.parts.length; default: false,
const partsCountWord = declOfNum(partsCount, ['часть', 'части', 'частей']);
return `${partsCount} ${partsCountWord}`;
},
...mapGetters(['isUserAuthentificated', 'getProcessing', 'userData']),
}, },
methods: { },
getArticleLevel, computed: {
getUserDataArticle(articleId) { partsDescription() {
return this.userData.articles[articleId]; const partsCount = this.article.parts.length;
}, const partsCountWord = declOfNum(partsCount, ['часть', 'части', 'частей']);
canAddArticle(articleId) { return `${partsCount} ${partsCountWord}`;
const article = this.getUserDataArticle(articleId);
return this.isUserAuthentificated && !this.getProcessing && !article;
},
addArticle(articleId) {
this.$store.dispatch('addUserArticle', articleId);
},
getArticleAddedAt(articleId) {
const article = this.getUserDataArticle(articleId);
return article.addedAt;
}
}, },
components: { ...mapGetters(['isUserAuthenticated', 'getProcessing', 'userData']),
YoutubeButton, },
methods: {
getArticleLevel,
getUserDataArticle(articleId) {
return this.userData.articles[articleId];
}, },
}; canAddArticle(articleId) {
const article = this.getUserDataArticle(articleId);
return this.isUserAuthenticated && !this.getProcessing && !article;
},
addArticle(articleId) {
this.$store.dispatch('addUserArticle', articleId);
},
getArticleAddedAt(articleId) {
const article = this.getUserDataArticle(articleId);
return article.addedAt;
},
},
components: {
YoutubeButton,
},
};
</script> </script>

View File

@@ -38,12 +38,20 @@
<v-tab-item :key="'german'"> <v-tab-item :key="'german'">
<div v-for="(paragraph, i) in part.content" :key="`paragraph1-${i}`"> <div v-for="(paragraph, i) in part.content" :key="`paragraph1-${i}`">
<span>&nbsp;&nbsp;</span> <span>&nbsp;&nbsp;</span>
<span v-for="(sentence, y) in paragraph.sentences" :key="`paragraph1-sentence${y}`" :style="textStyle"> <span
v-for="(sentence, y) in paragraph.sentences"
:key="`paragraph1-sentence${y}`"
:style="textStyle"
>
<span> <span>
{{ sentence.origText }} {{ sentence.origText }}
</span> </span>
<v-icon :size="fontSize" @click.prevent="toggleVisibility(i, y)">help</v-icon> <v-icon :size="fontSize" @click.prevent="toggleVisibility(i, y)">help</v-icon>
<span class="success--text" style="font-weight:bold;" v-if="getVisibilityFlag(i, y).value"> <span
v-if="getVisibilityFlag(i, y).value"
class="success--text"
style="font-weight:bold;"
>
{{ sentence.transText }} {{ sentence.transText }}
</span> </span>
</span> </span>
@@ -55,7 +63,11 @@
<v-layout row wrap v-for="(paragraph, i) in part.content" :key="`paragraph2-${i}`"> <v-layout row wrap v-for="(paragraph, i) in part.content" :key="`paragraph2-${i}`">
<v-flex xs6> <v-flex xs6>
<span>&nbsp;&nbsp;</span> <span>&nbsp;&nbsp;</span>
<span v-for="(sentence, y) in paragraph.sentences" :key="`paragraph2-sentence-orig${y}`" :style="textStyle"> <span
v-for="(sentence, y) in paragraph.sentences"
:key="`paragraph2-sentence-orig${y}`"
:style="textStyle"
>
<span> <span>
{{ sentence.origText }} {{ sentence.origText }}
</span> </span>
@@ -64,7 +76,11 @@
<v-flex xs6> <v-flex xs6>
<span>&nbsp;&nbsp;</span> <span>&nbsp;&nbsp;</span>
<span v-for="(sentence, y) in paragraph.sentences" :key="`paragraph2-sentence-trans${y}`" :style="textStyle"> <span
v-for="(sentence, y) in paragraph.sentences"
:key="`paragraph2-sentence-trans${y}`"
:style="textStyle"
>
<span> <span>
{{ sentence.transText }} {{ sentence.transText }}
</span> </span>
@@ -80,61 +96,57 @@
</template> </template>
<script> <script>
export default { export default {
props: { props: {
part: { part: {
type: Object, type: Object,
required: true, required: true,
},
}, },
data: () => ({ },
tabMode: 'german', data: () => ({
visibillityKeys: [], tabMode: 'german',
fontSize: 18, visibilityKeys: [],
}), fontSize: 18,
created() { }),
for (let i = 0; i < this.part.content.length; i++) { created() {
for (let y = 0; y < this.part.content[i].sentences.length; y++) { for (let i = 0; i < this.part.content.length; i++) {
this.visibillityKeys.push({ for (let y = 0; y < this.part.content[i].sentences.length; y++) {
key: `${i}${y}`, this.visibilityKeys.push({
value: false, key: `${i}${y}`,
}); value: false,
} });
} }
},
computed: {
playerWidth() {
if (this.$vuetify.breakpoint.mdAndUp) {
return '640px';
}
return '250px';
},
playerHeight() {
if (this.$vuetify.breakpoint.mdAndUp) {
return '390px';
}
return '190px';
},
textStyle() {
return {
fontSize: `${this.fontSize}px`,
};
},
},
methods: {
getVisibilityFlag(i, y) {
return this.visibillityKeys.find(v => v.key === `${i}${y}`);
},
toggleVisibility(i, y) {
let flag = this.getVisibilityFlag(i, y);
flag.value = !flag.value;
},
} }
}; },
computed: {
playerWidth() {
if (this.$vuetify.breakpoint.mdAndUp) {
return '640px';
}
return '250px';
},
playerHeight() {
if (this.$vuetify.breakpoint.mdAndUp) {
return '390px';
}
return '190px';
},
textStyle() {
return {
fontSize: `${this.fontSize}px`,
};
},
},
methods: {
getVisibilityFlag(i, y) {
return this.visibilityKeys.find(v => v.key === `${i}${y}`);
},
toggleVisibility(i, y) {
let flag = this.getVisibilityFlag(i, y);
flag.value = !flag.value;
},
},
};
</script> </script>
<style>
</style>

View File

@@ -25,38 +25,38 @@
</template> </template>
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
export default { export default {
props: { props: {
part: { part: {
type: Object, type: Object,
required: true, required: true,
},
articleId: {
type: String,
required: true,
},
}, },
computed: { articleId: {
...mapGetters(['isUserAuthentificated', 'getProcessing', 'userData']), type: String,
currentUserArticle() { required: true,
return this.userData.articles[this.articleId];
},
currentUserArticlePart() {
const article = this.currentUserArticle;
return article ? article.parts[this.part.id] : null;
},
isUserArticleAdded() {
return this.isUserAuthentificated && !this.getProcessing && !!this.currentUserArticle;
},
finishedAt() {
const { currentUserArticlePart } = this;
return currentUserArticlePart ? currentUserArticlePart.finishedAt : null;
},
}, },
methods: { },
computed: {
...mapGetters(['isUserAuthenticated', 'getProcessing', 'userData']),
currentUserArticle() {
return this.userData.articles[this.articleId];
}, },
}; currentUserArticlePart() {
const article = this.currentUserArticle;
return article ? article.parts[this.part.id] : null;
},
isUserArticleAdded() {
return this.isUserAuthenticated && !this.getProcessing && !!this.currentUserArticle;
},
finishedAt() {
const { currentUserArticlePart } = this;
return currentUserArticlePart ? currentUserArticlePart.finishedAt : null;
},
},
methods: {
},
};
</script> </script>

View File

@@ -38,53 +38,53 @@
</template> </template>
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { getFullOriginalWord, WORD_TYPES } from '@/utils'; import { getFullOriginalWord, WORD_TYPES } from '@/utils';
export default { export default {
props: { props: {
wordEntity: { wordEntity: {
type: Object, type: Object,
required: true, required: true,
},
}, },
data: () => ({ },
snackbar: { data: () => ({
isEnabled: false, snackbar: {
text: null, isEnabled: false,
}, text: null,
}),
computed: {
...mapGetters(['userData', 'getProcessing']),
isWord() {
return this.wordEntity.type === WORD_TYPES.WORD;
},
isRedewndung() {
return this.wordEntity.type === WORD_TYPES.REDEWNNDUNG;
},
isProcessing() {
return this.getProcessing;
},
}, },
methods: { }),
getFullOriginalWord, computed: {
addWord(entity) { ...mapGetters(['userData', 'getProcessing']),
const userWords = this.userData.words; isWord() {
const wordAdded = userWords[entity.key]; return this.wordEntity.type === WORD_TYPES.WORD;
if (wordAdded) { },
this.snackbar.isEnabled = true; isRedewndung() {
this.snackbar.text = 'Слово уже было добавлено'; return this.wordEntity.type === WORD_TYPES.REDEWNNDUNG;
return; },
} isProcessing() {
return this.getProcessing;
},
},
methods: {
getFullOriginalWord,
addWord(entity) {
const userWords = this.userData.words;
const wordAdded = userWords[entity.key];
if (wordAdded) {
this.snackbar.isEnabled = true;
this.snackbar.text = 'Слово уже было добавлено';
return;
}
if (Object.keys(userWords).length > 100) { if (Object.keys(userWords).length > 100) {
this.snackbar.isEnabled = true; this.snackbar.isEnabled = true;
this.snackbar.text = 'Слишком много добавленных слов'; this.snackbar.text = 'Слишком много добавленных слов';
return; return;
} }
this.$store.dispatch('addUserWord', entity); this.$store.dispatch('addUserWord', entity);
},
}, },
}; },
};
</script> </script>

View File

@@ -21,35 +21,35 @@
</template> </template>
<script> <script>
import WordCard from '@/components/Article/Word/Card'; import WordCard from '@/components/Article/Word/Card';
export default { export default {
props: { props: {
data: { data: {
type: Object, type: Object,
required: true, required: true,
},
}, },
computed: { },
userData() { computed: {
return this.$store.getters.userData; userData() {
}, return this.$store.getters.userData;
words() { },
const words = []; words() {
const words = [];
for (let property in this.data) { for (let property in this.data) {
if (this.data.hasOwnProperty(property)) { if (this.data.hasOwnProperty(property)) {
const word = Object.assign({}, this.data[property], { key: property }); const word = Object.assign({}, this.data[property], { key: property });
words.push(word); words.push(word);
}
} }
}
return words; return words;
},
}, },
components: { },
WordCard, components: {
}, WordCard,
} },
};
</script> </script>

View File

@@ -6,6 +6,6 @@
</template> </template>
<script> <script>
export default { export default {
}; };
</script> </script>

View File

@@ -23,38 +23,40 @@
<script> <script>
import ListItem from '@/components/Article/Details'; import ListItem from '@/components/Article/Details';
export default { export default {
data: () => ({ data: () => ({
levels: ['A1', 'A2', 'B1', 'B2', 'C1', 'C2'], levels: ['A1', 'A2', 'B1', 'B2', 'C1', 'C2'],
searchTerm: null, searchTerm: null,
levelTerm: [], levelTerm: [],
}), }),
computed: { computed: {
articles() { articles() {
return this.$store.getters.getArticles; return this.$store.getters.getArticles;
},
filteredArticles() {
const { articles, searchTerm, levelTerm } = this;
let filteredArticles = articles
if (searchTerm) {
filteredArticles = filteredArticles.filter(article =>
article.title.toLowerCase().indexOf(searchTerm.toLowerCase()) >= 0
|| article.description.toLowerCase().indexOf(searchTerm.toLowerCase()) >= 0
);
}
if (levelTerm.length) {
filteredArticles = filteredArticles.filter(article => levelTerm.filter(val => article.level.indexOf(val) !== -1).length > 0)
}
return filteredArticles;
},
}, },
components: { filteredArticles() {
ListItem, const { articles, searchTerm, levelTerm } = this;
} let filteredArticles = articles;
};
if (searchTerm) {
filteredArticles = filteredArticles.filter(article =>
article.title.toLowerCase().indexOf(searchTerm.toLowerCase()) >= 0
|| article.description.toLowerCase().indexOf(searchTerm.toLowerCase()) >= 0
);
}
if (levelTerm.length) {
filteredArticles = filteredArticles.filter(
article => levelTerm.filter(val => article.level.indexOf(val) !== -1).length > 0
);
}
return filteredArticles;
},
},
components: {
ListItem,
},
};
</script> </script>

View File

@@ -63,7 +63,7 @@
</v-radio-group> </v-radio-group>
<v-text-field <v-text-field
v-if="changeType == 'changeName'" v-if="changeType === 'changeName'"
prepend-icon="person" prepend-icon="person"
v-model="newName" v-model="newName"
name="newName" name="newName"
@@ -75,7 +75,7 @@
</v-text-field> </v-text-field>
<v-text-field <v-text-field
v-if="changeType == 'changeEmail'" v-if="changeType === 'changeEmail'"
prepend-icon="email" prepend-icon="email"
v-model="newEmail" v-model="newEmail"
name="newLogin" name="newLogin"
@@ -87,7 +87,7 @@
</v-text-field> </v-text-field>
<v-text-field <v-text-field
v-if="changeType == 'changePassword'" v-if="changeType === 'changePassword'"
prepend-icon="lock" prepend-icon="lock"
v-model="newPassword" v-model="newPassword"
name="newPassword" name="newPassword"
@@ -119,56 +119,56 @@
</template> </template>
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { emailRules, passwordRules, nameRules, EVENTS } from "@/utils"; import { emailRules, passwordRules, nameRules, EVENTS } from "@/utils";
export default { export default {
data: () => ({ data: () => ({
email: null, email: null,
password: null, password: null,
newEmail: null, newEmail: null,
newPassword: null, newPassword: null,
newName: null, newName: null,
changeType: 'changeName', changeType: 'changeName',
dialog: false, dialog: false,
isValid: false, isValid: false,
emailRules, emailRules,
passwordRules, passwordRules,
nameRules nameRules,
}), }),
computed: { computed: {
...mapGetters(['userName', 'userEmail', 'getProcessing', 'getError']), ...mapGetters(['userName', 'userEmail', 'getProcessing', 'getError']),
}, },
methods: { methods: {
changeUserData() { changeUserData() {
const { const {
email, email,
password, password,
newEmail, newEmail,
newPassword, newPassword,
newName, newName,
changeType, changeType,
} = this; } = this;
this.$store.dispatch('changeUserProfileData', { this.$store.dispatch('changeUserProfileData', {
email, email,
password, password,
newEmail, newEmail,
newPassword, newPassword,
newName, newName,
changeType, changeType,
});
},
},
created() {
this.$bus.$on(EVENTS.USER.DATA_CHANGED, () => {
this.dialog = false;
}); });
}, },
beforeDestroy() { },
this.$bus.$off(EVENTS.USER.DATA_CHANGED); created() {
}, this.$bus.$on(EVENTS.USER.DATA_CHANGED, () => {
}; this.dialog = false;
});
},
beforeDestroy() {
this.$bus.$off(EVENTS.USER.DATA_CHANGED);
},
};
</script> </script>

View File

@@ -4,5 +4,5 @@ export default {
databaseURL: "https://test.firebaseio.com", databaseURL: "https://test.firebaseio.com",
projectId: "test", projectId: "test",
storageBucket: "test.appspot.com", storageBucket: "test.appspot.com",
messagingSenderId: "test" messagingSenderId: "test",
}; };

View File

@@ -24,9 +24,9 @@ Vue.$db = db;
Vue.use(Vuetify); Vue.use(Vuetify);
Vue.use(VuetifyConfirm, { Vue.use(VuetifyConfirm, {
buttonTrueText: 'Да', buttonTrueText: 'Да',
buttonFalseText: 'Нет', buttonFalseText: 'Нет',
width: 400, width: 400,
}); });
Vue.use(VueYouTubeEmbed); Vue.use(VueYouTubeEmbed);
@@ -35,14 +35,14 @@ Vue.filter('formattedDate', formattedDate);
setUpEventBus(); setUpEventBus();
new Vue({ new Vue({
router, router,
store, store,
render: h => h(App), render: h => h(App),
created: function onApplicationCreated() { created: function onApplicationCreated() {
firebase.auth().onAuthStateChanged((user) => { firebase.auth().onAuthStateChanged((user) => {
this.$store.dispatch('stateChanged', user); this.$store.dispatch('stateChanged', user);
}); });
this.$store.dispatch('loadArticles'); this.$store.dispatch('loadArticles');
} },
}).$mount('#app'); }).$mount('#app');

View File

@@ -7,62 +7,62 @@ import Home from '@/views/Home';
Vue.use(Router); Vue.use(Router);
function AuthMiddleware(from, to, next) { function AuthMiddleware(from, to, next) {
if (Store.getters.isUserAuthentificated) { if (Store.getters.isUserAuthenticated) {
next(); next();
} else { } else {
next('/sign_in'); next('/sign_in');
} }
} }
export default new Router({ export default new Router({
routes: [ routes: [
{ {
path: '/', path: '/',
name: 'home', name: 'home',
component: Home component: Home,
}, },
{ {
path: '/articles', path: '/articles',
name: 'articles', name: 'articles',
component: () => import(/* webpackChunkName: "articles/index" */ '@/views/Articles'), component: () => import(/* webpackChunkName: "articles/index" */ '@/views/Articles'),
}, },
{ {
path: '/articles/:articleId', path: '/articles/:articleId',
name: 'article', name: 'article',
props: true, props: true,
component: () => import(/* webpackChunkName: "articles/article" */ '@/views/Article') component: () => import(/* webpackChunkName: "articles/article" */ '@/views/Article'),
}, },
{ {
path: '/articles/:articleId/part/:partId', path: '/articles/:articleId/part/:partId',
name: 'articlePart', name: 'articlePart',
props: true, props: true,
component: () => import(/* webpackChunkName: "articles/article_part" */ '@/views/ArticlePart') component: () => import(/* webpackChunkName: "articles/article_part" */ '@/views/ArticlePart'),
}, },
{ {
path: '/words', path: '/words',
name: 'words', name: 'words',
component: () => import(/* webpackChunkName: "words" */ '@/views/Words'), component: () => import(/* webpackChunkName: "words" */ '@/views/Words'),
}, },
{ {
path: '/profile', path: '/profile',
name: 'profile', name: 'profile',
component: () => import(/* webpackChunkName: "words" */ '@/views/Profile'), component: () => import(/* webpackChunkName: "words" */ '@/views/Profile'),
beforeEnter: AuthMiddleware, beforeEnter: AuthMiddleware,
}, },
{ {
path: '/sign_in', path: '/sign_in',
name: 'signIn', name: 'signIn',
component: () => import(/* webpackChunkName: "sign_in" */ '@/views/SignIn'), component: () => import(/* webpackChunkName: "sign_in" */ '@/views/SignIn'),
}, },
{ {
path: '/sign_up', path: '/sign_up',
name: 'signUp', name: 'signUp',
component: () => import(/* webpackChunkName: "sign_up" */ '@/views/SignUp'), component: () => import(/* webpackChunkName: "sign_up" */ '@/views/SignUp'),
}, },
{ {
path: '*', path: '*',
component: NotFound, component: NotFound,
} },
], ],
mode: 'history', mode: 'history',
}); });

View File

@@ -9,10 +9,10 @@ import userDataModule from '@/store/userData';
Vue.use(Vuex); Vue.use(Vuex);
export default new Vuex.Store({ export default new Vuex.Store({
modules: { modules: {
articleModule, articleModule,
generalModule, generalModule,
userModule, userModule,
userDataModule, userDataModule,
}, },
}); });

View File

@@ -6,7 +6,7 @@ import { EventBus, EVENTS } from '@/utils';
export default { export default {
state: { state: {
user: { user: {
isAuthentificated: false, isAuthenticated: false,
uid: null, uid: null,
email: null, email: null,
name: null, name: null,
@@ -14,12 +14,12 @@ export default {
}, },
mutations: { mutations: {
setUser(state, { uid, email }) { setUser(state, { uid, email }) {
state.user.isAuthentificated = true; state.user.isAuthenticated = true;
state.user.uid = uid; state.user.uid = uid;
state.user.email = email; state.user.email = email;
}, },
unSetUser(state) { unSetUser(state) {
state.user.isAuthentificated = false; state.user.isAuthenticated = false;
state.user.uid = null; state.user.uid = null;
}, },
setUserName(state, name) { setUserName(state, name) {
@@ -27,7 +27,7 @@ export default {
}, },
setUserEmail(state, email) { setUserEmail(state, email) {
Vue.set(state.user, 'email', email); Vue.set(state.user, 'email', email);
} },
}, },
actions: { actions: {
async signUp({ commit }, payload) { async signUp({ commit }, payload) {
@@ -94,8 +94,8 @@ export default {
if (changeType === 'changeName') { if (changeType === 'changeName') {
const { newName } = payload; const { newName } = payload;
return reauthenticatedUser.updateProfile({ return reauthenticatedUser.updateProfile({
displayName: newName, displayName: newName,
}) })
.then(() => commit('setUserName', newName)) .then(() => commit('setUserName', newName))
} }
@@ -123,7 +123,7 @@ export default {
}, },
}, },
getters: { getters: {
isUserAuthentificated: state => state.user.isAuthentificated, isUserAuthenticated: state => state.user.isAuthenticated,
userId: state => state.user.uid, userId: state => state.user.uid,
userName: state => state.user.name, userName: state => state.user.name,
userEmail: state => state.user.email, userEmail: state => state.user.email,

View File

@@ -44,7 +44,7 @@ export default {
await userDataRef.set({ await userDataRef.set({
articles: { articles: {
[articleId]: article, [articleId]: article,
} },
}, { merge: true }) }, { merge: true })
.then(() => commit('addUserArticle', { articleId, article })) .then(() => commit('addUserArticle', { articleId, article }))
.catch(e => window.console.error(e)); .catch(e => window.console.error(e));
@@ -67,7 +67,7 @@ export default {
await userDataRef.set({ await userDataRef.set({
words: { words: {
[key]: word, [key]: word,
} },
}, { merge: true }) }, { merge: true })
.then(() => commit('addUserWord', { wordKey: key, word })) .then(() => commit('addUserWord', { wordKey: key, word }))
.catch(e => window.console.error(e)); .catch(e => window.console.error(e));

View File

@@ -22,4 +22,4 @@ export const setUpEventBus = () => {
}, },
}, },
}); });
} };

View File

@@ -1,13 +1,13 @@
export const emailRules = [ export const emailRules = [
(value) => !!value || 'Пожалуйста, введите email', value => !!value || 'Пожалуйста, введите email',
(value) => /^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/.test(value) || 'Неправильный email', value => /^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/.test(value) || 'Неправильный email',
]; ];
export const passwordRules = [ export const passwordRules = [
(value) => !!value || 'Пожалуйста введите пароль', value => !!value || 'Пожалуйста введите пароль',
(value) => (value && value.length >= 6) || 'Пароль слишком короткий - минимум 6 символов', value => (value && value.length >= 6) || 'Пароль слишком короткий - минимум 6 символов',
]; ];
export const nameRules = [ export const nameRules = [
(value) => !!value || 'Пожалуйста введите ваше имя', value => !!value || 'Пожалуйста введите ваше имя',
]; ];

View File

@@ -8,4 +8,3 @@ export const declOfNum = (number, titles) => {
const cases = [2, 0, 1, 1, 1, 2]; const cases = [2, 0, 1, 1, 1, 2];
return titles[(number % 100 > 4 && number % 100 < 20) ? 2 : cases[(number % 10 < 5) ? number % 10 : 5]]; return titles[(number % 100 > 4 && number % 100 < 20) ? 2 : cases[(number % 10 < 5) ? number % 10 : 5]];
}; };

View File

@@ -13,24 +13,24 @@
<script> <script>
import ArticleDetails from '@/components/Article/Details'; import ArticleDetails from '@/components/Article/Details';
import ArticlePartsListItem from '@/components/Article/Part/ListItem'; import ArticlePartsListItem from '@/components/Article/Part/ListItem';
export default { export default {
props: { props: {
articleId: { articleId: {
type: String, type: String,
required: true, required: true,
},
}, },
computed: { },
article() { computed: {
return this.$store.getters.getArticles.find(article => article.id == this.articleId); article() {
}, return this.$store.getters.getArticles.find(article => article.id === this.articleId);
}, },
components: { },
ArticleDetails, components: {
ArticlePartsListItem, ArticleDetails,
}, ArticlePartsListItem,
}; },
};
</script> </script>

View File

@@ -58,89 +58,89 @@
</template> </template>
<script> <script>
import Vue from 'vue'; import Vue from 'vue';
import BookPartContent from '@/components/Article/Part/Content'; import BookPartContent from '@/components/Article/Part/Content';
import BookPartWords from '@/components/Article/Words'; import BookPartWords from '@/components/Article/Words';
export default { export default {
props: { props: {
articleId: { articleId: {
type: String, type: String,
required: true, required: true,
},
partId: {
type: String,
required: true,
},
}, },
components: { partId: {
BookPartContent, type: String,
BookPartWords, required: true,
}, },
computed: { },
currentUserArticle() { data: () => ({
const articles = this.$store.getters.userData.articles; part: null,
if (!articles) { finishDialog: false,
return null; rating: 0,
} }),
return articles[this.articleId]; computed: {
}, currentUserArticle() {
currentUserArticlePart() { const articles = this.$store.getters.userData.articles;
const article = this.currentUserArticle; if (!articles) {
if (!article) { return null;
return null;
}
const articleParts = article.parts;
if (!articleParts) {
return null;
}
return articleParts[this.partId];
},
finishedAt() {
const articlePart = this.currentUserArticlePart;
return articlePart ? articlePart.finishedAt : null
},
storedRating() {
const articlePart = this.currentUserArticlePart;
return articlePart ? articlePart.rating : 0;
},
},
methods: {
finishWork() {
this.$store.dispatch('finishUserArticlePart', {
articleId: this.articleId,
partId: this.partId,
rating: this.rating,
});
this.finishDialog = false;
} }
return articles[this.articleId];
}, },
data: () => ({ currentUserArticlePart() {
part: null, const article = this.currentUserArticle;
finishDialog: false, if (!article) {
rating: 0, return null;
}), }
created() {
const { articleId, partId } = this; const articleParts = article.parts;
Vue.$db.collection('articleParts') if (!articleParts) {
.where('articleId', '==', articleId) return null;
.where('articlePartId', '==', partId) }
.get()
.then((querySnapshot) => { return articleParts[this.partId];
const snapDocs = querySnapshot.docs; },
if (snapDocs.length > 0) { finishedAt() {
this.part = Object.assign({}, snapDocs[0].data()); const articlePart = this.currentUserArticlePart;
} return articlePart ? articlePart.finishedAt : null
}) },
.then(() => { storedRating() {
this.$store.dispatch('updateUserArticlePartStats', { const articlePart = this.currentUserArticlePart;
articleId, return articlePart ? articlePart.rating : 0;
partId, },
}); },
}) methods: {
.catch(e => window.console.error(e)); finishWork() {
} this.$store.dispatch('finishUserArticlePart', {
}; articleId: this.articleId,
partId: this.partId,
rating: this.rating,
});
this.finishDialog = false;
},
},
created() {
const { articleId, partId } = this;
Vue.$db.collection('articleParts')
.where('articleId', '==', articleId)
.where('articlePartId', '==', partId)
.get()
.then((querySnapshot) => {
const snapDocs = querySnapshot.docs;
if (snapDocs.length > 0) {
this.part = { ...snapDocs[0].data() };
}
})
.then(() => {
this.$store.dispatch('updateUserArticlePartStats', {
articleId,
partId,
});
})
.catch(e => window.console.error(e));
},
components: {
BookPartContent,
BookPartWords,
},
};
</script> </script>

View File

@@ -6,10 +6,10 @@
<script> <script>
import ArticlesList from '@/components/ArticlesList'; import ArticlesList from '@/components/ArticlesList';
export default { export default {
components: { components: {
ArticlesList, ArticlesList,
}, },
}; };
</script> </script>

View File

@@ -1,22 +1,18 @@
<template> <template>
<div> <div>
<v-alert <v-alert
:value="true" :value="true"
color="error" color="error"
icon="warning" icon="warning"
outline outline
> >
Страница, которую вы запросили, не существует. Страница, которую вы запросили, не существует.
</v-alert> </v-alert>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
name: 'notFound', name: 'notFound',
components: { };
}
}
</script> </script>

View File

@@ -1,14 +1,11 @@
<template> <template>
<div> <div>
<h2>Home</h2> <h2>Home</h2>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
name: 'home', name: 'home',
components: { };
}
}
</script> </script>

View File

@@ -28,17 +28,17 @@
<script> <script>
import UserProfileData from '@/components/User/ProfileData'; import UserProfileData from '@/components/User/ProfileData';
export default { export default {
beforeMount() { beforeMount() {
this.$store.commit('clearError'); this.$store.commit('clearError');
}, },
data: () => ({ data: () => ({
tabMode: 'myData', tabMode: 'myData',
}), }),
components: { components: {
UserProfileData, UserProfileData,
}, },
}; };
</script> </script>

View File

@@ -1,94 +1,101 @@
<template> <template>
<v-content> <v-content>
<v-container fluid fill-height> <v-container fluid fill-height>
<v-layout align-center justify-center> <v-layout align-center justify-center>
<v-flex xs12 sm8 md6> <v-flex xs12 sm8 md6>
<v-card class="elevation-12"> <v-card class="elevation-12">
<v-toolbar dark color="primary"> <v-toolbar dark color="primary">
<v-toolbar-title>Вход</v-toolbar-title> <v-toolbar-title>Вход</v-toolbar-title>
</v-toolbar> </v-toolbar>
<v-card-text> <v-card-text>
<v-alert <v-alert
:value="error" :value="error"
type="warning" type="warning"
> >
{{error}} {{error}}
</v-alert> </v-alert>
<v-form id="sign-in-form" v-model="isValid" @submit.prevent="signIn"> <v-form id="sign-in-form" v-model="isValid" @submit.prevent="signIn">
<v-text-field <v-text-field
prepend-icon="email" prepend-icon="email"
v-model="email" v-model="email"
name="login" name="login"
label="Email" label="Email"
type="email" type="email"
required required
:rules="emailRules" :rules="emailRules"
> >
</v-text-field> </v-text-field>
<v-text-field <v-text-field
prepend-icon="lock" prepend-icon="lock"
v-model="password" v-model="password"
name="password" name="password"
label="Пароль" label="Пароль"
id="password" id="password"
type="password" type="password"
required required
:rules="passwordRules" :rules="passwordRules"
> >
</v-text-field> </v-text-field>
</v-form> </v-form>
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn color="primary" type="submit" form="sign-in-form" :disabled="isProcessing || !isValid">Войти</v-btn> <v-btn
</v-card-actions> color="primary"
</v-card> type="submit"
</v-flex> form="sign-in-form"
</v-layout> :disabled="isProcessing || !isValid"
</v-container> >
Войти
</v-btn>
</v-card-actions>
</v-card>
</v-flex>
</v-layout>
</v-container>
</v-content> </v-content>
</template> </template>
<script> <script>
import { emailRules, passwordRules } from '@/utils'; import { emailRules, passwordRules } from '@/utils';
export default { export default {
beforeMount() { beforeMount() {
this.$store.commit('clearError'); this.$store.commit('clearError');
}, },
data: () => ({ data: () => ({
email: null, email: null,
password: null, password: null,
isValid: false, isValid: false,
emailRules, emailRules,
passwordRules, passwordRules,
}), }),
computed: { computed: {
error() { error() {
return this.$store.getters.getError; return this.$store.getters.getError;
},
isProcessing() {
return this.$store.getters.getProcessing;
},
isUserAuthentificated() {
return this.$store.getters.isUserAuthentificated;
},
}, },
watch: { isProcessing() {
isUserAuthentificated(val) { return this.$store.getters.getProcessing;
if (val === true) {
this.$router.push('/');
}
},
}, },
methods: { isUserAuthenticated() {
signIn() { return this.$store.getters.isUserAuthenticated;
const { email, password } = this;
this.$store.dispatch('signIn', { email, password });
},
}, },
} },
watch: {
isUserAuthenticated(val) {
if (val === true) {
this.$router.push('/');
}
},
},
methods: {
signIn() {
const { email, password } = this;
this.$store.dispatch('signIn', { email, password });
},
},
};
</script> </script>

View File

@@ -1,107 +1,114 @@
<template> <template>
<v-content> <v-content>
<v-container fluid fill-height> <v-container fluid fill-height>
<v-layout align-center justify-center> <v-layout align-center justify-center>
<v-flex xs12 sm8 md6> <v-flex xs12 sm8 md6>
<v-card class="elevation-12"> <v-card class="elevation-12">
<v-toolbar dark color="primary"> <v-toolbar dark color="primary">
<v-toolbar-title>Регистрация</v-toolbar-title> <v-toolbar-title>Регистрация</v-toolbar-title>
</v-toolbar> </v-toolbar>
<v-card-text> <v-card-text>
<v-alert <v-alert
:value="error" :value="error"
type="warning" type="warning"
> >
{{error}} {{error}}
</v-alert> </v-alert>
<v-form id="sign-up-form" v-model="isValid" @submit.prevent="signUp"> <v-form id="sign-up-form" v-model="isValid" @submit.prevent="signUp">
<v-text-field <v-text-field
prepend-icon="person" prepend-icon="person"
v-model="name" v-model="name"
name="name" name="name"
label="Имя" label="Имя"
type="text" type="text"
required required
:rules="nameRules" :rules="nameRules"
> >
</v-text-field> </v-text-field>
<v-text-field <v-text-field
prepend-icon="email" prepend-icon="email"
v-model="email" v-model="email"
name="login" name="login"
label="Email" label="Email"
type="email" type="email"
required required
:rules="emailRules" :rules="emailRules"
> >
</v-text-field> </v-text-field>
<v-text-field <v-text-field
prepend-icon="lock" prepend-icon="lock"
v-model="password" v-model="password"
name="password" name="password"
label="Пароль" label="Пароль"
id="password" id="password"
type="password" type="password"
required required
:rules="passwordRules" :rules="passwordRules"
> >
</v-text-field> </v-text-field>
</v-form> </v-form>
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn type="submit" color="primary" form="sign-up-form" :disabled="isProcessing || !isValid">Зарегистрироваться</v-btn> <v-btn
</v-card-actions> type="submit"
</v-card> color="primary"
</v-flex> form="sign-up-form"
</v-layout> :disabled="isProcessing || !isValid"
</v-container> >
Зарегистрироваться
</v-btn>
</v-card-actions>
</v-card>
</v-flex>
</v-layout>
</v-container>
</v-content> </v-content>
</template> </template>
<script> <script>
import { emailRules, passwordRules, nameRules } from '@/utils'; import { emailRules, passwordRules, nameRules } from '@/utils';
export default { export default {
beforeMount() { beforeMount() {
this.$store.commit('clearError'); this.$store.commit('clearError');
},
data: () => ({
email: null,
password: null,
name: null,
isValid: false,
emailRules,
passwordRules,
nameRules,
}),
computed: {
error() {
return this.$store.getters.getError;
}, },
data: () => ({ isProcessing() {
email: null, return this.$store.getters.getProcessing;
password: null, },
name: null, isUserAuthenticated() {
isValid: false, return this.$store.getters.isUserAuthenticated;
},
emailRules, },
passwordRules, watch: {
nameRules, isUserAuthenticated(val) {
}), if (val === true) {
computed: { this.$router.push('/');
error() {
return this.$store.getters.getError;
},
isProcessing() {
return this.$store.getters.getProcessing;
},
isUserAuthentificated() {
return this.$store.getters.isUserAuthentificated;
} }
}, },
watch: { },
isUserAuthentificated(val) { methods: {
if (val === true) { signUp() {
this.$router.push('/'); const { email, password, name } = this;
} this.$store.dispatch('signUp', { email, password, name });
},
}, },
methods: { },
signUp() { };
const { email, password, name } = this;
this.$store.dispatch('signUp', { email, password, name });
},
},
}
</script> </script>

View File

@@ -6,7 +6,6 @@
<script> <script>
export default { export default {
};
}
</script> </script>

9
webpack.config.js Normal file
View File

@@ -0,0 +1,9 @@
const path = require('path');
module.exports = {
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
},
},
};

104
yarn.lock
View File

@@ -2306,6 +2306,11 @@ constants-browserify@^1.0.0:
resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=
contains-path@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a"
integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=
content-disposition@0.5.2: content-disposition@0.5.2:
version "0.5.2" version "0.5.2"
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4"
@@ -2687,7 +2692,7 @@ debug@*, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1:
dependencies: dependencies:
ms "^2.1.1" ms "^2.1.1"
debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3: debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9:
version "2.6.9" version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
@@ -2868,6 +2873,14 @@ dns-txt@^2.0.2:
dependencies: dependencies:
buffer-indexof "^1.0.0" buffer-indexof "^1.0.0"
doctrine@1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa"
integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=
dependencies:
esutils "^2.0.2"
isarray "^1.0.0"
doctrine@^2.1.0: doctrine@^2.1.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
@@ -3055,7 +3068,7 @@ errno@^0.1.3, errno@~0.1.7:
dependencies: dependencies:
prr "~1.0.1" prr "~1.0.1"
error-ex@^1.3.1: error-ex@^1.2.0, error-ex@^1.3.1:
version "1.3.2" version "1.3.2"
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
@@ -3109,14 +3122,13 @@ eslint-config-airbnb-base@^13.1.0:
object.assign "^4.1.0" object.assign "^4.1.0"
object.entries "^1.0.4" object.entries "^1.0.4"
eslint-config-airbnb@^17.1.0: eslint-import-resolver-node@^0.3.2:
version "17.1.0" version "0.3.2"
resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-17.1.0.tgz#3964ed4bc198240315ff52030bf8636f42bc4732" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz#58f15fb839b8d0576ca980413476aab2472db66a"
integrity sha512-R9jw28hFfEQnpPau01NO5K/JWMGLi6aymiF6RsnMURjTk+MqZKllCqGK/0tOvHkPi/NWSSOU2Ced/GX++YxLnw== integrity sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==
dependencies: dependencies:
eslint-config-airbnb-base "^13.1.0" debug "^2.6.9"
object.assign "^4.1.0" resolve "^1.5.0"
object.entries "^1.0.4"
eslint-loader@^2.1.1: eslint-loader@^2.1.1:
version "2.1.2" version "2.1.2"
@@ -3129,6 +3141,30 @@ eslint-loader@^2.1.1:
object-hash "^1.1.4" object-hash "^1.1.4"
rimraf "^2.6.1" rimraf "^2.6.1"
eslint-module-utils@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.3.0.tgz#546178dab5e046c8b562bbb50705e2456d7bda49"
integrity sha512-lmDJgeOOjk8hObTysjqH7wyMi+nsHwwvfBykwfhjR1LNdd7C2uFJBvx4OpWYpXOw4df1yE1cDEVd1yLHitk34w==
dependencies:
debug "^2.6.8"
pkg-dir "^2.0.0"
eslint-plugin-import@^2.16.0:
version "2.16.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.16.0.tgz#97ac3e75d0791c4fac0e15ef388510217be7f66f"
integrity sha512-z6oqWlf1x5GkHIFgrSvtmudnqM6Q60KM4KvpWi5ubonMjycLjndvd5+8VAZIsTlHC03djdgJuyKG6XO577px6A==
dependencies:
contains-path "^0.1.0"
debug "^2.6.9"
doctrine "1.5.0"
eslint-import-resolver-node "^0.3.2"
eslint-module-utils "^2.3.0"
has "^1.0.3"
lodash "^4.17.11"
minimatch "^3.0.4"
read-pkg-up "^2.0.0"
resolve "^1.9.0"
eslint-plugin-jsx-a11y@^6.2.1: eslint-plugin-jsx-a11y@^6.2.1:
version "6.2.1" version "6.2.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.1.tgz#4ebba9f339b600ff415ae4166e3e2e008831cf0c" resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.1.tgz#4ebba9f339b600ff415ae4166e3e2e008831cf0c"
@@ -3671,7 +3707,7 @@ find-up@^1.0.0:
path-exists "^2.0.0" path-exists "^2.0.0"
pinkie-promise "^2.0.0" pinkie-promise "^2.0.0"
find-up@^2.1.0: find-up@^2.0.0, find-up@^2.1.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c=
@@ -4945,6 +4981,16 @@ levn@^0.3.0, levn@~0.3.0:
prelude-ls "~1.1.2" prelude-ls "~1.1.2"
type-check "~0.3.2" type-check "~0.3.2"
load-json-file@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8"
integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=
dependencies:
graceful-fs "^4.1.2"
parse-json "^2.2.0"
pify "^2.0.0"
strip-bom "^3.0.0"
loader-fs-cache@^1.0.0: loader-fs-cache@^1.0.0:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/loader-fs-cache/-/loader-fs-cache-1.0.1.tgz#56e0bf08bd9708b26a765b68509840c8dec9fdbc" resolved "https://registry.yarnpkg.com/loader-fs-cache/-/loader-fs-cache-1.0.1.tgz#56e0bf08bd9708b26a765b68509840c8dec9fdbc"
@@ -5905,6 +5951,13 @@ parse-asn1@^5.0.0:
pbkdf2 "^3.0.3" pbkdf2 "^3.0.3"
safe-buffer "^5.1.1" safe-buffer "^5.1.1"
parse-json@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=
dependencies:
error-ex "^1.2.0"
parse-json@^4.0.0: parse-json@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0"
@@ -5970,6 +6023,13 @@ path-to-regexp@0.1.7:
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
path-type@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73"
integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=
dependencies:
pify "^2.0.0"
path-type@^3.0.0: path-type@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f"
@@ -6596,6 +6656,23 @@ rc@^1.2.7:
minimist "^1.2.0" minimist "^1.2.0"
strip-json-comments "~2.0.1" strip-json-comments "~2.0.1"
read-pkg-up@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be"
integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=
dependencies:
find-up "^2.0.0"
read-pkg "^2.0.0"
read-pkg@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8"
integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=
dependencies:
load-json-file "^2.0.0"
normalize-package-data "^2.3.2"
path-type "^2.0.0"
read-pkg@^4.0.1: read-pkg@^4.0.1:
version "4.0.1" version "4.0.1"
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-4.0.1.tgz#963625378f3e1c4d48c85872b5a6ec7d5d093237" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-4.0.1.tgz#963625378f3e1c4d48c85872b5a6ec7d5d093237"
@@ -6870,7 +6947,7 @@ resolve-url@^0.2.1:
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
resolve@^1.10.0, resolve@^1.3.2, resolve@^1.8.1: resolve@^1.10.0, resolve@^1.3.2, resolve@^1.5.0, resolve@^1.8.1, resolve@^1.9.0:
version "1.10.0" version "1.10.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.0.tgz#3bdaaeaf45cc07f375656dfd2e54ed0810b101ba" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.0.tgz#3bdaaeaf45cc07f375656dfd2e54ed0810b101ba"
integrity sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg== integrity sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==
@@ -7494,6 +7571,11 @@ strip-ansi@^5.0.0:
dependencies: dependencies:
ansi-regex "^4.0.0" ansi-regex "^4.0.0"
strip-bom@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=
strip-eof@^1.0.0: strip-eof@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"