Directory Code

<div id="top"></div>
<div id="directory-app">
  <div class="directory-header">
    <div class="directory-filter">
      <label>Search for a Medical Provider</label>
      <input
        type="text"
        id="searchInput"
        placeholder="Or Search by Keyword..."
        autocomplete="off"
      />
    </div>
    <select id="categorySelect">
      <option selected disabled>Search By Specialty</option>
    </select>
    <button type="button" id="printBtn">Print this page</button>
    <div id="lastUpdatedInline">Directory last updated: 12/23/2025</div>
  </div>

  <div class="directory-scroll">
    <div id="directoryColumnsTop" class="directory-columns"></div>
    <div id="directoryContent"></div>
  </div>

  <button id="backToTopFloating" aria-label="Back to top">↑</button>
</div>

<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
  href="https://fonts.googleapis.com/css2?family=Libre+Baskerville:wght@600&family=Roboto:wght@500&display=swap"
  rel="stylesheet"
/>

<style>
  :root{--red:#a33038;--navy:#415465;--light:#bbc7cc;--heading:"Baskerville","Libre Baskerville","Times New Roman",serif;--para:"Roboto",system-ui,-apple-system,"Segoe UI",Arial,sans-serif;}
  .content-wrapper{padding-top:0!important;}
  #directory-app{font-size:10px;padding:0 5px;margin:0 15px;box-sizing:border-box;font-family:var(--para);letter-spacing: -.08px;font-weight:400; color:var(--navy);}
  .directory-header{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin:10px 0;background:transparent;}
  .directory-filter{display:contents;align-items:center;gap:10px;}
  .directory-filter label,#lastUpdatedInline,.directory-columns span,.cat-sep span{font-family:var(--heading);font-weight:600;}
  .directory-filter label{color:var(--navy);flex:0 0 100%;width:100%;order:1;margin:0 0 6px;font-size:1.7rem;}
  #lastUpdatedInline{white-space:nowrap;margin-left:auto;text-align:right;color:var(--navy);font-size:16px;order:5;}
  .directory-header select,.directory-header input{font:inherit;}
  #searchInput,#printBtn,.directory-header select{box-sizing:border-box;height:30px;padding:0 10px;line-height:normal;vertical-align:middle;}
  .directory-header select{background:#fff;color:var(--navy);border:1px solid var(--navy);}
  .directory-header select option:checked{background-color:var(--navy);color:#fff;}
  #categorySelect{order:2;}
  #searchInput{width:220px;flex:0 0 220px;border:1px solid var(--navy);color:var(--navy);background:#fff;order:3;}
  #searchInput:focus{outline:none;border-color:var(--navy);}
  #searchInput::placeholder{color:var(--navy);opacity:1;}
  #printBtn{display:none;cursor:pointer;background:var(--navy);color:#fff;border:1px solid var(--navy);order:4;}
  #printBtn:hover{filter:brightness(.92);}
  .directory-scroll{overflow-x:auto;padding:10px;}
  .directory-columns,.directory-row{display:grid;column-gap:5px;min-width:max-content;}
  .directory-columns{margin:6px 0;position:relative;background:var(--navy);color:#fff;padding:10px 15px;left:-20px;width:fit-content;}
  .directory-row{margin:14px 0;}
  .directory-row span,.directory-columns span{min-width:0;white-space:normal;overflow-wrap:anywhere;word-break:break-word;}
  .directory-columns span{text-transform:uppercase;}
  .hl{background:yellow;}
  .cat-sep{display:block;box-sizing:border-box;padding:14px 20px;margin-top:26px;border-top:2px solid var(--light);border-bottom:2px solid var(--light);}
  .cat-sep span{display:block;color:var(--red);text-transform:uppercase;letter-spacing:.04em;}
  #floatingCart{display:none;}
  #backToTopFloating{position:fixed;right:18px;bottom:18px;width:56px;height:56px;border-radius:999px;border:none;background:var(--red);color:#fff;cursor:pointer;font-size:30px;line-height:1;display:flex;align-items:center;justify-content:center;z-index:9999;box-shadow:0 10px 24px rgba(0,0,0,.22);font-weight:800;-webkit-text-stroke:2px #fff;text-shadow:0 0 0 #fff;}
  #backToTopFloating:hover{filter:brightness(.95);}
  #backToTopFloating:active{transform:translateY(1px);}
  #categorySelect{width:260px;min-width:260px;flex:0 0 260px;}

  @media (max-width:1024px){
  #directory-app{padding:0 14px;margin:0;}
  .directory-header{flex-direction:column;align-items:stretch;gap:10px;}
  .directory-filter{flex-direction:column;align-items:stretch;gap:8px;}
  .directory-filter label{display:block;white-space:normal;}
  .directory-header select,.directory-header input,#searchInput,#printBtn{width:100%!important;max-width:none!important;flex:0 0 auto!important;box-sizing:border-box;}
  #lastUpdatedInline{width:100%;text-align:right;}
  .directory-scroll{overflow-x:hidden;padding:0;}
  .directory-columns{display:none;}
  .directory-columns,.directory-row{min-width:0!important;width:100%!important;}
  .directory-row{display:block;grid-template-columns:none!important;margin:12px 0;padding:12px;border:1px solid rgba(0,0,0,.12);border-radius:12px;box-sizing:border-box;}
  .directory-row span{display:grid!important;grid-template-columns:42% 1fr!important;column-gap:10px!important;align-items:start!important;position:relative!important;width:100%!important;box-sizing:border-box!important;padding:8px 0!important;line-height:1.35!important;font-family:var(--para);font-weight:500;text-transform:none;color:var(--navy);letter-spacing:normal;white-space:normal!important;overflow-wrap:normal!important;word-break:normal!important;hyphens:none!important;}
  .directory-row span::before{content:attr(data-label) " ";position:static!important;width:auto!important;max-width:none!important;font-family:var(--heading);font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:var(--navy);line-height:1.2!important;white-space:normal!important;}
  .directory-row span .hl{display:inline!important;padding:0!important;}
  .directory-row span[data-label="EFF DATE"], .directory-row span[data-label="Eff Date"], .directory-row span[data-label="STREET ADDRESS"], .directory-row span[data-label="Street Address"], .directory-row span[data-label="CITY"], .directory-row span[data-label="City"] { overflow-wrap:normal!important;word-break:normal!important;white-space:normal!important;}
  }
</style>

<script>
  (() => {
    const S1 = "1quVZ_mPmE2sgONv4eOVYTTu2-K-n6j60";
    const SHEET1_NAME = "Active providers";
    const CAT_COL_INDEX_S1 = 8;
    const S2 = "18gR4n19-5N30kNzid7aDWzSunJ0O8tzZ";
    const GID2 = 720144501;

    const $=(s)=>document.querySelector(s);
    const esc=(s)=>String(s??"").replace(/[&<>"']/g,(m)=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#039;"}[m]));
    const reEsc=(s)=>s.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");
    const norm=(c)=>(c?c.f??c.v??"": "");
    const slug=(s)=>String(s||"").toLowerCase().replace(/[^a-z0-9]+/g,"-");
    const normKey=(s)=>String(s??"").trim().toLowerCase();

    const titleCaseLabel=(s)=>{
      const str=String(s??"").replace(/[\u200B-\u200D\uFEFF]/g,"").replace(/\u00A0/g," ").replace(/\s+/g," ").trim();
      if(!str)return str;
      const capWord=(w)=>{
        const raw=String(w||"");
        if(!raw)return raw;
        if(raw===raw.toUpperCase()&&/[A-Z]/.test(raw))return raw;
        if(raw.includes("/"))return raw.split("/").map(capWord).join("/");
        if(raw.includes("-"))return raw.split("-").map(capWord).join("-");
        const lower=raw.toLowerCase();
        return lower.charAt(0).toUpperCase()+lower.slice(1);
      };
      return str.split(" ").map(capWord).join(" ");
    };

    const grid=(labels)=>labels.map((t)=>{
      t=(t||"").toLowerCase().trim();
      if(t.includes("provider")||t.includes("facility"))return"185px";
      if(t.includes("specialty")||t.includes("category"))return"175px";
      if(t.includes("eff"))return"150px";
      if(t.includes("last")&&t.includes("name"))return"120px";
      if(t==="n"||t.includes("middle")||t.includes("mi")||t.includes("m.i"))return"46px";
      if(t.includes("first")&&t.includes("name"))return"140px";
      if(t.includes("degree"))return"70px";
      if(t.includes("street")&&t.includes("address"))return"185px";
      if(t==="city")return"100px";
      if(t==="state")return"55px";
      if(t.includes("zip"))return"66px";
      if(t.includes("phone"))return"100px";
      return"150px";
    }).join(" ");

    const mergeProviderName=(first,mi,last)=>{
      first=String(first||"").trim();mi=String(mi||"").trim();last=String(last||"").trim();
      if(!first&&!mi&&!last)return"";
      const mid=mi?(mi.length===1?mi+".":mi):"";
      return[first,mid,last].filter(Boolean).join(" ").replace(/\s+/g," ").trim();
    };

    const findIdx=(labels,preds)=>{
      const L=labels.map((s)=>String(s||"").toLowerCase().trim());
      for(let i=0;i<L.length;i++)if(preds.some((fn)=>fn(L[i])))return i;
      return-1;
    };

    const fetchGviz=async(spreadsheetId,params)=>{
      const qs=new URLSearchParams({tqx:"out:json",...params}).toString();
      const url=`https://docs.google.com/spreadsheets/d/${spreadsheetId}/gviz/tq?${qs}`;
      const t=await fetch(url).then((r)=>r.text());
      return JSON.parse(t.match(/setResponse\(([\s\S]+)\);/)[1]);
    };

    let term="",sections=[],displayCols=[],displayLabels=[],gridTpl="";

    const isCardMode=()=>window.matchMedia("(max-width:1024px)").matches;

    const wrapVal=(html)=>isCardMode()
      ? `<i class="tp-val" style="grid-column:2;min-width:0;font-style:normal;display:block">${html}</i>`
      : html;

    const resetRow=(rowEl)=>rowEl.querySelectorAll("span").forEach((s)=>{
      const t=s.textContent||"";
      s.innerHTML=wrapVal(esc(t));
    });

    const hi=(spanEl,rx)=>{
      const t=spanEl.textContent||"";
      if(!rx.test(t))return false;
      rx.lastIndex=0;
      const html=esc(t).replace(rx,(m)=>`<mark class="hl">${esc(m)}</mark>`);
      spanEl.innerHTML=wrapVal(html);
      return true;
    };

    const rowText=(rowEl)=>[...rowEl.querySelectorAll("span")].map((s)=>(s.textContent||"").toLowerCase()).join(" | ");

    const search=()=>{
      const q=term.trim();
      if(!q){
        sections.forEach((sec)=>{
          sec.rows.forEach((r)=>{resetRow(r);r.style.display="";});
          sec.el.style.display="";
        });
        return;
      }
      const qLower=q.toLowerCase();
      const phraseExists=sections.some((sec)=>sec.rows.some((r)=>rowText(r).includes(qLower)));
      const phraseRx=new RegExp(reEsc(q),"gi");
      const tokens=q.split(/\s+/).map((t)=>t.trim()).filter(Boolean);
      const tokenRxs=tokens.map((t)=>new RegExp(reEsc(t),"gi"));

      sections.forEach((sec)=>{
        let showSec=false;
        sec.rows.forEach((r)=>{
          resetRow(r);
          const text=rowText(r);
          let ok=false;
          if(phraseExists){
            ok=text.includes(qLower);
            if(ok)[...r.querySelectorAll("span")].forEach((s)=>hi(s,phraseRx));
          }else{
            ok=tokenRxs.every((rx)=>rx.test(text));
            if(ok)[...r.querySelectorAll("span")].forEach((s)=>tokenRxs.forEach((rx)=>hi(s,rx)));
          }
          r.style.display=ok?"":"none";
          if(ok)showSec=true;
        });
        sec.el.style.display=showSec?"":"none";
      });
    };

    const syncCategoryLines=()=>{
      const header=$("#directoryColumnsTop");
      if(!header)return;
      const w=Math.ceil(header.scrollWidth||header.getBoundingClientRect().width||0);
      if(!w)return;
      document.querySelectorAll("#directoryContent .cat-sep").forEach((cs)=>{
        cs.style.position="relative";cs.style.left="-20px";cs.style.width=w+"px";
      });
    };

    const buildDisplaySchema=(orderedIdx,orderedLabels)=>{
      const iFirst=findIdx(orderedLabels,[(t)=>t.includes("first")&&t.includes("name")]);
      const iLast=findIdx(orderedLabels,[(t)=>t.includes("last")&&t.includes("name")]);
      const iMI=findIdx(orderedLabels,[(t)=>t==="n"||t==="mi"||t.includes("middle")||t.includes("m.i")]);
      const hasName=iFirst>-1||iLast>-1||iMI>-1;
      const nameSrc={first:iFirst>-1?orderedIdx[iFirst]:null,mi:iMI>-1?orderedIdx[iMI]:null,last:iLast>-1?orderedIdx[iLast]:null};
      const cols=[];
      for(let i=0;i<orderedIdx.length;i++){
        if(hasName&&(i===iFirst||i===iLast||i===iMI))continue;
        cols.push({type:"normal",src:orderedIdx[i],label:orderedLabels[i]});
      }
      if(hasName)cols.splice(1,0,{type:"provider",label:"Provider/Facility",nameSrc});
      return cols;
    };

    const findCol2=(labels2,matchers)=>{
      const L=labels2.map((x)=>String(x||"").toLowerCase().trim());
      for(let i=0;i<L.length;i++)if(matchers.some((fn)=>fn(L[i])))return i;
      return-1;
    };

    const normalizeLabelKey=(s)=>String(s||"").toLowerCase().replace(/\s+/g," ").trim();

    const forceProviderLabelBreak=()=>{
      document.querySelectorAll('#directoryContent .directory-row span[data-label="Provider/Facility"]').forEach((s)=>{
        if(s.getAttribute("data-label")!=="Provider / Facility")s.setAttribute("data-label","Provider / Facility");
      });
    };

    const alignLastUpdatedToTableRight=()=>{
      const el=$("#lastUpdatedInline");
      const head=$("#directoryColumnsTop");
      const sc=document.querySelector(".directory-scroll");
      if(!el||!head||!sc)return;

      if(window.matchMedia("(max-width:767px)").matches){
        el.style.position="";
        el.style.left="";
        return;
      }

      const headRect=head.getBoundingClientRect();
      const scRect=sc.getBoundingClientRect();
      if(!headRect.width||!scRect.width)return;

      const targetRight=Math.min(headRect.right, scRect.right);

      el.style.position="relative";
      el.style.left="0px";

      const elRect=el.getBoundingClientRect();
      const dx=Math.round(targetRight - elRect.right);
      el.style.left=dx+"px";
    };

    let _tpAlignRAF=0;
    const scheduleAlign=()=>{
      if(_tpAlignRAF)return;
      _tpAlignRAF=requestAnimationFrame(()=>{
        _tpAlignRAF=0;
        alignLastUpdatedToTableRight();
      });
    };

    const load=async()=>{
      $("#directoryContent").innerHTML=`<p style="padding:20px;font-family:var(--para);color:var(--navy)">Loading...</p>`;
      try{
        // setLastUpdatedToday();

        const d1=await fetchGviz(S1,{sheet:SHEET1_NAME});
        const rawCols1=d1.table.cols.map((c,i)=>({label:(c.label||"").trim(),index:i})).filter((c)=>c.label);
        let orderedIdx=rawCols1.map((c)=>c.index);
        if(orderedIdx.includes(CAT_COL_INDEX_S1))orderedIdx=[CAT_COL_INDEX_S1,...orderedIdx.filter((i)=>i!==CAT_COL_INDEX_S1)];
        const orderedLabels=orderedIdx.map((i)=>rawCols1.find((c)=>c.index===i)?.label||"");

        displayCols=buildDisplaySchema(orderedIdx,orderedLabels);
        displayLabels=displayCols.map((c)=>c.label);
        gridTpl=grid(displayLabels);
        $("#directoryColumnsTop").style.gridTemplateColumns=gridTpl;
        $("#directoryColumnsTop").innerHTML=displayLabels.map((l)=>`<span>${esc(l)}</span>`).join("");

        let rows1=d1.table.rows.map((r)=>(r.c||[]).map(norm));
        let lastCat="";
        rows1.forEach((r)=>{if(r[CAT_COL_INDEX_S1])lastCat=r[CAT_COL_INDEX_S1];else r[CAT_COL_INDEX_S1]=lastCat;});

        const unified=[];
        rows1.forEach((r)=>{
          const data={};
          displayCols.forEach((c,idx)=>{
            const label=displayLabels[idx]||"";
            let val="";
            if(c.type==="provider"){
              const f=c.nameSrc.first!=null?r[c.nameSrc.first]:"",m=c.nameSrc.mi!=null?r[c.nameSrc.mi]:"",l=c.nameSrc.last!=null?r[c.nameSrc.last]:"";
              val=mergeProviderName(f,m,l);
            }else val=r[c.src]??"";
            data[label]=val;
          });
          const cat=r[CAT_COL_INDEX_S1]||data["SPECIALTY"]||data["Specialty"]||data["Category"]||"Other";
          unified.push({cat,data,src:1});
        });

        const d2=await fetchGviz(S2,{gid:String(GID2)});
        const labels2=d2.table.cols.map((c)=>(c.label||"").trim());
        const rows2=d2.table.rows.map((r)=>(r.c||[]).map(norm));

        const iFacility=findCol2(labels2,[(t)=>t==="facility name"||(t.includes("facility")&&t.includes("name"))]);
        const iAddress=findCol2(labels2,[(t)=>t==="address"||(t.includes("street")&&t.includes("address"))]);
        const iCity=findCol2(labels2,[(t)=>t==="city"]);
        const iState=findCol2(labels2,[(t)=>t==="state"]);
        const iZip=findCol2(labels2,[(t)=>t==="zip code"||t==="zip"||t.includes("zip")]);
        const iPhone=findCol2(labels2,[(t)=>t==="phone"||t.includes("phone")]);
        const iEff=findCol2(labels2,[(t)=>t.includes("eff")&&(t.includes("date")||t.includes("eff"))&&t.includes("date")]);
        const iSpec=findCol2(labels2,[(t)=>t==="specialty"||t.includes("specialty")]);

        rows2.forEach((r)=>{
          const data={};
          displayLabels.forEach((lab)=>(data[lab]=""));
          const byKey={};
          displayLabels.forEach((lab)=>(byKey[normalizeLabelKey(lab)]=lab));
          const setIfExists=(targetLabelGuess,value)=>{
            const key=normalizeLabelKey(targetLabelGuess);
            const real=byKey[key]||null;
            if(real)data[real]=value??"";
          };
          setIfExists("Provider/Facility",iFacility>-1?r[iFacility]:"");
          setIfExists("STREET ADDRESS",iAddress>-1?r[iAddress]:"");
          setIfExists("CITY",iCity>-1?r[iCity]:"");
          setIfExists("STATE",iState>-1?r[iState]:"");
          setIfExists("ZIP",iZip>-1?r[iZip]:"");
          setIfExists("PHONE",iPhone>-1?r[iPhone]:"");
          setIfExists("EFF DATE",iEff>-1?r[iEff]:"");
          setIfExists("SPECIALTY",iSpec>-1?r[iSpec]:"");
          const cat=(iSpec>-1?r[iSpec]:"")||data["SPECIALTY"]||"Other";
          unified.push({cat,data,src:2});
        });

        const canon=new Map();
        unified.forEach((x)=>{
          const k=normKey(x.cat||"Other");
          if(!canon.has(k))canon.set(k,{from1:null,from2:null});
          const obj=canon.get(k);
          if(x.src===1&&!obj.from1)obj.from1=x.cat||"Other";
          if(x.src===2&&!obj.from2)obj.from2=x.cat||"Other";
        });

        const catKeysSorted=[...canon.keys()].sort((a,b)=>{
          const A=canon.get(a).from1||canon.get(a).from2||"Other";
          const B=canon.get(b).from1||canon.get(b).from2||"Other";
          return A.localeCompare(B,undefined,{sensitivity:"base"});
        });

        $("#categorySelect").innerHTML=`<option value="" selected disabled>Search By Specialty</option>`+catKeysSorted.map((k)=>{
          const displayName=titleCaseLabel(canon.get(k).from1||canon.get(k).from2||"Other");
          return `<option value="${esc(k)}">${esc(displayName)}</option>`;
        }).join("");

        const grouped={};
        unified.forEach((x)=>{const k=normKey(x.cat||"Other");(grouped[k]??=[]).push(x);});

        sections=[];
        $("#directoryContent").innerHTML="";
        catKeysSorted.forEach((k)=>{
          const displayName=canon.get(k).from1||canon.get(k).from2||"Other";
          const rs=grouped[k]||[];
          const wrap=document.createElement("div");
          wrap.id="cat-"+slug(k);
          wrap.innerHTML=`<div class="cat-sep"><span>${esc(displayName)}</span></div>`;
          const rr=[];
          rs.forEach((item)=>{
            const el=document.createElement("div");
            el.className="directory-row";
            el.style.gridTemplateColumns=gridTpl;
            el.innerHTML=displayLabels.map((label)=>`<span data-label="${esc(label)}">${esc(item.data[label]??"")}</span>`).join("");
            rr.push(el);
            wrap.appendChild(el);
          });
          $("#directoryContent").appendChild(wrap);
          sections.push({el:wrap,rows:rr});
        });

        search();syncCategoryLines();forceProviderLabelBreak();
        requestAnimationFrame(()=>alignLastUpdatedToTableRight());

      }catch(e){
        $("#directoryContent").innerHTML=`<p style="padding:20px;font-family:var(--para);color:var(--navy)">The data could not be loaded. You can try reloading the page or come back after a few minutes.</p>`;
      }
    };

    $("#searchInput").oninput=(e)=>{term=e.target.value.trim();search();};
    $("#categorySelect").onchange=(e)=>{const k=e.target.value;if(k)$("#cat-"+slug(k)).scrollIntoView({behavior:"smooth"});};
    $("#printBtn").onclick=()=>print();
    $("#backToTopFloating").onclick=()=>scrollTo({top:0,behavior:"smooth"});

    window.addEventListener("resize",()=>{
      syncCategoryLines();
      scheduleAlign();
    },{passive:true});

    document.querySelector(".directory-scroll")?.addEventListener("scroll",scheduleAlign,{passive:true});

    load();
  })();
</script>

 

Buy me a coffee