Moves item reusable methods into mixin

This commit is contained in:
Alicia Sykes 2022-02-15 11:11:40 +00:00
parent 5bc9a5f660
commit 11c59504dc
2 changed files with 145 additions and 144 deletions

View File

@ -1,6 +1,6 @@
<template ref="container">
<div :class="`item-wrapper wrap-size-${itemSize}`">
<a @click="itemOpened"
<a @click="beforeLaunchItem"
@mouseup.right="openContextMenu"
@contextmenu.prevent
:href="hyperLinkHref"
@ -9,7 +9,7 @@
v-tooltip="getTooltipOptions()"
rel="noopener noreferrer" tabindex="0"
:id="`link-${id}`"
:style="`--open-icon: ${getUnicodeOpeningIcon()}; color: ${color}; ${customStyles}`"
:style="`--open-icon:${unicodeOpeningIcon};color:${color};background:${backgroundColor}`"
>
<!-- Item Text -->
<div :class="`tile-title ${!icon? 'bounce no-icon': ''}`" :id="`tile-${id}`" >
@ -23,7 +23,7 @@
<ItemOpenMethodIcon class="opening-method-icon" :isSmall="!icon || itemSize === 'small'"
:openingMethod="accumulatedTarget" position="bottom right"
:hotkey="hotkey" />
<!-- Status indicator dot (if enabled) showing weather srevice is availible -->
<!-- Status indicator dot (if enabled) showing weather service is available -->
<StatusIndicator
class="status-indicator"
v-if="enableStatusCheck"
@ -54,8 +54,6 @@
</template>
<script>
import axios from 'axios';
import router from '@/router';
import Icon from '@/components/LinkItems/ItemIcon.vue';
import ItemOpenMethodIcon from '@/components/LinkItems/ItemOpenMethodIcon';
import StatusIndicator from '@/components/LinkItems/StatusIndicator';
@ -66,11 +64,7 @@ import StoreKeys from '@/utils/StoreMutations';
import ItemMixin from '@/mixins/ItemMixin';
import { targetValidator } from '@/utils/ConfigHelpers';
import EditModeIcon from '@/assets/interface-icons/interactive-editor-edit-mode.svg';
import {
localStorageKeys,
serviceEndpoints,
modalNames,
} from '@/utils/defaults';
import { modalNames } from '@/utils/defaults';
export default {
name: 'Item',
@ -118,63 +112,54 @@ export default {
return `size-${itemSize} ${!icon ? 'short' : ''} `
+ `${isAddNew ? 'add-new' : ''} ${isEditMode ? 'is-edit-mode' : ''}`;
},
/* Used by certain themes (material), to show animated CSS icon */
unicodeOpeningIcon() {
switch (this.accumulatedTarget) {
case 'newtab': return '"\\f360"';
case 'sametab': return '"\\f24d"';
case 'parent': return '"\\f3bf"';
case 'top': return '"\\f102"';
case 'modal': return '"\\f2d0"';
case 'workspace': return '"\\f0b1"';
case 'clipboard': return '"\\f0ea"';
default: return '"\\f054"';
}
},
},
data() {
return {
contextMenuOpen: false,
getId: this.id,
editMenuOpen: false,
customStyles: {
color: this.color,
background: this.backgroundColor,
},
statusResponse: undefined,
contextPos: {
posX: undefined,
posY: undefined,
},
editMenuOpen: false,
};
},
methods: {
/* Called when an item is clicked, manages the opening of modal & resets the search field */
itemOpened(e) {
if (this.isEditMode) {
// If in edit mode, open settings, and don't launch app
beforeLaunchItem(e) {
if (this.isEditMode) { // If in edit mode, open settings, don't launch app
this.openItemSettings();
return;
}
if (e.altKey || this.accumulatedTarget === 'modal') {
if (e.altKey) {
e.preventDefault();
this.$emit('triggerModal', this.url);
this.launchItem('modal');
} else if (this.accumulatedTarget === 'modal') {
this.launchItem('modal');
} else if (this.accumulatedTarget === 'workspace') {
router.push({ name: 'workspace', query: { url: this.url } });
this.launchItem('workspace');
} else if (this.accumulatedTarget === 'clipboard') {
navigator.clipboard.writeText(this.url);
this.$toasted.show(this.$t('context-menus.item.copied-toast'));
} else {
this.$emit('itemClicked');
this.launchItem('clipboard');
}
// Clear search bar
this.$emit('itemClicked');
// Update the most/ last used ledger, for smart-sorting
if (!this.appConfig.disableSmartSort) {
this.incrementMostUsedCount(this.id);
this.incrementLastUsedCount(this.id);
}
},
/* Open custom context menu, and set position */
openContextMenu(e) {
this.contextMenuOpen = !this.contextMenuOpen;
if (e && window) {
// Calculate placement based on cursor and scroll position
this.contextPos = {
posX: e.clientX + window.pageXOffset,
posY: e.clientY + window.pageYOffset,
};
}
},
/* Closes the context menu, called when user clicks literally anywhere */
closeContextMenu() {
this.contextMenuOpen = false;
},
/* Returns configuration object for the tooltip */
getTooltipOptions() {
if (!this.description && !this.provider) return {}; // If no description, then skip
@ -194,79 +179,7 @@ export default {
classes: `item-description-tooltip tooltip-is-${this.itemSize}`,
};
},
/* Used by certain themes (material), to show animated CSS icon */
getUnicodeOpeningIcon() {
switch (this.accumulatedTarget) {
case 'newtab': return '"\\f360"';
case 'sametab': return '"\\f24d"';
case 'parent': return '"\\f3bf"';
case 'top': return '"\\f102"';
case 'modal': return '"\\f2d0"';
case 'workspace': return '"\\f0b1"';
case 'clipboard': return '"\\f0ea"';
default: return '"\\f054"';
}
},
/* Pulls together all user options, returns URL + Get params for ping endpoint */
makeApiUrl() {
const {
url, statusCheckUrl, statusCheckHeaders, statusCheckAllowInsecure, statusCheckAcceptCodes,
} = this;
const encode = (str) => encodeURIComponent(str);
this.statusResponse = undefined;
// Find base URL, where the API is hosted
const baseUrl = process.env.VUE_APP_DOMAIN || window.location.origin;
// Find correct URL to check, and encode
const urlToCheck = `?&url=${encode(statusCheckUrl || url)}`;
// Get, stringify and encode any headers
const headers = statusCheckHeaders
? `&headers=${encode(JSON.stringify(statusCheckHeaders))}` : '';
// Deterimine if user disabled security
const enableInsecure = statusCheckAllowInsecure ? '&enableInsecure=true' : '';
const acceptCodes = statusCheckAcceptCodes ? `&acceptCodes=${statusCheckAcceptCodes}` : '';
// Construct the full API endpoint's URL with GET params
return `${baseUrl}${serviceEndpoints.statusCheck}/${urlToCheck}`
+ `${headers}${enableInsecure}${acceptCodes}`;
},
/* Checks if a given service is currently online */
checkWebsiteStatus() {
const endpoint = this.makeApiUrl();
axios.get(endpoint)
.then((response) => {
if (response.data) this.statusResponse = response.data;
})
.catch(() => { // Something went very wrong.
this.statusResponse = {
statusText: 'Failed to make request',
statusSuccess: false,
};
});
},
/* Handle navigation options from the context menu */
launchItem(method) {
const { url } = this;
this.contextMenuOpen = false;
switch (method) {
case 'newtab':
window.open(url, '_blank');
break;
case 'sametab':
window.open(url, '_self');
break;
case 'modal':
this.$emit('triggerModal', url);
break;
case 'workspace':
router.push({ name: 'workspace', query: { url } });
break;
case 'clipboard':
navigator.clipboard.writeText(url);
this.$toasted.show(this.$t('context-menus.item.copied-toast'));
break;
default: window.open(url, '_blank');
}
},
/* Open the Edit Item moal form */
/* Open the Edit Item modal form */
openItemSettings() {
this.editMenuOpen = true;
this.contextMenuOpen = false;
@ -279,20 +192,6 @@ export default {
this.$modal.hide(modalNames.EDIT_ITEM);
this.$store.commit(StoreKeys.SET_MODAL_OPEN, false);
},
/* Used for smart-sort when sorting items by most used apps */
incrementMostUsedCount(itemId) {
const mostUsed = JSON.parse(localStorage.getItem(localStorageKeys.MOST_USED) || '{}');
let counter = mostUsed[itemId] || 0;
counter += 1;
mostUsed[itemId] = counter;
localStorage.setItem(localStorageKeys.MOST_USED, JSON.stringify(mostUsed));
},
/* Used for smart-sort when sorting by last used apps */
incrementLastUsedCount(itemId) {
const lastUsed = JSON.parse(localStorage.getItem(localStorageKeys.LAST_USED) || '{}');
lastUsed[itemId] = new Date().getTime();
localStorage.setItem(localStorageKeys.LAST_USED, JSON.stringify(lastUsed));
},
/* Open the modal for moving/ copying item to other section */
openMoveItemMenu() {
this.$modal.show(`${modalNames.MOVE_ITEM_TO}-${this.id}`);
@ -348,20 +247,16 @@ export default {
box-shadow: var(--item-hover-shadow);
background: var(--item-background-hover);
color: var(--item-text-color-hover);
// position: relative;
// .tile-title span.text {
// white-space: pre-wrap;
// }
}
&:focus {
outline: 2px solid var(--primary);
}
&.short:not(.size-large) {
height: 2rem;
}
&.add-new {
border: 2px dashed var(--primary) !important;
}
&.short:not(.size-large) {
height: 2rem;
}
}
/* Text in tile */
@ -410,13 +305,13 @@ export default {
}
}
/* Apply transofmation of icons on hover */
/* Apply transformation of icons on hover */
.tile-icon, .tile-svg {
filter: var(--item-icon-transform-hover);
}
}
/* Edit Mode Icon */
/* Edit icon, visible in edit mode */
.item .edit-mode-item {
width: 1rem;
height: 1rem;
@ -425,6 +320,10 @@ export default {
right: 0.2rem;
}
p.description {
display: none; // By default, we don't show the description
}
/* Specify layout for alternate sized icons */
.item {
/* Small Tile Specific Themes */
@ -506,9 +405,6 @@ export default {
}
}
}
p.description {
display: none; // By default, we don't show the description
}
&:before { // Certain themes (e.g. material) show css animated fas icon on hover
display: none;
font-family: FontAwesome;

View File

@ -1,7 +1,23 @@
/** Reusable mixin for items */
import { openingMethod as defaultOpeningMethod } from '@/utils/defaults';
import axios from 'axios';
import router from '@/router';
import {
openingMethod as defaultOpeningMethod,
serviceEndpoints,
localStorageKeys,
} from '@/utils/defaults';
export default {
data() {
return {
statusResponse: undefined,
contextMenuOpen: false,
contextPos: {
posX: undefined,
posY: undefined,
},
};
},
computed: {
appConfig() {
return this.$store.getters.appConfig;
@ -32,6 +48,95 @@ export default {
const noAnchorNeeded = ['modal', 'workspace', 'clipboard'];
return noAnchorNeeded.includes(this.accumulatedTarget) ? nothing : url;
},
/* Pulls together all user options, returns URL + Get params for ping endpoint */
makeApiUrl() {
const {
url, statusCheckUrl, statusCheckHeaders, statusCheckAllowInsecure, statusCheckAcceptCodes,
} = this;
const encode = (str) => encodeURIComponent(str);
this.statusResponse = undefined;
// Find base URL, where the API is hosted
const baseUrl = process.env.VUE_APP_DOMAIN || window.location.origin;
// Find correct URL to check, and encode
const urlToCheck = `?&url=${encode(statusCheckUrl || url)}`;
// Get, stringify and encode any headers
const headers = statusCheckHeaders
? `&headers=${encode(JSON.stringify(statusCheckHeaders))}` : '';
// Deterimine if user disabled security
const enableInsecure = statusCheckAllowInsecure ? '&enableInsecure=true' : '';
const acceptCodes = statusCheckAcceptCodes ? `&acceptCodes=${statusCheckAcceptCodes}` : '';
// Construct the full API endpoint's URL with GET params
return `${baseUrl}${serviceEndpoints.statusCheck}/${urlToCheck}`
+ `${headers}${enableInsecure}${acceptCodes}`;
},
/* Checks if a given service is currently online */
checkWebsiteStatus() {
const endpoint = this.makeApiUrl();
axios.get(endpoint)
.then((response) => {
if (response.data) this.statusResponse = response.data;
})
.catch(() => { // Something went very wrong.
this.statusResponse = {
statusText: 'Failed to make request',
statusSuccess: false,
};
});
},
},
methods: {
/* Open item, using specified method */
launchItem(method, link) {
const url = link || this.url;
this.contextMenuOpen = false;
switch (method) {
case 'newtab':
window.open(url, '_blank');
break;
case 'sametab':
window.open(url, '_self');
break;
case 'modal':
this.$emit('triggerModal', url);
break;
case 'workspace':
router.push({ name: 'workspace', query: { url } });
break;
case 'clipboard':
navigator.clipboard.writeText(url);
this.$toasted.show(this.$t('context-menus.item.copied-toast'));
break;
default: window.open(url, '_blank');
}
},
/* Open custom context menu, and set position */
openContextMenu(e) {
this.contextMenuOpen = !this.contextMenuOpen;
if (e && window) {
// Calculate placement based on cursor and scroll position
this.contextPos = {
posX: e.clientX + window.pageXOffset,
posY: e.clientY + window.pageYOffset,
};
}
},
/* Closes the context menu, called when user clicks literally anywhere */
closeContextMenu() {
this.contextMenuOpen = false;
},
/* Used for smart-sort when sorting items by most used apps */
incrementMostUsedCount(itemId) {
const mostUsed = JSON.parse(localStorage.getItem(localStorageKeys.MOST_USED) || '{}');
let counter = mostUsed[itemId] || 0;
counter += 1;
mostUsed[itemId] = counter;
localStorage.setItem(localStorageKeys.MOST_USED, JSON.stringify(mostUsed));
},
/* Used for smart-sort when sorting by last used apps */
incrementLastUsedCount(itemId) {
const lastUsed = JSON.parse(localStorage.getItem(localStorageKeys.LAST_USED) || '{}');
lastUsed[itemId] = new Date().getTime();
localStorage.setItem(localStorageKeys.LAST_USED, JSON.stringify(lastUsed));
},
},
methods: {},
};