Compare commits
	
		
			4 Commits
		
	
	
		
			8cd94b30f6
			...
			93b66b6a26
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 93b66b6a26 | |||
| ee1750c23c | |||
| f5104c807d | |||
| 2c49a72d94 | 
| @ -26,8 +26,7 @@ As a unique bonus, you can launch a full text editor from within. | |||||||
| xP | xP | ||||||
| -- | -- | ||||||
| The web frontend for 'xC', making use of its networked relay interface. | The web frontend for 'xC', making use of its networked relay interface. | ||||||
| So far it's quite basic, yet usable.  Build it using `make` in its directory, | So far it's quite basic, yet usable. | ||||||
| and run it from within the _public_ subdirectory. |  | ||||||
| 
 | 
 | ||||||
| xF | xF | ||||||
| -- | -- | ||||||
| @ -116,6 +115,11 @@ a Screen or tmux session. | |||||||
| file or something like `killall` if you want to terminate it.  You can run it | file or something like `killall` if you want to terminate it.  You can run it | ||||||
| as a `forking` type systemd user service. | as a `forking` type systemd user service. | ||||||
| 
 | 
 | ||||||
|  | xP | ||||||
|  | ~~ | ||||||
|  | Install the Go compiler, and build the server using `make` in its directory, | ||||||
|  | then run it from within the _public_ subdirectory. | ||||||
|  | 
 | ||||||
| Client Certificates | Client Certificates | ||||||
| ------------------- | ------------------- | ||||||
| 'xC' will use the SASL EXTERNAL method to authenticate using the TLS client | 'xC' will use the SASL EXTERNAL method to authenticate using the TLS client | ||||||
|  | |||||||
| @ -24,8 +24,8 @@ class RelayRpc extends EventTarget { | |||||||
| 			} | 			} | ||||||
| 			// It's going to be code 1006 with no further info.
 | 			// It's going to be code 1006 with no further info.
 | ||||||
| 			ws.onclose = event => { | 			ws.onclose = event => { | ||||||
| 				reject() |  | ||||||
| 				this.ws = undefined | 				this.ws = undefined | ||||||
|  | 				reject() | ||||||
| 			} | 			} | ||||||
| 		}) | 		}) | ||||||
| 	} | 	} | ||||||
| @ -122,15 +122,25 @@ class RelayRpc extends EventTarget { | |||||||
| 
 | 
 | ||||||
| // ---- Event processing -------------------------------------------------------
 | // ---- Event processing -------------------------------------------------------
 | ||||||
| 
 | 
 | ||||||
| // TODO: Probably reset state on disconnect, and indicate to user.
 |  | ||||||
| let rpc = new RelayRpc(proxy) | let rpc = new RelayRpc(proxy) | ||||||
| rpc.connect() |  | ||||||
| 	.then(result => { |  | ||||||
| 		rpc.send({command: 'Hello', version: 1}) |  | ||||||
| 	}) |  | ||||||
| 
 | 
 | ||||||
| let buffers = new Map() | let buffers = new Map() | ||||||
| let bufferCurrent = undefined | let bufferCurrent = undefined | ||||||
|  | let connecting = true | ||||||
|  | rpc.connect().then(result => { | ||||||
|  | 	buffers.clear() | ||||||
|  | 	bufferCurrent = undefined | ||||||
|  | 	rpc.send({command: 'Hello', version: 1}) | ||||||
|  | 	connecting = false | ||||||
|  | 	m.redraw() | ||||||
|  | }).catch(error => { | ||||||
|  | 	connecting = false | ||||||
|  | 	m.redraw() | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | rpc.addEventListener('close', event => { | ||||||
|  | 	m.redraw() | ||||||
|  | }) | ||||||
| 
 | 
 | ||||||
| rpc.addEventListener('BufferUpdate', event => { | rpc.addEventListener('BufferUpdate', event => { | ||||||
| 	let e = event.detail, b = buffers.get(e.bufferName) | 	let e = event.detail, b = buffers.get(e.bufferName) | ||||||
| @ -155,14 +165,18 @@ rpc.addEventListener('BufferRemove', event => { | |||||||
| rpc.addEventListener('BufferActivate', event => { | rpc.addEventListener('BufferActivate', event => { | ||||||
| 	let e = event.detail | 	let e = event.detail | ||||||
| 	bufferCurrent = e.bufferName | 	bufferCurrent = e.bufferName | ||||||
| 	// TODO: Somehow scroll to the end of it immediately.
 | 	setTimeout(() => { | ||||||
| 	// TODO: Focus the textarea.
 | 		let el = document.getElementById('input') | ||||||
|  | 		if (el !== null) | ||||||
|  | 			el.focus() | ||||||
|  | 	}) | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| rpc.addEventListener('BufferLine', event => { | rpc.addEventListener('BufferLine', event => { | ||||||
| 	let e = event.detail, b = buffers.get(e.bufferName) | 	let e = event.detail, b = buffers.get(e.bufferName) | ||||||
| 	if (b !== undefined) | 	if (b === undefined) | ||||||
| 		b.lines.push({when: e.when, rendition: e.rendition, items: e.items}) | 		return | ||||||
|  | 	b.lines.push({when: e.when, rendition: e.rendition, items: e.items}) | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| rpc.addEventListener('BufferClear', event => { | rpc.addEventListener('BufferClear', event => { | ||||||
| @ -194,11 +208,11 @@ function applyColor(fg, bg, inverse) { | |||||||
| 	if (inverse) | 	if (inverse) | ||||||
| 		[fg, bg] = [bg >= 0 ? bg : 15, fg >= 0 ? fg : 0] | 		[fg, bg] = [bg >= 0 ? bg : 15, fg >= 0 ? fg : 0] | ||||||
| 
 | 
 | ||||||
| 	let style = '' | 	let style = {} | ||||||
| 	if (fg >= 0) | 	if (fg >= 0) | ||||||
| 		style += `color: ${palette[fg]};` | 		style.color = palette[fg] | ||||||
| 	if (bg >= 0) | 	if (bg >= 0) | ||||||
| 		style += `background-color: ${palette[bg]};` | 		style.backgroundColor = palette[bg] | ||||||
| 	if (style) | 	if (style) | ||||||
| 		return style | 		return style | ||||||
| } | } | ||||||
| @ -295,6 +309,19 @@ let Content = { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| let Buffer = { | let Buffer = { | ||||||
|  | 	oncreate: vnode => { | ||||||
|  | 		if (vnode.dom === undefined) | ||||||
|  | 			return | ||||||
|  | 
 | ||||||
|  | 		let el = vnode.dom.children[1] | ||||||
|  | 		if (el !== null) | ||||||
|  | 			el.scrollTop = el.scrollHeight | ||||||
|  | 	}, | ||||||
|  | 
 | ||||||
|  | 	onupdate: vnode => { | ||||||
|  | 		Buffer.oncreate(vnode) | ||||||
|  | 	}, | ||||||
|  | 
 | ||||||
| 	view: vnode => { | 	view: vnode => { | ||||||
| 		let lines = [] | 		let lines = [] | ||||||
| 		let b = buffers.get(bufferCurrent) | 		let b = buffers.get(bufferCurrent) | ||||||
| @ -365,7 +392,7 @@ function onKeyDown(event) { | |||||||
| // and we'll probably have to intercept /all/ key presses.
 | // and we'll probably have to intercept /all/ key presses.
 | ||||||
| let Input = { | let Input = { | ||||||
| 	view: vnode => { | 	view: vnode => { | ||||||
| 		return m('textarea', { | 		return m('textarea#input', { | ||||||
| 			rows: 1, | 			rows: 1, | ||||||
| 			onkeydown: onKeyDown, | 			onkeydown: onKeyDown, | ||||||
| 		}) | 		}) | ||||||
| @ -374,8 +401,14 @@ let Input = { | |||||||
| 
 | 
 | ||||||
| let Main = { | let Main = { | ||||||
| 	view: vnode => { | 	view: vnode => { | ||||||
|  | 		let state = "Connected" | ||||||
|  | 		if (connecting) | ||||||
|  | 			state = "Connecting..." | ||||||
|  | 		else if (rpc.ws === undefined) | ||||||
|  | 			state = "Disconnected" | ||||||
|  | 
 | ||||||
| 		return m('.xP', {}, [ | 		return m('.xP', {}, [ | ||||||
| 			m('.title', {}, "xP"), | 			m('.title', {}, `xP (${state})`), | ||||||
| 			m('.middle', {}, [m(BufferList), m(Buffer)]), | 			m('.middle', {}, [m(BufferList), m(Buffer)]), | ||||||
| 			m('.status', {}, bufferCurrent), | 			m('.status', {}, bufferCurrent), | ||||||
| 			m(Input), | 			m(Input), | ||||||
| @ -383,9 +416,4 @@ let Main = { | |||||||
| 	}, | 	}, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // TODO: Buffer names should work as routes.
 | window.addEventListener('load', () => m.mount(document.body, Main)) | ||||||
| window.addEventListener('load', () => { |  | ||||||
| 	m.route(document.body, '/', { |  | ||||||
| 		'/': Main, |  | ||||||
| 	}) |  | ||||||
| }) |  | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user