From 21ef1ded86a95684dafdaf82d72c273e03ca1c0d Mon Sep 17 00:00:00 2001 From: Leon van Kammen Date: Wed, 27 Dec 2023 21:31:42 +0000 Subject: [PATCH] work in progress [might break] --- src/3rd/js/extra/$chat.js | 19 +++---- src/3rd/js/extra/$connections.js | 77 ++++++++++++++++---------- src/3rd/js/extra/$menu.js | 50 +++++++++++++++-- src/3rd/js/extra/accessibility.js | 1 + src/3rd/js/extra/network.js | 1 + src/3rd/js/extra/network/matrix.js | 82 ++++++++++++++++++++++++---- src/3rd/js/extra/network/trystero.js | 74 ++++++++++++++++--------- 7 files changed, 220 insertions(+), 84 deletions(-) diff --git a/src/3rd/js/extra/$chat.js b/src/3rd/js/extra/$chat.js index 30a14af..0acd141 100644 --- a/src/3rd/js/extra/$chat.js +++ b/src/3rd/js/extra/$chat.js @@ -135,7 +135,8 @@ chatComponent.css = ` button#showchat{ z-index: 1500; position: fixed; - bottom: 20px; + bottom: 24px; + height: 34px; left: 20px; width: 48%; background: white; @@ -158,6 +159,8 @@ chatComponent.css = ` border:none; width:90%; box-sizing:border-box; + height: 24px; + font-size: var(--xrf-font-size-2); } #messages{ position: absolute; @@ -207,6 +210,9 @@ chatComponent.css = ` #messages .msg.multiline { padding: 2px 14px; } + #messages .msg.config { +background:# + } #messages button { text-decoration:none; margin: 0px 15px 10px 0px; @@ -223,15 +229,6 @@ chatComponent.css = ` #messages,#chatbar,#chatbar *, #messages *{ } - #messages input{ - padding: 7px 15px; - border-block: none; - border-inline: none; - border: 1px solid #888; - background: var(--xrf-lighter-gray); - height: 18px; - max-width:168px; - } #messages button.emoticon, #messages .btn.emoticon { @@ -253,7 +250,7 @@ chatComponent.css = ` background:#EEE; } - nomargin{ + .nomargin{ margin:0; } ` diff --git a/src/3rd/js/extra/$connections.js b/src/3rd/js/extra/$connections.js index 3f1c1d7..0e00b77 100644 --- a/src/3rd/js/extra/$connections.js +++ b/src/3rd/js/extra/$connections.js @@ -26,21 +26,25 @@ connectionsComponent = {

-
+

`, init: (el) => new Proxy({ - webcam: [{plugin:{name:"No thanks"},config(){}}], - chatnetwork: [{plugin:{name:"No thanks"},config(){}}], - scene: [{plugin:{name:"No thanks"},config(){}}], + webcam: [{plugin:{name:"No thanks"},config: () => document.createElement('div')}], + chatnetwork: [{plugin:{name:"No thanks"},config: () => document.createElement('div')}], + scene: [{plugin:{name:"No thanks"},config: () => document.createElement('div')}], + + selectedWebcam: '', + selectedChatnetwork:'', + selectedScene: '', $webcam: $webcam = el.querySelector("#webcam"), $chatnetwork: $chatnetwork = el.querySelector("#chatnetwork"), $scene: $scene = el.querySelector("#scene"), $settings: $settings = el.querySelector("#settings"), - + $connect: $connect = el.querySelector("#connect"), install(opts){ this.opts = opts @@ -49,49 +53,62 @@ connectionsComponent = { $webcam.addEventListener('change', () => this.renderSettings() ) $chatnetwork.addEventListener('change', () => this.renderSettings() ) $scene.addEventListener('change', () => this.renderSettings() ) + }, show(){ $chat.visible = true if( !network.connected ){ + if( el.parentElement ) el.parentElement.remove() $chat.send({message:"", el}) this.renderSettings() + if( !network.meetinglink ){ // set default + $webcam.value = 'Peer2Peer' + $chatnetwork.value = 'Peer2Peer' + $scene.value = 'Peer2Peer' + } }else $chat.send({message:"you are already connected, refresh page to create new connection",class:['info']}) }, connect(){ - navigator.share({ - url: 'https://foo.com', - title: 'your meeting link' - }) + this.update() + this.webcam.selected.connect({webcam:true}) + this.chatnetwork.selected.connect({chat:true}) + this.scene.selected.connect({scene:true}) + this.$connect.setAttribute('disabled','disabled') + this.$connect.classList.add('disabled') + window.notify("🪐 connecting to awesomeness..") + }, + + update(){ + this.selectedWebcam = $webcam.value + this.selectedChatnetwork = $chatnetwork.value + this.selectedScene = $scene.value + }, + + forSelectedPluginsDo(cb){ + // this function looks weird but it's handy to prevent the same plugins rendering duplicate configurations + let plugins = {} + let select = (name) => (o) => o.plugin.name == name ? plugins[ o.plugin.name ] = o : '' + this.webcam.find( select(this.selectedWebcam) ) + this.chatnetwork.find( select(this.selectedChatnetwork) ) + this.scene.find( select(this.selectedScene) ) + for( let i in plugins ){ + try{ cb(plugins[i]) }catch(e){ console.error(e) } + } }, renderSettings(){ let opts = {webcam: $webcam.value, chatnetwork: $chatnetwork.value, scene: $scene.value } - let theWebcam = this.webcam.find( (p) => p.plugin.name == $webcam.value ) - let theChatnetwork = this.chatnetwork.find( (p) => p.plugin.name == $chatnetwork.value ) - let theScene = this.scene.find( (p) => p.plugin.name == $scene.value ) + this.update() $settings.innerHTML = '' - $settings.appendChild(theWebcam.config(opts)) - if( theChatnetwork.plugin.name != theWebcam.plugin.name ) $settings.appendChild( theChatnetwork.config(opts) ) - if( theScene.plugin.name != theWebcam.plugin.name && theScene.plugin.name != theChatnetwork.plugin.name ) - $settings.appendChild( scene.config(opts) ) + this.forSelectedPluginsDo( (plugin) => { + console.log("configuring "+plugin.plugin.name) + console.dir(plugin) + $settings.appendChild( plugin.config(opts) ) + }) }, - randomName(){ - var names = [] - let add = (s) => s.length < 6 && !s.match(/[0-9$]/) && !s.match(/_/) ? names.push(s) : false - for ( var i in window ) add(i) - for ( var i in Object.prototype ) add(i) - for ( var i in Function.prototype ) add(i) - for ( var i in Array.prototype ) add(i) - for ( var i in String.prototype ) add(i) - var a = names[Math.floor(Math.random() * names.length)]; - var b = names[Math.floor(Math.random() * names.length)]; - var c = names[Math.floor(Math.random() * names.length)]; - return String(`${a}-${b}-${c}`).toLowerCase() - } - },{ get(data,k,v){ return data[k] }, diff --git a/src/3rd/js/extra/$menu.js b/src/3rd/js/extra/$menu.js index 849115e..477e543 100644 --- a/src/3rd/js/extra/$menu.js +++ b/src/3rd/js/extra/$menu.js @@ -352,6 +352,13 @@ let utils = { QR.canvas = document.getElementById('qrcode') QR.draw( url, QR.canvas ) },0) + // mobile share + if( typeof navigator.share != 'undefined'){ + navigator.share({ + url, + title: 'your meeting link' + }) + } } } @@ -444,7 +451,7 @@ $menu.css = ` --xrf-lighter-gray: #e4e2fb96; --xrf-font-sans-serif: system-ui, -apple-system, segoe ui, roboto, ubuntu, helvetica, cantarell, noto sans, sans-serif; --xrf-font-monospace: menlo, monaco, lucida console, liberation mono, dejavu sans mono, bitstream vera sans mono, courier new, monospace, serif; - --xrf-font-size-0: 12px; + --xrf-font-size-0: 11px; --xrf-font-size-1: 14px; --xrf-font-size-2: 17px; --xrf-font-size-3: 21px; @@ -805,19 +812,42 @@ $menu.css = ` font-size: var(--xrf-font-size-0); margin-right:10px } + .ruler{ + width:97%; + margin:7px 0px; + } + + a.badge { text-decoration:none; } .xrf select{ - min-width: 200px;oborder-inline: none; + min-width: 200px; + border-inline: none; border-inline: none; border-block: none; - border: 1px solid #AAA; - height: 31px; + border: 3px solid var(--xrf-primary); border-radius: 5px; - background: var(--xrf-lighter-gray); + background: none; + border-radius:30px; + } + .xrf select, + .xrf option{ padding: 0px 16px; + min-width: 200px; + height: 35px; + } + + .xrf input{ + border-radius:30px; + padding: 7px 15px; + border-block: none; + border-inline: none; + border: 1px solid #888; + background: transparent; + height: 18px; + max-width:168px; } .xrf table tr td { @@ -825,10 +855,18 @@ $menu.css = ` text-align:right; } .xrf table tr td:nth-child(1){ - min-width:95px; + min-width:115px; + height:40px; padding-right:15px; } + .xrf small{ + font-size: var(--xrf-font-size-0); + } + .disabled{ + opacity:0.5 + } + ` diff --git a/src/3rd/js/extra/accessibility.js b/src/3rd/js/extra/accessibility.js index fe7e747..fb206cd 100644 --- a/src/3rd/js/extra/accessibility.js +++ b/src/3rd/js/extra/accessibility.js @@ -17,6 +17,7 @@ window.accessibility = (opts) => new Proxy({ settings(){ this.toggle() // *TODO* should show settings screen + if( this.enabled ) window.notify(`accessibility boosted, click here to tweak settings`) }, speak(str, override){ diff --git a/src/3rd/js/extra/network.js b/src/3rd/js/extra/network.js index 46a2e91..fa1113f 100644 --- a/src/3rd/js/extra/network.js +++ b/src/3rd/js/extra/network.js @@ -3,6 +3,7 @@ window.network = (opts) => new Proxy({ connected: false, + meetinglink: "", peers: {}, plugin: {}, opts, diff --git a/src/3rd/js/extra/network/matrix.js b/src/3rd/js/extra/network/matrix.js index f631f19..de56bde 100644 --- a/src/3rd/js/extra/network/matrix.js +++ b/src/3rd/js/extra/network/matrix.js @@ -1,10 +1,13 @@ window.matrix = (opts) => new Proxy({ + el: null, // HTML element + plugin:{ type: 'network', name: '[matrix] channel', - description: '[matrix] is a standardized decentralized privacy-friendly protocol', + description: 'a standardized decentralized privacy-friendly protocol', url: 'https://matrix.org', + protocol: 'matrix://', video: false, audio: false, chat: true, @@ -12,14 +15,45 @@ window.matrix = (opts) => new Proxy({ }, html: { - generic: (opts) => ` + generic: (opts) => `
+ matrix +
- + + + + + + + + + + + + + + + + +
matrixchannel - + +
server + +
user + +
authenticate + +
+
+ Support for Oauth / OpenID is in progress +

` }, @@ -29,20 +63,44 @@ window.matrix = (opts) => new Proxy({ network.plugin['matrix'] = this $connections.chatnetwork = $connections.chatnetwork.concat([this]) $connections.scene = $connections.scene.concat([this]) + this.reactToConnectionHrefs() + }, + + connect(opts){ + console.log("connecting "+this.plugin.name) + console.dir(opts) }, config(opts){ opts = {...opts, ...this.plugin } - let el = document.createElement('div') + this.el = document.createElement('div') let html = this.html.generic(opts) for( let i in opts ){ if( this.html[i] ) html += this.html[i](opts) } - el.innerHTML = html - el.querySelector('.badge').addEventListener('mouseover', () => { - window.notify(`${opts.name} is ${opts.description}.
You can basically make up a new channelname or use an existing one`) + this.el.innerHTML = html + window.notify(`${opts.name} is ${opts.description}, it is the hottest internet technology available at this moment.
Read more about it here.
You can basically make up a new channelname or use an existing one`) + return this.el + }, + + reactToConnectionHrefs(){ + xrf.addEventListener('href', (opts) => { + let {mesh} = opts + if( !opts.click ) return + if( mesh.userData.href.match(this.protocol) ){ + let parts = mesh.userData.href.replace(this.plugin.protocol,'') + if( parts[0] == 'r' ){ // room + $connections.$chatnetwork.value = this.plugin.name + $connections.$scene.value = this.plugin.name + $connections.show() + let server = parts.split("/")[1].replace(/:.*/,'') + let channel = parts.split("/")[1].replace(/.*:/,'') + this.el.querySelector('#channel').value = `#${channel}:${server}` + this.el.querySelector('#server').value = server + console.log("configured matrix") + } + }else window.notify("malformed connection URI: "+mesh.userData.href) }) - return el } }, { @@ -51,9 +109,9 @@ window.matrix = (opts) => new Proxy({ set(data,k,v){ let from = data[k] data[k] = v - switch( k ){ - default: matrix.opts.scene.dispatchEvent({type:`matrix.${k}.change`, from, to:v}) - } + //switch( k ){ + // default: matrix.opts.scene.dispatchEvent({type:`matrix.${k}.change`, from, to:v}) + //} } }) diff --git a/src/3rd/js/extra/network/trystero.js b/src/3rd/js/extra/network/trystero.js index ff5585b..7095e7f 100644 --- a/src/3rd/js/extra/network/trystero.js +++ b/src/3rd/js/extra/network/trystero.js @@ -5,6 +5,7 @@ window.trystero = (opts) => new Proxy({ name: 'Peer2Peer', description: 'P2P using WebRTC over bittorrent for signaling & encryption', url: 'https://github.com/dmotz/trystero', + protocol: 'trystero://', video: true, audio: true, chat: true, @@ -12,23 +13,12 @@ window.trystero = (opts) => new Proxy({ }, html: { - generic: (opts) => ` - - - - -
- - P2P - - -
- - ` + generic: (opts) => `` }, handle: null, // { selfId: .... } when connected - link: null, + ip: null, + roomid: '', selfId: null, connected: false, names: {}, @@ -41,17 +31,32 @@ window.trystero = (opts) => new Proxy({ $connections.webcam = $connections.webcam.concat([this]) $connections.chatnetwork = $connections.chatnetwork.concat([this]) $connections.scene = $connections.scene.concat([this]) + this.reactToConnectionHrefs() }, - connect(){ + connect(opts){ // embedded https://github.com/dmotz/trystero (trystero-torrent.min.js build) + console.log("connecting "+this.plugin.name) console.dir(opts) - this.handle = joinRoom( room.config, room.link ) - this.send({message:'📡 [trystero] opening P2P WebRTC-channel via bittorrent',class:['info']}) + //this.handle = joinRoom( room.config, room.link ) + //this.send({message:'📡 [trystero] opening P2P WebRTC-channel via bittorrent',class:['info']}) }, send(opts){ $chat.send({...opts, source: 'trystero'}) }, + createLink(opts){ + this.link = document.location.href.replace(/#.*/,'') + if( this.link.match(/localhost/) ){ + fetch('https://api.duckduckgo.com/?q=my+ip&format=json') + .then( (res) => res.json() ) + .then( (res) => { + const ipRegex = /Your IP address is ([0-9]+[.][0-9]+[.][0-9]+[.][0-9]+)/g; + const ip = ipRegex.exec(res.Answer)[1] + this.link = this.link.replace(/localhost/, ip ) + }) + } + }, + config(opts){ opts = {...opts, ...this.plugin } let el = document.createElement('div') @@ -59,12 +64,31 @@ window.trystero = (opts) => new Proxy({ for( let i in opts ){ if( this.html[i] ) html += this.html[i](opts) } - el.innerHTML = html - el.querySelector('#randomize').addEventListener('mouseover', () => window.notify("generate random channel name") ) - el.querySelector('.badge').addEventListener('mouseover', () => { - window.notify(`${opts.name} is ${opts.description}
by using a serverless technology called trystero.
You can basically make up your own channelname or choose an existing one`) - }) + window.notify(`${opts.name} is ${opts.description}
by using a serverless technology called webRTC via trystero.
You can basically make up your own channelname or choose an existing one.
Use this for hasslefree anonymous meetings.`) + // resolve ip + if( !this.link ) this.createLink(opts) return el + }, + + reactToConnectionHrefs(){ + xrf.addEventListener('href', (opts) => { + let {mesh} = opts + if( !opts.click ) return + if( mesh.userData.href.match(this.protocol) ){ + let parts = mesh.userData.href.replace(this.plugin.protocol,'') + console.dir(parts) + if( parts[0] == 'r' ){ // room + this.roomid = parts.split("/")[1].replace(/:.*/,'') + this.server = parts.split("/")[1].replace(/.*:/,'') + if( this.server != 'bittorrent' ) window.notify("only bittorrent is supported for trystero (for now) :/") + $connections.show() + $connections.$webcam.value = this.plugin.name + $connections.$chatnetwork.value = this.plugin.name + $connections.$scene.value = this.plugin.name + console.log("configured trystero") + } + }else window.notify("malformed connection URI: "+mesh.userData.href) + }) } }, @@ -74,9 +98,9 @@ window.trystero = (opts) => new Proxy({ set(data,k,v){ let from = data[k] data[k] = v - switch( k ){ - default: trystero.opts.scene.dispatchEvent({type:`trystero.${k}.change`, from, to:v}) - } + //switch( k ){ + // default: elcene.dispatchEvent({type:`trystero.${k}.change`, from, to:v}) + //} } })