UNPKG

8.44 kBPlain TextView Raw
1<template>
2 <div class='guacamoleClient' :class="[viewState, clientState, {'hide-overflow': options.autoScale, 'no-control': !control} ]" ref="main">
3
4 <div class="guac_client__header guac_client-slot">
5 <slot name="header"/>
6 </div>
7
8 <div class='flex-expand display-wrapper' ref="displayWrapper">
9
10 <img class='static-image' :src="staticImage.src" v-show="staticImage.src && !isConnected" >
11 <div class="static-overlay" v-show="!isConnected"/>
12
13 <div v-show='isConnected'
14 id='display'
15 @click='hideNav'
16 ref="display"
17 />
18
19 <guac-options-drawer
20 :options="options"
21 :viewState="viewState"
22 :client="client"
23 :resolution="resolution"
24 :control="control"
25 @setClipboard="setClipboard"
26 @disconnect="disconnect"
27 @connect="connect"
28 @exitFullscreen="exitFullscreen"
29 @resolutionChange="resolutionChange"
30 v-if="!hideOptions"
31 />
32
33 <transition name="'fade'">
34 <div class="guac_client-status guac-center" v-show="!isConnected">
35 <guac-notification :status="options.clientState" :options="options" :message="message ">
36 <slot name="status" slot="statusOverride" />
37 </guac-notification>
38 </div>
39 </transition>
40
41
42 </div>
43
44 <div class="guac_client__footer guac_client-slot">
45 <slot v-show='!isFullscreen' name="footer"/>
46 </div>
47
48 </div>
49</template>
50
51<script>
52
53 //Mixins
54 import GuacDisplay from './components/GuacDisplay'
55 import GuacConnection from './components/GuacConnection'
56 import GuacState from './components/GuacState'
57 import GuacInput from './components/GuacInput'
58 import GuacErrors from './components/GuacErrors'
59 import fscreen from 'fscreen'
60
61 //Components
62 import GuacOptionsDrawer from './components/GuacOptionsDrawer'
63 import GuacNotification from './components/GuacNotification'
64
65 import Guacamole from 'guacamole-common-js'
66 export default {
67 components: {GuacOptionsDrawer, GuacNotification},
68 props: { connectionID: { default: null },
69 control: { default: true },
70 webSocketTunnel: { default: null },
71 httpTunnel: { default: null },
72 defaultView: { default: 'thumbnail' },
73 resolution: { default: '1920x1080' },
74 hideOptions: { default: false }
75 },
76
77 name: 'GuacamoleClient',
78
79 mixins: [ GuacDisplay, GuacConnection, GuacState, GuacInput ],
80
81 beforeDestroy: function(){
82 try{ this.tunnel.disconnect() }catch(err){ }
83 try{ this.client.disconnect() }catch(err){ }
84
85 this.tunnel = this.display = this.client = this.keyboard = this.error = null;
86 this.staticImage = this.options = this.errors = null;
87 },
88
89 data () {
90 return {
91 errors: GuacErrors.ERRORS,
92 options: {
93 showOptionsDrawer: false,
94 showConnectionStatus: true,
95 autoScale: true,
96 scale: 1,
97 tunnelState: 'Not Connected',
98 clientState: 'Not Connected'
99 },
100 tunnel: null,
101 staticImage: {
102 src: null,
103 width: null,
104 height: null
105 },
106 client: null,
107 display: null,
108 keyboard: null,
109 mouse: null,
110 error: null,
111 viewState: this.defaultView,
112 updateActivity: _.throttle(this.emitActivityUpdate, 5000),
113 }
114 },
115 methods: {
116
117 updateStaticImage () {
118 if (!this.$refs.display || !this.display || !this.isConnected) return;
119 this.staticImage.src = this.display.flatten().toDataURL('image/png')
120 },
121
122 fullscreen() {
123 fscreen.addEventListener('fullscreenchange', this.fullScreedExited, false)
124 fscreen.requestFullscreen(this.$refs.displayWrapper)
125 setTimeout(this.adjustScale, 1000)
126 // this.$nextTick(this.adjustScale)
127
128 },
129
130 fullScreedExited(){
131 if (!fscreen.fullscreenElement) {
132 fscreen.removeEventListener('fullscreenchange', this.fullScreedExited, false)
133 this.viewState = 'full'
134 }
135 },
136
137 emitActivityUpdate(){
138 this.$emit('activity', Date.now())
139 },
140
141 resolutionChange(data){
142 this.$emit('resolutionChange', data)
143 },
144
145 exitFullscreen(){
146 fscreen.exitFullscreen();
147 this.viewState = 'full';
148 },
149
150 hideNav () {
151 this.options.showOptionsDrawer = false
152 this.$refs.display.focus()
153 },
154
155 setViewState(state) {
156 this.viewState = state
157 if (this.viewState == 'fullscreen'){
158 this.fullscreen()
159 }
160 }
161 },
162 computed: {
163 isFullscreen () {
164 return this.viewState == 'fullscreen'
165 },
166 isConnected () {
167 return this.connectionID && this.status == 'Connected'
168 },
169
170 enlargedView () {
171 if (!this.isConnected) return false
172 if (this.viewState == 'thumbnail') return false
173 return true
174 },
175
176 clientState () {
177 return this.options.clientState.toLowerCase()
178 },
179
180 message () {
181 if (this.error) {
182 // Get Error message
183 let message = this.error.message ? this.error.message : 'Connection has been disconnected'
184 console.log('Guacamole Error: ' + this.error.message)
185
186 // If reconnection is recommended, emit event to reconnect
187 if (this.error.reconnect){
188 this.disconnect()
189 this.$emit('reconnect')
190 console.log('Guacamole Error: ' + this.error.message)
191 return
192 }
193
194 return message
195 }
196 return 'Waiting for Guacamole Connection'
197 }
198 },
199 watch: {
200 'viewState': function (newState) {
201 this.$nextTick( () => {
202 this.adjustScale()
203 this.$emit('viewStateChanged', newState)
204 })
205 let interval = setInterval(this.adjustScale, 500)
206 setTimeout(() => {
207 clearInterval(interval)
208 }, 10000)
209 },
210 'options.showOptionsDrawer': function (showOptionsDrawer) {
211 if (!this.keyboard) return;
212
213 if (!showOptionsDrawer) {
214 this.keyboard.onkeydown = (keysym) => this.client.sendKeyEvent(1, keysym)
215 this.keyboard.onkeyup = (keysym) => this.client.sendKeyEvent(0, keysym)
216 } else {
217 this.keyboard.onkeydown = null
218 this.keyboard.onkeyup = null
219 }
220 }
221 },
222 mounted() {
223 this.disconnect()
224 this.connect()
225 setInterval(this.updateStaticImage, 5000)
226 }
227 }
228</script>
229
230<style scoped>
231
232 .static-image{
233 position: absolute;
234 height: 100%;
235 }
236
237
238 .static-overlay{
239 width: 100%;
240 height: 100%;
241 position: absolute;
242 background-color: #676a6cb5
243 }
244
245 .guacamoleClient {
246 position: inherit;
247 padding: 0px;
248 border: 0px;
249 display: flex;
250 flex-flow: column nowrap;
251
252 }
253
254 .guacamoleClient.thumbnail {
255 width: 450px;
256 z-index: 7;
257 border: 1px solid #e8e8e8;
258 border-radius: 5px;
259 box-sizing: border-box;
260 }
261
262 .guacamoleClient.full {
263 position: fixed !important;
264 top: 0px !important;
265 left: 0px !important;
266
267 height: 100% !important;
268 width: 100% !important;
269 z-index: 9999;
270 }
271
272
273
274 .display-wrapper{
275 background-color: #3d3d5c;;
276 display: flex;
277 width: 100%;
278 flex-direction: column;
279 justify-content: center;
280 overflow: hidden;
281 z-index: 8;
282 position: relative;
283 }
284
285 .thumbnail .display-wrapper{
286 height: 260px;
287 width: 450px;
288 pointer-events: none;
289 z-index: 7;
290 }
291
292 .full .client-slot{
293 z-index: 10;
294 }
295
296
297 .flex-expand{
298 flex: 1 1 auto;
299 align-items: center;
300 }
301
302 .flex-fixed{
303 flex: 0 0 auto;
304 }
305
306
307 .static-wrapper img{
308 margin: auto;
309 }
310 #display div{
311 margin: auto;
312 }
313
314 .guacamoleClient.connected #display:hover {
315 cursor: none;
316 }
317
318 .guacamoleClient.connected.no-control #display:hover {
319 cursor: inherit;
320 }
321
322 .hide-overflow {
323 overflow: hidden;
324 }
325
326 .guac_client-slot{
327 background-color: white;
328 }
329
330 .guac-center{
331 margin: auto;
332 position: absolute;
333 top: 0; left: 0; bottom: 0; right: 0;
334 height: 125px;
335 width: 400px;
336 background-color: #e8e8e8;
337 }
338
339 .fade-enter-active, .fade-leave-active {
340 transition: opacity 5s;
341 }
342 .fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
343 opacity: 0;
344 }
345
346</style>