Great big ESLint
This commit is contained in:
parent
051eabbdc3
commit
ebcb938da1
48 changed files with 3890 additions and 2536 deletions
|
|
@ -1,40 +1,62 @@
|
|||
<template>
|
||||
<div class="hostCard uk-card uk-card-default uk-card-hover uk-padding-remove uk-width-medium" v-bind:class="{ 'uk-card-secondary': $store.state.globalSettings.darkMode }">
|
||||
|
||||
<div
|
||||
class="hostCard uk-card uk-card-default uk-card-hover uk-padding-remove uk-width-medium"
|
||||
:class="{ 'uk-card-secondary': $store.state.globalSettings.darkMode }"
|
||||
>
|
||||
<div class="uk-card-media-top">
|
||||
<div class="snapshot-container uk-width-1-1 uk-height-auto">
|
||||
<img class="uk-width-1-1" v-bind:data-src="snapshotSrc" width="300" height="225" uk-img>
|
||||
<div v-if="!snapshotAvailable" class="uk-position-cover uk-flex uk-flex-center uk-flex-middle">Snapshot unavailable</div>
|
||||
<img
|
||||
class="uk-width-1-1"
|
||||
:data-src="snapshotSrc"
|
||||
width="300"
|
||||
height="225"
|
||||
uk-img
|
||||
/>
|
||||
<div
|
||||
v-if="!snapshotAvailable"
|
||||
class="uk-position-cover uk-flex uk-flex-center uk-flex-middle"
|
||||
>
|
||||
Snapshot unavailable
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="uk-card-body uk-padding-small">
|
||||
<div class="uk-margin-small uk-margin-remove-left uk-margin-remove-right uk-flex uk-flex-middle">
|
||||
<div
|
||||
class="uk-margin-small uk-margin-remove-left uk-margin-remove-right uk-flex uk-flex-middle"
|
||||
>
|
||||
<div class="uk-width-expand host-description">
|
||||
<div class="host-description"><b>{{ name }}</b></div>
|
||||
<div class="host-description">
|
||||
<b>{{ name }}</b>
|
||||
</div>
|
||||
<div class="host-description">{{ hostname }}:{{ port }}</div>
|
||||
</div>
|
||||
<a href="#" v-on:click="$emit('delete')" class="uk-icon uk-width-auto host-delete"><i class="material-icons">delete</i></a>
|
||||
<a
|
||||
href="#"
|
||||
class="uk-icon uk-width-auto host-delete"
|
||||
@click="$emit('delete')"
|
||||
><i class="material-icons">delete</i></a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="uk-card-footer uk-padding-small">
|
||||
<button
|
||||
<button
|
||||
class="uk-button uk-button-default uk-form-small uk-float-right uk-margin uk-margin-remove-top uk-width-1-1"
|
||||
v-on:click="$emit('connect')"
|
||||
>Connect</button>
|
||||
@click="$emit('connect')"
|
||||
>
|
||||
Connect
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import UIkit from 'uikit';
|
||||
import axios from 'axios'
|
||||
import axios from "axios";
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
name: 'hostCard',
|
||||
name: "HostCard",
|
||||
|
||||
props: {
|
||||
name: {
|
||||
|
|
@ -51,23 +73,32 @@ export default {
|
|||
}
|
||||
},
|
||||
|
||||
data: function () {
|
||||
data: function() {
|
||||
return {
|
||||
snapshotSrc: "",
|
||||
snapshotAvailable: false,
|
||||
polling: null
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
routesURL: function() {
|
||||
return `http://${this.hostname}:${this.port}/routes`;
|
||||
},
|
||||
snapshotURL: function() {
|
||||
return `http://${this.hostname}:${this.port}/api/v1/snapshot`;
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
// Try to load the microscope snapshot when mounted
|
||||
this.checkSnapshotAvailable()
|
||||
this.checkSnapshotAvailable();
|
||||
},
|
||||
|
||||
beforeDestroy () {
|
||||
beforeDestroy() {
|
||||
// Clear the polling timer
|
||||
if (this.polling !== null) {
|
||||
clearInterval(this.polling)
|
||||
clearInterval(this.polling);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -77,52 +108,42 @@ export default {
|
|||
// a snapshot timer if the snapshot route is available
|
||||
|
||||
// Send tag request
|
||||
axios.get(this.routesURL)
|
||||
.then((response) => {
|
||||
// If the host has a snapshot route available
|
||||
if ("/api/v1/snapshot" in response.data) {
|
||||
// Tell the view that a snapshot is available
|
||||
this.snapshotAvailable = true
|
||||
// Update the snapshot URL
|
||||
this.updateSnapshotURL()
|
||||
// If not already polling, start polling
|
||||
if (this.polling === null) {
|
||||
this.updateSnapshotPoll()
|
||||
axios
|
||||
.get(this.routesURL)
|
||||
.then(response => {
|
||||
// If the host has a snapshot route available
|
||||
if ("/api/v1/snapshot" in response.data) {
|
||||
// Tell the view that a snapshot is available
|
||||
this.snapshotAvailable = true;
|
||||
// Update the snapshot URL
|
||||
this.updateSnapshotURL();
|
||||
// If not already polling, start polling
|
||||
if (this.polling === null) {
|
||||
this.updateSnapshotPoll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
.catch(error => {
|
||||
// Tell the view that a snapshot is not available, and ignore
|
||||
this.snapshotAvailable = false
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
// Tell the view that a snapshot is not available, and ignore
|
||||
this.snapshotAvailable = false;
|
||||
});
|
||||
},
|
||||
|
||||
updateSnapshotURL: function() {
|
||||
// Set the snapshot image src to the snapshot URL,
|
||||
// adding a timestamp argument to act as a cache-breaker
|
||||
this.snapshotSrc = `${this.snapshotURL}?${Date.now()}`
|
||||
console.log(`Updating snapshot URL to ${this.snapshotSrc}`)
|
||||
this.snapshotSrc = `${this.snapshotURL}?${Date.now()}`;
|
||||
console.log(`Updating snapshot URL to ${this.snapshotSrc}`);
|
||||
},
|
||||
|
||||
updateSnapshotPoll: function() {
|
||||
// Start a timer to call updateSnapshotURL periodically
|
||||
this.polling = setInterval(() => {
|
||||
this.updateSnapshotURL()
|
||||
}, 15000)
|
||||
this.updateSnapshotURL();
|
||||
}, 15000);
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
routesURL: function () {
|
||||
return `http://${this.hostname}:${this.port}/routes`
|
||||
},
|
||||
snapshotURL: function () {
|
||||
return `http://${this.hostname}:${this.port}/api/v1/snapshot`
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
|
@ -135,8 +156,7 @@ export default {
|
|||
position: relative;
|
||||
}
|
||||
|
||||
img[data-src][src*='data:image'] {
|
||||
background: rgba(127,127,127,0.1);
|
||||
img[data-src][src*="data:image"] {
|
||||
background: rgba(127, 127, 127, 0.1);
|
||||
}
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,26 +1,63 @@
|
|||
<template>
|
||||
<div class="connectDisplay uk-padding uk-padding-remove-left">
|
||||
|
||||
<div uk-grid class="uk-height-1-1 uk-margin-remove uk-padding-remove" margin=0>
|
||||
|
||||
<div class="connectDisplay uk-padding uk-padding-remove-left">
|
||||
<div
|
||||
uk-grid
|
||||
class="uk-height-1-1 uk-margin-remove uk-padding-remove"
|
||||
margin="0"
|
||||
>
|
||||
<div class="uk-width-auto">
|
||||
|
||||
<div class="uk-card uk-card-default uk-card-hover uk-padding-remove uk-width-medium connect-card-align-top">
|
||||
|
||||
<div
|
||||
class="uk-card uk-card-default uk-card-hover uk-padding-remove uk-width-medium connect-card-align-top"
|
||||
>
|
||||
<div class="uk-card-body uk-padding-small">
|
||||
<form @submit.prevent="handleSubmit">
|
||||
<div class="uk-form-controls uk-margin">
|
||||
<label><input class="uk-radio" type="radio" name="radio_local" v-model="computedLocalMode" v-bind:value="true"> Connect locally</label><br>
|
||||
<label><input class="uk-radio" type="radio" name="radio_local" v-model="computedLocalMode" v-bind:value="false" checked> Connect remotely</label>
|
||||
<label
|
||||
><input
|
||||
v-model="computedLocalMode"
|
||||
class="uk-radio"
|
||||
type="radio"
|
||||
name="radio_local"
|
||||
:value="true"
|
||||
/>
|
||||
Connect locally</label
|
||||
><br />
|
||||
<label
|
||||
><input
|
||||
v-model="computedLocalMode"
|
||||
class="uk-radio"
|
||||
type="radio"
|
||||
name="radio_local"
|
||||
:value="false"
|
||||
checked
|
||||
/>
|
||||
Connect remotely</label
|
||||
>
|
||||
</div>
|
||||
<div v-if="!localMode">
|
||||
<div class="uk-inline uk-width-1-1">
|
||||
<span class="uk-form-icon"><i class="material-icons">dns</i></span>
|
||||
<input v-model="hostname" v-bind:class="IpFormClasses" class="uk-input uk-form-small" type="text" placeholder="Hostname or IP address">
|
||||
<span class="uk-form-icon"
|
||||
><i class="material-icons">dns</i></span
|
||||
>
|
||||
<input
|
||||
v-model="hostname"
|
||||
:class="IpFormClasses"
|
||||
class="uk-input uk-form-small"
|
||||
type="text"
|
||||
placeholder="Hostname or IP address"
|
||||
/>
|
||||
</div>
|
||||
<label class="uk-form-label" for="form-stacked-text">Port</label>
|
||||
<label class="uk-form-label" for="form-stacked-text"
|
||||
>Port</label
|
||||
>
|
||||
<div class="uk-form-controls">
|
||||
<input v-model="computedPort" class="uk-input uk-form-small" id="form-stacked-text" type="number" value=5000>
|
||||
<input
|
||||
id="form-stacked-text"
|
||||
v-model="computedPort"
|
||||
class="uk-input uk-form-small"
|
||||
type="number"
|
||||
value="5000"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
|
@ -28,102 +65,90 @@
|
|||
|
||||
<div class="uk-card-footer uk-padding-small">
|
||||
<button
|
||||
v-on:click="handleSubmit"
|
||||
class="uk-button uk-button-primary uk-form-small uk-float-right uk-margin uk-margin-remove-top uk-width-1-1">
|
||||
class="uk-button uk-button-primary uk-form-small uk-float-right uk-margin uk-margin-remove-top uk-width-1-1"
|
||||
@click="handleSubmit"
|
||||
>
|
||||
Connect
|
||||
</button>
|
||||
|
||||
<button
|
||||
v-if="$store.getters.ready"
|
||||
v-on:click="saveHost()"
|
||||
class="uk-button uk-button-default uk-form-small uk-margin-small uk-width-1-1">
|
||||
<button
|
||||
v-if="$store.getters.ready"
|
||||
class="uk-button uk-button-default uk-form-small uk-margin-small uk-width-1-1"
|
||||
@click="saveHost()"
|
||||
>
|
||||
Save Current
|
||||
</button>
|
||||
|
||||
<button
|
||||
v-if="$store.getters.ready"
|
||||
v-on:click="$store.commit('resetState')"
|
||||
class="uk-button uk-button-danger uk-form-small uk-float-right uk-margin uk-margin-remove-top uk-width-1-1">
|
||||
<button
|
||||
v-if="$store.getters.ready"
|
||||
class="uk-button uk-button-danger uk-form-small uk-float-right uk-margin uk-margin-remove-top uk-width-1-1"
|
||||
@click="$store.commit('resetState')"
|
||||
>
|
||||
Disconnect
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="uk-width-expand">
|
||||
<ul uk-accordion="multiple: true; animation: false">
|
||||
|
||||
<li class="uk-open">
|
||||
<a class="uk-accordion-title" href="#">Saved devices</a>
|
||||
<div class="uk-accordion-content">
|
||||
|
||||
<div class="uk-grid-medium uk-grid-match uk-margin-top" uk-grid>
|
||||
|
||||
<div v-for="host in savedHosts" :key="host.name">
|
||||
<hostCard
|
||||
:name="host.name"
|
||||
:hostname="host.hostname"
|
||||
<hostCard
|
||||
:name="host.name"
|
||||
:hostname="host.hostname"
|
||||
:port="host.port"
|
||||
v-on:connect="handleConnectButton(host)"
|
||||
v-on:delete="delSavedHost(host)"
|
||||
@connect="handleConnectButton(host)"
|
||||
@delete="delSavedHost(host)"
|
||||
></hostCard>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="uk-open">
|
||||
<a class="uk-accordion-title" href="#">Nearby devices</a>
|
||||
<div class="uk-accordion-content">
|
||||
|
||||
<div class="uk-grid-medium uk-grid-match uk-margin-top" uk-grid>
|
||||
|
||||
<div v-for="host in foundHostArray" :key="host.name">
|
||||
<hostCard
|
||||
:name="host.name"
|
||||
:hostname="host.hostname"
|
||||
<hostCard
|
||||
:name="host.name"
|
||||
:hostname="host.hostname"
|
||||
:port="host.port"
|
||||
:deletable="false"
|
||||
v-on:connect="handleConnectButton(host)"
|
||||
@connect="handleConnectButton(host)"
|
||||
></hostCard>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { version } from 'punycode';
|
||||
|
||||
// Import mDNS package if running in Electron
|
||||
import isElectron from '../../modules/isElectron';
|
||||
import isElectron from "../../modules/isElectron";
|
||||
if (isElectron()) {
|
||||
var mdns = require('mdns-js');
|
||||
var mdns = require("mdns-js");
|
||||
}
|
||||
|
||||
import hostCard from './connectComponents/hostCard.vue'
|
||||
import hostCard from "./connectComponents/hostCard.vue";
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
name: 'connectDisplay',
|
||||
name: "ConnectDisplay",
|
||||
|
||||
components: {
|
||||
hostCard
|
||||
},
|
||||
|
||||
data: function () {
|
||||
data: function() {
|
||||
return {
|
||||
localMode: true,
|
||||
hostname: "",
|
||||
|
|
@ -131,161 +156,205 @@ export default {
|
|||
selectedHost: "",
|
||||
savedHosts: [],
|
||||
foundHosts: {}
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
foundHostArray: function() {
|
||||
return Object.values(this.foundHosts);
|
||||
},
|
||||
// Stylises the hostname input box based on connection status
|
||||
IpFormClasses: function() {
|
||||
return {
|
||||
"uk-form-danger": !this.$store.state.available,
|
||||
"uk-form-success": this.$store.getters.ready
|
||||
};
|
||||
},
|
||||
|
||||
computedLocalMode: {
|
||||
get: function() {
|
||||
return this.localMode;
|
||||
},
|
||||
set: function(state) {
|
||||
this.localMode = state;
|
||||
this.setLocalMode(state);
|
||||
}
|
||||
},
|
||||
|
||||
computedPort: {
|
||||
get: function() {
|
||||
if (this.hostname.includes(":")) {
|
||||
var port = parseInt(this.hostname.split(":")[1]);
|
||||
return !isNaN(port) ? port : this.port;
|
||||
} else {
|
||||
return this.port;
|
||||
}
|
||||
},
|
||||
set: function(newPort) {
|
||||
this.port = newPort;
|
||||
if (this.hostname.includes(":")) {
|
||||
this.hostname = this.hostname.split(":")[0] + ":" + this.port;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// When savedHosts changes, serialise to JSON and save to localStorage
|
||||
watch: {
|
||||
savedHosts() {
|
||||
this.setLocalStorageObj("savedHosts", this.savedHosts);
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
// Propagate localMode settings
|
||||
this.setLocalMode(this.localMode)
|
||||
this.setLocalMode(this.localMode);
|
||||
|
||||
// Try loading savedHosts from localStorage. If null, don't change.
|
||||
this.savedHosts = this.getLocalStorageObj('savedHosts') || this.savedHosts
|
||||
this.savedHosts = this.getLocalStorageObj("savedHosts") || this.savedHosts;
|
||||
|
||||
// Handle mDNS browsing
|
||||
if (mdns) {
|
||||
// TODO: Have this run periodically on a timer
|
||||
|
||||
// Create a browser to search for 'openflexure' type services
|
||||
var browser = mdns.createBrowser(mdns.tcp('openflexure'));
|
||||
var browser = mdns.createBrowser(mdns.tcp("openflexure"));
|
||||
|
||||
// Start discovering services when ready
|
||||
browser.on('ready', function () {
|
||||
browser.discover();
|
||||
browser.on("ready", function() {
|
||||
browser.discover();
|
||||
});
|
||||
|
||||
browser.on('update', (data) => {
|
||||
console.log(data)
|
||||
browser.on("update", data => {
|
||||
console.log(data);
|
||||
|
||||
// We will be checking if it's a valid openflexure device
|
||||
var validDevice = false
|
||||
var validDevice = false;
|
||||
|
||||
// Go through each type of the host, make valid if 'openflexure' appears
|
||||
data.type.forEach((element) => {
|
||||
console.log(element)
|
||||
data.type.forEach(element => {
|
||||
console.log(element);
|
||||
if (element.name === "openflexure") {
|
||||
validDevice = true
|
||||
validDevice = true;
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
var hostData = {
|
||||
hostname: data.addresses[0],
|
||||
name: `${data.host} on ${data.networkInterface}`,
|
||||
port: data.port
|
||||
};
|
||||
|
||||
if (typeof data.port !== "undefined" && validDevice === true) {
|
||||
this.$set(this.foundHosts, hostData.hostname, hostData);
|
||||
}
|
||||
|
||||
if ((typeof data.port !== "undefined") && (validDevice === true)) {
|
||||
this.$set(this.foundHosts, hostData.hostname, hostData)
|
||||
}
|
||||
|
||||
console.log(this.foundHosts)
|
||||
console.log(this.foundHosts);
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
// When savedHosts changes, serialise to JSON and save to localStorage
|
||||
watch: {
|
||||
savedHosts(newSavedHosts) {
|
||||
this.setLocalStorageObj('savedHosts', this.savedHosts)
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
connectToHost: function(host) {
|
||||
console.log(host)
|
||||
console.log(host);
|
||||
// Set the global form values
|
||||
this.hostname = host.hostname
|
||||
this.port = host.port
|
||||
|
||||
this.hostname = host.hostname;
|
||||
this.port = host.port;
|
||||
|
||||
// Commit the hostname and port to store
|
||||
this.$store.commit('changeHost', [
|
||||
host.hostname,
|
||||
host.port
|
||||
]);
|
||||
this.$store.commit("changeHost", [host.hostname, host.port]);
|
||||
// Try to get config and state JSON from the newly submitted host
|
||||
this.$store.dispatch('firstConnect')
|
||||
.then (() => {
|
||||
console.log("Connected!")
|
||||
// Check client and server match
|
||||
this.checkServerVersion()
|
||||
// Switch to live view tab
|
||||
this.$root.$emit('globalTogglePanelRightTab', 'preview')
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error) // Let mixin handle error
|
||||
})
|
||||
this.$store
|
||||
.dispatch("firstConnect")
|
||||
.then(() => {
|
||||
console.log("Connected!");
|
||||
// Check client and server match
|
||||
this.checkServerVersion();
|
||||
// Switch to live view tab
|
||||
this.$root.$emit("globalTogglePanelRightTab", "preview");
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error); // Let mixin handle error
|
||||
});
|
||||
},
|
||||
|
||||
handleSubmit: function(event) {
|
||||
handleSubmit: function() {
|
||||
// Split host and port if needed
|
||||
if (this.hostname.includes(':')) {
|
||||
if (this.hostname.includes(":")) {
|
||||
this.port = this.computedPort;
|
||||
this.hostname = this.hostname.split(':')[0];
|
||||
this.hostname = this.hostname.split(":")[0];
|
||||
}
|
||||
|
||||
// Handle auto-local-connect
|
||||
var hostname;
|
||||
if (this.localMode) {
|
||||
var hostname = "localhost";
|
||||
}
|
||||
else {
|
||||
var hostname = this.hostname;
|
||||
hostname = "localhost";
|
||||
} else {
|
||||
hostname = this.hostname;
|
||||
}
|
||||
|
||||
var selectedHost = {
|
||||
hostname: hostname,
|
||||
port: this.port
|
||||
}
|
||||
};
|
||||
|
||||
this.connectToHost(selectedHost)
|
||||
this.connectToHost(selectedHost);
|
||||
},
|
||||
|
||||
handleConnectButton: function(host) {
|
||||
this.computedLocalMode = false
|
||||
this.connectToHost(host)
|
||||
this.computedLocalMode = false;
|
||||
this.connectToHost(host);
|
||||
},
|
||||
|
||||
checkServerVersion: function () {
|
||||
this.$store.dispatch('updateState')
|
||||
.then (() => {
|
||||
var clientVersion = process.env.PACKAGE.version
|
||||
var clientVersionMajor = clientVersion.substring(0, 3)
|
||||
console.log(clientVersionMajor)
|
||||
checkServerVersion: function() {
|
||||
this.$store
|
||||
.dispatch("updateState")
|
||||
.then(() => {
|
||||
var clientVersion = process.env.PACKAGE.version;
|
||||
var clientVersionMajor = clientVersion.substring(0, 3);
|
||||
console.log(clientVersionMajor);
|
||||
|
||||
var serverVersion = this.$store.state.apiState.version
|
||||
if (serverVersion != undefined) {
|
||||
var serverVersionMajor = serverVersion.substring(0, 3)
|
||||
}
|
||||
console.log(serverVersionMajor)
|
||||
var serverVersion = this.$store.state.apiState.version;
|
||||
if (serverVersion != undefined) {
|
||||
var serverVersionMajor = serverVersion.substring(0, 3);
|
||||
}
|
||||
console.log(serverVersionMajor);
|
||||
|
||||
if ((serverVersion == undefined) || (serverVersionMajor != clientVersionMajor)) {
|
||||
var versionWarning = `Client and microscope versions do not match.\
|
||||
if (
|
||||
serverVersion == undefined ||
|
||||
serverVersionMajor != clientVersionMajor
|
||||
) {
|
||||
var versionWarning = `Client and microscope versions do not match.\
|
||||
Consider updating your microscope software.\
|
||||
Some functionality may currently be broken.<br><br> \
|
||||
<b>Client version:</b> ${clientVersion}<br> \
|
||||
<b>Server version:</b> ${serverVersion}<br><br>`
|
||||
if (serverVersion < 1.1) {
|
||||
versionWarning = versionWarning + "You may need to install a never server version on a clean SD card."
|
||||
<b>Server version:</b> ${serverVersion}<br><br>`;
|
||||
if (serverVersion < 1.1) {
|
||||
versionWarning =
|
||||
versionWarning +
|
||||
"You may need to install a never server version on a clean SD card.";
|
||||
} else {
|
||||
versionWarning =
|
||||
versionWarning +
|
||||
"Try running 'ofm upgrade' on your microscope.";
|
||||
}
|
||||
this.modalDialog("Version mismatch", versionWarning);
|
||||
}
|
||||
else {
|
||||
versionWarning = versionWarning + "Try running 'ofm upgrade' on your microscope."
|
||||
}
|
||||
this.modalDialog("Version mismatch", versionWarning, status='warning')
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error) // Let mixin handle error
|
||||
})
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error); // Let mixin handle error
|
||||
});
|
||||
},
|
||||
|
||||
setLocalMode: function (state) {
|
||||
this.$store.commit("changeSetting", ['trackWindow', state]);
|
||||
this.$store.commit("changeSetting", ['disableStream', state]);
|
||||
this.$store.commit("changeSetting", ['autoGpuPreview', state]);
|
||||
setLocalMode: function(state) {
|
||||
this.$store.commit("changeSetting", ["trackWindow", state]);
|
||||
this.$store.commit("changeSetting", ["disableStream", state]);
|
||||
this.$store.commit("changeSetting", ["autoGpuPreview", state]);
|
||||
//this.$root.$emit('globalTogglePreview', state)
|
||||
},
|
||||
|
||||
delSavedHost: function (host) {
|
||||
console.log(host)
|
||||
delSavedHost: function(host) {
|
||||
console.log(host);
|
||||
var index = this.savedHosts.indexOf(host);
|
||||
if (index > -1) {
|
||||
this.savedHosts.splice(index, 1);
|
||||
|
|
@ -294,67 +363,19 @@ export default {
|
|||
|
||||
saveHost: function() {
|
||||
// We use unshift instead of push to add the entry to the beginning of the array
|
||||
this.savedHosts.unshift(
|
||||
{
|
||||
name: this.$store.state.apiConfig.name,
|
||||
hostname: this.$store.state.host,
|
||||
port: this.$store.state.port
|
||||
}
|
||||
)
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
computed: {
|
||||
foundHostArray: function () {
|
||||
return Object.values(this.foundHosts)
|
||||
},
|
||||
// Stylises the hostname input box based on connection status
|
||||
IpFormClasses: function () {
|
||||
return {
|
||||
'uk-form-danger': !this.$store.state.available,
|
||||
'uk-form-success': this.$store.getters.ready
|
||||
}
|
||||
},
|
||||
|
||||
computedLocalMode: {
|
||||
get: function() {
|
||||
return this.localMode
|
||||
},
|
||||
set: function(state) {
|
||||
this.localMode = state;
|
||||
this.setLocalMode(state)
|
||||
}
|
||||
},
|
||||
|
||||
computedPort: {
|
||||
get: function() {
|
||||
if (this.hostname.includes(':')) {
|
||||
var port = parseInt(this.hostname.split(':')[1]);
|
||||
return !isNaN(port) ? port : this.port
|
||||
}
|
||||
else {
|
||||
return this.port
|
||||
}
|
||||
},
|
||||
set: function(newPort) {
|
||||
this.port = newPort
|
||||
if (this.hostname.includes(':')) {
|
||||
this.hostname = this.hostname.split(':')[0] + ":" + this.port
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
this.savedHosts.unshift({
|
||||
name: this.$store.state.apiConfig.name,
|
||||
hostname: this.$store.state.host,
|
||||
port: this.$store.state.port
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped lang="less">
|
||||
|
||||
.connect-card-align-top {
|
||||
margin-top: 52px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,86 +1,137 @@
|
|||
<template>
|
||||
<div class="captureCard uk-card uk-card-default uk-card-hover uk-padding-remove uk-width-medium" v-bind:class="{ 'uk-card-secondary': $store.state.globalSettings.darkMode }">
|
||||
|
||||
<div
|
||||
class="captureCard uk-card uk-card-default uk-card-hover uk-padding-remove uk-width-medium"
|
||||
:class="{ 'uk-card-secondary': $store.state.globalSettings.darkMode }"
|
||||
>
|
||||
<div class="uk-card-media-top">
|
||||
<a class="lightbox-link" v-bind:href="imgURL" v-bind:data-caption="metadata.filename">
|
||||
<img class="uk-width-1-1" v-bind:data-src="thumbURL" v-bind:alt="metadata.id" width="300" height="225" uk-img>
|
||||
<a class="lightbox-link" :href="imgURL" :data-caption="metadata.filename">
|
||||
<img
|
||||
class="uk-width-1-1"
|
||||
:data-src="thumbURL"
|
||||
:alt="metadata.id"
|
||||
width="300"
|
||||
height="225"
|
||||
uk-img
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="uk-card-body uk-padding-small">
|
||||
<div class="uk-width-1-1 uk-margin-small uk-margin-remove-left uk-margin-remove-right" uk-grid>
|
||||
<div class="uk-margin-remove-top uk-padding-remove uk-width-expand">{{ metadata.filename }}</div>
|
||||
<div
|
||||
class="uk-width-1-1 uk-margin-small uk-margin-remove-left uk-margin-remove-right"
|
||||
uk-grid
|
||||
>
|
||||
<div class="uk-margin-remove-top uk-padding-remove uk-width-expand">
|
||||
{{ metadata.filename }}
|
||||
</div>
|
||||
<div class="uk-margin-remove-top uk-padding-remove uk-width-auto">
|
||||
<a href="#" v-on:click="delCaptureConfirm()" class="uk-icon">
|
||||
<a href="#" class="uk-icon" @click="delCaptureConfirm()">
|
||||
<i class="material-icons">delete</i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="uk-text-meta uk-margin-remove-top uk-padding-remove uk-width-expand"><time>{{ betterTimestring }}</time></div>
|
||||
<div class="uk-text-meta uk-margin-remove-top uk-padding-remove uk-width-auto">
|
||||
<a v-bind:href="metadataModalTarget" uk-toggle>More...</a>
|
||||
<div
|
||||
class="uk-text-meta uk-margin-remove-top uk-padding-remove uk-width-expand"
|
||||
>
|
||||
<time>{{ betterTimestring }}</time>
|
||||
</div>
|
||||
<div
|
||||
class="uk-text-meta uk-margin-remove-top uk-padding-remove uk-width-auto"
|
||||
>
|
||||
<a :href="metadataModalTarget" uk-toggle>More...</a>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="uk-card-footer uk-padding-small">
|
||||
<div v-for="tag in tags" :key="tag">
|
||||
<span v-if="tag==='temporary'" class="uk-label uk-label-danger uk-margin-small-right" uk-tooltip="title: Capture will be removed automatically; delay: 500">Temporary</span>
|
||||
<span v-else v-on:click="delTagConfirm(tag)" class="uk-label uk-margin-small-right deletable-label"> {{ tag }} </span>
|
||||
<span
|
||||
v-if="tag === 'temporary'"
|
||||
class="uk-label uk-label-danger uk-margin-small-right"
|
||||
uk-tooltip="title: Capture will be removed automatically; delay: 500"
|
||||
>Temporary</span
|
||||
>
|
||||
<span
|
||||
v-else
|
||||
class="uk-label uk-margin-small-right deletable-label"
|
||||
@click="delTagConfirm(tag)"
|
||||
>
|
||||
{{ tag }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<a v-bind:href="tagModalTarget" uk-toggle>
|
||||
<a :href="tagModalTarget" uk-toggle>
|
||||
<span class="uk-label uk-label-success uk-margin-small-right">Add</span>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
<div v-bind:id="metadataModalID" uk-modal>
|
||||
<div :id="metadataModalID" uk-modal>
|
||||
<div
|
||||
class="uk-modal-dialog uk-modal-body"
|
||||
:class="{
|
||||
'uk-light uk-background-secondary':
|
||||
$store.state.globalSettings.darkMode
|
||||
}"
|
||||
>
|
||||
<button class="uk-modal-close-default" type="button" uk-close></button>
|
||||
<h2 class="uk-modal-title">{{ metadata.filename }}</h2>
|
||||
<p><b>Path: </b>{{ path }}</p>
|
||||
<p><b>Time: </b>{{ betterTimestring }}</p>
|
||||
<p><b>ID: </b>{{ metadata.id }}</p>
|
||||
<p><b>Format: </b>{{ metadata.format }}</p>
|
||||
|
||||
<div class="uk-modal-dialog uk-modal-body" v-bind:class="{ 'uk-light uk-background-secondary': $store.state.globalSettings.darkMode }" >
|
||||
<button class="uk-modal-close-default" type="button" uk-close></button>
|
||||
<h2 class="uk-modal-title">{{ metadata.filename }}</h2>
|
||||
<p><b>Path: </b>{{ path }}</p>
|
||||
<p><b>Time: </b>{{ betterTimestring }}</p>
|
||||
<p><b>ID: </b>{{ metadata.id }}</p>
|
||||
<p><b>Format: </b>{{ metadata.format }}</p>
|
||||
|
||||
<div v-for="(value, key) in metadata.custom" :key="key" >
|
||||
<p><b>{{ key }}: </b>{{ value }}</p>
|
||||
</div>
|
||||
<div v-for="(value, key) in metadata.custom" :key="key">
|
||||
<p>
|
||||
<b>{{ key }}: </b>{{ value }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div v-bind:id="tagModalID" uk-modal>
|
||||
|
||||
<form class="uk-modal-dialog uk-modal-body uk-margin-auto-vertical" v-bind:class="{ 'uk-light uk-background-secondary': $store.state.globalSettings.darkMode }" @submit.prevent="handleTagSubmit">
|
||||
|
||||
<div class="uk-inline">
|
||||
<span class="uk-form-icon"><i class="material-icons">label</i></span>
|
||||
<input v-model="newtag" class="uk-input uk-form-width-medium uk-form-small" type="text" name="tagname" placeholder="tag">
|
||||
|
||||
<button class="uk-button uk-button-default uk-margin-left uk-form-small uk-modal-close" type="button">Cancel</button>
|
||||
<button type="submit" class="uk-button uk-button-primary uk-margin-left uk-form-small">Save</button>
|
||||
</div>
|
||||
<div :id="tagModalID" uk-modal>
|
||||
<form
|
||||
class="uk-modal-dialog uk-modal-body uk-margin-auto-vertical"
|
||||
:class="{
|
||||
'uk-light uk-background-secondary':
|
||||
$store.state.globalSettings.darkMode
|
||||
}"
|
||||
@submit.prevent="handleTagSubmit"
|
||||
>
|
||||
<div class="uk-inline">
|
||||
<span class="uk-form-icon"><i class="material-icons">label</i></span>
|
||||
<input
|
||||
v-model="newtag"
|
||||
class="uk-input uk-form-width-medium uk-form-small"
|
||||
type="text"
|
||||
name="tagname"
|
||||
placeholder="tag"
|
||||
/>
|
||||
|
||||
<button
|
||||
class="uk-button uk-button-default uk-margin-left uk-form-small uk-modal-close"
|
||||
type="button"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
class="uk-button uk-button-primary uk-margin-left uk-form-small"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import UIkit from 'uikit';
|
||||
import axios from 'axios'
|
||||
import UIkit from "uikit";
|
||||
import axios from "axios";
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
name: 'captureCard',
|
||||
name: "CaptureCard",
|
||||
|
||||
props: {
|
||||
metadata: {
|
||||
|
|
@ -93,11 +144,48 @@ export default {
|
|||
}
|
||||
},
|
||||
|
||||
data: function () {
|
||||
data: function() {
|
||||
return {
|
||||
tags: [],
|
||||
newtag: "",
|
||||
}
|
||||
newtag: ""
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
tagModalID: function() {
|
||||
return this.makeModalName("tag-modal-");
|
||||
},
|
||||
tagModalTarget: function() {
|
||||
return "#" + this.tagModalID;
|
||||
},
|
||||
metadataModalID: function() {
|
||||
return this.makeModalName("metadata-modal-");
|
||||
},
|
||||
metadataModalTarget: function() {
|
||||
return "#" + this.metadataModalID;
|
||||
},
|
||||
thumbURL: function() {
|
||||
return this.captureURL + "/download?thumbnail=true";
|
||||
},
|
||||
imgURL: function() {
|
||||
return this.captureURL + "/download/" + this.metadata.filename;
|
||||
},
|
||||
tagURL: function() {
|
||||
return this.captureURL + "/tags";
|
||||
},
|
||||
captureURL: function() {
|
||||
return this.$store.getters.uri + "/camera/capture/" + this.metadata.id;
|
||||
},
|
||||
betterTimestring: function() {
|
||||
var dtSplit = this.metadata.time.split("_");
|
||||
var date = dtSplit[0];
|
||||
var time = dtSplit[1].replace(/-/g, ":");
|
||||
return date + " " + time;
|
||||
}
|
||||
},
|
||||
|
||||
created: function() {
|
||||
this.getTagRequest();
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
|
@ -106,114 +194,78 @@ export default {
|
|||
console.log(this.newtag);
|
||||
this.newTagRequest(this.newtag);
|
||||
this.newtag = "";
|
||||
UIkit.modal(event.target.parentNode).hide(); // TODO: Remove somehow
|
||||
UIkit.modal(event.target.parentNode).hide(); // TODO: Remove somehow
|
||||
},
|
||||
|
||||
delCaptureConfirm: function(tag_string) {
|
||||
var context = this
|
||||
this.modalConfirm('Permanantly delete capture?')
|
||||
.then(function() {
|
||||
context.delCaptureRequest()
|
||||
delCaptureConfirm: function() {
|
||||
var context = this;
|
||||
this.modalConfirm("Permanantly delete capture?").then(function() {
|
||||
context.delCaptureRequest();
|
||||
});
|
||||
},
|
||||
|
||||
delCaptureRequest: function() {
|
||||
// Send tag DELETE request
|
||||
axios.delete(this.captureURL)
|
||||
.then(response => {
|
||||
// Emit signal to update capture list
|
||||
this.$root.$emit('globalUpdateCaptureList')
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error) // Let mixin handle error
|
||||
})
|
||||
axios
|
||||
.delete(this.captureURL)
|
||||
.then(() => {
|
||||
// Emit signal to update capture list
|
||||
this.$root.$emit("globalUpdateCaptureList");
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error); // Let mixin handle error
|
||||
});
|
||||
},
|
||||
|
||||
newTagRequest: function(tag_string) {
|
||||
// Send tag PUT request
|
||||
axios.put(this.tagURL, [tag_string])
|
||||
.then(response => {
|
||||
// Update tag array
|
||||
this.getTagRequest()
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error) // Let mixin handle error
|
||||
})
|
||||
axios
|
||||
.put(this.tagURL, [tag_string])
|
||||
.then(() => {
|
||||
// Update tag array
|
||||
this.getTagRequest();
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error); // Let mixin handle error
|
||||
});
|
||||
},
|
||||
|
||||
delTagConfirm: function(tag_string) {
|
||||
var context = this;
|
||||
this.modalConfirm(`Remove tag '${tag_string}'?`).then(function() {
|
||||
context.delTagRequest(tag_string)
|
||||
context.delTagRequest(tag_string);
|
||||
});
|
||||
},
|
||||
|
||||
delTagRequest: function(tag_string) {
|
||||
console.log(tag_string)
|
||||
console.log(tag_string);
|
||||
// Send tag DELETE request
|
||||
axios.delete(this.tagURL, {data: [tag_string]})
|
||||
.then(response => {
|
||||
// Update tag array
|
||||
this.getTagRequest()
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error) // Let mixin handle error
|
||||
})
|
||||
axios
|
||||
.delete(this.tagURL, { data: [tag_string] })
|
||||
.then(() => {
|
||||
// Update tag array
|
||||
this.getTagRequest();
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error); // Let mixin handle error
|
||||
});
|
||||
},
|
||||
|
||||
getTagRequest: function() {
|
||||
// Send tag request
|
||||
axios.get(this.tagURL)
|
||||
.then(response => {
|
||||
this.tags = response.data.metadata.tags
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error) // Let mixin handle error
|
||||
})
|
||||
axios
|
||||
.get(this.tagURL)
|
||||
.then(response => {
|
||||
this.tags = response.data.metadata.tags;
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error); // Let mixin handle error
|
||||
});
|
||||
},
|
||||
|
||||
makeModalName: function(prefix) {
|
||||
return prefix + this.metadata.id
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
created: function () {
|
||||
this.getTagRequest()
|
||||
},
|
||||
|
||||
computed: {
|
||||
tagModalID: function () {
|
||||
return this.makeModalName("tag-modal-")
|
||||
},
|
||||
tagModalTarget: function () {
|
||||
return "#" + this.tagModalID
|
||||
},
|
||||
metadataModalID: function () {
|
||||
return this.makeModalName("metadata-modal-")
|
||||
},
|
||||
metadataModalTarget: function () {
|
||||
return "#" + this.metadataModalID
|
||||
},
|
||||
thumbURL: function () {
|
||||
return this.captureURL + "/download?thumbnail=true"
|
||||
},
|
||||
imgURL: function () {
|
||||
return this.captureURL + "/download/" + this.metadata.filename
|
||||
},
|
||||
tagURL: function () {
|
||||
return this.captureURL + "/tags"
|
||||
},
|
||||
captureURL: function () {
|
||||
return this.$store.getters.uri + "/camera/capture/" + this.metadata.id
|
||||
},
|
||||
betterTimestring: function () {
|
||||
var dtSplit = this.metadata.time.split("_");
|
||||
var date = dtSplit[0]
|
||||
var time = dtSplit[1].replace(/-/g, ":")
|
||||
return date + " " + time
|
||||
return prefix + this.metadata.id;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,54 +1,76 @@
|
|||
<template>
|
||||
<div class="captureCard uk-card uk-card-primary uk-card-hover uk-padding-remove uk-width-medium">
|
||||
|
||||
<div
|
||||
class="captureCard uk-card uk-card-primary uk-card-hover uk-padding-remove uk-width-medium"
|
||||
>
|
||||
<div class="uk-card-media-top">
|
||||
|
||||
<a href="#" >
|
||||
<img class="uk-width-1-1" v-bind:data-src="thumbnail" v-bind:alt="metadata.scan_id" width="300" height="225" v-on:click="$root.$emit('globalUpdateCaptureFolder', metadata.custom.scan_id)" uk-img>
|
||||
<a href="#">
|
||||
<img
|
||||
class="uk-width-1-1"
|
||||
:data-src="thumbnail"
|
||||
:alt="metadata.scan_id"
|
||||
width="300"
|
||||
height="225"
|
||||
uk-img
|
||||
@click="
|
||||
$root.$emit('globalUpdateCaptureFolder', metadata.custom.scan_id)
|
||||
"
|
||||
/>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="uk-card-body uk-padding-small">
|
||||
<div class="uk-width-1-1 uk-margin-small uk-margin-remove-left uk-margin-remove-right" uk-grid>
|
||||
<div class="uk-margin-remove-top uk-padding-remove uk-width-expand"><b>Scan:</b> {{ metadata.custom.basename }}</div>
|
||||
<div
|
||||
class="uk-width-1-1 uk-margin-small uk-margin-remove-left uk-margin-remove-right"
|
||||
uk-grid
|
||||
>
|
||||
<div class="uk-margin-remove-top uk-padding-remove uk-width-expand">
|
||||
<b>Scan:</b> {{ metadata.custom.basename }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="uk-text-meta uk-margin-remove-top uk-padding-remove uk-width-expand"><time>{{ betterTimestring }}</time></div>
|
||||
<div class="uk-text-meta uk-margin-remove-top uk-padding-remove uk-width-auto">
|
||||
<a v-bind:href="metadataModalTarget" uk-toggle>More...</a>
|
||||
<div
|
||||
class="uk-text-meta uk-margin-remove-top uk-padding-remove uk-width-expand"
|
||||
>
|
||||
<time>{{ betterTimestring }}</time>
|
||||
</div>
|
||||
<div
|
||||
class="uk-text-meta uk-margin-remove-top uk-padding-remove uk-width-auto"
|
||||
>
|
||||
<a :href="metadataModalTarget" uk-toggle>More...</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="uk-card-footer uk-padding-small">
|
||||
<span v-for="tag in metadata.tags" :key="tag" class="uk-label uk-margin-small-right deletable-label"> {{ tag }} </span>
|
||||
<span
|
||||
v-for="tag in metadata.tags"
|
||||
:key="tag"
|
||||
class="uk-label uk-margin-small-right deletable-label"
|
||||
>
|
||||
{{ tag }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div v-bind:id="metadataModalID" uk-modal>
|
||||
|
||||
<div :id="metadataModalID" uk-modal>
|
||||
<div class="uk-modal-dialog uk-modal-body">
|
||||
<button class="uk-modal-close-default" type="button" uk-close></button>
|
||||
<h2 class="uk-modal-title">{{ metadata.basename }}</h2>
|
||||
<p><b>Time: </b>{{ betterTimestring }}</p>
|
||||
<p><b>Scan ID: </b>{{ metadata.custom.scan_id }}</p>
|
||||
|
||||
<div v-for="(value, key) in metadata.custom" :key="key" >
|
||||
<p><b>{{ key }}: </b>{{ value }}</p>
|
||||
<div v-for="(value, key) in metadata.custom" :key="key">
|
||||
<p>
|
||||
<b>{{ key }}: </b>{{ value }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
name: 'captureCard',
|
||||
name: "CaptureCard",
|
||||
|
||||
props: {
|
||||
metadata: {
|
||||
|
|
@ -61,33 +83,31 @@ export default {
|
|||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
makeModalName: function(prefix) {
|
||||
return prefix + this.metadata.id
|
||||
computed: {
|
||||
tagModalID: function() {
|
||||
return this.makeModalName("tag-modal-");
|
||||
},
|
||||
tagModalTarget: function() {
|
||||
return "#" + this.tagModalID;
|
||||
},
|
||||
metadataModalID: function() {
|
||||
return this.makeModalName("metadata-modal-");
|
||||
},
|
||||
metadataModalTarget: function() {
|
||||
return "#" + this.metadataModalID;
|
||||
},
|
||||
betterTimestring: function() {
|
||||
var dtSplit = this.metadata.custom.time.split("_");
|
||||
var date = dtSplit[0];
|
||||
var time = dtSplit[1].replace(/-/g, ":");
|
||||
return date + " " + time;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
computed: {
|
||||
tagModalID: function () {
|
||||
return this.makeModalName("tag-modal-")
|
||||
},
|
||||
tagModalTarget: function () {
|
||||
return "#" + this.tagModalID
|
||||
},
|
||||
metadataModalID: function () {
|
||||
return this.makeModalName("metadata-modal-")
|
||||
},
|
||||
metadataModalTarget: function () {
|
||||
return "#" + this.metadataModalID
|
||||
},
|
||||
betterTimestring: function () {
|
||||
var dtSplit = this.metadata.custom.time.split("_");
|
||||
var date = dtSplit[0]
|
||||
var time = dtSplit[1].replace(/-/g, ":")
|
||||
return date + " " + time
|
||||
methods: {
|
||||
makeModalName: function(prefix) {
|
||||
return prefix + this.metadata.id;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,108 +1,255 @@
|
|||
<template>
|
||||
<div class="galleryDisplay uk-padding uk-padding-remove-top">
|
||||
|
||||
<nav class="uk-navbar-container uk-navbar-transparent navbar" uk-navbar="mode: click">
|
||||
<div class="uk-navbar-left uk-padding-remove-top uk-padding-remove-bottom">
|
||||
<ul class="uk-navbar-nav">
|
||||
<li v-bind:class="[sortDescending ? 'uk-active' : '']"><a v-on:click="sortDescending=true;" class="uk-icon" href="#"><i class="material-icons">keyboard_arrow_down</i></a></li>
|
||||
<li v-bind:class="[!sortDescending ? 'uk-active' : '']"><a v-on:click="sortDescending=false;" class="uk-icon" href="#"><i class="material-icons">keyboard_arrow_up</i></a></li>
|
||||
<li>
|
||||
<a href="#">Filter</a>
|
||||
<div class="uk-navbar-dropdown" v-bind:class="{ 'uk-light uk-background-secondary': $store.state.globalSettings.darkMode }">
|
||||
<ul class="uk-nav uk-navbar-dropdown-nav">
|
||||
<form class="uk-form-stacked">
|
||||
<div v-for="tag in allTags" :key="tag" class="uk-margin-small">
|
||||
<label><input class="uk-checkbox" type="checkbox" v-bind:id="tag" v-bind:value="tag" v-model="checkedTags" checked> {{ tag }}</label>
|
||||
</div>
|
||||
</form>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
<div class="galleryDisplay uk-padding uk-padding-remove-top">
|
||||
<nav
|
||||
class="uk-navbar-container uk-navbar-transparent navbar"
|
||||
uk-navbar="mode: click"
|
||||
>
|
||||
<div
|
||||
class="uk-navbar-left uk-padding-remove-top uk-padding-remove-bottom"
|
||||
>
|
||||
<ul class="uk-navbar-nav">
|
||||
<li :class="[sortDescending ? 'uk-active' : '']">
|
||||
<a class="uk-icon" href="#" @click="sortDescending = true"
|
||||
><i class="material-icons">keyboard_arrow_down</i></a
|
||||
>
|
||||
</li>
|
||||
<li :class="[!sortDescending ? 'uk-active' : '']">
|
||||
<a class="uk-icon" href="#" @click="sortDescending = false"
|
||||
><i class="material-icons">keyboard_arrow_up</i></a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">Filter</a>
|
||||
<div
|
||||
class="uk-navbar-dropdown"
|
||||
:class="{
|
||||
'uk-light uk-background-secondary':
|
||||
$store.state.globalSettings.darkMode
|
||||
}"
|
||||
>
|
||||
<ul class="uk-nav uk-navbar-dropdown-nav">
|
||||
<form class="uk-form-stacked">
|
||||
<div
|
||||
v-for="tag in allTags"
|
||||
:key="tag"
|
||||
class="uk-margin-small"
|
||||
>
|
||||
<label
|
||||
><input
|
||||
:id="tag"
|
||||
v-model="checkedTags"
|
||||
class="uk-checkbox"
|
||||
type="checkbox"
|
||||
:value="tag"
|
||||
checked
|
||||
/>
|
||||
{{ tag }}</label
|
||||
>
|
||||
</div>
|
||||
</form>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div v-if="$store.getters.ready" class="uk-padding-remove-top" uk-lightbox="toggle: .lightbox-link">
|
||||
|
||||
<div v-if="(galleryFolder)" class="uk-flex uk-flex-middle uk-padding uk-padding-remove-horizontal uk-padding-remove-bottom">
|
||||
<a href="#" v-on:click="galleryFolder=''" class="uk-icon uk-margin-remove"><i class="material-icons">arrow_back</i></a>
|
||||
<div
|
||||
v-if="$store.getters.ready"
|
||||
class="uk-padding-remove-top"
|
||||
uk-lightbox="toggle: .lightbox-link"
|
||||
>
|
||||
<div
|
||||
v-if="galleryFolder"
|
||||
class="uk-flex uk-flex-middle uk-padding uk-padding-remove-horizontal uk-padding-remove-bottom"
|
||||
>
|
||||
<a href="#" class="uk-icon uk-margin-remove" @click="galleryFolder = ''"
|
||||
><i class="material-icons">arrow_back</i></a
|
||||
>
|
||||
<div class="uk-margin-left">
|
||||
<h3 class="uk-margin-remove uk-margin-left"><b>SCAN</b> {{ allScans[galleryFolder].metadata.filename }}</h3>
|
||||
<h3 class="uk-margin-remove uk-margin-left">
|
||||
<b>SCAN</b> {{ allScans[galleryFolder].metadata.filename }}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="uk-grid-medium uk-grid-match uk-margin-top" uk-grid>
|
||||
|
||||
<div v-for="item in sortedItems" :key="item.metadata.id">
|
||||
<scanCard
|
||||
<scanCard
|
||||
v-if="'isScan' in item"
|
||||
:metadata="item.metadata"
|
||||
:thumbnail="item.thumbnail"
|
||||
/>
|
||||
<captureCard
|
||||
<captureCard
|
||||
v-else
|
||||
:metadata="item.metadata"
|
||||
:temporary="item.temporary"
|
||||
:path="item.path"
|
||||
/>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import captureCard from './galleryComponents/captureCard.vue'
|
||||
import scanCard from './galleryComponents/scanCard.vue'
|
||||
import axios from "axios";
|
||||
import captureCard from "./galleryComponents/captureCard.vue";
|
||||
import scanCard from "./galleryComponents/scanCard.vue";
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
name: 'galleryDisplay',
|
||||
name: "GalleryDisplay",
|
||||
|
||||
components: {
|
||||
captureCard,
|
||||
scanCard
|
||||
},
|
||||
|
||||
data: function () {
|
||||
data: function() {
|
||||
return {
|
||||
captureList: [],
|
||||
checkedTags: [],
|
||||
sortDescending: true,
|
||||
galleryFolder: "",
|
||||
scanTag: 'scan'
|
||||
}
|
||||
scanTag: "scan"
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
captureApiUri: function() {
|
||||
return this.$store.getters.uri + "/camera/capture";
|
||||
},
|
||||
|
||||
allTags: function() {
|
||||
// Return an array of unique tags across all captures
|
||||
var tags = [];
|
||||
for (var capture of this.captureList) {
|
||||
for (var tag of capture.metadata.tags) {
|
||||
if (!tags.includes(tag)) {
|
||||
tags.push(tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
return tags.sort();
|
||||
},
|
||||
|
||||
noScanCaptureList: function() {
|
||||
var captures = [];
|
||||
for (var capture of this.captureList) {
|
||||
// Filter by selected tags
|
||||
var tags = capture.metadata.tags;
|
||||
|
||||
// Add to capture list if matched
|
||||
if (!tags.includes(this.scanTag)) {
|
||||
captures.push(capture);
|
||||
}
|
||||
}
|
||||
|
||||
return captures;
|
||||
},
|
||||
|
||||
allScans: function() {
|
||||
// Return an array of unique tags across all captures
|
||||
var scans = {};
|
||||
|
||||
for (var capture of this.captureList) {
|
||||
var custom = capture.metadata.custom;
|
||||
var tags = capture.metadata.tags;
|
||||
|
||||
if ("scan_id" in custom) {
|
||||
var id = custom["scan_id"];
|
||||
|
||||
// If this scan ID hasn't been seen before
|
||||
if (!(id in scans)) {
|
||||
scans[id] = {};
|
||||
scans[id].isScan = true;
|
||||
scans[id].captureList = [];
|
||||
scans[id].metadata = {
|
||||
filename: custom.basename,
|
||||
time: custom.time,
|
||||
id: custom.scan_id
|
||||
};
|
||||
scans[id].metadata.tags = [];
|
||||
scans[id].metadata.custom = {};
|
||||
}
|
||||
|
||||
// Add the capture object to the scan
|
||||
scans[id].captureList.push(capture);
|
||||
|
||||
// Add missing scan metadata, prioritising first capture
|
||||
for (var key of Object.keys(custom)) {
|
||||
if (!(key in scans[id].metadata.custom)) {
|
||||
scans[id].metadata.custom[key] = custom[key];
|
||||
}
|
||||
}
|
||||
|
||||
// Append missing tags
|
||||
for (var tag of tags) {
|
||||
if (!scans[id].metadata.tags.includes(tag)) {
|
||||
scans[id].metadata.tags.push(tag);
|
||||
}
|
||||
}
|
||||
|
||||
// Create a preview thumbnail
|
||||
if (!("thumbnail" in scans[id])) {
|
||||
scans[id].thumbnail =
|
||||
this.$store.getters.uri +
|
||||
"/camera/capture/" +
|
||||
capture.metadata.id +
|
||||
"/download?thumbnail=true";
|
||||
}
|
||||
}
|
||||
}
|
||||
return scans;
|
||||
},
|
||||
|
||||
scanList: function() {
|
||||
return Object.values(this.allScans);
|
||||
},
|
||||
|
||||
itemList: function() {
|
||||
if (this.galleryFolder) {
|
||||
console.log(this.allScans[this.galleryFolder].captureList);
|
||||
return this.allScans[this.galleryFolder].captureList;
|
||||
} else {
|
||||
return this.noScanCaptureList.concat(this.scanList);
|
||||
}
|
||||
},
|
||||
|
||||
filteredItems: function() {
|
||||
return this.filterCaptureList(this.itemList, this.checkedTags);
|
||||
},
|
||||
|
||||
sortedItems: function() {
|
||||
return this.sortCaptureList(this.filteredItems);
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
// A global signal listener to perform a gallery refresh
|
||||
this.$root.$on('globalUpdateCaptureList', () => {
|
||||
this.updateCaptureList()
|
||||
})
|
||||
this.$root.$on("globalUpdateCaptureList", () => {
|
||||
this.updateCaptureList();
|
||||
});
|
||||
// A global signal listener to set the gallery folder
|
||||
this.$root.$on('globalUpdateCaptureFolder', (folder) => {
|
||||
this.galleryFolder = folder
|
||||
})
|
||||
this.$root.$on("globalUpdateCaptureFolder", folder => {
|
||||
this.galleryFolder = folder;
|
||||
});
|
||||
},
|
||||
|
||||
methods: {
|
||||
updateCaptureList: function() {
|
||||
console.log("Updating capture list...")
|
||||
console.log("Updating capture list...");
|
||||
// Send move request
|
||||
axios.get(this.captureApiUri)
|
||||
.then(response => {
|
||||
this.$store.dispatch('updateState'); // Update store state for good measure
|
||||
this.captureList = response.data; // Update boxes from response
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error) // Let mixin handle error
|
||||
})
|
||||
axios
|
||||
.get(this.captureApiUri)
|
||||
.then(response => {
|
||||
this.$store.dispatch("updateState"); // Update store state for good measure
|
||||
this.captureList = response.data; // Update boxes from response
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error); // Let mixin handle error
|
||||
});
|
||||
},
|
||||
|
||||
filterCaptureList: function(list, filterTags) {
|
||||
|
|
@ -120,153 +267,33 @@ export default {
|
|||
// Add to capture list if matched
|
||||
if (includeCapture == true) {
|
||||
result.push(capture);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return result
|
||||
return result;
|
||||
},
|
||||
|
||||
sortCaptureList: function(list) {
|
||||
function compare(a, b) {
|
||||
if (a.metadata.time < b.metadata.time)
|
||||
return -1;
|
||||
if (a.metadata.time > b.metadata.time)
|
||||
return 1;
|
||||
if (a.metadata.time < b.metadata.time) return -1;
|
||||
if (a.metadata.time > b.metadata.time) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (this.sortDescending == true) {
|
||||
return list.sort(compare).reverse();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return list.sort(compare);
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
computed: {
|
||||
captureApiUri: function () {
|
||||
return this.$store.getters.uri + "/camera/capture"
|
||||
},
|
||||
|
||||
allTags: function () {
|
||||
// Return an array of unique tags across all captures
|
||||
var tags = [];
|
||||
for (var capture of this.captureList) {
|
||||
for (var tag of capture.metadata.tags) {
|
||||
if (!tags.includes(tag)) {
|
||||
tags.push(tag);
|
||||
};
|
||||
};
|
||||
};
|
||||
return tags.sort()
|
||||
},
|
||||
|
||||
noScanCaptureList: function () {
|
||||
var captures = [];
|
||||
for (var capture of this.captureList) {
|
||||
// Assume exclusion
|
||||
var includeCapture = false;
|
||||
|
||||
// Filter by selected tags
|
||||
var tags = capture.metadata.tags;
|
||||
|
||||
// Add to capture list if matched
|
||||
if (!tags.includes(this.scanTag)) {
|
||||
captures.push(capture);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
return captures
|
||||
},
|
||||
|
||||
allScans: function () {
|
||||
// Return an array of unique tags across all captures
|
||||
var scans = {};
|
||||
|
||||
for (var capture of this.captureList) {
|
||||
var custom = capture.metadata.custom;
|
||||
var tags = capture.metadata.tags;
|
||||
|
||||
if ('scan_id' in custom) {
|
||||
var id = custom['scan_id']
|
||||
|
||||
// If this scan ID hasn't been seen before
|
||||
if (!(id in scans)) {
|
||||
scans[id] = {}
|
||||
scans[id].isScan = true
|
||||
scans[id].captureList = []
|
||||
scans[id].metadata = {
|
||||
filename: custom.basename,
|
||||
time: custom.time,
|
||||
id: custom.scan_id
|
||||
}
|
||||
scans[id].metadata.tags = []
|
||||
scans[id].metadata.custom = {}
|
||||
};
|
||||
|
||||
// Add the capture object to the scan
|
||||
scans[id].captureList.push(capture)
|
||||
|
||||
// Add missing scan metadata, prioritising first capture
|
||||
for (var key of Object.keys(custom)) {
|
||||
if (!(key in scans[id].metadata.custom)) {
|
||||
scans[id].metadata.custom[key] = custom[key]
|
||||
};
|
||||
};
|
||||
|
||||
// Append missing tags
|
||||
for (var tag of tags) {
|
||||
if (!scans[id].metadata.tags.includes(tag)) {
|
||||
scans[id].metadata.tags.push(tag)
|
||||
};
|
||||
};
|
||||
|
||||
// Create a preview thumbnail
|
||||
if (!('thumbnail' in scans[id])) {
|
||||
scans[id].thumbnail = this.$store.getters.uri + "/camera/capture/" + capture.metadata.id + "/download?thumbnail=true"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
return scans
|
||||
},
|
||||
|
||||
scanList: function () {
|
||||
return Object.values(this.allScans)
|
||||
},
|
||||
|
||||
itemList: function () {
|
||||
if (this.galleryFolder) {
|
||||
console.log(this.allScans[this.galleryFolder].captureList)
|
||||
return this.allScans[this.galleryFolder].captureList
|
||||
}
|
||||
else {
|
||||
return this.noScanCaptureList.concat(this.scanList)
|
||||
}
|
||||
},
|
||||
|
||||
filteredItems: function () {
|
||||
return this.filterCaptureList(this.itemList, this.checkedTags)
|
||||
},
|
||||
|
||||
sortedItems: function () {
|
||||
return this.sortCaptureList(this.filteredItems)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.navbar {
|
||||
border-width: 0 0 1px 0;
|
||||
border-style: solid;
|
||||
border-color: rgba(180, 180, 180, 0.25)
|
||||
border-color: rgba(180, 180, 180, 0.25);
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,221 +1,246 @@
|
|||
<template>
|
||||
<div ref="streamDisplay" class="stream-display uk-width-1-1 uk-height-1-1 scrollTarget" id="stream-display">
|
||||
<div
|
||||
id="stream-display"
|
||||
ref="streamDisplay"
|
||||
class="stream-display uk-width-1-1 uk-height-1-1 scrollTarget"
|
||||
>
|
||||
<img
|
||||
ref="click-frame"
|
||||
class="uk-align-center uk-margin-remove-bottom"
|
||||
:hidden="!showStream"
|
||||
:src="streamImgUri"
|
||||
alt="Stream"
|
||||
@dblclick="clickMonitor"
|
||||
/>
|
||||
|
||||
<img class="uk-align-center uk-margin-remove-bottom" v-on:dblclick="clickMonitor" v-bind:hidden="!showStream" v-bind:src="streamImgUri" alt="Stream" ref="click-frame">
|
||||
<div v-if="!showStream">
|
||||
<div v-if="$store.state.waiting" class="uk-position-center">
|
||||
<div uk-spinner="ratio: 4.5"></div>
|
||||
</div>
|
||||
|
||||
<div v-if="!showStream">
|
||||
<div v-if="$store.state.waiting" class="uk-position-center">
|
||||
<div uk-spinner="ratio: 4.5" ></div>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="$store.state.globalSettings.disableStream"
|
||||
class="uk-position-center position-relative text-center"
|
||||
>
|
||||
Stream preview disabled
|
||||
</div>
|
||||
|
||||
<div v-else-if="$store.state.globalSettings.disableStream" class="uk-position-center position-relative text-center">
|
||||
Stream preview disabled
|
||||
</div>
|
||||
|
||||
<div v-else class="uk-position-center position-relative text-center">
|
||||
No active connection
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div v-else class="uk-position-center position-relative text-center">
|
||||
No active connection
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import axios from "axios";
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
name: 'stream-display',
|
||||
name: "StreamDisplay",
|
||||
|
||||
data: function () {
|
||||
data: function() {
|
||||
return {
|
||||
displaySize: [0, 0],
|
||||
displayPosition: [0, 0],
|
||||
GpuPreviewActive: false,
|
||||
resizeTimeoutId: setTimeout(this.doneResizing, 500)
|
||||
displaySize: [0, 0],
|
||||
displayPosition: [0, 0],
|
||||
GpuPreviewActive: false,
|
||||
resizeTimeoutId: setTimeout(this.doneResizing, 500)
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
showStream: function() {
|
||||
return (
|
||||
this.$store.getters.ready &&
|
||||
!this.$store.state.globalSettings.disableStream
|
||||
);
|
||||
},
|
||||
streamImgUri: function() {
|
||||
return this.$store.getters.uri + "/stream";
|
||||
},
|
||||
startPreviewUri: function() {
|
||||
return this.$store.getters.uri + "/camera/preview/start";
|
||||
},
|
||||
stopPreviewUri: function() {
|
||||
return this.$store.getters.uri + "/camera/preview/stop";
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
// A global signal listener to change the GPU preview state
|
||||
this.$root.$on('globalTogglePreview', (state) => {
|
||||
console.log(`Toggling preview to ${state}`)
|
||||
this.previewRequest(state)
|
||||
})
|
||||
this.$root.$on("globalTogglePreview", state => {
|
||||
console.log(`Toggling preview to ${state}`);
|
||||
this.previewRequest(state);
|
||||
});
|
||||
// A global signal listener to flash the stream element
|
||||
this.$root.$on('globalFlashStream', (state) => {
|
||||
this.flashStream()
|
||||
})
|
||||
this.$root.$on("globalFlashStream", () => {
|
||||
this.flashStream();
|
||||
});
|
||||
|
||||
// Mutation observer
|
||||
this.sizeObserver = new ResizeObserver(entries => {
|
||||
this.handleResize() // For any element attached to the observer, run handleResize() on change
|
||||
entries.forEach(entry => {}) // Optional: Run something per entry
|
||||
});
|
||||
// Fetch streamDisplay by ref
|
||||
const streamDisplayElement = this.$refs.streamDisplay.parentNode;
|
||||
// Attach streamDisplay to the size observer
|
||||
this.sizeObserver.observe(streamDisplayElement);
|
||||
// Mutation observer
|
||||
this.sizeObserver = new ResizeObserver(() => {
|
||||
this.handleResize(); // For any element attached to the observer, run handleResize() on change
|
||||
});
|
||||
// Fetch streamDisplay by ref
|
||||
const streamDisplayElement = this.$refs.streamDisplay.parentNode;
|
||||
// Attach streamDisplay to the size observer
|
||||
this.sizeObserver.observe(streamDisplayElement);
|
||||
},
|
||||
|
||||
},
|
||||
created: function() {
|
||||
// Watch for host 'ready'
|
||||
this.$store.watch(
|
||||
(state, getters) => {
|
||||
return getters.ready;
|
||||
},
|
||||
(newValue, oldValue) => {
|
||||
// 'ready' changed, so do something
|
||||
console.log(`Updating from ${oldValue} to ${newValue}`);
|
||||
this.previewRequest(this.$store.state.globalSettings.autoGpuPreview);
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
created: function () {
|
||||
// Watch for host 'ready'
|
||||
this.$store.watch(
|
||||
(state)=>{
|
||||
return this.$store.getters.ready
|
||||
},
|
||||
(newValue, oldValue)=>{
|
||||
// 'ready' changed, so do something
|
||||
this.previewRequest(this.$store.state.globalSettings.autoGpuPreview)
|
||||
}
|
||||
)
|
||||
},
|
||||
|
||||
beforeDestroy: function () {
|
||||
// Disconnect the size observer
|
||||
this.sizeObserver.disconnect()
|
||||
},
|
||||
beforeDestroy: function() {
|
||||
// Disconnect the size observer
|
||||
this.sizeObserver.disconnect();
|
||||
},
|
||||
|
||||
methods: {
|
||||
clickMonitor: function(event) {
|
||||
// Calculate steps from event coordinates and store config FOV
|
||||
let xCoordinate = event.offsetX;
|
||||
let yCoordinate = event.offsetY;
|
||||
// Calculate steps from event coordinates and store config FOV
|
||||
let xCoordinate = event.offsetX;
|
||||
let yCoordinate = event.offsetY;
|
||||
|
||||
let xRelative = (0.5*event.target.offsetWidth - xCoordinate)/event.target.offsetWidth;
|
||||
let yRelative = (0.5*event.target.offsetHeight - yCoordinate)/event.target.offsetHeight;
|
||||
let xRelative =
|
||||
(0.5 * event.target.offsetWidth - xCoordinate) /
|
||||
event.target.offsetWidth;
|
||||
let yRelative =
|
||||
(0.5 * event.target.offsetHeight - yCoordinate) /
|
||||
event.target.offsetHeight;
|
||||
|
||||
let xSteps = xRelative * this.$store.state.apiConfig.fov[0];
|
||||
let ySteps = yRelative * this.$store.state.apiConfig.fov[1];
|
||||
let xSteps = xRelative * this.$store.state.apiConfig.fov[0];
|
||||
let ySteps = yRelative * this.$store.state.apiConfig.fov[1];
|
||||
|
||||
// Emit a signal to move, acted on by panelNavigate.vue
|
||||
this.$root.$emit('globalMoveEvent', xSteps, ySteps, 0, false)
|
||||
},
|
||||
|
||||
flashStream: function() {
|
||||
let element = this.$refs.streamDisplay
|
||||
element.classList.remove("uk-animation-fade");
|
||||
element.offsetHeight; /* trigger reflow */
|
||||
element.classList.add("uk-animation-fade");
|
||||
},
|
||||
|
||||
handleResize: function(event) {
|
||||
// Only fires resize event after no resize in 500ms (prevents resize event spam)
|
||||
clearTimeout(this.resizeTimeoutId);
|
||||
this.resizeTimeoutId = setTimeout(this.handleDoneResize, 250)
|
||||
},
|
||||
|
||||
handleDoneResize: function() {
|
||||
// Recalculate size
|
||||
console.log("Recalculating frame size")
|
||||
this.recalculateSize();
|
||||
if (this.$store.state.globalSettings.autoGpuPreview == true && this.GpuPreviewActive == true) {
|
||||
// Reload preview
|
||||
this.$root.$emit('globalTogglePreview', true)
|
||||
}
|
||||
},
|
||||
|
||||
recalculateSize: function () {
|
||||
let element = this.$refs.streamDisplay.parentNode;
|
||||
let bound = element.getBoundingClientRect()
|
||||
|
||||
let elementSize = [bound.width, bound.height]
|
||||
|
||||
let elementPositionOnWindow = [bound.left, bound.top]
|
||||
let windowPositionOnDisplay = [window.screenX, window.screenY]
|
||||
let windowChromeHeight = window.outerHeight - window.innerHeight
|
||||
let elementPositionOnDisplay = [
|
||||
Math.max(0, windowPositionOnDisplay[0] + elementPositionOnWindow[0]),
|
||||
Math.max(0, windowPositionOnDisplay[1] + elementPositionOnWindow[1] + windowChromeHeight)
|
||||
]
|
||||
|
||||
this.displaySize = elementSize
|
||||
this.displayPosition = elementPositionOnDisplay
|
||||
|
||||
console.log(`Size: ${this.displaySize}`)
|
||||
console.log(`Position: ${this.displayPosition}`)
|
||||
},
|
||||
|
||||
previewRequest: function(state) {
|
||||
if (this.$store.getters.ready == true) {
|
||||
// Create URI and set this.GpuPreviewActive depending on if starting or stopping preview
|
||||
if (state == true) {
|
||||
this.GpuPreviewActive = true
|
||||
var requestUri = this.startPreviewUri;
|
||||
}
|
||||
else {
|
||||
this.GpuPreviewActive = false;
|
||||
var requestUri = this.stopPreviewUri;
|
||||
}
|
||||
|
||||
// Generate payload if tracking window position
|
||||
if (this.$store.state.globalSettings.trackWindow == true && state == true) {
|
||||
// Recalculate frame dimensions and position
|
||||
this.recalculateSize()
|
||||
// Copy data into payload array
|
||||
var payload = {
|
||||
window : [
|
||||
this.displayPosition[0],
|
||||
this.displayPosition[1],
|
||||
this.displaySize[0],
|
||||
this.displaySize[1],
|
||||
]
|
||||
}
|
||||
}
|
||||
else {
|
||||
var payload = {}
|
||||
}
|
||||
|
||||
// Send preview request
|
||||
axios.post(requestUri, payload)
|
||||
.then(response => {
|
||||
this.$store.dispatch('updateState'); // Update store state
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error) // Let mixin handle error
|
||||
})
|
||||
}
|
||||
// Emit a signal to move, acted on by panelNavigate.vue
|
||||
this.$root.$emit("globalMoveEvent", xSteps, ySteps, 0, false);
|
||||
},
|
||||
|
||||
},
|
||||
flashStream: function() {
|
||||
let element = this.$refs.streamDisplay;
|
||||
element.classList.remove("uk-animation-fade");
|
||||
element.offsetHeight; /* trigger reflow */
|
||||
element.classList.add("uk-animation-fade");
|
||||
},
|
||||
|
||||
computed: {
|
||||
showStream: function () {
|
||||
return this.$store.getters.ready && !this.$store.state.globalSettings.disableStream
|
||||
},
|
||||
streamImgUri: function () {
|
||||
return this.$store.getters.uri + "/stream"
|
||||
},
|
||||
startPreviewUri: function () {
|
||||
return this.$store.getters.uri + "/camera/preview/start"
|
||||
},
|
||||
stopPreviewUri: function () {
|
||||
return this.$store.getters.uri + "/camera/preview/stop"
|
||||
}
|
||||
}
|
||||
handleResize: function() {
|
||||
// Only fires resize event after no resize in 500ms (prevents resize event spam)
|
||||
clearTimeout(this.resizeTimeoutId);
|
||||
this.resizeTimeoutId = setTimeout(this.handleDoneResize, 250);
|
||||
},
|
||||
|
||||
}
|
||||
handleDoneResize: function() {
|
||||
// Recalculate size
|
||||
console.log("Recalculating frame size");
|
||||
this.recalculateSize();
|
||||
if (
|
||||
this.$store.state.globalSettings.autoGpuPreview == true &&
|
||||
this.GpuPreviewActive == true
|
||||
) {
|
||||
// Reload preview
|
||||
this.$root.$emit("globalTogglePreview", true);
|
||||
}
|
||||
},
|
||||
|
||||
recalculateSize: function() {
|
||||
let element = this.$refs.streamDisplay.parentNode;
|
||||
let bound = element.getBoundingClientRect();
|
||||
|
||||
let elementSize = [bound.width, bound.height];
|
||||
|
||||
let elementPositionOnWindow = [bound.left, bound.top];
|
||||
let windowPositionOnDisplay = [window.screenX, window.screenY];
|
||||
let windowChromeHeight = window.outerHeight - window.innerHeight;
|
||||
let elementPositionOnDisplay = [
|
||||
Math.max(0, windowPositionOnDisplay[0] + elementPositionOnWindow[0]),
|
||||
Math.max(
|
||||
0,
|
||||
windowPositionOnDisplay[1] +
|
||||
elementPositionOnWindow[1] +
|
||||
windowChromeHeight
|
||||
)
|
||||
];
|
||||
|
||||
this.displaySize = elementSize;
|
||||
this.displayPosition = elementPositionOnDisplay;
|
||||
|
||||
console.log(`Size: ${this.displaySize}`);
|
||||
console.log(`Position: ${this.displayPosition}`);
|
||||
},
|
||||
|
||||
previewRequest: function(state) {
|
||||
if (this.$store.getters.ready == true) {
|
||||
var requestUri = null;
|
||||
// Create URI and set this.GpuPreviewActive depending on if starting or stopping preview
|
||||
if (state == true) {
|
||||
this.GpuPreviewActive = true;
|
||||
requestUri = this.startPreviewUri;
|
||||
} else {
|
||||
this.GpuPreviewActive = false;
|
||||
requestUri = this.stopPreviewUri;
|
||||
}
|
||||
|
||||
// Generate payload if tracking window position
|
||||
var payload = {};
|
||||
if (
|
||||
this.$store.state.globalSettings.trackWindow == true &&
|
||||
state == true
|
||||
) {
|
||||
// Recalculate frame dimensions and position
|
||||
this.recalculateSize();
|
||||
// Copy data into payload array
|
||||
payload = {
|
||||
window: [
|
||||
this.displayPosition[0],
|
||||
this.displayPosition[1],
|
||||
this.displaySize[0],
|
||||
this.displaySize[1]
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
// Send preview request
|
||||
axios
|
||||
.post(requestUri, payload)
|
||||
.then(() => {
|
||||
this.$store.dispatch("updateState"); // Update store state
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error); // Let mixin handle error
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.stream-display img {
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
object-fit: contain
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.stream-display {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.position-relative {
|
||||
position: relative !important;
|
||||
position: relative !important;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue