This commit is contained in:
romankko2 committed 2024-07-03 20:49:46 +02:00
commit b00b49df6d
5 files changed
+104 -86

No files matched your search

+4 -1
View File
@@ -106,8 +106,11 @@ input[type="time"]::-webkit-calendar-picker-indicator
height: 40px !important height: 40px !important
.server-links .server-links
background: rgba(127, 57, 251, 1)
padding: 4px 5px
a a
text-decoration: underline color: #fff
@media (max-width: 534px) @media (max-width: 534px)
.mobile-view .mobile-view
+73 -41
View File
@@ -1,48 +1,14 @@
export function getServerLinks(description) { import { useToast } from 'vue-toast-notification';
const os = detectOS() const toast = useToast();
// Create a temporary DOM element to manipulate the HTML content declare global {
const tempDiv = document.createElement('div') interface Window {
tempDiv.innerHTML = description toast: typeof toast;
const links = new Set()
const paragraphs = tempDiv.querySelectorAll('p')
paragraphs.forEach(p => {
const text = p.textContent.trim()
if (os === 'mac' && text.startsWith('smb://')) {
links.add(`<a href="${text}" target="_blank" rel="noopener noreferrer">${text}</a>`)
} else if (os === 'win' && text.startsWith('\\\\')) {
links.add(`<a href="file://${text.replace(/\\/g, '/')}" target="_blank" rel="noopener noreferrer">${text}</a>`)
} else if (os === 'mac' && text.startsWith('\\\\')) {
const smbLink = 'smb:' + text.replace(/\\/g, '/')
links.add(`<a href="${smbLink}" target="_blank" rel="noopener noreferrer">${smbLink}</a>`)
} else if (os === 'win' && text.startsWith('smb://')) {
const windowsLink = text.replace(/^smb:/, '').replace(/\//g, '\\')
links.add(`<a href="file://${windowsLink}" target="_blank" rel="noopener noreferrer">${windowsLink}</a>`)
} }
const anchor = p.querySelector('a')
if (anchor) {
const href = anchor.getAttribute('href')
if (os === 'mac' && href.startsWith('smb://')) {
links.add(`<a href="${href}" target="_blank" rel="noopener noreferrer">${href}</a>`)
} else if (os === 'win' && href.startsWith('\\\\')) {
links.add(`<a href="file://${href.replace(/\\/g, '/')}" target="_blank" rel="noopener noreferrer">${href}</a>`)
} else if (os === 'mac' && href.startsWith('\\\\')) {
const smbLink = 'smb:' + href.replace(/\\/g, '/')
links.add(`<a href="${smbLink}" target="_blank" rel="noopener noreferrer">${smbLink}</a>`)
} else if (os === 'win' && href.startsWith('smb://')) {
const windowsLink = href.replace(/^smb:/, '').replace(/\//g, '\\')
links.add(`<a href="file://${windowsLink}" target="_blank" rel="noopener noreferrer">${windowsLink}</a>`)
}
}
})
return Array.from(links).join('<br>')
} }
window.toast = toast;
export function detectOS() { export function detectOS() {
const platform = window.navigator.platform const platform = window.navigator.platform
const macosPlatforms = ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K'] const macosPlatforms = ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K']
@@ -55,3 +21,69 @@ export function detectOS() {
} }
return 'win' return 'win'
} }
export function prepareHTMLDescription(description) {
if (!description) return description
const os = detectOS()
// make an array from the description of strings from between <p> and </p> tags
const paragraphs = description.split('<p>').map(p => p.split('</p>')[0])
const modifiedParagraphs = paragraphs.map(paragraph => {
const words = paragraph.split(' ')
const modifiedWords = words.map(word => {
let link = null
if (os === 'mac' && word.startsWith('smb://')) {
link = word
} else if (os === 'win' && word.startsWith('\\\\')) {
link = `${word.replace(/\//g, '\\')}`
} else if (os === 'mac' && word.startsWith('\\\\')) {
const smbLink = 'smb:' + word.replace(/\\/g, '/')
link = smbLink
} else if (os === 'win' && word.startsWith('smb://')) {
const windowsLink = word.replace(/^smb:/, '').replace(/\//g, '\\')
link = `${windowsLink}`
}
if (!link) return word
if (os === 'mac') return `<a href="${link}">${link}</a>`
return `<span style="cursor: pointer; text-decoration: underline" onclick="${getCopyFunction(link)}">${link}</span>`
})
return `<p>${modifiedWords.join(' ')}</p>`
})
description = modifiedParagraphs.join('')
return description;
}
function getCopyFunction(text) {
return `
console.log('${text.replace(/\\/g, '\\\\')}')
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText('${text.replace(/\\/g, '\\\\')}').then(() => {
window.toast.success('Link copied to clipboard!')
}).catch(err => {
window.toast.error('Failed to copy link to clipboard!')
});
} else {
const input = document.createElement('input');
input.style.position = 'fixed';
input.style.opacity = 0;
input.style.pointerEvents = 'none';
input.value = '${text.replace(/\\/g, '\\\\')}';
document.body.appendChild(input);
input.select();
input.focus();
document.execCommand('copy');
document.body.removeChild(input);
window.toast.success('Link copied to clipboard!')
}
`
}
@@ -1,22 +1,17 @@
<template> <template>
<div class="px-5 py-5 border-bottom" v-if="description" > <div class="px-5 py-5 border-bottom" v-if="description" >
<p>Popis zadania</p> <p>Popis zadania</p>
<section v-html="description" class="description-detail px-2 py-2 w-100 rounded mt-2" /> <section v-html="preparedDescription" class="description-detail px-2 py-2 w-100 rounded mt-2" />
</div>
<div v-if="hasMasterTaskDescLinks" class="px-5">
<p class="py-3">Odkazy na server</p>
<p class="server-links" v-html="masterTaskDescLinks" />
</div> </div>
<div class="px-5 py-5 border-bottom" v-if="inheritedDescription"> <div class="px-5 py-5 border-bottom" v-if="inheritedDescription">
<p>Popis mastertasku</p> <p>Popis mastertasku</p>
<section v-html="inheritedDescription" class="description-detail px-2 py-2 w-100 rounded mt-2" /> <section v-html="preparedInheritedDescription" class="description-detail px-2 py-2 w-100 rounded mt-2" />
</div> </div>
</template> </template>
<script> <script>
import { getServerLinks } from '@/plugins/tm@_utils/server-links.utils' import { prepareHTMLDescription } from '@/plugins/tm@_utils/server-links.utils'
export default { export default {
props: { props: {
@@ -31,14 +26,17 @@ export default {
} }
}, },
computed: { data() {
masterTaskDescLinks() { return {
return getServerLinks(this.description) copiedIndices: [],
preparedDescription: '',
preparedInheritedDescription: ''
}
}, },
hasMasterTaskDescLinks() { mounted() {
return this.masterTaskDescLinks.trim().length > 0 this.preparedDescription = prepareHTMLDescription(this.description)
} this.preparedInheritedDescription = prepareHTMLDescription(this.inheritedDescription)
} }
} }
</script> </script>
@@ -298,7 +298,7 @@ export default {
async save() { async save() {
if (this.mastertask.id) { if (this.mastertask.id) {
this.mastertask.employees = this.mastertask.employees.map(employee => { this.mastertask.employees = this.mastertask.employees.map(employee => {
const { duration } = this.mastertask.subtasks.find(({ employee_id }) => employee_id == employee.id) const { duration } = this.mastertask.subtasks.find(({ employee_id }) => employee_id == employee.id) || {}
employee.duration = duration employee.duration = duration
return employee return employee
}) })
@@ -1,27 +1,17 @@
<template> <template>
<div class="px-5 py-5 border-bottom" v-if="description" > <div class="px-5 py-5 border-bottom" v-if="description" >
<p>Popis zadania</p> <p>Popis zadania</p>
<section v-html="description" class="description-detail px-2 py-2 w-100 rounded mt-2" /> <section v-html="preparedDescription" class="description-detail px-2 py-2 w-100 rounded mt-2" />
</div>
<div v-if="hasSubtaskDescLinks" class="px-5">
<p class="py-3">Odkazy na server</p>
<p class="server-links" v-html="subtaskDescLinks" />
</div> </div>
<div class="px-5 py-5 border-bottom" v-if="mastertaskDescription"> <div class="px-5 py-5 border-bottom" v-if="mastertaskDescription">
<p>Popis mastertasku</p> <p>Popis mastertasku</p>
<section v-html="mastertaskDescription" class="description-detail px-2 py-2 w-100 rounded mt-2" /> <section v-html="preparedMastertaskDescription" class="description-detail px-2 py-2 w-100 rounded mt-2" />
</div>
<div v-if="hasSubtaskMTDescLinks" class="px-5">
<p class="py-3">Odkazy na server</p>
<p class="server-links" v-html="subtaskMTDecsLinks" />
</div> </div>
</template> </template>
<script> <script>
import { getServerLinks } from '@/plugins/tm@_utils/server-links.utils' import { prepareHTMLDescription } from '@/plugins/tm@_utils/server-links.utils'
export default { export default {
props: { props: {
@@ -36,22 +26,17 @@ export default {
} }
}, },
computed: { data() {
subtaskDescLinks() { return {
return getServerLinks(this.description) copiedIndices: [],
}, preparedDescription: '',
preparedMastertaskDescription: ''
subtaskMTDecsLinks() {
return getServerLinks(this.mastertaskDescription)
},
hasSubtaskDescLinks() {
return this.subtaskDescLinks.trim().length > 0
},
hasSubtaskMTDescLinks() {
return this.subtaskMTDecsLinks.trim().length > 0
}
} }
},
mounted() {
this.preparedDescription = prepareHTMLDescription(this.description)
this.preparedMastertaskDescription = prepareHTMLDescription(this.mastertaskDescription)
},
} }
</script> </script>