mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-08-23 08:03:49 +00:00
eslint fixes
This commit is contained in:
@@ -1,40 +1,38 @@
|
||||
<template>
|
||||
<li>
|
||||
<h2>{{ props.item.title }}</h2>
|
||||
<time class="createdBy" datetime="{{item.startDate.datetime}}">{{
|
||||
$d(newsItemStartDate(), "text")
|
||||
}}</time>
|
||||
<div class="content" v-if="shouldTruncate(item.content)">
|
||||
<div v-html="prepareContent(item.content)"></div>
|
||||
<div class="float-end">
|
||||
<button
|
||||
class="btn btn-sm btn-show read-more"
|
||||
@click="() => openModal(item)"
|
||||
>
|
||||
{{ $t("widget.news.readMore") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content" v-else>
|
||||
<div v-html="convertMarkdownToHtml(item.content)"></div>
|
||||
</div>
|
||||
<li>
|
||||
<h2>{{ props.item.title }}</h2>
|
||||
<time class="createdBy" datetime="{{item.startDate.datetime}}">{{
|
||||
$d(newsItemStartDate(), "text")
|
||||
}}</time>
|
||||
<div class="content" v-if="shouldTruncate(item.content)">
|
||||
<div v-html="prepareContent(item.content)"></div>
|
||||
<div class="float-end">
|
||||
<button
|
||||
class="btn btn-sm btn-show read-more"
|
||||
@click="() => openModal(item)"
|
||||
>
|
||||
{{ $t("widget.news.readMore") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content" v-else>
|
||||
<div v-html="convertMarkdownToHtml(item.content)"></div>
|
||||
</div>
|
||||
|
||||
<modal v-if="showModal" @close="closeModal">
|
||||
<template #header>
|
||||
<p class="news-title">{{ item.title }}</p>
|
||||
</template>
|
||||
<template #body>
|
||||
<p class="news-date">
|
||||
<time
|
||||
class="createdBy"
|
||||
datetime="{{item.startDate.datetime}}"
|
||||
>{{ $d(newsItemStartDate(), "text") }}</time
|
||||
>
|
||||
</p>
|
||||
<div v-html="convertMarkdownToHtml(item.content)"></div>
|
||||
</template>
|
||||
</modal>
|
||||
</li>
|
||||
<modal v-if="showModal" @close="closeModal">
|
||||
<template #header>
|
||||
<p class="news-title">{{ item.title }}</p>
|
||||
</template>
|
||||
<template #body>
|
||||
<p class="news-date">
|
||||
<time class="createdBy" datetime="{{item.startDate.datetime}}">{{
|
||||
$d(newsItemStartDate(), "text")
|
||||
}}</time>
|
||||
</p>
|
||||
<div v-html="convertMarkdownToHtml(item.content)"></div>
|
||||
</template>
|
||||
</modal>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -47,151 +45,147 @@ import { ref } from "vue";
|
||||
import { ISOToDatetime } from "../../../chill/js/date";
|
||||
|
||||
const props = defineProps({
|
||||
item: {
|
||||
type: Object as PropType<NewsItemType>,
|
||||
required: true,
|
||||
},
|
||||
maxLength: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 350,
|
||||
},
|
||||
maxLines: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 3,
|
||||
},
|
||||
item: {
|
||||
type: Object as PropType<NewsItemType>,
|
||||
required: true,
|
||||
},
|
||||
maxLength: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 350,
|
||||
},
|
||||
maxLines: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 3,
|
||||
},
|
||||
});
|
||||
|
||||
const selectedArticle = ref<NewsItemType | null>(null);
|
||||
const showModal = ref(false);
|
||||
|
||||
const openModal = (item: NewsItemType) => {
|
||||
selectedArticle.value = item;
|
||||
showModal.value = true;
|
||||
selectedArticle.value = item;
|
||||
showModal.value = true;
|
||||
};
|
||||
|
||||
const closeModal = () => {
|
||||
selectedArticle.value = null;
|
||||
showModal.value = false;
|
||||
selectedArticle.value = null;
|
||||
showModal.value = false;
|
||||
};
|
||||
|
||||
const shouldTruncate = (content: string): boolean => {
|
||||
const lines = content.split("\n");
|
||||
const lines = content.split("\n");
|
||||
|
||||
// Check if any line exceeds the maximum length
|
||||
const tooManyLines = lines.length > props.maxLines;
|
||||
// Check if any line exceeds the maximum length
|
||||
const tooManyLines = lines.length > props.maxLines;
|
||||
|
||||
return content.length > props.maxLength || tooManyLines;
|
||||
return content.length > props.maxLength || tooManyLines;
|
||||
};
|
||||
|
||||
const truncateContent = (content: string): string => {
|
||||
let truncatedContent = content.slice(0, props.maxLength);
|
||||
let linkDepth = 0;
|
||||
let linkStartIndex = -1;
|
||||
const lines = content.split("\n");
|
||||
let truncatedContent = content.slice(0, props.maxLength);
|
||||
let linkDepth = 0;
|
||||
let linkStartIndex = -1;
|
||||
const lines = content.split("\n");
|
||||
|
||||
// Truncate if amount of lines are too many
|
||||
if (lines.length > props.maxLines && content.length < props.maxLength) {
|
||||
const truncatedContent = lines
|
||||
.slice(0, props.maxLines)
|
||||
.join("\n")
|
||||
.trim();
|
||||
return truncatedContent + "...";
|
||||
// Truncate if amount of lines are too many
|
||||
if (lines.length > props.maxLines && content.length < props.maxLength) {
|
||||
const truncatedContent = lines.slice(0, props.maxLines).join("\n").trim();
|
||||
return truncatedContent + "...";
|
||||
}
|
||||
|
||||
for (let i = 0; i < truncatedContent.length; i++) {
|
||||
const char = truncatedContent[i];
|
||||
|
||||
if (char === "[") {
|
||||
linkDepth++;
|
||||
if (linkDepth === 1) {
|
||||
linkStartIndex = i;
|
||||
}
|
||||
} else if (char === "]") {
|
||||
linkDepth = Math.max(0, linkDepth - 1);
|
||||
} else if (char === "(" && linkDepth === 0) {
|
||||
truncatedContent = truncatedContent.slice(0, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < truncatedContent.length; i++) {
|
||||
const char = truncatedContent[i];
|
||||
while (linkDepth > 0) {
|
||||
truncatedContent += "]";
|
||||
linkDepth--;
|
||||
}
|
||||
|
||||
if (char === "[") {
|
||||
linkDepth++;
|
||||
if (linkDepth === 1) {
|
||||
linkStartIndex = i;
|
||||
}
|
||||
} else if (char === "]") {
|
||||
linkDepth = Math.max(0, linkDepth - 1);
|
||||
} else if (char === "(" && linkDepth === 0) {
|
||||
truncatedContent = truncatedContent.slice(0, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If a link was found, append the URL inside the parentheses
|
||||
if (linkStartIndex !== -1) {
|
||||
const linkEndIndex = content.indexOf(")", linkStartIndex);
|
||||
const url = content.slice(linkStartIndex + 1, linkEndIndex);
|
||||
truncatedContent = truncatedContent.slice(0, linkStartIndex) + `(${url})`;
|
||||
}
|
||||
|
||||
while (linkDepth > 0) {
|
||||
truncatedContent += "]";
|
||||
linkDepth--;
|
||||
}
|
||||
truncatedContent += "...";
|
||||
|
||||
// If a link was found, append the URL inside the parentheses
|
||||
if (linkStartIndex !== -1) {
|
||||
const linkEndIndex = content.indexOf(")", linkStartIndex);
|
||||
const url = content.slice(linkStartIndex + 1, linkEndIndex);
|
||||
truncatedContent =
|
||||
truncatedContent.slice(0, linkStartIndex) + `(${url})`;
|
||||
}
|
||||
|
||||
truncatedContent += "...";
|
||||
|
||||
return truncatedContent;
|
||||
return truncatedContent;
|
||||
};
|
||||
|
||||
const preprocess = (markdown: string): string => {
|
||||
return markdown;
|
||||
return markdown;
|
||||
};
|
||||
|
||||
const postprocess = (html: string): string => {
|
||||
DOMPurify.addHook("afterSanitizeAttributes", (node: any) => {
|
||||
if ("target" in node) {
|
||||
node.setAttribute("target", "_blank");
|
||||
node.setAttribute("rel", "noopener noreferrer");
|
||||
}
|
||||
if (
|
||||
!node.hasAttribute("target") &&
|
||||
(node.hasAttribute("xlink:href") || node.hasAttribute("href"))
|
||||
) {
|
||||
node.setAttribute("xlink:show", "new");
|
||||
}
|
||||
});
|
||||
DOMPurify.addHook("afterSanitizeAttributes", (node: any) => {
|
||||
if ("target" in node) {
|
||||
node.setAttribute("target", "_blank");
|
||||
node.setAttribute("rel", "noopener noreferrer");
|
||||
}
|
||||
if (
|
||||
!node.hasAttribute("target") &&
|
||||
(node.hasAttribute("xlink:href") || node.hasAttribute("href"))
|
||||
) {
|
||||
node.setAttribute("xlink:show", "new");
|
||||
}
|
||||
});
|
||||
|
||||
return DOMPurify.sanitize(html);
|
||||
return DOMPurify.sanitize(html);
|
||||
};
|
||||
|
||||
const convertMarkdownToHtml = (markdown: string): string => {
|
||||
marked.use({ hooks: { postprocess, preprocess }, async: false });
|
||||
const rawHtml = marked(markdown) as string;
|
||||
return rawHtml;
|
||||
marked.use({ hooks: { postprocess, preprocess }, async: false });
|
||||
const rawHtml = marked(markdown) as string;
|
||||
return rawHtml;
|
||||
};
|
||||
|
||||
const prepareContent = (content: string): string => {
|
||||
const htmlContent = convertMarkdownToHtml(content);
|
||||
return truncateContent(htmlContent);
|
||||
const htmlContent = convertMarkdownToHtml(content);
|
||||
return truncateContent(htmlContent);
|
||||
};
|
||||
|
||||
const newsItemStartDate = (): null | Date => {
|
||||
return ISOToDatetime(props.item?.startDate.datetime);
|
||||
return ISOToDatetime(props.item?.startDate.datetime);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
li {
|
||||
margin-bottom: 20px;
|
||||
overflow: hidden;
|
||||
padding: 0.8rem;
|
||||
background-color: #fbfbfb;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 20px;
|
||||
overflow: hidden;
|
||||
padding: 0.8rem;
|
||||
background-color: #fbfbfb;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1rem !important;
|
||||
text-transform: uppercase;
|
||||
font-size: 1rem !important;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.content {
|
||||
overflow: hidden;
|
||||
font-size: 0.9rem;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
font-size: 0.9rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.news-title {
|
||||
font-weight: bold;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
|
Reference in New Issue
Block a user