🔀 Rebased from master
This commit is contained in:
@@ -231,8 +231,8 @@ export default {
|
||||
const newItem = item;
|
||||
newItem.id = this.itemId;
|
||||
if (newItem.hotkey) newItem.hotkey = parseInt(newItem.hotkey, 10);
|
||||
const strToTags = (str) => {
|
||||
const tagArr = str.split(',');
|
||||
const strToTags = (tags) => {
|
||||
const tagArr = (typeof tags === 'string') ? tags.split(',') : tags;
|
||||
return tagArr.map((tag) => tag.trim().toLowerCase().replace(/[^a-z0-9]+/, ''));
|
||||
};
|
||||
const strToBool = (str) => {
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
<h3>{{ title }}</h3>
|
||||
<EditModeIcon v-if="isEditMode" @click="openEditModal"
|
||||
v-tooltip="editTooltip()" class="edit-mode-item" />
|
||||
<OpenIcon @click.prevent.stop="openContextMenu" @contextmenu.prevent
|
||||
class="edit-mode-item" />
|
||||
</label>
|
||||
<div class="collapsible-content">
|
||||
<div class="content-inner">
|
||||
@@ -31,6 +33,7 @@
|
||||
import { localStorageKeys } from '@/utils/defaults';
|
||||
import Icon from '@/components/LinkItems/ItemIcon.vue';
|
||||
import EditModeIcon from '@/assets/interface-icons/interactive-editor-edit-mode.svg';
|
||||
import OpenIcon from '@/assets/interface-icons/config-open-settings.svg';
|
||||
|
||||
export default {
|
||||
name: 'CollapsableContainer',
|
||||
@@ -48,6 +51,7 @@ export default {
|
||||
components: {
|
||||
Icon,
|
||||
EditModeIcon,
|
||||
OpenIcon,
|
||||
},
|
||||
computed: {
|
||||
isEditMode() {
|
||||
@@ -244,6 +248,8 @@ export default {
|
||||
float: right;
|
||||
right: 0.5rem;
|
||||
top: 0.5rem;
|
||||
margin-left: 0.2rem;
|
||||
margin-right: 0.2rem;
|
||||
}
|
||||
|
||||
/* Makes sections fill available space */
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
classes="dashy-modal">
|
||||
<div slot="top-right" @click="hide()">Close</div>
|
||||
<a @click="hide()" class="close-button" title="Close">x</a>
|
||||
<iframe v-if="url" :src="url" @keydown.esc="close" class="frame"/>
|
||||
<iframe v-if="url" :src="url" @keydown.esc="close" class="frame" allow="fullscreen" />
|
||||
<div v-else class="no-url">No URL Specified</div>
|
||||
</modal>
|
||||
</template>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template ref="container">
|
||||
<div :class="`item-wrapper wrap-size-${itemSize}`">
|
||||
<a @click="beforeLaunchItem"
|
||||
<a @click="itemClicked"
|
||||
@mouseup.right="openContextMenu"
|
||||
@contextmenu.prevent
|
||||
:href="hyperLinkHref"
|
||||
:href="url"
|
||||
:target="anchorTarget"
|
||||
:class="`item ${makeClassList}`"
|
||||
v-tooltip="getTooltipOptions()"
|
||||
@@ -91,6 +91,7 @@ export default {
|
||||
statusCheckInterval: Number, // Num seconds beteween repeating checks
|
||||
statusCheckAllowInsecure: Boolean, // Status check ignore SSL certs
|
||||
statusCheckAcceptCodes: String, // Allow status checks to pass with a code other than 200
|
||||
statusCheckMaxRedirects: Number, // Specify max number of redirects
|
||||
parentSectionTitle: String, // Title of parent section (for add new)
|
||||
isAddNew: Boolean, // Only set if 'fake' item used as Add New button
|
||||
},
|
||||
@@ -136,30 +137,6 @@ export default {
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
/* Called when an item is clicked, manages the opening of modal & resets the search field */
|
||||
beforeLaunchItem(e) {
|
||||
if (this.isEditMode) { // If in edit mode, open settings, don't launch app
|
||||
this.openItemSettings();
|
||||
return;
|
||||
}
|
||||
if (e.altKey) {
|
||||
e.preventDefault();
|
||||
this.launchItem('modal');
|
||||
} else if (this.accumulatedTarget === 'modal') {
|
||||
this.launchItem('modal');
|
||||
} else if (this.accumulatedTarget === 'workspace') {
|
||||
this.launchItem('workspace');
|
||||
} else if (this.accumulatedTarget === 'clipboard') {
|
||||
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);
|
||||
}
|
||||
},
|
||||
/* Returns configuration object for the tooltip */
|
||||
getTooltipOptions() {
|
||||
if (!this.description && !this.provider) return {}; // If no description, then skip
|
||||
@@ -179,7 +156,6 @@ export default {
|
||||
classes: `item-description-tooltip tooltip-is-${this.itemSize}`,
|
||||
};
|
||||
},
|
||||
/* Open the Edit Item modal form */
|
||||
openItemSettings() {
|
||||
this.editMenuOpen = true;
|
||||
this.contextMenuOpen = false;
|
||||
|
||||
@@ -45,11 +45,11 @@ export default {
|
||||
return this.$store.getters.appConfig;
|
||||
},
|
||||
/* Determines the type of icon */
|
||||
iconType: function iconType() {
|
||||
iconType() {
|
||||
return this.determineImageType(this.icon);
|
||||
},
|
||||
/* Gets the icon path, dependent on icon type */
|
||||
iconPath: function iconPath() {
|
||||
iconPath() {
|
||||
if (this.broken) return this.getFallbackIcon();
|
||||
return this.getIconPath(this.icon, this.url);
|
||||
},
|
||||
@@ -176,7 +176,7 @@ export default {
|
||||
},
|
||||
/* Fetches the path of local images, from Docker container */
|
||||
getLocalImagePath(img) {
|
||||
return `${iconCdns.localPath}/${img}`;
|
||||
return `/${iconCdns.localPath}/${img}`;
|
||||
},
|
||||
/* Formats the URL for fetching the generative icons */
|
||||
getGenerativeIcon(url, cdn) {
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
:statusCheckInterval="statusCheckInterval"
|
||||
:statusCheckAllowInsecure="item.statusCheckAllowInsecure"
|
||||
:statusCheckAcceptCodes="item.statusCheckAcceptCodes"
|
||||
:statusCheckMaxRedirects="item.statusCheckMaxRedirects"
|
||||
@itemClicked="$emit('itemClicked')"
|
||||
@triggerModal="triggerModal"
|
||||
:isAddNew="false"
|
||||
@@ -166,7 +167,7 @@ export default {
|
||||
return this.$store.state.editMode;
|
||||
},
|
||||
itemSize() {
|
||||
return this.$store.getters.iconSize;
|
||||
return this.displayData.itemSize || this.$store.getters.iconSize;
|
||||
},
|
||||
sortOrder() {
|
||||
return this.displayData.sortBy || defaultSortOrder;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<transition name="slide">
|
||||
<div class="context-menu" v-if="show && !isMenuDisabled"
|
||||
:style="posX && posY ? `top:${posY}px;left:${posX}px;` : ''">
|
||||
:style="posX && posY ? calcPosition() : ''">
|
||||
<!-- Open Options -->
|
||||
<ul class="menu-section">
|
||||
<li @click="openSection()">
|
||||
@@ -59,6 +59,13 @@ export default {
|
||||
removeSection() {
|
||||
this.$emit('removeSection');
|
||||
},
|
||||
calcPosition() {
|
||||
const bounds = this.$parent.$el.getBoundingClientRect();
|
||||
const left = this.posX < (bounds.right + bounds.left) / 2;
|
||||
const position = `top:${this.posY}px;${left ? 'left' : 'right'}:\
|
||||
${left ? this.posX : document.documentElement.clientWidth - this.posX}px;`;
|
||||
return position;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
:enableStatusCheck="shouldEnableStatusCheck(item.statusCheck)"
|
||||
:statusCheckAllowInsecure="item.statusCheckAllowInsecure"
|
||||
:statusCheckAcceptCodes="item.statusCheckAcceptCodes"
|
||||
:statusCheckMaxRedirects="item.statusCheckMaxRedirects"
|
||||
:statusCheckInterval="getStatusCheckInterval()"
|
||||
@itemClicked="$emit('itemClicked')"
|
||||
@triggerModal="triggerModal"
|
||||
|
||||
@@ -5,15 +5,23 @@
|
||||
@click="navVisible = !navVisible"
|
||||
/>
|
||||
<nav id="nav" v-if="navVisible">
|
||||
<router-link
|
||||
v-for="(link, index) in links"
|
||||
:key="index"
|
||||
:to="link.path"
|
||||
:href="link.path"
|
||||
:target="isUrl(link.path) ? '_blank' : ''"
|
||||
rel="noopener noreferrer"
|
||||
class="nav-item"
|
||||
>{{link.title}}</router-link>
|
||||
<!-- Render either router-link or anchor, depending if internal / external link -->
|
||||
<template v-for="(link, index) in links">
|
||||
<router-link v-if="!isUrl(link.path)"
|
||||
:key="index"
|
||||
:to="link.path"
|
||||
class="nav-item"
|
||||
>{{link.title}}
|
||||
</router-link>
|
||||
<a v-else
|
||||
:key="index"
|
||||
:href="link.path"
|
||||
:target="determineTarget(link)"
|
||||
class="nav-item"
|
||||
rel="noopener noreferrer"
|
||||
>{{link.title}}
|
||||
</a>
|
||||
</template>
|
||||
</nav>
|
||||
</div>
|
||||
</template>
|
||||
@@ -43,6 +51,16 @@ export default {
|
||||
return screenWidth && screenWidth < 600;
|
||||
},
|
||||
isUrl: (str) => new RegExp(/(http|https):\/\/(\S+)(:[0-9]+)?/).test(str),
|
||||
determineTarget(link) {
|
||||
if (!link.target) return '_blank';
|
||||
switch (link.target) {
|
||||
case 'sametab': return '_self';
|
||||
case 'newtab': return '_blank';
|
||||
case 'parent': return '_parent';
|
||||
case 'top': return '_top';
|
||||
default: return undefined;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -476,10 +476,13 @@ export default {
|
||||
/* Returns users specified widget options, or empty object */
|
||||
widgetOptions() {
|
||||
const options = this.widget.options || {};
|
||||
const timeout = this.widget.timeout || 500;
|
||||
const useProxy = this.appConfig.widgetsAlwaysUseProxy || !!this.widget.useProxy;
|
||||
const updateInterval = this.widget.updateInterval !== undefined
|
||||
? this.widget.updateInterval : null;
|
||||
return { useProxy, updateInterval, ...options };
|
||||
return {
|
||||
timeout, useProxy, updateInterval, ...options,
|
||||
};
|
||||
},
|
||||
/* A unique string to reference the widget by */
|
||||
widgetRef() {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="web-content" :id="id">
|
||||
<iframe :src="url" />
|
||||
<iframe :src="url" allow="fullscreen" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user