copious-transitions
Version:
Framework for working with frameworks
1,841 lines (1,632 loc) • 52.2 kB
HTML
<!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" > </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 © {{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">×</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