UNPKG

copious-transitions

Version:
1,841 lines (1,632 loc) 52.2 kB
<!doctype html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="author" content="Richard Leddy" /> <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes"> <meta id="theme-color" name="theme-color" content="#452770"> <link rel="canonical" href="{{canonical}}"> <title>{{pageTitle}}</title> <meta name="description" content="{{pageDescription}}"> <style> /*csslint important:false*/ /* ========================================================================== Pure Base Extras ========================================================================== */ /** * Extra rules that Pure adds on top of Normalize.css html { } */ /** * Always hide an element when it has the `hidden` HTML attribute. */ .hidden, [hidden] { display: none !important; } /** * Add this class to an image to make it fit within it's fluid parent wrapper while maintaining * aspect ratio. */ .pure-img { max-width: 100%; height: auto; display: block; } .items { display: flex; flex-wrap: wrap; margin-left: -10px; margin-top: -10px; } .items .item { flex: 1 0 300px; box-sizing: border-box; background: -webkit-linear-gradient(to right, rgba(242, 242, 210, 0.3), white)); background: linear-gradient(to right, rgba(242, 242, 210, 0.3), white ); color: #171e42; padding: 10px; margin-left: 10px; margin-top: 0px; } .items .extra-i { padding-left: 10%; padding-bottom: 4px; padding-right: 12px; font-size: 110%; font-family: sans-serif; } .middleBanner { text-align: 'center'; padding-left: 10%; padding-right: 10%; font-weight:bold; color: darkgreen; padding-top:4%; overflow:auto; } .applink { padding:3px; background-color: cornsilk; width:inherit; min-height: 100%; color:darkolivegreen; font-weight: bolder; } .extraBanner { text-align: 'center'; padding-left: 10%; padding-right: 10%; font-weight:bold; color: #FF4400; padding-top:4%; } .fillLowerWrap { width: 66%; margin-left:0px; margin-right:0px; padding: 8px; margin-top:8px; background: -webkit-linear-gradient(to right, white, #FAFAFF); background: linear-gradient(to right, white, #FAFAFF ); margin-left: 10px; } .fitMenuLower { width: 95%; height: 50%; margin-left:0px; margin-right:0px; padding: 8px; margin-top:8px; background: -webkit-linear-gradient(to right, white, #FAFAFF); background: linear-gradient(to right, white, #FAFAFF ); margin-left: 10px; } #squashMenu:hover { border: 1px solid rgb(230,230,240,0.4); padding-top:4px; background-color: #EFEFEF; } #squashMenuContainer { position:absolute; visibility:hidden; top : 0; left : 0; height:100%; width: 55%; z-index:100; border: rgba(252, 190, 190, 0.4) 2px solid; background-color: white; } .fade_able { position:absolute; visibility:hidden; top : 10px; left : 10px; height:80%; width: 40%; z-index:101; border: rgba(252, 190, 190, 0.4) 2px solid; background-color: white; overflow:hidden; } .solid_able { position:absolute; visibility:hidden; top : 10px; left : 10px; height:80%; width: 40%; z-index:111; border: rgba(252, 190, 190, 0.4) 2px solid; background-color: white; overflow: hidden; } @media screen and (max-width: 950px) { .solid_able { width: 90%; } } #thankyou_box { position:absolute; visibility:hidden; top : 25%; left : 25%; height:50%; width: 50%; z-index:150; border: rgba(100, 5, 5, 0.6) 2px solid; background-color: lightgoldenrodyellow; overflow: auto; } @media screen and (max-width: 1040px) { .fade_able { width: 60%; } } @media screen and (max-width: 600px) { .fade_able { width: 90%; } } .fade_able_content { height:100%; width: 100%; overflow:auto; } .togglebar { height:20px; visibility:inherit; background-color: navy; text-align:right; } .closer_x { padding:2px; color:purple; font-weight:bolder; border: solid 1px red; cursor:pointer; } @media (max-width: 1225px) { .fillLowerWrap { visibility : "none"; height : 0px; } } .fillLower { border: darkred 2px solid; height: 96%; width: 96%; margin-left: 10px; padding:8px; background: -webkit-linear-gradient(to right, rgba(252, 252, 240, 0.4), #FEFEFE); background: linear-gradient(to right, rgba(252, 252, 240, 0.4), #FEFEFE ); } button { cursor: pointer; font-size: 101%; font-weight: bold; color: darkblue; margin: 2px; width:120px; } button:hover { background-color : #CACAFF; color: darkred; } @media screen and (max-width: 390px) { .items .extra-i { padding-left: 1%; } } @media screen and (max-width: 600px) { .items .extra-i { padding-left: 3%; } } .longviz { visibility : "visibile"; height: 10px; background-color:inherit; } @media (max-width: 1040px) { .longviz { visibility : "none"; height : 0px; } } .shortviz { visibility : "none"; height:0px; margin-top:6px; } @media (max-width: 620px) { .shortviz { visibility : "visible"; height:2px; background-color:darkgreen; margin-bottom:12px; } } @media (min-width: 1040px) { .shortviz { visibility : "visible"; height:120px; border: 2px darkblue solid; background-color:#FFFFF6; margin-bottom:30px; margin-top:5px; } } @media (min-width: 380px) { .items .item { max-width: calc(100% - 20px); } .items .extra-i { padding-left: 3%; } } @media (min-width: 410px) { .items .item { max-width: calc(100% - 10px); } } @media (min-width: 620px) { .items .item { max-width: calc(50% - 10px); } } @media (min-width: 830px) { .items .item { max-width: calc(50% - 10px); } } @media (min-width: 1040px) { .items .item { max-width: calc(33.33333% - 10px); } } @media (min-width: 1250px) { .items .item { max-width: calc(25%- 10px); } } @media (min-width: 1460px) { .items .item { max-width: calc(20% - 10px); } } @media (min-width: 1670px) { .items .item { min-width: calc(16.66667% - 10px); } } body { border: 1px solid black; -moz-box-sizing: border-box; box-sizing: border-box; } @media screen and (orientation: portrait) { #mainNav { width: 100%; } } @media screen and (orientation: landscape) { #mainNav { width: 100%; } } main { border-left: solid 3px navy; border-top: solid 1px #8833BB; padding : 4px; } #mainNav { font-family: 'Montserrat', 'Helvetica Neue', Helvetica, Arial, sans-serif; font-weight: 700; text-transform: uppercase; background: blue; border-left: solid 3px navy; border-top: solid 3px navy; border-bottom: solid 3px rgba(252,252,255,0.7); min-height: 90px padding: 20px background: -webkit-linear-gradient(to left, rgba(242, 242, 210, 0.3), white); background: linear-gradient(to left, rgba(242, 242, 210, 0.3), white ); } #mainNav table { padding-left: 3%; } #mainNav table a:focus { outline: none; } #mainNav table .navbar-brand { font-size: 1.1rem; color: white; } #mainNav table .navbar-brand.active, #mainNav .navbar-brand:active, #mainNav .navbar-brand:focus, #mainNav .navbar-brand:hover { color: white; } #mainNav table .navbar-nav { letter-spacing: 1px; } #mainNav table .navbar-nav li.nav-item { display:inline; } #mainNav table .navbar-nav li.nav-item a.nav-link { color: darkgreen; text-decoration: none; vertical-align: top; padding-right: 10px; } #mainNav table .navbar-nav li.nav-item a.nav-link:hover { color: #18BC9C; outline: none; } #mainNav table .navbar-nav a.nav-text { background-color : rgba(242,222,255,0.6); border-radius: 25px; margin-bottom: 9px; margin-right: 6px; white-space: nowrap; } #mainNav table .navbar-nav li.nav-item a.nav-link:active, #mainNav .navbar-nav li.nav-item a.nav-link:focus { color: white; } .footer-list li { list-style-type: none; } .footer-list li a:hover { color: gold; } .hover_group { cursor:pointer; } .hover_group rect { fill:#e6e6e6; } .hover_group:hover rect { fill: #F6F6e6; } footer { padding:10px; background: -webkit-linear-gradient(to left, rgba(252,252,255,0.5), #fffbe2 ); background: linear-gradient(to left, rgba(252,252,255,0.5), #fffbe2 ); text-align: center; font-size: 0.85em; } footer a { text-decoration:none; color:darkgreen; font-weight:bold; font-style: italic; } .copiouslink:hover { fill:navy; } .copiouslink { fill:black; } * {margin: 0; padding: 0; box-sizing: border-box} .PhIOtjDr_0 { fill:none; stroke:#1c1448; stroke-width:4.59875107; stroke-miterlimit:4; stroke-dasharray: 2948 2950; stroke-dashoffset: 2949; animation: PhIOtjDr_draw 6666ms ease-in forwards; } @keyframes PhIOtjDr_draw { 100% {stroke-dashoffset: 0} } @keyframes PhIOtjDr_fade { 0% {stroke-opacity: 1} 97.1830985915493% {stroke-opacity: 1} 100% {stroke-opacity: 0} } .form_el { border:lightgray solid 1px; padding:6px; margin:2px; width:80%; } .form_el_inner { border:lightgray solid 1px; padding:6px; margin:2px; width:100%; } label { font-weight:bold; color:darkgreen; width:35%; } .field_el { width:65%; } @media (max-width: 1040px) { .field_el { width:94%; margin-left:3%; margin-right:3%; } } #contact_box { background: -webkit-linear-gradient(to right, rgba(252, 252, 240, 1.0), #FEFEFE)); background: linear-gradient(to right, rgba(252, 252, 240, 1.0), #FEFEFE ); } .textarea_field_el { width: 94%; margin:3%; } .error-message { visibility:hidden; width:75%; font-weight:bolder; color:red; background-color:white; border: solid 1px orange; padding:2px; margin:3px; } /* The Modal (background) */ .modal { display: none; /* Hidden by default */ position: relative; /* Stay in place */ z-index: 1; /* Sit on top */ left: 0; top: 0; width: 100%; /* Full width */ height: 100%; /* Full height */ overflow: auto; /* Enable scroll if needed */ background-color: rgb(0,0,0); /* Fallback color */ background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ -webkit-animation-name: fadeIn; /* Fade in the background */ -webkit-animation-duration: 0.4s; animation-name: fadeIn; animation-duration: 0.4s } /* Modal Content */ .modal-content { position: inherit; top: 0; background-color: #fefefe; width: 100%; -webkit-animation-name: slideIn; -webkit-animation-duration: 0.4s; animation-name: slideIn; animation-duration: 0.4s } /* The Close Button */ .close { color: white; float: right; font-size: 18px; font-weight: bold; } .close:hover, .close:focus { color: #000; text-decoration: none; cursor: pointer; } .modal-header { padding: 2px 16px; background-color: #4ca85c; color: white; } .modal-body {padding: 2px 16px;} .modal-footer { padding: 2px 16px; margin-bottom: 20px; background-color: darkgreen; color: white; } /* Add Animation */ @-webkit-keyframes slideIn { from {bottom: -300px; opacity: 0} to {bottom: 0; opacity: 1} } @keyframes slideIn { from {bottom: -300px; opacity: 0} to {top: 0; opacity: 1} } @-webkit-keyframes fadeIn { from {opacity: 0} to {opacity: 1} } @keyframes fadeIn { from {opacity: 0} to {opacity: 1} } #logout-control-top { visibility: hidden; display: none; } a { cursor: pointer; } </style> </head> <script> //var g_siteURL = "localhost"; var g_siteURL = "{{site_url}}"; var g_finalizers = [] var g_loginStateViewHolders = {} var g_loginValueViews = {} </script> <body> <nav id="mainNav"> <table style="width:100%"> <tr> <td style="width:62;height:63"> <a class="nav-link" href="/" target="{{canonical}}-again" > {{{svgLogo.content}}} </a> </td> <td> <ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link" href="{{relatedAsset.link}}" target="{{relatedAsset.name}}" > {{{relatedAsset.content}}} </a> </li> <li id="squashMenu" class="nav-item" style="visibility:hidden;cursor:pointer" onmousedown="menuHandler(this)" onmouseup="releaseMenu(this)"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path class="heroicon-ui" d="M4 5h16a1 1 0 0 1 0 2H4a1 1 0 1 1 0-2zm0 6h16a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2zm0 6h16a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2z"/></svg> </li> </ul> </td> <td> <button id="logout-control-top" class="logout" onclick="logout()">logout</button> </td> </tr> </table> </nav> <main> <div class="items"> <div class="item"> {{{svgBannerFrame.content}}} </div> <div id="greet_and_meet_1" class="item"> <div id="desktopCenter" class="shortviz" ></div> <p class="extra-i" style="color:navy"> Join in the <span style="font-weight:bold;">{{conversation}}</span> conversation. </p> <br> <a id="a4179" href="javascript:join_process()" style="cursor:pointer" > <p class="extra-i" style="text-align:center" > {{{join.button.content}}} </p> </a> </div> <div class="item"> <div class="longviz" >&nbsp;</div> <p class="extra-i" style="color:darkred"> Browse the blog or check out some demonstrations. </p> <br> <p class="extra-i" style="text-align:center"> {{{public_content_access.content}}} </p> <div id="desktopRight" class="shortviz" ></div> </div> <div id="greet_and_meet_2" class="item"> <p class="extra-i" style="color:darkgreen;font-weight:bold;"> Already a member? </p> <hr><br> <a id="a4199" href="javascript:login_process()" style="cursor:pointer"> <p class="extra-i" > {{{login.button.content}}} </p> </a> </div> <div id="lowerFiller" class="fillLowerWrap"> <div class="fillLower"> alpha test </div> </div> </div> </main> <footer> <ul class="footer-list"> <li> <a href="{{canonical}}" target="{{canonical}}-again">copyright &copy; {{copyRightYear}} {{companyShortLink}}</a> </li> </ul> </footer> <div id="squashMenuContainer" > this is a test; </div> <div id="contact_box" class="fade_able" style="z-index:102" > <div class="togglebar" onmouseenter="togglebar(this,1)" onmouseleave="togglebar(this,0)"><span class="closer_x" onmousedown="closefader('contact_box')">x</span></div> <!-- The Modal --> <div class="fade_able_content"> <div id="contactModal" class="modal"> <!-- Modal content --> <div class="modal-content"> <div class="modal-header"> <span id="contactModalCloser" class="close">&times;</span> <h3><i>Captcha</i> : I am not a robot</h3> </div> <div class="modal-body"> <div id="captcha-goes-here" style="border:1px solid lime;margin:2px;" > ------ </div> <div id="captcha-entry" > Type in the text that you see above: <input type="text" id="captcha-field" class="svgFormTextField" style="font-size:14px;margin-top:1px;margin-left:2px;border:1px solid black;"/> </div> </div> <div class="modal-footer"> <button onclick="captchaCheck()">submit</button> </div> </div> </div> <div id="myContactForm" style="padding-left:10%;padding-top:8px;padding-bottom:8px" > <div class="error-message" id="contact-errors_here" >no error</div> <div class="form_el" > <label for='contact-name' class='name'>Name<span> (required) </span></label> <input type='text' name='contact-name' id='contact-name' value='' class='field_el name' required onkeyup="onkey_checkContactError('contact-name')" /> </div> <div class="form_el" > <label for='contact-email' class='email'>Email<span> (required) </span></label> <input type='email' name='contact-email' id='contact-email' value=''class='field_el email' required onkeyup="onkey_checkContactError('contact-email')" /> </div> <div class="form_el" > <label for='contact-website' class='url'>Website<span> (optional)</span></label> <input type='text' name='contact-website' id='contact-website' value='' class='field_el url' onkeyup="onkey_checkContactError('contact-website')" /> </div> <div class="form_el" style="vertical-align:top"> <label for='contact-comment' class='grunion-field-label textarea'>Comment<span>(required)</span></label><br> <textarea name='contact-comment' id='contact-comment' rows='20' class='textarea_field_el' required onkeyup="onkey_checkContactError('contact-comment')" ></textarea> </div> <p class='contact-submit'> <button onclick="processContact()" >Submit</button> </p> <div class="form_el" style="height:20px;background-color:rgb(230,230,240,0.4);font-style: oblique;font-weight: bold;color:rgba(242, 242, 210, 0.3);"> copious contact (thank you for your interest and concerns) </div> </div> </div> </div> <div id="topicBox_1" class="fade_able" style="z-index:103" > <div class="togglebar" onmouseenter="togglebar(this,1)" onmouseleave="togglebar(this,0)"><span class="closer_x" onmousedown="closefader('topicBox_1')">x</span></div> <div class="fade_able_content" > <div style="min-width: 400px;min-height: 300px;"> {{{topicBox_1.content}}} </div> </div> </div> <div id="about_box" class="fade_able" style="z-index:104" > <div class="togglebar" onmouseenter="togglebar(this,1)" onmouseleave="togglebar(this,0)"><span class="closer_x" onmousedown="closefader('about_box')">x</span></div> <div class="fade_able_content" > <div style="min-width: 400px;min-height: 300px;overflow: auto;"> {{{aboutBox.content}}} </div> </div> </div> <div id="topicBox_2" class="fade_able" style="z-index:105" > <div class="togglebar" onmouseenter="togglebar(this,1)" onmouseleave="togglebar(this,0)"><span class="closer_x" onmousedown="closefader('topicBox_2')">x</span></div> <div class="fade_able_content" > <div style="min-width: 400px;min-height: 300px;"> {{{topicBox_2.content}}} </div> </div> </div> <div id="topicBox_3" class="fade_able" style="z-index:106" > <div class="togglebar" onmouseenter="togglebar(this,1)" onmouseleave="togglebar(this,0)"><span class="closer_x" onmousedown="closefader('topicBox_3')">x</span></div> <div class="fade_able_content" > <div style="min-width: 400px;min-height: 300px;"> {{{topicBox_3.content}}} </div> </div> </div> <div id="thankyou_box" class="fade_able" onclick="hide_thankyou_box(this)"> <div class="togglebar" onmouseenter="togglebar(this,1)" onmouseleave="togglebar(this,0)"><span class="closer_x" onmousedown="closefader('thankyou_box')">x</span></div> <div class="fade_able_content" > <span id="thankyou_box-message" style="color:coral;font-weight: 900;font-size:xx-large;">Thank you for your message.</span> </div> </div> <div id="register" class="solid_able" style="z-index:116" > <div class="togglebar" onmouseenter="togglebar(this,1)" onmouseleave="togglebar(this,0)"><span class="closer_x" onmousedown="closesolid('register')">x</span></div> <div class="fade_able_content" > <div style="min-width: 400px;min-height: 300px;"> {{{registerBox.content}}} </div> </div> </div> <div id="login" class="solid_able" style="z-index:117" > <div class="togglebar" onmouseenter="togglebar(this,1)" onmouseleave="togglebar(this,0)"><span class="closer_x" onmousedown="closesolid('login')">x</span></div> <div class="fade_able_content" > <div style="min-width: 400px;min-height: 300px;"> {{{loginBox.content}}} </div> </div> </div> </body> </html> <script> // // global defs of some static topology let centerBox = document.querySelector('#desktopCenter'); let rightBox = document.querySelector('#desktopRight'); let lowerFiller = document.querySelector('#lowerFiller'); const squashMenu = document.querySelector('#squashMenu'); const squashMenuContainer = document.querySelector('#squashMenuContainer'); // const greetAndMeetContainer1 = document.querySelector('#greet_and_meet_1'); const greetAndMeetContainer2 = document.querySelector('#greet_and_meet_2'); // let logoutCtrl = document.getElementById('logout-control-top') // const myContactForm = document.querySelector('#myContactForm'); const g_contact_port = '2004' var g_LoggedIn = false // ---- ---- ---- ---- ---- ---- // CONTENT EXCHANGE // === --------------------------------------- === --------------------------------------- === --------------------------------------- function clonify(obj) { if ( typeof obj === 'string' ) return(obj) try { let out = JSON.parse(JSON.stringify(obj)) return(out) } catch(e) { return(null) } } function addscript(script,whereScipt) { var scriptEl = document.createElement('script'); scriptEl.type = 'text/javascript'; scriptEl.text = script; whereScipt.appendChild(scriptEl); } function getCookie(cname) { // modified from w3school var name = cname + "="; var ca = document.cookie.split(';'); for(let i = 0; i < ca.length; i++) { var c = ca[i]; if ( typeof c === 'string' ) { c = c.trim() if (c.indexOf(name) == 0) { return c.substring(name.length); } } } return ""; } // streamer-scratchpad -- in the stream app was using this. // // async function fetchEndPoint(endpoint,port) { port = !(port) ? '' : ( port.length ? `:${port}` : '') let myRequest = new Request(`${location.protocol}//${g_siteURL}${port}/${endpoint}`); try { const body = await fetch(myRequest, { method: 'GET', // *GET, POST, PUT, DELETE, etc. mode: 'cors', // no-cors, *cors, same-origin cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached credentials: 'omit', // include, *same-origin, omit redirect: 'follow', // manual, *follow, error referrerPolicy: 'no-referrer', // no-referrer, *client }); // let infoObj = await body.json(); return(infoObj) // } catch (e) { console.log(e.message) return(false) } } // async function postData(url = '', data = {}, creds = 'omit', do_stringify = true) { // Default options are marked with * const response = await fetch(url, { method: 'POST', // *GET, POST, PUT, DELETE, etc. mode: 'cors', // no-cors, *cors, same-origin cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached credentials: creds, // include, *same-origin, omit headers: { 'Content-Type': 'application/json' }, redirect: 'follow', // manual, *follow, error referrerPolicy: 'no-referrer', // no-referrer, *client body: (do_stringify ? JSON.stringify(data) : data) // body data type must match "Content-Type" header }); if ( response.ok == false ) { console.log(response.status + ': ' + response.statusText) } return await response.json(); // parses JSON response into native JavaScript objects } // CONTENT FETCHING CLASS class Uploader { // constructor(props) { this.errorDiv = props.errorDiv this.fileDiv = props.fileDiv this.uploadEndpoint = props.uploadEndpoint this.fileType = props.fileType ? props.fileType : '.mp3' // for ( let prop in props ) { this[prop] = props[prop] } // this._msgTimeout = null } // errorMessage(emsg) { let errDiv = document.querySelector(this.errorDiv) if ( errDiv ) { if ( this._msgTimeout ) { clearTimeout(this._msgTimeout) } errDiv.innerHTML = emsg this._msgTimeout = setTimeout(() => { let errDivNxt = document.querySelector(this.errorDiv) errDivNxt.innerHTML = "" },1500) } } // checkFilesSelected(fileType) { let file = document.querySelector(this.fileDiv) if ( !file ) { return(false) } if ( !(file.value) || (file.value.indexOf(fileType) !== (file.value.length - 4)) ) { // File type is not .mp3 return(false) } return(true) } checkForm(event) { if ( this.emailField ) { let inspect_field = document.querySelector(this.emailField) let errField = document.querySelector(this.errorDiv) if ( inspect_field && !checkEmailField(inspect_field) ) { inspect_field.style.borderColor="red" if (errField) errField.style.color = "red" this.errorMessage("unrecognized mail format") return(false) } if ( inspect_field ) inspect_field.style.borderColor="black" } // if ( this.fileDiv ) { let inspect_field = document.querySelector(this.fileDiv) if ( !(inspect_field) || !(this.fileType) ) { this.errorMessage("This page has not specified either a file container <div> or a file type in props [fileDiv,fileType]") return(false) } if ( !this.checkFilesSelected(this.fileType) ) { inspect_field.style.borderColor="red" if (errField) errField.style.color = "red" this.errorMessage("no file selected") return(false) } if ( inspect_field ) inspect_field.style.borderColor="black" } if (errField) errField.style.color = "darkgreen" this.errorMessage("") return(true) } async uploader() { if ( this.checkForm() ) { try { let data = new FormData() this.app_prepData(data) let json = await postData(this.uploadEndpoint,data,'omit',false) this.success_report(json) this.errorMessage(this.positiveCompletion) document.querySelector(this.errorDiv).style.color = "blue" return true } catch (e) { let emsg = e.message this.errorMessage(emsg) return false } } } app_prepData(data) { // mp3 one file as default -- subclass and override let files = document.querySelector(this.fileDiv) let file = files.files[0] data.append('mp3file', file) let email = document.querySelector(this.emailField).value; data.append('email', email) } success_report(json) { if ( this.positiveCompletion ) this.errorMessage(this.positiveCompletion) document.querySelector(this.errorDiv).style.color = "blue" } } // === --------------------------------------- === --------------------------------------- === --------------------------------------- // VALIDATION // -- -- -- -- -- -- -- -- -- -- -- -- -- // var g_ComponentErrorsActivated = false var g_CurContainer = null // var reEmail = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i; function checkEmailField(efield) { let email = efield.value if ( !(reEmail.test(email)) ) { return(false) } return(true) } // ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- function getVal(the_field) { if ( the_field ) { let val = the_field.value; if ( val.length ) { val = encodeURIComponent(val) } return(val) } return("") } function is_empty(the_field) { if ( the_field && ( the_field.value.length > 0 ) ) { return(false) } return(true) } function colorize(theField,colr) { theField.style.borderColor = colr; } class ValidationContainer { // constructor(props) { this.errline = props.errors_here this.fields = props.fields this.checks = props.checks this.modal = props.modal this.closer = props.closer this.form = props.form this.where_captcha = props.captcha this.captch_input = props.captcha_field this.auth_port = props.auth_port this.password_rules = props.password_rules this.service_url = props.service_url this.errline.style.visibility = "hidden" this.failure_msg_prefix = props.failure_msg_prefix this.empty_checker = props.is_empty ? props.is_empty : is_empty } hideFormErrorMessage() { let errline = this.errline if ( errline ) { errline.innerHTML = "" errline.style.visibility = "hidden" } } formErrorMessage(msg) { let errline = this.errline if ( errline ) { errline.innerHTML = msg errline.style.visibility = "visible" } } emptyFieldMessage(fields) { // name_empty,email_empty,commment_empty let msg = "The following fields require values: " // let sep = ',' msg += fields.join(sep) this.formErrorMessage(msg); } emailFormatError() { this.formErrorMessage("Email does not match a known email format."); } passwordFieldError(whichFields) { this.formErrorMessage(`${whichFields} are required to have the same value`); } // checkFormValid() { if ( !g_ComponentErrorsActivated ) { return(true); } for ( let field in this.fields ) { let c = this.fields[field] colorize(c,"black") } // let mustHaveValue = this.checks.is_empty let empty_fields = mustHaveValue.filter((field) => { let c = this.fields[field] //colorize(c,"black") return(this.empty_checker(c)) }) // if ( empty_fields.length ) { this.emptyFieldMessage(empty_fields) empty_fields.forEach(field => { let c = this.fields[field] colorize(c,"red") }) return(false) } // let emailFields = this.checks.email emailFields.forEach(e_field => { let c = this.fields[e_field] if ( !checkEmailField(c) ) { this.emailFormatError(); colorize(c,"red") return(false); } }) // if ( this.password_rules && (typeof this.password_rules === "function") ) { if ( this.checks.passwords && (this.checks.passwords.length) ) { let pvalues = this.checks.passwords.map(pfield => { let c = this.fields[pfield] if ( c ) { return(c.value) } else { return(null) } }) // let [check,violation] = this.password_rules(pvalues) // if ( !check ) { let message = violation() this.passwordFieldError(message) return(false) } // this.hideFormErrorMessage() } } // return(true); } switchCaptchaDisplay(on_off) { if ( on_off ) { this.modal.style.display = "block"; // show captcha this.form.style.display = "none" } else { this.modal.style.display = "none"; // show captcha this.form.style.display = "block" } } } async function processUI_captchaService(handlerDefsValidator,calcAppDataDB,completionaAction,failureAction) { // g_ComponentErrorsActivated = true // will be processing errors, etc. some selective behavior permitted g_CurContainer = handlerDefsValidator // if ( g_CurContainer && g_CurContainer.checkFormValid() ) { try { // CAPTCH PROCESSING let captchaResult = await doCaptcha('','{{auth_path}}') // the captcha has to be processed first. // CAPTCH RESULT if ( captchaResult === true ) { if ( g_currenCaptchaTOKEN ) { let data = calcAppDataDB() // calcAppDataDB try { let resp = await postData(g_CurContainer.service_url, data) if ( resp.OK === "true" ) { g_currenCaptchaTOKEN = null; // check for duplicates if ( completionaAction ) completionaAction(resp); } else { g_CurContainer.formErrorMessage(`${g_CurContainer.failure_msg_prefix}: ${resp.reason}`) if ( failureAction ) failureAction(resp) } } catch (e) { g_CurContainer.formErrorMessage(`${g_CurContainer.failure_msg_prefix}: ${e.message}`) if ( failureAction ) failureAction(resp) } } } else { if ( captchaResult !== false ) { g_CurContainer.switchCaptchaDisplay(false) if ( captchaResult !== undefined ) { g_CurContainer.formErrorMessage(captchaResult) } else { g_CurContainer.formErrorMessage("Web service not responding.") } } } } catch(e) { console.log(e.message) } } else { throw new Error("The current container is not defined in processUI_captchaService.") } } // === --------------------------------------- === --------------------------------------- === --------------------------------------- // CONTENT GENERATION // ---- ---- ---- ---- ---- ---- function centerBoxText(tightpace) { if ( !tightpace ) { return `<div class="middleBanner"> <p style="text-align:center">{{middleBoxHook}}</p> <blockquote style="text-align:center;padding-bottom:4px;"> <button id="contact-btn" onmouseup="pinBox('#contact_box')" onmouseover="defadeBox('#contact_box')" onmouseleave="fade_apparition(this,event)" >contact</button> <button id="topicBox_1-btn" onmouseup="pinBox('#topicBox_1')" onmouseover="defadeBox('#topicBox_1')" onmouseleave="fade_apparition(this,event)" >{{topicBox_1.name}}</button> <button id="about-btn" onmouseup="pinBox('#about_box')" onmouseover="defadeBox('#about_box')" onmouseleave="fade_apparition(this,event)" >about</button> </blockquote> </div>`; } else { return `<div class="middleBanner"> <p style="text-align:center">{{middleBoxHook}}</p> <blockquote style="text-align:center;padding-bottom:4px;"> <button id="contact-btn" onmouseup="pinBox('#contact_box')" onmouseover="defadeBox('#contact_box')" onmouseleave="fade_apparition(this,event)" >contact</button> <button id="about-btn" onmouseup="pinBox('#about_box')" onmouseover="defadeBox('#about_box')" onmouseleave="fade_apparition(this,event)" >about</button> </blockquote> </div>`; } } function rightBoxText() { return `<div class="extraBanner"> <p style="text-align:center">{{rightBoxHook}}</p> <br> <blockquote style="text-align:center;padding-bottom:4px"> <button id="topicBox_2-btn" onmouseup="pinBox('#topicBox_2')" onmouseover="defadeBox('#topicBox_2')" onmouseleave="fade_apparition(this,event)" >{{topicBox_2.name}}</button> <button id="topicBox_3-btn" onmouseup="pinBox('#topicBox_3')" onmouseover="defadeBox('#topicBox_3')" onmouseleave="fade_apparition(this,event)" >{{topicBox_3.name}}</button> </blockquote> </div>`; } function logoutForDropdown() { if ( g_LoggedIn ) { return ` <div style='text-align:center' > <button class='logout' onclick='logout()'>logout</button> </div> ` } else { return "" } } // independent floating box.. function hide_thankyou_box(theBox) { theBox.style.visibility = "hidden" theBox.style.display = "none"; } function show_thankyou_box(msg) { let theBox = document.querySelector("#thankyou_box") if ( theBox ) { if ( msg ) { let mbox = document.querySelector("#thankyou_box-message") if ( mbox ) mbox.innerHTML = msg } theBox.style.visibility = "visible" theBox.style.display = "block"; } } // ---- ---- ---- ---- ---- ---- function lowerFillerText() { return `<div class="fillLower"> {{{decoratedLinks.content}}} </div>`; } function setupLogoutRestoration() { let g_originalGreetAndMeet1 = greetAndMeetContainer1.innerHTML let g_originalGreetAndMeet2 = greetAndMeetContainer2.innerHTML g_loginStateViewHolders["gAndM1"] = { 'element' : greetAndMeetContainer1, 'unauthed' : g_originalGreetAndMeet1, 'authed' : `{{{yourProileLinks.content}}}`, 'action' : `{{yourProileLinks.instantiate}}` } g_loginStateViewHolders["gAndM2"] = { 'element' : greetAndMeetContainer2, 'unauthed' : g_originalGreetAndMeet2, 'authed' : `{{{yourDashboardLinks.content}}}`, 'action' : `{{yourDashboardLinks.instantiate}}` } } function menuHandler(mHandle) { if ( squashMenuContainer.style.visibility !== "visible" && (mHandle !== null) ) { squashMenuContainer.style.visibility = "visible" squashMenuContainer.style.top = "60px"; squashMenuContainer.style.left = (Math.floor(window.innerWidth/2) - 40) + "px"; squashMenuContainer.style.height = (window.innerHeight - 64) + "px"; squashMenuContainer.style.width = (Math.floor(window.innerWidth/2) + 34) + "px"; // let lowerText = lowerFillerText(); let menuLower = `<div class="fitMenuLower"> ${lowerText} </div>` squashMenuContainer.innerHTML = logoutForDropdown() + centerBoxText(false) + rightBoxText() + menuLower; // } else { squashMenuContainer.style.visibility = "hidden" } } function releaseMenu(mHandle) { } // === --------------------------------------- === --------------------------------------- === --------------------------------------- // ANIMATION // -- -- -- -- -- -- -- -- -- -- -- -- -- // var g_apparition = null; var g_current_pin = null; var g_fade_scheduled = null; var g_defade_scheduled = null; function togglebar(the_bar,state) { // enter exit animation if ( state == 1 ) { if ( the_bar ) { the_bar.style.backgroundColor = "darkgreen" } } else { if ( the_bar ) { the_bar.style.backgroundColor = "navy" } } } function hideFader(fdr) { fdr.style.visibility = "hidden" fdr.style.zIndex = -10 stopDefade() stopFade() g_apparition = null; g_current_pin = null; if ( !g_ComponentErrorsActivated ) { if ( g_CurContainer ) g_CurContainer.hideFormErrorMessage(); } } function closefader(whichFader) { let fdr = document.querySelector('#' + whichFader); hideFader(fdr) if ( g_CurContainer ) g_CurContainer.hideFormErrorMessage(); } function closesolid(whichSolid) { let sld = document.querySelector('#' + whichSolid); sld.style.visibility = "hidden" sld.style.display = "none"; } // ---- ---- ---- ---- ---- ---- function unpin_current() { if ( g_CurContainer ) { g_CurContainer.switchCaptchaDisplay(false) g_CurContainer.hideFormErrorMessage(); } if ( g_current_pin != null ) { g_current_pin.style.visibility = "hidden"; g_current_pin.style.zIndex = -10 } } function fade_apparition(btn,evt) { if ( g_apparition !== null ) { var fader = g_apparition; //if ( evt ) console.log(fader.offsetWidth + "," + evt.clientX + "," + window.innerWidth) if ( ( evt !== undefined )&& (fader.offsetWidth >= evt.clientX) ) { return; } stopDefade() g_defade_scheduled = setInterval(() => { lowerAlpha(fader); },50); } } function stopDefade() { if ( g_defade_scheduled != null ) { clearInterval(g_defade_scheduled); } } function stopFade() { if ( g_fade_scheduled != null ) { clearInterval(g_fade_scheduled); } } function pin_ItsAlive(pinned) { g_apparition = null; } // ---- ---- ---- ---- ---- ---- function raiseAlpha(aGhost) { if ( aGhost.style.opacity == 1.0 ) { stopDefade() pinBoxElem(aGhost) } else { aGhost.style.opacity = parseFloat(aGhost.style.opacity) + 0.025; } } function lowerAlpha(aGhost) { if ( aGhost.style.opacity <= 0.2 ) { hideFader(aGhost) } else { aGhost.style.opacity = parseFloat(aGhost.style.opacity) - 0.1; } } // ---- ---- ---- ---- ---- ---- function replaceApparition(newGhost) { unpin_current() if ( g_apparition !== null ) { stopDefade() stopFade() g_apparition.style.visibility = "hidden"; newGhost.style.zIndex = -10 } if ( newGhost !== null ) { newGhost.style.opacity = "0.0" newGhost.style.visibility = "visible" newGhost.style.zIndex = 200 g_apparition = newGhost g_defade_scheduled = setInterval(() => { raiseAlpha(newGhost); },50); } } // ---- ---- ---- ---- ---- ---- function pinBoxElem(thisPin) { if ( g_current_pin !== thisPin ) unpin_current(); g_current_pin = thisPin; stopDefade() thisPin.style.opacity = "1.0" pin_ItsAlive(g_current_pin); } function pinBox(selector) { let thisPin = document.querySelector(selector); pinBoxElem(thisPin) } // ---- ---- ---- ---- ---- ---- function defadeBox(selector) { replaceApparition(document.querySelector(selector)); } function resize() { centerBox = document.querySelector('#desktopCenter'); rightBox = document.querySelector('#desktopRight'); lowerFiller = document.querySelector('#lowerFiller'); menuHandler(null) if ( window.innerWidth >= 1100 ) { if ( centerBox ) { centerBox.innerHTML = centerBoxText( (window.innerWidth <= 1040) ); centerBox.style.visibility = "visible"; centerBox.style.display = "block"; } rightBox.innerHTML = rightBoxText(); squashMenu.style.visibility = "hidden"; squashMenuContainer.style.visibility = "hidden"; rightBox.style.visibility = "visible"; rightBox.style.display = "block"; if ( g_LoggedIn ) { logoutCtrl.style.visibility = "visible"; logoutCtrl.style.display = "block"; } else { logoutCtrl.style.visibility = "hidden"; logoutCtrl.style.display = "none"; } let logoutCtrlInDropdown = document.getElementById('logout-control-dropdown') if ( logoutCtrlInDropdown ) { logoutCtrlInDropdown.style.visibility = "hidden"; logoutCtrlInDropdown.style.display = "none"; } } else { if ( centerBox ) { centerBox.textContent = ""; centerBox.style.visibility = "hidden"; centerBox.style.display = "none"; } rightBox.textContent = ""; rightBox.style.visibility = "hidden"; rightBox.style.display = "none"; squashMenu.style.visibility = "visible"; // logoutCtrl.style.visibility = "hidden"; logoutCtrl.style.display = "none"; if ( g_LoggedIn ) { let logoutCtrlInDropdown = document.getElementById('logout-control-dropdown') if ( logoutCtrlInDropdown ) { logoutCtrlInDropdown.style.visibility = "visible"; logoutCtrlInDropdown.style.display = "block"; } } else { let logoutCtrlInDropdown = document.getElementById('logout-control-dropdown') if ( logoutCtrlInDropdown ) { logoutCtrlInDropdown.style.visibility = "hidden"; logoutCtrlInDropdown.style.display = "none"; } } } if ( window.innerWidth >= 1100 ) { lowerFiller.innerHTML = lowerFillerText(); } else { lowerFiller.textContent = ""; } } // === --------------------------------------- === --------------------------------------- === --------------------------------------- // CAPTCHA // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- var g_currenCaptchaTOKEN = null; // delivered by the authorization handler, which maps this interaction to a session. var g_captaFinalResolution = null; // will be a function for completing a captcha async function captchaCheck(callBack) { // let captchaGuessField = g_CurContainer.captch_input if ( captchaGuessField ) { let captchaVal = captchaGuessField.value; if ( captchaVal && captchaVal.length && g_currenCaptchaTOKEN ) { // let port = g_CurContainer.auth_port port = !(port) ? '' : ( port.length ? `:${port}` : '') // try { let url = `${location.protocol}//${g_siteURL}${port}/{{auth_path}}/secondary/transition` let data = { 'captcha_val' : captchaVal, 'token' : g_currenCaptchaTOKEN } let resp = await postData(url, data) if ( resp.OK === "true" ) { if ( g_captaFinalResolution !== null ) { g_captaFinalResolution(1) } } else { if ( g_captaFinalResolution !== null ) { g_captaFinalResolution(2,"captcha does not match: try again") } } } catch (e) { console.log(e.message) } } } // } function captchaPromises() { return new Promise((resolve,reject) => { g_captaFinalResolution = (a,b) => { // if ( a === 1 ) { resolve(true); } else if ( a == 2 ) { resolve(b) } else if ( a == 3 ) { reject(-1) } } }) } async function doCaptcha(port,proxyPath) { // if (g_CurContainer ) g_CurContainer.switchCaptchaDisplay(true) else { throw new Error("Current container undefined in doCaptcha") } // try { port = !(port) ? '' : ( port.length ? `:${port}` : '') // let endpoint = `${location.protocol}//${g_siteURL}${port}/${proxyPath}/transition/captcha` let captchaObject = await postData(endpoint) if ( (captchaObject.type == "transition") && (captchaObject.OK == 'true') ) { let svgText = decodeURIComponent(captchaObject.elements.captcha) let captchaPlacement = g_CurContainer.where_captcha if ( captchaPlacement ) { captchaPlacement.innerHTML = svgText g_currenCaptchaTOKEN = captchaObject.transition.token } // return await captchaPromises(); // wait for user interaction to finish else } else { g_CurContainer.formErrorMessage("captcha service not available") } } catch (e) { console.log(e.message) // page level error may be needed } } // === --------------------------------------- === --------------------------------------- === --------------------------------------- // APPLICATIONS // -- -- -- -- -- -- -- -- -- -- -- -- -- // CONTACT APPLICATION var g_contact_Handling = null function initContact() { g_contact_Handling = new ValidationContainer({ "auth_port" : g_contact_port, "service_url" : `${location.protocol}//${g_siteURL}/{{auth_path}}/transition/contact`, "errors_here" : document.getElementById('contact-errors_here'), "failure_msg_prefix" : "Cannot Process Captcha", "fields" : { "name" : document.querySelector('#contact-name'), "email" : document.querySelector('#contact-email'), "website" : document.querySelector('#contact-website'), "comment" : document.querySelector('#contact-comment') }, "checks" : { "is_empty" : ["name","comment","email"], // ref into fields above... "email" : ["email"] }, "modal" : document.querySelector('#contactModal'), "closer" : document.querySelector('#contactModalCloser'), "form" : document.querySelector('#myContactForm'), "captcha" : document.querySelector('#captcha-goes-here'), "captcha_field" : document.querySelector("#captcha-field") }) g_CurContainer = g_contact_Handling; // has to be initlialized in the function } function contact_calcAppDataDB() { // let c_name = g_contact_Handling.fields["name"] let c_email = g_contact_Handling.fields["email"] let c_website = g_contact_Handling.fields["website"] let c_comment = g_contact_Handling.fields["comment"] // let data = { "name" : getVal(c_name), "website" : getVal(c_website), "email" : getVal(c_email), "comment" : getVal(c_comment), 'token' : g_currenCaptchaTOKEN } // return(data) } function contact_completionaAction() { unpin_current(); show_thankyou_box("Thank you for your message"); } function processContact() { processUI_captchaService( contact_calcAppDataDB, contact_calcAppDataDB, contact_completionaAction ) } function onkey_checkContactError(srcField) { if ( g_contact_Handling.checkFormValid() ) { let focusFld = '#' + srcField; let focusEl = document.querySelector(focusFld); focusEl.style.borderColor = 'black' g_contact_Handling.hideFormErrorMessage() } } g_finalizers.push(initContact) // --------- LOGIN // REGISTER // links on this page... var g_login_Handling = null function login_process() { let login = document.querySelector("#login") if ( login ) { login.style.visibility = "visible" login.style.display = "block"; // unpin_current(); g_CurContainer = g_login_Handling // //hide other things let register = document.querySelector("#register") if ( register ) { register.style.visibility = "hidden" register.style.display = "none"; } } login_opening_view() // app implements } // var g_register_Handling = null function join_process() { let register = document.querySelector("#register") if ( register ) { register.style.visibility = "visible" register.style.display = "block"; // unpin_current(); g_CurContainer = g_register_Handling g_ComponentErrorsActivated = true // //hide other things let login = document.querySelector("#login") if ( login ) { login.style.visibility = "hidden" login.style.display = "none"; } } register_opening_view() } function hide_join_process() { if ( g_register_Handling ) { g_register_Handling.switchCaptchaDisplay(false) } let register = document.querySelector("#register") if ( register ) { register.style.visibility = "hidden" register.style.display = "none"; } } function hide_login_process() { if ( g_login_Handling ) { g_login_Handling.switchCaptchaDisplay(false) } //hide other things let login = document.querySelector("#login") if ( login ) { login.style.visibility = "hidden" login.style.display = "none"; } } var g_login_failure = null function retry_password() { login_process() if ( g_login_failure ) g_login_failure() } var g_registration_failure = null function already_registered() { login_process() if ( g_registration_failure ) g_registration_failure() } // === --------------------------------------- === --------------------------------------- === --------------------------------------- async function logout(or