added copy image link on context menu with relative italian translation
This commit is contained in:
parent
76f354e3de
commit
6a0966034e
29
README.md
29
README.md
@ -4,33 +4,34 @@ This is just the WebUI for deemix, it should be used with deemix-pyweb or someth
|
|||||||
|
|
||||||
## What's left to do?
|
## What's left to do?
|
||||||
|
|
||||||
- Use Vue as much as possible
|
- [ ] Use Vue app-wide
|
||||||
- First step: rewrite the app in Single File Components way ✅
|
- First step: rewrite the app in Single File Components way ✅
|
||||||
- Second step: Implement custom contextmenu ⚒
|
- Second step: Implement routing for the whole app using Vue Router ⚒
|
||||||
|
- Third step: Remove jQuery
|
||||||
|
- [ ] Implement custom contextmenu ⚒
|
||||||
- Copy and paste functions ✅
|
- Copy and paste functions ✅
|
||||||
- Copy Link where possible ✅
|
- Copy Link where possible ✅
|
||||||
- Copy Image URL where possible
|
- Download Quality ✅
|
||||||
- Define cases
|
- Copy Image URL where possible ✅
|
||||||
- Third step: Implement routing for the whole app using Vue Router
|
- Resolve problem when positioning out of window (e.g. clicking on the bottom of the window)
|
||||||
- Fourth step: Remove jQuery
|
- [ ] Make i18n async (https://kazupon.github.io/vue-i18n/guide/lazy-loading.html)
|
||||||
- Make i18n async (https://kazupon.github.io/vue-i18n/guide/lazy-loading.html)
|
|
||||||
- Use ES2020 async imports, if possible
|
- Use ES2020 async imports, if possible
|
||||||
- Make the UI look coherent
|
- [ ] Make the UI look coherent
|
||||||
- Style buttons
|
- Style buttons
|
||||||
- Style text inputs
|
- Style text inputs
|
||||||
- Style checkboxes
|
- Style checkboxes
|
||||||
- Search tab
|
- [ ] Search tab
|
||||||
- Better placeholer before search
|
- Better placeholer before search
|
||||||
- Link Analyzer
|
- [ ] Link Analyzer
|
||||||
- Better placeholer before analyzing and error feedback
|
- Better placeholer before analyzing and error feedback
|
||||||
- Settings tab
|
- [ ] Settings tab
|
||||||
- Maybe tabbing the section for easy navigation
|
- Maybe tabbing the section for easy navigation
|
||||||
- Could use a carousel, but it's not worth adding a new dep
|
- Could use a carousel, but it's not worth adding a new dep
|
||||||
- Variable selector near template inputs
|
- Variable selector near template inputs
|
||||||
- Block selection where it's not needed (keep only titles artists albums labels and useful data)
|
- [ ] Block selection where it's not needed (keep only titles artists albums labels and useful data)
|
||||||
- There's a SASS mixin for this. Need to use it in the proper classes
|
- There's a SASS mixin for this. Need to use it in the proper classes
|
||||||
- Better feedback for socket.io possible errors
|
- [ ] Better feedback for socket.io possible errors
|
||||||
- Remove images size limit and add warning if > 1200
|
- [ ] Remove images size limit and add warning if > 1200
|
||||||
- ?
|
- ?
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
File diff suppressed because one or more lines are too long
@ -2,7 +2,7 @@
|
|||||||
<div class="context-menu" v-show="menuOpen" ref="contextMenu" :style="{ top: yPos, left: xPos }">
|
<div class="context-menu" v-show="menuOpen" ref="contextMenu" :style="{ top: yPos, left: xPos }">
|
||||||
<button
|
<button
|
||||||
class="menu-option"
|
class="menu-option"
|
||||||
v-for="option of options"
|
v-for="option of sortedOptions"
|
||||||
:key="option.label"
|
:key="option.label"
|
||||||
v-show="option.show"
|
v-show="option.show"
|
||||||
@click.prevent="option.action"
|
@click.prevent="option.action"
|
||||||
@ -23,7 +23,8 @@ export default {
|
|||||||
xPos: 0,
|
xPos: 0,
|
||||||
yPos: 0,
|
yPos: 0,
|
||||||
deezerHref: '',
|
deezerHref: '',
|
||||||
generalHref: ''
|
generalHref: '',
|
||||||
|
imgSrc: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -31,63 +32,85 @@ export default {
|
|||||||
// In the action property:
|
// In the action property:
|
||||||
// Use arrow functions to keep the Vue instance in 'this'
|
// Use arrow functions to keep the Vue instance in 'this'
|
||||||
// Use normal functions to keep the object instance in 'this'
|
// Use normal functions to keep the object instance in 'this'
|
||||||
|
const options = {
|
||||||
const options = [
|
cut: {
|
||||||
{
|
|
||||||
label: this.$t('globals.cut'),
|
label: this.$t('globals.cut'),
|
||||||
show: true,
|
show: true,
|
||||||
|
position: 1,
|
||||||
action: () => {
|
action: () => {
|
||||||
document.execCommand('Cut')
|
document.execCommand('Cut')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
copy: {
|
||||||
label: this.$t('globals.copy'),
|
label: this.$t('globals.copy'),
|
||||||
show: true,
|
show: true,
|
||||||
|
position: 2,
|
||||||
action: () => {
|
action: () => {
|
||||||
document.execCommand('Copy')
|
document.execCommand('Copy')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
copyLink: {
|
||||||
label: this.$t('globals.copyLink'),
|
label: this.$t('globals.copyLink'),
|
||||||
show: false,
|
show: false,
|
||||||
|
position: 3,
|
||||||
action: () => {
|
action: () => {
|
||||||
navigator.clipboard.writeText(this.generalHref).catch(err => {
|
navigator.clipboard.writeText(this.generalHref).catch(err => {
|
||||||
console.error('Link copying failed', err)
|
console.error('Link copying failed', err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
copyImageLink: {
|
||||||
label: this.$t('globals.copyDeezerLink'),
|
label: this.$t('globals.copyImageLink'),
|
||||||
show: false,
|
show: false,
|
||||||
|
position: 4,
|
||||||
action: () => {
|
action: () => {
|
||||||
navigator.clipboard.writeText(this.deezerHref).catch(err => {
|
navigator.clipboard.writeText(this.imgSrc).catch(err => {
|
||||||
console.error('Download link copying failed', err)
|
console.error('Image copying failed', err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
copyDeezerLink: {
|
||||||
|
label: this.$t('globals.copyDeezerLink'),
|
||||||
|
show: false,
|
||||||
|
position: 5,
|
||||||
|
action: () => {
|
||||||
|
navigator.clipboard.writeText(this.generalHref).catch(err => {
|
||||||
|
console.error('Deezer link copying failed', err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
paste: {
|
||||||
label: this.$t('globals.paste'),
|
label: this.$t('globals.paste'),
|
||||||
show: true,
|
show: true,
|
||||||
|
position: 6,
|
||||||
action: () => {
|
action: () => {
|
||||||
navigator.clipboard.readText().then(text => {
|
navigator.clipboard.readText().then(text => {
|
||||||
document.execCommand('insertText', undefined, text)
|
document.execCommand('insertText', undefined, text)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
|
||||||
downloadQualities.forEach(quality => {
|
let nextValuePosition = Object.values(options).length + 1
|
||||||
options.push({
|
|
||||||
|
downloadQualities.forEach((quality, index) => {
|
||||||
|
options[quality.objName] = {
|
||||||
label: `${this.$t('globals.download', [quality.label])}`,
|
label: `${this.$t('globals.download', [quality.label])}`,
|
||||||
show: false,
|
show: false,
|
||||||
|
position: nextValuePosition + index,
|
||||||
action: this.tryToDownloadTrack.bind(null, quality.value)
|
action: this.tryToDownloadTrack.bind(null, quality.value)
|
||||||
})
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return options
|
return options
|
||||||
},
|
},
|
||||||
qualities() {
|
// This computed property is used for rendering the options in the wanted order
|
||||||
return downloadQualities
|
// while keeping the options computed property an Object to make the properties
|
||||||
|
// accessible via property name (es this.options.copy)
|
||||||
|
sortedOptions() {
|
||||||
|
return Object.values(this.options).sort((first, second) => {
|
||||||
|
return first.position < second.position ? -1 : 1
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@ -110,24 +133,30 @@ export default {
|
|||||||
// Show 'Copy Link' option
|
// Show 'Copy Link' option
|
||||||
if (elementClicked.matches('a')) {
|
if (elementClicked.matches('a')) {
|
||||||
this.generalHref = elementClicked.href
|
this.generalHref = elementClicked.href
|
||||||
this.showCopyLinkOption()
|
this.options.copyLink.show = true
|
||||||
}
|
}
|
||||||
|
|
||||||
let link = null
|
// Show 'Copy Image Link' option
|
||||||
|
if (elementClicked.matches('img')) {
|
||||||
|
this.imgSrc = elementClicked.src
|
||||||
|
this.options.copyImageLink.show = true
|
||||||
|
}
|
||||||
|
|
||||||
|
let deezerLink = null
|
||||||
|
|
||||||
for (let i = 0; i < path.length; i++) {
|
for (let i = 0; i < path.length; i++) {
|
||||||
if (path[i] == document) break
|
if (path[i] == document) break
|
||||||
|
|
||||||
if (path[i].matches('[data-link]')) {
|
if (path[i].matches('[data-link]')) {
|
||||||
link = path[i].dataset.link
|
deezerLink = path[i].dataset.link
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show 'Copy Deezer Link' option
|
// Show 'Copy Deezer Link' option
|
||||||
if (link) {
|
if (deezerLink) {
|
||||||
this.deezerHref = link
|
this.deezerHref = deezerLink
|
||||||
this.showDeezerOptions(link)
|
this.showDeezerOptions()
|
||||||
}
|
}
|
||||||
|
|
||||||
this.menuOpen = true
|
this.menuOpen = true
|
||||||
@ -136,30 +165,32 @@ export default {
|
|||||||
if (!this.menuOpen) return
|
if (!this.menuOpen) return
|
||||||
|
|
||||||
// Finish all operations before closing (may be not necessary)
|
// Finish all operations before closing (may be not necessary)
|
||||||
this.$nextTick().then(() => {
|
this.$nextTick()
|
||||||
|
.then(() => {
|
||||||
this.menuOpen = false
|
this.menuOpen = false
|
||||||
|
|
||||||
this.options[2].show = false
|
this.options.copyLink.show = false
|
||||||
this.options[3].show = false
|
this.options.copyDeezerLink.show = false
|
||||||
|
this.options.copyImageLink.show = false
|
||||||
|
|
||||||
for (i = 5; i <= 10; i++) {
|
downloadQualities.forEach(quality => {
|
||||||
this.options[i].show = false
|
this.options[quality.objName].show = false
|
||||||
}
|
})
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
positionMenu(newX, newY) {
|
positionMenu(newX, newY) {
|
||||||
this.xPos = `${newX}px`
|
this.xPos = `${newX}px`
|
||||||
this.yPos = `${newY}px`
|
this.yPos = `${newY}px`
|
||||||
},
|
},
|
||||||
showCopyLinkOption() {
|
|
||||||
this.options[2].show = true
|
|
||||||
},
|
|
||||||
showDeezerOptions() {
|
showDeezerOptions() {
|
||||||
this.options[3].show = true
|
this.options.copyDeezerLink.show = true
|
||||||
|
|
||||||
for (i = 5; i <= 10; i++) {
|
downloadQualities.forEach(quality => {
|
||||||
this.options[i].show = true
|
this.options[quality.objName].show = true
|
||||||
}
|
})
|
||||||
},
|
},
|
||||||
tryToDownloadTrack(qualityValue) {
|
tryToDownloadTrack(qualityValue) {
|
||||||
Downloads.sendAddToQueue(this.deezerHref, qualityValue)
|
Downloads.sendAddToQueue(this.deezerHref, qualityValue)
|
||||||
|
@ -1,25 +1,31 @@
|
|||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
|
objName: 'flac',
|
||||||
label: 'FLAC',
|
label: 'FLAC',
|
||||||
value: 9
|
value: 9
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
objName: '320kbps',
|
||||||
label: 'MP3 320kbps',
|
label: 'MP3 320kbps',
|
||||||
value: 3
|
value: 3
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
objName: '128kbps',
|
||||||
label: 'MP3 128kbps',
|
label: 'MP3 128kbps',
|
||||||
value: 1
|
value: 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
objName: 'realityAudioHQ',
|
||||||
label: '360 Reality Audio [HQ]',
|
label: '360 Reality Audio [HQ]',
|
||||||
value: 15
|
value: 15
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
objName: 'realityAudioMQ',
|
||||||
label: '360 Reality Audio [MQ]',
|
label: '360 Reality Audio [MQ]',
|
||||||
value: 14
|
value: 14
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
objName: 'realityAudioLQ',
|
||||||
label: '360 Reality Audio [LQ]',
|
label: '360 Reality Audio [LQ]',
|
||||||
value: 13
|
value: 13
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ const en = {
|
|||||||
cut: 'cut',
|
cut: 'cut',
|
||||||
copy: 'copy',
|
copy: 'copy',
|
||||||
copyLink: 'copy link',
|
copyLink: 'copy link',
|
||||||
|
copyImageLink: 'copy image link',
|
||||||
copyDeezerLink: 'copy deezer link',
|
copyDeezerLink: 'copy deezer link',
|
||||||
paste: 'paste',
|
paste: 'paste',
|
||||||
listTabs: {
|
listTabs: {
|
||||||
|
@ -14,6 +14,7 @@ const it = {
|
|||||||
cut: 'taglia',
|
cut: 'taglia',
|
||||||
copy: 'copia',
|
copy: 'copia',
|
||||||
copyLink: 'copia link',
|
copyLink: 'copia link',
|
||||||
|
copyImageLink: 'copia link immagine',
|
||||||
copyDeezerLink: 'copia link deezer',
|
copyDeezerLink: 'copia link deezer',
|
||||||
paste: 'incolla',
|
paste: 'incolla',
|
||||||
listTabs: {
|
listTabs: {
|
||||||
|
Loading…
Reference in New Issue
Block a user