{"id":3273,"date":"2024-01-20T12:43:29","date_gmt":"2024-01-20T20:43:29","guid":{"rendered":"https:\/\/loopcntr.net\/opn-alpha\/?page_id=3273"},"modified":"2024-02-22T17:44:45","modified_gmt":"2024-02-23T01:44:45","slug":"contact-us","status":"publish","type":"page","link":"https:\/\/loopcntr.net\/opn-alpha\/contact-us\/","title":{"rendered":"Contact"},"content":{"rendered":"\n\n\n<figure class=\"wp-block-pullquote has-medium-font-size\"><blockquote><p><strong>A network is brought into being by the connections among its nodes.<\/strong> <\/p><\/blockquote><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">To contact Open Portal Network, please fill out the form below.<\/p>\n\n\n\n<style type=\"text\/css\">\n\n<\/style>\n\n<style type=\"text\/css\">main .entry-content .usp-pro-form{\r\n    width:100%;\r\n    margin-left:auto;\r\n    margin-right:auto;\r\n}\r\n\/*#_opncfe_how_hear {\r\n    cursor: pointer;\r\n    user-select: none;\r\n}*\/ \/* mjb 1\/29\/2024 *\/\r\n\r\n.how-hear-wrapper {\r\n    position: relative;\r\n}\r\n.how-hear-wrapper .usp-fieldset::before {\r\n    content: '';  \/* Uses box of no size but with borders to make the triangle *\/\r\n    position: absolute;\r\n    right: 1rem;\r\n    font-size: 2rem;\r\n    border: 8px solid;\r\n    box-sizing: content-box;\r\n    font-size: 0;\r\n}\r\n.how-hear-wrapper .how-hear-closed.usp-fieldset::before {\r\n    bottom: .35rem;\r\n    border-top-color: #333;\r\n    border-right-color: transparent;\r\n    border-left-color: transparent;\r\n    border-bottom-color: transparent;\r\n}\r\n.how-hear-wrapper .how-hear-opened.usp-fieldset::before {\r\n    bottom: -1.1rem;\r\n    border-top-color: transparent;\r\n    border-right-color: transparent;\r\n    border-left-color: transparent;\r\n    border-bottom-color: #333;\r\n    z-index:115;\r\n}\r\n\r\n.usp-pro-form .usp-pro .usp-fieldset, .usp-pro .how-hear-wrapper fieldset {\r\n    margin-bottom:0;\r\n}\r\n.how-hear-options-wrapper {\r\n    position:relative;\r\n    margin:-1.5rem 0 0;\r\n    padding: 0;\r\n    display: none;\r\n    width:100%;\r\n    max-width:30rem;\r\nborder:1px solid yellow;\r\n}\r\n.how-hear-options-wrapper button {\r\n    position:absolute;\r\n    top:0;\r\n    right:0;\r\n    padding:5px;\r\n    background-color:#fdfefd;\r\n    z-index:100;\r\n    border-radius:10px;\r\n}\r\n.options {\r\n    position:absolute;\r\n    top:9px;\r\n    list-style-type: none;\r\n    padding: 0;\r\n    width:100%;\r\n    height:fit-content;\r\n    border:1px solid lightgray; \r\n    background-color:#fdfefd;\r\n    -webkit-box-shadow: 5px 5px 5px 5px #000000; \r\n    box-shadow: 5px 5px 15px 5px #000000;\r\n}\r\n\r\n.options li {\r\n    padding: 5px 0.5rem;\r\n    border-bottom: 1px solid #eee;\r\n}\r\n\r\n.options li.tentative {\r\n    background-color: #A6FA6D;\r\n    border:dashed 2px #333;\r\n}\r\n.options li.selected {\r\n    background-color: #380;\r\n    color:white;\r\n    border:solid 2px white;\r\n    outline:solid 2px #4d4dff;\r\n}\r\n.options li:hover {\r\n    background-color: #A6FA6D;\r\n    color:black;\r\n}\r\n.usp-pro-form .usp-pro .usp-fieldset.how-hear-other-detail {\r\n    display:none;\r\n    margin-top:0;\r\n    padding-top:0;\r\n    margin-left: 1%;\r\n    gap: 0 0.5rem;\r\n    align-items: baseline;\r\n}\r\n.usp-pro-form .usp-pro .usp-fieldset.how-hear-other-detail.detail-visible {\r\n    display: flex;\r\n    justify-content: center;\r\n}\r\n.usp-pro-form .usp-pro .usp-fieldset.how-hear-other-detail label{\r\n    min-width:7em;\r\n    text-align:right;\r\n}\r\n.usp-pro-form .usp-pro .usp-fieldset.how-hear-other-detail input{\r\n    \/* max-width:28rem; *\/\r\n    margin-right:1%;\r\n}\r\n#noMatchMessage{\r\n    display: none;\r\n    padding:0;\r\n    margin:0;\r\n    color:black;\r\n    background-color:pink;\r\n    position:relative;\r\n    z-index:105;\r\n}\r\n\r\n@media screen and (max-width:500px){\r\n    .usp-pro-form .usp-pro .usp-fieldset.how-hear-other-detail{\r\n        flex-wrap:wrap;\r\n    }\r\n    .usp-pro-form .usp-pro .usp-fieldset.how-hear-other-detail input{\r\n        margin-left:auto;\r\n        max-width:25em;\r\n    }\r\n    .usp-pro-form .usp-pro .usp-fieldset.how-hear-other-detail label{\r\n        min-width:0;\r\n        text-align:left;\r\n    }\r\n}<\/style>\n<div class=\"usp-pro-form\">\n\n<!-- USP Pro @ https:\/\/plugin-planet.com\/usp-pro\/ -->\n<div id=\"usp-pro\" class=\"usp-pro usp-form-3258\">\n<form id=\"usp-form-3258\" class=\"usp-form\" method=\"post\" enctype=\"multipart\/form-data\" action=\"\" data-parsley-validate data-persist=\"garlic\">\n\n<!-- The CSS and JS specific to THIS form is held in custom fields below the end of this content -->\r\n\r\n<fieldset class=\"usp-fieldset usp-fieldset-default\">\n<label for=\"_opncfe_name\" class=\"usp-label usp-label-input usp-label-custom usp-form-3258\">Name (Required)<\/label>\n<input name=\"_opncfe_name\" id=\"_opncfe_name\" type=\"text\" value=\"\" data-required=\"true\" placeholder=\"Enter your name\" class=\"usp-input usp-input-custom usp-form-3258\" required=\"required\" \/>\n<input type=\"hidden\" name=\"_opncfe_name-required\" value=\"1\" \/>\n<\/fieldset>\n\r\n\r\n<fieldset class=\"usp-fieldset usp-fieldset-default\">\n<label for=\"_opncfe_email_address\" class=\"usp-label usp-label-input usp-label-custom usp-form-3258\">Email (Required)<\/label>\n<input name=\"_opncfe_email_address\" id=\"_opncfe_email_address\" type=\"text\" value=\"\" data-required=\"true\" placeholder=\"Enter your email address\" class=\"usp-input usp-input-custom usp-form-3258\" required=\"required\" \/>\n<input type=\"hidden\" name=\"_opncfe_email_address-required\" value=\"1\" \/>\n<\/fieldset>\n\r\n<input name=\"usp-email\" id=\"usp-email\" type=\"hidden\">\r\n\r\n<fieldset class=\"usp-fieldset usp-fieldset-default\">\n<label for=\"_opncfe_phone_number\" class=\"usp-label usp-label-input usp-label-custom usp-form-3258\">Phone Number (Optional)<\/label>\n<input name=\"_opncfe_phone_number\" id=\"_opncfe_phone_number\" type=\"text\" value=\"\" data-required=\"false\" placeholder=\"Enter your phone number\" class=\"usp-input usp-input-custom usp-form-3258\" \/>\n<\/fieldset>\n\r\n\r\n<div class=\"how-hear-wrapper\">\r\n   <fieldset class=\"usp-fieldset usp-fieldset-default how-hear-closed\">\n<label for=\"_opncfe_how_hear\" class=\"usp-label usp-label-input usp-label-custom usp-form-3258\">How did you hear about us? (Required)<\/label>\n<input name=\"_opncfe_how_hear\" id=\"_opncfe_how_hear\" type=\"text\" value=\"\" data-required=\"true\" placeholder=\"Select.. (Click or down arrow to open)\" class=\"usp-input usp-input-custom usp-form-3258\" required=\"required\" \/>\n<input type=\"hidden\" name=\"_opncfe_how_hear-required\" value=\"1\" \/>\n<\/fieldset>\n\r\n\r\n    <p id=\"noMatchMessage\">Not a match. Please choose one of the available options:<\/p>\r\n    <div class=\"how-hear-options-wrapper\">\r\n      <ul class=\"options\" role=\"listbox\">\r\n          <li role=\"option\" class=\"cbo-option\">Search Engine<\/li>\r\n          <li role=\"option\" class=\"cbo-option\">Social Media<\/li>\r\n          <li role=\"option\" class=\"cbo-option\">TV<\/li>\r\n          <li role=\"option\" class=\"cbo-option\">Radio<\/li>\r\n          <li role=\"option\" class=\"cbo-option\">Friend or Family<\/li>\r\n          <li role=\"option\" class=\"cbo-option include-how-hear-detail\" data-detail-label=\"Which website?\">Website<\/li>\r\n          <li role=\"option\" class=\"cbo-option include-how-hear-detail\" data-detail-label=\"Please explain:\">Other<\/li>\r\n          <!-- Add more options as needed -->\r\n      <\/ul>\r\n    <\/div>\r\n<\/div>\r\n    <fieldset class=\"usp-fieldset usp-fieldset-default how-hear-other-detail\">\n<label for=\"_opncfe_how_hear_other_detail\" class=\"usp-label usp-label-input usp-label-custom usp-form-3258\">Details:<\/label>\n<input name=\"_opncfe_how_hear_other_detail\" id=\"_opncfe_how_hear_other_detail\" type=\"text\" value=\"\" data-required=\"false\" placeholder=\"Enter details\" class=\"usp-input usp-input-custom usp-form-3258\" \/>\n<\/fieldset>\n\r\n\r\n\r\n<fieldset class=\"usp-fieldset usp-fieldset-default\">\n<label for=\"usp-title\" class=\"usp-label usp-label-title\">Subject or Other Interest (Required)<\/label>\n<input name=\"usp-title\" id=\"usp-title\" type=\"text\" value=\"\" data-required=\"true\" required=\"required\" maxlength=\"5000\" placeholder=\"Enter your subject here\" class=\"usp-input usp-input-title\" \/>\n<input type=\"hidden\" name=\"usp-title-required\" value=\"1\" \/>\n<\/fieldset>\n\r\n<input name=\"usp-subject\" id=\"usp-subject\" type=\"hidden\">\r\n\r\n<fieldset class=\"usp-fieldset usp-fieldset-default\">\n<label for=\"usp-content\" class=\"usp-label usp-label-content\">Other Details (Required)<\/label>\n<textarea name=\"usp-content\" id=\"usp-content\" rows=\"5\" cols=\"30\" maxlength=\"5000\" data-required=\"true\" required=\"required\" placeholder=\"Enter your message here\" class=\"usp-input usp-textarea usp-input-content\"><\/textarea>\n<input type=\"hidden\" name=\"usp-content-required\" value=\"1\" \/>\n<\/fieldset>\n\r\n\r\n<fieldset class=\"usp-fieldset usp-fieldset-default\">\n<input type=\"submit\" class=\"usp-submit contact-form-submit\" value=\"Send Message\" \/>\n<\/fieldset>\n\r\n\r\n<input type=\"hidden\" name=\"usp-alert-submit-message\" value=\"QDbAPyqyVTuuqzHtpzIwMJy2MJDtrJ91pvOgMKAmLJqyVTS0VPHyLzkiM19hLJ1yWFHtXPHyLzkiM191pzjyWFxhQDbAPyqyVUqcoTjtM2I0VTWuL2ftqT8trJ91VUqcqTucovO0q28tLaImnJ5yp3ZtMTS5pl4APy9sK19sK19sK19sK19sK19sK19sK19sK19sK19sK19sK19sK19sK19sK19sK19sK19sK19sK19sK19sK19sK19sK19sK19sK19sK18APt0XJJ91pvOgMKAmLJqyVTAioaEunJ5yMPO0nTHtMz9foT93nJ5aBt0XQDcMo3IlVT5uoJH6VPNtVPNtVPNtVPNtVPNtVPNyWI9sK29jozAzMI9hLJ1yWFHAPyyiqKVtMJ1unJj6VPNtVPNtVPNtVPNtVPNtVPHyqKAypy9yoJScoPHyQDcMo3IlVUObo25yVT51oJWypwbtVPNtVPNtVPNyWI9sK29jozAzMI9jnT9hMI9hqJ1vMKVyWD0XFT93VTEcMPO5o3HtnTIupvOuLz91qPO1pm8tWFIsK19ipT5wMzIsnT93K2uyLKVyWFNyWI9sK29jozAzMI9bo3qsnTIupy9iqTuypy9xMKEunJjyWD0XH3IvnzIwqPOipvOCqTuypvOWoaEypzImqQbtWFIjo3A0K3EcqTkyWFHAPt0XGJImp2SaMGbAPvNtVPHypT9mqS9wo250MJ50WFHAPt0X\"><input type=\"hidden\" name=\"usp-alert-submit-subject\" value=\"I2HtHzIwMJy2MJDtJJ91pvOAMKAmLJqyBvNyWKOip3EsqTy0oTHyWD==\">\r\n\r\n<input type=\"hidden\" name=\"usp-alert-submit-message-admin\" value=\"QDcAMKAmLJqyBvNtVPNtVPNtVPNtVPNtWFIjo3A0K2AioaEyoaDyWD0XQDcTpz9gBvNtVPNtVPNtVPNtVPNtVPNtWFIsK19ipT5wMzIsozSgMFHyQDcSoJScoQbtVPNtVPNtVPNtVPNtVPNtWFI1p2IlK2IgLJyfWFHAPyObo25yVT51oJWypwbtVPNtVPNtVPNyWI9sK29jozAzMI9jnT9hMI9hqJ1vMKVyWD0XFT93VTEcMPO5o3HtnTIupvOuLz91qPO1pm8tWFIsK19ipT5wMzIsnT93K2uyLKVyWFNyWI9sK29jozAzMI9bo3qsnTIupy9iqTuypy9xMKEunJjyWD0XH3IvnzIwqPOipvOCqTuypvOWoaEypzImqQbtWFIjo3A0K3EcqTkyWFHAPt0X\"><input type=\"hidden\" name=\"usp-alert-submit-subject-admin\" value=\"GzI3VR1yp3AuM2H6VPHypT9mqS90nKEfMFHy\"><input type=\"hidden\" name=\"usp-alert-submit-cc-admin\" value=\"MJEcqT9lDUA0LKWxqKA0MTShL2IlYzAioFkgnKAmrzSjDUAjLKWeLJ1cozDhL29gYTkcrzSfo29jDTkio3OwMJ50MKVho3Wa\">\r\n\r\n<fieldset class=\"usp-fieldset usp-fieldset-default\" hidden>\r\n<input name=\"usp-remember\" id=\"usp-remember\" type=\"checkbox\" data-required=\"true\" class=\"usp-remember usp-input usp-input-remember mjb-remember-form-data\" value=\"1\" checked=\"\" data-parsley-multiple=\"usp-remember\"> <label for=\"usp-remember\" class=\"usp-label usp-label-remember\"><strong>Remember form data in case of errors<\/strong><\/label>\r\n<\/fieldset>\r\n\r\n<input type=\"hidden\" name=\"usp-is-post-submit\" value=\"opn-contact-entries\" \/>\r\n<input name=\"usp-custom-type\" value=\"opn-contact-entries\" type=\"hidden\" \/>\r\n<input name=\"usp-is-contact\" value=\"1\" type=\"hidden\" \/>\r\n\n<div class=\"usp-hidden\">\n<input type=\"hidden\" name=\"PHPSESSID\" value=\"bbc530b0bc2911cc07b441a6e1cecb17\" \/>\n<input type=\"text\" name=\"usp-verify\" id=\"verify\" value=\"\" style=\"display:none;\" class=\"exclude\" \/>\n<input type=\"hidden\" id=\"usp_form_submit\" name=\"usp_form_submit\" value=\"9f693401d3\" \/>\n<input type=\"hidden\" name=\"usp-form-id\" value=\"3258\" \/>\n<\/div>\n\n<\/form>\n<\/div>\n\n<\/div>\n<script type=\"text\/javascript\">\njQuery(document).ready(function ($) {\r\n    \/** \r\n     * Function: wrapWordsInStrong\r\n     * Description: Make bold the characters in any label to the left of a left parenthesis, period or \r\n     * colon (except for the \"Terms\" label). This allows for longer instructions as part of the label \r\n     * with the most relevant label name put in bold. \r\n     * NOTE: If we do not want this on ALL forms, copy \r\n     * this code onto the individual forms we want it on, between script tags.\r\n     *\/\r\n    function wrapWordsInStrong() {\r\n        \/\/ Get all labels within the form.\r\n        const allLabels = $(\"#usp-pro label\");\r\n\r\n        \/\/ Convert NodeList to an array and exclude labels inside the .usp-opn-terms-fieldset class.\r\n        const labels = $(allLabels).filter(function () {\r\n        return !$(this).closest(\".usp-opn-terms-fieldset\").length;\r\n        });\r\n\r\n        labels.each(function () {\r\n        \/\/ Use a regular expression to find words before a word in parentheses, a comma or colon or, if none \r\n        \/\/ of those are found, then the entire label.\r\n        const regexMatch = \/^(.*?)(?=[:.(]|$)\/;\r\n\r\n        \/\/ Replace found words with the same words wrapped in <strong> tags\r\n        let newContent = $(this)\r\n            .html()\r\n            .replace(regexMatch, function (match) {\r\n            return \"<strong>\" + match + \"<\/strong>\";\r\n            });\r\n\r\n        \/\/ Update the label's content\r\n        $(this).html(newContent);\r\n        });\r\n    }\r\n\r\n    \/**\r\n     * Function: scrollToFormMsg\r\n     * Description: If the URL indicates a USP Pro form error, scroll down to the form error section.\r\n     *\/\r\n    function scrollToFormMsg() {\r\n        \/\/ Get the current URL\r\n        var currentURL = window.location.href;\r\n        if ( (currentURL.indexOf(\"usp_error_\") !== -1) || (currentURL.indexOf(\"usp_success\") !== -1) ){\r\n        $(\"html, body\").animate(\r\n            {\r\n            scrollTop: $(\"#usp-pro\").offset().top - 150,\r\n            },\r\n            1000\r\n        ); \/\/ 1000ms animation time\r\n        }\r\n    }\r\n    \/\/ Initially invoke the functions above to start the process after waiting a bit to be sure the elements are showing\r\n      setTimeout(function () {\r\n        wrapWordsInStrong();\r\n        scrollToFormMsg();\r\n      }, 250);\r\n\r\n    $(\"input#reset-all-including-cookie\").on(\"click\", function (e) {\r\n        \/\/ Ask user to confirm the reset\r\n        if (!(confirm(\"Please confirm: All form fields will be reset to blank except for your username and email. Continue?\") === true)) {\r\n            return;\r\n        } \r\n        \/\/ Check if the cookie \"remember\" exists (Cookie created by USP Pro)\r\n        if ($.cookie(\"remember\")) {\r\n            \/\/ Prevent default reset behavior\r\n            e.preventDefault();\r\n\r\n            \/\/ Delete the cookie so data won't persist into the next page load\r\n            $.cookie(\"remember\", \"\", { expires: -1, path: \"\/wpplay\/add-your-network-node\" });\r\n\r\n            \/\/ Get the current URL without the query string\r\n            const cleanURL = window.location.protocol + \"\/\/\" + window.location.host + window.location.pathname;\r\n\r\n            \/\/ Reload the page without the query string and append ?reset=true\r\n            window.location.href = cleanURL + \"?reset=true\";\r\n        }\r\n\r\n        \/\/ If the cookie doesn't exist, the default reset behavior will take place\r\n    });\r\n\r\n    \/\/ Check if the URL has ?reset=true\r\n    if (window.location.search.includes(\"reset=true\")) {\r\n        \/\/ Scroll to the form\r\n        $(\"html, body\").animate({\r\n            scrollTop: $(\"#usp-pro\").offset().top - 120,\r\n        }, 1000); \/\/ 1000ms animation time\r\n    }\r\n});\n<\/script>\n\n<script type=\"text\/javascript\">\"use strict\";\r\njQuery(function ($) {\r\n  $(document).ready(function () {\r\n    \/\/ let myI = 0; \/\/ for testing\r\n\r\n    const howHearFieldset = $(\".how-hear-wrapper .usp-fieldset\");\r\n    const optionsWrapper = $(\".how-hear-options-wrapper\");\r\n    const options = $(\".options\");\r\n    var items = options.find(\"li\");\r\n    \/\/ let currentIndex = -1;\r\n\r\n    const howHearInput = $(\"#_opncfe_how_hear\"); \/\/ input field holding value of selection\r\n    howHearInput.attr(\"aria-expanded\", \"false\"); \/\/ initialize aria-expanded for input field (Can we do this in the USP Pro field?)\r\n    howHearInput.attr(\"role\", \"combobox\"); \/\/ add aria \"combobox\" role (Can we do this in the USP Pro field?)\r\n    \/\/ const howHearDetail = $(\".usp-pro-form .usp-pro .usp-fieldset.how-hear-other-detail\");\r\n    const howHearDetail = $(\".how-hear-other-detail\");\r\n    let toggledOpen = false;\r\n    let hasMatch = true; \/\/ used in filtering the list when user starts typing in input field\r\n    let tentativeMatch = \"\";\r\n    var detailForMatch = {};\r\n\r\n    \/**\r\n     * Function: toggleAndSetFlags\r\n     * Description: Set flags and CSS classes and show or hide the options box and the error message box.\r\n     * @param {*} toggleItOpen\r\n     * @param {*} matched\r\n     *\/\r\n    function toggleAndSetFlags(toggleItOpen = true, matched = true) {\r\n      console.log(\r\n        \"In toggleAndSetFlags with toggleItOpen = \",\r\n        toggleItOpen,\r\n        \" and matched = \",\r\n        matched\r\n      );\r\n      const selected = options.find(\".selected\");\r\n      if (toggleItOpen) {\r\n        optionsWrapper.show();\r\n        howHearFieldset.removeClass(\"how-hear-closed\"); \/\/ Remove \"down\" triangle\r\n        howHearFieldset.addClass(\"how-hear-opened\"); \/\/ Add \"up\" triangle\r\n      } else {\r\n        \/\/ Close combobox\r\n        optionsWrapper.hide();\r\n        howHearFieldset.removeClass(\"how-hear-opened\"); \/\/ Remove \"up\" triangle\r\n        howHearFieldset.addClass(\"how-hear-closed\"); \/\/ Add \"down\" triangle\r\n      }\r\n      toggledOpen = toggleItOpen;\r\n      howHearInput.attr(\"aria-expanded\", toggleItOpen);\r\n\r\n      if (howHearInput.val().length == null) {\r\n        matched = true; \/\/ Input has been cleared, so matched\r\n        selected.removeClass(\"selected\");\r\n        options.find(\".tentative\").removeClass(\"tentative\");\r\n      }\r\n\r\n      if (matched || !toggledOpen) {\r\n        \/\/ mjb 2\/23\/2024\r\n        $(\"#noMatchMessage\").css(\"display\", \"none\");\r\n        hasMatch = true; \/\/ mjb 2\/23\/2024\r\n      } else {\r\n        if (toggledOpen) {\r\n          $(\"#noMatchMessage\").css(\"display\", \"block\");\r\n          selected.removeClass(\"selected\");\r\n          options.find(\".tentative\").removeClass(\"tentative\");\r\n          tentativeMatch = \"\";\r\n        }\r\n      }\r\n    }\r\n\r\n    \/**\r\n     * Function: moveSelection\r\n     * Description: Move highlighting to currently selected item. Remove highlighting\r\n     * from any previously or tentatively selected item.\r\n     *\/\r\n    function moveSelection(goDown = true) {\r\n      var selected = options.find(\".selected\");\r\n      var firstOption = options.children().first();\r\n      var lastOption = options.children().last();\r\n      items.removeClass(\"tentative\"); \/\/ Don't want \"tentative\" when have \"selected\"\r\n      if (selected.length === 0) {\r\n        firstOption.addClass(\"selected\");\r\n      } else if (goDown) {\r\n        var next = selected.next();\r\n        if (next.length) {\r\n          selected.removeClass(\"selected\");\r\n          next.addClass(\"selected\");\r\n        } else {\r\n          \/\/ If there's no next, cycle back to the first\r\n          selected.removeClass(\"selected\");\r\n          firstOption.addClass(\"selected\");\r\n        }\r\n      } else {\r\n        \/\/ go up\r\n        var prev = selected.prev();\r\n        if (prev.length) {\r\n          selected.removeClass(\"selected\");\r\n          prev.addClass(\"selected\");\r\n        } else {\r\n          \/\/ If there's no previous, cycle to the last\r\n          selected.removeClass(\"selected\");\r\n          lastOption.addClass(\"selected\");\r\n        }\r\n      }\r\n    }\r\n\r\n    \/**\r\n     * Function: inputNeedsChecking\r\n     * Description: Based on the typed character, tell if the combobox's input field needs checking.\r\n     * @param {*} typedChar\r\n     * @returns\r\n     *\/\r\n    function inputNeedsChecking(typedChar = \"\") {\r\n      switch (typedChar) {\r\n        case \"Backspace\":\r\n        case \"Delete\":\r\n          return true;\r\n      }\r\n      if (!(typedChar.length == 1)) return false; \/\/ Anything else that isn't a single character\r\n      var alphanumericRegex = \/[a-zA-Z0-9 ]\/; \/\/ Note this includes a space character.\r\n      if (alphanumericRegex.test(typedChar)) return true;\r\n      return false;\r\n    }\r\n\r\n    \/**\r\n     * Function: findMatch\r\n     * Description: Determine if the string typed into the combobox's input matches\r\n     * or partially matches one or more of the options in the options box.\r\n     * @returns\r\n     *\/\r\n    function findMatch() {\r\n      items.removeClass(\"tentative\"); \/\/ Remove any previous highlighting\r\n      let foundMatch = false;\r\n      items.filter(function () {\r\n        var match = $(this)\r\n          .text()\r\n          .toLowerCase()\r\n          .startsWith(howHearInput.val().trim().toLowerCase());\r\n        if (match) {\r\n          \/\/ If this is the first match, change the background color of the first matching item. We know it's the first match if `match` is true but we haven't changed `foundMatch` to true yet.\r\n          if (!foundMatch) {\r\n            if (!$(this).hasClass(\"selected\")) {\r\n              $(this).addClass(\"tentative\"); \/\/ Highlight the first filtered choice\r\n              \/* Remove the \"selected\" class any that have it because if one item is \"tentative\" then nothing should be \"selected\" *\/\r\n              items.removeClass(\"selected\");\r\n            }\r\n            tentativeMatch = $(this).text();\r\n            detailForMatch[\"show_detail_box\"] = $(this).hasClass(\r\n              \"include-how-hear-detail\"\r\n            );\r\n            detailForMatch[\"detail_label\"] = $(this).data(\"detail-label\");\r\n          }\r\n          foundMatch = true;\r\n        }\r\n        $(this).toggle(match);\r\n      });\r\n      return foundMatch;\r\n    }\r\n\r\n    \/\/ Detect mousedown on combobox surrounding fieldset so include the drop-down triangle\r\n    howHearFieldset.on(\"mousedown\", function () {\r\n      items = options.find(\"li\"); \/* mjb 2\/1\/24 1332 *\/\r\n      items.show(); \/* mjb 2\/1\/24 1332 *\/\r\n      toggleAndSetFlags(!toggledOpen, hasMatch);\r\n    });\r\n\r\n    \/\/* Keyboard navigation and selection\r\n    \/\/* Keydown event used when you have to stop default behavior and do something else.\r\n    howHearInput.on(\"keydown\", function (e) {\r\n      var selected = options.find(\".selected\");\r\n      switch (e.key) {\r\n        case \"Enter\":\r\n        case \"F4\":\r\n          e.stopPropagation(); \/\/ Stops LastPass password manager from throwing an error in the console.\r\n          e.preventDefault();\r\n          items.show(); \/\/ Show all items, not just the filtered ones. (Filter got removed elsewhere.)\r\n          toggleAndSetFlags(!toggledOpen, hasMatch);\r\n          break;\r\n\r\n        case \"Tab\":\r\n          if (toggledOpen) {\r\n            \/\/ We are leaving the field so close the options if open.\r\n            toggleAndSetFlags(false, hasMatch);\r\n          }\r\n      }\r\n    });\r\n\r\n    \/\/ Keyup event used when you need to know how you got there.\r\n    howHearInput.on(\"keyup\", function (e) {\r\n      var selected = options.find(\".selected\");\r\n      items = options.find(\"li:visible\"); \/\/ Filtered items only\r\n      let itemCount = items.length;\r\n      var inputValue = $(this).val().toLowerCase(); \/\/ What the user typed in the combobox.\r\n\r\n      switch (e.key) {\r\n        case \"Tab\":\r\n          items = options.find(\"li\"); \/\/ All items rather than filtered so always opened and show all.\r\n          items.show();\r\n          toggleAndSetFlags(true, true);\r\n          if (selected.length) {\r\n            howHearInput.val(selected.text()); \/\/ Is this redundant?\r\n            detailForMatch[\"show_detail_box\"] = selected.hasClass(\r\n              \"include-how-hear-detail\"\r\n            );\r\n            detailForMatch[\"detail_label\"] = selected.data(\"detail-label\");\r\n          }\r\n          break;\r\n\r\n        case \"ArrowDown\":\r\n          e.preventDefault();\r\n\r\n          if (!toggledOpen) {\r\n            \/\/ Open combobox if it isn't already\r\n            toggleAndSetFlags(true, hasMatch);\r\n            break;\r\n          }\r\n          moveSelection(true);\r\n          \/\/ Copy each new selection to the input box\r\n          howHearInput.val($(\".selected\").text());\r\n          \/\/ Arrow key causes direct selection so we need to reset tentativeMatch here.\r\n          tentativeMatch = \"\";\r\n\r\n          \/\/ Show box for user to enter details if chose \"Other\" or \"Website\" (based on a class and data found in the HTML itself)\r\n          detailForMatch[\"show_detail_box\"] = $(\".selected\").hasClass(\r\n            \"include-how-hear-detail\"\r\n          );\r\n          detailForMatch[\"detail_label\"] = $(\".selected\").data(\"detail-label\");\r\n          break;\r\n\r\n        case \"ArrowUp\":\r\n          e.preventDefault();\r\n\r\n          if (!toggledOpen) {\r\n            toggleAndSetFlags(true, hasMatch);\r\n            break;\r\n          }\r\n          moveSelection(false);\r\n          \/\/ Copy each new selection to the input box\r\n          howHearInput.val($(\".selected\").text());\r\n          \/\/ Arrow key causes direct selection so we need to reset tentativeMatch here.\r\n          tentativeMatch = \"\";\r\n          detailForMatch[\"show_detail_box\"] = $(\".selected\").hasClass(\r\n            \"include-how-hear-detail\"\r\n          );\r\n          detailForMatch[\"detail_label\"] = $(\".selected\").data(\"detail-label\");\r\n          break;\r\n\r\n        case \"Escape\": \/\/ Escape key\r\n          toggleAndSetFlags(false, hasMatch);\r\n          tentativeMatch = \"\";\r\n          detailForMatch[\"show_detail_box\"] = false;\r\n          detailForMatch[\"detail_label\"] = \"\";\r\n          break;\r\n\r\n        case \"Enter\":\r\n        case \"F4\": \/\/ Same as \"Enter\"\r\n          \/*\r\n           * We catch Enter and F4 on keydown event also so some code is there.\r\n           * Here we show\/hide detail for \"Other\" and \"Website\".\r\n           * If we are closing the combobox and there is a partial string match in input,\r\n           * we also put the entire matched string into input. *\/\r\n          if (!toggledOpen) {\r\n            items = options.find(\"li\"); \/\/ Stop filtering items so when you open it again you will see all of them.\r\n          }\r\n          \/*\r\n           * Check for partial string match.\r\n           *\/\r\n          if ($(this).val().length) {\r\n            if (!($(this).val() === selected.text())) {\r\n              \/\/ Check if the active element is one of our list items with the class 'option'. If so, use it.\r\n              tentativeMatch.length\r\n                ? howHearInput.val(tentativeMatch)\r\n                : howHearInput.val(\"\");\r\n              \/\/ if (tentativeMatch.length) {\r\n              \/\/     howHearInput.val(tentativeMatch);\r\n              \/\/ } else {\r\n              \/\/     howHearInput.val(\"\");\r\n              \/\/     matched = true; \/\/ mjb 2\/22\/2024 Don't show error message if closing and clearing.\r\n              \/\/ }\r\n              selected.removeClass(\"selected\");\r\n              options\r\n                .find(\".tentative\")\r\n                .addClass(\"selected\")\r\n                .removeClass(\"tentative\");\r\n            } else {\r\n              items = options.find(\"li\"); \/\/ Stop filtering items so when you open it again you will see all of them.\r\n              console.log(\"howHearInput has no length\");\r\n            }\r\n          }\r\n\r\n          if (detailForMatch[\"show_detail_box\"]) {\r\n            \/* Show detail and move focus inside it *\/\r\n            howHearDetail.css(\"display\", \"flex\");\r\n            howHearDetail\r\n              .children(\"label\")\r\n              .text(detailForMatch[\"detail_label\"])\r\n              .focus();\r\n          }\r\n\r\n        case \"Shift\": \/\/ Ignore, as it's the key it's used with that counts (probably Tab).\r\n          break;\r\n\r\n        default: \/\/ Any other key filter list box by what is typed\r\n          if (!inputNeedsChecking(e.key)) break;\r\n\r\n          hasMatch = false;\r\n\r\n          \/\/ If the input field is empty, remove filtering and hide the error message block. Then get out.\r\n          if (!howHearInput.val().trim().length) {\r\n            hasMatch = true;\r\n            $(\"#noMatchMessage\").css(\"display\", \"none\");\r\n            items.removeClass(\"selected\");\r\n            items.removeClass(\"tentative\");\r\n            items = options.find(\"li\"); \/\/ Remove any filtering\r\n            tentativeMatch = \"\";\r\n            detailForMatch[\"show_detail_box\"] = false;\r\n            detailForMatch[\"detail_label\"] = \"\";\r\n            items.show();\r\n            break;\r\n          }\r\n\r\n          \/\/ Check input against available options\r\n          \/*  First  we are checking the FILTERED list of options--but don't do that if removing characters *\/\r\n          if (!(\"Backspace\" === e.key || \"Delete\" === e.key)) {\r\n            hasMatch = findMatch();\r\n          }\r\n          \/* If input still does not match, remove filtering to show all options, check for match again,\r\n             and  if still no match is found, display error message. *\/\r\n          if (!hasMatch) {\r\n            items = options.find(\"li\"); \/\/ Remove any filtering\r\n            items.removeClass(\"selected\"); \/\/ Un-select anything that had previously been selected.\r\n\r\n            hasMatch = findMatch(); \/\/ Look for match again in UNfiltered options\r\n            if (!hasMatch) {\r\n              items.show();\r\n            }\r\n          }\r\n          toggleAndSetFlags(true, hasMatch);\r\n          if (detailForMatch[\"show_detail_box\"]) {\r\n            howHearDetail.css(\"display\", \"flex\");\r\n            howHearDetail\r\n              .children(\"label\")\r\n              .text(detailForMatch[\"detail_label\"])\r\n              .focus();\r\n          }\r\n      }\r\n    });\r\n\r\n    \/\/ Select option on click\r\n    items.on(\"mousedown\", function () {\r\n      var selected = options.find(\".selected\");\r\n      if (selected.length) {\r\n        \/\/ If something was previously selected then...\r\n        selected.removeClass(\"selected\"); \/\/ unselect what should no longer be selected\r\n      }\r\n      items.removeClass(\"tentative\");\r\n      $(this).addClass(\"selected\"); \/\/ select what should be selected because would need if keyboard opens the box again\r\n      hasMatch = true; \/\/ Because you just copied to the box so of course they match.\r\n      howHearInput.val($(this).text()); \/\/ Update the field holding the text value of the selection\r\n      howHearInput.focus();\r\n\r\n      \/\/ Mouse click causes direct selection so we need to reset tentativeMatch here.\r\n      tentativeMatch = \"\";\r\n\r\n      detailForMatch[\"show_detail_box\"] = $(this).hasClass(\r\n        \"include-how-hear-detail\"\r\n      );\r\n      detailForMatch[\"detail_label\"] = $(this).data(\"detail-label\");\r\n\r\n      toggleAndSetFlags(false, hasMatch);\r\n    });\r\n\r\n    \/\/ Close options when combo box loses focus\r\n    howHearInput.on(\"blur\", function () {\r\n      \/\/ If a new value was selected within the list box, use the new value.\r\n      \/\/ Is the code below redundant?\r\n      var activeElement = $(document.activeElement);\r\n      var selected = options.find(\".selected\");\r\n\r\n      if ($(this).val().length) {\r\n        if (!($(this).val() === selected.text())) {\r\n          selected.removeClass(\"selected\"); \/\/ unmatching item should no longer show as selected\r\n\r\n          \/\/ If the combobox is empty and we have a tentative match, use it.\r\n          console.log(\r\n            \"check length of tentativeMatch, which is \",\r\n            tentativeMatch.length\r\n          );\r\n          \/\/   tentativeMatch.length\r\n          \/\/     ? howHearInput.val(tentativeMatch)\r\n          \/\/         : howHearInput.val(\"\");\r\n          if (tentativeMatch.length) {\r\n            howHearInput.val(tentativeMatch);\r\n          } else {\r\n            howHearInput.val(\"\");\r\n            $(\"#noMatchMessage\").css(\"display\", \"none\"); \/\/ mjb 2\/22\/2024\r\n          }\r\n        }\r\n      }\r\n\r\n      if (detailForMatch[\"show_detail_box\"]) {\r\n        howHearDetail.css(\"display\", \"flex\");\r\n        howHearDetail\r\n          .children(\"label\")\r\n          .text(detailForMatch[\"detail_label\"])\r\n          .focus();\r\n      } else {\r\n        \/* No detail to show, so hide the field *\/\r\n        howHearDetail.css(\"display\", \"none\");\r\n      }\r\n\r\n      \/\/ Close combobox whenever you leave it, which blur event implies.\r\n      toggleAndSetFlags(false, hasMatch);\r\n    });\r\n\r\n    \/\/ Copy value of visible email address to hidden usp-email field so USP Pro will correctly mail the sender a receipt\r\n    $(\"#_opncfe_email_address\").change(function () {\r\n      $(\"#usp-email\").val($(this).val());\r\n    });\r\n\r\n    \/\/ Copy value of visible title (labeled \"Subject or...\") to hidden usp-subject field so USP Pro will correctly include the subject in all emails\r\n    $(\"#usp-title\").change(function () {\r\n      $(\"#usp-subject\").val($(this).val());\r\n    });\r\n  });\r\n});\r\n<\/script>\n\n","protected":false},"excerpt":{"rendered":"<p>A network is brought into being by the connections among its nodes. To contact Open Portal Network, please fill out the form below.<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-3273","page","type-page","status-publish","hentry"],"jetpack_sharing_enabled":true,"mfb_rest_fields":["jetpack_sharing_enabled"],"_links":{"self":[{"href":"https:\/\/loopcntr.net\/opn-alpha\/wp-json\/wp\/v2\/pages\/3273","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/loopcntr.net\/opn-alpha\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/loopcntr.net\/opn-alpha\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/loopcntr.net\/opn-alpha\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/loopcntr.net\/opn-alpha\/wp-json\/wp\/v2\/comments?post=3273"}],"version-history":[{"count":14,"href":"https:\/\/loopcntr.net\/opn-alpha\/wp-json\/wp\/v2\/pages\/3273\/revisions"}],"predecessor-version":[{"id":3382,"href":"https:\/\/loopcntr.net\/opn-alpha\/wp-json\/wp\/v2\/pages\/3273\/revisions\/3382"}],"wp:attachment":[{"href":"https:\/\/loopcntr.net\/opn-alpha\/wp-json\/wp\/v2\/media?parent=3273"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}