{"version":3,"sources":["webpack:///./app/javascript/utilities/viewport.js","webpack:///./app/javascript/utilities/dropdownUtils.js","webpack:///./app/javascript/utilities/debounceAction.js","webpack:///./app/javascript/utilities/getUserDataAndCsrfToken.js","webpack:///(webpack)/buildin/global.js","webpack:///./app/javascript/utilities/http/errors.js","webpack:///./node_modules/lodash.debounce/index.js","webpack:///./app/javascript/utilities/http/csrfToken.js","webpack:///./app/javascript/utilities/http/request.js","webpack:///./app/javascript/profileDropdown/flagButton.js","webpack:///./app/javascript/packs/profileDropdown.js","webpack:///./app/javascript/profileDropdown/blockButton.js"],"names":["isInViewport","element","offsetTop","allowPartialVisibility","boundingRect","getBoundingClientRect","clientHeight","window","innerHeight","document","documentElement","clientWidth","innerWidth","topIsInViewport","top","rightIsInViewport","right","bottomIsInViewport","bottom","leftIsInViewport","left","topIsOutOfViewport","bottomIsOutOfViewport","getDropdownRepositionListener","debounceAction","handleDropdownRepositions","querySelectorAll","classList","remove","isDropdownCurrentlyOpen","style","display","opacity","add","removeProperty","INTERACTIVE_ELEMENTS_QUERY","openDropdown","triggerElementId","dropdownContentId","dropdownContent","getElementById","setAttribute","querySelector","focus","closeDropdown","onClose","initializeDropdown","dropdownContentCloseButtonId","onOpen","triggerButton","keyUpListener","key","getAttribute","onCloseCleanupActions","contains","activeElement","clickOutsideListener","target","matches","removeEventListener","addEventListener","action","time","config","leading","configs","debounce","getWaitOnUserDataHandler","resolve","reject","waitTime","totalTimeWaiting","waitingOnUserData","csrfToken","content","undefined","user","body","dataset","currentUser","JSON","parse","setTimeout","Error","getUserDataAndCsrfToken","Promise","g","this","Function","e","module","exports","handleFetchAPIErrors","response","ok","json","then","data","error","SyntaxError","statusText","reTrim","reIsBadHex","reIsBinary","reIsOctal","freeParseInt","parseInt","freeGlobal","global","Object","freeSelf","self","root","objectToString","prototype","toString","nativeMax","Math","max","nativeMin","min","now","Date","isObject","value","type","toNumber","isObjectLike","call","isSymbol","other","valueOf","replace","isBinary","test","slice","func","wait","options","lastArgs","lastThis","maxWait","result","timerId","lastCallTime","lastInvokeTime","maxing","trailing","TypeError","invokeFunc","args","thisArg","apply","leadingEdge","timerExpired","shouldInvoke","timeSinceLastCall","trailingEdge","remainingWait","debounced","isInvoking","arguments","cancel","clearTimeout","flush","getCSRFToken","i","waitingOnCSRF","setInterval","metaTag","clearInterval","authToken","Honeybadger","notify","stringify","localStorage","current_user","request","url","headers","method","restOfOptions","jsonifiedBody","fetchOptions","Accept","credentials","fetch","initFlag","flagButton","userData","trustedOrAdmin","trusted","admin","profileUserId","id","profileUserName","isUserFlagged","confirm","reactable_type","category","reactable_id","innerHTML","alert","addFlagUserBehavior","initButtons","blockButton","innerText","unblock","once","block","user_block","blocked_id","status","initBlock","profileDropdownDiv","dropdownInitialized","username","reportAbuseLink","path","initDropdown"],"mappings":"0FAYO,SAASA,EAAa,GAIzB,IAHFC,EAAO,EAAPA,QAAQ,EAAD,EACPC,iBAAS,MAAG,EAAC,MACbC,8BAAsB,OAAQ,EAExBC,EAAeH,EAAQI,wBACvBC,EACJC,OAAOC,aAAeC,SAASC,gBAAgBJ,aAC3CK,EAAcJ,OAAOK,YAAcH,SAASC,gBAAgBC,YAC5DE,EACJT,EAAaU,KAAOR,GAAgBF,EAAaU,KAAOZ,EACpDa,EACJX,EAAaY,OAAS,GAAKZ,EAAaY,OAASL,EAC7CM,EACJb,EAAac,QAAUhB,GAAaE,EAAac,QAAUZ,EACvDa,EACJf,EAAagB,MAAQT,GAAeP,EAAagB,MAAQ,EACrDC,EAAqBjB,EAAaU,KAAOZ,EACzCoB,EAAwBlB,EAAac,QAAUZ,EAIrD,OAAIH,GAECU,GAAmBI,GAJtBI,GAAsBC,KAKnBH,GAAoBJ,GAIvBF,GACAI,GACAE,GACAJ,CAEJ,CA9CA,iC,uvCCYO,IAAMQ,EAAgC,WAAH,OACxCC,YAAeC,EAA2B,EAQtCA,EAA4B,WAEhC,IAI+C,EAF7C,IAFgChB,SAASiB,iBACzC,kCAG6C,IAA/C,2BAAiD,CAAC,IAAvCzB,EAAO,QAEhBA,EAAQ0B,UAAUC,OAAO,WAEzB,IAAMC,EAAoD,UAA1B5B,EAAQ6B,MAAMC,QAEzCF,IAEH5B,EAAQ6B,MAAME,QAAU,EACxB/B,EAAQ6B,MAAMC,QAAU,SAGrB/B,YAAa,CAAEC,aAElBA,EAAQ0B,UAAUM,IAAI,WAGnBJ,IAEH5B,EAAQ6B,MAAMI,eAAe,WAC7BjC,EAAQ6B,MAAMI,eAAe,WAEjC,CAAC,+BACH,EAKaC,EACX,+EASWC,EAAe,SAAH,GAAiD,IAAD,EAA1CC,EAAgB,EAAhBA,iBAAkBC,EAAiB,EAAjBA,kBACzCC,EAAkB9B,SAAS+B,eAAeF,GACzB7B,SAAS+B,eAAeH,GAEhCI,aAAa,gBAAiB,QAG7CF,EAAgBT,MAAMC,QAAU,QAGyB,QAAzD,EAAAQ,EAAgBG,cAAcP,UAA2B,OAAzD,EAA2DQ,OAC7D,EAUaC,EAAgB,SAAH,GAInB,IAAD,EAHJP,EAAgB,EAAhBA,iBACAC,EAAiB,EAAjBA,kBACAO,EAAO,EAAPA,QAEMN,EAAkB9B,SAAS+B,eAAeF,GAE3CC,IAM8B,QADnC,EAAA9B,SACG+B,eAAeH,UAAiB,OADnC,EAEII,aAAa,gBAAiB,SAGlCF,EAAgBT,MAAMI,eAAe,WAE9B,OAAPW,QAAO,IAAPA,OACF,EAeaC,EAAqB,SAAH,GAMxB,IALLT,EAAgB,EAAhBA,iBACAC,EAAiB,EAAjBA,kBACAS,EAA4B,EAA5BA,6BACAF,EAAO,EAAPA,QACAG,EAAM,EAANA,OAEMC,EAAgBxC,SAAS+B,eAAeH,GACxCE,EAAkB9B,SAAS+B,eAAeF,GAEhD,GAAKW,GAAkBV,EAAvB,CAMAU,EAAcR,aAAa,gBAAiB,SAC5CQ,EAAcR,aAAa,gBAAiBH,GAC5CW,EAAcR,aAAa,gBAAiB,QAE5C,IAkFkC,EAlF5BS,EAAgB,SAAH,GAAiB,IAAXC,EAAG,EAAHA,IACvB,GAAY,WAARA,EAGgD,SAAhDF,EAAcG,aAAa,mBAE3BR,EAAc,CACZP,mBACAC,oBACAO,QAASQ,IAEXJ,EAAcN,cAEX,GAAY,QAARQ,EAAe,EAEgB,OAAfZ,QAAe,IAAfA,OAAe,EAAfA,EAAiBe,SACxC7C,SAAS8C,iBAGTX,EAAc,CACZP,mBACAC,oBACAO,QAASQ,GAGf,CACF,EAGMG,EAAuB,SAAH,GAAoB,IAAdC,EAAM,EAANA,OAExBR,EAAgBxC,SAAS+B,eAAeH,IAE5CY,GACAQ,IAAWR,GACVV,EAAgBe,SAASG,IACzBR,EAAcK,SAASG,KAExBb,EAAc,CACZP,mBACAC,oBACAO,QAASQ,IAINI,EAAOC,QAAQvB,IAClBc,EAAcN,QAGpB,EAGMU,EAAwB,WACrB,OAAPR,QAAO,IAAPA,OACApC,SAASkD,oBAAoB,QAAST,GACtCzC,SAASkD,oBAAoB,QAASH,EACxC,EA0BA,GAvBAP,EAAcW,iBAAiB,SAAS,WAAO,IAAD,EAIJ,UADH,QADnC,EAAAnD,SACG+B,eAAeH,UAAiB,aADnC,EAEIe,aAAa,kBAEjBR,EAAc,CACZP,mBACAC,oBACAO,QAASQ,KAGXjB,EAAa,CACXC,mBACAC,sBAEI,OAANU,QAAM,IAANA,OAEAvC,SAASmD,iBAAiB,QAASV,GACnCzC,SAASmD,iBAAiB,QAASJ,GAEvC,IAEIT,EAG6C,QAD/C,EAAAtC,SACG+B,eAAeO,UAA6B,OAD/C,EAEIa,iBAAiB,SAAS,WAAO,IAAD,EAChChB,EAAc,CACZP,mBACAC,oBACAO,QAASQ,IAG8B,QAAzC,EAAA5C,SAAS+B,eAAeH,UAAiB,OAAzC,EAA2CM,OAC7C,IAGJ,MAAO,CACLC,cAAe,WACbA,EAAc,CACZP,mBACAC,oBACAO,QAASQ,GAEb,EA/GF,CAiHF,C,6zCCvOO,SAAS7B,EACdqC,GAEC,IAAD,yDAD8C,CAAC,EAAE,EAAD,EAA9CC,YAAI,MAAG,IAAG,MAAEC,cAAM,MAAG,CAAEC,SAAS,GAAO,EAEnCC,EAAO,KAAQF,GACrB,OAAOG,IAASL,EAAQC,EAAMG,EAChC,C,mCCtBA,kCAMA,IAAME,EAA2B,SAAH,GAA4C,IAAtCC,EAAO,EAAPA,QAASC,EAAM,EAANA,OAAO,EAAD,EAAEC,gBAAQ,MAAG,GAAE,EAC5DC,EAAmB,EAEvB,OAAO,SAASC,IACd,GAAyB,MAArBD,EAAJ,CAKA,IAdItE,EAcEwE,GAAyBhE,SAZd,QAFbR,EAAUQ,SAASiC,cAAc,4BAEbzC,EAAQyE,aAAUC,GAalCC,EAASnE,SAASoE,KAAKC,QAAvBF,KAER,GAAIA,QAAsBD,IAAdF,EAAZ,CACE,IAAMM,EAAcC,KAAKC,MAAML,GAE/BR,EAAQ,CAAEW,cAAaN,aAEzB,MAEAF,GAAoBD,EACpBY,WAAWV,EAAmBF,EAb9B,MAFED,EAAO,IAAIc,MAAM,oCAgBrB,CACF,EAEO,SAASC,IACd,OAAO,IAAIC,SAAQ,SAACjB,EAASC,GAC3BF,EAAyB,CAAEC,UAASC,UAApCF,EACF,GACF,C,oBClCA,IAAImB,EAGJA,EAAI,WACH,OAAOC,IACP,CAFG,GAIJ,IAECD,EAAIA,GAAK,IAAIE,SAAS,cAAb,EAIV,CAHE,MAAOC,GAEc,kBAAXlF,SAAqB+E,EAAI/E,OACrC,CAMAmF,EAAOC,QAAUL,C,kCClBV,SAASM,EAAqBC,GAEnC,GAAIA,EAASC,GACX,OAAOD,EAKT,IACEA,EAASE,OAAOC,MAAK,SAACC,GACpB,MAAM,IAAId,MAAMc,EAAKC,MACvB,GAOF,CANE,MAAOT,GACP,MAAIA,aAAaU,YACT,IAAIhB,MAAMU,EAASO,YAEnBX,CAEV,CACF,C,uGCpBA,YAUA,IASIY,EAAS,aAGTC,EAAa,qBAGbC,EAAa,aAGbC,EAAY,cAGZC,EAAeC,SAGfC,EAA8B,iBAAVC,GAAsBA,GAAUA,EAAOC,SAAWA,QAAUD,EAGhFE,EAA0B,iBAARC,MAAoBA,MAAQA,KAAKF,SAAWA,QAAUE,KAGxEC,EAAOL,GAAcG,GAAYtB,SAAS,cAATA,GAUjCyB,EAPcJ,OAAOK,UAOQC,SAG7BC,EAAYC,KAAKC,IACjBC,EAAYF,KAAKG,IAkBjBC,EAAM,WACR,OAAOT,EAAKU,KAAKD,KACnB,EA2MA,SAASE,EAASC,GAChB,IAAIC,SAAcD,EAClB,QAASA,IAAkB,UAARC,GAA4B,YAARA,EACzC,CA2EA,SAASC,EAASF,GAChB,GAAoB,iBAATA,EACT,OAAOA,EAET,GAhCF,SAAkBA,GAChB,MAAuB,iBAATA,GAtBhB,SAAsBA,GACpB,QAASA,GAAyB,iBAATA,CAC3B,CAqBKG,CAAaH,IAzTF,mBAyTYX,EAAee,KAAKJ,EAChD,CA6BMK,CAASL,GACX,OA3VM,IA6VR,GAAID,EAASC,GAAQ,CACnB,IAAIM,EAAgC,mBAAjBN,EAAMO,QAAwBP,EAAMO,UAAYP,EACnEA,EAAQD,EAASO,GAAUA,EAAQ,GAAMA,CAC3C,CACA,GAAoB,iBAATN,EACT,OAAiB,IAAVA,EAAcA,GAASA,EAEhCA,EAAQA,EAAMQ,QAAQ/B,EAAQ,IAC9B,IAAIgC,EAAW9B,EAAW+B,KAAKV,GAC/B,OAAQS,GAAY7B,EAAU8B,KAAKV,GAC/BnB,EAAamB,EAAMW,MAAM,GAAIF,EAAW,EAAI,GAC3C/B,EAAWgC,KAAKV,GAxWb,KAwW6BA,CACvC,CAEAlC,EAAOC,QAtPP,SAAkB6C,EAAMC,EAAMC,GAC5B,IAAIC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EAAiB,EACjBjF,GAAU,EACVkF,GAAS,EACTC,GAAW,EAEf,GAAmB,mBAARX,EACT,MAAM,IAAIY,UArIQ,uBA+IpB,SAASC,EAAWvF,GAClB,IAAIwF,EAAOX,EACPY,EAAUX,EAKd,OAHAD,EAAWC,OAAWjE,EACtBsE,EAAiBnF,EACjBgF,EAASN,EAAKgB,MAAMD,EAASD,EAE/B,CAEA,SAASG,EAAY3F,GAMnB,OAJAmF,EAAiBnF,EAEjBiF,EAAU7D,WAAWwE,EAAcjB,GAE5BzE,EAAUqF,EAAWvF,GAAQgF,CACtC,CAUA,SAASa,EAAa7F,GACpB,IAAI8F,EAAoB9F,EAAOkF,EAM/B,YAAyBrE,IAAjBqE,GAA+BY,GAAqBnB,GACzDmB,EAAoB,GAAOV,GANJpF,EAAOmF,GAM8BJ,CACjE,CAEA,SAASa,IACP,IAAI5F,EAAO2D,IACX,GAAIkC,EAAa7F,GACf,OAAO+F,EAAa/F,GAGtBiF,EAAU7D,WAAWwE,EAzBvB,SAAuB5F,GACrB,IAEIgF,EAASL,GAFW3E,EAAOkF,GAI/B,OAAOE,EAAS3B,EAAUuB,EAAQD,GAHR/E,EAAOmF,IAGkCH,CACrE,CAmBqCgB,CAAchG,GACnD,CAEA,SAAS+F,EAAa/F,GAKpB,OAJAiF,OAAUpE,EAINwE,GAAYR,EACPU,EAAWvF,IAEpB6E,EAAWC,OAAWjE,EACfmE,EACT,CAcA,SAASiB,IACP,IAAIjG,EAAO2D,IACPuC,EAAaL,EAAa7F,GAM9B,GAJA6E,EAAWsB,UACXrB,EAAWrD,KACXyD,EAAelF,EAEXkG,EAAY,CACd,QAAgBrF,IAAZoE,EACF,OAAOU,EAAYT,GAErB,GAAIE,EAGF,OADAH,EAAU7D,WAAWwE,EAAcjB,GAC5BY,EAAWL,EAEtB,CAIA,YAHgBrE,IAAZoE,IACFA,EAAU7D,WAAWwE,EAAcjB,IAE9BK,CACT,CAGA,OAxGAL,EAAOX,EAASW,IAAS,EACrBd,EAASe,KACX1E,IAAY0E,EAAQ1E,QAEpB6E,GADAK,EAAS,YAAaR,GACHtB,EAAUU,EAASY,EAAQG,UAAY,EAAGJ,GAAQI,EACrEM,EAAW,aAAcT,IAAYA,EAAQS,SAAWA,GAiG1DY,EAAUG,OAnCV,gBACkBvF,IAAZoE,GACFoB,aAAapB,GAEfE,EAAiB,EACjBN,EAAWK,EAAeJ,EAAWG,OAAUpE,CACjD,EA8BAoF,EAAUK,MA5BV,WACE,YAAmBzF,IAAZoE,EAAwBD,EAASe,EAAapC,IACvD,EA2BOsC,CACT,C,wFCvPO,SAASM,IAyBd,OAxBgB,IAAIhF,SAAQ,SAACjB,EAASC,GAEpC,IAAIiG,EAAI,EACFC,EAAgBC,aAAY,WAChC,IAAMC,EAAUhK,SAASiC,cAAc,2BAGvC,GAFA4H,GAAK,EAEDG,EAAS,CACXC,cAAcH,GACd,IAAMI,EAAYF,EAAQrH,aAAa,WACvC,OAAOgB,EAAQuG,EACjB,CAEA,GAjBc,KAiBVL,EAOF,OANAI,cAAcH,GACdK,YAAYC,OAAO,iCAAD,OACiB7F,KAAK8F,UACpCC,aAAaC,gBAGV3G,EAAO,IAAIc,MAAM,+CAE5B,GAzBmB,IA0BrB,GAEF,C,k8DCLO,SAAe8F,EAAQ,GAAD,+BA8B5B,yBA9BM,UAAuBC,GAAoB,IAAfxC,EAAO,uDAAG,CAAC,EAE1CyC,EAMEzC,EANFyC,QACAtG,EAKE6D,EALF7D,KAAK,EAKH6D,EAJF0C,cAAM,MAAG,MAAK,IAIZ1C,EAHFjE,iBAAS,YAAS4F,IAAc,EAE7BgB,EAAa,EACd3C,EAAO,GAIL4C,EAAgB,CACpBzG,KAAMA,GAAwB,kBAATA,EAAoBG,KAAK8F,UAAUjG,GAAQA,GAG5D0G,EAAY,KAChBH,SACAD,QAAQ,EAAD,CACLK,OAAQ,mBACR,eAAgB/G,EAChB,eAAgB,oBACb0G,GAELM,YAAa,eACVH,GACAD,GAGL,OAAOK,MAAMR,EAAKK,EACpB,IAAC,wB,+DCCM,SAASI,IACd,IAAMC,EAAanL,SAAS+B,eAC1B,yCAGGoJ,GAKLxG,cAA0BY,MAAK,WAC7B,IAAMpB,EAAOiH,WACb,GAAKjH,EAAL,CAKA,IAAMkH,EAAiBlH,EAAKmH,SAAWnH,EAAKoH,MACpCC,EAAkBL,EAAW9G,QAA7BmH,cAEHH,GAAkBlH,EAAKsH,KAAOxF,SAASuF,EAAe,KACzDL,EAAWhK,SAvEjB,SAA6BgK,GAC3B,MAA2CA,EAAW9G,QAA9CmH,EAAa,EAAbA,cAAeE,EAAe,EAAfA,gBAEnBC,EAAqD,SAArCR,EAAW9G,QAAQsH,cAsCvCR,EAAWhI,iBAAiB,SApC5B,WACsBrD,OAAO8L,QACzBD,EACI,gGACA,+FAIJnB,YAAQ,aAAc,CACpBG,OAAQ,OACRvG,KAAM,CACJyH,eAAgB,OAChBC,SAAU,QACVC,aAAcP,KAGfjG,MAAK,SAACH,GAAQ,OAAKA,EAASE,MAAM,IAClCC,MAAK,SAACH,GACmB,WAApBA,EAASiD,QACXsD,GAAgB,EAChBR,EAAWa,UAAS,iBAAaN,KAEjCC,GAAgB,EAChBR,EAAWa,UAAS,eAAWN,GAEnC,IAAE,OACK,SAAC1G,GACNmF,YAAYC,OACVuB,EAAgB,wBAA0B,sBAC1CH,GAEF1L,OAAOmM,MAAM,yBAAD,OAA0BjH,GACxC,GAEN,GAGF,CA+BIkH,CAAoBf,EARpB,MAFEA,EAAWhK,QAWf,GACF,C,YC1EA,SAASgL,KCJF,WACL,IAAMC,EAAcpM,SAAS+B,eAC3B,0CAEF,GAAKqK,EAAL,CAIA,IAAQZ,EAAkBY,EAAY/H,QAA9BmH,cA+EFrH,EAAOiH,WACRjH,IAIDA,EAAKsH,KAAOxF,SAASuF,EAAe,IACtCY,EAAY/K,MAAMC,QAAU,OAE5B2J,MAAM,gBAAD,OAAiBO,IACnBjG,MAAK,SAACH,GAAQ,OAAKA,EAASE,MAAM,IAClCC,MAAK,SAACH,GACmB,aAApBA,EAASiD,QACX+D,EAAYC,UAAY,UACxBD,EAAYjJ,iBAAiB,QAASmJ,EAAS,CAAEC,MAAM,KAEvDH,EAAYjJ,iBAAiB,QAASqJ,EAAO,CAAED,MAAM,GAEzD,IAjGJ,CAGA,SAASD,IACPrB,MAAM,gBAAD,OAAiBO,GAAiB,CACrCb,OAAQ,SACRD,QAAS,CACPK,OAAQ,mBACR,eAAgBjL,OAAOkE,UACvB,eAAgB,oBAElBI,KAAMG,KAAK8F,UAAU,CACnBoC,WAAY,CACVC,WAAYlB,OAIfjG,MAAK,SAACH,GAAQ,OAAKA,EAASE,MAAM,IAClCC,MAAK,SAACH,GACmB,cAApBA,EAASiD,QACX+D,EAAYC,UAAY,QAExBD,EAAYjJ,iBAAiB,QAASqJ,EAAO,CAAED,MAAM,KACxB,MAApBnH,EAASuH,QAClB7M,OAAOmM,MAAM,yBAAD,OACe7G,EAASK,MAAK,6CAG7C,IAAE,OACK,SAACT,GACNlF,OAAOmM,MAAM,yBAAD,OACejH,EAAC,8CAE9B,GACJ,CAEA,SAASwH,IACc1M,OAAO8L,QAAQ,kMAOlCX,MAAM,eAAgB,CACpBN,OAAQ,OACRD,QAAS,CACPK,OAAQ,mBACR,eAAgBjL,OAAOkE,UACvB,eAAgB,oBAElBI,KAAMG,KAAK8F,UAAU,CACnBoC,WAAY,CACVC,WAAYlB,OAIfjG,MAAK,SAACH,GAAQ,OAAKA,EAASE,MAAM,IAClCC,MAAK,SAACH,GACmB,YAApBA,EAASiD,QACX+D,EAAYC,UAAY,UACxBD,EAAYjJ,iBAAiB,QAASmJ,EAAS,CAAEC,MAAM,KAC1B,MAApBnH,EAASuH,QAClB7M,OAAOmM,MAAM,yBAAD,OACe7G,EAASK,MAAK,8CAG7C,IAAE,OACK,SAACT,GACNlF,OAAOmM,MAAM,yBAAD,OACejH,EAAC,8CAE9B,IAEFoH,EAAYjJ,iBAAiB,QAASqJ,EAAO,CAAED,MAAM,GAEzD,CAuBF,CDrGEK,GACA1B,GACF,EAEA,WACE,IAAM2B,EAAqB7M,SAASiC,cAAc,qBAElD,GAAuD,SAAnD4K,EAAmBxI,QAAQyI,oBAA/B,CAGA,IAAMxI,EAAc8G,WAEpB,GACGyB,KACAvI,GACCA,EAAYyI,WAAaF,EAAmBxI,QAAQ0I,UAHxD,CASAF,EAAmB3L,UAAUC,OAAO,UAEpCkB,YAAmB,CACjBT,iBAAkB,wBAClBC,kBAAmB,8BAIrB,IAAMmL,EAAkBH,EAAmB5K,cACzC,8BAEF+K,EAAgBhB,UAAS,mBAAegB,EAAgB3I,QAAQ4I,KAAI,+DAEpEd,IACAU,EAAmBxI,QAAQyI,qBAAsB,CAhBjD,CAVA,CA2BF,CAEAI,E","file":"js/profileDropdown-ff7fcf0ccd6d7a52a5a1.chunk.js","sourcesContent":["/**\n * Checks if an element is visible in the viewport\n *\n * @example\n * const element = document.getElementById('element');\n * isInViewport({element, allowPartialVisibility = true}); // true or false\n *\n * @param {HTMLElement} element - The HTML element to check\n * @param {number} [offsetTop=0] - Part of the screen to ignore counting from the top\n * @param {boolean} [allowPartialVisibility=false] - A boolean to flip the check between partial or completely visible in the viewport\n * @returns {boolean} isInViewport - true if the element is visible in the viewport\n */\nexport function isInViewport({\n element,\n offsetTop = 0,\n allowPartialVisibility = false,\n}) {\n const boundingRect = element.getBoundingClientRect();\n const clientHeight =\n window.innerHeight || document.documentElement.clientHeight;\n const clientWidth = window.innerWidth || document.documentElement.clientWidth;\n const topIsInViewport =\n boundingRect.top <= clientHeight && boundingRect.top >= offsetTop;\n const rightIsInViewport =\n boundingRect.right >= 0 && boundingRect.right <= clientWidth;\n const bottomIsInViewport =\n boundingRect.bottom >= offsetTop && boundingRect.bottom <= clientHeight;\n const leftIsInViewport =\n boundingRect.left <= clientWidth && boundingRect.left >= 0;\n const topIsOutOfViewport = boundingRect.top <= offsetTop;\n const bottomIsOutOfViewport = boundingRect.bottom >= clientHeight;\n const elementSpansEntireViewport =\n topIsOutOfViewport && bottomIsOutOfViewport;\n\n if (allowPartialVisibility) {\n return (\n (topIsInViewport || bottomIsInViewport || elementSpansEntireViewport) &&\n (leftIsInViewport || rightIsInViewport)\n );\n }\n return (\n topIsInViewport &&\n bottomIsInViewport &&\n leftIsInViewport &&\n rightIsInViewport\n );\n}\n","import { isInViewport } from '@utilities/viewport';\nimport { debounceAction } from '@utilities/debounceAction';\n\n/**\n * Helper function designed to be used on scroll to detect when dropdowns should switch from dropping downwards/upwards.\n * The action is debounced since scroll events are usually fired several at a time.\n *\n * @returns {Function} a debounced function that handles the repositioning of dropdowns\n * @example\n *\n * document.addEventListener('scroll', getDropdownRepositionListener());\n */\nexport const getDropdownRepositionListener = () =>\n debounceAction(handleDropdownRepositions);\n\n/**\n * Checks for all dropdowns on the page which have the attribute 'data-repositioning-dropdown', signalling\n * they should dynamically change between dropping downwards or upwards, depending on viewport position.\n *\n * Any dropdowns not fully in view when dropping down will be switched to dropping upwards.\n */\nconst handleDropdownRepositions = () => {\n // Select all of the dropdowns which should reposition\n const allRepositioningDropdowns = document.querySelectorAll(\n '[data-repositioning-dropdown]',\n );\n\n for (const element of allRepositioningDropdowns) {\n // Default to dropping downwards\n element.classList.remove('reverse');\n\n const isDropdownCurrentlyOpen = element.style.display === 'block';\n\n if (!isDropdownCurrentlyOpen) {\n // We can't determine position on an element with display:none, so we \"show\" the dropdown with 0 opacity very temporarily\n element.style.opacity = 0;\n element.style.display = 'block';\n }\n\n if (!isInViewport({ element })) {\n // If the element isn't fully visible when dropping down, reverse the direction\n element.classList.add('reverse');\n }\n\n if (!isDropdownCurrentlyOpen) {\n // Revert the temporary changes to determine position\n element.style.removeProperty('display');\n element.style.removeProperty('opacity');\n }\n }\n};\n\n/**\n * Helper query string to identify interactive/focusable HTML elements\n */\nexport const INTERACTIVE_ELEMENTS_QUERY =\n 'button, [href], input:not([type=\"hidden\"]), select, textarea, [tabindex=\"0\"]';\n\n/**\n * Open the given dropdown, updating aria attributes, and focusing the first interactive element\n *\n * @param {Object} args\n * @param {string} args.triggerElementId The id of the button which activates the dropdown\n * @param {string} args.dropdownContent The id of the dropdown content element\n */\nexport const openDropdown = ({ triggerElementId, dropdownContentId }) => {\n const dropdownContent = document.getElementById(dropdownContentId);\n const triggerElement = document.getElementById(triggerElementId);\n\n triggerElement.setAttribute('aria-expanded', 'true');\n\n // Style set inline to prevent specificity issues\n dropdownContent.style.display = 'block';\n\n // Send focus to the first suitable element\n dropdownContent.querySelector(INTERACTIVE_ELEMENTS_QUERY)?.focus();\n};\n\n/**\n * Close the given dropdown, updating aria attributes\n *\n * @param {Object} args\n * @param {string} args.triggerElementId The id of the button which activates the dropdown\n * @param {string} args.dropdownContent The id of the dropdown content element\n * @param {Function} args.onClose Optional function for any side-effects which should occur on dropdown close\n */\nexport const closeDropdown = ({\n triggerElementId,\n dropdownContentId,\n onClose,\n}) => {\n const dropdownContent = document.getElementById(dropdownContentId);\n\n if (!dropdownContent) {\n // Component may have unmounted\n return;\n }\n\n document\n .getElementById(triggerElementId)\n ?.setAttribute('aria-expanded', 'false');\n\n // Remove the inline style added when we opened the dropdown\n dropdownContent.style.removeProperty('display');\n\n onClose?.();\n};\n\n/**\n * A helper function to initialize dropdown behaviors. This function attaches open/close click and keyup listeners,\n * and makes sure relevant aria properties and keyboard focus are updated.\n *\n * @param {Object} args\n * @param {string} args.triggerButtonElementId The ID of the button which triggers the dropdown open/close behavior\n * @param {string} args.dropdownContentId The ID of the dropdown content which should open/close on trigger button press\n * @param {string} args.dropdownContentCloseButtonId Optional ID of any button within the dropdown content which should close the dropdown\n * @param {Function} args.onClose An optional callback for when the dropdown is closed. This can be passed to execute any side-effects required when the dropdown closes.\n * @param {Function} args.onOpen An optional callback for when the dropdown is opened. This can be passed to execute any side-effects required when the dropdown opens.\n *\n * @returns {{closeDropdown: Function}} Object with callback to close the initialized dropdown\n */\nexport const initializeDropdown = ({\n triggerElementId,\n dropdownContentId,\n dropdownContentCloseButtonId,\n onClose,\n onOpen,\n}) => {\n const triggerButton = document.getElementById(triggerElementId);\n const dropdownContent = document.getElementById(dropdownContentId);\n\n if (!triggerButton || !dropdownContent) {\n // The required props haven't been provided, do nothing\n return;\n }\n\n // Ensure default values have been applied\n triggerButton.setAttribute('aria-expanded', 'false');\n triggerButton.setAttribute('aria-controls', dropdownContentId);\n triggerButton.setAttribute('aria-haspopup', 'true');\n\n const keyUpListener = ({ key }) => {\n if (key === 'Escape') {\n // Close the dropdown and return focus to the trigger button to prevent focus being lost\n const isCurrentlyOpen =\n triggerButton.getAttribute('aria-expanded') === 'true';\n if (isCurrentlyOpen) {\n closeDropdown({\n triggerElementId,\n dropdownContentId,\n onClose: onCloseCleanupActions,\n });\n triggerButton.focus();\n }\n } else if (key === 'Tab') {\n // Close the dropdown if the user has tabbed away from it\n const isInsideDropdown = dropdownContent?.contains(\n document.activeElement,\n );\n if (!isInsideDropdown) {\n closeDropdown({\n triggerElementId,\n dropdownContentId,\n onClose: onCloseCleanupActions,\n });\n }\n }\n };\n\n // Close the dropdown if user has clicked outside\n const clickOutsideListener = ({ target }) => {\n // Get fresh handle every time, resulting in more streamlined functionality for cypress\n const triggerButton = document.getElementById(triggerElementId);\n if (\n triggerButton &&\n target !== triggerButton &&\n !dropdownContent.contains(target) &&\n !triggerButton.contains(target)\n ) {\n closeDropdown({\n triggerElementId,\n dropdownContentId,\n onClose: onCloseCleanupActions,\n });\n\n // If the user did not click on another interactive item, return focus to the trigger\n if (!target.matches(INTERACTIVE_ELEMENTS_QUERY)) {\n triggerButton.focus();\n }\n }\n };\n\n // Any necessary side effects required on dropdown close\n const onCloseCleanupActions = () => {\n onClose?.();\n document.removeEventListener('keyup', keyUpListener);\n document.removeEventListener('click', clickOutsideListener);\n };\n\n // Add the main trigger button toggle functionality\n triggerButton.addEventListener('click', () => {\n if (\n document\n .getElementById(triggerElementId)\n ?.getAttribute('aria-expanded') === 'true'\n ) {\n closeDropdown({\n triggerElementId,\n dropdownContentId,\n onClose: onCloseCleanupActions,\n });\n } else {\n openDropdown({\n triggerElementId,\n dropdownContentId,\n });\n onOpen?.();\n\n document.addEventListener('keyup', keyUpListener);\n document.addEventListener('click', clickOutsideListener);\n }\n });\n\n if (dropdownContentCloseButtonId) {\n // The dropdown content has a 'close' button inside that we also need to handle\n document\n .getElementById(dropdownContentCloseButtonId)\n ?.addEventListener('click', () => {\n closeDropdown({\n triggerElementId,\n dropdownContentId,\n onClose: onCloseCleanupActions,\n });\n\n document.getElementById(triggerElementId)?.focus();\n });\n }\n\n return {\n closeDropdown: () => {\n closeDropdown({\n triggerElementId,\n dropdownContentId,\n onClose: onCloseCleanupActions,\n });\n },\n };\n};\n","import debounce from 'lodash.debounce';\n\n/**\n * A util function to wrap any action with lodash's `debounce` (https://lodash.com/docs/#debounce).\n * To use this util, wrap it in the util like so: debounceAction(onSearchBoxType.bind(this));\n *\n * By default, this util uses a default time of 300ms, and includes a default config of `{ leading: false }`.\n * These values can be overridden: debounceAction(this.onSearchBoxType.bind(this), { time: 100, config: { leading: true }});\n *\n *\n * @param {Function} action - The function that should be wrapped with `debounce`.\n * @param {Number} [time=300] - The number of milliseconds to wait.\n * @param {Object} [config={ leading: false }] - Any configuration for the debounce function.\n *\n * @returns {Function} A function wrapped in `debounce`.\n */\nexport function debounceAction(\n action,\n { time = 300, config = { leading: false } } = {},\n) {\n const configs = { ...config };\n return debounce(action, time, configs);\n}\n","export function getCsrfToken() {\n const element = document.querySelector(`meta[name='csrf-token']`);\n\n return element !== null ? element.content : undefined;\n}\n\nconst getWaitOnUserDataHandler = ({ resolve, reject, waitTime = 20 }) => {\n let totalTimeWaiting = 0;\n\n return function waitingOnUserData() {\n if (totalTimeWaiting === 3000) {\n reject(new Error(\"Couldn't find user data on page.\"));\n return;\n }\n\n const csrfToken = getCsrfToken(document);\n const { user } = document.body.dataset;\n\n if (user && csrfToken !== undefined) {\n const currentUser = JSON.parse(user);\n\n resolve({ currentUser, csrfToken });\n return;\n }\n\n totalTimeWaiting += waitTime;\n setTimeout(waitingOnUserData, waitTime);\n };\n};\n\nexport function getUserDataAndCsrfToken() {\n return new Promise((resolve, reject) => {\n getWaitOnUserDataHandler({ resolve, reject })();\n });\n}\n","var g;\n\n// This works in non-strict mode\ng = (function() {\n\treturn this;\n})();\n\ntry {\n\t// This works if eval is allowed (see CSP)\n\tg = g || new Function(\"return this\")();\n} catch (e) {\n\t// This works if the window reference is available\n\tif (typeof window === \"object\") g = window;\n}\n\n// g can still be undefined, but nothing to do about it...\n// We return undefined, instead of nothing here, so it's\n// easier to handle this case. if(!global) { ...}\n\nmodule.exports = g;\n","// eslint-disable-next-line consistent-return\nexport function handleFetchAPIErrors(response) {\n // pass along a correct response\n if (response.ok) {\n return response;\n }\n\n // API errors contain the error message in {\"error\": \"error message\"}\n // but they could be unhandled 500 errors\n try {\n response.json().then((data) => {\n throw new Error(data.error);\n });\n } catch (e) {\n if (e instanceof SyntaxError) {\n throw new Error(response.statusText);\n } else {\n throw e;\n }\n }\n}\n","/**\n * lodash (Custom Build) \n * Build: `lodash modularize exports=\"npm\" -o ./`\n * Copyright jQuery Foundation and other contributors \n * Released under MIT license \n * Based on Underscore.js 1.8.3 \n * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n */\n\n/** Used as the `TypeError` message for \"Functions\" methods. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/** Used as references for various `Number` constants. */\nvar NAN = 0 / 0;\n\n/** `Object#toString` result references. */\nvar symbolTag = '[object Symbol]';\n\n/** Used to match leading and trailing whitespace. */\nvar reTrim = /^\\s+|\\s+$/g;\n\n/** Used to detect bad signed hexadecimal string values. */\nvar reIsBadHex = /^[-+]0x[0-9a-f]+$/i;\n\n/** Used to detect binary string values. */\nvar reIsBinary = /^0b[01]+$/i;\n\n/** Used to detect octal string values. */\nvar reIsOctal = /^0o[0-7]+$/i;\n\n/** Built-in method references without a dependency on `root`. */\nvar freeParseInt = parseInt;\n\n/** Detect free variable `global` from Node.js. */\nvar freeGlobal = typeof global == 'object' && global && global.Object === Object && global;\n\n/** Detect free variable `self`. */\nvar freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n\n/** Used as a reference to the global object. */\nvar root = freeGlobal || freeSelf || Function('return this')();\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar objectToString = objectProto.toString;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeMax = Math.max,\n nativeMin = Math.min;\n\n/**\n * Gets the timestamp of the number of milliseconds that have elapsed since\n * the Unix epoch (1 January 1970 00:00:00 UTC).\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Date\n * @returns {number} Returns the timestamp.\n * @example\n *\n * _.defer(function(stamp) {\n * console.log(_.now() - stamp);\n * }, _.now());\n * // => Logs the number of milliseconds it took for the deferred invocation.\n */\nvar now = function() {\n return root.Date.now();\n};\n\n/**\n * Creates a debounced function that delays invoking `func` until after `wait`\n * milliseconds have elapsed since the last time the debounced function was\n * invoked. The debounced function comes with a `cancel` method to cancel\n * delayed `func` invocations and a `flush` method to immediately invoke them.\n * Provide `options` to indicate whether `func` should be invoked on the\n * leading and/or trailing edge of the `wait` timeout. The `func` is invoked\n * with the last arguments provided to the debounced function. Subsequent\n * calls to the debounced function return the result of the last `func`\n * invocation.\n *\n * **Note:** If `leading` and `trailing` options are `true`, `func` is\n * invoked on the trailing edge of the timeout only if the debounced function\n * is invoked more than once during the `wait` timeout.\n *\n * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred\n * until to the next tick, similar to `setTimeout` with a timeout of `0`.\n *\n * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)\n * for details over the differences between `_.debounce` and `_.throttle`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Function\n * @param {Function} func The function to debounce.\n * @param {number} [wait=0] The number of milliseconds to delay.\n * @param {Object} [options={}] The options object.\n * @param {boolean} [options.leading=false]\n * Specify invoking on the leading edge of the timeout.\n * @param {number} [options.maxWait]\n * The maximum time `func` is allowed to be delayed before it's invoked.\n * @param {boolean} [options.trailing=true]\n * Specify invoking on the trailing edge of the timeout.\n * @returns {Function} Returns the new debounced function.\n * @example\n *\n * // Avoid costly calculations while the window size is in flux.\n * jQuery(window).on('resize', _.debounce(calculateLayout, 150));\n *\n * // Invoke `sendMail` when clicked, debouncing subsequent calls.\n * jQuery(element).on('click', _.debounce(sendMail, 300, {\n * 'leading': true,\n * 'trailing': false\n * }));\n *\n * // Ensure `batchLog` is invoked once after 1 second of debounced calls.\n * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });\n * var source = new EventSource('/stream');\n * jQuery(source).on('message', debounced);\n *\n * // Cancel the trailing debounced invocation.\n * jQuery(window).on('popstate', debounced.cancel);\n */\nfunction debounce(func, wait, options) {\n var lastArgs,\n lastThis,\n maxWait,\n result,\n timerId,\n lastCallTime,\n lastInvokeTime = 0,\n leading = false,\n maxing = false,\n trailing = true;\n\n if (typeof func != 'function') {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n wait = toNumber(wait) || 0;\n if (isObject(options)) {\n leading = !!options.leading;\n maxing = 'maxWait' in options;\n maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;\n trailing = 'trailing' in options ? !!options.trailing : trailing;\n }\n\n function invokeFunc(time) {\n var args = lastArgs,\n thisArg = lastThis;\n\n lastArgs = lastThis = undefined;\n lastInvokeTime = time;\n result = func.apply(thisArg, args);\n return result;\n }\n\n function leadingEdge(time) {\n // Reset any `maxWait` timer.\n lastInvokeTime = time;\n // Start the timer for the trailing edge.\n timerId = setTimeout(timerExpired, wait);\n // Invoke the leading edge.\n return leading ? invokeFunc(time) : result;\n }\n\n function remainingWait(time) {\n var timeSinceLastCall = time - lastCallTime,\n timeSinceLastInvoke = time - lastInvokeTime,\n result = wait - timeSinceLastCall;\n\n return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result;\n }\n\n function shouldInvoke(time) {\n var timeSinceLastCall = time - lastCallTime,\n timeSinceLastInvoke = time - lastInvokeTime;\n\n // Either this is the first call, activity has stopped and we're at the\n // trailing edge, the system time has gone backwards and we're treating\n // it as the trailing edge, or we've hit the `maxWait` limit.\n return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||\n (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));\n }\n\n function timerExpired() {\n var time = now();\n if (shouldInvoke(time)) {\n return trailingEdge(time);\n }\n // Restart the timer.\n timerId = setTimeout(timerExpired, remainingWait(time));\n }\n\n function trailingEdge(time) {\n timerId = undefined;\n\n // Only invoke if we have `lastArgs` which means `func` has been\n // debounced at least once.\n if (trailing && lastArgs) {\n return invokeFunc(time);\n }\n lastArgs = lastThis = undefined;\n return result;\n }\n\n function cancel() {\n if (timerId !== undefined) {\n clearTimeout(timerId);\n }\n lastInvokeTime = 0;\n lastArgs = lastCallTime = lastThis = timerId = undefined;\n }\n\n function flush() {\n return timerId === undefined ? result : trailingEdge(now());\n }\n\n function debounced() {\n var time = now(),\n isInvoking = shouldInvoke(time);\n\n lastArgs = arguments;\n lastThis = this;\n lastCallTime = time;\n\n if (isInvoking) {\n if (timerId === undefined) {\n return leadingEdge(lastCallTime);\n }\n if (maxing) {\n // Handle invocations in a tight loop.\n timerId = setTimeout(timerExpired, wait);\n return invokeFunc(lastCallTime);\n }\n }\n if (timerId === undefined) {\n timerId = setTimeout(timerExpired, wait);\n }\n return result;\n }\n debounced.cancel = cancel;\n debounced.flush = flush;\n return debounced;\n}\n\n/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return !!value && (type == 'object' || type == 'function');\n}\n\n/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return !!value && typeof value == 'object';\n}\n\n/**\n * Checks if `value` is classified as a `Symbol` primitive or object.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.\n * @example\n *\n * _.isSymbol(Symbol.iterator);\n * // => true\n *\n * _.isSymbol('abc');\n * // => false\n */\nfunction isSymbol(value) {\n return typeof value == 'symbol' ||\n (isObjectLike(value) && objectToString.call(value) == symbolTag);\n}\n\n/**\n * Converts `value` to a number.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to process.\n * @returns {number} Returns the number.\n * @example\n *\n * _.toNumber(3.2);\n * // => 3.2\n *\n * _.toNumber(Number.MIN_VALUE);\n * // => 5e-324\n *\n * _.toNumber(Infinity);\n * // => Infinity\n *\n * _.toNumber('3.2');\n * // => 3.2\n */\nfunction toNumber(value) {\n if (typeof value == 'number') {\n return value;\n }\n if (isSymbol(value)) {\n return NAN;\n }\n if (isObject(value)) {\n var other = typeof value.valueOf == 'function' ? value.valueOf() : value;\n value = isObject(other) ? (other + '') : other;\n }\n if (typeof value != 'string') {\n return value === 0 ? value : +value;\n }\n value = value.replace(reTrim, '');\n var isBinary = reIsBinary.test(value);\n return (isBinary || reIsOctal.test(value))\n ? freeParseInt(value.slice(2), isBinary ? 2 : 8)\n : (reIsBadHex.test(value) ? NAN : +value);\n}\n\nmodule.exports = debounce;\n","const MAX_RETRIES = 30;\nconst RETRY_INTERVAL = 250;\n\nexport function getCSRFToken() {\n const promise = new Promise((resolve, reject) => {\n // eslint-disable-next-line consistent-return\n let i = 0;\n const waitingOnCSRF = setInterval(() => {\n const metaTag = document.querySelector(\"meta[name='csrf-token']\");\n i += 1;\n\n if (metaTag) {\n clearInterval(waitingOnCSRF);\n const authToken = metaTag.getAttribute('content');\n return resolve(authToken);\n }\n\n if (i === MAX_RETRIES) {\n clearInterval(waitingOnCSRF);\n Honeybadger.notify(\n `Could not locate CSRF metatag ${JSON.stringify(\n localStorage.current_user,\n )}`,\n );\n return reject(new Error('Could not locate CSRF meta tag on the page.'));\n }\n }, RETRY_INTERVAL);\n });\n return promise;\n}\n","import { getCSRFToken } from './csrfToken';\n\n/**\n * Generic request with all the default headers required by the application.\n *\n * @example\n * import { request } from '@utilities/http';\n *\n * const response = await request('/notification_subscriptions/Article/26')\n *\n * Note:\n * The body option will typically be passed in as a JavaScript object.\n * A check is performed for this and automatically convert it to JSON if necessary.\n *\n * Requests send JSON by default but this can be easily overridden by adding\n * the Accept and Content-Type headers to the request options.\n *\n * The default method is GET.\n *\n * @param {string} url The URL to make the request to.\n * @param {RequestInit} [options={}] The request options.\n *\n * @return {Promise} the response\n */\nexport async function request(url, options = {}) {\n const {\n headers,\n body,\n method = 'GET',\n csrfToken = await getCSRFToken(),\n // These are any other options that might be passed in e.g. keepalive\n ...restOfOptions\n } = options;\n\n // There should never be a scenario where null is passed as the body,\n // but if ever there is, this logic should change.\n const jsonifiedBody = {\n body: body && typeof body !== 'string' ? JSON.stringify(body) : body,\n };\n\n const fetchOptions = {\n method,\n headers: {\n Accept: 'application/json',\n 'X-CSRF-Token': csrfToken,\n 'Content-Type': 'application/json',\n ...headers,\n },\n credentials: 'same-origin',\n ...jsonifiedBody,\n ...restOfOptions,\n };\n\n return fetch(url, fetchOptions);\n}\n","/* global userData */\n/* eslint-disable no-alert, import/order */\nimport { request } from '@utilities/http';\nimport { getUserDataAndCsrfToken } from '@utilities/getUserDataAndCsrfToken';\n\nfunction addFlagUserBehavior(flagButton) {\n const { profileUserId, profileUserName } = flagButton.dataset;\n\n let isUserFlagged = flagButton.dataset.isUserFlagged === 'true';\n\n function flag() {\n const confirmFlag = window.confirm(\n isUserFlagged\n ? 'Are you sure you want to unflag this person? This will make all of their posts visible again.'\n : 'Are you sure you want to flag this person? This will make all of their posts less visible.',\n );\n\n if (confirmFlag) {\n request('/reactions', {\n method: 'POST',\n body: {\n reactable_type: 'User',\n category: 'vomit',\n reactable_id: profileUserId,\n },\n })\n .then((response) => response.json())\n .then((response) => {\n if (response.result === 'create') {\n isUserFlagged = true;\n flagButton.innerHTML = `Unflag ${profileUserName}`;\n } else {\n isUserFlagged = false;\n flagButton.innerHTML = `Flag ${profileUserName}`;\n }\n })\n .catch((e) => {\n Honeybadger.notify(\n isUserFlagged ? 'Unable to unflag user' : 'Unable to flag user',\n profileUserId,\n );\n window.alert(`Something went wrong: ${e}`);\n });\n }\n }\n\n flagButton.addEventListener('click', flag);\n}\n\n/**\n * Adds a flag button visible only to trusted users on profile pages.\n * @function initFlag\n * @returns {(void|undefined)} This function has no useable return value.\n */\n\nexport function initFlag() {\n const flagButton = document.getElementById(\n 'user-profile-dropdownmenu-flag-button',\n );\n\n if (!flagButton) {\n // button not always present when this is called\n return;\n }\n\n getUserDataAndCsrfToken().then(() => {\n const user = userData();\n if (!user) {\n flagButton.remove();\n return;\n }\n\n const trustedOrAdmin = user.trusted || user.admin;\n const { profileUserId } = flagButton.dataset;\n\n if (!trustedOrAdmin || user.id === parseInt(profileUserId, 10)) {\n flagButton.remove();\n }\n addFlagUserBehavior(flagButton);\n });\n}\n/* eslint-enable no-alert */\n","import { initBlock } from '../profileDropdown/blockButton';\nimport { initFlag } from '../profileDropdown/flagButton';\nimport { initializeDropdown } from '@utilities/dropdownUtils';\n\n/* global userData */\n\nfunction initButtons() {\n initBlock();\n initFlag();\n}\n\nfunction initDropdown() {\n const profileDropdownDiv = document.querySelector('.profile-dropdown');\n\n if (profileDropdownDiv.dataset.dropdownInitialized === 'true') {\n return;\n }\n const currentUser = userData();\n\n if (\n !profileDropdownDiv ||\n (currentUser &&\n currentUser.username === profileDropdownDiv.dataset.username)\n ) {\n // Hide this menu when user views their own profile\n return;\n }\n\n profileDropdownDiv.classList.remove('hidden');\n\n initializeDropdown({\n triggerElementId: 'user-profile-dropdown',\n dropdownContentId: 'user-profile-dropdownmenu',\n });\n\n // Add actual link location (SEO doesn't like these \"useless\" links, so adding in here instead of in HTML)\n const reportAbuseLink = profileDropdownDiv.querySelector(\n '.report-abuse-link-wrapper',\n );\n reportAbuseLink.innerHTML = `Report Abuse`;\n\n initButtons();\n profileDropdownDiv.dataset.dropdownInitialized = true;\n}\n\ninitDropdown();\n","/* eslint-disable no-alert */\n\nexport function initBlock() {\n const blockButton = document.getElementById(\n 'user-profile-dropdownmenu-block-button',\n );\n if (!blockButton) {\n // button not always present when this is called\n return;\n }\n const { profileUserId } = blockButton.dataset;\n\n function unblock() {\n fetch(`/user_blocks/${profileUserId}`, {\n method: 'DELETE',\n headers: {\n Accept: 'application/json',\n 'X-CSRF-Token': window.csrfToken,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n user_block: {\n blocked_id: profileUserId,\n },\n }),\n })\n .then((response) => response.json())\n .then((response) => {\n if (response.result === 'unblocked') {\n blockButton.innerText = 'Block';\n /* eslint-disable-next-line no-use-before-define */\n blockButton.addEventListener('click', block, { once: true });\n } else if (response.status === 422) {\n window.alert(\n `Something went wrong: ${response.error} -- Please refresh the page to try again.`,\n );\n }\n })\n .catch((e) => {\n window.alert(\n `Something went wrong: ${e}. -- Please refresh the page to try again.`,\n );\n });\n }\n\n function block() {\n const confirmBlock = window.confirm(\n `Are you sure you want to block this person? This will:\n - prevent them from commenting on your posts\n - block all notifications from them\n - hide their posts from your feed`,\n );\n if (confirmBlock) {\n fetch(`/user_blocks`, {\n method: 'POST',\n headers: {\n Accept: 'application/json',\n 'X-CSRF-Token': window.csrfToken,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n user_block: {\n blocked_id: profileUserId,\n },\n }),\n })\n .then((response) => response.json())\n .then((response) => {\n if (response.result === 'blocked') {\n blockButton.innerText = 'Unblock';\n blockButton.addEventListener('click', unblock, { once: true });\n } else if (response.status === 422) {\n window.alert(\n `Something went wrong: ${response.error}. -- Please refresh the page to try again.`,\n );\n }\n })\n .catch((e) => {\n window.alert(\n `Something went wrong: ${e}. -- Please refresh the page to try again.`,\n );\n });\n } else {\n blockButton.addEventListener('click', block, { once: true });\n }\n }\n\n // userData() is a global function\n /* eslint-disable-next-line no-undef */\n const user = userData();\n if (!user) {\n return;\n }\n\n if (user.id === parseInt(profileUserId, 10)) {\n blockButton.style.display = 'none';\n } else {\n fetch(`/user_blocks/${profileUserId}`)\n .then((response) => response.json())\n .then((response) => {\n if (response.result === 'blocking') {\n blockButton.innerText = 'Unblock';\n blockButton.addEventListener('click', unblock, { once: true });\n } else {\n blockButton.addEventListener('click', block, { once: true });\n }\n });\n }\n}\n\n/* eslint-enable no-alert */\n"],"sourceRoot":""}