diff --git a/.eslintrc.yml b/.eslintrc.yml
index 2c39435f3..271427fe3 100644
--- a/.eslintrc.yml
+++ b/.eslintrc.yml
@@ -9,3 +9,12 @@ extends:
- "plugin:vue/strongly-recommended"
- "plugin:vue/recommended"
- prettier
+
+globals:
+ OC:
+ t:
+
+rules:
+ no-plusplus:
+ - error
+ - allowForLoopAfterthoughts: true
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 9df24b78c..7ca74a038 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -47,6 +47,16 @@ jobs:
Please run `npm run prettier-fix` in order to correct this.';
exit 1;
}
+
+ - name: Check for issues with vue and js files (eslint)
+ shell: bash
+ run: >-
+ npm run eslint || {
+ echo '::error ::The eslint style checker failed.
+ Please run `npm run eslint-fix` in order to correct this.';
+ exit 1;
+ }
+
- name: Check for formatting issues with CSS files (stylelint)
shell: bash
run: >-
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 36688b009..561248e23 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,8 @@
[#607](https://github.com/nextcloud/cookbook/pull/607) @christianlupus
- Enforce CSS styling using stylelint
[#608](https://github.com/nextcloud/cookbook/pull/608) @christianlupus
+- More code styling, cleanup & minor bugfixes
+ [#615](https://github.com/nextcloud/cookbook/pull/615) @seyfeb
## Deprecated
- Obsolete routes to old user interface, see `appinfo/routes.php`
diff --git a/src/components/AppControls.vue b/src/components/AppControls.vue
index f1aeddaa5..39fcc5705 100644
--- a/src/components/AppControls.vue
+++ b/src/components/AppControls.vue
@@ -1,30 +1,30 @@
-
+
{{ t("cookbook", "Filter") }}
{{
@@ -36,17 +36,17 @@
v-if="isSearch"
class="not-link"
:title="searchTitle"
- :disableDrop="true"
+ :disable-drop="true"
/>
@@ -54,13 +54,13 @@
v-if="isEdit"
class="not-link"
:title="t('cookbook', 'Edit recipe')"
- :disableDrop="true"
+ :disable-drop="true"
/>
{{ t("cookbook", "Reload recipe") }}
@@ -80,13 +80,13 @@
v-else-if="isCreate"
class="active"
:title="t('cookbook', 'New recipe')"
- :disableDrop="true"
+ :disable-drop="true"
/>
{{ t("cookbook", "Save changes") }}
@@ -105,7 +105,7 @@
v-if="isRecipe"
class="active"
:title="$store.state.recipe.name"
- :disableDrop="true"
+ :disable-drop="true"
>
{{ t("cookbook", "Reload recipe") }}
@@ -124,12 +124,12 @@
v-if="isRecipe"
class="no-arrow"
title=""
- :disableDrop="true"
+ :disable-drop="true"
>
{{ t("cookbook", "Print recipe") }}
@@ -156,12 +156,12 @@
v-if="isRecipe"
class="no-arrow"
title=""
- :disableDrop="true"
+ :disable-drop="true"
>
{{ t("cookbook", "Delete recipe") }}
@@ -171,11 +171,11 @@
v-if="isLoading"
class="active no-arrow"
:title="t('cookbook', 'App is loading')"
- :disableDrop="true"
+ :disable-drop="true"
>
@@ -183,11 +183,11 @@
v-else-if="isLoadingRecipe"
class="active no-arrow"
:title="t('cookbook', 'Loading recipe')"
- :disableDrop="true"
+ :disable-drop="true"
>
@@ -195,14 +195,14 @@
v-else-if="recipeNotFound"
class="active no-arrow"
:title="t('cookbook', 'Recipe not found')"
- :disableDrop="true"
+ :disable-drop="true"
/>
@@ -211,7 +211,6 @@
diff --git a/src/components/AppIndex.vue b/src/components/AppIndex.vue
index 742c06322..6570727ed 100644
--- a/src/components/AppIndex.vue
+++ b/src/components/AppIndex.vue
@@ -5,7 +5,7 @@
diff --git a/src/components/AppInvalidGuest.vue b/src/components/AppInvalidGuest.vue
index 8850c1fad..60ad1e337 100644
--- a/src/components/AppInvalidGuest.vue
+++ b/src/components/AppInvalidGuest.vue
@@ -26,7 +26,6 @@
diff --git a/src/components/AppNavigationCaption.vue b/src/components/AppNavigationCaption.vue
index 68c896bb3..6749306c3 100644
--- a/src/components/AppNavigationCaption.vue
+++ b/src/components/AppNavigationCaption.vue
@@ -146,16 +146,16 @@ export default {
hasUtils() {
if (this.editing) {
return false
- } else if (
+ }
+ if (
this.$slots.actions ||
this.$slots.counter ||
this.editable ||
this.undo
) {
return true
- } else {
- return false
}
+ return false
},
// is the icon shown?
// we don't show it on mobile if the entry is collapsible
diff --git a/src/components/AppSettings.vue b/src/components/AppSettings.vue
index ce15831ca..9791b0da3 100644
--- a/src/components/AppSettings.vue
+++ b/src/components/AppSettings.vue
@@ -11,8 +11,8 @@
? 'icon-loading-small'
: 'icon-history'
"
- @click="emit('reindex')"
:title="t('cookbook', 'Rescan library')"
+ @click="emit('reindex')"
/>
@@ -22,8 +22,8 @@
@@ -31,18 +31,18 @@
{{ t("cookbook", "Update interval in minutes") }}
@@ -19,11 +23,10 @@ export default {
}
},
methods: {
- toggleCollapsed: function () {
+ toggleCollapsed() {
this.collapsed = !this.collapsed
},
},
- mounted() {},
}
diff --git a/src/components/RecipeIngredient.vue b/src/components/RecipeIngredient.vue
index b599eac95..5aa6759e1 100644
--- a/src/components/RecipeIngredient.vue
+++ b/src/components/RecipeIngredient.vue
@@ -7,6 +7,7 @@
@click="toggleDone"
>
✔
+
@@ -14,7 +15,15 @@
diff --git a/src/components/RecipeTimer.vue b/src/components/RecipeTimer.vue
index 2bf9ab6d0..375a9dcb8 100644
--- a/src/components/RecipeTimer.vue
+++ b/src/components/RecipeTimer.vue
@@ -1,7 +1,7 @@
export default {
name: "RecipeTimer",
- props: ["value", "phase", "label", "timer"],
+ props: {
+ value: {
+ type: Object,
+ default() {
+ return { hours: 0, minutes: 0 }
+ },
+ },
+ phase: {
+ type: String,
+ default: "",
+ },
+ label: {
+ type: String,
+ default: "",
+ },
+ timer: {
+ type: Boolean,
+ default: false,
+ },
+ },
data() {
return {
countdown: null,
@@ -24,55 +43,59 @@ export default {
showFullTime: false,
}
},
- watch: {
- value() {
- this.resetTimeDisplay()
- },
- },
computed: {
- displayTime: function () {
+ displayTime() {
let text = ""
if (this.showFullTime) {
- text += this.hours.toString().padStart(2, "0") + ":"
+ text += `${this.hours.toString().padStart(2, "0")}:`
} else {
- text += this.hours.toString() + ":"
+ text += `${this.hours.toString()}:`
}
text += this.minutes.toString().padStart(2, "0")
if (this.showFullTime) {
- text += ":" + this.seconds.toString().padStart(2, "0")
+ text += `:${this.seconds.toString().padStart(2, "0")}`
}
return text
},
},
+ watch: {
+ value() {
+ this.resetTimeDisplay()
+ },
+ },
+ mounted() {
+ this.resetTimeDisplay()
+ },
methods: {
- onTimerEnd: function (button) {
+ onTimerEnd() {
window.clearInterval(this.countdown)
// I'll just use an alert until this functionality is finished
- let $this = this
- window.setTimeout(function () {
+ const $this = this
+ window.setTimeout(() => {
// The short timeout is needed or Vue doesn't have time to update the countdown
// display to display 00:00:00
+ // eslint-disable-next-line no-alert
alert(t("cookbook", "Cooking time is up!"))
- //cookbook.notify(t('cookbook', 'Cooking time is up!'))
+ // cookbook.notify(t('cookbook', 'Cooking time is up!'))
$this.countdown = null
$this.showFullTime = false
$this.resetTimeDisplay()
}, 100)
},
- resetTimeDisplay: function () {
+ resetTimeDisplay() {
if (this.value.hours) {
- this.hours = parseInt(this.value.hours)
+ this.hours = parseInt(this.value.hours, 10)
} else {
this.hours = 0
}
if (this.value.minutes) {
- this.minutes = parseInt(this.value.minutes)
+ this.minutes = parseInt(this.value.minutes, 10)
} else {
this.minutes = 0
}
this.seconds = 0
},
- timerToggle: function () {
+ timerToggle() {
// We will switch to full time display the first time this method is invoked.
// There should probably also be a way to reset the timer other than by letting
// it run its course...
@@ -81,16 +104,16 @@ export default {
}
if (this.countdown === null) {
// Pass this to callback function
- let $this = this
- this.countdown = window.setInterval(function () {
- $this.seconds--
+ const $this = this
+ this.countdown = window.setInterval(() => {
+ $this.seconds -= 1
if ($this.seconds < 0) {
$this.seconds = 59
- $this.minutes--
+ $this.minutes -= 1
}
if ($this.minutes < 0) {
$this.minutes = 59
- $this.hours--
+ $this.hours -= 1
}
if (
$this.hours === 0 &&
@@ -106,9 +129,6 @@ export default {
}
},
},
- mounted() {
- this.resetTimeDisplay()
- },
}
diff --git a/src/components/RecipeView.vue b/src/components/RecipeView.vue
index dd7347d14..52ebb7166 100644
--- a/src/components/RecipeView.vue
+++ b/src/components/RecipeView.vue
@@ -5,7 +5,7 @@
class="header"
:class="{ responsive: $store.state.recipe.image }"
>
-
+
@@ -22,7 +22,7 @@
// prettier-ignore
t('cookbook','Search recipes with this keyword')
"
- v-on:keyword-clicked="keywordClicked(keyword)"
+ @keyword-clicked="keywordClicked(keyword)"
/>
@@ -106,7 +106,7 @@
v-for="(ingredient, idx) in recipe.ingredients"
:key="'ingr' + idx"
:ingredient="ingredient"
- :recipeIngredientsHaveSubgroups="
+ :recipe-ingredients-have-subgroups="
recipeIngredientsHaveSubgroups
"
/>
@@ -126,7 +126,7 @@
-
+
{{ t("cookbook", "Nutrition Information") }}
{
- return this.convertRecipeReferences(this.escapeHtml(i))
- })
+ ).map((i) => this.convertRecipeReferences(this.escapeHtml(i)))
}
if (this.$store.state.recipe.recipeInstructions) {
recipe.instructions = Object.values(
this.$store.state.recipe.recipeInstructions
- ).map((i) => {
- return this.convertRecipeReferences(this.escapeHtml(i))
- })
+ ).map((i) => this.convertRecipeReferences(this.escapeHtml(i)))
}
if (this.$store.state.recipe.keywords) {
@@ -343,46 +355,46 @@ export default {
}
if (this.$store.state.recipe.cookTime) {
- let cookT = this.$store.state.recipe.cookTime.match(
+ const cookT = this.$store.state.recipe.cookTime.match(
/PT(\d+?)H(\d+?)M/
)
- let hh = parseInt(cookT[1]),
- mm = parseInt(cookT[2])
+ const hh = parseInt(cookT[1], 10)
+ const mm = parseInt(cookT[2], 10)
if (hh > 0 || mm > 0) {
recipe.timerCook = { hours: hh, minutes: mm }
}
}
if (this.$store.state.recipe.prepTime) {
- let prepT = this.$store.state.recipe.prepTime.match(
+ const prepT = this.$store.state.recipe.prepTime.match(
/PT(\d+?)H(\d+?)M/
)
- let hh = parseInt(prepT[1]),
- mm = parseInt(prepT[2])
+ const hh = parseInt(prepT[1], 10)
+ const mm = parseInt(prepT[2], 10)
if (hh > 0 || mm > 0) {
recipe.timerPrep = { hours: hh, minutes: mm }
}
}
if (this.$store.state.recipe.totalTime) {
- let totalT = this.$store.state.recipe.totalTime.match(
+ const totalT = this.$store.state.recipe.totalTime.match(
/PT(\d+?)H(\d+?)M/
)
- let hh = parseInt(totalT[1]),
- mm = parseInt(totalT[2])
+ const hh = parseInt(totalT[1], 10)
+ const mm = parseInt(totalT[2], 10)
if (hh > 0 || mm > 0) {
recipe.timerTotal = { hours: hh, minutes: mm }
}
}
if (this.$store.state.recipe.tool) {
- recipe.tools = this.$store.state.recipe.tool.map((i) => {
- return this.convertRecipeReferences(this.escapeHtml(i))
- })
+ recipe.tools = this.$store.state.recipe.tool.map((i) =>
+ this.convertRecipeReferences(this.escapeHtml(i))
+ )
}
if (this.$store.state.recipe.dateCreated) {
- let date = this.parseDateTime(
+ const date = this.parseDateTime(
this.$store.state.recipe.dateCreated
)
recipe.dateCreated =
@@ -390,7 +402,7 @@ export default {
}
if (this.$store.state.recipe.dateModified) {
- let date = this.parseDateTime(
+ const date = this.parseDateTime(
this.$store.state.recipe.dateModified
)
recipe.dateModified =
@@ -399,16 +411,17 @@ export default {
if (this.$store.state.recipe.nutrition) {
if (this.$store.state.recipe.nutrition instanceof Array) {
- this.$store.state.recipe.nutrition = {}
+ recipe.nutrition = {}
+ } else {
+ recipe.nutrition = this.$store.state.recipe.nutrition
}
} else {
- this.$store.state.recipe.nutrition = {}
+ recipe.nutrition = {}
}
- recipe.nutrition = this.$store.state.recipe.nutrition
return recipe
},
- recipeIngredientsHaveSubgroups: function () {
+ recipeIngredientsHaveSubgroups() {
if (this.recipe.ingredients && this.recipe.ingredients.length > 0) {
for (let idx = 0; idx < this.recipe.ingredients.length; ++idx) {
if (
@@ -422,27 +435,21 @@ export default {
}
return false
},
- showCreatedDate: function () {
- if (!this.recipe.dateCreated) {
- return false
- }
- return true
+ showCreatedDate() {
+ return this.recipe.dateCreated
},
- showModifiedDate: function () {
+ showModifiedDate() {
if (!this.recipe.dateModified) {
return false
- } else if (
+ }
+ return !(
this.$store.state.recipe.dateCreated &&
this.$store.state.recipe.dateModified &&
this.$store.state.recipe.dateCreated ===
this.$store.state.recipe.dateModified
- ) {
- // don't show modified date if create and modified timestamp are the same
- return false
- }
- return true
+ )
},
- showNutritions: function () {
+ showNutritionData() {
return (
this.recipe.nutrition &&
!(this.recipe.nutrition instanceof Array) &&
@@ -450,56 +457,63 @@ export default {
)
},
},
+ mounted() {
+ this.setup()
+ // Register data load method hook for access from the controls components
+ this.$root.$off("reloadRecipeView")
+ this.$root.$on("reloadRecipeView", () => {
+ this.setup()
+ })
+ },
methods: {
- escapeHtml: function (unsafeString) {
+ escapeHtml(unsafeString) {
return unsafeString
.replace(/&/g, "&")
- .replace(/\~/g, "˜")
+ .replace(/~/g, "˜")
.replace(//g, ">")
.replace(/"/g, """)
.replace(/'/g, "'")
},
- convertRecipeReferences: function (text) {
- let re = /(^|\s|[,._+&?!-])#r\/(\d+)(?=$|\s|[.,_+&?!-])/g
- let converted = text.replace(
+ convertRecipeReferences(text) {
+ const re = /(^|\s|[,._+&?!-])#r\/(\d+)(?=$|\s|[.,_+&?!-])/g
+ const converted = text.replace(
re,
- '$1#$2'
+ `$1#$2`
)
return converted
},
- isNullOrEmpty: function (str) {
- return !str || (typeof str === "string" && 0 === str.trim().length)
+ isNullOrEmpty(str) {
+ return !str || (typeof str === "string" && str.trim().length === 0)
},
/**
* Callback for click on keyword
*/
- keywordClicked: function (keyword) {
+ keywordClicked(keyword) {
if (keyword) {
- this.$router.push("/tags/" + keyword)
+ this.$router.push(`/tags/${keyword}`)
}
},
/* The schema.org standard requires the dates formatted as Date (https://schema.org/Date)
* or DateTime (https://schema.org/DateTime). This follows the ISO 8601 standard.
*/
- parseDateTime: function (dt) {
+ parseDateTime(dt) {
if (!dt) return null
- var date = moment(dt, moment.ISO_8601)
+ const date = moment(dt, moment.ISO_8601)
if (!date.isValid()) {
return null
}
return date
},
- setup: function () {
+ setup() {
// Make the control row show that a recipe is loading
if (!this.$store.state.recipe) {
this.$store.dispatch("setLoadingRecipe", { recipe: -1 })
// Make the control row show that the recipe is reloading
} else if (
- this.$store.state.recipe.id === parseInt(this.$route.params.id)
+ this.$store.state.recipe.id ===
+ parseInt(this.$route.params.id, 10)
) {
this.$store.dispatch("setReloadingRecipe", {
recipe: this.$route.params.id,
@@ -512,23 +526,21 @@ export default {
})
}
- let $this = this
+ const $this = this
axios
.get(
- this.$window.baseUrl +
- "/api/recipes/" +
- this.$route.params.id
+ `${this.$window.baseUrl}/api/recipes/${this.$route.params.id}`
)
- .then(function (response) {
- let recipe = response.data
+ .then((response) => {
+ const recipe = response.data
// Store recipe data in vuex
- $this.$store.dispatch("setRecipe", { recipe: recipe })
+ $this.$store.dispatch("setRecipe", { recipe })
// Always set the active page last!
$this.$store.dispatch("setPage", { page: "recipe" })
})
- .catch(function (e) {
+ .catch(() => {
if ($this.$store.state.loadingRecipe) {
// Reset loading recipe
$this.$store.dispatch("setLoadingRecipe", { recipe: 0 })
@@ -543,34 +555,11 @@ export default {
$this.$store.dispatch("setPage", { page: "recipe" })
+ // eslint-disable-next-line no-alert
alert(t("cookbook", "Loading recipe failed"))
})
},
},
- mounted() {
- this.setup()
- // Register data load method hook for access from the controls components
- this.$root.$off("reloadRecipeView")
- this.$root.$on("reloadRecipeView", () => {
- this.setup()
- })
- },
- /**
- * This is one tricky feature of Vue router. If different paths lead to
- * the same component (such as '/recipe/xxx' and '/recipe/yyy)',
- * the component will not automatically reload. So we have to manually
- * reload the page contents.
- * This can also be used to confirm that the user wants to leave the page
- * if there are unsaved changes.
- */
- beforeRouteUpdate(to, from, next) {
- // beforeRouteUpdate is called when the static route stays the same
- next()
- // Check if we should reload the component content
- if (this.$window.shouldReloadContent(from.fullPath, to.fullPath)) {
- this.setup()
- }
- },
}
@@ -783,8 +772,7 @@ main {
width: 36px;
height: 36px;
border: 1px solid var(--color-border-dark);
- margin: 0 1rem 1rem 0;
- margin-top: -6px;
+ margin: -6px 1rem 1rem 0;
background-color: var(--color-background-dark);
background-position: center;
background-repeat: no-repeat;
diff --git a/src/components/SearchResults.vue b/src/components/SearchResults.vue
index ad295f55f..c0d5d7b19 100644
--- a/src/components/SearchResults.vue
+++ b/src/components/SearchResults.vue
@@ -7,46 +7,73 @@
diff --git a/src/guest.js b/src/guest.js
index 8040ec3e9..fdf7d5b9a 100644
--- a/src/guest.js
+++ b/src/guest.js
@@ -8,13 +8,15 @@
import Vue from "vue"
import store from "./store"
-import AppInvalidGuest from "./components/AppInvalidGuest"
-;(function (OC, window) {
- "use strict"
+import AppInvalidGuest from "./components/AppInvalidGuest.vue"
+// eslint-disable-next-line func-names, import/newline-after-import
+;(function (OC, window) {
// Fetch Nextcloud nonce identifier for dynamic script loading
+ // eslint-disable-next-line camelcase,no-undef
__webpack_nonce__ = btoa(OC.requestToken)
+ // eslint-disable-next-line no-param-reassign
window.baseUrl = OC.generateUrl("apps/cookbook")
// Also make the injections available in Vue components
@@ -25,7 +27,7 @@ import AppInvalidGuest from "./components/AppInvalidGuest"
Vue.prototype.t = window.t
// Start the app once document is done loading
- document.addEventListener("DOMContentLoaded", function (event) {
+ document.addEventListener("DOMContentLoaded", () => {
const App = Vue.extend(AppInvalidGuest)
new App({
store,
diff --git a/src/main.js b/src/main.js
index 2dd43ef78..bc716a475 100644
--- a/src/main.js
+++ b/src/main.js
@@ -5,35 +5,35 @@
* @license AGPL3 or later
*/
-// TODO: Agree on a markdown parser
+// Markdown
+import VueShowdown from "vue-showdown"
+import Editor from "v-markdown-editor"
+import "v-markdown-editor/dist/v-markdown-editor.css"
import Vue from "vue"
import router from "./router"
import store from "./store"
-//import AppNavi from './components/AppNavi'
-import AppMain from "./components/AppMain"
+import AppMain from "./components/AppMain.vue"
-//Markdown
-import VueShowdown from "vue-showdown"
-import Editor from "v-markdown-editor"
-import "v-markdown-editor/dist/v-markdown-editor.css"
+// eslint-disable-next-line func-names, import/newline-after-import
;(function (OC, window) {
- "use strict"
-
// Fetch Nextcloud nonce identifier for dynamic script loading
+ // eslint-disable-next-line camelcase,no-undef
__webpack_nonce__ = btoa(OC.requestToken)
+ // eslint-disable-next-line no-param-reassign
window.baseUrl = OC.generateUrl("apps/cookbook")
// Check if two routes point to the same component but have different content
- window.shouldReloadContent = function (url1, url2) {
+ // eslint-disable-next-line no-param-reassign
+ window.shouldReloadContent = function shouldReloadContent(url1, url2) {
if (url1 === url2) {
return false // Obviously should not if both routes are the same
}
- let comps1 = url1.split("/")
- let comps2 = url2.split("/")
+ const comps1 = url1.split("/")
+ const comps2 = url2.split("/")
if (comps1.length < 2 || comps2.length < 2) {
return false // Just a failsafe, this should never happen
@@ -52,12 +52,9 @@ import "v-markdown-editor/dist/v-markdown-editor.css"
// If one of the routes is edit and the other is not
if (comps1.length !== comps2.length) {
// Only reload if changing from edit to create
- if (comps1.pop() === "create" || comps2.pop() === "create") {
- return true
- }
-
- return false
- } else if (comps1.pop() === "create") {
+ return comps1.pop() === "create" || comps2.pop() === "create"
+ }
+ if (comps1.pop() === "create") {
// But, if we are moving from create to view, do not reload
// the create component
return false
@@ -70,12 +67,13 @@ import "v-markdown-editor/dist/v-markdown-editor.css"
}
// Check if the two urls point to the same item instance
- window.isSameItemInstance = function (url1, url2) {
+ // eslint-disable-next-line no-param-reassign
+ window.isSameItemInstance = function isSameItemInstance(url1, url2) {
if (url1 === url2) {
return true // Obviously true if the routes are the same
}
- let comps1 = url1.split("/")
- let comps2 = url2.split("/")
+ const comps1 = url1.split("/")
+ const comps2 = url2.split("/")
if (comps1.length < 2 || comps2.length < 2) {
return false // Just a failsafe, this should never happen
}
@@ -89,28 +87,28 @@ import "v-markdown-editor/dist/v-markdown-editor.css"
// either of the urls have less than three components
return false
}
- if (comps1[2] !== comps2[2]) {
- // Different IDs, not same instance
- return false
- }
- return true
+ return comps1[2] === comps2[2]
}
// A simple function to sanitize HTML tags
- window.escapeHTML = function (text) {
- return text.replace(/[\"&'\/<>]/g, function (a) {
- return {
- "&": "&",
- '"': """,
- "'": "'",
- "<": "<",
- ">": ">",
- }[a]
- })
+ // eslint-disable-next-line no-param-reassign
+ window.escapeHTML = function escapeHTML(text) {
+ return text.replace(
+ /["&'/<>]/g,
+ (a) =>
+ ({
+ "&": "&",
+ '"': """,
+ "'": "'",
+ "<": "<",
+ ">": ">",
+ }[a])
+ )
}
// Fix the decimal separator for languages that use a comma instead of dot
- window.fixDecimalSeparator = function (value, io) {
+ // eslint-disable-next-line no-param-reassign
+ window.fixDecimalSeparator = function fixDecimalSeparator(value, io) {
// value is the string value of the number to process
// io is either 'i' as in input or 'o' as in output
if (!value) {
@@ -121,47 +119,55 @@ import "v-markdown-editor/dist/v-markdown-editor.css"
// e.g. 12,500.25
if (value.indexOf(".") > value.indexOf(",")) {
return value.replace(",", "")
- } else {
- return value.replace(",", ".")
}
- } else if (io === "o") {
+ return value.replace(",", ".")
+ }
+ if (io === "o") {
return value.toString().replace(".", ",")
}
+ return ""
}
// This will replace the PHP function nl2br in Vue components
- window.nl2br = function (text) {
+ // eslint-disable-next-line no-param-reassign
+ window.nl2br = function nl2br(text) {
return text.replace(/\n/g, "
")
}
// A simple function that converts a MySQL datetime into a timestamp.
- window.getTimestamp = function (date) {
+ // eslint-disable-next-line no-param-reassign
+ window.getTimestamp = function getTimestamp(date) {
if (date) {
return new Date(date)
- } else {
- return null
}
+ return null
}
// Push a new URL to the router, essentially navigating to that page.
- window.goTo = function (url) {
+ // eslint-disable-next-line no-param-reassign
+ window.goTo = function goTo(url) {
router.push(url)
}
// Notify the user if notifications are allowed
+ // eslint-disable-next-line no-param-reassign
window.notify = function notify(title, options) {
if (!("Notification" in window)) {
return
- } else if (Notification.permission === "granted") {
- var notification = new Notification(title, options)
+ }
+ if (Notification.permission === "granted") {
+ // eslint-disable-next-line no-unused-vars
+ const notification = new Notification(title, options)
} else if (Notification.permission !== "denied") {
- Notification.requestPermission(function (permission) {
+ Notification.requestPermission((permission) => {
if (!("permission" in Notification)) {
Notification.permission = permission
}
if (permission === "granted") {
- var notification = new Notification(title, options)
+ // eslint-disable-next-line no-unused-vars
+ const notification = new Notification(title, options)
} else {
+ // eslint-disable-next-line no-alert
alert(title)
}
})
@@ -172,9 +178,9 @@ import "v-markdown-editor/dist/v-markdown-editor.css"
Vue.prototype.$window = window
Vue.prototype.OC = OC
- //Markdown for Vue
+ // Markdown for Vue
Vue.use(VueShowdown, {
- //set default flavor for Markdown
+ // set default flavor for Markdown
flavor: "vanilla",
})
Vue.use(Editor)
@@ -183,7 +189,7 @@ import "v-markdown-editor/dist/v-markdown-editor.css"
Vue.prototype.t = window.t
// Start the app once document is done loading
- document.addEventListener("DOMContentLoaded", function (event) {
+ document.addEventListener("DOMContentLoaded", () => {
const App = Vue.extend(AppMain)
new App({
store,
diff --git a/src/router/index.js b/src/router/index.js
index 40b2a49a1..48e7ff47f 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -7,11 +7,11 @@
import Vue from "vue"
import VueRouter from "vue-router"
-import Index from "../components/AppIndex"
-import NotFound from "../components/NotFound"
-import RecipeView from "../components/RecipeView"
-import RecipeEdit from "../components/RecipeEdit"
-import Search from "../components/SearchResults"
+import Index from "../components/AppIndex.vue"
+import NotFound from "../components/NotFound.vue"
+import RecipeView from "../components/RecipeView.vue"
+import RecipeEdit from "../components/RecipeEdit.vue"
+import Search from "../components/SearchResults.vue"
Vue.use(VueRouter)
diff --git a/src/store/.eslintrc.yml b/src/store/.eslintrc.yml
new file mode 100644
index 000000000..f01dda6cb
--- /dev/null
+++ b/src/store/.eslintrc.yml
@@ -0,0 +1,8 @@
+extends: "../../.eslintrc.yml"
+
+rules:
+ no-param-reassign:
+ - error
+ - props: true
+ ignorePropertyModificationsFor:
+ - state
diff --git a/src/store/index.js b/src/store/index.js
index 6e269bc23..f631fb139 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -46,38 +46,41 @@ export default new Vuex.Store({
},
mutations: {
- setAppNavigationRefreshRequired(s, { b }) {
- s.appNavigation.refreshRequired = b
+ setAppNavigationRefreshRequired(state, { b }) {
+ state.appNavigation.refreshRequired = b
},
- setAppNavigationVisible(s, { b }) {
- s.appNavigation.visible = b
+ setAppNavigationVisible(state, { b }) {
+ state.appNavigation.visible = b
},
- setCategoryUpdating(s, { c }) {
- s.categoryUpdating = c
+ setCategoryUpdating(state, { c }) {
+ state.categoryUpdating = c
},
- setLoadingRecipe(s, { r }) {
- s.loadingRecipe = r
+ setLoadingRecipe(state, { r }) {
+ state.loadingRecipe = r
},
- setPage(s, { p }) {
- s.page = p
+ setPage(state, { p }) {
+ state.page = p
},
- setRecipe(s, { r }) {
- s.recipe = r
+ setRecipe(state, { r }) {
+ state.recipe = r
// Setting recipe also means that loading/reloading the recipe has finished
- s.loadingRecipe = 0
- s.reloadingRecipe = 0
+ state.loadingRecipe = 0
+ state.reloadingRecipe = 0
},
- setReloadingRecipe(s, { r }) {
- s.reloadingRecipe = r
+ setRecipeCategory(state, { c }) {
+ state.recipe.category = c
},
- setSavingRecipe(s, { b }) {
- s.savingRecipe = b
+ setReloadingRecipe(state, { r }) {
+ state.reloadingRecipe = r
},
- setUser(s, { u }) {
- s.user = u
+ setSavingRecipe(state, { b }) {
+ state.savingRecipe = b
},
- setUpdatingRecipeDirectory(s, { b }) {
- s.updatingRecipeDirectory = b
+ setUser(state, { u }) {
+ state.user = u
+ },
+ setUpdatingRecipeDirectory(state, { b }) {
+ state.updatingRecipeDirectory = b
},
},
@@ -88,10 +91,10 @@ export default new Vuex.Store({
createRecipe(c, { recipe }) {
const request = axios({
method: "POST",
- url: window.baseUrl + "/api/recipes",
+ url: `${window.baseUrl}/api/recipes`,
data: recipe,
})
- request.then((response) => {
+ request.then(() => {
// Refresh navigation to display changes
c.dispatch("setAppNavigationRefreshRequired", {
isRequired: true,
@@ -103,8 +106,8 @@ export default new Vuex.Store({
* Delete recipe on the server
*/
deleteRecipe(c, { id }) {
- const request = axios.delete(window.baseUrl + "/api/recipes/" + id)
- request.then((response) => {
+ const request = axios.delete(`${window.baseUrl}/api/recipes/${id}`)
+ request.then(() => {
// Refresh navigation to display changes
c.dispatch("setAppNavigationRefreshRequired", {
isRequired: true,
@@ -119,7 +122,7 @@ export default new Vuex.Store({
c.commit("setAppNavigationRefreshRequired", { b: isRequired })
},
setLoadingRecipe(c, { recipe }) {
- c.commit("setLoadingRecipe", { r: parseInt(recipe) })
+ c.commit("setLoadingRecipe", { r: parseInt(recipe, 10) })
},
setPage(c, { page }) {
c.commit("setPage", { p: page })
@@ -128,7 +131,7 @@ export default new Vuex.Store({
c.commit("setRecipe", { r: recipe })
},
setReloadingRecipe(c, { recipe }) {
- c.commit("setReloadingRecipe", { r: parseInt(recipe) })
+ c.commit("setReloadingRecipe", { r: parseInt(recipe, 10) })
},
setSavingRecipe(c, { saving }) {
c.commit("setSavingRecipe", { b: saving })
@@ -140,26 +143,25 @@ export default new Vuex.Store({
c.commit("setCategoryUpdating", { c: category })
},
updateCategoryName(c, { categoryNames }) {
- let oldName = categoryNames[0],
- newName = categoryNames[1]
+ const oldName = categoryNames[0]
+ const newName = categoryNames[1]
c.dispatch("setCategoryUpdating", { category: oldName })
const request = axios({
method: "PUT",
- url:
- window.baseUrl +
- "/api/category/" +
- encodeURIComponent(oldName),
+ url: `${window.baseUrl}/api/category/${encodeURIComponent(
+ oldName
+ )}`,
data: { name: newName },
})
request
- .then(function (response) {
- if (c.state.recipe.recipeCategory == oldName) {
- c.state.recipe.recipeCategory = newName
+ .then(() => {
+ if (c.state.recipe.recipeCategory === oldName) {
+ c.commit("setRecipeCategory", { c: newName })
}
})
- .catch(function (e) {
+ .catch((e) => {
if (e && e instanceof Error) {
throw e
}
@@ -175,7 +177,7 @@ export default new Vuex.Store({
c.commit("setUpdatingRecipeDirectory", { b: true })
c.dispatch("setRecipe", { recipe: null })
const request = axios({
- url: window.baseUrl + "/config",
+ url: `${window.baseUrl}/config`,
method: "POST",
data: { folder: dir },
})
@@ -194,10 +196,10 @@ export default new Vuex.Store({
updateRecipe(c, { recipe }) {
const request = axios({
method: "PUT",
- url: window.baseUrl + "/api/recipes/" + recipe.id,
+ url: `${window.baseUrl}/api/recipes/${recipe.id}`,
data: recipe,
})
- request.then((response) => {
+ request.then(() => {
// Refresh navigation to display changes
c.dispatch("setAppNavigationRefreshRequired", {
isRequired: true,