aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--package-lock.json35
-rw-r--r--package.json1
-rw-r--r--resources/vue/base-components.js1
-rw-r--r--resources/vue/components/FilesTable.vue27
-rw-r--r--resources/vue/components/StudipHighlightText.vue32
5 files changed, 48 insertions, 48 deletions
diff --git a/package-lock.json b/package-lock.json
index 09d74d5..e672221 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,9 +12,7 @@
"@fullcalendar/resource": "^6.1.19",
"@fullcalendar/vue3": "^6.1.19",
"@vojtechlanka/vue-tags-input": "^3.1.1",
- "jsonapi-serializer": "^3.6.9",
- "qrcode.vue": "^3.6.0",
- "sqids": "^0.3.0"
+ "jsonapi-serializer": "^3.6.9"
},
"devDependencies": {
"@axe-core/playwright": "^4.6.1",
@@ -95,12 +93,13 @@
"postcss": "^8.4.49",
"postcss-loader": "^8.1.1",
"postcss-scss": "^4.0.4",
+ "qrcode.vue": "^3.6.0",
"raw-loader": "^4.0.2",
- "sanitize-html": "^2.7.0",
"sass": "^1.29.0",
"sass-loader": "^16.0.4",
"select2": "4.0.13",
"sprintf-js": "^1.0.3",
+ "sqids": "^0.3.0",
"stream-browserify": "^3.0.0",
"style-loader": "^4.0.0",
"stylelint": "^15.11.0",
@@ -10800,11 +10799,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/parse-srcset": {
- "version": "1.0.2",
- "dev": true,
- "license": "MIT"
- },
"node_modules/parse5": {
"version": "7.1.2",
"dev": true,
@@ -11601,6 +11595,7 @@
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/qrcode.vue/-/qrcode.vue-3.6.0.tgz",
"integrity": "sha512-vQcl2fyHYHMjDO1GguCldJxepq2izQjBkDEEu9NENgfVKP6mv/e2SU62WbqYHGwTgWXLhxZ1NCD1dAZKHQq1fg==",
+ "dev": true,
"license": "MIT",
"peerDependencies": {
"vue": "^3.0.0"
@@ -12092,27 +12087,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/sanitize-html": {
- "version": "2.15.0",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "deepmerge": "^4.2.2",
- "escape-string-regexp": "^4.0.0",
- "htmlparser2": "^8.0.0",
- "is-plain-object": "^5.0.0",
- "parse-srcset": "^1.0.2",
- "postcss": "^8.3.11"
- }
- },
- "node_modules/sanitize-html/node_modules/is-plain-object": {
- "version": "5.0.0",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/sass": {
"version": "1.69.0",
"dev": true,
@@ -12535,6 +12509,7 @@
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/sqids/-/sqids-0.3.0.tgz",
"integrity": "sha512-lOQK1ucVg+W6n3FhRwwSeUijxe93b51Bfz5PMRMihVf1iVkl82ePQG7V5vwrhzB11v0NtsR25PSZRGiSomJaJw==",
+ "dev": true,
"license": "MIT"
},
"node_modules/stack-utils": {
diff --git a/package.json b/package.json
index 0d48bad..8278e7e 100644
--- a/package.json
+++ b/package.json
@@ -101,7 +101,6 @@
"postcss-scss": "^4.0.4",
"qrcode.vue": "^3.6.0",
"raw-loader": "^4.0.2",
- "sanitize-html": "^2.7.0",
"sass": "^1.29.0",
"sass-loader": "^16.0.4",
"select2": "4.0.13",
diff --git a/resources/vue/base-components.js b/resources/vue/base-components.js
index dd6561e..71dcbfe 100644
--- a/resources/vue/base-components.js
+++ b/resources/vue/base-components.js
@@ -26,6 +26,7 @@ const BaseComponents = {
StudipDialog: defineAsyncComponent(() => import('./components/StudipDialog.vue')),
StudipFileSize: defineAsyncComponent(() => import('./components/StudipFileSize.vue')),
StudipFolderSize: defineAsyncComponent(() => import('./components/StudipFolderSize.vue')),
+ StudipHighlightText: defineAsyncComponent(() => import('./components/StudipHighlightText.vue')),
StudipIcon: defineAsyncComponent(() => import('./components/StudipIcon.vue')),
StudipMessageBox: defineAsyncComponent(() => import('./components/StudipMessageBox.vue')),
StudipMultiPersonSearch: defineAsyncComponent(() => import('./components/StudipMultiPersonSearch.vue')),
diff --git a/resources/vue/components/FilesTable.vue b/resources/vue/components/FilesTable.vue
index 2bc83ce..2f9a5ad 100644
--- a/resources/vue/components/FilesTable.vue
+++ b/resources/vue/components/FilesTable.vue
@@ -177,7 +177,7 @@
<a :href="folder.url"
:title="$gettext('Ordner %{foldername} öffnen', { foldername: folder.name}, true)"
>
- <span v-html="highlightString(folder.name)"></span>
+ <studip-highlight-text :text="folder.name" :search-term="needleForFilter"></studip-highlight-text>
</a>
</td>
<td class="responsive-hidden" :data-sort-value="folder.object_count">
@@ -189,9 +189,11 @@
</td>
<td class="responsive-hidden" :class="{'filter-match': valueMatchesFilter(folder.author_name)}">
<a v-if="folder.author_url" :href="folder.author_url">
- <span v-html="highlightString(folder.author_name)"></span>
+ <studip-highlight-text :text="folder.author_name" :search-term="needleForFilter"></studip-highlight-text>
</a>
- <span v-else v-html="highlightString(folder.author_name)"></span>
+ <template v-else>
+ <studip-highlight-text :text="folder.author_name" :search-term="needleForFilter"></studip-highlight-text>
+ </template>
</td>
<td class="responsive-hidden" style="white-space: nowrap;">
<studip-date-time :timestamp="folder.chdate" :relative="true"></studip-date-time>
@@ -245,7 +247,7 @@
:id="`file-${file.id}`"
:title="$gettext('Details zur Datei %{filename} anzeigen', { filename: file.name }, true)"
>
- <span v-html="highlightString(file.name)"></span>
+ <studip-highlight-text :text="file.name" :search-term="needleForFilter"></studip-highlight-text>
<studip-icon v-if="file.isAccessible"
shape="accessibility"
role="info"
@@ -270,9 +272,11 @@
</td>
<td class="responsive-hidden" :class="{'filter-match': valueMatchesFilter(file.author_name)}">
<a v-if="file.author_url" :href="file.author_url">
- <span v-html="highlightString(file.author_name)"></span>
+ <studip-highlight-text :text="file.author_name" :search-term="needleForFilter"></studip-highlight-text>
</a>
- <span v-else v-html="highlightString(file.author_name)"></span>
+ <template v-else>
+ <studip-highlight-text :text="file.author_name" :search-term="needleForFilter"></studip-highlight-text>
+ </template>
</td>
<td data-sort-value="file.chdate" class="responsive-hidden" style="white-space: nowrap;">
<studip-date-time :timestamp="file.chdate" :relative="true"></studip-date-time>
@@ -312,7 +316,6 @@
</div>
</template>
<script>
-import sanitizeHTML from 'sanitize-html';
export default {
name: 'files-table',
@@ -447,16 +450,6 @@ export default {
}
return string.toLowerCase().includes(this.needleForFilter);
},
- highlightString (string) {
- let highlighted = sanitizeHTML(string);
- if (this.needleForFilter.length > 0) {
- // Escape needle for regexp, see https://stackoverflow.com/a/3561711
- const pattern = this.needleForFilter.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
- const regExp = new RegExp(pattern, 'gi');
- highlighted = highlighted.replace(regExp, '<span class="filter-match">$&</span>');
- }
- return highlighted;
- },
getAriaLabelForFolder(folder) {
return this.$gettext(
'Ordner %{name} auswählen',
diff --git a/resources/vue/components/StudipHighlightText.vue b/resources/vue/components/StudipHighlightText.vue
new file mode 100644
index 0000000..8ac73f4
--- /dev/null
+++ b/resources/vue/components/StudipHighlightText.vue
@@ -0,0 +1,32 @@
+<template>
+ <span>
+ <template v-for="(part, index) in computedParts" :key="index">
+ {{ part }}<span v-if="searchTerm && index < computedParts.length - 1" class="filter-match">{{ searchTerm }}</span>
+ </template>
+ </span>
+</template>
+
+<script>
+export default {
+ props: {
+ text: {
+ type: String,
+ default: ''
+ },
+ searchTerm: {
+ type: String,
+ default: ''
+ }
+ },
+ computed: {
+ computedParts() {
+ if (!this.searchTerm) {
+ return [this.text || ''];
+ }
+
+ console.log(this.text, (this.text || '').split(this.searchTerm));
+ return (this.text || '').split(this.searchTerm);
+ }
+ }
+};
+</script>