functions.js 529 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653166541665516656166571665816659166601666116662166631666416665166661666716668166691667016671166721667316674166751667616677166781667916680166811668216683166841668516686166871668816689166901669116692166931669416695166961669716698166991670016701167021670316704167051670616707167081670916710167111671216713167141671516716167171671816719167201672116722167231672416725167261672716728167291673016731167321673316734167351673616737167381673916740167411674216743167441674516746167471674816749167501675116752167531675416755167561675716758167591676016761167621676316764167651676616767167681676916770167711677216773167741677516776167771677816779167801678116782167831678416785167861678716788167891679016791167921679316794167951679616797167981679916800168011680216803168041680516806168071680816809168101681116812168131681416815168161681716818168191682016821168221682316824168251682616827168281682916830168311683216833168341683516836168371683816839168401684116842168431684416845168461684716848168491685016851168521685316854168551685616857168581685916860168611686216863168641686516866168671686816869168701687116872168731687416875168761687716878168791688016881168821688316884168851688616887168881688916890168911689216893168941689516896168971689816899169001690116902169031690416905169061690716908169091691016911169121691316914169151691616917169181691916920169211692216923169241692516926169271692816929169301693116932169331693416935169361693716938169391694016941169421694316944169451694616947169481694916950169511695216953169541695516956169571695816959169601696116962169631696416965169661696716968169691697016971169721697316974169751697616977169781697916980169811698216983169841698516986169871698816989169901699116992169931699416995169961699716998169991700017001170021700317004170051700617007170081700917010170111701217013170141701517016170171701817019170201702117022170231702417025170261702717028170291703017031170321703317034170351703617037170381703917040170411704217043170441704517046170471704817049170501705117052170531705417055170561705717058170591706017061170621706317064170651706617067170681706917070170711707217073170741707517076170771707817079170801708117082170831708417085170861708717088170891709017091170921709317094170951709617097170981709917100171011710217103171041710517106171071710817109171101711117112171131711417115171161711717118171191712017121171221712317124171251712617127171281712917130171311713217133171341713517136171371713817139171401714117142171431714417145171461714717148171491715017151171521715317154171551715617157171581715917160171611716217163171641716517166171671716817169171701717117172171731717417175171761717717178171791718017181171821718317184171851718617187171881718917190171911719217193171941719517196171971719817199172001720117202172031720417205172061720717208172091721017211172121721317214172151721617217172181721917220172211722217223172241722517226172271722817229172301723117232172331723417235172361723717238172391724017241172421724317244172451724617247172481724917250172511725217253172541725517256172571725817259172601726117262172631726417265172661726717268172691727017271172721727317274172751727617277172781727917280172811728217283172841728517286172871728817289172901729117292172931729417295172961729717298172991730017301173021730317304173051730617307173081730917310173111731217313173141731517316173171731817319173201732117322173231732417325173261732717328173291733017331173321733317334173351733617337173381733917340173411734217343173441734517346173471734817349173501735117352173531735417355173561735717358173591736017361173621736317364173651736617367173681736917370173711737217373173741737517376173771737817379173801738117382173831738417385173861738717388173891739017391173921739317394173951739617397173981739917400
  1. // Create language switcher instance
  2. var lang = new Lang();
  3. var langStrings = { token: {} };
  4. loadLanguageList();
  5. var falbackLanguage =
  6. languageList.filter(
  7. (p) => p.code == language(moment.locale(navigator.languages[0]))
  8. ).length > 0
  9. ? language(moment.locale(navigator.languages[0]))
  10. : "en";
  11. lang.init({
  12. //defaultLang: 'en',
  13. currentLang: getCookie("organizrLanguage")
  14. ? getCookie("organizrLanguage")
  15. : falbackLanguage,
  16. cookie: {
  17. name: "organizrLanguage",
  18. expiry: 365,
  19. path: "/",
  20. },
  21. allowCookieOverride: true,
  22. });
  23. var OAuthLoginNeeded = false;
  24. var directToHash = false;
  25. var pingOrg = false;
  26. var checkCommitLoadStatus = false;
  27. var timeouts = {};
  28. var increment = 0;
  29. var tabInformation = {};
  30. var tabActionsList = [];
  31. tabActionsList["refresh"] = [];
  32. tabActionsList["close"] = [];
  33. var customHTMLEditorObject = [];
  34. $.xhrPool = [];
  35. // Add new jquery serializeObject function
  36. $.fn.serializeObject = function () {
  37. var o = {};
  38. var a = this.serializeArray();
  39. $.each(a, function () {
  40. if (o[this.name] !== undefined) {
  41. if (!o[this.name].push) {
  42. o[this.name] = [o[this.name]];
  43. }
  44. o[this.name].push(this.value || "");
  45. } else {
  46. o[this.name] = this.value || "";
  47. }
  48. });
  49. return o;
  50. };
  51. // Start Organizr
  52. $(document).ready(function () {
  53. if (getCookie("organizrOAuth")) {
  54. OAuthLoginNeeded = true;
  55. }
  56. launch();
  57. local("r", "loggingIn");
  58. });
  59. /* NORMAL FUNCTIONS */
  60. function setLangCookie(lang) {
  61. Cookies.set("organizrLanguage", lang, {
  62. expires: 365,
  63. path: "/",
  64. });
  65. }
  66. function highlightObject(json) {
  67. if (typeof json != "string") {
  68. json = JSON.stringify(json, undefined, "\t");
  69. }
  70. json = json
  71. .replace(/&/g, "&")
  72. .replace(/</g, "&lt;")
  73. .replace(/>/g, "&gt;");
  74. return json.replace(
  75. /("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g,
  76. function (match) {
  77. var cls = "number";
  78. if (/^"/.test(match)) {
  79. if (/:$/.test(match)) {
  80. cls = "key";
  81. } else {
  82. cls = "string";
  83. }
  84. } else if (/true|false/.test(match)) {
  85. cls = "boolean";
  86. } else if (/null/.test(match)) {
  87. cls = "null";
  88. }
  89. return '<span class="' + cls + '">' + match + "</span>";
  90. }
  91. );
  92. }
  93. function orgDebug() {
  94. let cmd = $("#debug-input").val();
  95. let result = "";
  96. if (cmd !== "") {
  97. result = eval(cmd);
  98. }
  99. if (result !== "") {
  100. $("#debugResultsBox").removeClass("hidden");
  101. $("#debugResults").html(formatDebug(result));
  102. $(".cmdName").text(cmd);
  103. if (bowser.mobile !== true) {
  104. $("#debugResults > .whitebox").slimScroll();
  105. }
  106. } else {
  107. }
  108. }
  109. function getDepth(object) {
  110. var level = 1;
  111. for (var key in object) {
  112. if (!object.hasOwnProperty(key)) continue;
  113. if (typeof object[key] == "object") {
  114. var depth = getDepth(object[key]) + 1;
  115. level = Math.max(depth, level);
  116. }
  117. }
  118. return level;
  119. }
  120. function jsonToHTML(json) {
  121. var html = "";
  122. $.each(json, function (i, v) {
  123. if (typeof v === "object") {
  124. html += '<p class="tab0">' + i + ":</p>";
  125. $.each(v, function (index, value) {
  126. if (typeof value === "object") {
  127. html += '<p class="tab1">' + index + ":</p>";
  128. html += jsonToHTML2(value);
  129. } else {
  130. html += '<p class="tab1">' + index + ": " + value + "</p>";
  131. }
  132. });
  133. } else {
  134. html += '<p class="tab0">' + i + ": " + v + "</p>";
  135. }
  136. });
  137. return html;
  138. }
  139. function jsonToHTML2(json) {
  140. var html = "";
  141. $.each(json, function (i, v) {
  142. if (typeof v === "object") {
  143. html += '<p class="tab2">' + i + ":</p>";
  144. $.each(v, function (index, value) {
  145. if (typeof value === "object") {
  146. html += '<p class="tab3">' + index + ":</p>";
  147. html += jsonToHTML3(value);
  148. } else {
  149. html += '<p class="tab3">' + index + ": " + value + "</p>";
  150. }
  151. });
  152. } else {
  153. html += '<p class="tab2">' + i + ": " + v + "</p>";
  154. }
  155. });
  156. return html;
  157. }
  158. function jsonToHTML3(json) {
  159. var html = "";
  160. $.each(json, function (i, v) {
  161. if (typeof v === "object") {
  162. html += '<p class="tab4">' + i + ":</p>";
  163. $.each(v, function (index, value) {
  164. if (typeof value === "object") {
  165. html += '<p class="tab5">' + index + ":</p>";
  166. html += jsonToHTML2(value);
  167. } else {
  168. html += '<p class="tab5">' + index + ": " + value + "</p>";
  169. }
  170. });
  171. } else {
  172. html += '<p class="tab4">' + i + ": " + v + "</p>";
  173. }
  174. });
  175. return html;
  176. }
  177. function copyDebug() {
  178. var pre = $("#debugPreInfo").find(".whitebox").text();
  179. var debug = $("#debugResults").find(".whitebox").text();
  180. clipboard(true, pre + debug);
  181. console.log(pre + debug);
  182. }
  183. function formatDebug(result) {
  184. var formatted = "";
  185. switch (typeof result) {
  186. case "object":
  187. formatted = jsonToHTML(result);
  188. break;
  189. default:
  190. formatted = result;
  191. }
  192. return (
  193. '<pre class="whitebox bg-org text-success default-scroller">' +
  194. formatted +
  195. "</pre>"
  196. );
  197. }
  198. function getDebugPreInfo() {
  199. var formatted =
  200. "Version: " +
  201. activeInfo.version +
  202. "<br/>Branch: " +
  203. activeInfo.branch +
  204. "<br/>Server OS: " +
  205. activeInfo.serverOS +
  206. "<br/>PHP: " +
  207. activeInfo.phpVersion +
  208. "<br/>Install Type: " +
  209. (activeInfo.settings.misc.docker ? "Official Docker" : "Native") +
  210. "<br/>Auth Type: " +
  211. activeInfo.settings.misc.authType +
  212. "<br/>Auth Backend: " +
  213. activeInfo.settings.misc.authBackend +
  214. "<br/>Installed Plugins: " +
  215. formatDebug(activeInfo.settings.misc.installedPlugins) +
  216. "<br/>Installed Themes: " +
  217. formatDebug(activeInfo.settings.misc.installedThemes) +
  218. "<br/>Theme: " +
  219. activeInfo.theme +
  220. "<br/>Local: " +
  221. activeInfo.settings.user.local +
  222. "<br/>oAuth: " +
  223. activeInfo.settings.user.oAuthLogin +
  224. "<br/>Agent: " +
  225. activeInfo.settings.user.agent;
  226. formatted =
  227. '<pre class="whitebox bg-org text-success">' + formatted + "</pre>";
  228. $("#debugPreInfo").html(formatted);
  229. if (bowser.mobile !== true) {
  230. $("#debugPreInfo > .whitebox").slimScroll();
  231. }
  232. }
  233. function orgDebugList(cmd) {
  234. if (cmd !== "") {
  235. $("#debug-input").val(cmd);
  236. orgDebug();
  237. }
  238. }
  239. function updateIssueLink(line) {
  240. let preNumber = line.match(/\S*\#(.*)/g);
  241. if (preNumber !== null) {
  242. preNumber = preNumber.toString();
  243. let numberSplit = preNumber.split("#");
  244. let issueType = numberSplit[0].replace("(", "").replace(")", "");
  245. let issueNumber = numberSplit[1].replace("(", "").replace(")", "");
  246. let issueWord =
  247. issueType.toLowerCase() == "fr"
  248. ? '<i class="icon-arrow-up-circle"></i> feature'
  249. : '<i class="fa fa-github"></i> issue';
  250. let colorType =
  251. issueType.toLowerCase() == "fr" ? "label-info" : "label-primary";
  252. let issueLink =
  253. issueType.toLowerCase() == "fr"
  254. ? "https://feature.organizr.app/posts/" + issueNumber
  255. : "https://github.com/causefx/Organizr/issues/" + issueNumber;
  256. issueLink =
  257. '<span class="label upgrade-label text-uppercase ' +
  258. colorType +
  259. ' label-rounded font-12 pull-right"><a class="text-white text-uppercase" href="' +
  260. issueLink +
  261. '" target="_blank">' +
  262. issueWord +
  263. "</a></span>";
  264. return line.replace(preNumber, issueLink);
  265. } else {
  266. return line;
  267. }
  268. }
  269. function clipboard(trigger = true, string = null) {
  270. let clipboard = $("#internal-clipboard");
  271. if (string) {
  272. clipboard.attr("data-clipboard-text", string);
  273. }
  274. if (trigger) {
  275. clipboard.click();
  276. }
  277. }
  278. function getLangStrings() {
  279. let strings = JSON.stringify(window.langStrings, null, "\t");
  280. clipboard(true, strings);
  281. organizrConsole("JSON Function", "Copied JSON Strings to clipboard");
  282. }
  283. function getHiddenProp() {
  284. var prefixes = ["webkit", "moz", "ms", "o"];
  285. // if 'hidden' is natively supported just return it
  286. if ("hidden" in document) return "hidden";
  287. // otherwise loop over all the known prefixes until we find one
  288. for (var i = 0; i < prefixes.length; i++) {
  289. if (prefixes[i] + "Hidden" in document) return prefixes[i] + "Hidden";
  290. }
  291. // otherwise it's not supported
  292. return null;
  293. }
  294. function isHidden() {
  295. var prop = getHiddenProp();
  296. if (!prop) return false;
  297. return document[prop];
  298. }
  299. function loadLanguageList() {
  300. $.each(languageList, function (i, v) {
  301. lang.dynamic(v.code, "js/langpack/" + v.filename);
  302. });
  303. }
  304. function sleep(ms) {
  305. return new Promise((resolve) => setTimeout(resolve, ms));
  306. }
  307. function contains(target, pattern) {
  308. var value = 0;
  309. pattern.forEach(function (word) {
  310. value = value + target.includes(word);
  311. });
  312. return value === 1;
  313. }
  314. function isNumberKey(evt) {
  315. var charCode = evt.which ? evt.which : event.keyCode;
  316. if (charCode < 48 || charCode > 57) return false;
  317. return true;
  318. }
  319. function setTabInfo(id, action, value) {
  320. let tabInfo = findTab(id);
  321. if (!tabInfo) {
  322. organizrConsole("Set Tab Info", "No Tab Info Found... Id: " + id, "error");
  323. return false;
  324. }
  325. let tab = cleanClass(tabInfo.name);
  326. if (
  327. tab == "Organizr-Support" ||
  328. tab == "Organizr-Docs" ||
  329. tab == "Feature-Request"
  330. ) {
  331. return false;
  332. }
  333. if (tab !== null && action !== null && value !== null) {
  334. switch (action) {
  335. case "active":
  336. $.each(tabInformation, function (i, v) {
  337. tabInformation[i]["active"] = false;
  338. });
  339. break;
  340. default:
  341. //nada
  342. }
  343. tabInformation[id][action] = value;
  344. } else {
  345. return false;
  346. }
  347. }
  348. function tabTimerAction() {
  349. if (tabActionsList.close.length > 0) {
  350. $.each(tabActionsList.close, function (i, v) {
  351. var tab = v.tab;
  352. var minutes = tabInformation[v.id]["tabInfo"]["timeout_ms"] / 1000 / 60;
  353. var process = false;
  354. if (tabInformation[v.id]["loaded"]) {
  355. if (tabInformation[v.id]["active"] && idleTime >= 1) {
  356. process = true;
  357. }
  358. if (tabInformation[v.id]["active"] === false) {
  359. process = true;
  360. }
  361. if (process) {
  362. tabInformation[v.id]["increments"] =
  363. tabInformation[v.id]["increments"] + 1;
  364. if (tabInformation[v.id]["increments"] >= minutes) {
  365. tabInformation[v.id]["increments"] = 0;
  366. organizrConsole("Tab Function", "Auto Closing tab: " + tab);
  367. closeTab(v.id);
  368. }
  369. }
  370. }
  371. });
  372. }
  373. if (tabActionsList.refresh.length > 0) {
  374. $.each(tabActionsList.refresh, function (i, v) {
  375. var tab = v.tab;
  376. var minutes = tabInformation[v.id]["tabInfo"]["timeout_ms"] / 1000 / 60;
  377. var process = false;
  378. if (tabInformation[v.id]["loaded"]) {
  379. tabInformation[v.id]["increments"] =
  380. tabInformation[v.id]["increments"] + 1;
  381. if (tabInformation[v.id]["increments"] >= minutes) {
  382. tabInformation[v.id]["increments"] = 0;
  383. organizrConsole("Tab Function", "Auto Reloading tab: " + tab);
  384. reloadTab(v.id);
  385. }
  386. }
  387. });
  388. }
  389. }
  390. function timerIncrement() {
  391. increment = increment + 1;
  392. tabTimerAction();
  393. //check for cookieExpiry
  394. if (hasCookie) {
  395. if (getCookie("organizrToken")) {
  396. //do nothing
  397. } else {
  398. location.reload();
  399. }
  400. }
  401. idleTime = idleTime + 1;
  402. if (typeof activeInfo !== "undefined") {
  403. if (
  404. activeInfo.settings.lockout.enabled &&
  405. activeInfo.settings.user.oAuthLogin !== true
  406. ) {
  407. if (
  408. idleTime > activeInfo.settings.lockout.timer &&
  409. $("#lockScreen").length !== 1
  410. ) {
  411. if (
  412. activeInfo.user.groupID <= activeInfo.settings.lockout.minGroup &&
  413. activeInfo.user.groupID >= activeInfo.settings.lockout.maxGroup
  414. ) {
  415. lock();
  416. }
  417. }
  418. }
  419. }
  420. }
  421. function ajaxblocker(
  422. element = null,
  423. action = "out",
  424. message = "Loading...",
  425. background = "#707cd2",
  426. border = "#5761a9",
  427. colorText = "#fff"
  428. ) {
  429. switch (action) {
  430. case "in":
  431. case "fadein":
  432. $(element).block({
  433. message:
  434. '<p style="margin:0;padding:8px;font-size:24px;" lang="en">' +
  435. message +
  436. "</p>",
  437. css: {
  438. color: colorText,
  439. border: "1px solid " + border,
  440. backgroundColor: background,
  441. },
  442. });
  443. break;
  444. case "out":
  445. case "fadeout":
  446. $(element).unblock();
  447. break;
  448. default:
  449. $(element).unblock();
  450. }
  451. }
  452. function ajaxloader(element = null, action = "out") {
  453. var loader = `
  454. <div class="ajaxloader">
  455. <svg class="circular" viewBox="25 25 50 50">
  456. <circle class="path" cx="50" cy="50" fill="none" r="20" stroke-miterlimit="10" stroke-width="5"></circle>
  457. </svg>
  458. </div>`;
  459. switch (action) {
  460. case "in":
  461. case "fadein":
  462. $(loader).appendTo(element);
  463. break;
  464. case "out":
  465. case "fadeout":
  466. $(".ajaxloader").remove();
  467. break;
  468. default:
  469. $(".ajaxloader").remove();
  470. }
  471. }
  472. function getDefault(id) {
  473. let tabInfo = findTab(id);
  474. if (!tabInfo) {
  475. if (getHash() === false) {
  476. organizrConsole("Get Default", "No Tab Info Found... Id: " + id, "error");
  477. organizrConsole(
  478. "Get Default",
  479. "Trying to load next tab in cycle",
  480. "error"
  481. );
  482. loadNextTab(true);
  483. return false;
  484. }
  485. }
  486. if (
  487. getHash() === false ||
  488. (getHash() === "OrganizrLogin" && activeInfo.user.loggedin)
  489. ) {
  490. if (tabInfo) {
  491. switchTab(id);
  492. } else {
  493. $(".allTabsList").first().children().click();
  494. }
  495. } else if (getHash() == "OrganizrLogin") {
  496. loadNextTab(true);
  497. } else {
  498. let hashTab = getHash();
  499. let hashType = isNaN(hashTab) ? "name" : "id";
  500. let tabInfo = findTab(hashTab, hashType);
  501. if (!tabInfo) {
  502. organizrConsole(
  503. "Get Hash",
  504. "No Tab Info Found... Hash: " + hashTab,
  505. "error"
  506. );
  507. switchTab(id);
  508. return false;
  509. }
  510. let type = tabInfo.type;
  511. if (typeof hashTab !== "undefined" && typeof type !== "undefined") {
  512. directToHash = true;
  513. switchTab(tabInfo.id);
  514. } else {
  515. console.warn("Tab Function: " + hashTab + " is not a defined tab");
  516. switchTab(id);
  517. }
  518. }
  519. }
  520. function getTabType(id) {
  521. let tabInfo = findTab(id);
  522. if (!tabInfo) {
  523. organizrConsole(
  524. "Tab Type Function",
  525. "No Tab Info Found... Id: " + id,
  526. "error"
  527. );
  528. return false;
  529. }
  530. return tabInfo.type;
  531. }
  532. function getHash() {
  533. if ($(location).attr("hash")) {
  534. return dirtyHash($(location).attr("hash").substr(1));
  535. }
  536. return false;
  537. }
  538. function setHash(hash) {
  539. window.location.hash = "#" + cleanHash(hash);
  540. }
  541. function getQueryVariable(variable) {
  542. var query = window.location.search.substring(1);
  543. var vars = query.split("&");
  544. for (var i = 0; i < vars.length; i++) {
  545. var pair = vars[i].split("=");
  546. if (pair[0] == variable) {
  547. return pair[1];
  548. }
  549. }
  550. return false;
  551. }
  552. function iconPrefix(source) {
  553. var tabIcon = source.split("::");
  554. var icons = {
  555. materialize: "mdi mdi-",
  556. fontawesome: "fa fa-",
  557. themify: "ti-",
  558. simpleline: "icon-",
  559. weathericon: "wi wi-",
  560. alphanumeric: "fa-fw",
  561. };
  562. if (Array.isArray(tabIcon) && tabIcon.length === 2) {
  563. if (tabIcon[0] !== "url" && tabIcon[0] !== "alphanumeric") {
  564. return '<i class="' + icons[tabIcon[0]] + tabIcon[1] + ' fa-fw"></i>';
  565. } else if (tabIcon[0] == "alphanumeric") {
  566. return '<i class="fa-fw">' + tabIcon[1] + "</i>";
  567. } else {
  568. return '<img class="fa-fw" src="' + tabIcon[1] + '" alt="tabIcon" />';
  569. }
  570. } else {
  571. return '<img class="fa-fw" src="' + source + '" alt="tabIcon" />';
  572. }
  573. }
  574. function iconPrefixSplash(source) {
  575. var tabIcon = source.split("::");
  576. var icons = {
  577. materialize: "mdi mdi-",
  578. fontawesome: "fa fa-",
  579. themify: "ti-",
  580. simpleline: "icon-",
  581. weathericon: "wi wi-",
  582. alphanumeric: "fa-fw",
  583. };
  584. if (Array.isArray(tabIcon) && tabIcon.length === 2) {
  585. if (tabIcon[0] !== "url" && tabIcon[0] !== "alphanumeric") {
  586. return '<i class="' + icons[tabIcon[0]] + tabIcon[1] + ' fa-fw"></i>';
  587. } else if (tabIcon[0] == "alphanumeric") {
  588. return '<i class="fa-fw">' + tabIcon[1] + "</i>";
  589. } else {
  590. return tabIcon[1];
  591. }
  592. } else {
  593. return source;
  594. }
  595. }
  596. function cleanClass(string) {
  597. return string.replace(/ +/g, "-").replace(/\W+/g, "-");
  598. }
  599. function cleanHash(hash) {
  600. hash = encodeURI(hash);
  601. return hash.replaceAll("%20", "-");
  602. }
  603. function dirtyHash(hash) {
  604. hash = hash.replaceAll("-", "%20");
  605. return decodeURI(hash);
  606. }
  607. // What the hell is this? I don't remember this lol
  608. function noTabs(arrayItems) {
  609. if (arrayItems.data.user.loggedin === true) {
  610. organizrAPI2("GET", "api/v2/page/tabs")
  611. .success(function (data) {
  612. try {
  613. var json = data.response;
  614. organizrConsole("Organizr Function", "No tabs available");
  615. $(json.data).appendTo($(".organizr-area"));
  616. $(".organizr-area").removeClass("hidden");
  617. $("#preloader").fadeOut();
  618. } catch (e) {
  619. organizrCatchError(e, data);
  620. }
  621. })
  622. .fail(function (xhr) {
  623. OrganizrApiError(xhr, "Error");
  624. });
  625. } else {
  626. $(".show-login").trigger("click");
  627. }
  628. }
  629. function formatImage(icon) {
  630. if (!icon.id || icon.text == "Select or type Image") {
  631. return icon.text;
  632. }
  633. var baseUrl = "/user/pages/images/flags";
  634. var $icon = $(
  635. '<span><img src="' +
  636. icon.id +
  637. '" class="img-chooser" /> ' +
  638. icon.text +
  639. "</span>"
  640. );
  641. return $icon;
  642. }
  643. function formatIcon(icon) {
  644. if (!icon.id || icon.text == "Select or type Icon") {
  645. return icon.text;
  646. }
  647. var $icon = $("<span>" + iconPrefix(icon.id) + icon.text + "</span>");
  648. return $icon;
  649. }
  650. function logout() {
  651. message(
  652. "",
  653. " Goodbye!",
  654. activeInfo.settings.notifications.position,
  655. "#FFF",
  656. "success",
  657. "10000"
  658. );
  659. organizrAPI2("GET", "api/v2/logout")
  660. .success(function (data) {
  661. local("set", "message", "Goodbye|Logout Successful|success");
  662. history.replaceState(null, null, " ");
  663. if (
  664. activeInfo.settings.misc.authProxyOverrideLogout &&
  665. activeInfo.settings.misc.authProxyLogoutURL !== ""
  666. ) {
  667. location.href = activeInfo.settings.misc.authProxyLogoutURL;
  668. } else {
  669. location.reload();
  670. }
  671. })
  672. .fail(function (xhr) {
  673. OrganizrApiError(xhr, "Logout Failed");
  674. });
  675. }
  676. function reloadOrganizr() {
  677. location.reload();
  678. }
  679. function hideFrames(split = null) {
  680. let extra = split ? "-right" : "";
  681. $(".iFrame-listing" + extra + " div[class^='frame-container']")
  682. .addClass("hidden")
  683. .removeClass("show");
  684. $(".internal-listing" + extra + " div[class^='internal-container']")
  685. .addClass("hidden")
  686. .removeClass("show");
  687. $(".plugin-listing" + extra + " div[class^='plugin-container']")
  688. .addClass("hidden")
  689. .removeClass("show");
  690. }
  691. function closeSideMenu() {
  692. $(".content-wrapper").removeClass("show-sidebar");
  693. }
  694. function removeMenuActive() {
  695. $("#side-menu a").removeClass("active");
  696. }
  697. function swapDisplay(type, split) {
  698. let extra = split ? "-right" : "";
  699. switch (type) {
  700. case "internal":
  701. $("body").removeClass("fix-header");
  702. $(".iFrame-listing" + extra)
  703. .addClass("hidden")
  704. .removeClass("show");
  705. $(".internal-listing" + extra)
  706. .addClass("show")
  707. .removeClass("hidden");
  708. $(".login-area").addClass("hidden").removeClass("show");
  709. $(".plugin-listing" + extra)
  710. .addClass("hidden")
  711. .removeClass("show");
  712. //$('body').removeClass('fix-header');
  713. if (split) {
  714. $("#page-wrapper").addClass("split");
  715. $("#page-wrapper-right").removeClass("hidden");
  716. }
  717. break;
  718. case "iframe":
  719. $("body").addClass("fix-header");
  720. $(".iFrame-listing" + extra)
  721. .addClass("show")
  722. .removeClass("hidden");
  723. $(".internal-listing" + extra)
  724. .addClass("hidden")
  725. .removeClass("show");
  726. $(".login-area").addClass("hidden").removeClass("show");
  727. $(".plugin-listing" + extra)
  728. .addClass("hidden")
  729. .removeClass("show");
  730. //$('body').addClass('fix-header');
  731. if (split) {
  732. $("#page-wrapper").addClass("split");
  733. $("#page-wrapper-right").removeClass("hidden");
  734. }
  735. break;
  736. case "login":
  737. $("body").removeClass("fix-header");
  738. $(".iFrame-listing" + extra)
  739. .addClass("hidden")
  740. .removeClass("show");
  741. $(".internal-listing" + extra)
  742. .addClass("hidden")
  743. .removeClass("show");
  744. $(".login-area").addClass("show").removeClass("hidden");
  745. $(".plugin-listing" + extra)
  746. .addClass("hidden")
  747. .removeClass("show");
  748. if (activeInfo.settings.misc.minimalLoginScreen == true) {
  749. $(".sidebar").addClass("hidden");
  750. $(".navbar").addClass("hidden");
  751. $("#page-wrapper").addClass("hidden");
  752. }
  753. if (split) {
  754. $("#page-wrapper").addClass("split");
  755. $("#page-wrapper-right").removeClass("hidden");
  756. }
  757. break;
  758. case "plugin":
  759. $(".iFrame-listing" + extra)
  760. .addClass("hidden")
  761. .removeClass("show");
  762. $(".internal-listing" + extra)
  763. .addClass("hidden")
  764. .removeClass("show");
  765. $(".login-area").addClass("hidden").removeClass("show");
  766. $(".plugin-listing" + extra)
  767. .addClass("show")
  768. .removeClass("hidden");
  769. if (split) {
  770. $("#page-wrapper").addClass("split");
  771. $("#page-wrapper-right").removeClass("hidden");
  772. }
  773. break;
  774. default:
  775. }
  776. }
  777. function toggleParentActive(id) {
  778. var childTab = $("#menu-" + id);
  779. if (childTab.parent().hasClass("nav-second-level")) {
  780. if (!childTab.parent().hasClass("in")) {
  781. childTab.parent().addClass("collapse in");
  782. childTab.parent().parent().addClass("active");
  783. }
  784. }
  785. }
  786. function swapBodyClass(id) {
  787. let tabInfo = findTab(id);
  788. if (!tabInfo) {
  789. organizrConsole("Swap Body", "No Tab Info Found... Id: " + id, "error");
  790. return false;
  791. }
  792. let prior = $("body").attr("data-active-tab");
  793. let priorId = $("body").attr("data-active-tab-id");
  794. if (prior !== "") {
  795. $("body").removeClass("active-tab-" + prior);
  796. $("body").removeClass("active-tab-" + priorId);
  797. }
  798. $("body").attr("data-active-tab", tabInfo.name);
  799. $("body").attr("data-active-tab-id", tabInfo.id);
  800. $("body").addClass("active-tab-" + tabInfo.name);
  801. $("body").addClass("active-tab-" + tabInfo.id);
  802. }
  803. function editPageTitle(title) {
  804. document.title = title + " - " + activeInfo.appearance.title;
  805. }
  806. function switchToPlugin(plugin) {
  807. closeSideMenu();
  808. removeMenuActive();
  809. swapDisplay("plugin");
  810. $(".plugin-container").each(function () {
  811. $(this).addClass("hidden").removeClass("show");
  812. });
  813. $("#container-plugin-" + plugin)
  814. .addClass("show")
  815. .removeClass("hidden");
  816. }
  817. function switchTab(id, split = null) {
  818. let tabInfo = findTab(id);
  819. if (!tabInfo) {
  820. organizrConsole("Switch Tab", "No Tab Info Found... Id: " + id, "error");
  821. return false;
  822. }
  823. if (activeInfo.settings.misc.collapseSideMenuOnClick) {
  824. if (!$(".navbar ").hasClass("sidebar-hidden")) {
  825. toggleSideMenu();
  826. }
  827. }
  828. let extra = split ? "right-" : "";
  829. let type = tabInfo.type;
  830. // need to rework for split
  831. if (type !== 2) {
  832. hideFrames(split);
  833. closeSideMenu();
  834. removeMenuActive();
  835. toggleParentActive(id);
  836. swapBodyClass(id);
  837. }
  838. if (type !== 2 && type !== "plugin") {
  839. setHash(tabInfo.name);
  840. }
  841. switch (type) {
  842. case 0:
  843. case "0":
  844. case "internal":
  845. swapDisplay("internal", split);
  846. var newTab = $("#internal-" + extra + id);
  847. $("#menu-" + id)
  848. .find("a")
  849. .addClass("active");
  850. editPageTitle(tabInfo.name);
  851. if (newTab.hasClass("loaded")) {
  852. organizrConsole("Tab Function", "Switching to tab: " + tabInfo.name);
  853. newTab.addClass("show").removeClass("hidden");
  854. setTabInfo(id, "active", true);
  855. } else {
  856. //$("#preloader").fadeIn();
  857. organizrConsole("Tab Function", "Loading new tab for: " + tabInfo.name);
  858. $("#menu-" + id + " a")
  859. .children()
  860. .addClass("tabLoaded");
  861. newTab.addClass("show loaded").removeClass("hidden");
  862. loadInternal(id, split);
  863. setTabInfo(id, "active", true);
  864. setTabInfo(id, "loaded", true);
  865. //$("#preloader").fadeOut();
  866. }
  867. break;
  868. case 1:
  869. case "1":
  870. case "iframe":
  871. swapDisplay("iframe", split);
  872. var newTab = $("#container-" + extra + id);
  873. var tabURL = newTab.attr("data-url");
  874. $("#menu-" + id)
  875. .find("a")
  876. .addClass("active");
  877. editPageTitle(tabInfo.name);
  878. if (newTab.hasClass("loaded")) {
  879. organizrConsole("Tab Function", "Switching to tab: " + tabInfo.name);
  880. newTab.addClass("show").removeClass("hidden");
  881. setTabInfo(id, "active", true);
  882. } else {
  883. $("#preloader").fadeIn();
  884. organizrConsole("Tab Function", "Loading new tab for: " + tabInfo.name);
  885. $("#menu-" + id + " a")
  886. .children()
  887. .addClass("tabLoaded");
  888. newTab.addClass("show loaded").removeClass("hidden");
  889. $(buildFrame(id, extra)).appendTo(newTab);
  890. setTabInfo(id, "active", true);
  891. setTabInfo(id, "loaded", true);
  892. $("#preloader").fadeOut();
  893. }
  894. $("#frame-" + id).focus();
  895. break;
  896. case 2:
  897. case 3:
  898. case "2":
  899. case "3":
  900. case "_blank":
  901. case "popout":
  902. popTab(id);
  903. break;
  904. case "plugin":
  905. swapDisplay("plugin");
  906. $("#container-plugin-" + id)
  907. .addClass("show")
  908. .removeClass("hidden");
  909. break;
  910. default:
  911. organizrConsole("Tab Function", "Action not set", "error");
  912. }
  913. }
  914. function popTab(id) {
  915. let tabInfo = findTab(id);
  916. if (!tabInfo) {
  917. organizrConsole(
  918. "Pop Tab Function",
  919. "No Tab Info Found... Id: " + id,
  920. "error"
  921. );
  922. return false;
  923. }
  924. let name = tabInfo.name;
  925. switch (tabInfo.type) {
  926. case 0:
  927. case "0":
  928. case "internal":
  929. console.warn(
  930. "Tab Function: New window not supported for tab id: " +
  931. id +
  932. " | " +
  933. name
  934. );
  935. break;
  936. case 1:
  937. case "1":
  938. case "iframe":
  939. case 2:
  940. case 3:
  941. case "2":
  942. case "3":
  943. case "_blank":
  944. case "popout":
  945. organizrConsole(
  946. "Tab Function",
  947. "Creating New Window for tab id: " + id + " | " + name
  948. );
  949. window.open(tabInfo.access_url, "_blank");
  950. break;
  951. default:
  952. organizrConsole("Tab Function", "Action not set", "error");
  953. }
  954. }
  955. function closeTab(id) {
  956. let tabInfo = findTab(id);
  957. if (!tabInfo) {
  958. organizrConsole(
  959. "Close Tab Function",
  960. "No Tab Info Found... Id: " + id,
  961. "error"
  962. );
  963. return false;
  964. }
  965. // check if current tab?
  966. if ($(".active-tab-" + id).length > 0) {
  967. closeCurrentTab(event);
  968. } else {
  969. if ($(".frame-" + id).hasClass("loaded")) {
  970. switch (tabInfo.type) {
  971. case 0:
  972. case "0":
  973. case "internal":
  974. // quick check if homepage
  975. if (tabInfo.access_url == "api/v2/page/homepage") {
  976. organizrConsole(
  977. "Organizr Function",
  978. "Clearing All Homepage AJAX calls"
  979. );
  980. clearAJAX("homepage");
  981. $.xhrPool.abortAll();
  982. }
  983. organizrConsole("Tab Function", "Closing tab: " + tabInfo.name);
  984. $("#internal-" + id).html("");
  985. $("#menu-" + id + " a").removeClass("active");
  986. $("#menu-" + id + " a")
  987. .children()
  988. .removeClass("tabLoaded");
  989. $("#internal-" + id).removeClass("loaded show");
  990. $("#menu-" + id).removeClass("active");
  991. setTabInfo(id, "loaded", false);
  992. break;
  993. case 1:
  994. case "1":
  995. case "iframe":
  996. organizrConsole("Tab Function", "Closing tab: " + tab);
  997. $("#menu-" + id + " a").removeClass("active");
  998. $("#menu-" + id + " a")
  999. .children()
  1000. .removeClass("tabLoaded");
  1001. $("#container-" + id).removeClass("loaded show");
  1002. $("#frame-" + id).remove();
  1003. setTabInfo(id, "loaded", false);
  1004. break;
  1005. case 2:
  1006. case 3:
  1007. case "2":
  1008. case "3":
  1009. case "_blank":
  1010. case "popout":
  1011. break;
  1012. default:
  1013. organizrConsole("Tab Function", "Action not set", "error");
  1014. }
  1015. }
  1016. }
  1017. }
  1018. function reloadTab(id) {
  1019. let tabInfo = findTab(id);
  1020. if (!tabInfo) {
  1021. organizrConsole(
  1022. "Reload Tab Function",
  1023. "No Tab Info Found... Id: " + id,
  1024. "error"
  1025. );
  1026. return false;
  1027. }
  1028. $("#preloader").fadeIn();
  1029. organizrConsole("Tab Function", "Reloading tab: " + tabInfo.name);
  1030. switch (tabInfo.type) {
  1031. case 0:
  1032. case "0":
  1033. case "internal":
  1034. if (tabInfo.access_url == "api/v2/page/homepage") {
  1035. organizrConsole(
  1036. "Organizr Function",
  1037. "Clearing All Homepage AJAX calls"
  1038. );
  1039. clearAJAX("homepage");
  1040. $.xhrPool.abortAll();
  1041. }
  1042. $("#frame-" + id).html("");
  1043. loadInternal(id);
  1044. break;
  1045. case 1:
  1046. case "1":
  1047. case "iframe":
  1048. $("#frame-" + id).attr("src", $("#frame-" + id).attr("src"));
  1049. break;
  1050. case 2:
  1051. case 3:
  1052. case "2":
  1053. case "3":
  1054. case "_blank":
  1055. case "popout":
  1056. break;
  1057. default:
  1058. organizrConsole("Tab Function", "Action not set", "error");
  1059. }
  1060. $("#preloader").fadeOut();
  1061. }
  1062. function reloadCurrentTab() {
  1063. //$("#preloader").fadeIn();
  1064. organizrConsole("Tab Function", "Reloading Current tab");
  1065. let id = null;
  1066. let iframe = $(".iFrame-listing").find(".show");
  1067. let internal = $(".internal-listing").find(".show");
  1068. if (iframe.length > 0) {
  1069. var type = "iframe";
  1070. } else if (internal.length > 0) {
  1071. var type = "internal";
  1072. } else {
  1073. var type = "not set";
  1074. }
  1075. switch (type) {
  1076. case 0:
  1077. case "0":
  1078. case "internal":
  1079. let activeInternal = $(".internal-listing").find(".show");
  1080. if (activeInternal) {
  1081. id = activeInternal.attr("id");
  1082. id = id.split("-")[1];
  1083. }
  1084. if (id) {
  1085. var tabInfo = findTab(id);
  1086. if (!tabInfo) {
  1087. organizrConsole(
  1088. "Reload Current Tab Function",
  1089. "No Tab Info Found... Id: " + id,
  1090. "error"
  1091. );
  1092. return false;
  1093. }
  1094. } else {
  1095. return false;
  1096. }
  1097. if (tabInfo.access_url == "api/v2/page/homepage") {
  1098. organizrConsole(
  1099. "Organizr Function",
  1100. "Clearing All Homepage AJAX calls"
  1101. );
  1102. clearAJAX("homepage");
  1103. $.xhrPool.abortAll();
  1104. }
  1105. $(activeInternal).html("");
  1106. loadInternal(id);
  1107. break;
  1108. case 1:
  1109. case "1":
  1110. case "iframe":
  1111. let activeFrame = $(".iFrame-listing").find(".show").children("iframe");
  1112. if (RegExp("^/.*").test(activeFrame.attr("src"))) {
  1113. activeFrame.attr("src", activeFrame[0].contentWindow.location.pathname);
  1114. } else {
  1115. activeFrame.attr("src", activeFrame.attr("src"));
  1116. }
  1117. break;
  1118. case 2:
  1119. case 3:
  1120. case "2":
  1121. case "3":
  1122. case "_blank":
  1123. case "popout":
  1124. break;
  1125. default:
  1126. console.error("Tab Function: Action not set");
  1127. }
  1128. //$("#preloader").fadeOut();
  1129. }
  1130. function loadNextTab(loadNextTabIfNotLoaded = false) {
  1131. let next = $("#page-wrapper").find(".loaded").attr("id");
  1132. if (next) {
  1133. next = next.split("-")[1];
  1134. }
  1135. if (typeof next !== "undefined") {
  1136. let parent = $("#menu-" + next).parent();
  1137. if (
  1138. parent.hasClass("in") === false &&
  1139. parent.hasClass("nav-second-level")
  1140. ) {
  1141. parent.parent().find("a").first().trigger("click");
  1142. }
  1143. switchTab(next);
  1144. } else {
  1145. if (loadNextTabIfNotLoaded) {
  1146. if (findTab(0, "type")) {
  1147. var id = findTab(0, "type")["id"];
  1148. } else {
  1149. var id = findTab(1, "type")["id"];
  1150. }
  1151. tabActions(1, id);
  1152. } else {
  1153. organizrConsole("Tab Function", "No Available Tab to open", "error");
  1154. }
  1155. }
  1156. }
  1157. function closeCurrentTab(event) {
  1158. let extra = "";
  1159. let split = "";
  1160. if (typeof event !== "undefined") {
  1161. if (event.ctrlKey && event.altKey && !event.shiftKey) {
  1162. extra = "-right";
  1163. split = true;
  1164. }
  1165. }
  1166. if ($(".plugin-listing").hasClass("show")) {
  1167. hideFrames(split);
  1168. loadNextTab();
  1169. return false;
  1170. }
  1171. let id = $("body").attr("data-active-tab-id");
  1172. let tabInfo = findTab(id);
  1173. if (!tabInfo) {
  1174. organizrConsole(
  1175. "Close Current Tab Function",
  1176. "No Tab Info Found... Id: " + id,
  1177. "error"
  1178. );
  1179. return false;
  1180. }
  1181. var iframe = $(".iFrame-listing" + extra).find(".show");
  1182. var internal = $(".internal-listing" + extra).find(".show");
  1183. if (iframe.length > 0) {
  1184. var type = "iframe";
  1185. } else if (internal.length > 0) {
  1186. var type = "internal";
  1187. } else {
  1188. var type = "not set";
  1189. }
  1190. switch (type) {
  1191. case 0:
  1192. case "0":
  1193. case "internal":
  1194. // quick check if homepage
  1195. if (tabInfo.access_url == "api/v2/page/homepage") {
  1196. organizrConsole(
  1197. "Organizr Function",
  1198. "Clearing All Homepage AJAX calls"
  1199. );
  1200. clearAJAX("homepage");
  1201. $.xhrPool.abortAll();
  1202. }
  1203. organizrConsole("Organizr Function", "Closing tab: " + tabInfo.name);
  1204. $("#internal" + extra + "-" + id).html("");
  1205. $("#menu-" + id + " a").removeClass("active");
  1206. $("#menu-" + id + " a")
  1207. .children()
  1208. .removeClass("tabLoaded");
  1209. $("#internal" + extra + "-" + id).removeClass("loaded show");
  1210. $("#menu-" + id).removeClass("active");
  1211. setTabInfo(id, "loaded", false);
  1212. setTabInfo(id, "active", false);
  1213. loadNextTab();
  1214. break;
  1215. case 1:
  1216. case "1":
  1217. case "iframe":
  1218. organizrConsole("Organizr Function", "Closing tab: " + tabInfo.name);
  1219. $("#menu-" + id + " a").removeClass("active");
  1220. $("#menu-" + id + " a")
  1221. .children()
  1222. .removeClass("tabLoaded");
  1223. $("#container" + extra + "-" + id)
  1224. .removeClass("loaded show")
  1225. .addClass("hidden");
  1226. $("#frame" + extra + "-" + id).remove();
  1227. setTabInfo(id, "loaded", false);
  1228. setTabInfo(id, "active", false);
  1229. loadNextTab();
  1230. break;
  1231. case 2:
  1232. case 3:
  1233. case "2":
  1234. case "3":
  1235. case "_blank":
  1236. case "popout":
  1237. break;
  1238. default:
  1239. organizrConsole("Tab Function", "No Available Tab to open", "error");
  1240. }
  1241. }
  1242. function openInNewBrowserTab() {
  1243. let id = $("body").attr("data-active-tab-id");
  1244. let tabInfo = findTab(id);
  1245. if (!tabInfo) {
  1246. organizrConsole(
  1247. "Open In New Browser Tab Function",
  1248. "No Tab Info Found... Id: " + id,
  1249. "error"
  1250. );
  1251. return false;
  1252. }
  1253. let url = tabInfo.access_url;
  1254. window.open(url, "_blank");
  1255. }
  1256. function findTab(query, term = "id") {
  1257. let tabInfo = activeInfo.tabs.filter((tab) => tab[term] == query);
  1258. return tabInfo.length >= 1 ? tabInfo[0] : false;
  1259. }
  1260. function tabActions(event, id, redirectURL = "") {
  1261. if (event.which == 3) {
  1262. return false;
  1263. }
  1264. let tabInfo = findTab(id);
  1265. if (!tabInfo) {
  1266. organizrConsole(
  1267. "Tab Action Function",
  1268. "No Tab Info Found... Id: " + id,
  1269. "error"
  1270. );
  1271. return false;
  1272. }
  1273. let type = tabInfo.type;
  1274. let name = tabInfo.name;
  1275. if ((event.ctrlKey && !event.shiftKey && !event.altKey) || event.which == 2) {
  1276. popTab(id);
  1277. } else if (event.altKey && !event.shiftKey && !event.ctrlKey) {
  1278. closeTab(id);
  1279. } else if (event.shiftKey && !event.ctrlKey && !event.altKey) {
  1280. reloadTab(id);
  1281. } else if (event.ctrlKey && event.shiftKey && !event.altKey) {
  1282. organizrConsole("Tab Function", "Action not defined yet", "info");
  1283. } else if (event.ctrlKey && event.altKey && !event.shiftKey) {
  1284. organizrConsole("Tab Function", "Action not defined yet", "info");
  1285. switchTab(id, true);
  1286. } else if (event.shiftKey && event.altKey && !event.ctrlKey) {
  1287. organizrConsole("Tab Function", "Action not defined yet", "info");
  1288. } else {
  1289. switchTab(id);
  1290. if (type !== 2) {
  1291. $(".splash-screen").removeClass("in").addClass("hidden");
  1292. }
  1293. if (redirectURL) {
  1294. $(".close-popup").trigger("click");
  1295. $("#frame-" + id).attr("src", redirectURL);
  1296. }
  1297. }
  1298. }
  1299. function reverseObject(object) {
  1300. var newObject = {};
  1301. var keys = [];
  1302. for (var key in object) {
  1303. keys.push(key);
  1304. }
  1305. for (var i = keys.length - 1; i >= 0; i--) {
  1306. var value = object[keys[i]];
  1307. newObject[keys[i]] = value;
  1308. }
  1309. return newObject;
  1310. }
  1311. function hasValue(test) {
  1312. if (Array.isArray(test) && test[0] !== "") {
  1313. return true;
  1314. } else {
  1315. return false;
  1316. }
  1317. }
  1318. function arrayContains(needle, arrhaystack) {
  1319. return arrhaystack.indexOf(needle) > -1;
  1320. }
  1321. /* END NORMAL FUNCTIONS */
  1322. /* BUILD FUNCTIONS */
  1323. /* END BUILD FUNCTIONS */
  1324. /* ORGANIZR API FUNCTIONS */
  1325. function selectOptions(options, active) {
  1326. var selectOptions = "";
  1327. $.each(options, function (i, v) {
  1328. activeTest = active.split(",");
  1329. if (activeTest.length > 1) {
  1330. var selected = arrayContains(v.value, activeTest) ? "selected" : "";
  1331. } else {
  1332. var selected = active.toString() == v.value ? "selected" : "";
  1333. }
  1334. var disabled = v.disabled ? " disabled" : "";
  1335. selectOptions +=
  1336. "<option " +
  1337. selected +
  1338. disabled +
  1339. ' value="' +
  1340. v.value +
  1341. '">' +
  1342. v.name +
  1343. "</option>";
  1344. });
  1345. return selectOptions;
  1346. }
  1347. function accordionOptions(options, parentID) {
  1348. var accordionOptions = "";
  1349. $.each(options, function (i, v) {
  1350. var id = v.id;
  1351. var extraClass = v.class ? " " + v.class : "";
  1352. var header = v.header ? " " + v.header : "";
  1353. if (typeof v.body == "object") {
  1354. if (typeof v.body.length == "undefined") {
  1355. var body = buildFormItem(v.body);
  1356. } else {
  1357. var body = "";
  1358. $.each(v.body, function (int, val) {
  1359. body += buildFormItem(val);
  1360. });
  1361. }
  1362. } else {
  1363. var body = v.body;
  1364. }
  1365. accordionOptions +=
  1366. `
  1367. <div class="panel">
  1368. <div class="panel-heading" id="` +
  1369. id +
  1370. `-heading" role="tab">
  1371. <a class="panel-title collapsed" data-toggle="collapse" href="#` +
  1372. id +
  1373. `-collapse" data-parent="#` +
  1374. parentID +
  1375. `" aria-expanded="false" aria-controls="` +
  1376. id +
  1377. `-collapse"><span lang="en">` +
  1378. header +
  1379. `</span></a>
  1380. </div>
  1381. <div class="panel-collapse collapse" id="` +
  1382. id +
  1383. `-collapse" aria-labelledby="` +
  1384. id +
  1385. `-heading" role="tabpanel" aria-expanded="false" style="height: 0px;">
  1386. <div class="panel-body">` +
  1387. body +
  1388. `</div>
  1389. </div>
  1390. </div>
  1391. `;
  1392. });
  1393. return accordionOptions;
  1394. }
  1395. function buildAccordion(array, open = false) {
  1396. var items = "";
  1397. var mainId = createRandomString(10);
  1398. $.each(array, function (i, v) {
  1399. var collapse = open && i == 0 ? "collapse in" : "collapse";
  1400. var collapsed = open && i == 0 ? "" : "collapsed";
  1401. var id = mainId + "-" + i;
  1402. items +=
  1403. `
  1404. <div class="panel">
  1405. <div class="panel-heading bg-org" id="` +
  1406. id +
  1407. `-heading" role="tab"> <a class="panel-title ` +
  1408. collapsed +
  1409. `" data-toggle="collapse" href="#` +
  1410. id +
  1411. `-collapse" data-parent="#` +
  1412. mainId +
  1413. `" aria-expanded="false" aria-controls="` +
  1414. id +
  1415. `-collapse"> <span lang="en">` +
  1416. v.title +
  1417. `</span> </a> </div>
  1418. <div class="panel-collapse ` +
  1419. collapse +
  1420. `" id="` +
  1421. id +
  1422. `-collapse" aria-labelledby="` +
  1423. id +
  1424. `-heading" role="tabpanel">
  1425. <div class="panel-body" lang="en"> ` +
  1426. v.body +
  1427. ` </div>
  1428. </div>
  1429. </div>
  1430. `;
  1431. });
  1432. return (
  1433. '<div class="panel-group" id="' +
  1434. mainId +
  1435. '" aria-multiselectable="true" role="tablist">' +
  1436. items +
  1437. "</div>"
  1438. );
  1439. }
  1440. function buildFormItem(item) {
  1441. var placeholder = item.placeholder
  1442. ? ' placeholder="' + item.placeholder + '"'
  1443. : "";
  1444. var id = item.id ? ' id="' + item.id + '"' : "";
  1445. var type = item.type ? ' data-type="' + item.type + '"' : "";
  1446. var label = item.label ? ' data-label="' + item.label + '"' : "";
  1447. var value = item.value ? ' value="' + item.value + '"' : "";
  1448. var textarea = item.value ? item.value : "";
  1449. var name = item.name ? ' name="' + item.name + '"' : "";
  1450. var extraClass = item.class ? " " + item.class : "";
  1451. var icon = item.icon ? " " + item.icon : "";
  1452. var text = item.text ? " " + item.text : "";
  1453. var attr = item.attr ? " " + item.attr : "";
  1454. var disabled = item.disabled ? " disabled" : "";
  1455. var href = item.href ? ' href="' + item.href + '"' : "";
  1456. var pwd1 = createRandomString(6);
  1457. var pwd2 = createRandomString(6);
  1458. var pwd3 = createRandomString(6);
  1459. var helpInfo = item.help
  1460. ? '<div class="collapse" id="help-info-' +
  1461. item.name +
  1462. '"><blockquote lang="en">' +
  1463. item.help +
  1464. "</blockquote></div>"
  1465. : "";
  1466. var smallLabel = item.smallLabel
  1467. ? '<label><span lang="en">' + item.smallLabel + "</span></label>" + helpInfo
  1468. : "" + helpInfo;
  1469. var pwgMgr =
  1470. `
  1471. <input name="disable-pwd-mgr-` +
  1472. pwd1 +
  1473. `" type="password" id="disable-pwd-mgr-` +
  1474. pwd1 +
  1475. `" style="display: none;" value="disable-pwd-mgr-` +
  1476. pwd1 +
  1477. `" />
  1478. <input name="disable-pwd-mgr-` +
  1479. pwd2 +
  1480. `" type="password" id="disable-pwd-mgr-` +
  1481. pwd2 +
  1482. `" style="display: none;" value="disable-pwd-mgr-` +
  1483. pwd2 +
  1484. `" />
  1485. <input name="disable-pwd-mgr-` +
  1486. pwd3 +
  1487. `" type="password" id="disable-pwd-mgr-` +
  1488. pwd3 +
  1489. `" style="display: none;" value="disable-pwd-mgr-` +
  1490. pwd3 +
  1491. `" />
  1492. `;
  1493. //+tof(item.value,'c')+`
  1494. switch (item.type) {
  1495. case "select-input":
  1496. return (
  1497. smallLabel +
  1498. '<input list="' +
  1499. item.name +
  1500. 'Options" data-changed="false" lang="en" type="text" class="form-control' +
  1501. extraClass +
  1502. '"' +
  1503. placeholder +
  1504. value +
  1505. id +
  1506. name +
  1507. disabled +
  1508. type +
  1509. label +
  1510. attr +
  1511. ' autocomplete="new-password" /><datalist id="' +
  1512. item.name +
  1513. 'Options">' +
  1514. selectOptions(item.options, item.value) +
  1515. "</datalist>"
  1516. );
  1517. case "input":
  1518. case "text":
  1519. return (
  1520. smallLabel +
  1521. '<input data-changed="false" lang="en" type="text" class="form-control' +
  1522. extraClass +
  1523. '"' +
  1524. placeholder +
  1525. value +
  1526. id +
  1527. name +
  1528. disabled +
  1529. type +
  1530. label +
  1531. attr +
  1532. ' autocomplete="new-password" />'
  1533. );
  1534. case "number":
  1535. return (
  1536. smallLabel +
  1537. '<input data-changed="false" lang="en" type="number" class="form-control' +
  1538. extraClass +
  1539. '"' +
  1540. placeholder +
  1541. value +
  1542. id +
  1543. name +
  1544. disabled +
  1545. type +
  1546. label +
  1547. attr +
  1548. ' autocomplete="new-password" />'
  1549. );
  1550. case "textbox":
  1551. return (
  1552. smallLabel +
  1553. '<textarea data-changed="false" class="form-control' +
  1554. extraClass +
  1555. '"' +
  1556. placeholder +
  1557. id +
  1558. name +
  1559. disabled +
  1560. type +
  1561. label +
  1562. attr +
  1563. ' autocomplete="new-password">' +
  1564. textarea +
  1565. "</textarea>"
  1566. );
  1567. case "password":
  1568. return (
  1569. smallLabel +
  1570. pwgMgr +
  1571. '<input data-changed="false" lang="en" type="password" class="form-control' +
  1572. extraClass +
  1573. '"' +
  1574. placeholder +
  1575. value +
  1576. id +
  1577. name +
  1578. disabled +
  1579. type +
  1580. label +
  1581. attr +
  1582. ' autocomplete="new-password" />'
  1583. );
  1584. case "password-alt":
  1585. return (
  1586. smallLabel +
  1587. '<div class="input-group">' +
  1588. pwgMgr +
  1589. '<input data-changed="false" lang="en" type="password" class="password-alt form-control' +
  1590. extraClass +
  1591. '"' +
  1592. placeholder +
  1593. value +
  1594. id +
  1595. name +
  1596. disabled +
  1597. type +
  1598. label +
  1599. attr +
  1600. ' autocomplete="new-password" /><span class="input-group-btn"> <button class="btn btn-default showPassword" type="button"><i class="fa fa-eye passwordToggle"></i></button></span></div>'
  1601. );
  1602. case "password-alt-copy":
  1603. return (
  1604. smallLabel +
  1605. '<div class="input-group">' +
  1606. pwgMgr +
  1607. '<input data-changed="false" lang="en" type="password" class="password-alt form-control' +
  1608. extraClass +
  1609. '"' +
  1610. placeholder +
  1611. value +
  1612. id +
  1613. name +
  1614. disabled +
  1615. type +
  1616. label +
  1617. attr +
  1618. ' autocomplete="new-password" /><span class="input-group-btn"> <button class="btn btn-primary clipboard" type="button" data-clipboard-text="' +
  1619. item.value +
  1620. '"><i class="fa icon-docs"></i></button></span><span class="input-group-btn"> <button class="btn btn-inverse showPassword" type="button"><i class="fa fa-eye passwordToggle"></i></button></span></div>'
  1621. );
  1622. case "hidden":
  1623. return (
  1624. '<input data-changed="false" lang="en" type="hidden" class="form-control' +
  1625. extraClass +
  1626. '"' +
  1627. placeholder +
  1628. value +
  1629. id +
  1630. name +
  1631. disabled +
  1632. type +
  1633. label +
  1634. attr +
  1635. " />"
  1636. );
  1637. case "select":
  1638. return (
  1639. smallLabel +
  1640. '<select data-changed="false" class="form-control' +
  1641. extraClass +
  1642. '"' +
  1643. placeholder +
  1644. value +
  1645. id +
  1646. name +
  1647. disabled +
  1648. type +
  1649. label +
  1650. attr +
  1651. ">" +
  1652. selectOptions(item.options, item.value) +
  1653. "</select>"
  1654. );
  1655. case "select2":
  1656. var select2ID = item.id ? "#" + item.id : "." + item.name;
  1657. let settings = item.settings ? item.settings : "{}";
  1658. return (
  1659. smallLabel +
  1660. '<select class="m-b-10 ' +
  1661. extraClass +
  1662. '"' +
  1663. placeholder +
  1664. value +
  1665. id +
  1666. name +
  1667. disabled +
  1668. type +
  1669. label +
  1670. attr +
  1671. ' multiple="multiple" data-placeholder="">' +
  1672. selectOptions(item.options, item.value) +
  1673. '</select><script>$("' +
  1674. select2ID +
  1675. '").select2(' +
  1676. settings +
  1677. ').on("select2:unselecting", function() { $(this).data("unselecting", true); }).on("select2:opening", function(e) { if ($(this).data("unselecting")) { $(this).removeData("unselecting"); e.preventDefault(); } });</script>'
  1678. );
  1679. case "switch":
  1680. case "checkbox":
  1681. return (
  1682. smallLabel +
  1683. '<input data-changed="false" type="checkbox" class="js-switch' +
  1684. extraClass +
  1685. '" data-size="medium" data-color="#99d683" data-secondary-color="#f96262"' +
  1686. name +
  1687. value +
  1688. tof(item.value, "c") +
  1689. id +
  1690. disabled +
  1691. type +
  1692. label +
  1693. attr +
  1694. ' /><input data-changed="false" type="hidden"' +
  1695. name +
  1696. 'value="false">'
  1697. );
  1698. case "button":
  1699. return (
  1700. smallLabel +
  1701. '<button class="btn btn-sm btn-success btn-rounded waves-effect waves-light b-none' +
  1702. extraClass +
  1703. '" ' +
  1704. href +
  1705. attr +
  1706. ' type="button"><span class="btn-label"><i class="' +
  1707. icon +
  1708. '"></i></span><span lang="en">' +
  1709. text +
  1710. "</span></button>"
  1711. );
  1712. case "blank":
  1713. return "";
  1714. case "accordion":
  1715. return (
  1716. '<div class="panel-group' +
  1717. extraClass +
  1718. '"' +
  1719. placeholder +
  1720. value +
  1721. id +
  1722. name +
  1723. disabled +
  1724. type +
  1725. label +
  1726. attr +
  1727. ' aria-multiselectable="true" role="tablist">' +
  1728. accordionOptions(item.options, item.id) +
  1729. "</div>"
  1730. );
  1731. case "html":
  1732. return item.html;
  1733. case "arrayMultiple":
  1734. return '<span class="text-danger">BuildFormItem Class not setup...';
  1735. case "cron":
  1736. return `${smallLabel}<div class="input-group"><input data-changed="false" class="form-control ${extraClass}" ${placeholder} ${value} ${id} ${name} ${disabled} ${type} ${label} ${attr} autocomplete="new-password"><span class="input-group-btn"><button class="btn btn-info test-cron" type="button"><i class="fa fa-flask"></i></button></span></div>`;
  1737. case "folder":
  1738. return `${smallLabel}<div class="input-group"><input data-changed="false" class="form-control ${extraClass}" ${placeholder} ${value} ${id} ${name} ${disabled} ${type} ${label} ${attr} autocomplete="new-password"><span class="input-group-btn"><button class="btn btn-info test-folder" type="button"><i class="fa fa-flask"></i></button></span></div>`;
  1739. default:
  1740. return '<span class="text-danger">BuildFormItem Class not setup...';
  1741. }
  1742. }
  1743. function checkCronFile() {
  1744. $(".cron-results-container").removeClass("hidden");
  1745. organizrAPI2("GET", "api/v2/test/cron")
  1746. .success(function (data) {
  1747. try {
  1748. $(".cron-results").text("Cron file is setup correctly");
  1749. } catch (e) {
  1750. $(".cron-results").text("Unknown error");
  1751. organizrCatchError(e, data);
  1752. }
  1753. })
  1754. .fail(function (xhr) {
  1755. $(".cron-results").text("Cron file is not setup or is setup incorrectly");
  1756. OrganizrApiError(xhr);
  1757. });
  1758. }
  1759. function buildPluginsItem(array, type = "enabled") {
  1760. var activePlugins = "";
  1761. var inactivePlugins = "";
  1762. $.each(array, function (i, v) {
  1763. var settingsPage =
  1764. v.settings == true && type == "enabled"
  1765. ? `
  1766. <!-- Plugin Settings Page -->
  1767. <form id="` +
  1768. v.idPrefix +
  1769. `-settings-page" class="mfp-hide white-popup mfp-with-anim addFormTick col-md-10 col-md-offset-1" autocomplete="off">
  1770. <div class="panel bg-org panel-info">
  1771. <div class="panel-heading">
  1772. <span lang="en">` +
  1773. v.name +
  1774. ` Settings</span>
  1775. <button type="button" class="btn bg-org btn-circle close-popup pull-right"><i class="fa fa-times"></i> </button>
  1776. <button id="` +
  1777. v.idPrefix +
  1778. `-settings-page-save" onclick="submitSettingsForm('` +
  1779. v.idPrefix +
  1780. `-settings-page')" class="btn btn-sm btn-info btn-rounded waves-effect waves-light pull-right hidden animated loop-animation rubberBand m-r-20" type="button"><span class="btn-label"><i class="fa fa-save"></i></span><span lang="en">Save</span></button>
  1781. </div>
  1782. <div class="panel-wrapper collapse in" aria-expanded="true">
  1783. <div class="bg-org">
  1784. <fieldset id="` +
  1785. v.idPrefix +
  1786. `-settings-items" style="border:0;" class=""><h2>Loading...</h2></fieldset>
  1787. </div>
  1788. <div class="clearfix"></div>
  1789. </div>
  1790. </div>
  1791. </form>
  1792. `
  1793. : "";
  1794. var href =
  1795. v.settings == true
  1796. ? "#" + v.idPrefix + "-settings-page"
  1797. : "javascript:void(0);";
  1798. if (v.enabled == true) {
  1799. var activeToggle =
  1800. `<li><a class="btn default btn-outline disablePlugin" href="javascript:void(0);" data-plugin-name="` +
  1801. v.name +
  1802. `" data-config-prefix="` +
  1803. v.configPrefix +
  1804. `" data-config-name="` +
  1805. v.configPrefix +
  1806. `-enabled"><i class="ti-power-off fa-2x"></i></a></li>`;
  1807. var settings =
  1808. `<li><a class="btn default btn-outline popup-with-form" href="` +
  1809. href +
  1810. `" data-effect="mfp-3d-unfold"data-plugin-name="` +
  1811. v.name +
  1812. `" id="` +
  1813. v.idPrefix +
  1814. `-settings-button" data-config-prefix="` +
  1815. v.configPrefix +
  1816. `" data-api="${v.api}" data-settings="${v.settings}" data-bind="${v.bind}"><i class="ti-panel fa-2x"></i></a></li>`;
  1817. } else {
  1818. var activeToggle =
  1819. `<li><a class="btn default btn-outline enablePlugin" href="javascript:void(0);" data-plugin-name="` +
  1820. v.name +
  1821. `" data-config-prefix="` +
  1822. v.configPrefix +
  1823. `" data-config-name="` +
  1824. v.configPrefix +
  1825. `-enabled"><i class="ti-plug fa-2x"></i></a></li>`;
  1826. var settings = "";
  1827. }
  1828. var plugin =
  1829. `
  1830. <div class="col-lg-2 col-md-2 col-sm-6 col-xs-6 m-b-10">
  1831. <div class="white-box m-0">
  1832. <div class="el-card-item p-0">
  1833. <div class="el-card-avatar el-overlay-1 m-0"> <img class="lazyload" data-src="` +
  1834. v.image +
  1835. `">
  1836. <div class="el-overlay">
  1837. <ul class="el-info">
  1838. ${settings} ${activeToggle}
  1839. </ul>
  1840. </div>
  1841. </div>
  1842. <div class="el-card-content">
  1843. <h3 class="box-title elip">` +
  1844. v.name +
  1845. `</h3>
  1846. <small class="elip text-uppercase p-b-10">` +
  1847. v.category +
  1848. `</small>
  1849. </div>
  1850. </div>
  1851. </div>
  1852. </div>
  1853. `;
  1854. if (v.enabled == true) {
  1855. activePlugins += plugin + settingsPage;
  1856. } else {
  1857. inactivePlugins += plugin + settingsPage;
  1858. }
  1859. });
  1860. activePlugins =
  1861. activePlugins.length !== 0
  1862. ? activePlugins
  1863. : '<h2 class="text-center" lang="en">Nothing Active</h2>';
  1864. inactivePlugins =
  1865. inactivePlugins.length !== 0
  1866. ? inactivePlugins
  1867. : '<h2 class="text-center" lang="en">Everything Active</h2>';
  1868. return type === "enabled"
  1869. ? `
  1870. <div class="panel bg-org panel-info">
  1871. <div class="panel-heading">
  1872. <span lang="en">Active Plugins</span>
  1873. </div>
  1874. <div class="panel-wrapper collapse in" aria-expanded="true">
  1875. <div class="panel-body bg-org">
  1876. <div class="row el-element-overlay m-b-40">` +
  1877. activePlugins +
  1878. `</div>
  1879. </div>
  1880. </div>
  1881. </div>
  1882. <div class="clearfix"></div>`
  1883. : `
  1884. <div class="panel bg-org panel-info">
  1885. <div class="panel-heading">
  1886. <span lang="en">Inactive Plugins</span>
  1887. </div>
  1888. <div class="panel-wrapper collapse in" aria-expanded="true">
  1889. <div class="panel-body bg-org">
  1890. <div class="row el-element-overlay m-b-40">` +
  1891. inactivePlugins +
  1892. `</div>
  1893. </div>
  1894. </div>
  1895. </div>`;
  1896. }
  1897. function buildPluginsItemOld(array) {
  1898. var activePlugins = "";
  1899. var inactivePlugins = "";
  1900. $.each(array, function (i, v) {
  1901. var settingsPage =
  1902. v.settings == true
  1903. ? `
  1904. <!-- Plugin Settings Page -->
  1905. <form id="` +
  1906. v.idPrefix +
  1907. `-settings-page" class="mfp-hide white-popup mfp-with-anim addFormTick col-md-10 col-md-offset-1" autocomplete="off">
  1908. <div class="panel bg-org panel-info">
  1909. <div class="panel-heading">
  1910. <span lang="en">` +
  1911. v.name +
  1912. ` Settings</span>
  1913. <button type="button" class="btn bg-org btn-circle close-popup pull-right"><i class="fa fa-times"></i> </button>
  1914. <button id="` +
  1915. v.idPrefix +
  1916. `-settings-page-save" onclick="submitSettingsForm('` +
  1917. v.idPrefix +
  1918. `-settings-page')" class="btn btn-sm btn-info btn-rounded waves-effect waves-light pull-right hidden animated loop-animation rubberBand m-r-20" type="button"><span class="btn-label"><i class="fa fa-save"></i></span><span lang="en">Save</span></button>
  1919. </div>
  1920. <div class="panel-wrapper collapse in" aria-expanded="true">
  1921. <div class="bg-org">
  1922. <fieldset id="` +
  1923. v.idPrefix +
  1924. `-settings-items" style="border:0;" class=""><h2>Loading...</h2></fieldset>
  1925. </div>
  1926. <div class="clearfix"></div>
  1927. </div>
  1928. </div>
  1929. </form>
  1930. `
  1931. : "";
  1932. var href =
  1933. v.settings == true
  1934. ? "#" + v.idPrefix + "-settings-page"
  1935. : "javascript:void(0);";
  1936. if (v.enabled == true) {
  1937. var activeToggle =
  1938. `<li><a class="btn default btn-outline disablePlugin" href="javascript:void(0);" data-plugin-name="` +
  1939. v.name +
  1940. `" data-config-prefix="` +
  1941. v.configPrefix +
  1942. `" data-config-name="` +
  1943. v.configPrefix +
  1944. `-enabled"><i class="ti-power-off fa-2x"></i></a></li>`;
  1945. var settings =
  1946. `<li><a class="btn default btn-outline popup-with-form" href="` +
  1947. href +
  1948. `" data-effect="mfp-3d-unfold"data-plugin-name="` +
  1949. v.name +
  1950. `" id="` +
  1951. v.idPrefix +
  1952. `-settings-button" data-config-prefix="` +
  1953. v.configPrefix +
  1954. `" data-api="${v.api}" data-settings="${v.settings}" data-bind="${v.bind}"><i class="ti-panel fa-2x"></i></a></li>`;
  1955. } else {
  1956. var activeToggle =
  1957. `<li><a class="btn default btn-outline enablePlugin" href="javascript:void(0);" data-plugin-name="` +
  1958. v.name +
  1959. `" data-config-prefix="` +
  1960. v.configPrefix +
  1961. `" data-config-name="` +
  1962. v.configPrefix +
  1963. `-enabled"><i class="ti-plug fa-2x"></i></a></li>`;
  1964. var settings = "";
  1965. }
  1966. var plugin =
  1967. `
  1968. <div class="col-lg-2 col-md-2 col-sm-4 col-xs-4">
  1969. <div class="white-box m-0">
  1970. <div class="el-card-item p-0">
  1971. <div class="el-card-avatar el-overlay-1 m-0"> <img class="lazyload" data-src="` +
  1972. v.image +
  1973. `">
  1974. <div class="el-overlay">
  1975. <ul class="el-info">
  1976. ${settings} ${activeToggle}
  1977. </ul>
  1978. </div>
  1979. </div>
  1980. <div class="el-card-content">
  1981. <h3 class="box-title elip">` +
  1982. v.name +
  1983. `</h3>
  1984. <small class="elip text-uppercase p-b-10">` +
  1985. v.category +
  1986. `</small>
  1987. </div>
  1988. </div>
  1989. </div>
  1990. </div>
  1991. `;
  1992. if (v.enabled == true) {
  1993. activePlugins += plugin + settingsPage;
  1994. } else {
  1995. inactivePlugins += plugin + settingsPage;
  1996. }
  1997. });
  1998. activePlugins =
  1999. activePlugins.length !== 0
  2000. ? activePlugins
  2001. : '<h2 class="text-center" lang="en">Nothing Active</h2>';
  2002. inactivePlugins =
  2003. inactivePlugins.length !== 0
  2004. ? inactivePlugins
  2005. : '<h2 class="text-center" lang="en">Everything Active</h2>';
  2006. var panes =
  2007. `
  2008. <select class="form-control settings-dropdown-box plugin-menu w-100 visible-xs">
  2009. <option value="#settings-plugins-active-anchor" lang="en">Active</option>
  2010. <option value="#settings-plugins-inactive-anchor" lang="en">Inactive</option>
  2011. <option value="#settings-plugins-marketplace-anchor" lang="en">Marketplace</option>
  2012. </select>
  2013. <ul class="nav customtab2 nav-tabs nav-non-mobile hidden-xs" data-dropdown="plugin-menu" role="tablist">
  2014. <li onclick="changeSettingsMenu('Settings::Plugins::Active')" role="presentation" class="active"><a id="settings-plugins-active-anchor" href="#settings-plugins-active" aria-controls="home" role="tab" data-toggle="tab" aria-expanded="false"><span class="visible-xs"><i class="ti-file"></i></span><span class="hidden-xs" lang="en">Active</span></a>
  2015. </li>
  2016. <li onclick="changeSettingsMenu('Settings::Plugins::Inactive')" role="presentation" class=""><a id="settings-plugins-inactive-anchor" href="#settings-plugins-inactive" aria-controls="home" role="tab" data-toggle="tab" aria-expanded="false"><span class="visible-xs"><i class="ti-zip"></i></span><span class="hidden-xs" lang="en">Inactive</span></a>
  2017. </li>
  2018. <li onclick="changeSettingsMenu('Settings::Plugins::Marketplace');loadMarketplace('plugins');" role="presentation" class=""><a id="settings-plugins-marketplace-anchor" href="#settings-plugins-marketplace" aria-controls="home" role="tab" data-toggle="tab" aria-expanded="false"><span class="visible-xs"><i class="ti-shopping-cart-full"></i></span><span class="hidden-xs" lang="en">Marketplace</span></a>
  2019. </li>
  2020. </ul>
  2021. <!-- Tab panes -->
  2022. <div class="tab-content">
  2023. <div role="tabpanel" class="tab-pane fade in active" id="settings-plugins-active">
  2024. <div class="panel bg-org panel-info">
  2025. <div class="panel-heading">
  2026. <span lang="en">Active Plugins</span>
  2027. </div>
  2028. <div class="panel-wrapper collapse in" aria-expanded="true">
  2029. <div class="panel-body bg-org">
  2030. <div class="row el-element-overlay m-b-40">` +
  2031. activePlugins +
  2032. `</div>
  2033. </div>
  2034. </div>
  2035. </div>
  2036. <div class="clearfix"></div>
  2037. </div>
  2038. <div role="tabpanel" class="tab-pane fade" id="settings-plugins-inactive">
  2039. <div class="panel bg-org panel-info">
  2040. <div class="panel-heading">
  2041. <span lang="en">Inactive Plugins</span>
  2042. </div>
  2043. <div class="panel-wrapper collapse in" aria-expanded="true">
  2044. <div class="panel-body bg-org">
  2045. <div class="row el-element-overlay m-b-40">` +
  2046. inactivePlugins +
  2047. `</div>
  2048. </div>
  2049. </div>
  2050. </div>
  2051. </div>
  2052. <div role="tabpanel" class="tab-pane fade" id="settings-plugins-marketplace">
  2053. <div class="panel bg-org panel-info">
  2054. <div class="panel-heading">
  2055. <span lang="en">Plugin Marketplace</span>
  2056. </div>
  2057. <div class="panel-wrapper collapse in" aria-expanded="true">
  2058. <div class="table-responsive">
  2059. <table class="table table-hover manage-u-table">
  2060. <thead>
  2061. <tr>
  2062. <th width="70" class="text-center" lang="en">PLUGIN</th>
  2063. <th></th>
  2064. <th lang="en">CATEGORY</th>
  2065. <th lang="en">STATUS</th>
  2066. <th lang="en" style="text-align:center">INFO</th>
  2067. <th lang="en" style="text-align:center">INSTALL</th>
  2068. <th lang="en" style="text-align:center">DELETE</th>
  2069. </tr>
  2070. </thead>
  2071. <tbody id="managePluginTable"></tbody>
  2072. </table>
  2073. </div>
  2074. </div>
  2075. </div>
  2076. </div>
  2077. </div>
  2078. `;
  2079. return panes;
  2080. }
  2081. function loadMarketplace(type) {
  2082. marketplaceJSON(type)
  2083. .success(function (data) {
  2084. try {
  2085. var response = JSON.parse(data);
  2086. } catch (e) {
  2087. organizrCatchError(e, data);
  2088. }
  2089. switch (type) {
  2090. case "plugins":
  2091. loadMarketplacePluginsItems(response);
  2092. break;
  2093. case "themes":
  2094. loadMarketplaceThemesItems(response);
  2095. break;
  2096. default:
  2097. }
  2098. })
  2099. .fail(function (xhr) {
  2100. OrganizrApiError(xhr);
  2101. });
  2102. }
  2103. function loadThemeMarketplace() {
  2104. $("#manageThemeTable").html(
  2105. '<td class="text-center" colspan="12"><i class="fa fa-spin fa-spinner"></i></td>'
  2106. );
  2107. organizrAPI2("GET", "api/v2/themes/marketplace")
  2108. .success(function (data) {
  2109. try {
  2110. let response = data.response;
  2111. loadMarketplaceThemesItems(response.data);
  2112. } catch (e) {
  2113. organizrCatchError(e, data);
  2114. }
  2115. })
  2116. .fail(function (xhr) {
  2117. OrganizrApiError(xhr, "loadThemeMarketplace Failed");
  2118. });
  2119. }
  2120. function loadPluginMarketplace() {
  2121. $("#managePluginTable").html(
  2122. '<td class="text-center" colspan="12"><i class="fa fa-spin fa-spinner"></i></td>'
  2123. );
  2124. organizrAPI2("GET", "api/v2/plugins/marketplace")
  2125. .success(function (data) {
  2126. try {
  2127. let response = data.response;
  2128. loadMarketplacePluginsItems(response.data);
  2129. } catch (e) {
  2130. organizrCatchError(e, data);
  2131. }
  2132. })
  2133. .fail(function (xhr) {
  2134. OrganizrApiError(xhr, "loadPluginMarketplace Failed");
  2135. });
  2136. }
  2137. function loadMarketplacePluginsItems(plugins) {
  2138. var pluginList = "";
  2139. $.each(plugins, function (i, v) {
  2140. if (v.icon == null || v.icon == "") {
  2141. v.icon = "test.png";
  2142. }
  2143. var installButton =
  2144. v.status == "Update Available" ? "fa fa-download" : "fa fa-plus";
  2145. var removeButton = v.status == "Not Installed" ? "disabled" : "";
  2146. v.name = i;
  2147. pluginList +=
  2148. `
  2149. <tr class="pluginManagement" data-name="${i}" data-version="${v.version}" data-repo="${v.repo}">
  2150. <td class="text-center el-element-overlay">
  2151. <div class="el-card-item p-0">
  2152. <div class="el-card-avatar el-overlay-1 m-0">
  2153. <img alt="user-img" src="` +
  2154. v.icon +
  2155. `" width="45">
  2156. </div>
  2157. </div>
  2158. </td>
  2159. <td>` +
  2160. i +
  2161. `
  2162. <br><span class="text-muted">` +
  2163. v.version +
  2164. `</span>
  2165. <br><span class="text-muted">` +
  2166. v.author +
  2167. `</span>
  2168. </td>
  2169. <td>` +
  2170. v.category +
  2171. `</td>
  2172. <td lang="en">` +
  2173. v.status +
  2174. `</td>
  2175. <td style="text-align:center"><button type="button" onclick='aboutPlugin(` +
  2176. JSON.stringify(v) +
  2177. `);' class="btn btn-success btn-outline btn-circle btn-lg popup-with-form" href="#about-plugin-form" data-effect="mfp-3d-unfold"><i class="fa fa-info"></i></button></td>
  2178. <td style="text-align:center"><button type="button" onclick='installPlugin("` +
  2179. cleanClass(i) +
  2180. `");' class="btn btn-info btn-outline btn-circle btn-lg"><i class="` +
  2181. installButton +
  2182. `"></i></button></td>
  2183. <td style="text-align:center"><button type="button" onclick='removePlugin("` +
  2184. cleanClass(i) +
  2185. `");' class="btn btn-danger btn-outline btn-circle btn-lg" ` +
  2186. removeButton +
  2187. `><i class="fa fa-trash"></i></button></td>
  2188. </tr>
  2189. `;
  2190. });
  2191. $("#managePluginTable").html(pluginList);
  2192. }
  2193. function getRepoUsernameAndRepoName(repo) {
  2194. let parts = repo.split("/");
  2195. if (parts.length) {
  2196. return parts[parts.length - 2] + "/" + parts[parts.length - 1];
  2197. } else {
  2198. return repo;
  2199. }
  2200. }
  2201. function loadMarketplaceThemesItems(themes) {
  2202. var themeList = "";
  2203. $.each(themes, function (i, v) {
  2204. if (v.icon == null || v.icon == "") {
  2205. v.icon = "test.png";
  2206. }
  2207. //v.status = themeStatus(i,v.version);
  2208. var installButton =
  2209. v.status == "Update Available" ? "fa fa-download" : "fa fa-plus";
  2210. var removeButton = v.status == "Not Installed" ? "disabled" : "";
  2211. let category =
  2212. v.repo == "https://github.com/Organizr/Organizr-Themes"
  2213. ? "Official"
  2214. : "3rd Party";
  2215. let categoryTooltip = getRepoUsernameAndRepoName(v.repo);
  2216. v.name = i;
  2217. let cleanName = i.replace(/_/gi, " ");
  2218. themeList += `
  2219. <tr class="themeManagement" data-name="${i}" data-version="${
  2220. v.version
  2221. }">
  2222. <td class="text-center el-element-overlay">
  2223. <div class="el-card-item p-0">
  2224. <div class="el-card-avatar el-overlay-1 m-0">
  2225. <img alt="user-img" src="${v.icon}" width="45">
  2226. </div>
  2227. </div>
  2228. </td>
  2229. <td>${cleanName}
  2230. <br><span class="text-muted">${v.version}</span>
  2231. <br><span class="text-muted">${v.author}</span>
  2232. </td>
  2233. <td><span data-toggle="tooltip" title="${categoryTooltip}" data-placement="bottom">${category}</span></td>
  2234. <td lang="en">${v.status}</td>
  2235. <td style="text-align:center"><button type="button" onclick='aboutTheme(${JSON.stringify(
  2236. v
  2237. )});' class="btn btn-success btn-outline btn-circle btn-lg popup-with-form" href="#about-theme-form" data-effect="mfp-3d-unfold"><i class="fa fa-info"></i></button></td>
  2238. <td style="text-align:center"><button type="button" onclick='installTheme("${cleanClass(
  2239. i
  2240. )}");themeAnalytics("${
  2241. v.name
  2242. }");' class="btn btn-info btn-outline btn-circle btn-lg"><i class="${installButton}"></i></button></td>
  2243. <td style="text-align:center"><button type="button" onclick='removeTheme("${cleanClass(
  2244. i
  2245. )}");' class="btn btn-danger btn-outline btn-circle btn-lg" ${removeButton}><i class="fa fa-trash"></i></button></td>
  2246. </tr>
  2247. `;
  2248. });
  2249. $("#manageThemeTable").html(themeList);
  2250. }
  2251. function aboutPluginImages(images) {
  2252. var imageList = "";
  2253. if (Object.keys(images).length !== 0) {
  2254. var imageCount = 0;
  2255. $.each(images, function (i, v) {
  2256. imageCount++;
  2257. var active = imageCount == 1 ? "active" : "";
  2258. imageList +=
  2259. `
  2260. <div class="` +
  2261. active +
  2262. ` item">
  2263. <div class="overlaybg"><img src="` +
  2264. v +
  2265. `" /></div>
  2266. <div class="news-content"><span class="label label-info label-rounded">` +
  2267. i +
  2268. `</span></div>
  2269. </div>
  2270. `;
  2271. });
  2272. } else {
  2273. imageList += `
  2274. <div class="active item">
  2275. <div class="overlaybg"><img src="https://via.placeholder.com/350x150" /></div>
  2276. </div>
  2277. `;
  2278. }
  2279. return imageList;
  2280. }
  2281. function aboutPluginFiles(fileList) {
  2282. var files = [];
  2283. $.each(fileList, function (i, v) {
  2284. var splitFiles = v.split("|");
  2285. var formattedSplit = [];
  2286. $.each(splitFiles, function (i, v) {
  2287. var arrayFilePush = {
  2288. text: v,
  2289. };
  2290. formattedSplit.push(arrayFilePush);
  2291. });
  2292. var arrayPush = {
  2293. text: i,
  2294. nodes: formattedSplit,
  2295. };
  2296. files.push(arrayPush);
  2297. });
  2298. return files;
  2299. }
  2300. function pluginFileList(fileList, folder, type) {
  2301. var files = [];
  2302. $.each(fileList, function (i, v) {
  2303. var splitFiles = v.split("|");
  2304. var formattedSplit = [];
  2305. var prePath = i.length !== 1 ? i + "/" : i;
  2306. $.each(splitFiles, function (i, v) {
  2307. var arrayPush = {
  2308. fileName: v,
  2309. path: prePath,
  2310. githubPath:
  2311. "https://raw.githubusercontent.com/causefx/Organizr/v2-" +
  2312. type +
  2313. "/" +
  2314. folder +
  2315. prePath +
  2316. v,
  2317. };
  2318. files.push(arrayPush);
  2319. });
  2320. });
  2321. return files;
  2322. }
  2323. function aboutTheme(theme) {
  2324. var files = aboutPluginFiles(theme.files);
  2325. var imageList = aboutPluginImages(theme.images);
  2326. var homepageLink =
  2327. theme.website !== "" || theme.website !== null
  2328. ? "onclick=\"window.open('" + theme.website + "','_blank');\""
  2329. : " ";
  2330. var infoBox =
  2331. `
  2332. <div class="row">
  2333. <div class="col-lg-6 col-sm-12 col-xs-12">
  2334. <div class="row">
  2335. <div class="col-lg-12 col-sm-12 col-xs-12">
  2336. <div class="white-box p-10" id="aboutThemeScroll">
  2337. ` +
  2338. theme.description +
  2339. `
  2340. </div>
  2341. </div>
  2342. <div class="clearfix">&nbsp;</div>
  2343. <div class="col-lg-4 col-sm-4 col-xs-12">
  2344. <div class="white-box mouse">
  2345. <ul class="list-inline two-part text-center m-b-0">
  2346. <li><i class="icon-envelope-open text-info"></i></li>
  2347. </ul>
  2348. </div>
  2349. </div>
  2350. <div class="col-lg-4 col-sm-4 col-xs-12">
  2351. <div class="white-box mouse" ` +
  2352. homepageLink +
  2353. `>
  2354. <ul class="list-inline two-part text-center m-b-0">
  2355. <li><i class="icon-home text-danger"></i></li>
  2356. </ul>
  2357. </div>
  2358. </div>
  2359. <div class="col-lg-4 col-sm-4 col-xs-12">
  2360. <div class="white-box mouse" onclick="$('.themeFileList').toggleClass('hidden');">
  2361. <ul class="list-inline two-part text-center m-b-0">
  2362. <li><i class="icon-folder text-purple"></i></li>
  2363. </ul>
  2364. </div>
  2365. </div>
  2366. <div class="col-sm-12 col-xs-12 themeFileList hidden">
  2367. <div id="treeviewTheme" class=""></div>
  2368. </div>
  2369. </div>
  2370. </div>
  2371. <div class="col-lg-6 col-sm-12 col-xs-12">
  2372. <div class="news-slide m-b-15">
  2373. <div class="vcarousel slide">
  2374. <!-- Carousel items -->
  2375. <div class="carousel-inner">
  2376. ` +
  2377. imageList +
  2378. `
  2379. </div>
  2380. </div>
  2381. </div>
  2382. </div>
  2383. </div>`;
  2384. $("#about-theme-title").html(
  2385. theme.name + "&nbsp;<small>" + theme.version + "</small>"
  2386. );
  2387. $("#about-theme-body").html(infoBox);
  2388. $(".vcarousel").carousel({
  2389. interval: 3000,
  2390. });
  2391. $("#treeviewTheme").treeview({
  2392. levels: 1,
  2393. expandIcon: "ti-angle-right",
  2394. onhoverColor: "rgba(0, 0, 0, 0.05)",
  2395. selectedBackColor: "#03a9f3",
  2396. collapseIcon: "ti-angle-down",
  2397. data: JSON.stringify(files),
  2398. });
  2399. $("#aboutThemeScroll").slimScroll({
  2400. height: "225px",
  2401. });
  2402. }
  2403. function aboutPlugin(plugin) {
  2404. var files = aboutPluginFiles(plugin.files);
  2405. var imageList = aboutPluginImages(plugin.images);
  2406. var homepageLink =
  2407. plugin.website !== "" || plugin.website !== null
  2408. ? "onclick=\"window.open('" + plugin.website + "','_blank');\""
  2409. : " ";
  2410. var infoBox =
  2411. `
  2412. <div class="row">
  2413. <div class="col-lg-6 col-sm-12 col-xs-12">
  2414. <div class="row">
  2415. <div class="col-lg-12 col-sm-12 col-xs-12">
  2416. <div class="white-box p-10" id="aboutPluginScroll">
  2417. ` +
  2418. plugin.description +
  2419. `
  2420. </div>
  2421. </div>
  2422. <div class="clearfix">&nbsp;</div>
  2423. <div class="col-lg-4 col-sm-4 col-xs-12">
  2424. <div class="white-box mouse">
  2425. <ul class="list-inline two-part text-center m-b-0">
  2426. <li><i class="icon-envelope-open text-info"></i></li>
  2427. </ul>
  2428. </div>
  2429. </div>
  2430. <div class="col-lg-4 col-sm-4 col-xs-12">
  2431. <div class="white-box mouse" ` +
  2432. homepageLink +
  2433. `>
  2434. <ul class="list-inline two-part text-center m-b-0">
  2435. <li><i class="icon-home text-danger"></i></li>
  2436. </ul>
  2437. </div>
  2438. </div>
  2439. <div class="col-lg-4 col-sm-4 col-xs-12">
  2440. <div class="white-box mouse" onclick="$('.pluginFileList').toggleClass('hidden');">
  2441. <ul class="list-inline two-part text-center m-b-0">
  2442. <li><i class="icon-folder text-purple"></i></li>
  2443. </ul>
  2444. </div>
  2445. </div>
  2446. <div class="col-sm-12 col-xs-12 pluginFileList hidden">
  2447. <div id="treeview5" class=""></div>
  2448. </div>
  2449. </div>
  2450. </div>
  2451. <div class="col-lg-6 col-sm-12 col-xs-12">
  2452. <div class="news-slide m-b-15">
  2453. <div class="vcarousel slide">
  2454. <!-- Carousel items -->
  2455. <div class="carousel-inner">
  2456. ` +
  2457. imageList +
  2458. `
  2459. </div>
  2460. </div>
  2461. </div>
  2462. </div>
  2463. </div>`;
  2464. $("#about-plugin-title").html(
  2465. plugin.name + "&nbsp;<small>" + plugin.version + "</small>"
  2466. );
  2467. $("#about-plugin-body").html(infoBox);
  2468. $(".vcarousel").carousel({
  2469. interval: 3000,
  2470. });
  2471. $("#treeview5").treeview({
  2472. levels: 1,
  2473. expandIcon: "ti-angle-right",
  2474. onhoverColor: "rgba(0, 0, 0, 0.05)",
  2475. selectedBackColor: "#03a9f3",
  2476. collapseIcon: "ti-angle-down",
  2477. data: JSON.stringify(files),
  2478. });
  2479. $("#aboutPluginScroll").slimScroll({
  2480. height: "225px",
  2481. });
  2482. }
  2483. function removePlugin(plugin = null) {
  2484. if (plugin == null) {
  2485. return false;
  2486. }
  2487. message(
  2488. "Removing Plugin",
  2489. plugin,
  2490. activeInfo.settings.notifications.position,
  2491. "#FFF",
  2492. "success",
  2493. "5000"
  2494. );
  2495. organizrAPI2("DELETE", "api/v2/plugins/manage/" + plugin, {})
  2496. .success(function (data) {
  2497. try {
  2498. let html = data.response;
  2499. loadPluginMarketplace();
  2500. message(
  2501. plugin + " Removed",
  2502. "",
  2503. activeInfo.settings.notifications.position,
  2504. "#FFF",
  2505. "success",
  2506. "5000"
  2507. );
  2508. } catch (e) {
  2509. organizrCatchError(e, data);
  2510. }
  2511. })
  2512. .fail(function (xhr) {
  2513. OrganizrApiError(xhr, "Removal Failed");
  2514. });
  2515. }
  2516. function removeTheme(theme = null) {
  2517. if (theme == null) {
  2518. return false;
  2519. }
  2520. message(
  2521. "Removing Theme",
  2522. theme,
  2523. activeInfo.settings.notifications.position,
  2524. "#FFF",
  2525. "success",
  2526. "5000"
  2527. );
  2528. organizrAPI2("DELETE", "api/v2/themes/manage/" + theme, {})
  2529. .success(function (data) {
  2530. try {
  2531. let html = data.response;
  2532. loadThemeMarketplace();
  2533. message(
  2534. theme + " Removed",
  2535. "",
  2536. activeInfo.settings.notifications.position,
  2537. "#FFF",
  2538. "success",
  2539. "5000"
  2540. );
  2541. } catch (e) {
  2542. organizrCatchError(e, data);
  2543. }
  2544. })
  2545. .fail(function (xhr) {
  2546. OrganizrApiError(xhr, "Removal Failed");
  2547. });
  2548. }
  2549. function installPlugin(plugin = null) {
  2550. if (plugin == null) {
  2551. return false;
  2552. }
  2553. message(
  2554. "Installing Plugin",
  2555. plugin,
  2556. activeInfo.settings.notifications.position,
  2557. "#FFF",
  2558. "success",
  2559. "5000"
  2560. );
  2561. organizrAPI2("POST", "api/v2/plugins/manage/" + plugin, {})
  2562. .success(function (data) {
  2563. try {
  2564. var html = data.response;
  2565. loadPluginMarketplace();
  2566. message(
  2567. plugin + " Installed",
  2568. "",
  2569. activeInfo.settings.notifications.position,
  2570. "#FFF",
  2571. "success",
  2572. "5000"
  2573. );
  2574. } catch (e) {
  2575. organizrCatchError(e, data);
  2576. }
  2577. })
  2578. .fail(function (xhr) {
  2579. OrganizrApiError(xhr, "Install Failed");
  2580. });
  2581. }
  2582. function installTheme(theme = null) {
  2583. if (theme == null) {
  2584. return false;
  2585. }
  2586. message(
  2587. "Installing Theme",
  2588. theme,
  2589. activeInfo.settings.notifications.position,
  2590. "#FFF",
  2591. "success",
  2592. "5000"
  2593. );
  2594. organizrAPI2("POST", "api/v2/themes/manage/" + theme, {})
  2595. .success(function (data) {
  2596. try {
  2597. var html = data.response;
  2598. loadThemeMarketplace();
  2599. message(
  2600. theme + " Installed",
  2601. "",
  2602. activeInfo.settings.notifications.position,
  2603. "#FFF",
  2604. "success",
  2605. "5000"
  2606. );
  2607. } catch (e) {
  2608. organizrCatchError(e, data);
  2609. }
  2610. })
  2611. .fail(function (xhr) {
  2612. OrganizrApiError(xhr, "Install Failed");
  2613. });
  2614. }
  2615. function pluginStatus(name = null, version = null) {
  2616. var installedPlugins = [];
  2617. var installedPluginsList = [];
  2618. if (activeInfo.settings.misc.installedPlugins !== "") {
  2619. installedPlugins = activeInfo.settings.misc.installedPlugins.split("|");
  2620. $.each(installedPlugins, function (i, v) {
  2621. var plugin = v.split(":");
  2622. installedPluginsList[plugin[0]] = plugin[1];
  2623. });
  2624. if (typeof installedPluginsList[name] !== "undefined") {
  2625. if (version !== installedPluginsList[name]) {
  2626. return "Update Available";
  2627. } else {
  2628. return "Up to date";
  2629. }
  2630. } else {
  2631. return "Not Installed";
  2632. }
  2633. } else {
  2634. return "Not Installed";
  2635. }
  2636. }
  2637. function themeStatus(name = null, version = null) {
  2638. var installedThemes = [];
  2639. var installedThemesList = [];
  2640. if (activeInfo.settings.misc.installedThemes !== "") {
  2641. installedThemes = activeInfo.settings.misc.installedThemes.split("|");
  2642. $.each(installedThemes, function (i, v) {
  2643. var theme = v.split(":");
  2644. installedThemesList[theme[0]] = theme[1];
  2645. });
  2646. if (typeof installedThemesList[name] !== "undefined") {
  2647. if (version !== installedThemesList[name]) {
  2648. return "Update Available";
  2649. } else {
  2650. return "Up to date";
  2651. }
  2652. } else {
  2653. return "Not Installed";
  2654. }
  2655. } else {
  2656. return "Not Installed";
  2657. }
  2658. }
  2659. function copyHomepageJSON(item) {
  2660. organizrAPI2("GET", "api/v2/settings/homepage/" + item + "/debug")
  2661. .success(function (data) {
  2662. try {
  2663. let response = data.response;
  2664. let debug = response.data;
  2665. clipboard(true, JSON.stringify(debug, null, "\t"));
  2666. message(
  2667. "",
  2668. window.lang.translate("Copied JSON to clipboard"),
  2669. activeInfo.settings.notifications.position,
  2670. "#FFF",
  2671. "success",
  2672. "5000"
  2673. );
  2674. } catch (e) {
  2675. organizrCatchError(e, data);
  2676. }
  2677. })
  2678. .fail(function (xhr) {
  2679. OrganizrApiError(xhr, "Copy JSON Failed");
  2680. });
  2681. }
  2682. function homepageItemFormHTML(v) {
  2683. let docs =
  2684. typeof v.docs == "undefined"
  2685. ? ""
  2686. : `<small class="pull-right m-r-5"><a data-toggle="tooltip" title="Go to Support Doc" data-placement="bottom" class="btn btn-circle btn-primary waves-effect waves-light" href="${v.docs}" target="_blank"> <i class="fa-fw fa fa-question-circle"></i></a></small>`;
  2687. let debug = typeof v.debug == "undefined" ? false : true;
  2688. debug = debug === true ? v.debug : false;
  2689. debug =
  2690. debug === true
  2691. ? `<small class="pull-right m-r-5"><a data-toggle="tooltip" title="Copy JSON Settings" data-placement="bottom" href="javascript:copyHomepageJSON('${v.name}')" class="btn btn-circle btn-info waves-effect waves-light copyHomepageJSON"> <i class="fa-fw ti-clipboard"></i></a></small>`
  2692. : "";
  2693. return (
  2694. `
  2695. <a id="editHomepageItemCall" href="#editHomepageItemDiv" class="hidden">homepage item</a>
  2696. <form id="homepage-` +
  2697. v.name +
  2698. `-form" class="white-popup mfp-with-anim homepageForm addFormTick">
  2699. <fieldset style="border:0;" class="col-md-10 col-md-offset-1">
  2700. <div class="panel bg-org panel-info">
  2701. <div class="panel-heading">
  2702. <span class="" lang="en">` +
  2703. v.name +
  2704. `</span>
  2705. <button data-toggle="tooltip" title="Close" data-placement="bottom" type="button" class="btn btn-default btn-circle close-popup pull-right close-editHomepageItemDiv"><i class="fa fa-times"></i> </button>
  2706. ${docs}${debug}
  2707. <button data-toggle="tooltip" title="Reset" data-placement="bottom" id="homepage-` +
  2708. v.name +
  2709. `-form-reset" onclick="editHomepageItem('` +
  2710. v.name +
  2711. `', true)" class="btn btn-inverse btn-circle waves-effect waves-light pull-right hidden m-r-5" type="button"><span class=""><i class="fa fa-undo"></i></span></button>
  2712. <button data-toggle="tooltip" title="Save" data-placement="bottom" id="homepage-` +
  2713. v.name +
  2714. `-form-save" onclick="submitSettingsForm('homepage-` +
  2715. v.name +
  2716. `-form', true)" class="btn btn-success btn-circle waves-effect waves-light pull-right hidden animated loop-animation rubberBand m-r-5" type="button"><span class=""><i class="fa fa-save"></i></span></button>
  2717. </div>
  2718. <div class="panel-wrapper collapse in" aria-expanded="true">
  2719. <div class="bg-org">
  2720. ` +
  2721. buildFormGroup(v.settings) +
  2722. `
  2723. </div>
  2724. </div>
  2725. </div>
  2726. </fieldset>
  2727. <div class="clearfix"></div>
  2728. </form>
  2729. `
  2730. );
  2731. }
  2732. function clearHomepageOriginal() {
  2733. $("#editHomepageItem").html("");
  2734. }
  2735. function completeHomepageLoad(item, data) {
  2736. /*
  2737. if(item == 'CustomHTML'){
  2738. let iteration = 0;
  2739. $.each(data.settings, function(i,customItem) {
  2740. let iterationString = (parseInt(iteration, 10) + 101).toString().substr(1);
  2741. let customEditor = 'customHTML'+iterationString+'Editor';
  2742. let customTextarea = 'customHTML'+iterationString+'Textarea';
  2743. let HTMLMode = ace.require("ace/mode/html").Mode;
  2744. customHTMLEditorObject[iterationString] = ace.edit(customEditor);
  2745. customHTMLEditorObject[iterationString].session.setMode(new HTMLMode());
  2746. customHTMLEditorObject[iterationString].setTheme("ace/theme/idle_fingers");
  2747. customHTMLEditorObject[iterationString].setShowPrintMargin(false);
  2748. customHTMLEditorObject[iterationString].session.on('change', function(delta) {
  2749. $('.' + customTextarea).val(customHTMLEditorObject[iterationString].getValue());
  2750. //$('#homepage-CustomHTML-form-save').removeClass('hidden');
  2751. });
  2752. iteration++;
  2753. });
  2754. }
  2755. */
  2756. pageLoad();
  2757. }
  2758. function editHomepageItem(item, reload = false) {
  2759. ajaxloader(".editHomepageItemBox-" + item, "in");
  2760. organizrAPI2("GET", "api/v2/settings/homepage/" + item)
  2761. .success(function (data) {
  2762. try {
  2763. let response = data.response;
  2764. let html = homepageItemFormHTML(response.data);
  2765. $("#editHomepageItem").html(html);
  2766. if (reload) {
  2767. ajaxloader(".editHomepageItemBox-" + item);
  2768. return false;
  2769. }
  2770. /*$("#editHomepageItemCall").animatedModal({
  2771. top: '40px',
  2772. left: '0px',
  2773. color: '#000000eb',
  2774. animatedIn: 'bounceInUp',
  2775. animatedOut: 'bounceOutDown',
  2776. position: 'fixed',
  2777. afterClose: function() {
  2778. $('body, html').css({'overflow':'hidden'});
  2779. }
  2780. });*/
  2781. new Custombox.modal({
  2782. content: {
  2783. effect: "slidetogether",
  2784. animateFrom: "bottom",
  2785. animateTo: "bottom",
  2786. target: "#editHomepageItemDiv",
  2787. width: "100%",
  2788. delay: 0,
  2789. fullscreen: true,
  2790. clone: false,
  2791. onComplete: completeHomepageLoad(item, response.data),
  2792. onClose: clearHomepageOriginal,
  2793. },
  2794. loader: { active: true },
  2795. }).open();
  2796. //$('#editHomepageItemCall').click();
  2797. } catch (e) {
  2798. organizrCatchError(e, data);
  2799. }
  2800. ajaxloader(".editHomepageItemBox-" + item);
  2801. })
  2802. .fail(function (xhr) {
  2803. OrganizrApiError(xhr, "Edit Homepage Failed");
  2804. ajaxloader(".editHomepageItemBox-" + item);
  2805. });
  2806. }
  2807. function buildHomepageItem(array) {
  2808. var listing = "";
  2809. if (Array.isArray(array)) {
  2810. $.each(array, function (i, v) {
  2811. if (v.enabled) {
  2812. listing +=
  2813. `
  2814. <div class="col-lg-2 col-md-2 col-sm-6 col-xs-6">
  2815. <div class="white-box bg-org m-0">
  2816. <div class="el-card-item p-0 editHomepageItemBox-` +
  2817. v.name +
  2818. `">
  2819. <div class="el-card-avatar el-overlay-1">
  2820. <a onclick="editHomepageItem('` +
  2821. v.name +
  2822. `')"><img class="lazyload tabImages mouse" data-src="` +
  2823. v.image +
  2824. `"></a>
  2825. </div>
  2826. <div class="el-card-content">
  2827. <h3 class="box-title elip">` +
  2828. v.name +
  2829. `</h3>
  2830. <small class="elip text-uppercase elip">` +
  2831. v.category +
  2832. `</small><br>
  2833. </div>
  2834. </div>
  2835. </div>
  2836. </div>
  2837. `;
  2838. }
  2839. });
  2840. }
  2841. return listing;
  2842. }
  2843. function buildPluginsOLD() {
  2844. organizrAPI2("GET", "api/v2/plugins")
  2845. .success(function (data) {
  2846. try {
  2847. var response = data.response;
  2848. } catch (e) {
  2849. organizrCatchError(e, data);
  2850. }
  2851. $("#main-plugin-area").html(buildPluginsItemOLD(response.data));
  2852. })
  2853. .fail(function (xhr) {
  2854. OrganizrApiError(xhr);
  2855. });
  2856. }
  2857. function buildPlugins(status = "enabled") {
  2858. organizrAPI2("GET", "api/v2/plugins/" + status)
  2859. .success(function (data) {
  2860. try {
  2861. var response = data.response;
  2862. } catch (e) {
  2863. organizrCatchError(e, data);
  2864. }
  2865. $("#" + status + "-plugin-area").html(
  2866. buildPluginsItem(response.data, status)
  2867. );
  2868. })
  2869. .fail(function (xhr) {
  2870. OrganizrApiError(xhr);
  2871. });
  2872. }
  2873. function buildHomepage() {
  2874. organizrAPI2("GET", "api/v2/settings/homepage")
  2875. .success(function (data) {
  2876. try {
  2877. var response = data.response;
  2878. } catch (e) {
  2879. organizrCatchError(e, data);
  2880. }
  2881. $("#settings-homepage-list").html(buildHomepageItem(response.data));
  2882. })
  2883. .fail(function (xhr) {
  2884. OrganizrApiError(xhr);
  2885. });
  2886. }
  2887. function buildFormGroup(array) {
  2888. var mainCount = 0;
  2889. var group = '<div class="tab-content w-100">';
  2890. var uList =
  2891. '<div class="vtabs customvtab"><ul class="nav tabs-vertical" role="tablist">';
  2892. $.each(array, function (i, v) {
  2893. mainCount++;
  2894. var count = 0;
  2895. var total = v.length;
  2896. var active = mainCount == 1 ? "active" : "";
  2897. var customID = createRandomString(10);
  2898. if (i == "custom") {
  2899. group += v;
  2900. } else {
  2901. uList +=
  2902. `<li role="presentation" class="` +
  2903. active +
  2904. `"><a href="#` +
  2905. customID +
  2906. cleanClass(i) +
  2907. `" aria-controls="` +
  2908. i +
  2909. `" role="tab" data-toggle="tab" aria-expanded="false"><span lang="en">` +
  2910. i +
  2911. `</span></a></li>`;
  2912. group +=
  2913. `
  2914. <!-- FORM GROUP -->
  2915. <div role="tabpanel" class="tab-pane fade in ` +
  2916. active +
  2917. `" id="` +
  2918. customID +
  2919. cleanClass(i) +
  2920. `">
  2921. `;
  2922. $.each(v, function (i, v) {
  2923. var override = "6";
  2924. if (typeof v.override !== "undefined") {
  2925. override = v.override;
  2926. }
  2927. var arrayMultiple = false;
  2928. if (typeof v.type !== "undefined") {
  2929. if (v.type == "arrayMultiple") {
  2930. arrayMultiple = true;
  2931. }
  2932. }
  2933. count++;
  2934. if (count % 2 !== 0) {
  2935. group += '<div class="row start">';
  2936. }
  2937. var helpID = "#help-info-" + v.name;
  2938. var helpTip = v.help
  2939. ? '<sup><a class="help-tip" data-toggle="collapse" href="' +
  2940. helpID +
  2941. '" aria-expanded="true"><i class="m-l-5 fa fa-question-circle text-info" title="Help" data-toggle="tooltip"></i></a></sup>'
  2942. : "";
  2943. var builtItems = "";
  2944. if (arrayMultiple == true) {
  2945. $.each(v.value, function (index, value) {
  2946. if (typeof value === "object") {
  2947. builtItems += '<div class="row m-b-40">';
  2948. $.each(value, function (number, formItem) {
  2949. let clearfix =
  2950. formItem.type == "blank"
  2951. ? '<div class="clearfix"></div>'
  2952. : "";
  2953. builtItems += `
  2954. <!-- INPUT BOX Yes Multiple -->
  2955. <div class="col-md-6 p-b-10">
  2956. <div class="form-group">
  2957. <label class="control-label col-md-12"><span lang="en">${
  2958. formItem.label
  2959. }</span>${helpTip}</label>
  2960. <div class="col-md-12">${buildFormItem(
  2961. formItem
  2962. )}</div> <!-- end div -->
  2963. </div>
  2964. </div>
  2965. ${clearfix}
  2966. <!--/ INPUT BOX -->
  2967. `;
  2968. });
  2969. builtItems += "</div>";
  2970. } else {
  2971. builtItems += buildFormItem(value);
  2972. }
  2973. });
  2974. } else {
  2975. builtItems =
  2976. `
  2977. <!-- INPUT BOX no Multiple-->
  2978. <div class="col-md-` +
  2979. override +
  2980. ` p-b-10">
  2981. <div class="form-group">
  2982. <label class="control-label col-md-12"><span lang="en">${
  2983. v.label
  2984. }</span>${helpTip}</label>
  2985. <div class="col-md-12">
  2986. ${buildFormItem(v)}
  2987. </div>
  2988. </div>
  2989. </div>
  2990. <!--/ INPUT BOX -->
  2991. `;
  2992. }
  2993. group += builtItems;
  2994. if (count % 2 == 0 || count == total) {
  2995. group += "</div><!--end-->";
  2996. }
  2997. });
  2998. group += "</div>";
  2999. }
  3000. });
  3001. return uList + "</ul>" + group + "</div>";
  3002. }
  3003. function createImageSwal(attr) {
  3004. let title = attr.attr("data-title");
  3005. let fullPath = attr.attr("data-image-path");
  3006. let clipboardText = attr.attr("data-clipboard-text");
  3007. let name = attr.attr("data-image-name");
  3008. let extension = attr.attr("data-image-name-ext");
  3009. let div =
  3010. `
  3011. <div class="panel panel-default">
  3012. <div class="panel-heading"><h1><img class="center" src="` +
  3013. fullPath +
  3014. `" style="height: 50px; width: 50px">` +
  3015. title +
  3016. `</h1></div>
  3017. <div class="panel-wrapper collapse in">
  3018. <div class="panel-body">
  3019. <h5 lang="en">Choose action:</h5>
  3020. <div class="button-box">
  3021. <button class="btn btn-info waves-effect waves-light clipboard" type="button" data-clipboard-text="` +
  3022. clipboardText +
  3023. `"><span class="btn-label"><i class="ti-clipboard"></i></span><span lang="en">Copy to Clipboard</span></button>
  3024. <button class="btn btn-danger waves-effect waves-light deleteImage" type="button" data-image-path="` +
  3025. fullPath +
  3026. `" data-image-name="` +
  3027. name +
  3028. `" data-image-name-ext="` +
  3029. extension +
  3030. `"><span class="btn-label"><i class="fa fa-trash"></i></span><span lang="en">Delete</span></button>
  3031. </div>
  3032. </div>
  3033. </div>
  3034. </div>
  3035. `;
  3036. swal({
  3037. content: createElementFromHTML(div),
  3038. buttons: false,
  3039. className: "bg-org",
  3040. });
  3041. }
  3042. function buildImageManagerViewItem(array) {
  3043. var imageListing = "";
  3044. if (Array.isArray(array)) {
  3045. $.each(array, function (i, v) {
  3046. var filepath = v.split("/");
  3047. var name = filepath[filepath.length - 1].split(".");
  3048. var clipboardText = v.replace(/ /g, "%20");
  3049. var fileAndExt = filepath[filepath.length - 1];
  3050. imageListing +=
  3051. `
  3052. <a class="imageManagerItem" href="javascript:void(0);" data-toggle="lightbox" data-gallery="multiimages" data-title="` +
  3053. name[0] +
  3054. `" data-clipboard-text="` +
  3055. clipboardText +
  3056. `" data-image-path="` +
  3057. v +
  3058. `" data-image-name="` +
  3059. name[0] +
  3060. `" data-image-name-ext="` +
  3061. fileAndExt +
  3062. `"><img data-toggle="tooltip" title="${name[0]}" data-placement="bottom" data-src="` +
  3063. v +
  3064. `" alt="tabImage" class="all studio lazyload" /> </a>
  3065. `;
  3066. });
  3067. }
  3068. return imageListing;
  3069. }
  3070. function buildImageManagerView() {
  3071. organizrAPI2("GET", "api/v2/image")
  3072. .success(function (data) {
  3073. try {
  3074. let response = data.response;
  3075. $(".settings-image-manager-list").html(
  3076. buildImageManagerViewItem(response.data)
  3077. );
  3078. $container = $("#gallery-content-center");
  3079. try {
  3080. if (typeof $container.isotope == "undefined") {
  3081. $container.isotope({ itemSelector: "img" });
  3082. } else {
  3083. $container.isotope({ itemSelector: "img" });
  3084. }
  3085. } catch (e) {
  3086. $container.isotope("destroy");
  3087. $container.isotope({ itemSelector: "img" });
  3088. }
  3089. } catch (e) {
  3090. organizrCatchError(e, data);
  3091. }
  3092. })
  3093. .fail(function (xhr) {
  3094. OrganizrApiError(xhr);
  3095. });
  3096. }
  3097. function buildPluginsSettings() {
  3098. organizrAPI2("GET", "api/v2/settings/plugin")
  3099. .success(function (data) {
  3100. try {
  3101. let response = data.response;
  3102. $("#plugin-settings-form").html(buildFormGroup(response.data));
  3103. } catch (e) {
  3104. organizrCatchError(e, data);
  3105. }
  3106. })
  3107. .fail(function (xhr) {
  3108. OrganizrApiError(xhr);
  3109. });
  3110. }
  3111. function buildThemeSettings() {
  3112. organizrAPI2("GET", "api/v2/settings/theme")
  3113. .success(function (data) {
  3114. try {
  3115. let response = data.response;
  3116. $("#theme-settings-form").html(buildFormGroup(response.data));
  3117. } catch (e) {
  3118. organizrCatchError(e, data);
  3119. }
  3120. })
  3121. .fail(function (xhr) {
  3122. OrganizrApiError(xhr);
  3123. });
  3124. }
  3125. function buildCustomizeAppearance() {
  3126. organizrAPI2("GET", "api/v2/settings/appearance")
  3127. .success(function (data) {
  3128. try {
  3129. var response = data.response;
  3130. } catch (e) {
  3131. organizrCatchError(e, data);
  3132. }
  3133. $("#customize-appearance-form").html(buildFormGroup(response.data));
  3134. $("input.pick-a-color-custom-options").ColorPickerSliders({
  3135. placement: "bottom",
  3136. color: "#987654",
  3137. hsvpanel: true,
  3138. previewformat: "hex",
  3139. });
  3140. })
  3141. .fail(function (xhr) {
  3142. OrganizrApiError(xhr);
  3143. });
  3144. }
  3145. function buildSSO() {
  3146. organizrAPI2("GET", "api/v2/settings/sso")
  3147. .success(function (data) {
  3148. try {
  3149. var response = data.response;
  3150. } catch (e) {
  3151. organizrCatchError(e, data);
  3152. }
  3153. $("#sso-form").html(buildFormGroup(response.data));
  3154. })
  3155. .fail(function (xhr) {
  3156. console.error("Organizr Function: API Connection Failed");
  3157. });
  3158. }
  3159. function buildSettingsMain() {
  3160. organizrAPI2("GET", "api/v2/settings/main")
  3161. .success(function (data) {
  3162. try {
  3163. var response = data.response;
  3164. } catch (e) {
  3165. organizrCatchError(e, data);
  3166. }
  3167. $("#settings-main-form").html(buildFormGroup(response.data));
  3168. changeAuth();
  3169. })
  3170. .fail(function (xhr) {
  3171. OrganizrApiError(xhr);
  3172. });
  3173. }
  3174. function buildUserManagement() {
  3175. organizrAPI2("GET", "api/v2/users?includeGroups")
  3176. .success(function (data) {
  3177. try {
  3178. var response = data.response;
  3179. } catch (e) {
  3180. organizrCatchError(e, data);
  3181. }
  3182. $("#manageUserTable").html(buildUserManagementItem(response.data));
  3183. })
  3184. .fail(function (xhr) {
  3185. OrganizrApiError(xhr);
  3186. });
  3187. }
  3188. function buildGroupManagement() {
  3189. organizrAPI2("GET", "api/v2/groups?includeUsers")
  3190. .success(function (data) {
  3191. try {
  3192. var response = data.response;
  3193. } catch (e) {
  3194. organizrCatchError(e, data);
  3195. }
  3196. $("#manageGroupTable").html(buildGroupManagementItem(response.data));
  3197. })
  3198. .fail(function (xhr) {
  3199. OrganizrApiError(xhr);
  3200. });
  3201. }
  3202. function buildTabEditor() {
  3203. organizrAPI2("GET", "api/v2/tabs")
  3204. .success(function (data) {
  3205. try {
  3206. var response = data.response;
  3207. } catch (e) {
  3208. organizrCatchError(e, data);
  3209. }
  3210. $("#tabEditorTable").html(buildTabEditorItem(response.data));
  3211. checkTabHomepageItems();
  3212. addTabSortable();
  3213. })
  3214. .fail(function (xhr) {
  3215. OrganizrApiError(xhr);
  3216. });
  3217. }
  3218. function addTabSortable() {
  3219. let el = document.getElementById("tabEditorTable");
  3220. let tabSorter = new Sortable(el, {
  3221. handle: ".sort-tabs-handle",
  3222. ghostClass: "sortable-ghost",
  3223. multiDrag: true,
  3224. selectedClass: "multi-selected",
  3225. onUpdate: function (evt) {
  3226. $("input.order").each(function (idx) {
  3227. $(this).val(idx + 1);
  3228. });
  3229. newTabsGlobal = $("#submit-tabs-form").serializeToJSON();
  3230. $(".saveTabOrderButton").removeClass("hidden");
  3231. },
  3232. });
  3233. }
  3234. function checkTabHomepageItems() {
  3235. var tabList = $(".checkTabHomepageItem");
  3236. $.each(tabList, function (i, v) {
  3237. var el = $(v);
  3238. var id = el.attr("id");
  3239. var name = el.attr("data-name");
  3240. var url = el.attr("data-url");
  3241. var urlLocal = el.attr("data-url-local");
  3242. checkTabHomepageItem(id, name, url, urlLocal);
  3243. });
  3244. }
  3245. function sortHomepageItemHrefs() {
  3246. var hrefList = $(".popup-with-form");
  3247. window.hrefList = new Array();
  3248. $.each(hrefList, function (i, v) {
  3249. var el = $(v);
  3250. var href = el.attr("href");
  3251. if (href.includes("#homepage-")) {
  3252. var splitHref = href.split("-");
  3253. window.hrefList[splitHref[1]] = i;
  3254. }
  3255. });
  3256. }
  3257. function checkTabHomepageItemList(name, url, urlLocal, id, check, tab) {
  3258. // might use this later
  3259. if (name.includes(check) || url.includes(check) || urlLocal.includes(check)) {
  3260. addEditHomepageItem(id, tab);
  3261. }
  3262. }
  3263. function checkTabHomepageItem(id, name, url, urlLocal) {
  3264. name = name.toLowerCase();
  3265. url = url.toLowerCase();
  3266. urlLocal = urlLocal.toLowerCase();
  3267. try {
  3268. let urlObject = new URL(url);
  3269. if (urlObject.pathname !== "/" && urlObject !== "#") {
  3270. url = urlObject.pathname;
  3271. }
  3272. } catch {
  3273. url = url;
  3274. }
  3275. if (
  3276. name.includes("sonarr") ||
  3277. url.includes("sonarr") ||
  3278. urlLocal.includes("sonarr")
  3279. ) {
  3280. addEditHomepageItem(id, "Sonarr");
  3281. } else if (
  3282. name.includes("radarr") ||
  3283. url.includes("radarr") ||
  3284. urlLocal.includes("radarr")
  3285. ) {
  3286. addEditHomepageItem(id, "Radarr");
  3287. } else if (
  3288. name.includes("lidarr") ||
  3289. url.includes("lidarr") ||
  3290. urlLocal.includes("lidarr")
  3291. ) {
  3292. addEditHomepageItem(id, "Lidarr");
  3293. } else if (
  3294. name.includes("couchpotato") ||
  3295. url.includes("couchpotato") ||
  3296. urlLocal.includes("couchpotato")
  3297. ) {
  3298. addEditHomepageItem(id, "CouchPotato");
  3299. } else if (
  3300. name.includes("sick") ||
  3301. url.includes("sick") ||
  3302. urlLocal.includes("sick")
  3303. ) {
  3304. addEditHomepageItem(id, "SickRage");
  3305. } else if (
  3306. (name.includes("plex") ||
  3307. url.includes("plex") ||
  3308. urlLocal.includes("plex")) &&
  3309. !name.includes("plexpy")
  3310. ) {
  3311. addEditHomepageItem(id, "Plex");
  3312. } else if (
  3313. name.includes("emby") ||
  3314. url.includes("emby") ||
  3315. urlLocal.includes("emby")
  3316. ) {
  3317. addEditHomepageItem(id, "Emby");
  3318. } else if (
  3319. name.includes("jdownloader") ||
  3320. url.includes("jdownloader") ||
  3321. urlLocal.includes("jdownloader") ||
  3322. name.includes("rsscrawler") ||
  3323. url.includes("rsscrawler") ||
  3324. urlLocal.includes("rsscrawler")
  3325. ) {
  3326. addEditHomepageItem(id, "jDownloader");
  3327. } else if (
  3328. name.includes("sab") ||
  3329. url.includes("sab") ||
  3330. urlLocal.includes("sab")
  3331. ) {
  3332. addEditHomepageItem(id, "SabNZBD");
  3333. } else if (
  3334. name.includes("nzbget") ||
  3335. url.includes("nzbget") ||
  3336. urlLocal.includes("nzbget")
  3337. ) {
  3338. addEditHomepageItem(id, "NZBGet");
  3339. } else if (
  3340. name.includes("transmission") ||
  3341. url.includes("transmission") ||
  3342. urlLocal.includes("transmission")
  3343. ) {
  3344. addEditHomepageItem(id, "Transmission");
  3345. } else if (
  3346. name.includes("qbit") ||
  3347. url.includes("qbit") ||
  3348. urlLocal.includes("qbit")
  3349. ) {
  3350. addEditHomepageItem(id, "qBittorrent");
  3351. } else if (
  3352. name.includes("rtorrent") ||
  3353. url.includes("rtorrent") ||
  3354. urlLocal.includes("rtorrent")
  3355. ) {
  3356. addEditHomepageItem(id, "rTorrent");
  3357. } else if (
  3358. name.includes("utorrent") ||
  3359. url.includes("utorrent") ||
  3360. urlLocal.includes("utorrent")
  3361. ) {
  3362. addEditHomepageItem(id, "utorrent");
  3363. } else if (
  3364. name.includes("deluge") ||
  3365. url.includes("deluge") ||
  3366. urlLocal.includes("deluge")
  3367. ) {
  3368. addEditHomepageItem(id, "Deluge");
  3369. } else if (
  3370. name.includes("ombi") ||
  3371. url.includes("ombi") ||
  3372. urlLocal.includes("ombi")
  3373. ) {
  3374. addEditHomepageItem(id, "Ombi");
  3375. } else if (
  3376. name.includes("healthcheck") ||
  3377. url.includes("healthcheck") ||
  3378. urlLocal.includes("healthcheck")
  3379. ) {
  3380. addEditHomepageItem(id, "HealthChecks");
  3381. } else if (
  3382. name.includes("jackett") ||
  3383. url.includes("jackett") ||
  3384. urlLocal.includes("jackett")
  3385. ) {
  3386. addEditHomepageItem(id, "Jackett");
  3387. } else if (
  3388. name.includes("prowlarr") ||
  3389. url.includes("prowlarr") ||
  3390. urlLocal.includes("prowlarr")
  3391. ) {
  3392. addEditHomepageItem(id, "Prowlarr");
  3393. } else if (
  3394. name.includes("unifi") ||
  3395. url.includes("unifi") ||
  3396. urlLocal.includes("unifi")
  3397. ) {
  3398. addEditHomepageItem(id, "Unifi");
  3399. } else if (
  3400. name.includes("tautulli") ||
  3401. url.includes("tautulli") ||
  3402. urlLocal.includes("tautulli")
  3403. ) {
  3404. addEditHomepageItem(id, "Tautulli");
  3405. }
  3406. }
  3407. function addEditHomepageItem(id, type) {
  3408. let html = '<i class="ti-home"></i>';
  3409. $("#" + id).html(html);
  3410. $("#" + id).attr("onclick", 'editHomepageItem("' + type + '")');
  3411. return false;
  3412. }
  3413. function buildCategoryEditor() {
  3414. organizrAPI2("GET", "api/v2/tabs")
  3415. .success(function (data) {
  3416. try {
  3417. var response = data.response;
  3418. } catch (e) {
  3419. organizrCatchError(e, data);
  3420. }
  3421. $("#categoryEditorTable").html(buildCategoryEditorItem(response.data));
  3422. })
  3423. .fail(function (xhr) {
  3424. OrganizrApiError(xhr);
  3425. });
  3426. }
  3427. /* END ORGANIZR API FUNCTIONS */
  3428. function buildLanguage(replace = false, newLang = null) {
  3429. var languageItems = "";
  3430. var currentLanguage = getCookie("organizrLanguage")
  3431. ? getCookie("organizrLanguage")
  3432. : window.lang.currentLang;
  3433. var newLangCode = "";
  3434. $.each(languageList, function (i, v) {
  3435. if (newLang === v.language) {
  3436. newLangCode = v.code;
  3437. }
  3438. var active = v.code == currentLanguage ? "" : "";
  3439. languageItems +=
  3440. `
  3441. <a onclick="window.lang.change('` +
  3442. v.code +
  3443. `');buildLanguage(true,'` +
  3444. v.language +
  3445. `')" href="javascript:void(0);" class="` +
  3446. active +
  3447. `">
  3448. <div class="mail-content"><h5 class="m-0">` +
  3449. v.language +
  3450. `</h5><span class="mail-desc" lang="en">` +
  3451. active +
  3452. `</span></div>
  3453. </a>
  3454. `;
  3455. });
  3456. var lang = `
  3457. <li class="dropdown" id="languageDropdown">
  3458. <a class="dropdown-toggle waves-effect waves-light" data-toggle="dropdown" href="#" aria-expanded="false"> <i class="fa fa-language"></i><span></span></a>
  3459. <ul class="dropdown-menu mailbox animated bounceInDown language-box">
  3460. <li>
  3461. <div class="drop-title" lang="en">Choose Language</div>
  3462. </li>
  3463. <li>
  3464. <div class="message-center default-scrollbar">${languageItems}</div>
  3465. </li>
  3466. </ul>
  3467. <!-- /.dropdown-messages -->
  3468. </li>
  3469. `;
  3470. if (replace == true) {
  3471. setLangCookie(newLangCode);
  3472. $("#languageDropdown").replaceWith(lang);
  3473. message(
  3474. "",
  3475. window.lang.translate("Changed Language To") + ": " + newLang,
  3476. activeInfo.settings.notifications.position,
  3477. "#FFF",
  3478. "success",
  3479. "3500"
  3480. );
  3481. } else if (replace == "wizard") {
  3482. $(lang).appendTo(".navbar-right");
  3483. } else {
  3484. return lang;
  3485. }
  3486. }
  3487. function updateUserInformation() {
  3488. var passwordMatch = true;
  3489. var username = $("#accountUsername").val();
  3490. var email = $("#accountEmail").val();
  3491. var password1 = $("#accountPassword1").val();
  3492. var password2 = $("#accountPassword2").val();
  3493. if (password1 != password2) {
  3494. passwordMatch = false;
  3495. messageSingle(
  3496. "",
  3497. "Passwords do not match",
  3498. activeInfo.settings.notifications.position,
  3499. "#FFF",
  3500. "error",
  3501. "5000"
  3502. );
  3503. return false;
  3504. }
  3505. if (username !== "" && email !== "" && passwordMatch == true) {
  3506. var post = {
  3507. username: username,
  3508. email: email,
  3509. };
  3510. if (password1 !== "") {
  3511. post["password"] = password1;
  3512. }
  3513. ajaxloader(".content-wrap", "in");
  3514. organizrAPI2("PUT", "api/v2/users/" + activeInfo.user.userID, post)
  3515. .success(function (data) {
  3516. try {
  3517. var response = data.response;
  3518. $.magnificPopup.close();
  3519. messageSingle(
  3520. "",
  3521. window.lang.translate("User Info Updated"),
  3522. activeInfo.settings.notifications.position,
  3523. "#FFF",
  3524. "success",
  3525. "5000"
  3526. );
  3527. } catch (e) {
  3528. organizrCatchError(e, data);
  3529. }
  3530. ajaxloader();
  3531. })
  3532. .fail(function (xhr) {
  3533. OrganizrApiError(xhr, "Update User");
  3534. ajaxloader();
  3535. });
  3536. }
  3537. }
  3538. function twoFA(action, type, secret = null) {
  3539. switch (action) {
  3540. case "activate":
  3541. organizrAPI2("POST", "api/v2/2fa/" + type, {})
  3542. .success(function (data) {
  3543. try {
  3544. var html = data.response;
  3545. } catch (e) {
  3546. organizrCatchError(e, data);
  3547. }
  3548. let div =
  3549. `
  3550. <div class="panel panel-default">
  3551. <div class="panel-heading">Enable 2FA: ` +
  3552. html.data.type +
  3553. `</div>
  3554. <div class="panel-wrapper collapse in">
  3555. <div class="panel-body">
  3556. <p class="twofa-modal-image"><img class="center" src="` +
  3557. html.data.url +
  3558. `"></p>
  3559. <h5 class="twofa-modal-secret text-center">` +
  3560. html.data.secret +
  3561. `</h5>
  3562. <div class="form-group m-t-10">
  3563. <div class="input-group" style="width: 100%;">
  3564. <div class="input-group-addon hidden-xs"><i class="ti-lock"></i></div>
  3565. <input type="text" class="form-control tfa-input" id="twofa-verify" placeholder="Code" autocomplete="off" autocorrect="off" autocapitalize="off" maxlength="6" spellcheck="false" autofocus="" required="">
  3566. </div>
  3567. <br>
  3568. <button class="btn btn-block btn-info" onclick="twoFA('verify','google');">Verify</button>
  3569. </div>
  3570. </div>
  3571. </div>
  3572. </div>
  3573. `;
  3574. swal({
  3575. content: createElementFromHTML(div),
  3576. buttons: false,
  3577. className: "bg-org",
  3578. });
  3579. })
  3580. .fail(function (xhr) {
  3581. OrganizrApiError(xhr, "2FA");
  3582. });
  3583. break;
  3584. case "deactivate":
  3585. organizrAPI2("DELETE", "api/v2/2fa")
  3586. .success(function (data) {
  3587. try {
  3588. message(
  3589. "2FA Removed",
  3590. "",
  3591. activeInfo.settings.notifications.position,
  3592. "#FFF",
  3593. "success",
  3594. "5000"
  3595. );
  3596. $(".2fa-list").replaceWith(buildTwoFA("internal"));
  3597. } catch (e) {
  3598. organizrCatchError(e, data);
  3599. }
  3600. })
  3601. .fail(function (xhr) {
  3602. OrganizrApiError(xhr, "2FA");
  3603. });
  3604. break;
  3605. case "verify":
  3606. var secret = $(".twofa-modal-secret").text();
  3607. var code = $("#twofa-verify").val();
  3608. if (type !== "" && secret !== "" && code !== "") {
  3609. organizrAPI2("POST", "api/v2/2fa", {
  3610. type: type,
  3611. secret: secret,
  3612. code: code,
  3613. })
  3614. .success(function (data) {
  3615. try {
  3616. var html = data.response;
  3617. message(
  3618. "2FA Success",
  3619. "Input Code Validated! Saving...",
  3620. activeInfo.settings.notifications.position,
  3621. "#FFF",
  3622. "success",
  3623. "5000"
  3624. );
  3625. swal.close();
  3626. twoFA("save", type, secret);
  3627. } catch (e) {
  3628. organizrCatchError(e, data);
  3629. }
  3630. })
  3631. .fail(function (xhr) {
  3632. OrganizrApiError(xhr, "2FA");
  3633. });
  3634. } else {
  3635. message(
  3636. "2FA Failed",
  3637. "Input Code",
  3638. activeInfo.settings.notifications.position,
  3639. "#FFF",
  3640. "warning",
  3641. "5000"
  3642. );
  3643. }
  3644. break;
  3645. case "save":
  3646. organizrAPI2("PUT", "api/v2/2fa", { type: type, secret: secret })
  3647. .success(function (data) {
  3648. try {
  3649. var html = data.response;
  3650. message(
  3651. "2FA Success",
  3652. "2FA Saved",
  3653. activeInfo.settings.notifications.position,
  3654. "#FFF",
  3655. "success",
  3656. "5000"
  3657. );
  3658. $(".2fa-list").replaceWith(buildTwoFA(type));
  3659. } catch (e) {
  3660. organizrCatchError(e, data);
  3661. }
  3662. })
  3663. .fail(function (xhr) {
  3664. OrganizrApiError(xhr, "2FA");
  3665. });
  3666. break;
  3667. }
  3668. }
  3669. function buildTwoFA(current) {
  3670. switch (current) {
  3671. case "internal":
  3672. var option = `
  3673. <div class="col-lg-3 col-sm-6 row-in-br">
  3674. <ul class="col-in">
  3675. <li>
  3676. <span class="circle circle-md bg-info"><i class="mdi mdi-webpack mdi-24px"></i></span>
  3677. </li>
  3678. <li class="col-middle">
  3679. <h5>Organizr Authenticator</h5>
  3680. <h5><span lang="en">Current</span></h5>
  3681. </li>
  3682. </ul>
  3683. </div>
  3684. <div class="col-lg-3 col-sm-6 row-in-br">
  3685. <ul class="col-in">
  3686. <li>
  3687. <span class="circle circle-md bg-info"><i class="fa fa-google"></i></span>
  3688. </li>
  3689. <li class="col-middle">
  3690. <h5>Google Authenticator</h5>
  3691. <h5><a href="javascript:void(0)" onclick="twoFA('activate','google');"><span lang="en">Activate</span></a></h5>
  3692. </li>
  3693. </ul>
  3694. </div>
  3695. `;
  3696. break;
  3697. case "google":
  3698. var option = `
  3699. <div class="col-lg-3 col-sm-6 row-in-br">
  3700. <ul class="col-in">
  3701. <li>
  3702. <span class="circle circle-md bg-info"><i class="fa fa-google"></i></span>
  3703. </li>
  3704. <li class="col-middle">
  3705. <h5>Google Authenticator</h5>
  3706. <h5><a href="javascript:void(0)" onclick="twoFA('deactivate','google');"><span lang="en">Deactivate</span></a></h5>
  3707. </li>
  3708. </ul>
  3709. </div>
  3710. `;
  3711. break;
  3712. default:
  3713. break;
  3714. }
  3715. var element =
  3716. `
  3717. <div class="white-box 2fa-list">
  3718. <div class="row row-in">
  3719. ` +
  3720. option +
  3721. `
  3722. </div>
  3723. </div>
  3724. `;
  3725. return element;
  3726. }
  3727. function scrapeCall() {
  3728. // Define the URL to scrape [only supports GET at the moment
  3729. var url = "https://api.github.com/users/causefx/repos";
  3730. // Define callbacks variable first
  3731. var callbacks = $.Callbacks();
  3732. // Add functions that will deal with the data
  3733. callbacks.add(scrapeFunction);
  3734. // Call the API function to scrape the page you want [types = 'json' or 'html']
  3735. scrapeAPI(url, callbacks, "json");
  3736. }
  3737. function scrapeFunction(data) {
  3738. // Here you would do whatever you like
  3739. if (data.data.result == "Success") {
  3740. console.log("Success!!!");
  3741. }
  3742. console.log("data:");
  3743. console.log(data);
  3744. }
  3745. function scrapeAPI(url, callbacks = null, type = null) {
  3746. if (typeof url === "undefined") {
  3747. console.log("error");
  3748. return false;
  3749. }
  3750. organizrAPI2("POST", "api/v2/homepage/scrape", { url: url, type: type })
  3751. .success(function (data) {
  3752. try {
  3753. let response = data.response;
  3754. if (response) {
  3755. if (callbacks) {
  3756. callbacks.fire(response);
  3757. }
  3758. }
  3759. } catch (e) {
  3760. organizrCatchError(e, data);
  3761. }
  3762. })
  3763. .fail(function (xhr) {
  3764. OrganizrApiError(xhr, "Scrape");
  3765. });
  3766. }
  3767. function revokeToken(id) {
  3768. organizrAPI2("DELETE", "api/v2/token/" + id, {})
  3769. .success(function (data) {
  3770. try {
  3771. $("#token-" + id).fadeOut();
  3772. message(
  3773. window.lang.translate("Removed Token"),
  3774. "",
  3775. activeInfo.settings.notifications.position,
  3776. "#FFF",
  3777. "success",
  3778. "3500"
  3779. );
  3780. } catch (e) {
  3781. organizrCatchError(e, data);
  3782. }
  3783. })
  3784. .fail(function (xhr) {
  3785. ajaxloader();
  3786. OrganizrApiError(xhr, "Revoke Token");
  3787. });
  3788. }
  3789. function buildActiveTokens(array) {
  3790. var parser = new UAParser();
  3791. var tokens = "";
  3792. $.each(array, function (i, v) {
  3793. parser.setUA(v.browser);
  3794. var result = parser.getResult();
  3795. var className =
  3796. activeInfo.user.token === v.token ? "bg-success text-inverse" : "";
  3797. var extraText =
  3798. activeInfo.user.token === v.token
  3799. ? '<span class="tooltip-info" data-toggle="tooltip" data-placement="right" title="" data-original-title="Current Token">...' +
  3800. v.token.substr(-10, 10) +
  3801. "</span>"
  3802. : v.token.substr(-10, 10);
  3803. if (typeof v.created == "object") {
  3804. v.created = v.created.date;
  3805. }
  3806. if (typeof v.expires == "object") {
  3807. v.expires = v.expires.date;
  3808. }
  3809. v.created = v.created.indexOf("Z") !== -1 ? v.created : v.created + "Z";
  3810. v.expires = v.expires.indexOf("Z") !== -1 ? v.expires : v.expires + "Z";
  3811. tokens +=
  3812. `
  3813. <tr id="token-` +
  3814. v.id +
  3815. `" class="` +
  3816. className +
  3817. `">
  3818. <td>` +
  3819. v.id +
  3820. `</td>
  3821. <td>` +
  3822. extraText +
  3823. `</td>
  3824. <td>` +
  3825. moment(v.created).format("LLL") +
  3826. `</td>
  3827. <td>` +
  3828. moment(v.expires).format("LLL") +
  3829. `</td>
  3830. <td>` +
  3831. v.ip +
  3832. `</td>
  3833. <td>
  3834. <button class="btn btn-danger waves-effect waves-light" type="button" onclick="revokeToken('` +
  3835. v.id +
  3836. `');"><i class="fa fa-ban"></i></button>
  3837. </td>
  3838. </tr>
  3839. `;
  3840. });
  3841. return (
  3842. `
  3843. <div class="col-lg-12">
  3844. <div class="panel panel-info">
  3845. <div class="panel-heading"> <span lang="en">Active Tokens</span>
  3846. <div class="pull-right"><a href="#" data-perform="panel-collapse"><i class="ti-plus"></i></a> </div>
  3847. </div>
  3848. <div class="panel-wrapper collapse" aria-expanded="true">
  3849. <div class="panel-body bg-org p-0">
  3850. <div class="table-responsive">
  3851. <table class="table color-table info-table">
  3852. <thead>
  3853. <tr>
  3854. <th>#</th>
  3855. <th lang="en">Token</th>
  3856. <th lang="en">Created</th>
  3857. <th lang="en">Expires</th>
  3858. <th lang="en">IP</th>
  3859. <th lang="en">Action</th>
  3860. </tr>
  3861. </thead>
  3862. <tbody>
  3863. ` +
  3864. tokens +
  3865. `
  3866. </tbody>
  3867. </table>
  3868. </div>
  3869. </div>
  3870. </div>
  3871. </div>
  3872. </div>
  3873. `
  3874. );
  3875. }
  3876. function accountManager(user) {
  3877. var passwordMessage = "";
  3878. switch (activeInfo.settings.misc.authBackend) {
  3879. case "plex":
  3880. passwordMessage = `
  3881. <div class="col-lg-12">
  3882. <div class="panel panel-info">
  3883. <div class="panel-heading"> <span lang="en">Password Notice</span>
  3884. <div class="pull-right"><a href="#" data-perform="panel-collapse"><i class="ti-plus"></i></a> </div>
  3885. </div>
  3886. <div class="panel-wrapper collapse" aria-expanded="true">
  3887. <div class="panel-body bg-org">
  3888. <p lang="en">If you signed in with a Plex Acct... Please use the following link to change your password there:</p><br>
  3889. <p><a href="https://app.plex.tv/auth#?resetPassword" target="_blank" lang="en">Change Password on Plex Website</a></p>
  3890. </div>
  3891. </div>
  3892. </div>
  3893. </div>
  3894. `;
  3895. break;
  3896. case "emby":
  3897. passwordMessage = `
  3898. <div class="col-lg-12">
  3899. <div class="panel panel-info">
  3900. <div class="panel-heading"> <span lang="en">Password Notice</span>
  3901. <div class="pull-right"><a href="#" data-perform="panel-collapse"><i class="ti-minus"></i></a> <a href="#" data-perform="panel-dismiss"><i class="ti-close"></i></a> </div>
  3902. </div>
  3903. <div class="panel-wrapper collapse in" aria-expanded="true">
  3904. <div class="panel-body bg-org">
  3905. <p lang="en">If you signed in with a Emby Acct... Please use the following link to change your password there:</p><br>
  3906. <p><a href="https://emby.media/community/index.php?app=core&module=global&section=lostpass" target="_blank">Change Password on Emby Website</a></p>
  3907. </div>
  3908. </div>
  3909. </div>
  3910. </div>
  3911. `;
  3912. break;
  3913. default:
  3914. passwordMessage = "";
  3915. break;
  3916. }
  3917. if (user.data.user.loggedin === true) {
  3918. var twoFADisable =
  3919. buildTwoFA(user.data.user.authService) == "internal" ? "" : "disabled";
  3920. var activeTokens = buildActiveTokens(user.data.user.tokenList);
  3921. var accountDiv =
  3922. `
  3923. <div id="account-area" class="white-popup mfp-with-anim mfp-hide">
  3924. <div class="col-md-10 col-md-offset-1">
  3925. <div class="row">
  3926. <div class="col-md-12">
  3927. <div class="panel panel-info m-0">
  3928. <div class="panel-heading">
  3929. <span lang="en">Account Information</span>
  3930. <div class="btn-group pull-right">
  3931. <button class="btn btn-info waves-effect waves-light" type="button" onclick="updateUserInformation();">
  3932. <i class="fa fa-save"></i>
  3933. </button>
  3934. </div>
  3935. </div>
  3936. <div class="panel-wrapper collapse in main-email-panel" aria-expanded="true">
  3937. <div class="panel-body">
  3938. <div class="form-body">
  3939. ` +
  3940. buildTwoFA(user.data.user.authService) +
  3941. `
  3942. <div class="row">
  3943. <div class="col-lg-12">
  3944. <div class="panel panel-info">
  3945. <div class="panel-heading"> <span lang="en">User Information</span>
  3946. <div class="pull-right"><a href="#" data-perform="panel-collapse"><i class="ti-plus"></i></a> </div>
  3947. </div>
  3948. <div class="panel-wrapper collapse" aria-expanded="true">
  3949. <div class="panel-body bg-org p-0 p-t-10">
  3950. <div class="col-md-6">
  3951. <div class="form-group">
  3952. <label class="control-label" lang="en">Username</label>
  3953. <input ` +
  3954. twoFADisable +
  3955. ` type="text" id="accountUsername" class="form-control" value="` +
  3956. activeInfo.user.username +
  3957. `"></div>
  3958. </div>
  3959. <div class="col-md-6">
  3960. <div class="form-group">
  3961. <label class="control-label" lang="en">Email</label>
  3962. <input ` +
  3963. twoFADisable +
  3964. ` type="text" id="accountEmail" class="form-control" value="` +
  3965. activeInfo.user.email +
  3966. `"></div>
  3967. </div>
  3968. <div class="col-md-6 userManagementPassword">
  3969. <div class="form-group">
  3970. <label class="control-label" lang="en">Password</label>
  3971. <input type="password" id="accountPassword1" class="form-control"></div>
  3972. </div>
  3973. <div class="col-md-6 userManagementPassword">
  3974. <div class="form-group">
  3975. <label class="control-label" lang="en">Verify Password</label>
  3976. <input type="password" id="accountPassword2" class="form-control"></div>
  3977. </div>
  3978. </div>
  3979. </div>
  3980. </div>
  3981. </div>
  3982. </div>
  3983. <!--/row-->
  3984. <div class="row">
  3985. ` +
  3986. activeTokens +
  3987. passwordMessage +
  3988. `
  3989. </div>
  3990. <!--/row-->
  3991. </div>
  3992. </div>
  3993. </div>
  3994. </div>
  3995. </div>
  3996. </div>
  3997. </div>
  3998. </div>
  3999. `;
  4000. $(".organizr-area").after(accountDiv);
  4001. pageLoad();
  4002. }
  4003. }
  4004. function userMenu(user) {
  4005. $("body").attr("data-active-user-group-name", user.data.user.group);
  4006. $("body").attr("data-active-user-group-id", user.data.user.groupID);
  4007. var sideMenu = "";
  4008. var menuList =
  4009. '<li class="hidden-xs" onclick="toggleFullScreen();"><a class="waves-effect waves-light"> <i class="ti-fullscreen fullscreen-icon"></i></a></li>';
  4010. var showDebug = activeInfo.settings.misc.debugArea
  4011. ? '<li><a href="javascript:void(0)" onclick="toggleDebug();"><i class="mdi mdi-bug fa-fw"></i> <span lang="en">Debug Area</span></a></li>'
  4012. : "";
  4013. menuList += buildLanguage();
  4014. if (user.data.user.loggedin === true) {
  4015. menuList +=
  4016. `
  4017. <li class="dropdown">
  4018. <a class="dropdown-toggle profile-pic" data-toggle="dropdown" href="javascript:void(0)"><img alt="" class="img-circle profile-image" src="` +
  4019. user.data.user.image +
  4020. `" width="36"><b class="hidden-xs">` +
  4021. user.data.user.username +
  4022. `</b><span class="caret"></span></a>
  4023. <ul class="dropdown-menu dropdown-user animated flipInY">
  4024. <li>
  4025. <div class="dw-user-box">
  4026. <div class="u-img"><img alt="user" src="` +
  4027. user.data.user.image +
  4028. `"></div>
  4029. <div class="u-text"><h4>` +
  4030. user.data.user.username +
  4031. `</h4><p class="text-muted">` +
  4032. user.data.user.email +
  4033. `</p><p class="text-muted">` +
  4034. user.data.user.group +
  4035. `</p></div>
  4036. </div>
  4037. </li>
  4038. <li class="divider" role="separator"></li>
  4039. <li class="append-menu"><a class="inline-popups" href="#account-area" data-effect="mfp-zoom-out"><i class="ti-settings fa-fw"></i> <span lang="en">Account Settings</span></a></li>
  4040. <li class="divider" role="separator"></li>
  4041. <li><a href="javascript:void(0)" onclick="lock();"><i class="ti-lock fa-fw"></i> <span lang="en">Lock Screen</span></a></li>
  4042. ${showDebug}
  4043. <li><a href="javascript:void(0)" onclick="logout();"><i class="fa fa-sign-out fa-fw"></i> <span lang="en">Logout</span></a></li>
  4044. </ul><!-- /.dropdown-user -->
  4045. </li><!-- /.dropdown -->
  4046. `;
  4047. sideMenu +=
  4048. `
  4049. <li class="user-pro">
  4050. <a href="#" class="waves-effect">
  4051. <img src="` +
  4052. user.data.user.image +
  4053. `" alt="user-img" class="img-circle">
  4054. <span class="hide-menu">` +
  4055. user.data.user.username +
  4056. `<span class="fa arrow"></span></span>
  4057. </a>
  4058. <ul class="nav nav-second-level collapse" aria-expanded="false" style="height: 0px;">
  4059. <li class="append-menu"><a class="inline-popups" href="#account-area" data-effect="mfp-zoom-out"><i class="ti-settings fa-fw"></i> <span lang="en">Account Settings</span></a></li>
  4060. <li><a href="javascript:void(0)" onclick="lock();"><i class="ti-lock fa-fw"></i> <span lang="en">Lock Screen</span></a></li>
  4061. ${showDebug}
  4062. <li><a href="javascript:void(0)" onclick="logout();"><i class="fa fa-sign-out fa-fw"></i> <span lang="en">Logout</span></a></li>
  4063. </ul>
  4064. </li>
  4065. `;
  4066. } else {
  4067. menuList +=
  4068. `
  4069. <li class="dropdown">
  4070. <a class="dropdown-toggle profile-pic" data-toggle="dropdown" href="javascript:void(0)"><img alt="" class="img-circle profile-image" src="` +
  4071. user.data.user.image +
  4072. `" width="36"><b class="hidden-xs">` +
  4073. user.data.user.username +
  4074. `</b><span class="caret"></span></a>
  4075. <ul class="dropdown-menu dropdown-user animated flipInY">
  4076. <li>
  4077. <div class="dw-user-box">
  4078. <div class="u-img"><img alt="user" src="` +
  4079. user.data.user.image +
  4080. `"></div>
  4081. <div class="u-text"><h4>` +
  4082. user.data.user.username +
  4083. `</h4></div>
  4084. </div>
  4085. </li>
  4086. <li class="divider" role="separator"></li>
  4087. <li class="append-menu"><a href="javascript:void(0)" class="show-login"><i class="fa fa-sign-in fa-fw"></i> <span lang="en">Login/Register</span></a></li>
  4088. </ul><!-- /.dropdown-user -->
  4089. </li><!-- /.dropdown -->
  4090. `;
  4091. sideMenu +=
  4092. `
  4093. <li class="user-pro">
  4094. <a href="#" class="waves-effect">
  4095. <img src="` +
  4096. user.data.user.image +
  4097. `" alt="user-img" class="img-circle">
  4098. <span class="hide-menu">` +
  4099. user.data.user.username +
  4100. `<span class="fa arrow"></span></span>
  4101. </a>
  4102. <ul class="nav nav-second-level collapse" aria-expanded="false" style="height: 0px;">
  4103. <li class="append-menu"><a href="javascript:void(0)" class="show-login"><i class="fa fa-sign-in fa-fw"></i> <span lang="en">Login/Register</span></a></li>
  4104. </ul>
  4105. </li>
  4106. `;
  4107. }
  4108. $(menuList).appendTo(".navbar-right").html;
  4109. //$(sideMenu).appendTo('#side-menu').html;
  4110. //message("",window.lang.translate('Welcome')+" "+user.data.user.username,activeInfo.settings.notifications.position,"#FFF","success","3500");
  4111. console.info(
  4112. "%c " +
  4113. window.lang.translate("Welcome") +
  4114. " %c ".concat(user.data.user.username, " "),
  4115. "color: white; background: #AD80FD; font-weight: 700;",
  4116. "color: #AD80FD; background: white; font-weight: 700;"
  4117. );
  4118. }
  4119. function menuExtraTabs() {
  4120. return [
  4121. {
  4122. id: 99999991,
  4123. type: 2,
  4124. group_id: 1,
  4125. name: "Github Repo",
  4126. access_url: "https://github.com/causefx/organizr",
  4127. url: "https://github.com/causefx/organizr",
  4128. image: "fontawesome::github",
  4129. active: activeInfo.settings.menuLink.githubMenuLink,
  4130. ping_url: null,
  4131. },
  4132. {
  4133. id: 99999992,
  4134. type: 1,
  4135. group_id: 1,
  4136. name: "Organizr Support",
  4137. access_url: "https://organizr.app/support",
  4138. url: "https://organizr.app/support",
  4139. image: "fontawesome::life-ring",
  4140. active: activeInfo.settings.menuLink.organizrSupportMenuLink,
  4141. ping_url: null,
  4142. },
  4143. {
  4144. id: 99999993,
  4145. type: 2,
  4146. group_id: 1,
  4147. name: "Organizr Docs",
  4148. access_url: "https://docs.organizr.app",
  4149. url: "https://docs.organizr.app",
  4150. image: "simpleline::docs",
  4151. active: activeInfo.settings.menuLink.organizrDocsMenuLink,
  4152. ping_url: null,
  4153. },
  4154. {
  4155. id: 99999994,
  4156. type: 1,
  4157. group_id: 1,
  4158. name: "Feature Request",
  4159. access_url: "https://feature.organizr.app",
  4160. url: "https://feature.organizr.app",
  4161. image: "simpleline::arrow-up-circle",
  4162. active: activeInfo.settings.menuLink.organizrFeatureRequestLink,
  4163. ping_url: null,
  4164. },
  4165. ];
  4166. }
  4167. function menuExtras(active) {
  4168. let adminMenu = '<li class="devider"></li>';
  4169. let extraOrganizrLinks = menuExtraTabs();
  4170. activeInfo.tabs = [].concat(activeInfo.tabs, menuExtraTabs());
  4171. $.each(extraOrganizrLinks, function (i, v) {
  4172. tabInformation[v.id] = {
  4173. id: v.id,
  4174. name: cleanClass(v.name),
  4175. active: false,
  4176. loaded: false,
  4177. increments: 0,
  4178. tabInfo: v,
  4179. };
  4180. if (v.type == 1) {
  4181. let frame = buildFrameContainer(v.id);
  4182. $(frame).appendTo($(".iFrame-listing"));
  4183. }
  4184. adminMenu +=
  4185. activeInfo.user.groupID <= v.group_id && v.active
  4186. ? buildMenuList(v.id)
  4187. : "";
  4188. });
  4189. if (active === true) {
  4190. return activeInfo.settings.menuLink.organizrSignoutMenuLink
  4191. ? `
  4192. <li class="devider"></li>
  4193. <li id="sign-out"><a class="waves-effect" onclick="logout();"><i class="fa fa-sign-out fa-fw"></i> <span class="hide-menu" lang="en">Logout</span></a></li>
  4194. ` + adminMenu
  4195. : "" + adminMenu;
  4196. } else {
  4197. return activeInfo.settings.menuLink.organizrSignoutMenuLink
  4198. ? `
  4199. <li class="devider"></li>
  4200. <li id="menu-login"><a class="waves-effect show-login" href="javascript:void(0)"><i class="mdi mdi-login fa-fw"></i> <span class="hide-menu" lang="en">Login/Register</span></a></li>
  4201. `
  4202. : "";
  4203. }
  4204. }
  4205. function categoryProcess(arrayItems) {
  4206. var menuList = "";
  4207. let categoryIn = activeInfo.settings.misc.expandCategoriesByDefault
  4208. ? "in"
  4209. : "";
  4210. let categoryActive = activeInfo.settings.misc.expandCategoriesByDefault
  4211. ? "active"
  4212. : "";
  4213. let categoryExpanded = activeInfo.settings.misc.expandCategoriesByDefault
  4214. ? "true"
  4215. : "false";
  4216. if (
  4217. Array.isArray(arrayItems["data"]["categories"]) &&
  4218. Array.isArray(arrayItems["data"]["tabs"])
  4219. ) {
  4220. $.each(arrayItems["data"]["categories"], function (i, v) {
  4221. if (v.count !== 0 && v.category_id !== 0) {
  4222. menuList +=
  4223. `
  4224. <li class="allGroupsList ` +
  4225. categoryActive +
  4226. `" data-group-name="` +
  4227. cleanClass(v.category) +
  4228. `">
  4229. <a class="waves-effect" href="javascript:void(0)">` +
  4230. iconPrefix(v.image) +
  4231. `<span class="hide-menu">` +
  4232. v.category +
  4233. ` <span class="fa arrow"></span> <span class="label label-rouded label-inverse pull-right">` +
  4234. v.count +
  4235. `</span></span><div class="menu-category-ping" data-good="0" data-bad="0"></div></a>
  4236. <ul class="nav nav-second-level category-` +
  4237. v.category_id +
  4238. ` collapse ` +
  4239. categoryIn +
  4240. `" aria-expanded="` +
  4241. categoryExpanded +
  4242. `"></ul>
  4243. </li>
  4244. `;
  4245. }
  4246. });
  4247. $(menuList).appendTo($("#side-menu"));
  4248. }
  4249. }
  4250. function buildFrame(id, split = null) {
  4251. let extra = split ? "right-" : "";
  4252. let tabInfo = findTab(id);
  4253. if (!tabInfo) {
  4254. organizrConsole("Build Frame", "No Tab Info Found... Id: " + id, "error");
  4255. return false;
  4256. }
  4257. var sandbox = activeInfo.settings.misc.sandbox;
  4258. sandbox = sandbox.replace(/,/gi, " ");
  4259. sandbox = sandbox ? ' sandbox="' + sandbox + '"' : "";
  4260. var allow = activeInfo.settings.misc.iframeAllow;
  4261. allow = allow.replace(/,/gi, "; ");
  4262. allow = allow ? ' allow="' + allow + '"' : "";
  4263. return (
  4264. `
  4265. <iframe ` +
  4266. allow +
  4267. ` frameborder="0" id="frame-` +
  4268. extra +
  4269. id +
  4270. `" ` +
  4271. sandbox +
  4272. ` scrolling="auto" src="` +
  4273. tabInfo.access_url +
  4274. `" class="iframe"></iframe>
  4275. `
  4276. );
  4277. }
  4278. function buildFrameContainer(id, split = null) {
  4279. let extra = split ? "right-" : "";
  4280. return (
  4281. `<div id="container-` +
  4282. extra +
  4283. id +
  4284. `" class="frame-container frame-${id} hidden" ></div>`
  4285. );
  4286. }
  4287. function buildInternalContainer(id, split = null) {
  4288. let extra = split ? "right-" : "";
  4289. return (
  4290. `<div id="internal-` +
  4291. extra +
  4292. id +
  4293. `" class="internal-container frame-${id} hidden"></div>`
  4294. );
  4295. }
  4296. function buildMenuList(id) {
  4297. let tabInfo = findTab(id);
  4298. if (!tabInfo) {
  4299. organizrConsole(
  4300. "Build Menu List",
  4301. "No Tab Info Found... Id: " + id,
  4302. "error"
  4303. );
  4304. return false;
  4305. }
  4306. let name = tabInfo.name;
  4307. let icon = tabInfo.image;
  4308. let ping = typeof tabInfo.ping_url !== "undefined" ? tabInfo.ping_url : null;
  4309. ping =
  4310. ping !== null && ping !== ""
  4311. ? `<small class="menu-` +
  4312. cleanClass(ping) +
  4313. `-ping-ms hidden-xs label label-rouded label-inverse pull-right pingTime hidden">
  4314. </small><div class="menu-` +
  4315. cleanClass(ping) +
  4316. `-ping" data-tab-name="` +
  4317. name +
  4318. `" data-previous-state=""></div>`
  4319. : "";
  4320. return (
  4321. `<li class="allTabsList" id="menu-${id}" data-tab-id="${id}"><a class="waves-effect" href="javascript:void(0)" onclick="tabActions(event,'${id}');" onauxclick="tabActions(event,'${id}');">` +
  4322. iconPrefix(icon) +
  4323. `<span class="hide-menu elip sidebar-tabName">` +
  4324. name +
  4325. `</span>` +
  4326. ping +
  4327. `</a></li>`
  4328. );
  4329. }
  4330. function tabProcess(arrayItems) {
  4331. var iFrameList = "";
  4332. var internalList = "";
  4333. var defaultTabId = null;
  4334. if (
  4335. Array.isArray(arrayItems["data"]["tabs"]) &&
  4336. arrayItems["data"]["tabs"].length > 0
  4337. ) {
  4338. $.each(arrayItems["data"]["tabs"], function (i, v) {
  4339. if (v.enabled === 1 && v.access_url) {
  4340. tabInformation[v.id] = {
  4341. id: v.id,
  4342. name: cleanClass(v.name),
  4343. active: false,
  4344. loaded: false,
  4345. increments: 0,
  4346. tabInfo: v,
  4347. };
  4348. switch (v.timeout) {
  4349. case 1:
  4350. case "1":
  4351. tabActionsList["close"].push({
  4352. id: v.id,
  4353. tab: cleanClass(v.name),
  4354. action_ms: v.timeout_ms,
  4355. });
  4356. break;
  4357. case 2:
  4358. case "2":
  4359. tabActionsList["refresh"].push({
  4360. id: v.id,
  4361. tab: cleanClass(v.name),
  4362. action_ms: v.timeout_ms,
  4363. });
  4364. break;
  4365. default:
  4366. //nada
  4367. }
  4368. if (v.default === 1) {
  4369. defaultTabId = v.id;
  4370. }
  4371. var menuList = buildMenuList(v.id);
  4372. if (v.category_id === 0) {
  4373. if (activeInfo.settings.misc.unsortedTabs === "top") {
  4374. $(menuList).prependTo($("#side-menu"));
  4375. } else if (activeInfo.settings.misc.unsortedTabs === "bottom") {
  4376. $(menuList).appendTo($("#side-menu"));
  4377. }
  4378. } else {
  4379. if (activeInfo.settings.misc.unsortedTabs === "top") {
  4380. $(menuList).prependTo($(".category-" + v.category_id));
  4381. } else if (activeInfo.settings.misc.unsortedTabs === "bottom") {
  4382. $(menuList).appendTo($(".category-" + v.category_id));
  4383. }
  4384. }
  4385. switch (v.type) {
  4386. case 0:
  4387. case "0":
  4388. case "internal":
  4389. internalList = buildInternalContainer(v.id);
  4390. $(internalList).appendTo($(".internal-listing"));
  4391. internalList = buildInternalContainer(v.id, true);
  4392. $(internalList).appendTo($(".internal-listing-right"));
  4393. if (v.preload) {
  4394. var newTab = $("#internal-" + v.id);
  4395. organizrConsole(
  4396. "Tab Function",
  4397. "Preloading new tab for: " + cleanClass(v.name)
  4398. );
  4399. $("#menu-" + v.id + " a")
  4400. .children()
  4401. .addClass("tabLoaded");
  4402. newTab.addClass("loaded");
  4403. loadInternal(v.id);
  4404. }
  4405. break;
  4406. case 1:
  4407. case "1":
  4408. case "iframe":
  4409. iFrameList = buildFrameContainer(v.id);
  4410. $(iFrameList).appendTo($(".iFrame-listing"));
  4411. iFrameList = buildFrameContainer(v.id, true);
  4412. $(iFrameList).appendTo($(".iFrame-listing-right"));
  4413. if (v.preload) {
  4414. var newTab = $("#container-" + v.id);
  4415. organizrConsole(
  4416. "Tab Function",
  4417. "Preloading new tab for: " + cleanClass(v.name)
  4418. );
  4419. $("#menu-" + v.id + " a")
  4420. .children()
  4421. .addClass("tabLoaded");
  4422. newTab.addClass("loaded");
  4423. $(buildFrame(v.id)).appendTo(newTab);
  4424. }
  4425. break;
  4426. case 2:
  4427. case 3:
  4428. case "2":
  4429. case "3":
  4430. case "_blank":
  4431. case "popout":
  4432. break;
  4433. default:
  4434. organizrConsole("Tab Function", "Action not set", "error");
  4435. }
  4436. }
  4437. });
  4438. $("#side-menu").metisMenu({
  4439. toggle: activeInfo.settings.misc.autoCollapseCategories,
  4440. });
  4441. getDefault(defaultTabId);
  4442. } else {
  4443. noTabs(arrayItems);
  4444. }
  4445. $(menuExtras(arrayItems.data.user.loggedin)).appendTo($("#side-menu"));
  4446. }
  4447. function buildLogin() {
  4448. swapDisplay("login");
  4449. closeSideMenu();
  4450. removeMenuActive();
  4451. $("#menu-login a").addClass("active");
  4452. organizrAPI2("GET", "api/v2/page/login")
  4453. .success(function (data) {
  4454. try {
  4455. var response = data.response;
  4456. organizrConsole("Organizr Function", "Opening Login Page");
  4457. $(".login-area").html(response.data);
  4458. setHash("OrganizrLogin");
  4459. } catch (e) {
  4460. organizrCatchError(e, data);
  4461. }
  4462. })
  4463. .fail(function (xhr) {
  4464. OrganizrApiError(xhr, "Login Error");
  4465. });
  4466. $("#preloader").fadeOut();
  4467. }
  4468. function buildLockscreen() {
  4469. $("#preloader").fadeIn();
  4470. closeSideMenu();
  4471. organizrAPI2("GET", "api/v2/page/lockscreen")
  4472. .success(function (data) {
  4473. try {
  4474. var response = data.response;
  4475. organizrConsole("Organizr Function", "Adding Lockscreen");
  4476. $(response.data).appendTo($("body"));
  4477. } catch (e) {
  4478. organizrCatchError(e, data);
  4479. }
  4480. })
  4481. .fail(function (xhr) {
  4482. OrganizrApiError(xhr);
  4483. });
  4484. $("#preloader").fadeOut();
  4485. }
  4486. function buildSplashScreenItem(arrayItems) {
  4487. var splashList = "";
  4488. if (
  4489. Array.isArray(arrayItems["data"]["tabs"]) &&
  4490. arrayItems["data"]["tabs"].length > 0
  4491. ) {
  4492. arrayItems["data"]["tabs"].sort(
  4493. (a, b) => parseFloat(a.order) - parseFloat(b.order)
  4494. );
  4495. $.each(arrayItems["data"]["tabs"], function (i, v) {
  4496. if (v.enabled === 1 && v.splash === 1 && v.access_url) {
  4497. var image = iconPrefixSplash(v.image);
  4498. if (image.indexOf(".") !== -1) {
  4499. var dataSrc = 'data-src="' + iconPrefixSplash(v.image) + '"';
  4500. var nonImage = "";
  4501. } else {
  4502. var dataSrc = "";
  4503. var nonImage =
  4504. '<span class="text-uppercase badge bg-org splash-badge">' +
  4505. image +
  4506. "</span>";
  4507. }
  4508. splashList += `
  4509. <div class="col-xs-12 col-sm-3 col-md-3 col-lg-3 col-xl-2 mouse hvr-grow m-b-20" id="menu-${cleanClass(
  4510. v.name
  4511. )}" type="${v.type}" data-url="${
  4512. v.access_url
  4513. }" onclick="tabActions(event,'${v.id}');">
  4514. <div class="homepage-drag fc-event bg-org lazyload" ${dataSrc}>
  4515. ${nonImage}
  4516. <span class="homepage-text">&nbsp; ${v.name}</span>
  4517. </div>
  4518. </div>
  4519. `;
  4520. }
  4521. });
  4522. }
  4523. return splashList !== "" ? splashList : false;
  4524. }
  4525. function buildSplashScreen(json) {
  4526. let hiddenSplash = directToHash ? "hidden" : "in";
  4527. var items = buildSplashScreenItem(json);
  4528. var menu =
  4529. '<li ><a href="javascript:void(0)" onclick="$(\'.splash-screen\').removeClass(\'hidden\').addClass(\'in\')"><i class="ti-layout-grid2 fa-fw"></i> <span lang="en">Splash Page</span></a></li>';
  4530. if (items) {
  4531. closeSideMenu();
  4532. organizrConsole("Organizr Function", "Adding Splash Screen");
  4533. var splash =
  4534. `
  4535. <section id="splashScreen" class="lock-screen splash-screen default-scroller fade ${hiddenSplash}">
  4536. <div class="row p-20 flexbox">` +
  4537. items +
  4538. `</div>
  4539. <div class="row p-20 p-t-0 flexbox">
  4540. <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 col-xl-12 mouse hvr-wobble-bottom bottom-close-splash" onclick="$('.splash-screen').addClass('hidden').removeClass('in')">
  4541. <div class="homepage-drag fc-event bg-danger lazyload" data-src="">
  4542. <span class="homepage-text">&nbsp; Close Splash</span>
  4543. </div>
  4544. </div>
  4545. </div>
  4546. </section>
  4547. `;
  4548. $(splash).appendTo($("body"));
  4549. $(".append-menu").after(menu);
  4550. }
  4551. }
  4552. function buildUserGroupSelect(array, userID, groupID) {
  4553. var groupSelect = "";
  4554. var selected = "";
  4555. var disabled = "";
  4556. if (groupID == 0 && userID == 1) {
  4557. disabled = "disabled";
  4558. }
  4559. $.each(array, function (i, v) {
  4560. selected = "";
  4561. if (v.group_id == groupID) {
  4562. selected = "selected";
  4563. }
  4564. var selectDisable = v.group_id == 0 || v.group_id == 999 ? "disabled" : "";
  4565. groupSelect +=
  4566. "<option " +
  4567. selected +
  4568. " " +
  4569. selectDisable +
  4570. ' value="' +
  4571. v.group_id +
  4572. '">' +
  4573. v.group +
  4574. "</option>";
  4575. });
  4576. return (
  4577. '<td><select name="userGroupSelect" class="form-control userGroupSelect" ' +
  4578. disabled +
  4579. ">" +
  4580. groupSelect +
  4581. "</select></td>"
  4582. );
  4583. }
  4584. function buildTabGroupSelect(array, tabID, groupID, type) {
  4585. var groupSelect = "";
  4586. var selected = "";
  4587. let name = type == "tabGroupSelectMax" ? "group_id_max" : "group_id";
  4588. $.each(array, function (i, v) {
  4589. selected = "";
  4590. if (v.group_id == groupID) {
  4591. selected = "selected";
  4592. }
  4593. groupSelect +=
  4594. "<option " +
  4595. selected +
  4596. ' value="' +
  4597. v.group_id +
  4598. '">' +
  4599. v.group +
  4600. "</option>";
  4601. });
  4602. return (
  4603. '<td><select name="tab[' +
  4604. tabID +
  4605. "]." +
  4606. name +
  4607. '" class="form-control ' +
  4608. type +
  4609. '">' +
  4610. groupSelect +
  4611. "</select></td>"
  4612. );
  4613. }
  4614. function buildTabTypeSelect(tabID, typeID, disabled) {
  4615. var array = [
  4616. {
  4617. type_id: 0,
  4618. type: "Organizr",
  4619. },
  4620. {
  4621. type_id: 1,
  4622. type: "iFrame",
  4623. },
  4624. {
  4625. type_id: 2,
  4626. type: "New Window",
  4627. },
  4628. ];
  4629. var typeSelect = "";
  4630. var selected = "";
  4631. disabled = disabled == "disabled" && typeID !== 0 ? null : disabled;
  4632. $.each(array, function (i, v) {
  4633. selected = "";
  4634. if (v.type_id == typeID) {
  4635. selected = "selected";
  4636. }
  4637. var disabledAttr =
  4638. disabled === "disabled" && v.type !== "Internal" ? "disabled" : "";
  4639. typeSelect +=
  4640. "<option " +
  4641. selected +
  4642. ' value="' +
  4643. v.type_id +
  4644. '" ' +
  4645. disabledAttr +
  4646. ">" +
  4647. v.type +
  4648. "</option>";
  4649. });
  4650. return (
  4651. '<td><select name="tab[' +
  4652. tabID +
  4653. '].type" class="form-control tabTypeSelect">' +
  4654. typeSelect +
  4655. "</select></td>"
  4656. );
  4657. }
  4658. function buildTabCategorySelect(array, tabID, categoryID) {
  4659. var categorySelect = "";
  4660. var selected = "";
  4661. $.each(array, function (i, v) {
  4662. selected = "";
  4663. if (v.category_id == categoryID) {
  4664. selected = "selected";
  4665. }
  4666. categorySelect +=
  4667. "<option " +
  4668. selected +
  4669. ' value="' +
  4670. v.category_id +
  4671. '">' +
  4672. v.category +
  4673. "</option>";
  4674. });
  4675. return (
  4676. '<td><select name="tab[' +
  4677. tabID +
  4678. '].category_id" class="form-control tabCategorySelect">' +
  4679. categorySelect +
  4680. "</select></td>"
  4681. );
  4682. }
  4683. function buildUserManagementItem(array) {
  4684. var userList = "";
  4685. $.each(array.users, function (i, v) {
  4686. var disabledDelete =
  4687. v.group_id == 999 || v.group_id == 0 ? "disabled" : "deleteUser";
  4688. userList +=
  4689. `
  4690. <tr class="userManagement" data-id="` +
  4691. v.id +
  4692. `" data-username="` +
  4693. v.username +
  4694. `" data-group="` +
  4695. v.group +
  4696. `" data-email="` +
  4697. v.email +
  4698. `">
  4699. <td class="text-center el-element-overlay">
  4700. <div class="el-card-item p-0">
  4701. <div class="el-card-avatar el-overlay-1 m-0">
  4702. <img alt="user-img" class="img-circle" src="` +
  4703. v.image +
  4704. `" width="45">
  4705. <div class="el-overlay">
  4706. <ul class="el-info">
  4707. ` +
  4708. v.id +
  4709. `
  4710. </ul>
  4711. </div>
  4712. </div>
  4713. </div>
  4714. </td>
  4715. <td>` +
  4716. v.username +
  4717. `
  4718. <br/><span class="text-muted">` +
  4719. v.email +
  4720. `</span></td>
  4721. <td>` +
  4722. moment(v.register_date).format("ll") +
  4723. `
  4724. <br/><span class="text-muted">` +
  4725. moment(v.register_date).format("LT") +
  4726. `</span></td>
  4727. ` +
  4728. buildUserGroupSelect(array.groups, v.id, v.group_id) +
  4729. `
  4730. <td><button type="button" class="btn btn-info btn-outline btn-circle btn-lg m-r-5 editUserButton popup-with-form" href="#edit-user-form" data-effect="mfp-3d-unfold"><i class="ti-pencil-alt"></i></button></td>
  4731. <td><button type="button" class="btn btn-info btn-outline btn-circle btn-lg m-r-20 emailUser"><i class="ti-email"></i></button></td>
  4732. <td><button type="button" class="btn btn-danger btn-outline btn-circle btn-lg m-r-5 ` +
  4733. disabledDelete +
  4734. `"><i class="ti-trash"></i></button></td>
  4735. </tr>
  4736. `;
  4737. });
  4738. return userList;
  4739. }
  4740. function buildGroupManagementItem(array) {
  4741. var userList = "";
  4742. $.each(array.groups, function (i, v) {
  4743. var userCount = array.users.reduce(function (n, group) {
  4744. return n + (group.group_id == v.group_id);
  4745. }, 0);
  4746. var disabledDefault =
  4747. v.group_id == 0 || v.group_id == 999 ? "disabled" : "";
  4748. var disabledDelete =
  4749. userCount > 0 || v.default == 1 || v.group_id == 999 || v.group_id <= 1
  4750. ? "disabled"
  4751. : "";
  4752. var defaultIcon =
  4753. v.default == 1 ? "icon-user-following" : "icon-user-follow";
  4754. var defaultColor = v.default == 1 ? "btn-info disabled" : "btn-warning";
  4755. userList +=
  4756. `
  4757. <tr class="userManagement" data-id="` +
  4758. v.id +
  4759. `" data-group-id="` +
  4760. v.group_id +
  4761. `" data-group="` +
  4762. v.group +
  4763. `" data-default="` +
  4764. tof(v.default) +
  4765. `" data-image="` +
  4766. v.image +
  4767. `" data-user-count="` +
  4768. userCount +
  4769. `">
  4770. <td class="text-center el-element-overlay">
  4771. <div class="el-card-item p-0">
  4772. <div class="el-card-avatar el-overlay-1 m-0">
  4773. <div class="tabEditorIcon">` +
  4774. iconPrefix(v.image) +
  4775. `</div>
  4776. <div class="el-overlay">
  4777. <ul class="el-info">
  4778. ` +
  4779. v.group_id +
  4780. `
  4781. </ul>
  4782. </div>
  4783. </div>
  4784. </div>
  4785. </td>
  4786. <td>` +
  4787. v.group +
  4788. `</td>
  4789. <td>` +
  4790. userCount +
  4791. `</td>
  4792. <td><button type="button" class="btn ` +
  4793. defaultColor +
  4794. ` btn-outline btn-circle btn-lg m-r-5 changeDefaultGroup" ` +
  4795. disabledDefault +
  4796. `><i class="` +
  4797. defaultIcon +
  4798. `"></i></button></td>
  4799. <td><button type="button" class="btn btn-info btn-outline btn-circle btn-lg m-r-5 editGroupButton popup-with-form" href="#edit-group-form" data-effect="mfp-3d-unfold"><i class="ti-pencil-alt"></i></button></td>
  4800. <td><button type="button" class="btn btn-danger btn-outline btn-circle btn-lg m-r-5 deleteUserGroup" ` +
  4801. disabledDelete +
  4802. `><i class="ti-trash"></i></button></td>
  4803. </tr>
  4804. `;
  4805. });
  4806. return userList;
  4807. }
  4808. function buildCategoryEditorItem(array) {
  4809. var categoryList = "";
  4810. $.each(array.categories, function (i, v) {
  4811. var tabCount = array.tabs.reduce(function (n, category) {
  4812. return n + (category.category_id == v.category_id);
  4813. }, 0);
  4814. var disabledDefault = v.default == 1 ? "disabled" : "";
  4815. var disabledDelete =
  4816. tabCount > 0 || v.default == 1 || v.category_id == 0 ? "disabled" : "";
  4817. var defaultIcon =
  4818. v.default == 1 ? "icon-user-following" : "icon-user-follow";
  4819. var defaultColor = v.default == 1 ? "btn-info disabled" : "btn-warning";
  4820. categoryList +=
  4821. `
  4822. <tr class="categoryEditor" data-id="` +
  4823. v.id +
  4824. `" data-order="` +
  4825. v.order +
  4826. `" data-category-id="` +
  4827. v.category_id +
  4828. `" data-name="` +
  4829. v.category +
  4830. `" data-default="` +
  4831. tof(v.default) +
  4832. `" data-image="` +
  4833. v.image +
  4834. `" data-tab-count="` +
  4835. tabCount +
  4836. `">
  4837. <input type="hidden" class="form-control order" name="category[` +
  4838. v.id +
  4839. `].order" value="` +
  4840. v.order +
  4841. `">
  4842. <input type="hidden" class="form-control" name="category[` +
  4843. v.id +
  4844. `].originalOrder" value="` +
  4845. v.order +
  4846. `">
  4847. <input type="hidden" class="form-control" name="category[` +
  4848. v.id +
  4849. `].name" value="` +
  4850. v.category +
  4851. `">
  4852. <input type="hidden" class="form-control" name="category[` +
  4853. v.id +
  4854. `].id" value="` +
  4855. v.id +
  4856. `">
  4857. <td class="text-center el-element-overlay">
  4858. <div class="el-card-item p-0">
  4859. <div class="el-card-avatar el-overlay-1 m-0">
  4860. <div class="tabEditorIcon">` +
  4861. iconPrefix(v.image) +
  4862. `</div>
  4863. <div class="el-overlay bg-org">
  4864. <ul class="el-info">
  4865. <i class="fa fa-bars"></i>
  4866. </ul>
  4867. </div>
  4868. </div>
  4869. </div>
  4870. </td>
  4871. <td>` +
  4872. v.category +
  4873. `</td>
  4874. <td style="text-align:center">` +
  4875. tabCount +
  4876. `</td>
  4877. <td style="text-align:center"><button type="button" class="btn ` +
  4878. defaultColor +
  4879. ` btn-outline btn-circle btn-lg m-r-5 changeDefaultCategory" ` +
  4880. disabledDefault +
  4881. `><i class="` +
  4882. defaultIcon +
  4883. `"></i></button></td>
  4884. <td style="text-align:center"><button type="button" class="btn btn-info btn-outline btn-circle btn-lg m-r-5 editCategoryButton popup-with-form" href="#edit-category-form" data-effect="mfp-3d-unfold"><i class="ti-pencil-alt"></i></button></td>
  4885. <td style="text-align:center"><button type="button" class="btn btn-danger btn-outline btn-circle btn-lg m-r-5 deleteCategory" ` +
  4886. disabledDelete +
  4887. `><i class="ti-trash"></i></button></td>
  4888. </tr>
  4889. `;
  4890. });
  4891. return categoryList;
  4892. }
  4893. function buildTabEditorItem(array) {
  4894. var tabList = "";
  4895. $.each(array.tabs, function (i, v) {
  4896. let deleteDisabled = "deleteTab";
  4897. let buttonDisabled = "";
  4898. let typeDisabled = "";
  4899. if (v.url !== null) {
  4900. deleteDisabled =
  4901. v.url.indexOf("/page/settings") > 0 ? "disabled" : "deleteTab";
  4902. buttonDisabled = v.url.indexOf("/page/settings") > 0 ? "disabled" : "";
  4903. typeDisabled = v.url.indexOf("/v2/page/") > 0 ? "disabled" : "";
  4904. }
  4905. tabList +=
  4906. `
  4907. <tr class="tabEditor" data-order="` +
  4908. v.order +
  4909. `" data-original-order="` +
  4910. v.order +
  4911. `" data-id="` +
  4912. v.id +
  4913. `" data-group-id="` +
  4914. v.group_id +
  4915. `" data-category-id="` +
  4916. v.category_id +
  4917. `" data-name="` +
  4918. v.name +
  4919. `" data-url="` +
  4920. v.url +
  4921. `" data-local-url="` +
  4922. v.url_local +
  4923. `" data-ping-url="` +
  4924. v.ping_url +
  4925. `" data-image="` +
  4926. v.image +
  4927. `" data-tab-action-type="` +
  4928. v.timeout +
  4929. `" data-tab-action-time="` +
  4930. v.timeout_ms +
  4931. `">
  4932. <input type="hidden" class="form-control" name="tab[` +
  4933. v.id +
  4934. `].id" value="` +
  4935. v.id +
  4936. `">
  4937. <input type="hidden" class="form-control order" name="tab[` +
  4938. v.id +
  4939. `].order" value="` +
  4940. v.order +
  4941. `">
  4942. <input type="hidden" class="form-control" name="tab[` +
  4943. v.id +
  4944. `].originalOrder" value="` +
  4945. v.order +
  4946. `">
  4947. <td class="mouse-grab sort-tabs-handle">
  4948. <i class="icon-options-vertical m-r-5"></i>
  4949. <!-- May use later on
  4950. <div class="btn-group dropside visible-xs">
  4951. <button aria-expanded="false" data-toggle="dropdown" class="btn btn-default btn-outline dropdown-toggle waves-effect waves-light" type="button"> <i class="icon-options-vertical m-r-5"></i> <span class="caret"></span></button>
  4952. <ul role="menu" class="dropdown-menu">
  4953. <li><a href="#"><i class="fa fa-angle-double-up"></i></a></li>
  4954. <li><a href="#"><i class="fa fa-angle-up"></i></a></li>
  4955. <li><a href="#"><i class="fa fa-angle-double-down"></i></a></li>
  4956. <li><a href="#"><i class="fa fa-angle-down"></i></a></li>
  4957. </ul>
  4958. </div>
  4959. -->
  4960. </td>
  4961. <td style="text-align:center" class="text-center el-element-overlay">
  4962. <div class="el-card-item p-0">
  4963. <div class="el-card-avatar el-overlay-1 m-0 tooltip-info" data-toggle="tooltip" data-placement="top" title="" data-original-title="${v.id}">
  4964. <div class="tabEditorIcon">` +
  4965. iconPrefix(v.image) +
  4966. `</div>
  4967. </div>
  4968. </div>
  4969. </td>
  4970. <td><span class="tooltip-info" data-toggle="tooltip" data-placement="right" title="" data-original-title="` +
  4971. v.url +
  4972. `">` +
  4973. v.name +
  4974. `</span><span id="checkTabHomepageItem-` +
  4975. v.id +
  4976. `" data-url="` +
  4977. v.url +
  4978. `" data-url-local="` +
  4979. v.url_local +
  4980. `" data-name="` +
  4981. v.name +
  4982. `" class="checkTabHomepageItem mouse label label-rouded label-inverse pull-right"></span></td>
  4983. ` +
  4984. buildTabCategorySelect(array.categories, v.id, v.category_id) +
  4985. `
  4986. ` +
  4987. buildTabGroupSelect(array.groups, v.id, v.group_id, "tabGroupSelectMin") +
  4988. `
  4989. ` +
  4990. buildTabGroupSelect(
  4991. array.groups,
  4992. v.id,
  4993. v.group_id_max,
  4994. "tabGroupSelectMax"
  4995. ) +
  4996. `
  4997. ` +
  4998. buildTabTypeSelect(v.id, v.type, typeDisabled) +
  4999. `
  5000. <td style="text-align:center"><div class="radio radio-purple"><input onclick="radioLoop(this);" type="radio" class="defaultSwitch" id="tab[` +
  5001. v.id +
  5002. `].default" name="tab[` +
  5003. v.id +
  5004. `].default" value="true" ` +
  5005. tof(v.default, "c") +
  5006. `><label for="tab[` +
  5007. v.id +
  5008. `].default"></label></div></td>
  5009. <td style="text-align:center"><input ` +
  5010. buttonDisabled +
  5011. ` type="checkbox" class="js-switch enabledSwitch ` +
  5012. buttonDisabled +
  5013. `" data-size="small" data-color="#99d683" data-secondary-color="#f96262" name="tab[` +
  5014. v.id +
  5015. `].enabled" value="true" ` +
  5016. tof(v.enabled, "c") +
  5017. `/><input type="hidden" class="form-control" name="tab[` +
  5018. v.id +
  5019. `].enabled" value="false"></td>
  5020. <td style="text-align:center"><input type="checkbox" class="js-switch splashSwitch" data-size="small" data-color="#99d683" data-secondary-color="#f96262" name="tab[` +
  5021. v.id +
  5022. `].splash" value="true" ` +
  5023. tof(v.splash, "c") +
  5024. `/><input type="hidden" class="form-control" name="tab[` +
  5025. v.id +
  5026. `].splash" value="false"></td>
  5027. <td style="text-align:center"><input type="checkbox" class="js-switch pingSwitch" data-size="small" data-color="#99d683" data-secondary-color="#f96262" name="tab[` +
  5028. v.id +
  5029. `].ping" value="true" ` +
  5030. tof(v.ping, "c") +
  5031. `/><input type="hidden" class="form-control" name="tab[` +
  5032. v.id +
  5033. `].ping" value="false"></td>
  5034. <td style="text-align:center"><input type="checkbox" class="js-switch preloadSwitch" data-size="small" data-color="#99d683" data-secondary-color="#f96262" name="tab[` +
  5035. v.id +
  5036. `].preload" value="true" ` +
  5037. tof(v.preload, "c") +
  5038. `/><input type="hidden" class="form-control" name="tab[` +
  5039. v.id +
  5040. `].preload" value="false"></td>
  5041. <td style="text-align:center"><input type="checkbox" class="js-switch addToAdminSwitch" data-size="small" data-color="#99d683" data-secondary-color="#f96262" name="tab[` +
  5042. v.id +
  5043. `].add_to_admin" value="true" ` +
  5044. tof(v.add_to_admin, "c") +
  5045. `/><input type="hidden" class="form-control" name="tab[` +
  5046. v.id +
  5047. `].add_to_admin" value="false"></td>
  5048. <td style="text-align:center"><button type="button" class="btn btn-info btn-outline btn-circle btn-lg m-r-5 editTabButton popup-with-form" onclick="editTabForm('` +
  5049. v.id +
  5050. `')" href="#edit-tab-form" data-effect="mfp-3d-unfold"><i class="ti-pencil-alt"></i></button></td>
  5051. <td style="text-align:center"><button type="button" class="btn btn-danger btn-outline btn-circle btn-lg m-r-5 ` +
  5052. deleteDisabled +
  5053. `"><i class="ti-trash"></i></button></td>
  5054. </tr>
  5055. `;
  5056. });
  5057. return tabList;
  5058. }
  5059. function editTabForm(id) {
  5060. organizrAPI2("GET", "api/v2/tabs/" + id, true)
  5061. .success(function (data) {
  5062. try {
  5063. let response = data.response;
  5064. $(".tabIconImageList").val(null).trigger("change");
  5065. $(".tabIconIconList").val(null).trigger("change");
  5066. $("#edit-tab-form [name=name]").val(response.data.name);
  5067. $("#originalTabName").html(response.data.name);
  5068. $("#edit-tab-form [name=url]").val(response.data.url);
  5069. $("#edit-tab-form [name=url_local]").val(response.data.url_local);
  5070. $("#edit-tab-form [name=ping_url]").val(response.data.ping_url);
  5071. $("#edit-tab-form [name=image]").val(response.data.image);
  5072. $("#edit-tab-form [name=id]").val(response.data.id);
  5073. $("#edit-tab-form [name=timeout_ms]").val(
  5074. convertMsToMinutes(response.data.timeout_ms)
  5075. );
  5076. $("#edit-tab-form [name=timeout]").val(response.data.timeout);
  5077. if (response.data.url.indexOf("/?v") > 0) {
  5078. $("#edit-tab-form [name=url]").prop("disabled", "true");
  5079. } else {
  5080. $("#edit-tab-form [name=url]").prop("disabled", null);
  5081. }
  5082. } catch (e) {
  5083. organizrCatchError(e, data);
  5084. }
  5085. })
  5086. .fail(function (xhr) {
  5087. OrganizrApiError(xhr, "Tab Error");
  5088. });
  5089. }
  5090. function getSubmitSettingsFormValueSingle(form, index, value) {
  5091. var values = {};
  5092. if (value !== "#987654" && index.includes("disable-pwd-mgr") == false) {
  5093. var input = $("#" + form + " [name='" + index + "']");
  5094. var dataType = input.attr("data-type");
  5095. switch (dataType) {
  5096. case "switch":
  5097. case "checkbox":
  5098. var value = input.prop("checked") ? true : false;
  5099. break;
  5100. case "select2":
  5101. var value = input.val() !== null ? input.val().toString() : "";
  5102. break;
  5103. default:
  5104. var value = input.val();
  5105. }
  5106. values = { name: index, value: value, type: dataType };
  5107. return values;
  5108. }
  5109. return false;
  5110. }
  5111. function getSubmitSettingsFormValueObject(form, index, value) {
  5112. var values = [];
  5113. $.each(value, function (i, v) {
  5114. var objectList = [];
  5115. var object = [];
  5116. $.each(v, function (key, val) {
  5117. if (val !== "#987654" && key.includes("disable-pwd-mgr") == false) {
  5118. var input = $(
  5119. "#" + form + " [name='" + index + "[" + i + "]." + key + "']"
  5120. );
  5121. var dataType = input.attr("data-type");
  5122. var dataLabel = input.attr("data-label");
  5123. switch (dataType) {
  5124. case "switch":
  5125. case "checkbox":
  5126. var value = input.prop("checked") ? true : false;
  5127. break;
  5128. case "select2":
  5129. var value = input.val() !== null ? input.val().toString() : "";
  5130. break;
  5131. default:
  5132. var value = input.val();
  5133. }
  5134. var newKey = index + "[" + i + "]." + key;
  5135. object.push({
  5136. type: dataType,
  5137. name: newKey,
  5138. label: dataLabel,
  5139. value: value,
  5140. });
  5141. }
  5142. });
  5143. values.push(object);
  5144. });
  5145. values = { name: index, value: values, type: "array" };
  5146. return values;
  5147. }
  5148. function submitSettingsForm(form, homepageItem = false) {
  5149. var list = $("#" + form).serializeToJSON();
  5150. var size = 0;
  5151. var submit = {};
  5152. $.each(list, function (i, v) {
  5153. var values = false;
  5154. if (Object.prototype.toString.call(v) === "[object Object]") {
  5155. values = getSubmitSettingsFormValueObject(form, i, v);
  5156. } else {
  5157. values = getSubmitSettingsFormValueSingle(form, i, v);
  5158. }
  5159. size++;
  5160. if (values) {
  5161. submit[i] = values.value;
  5162. }
  5163. });
  5164. var callbacks = $.Callbacks();
  5165. // Custom Callbacks
  5166. switch (form) {
  5167. case "customize-appearance-form":
  5168. break;
  5169. default:
  5170. }
  5171. if (size > 0) {
  5172. organizrAPI2("PUT", "api/v2/config", submit, true)
  5173. .success(function (data) {
  5174. try {
  5175. var response = data.response;
  5176. } catch (e) {
  5177. organizrCatchError(e, data);
  5178. }
  5179. if (callbacks) {
  5180. callbacks.fire();
  5181. }
  5182. if (homepageItem && !activeInfo.settings.misc.disableHomepageModals) {
  5183. let html = `
  5184. <div class="panel panel-default">
  5185. <div class="panel-heading">${response.message}</div>
  5186. <div class="panel-wrapper collapse in">
  5187. <div class="panel-body">
  5188. <div class="overlay-box">
  5189. <div class="user-content">
  5190. <h4 lang="en">Close Homepage Settings?</h4>
  5191. <div class="button-box">
  5192. <button class="btn btn-info waves-effect waves-light" type="button" onclick="swal.close();Custombox.modal.close()"><span class="btn-label"><i class="ti-check"></i></span>Yes</button>
  5193. <button class="btn btn-danger waves-effect waves-light" type="button" onclick="swal.close()"><span class="btn-label"><i class="ti-close"></i></span>No</button>
  5194. </div>
  5195. <p class="close-homepage-timer">Auto Closing in 5 seconds...</p>
  5196. </div>
  5197. </div>
  5198. </div>
  5199. </div>
  5200. </div>
  5201. `;
  5202. swal({
  5203. content: createElementFromHTML(html),
  5204. buttons: false,
  5205. className: "bg-org",
  5206. timer: 5000,
  5207. });
  5208. textTimer(
  5209. 5,
  5210. ".close-homepage-timer",
  5211. "Seconds remaining: ",
  5212. "Closing..."
  5213. );
  5214. } else {
  5215. message(
  5216. "Updated Items",
  5217. response.message,
  5218. activeInfo.settings.notifications.position,
  5219. "#FFF",
  5220. "success",
  5221. "5000"
  5222. );
  5223. }
  5224. })
  5225. .fail(function (xhr) {
  5226. OrganizrApiError(xhr, "Update Error");
  5227. });
  5228. $("#" + form + " :input").each(function () {
  5229. var input = $(this);
  5230. input
  5231. .closest(".form-group")
  5232. .removeClass("has-success")
  5233. .removeClass("has-error");
  5234. });
  5235. $("#" + form + "-save").addClass("hidden");
  5236. } else {
  5237. $("#" + form + " :input").each(function () {
  5238. var input = $(this);
  5239. input
  5240. .closest(".form-group")
  5241. .removeClass("has-success")
  5242. .addClass("has-error");
  5243. });
  5244. }
  5245. }
  5246. function textTimer(seconds, el, preText, postText) {
  5247. var seconds_left = seconds;
  5248. var interval = setInterval(function () {
  5249. $(el).html(preText + " " + --seconds_left);
  5250. if (seconds_left <= 0) {
  5251. $(el).html(postText);
  5252. clearInterval(interval);
  5253. }
  5254. }, 1000);
  5255. }
  5256. function submitHomepageOrder() {
  5257. var list = $("#homepage-values").serializeToJSON();
  5258. var size = 0;
  5259. var submit = {};
  5260. $.each(list, function (i, v) {
  5261. if (v !== "") {
  5262. size++;
  5263. submit[i] = v;
  5264. }
  5265. });
  5266. var callbacks = $.Callbacks();
  5267. if (size > 0) {
  5268. organizrAPI2("PUT", "api/v2/config", submit, true)
  5269. .success(function (data) {
  5270. try {
  5271. var response = data.response;
  5272. $("#submitHomepageOrder-save").addClass("hidden");
  5273. } catch (e) {
  5274. organizrCatchError(e, data);
  5275. }
  5276. message(
  5277. "Updated Homepage Order",
  5278. response.message,
  5279. activeInfo.settings.notifications.position,
  5280. "#FFF",
  5281. "success",
  5282. "5000"
  5283. );
  5284. if (callbacks) {
  5285. callbacks.fire();
  5286. }
  5287. })
  5288. .fail(function (xhr) {
  5289. OrganizrApiError(xhr, "Update Error");
  5290. });
  5291. } else {
  5292. console.log("add error");
  5293. }
  5294. }
  5295. function submitTabOrder(newTabs) {
  5296. var data = [];
  5297. var process = false;
  5298. $.each(newTabs.tab, function (i, v) {
  5299. if (v.originalOrder == v.order) {
  5300. delete newTabs.tab[i];
  5301. } else {
  5302. let temp = {
  5303. order: v.order,
  5304. id: v.id,
  5305. };
  5306. data.push(temp);
  5307. process = true;
  5308. }
  5309. });
  5310. if (!process) {
  5311. message(
  5312. "Tab Order Warning",
  5313. "Order was not changed - Submission not needed",
  5314. activeInfo.settings.notifications.position,
  5315. "#FFF",
  5316. "warning",
  5317. "5000"
  5318. );
  5319. $(".saveTabOrderButton").addClass("hidden");
  5320. return false;
  5321. }
  5322. var callbacks = $.Callbacks();
  5323. callbacks.add(buildTabEditor);
  5324. organizrAPI2("PUT", "api/v2/tabs", data, true)
  5325. .success(function (data) {
  5326. try {
  5327. var response = data.response;
  5328. } catch (e) {
  5329. organizrCatchError(e, data);
  5330. }
  5331. message(
  5332. "Tab Order Updated",
  5333. response.message,
  5334. activeInfo.settings.notifications.position,
  5335. "#FFF",
  5336. "success",
  5337. "5000"
  5338. );
  5339. if (callbacks) {
  5340. callbacks.fire();
  5341. }
  5342. $(".saveTabOrderButton").addClass("hidden");
  5343. })
  5344. .fail(function (xhr) {
  5345. OrganizrApiError(xhr, "Update Error");
  5346. });
  5347. }
  5348. function submitCategoryOrder() {
  5349. var data = [];
  5350. var categories = $("#submit-categories-form").serializeToJSON();
  5351. var callbacks = $.Callbacks();
  5352. callbacks.add(buildCategoryEditor);
  5353. $.each(categories.category, function (i, v) {
  5354. if (v.originalOrder == v.order) {
  5355. delete categories.category[i];
  5356. } else {
  5357. let temp = {
  5358. order: v.order,
  5359. id: v.id,
  5360. };
  5361. data.push(temp);
  5362. }
  5363. });
  5364. organizrAPI2("PUT", "api/v2/categories", data, true)
  5365. .success(function (data) {
  5366. try {
  5367. var response = data.response;
  5368. } catch (e) {
  5369. organizrCatchError(e, data);
  5370. }
  5371. message(
  5372. "Category Order Updated",
  5373. response.message,
  5374. activeInfo.settings.notifications.position,
  5375. "#FFF",
  5376. "success",
  5377. "5000"
  5378. );
  5379. if (callbacks) {
  5380. callbacks.fire();
  5381. }
  5382. $(".saveTabOrderButton").addClass("hidden");
  5383. })
  5384. .fail(function (xhr) {
  5385. OrganizrApiError(xhr, "Update Error");
  5386. });
  5387. }
  5388. function buildTR(array, type, badge) {
  5389. var listing = "";
  5390. var arrayItems = array.split("|");
  5391. if (hasValue(arrayItems) === true) {
  5392. $.each(arrayItems, function (i, v) {
  5393. listing +=
  5394. `
  5395. <tr>
  5396. <td width="70"><span class="label label-` +
  5397. badge +
  5398. `"><span lang="en">` +
  5399. type +
  5400. `</span></span></td>
  5401. <td class="text-capitalize">` +
  5402. updateIssueLink(v) +
  5403. `</td>
  5404. </tr>
  5405. `;
  5406. });
  5407. return listing;
  5408. }
  5409. return " ";
  5410. }
  5411. function buildVersion(array) {
  5412. var x = 0;
  5413. var versions =
  5414. '<div class="col-md-3 col-sm-4 col-xs-6 m-b-10 pull-right"><button onclick="manualUpdateCheck()" class="btn btn-sm btn-primary btn-rounded waves-effect waves-light pull-right row b-none buttonManualUpdateCheck" type="button"><span class="btn-label"><i class="fa fa-globe"></i></span><span lang="en">Check For Updates</span></button></div><div class="clearfix"></div>';
  5415. var listing = "";
  5416. var currentV = currentVersion;
  5417. var installed = "";
  5418. var spanClass = "";
  5419. var button = "";
  5420. $.each(array, function (i, v) {
  5421. listing += buildTR(v.new, "NEW", "info");
  5422. listing += buildTR(v.fixed, "FIXED", "success");
  5423. listing += buildTR(v.notes, "NOTE", "warning");
  5424. if (currentV === i) {
  5425. button =
  5426. '<button class="btn btn-sm btn-success btn-rounded waves-effect waves-light disabled pull-right row b-none" type="button"><span class="btn-label"><i class="fa fa-check"></i></span><span lang="en">Installed</span></button>';
  5427. } else if (x === 0) {
  5428. button =
  5429. '<button class="btn btn-sm btn-info btn-rounded waves-effect waves-light pull-right row b-none" type="button" onclick="updateNow();"><span class="btn-label"><i class="fa fa-download"></i></span><span lang="en">Install Update</span></button>';
  5430. }
  5431. let tableClass = x == 0 ? "" : "hidden";
  5432. let divClassPadding = x == 0 ? "" : "p-b-0";
  5433. let divClassMargin = x == 0 ? "" : "m-b-0";
  5434. let toggleButtonText = x == 0 ? "Less" : "More";
  5435. let toggleButtonIcon = x == 0 ? "up" : "down";
  5436. let divStatus = x == 0 ? "opened" : "closed";
  5437. versions +=
  5438. `
  5439. <div class="white-box bg-org ${divClassPadding} update-main-div-${x}" data-status="${divStatus}">
  5440. <div class="col-md-3 col-sm-4 col-xs-6 pull-right">` +
  5441. button +
  5442. `</div>
  5443. <h3 class="box-title ${divClassMargin} update-box-title-${x}">` +
  5444. i +
  5445. `</h3>
  5446. <div class="row sales-report">
  5447. <div class="col-md-12 col-sm-12 col-xs-12">
  5448. <div class="pull-left">
  5449. <span class="tooltip-info" data-toggle="tooltip" data-placement="right" title="" data-original-title="` +
  5450. moment(v.date).format("LL") +
  5451. `">` +
  5452. moment.utc(v.date, "YYYY-MM-DD hh:mm[Z]").local().fromNow() +
  5453. `</span>
  5454. <p class="text-info p-0">` +
  5455. v.title +
  5456. `</p>
  5457. </div>
  5458. <button class="btn btn-sm btn-primary btn-rounded waves-effect waves-light pull-right" onclick="toggleGithubVersion(${x})" type="button"><span class="btn-label"><i class="fa fa-long-arrow-${toggleButtonIcon} toggleButtonIcon-${x}"></i></span><span lang="en" class="toggleButton-${x}">${toggleButtonText}</span></button>
  5459. </div>
  5460. </div>
  5461. <div class="table-responsive ${tableClass} update-table-${x}">
  5462. <table class="table inverse-bordered-table">
  5463. <tbody>
  5464. ` +
  5465. listing +
  5466. `
  5467. </tbody>
  5468. </table>
  5469. </div>
  5470. </div>
  5471. `;
  5472. listing = "";
  5473. button = "";
  5474. x++;
  5475. });
  5476. return versions;
  5477. }
  5478. function toggleGithubVersion(id) {
  5479. let status = $(".update-main-div-" + id).attr("data-status");
  5480. if (status == "opened") {
  5481. $(".update-main-div-" + id).attr("data-status", "closed");
  5482. $(".update-main-div-" + id).addClass("p-b-0");
  5483. $(".update-box-title-" + id).addClass("m-b-0");
  5484. $(".update-table-" + id).addClass("hidden");
  5485. $(".toggleButton-" + id).text("More");
  5486. $(".toggleButtonIcon-" + id)
  5487. .removeClass("fa-long-arrow-up")
  5488. .addClass("fa-long-arrow-down");
  5489. } else {
  5490. $(".update-main-div-" + id).attr("data-status", "opened");
  5491. $(".update-main-div-" + id).removeClass("p-b-0");
  5492. $(".update-box-title-" + id).removeClass("m-b-0");
  5493. $(".update-table-" + id).removeClass("hidden");
  5494. $(".toggleButton-" + id).text("Less");
  5495. $(".toggleButtonIcon-" + id)
  5496. .addClass("fa-long-arrow-up")
  5497. .removeClass("fa-long-arrow-down");
  5498. }
  5499. }
  5500. function manualUpdateCheck() {
  5501. $(".buttonManualUpdateCheck").addClass("disabled");
  5502. $(".buttonManualUpdateCheck i")
  5503. .removeClass("fa-globe")
  5504. .addClass("fa-refresh fa-spin");
  5505. setTimeout(function () {
  5506. updateCheck();
  5507. checkCommitLoad();
  5508. }, 1000);
  5509. setTimeout(function () {
  5510. $(".buttonManualUpdateCheck").removeClass("disabled");
  5511. $(".buttonManualUpdateCheck i")
  5512. .removeClass("fa-refresh fa-spin fa-globe")
  5513. .addClass("fa-check");
  5514. }, 1500);
  5515. return true;
  5516. }
  5517. function updateCheck() {
  5518. githubVersions()
  5519. .success(function (data) {
  5520. try {
  5521. var response = JSON.parse(data);
  5522. } catch (e) {
  5523. organizrCatchError(e, data);
  5524. }
  5525. for (var a in reverseObject(response)) {
  5526. var latest = a;
  5527. break;
  5528. }
  5529. if (latest !== currentVersion) {
  5530. organizrConsole(
  5531. "Update Function",
  5532. "Update to " + latest + " is available",
  5533. "warning"
  5534. );
  5535. if (activeInfo.settings.misc.docker === false) {
  5536. let tabInfo = findTab("api/v2/page/settings", "access_url");
  5537. if (tabInfo) {
  5538. messageSingle(
  5539. window.lang.translate("Update Available"),
  5540. latest +
  5541. " " +
  5542. window.lang.translate("is available, goto") +
  5543. ' <a href="javascript:void(0)" onclick="tabActions(event,\'' +
  5544. tabInfo.id +
  5545. "');clickPath('update')\"><span lang=\"en\">Update Tab</span></a>",
  5546. activeInfo.settings.notifications.position,
  5547. "#FFF",
  5548. "update",
  5549. "60000"
  5550. );
  5551. }
  5552. }
  5553. } else {
  5554. organizrConsole(
  5555. "Update Function",
  5556. "Already running latest version: " + latest,
  5557. "info"
  5558. );
  5559. }
  5560. $("#githubVersions").html(buildVersion(reverseObject(response)));
  5561. })
  5562. .fail(function (xhr) {
  5563. OrganizrApiError(xhr);
  5564. });
  5565. }
  5566. function ignoreNewsId(id) {
  5567. organizrAPI2("POST", "api/v2/news/" + id, {})
  5568. .success(function (data) {
  5569. try {
  5570. let response = data.response;
  5571. message(
  5572. "News Item",
  5573. "Item now ignored",
  5574. activeInfo.settings.notifications.position,
  5575. "#FFF",
  5576. "success",
  5577. "5000"
  5578. );
  5579. $(".newsItem-" + id).remove();
  5580. $(".newsHeart-" + id).remove();
  5581. } catch (e) {
  5582. organizrCatchError(e, data);
  5583. }
  5584. })
  5585. .fail(function (xhr) {
  5586. OrganizrApiError(xhr, "News");
  5587. });
  5588. }
  5589. function newsLoad() {
  5590. newsJSON()
  5591. .success(function (data) {
  5592. try {
  5593. var response = JSON.parse(data);
  5594. var items = [];
  5595. var limit = 5;
  5596. var count = 0;
  5597. organizrAPI2("get", "api/v2/news")
  5598. .success(function (data) {
  5599. try {
  5600. let ignoredIds = data.response.data;
  5601. ignoredIds = ignoredIds == null ? [] : ignoredIds;
  5602. $.each(response, function (i, v) {
  5603. count++;
  5604. let ignore = ignoredIds.includes(v.id);
  5605. let alertDefined =
  5606. typeof v.important !== "undefined" && v.important !== false;
  5607. let alert =
  5608. alertDefined && ignore == false
  5609. ? `<span class="animated loop-animation flash text-danger mouse newsItem-${v.id}" onclick="ignoreNewsId('${v.id}')">&nbsp; <i class="ti-alert"></i>&nbsp; Important Message - Click me to Ignore</span>`
  5610. : "";
  5611. let heartBeat =
  5612. alertDefined && ignore == false
  5613. ? `<div class="notify pull-left newsHeart-${v.id}"><span class="heartbit"></span><span class="point"></span></div>`
  5614. : "";
  5615. let newBody =
  5616. `
  5617. <h5 class="pull-left"><i class="ti-calendar"></i>&nbsp;` +
  5618. moment(v.date).format("LLL") +
  5619. alert +
  5620. `</h5>
  5621. <h5 class="pull-right">` +
  5622. v.author +
  5623. `</h5>
  5624. <div class="clearfix"></div>
  5625. ` +
  5626. (v.subTitle ? "<h5>" + v.subTitle + "</h5>" : "") +
  5627. `
  5628. <p>` +
  5629. v.body +
  5630. `</p>
  5631. `;
  5632. if (count <= limit) {
  5633. items[i] = {
  5634. title: v.title + heartBeat,
  5635. body: newBody,
  5636. };
  5637. }
  5638. });
  5639. var body = buildAccordion(items, true);
  5640. $("#organizrNewsPanel").html(body);
  5641. } catch (e) {
  5642. organizrCatchError(e, data);
  5643. }
  5644. })
  5645. .fail(function (xhr) {
  5646. OrganizrApiError(xhr, "News");
  5647. });
  5648. } catch (e) {
  5649. organizrCatchError(e, data);
  5650. }
  5651. })
  5652. .fail(function (xhr) {
  5653. OrganizrApiError(xhr);
  5654. });
  5655. }
  5656. function checkPluginUpdates() {
  5657. if (!activeInfo.user.loggedin || activeInfo.user.groupID > 1) {
  5658. return false;
  5659. }
  5660. organizrAPI2("get", "api/v2/plugins/marketplace")
  5661. .success(function (data) {
  5662. try {
  5663. let update = false;
  5664. let pluginsNeedingUpdate = [];
  5665. let plugins = data.response.data;
  5666. $.each(plugins, function (i, v) {
  5667. if (v.needs_update) {
  5668. update = true;
  5669. pluginsNeedingUpdate.push(i);
  5670. }
  5671. });
  5672. if (update) {
  5673. pluginsNeedingUpdate = "[" + pluginsNeedingUpdate.join(", ") + "]";
  5674. messageSingle(
  5675. window.lang.translate("Update Available"),
  5676. '<a href="javascript:void(0)" onclick="shortcut(\'plugin-marketplace\');"><span lang="en">The following plugin(s) need updates</span></a>: ' +
  5677. pluginsNeedingUpdate,
  5678. activeInfo.settings.notifications.position,
  5679. "#FFF",
  5680. "update",
  5681. "600000"
  5682. );
  5683. }
  5684. } catch (e) {
  5685. organizrCatchError(e, data);
  5686. }
  5687. })
  5688. .fail(function (xhr) {
  5689. OrganizrApiError(xhr, "Marketplace");
  5690. });
  5691. }
  5692. function checkCommitLoad() {
  5693. if (
  5694. activeInfo.settings.misc.docker &&
  5695. activeInfo.settings.misc.githubCommit !== "n/a" &&
  5696. activeInfo.settings.misc.githubCommit !== null
  5697. ) {
  5698. if (checkCommitLoadStatus == false) {
  5699. checkCommitLoadStatus = true;
  5700. getLatestCommitJSON()
  5701. .success(function (data) {
  5702. try {
  5703. var latest = data.sha.toString().trim();
  5704. var current = activeInfo.settings.misc.githubCommit
  5705. .toString()
  5706. .trim();
  5707. var link =
  5708. "https://github.com/causefx/Organizr/compare/" +
  5709. current +
  5710. "..." +
  5711. latest;
  5712. if (latest !== current) {
  5713. messageSingle(
  5714. window.lang.translate("Update Available"),
  5715. ' <a href="' +
  5716. link +
  5717. '" target="_blank"><span lang="en">Compare Difference</span></a> <span lang="en">or</span> <a href="javascript:void(0)" onclick="updateNow()"><span lang="en">Update Now</span></a>',
  5718. activeInfo.settings.notifications.position,
  5719. "#FFF",
  5720. "update",
  5721. "600000"
  5722. );
  5723. } else {
  5724. organizrConsole(
  5725. "Update Function",
  5726. "Organizr Docker - Up to date"
  5727. );
  5728. }
  5729. } catch (e) {
  5730. organizrCatchError(e, data);
  5731. }
  5732. checkCommitLoadStatus = false;
  5733. })
  5734. .fail(function (xhr) {
  5735. console.error("Organizr Function: Github Connection Failed");
  5736. checkCommitLoadStatus = false;
  5737. });
  5738. }
  5739. }
  5740. }
  5741. function sponsorLoad() {
  5742. sponsorsJSON()
  5743. .success(function (data) {
  5744. try {
  5745. var response = JSON.parse(data);
  5746. } catch (e) {
  5747. organizrCatchError(e, data);
  5748. }
  5749. $("#sponsorList").html(buildSponsor(response));
  5750. $("#sponsorListModals").html(buildSponsorModal(response));
  5751. $(".sponsor-items").owlCarousel({
  5752. nav: false,
  5753. autoplay: true,
  5754. dots: false,
  5755. margin: 10,
  5756. autoWidth: true,
  5757. items: 4,
  5758. });
  5759. })
  5760. .fail(function (xhr) {
  5761. OrganizrApiError(xhr);
  5762. });
  5763. }
  5764. function backersLoad() {
  5765. organizrAPI2("GET", "api/v2/sponsors/all")
  5766. .success(function (data) {
  5767. try {
  5768. let json = data.response;
  5769. $("#backersList").html(buildBackers(json.data));
  5770. $(".backers-items").owlCarousel({
  5771. nav: false,
  5772. autoplay: true,
  5773. dots: false,
  5774. margin: 10,
  5775. autoWidth: true,
  5776. items: 4,
  5777. });
  5778. } catch (e) {
  5779. organizrCatchError(e, data);
  5780. }
  5781. })
  5782. .fail(function (xhr) {
  5783. OrganizrApiError(xhr);
  5784. });
  5785. }
  5786. function buildBackers(array) {
  5787. let backers = "";
  5788. $.each(array, function (i, v) {
  5789. if (v.type == "USER" && v.role == "BACKER" && v.isActive) {
  5790. v.name = v.name ? v.name : "User";
  5791. v.image = v.image ? v.image : "plugins/images/default_user.png";
  5792. backers += `
  5793. <!-- /.usercard -->
  5794. <div class="item lazyload recent-sponsor imageSource" data-src="${v.image}">
  5795. <span class="elip recent-title">${v.name}</span>
  5796. </div>
  5797. <!-- /.usercard-->
  5798. `;
  5799. }
  5800. });
  5801. backers += `
  5802. <!-- /.usercard -->
  5803. <div class="item lazyload recent-sponsor mouse imageSource mouse" onclick="window.open('https://opencollective.com/organizr', '_blank')" data-src="plugins/images/sponsor-open-collective.png">
  5804. <span class="elip recent-title" lang="en">You</span>
  5805. </div>
  5806. <!-- /.usercard-->
  5807. `;
  5808. return backers;
  5809. }
  5810. function sponsorDetails(id) {
  5811. sponsorsJSON()
  5812. .success(function (data) {
  5813. try {
  5814. let response = JSON.parse(data);
  5815. let coupon = response[id].coupon == null ? false : true;
  5816. let couponAbout = response[id].coupon_about == null ? false : true;
  5817. let extraInfo =
  5818. coupon && couponAbout
  5819. ? `
  5820. <hr/>
  5821. <h3>Coupon Code:</h3>
  5822. <p><span class="label label-rouded label-info pull-right">${response[id].coupon}</span>
  5823. <span class=" pull-left">${response[id].coupon_about}</span></p>
  5824. `
  5825. : "";
  5826. if (typeof response[id].logo_dark !== "undefined") {
  5827. if (activeInfo.style == "dark") {
  5828. response[id].logo = response[id].logo_dark;
  5829. }
  5830. }
  5831. let html = `
  5832. <div class="panel panel-default">
  5833. <div class="panel-heading">${response[id].company_name}</div>
  5834. <div class="panel-wrapper collapse in">
  5835. <div class="panel-body">
  5836. <div class="overlay-box">
  5837. <div class="user-content">
  5838. <a href="javascript:void(0)"><img src="${response[id].logo}" class="thumb-lg img-circle" alt="img"></a>
  5839. <h4 class="text-white">${response[id].company_name}</h4>
  5840. <h5 class="text-white"><a href="${response[id].website}" target="_blank">Website</a></h5>
  5841. </div>
  5842. </div>
  5843. <hr/>
  5844. <div class="text-left">${response[id].about} ${extraInfo}</div>
  5845. </div>
  5846. </div>
  5847. </div>
  5848. `;
  5849. swal({
  5850. content: createElementFromHTML(html),
  5851. buttons: false,
  5852. className: "bg-org",
  5853. });
  5854. } catch (e) {
  5855. organizrCatchError(e, data);
  5856. }
  5857. })
  5858. .fail(function (xhr) {
  5859. OrganizrApiError(xhr);
  5860. });
  5861. }
  5862. function sponsorAbout(id, array) {
  5863. var coupon = array.coupon != null;
  5864. var couponAbout = array.coupon_about != null;
  5865. var extraInfo =
  5866. coupon && couponAbout
  5867. ? `
  5868. <h3>Coupon Code:</h3>
  5869. <p><span class="label label-rouded label-info pull-right">` +
  5870. array.coupon +
  5871. `</span>
  5872. <span class=" pull-left">` +
  5873. array.coupon_about +
  5874. `</span></p>
  5875. `
  5876. : "";
  5877. if (typeof array.logo_dark !== "undefined") {
  5878. if (activeInfo.style == "dark") {
  5879. array.logo = array.logo_dark;
  5880. }
  5881. }
  5882. return (
  5883. `
  5884. <!-- modal content -->
  5885. <div id="sponsor-` +
  5886. id +
  5887. `-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel-` +
  5888. id +
  5889. `" aria-hidden="true" style="display: none;">
  5890. <div class="modal-dialog">
  5891. <div class="modal-content">
  5892. <div class="modal-header">
  5893. <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
  5894. <h4 class="modal-title" id="mySmallModalLabel-` +
  5895. id +
  5896. `">` +
  5897. array.company_name +
  5898. `</h4> </div>
  5899. <div class="modal-body">
  5900. <div class="row">
  5901. <div class="col-md-12">
  5902. <div class="comment-center p-t-10">
  5903. <div class="comment-body b-none">
  5904. <div class="user-img"> <img src="` +
  5905. array.logo +
  5906. `" alt="user" class="img-circle"> </div>
  5907. <div class="mail-content">
  5908. <h5><a href="` +
  5909. array.website +
  5910. `" target="_blank">` +
  5911. array.company_name +
  5912. `</a></h5>
  5913. ` +
  5914. array.about +
  5915. extraInfo +
  5916. `
  5917. </div>
  5918. </div>
  5919. </div>
  5920. </div>
  5921. </div>
  5922. </div>
  5923. </div>
  5924. <!-- /.modal-content -->
  5925. </div>
  5926. <!-- /.modal-dialog -->
  5927. </div>
  5928. <!-- /.modal -->
  5929. `
  5930. );
  5931. }
  5932. function buildSponsor(array) {
  5933. var sponsors = "";
  5934. $.each(array, function (i, v) {
  5935. var hasCoupon = "";
  5936. if (v.about) {
  5937. if (v.coupon) {
  5938. hasCoupon = `
  5939. <span class="text-center has-coupon-text">Has Coupon</span>
  5940. <span class="text-center has-coupon"><i class="fa fa-ticket" aria-hidden="true"></i></span>
  5941. `;
  5942. }
  5943. }
  5944. var sponsorAboutModal = v.about
  5945. ? "onclick=\"sponsorDetails('" +
  5946. i +
  5947. "');sponsorAnalytics('" +
  5948. v.company_name +
  5949. "');\""
  5950. : "onclick=\"window.open('" +
  5951. v.website +
  5952. "', '_blank');sponsorAnalytics('" +
  5953. v.company_name +
  5954. "');\"";
  5955. if (typeof v.logo_dark !== "undefined") {
  5956. if (activeInfo.style == "dark") {
  5957. v.logo = v.logo_dark;
  5958. }
  5959. }
  5960. sponsors += `
  5961. <!-- /.usercard -->
  5962. <div class="item lazyload recent-sponsor mouse imageSource mouse" ${sponsorAboutModal} data-src="${v.logo}" data-id="${i}">
  5963. <span class="elip recent-title">${v.company_name}</span>
  5964. ${hasCoupon}
  5965. </div>
  5966. <!-- /.usercard-->
  5967. `;
  5968. });
  5969. sponsors += `
  5970. <!-- /.usercard -->
  5971. <div class="item lazyload recent-sponsor mouse imageSource mouse" onclick="window.open('https://www.patreon.com/bePatron?c=1320444&rid=2874514', '_blank')" data-src="plugins/images/sponsor-patreon.png">
  5972. <span class="elip recent-title" lang="en">Patreon Sponsor</span>
  5973. </div>
  5974. <div class="item lazyload recent-sponsor mouse imageSource mouse" onclick="window.open('https://opencollective.com/organizr', '_blank')" data-src="plugins/images/sponsor-open-collective.png">
  5975. <span class="elip recent-title" lang="en">OpenCollective Sponsor</span>
  5976. </div>
  5977. <!-- /.usercard-->
  5978. `;
  5979. return sponsors;
  5980. }
  5981. function buildSponsorModal(array) {
  5982. var sponsors = "";
  5983. $.each(array, function (i, v) {
  5984. var sponsorAboutModal = v.about ? sponsorAbout(i, v) : "";
  5985. sponsors += sponsorAboutModal;
  5986. });
  5987. return sponsors;
  5988. }
  5989. function sponsorAnalytics(sponsor_name) {
  5990. var uuid = activeInfo.settings.misc.uuid;
  5991. $.ajax({
  5992. type: "POST",
  5993. url: "https://api.organizr.app/",
  5994. data: {
  5995. sponsor_name: sponsor_name,
  5996. user_uuid: uuid,
  5997. cmd: "sponsor",
  5998. },
  5999. cache: false,
  6000. async: true,
  6001. complete: function (xhr, status) {
  6002. if (xhr.status === 200) {
  6003. let result = $.parseJSON(xhr.responseText);
  6004. }
  6005. },
  6006. });
  6007. }
  6008. function themeAnalytics(theme_name) {
  6009. var uuid = activeInfo.settings.misc.uuid;
  6010. $.ajax({
  6011. type: "POST",
  6012. url: "https://api.organizr.app/",
  6013. data: {
  6014. theme_name: theme_name,
  6015. user_uuid: uuid,
  6016. cmd: "theme",
  6017. },
  6018. cache: false,
  6019. async: true,
  6020. complete: function (xhr, status) {
  6021. if (xhr.status === 200) {
  6022. let result = $.parseJSON(xhr.responseText);
  6023. }
  6024. },
  6025. });
  6026. }
  6027. function getOrganizrBackups() {
  6028. organizrAPI2("GET", "api/v2/backup")
  6029. .success(function (data) {
  6030. try {
  6031. let json = data.response;
  6032. $("#backup-file-list").html(buildOrganizrBackups(json.data));
  6033. } catch (e) {
  6034. organizrCatchError(e, data);
  6035. }
  6036. })
  6037. .fail(function (xhr) {
  6038. OrganizrApiError(xhr);
  6039. });
  6040. }
  6041. function createOrganizrBackup() {
  6042. $("#settings-settings-backup").block({
  6043. message:
  6044. '<p style="margin:0;padding:8px;font-size:24px;" lang="en">Backing up...</p>',
  6045. css: {
  6046. color: "#fff",
  6047. border: "1px solid #5761a9",
  6048. backgroundColor: "#707cd2",
  6049. },
  6050. });
  6051. organizrAPI2("POST", "api/v2/backup", {})
  6052. .success(function (data) {
  6053. try {
  6054. let response = data.response;
  6055. if (response) {
  6056. getOrganizrBackups();
  6057. }
  6058. } catch (e) {
  6059. organizrCatchError(e, data);
  6060. }
  6061. $("#settings-settings-backup").unblock();
  6062. })
  6063. .fail(function (xhr) {
  6064. $("#settings-settings-backup").unblock();
  6065. OrganizrApiError(xhr, "Backup Error");
  6066. });
  6067. }
  6068. function buildOrganizrBackups(array) {
  6069. let list = "";
  6070. if (array.total_files > 0) {
  6071. $.each(array.files, function (i, v) {
  6072. i++;
  6073. let pattern = /\[[^\]]*\]/gm;
  6074. let version =
  6075. typeof v.name.match(pattern)[1] !== "undefined"
  6076. ? v.name.match(pattern)[1]
  6077. : "N/A";
  6078. list += `
  6079. <tr>
  6080. <td>${i}</td>
  6081. <td class="txt-oflo">${v.name}</td>
  6082. <td><span class="label label-primary label-rouded">${version}</span> </td>
  6083. <td class="txt-oflo">${v.size}</td>
  6084. <td><span class="text-info tooltip-info" data-toggle="tooltip" data-placement="right" title="" data-original-title="${moment(
  6085. v.date
  6086. ).format("LLL")}">${moment
  6087. .utc(v.date, "YYYY-MM-DD hh:mm[Z]")
  6088. .local()
  6089. .fromNow()}</span></td>
  6090. <td><span class="text-primary"><a href="api/v2/backup/${
  6091. v.name
  6092. }"><i class="fa fa-download download-backup" data-file="${
  6093. v.name
  6094. }"></i></a> | <a href="javascript:void(0)"><i class="fa fa-trash-o delete-backup" data-file="${
  6095. v.name
  6096. }"></i></a></span></td>
  6097. </tr>
  6098. `;
  6099. });
  6100. } else {
  6101. list =
  6102. '<tr><td class="text-center" colspan="6">No Backups made yet</td></tr>';
  6103. }
  6104. $("#backup-total-files").html(array.total_files);
  6105. $("#backup-total-size").html(array.total_size);
  6106. return list;
  6107. }
  6108. function updateBar() {
  6109. return `
  6110. <div class="white-box m-0">
  6111. <div class="row">
  6112. <div class="col-lg-12">
  6113. <h3 id="update-title" class="box-title pull-left"></h3><h3 id="update-time" class="box-title pull-right hidden"><span id="update-seconds"></span>&nbsp;<span lang="en">Seconds</span></h3>
  6114. <div class="clearfix"></div>
  6115. <div class="progress progress-lg">
  6116. <div id="update-bar" class="progress-bar progress-bar-primary progress-bar-striped active" style="width: 0%;" role="progressbar">0%</div>
  6117. </div>
  6118. </div>
  6119. <h6>If error occurs - Use Esc key to close modal</h6>
  6120. </div>
  6121. </div>
  6122. `;
  6123. }
  6124. function showUpdateBar() {
  6125. swal({
  6126. content: createElementFromHTML(updateBar()),
  6127. buttons: false,
  6128. className: "bg-org",
  6129. closeOnClickOutside: false,
  6130. });
  6131. }
  6132. function updateUpdateBar(title, percent, update = false) {
  6133. $("#update-title").text(title);
  6134. $("#update-bar").text(percent);
  6135. $("#update-bar").css("width", percent);
  6136. if (update) {
  6137. $("#update-time").removeClass("hidden");
  6138. countdown(10);
  6139. }
  6140. }
  6141. function countdown(remaining) {
  6142. if (remaining === 0) {
  6143. local("set", "message", "Organizr Update|Update Successful|update");
  6144. location.reload(true);
  6145. }
  6146. $("#update-seconds").text(remaining);
  6147. setTimeout(function () {
  6148. countdown(remaining - 1);
  6149. }, 1000);
  6150. }
  6151. function dockerUpdate() {
  6152. if (activeInfo.settings.misc.docker) {
  6153. showUpdateBar();
  6154. updateUpdateBar("Starting Download", "20%");
  6155. messageSingle(
  6156. window.lang.translate("[DO NOT CLOSE WINDOW]"),
  6157. window.lang.translate("Starting Update Process"),
  6158. activeInfo.settings.notifications.position,
  6159. "#FFF",
  6160. "success",
  6161. "60000"
  6162. );
  6163. organizrAPI2("GET", "api/v2/update/docker")
  6164. .success(function (data) {
  6165. updateUpdateBar("Restarting Organizr in", "100%", true);
  6166. messageSingle(
  6167. window.lang.translate("[DO NOT CLOSE WINDOW]"),
  6168. "Update complete",
  6169. activeInfo.settings.notifications.position,
  6170. "#FFF",
  6171. "success",
  6172. "60000"
  6173. );
  6174. })
  6175. .fail(function (xhr) {
  6176. OrganizrApiError(xhr, "Update Error");
  6177. });
  6178. }
  6179. }
  6180. function windowsUpdate() {
  6181. if (activeInfo.serverOS == "win") {
  6182. showUpdateBar();
  6183. updateUpdateBar("Starting Download", "20%");
  6184. messageSingle(
  6185. window.lang.translate("[DO NOT CLOSE WINDOW]"),
  6186. window.lang.translate("Starting Update Process"),
  6187. activeInfo.settings.notifications.position,
  6188. "#FFF",
  6189. "success",
  6190. "60000"
  6191. );
  6192. organizrAPI2("GET", "api/v2/update/windows")
  6193. .success(function (data) {
  6194. updateUpdateBar("Restarting Organizr in", "100%", true);
  6195. messageSingle(
  6196. window.lang.translate("[DO NOT CLOSE WINDOW]"),
  6197. "Update complete",
  6198. activeInfo.settings.notifications.position,
  6199. "#FFF",
  6200. "success",
  6201. "60000"
  6202. );
  6203. })
  6204. .fail(function (xhr) {
  6205. OrganizrApiError(xhr, "Update Error");
  6206. });
  6207. }
  6208. }
  6209. function linuxUpdate() {
  6210. if (activeInfo.serverOS !== "win" && !activeInfo.settings.misc.docker) {
  6211. showUpdateBar();
  6212. updateUpdateBar("Starting Download", "20%");
  6213. messageSingle(
  6214. window.lang.translate("[DO NOT CLOSE WINDOW]"),
  6215. window.lang.translate("Starting Update Process"),
  6216. activeInfo.settings.notifications.position,
  6217. "#FFF",
  6218. "success",
  6219. "60000"
  6220. );
  6221. organizrAPI2("GET", "api/v2/update/linux")
  6222. .success(function (data) {
  6223. updateUpdateBar("Restarting Organizr in", "100%", true);
  6224. messageSingle(
  6225. window.lang.translate("[DO NOT CLOSE WINDOW]"),
  6226. "Update complete",
  6227. activeInfo.settings.notifications.position,
  6228. "#FFF",
  6229. "success",
  6230. "60000"
  6231. );
  6232. })
  6233. .fail(function (xhr) {
  6234. OrganizrApiError(xhr, "Update Error");
  6235. });
  6236. }
  6237. }
  6238. function updateNow() {
  6239. clearAJAX();
  6240. if (activeInfo.settings.misc.docker) {
  6241. dockerUpdate();
  6242. return false;
  6243. }
  6244. if (activeInfo.serverOS === "win") {
  6245. windowsUpdate();
  6246. return false;
  6247. }
  6248. if (activeInfo.serverOS !== "win" && !activeInfo.settings.misc.docker) {
  6249. linuxUpdate();
  6250. return false;
  6251. }
  6252. organizrConsole("Update Function", "Starting Update Process");
  6253. showUpdateBar();
  6254. updateUpdateBar("Starting Download", "5%");
  6255. messageSingle(
  6256. window.lang.translate("[DO NOT CLOSE WINDOW]"),
  6257. window.lang.translate("Starting Update Process"),
  6258. activeInfo.settings.notifications.position,
  6259. "#FFF",
  6260. "success",
  6261. "60000"
  6262. );
  6263. organizrAPI2("GET", "api/v2/update/download/" + activeInfo.branch)
  6264. .success(function (data) {
  6265. updateUpdateBar("Starting Unzip", "50%");
  6266. messageSingle(
  6267. window.lang.translate("[DO NOT CLOSE WINDOW]"),
  6268. window.lang.translate("Update File Downloaded"),
  6269. activeInfo.settings.notifications.position,
  6270. "#FFF",
  6271. "success",
  6272. "60000"
  6273. );
  6274. organizrAPI2("GET", "api/v2/update/unzip/" + activeInfo.branch)
  6275. .success(function (data) {
  6276. updateUpdateBar("Starting Copy", "70%");
  6277. messageSingle(
  6278. window.lang.translate("[DO NOT CLOSE WINDOW]"),
  6279. window.lang.translate("Update File Unzipped"),
  6280. activeInfo.settings.notifications.position,
  6281. "#FFF",
  6282. "success",
  6283. "60000"
  6284. );
  6285. organizrAPI2("GET", "api/v2/update/move/" + activeInfo.branch)
  6286. .success(function (data) {
  6287. updateUpdateBar("Starting Cleanup", "90%");
  6288. messageSingle(
  6289. window.lang.translate("[DO NOT CLOSE WINDOW]"),
  6290. window.lang.translate("Update Files Copied"),
  6291. activeInfo.settings.notifications.position,
  6292. "#FFF",
  6293. "success",
  6294. "60000"
  6295. );
  6296. organizrAPI2("GET", "api/v2/update/cleanup/" + activeInfo.branch)
  6297. .success(function (data) {
  6298. updateUpdateBar("Restarting Organizr in", "100%", true);
  6299. messageSingle(
  6300. window.lang.translate("[DO NOT CLOSE WINDOW]"),
  6301. window.lang.translate("Update Cleanup Finished"),
  6302. activeInfo.settings.notifications.position,
  6303. "#FFF",
  6304. "success",
  6305. "60000"
  6306. );
  6307. })
  6308. .fail(function (xhr) {
  6309. OrganizrApiError(xhr, "Update Error");
  6310. });
  6311. })
  6312. .fail(function (xhr) {
  6313. OrganizrApiError(xhr, "Update Error");
  6314. });
  6315. })
  6316. .fail(function (xhr) {
  6317. OrganizrApiError(xhr, "Update Error");
  6318. });
  6319. })
  6320. .fail(function (xhr) {
  6321. OrganizrApiError(xhr, "Update Error");
  6322. });
  6323. }
  6324. function settingsAPI2(post, callbacks = null, asyncValue = true) {
  6325. organizrAPI2("POST", post.api, post.data, asyncValue)
  6326. .success(function (data) {
  6327. try {
  6328. var response = JSON.parse(data);
  6329. } catch (e) {
  6330. organizrCatchError(e, data);
  6331. }
  6332. message(
  6333. post.messageTitle,
  6334. post.messageBody,
  6335. activeInfo.settings.notifications.position,
  6336. "#FFF",
  6337. "success",
  6338. "5000"
  6339. );
  6340. if (callbacks) {
  6341. callbacks.fire();
  6342. }
  6343. })
  6344. .fail(function (xhr) {
  6345. console.error(post.error);
  6346. });
  6347. }
  6348. $.xhrPool.abortAll = function (url) {
  6349. $(this).each(function (i, jqXHR) {
  6350. // cycle through list of recorded connection
  6351. if (!url || url === jqXHR.requestURL) {
  6352. organizrConsole("Organizr API Abort", jqXHR.requestURL, "info");
  6353. jqXHR.abort(); // aborts connection
  6354. $.xhrPool.splice(i, 1); // removes from list by index
  6355. }
  6356. });
  6357. };
  6358. $.ajaxPrefilter(function (options, originalOptions, jqXHR) {
  6359. //organizrConsole('Organizr API Function',options.url,'info');
  6360. jqXHR.requestURL = options.url;
  6361. });
  6362. function organizrAPI2(type, path, data = null, asyncValue = true) {
  6363. $.xhrPool.abortAll(path);
  6364. var timeout = 10000;
  6365. switch (path) {
  6366. case "api/v2/update/windows":
  6367. case "api/v2/update/docker":
  6368. case "api/v2/login":
  6369. timeout = 240000;
  6370. break;
  6371. default:
  6372. timeout = 60000;
  6373. }
  6374. switch (type) {
  6375. case "get":
  6376. case "GET":
  6377. case "g":
  6378. return $.ajax({
  6379. url: path,
  6380. method: "GET",
  6381. beforeSend: function (request) {
  6382. request.setRequestHeader("Token", activeInfo.token);
  6383. request.setRequestHeader("formKey", local("g", "formKey"));
  6384. $.xhrPool.push(request);
  6385. },
  6386. complete: function (jqXHR) {
  6387. var i = $.xhrPool.indexOf(jqXHR); // get index for current connection completed
  6388. if (i > -1) $.xhrPool.splice(i, 1); // removes from list by index
  6389. },
  6390. timeout: timeout,
  6391. });
  6392. case "delete":
  6393. case "DELETE":
  6394. case "d":
  6395. return $.ajax({
  6396. url: path,
  6397. method: "DELETE",
  6398. beforeSend: function (request) {
  6399. request.setRequestHeader("Token", activeInfo.token);
  6400. request.setRequestHeader("formKey", local("g", "formKey"));
  6401. $.xhrPool.push(request);
  6402. },
  6403. complete: function (jqXHR) {
  6404. var i = $.xhrPool.indexOf(jqXHR); // get index for current connection completed
  6405. if (i > -1) $.xhrPool.splice(i, 1); // removes from list by index
  6406. },
  6407. timeout: timeout,
  6408. });
  6409. case "post":
  6410. case "POST":
  6411. case "p":
  6412. data.formKey = local("g", "formKey");
  6413. return $.ajax({
  6414. url: path,
  6415. method: "POST",
  6416. async: asyncValue,
  6417. beforeSend: function (request) {
  6418. request.setRequestHeader("Token", activeInfo.token);
  6419. request.setRequestHeader("formKey", local("g", "formKey"));
  6420. $.xhrPool.push(request);
  6421. },
  6422. complete: function (jqXHR) {
  6423. var i = $.xhrPool.indexOf(jqXHR); // get index for current connection completed
  6424. if (i > -1) $.xhrPool.splice(i, 1); // removes from list by index
  6425. },
  6426. data: data,
  6427. });
  6428. case "put":
  6429. case "PUT":
  6430. data.formKey = local("g", "formKey");
  6431. return $.ajax({
  6432. url: path,
  6433. method: "PUT",
  6434. async: asyncValue,
  6435. beforeSend: function (request) {
  6436. request.setRequestHeader("Token", activeInfo.token);
  6437. request.setRequestHeader("formKey", local("g", "formKey"));
  6438. $.xhrPool.push(request);
  6439. },
  6440. complete: function (jqXHR) {
  6441. var i = $.xhrPool.indexOf(jqXHR); // get index for current connection completed
  6442. if (i > -1) $.xhrPool.splice(i, 1); // removes from list by index
  6443. },
  6444. data: JSON.stringify(data),
  6445. contentType: "application/json",
  6446. });
  6447. default:
  6448. console.warn("Organizr API: Method Not Supported");
  6449. }
  6450. }
  6451. function loadSettingsPage2(api, element, organizrFn) {
  6452. $(element).html(
  6453. '<h2 class="col-lg-12 m-t-0 text-center well bg-org"><i class="fa fa-spin fa-refresh"></i><br> <span lang="en">Loading</span></h2><div class="clearfix"></div>'
  6454. );
  6455. organizrAPI2("get", api)
  6456. .success(function (data) {
  6457. try {
  6458. var response = data.response;
  6459. } catch (e) {
  6460. organizrCatchError(e, data);
  6461. }
  6462. organizrConsole("Organizr Function", "Loading " + organizrFn);
  6463. $(element).html(response.data);
  6464. })
  6465. .fail(function (xhr) {
  6466. OrganizrApiError(xhr);
  6467. });
  6468. }
  6469. function loadInternal(id, split = null) {
  6470. let extra = split ? "right-" : "";
  6471. let tabInfo = findTab(id);
  6472. if (!tabInfo) {
  6473. organizrConsole("Load Internal", "No Tab Info Found... Id: " + id, "error");
  6474. return false;
  6475. }
  6476. let url = tabInfo.access_url;
  6477. organizrAPI2("get", url)
  6478. .success(function (data) {
  6479. try {
  6480. var html = data.response;
  6481. $("#internal-" + extra + id).html(html.data);
  6482. } catch (e) {
  6483. organizrCatchError(e, data);
  6484. }
  6485. })
  6486. .fail(function (xhr) {
  6487. OrganizrApiError(xhr);
  6488. });
  6489. }
  6490. function loadInternalOriginal(url, tabName) {
  6491. organizrAPI("get", url)
  6492. .success(function (data) {
  6493. try {
  6494. var html = JSON.parse(data);
  6495. } catch (e) {
  6496. organizrCatchError(e, data);
  6497. }
  6498. $("#internal-" + tabName).html(html.data);
  6499. })
  6500. .fail(function (xhr) {
  6501. OrganizrApiError(xhr);
  6502. });
  6503. }
  6504. function loadSettingsPage(api, element, organizrFn) {
  6505. organizrAPI("get", api)
  6506. .success(function (data) {
  6507. try {
  6508. var response = JSON.parse(data);
  6509. } catch (e) {
  6510. organizrCatchError(e, data);
  6511. }
  6512. organizrConsole("Organizr Function", "Loading " + organizrFn);
  6513. $(element).html(response.data);
  6514. })
  6515. .fail(function (xhr) {
  6516. OrganizrApiError(xhr);
  6517. });
  6518. }
  6519. function settingsAPI(post, callbacks = null, asyncValue = true) {
  6520. organizrAPI("POST", post.api, post, asyncValue)
  6521. .success(function (data) {
  6522. try {
  6523. var response = JSON.parse(data);
  6524. } catch (e) {
  6525. organizrCatchError(e, data);
  6526. }
  6527. message(
  6528. post.messageTitle,
  6529. post.messageBody,
  6530. activeInfo.settings.notifications.position,
  6531. "#FFF",
  6532. "success",
  6533. "5000"
  6534. );
  6535. if (callbacks) {
  6536. callbacks.fire();
  6537. }
  6538. })
  6539. .fail(function (xhr) {
  6540. console.error(post.error);
  6541. });
  6542. }
  6543. function organizrAPI(type, path, data = null, asyncValue = true) {
  6544. var timeout = 10000;
  6545. switch (path) {
  6546. case "api/?v1/windows/update":
  6547. case "api/?v1/docker/update":
  6548. timeout = 120000;
  6549. break;
  6550. default:
  6551. timeout = 60000;
  6552. }
  6553. switch (type) {
  6554. case "get":
  6555. case "GET":
  6556. case "g":
  6557. return $.ajax({
  6558. url: path,
  6559. method: "GET",
  6560. beforeSend: function (request) {
  6561. request.setRequestHeader("Token", activeInfo.token);
  6562. request.setRequestHeader("formKey", local("g", "formKey"));
  6563. },
  6564. timeout: timeout,
  6565. });
  6566. case "post":
  6567. case "POST":
  6568. case "p":
  6569. data.formKey = local("g", "formKey");
  6570. return $.ajax({
  6571. url: path,
  6572. method: "POST",
  6573. async: asyncValue,
  6574. beforeSend: function (request) {
  6575. request.setRequestHeader("Token", activeInfo.token);
  6576. request.setRequestHeader("formKey", local("g", "formKey"));
  6577. },
  6578. data: {
  6579. data: data,
  6580. },
  6581. });
  6582. default:
  6583. console.warn("Organizr API: Method Not Supported");
  6584. }
  6585. }
  6586. function githubVersions() {
  6587. return $.ajax({
  6588. url:
  6589. "https://raw.githubusercontent.com/causefx/Organizr/" +
  6590. activeInfo.branch +
  6591. "/js/version.json",
  6592. });
  6593. }
  6594. function sponsorsJSON() {
  6595. return $.ajax({
  6596. url: "https://raw.githubusercontent.com/causefx/Organizr/v2-develop/js/sponsors.json",
  6597. });
  6598. }
  6599. function newsJSON() {
  6600. return $.ajax({
  6601. url: "https://raw.githubusercontent.com/causefx/Organizr/v2-develop/js/news.json",
  6602. });
  6603. }
  6604. function getLatestCommitJSON() {
  6605. return $.ajax({
  6606. url:
  6607. "https://api.github.com/repos/causefx/Organizr/commits/" +
  6608. activeInfo.branch,
  6609. });
  6610. }
  6611. function marketplaceJSON(type) {
  6612. return $.ajax({
  6613. url:
  6614. "https://raw.githubusercontent.com/causefx/Organizr/v2-" +
  6615. type +
  6616. "/" +
  6617. type +
  6618. ".json",
  6619. });
  6620. }
  6621. function allIcons() {
  6622. return $.ajax({
  6623. url: "js/icons.json",
  6624. });
  6625. }
  6626. function organizrConnect(path) {
  6627. return $.ajax({
  6628. url: path,
  6629. });
  6630. }
  6631. function changeSettingsMenu(path) {
  6632. var menuItems = path.split("::");
  6633. var menu = "";
  6634. if (Array.isArray(menuItems)) {
  6635. $.each(menuItems, function (i, v) {
  6636. menu += '<li><a lang="en">' + v + "</a></li>";
  6637. });
  6638. }
  6639. $("#settingsBreadcrumb").html(menu);
  6640. }
  6641. function buildWizard() {
  6642. organizrAPI2("GET", "api/v2/page/wizard")
  6643. .success(function (data) {
  6644. try {
  6645. var json = data.response;
  6646. } catch (e) {
  6647. organizrCatchError(e, data);
  6648. }
  6649. organizrConsole("Organizr Function", "Starting Install Wizard");
  6650. $(json.data).appendTo($(".organizr-area"));
  6651. $(".organizr-area").removeClass("hidden");
  6652. })
  6653. .fail(function (xhr) {
  6654. OrganizrApiError(xhr, "Wiizard Error");
  6655. });
  6656. $("#preloader").fadeOut();
  6657. }
  6658. function buildDependencyCheck(orgdata) {
  6659. organizrAPI2("GET", "api/v2/page/dependencies")
  6660. .success(function (data) {
  6661. try {
  6662. var json = data.response;
  6663. } catch (e) {
  6664. organizrCatchError(e, data);
  6665. }
  6666. organizrConsole("Organizr Function", "Starting Dependencies Check");
  6667. $(json.data).appendTo($(".organizr-area"));
  6668. $(".organizr-area").removeClass("hidden");
  6669. $(buildBrowserInfo()).appendTo($("#browser-info"));
  6670. $("#web-folder").html(buildWebFolder(orgdata));
  6671. $("#php-version-check").html(buildPHPCheck(orgdata));
  6672. $(buildDependencyInfo(orgdata)).appendTo($("#depenency-info"));
  6673. })
  6674. .fail(function (xhr) {
  6675. OrganizrApiError(xhr, "Dependency Error");
  6676. });
  6677. $("#preloader").fadeOut();
  6678. }
  6679. function buildDependencyInfo(arrayItems) {
  6680. let listing = "";
  6681. $.each(arrayItems.data.status.dependenciesActive, function (i, v) {
  6682. listing +=
  6683. '<li class="depenency-item" data-name="' +
  6684. v +
  6685. '"><a href="javascript:void(0)"><i class="fa fa-check text-success"></i> ' +
  6686. v +
  6687. "</a></li>";
  6688. });
  6689. $.each(arrayItems.data.status.dependenciesInactive, function (i, v) {
  6690. listing +=
  6691. '<li class="depenency-item" data-name="' +
  6692. v +
  6693. '"><a href="javascript:void(0)"><i class="fa fa-close text-danger"><div class="notify"><span class="heartbit depend-heartbit"></span></div></i> ' +
  6694. v +
  6695. "</a></li>";
  6696. });
  6697. let className =
  6698. arrayItems.data.status.dependenciesInactive.length !== 0
  6699. ? "bg-danger text-warning"
  6700. : "bg-primary";
  6701. let icon =
  6702. arrayItems.data.status.dependenciesInactive.length !== 0
  6703. ? "fa fa-exclamation-triangle"
  6704. : "fa fa-check-circle"; //dependency-dependencies-check-listing-header
  6705. let header =
  6706. arrayItems.data.status.dependenciesInactive.length !== 0
  6707. ? "panel-danger"
  6708. : "panel-info";
  6709. let listingIcon =
  6710. arrayItems.data.status.dependenciesInactive.length !== 0
  6711. ? "ti-alert"
  6712. : "ti-check-box";
  6713. let listingText =
  6714. arrayItems.data.status.dependenciesInactive.length !== 0
  6715. ? "Dependencies Missing"
  6716. : "Dependencies OK";
  6717. $(".dependency-dependencies-check-listing-header")
  6718. .removeClass("panel-danger")
  6719. .addClass(header);
  6720. $(".dependency-dependencies-check-listing i")
  6721. .first()
  6722. .removeClass("ti-alert")
  6723. .addClass(listingIcon);
  6724. $(".dependency-dependencies-check-listing span").text(listingText);
  6725. $(".dependency-dependencies-check")
  6726. .removeClass("bg-warning")
  6727. .addClass(className);
  6728. $(".dependency-dependencies-check i")
  6729. .removeClass("fa fa-spin fa-spinner")
  6730. .addClass(icon);
  6731. return listing;
  6732. }
  6733. function buildWebFolder(arrayItems) {
  6734. let writable = "Not Writable - Please fix permissions";
  6735. let className = "bg-danger text-warning";
  6736. let icon = "fa fa-exclamation-triangle";
  6737. if (arrayItems.data.status.writable == "yes") {
  6738. writable = "Writable - All Good";
  6739. className = "bg-primary";
  6740. icon = "fa fa-check-circle";
  6741. }
  6742. $(".dependency-permissions-check")
  6743. .removeClass("bg-warning")
  6744. .addClass(className);
  6745. $(".dependency-permissions-check i")
  6746. .removeClass("fa fa-spin fa-spinner")
  6747. .addClass(icon);
  6748. $("#web-folder").addClass(className);
  6749. return writable;
  6750. }
  6751. function buildPHPCheck(arrayItems) {
  6752. let phpTest = "Upgrade PHP Version to 7.2+";
  6753. let className = "bg-danger text-warning";
  6754. let icon = "fa fa-exclamation-triangle";
  6755. if (arrayItems.data.status.minVersion == "yes") {
  6756. phpTest = "PHP Version Approved";
  6757. className = "bg-primary";
  6758. icon = "fa fa-check-circle";
  6759. }
  6760. $(".dependency-phpversion-check")
  6761. .removeClass("bg-warning")
  6762. .addClass(className);
  6763. $(".dependency-phpversion-check i")
  6764. .removeClass("fa fa-spin fa-spinner")
  6765. .addClass(icon);
  6766. $("#php-version-check").addClass(className);
  6767. $("#php-version-check-user").html(
  6768. '<span lang="en">Webserver User</span>: ' + arrayItems.data.status.php_user
  6769. );
  6770. return phpTest;
  6771. }
  6772. function buildBrowserInfo() {
  6773. var listing = "";
  6774. $.each(activeInfo, function (i, v) {
  6775. listing +=
  6776. `
  6777. <tr>
  6778. <td>` +
  6779. i +
  6780. `</td>
  6781. <td>` +
  6782. tof(v) +
  6783. `</td>
  6784. </tr>
  6785. `;
  6786. });
  6787. return (
  6788. `
  6789. <table class="table table-hover">
  6790. <tbody>
  6791. ` +
  6792. listing +
  6793. `
  6794. </tbody>
  6795. </table>
  6796. `
  6797. );
  6798. }
  6799. function tof(string, type) {
  6800. var result;
  6801. if (
  6802. typeof string == "undefined" ||
  6803. string == "false" ||
  6804. string == false ||
  6805. string == null ||
  6806. string == 0 ||
  6807. string == "off" ||
  6808. string == "no"
  6809. ) {
  6810. result = "0";
  6811. } else if (
  6812. string == "true" ||
  6813. string == true ||
  6814. string == 1 ||
  6815. string == "on" ||
  6816. string == "yes"
  6817. ) {
  6818. result = "1";
  6819. }
  6820. switch (type) {
  6821. case "bool":
  6822. case "b":
  6823. return result == "0" ? false : result == "1" ? true : string;
  6824. case "switch":
  6825. case "s":
  6826. return result == "0" ? "off" : result == "1" ? "on" : string;
  6827. case "checkbox":
  6828. case "c":
  6829. return result == "0" ? "" : result == "1" ? "checked" : string;
  6830. case "integer":
  6831. case "number":
  6832. case "i":
  6833. case "n":
  6834. return result == "0" ? 0 : result == "1" ? 1 : string;
  6835. case "question":
  6836. case "q":
  6837. return result == "0" ? "yes" : result == "1" ? "no" : string;
  6838. case "string":
  6839. return string.toString();
  6840. default:
  6841. return result == "0" ? "false" : result == "1" ? "true" : string;
  6842. }
  6843. }
  6844. function createRandomString(length) {
  6845. var str = "";
  6846. for (; str.length < length; str += Math.random().toString(36).substr(2));
  6847. return str.substr(0, length);
  6848. }
  6849. function generateAPI() {
  6850. var string = createRandomString(20);
  6851. $("#form-api").focus();
  6852. $("#form-api").val(string);
  6853. $("#form-api").focusout();
  6854. $("#verify-api").text(string);
  6855. $("#form-username").focus();
  6856. }
  6857. function getCookie(cname) {
  6858. var name = cname + "=";
  6859. var decodedCookie = decodeURIComponent(document.cookie);
  6860. var ca = decodedCookie.split(";");
  6861. for (var i = 0; i < ca.length; i++) {
  6862. var c = ca[i];
  6863. while (c.charAt(0) == " ") {
  6864. c = c.substring(1);
  6865. }
  6866. if (c.indexOf(name) == 0) {
  6867. return c.substring(name.length, c.length);
  6868. }
  6869. }
  6870. return "";
  6871. }
  6872. function localStorageSupport() {
  6873. return "localStorage" in window && window["localStorage"] !== null;
  6874. }
  6875. function local(type, key, value = null) {
  6876. if (localStorageSupport) {
  6877. switch (type) {
  6878. case "set":
  6879. case "s":
  6880. localStorage.setItem(key, value);
  6881. break;
  6882. case "get":
  6883. case "g":
  6884. return localStorage.getItem(key);
  6885. case "remove":
  6886. case "r":
  6887. localStorage.removeItem(key);
  6888. break;
  6889. default:
  6890. console.warn("Organizr Function: localStorage action not defined");
  6891. }
  6892. }
  6893. }
  6894. function language(language) {
  6895. var language = language.split("-");
  6896. return language[0];
  6897. }
  6898. function logIcon(type, label = false) {
  6899. type = type.toLowerCase();
  6900. let info = { color: "info", icon: "fa fa-check" };
  6901. switch (type) {
  6902. case "success":
  6903. info.color = "info";
  6904. info.icon = "fa fa-check";
  6905. break;
  6906. case "info":
  6907. info.color = "info";
  6908. info.icon = "mdi mdi-information";
  6909. break;
  6910. case "notice":
  6911. info.color = "inverse";
  6912. info.icon = "mdi mdi-information-variant";
  6913. break;
  6914. case "debug":
  6915. info.color = "primary";
  6916. info.icon = "mdi mdi-code-tags-check";
  6917. break;
  6918. case "warning":
  6919. info.color = "warning";
  6920. info.icon = "mdi mdi-alert-box";
  6921. break;
  6922. case "error":
  6923. info.color = "danger";
  6924. info.icon = "mdi mdi-alert-outline";
  6925. break;
  6926. case "critical":
  6927. info.color = "danger";
  6928. info.icon = "mdi mdi-alert";
  6929. break;
  6930. case "alert":
  6931. info.color = "danger";
  6932. info.icon = "mdi mdi-alert-octagon";
  6933. break;
  6934. case "emergency":
  6935. info.color = "danger";
  6936. info.icon = "mdi mdi-alert-octagram";
  6937. break;
  6938. default:
  6939. info = { color: "info", icon: "fa fa-check" };
  6940. break;
  6941. }
  6942. if (label) {
  6943. return (
  6944. '<span class="label label-' +
  6945. info.color +
  6946. ' log-label"> <i class="fa ' +
  6947. info.icon +
  6948. ' m-l-5 fa-fw"></i>&nbsp; <span lang="en" class="text-uppercase">' +
  6949. type +
  6950. "</span></span>"
  6951. );
  6952. } else {
  6953. return (
  6954. '<button class="btn btn-xs btn-' +
  6955. info.color +
  6956. ' log-label no-mouse" type="button"><span class="btn-label pull-left"><i class="' +
  6957. info.icon +
  6958. ' fa-fw"></i></span><span class="text-uppercase" lang="en">' +
  6959. type +
  6960. "</span></button>"
  6961. );
  6962. }
  6963. }
  6964. function toggleKillOrganizrLiveUpdate(interval = 5000) {
  6965. if ($(".organizr-log-live-update").hasClass("kill-organizr-log")) {
  6966. clearTimeout(timeouts["organizr-log"]);
  6967. $(".organizr-log-live-update i").toggleClass(
  6968. "fa-dot-circle-o animated loop-animation swing"
  6969. );
  6970. $(".organizr-log-live-update").toggleClass("kill-organizr-log");
  6971. } else {
  6972. $(".organizr-log-live-update").toggleClass("kill-organizr-log");
  6973. organizrLogLiveUpdate(interval);
  6974. }
  6975. }
  6976. function organizrLogLiveUpdate(interval = 5000) {
  6977. var timeout = interval;
  6978. let timeoutTitle = "organizr-log";
  6979. $(".organizr-log-live-update i").toggleClass(
  6980. "fa-dot-circle-o animated loop-animation swing"
  6981. );
  6982. organizrLogTable.ajax.reload(null, false);
  6983. setTimeout(function () {
  6984. if ($(".organizr-log-live-update").hasClass("kill-organizr-log")) {
  6985. $(".organizr-log-live-update i").toggleClass(
  6986. "fa-dot-circle-o animated loop-animation swing"
  6987. );
  6988. }
  6989. }, interval - 500);
  6990. if (typeof timeouts[timeoutTitle] !== "undefined") {
  6991. clearTimeout(timeouts[timeoutTitle]);
  6992. }
  6993. timeouts[timeoutTitle] = setTimeout(function () {
  6994. organizrLogLiveUpdate(timeout);
  6995. }, timeout);
  6996. delete timeout;
  6997. }
  6998. function radioLoop(element) {
  6999. $('[type=radio][id!="' + element.id + '"]').each(function () {
  7000. this.checked = false;
  7001. });
  7002. }
  7003. function loadAppearance(appearance) {
  7004. var cssSettings = "";
  7005. document.title = appearance.title;
  7006. if (appearance.useLogo === false) {
  7007. $("#main-logo").html(appearance.title);
  7008. $("#side-logo").html(appearance.title);
  7009. } else {
  7010. $("#main-logo").html(
  7011. '<img alt="home" class="dark-logo" src="' + appearance.logo + '">'
  7012. );
  7013. $("#side-logo").html(
  7014. '<img alt="home" class="dark-logo-side" src="' + appearance.logo + '">'
  7015. );
  7016. }
  7017. if (appearance.headerColor !== "") {
  7018. cssSettings +=
  7019. `
  7020. .navbar-header{
  7021. background: ` +
  7022. appearance.headerColor +
  7023. `;
  7024. }
  7025. `;
  7026. }
  7027. if (appearance.headerTextColor !== "") {
  7028. cssSettings +=
  7029. `
  7030. .navbar-top-links > li > a {
  7031. color: ` +
  7032. appearance.headerTextColor +
  7033. `;
  7034. }
  7035. `;
  7036. }
  7037. if (appearance.sidebarColor !== "") {
  7038. cssSettings +=
  7039. `
  7040. .sidebar, .sidebar .sidebar-head{
  7041. background: ` +
  7042. appearance.sidebarColor +
  7043. `;
  7044. }
  7045. `;
  7046. }
  7047. if (appearance.sidebarTextColor !== "") {
  7048. cssSettings +=
  7049. `
  7050. #side-menu li a,
  7051. .sidebar .sidebar-head h3,
  7052. #side-menu > li > a.active, #side-menu > li > ul > li > a.active
  7053. {
  7054. color: ` +
  7055. appearance.sidebarTextColor +
  7056. `;
  7057. }
  7058. `;
  7059. }
  7060. if (appearance.accentColor !== "") {
  7061. cssSettings +=
  7062. `
  7063. .bg-info,
  7064. .fc-toolbar,
  7065. .progress-bar-info,
  7066. .label-info,
  7067. .tabs-style-iconbox nav ul li.tab-current a,
  7068. .swapLog.active {
  7069. background-color: ` +
  7070. appearance.accentColor +
  7071. ` !important;
  7072. }
  7073. .panel-blue .panel-heading, .panel-info .panel-heading {
  7074. border-color: ` +
  7075. appearance.accentColor +
  7076. `;
  7077. }
  7078. .tabs-style-iconbox nav ul li.tab-current a::after {
  7079. border-top-color: ` +
  7080. appearance.accentColor +
  7081. `;
  7082. }
  7083. .customvtab .tabs-vertical li.active a,
  7084. .customvtab .tabs-vertical li.active a:focus,
  7085. .customvtab .tabs-vertical li.active a:hover {
  7086. border-right: 2px solid ` +
  7087. appearance.accentColor +
  7088. `;
  7089. }
  7090. .text-info,
  7091. .btn-link, a {
  7092. color: ` +
  7093. appearance.accentColor +
  7094. `;
  7095. }
  7096. `;
  7097. }
  7098. if (appearance.accentTextColor !== "") {
  7099. cssSettings +=
  7100. `
  7101. .bg-info,
  7102. .progress-bar,
  7103. .panel-default .panel-heading,
  7104. .mailbox-widget .customtab li.active a, .mailbox-widget .customtab li.active, .mailbox-widget .customtab li.active a:focus,
  7105. .mailbox-widget .customtab li a,
  7106. .tabs-style-iconbox nav ul li.tab-current a
  7107. .swapLog.active {
  7108. color: ` +
  7109. appearance.accentTextColor +
  7110. `;
  7111. }
  7112. `;
  7113. }
  7114. if (appearance.buttonColor !== "") {
  7115. cssSettings +=
  7116. `
  7117. .btn-info, .btn-info.disabled,
  7118. .btn,
  7119. .paginate_button.current,
  7120. .paginate_button:hover {
  7121. background: ` +
  7122. appearance.buttonColor +
  7123. ` !important;
  7124. border: 1px solid ` +
  7125. appearance.buttonColor +
  7126. ` !important;
  7127. }
  7128. `;
  7129. }
  7130. if (appearance.buttonTextColor !== "") {
  7131. cssSettings +=
  7132. `
  7133. .btn-info, .btn-info.disabled,
  7134. .btn
  7135. .paginate_button.current
  7136. .paginate_button:hover {
  7137. color: ` +
  7138. appearance.buttonTextColor +
  7139. ` !important;
  7140. }
  7141. `;
  7142. }
  7143. if (appearance.loginWallpaper !== "" || appearance.randomMediaImage) {
  7144. if (appearance.randomMediaImage) {
  7145. appearance.loginWallpaper = appearance.randomMediaImage;
  7146. }
  7147. cssSettings +=
  7148. `
  7149. .login-register {
  7150. background: url(` +
  7151. randomCSV(appearance.loginWallpaper) +
  7152. `) center center/cover no-repeat!important;
  7153. height: 100%;
  7154. position: fixed;
  7155. }
  7156. .lock-screen {
  7157. background: url(` +
  7158. randomCSV(appearance.loginWallpaper) +
  7159. `) center center/cover no-repeat!important;
  7160. height: 100%;
  7161. position: fixed;
  7162. z-index: 1001;
  7163. top: 0;
  7164. width: 100%;
  7165. -webkit-user-select: none;
  7166. -moz-user-select: none;
  7167. -ms-user-select: none;
  7168. -o-user-select: none;
  7169. user-select: none;
  7170. }
  7171. `;
  7172. }
  7173. if (activeInfo["settings"]["misc"]["autoExpandNavBar"] == false) {
  7174. cssSettings += `
  7175. @media only screen and (min-width: 768px) {
  7176. .sidebar:hover .hide-menu {
  7177. display: none;
  7178. }
  7179. .sidebar:hover .sidebar-head,
  7180. .sidebar:hover {
  7181. width: 60px;
  7182. }
  7183. .sidebar:hover .nav-second-level li a {
  7184. padding-left: 15px;
  7185. }
  7186. }
  7187. `;
  7188. }
  7189. if (cssSettings !== "") {
  7190. $("#user-appearance").html(cssSettings);
  7191. }
  7192. if (appearance.customThemeCss !== "") {
  7193. $("#custom-theme-css").html(appearance.customThemeCss);
  7194. }
  7195. if (appearance.customCss !== "") {
  7196. $("#custom-css").html(appearance.customCss);
  7197. }
  7198. }
  7199. function resetCustomColors() {
  7200. let colors = [
  7201. "headerColor",
  7202. "headerTextColor",
  7203. "sidebarColor",
  7204. "sidebarTextColor",
  7205. "accentColor",
  7206. "accentTextColor",
  7207. "buttonColor",
  7208. "buttonTextColor",
  7209. ];
  7210. $.each(colors, function (i, v) {
  7211. $("#customize-appearance-form [name=" + v + "]")
  7212. .val("")
  7213. .trigger("change");
  7214. });
  7215. messageSingle(
  7216. window.lang.translate("Colors Reverted"),
  7217. window.lang.translate("Please Save"),
  7218. activeInfo.settings.notifications.position,
  7219. "#FFF",
  7220. "success",
  7221. "10000"
  7222. );
  7223. }
  7224. function randomCSV(values) {
  7225. if (typeof values == "string") {
  7226. if (values.includes(",")) {
  7227. var csv = values.split(",");
  7228. var luckyNumber = Math.floor(Math.random() * csv.length);
  7229. return csv[luckyNumber];
  7230. } else {
  7231. return values;
  7232. }
  7233. }
  7234. return false;
  7235. }
  7236. function loadCustomJava(appearance) {
  7237. if (appearance.customThemeJava !== "") {
  7238. $("#custom-theme-javascript").html(appearance.customThemeJava);
  7239. }
  7240. if (appearance.customJava !== "") {
  7241. $("#custom-javascript").html(appearance.customJava);
  7242. }
  7243. }
  7244. function clearForm(form) {
  7245. $(form + " input[type=text]").each(function () {
  7246. $(this).val("");
  7247. });
  7248. $(form + " input[type=password]").each(function () {
  7249. $(this).val("");
  7250. });
  7251. }
  7252. function checkMessage() {
  7253. var check = local("get", "message") ? local("get", "message") : false;
  7254. if (check) {
  7255. local("remove", "message");
  7256. var message = check.split("|");
  7257. messageSingle(
  7258. window.lang.translate(message[0]),
  7259. window.lang.translate(message[1]),
  7260. activeInfo.settings.notifications.position,
  7261. "#FFF",
  7262. message[2],
  7263. "10000"
  7264. );
  7265. }
  7266. }
  7267. function setError(error) {
  7268. local("set", "error", error);
  7269. var url = window.location.href.split("?")[0];
  7270. url = url.split("#")[0];
  7271. window.location.href = url + "?error";
  7272. }
  7273. function buildErrorPage(error) {
  7274. var description = "";
  7275. var message = "";
  7276. var color = "";
  7277. switch (error) {
  7278. case "401":
  7279. description = "Unauthorized";
  7280. message = "Look, you dont belong here";
  7281. color = "danger";
  7282. break;
  7283. case "404":
  7284. description = "Not Found";
  7285. message = "I think I lost it...";
  7286. color = "primary";
  7287. break;
  7288. default:
  7289. description = "Something happened";
  7290. message = "But I dont know what";
  7291. color = "muted";
  7292. }
  7293. return (
  7294. `
  7295. <div class="error-box">
  7296. <div class="error-body text-center">
  7297. <h1 class="text-` +
  7298. color +
  7299. `">` +
  7300. error +
  7301. `</h1>
  7302. <h3 class="text-uppercase">` +
  7303. description +
  7304. `</h3>
  7305. <p class="text-muted m-t-30 m-b-30" lang="en">` +
  7306. message +
  7307. `</p>
  7308. <a href="javascript:void(0);" class="btn btn-` +
  7309. color +
  7310. ` btn-rounded waves-effect waves-light m-b-40 closeErrorPage animated tada loop-animation" lang="en">OK</a>
  7311. </div>
  7312. </div>
  7313. `
  7314. );
  7315. }
  7316. $.urlParam = function (name) {
  7317. var results = new RegExp("[?&]" + name + "=([^&#]*)").exec(
  7318. window.location.href
  7319. );
  7320. if (results == null) {
  7321. return null;
  7322. } else {
  7323. return decodeURI(results[1]) || 0;
  7324. }
  7325. };
  7326. function errorPage(error = null, uri = null) {
  7327. if (error) {
  7328. local("set", "error", error);
  7329. }
  7330. if (uri) {
  7331. local("set", "uri", uri);
  7332. }
  7333. //var urlParams = new URLSearchParams(window.location.search);
  7334. if ($.urlParam("error") !== null && !isNaN(Number($.urlParam("error")))) {
  7335. local("set", "error", $.urlParam("error"));
  7336. }
  7337. if ($.urlParam("return") !== null && activeInfo.user.loggedin !== true) {
  7338. local("set", "uri", $.urlParam("return"));
  7339. }
  7340. if (window.location !== window.parent.location) {
  7341. var count = 0;
  7342. for (var k in window.parent.location) {
  7343. if (window.parent.location.hasOwnProperty(k)) {
  7344. ++count;
  7345. }
  7346. }
  7347. if (count == 0 || count == "undefined") {
  7348. return false;
  7349. }
  7350. var iframeError = local("get", "error");
  7351. parent.errorPage(iframeError);
  7352. local("remove", "uri");
  7353. $("html").html("");
  7354. return false;
  7355. }
  7356. if (local("get", "error")) {
  7357. //show error page
  7358. $(".error-page").html(buildErrorPage(local("get", "error")));
  7359. $(".error-page").fadeIn();
  7360. local("remove", "error");
  7361. window.history.pushState({}, document.title, "./");
  7362. }
  7363. }
  7364. function uriRedirect(uri = null) {
  7365. if (uri) {
  7366. local("set", "uri", uri);
  7367. }
  7368. if (activeInfo.user.loggedin === true && activeInfo.user.locked !== 1) {
  7369. var redirect = local("get", "uri");
  7370. local("remove", "uri");
  7371. if (redirect !== null) {
  7372. window.location.href = decodeURIComponent(decodeURI(redirect));
  7373. }
  7374. }
  7375. }
  7376. function changeTheme(theme) {
  7377. //$("#preloader").fadeIn();
  7378. $("#theme").attr({
  7379. href: theme + ".css?v=" + activeInfo.version,
  7380. });
  7381. //$("#preloader").fadeOut();
  7382. console.info(
  7383. "%c Theme %c ".concat(theme, " "),
  7384. "color: white; background: #AD80FD; font-weight: 700;",
  7385. "color: #AD80FD; background: white; font-weight: 700;"
  7386. );
  7387. }
  7388. function changeStyle(style) {
  7389. //$("#preloader").fadeIn();
  7390. $("#style").attr({
  7391. href: "css/" + style + ".min.css?v=" + activeInfo.version,
  7392. });
  7393. //$("#preloader").fadeOut();
  7394. console.info(
  7395. "%c Style %c ".concat(style, " "),
  7396. "color: white; background: #AD80FD; font-weight: 700;",
  7397. "color: #AD80FD; background: white; font-weight: 700;"
  7398. );
  7399. }
  7400. function setSSO() {
  7401. $.each(activeInfo.sso, function (i, v) {
  7402. if (v !== false) {
  7403. local("set", i, v);
  7404. } else {
  7405. local("r", i);
  7406. }
  7407. });
  7408. // other items to remove
  7409. $.each(localStorage, function (i, v) {
  7410. if (typeof v == "string") {
  7411. if (i.startsWith("user-")) {
  7412. if (typeof activeInfo.sso[i] == "undefined") {
  7413. local("r", i);
  7414. }
  7415. }
  7416. }
  7417. });
  7418. }
  7419. function buildStreamItem(array, source) {
  7420. var cards = "";
  7421. var count = 0;
  7422. var total = array.length;
  7423. var sourceIcon = source === "jellyfin" ? "fish" : source;
  7424. var streamDetails = {
  7425. direct: 0,
  7426. transcode: 0,
  7427. };
  7428. var bandwidthDetails = {
  7429. wan: 0,
  7430. lan: 0,
  7431. };
  7432. cards += '<div class="flexbox">';
  7433. $.each(array, function (i, v) {
  7434. var icon = "";
  7435. var width = 100;
  7436. var bg = "";
  7437. count++;
  7438. v.nowPlayingImageURL = v.useImage ? v.useImage : v.nowPlayingImageURL;
  7439. switch (v.type) {
  7440. case "music":
  7441. icon = "icon-music-tone-alt";
  7442. width =
  7443. v.nowPlayingImageURL !== "plugins/images/homepage/no-np.png"
  7444. ? 56
  7445. : 100;
  7446. bg =
  7447. v.nowPlayingImageURL !== "plugins/images/homepage/no-np.png"
  7448. ? `
  7449. <img class="imageSource imageSourceLeft" src="` +
  7450. v.nowPlayingImageURL +
  7451. `">
  7452. <img class="imageSource imageSourceRight" src="` +
  7453. v.nowPlayingImageURL +
  7454. `">
  7455. `
  7456. : "";
  7457. break;
  7458. case "movie":
  7459. icon = "icon-film";
  7460. break;
  7461. case "tv":
  7462. icon = "icon-screen-desktop";
  7463. break;
  7464. case "video":
  7465. icon = "icon-screen-film";
  7466. break;
  7467. default:
  7468. }
  7469. var userThumb = v.userThumb
  7470. ? '<img src="' + v.userThumb + '" class="nowPlayingUserThumb" alt="User">'
  7471. : "";
  7472. if (v.sessionType == "Direct Playing") {
  7473. var userStream = "Direct Play";
  7474. var userVideo = "Direct Play";
  7475. var userAudio = "Direct Play";
  7476. streamDetails["direct"] = streamDetails["direct"] + 1;
  7477. } else {
  7478. var userStream = v.userStream.stream;
  7479. var userVideo =
  7480. v.userStream.videoDecision +
  7481. " (" +
  7482. v.userStream.sourceVideoCodec +
  7483. ' <i class="mdi mdi-ray-start-arrow"></i> ' +
  7484. v.userStream.videoCodec +
  7485. " " +
  7486. v.userStream.videoResolution +
  7487. ")";
  7488. var userAudio =
  7489. v.userStream.audioDecision +
  7490. " (" +
  7491. v.userStream.sourceAudioCodec +
  7492. ' <i class="mdi mdi-ray-start-arrow"></i> ' +
  7493. v.userStream.audioCodec +
  7494. ")";
  7495. streamDetails["transcode"] = streamDetails["transcode"] + 1;
  7496. }
  7497. var streamInfo = "";
  7498. streamInfo +=
  7499. `<div class="text-muted m-t-20 text-uppercase"><span class="text-uppercase"><i class="mdi mdi-play-circle-outline"></i> Stream: ` +
  7500. userStream +
  7501. `</span></div>`;
  7502. streamInfo += v.userStream.videoResolution
  7503. ? `<div class="text-muted m-t-20 text-uppercase"><span class="text-uppercase"><i class="mdi mdi-video"></i> Video: ` +
  7504. userVideo +
  7505. `</span></div>`
  7506. : "";
  7507. streamInfo +=
  7508. `<div class="text-muted m-t-20 text-uppercase"><span class="text-uppercase"><i class="mdi mdi-speaker"></i> Audio: ` +
  7509. userAudio +
  7510. `</span></div>`;
  7511. v.session = v.session.replace(/[\W_]+/g, "-");
  7512. bandwidthDetails[v.bandwidthType] =
  7513. bandwidthDetails[v.bandwidthType] + parseFloat(v.bandwidth);
  7514. cards +=
  7515. `
  7516. <div class="col-xl-2 col-lg-3 col-md-4 col-sm-6 col-xs-12 nowPlayingItem">
  7517. <div class="white-box">
  7518. <div class="el-card-item p-b-10">
  7519. <div class="el-card-avatar el-overlay-1 m-b-0">` +
  7520. bg +
  7521. `<img class="imageSource" style="width:` +
  7522. width +
  7523. `%;margin-left: auto;margin-right: auto;" src="` +
  7524. v.nowPlayingImageURL +
  7525. `">
  7526. <div class="el-overlay">
  7527. <ul class="el-info p-t-20 m-t-20">
  7528. <li><a class="btn b-none inline-popups" href="#` +
  7529. v.session +
  7530. `" data-effect="mfp-zoom-out"><i class="mdi mdi-server-network mdi-24px"></i></a></li>
  7531. <li><a class="btn b-none metadata-get" data-source="` +
  7532. source +
  7533. `" data-key="` +
  7534. v.metadataKey +
  7535. `" data-uid="` +
  7536. v.uid +
  7537. `"><i class="mdi mdi-information mdi-24px"></i></a></li>
  7538. <li><a class="btn b-none openTab" data-tab-name="` +
  7539. v.tabName +
  7540. `" data-type="` +
  7541. v.type +
  7542. `" data-open-tab="` +
  7543. v.openTab +
  7544. `" data-url="` +
  7545. v.address +
  7546. `" href="javascript:void(0);"><i class=" mdi mdi-` +
  7547. sourceIcon +
  7548. ` mdi-24px"></i></a></li>
  7549. <li><a class="btn b-none refreshImage" data-type="nowPlaying" data-image="` +
  7550. v.nowPlayingOriginalImage +
  7551. `" href="javascript:void(0);"><i class="mdi mdi-refresh mdi-24px"></i></a></li>
  7552. <a class="inline-popups ` +
  7553. v.uid +
  7554. ` hidden" href="#` +
  7555. v.uid +
  7556. `-metadata-div" data-effect="mfp-zoom-out"></a>
  7557. </ul>
  7558. </div>
  7559. </div>
  7560. <div class="el-card-content">
  7561. <div class="progress">
  7562. <div class="progress-bar progress-bar-info" style="width: ` +
  7563. v.watched +
  7564. `%;" role="progressbar"><span class="hidden">` +
  7565. v.watched +
  7566. `%</span></div>
  7567. <div class="progress-bar progress-bar-inverse" style="width: ` +
  7568. v.transcoded +
  7569. `%;" role="progressbar"></div>
  7570. </div>
  7571. <h3 class="box-title pull-left p-l-10 elip" style="width:90%">` +
  7572. v.nowPlayingTitle +
  7573. `</h3>
  7574. <h3 class="box-title pull-right vertical-middle" style="width:10%"><i class="icon-control-` +
  7575. v.state +
  7576. ` fa-fw text-info" style=""></i></h3>
  7577. <div class="clearfix"></div>
  7578. <small class="pull-left p-l-10 w-50 elip"><span class="pull-left"><i class="` +
  7579. icon +
  7580. ` fa-fw text-info"></i>` +
  7581. v.nowPlayingBottom +
  7582. `</span></small>
  7583. <small class="pull-right p-r-10 w-50"><span class="pull-right"><span class="">` +
  7584. v.user +
  7585. ` <i class="icon-user"></i></span></span></small>
  7586. <br>
  7587. </div>
  7588. </div>
  7589. </div>
  7590. </div>
  7591. <div id="` +
  7592. v.session +
  7593. `" class="white-popup mfp-with-anim mfp-hide">
  7594. <div class="col-md-6 col-md-offset-3">
  7595. <div class="white-box m-b-0 bg-info">
  7596. <h3 class="text-white box-title m-b-0">` +
  7597. v.sessionType +
  7598. `<span class="pull-right"><i class="mdi mdi-network-upload"></i> ` +
  7599. v.bandwidth +
  7600. ` kbps <button type="button" class="btn bg-org btn-circle close-popup m-l-10"><i class="fa fa-times"></i> </button></span></h3>
  7601. </div>
  7602. <div class="white-box">
  7603. <div class="row">
  7604. <div class="p-l-20 p-r-20">
  7605. <div class="pull-left">
  7606. <span class="text-uppercase"><i class="mdi mdi-` +
  7607. v.bandwidthType +
  7608. `"></i> ` +
  7609. v.bandwidthType +
  7610. `</span>
  7611. <span class="text-uppercase"><i class="mdi mdi-account-network"></i> ` +
  7612. v.userAddress +
  7613. `</span>
  7614. ` +
  7615. streamInfo +
  7616. `
  7617. <div class="text-muted m-t-20 text-uppercase"><span class="text-uppercase"><i class="mdi mdi-` +
  7618. source +
  7619. `"></i> Product: ` +
  7620. v.userStream.product +
  7621. `</span></div>
  7622. <div class="text-muted m-t-20 text-uppercase"><span class="text-uppercase"><i class="mdi mdi-laptop-mac"></i> Device: ` +
  7623. v.userStream.device +
  7624. `</span></div>
  7625. </div>
  7626. <div data-label="` +
  7627. v.watched +
  7628. `%" class="css-bar css-bar-` +
  7629. Math.ceil(v.watched / 5) * 5 +
  7630. ` css-bar-lg m-b-0 css-bar-info pull-right">` +
  7631. userThumb +
  7632. `</div>
  7633. </div>
  7634. </div>
  7635. </div>
  7636. </div>
  7637. </div>
  7638. <div id="` +
  7639. v.uid +
  7640. `-metadata-div" class="white-popup mfp-with-anim mfp-hide">
  7641. <div class="col-md-8 col-md-offset-2 ` +
  7642. v.uid +
  7643. `-metadata-info"></div>
  7644. </div>
  7645. `;
  7646. });
  7647. cards += "</div><!--end-->";
  7648. cards += buildStreamTooltip(bandwidthDetails, streamDetails, source);
  7649. return cards;
  7650. }
  7651. function buildStreamTooltip(bandwidth, streams, type) {
  7652. var html = "";
  7653. var streamText = "Streams: ";
  7654. var bandwidthText = " | Bandwidth: ";
  7655. var bandwidthTotal =
  7656. parseFloat(bandwidth["wan"]) + parseFloat(bandwidth["lan"]);
  7657. if (type !== "plex") {
  7658. bandwidthText += (parseFloat(bandwidth["wan"]) / 1000).toFixed(1) + " Mbps";
  7659. } else {
  7660. bandwidthText += (parseFloat(bandwidthTotal) / 1000).toFixed(1) + " Mbps";
  7661. if (bandwidth["wan"] !== 0) {
  7662. bandwidthText +=
  7663. " | WAN: " + (parseFloat(bandwidth["wan"]) / 1000).toFixed(1) + " Mbps";
  7664. }
  7665. if (bandwidth["lan"] !== 0) {
  7666. bandwidthText +=
  7667. " | LAN: " + (parseFloat(bandwidth["lan"]) / 1000).toFixed(1) + " Mbps";
  7668. }
  7669. }
  7670. var spacer = "";
  7671. if (streams["direct"] !== 0) {
  7672. streamText += streams["direct"] + " Direct Play(s)";
  7673. spacer = " & ";
  7674. }
  7675. if (streams["transcode"] !== 0) {
  7676. streamText += spacer + streams["transcode"] + " Transcode(s)";
  7677. }
  7678. html +=
  7679. '<span class="label label-info m-l-20 mouse" title="" data-toggle="tooltip" data-original-title="' +
  7680. streamText +
  7681. bandwidthText +
  7682. '" data-placement="bottom"><i class="fa fa-info"></i></span>';
  7683. return (
  7684. `
  7685. <script>$('.streamDetails-` +
  7686. type +
  7687. `').html('` +
  7688. html +
  7689. `');$('[data-toggle="tooltip"]').tooltip();</script>
  7690. `
  7691. );
  7692. }
  7693. function buildRecentItem(array, type, extra = null) {
  7694. var items = "";
  7695. $.each(array, function (i, v) {
  7696. if (extra == null) {
  7697. var className = "";
  7698. var extraImg = "";
  7699. switch (v.type) {
  7700. case "music":
  7701. className = "recent-cover recent-item recent-music";
  7702. extraImg =
  7703. '<img src="' +
  7704. v.imageURL +
  7705. '" class="imageSourceAlt imageSourceTop recent-cover"><img src="' +
  7706. v.imageURL +
  7707. '" class="imageSourceAlt imageSourceBottom recent-cover">';
  7708. break;
  7709. case "movie":
  7710. className = "recent-poster recent-item recent-movie";
  7711. break;
  7712. case "tv":
  7713. className = "recent-poster recent-item recent-tv";
  7714. break;
  7715. case "video":
  7716. className = "recent-poster recent-item recent-video";
  7717. break;
  7718. default:
  7719. }
  7720. items +=
  7721. `
  7722. <div class="item lazyload ` +
  7723. className +
  7724. ` metadata-get mouse imageSource" data-source="` +
  7725. type +
  7726. `" data-key="` +
  7727. v.metadataKey +
  7728. `" data-uid="` +
  7729. v.uid +
  7730. `" data-src="` +
  7731. v.imageURL +
  7732. `">
  7733. ` +
  7734. extraImg +
  7735. `
  7736. <div class="hover-homepage-item">
  7737. <span class="elip request-title-movie">
  7738. <a class="text-white refreshImage" data-type="recent-item" data-image="` +
  7739. v.originalImage +
  7740. `" href="javascript:void(0);"><i class="mdi mdi-refresh mdi-24px"></i></a>
  7741. </span>
  7742. </div>
  7743. <span class="elip recent-title">` +
  7744. v.title +
  7745. `<br/>` +
  7746. v.secondaryTitle +
  7747. `</span>
  7748. <div id="` +
  7749. v.uid +
  7750. `-metadata-div" class="white-popup mfp-with-anim mfp-hide">
  7751. <div class="col-md-8 col-md-offset-2 ` +
  7752. v.uid +
  7753. `-metadata-info"></div>
  7754. </div>
  7755. </div>
  7756. `;
  7757. } else {
  7758. items +=
  7759. `
  7760. <a class="inline-popups ` +
  7761. v.uid +
  7762. ` hidden" href="#` +
  7763. v.uid +
  7764. `-metadata-div" data-effect="mfp-zoom-out"></a>
  7765. `;
  7766. }
  7767. });
  7768. return items;
  7769. }
  7770. function buildPlaylistItem(array, type, extra = null) {
  7771. var items = "";
  7772. $.each(array, function (i, v) {
  7773. if (i !== "title") {
  7774. if (extra == null) {
  7775. items +=
  7776. `
  7777. <div class="item lazyload recent-poster metadata-get mouse imageSource" data-source="` +
  7778. type +
  7779. `" data-key="` +
  7780. v.metadataKey +
  7781. `" data-uid="` +
  7782. v.uid +
  7783. `" data-src="` +
  7784. v.imageURL +
  7785. `">
  7786. <div class="hover-homepage-item">
  7787. <span class="elip request-title-movie">
  7788. <a class="text-white refreshImage" data-type="recent-item" data-image="` +
  7789. v.originalImage +
  7790. `" href="javascript:void(0);"><i class="mdi mdi-refresh mdi-24px"></i></a>
  7791. </span>
  7792. </div>
  7793. <span class="elip recent-title">` +
  7794. v.title +
  7795. `</span>
  7796. <div id="` +
  7797. v.uid +
  7798. `-metadata-div" class="white-popup mfp-with-anim mfp-hide">
  7799. <div class="col-md-8 col-md-offset-2 ` +
  7800. v.uid +
  7801. `-metadata-info"></div>
  7802. </div>
  7803. </div>
  7804. `;
  7805. } else {
  7806. items +=
  7807. `
  7808. <a class="inline-popups ` +
  7809. v.uid +
  7810. ` hidden" href="#` +
  7811. v.uid +
  7812. `-metadata-div" data-effect="mfp-zoom-out"></a>
  7813. `;
  7814. }
  7815. }
  7816. });
  7817. return items;
  7818. }
  7819. function buildRequestAdminMenuItem(value, category, id, type) {
  7820. var action = "";
  7821. var text = "";
  7822. var extra = "";
  7823. switch (category) {
  7824. case "approved":
  7825. if (value) {
  7826. //nada
  7827. } else {
  7828. action = "approve";
  7829. text = "Approve";
  7830. extra =
  7831. `<li><a class="mouse" onclick="requestActions('` +
  7832. id +
  7833. `', 'deny', '` +
  7834. type +
  7835. `');" lang="en">Deny</a></li>`;
  7836. }
  7837. break;
  7838. case "available":
  7839. if (value) {
  7840. action = "unavailable";
  7841. text = "Mark as Unavailable";
  7842. } else {
  7843. action = "available";
  7844. text = "Mark as Available";
  7845. }
  7846. break;
  7847. default:
  7848. }
  7849. return action
  7850. ? `<li><a class="mouse" onclick="requestActions('` +
  7851. id +
  7852. `', '` +
  7853. action +
  7854. `', '` +
  7855. type +
  7856. `');" lang="en">` +
  7857. text +
  7858. `</a></li>` +
  7859. extra
  7860. : "";
  7861. }
  7862. function buildRequestItem(array, extra = null) {
  7863. var items = "";
  7864. let service = activeInfo.settings.homepage.requests.service;
  7865. $.each(array, function (i, v) {
  7866. if (extra == null) {
  7867. var approveID =
  7868. v.type == "tv" && service === "ombi" ? v.id : v.request_id;
  7869. var iconType = v.type == "tv" ? "fa-tv " : "fa-film";
  7870. var badge = "";
  7871. var badge2 = "";
  7872. var bg = v.background.includes(".")
  7873. ? v.background
  7874. : "plugins/images/homepage/no-np.png";
  7875. v.user =
  7876. (activeInfo.settings.homepage.ombi.alias && service === "ombi") ||
  7877. (activeInfo.settings.homepage.overseerr.enabled &&
  7878. service === "overseerr")
  7879. ? v.userAlias
  7880. : v.user;
  7881. //Set Status
  7882. var status = v.approved
  7883. ? '<span class="badge bg-org m-r-10" lang="en">Approved</span>'
  7884. : '<span class="badge bg-danger m-r-10" lang="en">Unapproved</span>';
  7885. status += v.available
  7886. ? '<span class="badge bg-org m-r-10" lang="en">Available</span>'
  7887. : '<span class="badge bg-danger m-r-10" lang="en">Unavailable</span>';
  7888. status += v.denied
  7889. ? '<span class="badge bg-danger m-r-10" lang="en">Denied</span>'
  7890. : "";
  7891. //Set Class
  7892. var className = v.approved ? "request-approved" : "request-unapproved";
  7893. className += v.available ? " request-available" : " request-unavailable";
  7894. className += v.denied ? " request-denied" : " request-notdenied";
  7895. //Set badge
  7896. badge = v.approved ? "bg-info" : "bg-warning";
  7897. badge = v.denied ? "bg-danger" : badge;
  7898. badge2 = v.available ? "bg-success" : "bg-danger";
  7899. //Is Admin?
  7900. var adminFunctions =
  7901. `<div class="btn-group m-r-10">
  7902. <button aria-expanded="false" data-toggle="dropdown" class="btn btn-info btn-outline dropdown-toggle waves-effect waves-light" type="button"> <i class="fa fa-ellipsis-v m-r-5"></i> <span class="caret"></span></button>
  7903. <ul role="menu" class="dropdown-menu">
  7904. <li><h5 class="text-center" lang="en">Request Options</h5></li>
  7905. <li class="divider"></li>
  7906. ` +
  7907. buildRequestAdminMenuItem(v.approved, "approved", approveID, v.type) +
  7908. `
  7909. ` +
  7910. buildRequestAdminMenuItem(v.available, "available", approveID, v.type) +
  7911. `
  7912. <li><a class="mouse" onclick="requestActions('` +
  7913. v.request_id +
  7914. `', 'delete', '` +
  7915. v.type +
  7916. `');" lang="en">Delete</a></li>
  7917. </ul>
  7918. </div>`;
  7919. adminFunctions = activeInfo.user.groupID <= 1 ? adminFunctions : "";
  7920. var user =
  7921. activeInfo.user.groupID <= 1
  7922. ? '<span lang="en">Requested By:</span> ' + v.user
  7923. : "";
  7924. var user2 = activeInfo.user.groupID <= 1 ? "<br>" + v.user : "";
  7925. var divId = v.type == "movie" ? v.request_id : v.id;
  7926. items +=
  7927. `
  7928. <div class="item lazyload recent-poster request-item request-` +
  7929. v.type +
  7930. ` ` +
  7931. className +
  7932. ` request-` +
  7933. divId +
  7934. `-div mouse" data-target="request-` +
  7935. v.id +
  7936. `" data-src="` +
  7937. v.poster +
  7938. `">
  7939. <div class="outside-request-div">
  7940. <div class="inside-over-request-div ` +
  7941. badge2 +
  7942. `"></div>
  7943. <div class="inside-request-div ` +
  7944. badge +
  7945. `"></div>
  7946. </div>
  7947. <div class="hover-homepage-item"></div>
  7948. <span class="elip request-title-` +
  7949. v.type +
  7950. `"><i class="fa ` +
  7951. iconType +
  7952. `"></i></span>
  7953. <span class="elip recent-title">` +
  7954. v.title +
  7955. user2 +
  7956. `</span>
  7957. <div id="request-` +
  7958. v.id +
  7959. `" class="white-popup mfp-with-anim mfp-hide">
  7960. <div class="col-md-8 col-md-offset-2">
  7961. <div class="white-box m-b-0">
  7962. <div class="user-bg lazyload" data-src="` +
  7963. bg +
  7964. `">
  7965. <div class="col-xs-2 p-10">` +
  7966. adminFunctions +
  7967. `</div>
  7968. <div class="col-xs-10">
  7969. <h2 class="m-b-0 font-medium pull-right text-right">
  7970. ` +
  7971. v.title +
  7972. `<button type="button" class="btn bg-org btn-circle close-popup m-l-10"><i class="fa fa-times"></i> </button><br>
  7973. <small class="m-t-0 text-white">` +
  7974. user +
  7975. `</small><br>
  7976. ` +
  7977. buildYoutubeLink(v.title + " " + v.type) +
  7978. `
  7979. </h2>
  7980. </div>
  7981. <div class="genre-list p-10">` +
  7982. status +
  7983. `</div>
  7984. </div>
  7985. </div>
  7986. <div class="panel panel-info p-b-0 p-t-0">
  7987. <div class="panel-body p-b-0 p-t-0 m-b-0">
  7988. <div class="p-20 text-center">
  7989. <p class="">` +
  7990. v.overview +
  7991. `</p>
  7992. </div>
  7993. <div class="row">
  7994. <div class="col-lg-12">
  7995. <div class="owl-carousel owl-theme metadata-actors p-b-10"></div>
  7996. </div>
  7997. </div>
  7998. </div>
  7999. </div>
  8000. </div>
  8001. </div>
  8002. </div>
  8003. `;
  8004. } else {
  8005. items +=
  8006. `
  8007. <a class="inline-popups hidden" id="link-request-` +
  8008. v.id +
  8009. `" href="#request-` +
  8010. v.id +
  8011. `" data-effect="mfp-zoom-out" ></a>
  8012. `;
  8013. }
  8014. });
  8015. return items !== "" || extra == null
  8016. ? items
  8017. : '<h2 class="text-center">No items</h2>';
  8018. }
  8019. function buildStream(array, type) {
  8020. var streams =
  8021. typeof array.content !== "undefined" ? array.content.length : false;
  8022. var originalType = type;
  8023. //type = (type === 'emby' && activeInfo.settings.homepage.media.jellyfin) ? 'jellyfin' : type;
  8024. return streams
  8025. ? `
  8026. <div id="` +
  8027. type +
  8028. `Streams">
  8029. <div class="el-element-overlay row">
  8030. <div class="col-md-12">
  8031. <h4 class="pull-left homepage-element-title"><span lang="en">Active</span> ` +
  8032. toUpper(type) +
  8033. ` <span lang="en">Streams</span> : </h4><h4 class="pull-left">&nbsp;<span class="label label-info m-l-20 checkbox-circle mouse" onclick="homepageStream('` +
  8034. originalType +
  8035. `')">` +
  8036. streams +
  8037. `</span><span class="streamDetails-` +
  8038. type +
  8039. `"></span></h4>
  8040. <hr class="hidden-xs">
  8041. </div>
  8042. <div class="clearfix"></div>
  8043. <!-- .cards -->
  8044. ` +
  8045. buildStreamItem(array.content, type) +
  8046. `
  8047. <!-- /.cards-->
  8048. </div>
  8049. </div>
  8050. <div class="clearfix"></div>
  8051. `
  8052. : "";
  8053. }
  8054. function buildRecent(array, type) {
  8055. var recent = typeof array.content !== "undefined" ? true : false;
  8056. array.content = recent ? Object.values(array.content) : false;
  8057. var movie = recent
  8058. ? array.content.filter((p) => p.type == "movie").length > 0
  8059. ? true
  8060. : false
  8061. : false;
  8062. var tv = recent
  8063. ? array.content.filter((p) => p.type == "tv").length > 0
  8064. ? true
  8065. : false
  8066. : false;
  8067. var video = recent
  8068. ? array.content.filter((p) => p.type == "video").length > 0
  8069. ? true
  8070. : false
  8071. : false;
  8072. var music = recent
  8073. ? array.content.filter((p) => p.type == "music").length > 0
  8074. ? true
  8075. : false
  8076. : false;
  8077. var dropdown = "";
  8078. var header = "";
  8079. var headerAlt = "";
  8080. var refreshType = type;
  8081. //type = (type === 'emby' && activeInfo.settings.homepage.media.jellyfin) ? 'jellyfin' : type;
  8082. dropdown +=
  8083. recent && movie
  8084. ? `<li><a data-filter="recent-movie" server-filter="` +
  8085. type +
  8086. `" href="javascript:void(0);">Movies</a></li>`
  8087. : "";
  8088. dropdown +=
  8089. recent && tv
  8090. ? `<li><a data-filter="recent-tv" server-filter="` +
  8091. type +
  8092. `" href="javascript:void(0);">Shows</a></li>`
  8093. : "";
  8094. dropdown +=
  8095. recent && video
  8096. ? `<li><a data-filter="recent-video" server-filter="` +
  8097. type +
  8098. `" href="javascript:void(0);">Videos</a></li>`
  8099. : "";
  8100. dropdown +=
  8101. recent && music
  8102. ? `<li><a data-filter="recent-music" server-filter="` +
  8103. type +
  8104. `" href="javascript:void(0);">Music</a></li>`
  8105. : "";
  8106. var dropdownMenu =
  8107. `
  8108. <div class="btn-group pull-right">
  8109. <button type="button" class="btn btn-info waves-effect hidden-xs" onclick="owlChange('` +
  8110. type +
  8111. `-recent','previous');"><i class="fa fa-chevron-left"></i></button>
  8112. <button type="button" class="btn btn-info waves-effect hidden-xs" onclick="owlChange('` +
  8113. type +
  8114. `-recent','next');"><i class="fa fa-chevron-right"></i></button>
  8115. <button aria-expanded="false" data-toggle="dropdown" class="btn btn-info dropdown-toggle waves-effect waves-light" type="button">
  8116. <i class="fa fa-filter m-r-5"></i><span class="caret"></span>
  8117. </button>
  8118. <ul role="menu" class="dropdown-menu recent-filter">
  8119. <li><a data-filter="all" server-filter="` +
  8120. type +
  8121. `" href="javascript:void(0);">All</a></li>
  8122. <li class="divider"></li>
  8123. ` +
  8124. dropdown +
  8125. `
  8126. </ul>
  8127. </div>`;
  8128. if (activeInfo.settings.homepage.options.alternateHomepageHeaders) {
  8129. var headerAlt =
  8130. `
  8131. <div class="col-md-12">
  8132. <h4 class="pull-left homepage-element-title"><span class="mouse" onclick="homepageRecent('` +
  8133. type +
  8134. `')" lang="en">Recently Added</span> : </h4><h4 class="pull-left">&nbsp;</h4>
  8135. ` +
  8136. dropdownMenu +
  8137. `
  8138. <hr class="hidden-xs"><div class="clearfix"></div>
  8139. </div>
  8140. <div class="clearfix"></div>
  8141. `;
  8142. } else {
  8143. var header =
  8144. `
  8145. <div class="panel-heading bg-info p-t-10 p-b-10">
  8146. <span onclick="homepageRecent('` +
  8147. type +
  8148. `')" class="pull-left m-t-5 mouse"><img class="lazyload homepageImageTitle" data-src="plugins/images/tabs/` +
  8149. type +
  8150. `.png"> &nbsp; <span lang="en">Recently Added</span></span>
  8151. ` +
  8152. dropdownMenu +
  8153. `
  8154. <div class="clearfix"></div>
  8155. </div>
  8156. `;
  8157. }
  8158. return recent
  8159. ? `
  8160. <div id="` +
  8161. type +
  8162. `Recent" class="row">
  8163. ` +
  8164. headerAlt +
  8165. `
  8166. <div class="col-lg-12">
  8167. <div class="panel panel-default">
  8168. ` +
  8169. header +
  8170. `
  8171. <div class="panel-wrapper p-b-0 collapse in">
  8172. <div class="` +
  8173. type +
  8174. `-recent-hidden hidden"></div>
  8175. <div class="owl-carousel owl-theme recent-items ` +
  8176. type +
  8177. `-recent">
  8178. ` +
  8179. buildRecentItem(array.content, type) +
  8180. `
  8181. </div>
  8182. ` +
  8183. buildRecentItem(array.content, type, true) +
  8184. `
  8185. </div>
  8186. </div>
  8187. </div>
  8188. </div>
  8189. `
  8190. : "";
  8191. }
  8192. function owlChange(elm, action) {
  8193. switch (action) {
  8194. case "next":
  8195. $("." + elm).trigger("next.owl");
  8196. break;
  8197. case "previous":
  8198. $("." + elm).trigger("prev.owl");
  8199. break;
  8200. default:
  8201. return false;
  8202. }
  8203. return false;
  8204. }
  8205. function cleanPlaylistTitle(string) {
  8206. var test = string.split(".");
  8207. if (test.length > 1) {
  8208. if (!isNaN(test[0])) {
  8209. return test[1];
  8210. }
  8211. }
  8212. return string;
  8213. }
  8214. function buildPlaylist(array, type) {
  8215. var playlist =
  8216. typeof array.content !== "undefined"
  8217. ? Object.keys(array.content).length
  8218. : false;
  8219. var dropdown = "";
  8220. var first = "";
  8221. var firstButton = "";
  8222. var hidden = "";
  8223. var count = 0;
  8224. var items = "";
  8225. var header = "";
  8226. var headerAlt = "";
  8227. if (playlist) {
  8228. $.each(array.content, function (i, v) {
  8229. v.title = cleanPlaylistTitle(v.title);
  8230. count++;
  8231. first = count == 1 ? v.title : first;
  8232. firstButton = count == 1 ? i + "-playlist" : firstButton;
  8233. hidden = count == 1 ? "" : " owl-hidden hidden";
  8234. dropdown +=
  8235. `<li><a data-filter="` +
  8236. i +
  8237. `" server-filter="` +
  8238. type +
  8239. `" data-title="` +
  8240. encodeURI(v.title) +
  8241. `" href="javascript:void(0);">` +
  8242. v.title +
  8243. `</a></li>`;
  8244. items +=
  8245. `
  8246. <div class="owl-carousel owl-theme playlist-items ` +
  8247. type +
  8248. `-playlist ` +
  8249. hidden +
  8250. ` ` +
  8251. i +
  8252. `-playlist">
  8253. ` +
  8254. buildPlaylistItem(v, type) +
  8255. `
  8256. </div>
  8257. ` +
  8258. buildPlaylistItem(v, type, true) +
  8259. `
  8260. `;
  8261. });
  8262. var builtDropdown =
  8263. `
  8264. <button type="button" class="btn btn-info waves-effect hidden-xs playlist-previous" onclick="owlChange('` +
  8265. firstButton +
  8266. `','previous');"><i class="fa fa-chevron-left"></i></button>
  8267. <button type="button" class="btn btn-info waves-effect hidden-xs playlist-next" onclick="owlChange('` +
  8268. firstButton +
  8269. `','next');"><i class="fa fa-chevron-right"></i></button>
  8270. <button aria-expanded="false" data-toggle="dropdown" class="btn btn-info dropdown-toggle waves-effect waves-light" type="button">
  8271. <i class="mdi mdi-playlist-play m-r-5 fa-lg"></i><span class="caret"></span>
  8272. </button>
  8273. <ul role="menu" class="dropdown-menu playlist-filter">
  8274. ` +
  8275. dropdown +
  8276. `
  8277. </ul>
  8278. `;
  8279. }
  8280. if (activeInfo.settings.homepage.options.alternateHomepageHeaders) {
  8281. var headerAlt =
  8282. `
  8283. <div class="col-md-12">
  8284. <h4 class="pull-left homepage-element-title"><span onclick="homepagePlaylist('` +
  8285. type +
  8286. `')" class="` +
  8287. type +
  8288. `-playlistTitle mouse">` +
  8289. first +
  8290. `</span> : </h4><h4 class="pull-left">&nbsp;</h4>
  8291. <div class="btn-group pull-right">
  8292. ` +
  8293. builtDropdown +
  8294. `
  8295. </div>
  8296. <hr class="hidden-xs"><div class="clearfix"></div>
  8297. </div>
  8298. <div class="clearfix"></div>
  8299. `;
  8300. } else {
  8301. var header =
  8302. `
  8303. <div class="panel-heading bg-info p-t-10 p-b-10">
  8304. <span class="pull-left m-t-5 mouse homepage-element-title" onclick="homepagePlaylist('` +
  8305. type +
  8306. `')"><img class="lazyload homepageImageTitle" data-src="plugins/images/tabs/` +
  8307. type +
  8308. `.png"> &nbsp; <span class="` +
  8309. type +
  8310. `-playlistTitle">` +
  8311. first +
  8312. `</span></span>
  8313. <div class="btn-group pull-right">
  8314. ` +
  8315. builtDropdown +
  8316. `
  8317. </div>
  8318. <div class="clearfix"></div>
  8319. </div>
  8320. `;
  8321. }
  8322. return playlist
  8323. ? `
  8324. <div id="` +
  8325. type +
  8326. `Playlist" class="row">
  8327. ` +
  8328. headerAlt +
  8329. `
  8330. <div class="col-lg-12">
  8331. <div class="panel panel-default">
  8332. ` +
  8333. header +
  8334. `
  8335. <div class="panel-wrapper p-b-0 collapse in">
  8336. ` +
  8337. items +
  8338. `
  8339. </div>
  8340. </div>
  8341. </div>
  8342. </div>
  8343. `
  8344. : "";
  8345. }
  8346. function buildRequest(service, div, array) {
  8347. var requests = typeof array.content !== "undefined";
  8348. var dropdown = "";
  8349. var headerAlt = "";
  8350. var header = "";
  8351. var requestButton =
  8352. activeInfo["settings"]["homepage"][service]["enabled"] === true
  8353. ? `<button href="#new-request" id="newRequestButton" class="btn btn-info waves-effect waves-light inline-popups" data-effect="mfp-zoom-out"><i class="fa fa-search m-l-5"></i></button>`
  8354. : "";
  8355. if (requests) {
  8356. var builtDropdown =
  8357. `
  8358. <button type="button" class="btn btn-info waves-effect hidden-xs" onclick="owlChange('request-items-${service}','previous');"><i class="fa fa-chevron-left"></i></button>
  8359. <button type="button" class="btn btn-info waves-effect hidden-xs" onclick="owlChange('request-items-${service}','next');"><i class="fa fa-chevron-right"></i></button>
  8360. <button aria-expanded="false" data-toggle="dropdown" class="btn btn-info dropdown-toggle waves-effect waves-light" type="button">
  8361. <i class="fa fa-filter m-r-5"></i><span class="caret"></span>
  8362. </button>
  8363. ` +
  8364. requestButton +
  8365. `
  8366. <div role="menu" class="dropdown-menu request-filter">
  8367. <div class="checkbox checkbox-success m-l-20 checkbox-circle">
  8368. <input id="request-filter-available-${service}" data-filter="request-available" class="filter-request-input" type="checkbox" checked="">
  8369. <label for="request-filter-available-${service}"> <span lang="en">Available</span> </label>
  8370. </div>
  8371. <div class="checkbox checkbox-danger m-l-20 checkbox-circle">
  8372. <input id="request-filter-unavailable-${service}" data-filter="request-unavailable" class="filter-request-input" type="checkbox" checked="">
  8373. <label for="request-filter-unavailable-${service}"> <span lang="en">Unavailable</span> </label>
  8374. </div>
  8375. <div class="checkbox checkbox-info m-l-20 checkbox-circle">
  8376. <input id="request-filter-approved-${service}" data-filter="request-approved" class="filter-request-input" type="checkbox" checked="">
  8377. <label for="request-filter-approved-${service}"> <span lang="en">Approved</span> </label>
  8378. </div>
  8379. <div class="checkbox checkbox-warning m-l-20 checkbox-circle">
  8380. <input id="request-filter-unapproved-${service}" data-filter="request-unapproved" class="filter-request-input" type="checkbox" checked="">
  8381. <label for="request-filter-unapproved-${service}"> <span lang="en">Unapproved</span> </label>
  8382. </div>
  8383. <div class="checkbox checkbox-purple m-l-20 checkbox-circle">
  8384. <input id="request-filter-denied-${service}" data-filter="request-denied" class="filter-request-input" type="checkbox" checked="">
  8385. <label for="request-filter-denied-${service}"> <span lang="en">Denied</span> </label>
  8386. </div>
  8387. <div class="checkbox checkbox-inverse m-l-20 checkbox-circle">
  8388. <input id="request-filter-movie-${service}" data-filter="request-movie" class="filter-request-input" type="checkbox" checked="">
  8389. <label for="request-filter-movie-${service}"> <span lang="en">Movie</span> </label>
  8390. </div>
  8391. <div class="checkbox checkbox-inverse m-l-20 checkbox-circle">
  8392. <input id="request-filter-tv-${service}" data-filter="request-tv" class="filter-request-input" type="checkbox" checked="">
  8393. <label for="request-filter-tv-${service}"> <span lang="en">TV</span> </label>
  8394. </div>
  8395. </div>
  8396. `;
  8397. }
  8398. if (activeInfo.settings.homepage.options.alternateHomepageHeaders) {
  8399. var headerAlt =
  8400. `
  8401. <div class="col-md-12">
  8402. <h4 class="pull-left homepage-element-title"><span class="mouse" onclick="homepageRequests('${service}')" lang="en">Requests</span> : </h4><h4 class="pull-left">&nbsp;</h4>
  8403. <div class="btn-group pull-right">
  8404. ` +
  8405. builtDropdown +
  8406. `
  8407. </div>
  8408. <hr class="hidden-xs"><div class="clearfix"></div>
  8409. </div>
  8410. <div class="clearfix"></div>
  8411. `;
  8412. } else {
  8413. var header =
  8414. `
  8415. <div class="panel-heading bg-info p-t-10 p-b-10">
  8416. <span class="pull-left m-t-5 mouse homepage-element-title" onclick="homepageRequests('${service}')"><img class="lazyload homepageImageTitle" data-src="plugins/images/tabs/` +
  8417. service +
  8418. `.png"> &nbsp; <span lang="en">Requests</span></span>
  8419. <div class="btn-group pull-right">
  8420. ` +
  8421. builtDropdown +
  8422. `
  8423. </div>
  8424. <div class="clearfix"></div>
  8425. </div>
  8426. `;
  8427. }
  8428. return requests
  8429. ? `
  8430. <div id="${service}-requests" class="row">
  8431. ` +
  8432. headerAlt +
  8433. `
  8434. <div class="col-lg-12">
  8435. <div class="panel panel-default">
  8436. ` +
  8437. header +
  8438. `
  8439. <div class="panel-wrapper p-b-0 collapse in">
  8440. <div class="owl-carousel owl-theme request-items-` +
  8441. service +
  8442. `">
  8443. ` +
  8444. buildRequestItem(array.content) +
  8445. `
  8446. </div>
  8447. ` +
  8448. buildRequestItem(array.content, true) +
  8449. `
  8450. </div>
  8451. </div>
  8452. </div>
  8453. </div>
  8454. <div id="new-request" class="white-popup mfp-with-anim mfp-hide">
  8455. <div class="col-md-8 col-md-offset-2">
  8456. <div class="white-box m-b-0 search-div resultBox-outside">
  8457. <div class="form-group m-b-0">
  8458. <div id="request-input-div" class="input-group">
  8459. <input id="request-input" lang="en" placeholder="Request a Show or Movie" type="text" class="form-control inline-focus">
  8460. <input id="request-page" type="hidden" class="form-control">
  8461. <div class="input-group-btn">
  8462. <button type="button" class="btn waves-effect waves-light btn-info dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><span lang="en">Suggestions</span> <span class="caret"></span></button>
  8463. <ul class="dropdown-menu dropdown-menu-right">
  8464. <li><a onclick="requestList('org-mod', 'movie');" href="javascript:void(0)" lang="en">Organizr Mod Picks</a></li>
  8465. <li><a onclick="requestList('theatre-movie', 'movie');" href="javascript:void(0)" lang="en">In Theatres</a></li>
  8466. <li><a onclick="requestList('top-movie', 'movie');" href="javascript:void(0)" lang="en">Top Movies</a></li>
  8467. <li><a onclick="requestList('pop-movie', 'movie');" href="javascript:void(0)" lang="en">Popular Movies</a></li>
  8468. <li><a onclick="requestList('up-movie', 'movie');" href="javascript:void(0)" lang="en">Upcoming Movies</a></li>
  8469. <li><a onclick="requestList('top-tv', 'tv');" href="javascript:void(0)" lang="en">Top TV</a></li>
  8470. <li><a onclick="requestList('pop-tv', 'tv');" href="javascript:void(0)" lang="en">Popular TV</a></li>
  8471. <li><a onclick="requestList('today-tv', 'tv');" href="javascript:void(0)" lang="en">Airs Today TV</a></li>
  8472. </ul>
  8473. </div>
  8474. </div>
  8475. <div class="clearfix"></div>
  8476. </div>
  8477. <div id="request-results" class="row el-element-overlay resultBox-inside"></div>
  8478. </div>
  8479. </div>
  8480. </div>
  8481. `
  8482. : "";
  8483. }
  8484. function pagination(c, m) {
  8485. var current = c,
  8486. last = m,
  8487. delta = 2,
  8488. left = current - delta,
  8489. right = current + delta + 1,
  8490. range = [],
  8491. rangeWithDots = [],
  8492. l;
  8493. for (let i = 1; i <= last; i++) {
  8494. if (i == 1 || i == last || (i >= left && i < right)) {
  8495. range.push(i);
  8496. }
  8497. }
  8498. for (let i of range) {
  8499. if (l) {
  8500. if (i - l === 2) {
  8501. rangeWithDots.push(l + 1);
  8502. } else if (i - l !== 1) {
  8503. rangeWithDots.push("...");
  8504. }
  8505. }
  8506. rangeWithDots.push(i);
  8507. l = i;
  8508. }
  8509. return rangeWithDots;
  8510. }
  8511. function buildRequestResult(
  8512. array,
  8513. media_type = null,
  8514. list = null,
  8515. page = null,
  8516. search = false
  8517. ) {
  8518. var comments = typeof array.comments !== "undefined" ? true : false;
  8519. var comment = "";
  8520. var results = ``;
  8521. var buttons = ``;
  8522. var next = ``;
  8523. var tv = 0;
  8524. var movie = 0;
  8525. var total = 0;
  8526. var totalPages = array.total_pages;
  8527. var currentPage = page * 1;
  8528. var pagePrevious = page * 1 - 1;
  8529. var pageNext = page * 1 + 1;
  8530. var pageFirst = 1;
  8531. var pageLast = totalPages;
  8532. var previousHidden = currentPage == 1 ? "disabled" : "";
  8533. var nextHidden = currentPage == totalPages ? "disabled" : "";
  8534. var pageList = "";
  8535. let previousEnabled = pagePrevious !== 0;
  8536. let nextEnabled = pageNext <= totalPages;
  8537. if (array.results.length == 0) {
  8538. return '<h2 class="text-center" lang="en">No Results</h2>';
  8539. }
  8540. $.each(array.results, function (i, v) {
  8541. media_type = v.media_type ? v.media_type : media_type;
  8542. if (media_type == "tv" || media_type == "movie") {
  8543. total = total + 1;
  8544. tv = media_type == "tv" ? tv + 1 : tv;
  8545. movie = media_type == "movie" ? movie + 1 : movie;
  8546. var bg =
  8547. v.poster_path !== null
  8548. ? `https://image.tmdb.org/t/p/w300/` + v.poster_path
  8549. : "plugins/images/homepage/no-list.png";
  8550. var top = v.title
  8551. ? v.title
  8552. : v.original_title
  8553. ? v.original_title
  8554. : v.original_name
  8555. ? v.original_name
  8556. : "";
  8557. var bottom = v.release_date
  8558. ? v.release_date
  8559. : v.first_air_date
  8560. ? v.first_air_date
  8561. : "";
  8562. if (comments) {
  8563. if (array.comments[media_type + ":" + v.id] !== null) {
  8564. comment = array.comments[media_type + ":" + v.id];
  8565. }
  8566. }
  8567. results +=
  8568. `
  8569. <div class="col-lg-3 col-md-4 col-sm-6 col-xs-12 m-t-20 request-result-item request-result-` +
  8570. media_type +
  8571. `">
  8572. <div class="white-box m-b-10">
  8573. <div class="el-card-item p-b-0">
  8574. <div class="el-card-avatar el-overlay-1 m-b-5 preloader-` +
  8575. v.id +
  8576. `"> <img class="lazyload resultImages" data-src="` +
  8577. bg +
  8578. `">
  8579. <div class="el-overlay">
  8580. <span class="text-info p-a-5 font-normal">` +
  8581. comment +
  8582. `</span>
  8583. <ul class="el-info">
  8584. <li><a class="btn default btn-outline" href="javascript:void(0);" onclick="processRequest('` +
  8585. v.id +
  8586. `','` +
  8587. media_type +
  8588. `');"><i class="icon-link"></i>&nbsp; <span lang="en">Request</span></a></li>
  8589. <li><a class="btn default btn-outline" href="https://www.themoviedb.org/` +
  8590. media_type +
  8591. `/` +
  8592. v.id +
  8593. `" target="_blank"><i class="icon-info"></i></a></li>
  8594. </ul>
  8595. </div>
  8596. </div>
  8597. <div class="el-card-content bg-org">
  8598. <h3 class="box-title elip">` +
  8599. top +
  8600. `</h3> <small>` +
  8601. bottom +
  8602. `</small>
  8603. <br>
  8604. </div>
  8605. </div>
  8606. </div>
  8607. </div>
  8608. `;
  8609. }
  8610. comment = "";
  8611. });
  8612. if (list && page && search == false) {
  8613. $.each(pagination(currentPage, totalPages), function (key, value) {
  8614. var activePage = currentPage == value ? "active" : "";
  8615. var disabled = value == "..." ? "disabled" : "";
  8616. var pageLink =
  8617. value == "..."
  8618. ? ""
  8619. : `onclick="requestList('` +
  8620. list +
  8621. `', '` +
  8622. media_type +
  8623. `', '` +
  8624. value +
  8625. `');"`;
  8626. pageList +=
  8627. '<li class="' +
  8628. activePage +
  8629. disabled +
  8630. '"> <a ' +
  8631. pageLink +
  8632. ' href="javascript:void(0)">' +
  8633. value +
  8634. "</a> </li>";
  8635. });
  8636. let previousOnclick = previousEnabled
  8637. ? `onclick="requestList('${list}', '${media_type}', '${pagePrevious}')";`
  8638. : ``;
  8639. let nextOnclick = nextEnabled
  8640. ? `onclick="requestList('${list}', '${media_type}', '${pageNext}')";`
  8641. : ``;
  8642. next =
  8643. `
  8644. <div class="clearfix"></div>
  8645. <div class="button-box text-center p-b-0">
  8646. <ul class="pagination m-b-0">
  8647. <li class="` +
  8648. previousHidden +
  8649. `"> <a href="javascript:void(0)" ${previousOnclick}><i class="fa fa-angle-left"></i></a> </li>
  8650. ` +
  8651. pageList +
  8652. `
  8653. <li class="` +
  8654. nextHidden +
  8655. `"> <a href="javascript:void(0)" ${nextOnclick}><i class="fa fa-angle-right"></i></a> </li>
  8656. </ul>
  8657. </div>
  8658. `;
  8659. }
  8660. if (list && page && search == true) {
  8661. $.each(pagination(currentPage, totalPages), function (key, value) {
  8662. var activePage = currentPage == value ? "active" : "";
  8663. var disabled = value == "..." ? "disabled" : "";
  8664. var pageLink =
  8665. value == "..."
  8666. ? ""
  8667. : `onclick="$('#request-page').val(` + value + `);doneTyping();"`;
  8668. pageList +=
  8669. '<li class="' +
  8670. activePage +
  8671. disabled +
  8672. '"> <a ' +
  8673. pageLink +
  8674. ' href="javascript:void(0)">' +
  8675. value +
  8676. "</a> </li>";
  8677. });
  8678. next =
  8679. `
  8680. <div class="clearfix"></div>
  8681. <div class="button-box text-center p-b-0">
  8682. <ul class="pagination m-b-0">
  8683. <li class="` +
  8684. previousHidden +
  8685. `"> <a href="javascript:void(0)" onclick="$('#request-page').val(` +
  8686. pagePrevious +
  8687. `);doneTyping();"><i class="fa fa-angle-left"></i></a> </li>
  8688. ` +
  8689. pageList +
  8690. `
  8691. <li class="` +
  8692. nextHidden +
  8693. `"> <a href="javascript:void(0)" onclick="$('#request-page').val(` +
  8694. pageNext +
  8695. `);doneTyping();"><i class="fa fa-angle-right"></i></a> </li>
  8696. </ul>
  8697. </div>
  8698. `;
  8699. }
  8700. var buttons =
  8701. `
  8702. <div class="button-box p-20 text-center p-b-0">
  8703. <button class="btn btn-inverse waves-effect waves-light filter-request-result" data-filter="request-result-all"><span>` +
  8704. total +
  8705. `</span> <i class="fa fa-th-large m-l-5 fa-fw"></i></button>
  8706. <button class="btn btn-primary waves-effect waves-light filter-request-result" data-filter="request-result-movie"><span>` +
  8707. movie +
  8708. `</span> <i class="fa fa-film m-l-5 fa-fw"></i></button>
  8709. <button class="btn btn-info waves-effect waves-light filter-request-result" data-filter="request-result-tv"><span>` +
  8710. tv +
  8711. `</span> <i class="fa fa-tv m-l-5 fa-fw"></i></button>
  8712. </div>
  8713. `;
  8714. return buttons + next + results + next;
  8715. }
  8716. function buildRequestOverseerrSeasons(array) {
  8717. var hasSeasons = typeof array.data.seasons !== "undefined";
  8718. if (hasSeasons) {
  8719. let seasons = array.data.seasons;
  8720. let id = array.data.id;
  8721. let SeasonItems = "";
  8722. $.each(seasons, function (i, v) {
  8723. if (v.seasonNumber !== 0) {
  8724. SeasonItems += `
  8725. <tr>
  8726. <td><input type="checkbox" name="overseerr-season-${v.seasonNumber}" class="js-switch overseerr-season" data-seasonNumber="${v.seasonNumber}" data-color="#6164c1" data-size="small" /></td>
  8727. <td>${v.name}</td>
  8728. <td>${v.episodeCount}</td>
  8729. </tr>
  8730. `;
  8731. }
  8732. });
  8733. let html = `
  8734. <div class="panel">
  8735. <div class="bg-org2">
  8736. <div class="panel-heading">Choose Seasons</div>
  8737. <div class="panel-wrapper collapse in text-left">
  8738. <div class="table-responsive">
  8739. <table class="table color-bordered-table primary-bordered-table">
  8740. <thead>
  8741. <tr>
  8742. <th width="20"><input type="checkbox" class="js-switch select-all-overseerr-seasons" data-color="#6164c1" data-size="small" /></th>
  8743. <th lang="en">Season</th>
  8744. <th lang="en"># Of Episodes</th>
  8745. </tr>
  8746. </thead>
  8747. <tbody>${SeasonItems}</tbody>
  8748. </table>
  8749. </div>
  8750. <div class="pull-right p-b-20">
  8751. <button class="fcbtn btn btn-info btn-outline btn-1c" lang="en" onclick="swal.close();">Cancel</button>
  8752. <button class="fcbtn btn btn-success btn-outline btn-1c submit-overseerr-seasons" lang="en" data-seasons="[]" data-id="${id}" disabled onclick="processOverseerrSeasons(this)">Request Seasons</button>
  8753. </div>
  8754. </div>
  8755. </div>
  8756. </div>
  8757. `;
  8758. swal({
  8759. content: createElementFromHTML(html),
  8760. button: null,
  8761. className: "bg-org",
  8762. dangerMode: false,
  8763. });
  8764. }
  8765. }
  8766. function processOverseerrSeasons(el) {
  8767. let seasons = $(el).attr("data-seasons");
  8768. let id = $(el).attr("data-id");
  8769. overseerrActions(id, "add", "tv", seasons);
  8770. }
  8771. function processRequest(id, type) {
  8772. let service = activeInfo.settings.homepage.requests.service;
  8773. switch (service) {
  8774. case "ombi":
  8775. requestActions(id, "add", type);
  8776. return false;
  8777. case "overseerr":
  8778. if (
  8779. type === "tv" &&
  8780. activeInfo.settings.homepage.overseerr.userSelectTv === true
  8781. ) {
  8782. organizrAPI2(
  8783. "GET",
  8784. "api/v2/homepage/overseerr/metadata/" + type + "/" + id
  8785. )
  8786. .success(function (data) {
  8787. try {
  8788. let response = data.response;
  8789. buildRequestOverseerrSeasons(response);
  8790. } catch (e) {
  8791. organizrCatchError(e, data);
  8792. }
  8793. })
  8794. .fail(function (xhr) {
  8795. OrganizrApiError(xhr, "Overseerr Error");
  8796. });
  8797. } else {
  8798. requestActions(id, "add", type);
  8799. }
  8800. return false;
  8801. default:
  8802. organizrConsole(
  8803. "Request Function",
  8804. "Service for Processing not setup",
  8805. "error"
  8806. );
  8807. return false;
  8808. }
  8809. }
  8810. function requestActions(id = null, action = null, type = null, extra = null) {
  8811. let service = activeInfo.settings.homepage.requests.service;
  8812. switch (service) {
  8813. case "ombi":
  8814. ombiActions(id, action, type, extra);
  8815. break;
  8816. case "overseerr":
  8817. overseerrActions(id, action, type, extra);
  8818. break;
  8819. default:
  8820. organizrConsole(
  8821. "Request Function",
  8822. "Service for Request not setup",
  8823. "error"
  8824. );
  8825. return false;
  8826. }
  8827. }
  8828. //Overseerr Actions
  8829. function overseerrActions(id, action, type = null, extra = null) {
  8830. ajaxloader(".request-" + id + "-div", "in");
  8831. ajaxloader(".preloader-" + id, "in");
  8832. //$.magnificPopup.close();
  8833. messageSingle(
  8834. window.lang.translate("Submitting Action to Overseerr"),
  8835. "",
  8836. activeInfo.settings.notifications.position,
  8837. "#FFF",
  8838. "success",
  8839. "10000"
  8840. );
  8841. switch (action) {
  8842. case "add":
  8843. let seasons = extra !== null ? "/" + extra : "";
  8844. var method = "POST";
  8845. var apiUrl =
  8846. "api/v2/homepage/overseerr/requests/" + type + "/" + id + seasons;
  8847. var data = {};
  8848. break;
  8849. case "available":
  8850. case "pending":
  8851. case "unavailable":
  8852. case "approve":
  8853. var method = "POST";
  8854. var apiUrl =
  8855. "api/v2/homepage/overseerr/requests/" + type + "/" + id + "/" + action;
  8856. var data = {};
  8857. break;
  8858. case "deny":
  8859. var method = "PUT";
  8860. var apiUrl =
  8861. "api/v2/homepage/overseerr/requests/" + type + "/" + id + "/" + action;
  8862. var data = {};
  8863. break;
  8864. case "delete":
  8865. var method = "DELETE";
  8866. var apiUrl = "api/v2/homepage/overseerr/requests/" + type + "/" + id;
  8867. var data = {};
  8868. break;
  8869. default:
  8870. return false;
  8871. }
  8872. organizrAPI2(method, apiUrl, data)
  8873. .success(function (data) {
  8874. try {
  8875. let response = data.response;
  8876. if (action == "add") {
  8877. addTempRequest();
  8878. setTimeout(function () {
  8879. ajaxloader();
  8880. }, 2000);
  8881. }
  8882. messageSingle(
  8883. response.message,
  8884. "",
  8885. activeInfo.settings.notifications.position,
  8886. "#FFF",
  8887. "success",
  8888. "5000"
  8889. );
  8890. homepageRequests("overseerr");
  8891. cleanCloseSwal();
  8892. } catch (e) {
  8893. organizrCatchError(e, data);
  8894. }
  8895. })
  8896. .fail(function (xhr) {
  8897. ajaxloader();
  8898. OrganizrApiError(xhr, "Overseerr Error");
  8899. });
  8900. }
  8901. //Ombi actions
  8902. function ombiActions(id, action, type, extra = null) {
  8903. var msg =
  8904. activeInfo.user.groupID <= 1
  8905. ? '<a href="https://github.com/tidusjar/Ombi/issues/2176" target="_blank">Not Org Fault - Ask Ombi</a>'
  8906. : "Connection Error to Request Server";
  8907. ajaxloader(".request-" + id + "-div", "in");
  8908. ajaxloader(".preloader-" + id, "in");
  8909. //$.magnificPopup.close();
  8910. messageSingle(
  8911. window.lang.translate("Submitting Action to Ombi"),
  8912. "",
  8913. activeInfo.settings.notifications.position,
  8914. "#FFF",
  8915. "success",
  8916. "10000"
  8917. );
  8918. switch (action) {
  8919. case "add":
  8920. var method = "POST";
  8921. var apiUrl = "api/v2/homepage/ombi/requests/" + type + "/" + id;
  8922. var data = {};
  8923. break;
  8924. case "available":
  8925. case "unavailable":
  8926. case "approve":
  8927. var method = "POST";
  8928. var apiUrl =
  8929. "api/v2/homepage/ombi/requests/" + type + "/" + id + "/" + action;
  8930. var data = {};
  8931. break;
  8932. case "deny":
  8933. var method = "PUT";
  8934. var apiUrl =
  8935. "api/v2/homepage/ombi/requests/" + type + "/" + id + "/" + action;
  8936. var data = {};
  8937. break;
  8938. case "delete":
  8939. var method = "DELETE";
  8940. var apiUrl = "api/v2/homepage/ombi/requests/" + type + "/" + id;
  8941. var data = {};
  8942. break;
  8943. default:
  8944. return false;
  8945. }
  8946. organizrAPI2(method, apiUrl, data)
  8947. .success(function (data) {
  8948. try {
  8949. let response = data.response;
  8950. if (action == "add") {
  8951. addTempRequest();
  8952. }
  8953. messageSingle(
  8954. response.message,
  8955. "",
  8956. activeInfo.settings.notifications.position,
  8957. "#FFF",
  8958. "success",
  8959. "5000"
  8960. );
  8961. homepageRequests("ombi");
  8962. ajaxloader();
  8963. } catch (e) {
  8964. organizrCatchError(e, data);
  8965. }
  8966. })
  8967. .fail(function (xhr) {
  8968. ajaxloader();
  8969. OrganizrApiError(xhr, "Ombi Error");
  8970. });
  8971. }
  8972. function addTempRequest() {
  8973. let service = activeInfo.settings.homepage.requests.service;
  8974. let html = `
  8975. <div class="item lazyload recent-poster request-item request-adding mouse" data-src="">
  8976. <div class="outside-request-div">
  8977. <div class="inside-over-request-div bg-danger"></div>
  8978. <div class="inside-request-div bg-info"></div>
  8979. </div>
  8980. <div class="hover-homepage-item"></div>
  8981. <span class="elip request-title-tv"><i class="fa fa-tv"></i></span>
  8982. <span class="elip recent-title">Adding Request</span>
  8983. </div>
  8984. `;
  8985. $(".request-items-" + service)
  8986. .trigger("add.owl", [html, 0])
  8987. .trigger("refresh.owl");
  8988. setTimeout(function () {
  8989. ajaxloader(".request-adding", "in");
  8990. }, 100);
  8991. }
  8992. function cleanCloseSwal() {
  8993. let state = swal.getState().isOpen;
  8994. if (state === true) {
  8995. swal.close();
  8996. }
  8997. }
  8998. function doneTyping() {
  8999. let title = $("#request-input").val();
  9000. if (title == "") {
  9001. return false;
  9002. }
  9003. var page = $("#request-page").val() ? $("#request-page").val() : 1;
  9004. if (typeof searchTerm !== "undefined") {
  9005. if (searchTerm !== $("#request-input").val()) {
  9006. page = 1;
  9007. }
  9008. }
  9009. ajaxloader(".search-div", "in");
  9010. searchTerm = title;
  9011. $("#request-page").val(page);
  9012. requestSearch(title, page)
  9013. .success(function (data) {
  9014. $("#request-results").html(
  9015. buildRequestResult(data, "", title, page, true)
  9016. );
  9017. if (bowser.mobile !== true) {
  9018. $(".resultBox-inside").slimScroll({
  9019. height: "100%",
  9020. position: "right",
  9021. size: "5px",
  9022. color: "#dcdcdc",
  9023. });
  9024. }
  9025. $(".mfp-wrap").animate(
  9026. {
  9027. scrollTop: "0",
  9028. },
  9029. 500
  9030. );
  9031. ajaxloader();
  9032. })
  9033. .fail(function (xhr) {
  9034. OrganizrApiError(xhr, "TMDB Error");
  9035. ajaxloader();
  9036. });
  9037. }
  9038. function requestList(list, type, page = 1) {
  9039. ajaxloader(".search-div", "in");
  9040. requestSearchList(list, page)
  9041. .success(function (data) {
  9042. if (typeof data.results !== "undefined") {
  9043. var results = data.results;
  9044. } else if (typeof data.items !== "undefined") {
  9045. var results = data.items;
  9046. }
  9047. $("#request-results").html(buildRequestResult(data, type, list, page));
  9048. if (bowser.mobile !== true) {
  9049. $(".resultBox-inside").slimScroll({
  9050. height: "100%",
  9051. position: "right",
  9052. size: "5px",
  9053. color: "#dcdcdc",
  9054. });
  9055. }
  9056. $(".mfp-wrap").animate(
  9057. {
  9058. scrollTop: "0",
  9059. },
  9060. 500
  9061. );
  9062. ajaxloader();
  9063. })
  9064. .fail(function (xhr) {
  9065. OrganizrApiError(xhr, "TMDB Error");
  9066. ajaxloader();
  9067. });
  9068. }
  9069. function buildDownloaderItem(array, source, type = "none") {
  9070. var queue = "";
  9071. var count = 0;
  9072. var history = "";
  9073. switch (source) {
  9074. case "jdownloader":
  9075. if (array.content === false) {
  9076. queue =
  9077. '<tr><td class="max-texts" lang="en">Connection Error to ' +
  9078. source +
  9079. "</td></tr>";
  9080. break;
  9081. }
  9082. if (
  9083. array.content.queueItems.length == 0 &&
  9084. array.content.grabberItems.length == 0 &&
  9085. array.content.encryptedItems.length == 0 &&
  9086. array.content.offlineItems.length == 0
  9087. ) {
  9088. queue =
  9089. '<tr><td class="max-texts" lang="en">Nothing in queue</td></tr>';
  9090. } else {
  9091. if (array.content.$status[0] == "RUNNING") {
  9092. queue += `
  9093. <tr><td>
  9094. <a href="#" onclick="return false;"><span class="downloader mouse" data-source="jdownloader" data-action="pause" data-target="main"><i class="fa fa-pause"></i></span></a>
  9095. <a href="#" onclick="return false;"><span class="downloader mouse" data-source="jdownloader" data-action="stop" data-target="main"><i class="fa fa-stop"></i></span></a>
  9096. </td></tr>
  9097. `;
  9098. } else if (array.content.$status[0] == "PAUSE") {
  9099. queue += `<tr><td><a href="#" onclick="return false;"><span class="downloader mouse" data-source="jdownloader" data-action="resume" data-target="main"><i class="fa fa-fast-forward"></i></span></a></td></tr>`;
  9100. } else {
  9101. queue += `<tr><td><a href="#" onclick="return false;"><span class="downloader mouse" data-source="jdownloader" data-action="start" data-target="main"><i class="fa fa-play"></i></span></a></td></tr>`;
  9102. }
  9103. if (array.content.$status[1]) {
  9104. queue += `<tr><td><a href="#" onclick="return false;"><span class="downloader mouse" data-source="jdownloader" data-action="update" data-target="main"><i class="fa fa-globe"></i></span></a></td></tr>`;
  9105. }
  9106. }
  9107. $.each(array.content.queueItems, function (i, v) {
  9108. count = count + 1;
  9109. if (v.speed == null) {
  9110. v.speed = "Stopped";
  9111. }
  9112. if (v.eta == null) {
  9113. if (v.percentage == "100") {
  9114. v.speed = "Completed";
  9115. v.eta = "--";
  9116. } else {
  9117. v.eta = "--";
  9118. }
  9119. }
  9120. if (v.enabled == null) {
  9121. v.speed = "Disabled";
  9122. }
  9123. queue +=
  9124. `
  9125. <tr>
  9126. <td class="max-texts">` +
  9127. v.name +
  9128. `</td>
  9129. <td>` +
  9130. v.speed +
  9131. `</td>
  9132. <td class="hidden-xs" alt="` +
  9133. v.done +
  9134. `">` +
  9135. v.size +
  9136. `</td>
  9137. <td class="hidden-xs">` +
  9138. v.eta +
  9139. `</td>
  9140. <td class="text-right">
  9141. <div class="progress progress-lg m-b-0">
  9142. <div class="progress-bar progress-bar-info" style="width: ` +
  9143. v.percentage +
  9144. `%;" role="progressbar">` +
  9145. v.percentage +
  9146. `%</div>
  9147. </div>
  9148. </td>
  9149. </tr>
  9150. `;
  9151. });
  9152. $.each(array.content.grabberItems, function (i, v) {
  9153. count = count + 1;
  9154. queue +=
  9155. `
  9156. <tr>
  9157. <td class="max-texts">` +
  9158. v.name +
  9159. `</td>
  9160. <td>Online</td>
  9161. <td class="hidden-xs"> -- </td>
  9162. <td class="hidden-xs"> -- </td>
  9163. <td class="text-right">
  9164. <div class="progress progress-lg m-b-0">
  9165. <div class="progress-bar progress-bar-info" style="width: 0%;" role="progressbar">0%</div>
  9166. </div>
  9167. </td>
  9168. </tr>
  9169. `;
  9170. });
  9171. $.each(array.content.encryptedItems, function (i, v) {
  9172. count = count + 1;
  9173. queue +=
  9174. `
  9175. <tr>
  9176. <td class="max-texts">` +
  9177. v.name +
  9178. `</td>
  9179. <td>Encrypted</td>
  9180. <td class="hidden-xs"> -- </td>
  9181. <td class="hidden-xs"> -- </td>
  9182. <td class="text-right">
  9183. <div class="progress progress-lg m-b-0">
  9184. <div class="progress-bar progress-bar-info" style="width: 0%;" role="progressbar">0%</div>
  9185. </div>
  9186. </td>
  9187. </tr>
  9188. `;
  9189. });
  9190. $.each(array.content.offlineItems, function (i, v) {
  9191. count = count + 1;
  9192. queue +=
  9193. `
  9194. <tr>
  9195. <td class="max-texts">` +
  9196. v.name +
  9197. `</td>
  9198. <td>Offline</td>
  9199. <td class="hidden-xs"> -- </td>
  9200. <td class="hidden-xs"> -- </td>
  9201. <td class="text-right">
  9202. <div class="progress progress-lg m-b-0">
  9203. <div class="progress-bar progress-bar-info" style="width: 0%;" role="progressbar">0%</div>
  9204. </div>
  9205. </td>
  9206. </tr>
  9207. `;
  9208. });
  9209. break;
  9210. case "sabnzbd":
  9211. if (array.content === false) {
  9212. queue =
  9213. '<tr><td class="max-texts" lang="en">Connection Error to ' +
  9214. source +
  9215. "</td></tr>";
  9216. break;
  9217. }
  9218. if (array.content.queueItems.queue.paused) {
  9219. var state = `<a href="#" onclick="return false;"><span class="downloader mouse" data-source="sabnzbd" data-action="resume" data-target="main"><i class="fa fa-play"></i></span></a>`;
  9220. var active = "grayscale";
  9221. } else {
  9222. var state = `<a href="#" onclick="return false;"><span class="downloader mouse" data-source="sabnzbd" data-action="pause" data-target="main"><i class="fa fa-pause"></i></span></a>`;
  9223. var active = "";
  9224. }
  9225. $(".sabnzbd-downloader-action").html(state);
  9226. if (array.content.queueItems.queue.slots.length == 0) {
  9227. queue =
  9228. '<tr><td class="max-texts" lang="en">Nothing in queue</td></tr>';
  9229. }
  9230. $.each(array.content.queueItems.queue.slots, function (i, v) {
  9231. count = count + 1;
  9232. var action = v.status == "Downloading" ? "pause" : "resume";
  9233. var actionIcon = v.status == "Downloading" ? "pause" : "play";
  9234. queue +=
  9235. `
  9236. <tr>
  9237. <td class="max-texts">` +
  9238. v.filename +
  9239. `</td>
  9240. <td class="hidden-xs sabnzbd-` +
  9241. cleanClass(v.status) +
  9242. `">` +
  9243. v.status +
  9244. `</td>
  9245. <td class="downloader mouse" data-target="` +
  9246. v.nzo_id +
  9247. `" data-source="sabnzbd" data-action="` +
  9248. action +
  9249. `"><i class="fa fa-` +
  9250. actionIcon +
  9251. `"></i></td>
  9252. <td class="hidden-xs"><span class="label label-info">` +
  9253. v.cat +
  9254. `</span></td>
  9255. <td class="hidden-xs">` +
  9256. v.size +
  9257. `</td>
  9258. <td class="hidden-xs" alt="` +
  9259. v.eta +
  9260. `">` +
  9261. v.timeleft +
  9262. `</td>
  9263. <td class="text-right">
  9264. <div class="progress progress-lg m-b-0">
  9265. <div class="progress-bar progress-bar-info" style="width: ` +
  9266. v.percentage +
  9267. `%;" role="progressbar">` +
  9268. v.percentage +
  9269. `%</div>
  9270. </div>
  9271. </td>
  9272. </tr>
  9273. `;
  9274. });
  9275. if (array.content.historyItems.history.slots.length == 0) {
  9276. history =
  9277. '<tr><td class="max-texts" lang="en">Nothing in history</td></tr>';
  9278. }
  9279. $.each(array.content.historyItems.history.slots, function (i, v) {
  9280. history +=
  9281. `
  9282. <tr>
  9283. <td class="max-texts">` +
  9284. v.name +
  9285. `</td>
  9286. <td class="hidden-xs sabnzbd-` +
  9287. cleanClass(v.status) +
  9288. `">` +
  9289. v.status +
  9290. `</td>
  9291. <td class="hidden-xs"><span class="label label-info">` +
  9292. v.category +
  9293. `</span></td>
  9294. <td class="hidden-xs">` +
  9295. v.size +
  9296. `</td>
  9297. <td class="text-right">
  9298. <div class="progress progress-lg m-b-0">
  9299. <div class="progress-bar progress-bar-info" style="width: 100%;" role="progressbar">100%</div>
  9300. </div>
  9301. </td>
  9302. </tr>
  9303. `;
  9304. });
  9305. break;
  9306. case "nzbget":
  9307. if (array.content === false) {
  9308. queue =
  9309. '<tr><td class="max-texts" lang="en">Connection Error to ' +
  9310. source +
  9311. "</td></tr>";
  9312. break;
  9313. }
  9314. if (array.content.queueItems.result.length == 0) {
  9315. queue =
  9316. '<tr><td class="max-texts" lang="en">Nothing in queue</td></tr>';
  9317. }
  9318. $.each(array.content.queueItems.result, function (i, v) {
  9319. count = count + 1;
  9320. var action = v.Status == "Downloading" ? "pause" : "resume";
  9321. var actionIcon = v.Status == "Downloading" ? "pause" : "play";
  9322. var percent = Math.floor(
  9323. ((v.FileSizeMB - v.RemainingSizeMB) * 100) / v.FileSizeMB
  9324. );
  9325. var size = v.FileSizeMB * 1000000;
  9326. v.Category = v.Category !== "" ? v.Category : "Not Set";
  9327. queue +=
  9328. `
  9329. <tr>
  9330. <td class="max-texts">` +
  9331. v.NZBName +
  9332. `</td>
  9333. <td class="hidden-xs nzbget-` +
  9334. cleanClass(v.Status) +
  9335. `">` +
  9336. v.Status +
  9337. `</td>
  9338. <!--<td class="downloader mouse" data-target="` +
  9339. v.NZBID +
  9340. `" data-source="sabnzbd" data-action="` +
  9341. action +
  9342. `"><i class="fa fa-` +
  9343. actionIcon +
  9344. `"></i></td>-->
  9345. <td class="hidden-xs"><span class="label label-info">` +
  9346. v.Category +
  9347. `</span></td>
  9348. <td class="hidden-xs">` +
  9349. humanFileSize(size, true) +
  9350. `</td>
  9351. <td class="text-right">
  9352. <div class="progress progress-lg m-b-0">
  9353. <div class="progress-bar progress-bar-info" style="width: ` +
  9354. percent +
  9355. `%;" role="progressbar">` +
  9356. percent +
  9357. `%</div>
  9358. </div>
  9359. </td>
  9360. </tr>
  9361. `;
  9362. });
  9363. if (array.content.historyItems.result.length == 0) {
  9364. history =
  9365. '<tr><td class="max-texts" lang="en">Nothing in history</td></tr>';
  9366. }
  9367. $.each(array.content.historyItems.result, function (i, v) {
  9368. v.Category = v.Category !== "" ? v.Category : "Not Set";
  9369. var size = v.FileSizeMB * 1000000;
  9370. history +=
  9371. `
  9372. <tr>
  9373. <td class="max-texts">` +
  9374. v.NZBName +
  9375. `</td>
  9376. <td class="hidden-xs nzbget-` +
  9377. cleanClass(v.Status) +
  9378. `">` +
  9379. v.Status +
  9380. `</td>
  9381. <td class="hidden-xs"><span class="label label-info">` +
  9382. v.Category +
  9383. `</span></td>
  9384. <td class="hidden-xs">` +
  9385. humanFileSize(size, true) +
  9386. `</td>
  9387. <td class="text-right">
  9388. <div class="progress progress-lg m-b-0">
  9389. <div class="progress-bar progress-bar-info" style="width: 100%;" role="progressbar">100%</div>
  9390. </div>
  9391. </td>
  9392. </tr>
  9393. `;
  9394. });
  9395. break;
  9396. case "transmission":
  9397. if (array.content === false) {
  9398. queue =
  9399. '<tr><td class="max-texts" lang="en">Connection Error to ' +
  9400. source +
  9401. "</td></tr>";
  9402. break;
  9403. }
  9404. if (array.content.queueItems == 0) {
  9405. queue =
  9406. '<tr><td class="max-texts" lang="en">Nothing in queue</td></tr>';
  9407. }
  9408. $.each(array.content.queueItems, function (i, v) {
  9409. count = count + 1;
  9410. switch (v.status) {
  9411. case 7:
  9412. case "7":
  9413. var status = "No Peers";
  9414. break;
  9415. case 6:
  9416. case "6":
  9417. var status = "Seeding";
  9418. break;
  9419. case 5:
  9420. case "5":
  9421. var status = "Seeding Queued";
  9422. break;
  9423. case 4:
  9424. case "4":
  9425. var status = "Downloading";
  9426. break;
  9427. case 3:
  9428. case "3":
  9429. var status = "Queued";
  9430. break;
  9431. case 2:
  9432. case "2":
  9433. var status = "Checking Files";
  9434. break;
  9435. case 1:
  9436. case "1":
  9437. var status = "File Check Queued";
  9438. break;
  9439. case 0:
  9440. case "0":
  9441. var status = "Complete";
  9442. break;
  9443. default:
  9444. var status = "Complete";
  9445. }
  9446. var percent = Math.floor(v.percentDone * 100);
  9447. v.Category = v.Category !== "" ? v.Category : "Not Set";
  9448. queue +=
  9449. `
  9450. <tr>
  9451. <td class="max-texts">` +
  9452. v.name +
  9453. `</td>
  9454. <td class="hidden-xs transmission-` +
  9455. cleanClass(status) +
  9456. `">` +
  9457. status +
  9458. `</td>
  9459. <td class="hidden-xs">` +
  9460. v.downloadDir +
  9461. `</td>
  9462. <td class="hidden-xs">` +
  9463. humanFileSize(v.totalSize, true) +
  9464. `</td>
  9465. <td class="text-right">
  9466. <div class="progress progress-lg m-b-0">
  9467. <div class="progress-bar progress-bar-info" style="width: ` +
  9468. percent +
  9469. `%;" role="progressbar">` +
  9470. percent +
  9471. `%</div>
  9472. </div>
  9473. </td>
  9474. </tr>
  9475. `;
  9476. });
  9477. break;
  9478. case "rTorrent":
  9479. if (array.content === false) {
  9480. queue =
  9481. '<tr><td class="max-texts" lang="en">Connection Error to ' +
  9482. source +
  9483. "</td></tr>";
  9484. break;
  9485. }
  9486. if (array.content.queueItems == 0) {
  9487. queue =
  9488. '<tr><td class="max-texts" lang="en">Nothing in queue</td></tr>';
  9489. }
  9490. $.each(array.content.queueItems, function (i, v) {
  9491. count = count + 1;
  9492. var percent = Math.floor((v.downloaded / v.size) * 100);
  9493. var size = v.size != -1 ? humanFileSize(v.size, false) : "?";
  9494. var upload = v.seed !== "" ? humanFileSize(v.seed, true) : "0 B";
  9495. var download = v.leech !== "" ? humanFileSize(v.leech, true) : "0 B";
  9496. var upTotal =
  9497. v.upTotal !== "" ? humanFileSize(v.upTotal, false) : "0 B";
  9498. var downTotal =
  9499. v.downTotal !== "" ? humanFileSize(v.downTotal, false) : "0 B";
  9500. var date = new Date(0);
  9501. date.setUTCSeconds(v.date);
  9502. date = moment(date).format("LLL");
  9503. queue +=
  9504. `
  9505. <tr>
  9506. <td class="max-texts"><span class="tooltip-info" data-toggle="tooltip" data-placement="right" title="" data-original-title="` +
  9507. date +
  9508. `">` +
  9509. v.name +
  9510. `</span></td>
  9511. <td class="hidden-xs rtorrent-` +
  9512. cleanClass(v.status) +
  9513. `">` +
  9514. v.status +
  9515. `</td>
  9516. <td class="hidden-xs"><span class="tooltip-info" data-toggle="tooltip" data-placement="right" title="" data-original-title="` +
  9517. downTotal +
  9518. `"><i class="fa fa-download"></i>&nbsp;` +
  9519. download +
  9520. `</span></td>
  9521. <td class="hidden-xs"><span class="tooltip-info" data-toggle="tooltip" data-placement="right" title="" data-original-title="` +
  9522. upTotal +
  9523. `"><i class="fa fa-upload"></i>&nbsp;` +
  9524. upload +
  9525. `</span></td>
  9526. <td class="hidden-xs">` +
  9527. size +
  9528. `</td>
  9529. <td class="hidden-xs"><span class="label label-info">` +
  9530. v.label +
  9531. `</span></td>
  9532. <td class="text-right">
  9533. <div class="progress progress-lg m-b-0">
  9534. <div class="progress-bar progress-bar-info" style="width: ` +
  9535. percent +
  9536. `%;" role="progressbar">` +
  9537. percent +
  9538. `%</div>
  9539. </div>
  9540. </td>
  9541. </tr>
  9542. `;
  9543. });
  9544. break;
  9545. case "utorrent":
  9546. if (array.content === false) {
  9547. queue =
  9548. '<tr><td class="max-texts" lang="en">Connection Error to ' +
  9549. source +
  9550. "</td></tr>";
  9551. break;
  9552. }
  9553. if (array.content.queueItems == 0) {
  9554. queue =
  9555. '<tr><td class="max-texts" lang="en">Nothing in queue</td></tr>';
  9556. }
  9557. $.each(array.content.queueItems, function (i, v) {
  9558. count = count + 1;
  9559. var upload = v.upSpeed !== "" ? humanFileSize(v.upSpeed, false) : "0 B";
  9560. var download =
  9561. v.downSpeed !== "" ? humanFileSize(v.downSpeed, false) : "0 B";
  9562. var size = v.Size !== "" ? humanFileSize(v.Size, false) : "0 B";
  9563. queue +=
  9564. `
  9565. <tr>
  9566. <td class="max-texts"><span class="tooltip-info" data-toggle="tooltip" data-placement="right" title="">` +
  9567. v.Name +
  9568. `</span></td>
  9569. <td class="hidden-xs utorrent-` +
  9570. cleanClass(v.Status) +
  9571. `">` +
  9572. v.Status +
  9573. `</td>
  9574. <td class="hidden-xs"><span class="label label-info">` +
  9575. v.Labels +
  9576. `</span></td>
  9577. <td class="hidden-xs"><span class="tooltip-info" data-toggle="tooltip" data-placement="right" title="" data-original-title="` +
  9578. download +
  9579. `"><i class="fa fa-download"></i>&nbsp;` +
  9580. download +
  9581. `</span></td>
  9582. <td class="hidden-xs"><span class="tooltip-info" data-toggle="tooltip" data-placement="right" title="" data-original-title="` +
  9583. upload +
  9584. `"><i class="fa fa-upload"></i>&nbsp;` +
  9585. upload +
  9586. `</span></td>
  9587. <td class="hidden-xs">` +
  9588. size +
  9589. `</td>
  9590. <td class="text-right">
  9591. <div class="progress progress-lg m-b-0">
  9592. <div class="progress-bar progress-bar-info" style="width: ` +
  9593. v.Percent +
  9594. `;" role="progressbar">` +
  9595. v.Percent +
  9596. `</div>
  9597. </div>
  9598. </td>
  9599. </tr>
  9600. `;
  9601. });
  9602. break;
  9603. case "sonarr":
  9604. if (array.content === false) {
  9605. queue =
  9606. '<tr><td class="max-texts" lang="en">Connection Error to ' +
  9607. source +
  9608. "</td></tr>";
  9609. break;
  9610. }
  9611. if (array.content.queueItems == 0) {
  9612. queue =
  9613. '<tr><td class="max-texts" lang="en">Nothing in queue</td></tr>';
  9614. break;
  9615. }
  9616. if (array.content.queueItems.records == 0) {
  9617. queue =
  9618. '<tr><td class="max-texts" lang="en">Nothing in queue</td></tr>';
  9619. break;
  9620. }
  9621. let sonarrQueueSet =
  9622. typeof array.content.queueItems.records == "undefined"
  9623. ? array.content.queueItems
  9624. : array.content.queueItems.records;
  9625. $.each(sonarrQueueSet, function (i, v) {
  9626. count = count + 1;
  9627. var percent = Math.floor(((v.size - v.sizeleft) / v.size) * 100);
  9628. percent = isNaN(percent) ? "0" : percent;
  9629. var size = v.size != -1 ? humanFileSize(v.size, false) : "?";
  9630. v.name = typeof v.series == "undefined" ? v.title : v.series.title;
  9631. queue +=
  9632. `
  9633. <tr>
  9634. <td class="">` +
  9635. v.name +
  9636. `</td>
  9637. <td class="">S` +
  9638. pad(v.episode.seasonNumber, 2) +
  9639. `E` +
  9640. pad(v.episode.episodeNumber, 2) +
  9641. `</td>
  9642. <td class="max-texts">` +
  9643. v.episode.title +
  9644. `</td>
  9645. <td class="hidden-xs sonarr-` +
  9646. cleanClass(v.status) +
  9647. `">` +
  9648. v.status +
  9649. `</td>
  9650. <td class="hidden-xs">` +
  9651. size +
  9652. `</td>
  9653. <td class="hidden-xs"><span class="label label-info">` +
  9654. v.protocol +
  9655. `</span></td>
  9656. <td class="text-right">
  9657. <div class="progress progress-lg m-b-0">
  9658. <div class="progress-bar progress-bar-info" style="width: ` +
  9659. percent +
  9660. `%;" role="progressbar">` +
  9661. percent +
  9662. `%</div>
  9663. </div>
  9664. </td>
  9665. </tr>
  9666. `;
  9667. });
  9668. break;
  9669. case "radarr":
  9670. if (array.content === false) {
  9671. queue =
  9672. '<tr><td class="max-texts" lang="en">Connection Error to ' +
  9673. source +
  9674. "</td></tr>";
  9675. break;
  9676. }
  9677. if (array.content.queueItems == 0) {
  9678. queue =
  9679. '<tr><td class="max-texts" lang="en">Nothing in queue</td></tr>';
  9680. break;
  9681. }
  9682. if (array.content.queueItems.records == 0) {
  9683. queue =
  9684. '<tr><td class="max-texts" lang="en">Nothing in queue</td></tr>';
  9685. break;
  9686. }
  9687. let queueSet =
  9688. typeof array.content.queueItems.records == "undefined"
  9689. ? array.content.queueItems
  9690. : array.content.queueItems.records;
  9691. $.each(queueSet, function (i, v) {
  9692. count = count + 1;
  9693. var percent = Math.floor(((v.size - v.sizeleft) / v.size) * 100);
  9694. percent = isNaN(percent) ? "0" : percent;
  9695. var size = v.size != -1 ? humanFileSize(v.size, false) : "?";
  9696. v.name = typeof v.movie == "undefined" ? v.title : v.movie.title;
  9697. queue += `
  9698. <tr>
  9699. <td class="max-texts">${v.name}</td>
  9700. <td class="hidden-xs sonarr-${cleanClass(v.status)}">${
  9701. v.status
  9702. }</td>
  9703. <td class="hidden-xs">${size}</td>
  9704. <td class="hidden-xs"><span class="label label-info">${
  9705. v.protocol
  9706. }</span></td>
  9707. <td class="text-right">
  9708. <div class="progress progress-lg m-b-0">
  9709. <div class="progress-bar progress-bar-info" style="width: ${percent}%;" role="progressbar">${percent}%</div>
  9710. </div>
  9711. </td>
  9712. </tr>
  9713. `;
  9714. });
  9715. if (queue == "") {
  9716. queue =
  9717. '<tr><td class="max-texts" lang="en">Nothing in queue</td></tr>';
  9718. }
  9719. break;
  9720. case "qBittorrent":
  9721. if (array.content === false) {
  9722. queue =
  9723. '<tr><td class="max-texts" lang="en">Connection Error to ' +
  9724. source +
  9725. "</td></tr>";
  9726. break;
  9727. }
  9728. if (array.content.queueItems == 0) {
  9729. queue =
  9730. '<tr><td class="max-texts" lang="en">Nothing in queue</td></tr>';
  9731. }
  9732. $.each(array.content.queueItems, function (i, v) {
  9733. count = count + 1;
  9734. switch (v.state) {
  9735. case "stalledDL":
  9736. var status = "No Peers";
  9737. break;
  9738. case "metaDL":
  9739. var status = "Getting Metadata";
  9740. break;
  9741. case "uploading":
  9742. var status = "Seeding";
  9743. break;
  9744. case "queuedUP":
  9745. var status = "Seeding Queued";
  9746. break;
  9747. case "downloading":
  9748. var status = "Downloading";
  9749. break;
  9750. case "queuedDL":
  9751. var status = "Queued";
  9752. break;
  9753. case "checkingDL":
  9754. case "checkingUP":
  9755. var status = "Checking Files";
  9756. break;
  9757. case "pausedDL":
  9758. var status = "Paused";
  9759. break;
  9760. case "pausedUP":
  9761. var status = "Complete";
  9762. break;
  9763. default:
  9764. var status = "Complete";
  9765. }
  9766. var percent = Math.floor(v.progress * 100);
  9767. var size = v.total_size != -1 ? humanFileSize(v.total_size, true) : "?";
  9768. queue +=
  9769. `
  9770. <tr>
  9771. <td class="max-texts">` +
  9772. v.name +
  9773. `</td>
  9774. <td class="hidden-xs qbit-` +
  9775. cleanClass(status) +
  9776. `">` +
  9777. status +
  9778. `</td>
  9779. <td class="hidden-xs">` +
  9780. v.save_path +
  9781. `</td>
  9782. <td class="hidden-xs">` +
  9783. size +
  9784. `</td>
  9785. <td class="text-right">
  9786. <div class="progress progress-lg m-b-0">
  9787. <div class="progress-bar progress-bar-info" style="width: ` +
  9788. percent +
  9789. `%;" role="progressbar">` +
  9790. percent +
  9791. `%</div>
  9792. </div>
  9793. </td>
  9794. </tr>
  9795. `;
  9796. });
  9797. break;
  9798. case "deluge":
  9799. if (array.content === false) {
  9800. queue =
  9801. '<tr><td class="max-texts" lang="en">Connection Error to ' +
  9802. source +
  9803. "</td></tr>";
  9804. break;
  9805. }
  9806. if (array.content.queueItems.length == 0) {
  9807. queue =
  9808. '<tr><td class="max-texts" lang="en">Nothing in queue</td></tr>';
  9809. }
  9810. $.each(array.content.queueItems, function (i, v) {
  9811. count = count + 1;
  9812. var percent = Math.floor(v.progress);
  9813. var size = v.total_size != -1 ? humanFileSize(v.total_size, true) : "?";
  9814. var upload =
  9815. v.upload_payload_rate != -1
  9816. ? humanFileSize(v.upload_payload_rate, true)
  9817. : "?";
  9818. var download =
  9819. v.download_payload_rate != -1
  9820. ? humanFileSize(v.download_payload_rate, true)
  9821. : "?";
  9822. var action = v.Status == "Downloading" ? "pause" : "resume";
  9823. var actionIcon = v.Status == "Downloading" ? "pause" : "play";
  9824. queue +=
  9825. `
  9826. <tr>
  9827. <td class="max-texts">` + v.name;
  9828. if (v.tracker_status != "")
  9829. queue +=
  9830. `<i class="fa fa-caret-down ml-2" style="cursor:pointer" onclick="$(this).toggleClass('fa-caret-down');$(this).toggleClass('fa-caret-up');$('#status-` +
  9831. v.hash +
  9832. `').toggleClass('d-none');" aria-hidden="true"></i><br /><div class="well mb-0 mt-2 p-3 d-none" id="status-` +
  9833. v.hash +
  9834. `">` +
  9835. v.tracker_status +
  9836. `</div>`;
  9837. queue +=
  9838. `</td>
  9839. <td class="hidden-xs deluge-` +
  9840. cleanClass(v.state) +
  9841. `">` +
  9842. v.state +
  9843. `</td>
  9844. <td class="hidden-xs">` +
  9845. size +
  9846. `</td>
  9847. <td class="hidden-xs"><i class="fa fa-download"></i>&nbsp;` +
  9848. download +
  9849. `</td>
  9850. <td class="hidden-xs"><i class="fa fa-upload"></i>&nbsp;` +
  9851. upload +
  9852. `</td>
  9853. <td class="text-right">
  9854. <div class="progress progress-lg m-b-0">
  9855. <div class="progress-bar progress-bar-info" style="width: ` +
  9856. percent +
  9857. `%;" role="progressbar">` +
  9858. percent +
  9859. `%</div>
  9860. </div>
  9861. </td>
  9862. </tr>
  9863. `;
  9864. });
  9865. break;
  9866. default:
  9867. return false;
  9868. }
  9869. if (queue !== "") {
  9870. $("." + source + "-queue").html(queue);
  9871. }
  9872. if (history !== "") {
  9873. $("." + source + "-history").html(history);
  9874. }
  9875. $("#count-" + source).html(count);
  9876. }
  9877. function buildDownloader(source) {
  9878. var queueButton = "QUEUE";
  9879. var historyButton = "HISTORY";
  9880. switch (source) {
  9881. case "jdownloader":
  9882. var queue = true;
  9883. var history = false;
  9884. queueButton = "REFRESH";
  9885. break;
  9886. case "sabnzbd":
  9887. case "nzbget":
  9888. var queue = true;
  9889. var history = true;
  9890. break;
  9891. case "transmission":
  9892. case "qBittorrent":
  9893. case "deluge":
  9894. case "utorrent":
  9895. var queue = true;
  9896. break;
  9897. case "rTorrent":
  9898. case "sonarr":
  9899. case "radarr":
  9900. var queue = true;
  9901. var history = false;
  9902. queueButton = "REFRESH";
  9903. break;
  9904. default:
  9905. var queue = false;
  9906. var history = false;
  9907. }
  9908. var menu = `<ul class="nav customtab nav-tabs pull-right" role="tablist">`;
  9909. var listing = "";
  9910. var state = "";
  9911. var active = "";
  9912. var headerAlt = "";
  9913. var header = "";
  9914. //console.log(array);
  9915. //console.log(queueItems);
  9916. //console.log(historyItems);
  9917. //console.log(downloader);
  9918. if (queue) {
  9919. menu +=
  9920. `
  9921. <li role="presentation" class="active" onclick="homepageDownloader('` +
  9922. source +
  9923. `')"><a href="#` +
  9924. source +
  9925. `-queue" aria-controls="home" role="tab" data-toggle="tab" aria-expanded="true"><span class="visible-xs"><i class="ti-download"></i></span><span class="hidden-xs">` +
  9926. queueButton +
  9927. `</span></a></li>
  9928. `;
  9929. listing +=
  9930. `
  9931. <div role="tabpanel" class="tab-pane fade active in" id="` +
  9932. source +
  9933. `-queue">
  9934. <div class="inbox-center table-responsive">
  9935. <table class="table table-hover">
  9936. <tbody class="` +
  9937. source +
  9938. `-queue"></tbody>
  9939. </table>
  9940. </div>
  9941. <div class="clearfix"></div>
  9942. </div>
  9943. `;
  9944. }
  9945. if (history) {
  9946. menu +=
  9947. `
  9948. <li role="presentation" class=""><a href="#` +
  9949. source +
  9950. `-history" aria-controls="profile" role="tab" data-toggle="tab" aria-expanded="false"><span class="visible-xs"><i class="ti-time"></i></span> <span class="hidden-xs">` +
  9951. historyButton +
  9952. `</span></a></li>
  9953. `;
  9954. listing +=
  9955. `
  9956. <div role="tabpanel" class="tab-pane fade" id="` +
  9957. source +
  9958. `-history">
  9959. <div class="inbox-center table-responsive">
  9960. <table class="table table-hover">
  9961. <tbody class="` +
  9962. source +
  9963. `-history"></tbody>
  9964. </table>
  9965. </div>
  9966. <div class="clearfix"></div>
  9967. </div>
  9968. `;
  9969. }
  9970. menu += "</ul>";
  9971. if (activeInfo.settings.homepage.options.alternateHomepageHeaders) {
  9972. var headerAlt =
  9973. `
  9974. <div class="col-md-12">
  9975. <h2 class="text-white m-0 pull-left text-uppercase"><img class="lazyload homepageImageTitle ` +
  9976. active +
  9977. `" data-src="plugins/images/tabs/` +
  9978. source +
  9979. `.png"> &nbsp; ` +
  9980. state +
  9981. `</h2>
  9982. ` +
  9983. menu +
  9984. `
  9985. <hr class="hidden-xs"><div class="clearfix"></div>
  9986. </div>
  9987. <div class="clearfix"></div>
  9988. `;
  9989. } else {
  9990. var header =
  9991. `
  9992. <div class="white-box bg-info m-b-0 p-b-0 p-t-10 mailbox-widget">
  9993. <h2 class="text-white m-0 pull-left text-uppercase"><img class="lazyload homepageImageTitle ` +
  9994. active +
  9995. `" data-src="plugins/images/tabs/` +
  9996. source +
  9997. `.png"> &nbsp; ` +
  9998. state +
  9999. `</h2>
  10000. ` +
  10001. menu +
  10002. `
  10003. <div class="clearfix"></div>
  10004. </div>
  10005. `;
  10006. }
  10007. return (
  10008. `
  10009. <div class="row">
  10010. ` +
  10011. headerAlt +
  10012. `
  10013. <div class="col-lg-12">
  10014. ` +
  10015. header +
  10016. `
  10017. <div class="white-box p-0">
  10018. <div class="tab-content m-t-0">` +
  10019. listing +
  10020. `</div>
  10021. </div>
  10022. </div>
  10023. </div>
  10024. `
  10025. );
  10026. }
  10027. function buildDownloaderCombined(source) {
  10028. var first = $(".combinedDownloadRow").length == 0 ? true : false;
  10029. var active = first ? "active" : "";
  10030. var queueButton = "QUEUE";
  10031. var historyButton = "HISTORY";
  10032. switch (source) {
  10033. case "jdownloader":
  10034. var queue = true;
  10035. var history = false;
  10036. queueButton = "REFRESH";
  10037. break;
  10038. case "sabnzbd":
  10039. case "nzbget":
  10040. var queue = true;
  10041. var history = true;
  10042. break;
  10043. case "utorrent":
  10044. var queue = true;
  10045. break;
  10046. case "transmission":
  10047. case "qBittorrent":
  10048. case "deluge":
  10049. case "rTorrent":
  10050. case "sonarr":
  10051. case "radarr":
  10052. var queue = true;
  10053. var history = false;
  10054. queueButton = "REFRESH";
  10055. break;
  10056. default:
  10057. var queue = false;
  10058. var history = false;
  10059. }
  10060. var mainMenu = `<ul class="nav customtab nav-tabs combinedMenuList" role="tablist">`;
  10061. var addToMainMenu =
  10062. `<li role="presentation" class="` +
  10063. active +
  10064. `"><a onclick="homepageDownloader('` +
  10065. source +
  10066. `')" href="#combined-` +
  10067. source +
  10068. `" aria-controls="home" role="tab" data-toggle="tab" aria-expanded="true"><span class=""><img src="./plugins/images/tabs/` +
  10069. source +
  10070. `.png" class="homepageImageTitle"><span class="badge bg-org downloaderCount" id="count-` +
  10071. source +
  10072. `"><i class="fa fa-spinner fa-spin"></i></span></span></a></li>`;
  10073. var listing = "";
  10074. var headerAlt = "";
  10075. var header = "";
  10076. var menu = `<ul class="nav customtab nav-tabs m-t-5" role="tablist">`;
  10077. if (queue) {
  10078. menu +=
  10079. `
  10080. <li role="presentation" class="active" onclick="homepageDownloader('` +
  10081. source +
  10082. `')"><a href="#` +
  10083. source +
  10084. `-queue" aria-controls="home" role="tab" data-toggle="tab" aria-expanded="true"><span class="visible-xs"><i class="ti-download"></i></span><span class="hidden-xs">` +
  10085. queueButton +
  10086. `</span></a></li>
  10087. `;
  10088. listing +=
  10089. `
  10090. <div role="tabpanel" class="tab-pane fade active in" id="` +
  10091. source +
  10092. `-queue">
  10093. <div class="inbox-center table-responsive">
  10094. <table class="table table-hover">
  10095. <tbody class="` +
  10096. source +
  10097. `-queue"></tbody>
  10098. </table>
  10099. </div>
  10100. <div class="clearfix"></div>
  10101. </div>
  10102. `;
  10103. }
  10104. if (history) {
  10105. menu +=
  10106. `
  10107. <li role="presentation" class=""><a href="#` +
  10108. source +
  10109. `-history" aria-controls="profile" role="tab" data-toggle="tab" aria-expanded="false"><span class="visible-xs"><i class="ti-time"></i></span> <span class="hidden-xs">` +
  10110. historyButton +
  10111. `</span></a></li>
  10112. `;
  10113. listing +=
  10114. `
  10115. <div role="tabpanel" class="tab-pane fade" id="` +
  10116. source +
  10117. `-history">
  10118. <div class="inbox-center table-responsive">
  10119. <table class="table table-hover">
  10120. <tbody class="` +
  10121. source +
  10122. `-history"></tbody>
  10123. </table>
  10124. </div>
  10125. <div class="clearfix"></div>
  10126. </div>
  10127. `;
  10128. }
  10129. menu +=
  10130. '<li class="' +
  10131. source +
  10132. '-downloader-action"></li></ul><div class="clearfix"></div>';
  10133. menu = queue && history ? menu : "";
  10134. var listingMain =
  10135. '<div role="tabpanel" class="tab-pane fade ' +
  10136. active +
  10137. ' in" id="combined-' +
  10138. source +
  10139. '">' +
  10140. menu +
  10141. '<div class="tab-content m-t-0 listingSingle">' +
  10142. listing +
  10143. "</div></div>";
  10144. mainMenu += first ? addToMainMenu + "</ul>" : "";
  10145. if (first) {
  10146. if (activeInfo.settings.homepage.options.alternateHomepageHeaders) {
  10147. var headerAlt =
  10148. `
  10149. <div class="col-md-12">
  10150. ` +
  10151. mainMenu +
  10152. `
  10153. <div class="clearfix"></div>
  10154. </div>
  10155. <div class="clearfix"></div>
  10156. `;
  10157. } else {
  10158. var header =
  10159. `
  10160. <div class="white-box bg-info m-b-0 p-b-0 p-10 mailbox-widget">
  10161. ` +
  10162. mainMenu +
  10163. `
  10164. <div class="clearfix"></div>
  10165. </div>
  10166. `;
  10167. }
  10168. var built =
  10169. `
  10170. <div class="row combinedDownloadRow">
  10171. ` +
  10172. headerAlt +
  10173. `
  10174. <div class="col-lg-12">
  10175. ` +
  10176. header +
  10177. `
  10178. <div class="white-box p-0">
  10179. <div class="tab-content m-t-0 listingMain">` +
  10180. listingMain +
  10181. `</div>
  10182. </div>
  10183. </div>
  10184. </div>
  10185. `;
  10186. $("#homepageOrderdownloader").html(built);
  10187. } else {
  10188. $(addToMainMenu).appendTo(".combinedMenuList");
  10189. $(listingMain).appendTo(".listingMain");
  10190. }
  10191. }
  10192. function buildMetadata(array, source) {
  10193. var metadata = "";
  10194. var genres = "";
  10195. var actors = "";
  10196. var rating = '<div class="col-xs-2 p-10"></div>';
  10197. var sourceIcon = source === "jellyfin" ? "fish" : source;
  10198. $.each(array.content, function (i, v) {
  10199. // Normalize per-item source when coming from JellyStat or unknown
  10200. var itemSource = source;
  10201. try {
  10202. if (
  10203. source === "jellystat" ||
  10204. (source !== "emby" && source !== "jellyfin")
  10205. ) {
  10206. if (v.tabName) {
  10207. var tn = String(v.tabName).toLowerCase();
  10208. if (tn.indexOf("emby") !== -1) {
  10209. itemSource = "emby";
  10210. } else if (tn.indexOf("jellyfin") !== -1) {
  10211. itemSource = "jellyfin";
  10212. }
  10213. }
  10214. // Fallback inference from address if tabName did not resolve
  10215. if (
  10216. (itemSource === source || itemSource === "jellystat") &&
  10217. v.address
  10218. ) {
  10219. var addr = String(v.address).toLowerCase();
  10220. if (addr.indexOf("jellyfin") !== -1) {
  10221. itemSource = "jellyfin";
  10222. } else if (addr.indexOf("emby") !== -1) {
  10223. itemSource = "emby";
  10224. }
  10225. }
  10226. }
  10227. } catch (e) {}
  10228. // Normalize to lowercase to avoid casing issues like 'Emby'
  10229. itemSource = (itemSource || "").toString().toLowerCase();
  10230. var hasActor = typeof v.metadata.actors !== "string" ? true : false;
  10231. var hasGenre = typeof v.metadata.genres !== "string" ? true : false;
  10232. if (hasActor) {
  10233. $.each(v.metadata.actors, function (i, v) {
  10234. actors +=
  10235. '<div class="item lazyload recent-poster" data-src="' +
  10236. v.thumb.replace("http://", "https://") +
  10237. '" alt="' +
  10238. v.name +
  10239. '" ><span class="elip recent-title p-a-5">' +
  10240. v.name +
  10241. '<br><small class="font-light">' +
  10242. v.role +
  10243. "</small></span></div>";
  10244. });
  10245. }
  10246. if (hasGenre) {
  10247. $.each(v.metadata.genres, function (i, v) {
  10248. genres += '<span class="badge bg-org m-r-10">' + v + "</span>";
  10249. });
  10250. }
  10251. if (v.metadata.rating) {
  10252. var ratingRound = Math.ceil(v.metadata.rating) * 10;
  10253. rating =
  10254. `<div class="col-xs-2 p-10"><div data-label="` +
  10255. v.metadata.rating * 10 +
  10256. `%" class="css-bar css-bar-` +
  10257. Math.ceil(ratingRound / 5) * 5 +
  10258. ` css-bar-sm m-b-0 css-bar-info"><img src="plugins/images/rotten.png" class="nowPlayingUserThumb" alt="User"></div></div>`;
  10259. }
  10260. var seconds = v.metadata.duration / 1000; // or "2000"
  10261. seconds = parseInt(seconds); //because moment js dont know to handle number in string format
  10262. var format =
  10263. Math.floor(moment.duration(seconds, "seconds").asHours()) +
  10264. ":" +
  10265. moment.duration(seconds, "seconds").minutes() +
  10266. ":" +
  10267. moment.duration(seconds, "seconds").seconds();
  10268. // Build icon HTML: use image for Emby to avoid missing MDI glyphs; keep MDI for others
  10269. var sourceIconHtml = "";
  10270. var iconChoice = itemSource === "jellyfin" ? "fish" : itemSource;
  10271. if (itemSource === "emby") {
  10272. sourceIconHtml =
  10273. '<img src="plugins/images/tabs/emby.png" class="metadata-source-image" style="height:24px;width:24px;" />';
  10274. } else {
  10275. sourceIconHtml = '<i class="fa mdi mdi-' + iconChoice + ' fa-2x"></i>';
  10276. }
  10277. metadata =
  10278. `
  10279. <div class="white-box m-b-0">
  10280. <div class="user-bg lazyload" data-src="` +
  10281. v.nowPlayingImageURL +
  10282. `">
  10283. ` +
  10284. rating +
  10285. `
  10286. <div class="col-xs-10">
  10287. <h2 class="m-b-0 font-medium pull-right text-right">
  10288. ` +
  10289. v.title +
  10290. `<button type="button" class="btn bg-org btn-circle close-popup m-l-10"><i class="fa fa-times"></i> </button><br>
  10291. <small class="m-t-0 text-white">` +
  10292. v.metadata.tagline +
  10293. `</small><br>
  10294. <button class="btn waves-effect waves-light openTab bg-` +
  10295. itemSource +
  10296. `" type="button" data-tab-name="` +
  10297. cleanClass(v.tabName) +
  10298. `" data-type="` +
  10299. v.type +
  10300. `" data-open-tab="` +
  10301. v.openTab +
  10302. `" data-url="` +
  10303. v.address +
  10304. `" href="javascript:void(0);"> ` +
  10305. sourceIconHtml +
  10306. ` </button>
  10307. ` +
  10308. buildYoutubeLink(v.title + " " + v.metadata.year + " " + v.type) +
  10309. `
  10310. </h2>
  10311. </div>
  10312. <div class="genre-list p-10">` +
  10313. genres +
  10314. `</div>
  10315. </div>
  10316. </div>
  10317. <div class="panel panel-info p-b-0 p-t-0">
  10318. <div class="panel-body p-b-0 p-t-0 m-b-0">
  10319. <div class="p-20 text-center">
  10320. <p class="">` +
  10321. v.metadata.summary +
  10322. `</p>
  10323. </div>
  10324. <div class="row">
  10325. <div class="col-lg-12">
  10326. <div class="owl-carousel owl-theme metadata-actors p-b-10">` +
  10327. actors +
  10328. `</div>
  10329. </div>
  10330. </div>
  10331. </div>
  10332. </div>
  10333. `;
  10334. });
  10335. return metadata;
  10336. }
  10337. function buildYoutubeLink(title) {
  10338. if (title) {
  10339. var str = createRandomString(10);
  10340. return (
  10341. `
  10342. <button class="btn btn-youtube waves-effect waves-light" type="button" onclick="youtubeCheck('` +
  10343. escape(title) +
  10344. `','` +
  10345. str +
  10346. `')"> <i class="fa fa-youtube-play fa-2x"></i> </button>
  10347. <a class="hidden inline-popups ` +
  10348. str +
  10349. `" href="#open-youtube" data-effect="mfp-zoom-out"></a>
  10350. `
  10351. );
  10352. }
  10353. }
  10354. function buildPVRLink(href, ico = "", frame = "", showLink = true) {
  10355. if (href && showLink) {
  10356. var styleOverride = `width:55px;height:44px;background-image: url(${ico});background-repeat:no-repeat;background-size:25px;background-position:center;`;
  10357. if (frame) {
  10358. return `
  10359. <div class="btn btn-inverse waves-effect waves-light" type="button" onclick="tabActions(event,'${frame}','${href}');" style="${styleOverride}"></div>
  10360. `;
  10361. } else {
  10362. return `
  10363. <div class="btn btn-inverse waves-effect waves-light" type="button" onclick="window.open('${href}')" style="${styleOverride}"></div>
  10364. `;
  10365. }
  10366. } else {
  10367. return `
  10368. `;
  10369. }
  10370. }
  10371. function buildCalendarMetadata(array) {
  10372. var metadata = "";
  10373. var genres = "";
  10374. var actors = "";
  10375. var rating = '<div class="col-xs-2 p-10"></div>';
  10376. var hasGenre = typeof array.genres !== "string" ? true : false;
  10377. if (hasGenre) {
  10378. $.each(array.genres, function (i, v) {
  10379. genres += '<span class="badge bg-org m-r-10">' + v + "</span>";
  10380. });
  10381. }
  10382. if (array.ratings) {
  10383. var ratingRound = Math.ceil(array.ratings) * 10;
  10384. rating =
  10385. `<div class="col-xs-2 p-10"><div data-label="` +
  10386. array.ratings * 10 +
  10387. `%" class="css-bar css-bar-` +
  10388. Math.ceil(ratingRound / 5) * 5 +
  10389. ` css-bar-sm m-b-0 css-bar-info"><img src="plugins/images/rotten.png" class="nowPlayingUserThumb" alt="User"></div></div>`;
  10390. }
  10391. var seconds = array.runtime / 1000; // or "2000"
  10392. seconds = parseInt(seconds); //because moment js dont know to handle number in string format
  10393. var format =
  10394. Math.floor(moment.duration(seconds, "seconds").asHours()) +
  10395. ":" +
  10396. moment.duration(seconds, "seconds").minutes() +
  10397. ":" +
  10398. moment.duration(seconds, "seconds").seconds();
  10399. metadata =
  10400. `
  10401. <div class="white-box m-b-0">
  10402. <div class="user-bg lazyload" data-src="` +
  10403. array.image +
  10404. `">
  10405. ` +
  10406. rating +
  10407. `
  10408. <div class="col-xs-10">
  10409. <h2 class="m-b-0 font-medium pull-right text-right">
  10410. ` +
  10411. array.topTitle +
  10412. `<button type="button" class="btn bg-org btn-circle close-popup m-l-10"><i class="fa fa-times"></i> </button><br>
  10413. <small class="m-t-0 text-white">` +
  10414. array.bottomTitle +
  10415. `</small><br>
  10416. ` +
  10417. buildPVRLink(array.href, array.icon, array.frame, array.showLink) +
  10418. buildYoutubeLink(array.topTitle) +
  10419. `
  10420. </h2>
  10421. </div>
  10422. <div class="genre-list p-10">` +
  10423. genres +
  10424. `</div>
  10425. </div>
  10426. </div>
  10427. <div class="panel panel-info p-b-0 p-t-0">
  10428. <div class="panel-body p-b-0 p-t-0 m-b-0">
  10429. <div class="p-20 text-center">
  10430. <p class="">` +
  10431. array.overview +
  10432. `</p>
  10433. </div>
  10434. </div>
  10435. </div>
  10436. `;
  10437. return metadata;
  10438. }
  10439. function buildHealthChecks(array) {
  10440. if (array === false) {
  10441. return "";
  10442. }
  10443. var checks =
  10444. typeof array.content.checks !== "undefined"
  10445. ? array.content.checks.length
  10446. : false;
  10447. return checks
  10448. ? `
  10449. <div id="allHealthChecks" class="m-b-30">
  10450. <div class="el-element-overlay row">
  10451. <div class="col-md-12">
  10452. <h4 class="pull-left homepage-element-title"><span lang="en">Health Checks</span> : </h4><h4 class="pull-left">&nbsp;<span class="label label-info m-l-20 checkbox-circle good-health-checks mouse" onclick="homepageHealthChecks()">` +
  10453. checks +
  10454. `</span></h4>
  10455. <hr class="hidden-xs">
  10456. </div>
  10457. <div class="clearfix"></div>
  10458. <!-- .cards -->
  10459. <div class="healthCheckCards">
  10460. ` +
  10461. buildHealthChecksItem(array) +
  10462. `
  10463. </div>
  10464. <!-- /.cards-->
  10465. </div>
  10466. </div>
  10467. <div class="clearfix"></div>
  10468. `
  10469. : "";
  10470. }
  10471. function buildPihole(array) {
  10472. if (array === false) {
  10473. return "";
  10474. }
  10475. var html = `
  10476. <div id="allPihole">
  10477. <div class="el-element-overlay row">`;
  10478. if (array["options"]["title"]) {
  10479. html += `
  10480. <div class="col-md-12">
  10481. <h4 class="pull-left homepage-element-title"><span lang="en">Pi-hole</span> : </h4><h4 class="pull-left">&nbsp;</h4>
  10482. <hr class="hidden-xs ml-2">
  10483. </div>
  10484. <div class="clearfix"></div>
  10485. `;
  10486. }
  10487. html +=
  10488. `
  10489. <div class="piholeCards col-sm-12 my-3">
  10490. ` +
  10491. buildPiholeItem(array) +
  10492. `
  10493. </div>
  10494. </div>
  10495. </div>
  10496. `;
  10497. return array ? html : "";
  10498. }
  10499. function buildAdGuard(array) {
  10500. if (array === false) {
  10501. return "";
  10502. }
  10503. var html = `
  10504. <div id="allAdGuard">
  10505. <div class="el-element-overlay row">`;
  10506. if (array["options"]["title"]) {
  10507. html += `
  10508. <div class="col-md-12">
  10509. <h4 class="pull-left homepage-element-title"><span lang="en">AdGuard Home</span> : </h4><h4 class="pull-left">&nbsp;</h4>
  10510. <hr class="hidden-xs ml-2">
  10511. </div>
  10512. <div class="clearfix"></div>
  10513. `;
  10514. }
  10515. html +=
  10516. `
  10517. <div class="adguardCards col-sm-12 my-3">
  10518. ` +
  10519. buildAdGuardItem(array) +
  10520. `
  10521. </div>
  10522. </div>
  10523. </div>
  10524. `;
  10525. return array ? html : "";
  10526. }
  10527. function buildUnifi(array) {
  10528. if (array === false) {
  10529. return "";
  10530. }
  10531. var items =
  10532. typeof array.content.unifi.data !== "undefined"
  10533. ? array.content.unifi.data.length
  10534. : false;
  10535. return items
  10536. ? `
  10537. <div id="allUnifi">
  10538. <!-- <div class="row">
  10539. <div class="col-md-12">
  10540. <div class="white-box">
  10541. <h3 class="box-title">Unifi</h3>
  10542. ` +
  10543. buildUnifiItemNew(array.content.unifi.data) +
  10544. `
  10545. </div>
  10546. </div>
  10547. </div> -->
  10548. <div class="row">
  10549. <div class="col-md-12">
  10550. <h4 class="pull-left homepage-element-title"><span lang="en">UniFi</span> : </h4><h4 class="pull-left">&nbsp;</h4>
  10551. <hr class="hidden-xs">
  10552. </div>
  10553. <div class="clearfix"></div>
  10554. <!-- .cards -->
  10555. <div class="unifiCards">
  10556. ` +
  10557. buildUnifiItem(array.content.unifi.data) +
  10558. `
  10559. </div>
  10560. <!-- /.cards-->
  10561. </div>
  10562. </div>
  10563. <div class="clearfix"></div>
  10564. `
  10565. : "";
  10566. }
  10567. function buildUnifiItemNew(array) {
  10568. let items = "";
  10569. let count = 0;
  10570. let navTabItems = "";
  10571. $.each(array, function (i, v) {
  10572. let name = typeof v.subsystem !== "undefined" ? v.subsystem : "";
  10573. let stats = {};
  10574. let panelColor = "";
  10575. let proceed = v.status == "ok";
  10576. let active = count <= 0 ? "active in" : "";
  10577. let icon = "ti-home";
  10578. count++;
  10579. switch (name) {
  10580. case "wlan":
  10581. panelColor = "info";
  10582. stats["clients"] = v.num_user;
  10583. stats["tx"] = v["tx_bytes-r"];
  10584. stats["rx"] = v["rx_bytes-r"];
  10585. break;
  10586. case "wan":
  10587. panelColor = "success";
  10588. stats["IP"] = v.wan_ip;
  10589. stats["tx"] = v["tx_bytes-r"];
  10590. stats["rx"] = v["rx_bytes-r"];
  10591. break;
  10592. case "lan":
  10593. panelColor = "primary";
  10594. stats["clients"] = v.num_user;
  10595. stats["tx"] = v["tx_bytes-r"];
  10596. stats["rx"] = v["rx_bytes-r"];
  10597. break;
  10598. case "www":
  10599. panelColor = "warning";
  10600. stats["drops"] = v.drops;
  10601. stats["latency"] = v.latency;
  10602. stats["uptime"] = v.uptime;
  10603. stats["tx"] = v["tx_bytes-r"];
  10604. stats["rx"] = v["rx_bytes-r"];
  10605. break;
  10606. case "vpn":
  10607. panelColor = "inverse";
  10608. stats["clients"] = v.remote_user_num_active;
  10609. stats["tx"] = v.remote_user_tx_bytes;
  10610. stats["rx"] = v.remote_user_rx_bytes;
  10611. break;
  10612. default:
  10613. }
  10614. var statItems = "";
  10615. if (proceed) {
  10616. navTabItems += `<li role="presentation" class="${active}"><a href="#unifi-${name}" aria-controls="unifi-${name}" role="tab" data-toggle="tab" aria-expanded="false"><span class="visible-xs"><i class="${icon}"></i></span><span class="hidden-xs text-uppercase"> ${name}</span></a></li>`;
  10617. $.each(stats, function (istat, vstat) {
  10618. statItems += `
  10619. <div class="stat-item">
  10620. <h6 class="text-uppercase">${istat}</h6>
  10621. <b>${vstat}</b>
  10622. </div>
  10623. `;
  10624. });
  10625. items += `
  10626. <div role="tabpanel" class="tab-pane fade ${active}" id="unifi-${name}">
  10627. <div class="col-md-12">${statItems}</div>
  10628. <div class="clearfix"></div>
  10629. </div>
  10630. `;
  10631. }
  10632. });
  10633. let navTabs = `<ul class="nav customtab nav-tabs" role="tablist">${navTabItems}</ul>`;
  10634. items = `<div class="tab-content">${items}</div>`;
  10635. return navTabs + items;
  10636. }
  10637. function buildUnifiItem(array) {
  10638. var items = "";
  10639. $.each(array, function (i, v) {
  10640. var name = typeof v.subsystem !== "undefined" ? v.subsystem : "";
  10641. var stats = {};
  10642. var panelColor = "";
  10643. var proceed = v.status == "ok";
  10644. switch (name) {
  10645. case "wlan":
  10646. panelColor = "info";
  10647. stats["clients"] = v.num_user;
  10648. stats["tx"] = v["tx_bytes-r"];
  10649. stats["rx"] = v["rx_bytes-r"];
  10650. break;
  10651. case "wan":
  10652. panelColor = "success";
  10653. stats["IP"] = v.wan_ip;
  10654. stats["tx"] = v["tx_bytes-r"];
  10655. stats["rx"] = v["rx_bytes-r"];
  10656. break;
  10657. case "lan":
  10658. panelColor = "primary";
  10659. stats["clients"] = v.num_user;
  10660. stats["tx"] = v["tx_bytes-r"];
  10661. stats["rx"] = v["rx_bytes-r"];
  10662. break;
  10663. case "www":
  10664. panelColor = "warning";
  10665. stats["drops"] = v.drops;
  10666. stats["latency"] = v.latency;
  10667. stats["uptime"] = v.uptime;
  10668. stats["tx"] = v["tx_bytes-r"];
  10669. stats["rx"] = v["rx_bytes-r"];
  10670. break;
  10671. case "vpn":
  10672. panelColor = "inverse";
  10673. stats["clients"] = v.remote_user_num_active;
  10674. stats["tx"] = v.remote_user_tx_bytes;
  10675. stats["rx"] = v.remote_user_rx_bytes;
  10676. break;
  10677. default:
  10678. }
  10679. var statItems = "";
  10680. if (proceed) {
  10681. $.each(stats, function (istat, vstat) {
  10682. statItems += `
  10683. <div class="stat-item">
  10684. <h6 class="text-uppercase">${istat}</h6>
  10685. <b>${vstat}</b>
  10686. </div>
  10687. `;
  10688. });
  10689. items += `
  10690. <div class="col-lg-4 col-md-6 col-center">
  10691. <div class="panel panel-${panelColor}">
  10692. <div class="panel-heading"> <span class="text-uppercase">${name}</span>
  10693. <div class="pull-right"><a href="#" data-perform="panel-collapse"><i class="ti-minus"></i></a></div>
  10694. </div>
  10695. <div class="panel-wrapper collapse in" aria-expanded="true">
  10696. <div class="panel-body">
  10697. ${statItems}
  10698. </div>
  10699. </div>
  10700. </div>
  10701. </div>
  10702. `;
  10703. }
  10704. });
  10705. return items;
  10706. }
  10707. function healthCheckIcon(tags) {
  10708. var allTags = tags.split(" ");
  10709. var useIcon = "";
  10710. $.each(allTags, function (i, v) {
  10711. //check for image
  10712. var file =
  10713. v.substring(v.lastIndexOf(".") + 1, v.length).toLowerCase() ||
  10714. v.toLowerCase();
  10715. switch (file) {
  10716. case "png":
  10717. case "jpg":
  10718. case "jpeg":
  10719. case "gif":
  10720. useIcon =
  10721. '<img class="lazyload loginTitle" data-src="' + v + '">&nbsp;';
  10722. break;
  10723. default:
  10724. }
  10725. });
  10726. return useIcon;
  10727. }
  10728. function buildHealthChecksItem(array) {
  10729. var checks = "";
  10730. $.each(array.content.checks, function (i, v) {
  10731. var hasIcon = healthCheckIcon(v.tags);
  10732. v.name = v.name ? v.name : "New Item";
  10733. v.desc =
  10734. array.options.desc && v.desc ? "<h5>Notes: " + v.desc + "</h5>" : "";
  10735. switch (v.status) {
  10736. case "up":
  10737. var statusColor = "success";
  10738. var statusIcon = "ti-link text-success";
  10739. var nextPing = moment
  10740. .utc(v.next_ping, "YYYY-MM-DD hh:mm[Z]")
  10741. .local()
  10742. .fromNow();
  10743. var lastPing = moment
  10744. .utc(v.last_ping, "YYYY-MM-DD hh:mm[Z]")
  10745. .local()
  10746. .fromNow();
  10747. break;
  10748. case "down":
  10749. var statusColor = "danger animated-3 loop-animation flash";
  10750. var statusIcon = "ti-unlink text-danger";
  10751. var nextPing = "Service Down";
  10752. var lastPing = moment
  10753. .utc(v.last_ping, "YYYY-MM-DD hh:mm[Z]")
  10754. .local()
  10755. .fromNow();
  10756. break;
  10757. case "new":
  10758. var statusColor = "info";
  10759. var statusIcon = "ti-time text-info";
  10760. var nextPing = "Waiting...";
  10761. var lastPing = "n/a";
  10762. break;
  10763. case "grace":
  10764. var statusColor = "warning";
  10765. var statusIcon = "ti-alert text-warning";
  10766. var nextPing = moment
  10767. .utc(v.next_ping, "YYYY-MM-DD hh:mm[Z]")
  10768. .local()
  10769. .fromNow();
  10770. var lastPing = "Missed";
  10771. break;
  10772. case "paused":
  10773. var statusColor = "primary";
  10774. var statusIcon = "ti-control-pause text-primary";
  10775. var nextPing = "Paused";
  10776. var lastPing = moment
  10777. .utc(v.last_ping, "YYYY-MM-DD hh:mm[Z]")
  10778. .local()
  10779. .fromNow();
  10780. break;
  10781. default:
  10782. var statusColor = "warning";
  10783. var statusIcon = "ti-timer text-warning";
  10784. var nextPing = "Waiting...";
  10785. var lastPing = "n/a";
  10786. }
  10787. var tagPrimaryElem = "",
  10788. tagSecondaryElem = "";
  10789. if (array.options.tags && v.tags) {
  10790. v.tags = v.tags.split(" ");
  10791. $.each(v.tags, function (key, value) {
  10792. if (isURL(value)) {
  10793. v.tags = arrayRemove(v.tags, value);
  10794. }
  10795. });
  10796. tagPrimaryElem =
  10797. '<span class="pull-right mt-3 mr-2"><span class="label text-uppercase bg-' +
  10798. statusColor.replace("animated-3 loop-animation flash", "") +
  10799. ' label-rounded font-12">' +
  10800. v.tags[0] +
  10801. "</span></span>";
  10802. tagSecondaryElem = "<h5>Tags: ";
  10803. tagSecondaryElem += v.tags
  10804. .map((t) => {
  10805. return t;
  10806. })
  10807. .join(", ");
  10808. tagSecondaryElem += "</h5>";
  10809. }
  10810. checks +=
  10811. `
  10812. <div class="col-xl-2 col-lg-3 col-md-4 col-sm-6 col-xs-12">
  10813. <div class="card bg-inverse text-white mb-3 showMoreHealth mouse" data-id="` +
  10814. i +
  10815. `">
  10816. <div class="card-body bg-org-alt pt-1 pb-1">
  10817. <div class="d-flex no-block align-items-center">
  10818. <div class="left-health bg-` +
  10819. statusColor +
  10820. `"></div>
  10821. <div class="ml-1 w-100">
  10822. <span class="pull-right mt-3 mb-2"><i class="` +
  10823. statusIcon +
  10824. ` font-20"></i></span>
  10825. ` +
  10826. tagPrimaryElem +
  10827. `
  10828. <h3 class="d-flex no-block align-items-center mt-2 mb-2">` +
  10829. hasIcon +
  10830. v.name +
  10831. `</h3>
  10832. <div class="clearfix"></div>
  10833. <div class="d-none showMoreHealthDiv-` +
  10834. i +
  10835. `"><h5>Last: ` +
  10836. lastPing +
  10837. `</h5><h5>Next: ` +
  10838. nextPing +
  10839. `</h5>` +
  10840. v.desc +
  10841. tagSecondaryElem +
  10842. `</div>
  10843. <div class="clearfix"></div>
  10844. </div>
  10845. </div>
  10846. </div>
  10847. </div>
  10848. </div>
  10849. `;
  10850. });
  10851. return checks;
  10852. }
  10853. function isURL(str) {
  10854. const pattern = new RegExp(
  10855. "^(https?:\\/\\/)?" + // protocol
  10856. "((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|" + // domain name
  10857. "((\\d{1,3}\\.){3}\\d{1,3}))" + // OR ip (v4) address
  10858. "(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*" + // port and path
  10859. "(\\?[;&a-z\\d%_.~+=-]*)?" + // query string
  10860. "(\\#[-a-z\\d_]*)?$",
  10861. "i"
  10862. ); // fragment locator
  10863. return !!pattern.test(str);
  10864. }
  10865. function arrayRemove(arr, value) {
  10866. return arr.filter(function (ele) {
  10867. return ele != value;
  10868. });
  10869. }
  10870. function buildAdGuardItem(array) {
  10871. var stats = `
  10872. <style>
  10873. .bg-green {
  10874. background-color: #00a65a !important;
  10875. }
  10876. .bg-aqua {
  10877. background-color: #00c0ef!important;
  10878. }
  10879. .bg-yellow {
  10880. background-color: #f39c12!important;
  10881. }
  10882. .bg-red {
  10883. background-color: #dd4b39!important;
  10884. }
  10885. .adguard-stat {
  10886. color: #fff !important;
  10887. }
  10888. .adguard-stat .card-body h3 {
  10889. font-size: 38px;
  10890. font-weight: 700;
  10891. }
  10892. .adguard-stat .card-body i {
  10893. font-size: 5em;
  10894. float: right;
  10895. color: #ffffff6b;
  10896. }
  10897. .inline-block {
  10898. display: inline-block;
  10899. }
  10900. </style>
  10901. `;
  10902. var length = Object.keys(array["data"]).length;
  10903. var combine = array["options"]["combine"];
  10904. var totalQueries = function (data) {
  10905. var card = `
  10906. <div class="col-lg-3 col-md-6 col-sm-6 col-xs-12">
  10907. <div class="card text-white mb-3 adguard-stat bg-green">
  10908. <div class="card-body">
  10909. <div class="inline-block">
  10910. <p class="d-inline mr-1">Total Queries</p>`;
  10911. for (var key in data) {
  10912. var e = data[key];
  10913. if (length > 1 && !combine) {
  10914. card += `<p class="d-inline text-muted">(` + key + `)</p>`;
  10915. }
  10916. card +=
  10917. `<h3 data-toggle="tooltip" data-placement="right" title="` +
  10918. key +
  10919. `">` +
  10920. e["num_dns_queries"].toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") +
  10921. `</h3>`;
  10922. }
  10923. card += `
  10924. </div>
  10925. <i class="fa fa-globe inline-block" aria-hidden="true"></i>
  10926. </div>
  10927. </div>
  10928. </div>
  10929. `;
  10930. return card;
  10931. };
  10932. var totalBlocked = function (data) {
  10933. var card = `
  10934. <div class="col-lg-3 col-md-6 col-sm-6 col-xs-12">
  10935. <div class="card bg-inverse text-white mb-3 adguard-stat bg-aqua">
  10936. <div class="card-body">
  10937. <div class="inline-block">
  10938. <p class="d-inline mr-1">Queries Blocked</p>`;
  10939. for (var key in data) {
  10940. var e = data[key];
  10941. if (length > 1 && !combine) {
  10942. card += `<p class="d-inline text-muted">(${key})</p>`;
  10943. }
  10944. card += `<h3 data-toggle="tooltip" data-placement="right" title="${key}">${e[
  10945. "num_blocked_filtering"
  10946. ]
  10947. .toString()
  10948. .replace(/\B(?=(\d{3})+(?!\d))/g, ",")}</h3>`;
  10949. }
  10950. card += `
  10951. </div>
  10952. <i class="fa fa-hand-paper-o inline-block" aria-hidden="true"></i>
  10953. </div>
  10954. </div>
  10955. </div>
  10956. `;
  10957. return card;
  10958. };
  10959. var avgProcessingTime = function (data) {
  10960. var card = `
  10961. <div class="col-lg-3 col-md-6 col-sm-6 col-xs-12">
  10962. <div class="card bg-inverse text-white mb-3 adguard-stat bg-purple">
  10963. <div class="card-body">
  10964. <div class="inline-block">
  10965. <p class="d-inline mr-1">Avg Processing Time</p>`;
  10966. for (var key in data) {
  10967. var e = data[key];
  10968. if (length > 1 && !combine) {
  10969. card += `<p class="d-inline text-muted">(${key})</p>`;
  10970. }
  10971. ms_time = parseFloat(e["avg_processing_time"]) * 1000;
  10972. card += `<h3 data-toggle="tooltip" data-placement="right" title="${key}">${ms_time.toFixed(
  10973. 2
  10974. )} ms</h3>`;
  10975. }
  10976. card += `
  10977. </div>
  10978. <i class="fa fa-group inline-block" aria-hidden="true"></i>
  10979. </div>
  10980. </div>
  10981. </div>
  10982. `;
  10983. return card;
  10984. };
  10985. var domainsBlocked = function (data) {
  10986. var card = `
  10987. <div class="col-lg-3 col-md-6 col-sm-6 col-xs-12">
  10988. <div class="card bg-inverse text-white mb-3 adguard-stat bg-red">
  10989. <div class="card-body">
  10990. <div class="inline-block">
  10991. <p class="d-inline mr-1">Domains on Blocklist</p>`;
  10992. for (var key in data) {
  10993. var e = data[key];
  10994. if (length > 1 && !combine) {
  10995. card += `<p class="d-inline text-muted">(${key})</p>`;
  10996. }
  10997. var total_domains_blocked = 0;
  10998. for (var key in e["filters"]) {
  10999. total_domains_blocked += parseFloat(e["filters"][key]["rules_count"]);
  11000. }
  11001. card += `<h3 data-toggle="tooltip" data-placement="right" title="${key}">${total_domains_blocked
  11002. .toString()
  11003. .replace(/\B(?=(\d{3})+(?!\d))/g, ",")}</h3>`;
  11004. }
  11005. card += `
  11006. </div>
  11007. <i class="fa fa-list inline-block" aria-hidden="true"></i>
  11008. </div>
  11009. </div>
  11010. </div>
  11011. `;
  11012. return card;
  11013. };
  11014. var domainsBlocked = function (data) {
  11015. var card = `
  11016. <div class="col-lg-3 col-md-6 col-sm-6 col-xs-12">
  11017. <div class="card bg-inverse text-white mb-3 adguard-stat bg-red">
  11018. <div class="card-body">
  11019. <div class="inline-block">
  11020. <p class="d-inline mr-1">Domains on Blocklist</p>`;
  11021. for (var key in data) {
  11022. var e = data[key];
  11023. if (length > 1 && !combine) {
  11024. card += `<p class="d-inline text-muted">(${key})</p>`;
  11025. }
  11026. var total_domains_blocked = 0;
  11027. for (var key in e["filters"]) {
  11028. total_domains_blocked += parseFloat(e["filters"][key]["rules_count"]);
  11029. }
  11030. total_domains_blocked += Object.keys(e["user_rules"]).length;
  11031. card += `<h3 data-toggle="tooltip" data-placement="right" title="${key}">${total_domains_blocked
  11032. .toString()
  11033. .replace(/\B(?=(\d{3})+(?!\d))/g, ",")}</h3>`;
  11034. }
  11035. card += `
  11036. </div>
  11037. <i class="fa fa-list inline-block" aria-hidden="true"></i>
  11038. </div>
  11039. </div>
  11040. </div>
  11041. `;
  11042. return card;
  11043. };
  11044. var percentBlocked = function (data) {
  11045. var card = `
  11046. <div class="col-lg-3 col-md-6 col-sm-6 col-xs-12">
  11047. <div class="card bg-inverse text-white mb-3 adguard-stat bg-yellow">
  11048. <div class="card-body">
  11049. <div class="inline-block">
  11050. <p class="d-inline mr-1">Percent Blocked</p>`;
  11051. for (var key in data) {
  11052. var e = data[key];
  11053. if (typeof e["FTLnotrunning"] == "undefined") {
  11054. if (length > 1 && !combine) {
  11055. card += `<p class="d-inline text-muted">(${key})</p>`;
  11056. }
  11057. var percent =
  11058. 100 *
  11059. (parseFloat(e["num_blocked_filtering"]) /
  11060. parseFloat(e["num_dns_queries"]));
  11061. card += `<h3 data-toggle="tooltip" data-placement="right" title="${key}">${percent.toFixed(
  11062. 2
  11063. )}%</h3>`;
  11064. }
  11065. }
  11066. card += `
  11067. </div>
  11068. <i class="fa fa-pie-chart inline-block" aria-hidden="true"></i>
  11069. </div>
  11070. </div>
  11071. </div>
  11072. `;
  11073. return card;
  11074. };
  11075. if (combine) {
  11076. stats += '<div class="row">';
  11077. if (array["options"]["queries"]) {
  11078. stats += totalQueries(array["data"]);
  11079. }
  11080. if (array["options"]["blocked_count"]) {
  11081. stats += totalBlocked(array["data"]);
  11082. }
  11083. if (array["options"]["blocked_percent"]) {
  11084. stats += percentBlocked(array["data"]);
  11085. }
  11086. if (array["options"]["processing_time"]) {
  11087. stats += avgProcessingTime(array["data"]);
  11088. }
  11089. if (array["options"]["domain_count"]) {
  11090. stats += domainsBlocked(array["filters"]);
  11091. }
  11092. stats += "</div>";
  11093. } else {
  11094. for (var key in array["data"]) {
  11095. var data = array["data"][key];
  11096. obj = {};
  11097. obj[key] = data;
  11098. stats += '<div class="row">';
  11099. if (array["options"]["queries"]) {
  11100. stats += totalQueries(array["data"]);
  11101. }
  11102. if (array["options"]["blocked_count"]) {
  11103. stats += totalBlocked(array["data"]);
  11104. }
  11105. if (array["options"]["blocked_percent"]) {
  11106. stats += percentBlocked(array["data"]);
  11107. }
  11108. if (array["options"]["processing_time"]) {
  11109. stats += avgProcessingTime(array["data"]);
  11110. }
  11111. if (array["options"]["domain_count"]) {
  11112. stats += domainsBlocked(array["filters"]);
  11113. }
  11114. stats += "</div>";
  11115. }
  11116. }
  11117. return stats;
  11118. }
  11119. function buildPiholeItem(array) {
  11120. var stats = `
  11121. <style>
  11122. .bg-green {
  11123. background-color: #00a65a !important;
  11124. }
  11125. .bg-aqua {
  11126. background-color: #00c0ef!important;
  11127. }
  11128. .bg-yellow {
  11129. background-color: #f39c12!important;
  11130. }
  11131. .bg-red {
  11132. background-color: #dd4b39!important;
  11133. }
  11134. .pihole-stat {
  11135. color: #fff !important;
  11136. }
  11137. .pihole-stat .card-body h3 {
  11138. font-size: 38px;
  11139. font-weight: 700;
  11140. }
  11141. .pihole-stat .card-body i {
  11142. font-size: 5em;
  11143. float: right;
  11144. color: #ffffff6b;
  11145. }
  11146. .inline-block {
  11147. display: inline-block;
  11148. }
  11149. ul.multi-column {
  11150. column-count: 1;
  11151. column-gap: 2em;
  11152. }
  11153. @media (min-width: 650px) {
  11154. ul.multi-column {
  11155. column-count: 3;
  11156. }
  11157. }
  11158. @media (min-width: 1200px) {
  11159. ul.multi-column {
  11160. column-count: 5;
  11161. }
  11162. }
  11163. </style>
  11164. `;
  11165. var length = Object.keys(array["data"]).length;
  11166. var combine = array["options"]["combine"];
  11167. var totalQueries = function (data) {
  11168. var card = `
  11169. <div class="col-lg-4 col-md-6 col-sm-6 col-xs-12">
  11170. <div class="card text-white mb-3 pihole-stat bg-green">
  11171. <div class="card-body">
  11172. <div class="inline-block">
  11173. <p class="d-inline mr-1">Total queries (last 24 hours)</p>`;
  11174. for (var key in data) {
  11175. var e = data[key];
  11176. if (typeof e["FTLnotrunning"] == "undefined") {
  11177. if (length > 1 && !combine) {
  11178. card += `<p class="d-inline text-muted">(` + key + `)</p>`;
  11179. }
  11180. let value = "Error";
  11181. if (e.length == undefined) {
  11182. value = e["sum_queries"]
  11183. .toString()
  11184. .replace(/\B(?=(\d{3})+(?!\d))/g, ",");
  11185. }
  11186. card +=
  11187. `<h3 data-toggle="tooltip" data-placement="right" title="` +
  11188. key +
  11189. `">` +
  11190. value +
  11191. `</h3>`;
  11192. }
  11193. }
  11194. card += `
  11195. </div>
  11196. <i class="fa fa-globe inline-block" aria-hidden="true"></i>
  11197. </div>
  11198. </div>
  11199. </div>
  11200. `;
  11201. return card;
  11202. };
  11203. var totalBlocked = function (data) {
  11204. var card = `
  11205. <div class="col-lg-4 col-md-6 col-sm-6 col-xs-12">
  11206. <div class="card bg-inverse text-white mb-3 pihole-stat bg-aqua">
  11207. <div class="card-body">
  11208. <div class="inline-block">
  11209. <p class="d-inline mr-1">Queries Blocked (last 24 hours)</p>`;
  11210. for (var key in data) {
  11211. var e = data[key];
  11212. if (typeof e["FTLnotrunning"] == "undefined") {
  11213. if (length > 1 && !combine) {
  11214. card += `<p class="d-inline text-muted">(${key})</p>`;
  11215. }
  11216. let value = "Error";
  11217. if (e.length == undefined) {
  11218. value = e["sum_blocked"]
  11219. .toString()
  11220. .replace(/\B(?=(\d{3})+(?!\d))/g, ",");
  11221. }
  11222. card +=
  11223. `<h3 data-toggle="tooltip" data-placement="right" title="` +
  11224. key +
  11225. `">` +
  11226. value +
  11227. `</h3>`;
  11228. }
  11229. }
  11230. card += `
  11231. </div>
  11232. <i class="fa fa-hand-paper-o inline-block" aria-hidden="true"></i>
  11233. </div>
  11234. </div>
  11235. </div>
  11236. `;
  11237. return card;
  11238. };
  11239. var percentBlocked = function (data) {
  11240. var card = `
  11241. <div class="col-lg-4 col-md-6 col-sm-6 col-xs-12">
  11242. <div class="card bg-inverse text-white mb-3 pihole-stat bg-yellow">
  11243. <div class="card-body">
  11244. <div class="inline-block">
  11245. <p class="d-inline mr-1">Percent Blocked (last 24 hours)</p>`;
  11246. for (var key in data) {
  11247. var e = data[key];
  11248. if (typeof e["FTLnotrunning"] == "undefined") {
  11249. if (length > 1 && !combine) {
  11250. card += `<p class="d-inline text-muted">(${key})</p>`;
  11251. }
  11252. let value = "Error";
  11253. if (e.length == undefined) {
  11254. value = e["percent_blocked"].toFixed(1);
  11255. }
  11256. card +=
  11257. `<h3 data-toggle="tooltip" data-placement="right" title="` +
  11258. key +
  11259. `">` +
  11260. value +
  11261. `</h3>`;
  11262. }
  11263. }
  11264. card += `
  11265. </div>
  11266. <i class="fa fa-pie-chart inline-block" aria-hidden="true"></i>
  11267. </div>
  11268. </div>
  11269. </div>
  11270. `;
  11271. return card;
  11272. };
  11273. var domainsBlocked = function (data) {
  11274. var card = `
  11275. <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
  11276. <div class="card bg-inverse text-white mb-3 pihole-stat bg-red">
  11277. <div class="card-body">
  11278. <div class="inline-block">
  11279. <p class="d-inline mr-1">Domains on Blocklist (last 24 hours)</p>`;
  11280. for (var key in data) {
  11281. var e = data[key];
  11282. if (typeof e["FTLnotrunning"] == "undefined") {
  11283. if (length > 1 && !combine) {
  11284. card += `<p class="d-inline text-muted">(${key})</p>`;
  11285. }
  11286. let value = "Error";
  11287. value = e["domains_being_blocked"]
  11288. .map(function (x) {
  11289. return `<li>${x.toString()}</li>`;
  11290. })
  11291. .join("");
  11292. card +=
  11293. `<ul class="multi-column" data-toggle="tooltip" title="` +
  11294. key +
  11295. `">` +
  11296. value +
  11297. `</ul>`;
  11298. }
  11299. }
  11300. card += `
  11301. </div>
  11302. <i class="fa fa-list inline-block" aria-hidden="true"></i>
  11303. </div>
  11304. </div>
  11305. </div>
  11306. `;
  11307. return card;
  11308. };
  11309. if (combine) {
  11310. stats += '<div class="row">';
  11311. stats += totalQueries(array["data"]);
  11312. stats += totalBlocked(array["data"]);
  11313. stats += percentBlocked(array["data"]);
  11314. stats += domainsBlocked(array["data"]);
  11315. stats += "</div>";
  11316. } else {
  11317. for (var key in array["data"]) {
  11318. var data = array["data"][key];
  11319. obj = {};
  11320. obj[key] = data;
  11321. stats += '<div class="row">';
  11322. stats += totalQueries(obj);
  11323. stats += totalBlocked(obj);
  11324. stats += percentBlocked(obj);
  11325. stats += domainsBlocked(obj);
  11326. stats += "</div>";
  11327. }
  11328. }
  11329. return stats;
  11330. }
  11331. function homepagePihole(timeout) {
  11332. var timeout =
  11333. typeof timeout !== "undefined"
  11334. ? timeout
  11335. : activeInfo.settings.homepage.refresh.homepagePiholeRefresh;
  11336. organizrAPI2("GET", "api/v2/homepage/pihole/stats")
  11337. .success(function (data) {
  11338. try {
  11339. let response = data.response;
  11340. document.getElementById("homepageOrderPihole").innerHTML = "";
  11341. if (response.data !== null) {
  11342. buildPihole(response.data);
  11343. $("#homepageOrderPihole").html(buildPihole(response.data));
  11344. }
  11345. } catch (e) {
  11346. organizrCatchError(e, data);
  11347. }
  11348. })
  11349. .fail(function (xhr) {
  11350. OrganizrApiError(xhr);
  11351. });
  11352. let timeoutTitle = "PiHole-Homepage";
  11353. if (typeof timeouts[timeoutTitle] !== "undefined") {
  11354. clearTimeout(timeouts[timeoutTitle]);
  11355. }
  11356. timeouts[timeoutTitle] = setTimeout(function () {
  11357. homepagePihole(timeout);
  11358. }, timeout);
  11359. delete timeout;
  11360. }
  11361. function homepageAdGuard(timeout) {
  11362. var timeout =
  11363. typeof timeout !== "undefined"
  11364. ? timeout
  11365. : activeInfo.settings.homepage.refresh.homepageAdGuardRefresh;
  11366. organizrAPI2("GET", "api/v2/homepage/adguard/stats")
  11367. .success(function (data) {
  11368. try {
  11369. let response = data.response;
  11370. document.getElementById("homepageOrderAdGuard").innerHTML = "";
  11371. if (response.data !== null) {
  11372. buildAdGuard(response.data);
  11373. $("#homepageOrderAdGuard").html(buildAdGuard(response.data));
  11374. }
  11375. } catch (e) {
  11376. organizrCatchError(e, data);
  11377. }
  11378. })
  11379. .fail(function (xhr) {
  11380. OrganizrApiError(xhr);
  11381. });
  11382. let timeoutTitle = "AdGuard-Homepage";
  11383. if (typeof timeouts[timeoutTitle] !== "undefined") {
  11384. clearTimeout(timeouts[timeoutTitle]);
  11385. }
  11386. timeouts[timeoutTitle] = setTimeout(function () {
  11387. homepageAdGuard(timeout);
  11388. }, timeout);
  11389. delete timeout;
  11390. }
  11391. function homepageHealthChecks(tags, timeout) {
  11392. tags =
  11393. typeof tags !== "undefined"
  11394. ? tags
  11395. : activeInfo.settings.homepage.options.healthChecksTags;
  11396. if (tags == "") {
  11397. var apiUrl = "api/v2/homepage/healthchecks";
  11398. } else {
  11399. var apiUrl = "api/v2/homepage/healthchecks/" + tags;
  11400. }
  11401. timeout =
  11402. typeof timeout !== "undefined"
  11403. ? timeout
  11404. : activeInfo.settings.homepage.refresh.homepageHealthChecksRefresh;
  11405. organizrAPI2("GET", apiUrl)
  11406. .success(function (data) {
  11407. try {
  11408. var response = data.response;
  11409. document.getElementById("homepageOrderhealthchecks").innerHTML = "";
  11410. if (response.data !== null) {
  11411. $("#homepageOrderhealthchecks").html(
  11412. buildHealthChecks(response.data)
  11413. );
  11414. }
  11415. } catch (e) {
  11416. organizrCatchError(e, data);
  11417. }
  11418. })
  11419. .fail(function (xhr) {
  11420. OrganizrApiError(xhr);
  11421. });
  11422. let timeoutTitle = "HealthChecks-Homepage";
  11423. if (typeof timeouts[timeoutTitle] !== "undefined") {
  11424. clearTimeout(timeouts[timeoutTitle]);
  11425. }
  11426. timeouts[timeoutTitle] = setTimeout(function () {
  11427. homepageHealthChecks(tags, timeout);
  11428. }, timeout);
  11429. delete timeout;
  11430. }
  11431. function homepageUnifi(timeout) {
  11432. var timeout =
  11433. typeof timeout !== "undefined"
  11434. ? timeout
  11435. : activeInfo.settings.homepage.refresh.homepageUnifiRefresh;
  11436. organizrAPI2("GET", "api/v2/homepage/unifi/data")
  11437. .success(function (data) {
  11438. try {
  11439. let response = data.response;
  11440. document.getElementById("homepageOrderunifi").innerHTML = "";
  11441. if (response.data !== null) {
  11442. $("#homepageOrderunifi").html(buildUnifi(response.data));
  11443. }
  11444. } catch (e) {
  11445. organizrCatchError(e, data);
  11446. }
  11447. })
  11448. .fail(function (xhr) {
  11449. OrganizrApiError(xhr);
  11450. });
  11451. var timeoutTitle = "Unifi-Homepage";
  11452. if (typeof timeouts[timeoutTitle] !== "undefined") {
  11453. clearTimeout(timeouts[timeoutTitle]);
  11454. }
  11455. timeouts[timeoutTitle] = setTimeout(function () {
  11456. homepageUnifi(timeout);
  11457. }, timeout);
  11458. delete timeout;
  11459. }
  11460. function homepageDownloader(type, timeout) {
  11461. var timeout =
  11462. typeof timeout !== "undefined"
  11463. ? timeout
  11464. : activeInfo.settings.homepage.refresh.homepageDownloadRefresh;
  11465. switch (type) {
  11466. case "jdownloader":
  11467. var action = "getJdownloader";
  11468. break;
  11469. case "sabnzbd":
  11470. var action = "getSabnzbd";
  11471. break;
  11472. case "nzbget":
  11473. var action = "getNzbget";
  11474. break;
  11475. case "transmission":
  11476. var action = "getTransmission";
  11477. break;
  11478. case "sonarr":
  11479. var action = "getSonarrQueue";
  11480. break;
  11481. case "radarr":
  11482. var action = "getRadarrQueue";
  11483. break;
  11484. case "qBittorrent":
  11485. var action = "getqBittorrent";
  11486. break;
  11487. case "deluge":
  11488. var action = "getDeluge";
  11489. break;
  11490. case "rTorrent":
  11491. var action = "getrTorrent";
  11492. break;
  11493. case "utorrent":
  11494. var action = "getutorrent";
  11495. break;
  11496. default:
  11497. }
  11498. let lowerType = type.toLowerCase();
  11499. organizrAPI2("GET", "api/v2/homepage/" + lowerType + "/queue")
  11500. .success(function (data) {
  11501. try {
  11502. let response = data.response;
  11503. if (response.data !== null) {
  11504. buildDownloaderItem(response.data, type);
  11505. }
  11506. } catch (e) {
  11507. organizrCatchError(e, data);
  11508. }
  11509. })
  11510. .fail(function (xhr) {
  11511. OrganizrApiError(xhr);
  11512. });
  11513. let timeoutTitle = type + "-Downloader-Homepage";
  11514. if (typeof timeouts[timeoutTitle] !== "undefined") {
  11515. clearTimeout(timeouts[timeoutTitle]);
  11516. }
  11517. timeouts[timeoutTitle] = setTimeout(function () {
  11518. homepageDownloader(type, timeout);
  11519. }, timeout);
  11520. delete timeout;
  11521. }
  11522. function homepageStream(type, timeout) {
  11523. var timeout =
  11524. typeof timeout !== "undefined"
  11525. ? timeout
  11526. : activeInfo.settings.homepage.refresh.homepageStreamRefresh;
  11527. organizrAPI2("GET", "api/v2/homepage/" + type + "/streams")
  11528. .success(function (data) {
  11529. try {
  11530. let response = data.response;
  11531. document.getElementById(
  11532. "homepageOrder" + type + "nowplaying"
  11533. ).innerHTML = "";
  11534. $("#homepageOrder" + type + "nowplaying").html(
  11535. buildStream(response.data, type)
  11536. );
  11537. } catch (e) {
  11538. organizrCatchError(e, data);
  11539. }
  11540. })
  11541. .fail(function (xhr) {
  11542. OrganizrApiError(xhr);
  11543. });
  11544. let timeoutTitle = type + "-Stream-Homepage";
  11545. if (typeof timeouts[timeoutTitle] !== "undefined") {
  11546. clearTimeout(timeouts[timeoutTitle]);
  11547. }
  11548. timeouts[timeoutTitle] = setTimeout(function () {
  11549. homepageStream(type, timeout);
  11550. }, timeout);
  11551. delete timeout;
  11552. }
  11553. function homepageRecent(type, timeout) {
  11554. var timeout =
  11555. typeof timeout !== "undefined"
  11556. ? timeout
  11557. : activeInfo.settings.homepage.refresh.homepageRecentRefresh;
  11558. switch (type) {
  11559. case "plex":
  11560. var action = "getPlexRecent";
  11561. break;
  11562. case "emby":
  11563. case "jellyfin":
  11564. var action = "getEmbyRecent";
  11565. break;
  11566. default:
  11567. }
  11568. organizrAPI2("GET", "api/v2/homepage/" + type + "/recent")
  11569. .success(function (data) {
  11570. try {
  11571. let response = data.response;
  11572. document.getElementById("homepageOrder" + type + "recent").innerHTML =
  11573. "";
  11574. $("." + type + "-recent").trigger("destroy.owl.carousel");
  11575. $("#homepageOrder" + type + "recent").html(
  11576. buildRecent(response.data, type)
  11577. );
  11578. $(".recent-items").owlCarousel({
  11579. nav: false,
  11580. autoplay: false,
  11581. dots: false,
  11582. margin: 10,
  11583. autoWidth: true,
  11584. items: 4,
  11585. });
  11586. } catch (e) {
  11587. organizrCatchError(e, data);
  11588. }
  11589. })
  11590. .fail(function (xhr) {
  11591. OrganizrApiError(xhr);
  11592. });
  11593. let timeoutTitle = type + "-Recent-Homepage";
  11594. if (typeof timeouts[timeoutTitle] !== "undefined") {
  11595. clearTimeout(timeouts[timeoutTitle]);
  11596. }
  11597. timeouts[timeoutTitle] = setTimeout(function () {
  11598. homepageRecent(type, timeout);
  11599. }, timeout);
  11600. delete timeout;
  11601. }
  11602. function homepagePlaylist(type, timeout = 30000) {
  11603. organizrAPI2("GET", "api/v2/homepage/" + type + "/playlists")
  11604. .success(function (data) {
  11605. try {
  11606. let response = data.response;
  11607. document.getElementById("homepageOrder" + type + "playlist").innerHTML =
  11608. "";
  11609. $("#homepageOrder" + type + "playlist").html(
  11610. buildPlaylist(response.data, type)
  11611. );
  11612. $(".playlist-items").owlCarousel({
  11613. nav: false,
  11614. autoplay: false,
  11615. dots: false,
  11616. margin: 10,
  11617. autoWidth: true,
  11618. items: 4,
  11619. });
  11620. } catch (e) {
  11621. organizrCatchError(e, data);
  11622. }
  11623. })
  11624. .fail(function (xhr) {
  11625. OrganizrApiError(xhr);
  11626. });
  11627. }
  11628. function defaultRequestFilter(service) {
  11629. switch (service) {
  11630. case "ombi":
  11631. var defaultFilter = {
  11632. "request-filter-approved-ombi":
  11633. activeInfo.settings.homepage.ombi.ombiDefaultFilterApproved,
  11634. "request-filter-unapproved-ombi":
  11635. activeInfo.settings.homepage.ombi.ombiDefaultFilterUnapproved,
  11636. "request-filter-available-ombi":
  11637. activeInfo.settings.homepage.ombi.ombiDefaultFilterAvailable,
  11638. "request-filter-unavailable-ombi":
  11639. activeInfo.settings.homepage.ombi.ombiDefaultFilterUnavailable,
  11640. "request-filter-denied-ombi":
  11641. activeInfo.settings.homepage.ombi.ombiDefaultFilterDenied,
  11642. };
  11643. $.each(defaultFilter, function (i, v) {
  11644. if (v == false) {
  11645. $("#" + i).click();
  11646. }
  11647. });
  11648. case "overseerr":
  11649. var defaultFilter = {
  11650. "request-filter-approved-overseerr":
  11651. activeInfo.settings.homepage.overseerr.overseerrDefaultFilterApproved,
  11652. "request-filter-unapproved-overseerr":
  11653. activeInfo.settings.homepage.overseerr
  11654. .overseerrDefaultFilterUnapproved,
  11655. "request-filter-available-overseerr":
  11656. activeInfo.settings.homepage.overseerr
  11657. .overseerrDefaultFilterAvailable,
  11658. "request-filter-unavailable-overseerr":
  11659. activeInfo.settings.homepage.overseerr
  11660. .overseerrDefaultFilterUnavailable,
  11661. "request-filter-denied-overseerr":
  11662. activeInfo.settings.homepage.overseerr.overseerrDefaultFilterDenied,
  11663. };
  11664. $.each(defaultFilter, function (i, v) {
  11665. if (v == false) {
  11666. $("#" + i).click();
  11667. }
  11668. });
  11669. }
  11670. }
  11671. function homepageRequests(service, timeout) {
  11672. switch (service) {
  11673. case "ombi":
  11674. var apiUrl = "api/v2/homepage/ombi/requests";
  11675. var div = "homepageOrderombi";
  11676. var timeout =
  11677. typeof timeout !== "undefined"
  11678. ? timeout
  11679. : activeInfo.settings.homepage.refresh.ombiRefresh;
  11680. break;
  11681. case "overseerr":
  11682. var apiUrl = "api/v2/homepage/overseerr/requests";
  11683. var div = "homepageOrderoverseerr";
  11684. var timeout =
  11685. typeof timeout !== "undefined"
  11686. ? timeout
  11687. : activeInfo.settings.homepage.refresh.overseerrRefresh;
  11688. break;
  11689. default:
  11690. return false;
  11691. }
  11692. organizrAPI2("GET", apiUrl)
  11693. .success(function (data) {
  11694. try {
  11695. let response = data.response;
  11696. document.getElementById(div).innerHTML = "";
  11697. if (response.data.content !== false) {
  11698. $("#" + div).html(buildRequest(service, div, response.data));
  11699. }
  11700. $(".request-items-" + service).owlCarousel({
  11701. nav: false,
  11702. autoplay: false,
  11703. dots: false,
  11704. margin: 10,
  11705. autoWidth: true,
  11706. items: 4,
  11707. });
  11708. // Default Filter
  11709. defaultRequestFilter(service);
  11710. } catch (e) {
  11711. organizrCatchError(e, data);
  11712. }
  11713. })
  11714. .fail(function (xhr) {
  11715. OrganizrApiError(xhr);
  11716. });
  11717. if (typeof timeouts[service + "-Requests-Homepage"] !== "undefined") {
  11718. clearTimeout(timeouts[service + "-Requests-Homepage"]);
  11719. }
  11720. timeouts[service + "-Requests-Homepage"] = setTimeout(function () {
  11721. homepageRequests(service, timeout);
  11722. }, timeout);
  11723. delete timeout;
  11724. }
  11725. function testAPIConnection(service, data = "") {
  11726. messageSingle(
  11727. "",
  11728. " Testing now...",
  11729. activeInfo.settings.notifications.position,
  11730. "#FFF",
  11731. "info",
  11732. "60000"
  11733. );
  11734. organizrAPI2("POST", "api/v2/test/" + service, data)
  11735. .success(function (data) {
  11736. try {
  11737. let response = data.response;
  11738. messageSingle(
  11739. "",
  11740. " API Connection Success",
  11741. activeInfo.settings.notifications.position,
  11742. "#FFF",
  11743. "success",
  11744. "10000"
  11745. );
  11746. } catch (e) {
  11747. organizrCatchError(e, data);
  11748. }
  11749. })
  11750. .fail(function (xhr) {
  11751. OrganizrApiError(xhr, "API Error");
  11752. });
  11753. }
  11754. function getUnifiSite() {
  11755. messageSingle(
  11756. "",
  11757. " Grabbing now...",
  11758. activeInfo.settings.notifications.position,
  11759. "#FFF",
  11760. "info",
  11761. "10000"
  11762. );
  11763. organizrAPI2("POST", "api/v2/test/unifi/site", {})
  11764. .success(function (data) {
  11765. try {
  11766. var response = data.response;
  11767. if (response.data !== false) {
  11768. var sites = "";
  11769. if (response.data.data) {
  11770. $.each(response.data.data, function (i, v) {
  11771. sites +=
  11772. '<div class="form-group row"><div class="col-sm-12"><h4 class="mouse" onclick="unifiSiteApply(\'' +
  11773. v.name +
  11774. "')\">" +
  11775. v.desc +
  11776. "</h4></div></div>";
  11777. });
  11778. } else {
  11779. //console.log('no');
  11780. }
  11781. var div =
  11782. `
  11783. <div class="row">
  11784. <div class="col-12">
  11785. <div class="card m-b-0">
  11786. <div class="form-horizontal">
  11787. <div class="card-body">
  11788. <h4 class="card-title" lang="en">Choose Unifi Site</h4>
  11789. ` +
  11790. sites +
  11791. `
  11792. </div>
  11793. </div>
  11794. </div>
  11795. </div>
  11796. </div>
  11797. `;
  11798. swal({
  11799. content: createElementFromHTML(div),
  11800. buttons: false,
  11801. className: "bg-org",
  11802. });
  11803. } else {
  11804. messageSingle(
  11805. "API Connection Failed",
  11806. response.data,
  11807. activeInfo.settings.notifications.position,
  11808. "#FFF",
  11809. "error",
  11810. "10000"
  11811. );
  11812. }
  11813. } catch (e) {
  11814. organizrCatchError(e, data);
  11815. }
  11816. })
  11817. .fail(function (xhr) {
  11818. OrganizrApiError(xhr, "API Error");
  11819. });
  11820. }
  11821. function unifiSiteApply(name) {
  11822. $("#homepage-UniFi-form [name=unifiSiteName]").val(name);
  11823. $("#homepage-UniFi-form [name=unifiSiteName]").change();
  11824. swal.close();
  11825. messageSingle(
  11826. "",
  11827. " Grabbed Site - Please Save Now",
  11828. activeInfo.settings.notifications.position,
  11829. "#FFF",
  11830. "success",
  11831. "10000"
  11832. );
  11833. }
  11834. function homepageCalendar(timeout) {
  11835. var timeout =
  11836. typeof timeout !== "undefined"
  11837. ? timeout
  11838. : activeInfo.settings.homepage.refresh.calendarRefresh;
  11839. if (activeInfo.settings.homepage.options.alternateHomepageHeaders) {
  11840. $(".fc-toolbar").addClass("fc-alternate");
  11841. }
  11842. organizrAPI2("GET", "api/v2/homepage/calendar")
  11843. .success(function (data) {
  11844. try {
  11845. let response = data.response;
  11846. $("#calendar").fullCalendar("removeEvents");
  11847. $("#calendar").fullCalendar("addEventSource", response.data.events);
  11848. $("#calendar").fullCalendar("addEventSource", response.data.ical);
  11849. $("#calendar").fullCalendar("today");
  11850. } catch (e) {
  11851. organizrCatchError(e, data);
  11852. }
  11853. })
  11854. .fail(function (xhr) {
  11855. OrganizrApiError(xhr);
  11856. });
  11857. if (typeof timeouts["calendar-Homepage"] !== "undefined") {
  11858. clearTimeout(timeouts["calendar-Homepage"]);
  11859. }
  11860. timeouts["calendar-Homepage"] = setTimeout(function () {
  11861. homepageCalendar(timeout);
  11862. }, timeout);
  11863. delete timeout;
  11864. }
  11865. function buildTautulliItem(array) {
  11866. var cards = "";
  11867. var homestats = array.homestats.data;
  11868. var libstats = array.libstats;
  11869. var options = array.options;
  11870. var friendlyName = array.options.friendlyName;
  11871. var buildLibraries = function (data) {
  11872. var libs = data.data;
  11873. var movies = [];
  11874. var tv = [];
  11875. var audio = [];
  11876. libs.forEach((e) => {
  11877. switch (e["section_type"]) {
  11878. case "movie":
  11879. movies.push(e);
  11880. break;
  11881. case "show":
  11882. tv.push(e);
  11883. break;
  11884. case "artist":
  11885. audio.push(e);
  11886. break;
  11887. default:
  11888. break;
  11889. }
  11890. });
  11891. movies = movies.sort((a, b) =>
  11892. parseInt(a["count"]) > parseInt(b["count"]) ? -1 : 1
  11893. );
  11894. tv = tv.sort((a, b) =>
  11895. parseInt(a["count"]) > parseInt(b["count"]) ? -1 : 1
  11896. );
  11897. audio = audio.sort((a, b) =>
  11898. parseInt(a["count"]) > parseInt(b["count"]) ? -1 : 1
  11899. );
  11900. var buildCard = function (type, data) {
  11901. var extraField = null;
  11902. var section_name = null;
  11903. if (type == "movie") {
  11904. extraField = "Movies";
  11905. section_name = "Movie Libraries";
  11906. } else if (type == "show") {
  11907. extraField = "Shows/Seasons/Episodes";
  11908. section_name = "TV Show Libraries";
  11909. } else if (type == "artist") {
  11910. extraField = "Artists/Albums/Tracks";
  11911. section_name = "Music Libraries";
  11912. }
  11913. var cardTitle =
  11914. '<th><span class="pull-left cardTitle">' +
  11915. section_name.toUpperCase() +
  11916. '</span><span class="pull-right cardCountType">' +
  11917. extraField.toUpperCase() +
  11918. "</th>";
  11919. var card =
  11920. `
  11921. <div class="col-lg-4 col-md-6 col-sm-12 col-xs-12">
  11922. <div class="card text-white mb-3 homepage-tautulli-card library-card">
  11923. <div class="card-body h-100 bg-org-alt">
  11924. <table class="h-100 w-100">
  11925. <tr>
  11926. <td rowspan='2' class="poster-td text-center"><img src="data/cache/tautulli-` +
  11927. type +
  11928. `.svg" class="lib-icon" alt="library icon"></td>
  11929. ${cardTitle}
  11930. </tr>
  11931. <tr>
  11932. <td>
  11933. <div class="scrollable default-scroller">`;
  11934. for (var i = 0; i < data.length; i++) {
  11935. var rowType =
  11936. i == 0
  11937. ? "tautulliFirstItem"
  11938. : i == data.length - 1
  11939. ? "tautulliLastItem"
  11940. : "";
  11941. var rowValue = "";
  11942. var firstDivCol = "";
  11943. var secondDivCol = "";
  11944. if (type == "movie") {
  11945. rowValue = data[i]["count"];
  11946. firstDivCol = "col-md-9";
  11947. secondDivCol = "col-md-2";
  11948. } else {
  11949. rowValue =
  11950. data[i]["count"] +
  11951. '<span class="tautulliSeparator"> / </span>' +
  11952. data[i]["parent_count"] +
  11953. '<span class="tautulliSeparator"> / </span>' +
  11954. data[i]["child_count"];
  11955. firstDivCol = "col-md-5";
  11956. secondDivCol = "col-md-6";
  11957. }
  11958. card += `
  11959. <div class="cardListItem elip row w-100 p-r-0 m-0 ${rowType}">
  11960. <div class="tautulliRank col-md-1 p-0">${
  11961. i + 1
  11962. }</div>
  11963. <div class="${firstDivCol} p-0 text-left elip"> ${
  11964. data[i]["section_name"]
  11965. }</div>
  11966. <div class="${secondDivCol} cardListCount text-right m-l-10 p-0">${rowValue}</div>
  11967. </div>
  11968. `;
  11969. }
  11970. card += `
  11971. </div>
  11972. </td>
  11973. </tr>
  11974. </table>
  11975. </div>
  11976. </div>
  11977. </div>`;
  11978. return card;
  11979. };
  11980. var card = movies.length > 0 ? buildCard("movie", movies) : "";
  11981. card += tv.length > 0 ? buildCard("show", tv) : "";
  11982. card += audio.length > 0 ? buildCard("artist", audio) : "";
  11983. return card;
  11984. };
  11985. var buildStats = function (data, stat, friendlyName = true) {
  11986. var card = "";
  11987. data.forEach((e) => {
  11988. let classes = "";
  11989. if (e["stat_id"] == stat && e["rows"].length > 0) {
  11990. if (stat === "top_platforms") {
  11991. classes = " platform-" + e["rows"][0]["platform_name"] + "-rgba";
  11992. } else {
  11993. classes = " bg-org-alt";
  11994. }
  11995. card += `
  11996. <div class="col-xl-3 col-lg-4 col-md-6 col-sm-12 col-xs-12">
  11997. <div class="card text-white mb-3 homepage-tautulli-card">`;
  11998. if (stat !== "top_users" && stat !== "top_platforms") {
  11999. card +=
  12000. `
  12001. <div class="bg-img-cont">
  12002. <img class="bg-img" src="` +
  12003. e["rows"][0]["art"] +
  12004. `" alt="background art">
  12005. </div>
  12006. `;
  12007. }
  12008. card +=
  12009. `
  12010. <div class="card-body h-100` +
  12011. classes +
  12012. `">
  12013. <table class="h-100 w-100">
  12014. <tr>`;
  12015. if (stat == "top_users") {
  12016. card +=
  12017. `<td rowspan="2" class="poster-td text-center"><img src="` +
  12018. e["rows"][0]["user_thumb"] +
  12019. `" class="poster avatar" alt="user avatar"></td>`;
  12020. } else if (stat == "top_platforms") {
  12021. card +=
  12022. `<td rowspan="2" class="poster-td text-center"><img src="data/cache/tautulli-` +
  12023. e["rows"][0]["platform_name"] +
  12024. `.svg" class="poster" alt="platform icon"></td>`;
  12025. } else {
  12026. card +=
  12027. `<td rowspan="2" class="poster-td"><img src="` +
  12028. e["rows"][0]["thumb"] +
  12029. `" class="poster" alt="movie poster"></td>`;
  12030. }
  12031. var extraField = null;
  12032. if (e["stat_title"].includes("Popular")) {
  12033. extraField = "users";
  12034. } else if (
  12035. e["stat_title"].includes("Watched") ||
  12036. e["stat_title"].includes("Active")
  12037. ) {
  12038. extraField = "plays";
  12039. }
  12040. var cardTitle =
  12041. '<th><span class="pull-left cardTitle">' +
  12042. e["stat_title"].toUpperCase() +
  12043. '</span><span class="pull-right cardCountType">' +
  12044. extraField.toUpperCase() +
  12045. "</th>";
  12046. card +=
  12047. cardTitle +
  12048. `
  12049. </tr>
  12050. <tr>
  12051. <td><div class="scrollable default-scroller">`;
  12052. for (var i = 0; i < e["rows"].length; i++) {
  12053. var item = e["rows"][i];
  12054. var rowType =
  12055. i == 0
  12056. ? "tautulliFirstItem"
  12057. : i == e["rows"].length - 1
  12058. ? "tautulliLastItem"
  12059. : "";
  12060. var rowNameValue = "";
  12061. var rowValue = "";
  12062. if (stat == "top_users") {
  12063. if (friendlyName) {
  12064. rowNameValue = item["friendly_name"];
  12065. } else {
  12066. rowNameValue = item["user"];
  12067. }
  12068. rowValue = item["total_plays"];
  12069. } else if (stat == "top_platforms") {
  12070. rowNameValue = item["platform"];
  12071. rowValue = item["total_plays"];
  12072. } else if (extraField == "users") {
  12073. rowNameValue = item["title"];
  12074. rowValue = item["users_watched"];
  12075. } else {
  12076. rowNameValue = item["title"];
  12077. rowValue = item["total_plays"];
  12078. }
  12079. card += `
  12080. <div class="cardListItem elip row w-100 p-r-0 m-0 ${rowType}">
  12081. <div class="tautulliRank col-md-1 p-0">${
  12082. i + 1
  12083. }</div>
  12084. <div class="col-md-9 p-0 text-left elip">${rowNameValue}</div>
  12085. <div class="col-md-2 cardListCount text-right m-l-10 p-0">${rowValue}</div>
  12086. </div>`;
  12087. }
  12088. card += `
  12089. </div></td>
  12090. </tr>
  12091. </table>
  12092. </div>
  12093. </div>
  12094. </div>`;
  12095. } else {
  12096. return "";
  12097. }
  12098. });
  12099. return card;
  12100. };
  12101. cards += '<div class="row tautulliTop">';
  12102. cards += options["libraries"] ? buildLibraries(libstats) : "";
  12103. cards += options["popularMovies"]
  12104. ? buildStats(homestats, "popular_movies")
  12105. : "";
  12106. cards += options["popularTV"] ? buildStats(homestats, "popular_tv") : "";
  12107. cards += options["topMovies"] ? buildStats(homestats, "top_movies") : "";
  12108. cards += options["topTV"] ? buildStats(homestats, "top_tv") : "";
  12109. cards += options["topUsers"]
  12110. ? buildStats(homestats, "top_users", friendlyName)
  12111. : "";
  12112. cards += options["topPlatforms"]
  12113. ? buildStats(homestats, "top_platforms")
  12114. : "";
  12115. cards += "</div>";
  12116. cards += '<div class="row tautulliLibraries">';
  12117. cards += "</div>";
  12118. return cards;
  12119. }
  12120. function buildTautulli(array) {
  12121. if (array === false) {
  12122. return "";
  12123. }
  12124. var html = `
  12125. <div id="allTautulli">
  12126. <div class="el-element-overlay row">`;
  12127. if (array["options"]["title"]) {
  12128. html +=
  12129. `
  12130. <div class="col-md-12">
  12131. <h4 class="pull-left homepage-element-title"><span class="mouse" onclick="homepageTautulli()">` +
  12132. activeInfo.settings.homepage.options.titles.tautulli +
  12133. `</span> : </h4><h4 class="pull-left">&nbsp;</h4>
  12134. <hr class="hidden-xs ml-2">
  12135. </div>
  12136. <div class="clearfix"></div>
  12137. `;
  12138. }
  12139. html +=
  12140. `
  12141. <div class="tautulliCards col-sm-12 my-3">
  12142. ` +
  12143. buildTautulliItem(array) +
  12144. `
  12145. </div>
  12146. </div>
  12147. </div>
  12148. `;
  12149. return array ? html : "";
  12150. }
  12151. function homepageTautulli(timeout) {
  12152. var timeout =
  12153. typeof timeout !== "undefined"
  12154. ? timeout
  12155. : activeInfo.settings.homepage.refresh.homepageTautulliRefresh;
  12156. organizrAPI2("GET", "api/v2/homepage/tautulli/data")
  12157. .success(function (data) {
  12158. try {
  12159. let response = data.response;
  12160. document.getElementById("homepageOrdertautulli").innerHTML = "";
  12161. if (response.data !== null) {
  12162. $("#homepageOrdertautulli").html(buildTautulli(response.data));
  12163. }
  12164. } catch (e) {
  12165. organizrCatchError(e, data);
  12166. }
  12167. })
  12168. .fail(function (xhr) {
  12169. OrganizrApiError(xhr);
  12170. });
  12171. let timeoutTitle = "Tautulli-Homepage";
  12172. if (typeof timeouts[timeoutTitle] !== "undefined") {
  12173. clearTimeout(timeouts[timeoutTitle]);
  12174. }
  12175. timeouts[timeoutTitle] = setTimeout(function () {
  12176. homepageTautulli(timeout);
  12177. }, timeout);
  12178. delete timeout;
  12179. }
  12180. function weatherIcon(code, daytime = true) {
  12181. switch (code) {
  12182. case 1:
  12183. case 2:
  12184. return daytime ? "wi-day-sunny" : "wi-night-clear";
  12185. case 3:
  12186. case 4:
  12187. case 5:
  12188. case 6:
  12189. case 22:
  12190. return daytime ? "wi-day-sunny-overcast" : "wi-night-alt-partly-cloudy";
  12191. case 7:
  12192. case 8:
  12193. case 9:
  12194. return daytime ? "wi-day-cloudy-high" : "wi-night-partly-cloudy";
  12195. case 10:
  12196. case 11:
  12197. case 12:
  12198. return daytime ? "wi-day-thunderstorm" : "wi-night-thunderstorm";
  12199. case 13:
  12200. case 14:
  12201. case 15:
  12202. return daytime ? "wi-day-haze" : "wi-night-cloudy-windy";
  12203. case 16:
  12204. case 17:
  12205. case 18:
  12206. return daytime ? "wi-day-fog" : "wi-night-fog";
  12207. case 19:
  12208. case 20:
  12209. case 21:
  12210. return daytime ? "wi-day-cloudy-high" : "wi-night-cloudy-high";
  12211. case 23:
  12212. case 25:
  12213. return daytime ? "wi-day-rain" : "wi-night-rain";
  12214. case 24:
  12215. case 26:
  12216. return daytime ? "wi-day-snow" : "wi-night-snow";
  12217. case 27:
  12218. case 28:
  12219. case 30:
  12220. case 31:
  12221. case 33:
  12222. return daytime ? "wi-day-rain-mix" : "wi-night-alt-rain-mix";
  12223. case 29:
  12224. case 32:
  12225. case 34:
  12226. case 35:
  12227. return daytime
  12228. ? "wi-day-snow-thunderstorm"
  12229. : "wi-night-alt-snow-thunderstorm";
  12230. default:
  12231. return daytime ? "wi-day-sunny" : "wi-night-clear";
  12232. }
  12233. }
  12234. function buildWeatherAndAir(array) {
  12235. var returnData = "";
  12236. if (typeof array.content === "undefined") {
  12237. return "";
  12238. }
  12239. if (array.content.weather !== false) {
  12240. if (array.content.weather.error === null) {
  12241. let dates = {};
  12242. $.each(array.content.weather.data, function (i, v) {
  12243. let date = moment(v.datetime).format("YYYY-MM-DD");
  12244. if (typeof dates[date] === "undefined") {
  12245. dates[date] = v;
  12246. dates[date]["temps"] = {
  12247. high: v.temperature.value,
  12248. low: v.temperature.value,
  12249. };
  12250. } else {
  12251. if (moment(v.datetime).format("hh:mm a") == "12:00 pm") {
  12252. dates[date]["icon_code"] = v.icon_code;
  12253. dates[date]["is_day_time"] = v.is_day_time;
  12254. }
  12255. if (v.temperature.value > dates[date]["temps"]["high"]) {
  12256. dates[date]["temps"]["high"] = v.temperature.value;
  12257. }
  12258. if (v.temperature.value < dates[date]["temps"]["low"]) {
  12259. dates[date]["temps"]["low"] = v.temperature.value;
  12260. }
  12261. }
  12262. });
  12263. let weatherItems = '<div class="row">';
  12264. let weatherItemsCount = 0;
  12265. $.each(dates, function (i, v) {
  12266. if (weatherItemsCount === 0) {
  12267. weatherItems +=
  12268. `
  12269. <div class="col-lg-4 col-sm-12 col-xs-12">
  12270. <div class="white-box">
  12271. <h3 class="box-title"><small class="pull-right m-t-10">Feels Like ` +
  12272. Math.round(v.feels_like_temperature.value) +
  12273. `°</small>` +
  12274. moment(v.datetime).format("dddd") +
  12275. `<br/><small class="text-uppercase elip">` +
  12276. v.weather_text +
  12277. `</small></h3>
  12278. <ul class="list-inline two-part" style="margin-top: -13px;">
  12279. <li><i class="wi ` +
  12280. weatherIcon(v.icon_code, v.is_day_time) +
  12281. ` text-info"></i></li>
  12282. <li class="text-right"><span class="counter">` +
  12283. Math.round(v.temperature.value) +
  12284. `<small><sup>°` +
  12285. v.temperature.units +
  12286. `</sup></small></span></li>
  12287. </ul>
  12288. <ul class="list-inline m-b-0">
  12289. <li class="pull-left w-50 hidden-xs"></li>
  12290. <li class="pull-right" style="width:75px"><small><i class="wi wi-strong-wind m-r-5 text-primary tooltip-primary" data-toggle="tooltip" data-placement="top" title="" data-original-title="Wind"></i>` +
  12291. Math.round(v.wind.speed.value) +
  12292. ` ` +
  12293. v.wind.speed.units +
  12294. `</small></li>
  12295. <li class="pull-right" style="width:75px"><small><i class="wi wi-barometer m-r-5 text-primary tooltip-primary" data-toggle="tooltip" data-placement="top" title="" data-original-title="Pressure"></i>` +
  12296. Math.round(v.pressure.value) +
  12297. ` ` +
  12298. v.pressure.units +
  12299. `</small></li>
  12300. <li class="pull-right" style="width:45px"><small><i class="wi wi-humidity m-r-5 text-primary tooltip-primary" data-toggle="tooltip" data-placement="top" title="" data-original-title="Humidity"></i>` +
  12301. Math.round(v.relative_humidity) +
  12302. `</small></li>
  12303. <li class="pull-right" style="width:45px"><small><i class="wi wi-raindrop m-r-5 text-primary tooltip-primary" data-toggle="tooltip" data-placement="top" title="" data-original-title="Dew Point"></i>` +
  12304. Math.round(v.dew_point.value) +
  12305. `°</small></li>
  12306. <div class="clearfix"></div>
  12307. </ul>
  12308. </div>
  12309. </div>
  12310. `;
  12311. } else if (weatherItemsCount !== 5) {
  12312. weatherItems +=
  12313. `
  12314. <div class="col-lg-2 col-sm-3 col-xs-12">
  12315. <div class="white-box">
  12316. <h3 class="box-title">` +
  12317. moment(v.datetime).format("dddd") +
  12318. `</h3>
  12319. <ul class="list-inline two-part">
  12320. <li><i class="wi ` +
  12321. weatherIcon(v.icon_code, v.is_day_time) +
  12322. ` text-info"></i></li>
  12323. <li class="text-right"><span class="counter">` +
  12324. Math.round(v.temps.high) +
  12325. `<small><sup>°` +
  12326. v.temperature.units +
  12327. `</sup></small></span></li>
  12328. </ul>
  12329. <ul class="list-inline m-b-0">
  12330. <li class="pull-left w-100"><small class="text-uppercase elip">` +
  12331. v.weather_text +
  12332. `</small></li>
  12333. <div class="clearfix"></div>
  12334. </ul>
  12335. </div>
  12336. </div>
  12337. `;
  12338. }
  12339. weatherItemsCount++;
  12340. });
  12341. weatherItems += "</div>";
  12342. returnData += weatherItems;
  12343. }
  12344. }
  12345. if (array.content.air !== false) {
  12346. if (array.content.air.error === null) {
  12347. let airItems = '<div class="row">';
  12348. let activeClasses = {
  12349. poor: "",
  12350. low: "",
  12351. moderate: "",
  12352. good: "",
  12353. excellent: "",
  12354. text: "",
  12355. };
  12356. if (array.content.air.data.indexes.baqi.aqi <= 20) {
  12357. activeClasses["poor"] = "active";
  12358. activeClasses["text"] = "text-poor-gradient";
  12359. } else if (array.content.air.data.indexes.baqi.aqi <= 40) {
  12360. activeClasses["low"] = "active";
  12361. activeClasses["text"] = "text-low-gradient";
  12362. } else if (array.content.air.data.indexes.baqi.aqi <= 60) {
  12363. activeClasses["moderate"] = "active";
  12364. activeClasses["text"] = "text-moderate-gradient";
  12365. } else if (array.content.air.data.indexes.baqi.aqi <= 80) {
  12366. activeClasses["good"] = "active";
  12367. activeClasses["text"] = "text-good-gradient";
  12368. } else if (array.content.air.data.indexes.baqi.aqi <= 100) {
  12369. activeClasses["excellent"] = "active";
  12370. activeClasses["text"] = "text-excellent-gradient";
  12371. }
  12372. airItems += `
  12373. <div class="col-lg-4 col-sm-12 col-xs-12">
  12374. <div class="white-box text-white">
  12375. <div class="aqi-scale-component-wrapper">
  12376. <div class="aqi__header">
  12377. <div class="aqi__value">
  12378. <div class="component-wrapper aqi-number ${
  12379. activeClasses["text"]
  12380. }">${
  12381. array.content.air.data.indexes.baqi.aqi
  12382. }</div>
  12383. </div>
  12384. <div class="aqi__text"><h2 >AirQuality Index</h2></div>
  12385. </div>
  12386. <div class="aqi-scale m-t-40">
  12387. <div class="category">
  12388. <div class="chip ${activeClasses["poor"]}">
  12389. <div class="chip__text text-white">Poor</div>
  12390. <div class="chip__bar bg-poor-gradient"></div>
  12391. </div>
  12392. <div class="category__min-value text-white">0</div>
  12393. <div class="category__max-value text-white">20</div>
  12394. </div>
  12395. <div class="category">
  12396. <div class="chip ${activeClasses["low"]}">
  12397. <div class="chip__text text-white">Low</div>
  12398. <div class="chip__bar bg-low-gradient"></div>
  12399. </div>
  12400. <div class="category__max-value text-white">40</div>
  12401. </div>
  12402. <div class="category">
  12403. <div class="chip ${activeClasses["moderate"]}">
  12404. <div class="chip__text text-white">Moderate</div>
  12405. <div class="chip__bar bg-moderate-gradient"></div>
  12406. </div>
  12407. <div class="category__max-value text-white">60</div>
  12408. </div>
  12409. <div class="category">
  12410. <div class="chip ${activeClasses["good"]}">
  12411. <div class="chip__text text-white">Good</div>
  12412. <div class="chip__bar bg-good-gradient"></div>
  12413. </div>
  12414. <div class="category__max-value text-white">80</div>
  12415. </div>
  12416. <div class="category">
  12417. <div class="chip ${activeClasses["excellent"]}">
  12418. <div class="chip__text text-white">Excellent</div>
  12419. <div class="chip__bar bg-excellent-gradient"></div>
  12420. </div>
  12421. <div class="category__max-value text-white">100</div>
  12422. </div>
  12423. </div>
  12424. </div>
  12425. </div>
  12426. </div>
  12427. ${buildPollutant(array.content.air.data.pollutants)}
  12428. ${buildHealthRecommendation(
  12429. array.content.air.data.health_recommendations
  12430. )}
  12431. `;
  12432. airItems += "</div>";
  12433. returnData += airItems;
  12434. }
  12435. }
  12436. if (array.content.pollen !== false) {
  12437. if (array.content.pollen.error === null) {
  12438. }
  12439. }
  12440. return returnData;
  12441. }
  12442. function buildHealthRecommendation(array) {
  12443. var healthHeader = "";
  12444. var healthSection = "";
  12445. $.each(array, function (i, v) {
  12446. var title = i
  12447. .toString()
  12448. .replace("_", " ")
  12449. .toLowerCase()
  12450. .split(" ")
  12451. .map((word) => word.charAt(0).toUpperCase() + word.substring(1))
  12452. .join(" ");
  12453. switch (i) {
  12454. case "general_population":
  12455. var icon = "fa fa-group";
  12456. break;
  12457. case "elderly":
  12458. var icon = "ti ti-wheelchair";
  12459. break;
  12460. case "lung_diseases":
  12461. var icon = "mdi mdi-spray";
  12462. break;
  12463. case "heart_diseases":
  12464. var icon = "mdi mdi-heart-pulse";
  12465. break;
  12466. case "active":
  12467. var icon = "mdi mdi-run-fast";
  12468. break;
  12469. case "pregnant_women":
  12470. var icon = "mdi mdi-human-pregnant";
  12471. break;
  12472. case "children":
  12473. var icon = "fa fa-child";
  12474. break;
  12475. default:
  12476. var icon = "";
  12477. }
  12478. healthHeader +=
  12479. '<li><a href="#section-health-' +
  12480. i +
  12481. '" class="sticon ' +
  12482. icon +
  12483. '"></a></li>';
  12484. healthSection += `
  12485. <section id="section-pollutant-${i}" class="" >
  12486. <h5 class="m-t-0">${title}</h5>
  12487. <span>${v}</span>
  12488. </section>
  12489. `;
  12490. });
  12491. var html = `
  12492. <div class="col-lg-4 hidden-xs hidden-sm">
  12493. <div class="white-box text-white p-0">
  12494. <!-- Tabstyle start -->
  12495. <section class="">
  12496. <div class="sttabs sttabs-main-weather-health-div tabs-style-iconbox">
  12497. <nav>
  12498. <ul>${healthHeader}</ul>
  12499. </nav>
  12500. <div class="content-wrap health-and-pollutant-section default-scroller">${healthSection}</div>
  12501. <!-- /content -->
  12502. </div>
  12503. <!-- /tabs -->
  12504. </section>
  12505. <!-- Tabstyle start -->
  12506. </div>
  12507. </div>
  12508. <script>
  12509. (function() {
  12510. [].slice.call(document.querySelectorAll('.sttabs-main-weather-health-div')).forEach(function(el) {
  12511. new CBPFWTabs(el);
  12512. });
  12513. })();
  12514. </script>`;
  12515. return html;
  12516. }
  12517. function buildPollutant(array) {
  12518. var pollutantHeader = "";
  12519. var pollutantSection = "";
  12520. $.each(array, function (i, v) {
  12521. pollutantHeader +=
  12522. '<li><a href="#section-pollutant-' +
  12523. i +
  12524. '" class="sticon"><strong>' +
  12525. v.display_name +
  12526. '</strong><br/><small class="elip">' +
  12527. v.concentration.value +
  12528. " " +
  12529. v.concentration.units +
  12530. "</small></a></li>";
  12531. pollutantSection += `
  12532. <section id="section-pollutant-${i}">
  12533. <h5 class="m-t-0">${v.full_name}</h5>
  12534. <h6>Sources</h6>
  12535. <span>${v.sources_and_effects.sources}</span>
  12536. <hr>
  12537. <h6>Effects</h6>
  12538. <span>${v.sources_and_effects.effects}</span>
  12539. </section>
  12540. `;
  12541. });
  12542. var html = `
  12543. <div class="col-lg-4 hidden-xs hidden-sm">
  12544. <div class="white-box text-white p-0">
  12545. <!-- Tabstyle start -->
  12546. <section class="">
  12547. <div class="sttabs sttabs-main-weather-pollutant-div tabs-style-iconbox">
  12548. <nav>
  12549. <ul>${pollutantHeader}</ul>
  12550. </nav>
  12551. <div class="content-wrap health-and-pollutant-section default-scroller">${pollutantSection}</div>
  12552. <!-- /content -->
  12553. </div>
  12554. <!-- /tabs -->
  12555. </section>
  12556. <!-- Tabstyle start -->
  12557. </div>
  12558. </div>
  12559. <script>
  12560. (function() {
  12561. [].slice.call(document.querySelectorAll('.sttabs-main-weather-pollutant-div')).forEach(function(el) {
  12562. new CBPFWTabs(el);
  12563. });
  12564. })();
  12565. </script>`;
  12566. return html;
  12567. }
  12568. function homepageWeatherAndAir(timeout) {
  12569. var timeout =
  12570. typeof timeout !== "undefined"
  12571. ? timeout
  12572. : activeInfo.settings.homepage.refresh.homepageWeatherAndAirRefresh;
  12573. organizrAPI2("GET", "api/v2/homepage/weather/data")
  12574. .success(function (data) {
  12575. try {
  12576. let response = data.response;
  12577. if (response.data !== null) {
  12578. document.getElementById("homepageOrderWeatherAndAir").innerHTML = "";
  12579. $("#homepageOrderWeatherAndAir").html(
  12580. buildWeatherAndAir(response.data)
  12581. );
  12582. }
  12583. } catch (e) {
  12584. organizrCatchError(e, data);
  12585. }
  12586. })
  12587. .fail(function (xhr) {
  12588. OrganizrApiError(xhr);
  12589. });
  12590. let timeoutTitle = "WeatherAndAir-Homepage";
  12591. if (typeof timeouts[timeoutTitle] !== "undefined") {
  12592. clearTimeout(timeouts[timeoutTitle]);
  12593. }
  12594. timeouts[timeoutTitle] = setTimeout(function () {
  12595. homepageWeatherAndAir(timeout);
  12596. }, timeout);
  12597. delete timeout;
  12598. }
  12599. function buildMonitorrItem(array) {
  12600. var cards = "";
  12601. var options = array["options"];
  12602. var services = array["services"];
  12603. var tabName = "";
  12604. var buildCard = function (name, data) {
  12605. if (data.status == true) {
  12606. var statusColor = "success";
  12607. var imageText = "fa fa-check-circle text-success";
  12608. } else if (data.status == "unresponsive") {
  12609. var statusColor = "warning animated-3 loop-animation flash";
  12610. var imageText = "fa fa-times-circle text-warning";
  12611. } else {
  12612. var statusColor = "danger animated-3 loop-animation flash";
  12613. var imageText = "fa fa-times-circle text-danger";
  12614. }
  12615. if (typeof data.link !== "undefined" && data.link.includes("#")) {
  12616. tabName = data.link.substring(data.link.indexOf("#") + 1);
  12617. console.log(tabName);
  12618. // Need to rework tabActions
  12619. monitorrLink =
  12620. '<a href="javascript:void(0)" onclick="tabActions(event,\'' +
  12621. tabName +
  12622. "',1)\">";
  12623. } else if (typeof data.link !== "undefined") {
  12624. monitorrLink = '<a href="' + data.link + '" target="_blank">';
  12625. }
  12626. if (options["compact"]) {
  12627. var card =
  12628. `
  12629. <div class="col-xl-2 col-lg-3 col-md-4 col-sm-6 col-xs-12">
  12630. <div class="card bg-inverse text-white mb-3 monitorr-card">
  12631. <div class="card-body bg-org-alt pt-1 pb-1">
  12632. <div class="d-flex no-block align-items-center">
  12633. <div class="left-health bg-` +
  12634. statusColor +
  12635. `"></div>
  12636. <div class="ml-1 w-100">
  12637. <i class="` +
  12638. imageText +
  12639. ` font-20 pull-right mt-3 mb-2"></i>
  12640. `;
  12641. if (typeof data.link !== "undefined") {
  12642. card += monitorrLink;
  12643. }
  12644. card +=
  12645. `<h3 class="d-flex no-block align-items-center mt-2 mb-2"><img class="lazyload loginTitle" src="` +
  12646. data.image +
  12647. `">&nbsp;` +
  12648. name +
  12649. `</h3>
  12650. `;
  12651. if (typeof data.link !== "undefined") {
  12652. card += `</a>`;
  12653. }
  12654. card += `<div class="clearfix"></div>
  12655. </div>
  12656. </div>
  12657. </div>
  12658. </div>
  12659. </div>`;
  12660. } else {
  12661. var card = `
  12662. <div class="col-lg-2 col-md-3 col-sm-4 col-xs-6">
  12663. <div class="card bg-inverse text-white mb-3 monitorr-card">
  12664. <div class="card-body bg-org-alt text-center">
  12665. `;
  12666. if (typeof data.link !== "undefined") {
  12667. card += `<a href="` + data.link + `" target="_blank">`;
  12668. }
  12669. card +=
  12670. `<div class="d-block">
  12671. <h3 class="mt-0 mb-3">` +
  12672. name +
  12673. `</h3>
  12674. <img class="monitorrImage" src="` +
  12675. data.image +
  12676. `" alt="service icon">
  12677. </div>
  12678. <div class="d-inline-block mt-4 py-2 px-4 badge indicator bg-` +
  12679. statusColor +
  12680. `">
  12681. <p class="mb-0">`;
  12682. if (data.status == true) {
  12683. card += "ONLINE";
  12684. } else if (data.status == "unresponsive") {
  12685. card += "UNRESPONSIVE";
  12686. } else {
  12687. card += "OFFLINE";
  12688. }
  12689. card += `</p>
  12690. </div>
  12691. `;
  12692. if (typeof data.link !== "undefined") {
  12693. card += `</a>`;
  12694. }
  12695. card += `</div>
  12696. </div>
  12697. </div>
  12698. `;
  12699. }
  12700. return card;
  12701. };
  12702. for (var key in services) {
  12703. cards += buildCard(key, services[key]);
  12704. }
  12705. return cards;
  12706. }
  12707. function buildMonitorr(array) {
  12708. if (array === false) {
  12709. return "";
  12710. }
  12711. if (array.error != undefined) {
  12712. organizrConsole("Monitorr Function", array.error, "error");
  12713. } else {
  12714. var services =
  12715. typeof array.services !== "undefined"
  12716. ? Object.keys(array.services).length
  12717. : false;
  12718. var html = `
  12719. <div id="allMonitorr">
  12720. <div class="el-element-overlay row">`;
  12721. if (array["options"]["titleToggle"]) {
  12722. html +=
  12723. `
  12724. <div class="col-md-12">
  12725. <h4 class="pull-left homepage-element-title"><span lang="en">` +
  12726. array["options"]["title"] +
  12727. `</span> : </h4><h4 class="pull-left">&nbsp;<span class="label label-info m-l-20 checkbox-circle good-monitorr-services mouse" onclick="homepageMonitorr()">` +
  12728. services +
  12729. `</span></h4></h4>
  12730. <hr class="hidden-xs ml-2">
  12731. </div>
  12732. <div class="clearfix"></div>
  12733. `;
  12734. }
  12735. html +=
  12736. `
  12737. <div class="monitorrCards">
  12738. ` +
  12739. buildMonitorrItem(array) +
  12740. `
  12741. </div>
  12742. </div>
  12743. </div>
  12744. <div class="clearfix"></div>
  12745. `;
  12746. }
  12747. return array ? html : "";
  12748. }
  12749. function homepageMonitorr(timeout) {
  12750. var timeout =
  12751. typeof timeout !== "undefined"
  12752. ? timeout
  12753. : activeInfo.settings.homepage.refresh.homepagePiholeRefresh;
  12754. organizrAPI2("GET", "api/v2/homepage/monitorr/data")
  12755. .success(function (data) {
  12756. try {
  12757. let response = data.response;
  12758. document.getElementById("homepageOrderMonitorr").innerHTML = "";
  12759. if (response.data !== null) {
  12760. buildMonitorr(response.data);
  12761. $("#homepageOrderMonitorr").html(buildMonitorr(response.data));
  12762. }
  12763. } catch (e) {
  12764. organizrCatchError(e, data);
  12765. }
  12766. })
  12767. .fail(function (xhr) {
  12768. OrganizrApiError(xhr);
  12769. });
  12770. let timeoutTitle = "Monitorr-Homepage";
  12771. if (typeof timeouts[timeoutTitle] !== "undefined") {
  12772. clearTimeout(timeouts[timeoutTitle]);
  12773. }
  12774. timeouts[timeoutTitle] = setTimeout(function () {
  12775. homepageMonitorr(timeout);
  12776. }, timeout);
  12777. delete timeout;
  12778. }
  12779. function buildUptimeKumaItem(array) {
  12780. var cards = "";
  12781. var options = array["options"];
  12782. var services = array["data"];
  12783. var tabName = "";
  12784. var buildCard = function (name, data) {
  12785. if (data.status == true) {
  12786. var statusColor = "success";
  12787. var imageText = "fa fa-check-circle text-success";
  12788. } else {
  12789. var statusColor = "danger animated-3 loop-animation flash";
  12790. var imageText = "fa fa-times-circle text-danger";
  12791. }
  12792. tabName = data.name;
  12793. kumaLink =
  12794. '<a href="javascript:void(0)" onclick="tabActions(event,\'' +
  12795. tabName +
  12796. "',1)\">";
  12797. if (options["compact"]) {
  12798. var card =
  12799. `
  12800. <div class="col-xl-2 col-lg-3 col-md-4 col-sm-6 col-xs-12">
  12801. <div class="card bg-inverse text-white mb-3 monitorr-card">
  12802. <div class="card-body bg-org-alt pt-1 pb-1">
  12803. <div class="d-flex no-block align-items-center">
  12804. <div class="left-health bg-` +
  12805. statusColor +
  12806. `"></div>
  12807. <div class="ml-1 w-100">
  12808. <i class="` +
  12809. imageText +
  12810. ` font-20 pull-right mt-3 mb-2"></i>
  12811. `;
  12812. if (typeof data.url !== "undefined") {
  12813. card += kumaLink;
  12814. }
  12815. card +=
  12816. `<h3 class="d-flex no-block align-items-center mt-2 mb-2"><img class="lazyload loginTitle">&nbsp;` +
  12817. data.name;
  12818. if (data.latency != null && options.showLatency) {
  12819. card +=
  12820. `<span class="ml-3 font-12 align-self-center text-dark">` +
  12821. data.latency +
  12822. `ms</span></h3>`;
  12823. }
  12824. card += `</h3>`;
  12825. if (typeof data.url !== "undefined") {
  12826. card += `</a>`;
  12827. }
  12828. card += `<div class="clearfix"></div>
  12829. </div>
  12830. </div>
  12831. </div>
  12832. </div>
  12833. </div>`;
  12834. } else {
  12835. var card = `
  12836. <div class="col-lg-2 col-md-3 col-sm-4 col-xs-6">
  12837. <div class="card bg-inverse text-white mb-3 monitorr-card">
  12838. <div class="card-body bg-org-alt text-center">
  12839. `;
  12840. if (typeof data.url !== "undefined") {
  12841. card += `<a href="` + data.url + `" target="_blank">`;
  12842. }
  12843. card +=
  12844. `<div class="d-block">
  12845. <h3 class="mt-0 mb-2">` +
  12846. data.name +
  12847. `</h3>`;
  12848. if (data.latency != null && options.showLatency) {
  12849. card += `<p class="text-dark mb-0">` + data.latency + `ms</p>`;
  12850. }
  12851. card +=
  12852. `</div>
  12853. <div class="d-inline-block mt-4 py-2 px-4 badge indicator bg-` +
  12854. statusColor +
  12855. `">
  12856. <p class="mb-0">`;
  12857. if (data.status == true) {
  12858. card += "ONLINE";
  12859. } else {
  12860. card += "OFFLINE";
  12861. }
  12862. card += `</p>
  12863. </div>
  12864. `;
  12865. if (typeof data.url !== "undefined") {
  12866. card += `</a>`;
  12867. }
  12868. card += `</div>
  12869. </div>
  12870. </div>
  12871. `;
  12872. }
  12873. return card;
  12874. };
  12875. for (var key in services) {
  12876. cards += buildCard(key, services[key]);
  12877. }
  12878. return cards;
  12879. }
  12880. function buildUptimeKuma(array) {
  12881. if (array === false) {
  12882. return "";
  12883. }
  12884. if (array.error != undefined) {
  12885. organizrConsole("Uptime Kuma Function", array.error, "error");
  12886. } else {
  12887. var html = `
  12888. <div id="allUptimeKuma">
  12889. <div class="el-element-overlay row">`;
  12890. if (array["options"]["titleToggle"]) {
  12891. html +=
  12892. `
  12893. <div class="col-md-12">
  12894. <h4 class="pull-left homepage-element-title"><span lang="en">` +
  12895. array["options"]["title"] +
  12896. `</span> : </h4>
  12897. <hr class="hidden-xs ml-2">
  12898. </div>
  12899. <div class="clearfix"></div>
  12900. `;
  12901. }
  12902. html +=
  12903. `
  12904. <div class="uptimeKumaCards">
  12905. ` +
  12906. buildUptimeKumaItem(array) +
  12907. `
  12908. </div>
  12909. </div>
  12910. </div>
  12911. <div class="clearfix"></div>
  12912. `;
  12913. }
  12914. return array ? html : "";
  12915. }
  12916. function homepageUptimeKuma(timeout) {
  12917. var timeout =
  12918. typeof timeout !== "undefined"
  12919. ? timeout
  12920. : activeInfo.settings.homepage.refresh.homepageUptimeKumaRefresh;
  12921. organizrAPI2("GET", "api/v2/homepage/kuma/data")
  12922. .success(function (data) {
  12923. try {
  12924. let response = data.response;
  12925. document.getElementById("homepageOrderUptimeKuma").innerHTML = "";
  12926. if (response.data !== null) {
  12927. buildUptimeKuma(response.data);
  12928. $("#homepageOrderUptimeKuma").html(buildUptimeKuma(response.data));
  12929. }
  12930. } catch (e) {
  12931. console.log(e);
  12932. organizrCatchError(e, data);
  12933. }
  12934. })
  12935. .fail(function (xhr) {
  12936. OrganizrApiError(xhr);
  12937. });
  12938. let timeoutTitle = "UptimeKuma-Homepage";
  12939. if (typeof timeouts[timeoutTitle] !== "undefined") {
  12940. clearTimeout(timeouts[timeoutTitle]);
  12941. }
  12942. timeouts[timeoutTitle] = setTimeout(function () {
  12943. homepageUptimeKuma(timeout);
  12944. }, timeout);
  12945. delete timeout;
  12946. }
  12947. function buildPromPageItem(array) {
  12948. var cards = "";
  12949. var options = array["options"];
  12950. var services = array["data"];
  12951. var tabName = "";
  12952. console.log(options);
  12953. var buildCard = function (name, data) {
  12954. if (data.status == true) {
  12955. var statusColor = "success";
  12956. var imageText = "fa fa-check-circle text-success";
  12957. } else {
  12958. var statusColor = "danger animated-3 loop-animation flash";
  12959. var imageText = "fa fa-times-circle text-danger";
  12960. }
  12961. tabName = data.name;
  12962. if (options["compact"]) {
  12963. var card =
  12964. `
  12965. <div class="col-xl-2 col-lg-3 col-md-4 col-sm-6 col-xs-12">
  12966. <div class="card bg-inverse text-white mb-3 monitorr-card">
  12967. <div class="card-body bg-org-alt pt-1 pb-1">
  12968. <div class="d-flex no-block align-items-center">
  12969. <div class="left-health bg-` +
  12970. statusColor +
  12971. `"></div>
  12972. <div class="ml-1 w-100">
  12973. <i class="` +
  12974. imageText +
  12975. ` font-20 pull-right mt-3 mb-2"></i>
  12976. `;
  12977. card +=
  12978. `<h3 class="d-flex no-block align-items-center mt-2 mb-2"><img class="lazyload loginTitle">&nbsp;` +
  12979. data.name;
  12980. if (data.uptime != null && options.showUptime) {
  12981. card +=
  12982. `<span class="ml-3 font-12 align-self-center text-dark">` +
  12983. Math.round(data.uptime * 100) / 100 +
  12984. `%</span></h3>`;
  12985. }
  12986. card += `</h3>`;
  12987. card += `<div class="clearfix"></div>
  12988. </div>
  12989. </div>
  12990. </div>
  12991. </div>
  12992. </div>`;
  12993. } else {
  12994. var card = `
  12995. <div class="col-lg-2 col-md-3 col-sm-4 col-xs-6">
  12996. <div class="card bg-inverse text-white mb-3 monitorr-card">
  12997. <div class="card-body bg-org-alt text-center">
  12998. `;
  12999. card +=
  13000. `<div class="d-block">
  13001. <h3 class="mt-0 mb-2">` +
  13002. data.name +
  13003. `</h3>`;
  13004. if (data.uptime != null && options.showUptime) {
  13005. card +=
  13006. `<p class="text-dark mb-0">` +
  13007. Math.round(data.uptime * 100) / 100 +
  13008. `%</p>`;
  13009. }
  13010. card +=
  13011. `</div>
  13012. <div class="d-inline-block mt-4 py-2 px-4 badge indicator bg-` +
  13013. statusColor +
  13014. `">
  13015. <p class="mb-0">`;
  13016. if (data.status == true) {
  13017. card += "UP";
  13018. } else {
  13019. card += "DOWN";
  13020. }
  13021. card += `</p>
  13022. </div>
  13023. `;
  13024. card += `</div>
  13025. </div>
  13026. </div>
  13027. `;
  13028. }
  13029. return card;
  13030. };
  13031. for (var key in services) {
  13032. cards += buildCard(key, services[key]);
  13033. }
  13034. return cards;
  13035. }
  13036. function buildPromPage(array) {
  13037. if (array === false) {
  13038. return "";
  13039. }
  13040. if (array.error != undefined) {
  13041. organizrConsole("PromPage Function", array.error, "error");
  13042. } else {
  13043. var html = `
  13044. <div id="allPromPage">
  13045. <div class="el-element-overlay row">`;
  13046. if (array["options"]["titleToggle"]) {
  13047. html +=
  13048. `
  13049. <div class="col-md-12">
  13050. <h4 class="pull-left homepage-element-title"><span lang="en">` +
  13051. array["options"]["title"] +
  13052. `</span> : </h4>
  13053. <hr class="hidden-xs ml-2">
  13054. </div>
  13055. <div class="clearfix"></div>
  13056. `;
  13057. }
  13058. html +=
  13059. `
  13060. <div class="promPageCards">
  13061. ` +
  13062. buildPromPageItem(array) +
  13063. `
  13064. </div>
  13065. </div>
  13066. </div>
  13067. <div class="clearfix"></div>
  13068. `;
  13069. }
  13070. return array ? html : "";
  13071. }
  13072. function homepagePromPage(timeout) {
  13073. var timeout =
  13074. typeof timeout !== "undefined"
  13075. ? timeout
  13076. : activeInfo.settings.homepage.refresh.homepagePromPageRefresh;
  13077. organizrAPI2("GET", "api/v2/homepage/prompage/data")
  13078. .success(function (data) {
  13079. try {
  13080. let response = data.response;
  13081. document.getElementById("homepageOrderPromPage").innerHTML = "";
  13082. if (response.data !== null) {
  13083. buildUptimeKuma(response.data);
  13084. $("#homepageOrderPromPage").html(buildPromPage(response.data));
  13085. }
  13086. } catch (e) {
  13087. console.log(e);
  13088. organizrCatchError(e, data);
  13089. }
  13090. })
  13091. .fail(function (xhr) {
  13092. OrganizrApiError(xhr);
  13093. });
  13094. let timeoutTitle = "PromPage-Homepage";
  13095. if (typeof timeouts[timeoutTitle] !== "undefined") {
  13096. clearTimeout(timeouts[timeoutTitle]);
  13097. }
  13098. timeouts[timeoutTitle] = setTimeout(function () {
  13099. homepagePromPage(timeout);
  13100. }, timeout);
  13101. delete timeout;
  13102. }
  13103. function homepageSpeedtest(timeout) {
  13104. var timeout =
  13105. typeof timeout !== "undefined"
  13106. ? timeout
  13107. : activeInfo.settings.homepage.refresh.homepageSpeedtestRefresh;
  13108. organizrAPI2("GET", "api/v2/homepage/speedtest/data")
  13109. .success(function (data) {
  13110. try {
  13111. let response = data.response;
  13112. document.getElementById("homepageOrderSpeedtest").innerHTML = "";
  13113. if (response.data !== null) {
  13114. $("#homepageOrderSpeedtest").html(buildSpeedtest(response.data));
  13115. }
  13116. } catch (e) {
  13117. organizrCatchError(e, data);
  13118. }
  13119. })
  13120. .fail(function (xhr) {
  13121. OrganizrApiError(xhr);
  13122. });
  13123. let timeoutTitle = "Speedtest-Homepage";
  13124. if (typeof timeouts[timeoutTitle] !== "undefined") {
  13125. clearTimeout(timeouts[timeoutTitle]);
  13126. }
  13127. timeouts[timeoutTitle] = setTimeout(function () {
  13128. homepageSpeedtest(timeout);
  13129. }, timeout);
  13130. delete timeout;
  13131. }
  13132. function buildSpeedtest(array) {
  13133. if (array === false) {
  13134. return "";
  13135. }
  13136. var html = `
  13137. <style>
  13138. .shadow-sm {
  13139. -webkit-box-shadow: 0 0.125rem 0.25rem rgba(0,0,0,0.075) !important;
  13140. box-shadow: 0 0.125rem 0.25rem rgba(0,0,0,0.075) !important;
  13141. }
  13142. .speedtest-card {
  13143. background-color: #2d2c2c;
  13144. }
  13145. .speedtest-card .text-success {
  13146. color: #07db71 !important;
  13147. }
  13148. .speedtest-card .text-warning {
  13149. color: #fca503 !important;
  13150. }
  13151. .speedtest-card .text-primary {
  13152. color: #3e95cd !important;
  13153. }
  13154. .speedtest-card span.icon {
  13155. font-size: 2em;
  13156. }
  13157. .speedtest-card h5 {
  13158. }
  13159. .speedtest-card h4,
  13160. .speedtest-card h3 {
  13161. font-weight: 450;
  13162. line-height: 1.2;
  13163. }
  13164. .speedtest-card .text-muted,
  13165. .speedtest-card h5 {
  13166. color: #9e9e9e !important;
  13167. }
  13168. </style>
  13169. `;
  13170. var current = array.data.current;
  13171. var average = array.data.average;
  13172. var maximum = array.data.maximum;
  13173. var minimum = array.data.minimum;
  13174. var options = array.options;
  13175. html += `
  13176. <div id="allSpeedtest">
  13177. `;
  13178. if (options.titleToggle) {
  13179. html +=
  13180. `
  13181. <div class="row">
  13182. <div class="col-sm-12">
  13183. <h4 class="pull-left homepage-element-title"><span lang="en">` +
  13184. array["options"]["title"] +
  13185. ` : </h4>
  13186. </div>
  13187. </div>
  13188. `;
  13189. }
  13190. html +=
  13191. `
  13192. <div class="row">
  13193. <div class="my-2 col-lg-4 col-md-4 col-sm-12">
  13194. <div class="card speedtest-card shadow-sm mb-3">
  13195. <div class="card-body">
  13196. <div class="d-flex align-items-center justify-content-between">
  13197. <h4>Ping</h4>
  13198. <span class="ti-pulse icon text-success" />
  13199. </div>
  13200. <div class="text-truncate">
  13201. <h3 class="d-inline">` +
  13202. parseFloat(current.ping).toFixed(1) +
  13203. `</h3>
  13204. <p class="d-inline ml-1 text-white">ms (current)</p>
  13205. </div>`;
  13206. if (average != undefined) {
  13207. html +=
  13208. `
  13209. <div class="text-truncate text-muted">
  13210. <h5 class="d-inline">` +
  13211. parseFloat(average.ping).toFixed(1) +
  13212. `</h5>
  13213. <p class="d-inline ml-1">ms (average)</p>
  13214. </div>
  13215. `;
  13216. }
  13217. if (maximum != undefined) {
  13218. html +=
  13219. `
  13220. <div class="text-truncate text-muted">
  13221. <h5 class="d-inline">` +
  13222. parseFloat(maximum.ping).toFixed(1) +
  13223. `</h5>
  13224. <p class="d-inline ml-1">ms (maximum)</p>
  13225. </div>
  13226. `;
  13227. }
  13228. if (minimum != undefined) {
  13229. html +=
  13230. `
  13231. <div class="text-truncate text-muted">
  13232. <h5 class="d-inline">` +
  13233. parseFloat(minimum.ping).toFixed(1) +
  13234. `</h5>
  13235. <p class="d-inline ml-1">ms (minimum)</p>
  13236. </div>
  13237. `;
  13238. }
  13239. html +=
  13240. ` </div>
  13241. </div>
  13242. </div>
  13243. <div class="my-2 col-lg-4 col-md-4 col-sm-12">
  13244. <div class="card speedtest-card shadow-sm mb-3">
  13245. <div class="card-body">
  13246. <div class="d-flex align-items-center justify-content-between">
  13247. <h4>Download</h4>
  13248. <span class="ti-download icon text-warning" />
  13249. </div>
  13250. <div class="text-truncate">
  13251. <h3 class="d-inline">` +
  13252. parseFloat(current.download).toFixed(1) +
  13253. `</h3>
  13254. <p class="d-inline ml-1 text-white">Mbit/s (current)</p>
  13255. </div>`;
  13256. if (average != undefined) {
  13257. html +=
  13258. `
  13259. <div class="text-truncate text-muted">
  13260. <h5 class="d-inline">` +
  13261. parseFloat(average.download).toFixed(1) +
  13262. `</h5>
  13263. <p class="d-inline ml-1">Mbit/s (average)</p>
  13264. </div>
  13265. `;
  13266. }
  13267. if (maximum != undefined) {
  13268. html +=
  13269. `
  13270. <div class="text-truncate text-muted">
  13271. <h5 class="d-inline">` +
  13272. parseFloat(maximum.download).toFixed(1) +
  13273. `</h5>
  13274. <p class="d-inline ml-1">Mbit/s (maximum)</p>
  13275. </div>
  13276. `;
  13277. }
  13278. if (minimum != undefined) {
  13279. html +=
  13280. `
  13281. <div class="text-truncate text-muted">
  13282. <h5 class="d-inline">` +
  13283. parseFloat(minimum.download).toFixed(1) +
  13284. `</h5>
  13285. <p class="d-inline ml-1">Mbit/s (minimum)</p>
  13286. </div>
  13287. `;
  13288. }
  13289. html +=
  13290. ` </div>
  13291. </div>
  13292. </div>
  13293. <div class="my-2 col-lg-4 col-md-4 col-sm-12">
  13294. <div class="card speedtest-card shadow-sm mb-3">
  13295. <div class="card-body">
  13296. <div class="d-flex align-items-center justify-content-between">
  13297. <h4>Upload</h4>
  13298. <span class="ti-upload icon text-primary" />
  13299. </div>
  13300. <div class="text-truncate">
  13301. <h3 class="d-inline">` +
  13302. parseFloat(current.upload).toFixed(1) +
  13303. `</h3>
  13304. <p class="d-inline ml-1 text-white">Mbit/s (current)</p>
  13305. </div>`;
  13306. if (average != undefined) {
  13307. html +=
  13308. `
  13309. <div class="text-truncate text-muted">
  13310. <h5 class="d-inline">` +
  13311. parseFloat(average.upload).toFixed(1) +
  13312. `</h5>
  13313. <p class="d-inline ml-1">Mbit/s (average)</p>
  13314. </div>
  13315. `;
  13316. }
  13317. if (maximum != undefined) {
  13318. html +=
  13319. `
  13320. <div class="text-truncate text-muted">
  13321. <h5 class="d-inline">` +
  13322. parseFloat(maximum.upload).toFixed(1) +
  13323. `</h5>
  13324. <p class="d-inline ml-1">Mbit/s (maximum)</p>
  13325. </div>
  13326. `;
  13327. }
  13328. if (minimum != undefined) {
  13329. html +=
  13330. `
  13331. <div class="text-truncate text-muted">
  13332. <h5 class="d-inline">` +
  13333. parseFloat(minimum.upload).toFixed(1) +
  13334. `</h5>
  13335. <p class="d-inline ml-1">Mbit/s (minimum)</p>
  13336. </div>
  13337. `;
  13338. }
  13339. html += ` </div>
  13340. </div>
  13341. </div>
  13342. </div>
  13343. </div>
  13344. `;
  13345. return array ? html : "";
  13346. }
  13347. function buildNetdataItem(array) {
  13348. var html = `
  13349. <style>
  13350. .all-netdata .easyPieChart-value {
  13351. position: absolute;
  13352. top: 77px;
  13353. width: 100%;
  13354. text-align: center;
  13355. left: 0;
  13356. font-size: 24.4625px;
  13357. font-weight: normal;
  13358. }
  13359. .all-netdata .easyPieChart-title {
  13360. position: absolute;
  13361. width: 100%;
  13362. text-align: center;
  13363. left: 0;
  13364. font-weight: bold;
  13365. }
  13366. .all-netdata .easyPieChart-units {
  13367. position: absolute;
  13368. top: 118px;
  13369. width: 100%;
  13370. text-align: center;
  13371. left: 0;
  13372. font-size: 15px;
  13373. font-weight: normal;
  13374. }
  13375. .all-netdata .gauge-chart .gauge-value {
  13376. position: relative;
  13377. width: 100%;
  13378. text-align: center;
  13379. top: 30px;
  13380. color: #dcdcdc;
  13381. font-weight: bold;
  13382. left: 0;
  13383. font-size: 26px;
  13384. }
  13385. .all-netdata .gauge-chart .gauge-title {
  13386. position: relative;
  13387. width: 100%;
  13388. text-align: center;
  13389. top: -10px;
  13390. //color: #fff;
  13391. font-weight: bold;
  13392. left: 0;
  13393. font-size: 15px;
  13394. }
  13395. .all-netdata .chart-lg .gauge-chart .gauge-value {
  13396. top: 70px;
  13397. font-size: 26px;
  13398. }
  13399. .all-netdata .chart-lg .gauge-chart .gauge-title {
  13400. top: 45px;
  13401. font-size: 15px;
  13402. }
  13403. .all-netdata .chart-md .gauge-chart .gauge-value {
  13404. top: 65px;
  13405. font-size: 26px;
  13406. }
  13407. .all-netdata .chart-md .gauge-chart .gauge-title {
  13408. top: 45px;
  13409. font-size: 15px;
  13410. }
  13411. .all-netdata .chart-sm .gauge-chart .gauge-value {
  13412. top: 65px;
  13413. font-size: 26px;
  13414. }
  13415. .all-netdata .chart-sm .gauge-chart .gauge-title {
  13416. top: 45px;
  13417. font-size: 15px;
  13418. }
  13419. .all-netdata .chart-lg,
  13420. .all-netdata .chart-md,
  13421. .all-netdata .chart-sm {
  13422. display: inline-block;
  13423. margin: 15px;
  13424. }
  13425. .all-netdata .chart-lg,
  13426. .all-netdata .chart-lg .chart {
  13427. height: 180px;
  13428. width: 180px;
  13429. }
  13430. .all-netdata .chart-md,
  13431. .all-netdata .chart-md .chart {
  13432. height: 160px;
  13433. width: 160px;
  13434. }
  13435. .all-netdata .chart-sm,
  13436. .all-netdata .chart-sm .chart {
  13437. height: 140px;
  13438. width: 140px;
  13439. }
  13440. .all-netdata .chart-lg .gauge-chart,
  13441. .all-netdata .gauge-cont.chart-lg {
  13442. //height: 300px;
  13443. width: 300px;
  13444. }
  13445. .all-netdata .chart-md .gauge-chart,
  13446. .all-netdata .gauge-cont.chart-md {
  13447. //height: 275px;
  13448. width: 275px;
  13449. }
  13450. .all-netdata .chart-sm .gauge-chart,
  13451. .all-netdata .gauge-cont.chart-sm {
  13452. //height: 250px;
  13453. width: 250px;
  13454. }
  13455. .all-netdata .chart-lg .easyPieChart-title {
  13456. top: 37px;
  13457. font-size: 15px;
  13458. }
  13459. .all-netdata .chart-md .easyPieChart-title {
  13460. top: 33px;
  13461. font-size: 13.5px;
  13462. }
  13463. .all-netdata .chart-sm .easyPieChart-title {
  13464. top: 30px;
  13465. font-size: 12px;
  13466. }
  13467. .all-netdata .chart-lg .easyPieChart-value {
  13468. top: 75px;
  13469. font-size: 24.4625px;
  13470. }
  13471. .all-netdata .chart-md .easyPieChart-value {
  13472. top: 65px;
  13473. font-size: 24.4625px;
  13474. }
  13475. .all-netdata .chart-sm .easyPieChart-value {
  13476. top: 55px;
  13477. font-size: 24.4625px;
  13478. }
  13479. .all-netdata .chart-lg .easyPieChart-units {
  13480. top: 130px;
  13481. font-size: 15px;
  13482. }
  13483. .all-netdata .chart-md .easyPieChart-units {
  13484. top: 108px;
  13485. font-size: 15px;
  13486. }
  13487. .all-netdata .chart-sm .easyPieChart-units {
  13488. top: 95px;
  13489. font-size: 15px;
  13490. }
  13491. </style>
  13492. `;
  13493. var buildEasyPieChart = function (e, i, size, easySize, display) {
  13494. return (
  13495. `
  13496. <div class="chart-` +
  13497. size +
  13498. ` my-3 text-center ` +
  13499. display +
  13500. `">
  13501. <div class="chart" id="easyPieChart` +
  13502. (i + 1) +
  13503. `" data-percent="` +
  13504. e.percent +
  13505. `">
  13506. <span class="easyPieChart-title">` +
  13507. e.title +
  13508. `</span>
  13509. <span class="easyPieChart-value" id="easyPieChart` +
  13510. (i + 1) +
  13511. `Value">` +
  13512. parseFloat(e.value).toFixed(1) +
  13513. `</span>
  13514. <span class="easyPieChart-units" id="easyPieChart` +
  13515. (i + 1) +
  13516. `Units">` +
  13517. e.units +
  13518. `</span>
  13519. </div>
  13520. </div>
  13521. <script>
  13522. $(function() {
  13523. var opts = {
  13524. size: ` +
  13525. easySize +
  13526. `,
  13527. lineWidth: 7,
  13528. scaleColor: false,
  13529. barColor: '#` +
  13530. e.colour +
  13531. `',
  13532. trackColor: '#636363',
  13533. };
  13534. if(` +
  13535. e.percent +
  13536. ` == 0) {
  13537. opts.lineCap = 'butt';
  13538. }
  13539. $('#easyPieChart` +
  13540. (i + 1) +
  13541. `').easyPieChart(opts);
  13542. });
  13543. </script>
  13544. `
  13545. );
  13546. };
  13547. var buildGaugeChart = function (e, i, size, easySize, display) {
  13548. switch (size) {
  13549. case "lg":
  13550. easySize = 300;
  13551. break;
  13552. case "sm":
  13553. easySize = 275;
  13554. break;
  13555. case "md":
  13556. default:
  13557. easySize = 250;
  13558. break;
  13559. }
  13560. return (
  13561. `
  13562. <div class="mx-0 gauge-cont chart-` +
  13563. size +
  13564. ` my-3 text-center ` +
  13565. display +
  13566. `">
  13567. <div class="gauge-chart text-center">
  13568. <span class="gauge-title d-block" id="gaugeChart` +
  13569. (i + 1) +
  13570. `Title">` +
  13571. e.title +
  13572. `</span>
  13573. <span class="gauge-value d-block" id="gaugeChart` +
  13574. (i + 1) +
  13575. `Value">` +
  13576. parseFloat(e.value).toFixed(1) +
  13577. `</span>
  13578. <canvas id="gaugeChart` +
  13579. (i + 1) +
  13580. `" style="width: 100%"></canvas>
  13581. </div>
  13582. </div>
  13583. <script>
  13584. $(function() {
  13585. var opts = {
  13586. angle: 0.14, // The span of the gauge arc
  13587. lineWidth: 0.54, // The line thickness
  13588. radiusScale: 1, // Relative radius
  13589. pointer: {
  13590. length: 0.77, // // Relative to gauge radius
  13591. strokeWidth: 0.075, // The thickness
  13592. color: '#A1A1A1' // Fill color
  13593. },
  13594. limitMax: false, // If false, max value increases automatically if value > maxValue
  13595. limitMin: false, // If true, the min value of the gauge will be fixed
  13596. colorStart: '#` +
  13597. e.colour +
  13598. `', // Colors
  13599. colorStop: '#` +
  13600. e.colour +
  13601. `', // just experiment with them
  13602. strokeColor: '#636363', // to see which ones work best for you
  13603. generateGradient: true,
  13604. highDpiSupport: true, // High resolution support
  13605. };
  13606. var target = document.getElementById('gaugeChart` +
  13607. (i + 1) +
  13608. `'); // your canvas element
  13609. var gauge = new Gauge(target).setOptions(opts); // create sexy gauge!
  13610. gauge.maxValue = ` +
  13611. e.max +
  13612. `; // set max gauge value
  13613. gauge.setMinValue(0); // Prefer setter over gauge.minValue = 0
  13614. gauge.animationSpeed = 8; // set animation speed (32 is default value)
  13615. gauge.set(` +
  13616. e.percent +
  13617. `); // set actual value
  13618. window.netdata[` +
  13619. (i + 1) +
  13620. `] = gauge
  13621. });
  13622. </script>
  13623. `
  13624. );
  13625. };
  13626. array.forEach((e, i) => {
  13627. var size = e.size;
  13628. var easySize;
  13629. if (size == "") {
  13630. size = "md";
  13631. }
  13632. switch (size) {
  13633. case "lg":
  13634. easySize = 180;
  13635. break;
  13636. case "sm":
  13637. easySize = 140;
  13638. break;
  13639. case "md":
  13640. default:
  13641. easySize = 160;
  13642. break;
  13643. }
  13644. var display = " ";
  13645. if (e.lg) {
  13646. display += " d-xl-inline-block d-lg-inline-block";
  13647. } else {
  13648. display += " d-xl-none d-lg-none d-none";
  13649. }
  13650. if (e.md) {
  13651. display += " d-md-inline-block";
  13652. } else {
  13653. display += " d-md-none d-none";
  13654. }
  13655. if (e.sm) {
  13656. display += " d-sm-inline-block d-xs-inline-block";
  13657. } else {
  13658. display += " d-sm-none d-xs-none d-none";
  13659. }
  13660. display += " ";
  13661. if (e.error) {
  13662. organizrConsole(
  13663. "Netdata Function",
  13664. "(Chart " + (i + 1) + "): " + e.error,
  13665. "error"
  13666. );
  13667. } else if (e.chart == "easypiechart") {
  13668. html += buildEasyPieChart(e, i, size, easySize, display);
  13669. } else if (e.chart == "gauge") {
  13670. html += buildGaugeChart(e, i, size, easySize, display);
  13671. }
  13672. });
  13673. return html;
  13674. }
  13675. function buildNetdata(array) {
  13676. var data = array.data;
  13677. if (array === false) {
  13678. return "";
  13679. }
  13680. window.netdata = [];
  13681. var html = `
  13682. <style>
  13683. .clearfix {
  13684. *zoom: 1;
  13685. }
  13686. .all-netdata .clearfix:before,
  13687. .all-netdata .clearfix:after {
  13688. display: table;
  13689. content: "";
  13690. }
  13691. .all-netdata .clearfix:after {
  13692. clear: both;
  13693. }
  13694. .all-netdata .easyPieChart {
  13695. position: relative;
  13696. text-align: center;
  13697. }
  13698. .all-netdata .easyPieChart canvas {
  13699. position: absolute;
  13700. top: 0;
  13701. left: 0;
  13702. }
  13703. .all-netdata .chart {
  13704. float: left;
  13705. //margin: 10px;
  13706. }
  13707. .all-netdata .percentage,
  13708. .all-netdata .label {
  13709. text-align: center;
  13710. color: #333;
  13711. font-weight: 100;
  13712. font-size: 1.2em;
  13713. margin-bottom: 0.3em;
  13714. }
  13715. .all-netdata .credits {
  13716. padding-top: 0.5em;
  13717. clear: both;
  13718. color: #999;
  13719. }
  13720. .all-netdata .credits a {
  13721. color: #333;
  13722. }
  13723. .all-netdata .dark {
  13724. background: #333;
  13725. }
  13726. .all-netdata .dark .percentage-light,
  13727. .all-netdata .dark .label {
  13728. text-align: center;
  13729. color: #999;
  13730. font-weight: 100;
  13731. font-size: 1.2em;
  13732. margin-bottom: 0.3em;
  13733. }
  13734. .all-netdata .button {
  13735. -webkit-box-shadow: inset 0 0 1px #000, inset 0 1px 0 1px rgba(255,255,255,0.2), 0 1px 1px -1px rgba(0, 0, 0, .5);
  13736. -moz-box-shadow: inset 0 0 1px #000, inset 0 1px 0 1px rgba(255,255,255,0.2), 0 1px 1px -1px rgba(0, 0, 0, .5);
  13737. box-shadow: inset 0 0 1px #000, inset 0 1px 0 1px rgba(255,255,255,0.2), 0 1px 1px -1px rgba(0, 0, 0, .5);
  13738. -webkit-border-radius: 3px;
  13739. -moz-border-radius: 3px;
  13740. border-radius: 3px;
  13741. padding: 6px 20px;
  13742. font-weight: bold;
  13743. text-transform: uppercase;
  13744. display: block;
  13745. margin: 0 auto 2em;
  13746. max-width: 200px;
  13747. text-align: center;
  13748. background-color: #5c5c5c;
  13749. background-image: -moz-linear-gradient(top, #666666, #4d4d4d);
  13750. background-image: -ms-linear-gradient(top, #666666, #4d4d4d);
  13751. background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#666666), to(#4d4d4d));
  13752. background-image: -webkit-linear-gradient(top, #666666, #4d4d4d);
  13753. background-image: -o-linear-gradient(top, #666666, #4d4d4d);
  13754. background-image: linear-gradient(top, #666666, #4d4d4d);
  13755. background-repeat: repeat-x;
  13756. filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#666666', endColorstr='#4d4d4d', GradientType=0);
  13757. color: #ffffff;
  13758. text-shadow: 0 1px 1px #333333;
  13759. }
  13760. .all-netdata .button:hover {
  13761. color: #ffffff;
  13762. text-decoration: none;
  13763. background-color: #616161;
  13764. background-image: -moz-linear-gradient(top, #6b6b6b, #525252);
  13765. background-image: -ms-linear-gradient(top, #6b6b6b, #525252);
  13766. background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#6b6b6b), to(#525252));
  13767. background-image: -webkit-linear-gradient(top, #6b6b6b, #525252);
  13768. background-image: -o-linear-gradient(top, #6b6b6b, #525252);
  13769. background-image: linear-gradient(top, #6b6b6b, #525252);
  13770. background-repeat: repeat-x;
  13771. filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#6b6b6b', endColorstr='#525252', GradientType=0);
  13772. }
  13773. .all-netdata .button:active {
  13774. background-color: #575757;
  13775. background-image: -moz-linear-gradient(top, #616161, #474747);
  13776. background-image: -ms-linear-gradient(top, #616161, #474747);
  13777. background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#616161), to(#474747));
  13778. background-image: -webkit-linear-gradient(top, #616161, #474747);
  13779. background-image: -o-linear-gradient(top, #616161, #474747);
  13780. background-image: linear-gradient(top, #616161, #474747);
  13781. background-repeat: repeat-x;
  13782. filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#616161', endColorstr='#474747', GradientType=0);
  13783. -webkit-transform: translate(0, 1px);
  13784. -moz-transform: translate(0, 1px);
  13785. -ms-transform: translate(0, 1px);
  13786. -o-transform: translate(0, 1px);
  13787. transform: translate(0, 1px);
  13788. }
  13789. .all-netdata .button:disabled {
  13790. background-color: #dddddd;
  13791. background-image: -moz-linear-gradient(top, #e7e7e7, #cdcdcd);
  13792. background-image: -ms-linear-gradient(top, #e7e7e7, #cdcdcd);
  13793. background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#e7e7e7), to(#cdcdcd));
  13794. background-image: -webkit-linear-gradient(top, #e7e7e7, #cdcdcd);
  13795. background-image: -o-linear-gradient(top, #e7e7e7, #cdcdcd);
  13796. background-image: linear-gradient(top, #e7e7e7, #cdcdcd);
  13797. background-repeat: repeat-x;
  13798. filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#e7e7e7', endColorstr='#cdcdcd', GradientType=0);
  13799. color: #939393;
  13800. text-shadow: 0 1px 1px #fff;
  13801. }
  13802. </style>
  13803. `;
  13804. html += `
  13805. <div class="row m-b-30">
  13806. <div class="d-block text-center all-netdata">
  13807. `;
  13808. html += buildNetdataItem(data);
  13809. html += `
  13810. </div>
  13811. </div>`;
  13812. return array ? html : "";
  13813. }
  13814. function homepageNetdata(timeout) {
  13815. var timeout =
  13816. typeof timeout !== "undefined"
  13817. ? timeout
  13818. : activeInfo.settings.homepage.refresh.homepageNetdataRefresh;
  13819. organizrAPI2("GET", "api/v2/homepage/netdata/data")
  13820. .success(function (data) {
  13821. try {
  13822. let response = data.response;
  13823. if (!tryUpdateNetdata(response.data.data)) {
  13824. document.getElementById("homepageOrderNetdata").innerHTML = "";
  13825. if (response.data !== null) {
  13826. $("#homepageOrderNetdata").html(buildNetdata(response.data));
  13827. }
  13828. }
  13829. } catch (e) {
  13830. organizrCatchError(e, data);
  13831. }
  13832. })
  13833. .fail(function (xhr) {
  13834. OrganizrApiError(xhr);
  13835. });
  13836. var timeoutTitle = "Netdata-Homepage";
  13837. if (typeof timeouts[timeoutTitle] !== "undefined") {
  13838. clearTimeout(timeouts[timeoutTitle]);
  13839. }
  13840. timeouts[timeoutTitle] = setTimeout(function () {
  13841. homepageNetdata(timeout);
  13842. }, timeout);
  13843. delete timeout;
  13844. }
  13845. function tryUpdateNetdata(array) {
  13846. var existing = false;
  13847. array.forEach((e, i) => {
  13848. var id = i + 1;
  13849. if (e.chart == "easypiechart") {
  13850. if ($("#easyPieChart" + id).length) {
  13851. $("#easyPieChart" + id)
  13852. .data("easyPieChart")
  13853. .update(e.percent);
  13854. $("#easyPieChart" + id + "Value").html(parseFloat(e.value).toFixed(1));
  13855. existing = true;
  13856. }
  13857. } else if (e.chart == "gauge") {
  13858. if (window.netdata) {
  13859. if (window.netdata[i + 1]) {
  13860. window.netdata[i + 1].set(e.percent); // set actual value
  13861. $("#gaugeChart" + (i + 1) + "Value").html(
  13862. parseFloat(e.value).toFixed(1)
  13863. );
  13864. existing = true;
  13865. }
  13866. } else {
  13867. existing = false;
  13868. }
  13869. } else {
  13870. existing = false;
  13871. }
  13872. });
  13873. return existing;
  13874. }
  13875. function homepageJackett() {
  13876. if (activeInfo.settings.homepage.options.alternateHomepageHeaders) {
  13877. var header = `
  13878. <div class="col-md-12">
  13879. <h2 class="text-white m-0 pull-left text-uppercase"><img class="lazyload homepageImageTitle" data-src="plugins/images/tabs/jackett.png"> &nbsp; <span lang="en">Jackett</span>&nbsp;</h2>
  13880. <hr class="hidden-xs"><div class="clearfix"></div>
  13881. </div>
  13882. <div class="clearfix"></div>
  13883. <script>$('.jackett-panel').removeClass('panel panel-default');</script>
  13884. `;
  13885. } else {
  13886. var header = `
  13887. <div class="panel-heading bg-info p-t-10 p-b-10">
  13888. <span class="pull-left m-t-5 text-white"><img class="lazyload homepageImageTitle" data-src="plugins/images/tabs/jackett.png" > &nbsp; <span lang="en">Jackett</span></span>
  13889. <div class="clearfix"></div>
  13890. </div>
  13891. `;
  13892. }
  13893. let html =
  13894. `
  13895. <div id="jackettSearch" class="row">
  13896. <div class="col-lg-12">
  13897. <div class="jackett-panel panel panel-default">
  13898. ` +
  13899. header +
  13900. `
  13901. <div class="panel-wrapper p-b-0 collapse in">
  13902. <div class="white-box">
  13903. <h3 class="box-title m-b-0" lang="en">Search</h3>
  13904. <form onsubmit="searchJackett();return false;">
  13905. <div class="input-group m-b-30">
  13906. <span class="input-group-btn hidden">
  13907. <button type="button" class="btn waves-effect waves-light btn-primary clearJackett" onclick="clearJackett();"><i class="fa fa-eraser"></i></button>
  13908. </span>
  13909. <input id="jackett-search-query" class="form-control" placeholder="Search for..." lang="en">
  13910. <span class="input-group-btn">
  13911. <button type="submit" class="btn waves-effect waves-light btn-info"><i class="fa fa-search"></i></button>
  13912. </span>
  13913. </div>
  13914. </form>
  13915. <div class="jackettDataTable hidden">
  13916. <h3 class="box-title m-b-0" lang="en">Results</h3>
  13917. <div class="table-responsive">
  13918. <table id="jackettDataTable" class="table table-striped">
  13919. <thead>
  13920. <tr>
  13921. <th lang="en">Date</th>
  13922. <th lang="en">Tracker</th>
  13923. <th lang="en">Name</th>
  13924. <th lang="en">Size</th>
  13925. <th lang="en">Files</th>
  13926. <th lang="en">Grabs</th>
  13927. <th lang="en">Seeds</th>
  13928. <th lang="en">Leechers</th>
  13929. <th lang="en">Download</th>
  13930. </tr>
  13931. </thead>
  13932. <tbody></tbody>
  13933. </table>
  13934. </div>
  13935. </div>
  13936. </div>
  13937. </div>
  13938. </div>
  13939. </div>
  13940. </div>
  13941. `;
  13942. $("#homepageOrderJackett").html(html);
  13943. }
  13944. function clearJackett() {
  13945. $("#jackett-search-query").val("");
  13946. $(".clearJackett").parent().addClass("hidden");
  13947. $("#jackettDataTable").DataTable().destroy();
  13948. $(".jackettDataTable").addClass("hidden");
  13949. }
  13950. function searchJackett() {
  13951. let query = $("#jackett-search-query").val();
  13952. if (query !== "") {
  13953. $(".jackettDataTable").removeClass("hidden");
  13954. //ajaxloader('#jackettSearch .panel-wrapper', 'in');
  13955. ajaxblocker(".jackett-panel .white-box", "in", "Searching...");
  13956. } else {
  13957. return false;
  13958. }
  13959. $.fn.dataTable.ext.errMode = "none";
  13960. $("#jackettDataTable").DataTable().destroy();
  13961. let preferBlackholeDownload =
  13962. activeInfo.settings.homepage.jackett.homepageJackettBackholeDownload;
  13963. let jackettTable = $("#jackettDataTable")
  13964. .on("error.dt", function (e, settings, techNote, message) {
  13965. console.log("An error has been reported by DataTables: ", message);
  13966. $("#jackettDataTable").DataTable().destroy();
  13967. ajaxblocker(".jackett-panel .white-box");
  13968. $(".clearJackett").parent().removeClass("hidden");
  13969. window.message(
  13970. "Jackett Connection Error",
  13971. "",
  13972. activeInfo.settings.notifications.position,
  13973. "#FFF",
  13974. "error",
  13975. "5000"
  13976. );
  13977. })
  13978. .DataTable({
  13979. ajax: {
  13980. url: "api/v2/homepage/jackett/" + query,
  13981. dataSrc: function (json) {
  13982. return json.response.data.content.Results;
  13983. },
  13984. },
  13985. columns: [
  13986. {
  13987. data: "PublishDate",
  13988. render: function (data, type, row) {
  13989. if (type === "display" || type === "filter") {
  13990. var m = moment.tz(data, activeInfo.timezone);
  13991. return moment.utc(m, "YYYY-MM-DD hh:mm[Z]").local().fromNow();
  13992. }
  13993. return data;
  13994. },
  13995. },
  13996. { data: "Tracker" },
  13997. {
  13998. data: "Title",
  13999. render: function (data, type, row) {
  14000. if (row.Details !== null) {
  14001. return (
  14002. '<a href="' + row.Details + '" target="_blank">' + data + "</a>"
  14003. );
  14004. } else {
  14005. return data;
  14006. }
  14007. },
  14008. },
  14009. {
  14010. data: "Size",
  14011. render: function (data, type, row) {
  14012. if (type === "display" || type === "filter") {
  14013. return humanFileSize(data, false);
  14014. }
  14015. return humanFileSize(data, false);
  14016. },
  14017. },
  14018. { data: "Files" },
  14019. { data: "Grabs" },
  14020. { data: "Seeders" },
  14021. { data: "Peers" },
  14022. {
  14023. data: "MagnetUri",
  14024. render: function (data, type, row) {
  14025. if (type === "display" || type === "filter") {
  14026. if (
  14027. preferBlackholeDownload === true &&
  14028. row.BlackholeLink !== null
  14029. ) {
  14030. return (
  14031. "<a onclick=\"jackettDownload('" +
  14032. row.BlackholeLink +
  14033. '\');return false;" href="#"><i class="fa fa-cloud-download"></i></a>'
  14034. );
  14035. } else if (data !== null) {
  14036. return (
  14037. '<a href="' +
  14038. data +
  14039. '" target="_blank"><i class="fa fa-magnet"></i></a>'
  14040. );
  14041. } else if (row.Details !== null) {
  14042. return (
  14043. '<a href="' +
  14044. row.Details +
  14045. '" target="_blank"><i class="fa fa-cloud-download"></i></a>'
  14046. );
  14047. } else if (row.Guid !== null) {
  14048. return (
  14049. '<a href="' +
  14050. row.Guid +
  14051. '" target="_blank"><i class="fa fa-cloud-download"></i></a>'
  14052. );
  14053. } else if (row.Link !== null) {
  14054. return (
  14055. '<a href="' +
  14056. row.Link +
  14057. '" target="_blank"><i class="fa fa-download"></i></a>'
  14058. );
  14059. } else {
  14060. return "No Download Link";
  14061. }
  14062. }
  14063. return data;
  14064. },
  14065. },
  14066. ],
  14067. order: [[0, "desc"]],
  14068. initComplete: function (settings, json) {
  14069. //ajaxloader();
  14070. ajaxblocker(".jackett-panel .white-box");
  14071. $(".clearJackett").parent().removeClass("hidden");
  14072. },
  14073. });
  14074. }
  14075. function jackettDownload(url) {
  14076. let blackholeLink = url.substring(url.indexOf("/bh/"));
  14077. var post = {
  14078. url: blackholeLink,
  14079. };
  14080. organizrAPI2("POST", "api/v2/homepage/jackett/download/", post, true)
  14081. .success(function () {
  14082. message(
  14083. "Torrent downloaded",
  14084. "",
  14085. activeInfo.settings.notifications.position,
  14086. "#FFF",
  14087. "success",
  14088. "5000"
  14089. );
  14090. })
  14091. .fail(function (xhr) {
  14092. OrganizrApiError(xhr, "Error downloading torrent");
  14093. });
  14094. }
  14095. function homepageProwlarr() {
  14096. if (activeInfo.settings.homepage.options.alternateHomepageHeaders) {
  14097. var header = `
  14098. <div class="col-md-12">
  14099. <h2 class="text-white m-0 pull-left text-uppercase"><img class="lazyload homepageImageTitle" data-src="plugins/images/tabs/prowlarr.png"> &nbsp; <span lang="en">Prowlarr</span>&nbsp;</h2>
  14100. <hr class="hidden-xs"><div class="clearfix"></div>
  14101. </div>
  14102. <div class="clearfix"></div>
  14103. <script>$('.prowlarr-panel').removeClass('panel panel-default');</script>
  14104. `;
  14105. } else {
  14106. var header = `
  14107. <div class="panel-heading bg-info p-t-10 p-b-10">
  14108. <span class="pull-left m-t-5 text-white"><img class="lazyload homepageImageTitle" data-src="plugins/images/tabs/prowlarr.png" > &nbsp; <span lang="en">Prowlarr</span></span>
  14109. <div class="clearfix"></div>
  14110. </div>
  14111. `;
  14112. }
  14113. let html =
  14114. `
  14115. <div id="prowlarrSearch" class="row">
  14116. <div class="col-lg-12">
  14117. <div class="prowlarr-panel panel panel-default">
  14118. ` +
  14119. header +
  14120. `
  14121. <div class="panel-wrapper p-b-0 collapse in">
  14122. <div class="white-box">
  14123. <h3 class="box-title m-b-0" lang="en">Search</h3>
  14124. <form onsubmit="searchProwlarr();return false;">
  14125. <div class="input-group m-b-30">
  14126. <span class="input-group-btn hidden">
  14127. <button type="button" class="btn waves-effect waves-light btn-primary clearProwlarr" onclick="clearProwlarr();"><i class="fa fa-eraser"></i></button>
  14128. </span>
  14129. <input id="prowlarr-search-query" class="form-control" placeholder="Search for..." lang="en">
  14130. <span class="input-group-btn">
  14131. <button type="submit" class="btn waves-effect waves-light btn-info"><i class="fa fa-search"></i></button>
  14132. </span>
  14133. </div>
  14134. </form>
  14135. <div class="prowlarrDataTable hidden">
  14136. <h3 class="box-title m-b-0" lang="en">Results</h3>
  14137. <div class="table-responsive">
  14138. <table id="prowlarrDataTable" class="table table-striped">
  14139. <thead>
  14140. <tr>
  14141. <th lang="en">Date</th>
  14142. <th lang="en">Indexer</th>
  14143. <th lang="en">Title</th>
  14144. <th lang="en">Size</th>
  14145. <th lang="en">Grabs</th>
  14146. <th lang="en">Seeders</th>
  14147. <th lang="en">Leechers</th>
  14148. <th lang="en">Download</th>
  14149. </tr>
  14150. </thead>
  14151. <tbody></tbody>
  14152. </table>
  14153. </div>
  14154. </div>
  14155. </div>
  14156. </div>
  14157. </div>
  14158. </div>
  14159. </div>
  14160. `;
  14161. $("#homepageOrderProwlarr").html(html);
  14162. }
  14163. function clearProwlarr() {
  14164. $("#prowlarr-search-query").val("");
  14165. $(".clearProwlarr").parent().addClass("hidden");
  14166. $("#prowlarrDataTable").DataTable().destroy();
  14167. $(".prowlarrDataTable").addClass("hidden");
  14168. }
  14169. function searchProwlarr() {
  14170. let query = $("#prowlarr-search-query").val();
  14171. if (query !== "") {
  14172. $(".prowlarrDataTable").removeClass("hidden");
  14173. ajaxloader("#prowlarrSearch .panel-wrapper", "in");
  14174. } else {
  14175. return false;
  14176. }
  14177. $.fn.dataTable.ext.errMode = "none";
  14178. $("#prowlarrDataTable").DataTable().destroy();
  14179. let preferBlackholeDownload =
  14180. activeInfo.settings.homepage.prowlarr.homepageProwlarrBackholeDownload;
  14181. let prowlarrTable = $("#prowlarrDataTable")
  14182. .on("error.dt", function (e, settings, techNote, message) {
  14183. console.log("An error has been reported by DataTables: ", message);
  14184. })
  14185. .DataTable({
  14186. ajax: {
  14187. url: "api/v2/homepage/prowlarr/" + query,
  14188. dataSrc: function (json) {
  14189. return json.response.data.content;
  14190. },
  14191. },
  14192. columns: [
  14193. {
  14194. data: "publishDate",
  14195. render: function (data, type, row) {
  14196. if (type === "display" || type === "filter") {
  14197. var m = moment.tz(data, activeInfo.timezone);
  14198. return moment.utc(m, "YYYY-MM-DD hh:mm[Z]").local().fromNow();
  14199. }
  14200. return data;
  14201. },
  14202. },
  14203. { data: "indexer" },
  14204. {
  14205. data: "title",
  14206. render: function (data, type, row) {
  14207. if (row.Details !== null) {
  14208. return (
  14209. '<a href="' +
  14210. row["infoUrl"] +
  14211. '" target="_blank">' +
  14212. data +
  14213. "</a>"
  14214. );
  14215. } else {
  14216. return data;
  14217. }
  14218. },
  14219. },
  14220. {
  14221. data: "size",
  14222. render: function (data) {
  14223. return humanFileSize(data, false);
  14224. },
  14225. },
  14226. { data: "grabs" },
  14227. { data: "seeders" },
  14228. { data: "leechers" },
  14229. {
  14230. data: "downloadUrl",
  14231. render: function (data, type, row) {
  14232. if (type === "display" || type === "filter") {
  14233. if (data !== null) {
  14234. if (preferBlackholeDownload === true && row.guid !== null) {
  14235. return (
  14236. "<a onclick=\"prowlarrDownload('" +
  14237. row.guid +
  14238. "," +
  14239. row.indexerId +
  14240. '\');return false;" href="#"><i class="fa fa-cloud-download"></i></a>'
  14241. );
  14242. } else {
  14243. return (
  14244. '<a href="' +
  14245. data +
  14246. '" target="_blank"><i class="fa fa-download"></i></a>'
  14247. );
  14248. }
  14249. } else {
  14250. return "No Download Link";
  14251. }
  14252. }
  14253. return data;
  14254. },
  14255. },
  14256. ],
  14257. order: [[5, "desc"]],
  14258. initComplete: function (settings, json) {
  14259. ajaxloader();
  14260. //ajaxblocker('.prowlarr-panel .white-box');
  14261. $(".clearProwlarr").parent().removeClass("hidden");
  14262. },
  14263. });
  14264. }
  14265. function prowlarrDownload(url) {
  14266. const args = url.split(",");
  14267. var post = {
  14268. guid: args[0],
  14269. indexerId: args[1],
  14270. };
  14271. organizrAPI2("POST", "api/v2/homepage/prowlarr/download/", post, true)
  14272. .success(function () {
  14273. message(
  14274. "Torrent downloaded",
  14275. "",
  14276. activeInfo.settings.notifications.position,
  14277. "#FFF",
  14278. "success",
  14279. "5000"
  14280. );
  14281. })
  14282. .fail(function (xhr) {
  14283. OrganizrApiError(xhr, "Error downloading torrent");
  14284. });
  14285. }
  14286. function homepageOctoprint(timeout) {
  14287. var timeout =
  14288. typeof timeout !== "undefined"
  14289. ? timeout
  14290. : activeInfo.settings.homepage.refresh.homepageOctoprintRefresh;
  14291. organizrAPI2("GET", "api/v2/homepage/octoprint/data")
  14292. .success(function (data) {
  14293. try {
  14294. let response = data.response;
  14295. document.getElementById("homepageOrderOctoprint").innerHTML = "";
  14296. if (response.data !== null) {
  14297. $("#homepageOrderOctoprint").html(buildOctoprint(response.data));
  14298. }
  14299. } catch (e) {
  14300. organizrCatchError(e, data);
  14301. }
  14302. })
  14303. .fail(function (xhr) {
  14304. OrganizrApiError(xhr);
  14305. });
  14306. let timeoutTitle = "Octoprint-Homepage";
  14307. if (typeof timeouts[timeoutTitle] !== "undefined") {
  14308. clearTimeout(timeouts[timeoutTitle]);
  14309. }
  14310. timeouts[timeoutTitle] = setTimeout(function () {
  14311. homepageOctoprint(timeout);
  14312. }, timeout);
  14313. delete timeout;
  14314. }
  14315. function buildOctoprint(array) {
  14316. var menu = `<ul class="nav customtab nav-tabs pull-right" role="tablist">`;
  14317. var headerAlt = "";
  14318. var header = "";
  14319. var content = "";
  14320. var webcamUrl = "";
  14321. var webcamHtml = "";
  14322. var css = `
  14323. <style>
  14324. .octoprint-webcam {
  14325. max-height: 400px;
  14326. max-width: 100%;
  14327. float: right;
  14328. }
  14329. .octoprint-block {
  14330. margin-left: 0px;
  14331. margin-right: 0px;
  14332. }
  14333. .octoprint-button-spacer {
  14334. padding-right: 46px;
  14335. }
  14336. </style>
  14337. `;
  14338. menu += `
  14339. <li role="presentation" class="active" ><a href="" aria-controls="home" role="tab" data-toggle="tab" aria-expanded="true" onclick="homepageOctoprint();"><span class="visible-xs"><i class="ti-download"></i></span><span class="hidden-xs">REFRESH</span></a></li>
  14340. `;
  14341. menu += "</ul>";
  14342. if (activeInfo.settings.homepage.options.alternateHomepageHeaders) {
  14343. var headerAlt =
  14344. `
  14345. <div class="col-md-12">
  14346. <h2 class="text-white m-0 pull-left text-uppercase"><img class="lazyload homepageImageTitle" data-src="plugins/images/tabs/octoprint.png"> &nbsp; </h2>
  14347. ` +
  14348. menu +
  14349. `
  14350. <hr class="hidden-xs"><div class="clearfix"></div>
  14351. </div>
  14352. <div class="clearfix"></div>
  14353. `;
  14354. } else {
  14355. var header =
  14356. `
  14357. <div class="white-box bg-info m-b-0 p-b-0 p-t-10 mailbox-widget">
  14358. <h2 class="text-white m-0 pull-left text-uppercase"><img class="lazyload homepageImageTitle" data-src="plugins/images/tabs/octoprint.png"> &nbsp; </h2>
  14359. ` +
  14360. menu +
  14361. `
  14362. <div class="clearfix"></div>
  14363. </div>
  14364. `;
  14365. }
  14366. content = "<p>State: " + array.data.job.state + "</p>";
  14367. if (array.data.job.state == "Printing") {
  14368. content += "<p>File: " + array.data.job.job.file.display + "</p>";
  14369. content +=
  14370. "<p>Progress: " +
  14371. parseFloat(array.data.job.progress.completion).toFixed(0) +
  14372. "%</p>";
  14373. content +=
  14374. "<p>Approx. Total Print Time: " +
  14375. octoprintFormatTime(array.data.job.job.estimatedPrintTime) +
  14376. "</p>";
  14377. content +=
  14378. "<p>Print Time Left: " +
  14379. octoprintFormatTime(array.data.job.progress.printTimeLeft) +
  14380. "</p>";
  14381. }
  14382. if (array.data.settings.webcam.webcamEnabled) {
  14383. webcamUrl = array.data.settings.webcam.streamUrl;
  14384. if (webcamUrl[0] == "/") {
  14385. webcamUrl = array.data.url + webcamUrl;
  14386. }
  14387. }
  14388. if (webcamUrl) {
  14389. var webcamHtml =
  14390. `<div class="col-lg-4"><img class="octoprint-webcam" src="` +
  14391. webcamUrl +
  14392. `"></div>`;
  14393. }
  14394. return (
  14395. css +
  14396. `
  14397. <div class="row">
  14398. ` +
  14399. headerAlt +
  14400. `
  14401. <div class="col-lg-12">
  14402. ` +
  14403. header +
  14404. `
  14405. <div class="row octoprint-block white-box">
  14406. <div class="col-lg-8 text-white">
  14407. <div class="tab-content m-t-0">` +
  14408. content +
  14409. `</div>
  14410. </div>
  14411. ` +
  14412. webcamHtml +
  14413. `
  14414. </div>
  14415. </div>
  14416. </div>
  14417. `
  14418. );
  14419. }
  14420. function octoprintFormatTime(seconds) {
  14421. var format = "";
  14422. var days = Math.floor(moment.duration(seconds, "seconds").asDays());
  14423. var hours = Math.floor(moment.duration(seconds, "seconds").asHours());
  14424. var minutes = moment.duration(seconds, "seconds").minutes();
  14425. var seconds = moment.duration(seconds, "seconds").seconds();
  14426. if (days > 0) {
  14427. format += days + " " + octoprintPluralize("day", days) + " ";
  14428. }
  14429. if (hours > 0) {
  14430. format += hours + " " + octoprintPluralize("hour", hours) + " ";
  14431. }
  14432. if (minutes > 0) {
  14433. format += minutes + " " + octoprintPluralize("minute", minutes) + " ";
  14434. }
  14435. if (seconds > 0) {
  14436. format += seconds + " " + octoprintPluralize("second", seconds) + " ";
  14437. }
  14438. return format;
  14439. }
  14440. function octoprintPluralize(s, n) {
  14441. if (n > 1) {
  14442. return s + "s";
  14443. }
  14444. return s;
  14445. }
  14446. function pad(n, width, z) {
  14447. z = z || "0";
  14448. n = n + "";
  14449. return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
  14450. }
  14451. // Thanks Swifty!
  14452. function PopupCenter(url, title, w, h) {
  14453. // Fixes dual-screen position Most browsers Firefox
  14454. var dualScreenLeft =
  14455. window.screenLeft != undefined ? window.screenLeft : window.screenX;
  14456. var dualScreenTop =
  14457. window.screenTop != undefined ? window.screenTop : window.screenY;
  14458. var width = window.innerWidth
  14459. ? window.innerWidth
  14460. : document.documentElement.clientWidth
  14461. ? document.documentElement.clientWidth
  14462. : screen.width;
  14463. var height = window.innerHeight
  14464. ? window.innerHeight
  14465. : document.documentElement.clientHeight
  14466. ? document.documentElement.clientHeight
  14467. : screen.height;
  14468. var left = width / 2 - w / 2 + dualScreenLeft;
  14469. var top = height / 2 - h / 2 + dualScreenTop;
  14470. var newWindow = window.open(
  14471. url,
  14472. title,
  14473. "scrollbars=yes, width=" +
  14474. w +
  14475. ", height=" +
  14476. h +
  14477. ", top=" +
  14478. top +
  14479. ", left=" +
  14480. left
  14481. );
  14482. // Puts focus on the newWindow
  14483. if (window.focus) {
  14484. newWindow.focus();
  14485. }
  14486. return newWindow;
  14487. }
  14488. function getPlexHeaders() {
  14489. let plexTitle =
  14490. activeInfo.appearance.title == ""
  14491. ? "Organizr"
  14492. : cleanClass(activeInfo.appearance.title);
  14493. return {
  14494. Accept: "application/json",
  14495. "X-Plex-Product": plexTitle,
  14496. "X-Plex-Version": "2.0",
  14497. "X-Plex-Client-Identifier": activeInfo.settings.misc.uuid,
  14498. "X-Plex-Model": "Plex OAuth",
  14499. "X-Plex-Platform": activeInfo.osName,
  14500. "X-Plex-Platform-Version": activeInfo.osVersion,
  14501. "X-Plex-Device": activeInfo.browserName,
  14502. "X-Plex-Device-Name": activeInfo.browserVersion,
  14503. "X-Plex-Device-Screen-Resolution":
  14504. window.screen.width + "x" + window.screen.height,
  14505. "X-Plex-Language": "en",
  14506. };
  14507. }
  14508. var plex_oauth_window = null;
  14509. const plex_oauth_loader =
  14510. "<style>" +
  14511. ".login-loader-container {" +
  14512. 'font-family: "Open Sans", Arial, sans-serif;' +
  14513. "position: absolute;" +
  14514. "top: 0;" +
  14515. "right: 0;" +
  14516. "bottom: 0;" +
  14517. "left: 0;" +
  14518. "}" +
  14519. ".login-loader-message {" +
  14520. "color: #282A2D;" +
  14521. "text-align: center;" +
  14522. "position: absolute;" +
  14523. "left: 50%;" +
  14524. "top: 25%;" +
  14525. "transform: translate(-50%, -50%);" +
  14526. "}" +
  14527. ".login-loader {" +
  14528. "border: 5px solid #ccc;" +
  14529. "-webkit-animation: spin 1s linear infinite;" +
  14530. "animation: spin 1s linear infinite;" +
  14531. "border-top: 5px solid #282A2D;" +
  14532. "border-radius: 50%;" +
  14533. "width: 50px;" +
  14534. "height: 50px;" +
  14535. "position: relative;" +
  14536. "left: calc(50% - 25px);" +
  14537. "}" +
  14538. "@keyframes spin {" +
  14539. "0% { transform: rotate(0deg); }" +
  14540. "100% { transform: rotate(360deg); }" +
  14541. "}" +
  14542. "</style>" +
  14543. '<div class="login-loader-container">' +
  14544. '<div class="login-loader-message">' +
  14545. '<div class="login-loader"></div>' +
  14546. "<br>" +
  14547. "Redirecting to the login page..." +
  14548. "</div>" +
  14549. "</div>";
  14550. function closePlexOAuthWindow() {
  14551. if (plex_oauth_window) {
  14552. plex_oauth_window.close();
  14553. }
  14554. }
  14555. getPlexOAuthPin = function () {
  14556. var x_plex_headers = getPlexHeaders();
  14557. var deferred = $.Deferred();
  14558. $.ajax({
  14559. url: "https://plex.tv/api/v2/pins?strong=true",
  14560. type: "POST",
  14561. headers: x_plex_headers,
  14562. success: function (data) {
  14563. deferred.resolve({ pin: data.id, code: data.code });
  14564. },
  14565. error: function () {
  14566. closePlexOAuthWindow();
  14567. deferred.reject();
  14568. },
  14569. });
  14570. return deferred;
  14571. };
  14572. var polling = null;
  14573. function PlexOAuth(
  14574. successCallback,
  14575. errorCallback,
  14576. maxRetryCallback,
  14577. pollingCallback,
  14578. preFunction,
  14579. clientID = null
  14580. ) {
  14581. if (typeof preFunction === "function") {
  14582. preFunction();
  14583. }
  14584. closePlexOAuthWindow();
  14585. plex_oauth_window = PopupCenter("", "Plex-OAuth", 600, 700);
  14586. $(plex_oauth_window.document.body).html(plex_oauth_loader);
  14587. getPlexOAuthPin().then(
  14588. function (data) {
  14589. var x_plex_headers = getPlexHeaders();
  14590. const pin = data.pin;
  14591. const code = data.code;
  14592. var oauth_params = {
  14593. clientID: x_plex_headers["X-Plex-Client-Identifier"],
  14594. "context[device][product]": x_plex_headers["X-Plex-Product"],
  14595. "context[device][version]": x_plex_headers["X-Plex-Version"],
  14596. "context[device][platform]": x_plex_headers["X-Plex-Platform"],
  14597. "context[device][platformVersion]":
  14598. x_plex_headers["X-Plex-Platform-Version"],
  14599. "context[device][device]": x_plex_headers["X-Plex-Device"],
  14600. "context[device][deviceName]": x_plex_headers["X-Plex-Device-Name"],
  14601. "context[device][model]": x_plex_headers["X-Plex-Model"],
  14602. "context[device][screenResolution]":
  14603. x_plex_headers["X-Plex-Device-Screen-Resolution"],
  14604. "context[device][layout]": "desktop",
  14605. code: code,
  14606. };
  14607. plex_oauth_window.location =
  14608. "https://app.plex.tv/auth/#!?" + encodeData(oauth_params);
  14609. polling = pin;
  14610. let maxPollCount = 120;
  14611. (function poll() {
  14612. maxPollCount--;
  14613. $.ajax({
  14614. url: "https://plex.tv/api/v2/pins/" + pin,
  14615. type: "GET",
  14616. headers: x_plex_headers,
  14617. success: function (data) {
  14618. if (data.authToken) {
  14619. polling = null;
  14620. closePlexOAuthWindow();
  14621. if (typeof successCallback === "function") {
  14622. successCallback("plex", data.authToken, clientID);
  14623. }
  14624. }
  14625. },
  14626. complete: function () {
  14627. if (maxPollCount <= 0) {
  14628. closePlexOAuthWindow();
  14629. if (typeof maxRetryCallback === "function") {
  14630. maxRetryCallback();
  14631. }
  14632. } else if (polling === pin) {
  14633. setTimeout(function () {
  14634. poll();
  14635. }, 1000);
  14636. if (typeof pollingCallback === "function") {
  14637. pollingCallback(maxPollCount);
  14638. }
  14639. }
  14640. },
  14641. timeout: 1000,
  14642. });
  14643. })();
  14644. },
  14645. function () {
  14646. closePlexOAuthWindow();
  14647. if (typeof errorCallback === "function") {
  14648. errorCallback();
  14649. }
  14650. }
  14651. );
  14652. }
  14653. function openOAuth(provider) {
  14654. // will actually fix this later
  14655. closePlexOAuthWindow();
  14656. plex_oauth_window = PopupCenter("", "OAuth", 600, 700);
  14657. $(plex_oauth_window.document.body).html(plex_oauth_loader);
  14658. plex_oauth_window.location = "api/v2/oauth/trakt";
  14659. }
  14660. function encodeData(data) {
  14661. return Object.keys(data)
  14662. .map(function (key) {
  14663. return [key, data[key]].map(encodeURIComponent).join("=");
  14664. })
  14665. .join("&");
  14666. }
  14667. function oAuthSuccess(type, token, id = null) {
  14668. switch (type) {
  14669. case "plex":
  14670. if (id) {
  14671. $(id).val(token);
  14672. $(id).change();
  14673. messageSingle(
  14674. "",
  14675. window.lang.translate("Grabbed Token - Please Save"),
  14676. activeInfo.settings.notifications.position,
  14677. "#FFF",
  14678. "success",
  14679. "5000"
  14680. );
  14681. } else {
  14682. $("#oAuth-Input").val(token);
  14683. $("#oAuthType-Input").val(type);
  14684. $("#login-username-Input").addClass("hidden");
  14685. $("#login-password-Input").addClass("hidden");
  14686. $("#oAuth-div").removeClass("hidden");
  14687. $(".login-button").first().trigger("click");
  14688. }
  14689. break;
  14690. default:
  14691. break;
  14692. }
  14693. }
  14694. function oAuthError() {
  14695. messageSingle(
  14696. "",
  14697. window.lang.translate("Error Connecting to oAuth Provider"),
  14698. activeInfo.settings.notifications.position,
  14699. "#FFF",
  14700. "error",
  14701. "5000"
  14702. );
  14703. }
  14704. function oAuthMaxRetry() {
  14705. messageSingle(
  14706. "",
  14707. window.lang.translate("Max Retry Error Connecting to oAuth Provider"),
  14708. activeInfo.settings.notifications.position,
  14709. "#FFF",
  14710. "error",
  14711. "5000"
  14712. );
  14713. }
  14714. function oAuthStart(type) {
  14715. switch (type) {
  14716. case "plex":
  14717. PlexOAuth(oAuthSuccess, oAuthError, oAuthMaxRetry, null, null);
  14718. break;
  14719. default:
  14720. break;
  14721. }
  14722. }
  14723. function oidcStart(provider) {
  14724. // Redirect in same window to OIDC provider
  14725. window.location.href =
  14726. "api/v2/oidc/" + encodeURIComponent(provider) + "/authorize";
  14727. }
  14728. function testOIDCConnection(provider) {
  14729. organizrAPI2(
  14730. "GET",
  14731. "api/v2/oidc/" + encodeURIComponent(provider) + "/test",
  14732. ""
  14733. )
  14734. .success(function (data) {
  14735. if (data.response.result === "success") {
  14736. messageSingle(
  14737. "OIDC Test",
  14738. data.response.message || "Connection successful",
  14739. activeInfo.settings.notifications.position,
  14740. "#FFF",
  14741. "success",
  14742. "5000"
  14743. );
  14744. } else {
  14745. messageSingle(
  14746. "OIDC Test",
  14747. data.response.message || "Connection failed",
  14748. activeInfo.settings.notifications.position,
  14749. "#FFF",
  14750. "error",
  14751. "5000"
  14752. );
  14753. }
  14754. })
  14755. .fail(function (xhr) {
  14756. var msg = "Connection failed";
  14757. try {
  14758. var resp = JSON.parse(xhr.responseText);
  14759. msg = resp.response.message || msg;
  14760. } catch (e) {}
  14761. messageSingle(
  14762. "OIDC Test",
  14763. msg,
  14764. activeInfo.settings.notifications.position,
  14765. "#FFF",
  14766. "error",
  14767. "5000"
  14768. );
  14769. });
  14770. }
  14771. function clearAJAX(id = "all") {
  14772. if (id == "all") {
  14773. $.each(timeouts, function (i, v) {
  14774. clearTimeout(timeouts[i]);
  14775. });
  14776. } else if (id == "homepage") {
  14777. $.each(timeouts, function (i, v) {
  14778. if (i.indexOf("-Homepage") > 0) {
  14779. clearTimeout(timeouts[i]);
  14780. }
  14781. });
  14782. } else {
  14783. clearTimeout(timeouts[id]);
  14784. }
  14785. }
  14786. //Generate API
  14787. function generateCode() {
  14788. var code = "";
  14789. var possible = "abcdefghijklmnopqrstuvwxyz0123456789";
  14790. for (var i = 0; i < 20; i++)
  14791. code += possible.charAt(Math.floor(Math.random() * possible.length));
  14792. return code;
  14793. }
  14794. // uppercase word
  14795. function toUpper(str) {
  14796. return str
  14797. .toLowerCase()
  14798. .split(" ")
  14799. .map(function (word) {
  14800. return word[0].toUpperCase() + word.substr(1);
  14801. })
  14802. .join(" ");
  14803. }
  14804. // human filesize
  14805. function humanFileSize(bytes, si) {
  14806. var thresh = si ? 1000 : 1024;
  14807. if (Math.abs(bytes) < thresh) {
  14808. return bytes + " B";
  14809. }
  14810. var units = si
  14811. ? ["kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]
  14812. : ["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"];
  14813. var u = -1;
  14814. do {
  14815. bytes /= thresh;
  14816. ++u;
  14817. } while (Math.abs(bytes) >= thresh && u < units.length - 1);
  14818. return bytes.toFixed(1) + " " + units[u];
  14819. }
  14820. //youtube search
  14821. function youtubeSearch(searchQuery) {
  14822. return $.ajax({
  14823. url: "api/v2/homepage/youtube/" + searchQuery,
  14824. });
  14825. }
  14826. function youtubeCheck(title, link) {
  14827. youtubeSearch(title)
  14828. .success(function (data) {
  14829. var response = data.response;
  14830. if (response.data) {
  14831. inlineLoad();
  14832. var id = response.data.items["0"].id.videoId;
  14833. var div =
  14834. `
  14835. <div id="player-` +
  14836. link +
  14837. `" data-plyr-provider="youtube" data-plyr-embed-id="` +
  14838. id +
  14839. `"
  14840. ></div>
  14841. <div class="clearfix"></div>
  14842. `;
  14843. $(".youtube-div").html(div);
  14844. $("." + link).trigger("click");
  14845. player = new Plyr("#player-" + link);
  14846. }
  14847. })
  14848. .fail(function (xhr) {
  14849. OrganizrApiError(xhr, "YouTube API Error");
  14850. // Fallback: open YouTube search in a new tab/window
  14851. var q = "";
  14852. try {
  14853. q = decodeURIComponent(title);
  14854. } catch (e1) {
  14855. try {
  14856. q = unescape(title);
  14857. } catch (e2) {
  14858. q = title;
  14859. }
  14860. }
  14861. var url =
  14862. "https://www.youtube.com/results?search_query=" +
  14863. encodeURIComponent(q + " trailer");
  14864. window.open(url, "_blank");
  14865. });
  14866. }
  14867. function requestSearch(title, page = 1) {
  14868. return $.ajax({
  14869. url:
  14870. "https://api.themoviedb.org/3/search/multi?api_key=83cf4ee97bb728eeaf9d4a54e64356a1&language=" +
  14871. activeInfo.language +
  14872. "&query=" +
  14873. title +
  14874. "&page=" +
  14875. page +
  14876. "&include_adult=false",
  14877. });
  14878. }
  14879. function requestSearchList(list, page = 1) {
  14880. var url = "";
  14881. switch (list) {
  14882. case "top-movie":
  14883. url =
  14884. "https://api.themoviedb.org/3/movie/top_rated?api_key=83cf4ee97bb728eeaf9d4a54e64356a1&language=" +
  14885. activeInfo.language +
  14886. "&region=US&page=" +
  14887. page;
  14888. break;
  14889. case "pop-movie":
  14890. url =
  14891. "https://api.themoviedb.org/3/movie/popular?api_key=83cf4ee97bb728eeaf9d4a54e64356a1&language=" +
  14892. activeInfo.language +
  14893. "&region=US&page=" +
  14894. page;
  14895. break;
  14896. case "up-movie":
  14897. url =
  14898. "https://api.themoviedb.org/3/movie/upcoming?api_key=83cf4ee97bb728eeaf9d4a54e64356a1&language=" +
  14899. activeInfo.language +
  14900. "&region=US&page=" +
  14901. page;
  14902. break;
  14903. case "theatre-movie":
  14904. url =
  14905. "https://api.themoviedb.org/3/movie/now_playing?api_key=83cf4ee97bb728eeaf9d4a54e64356a1&language=" +
  14906. activeInfo.language +
  14907. "&region=US&page=" +
  14908. page;
  14909. break;
  14910. case "top-tv":
  14911. url =
  14912. "https://api.themoviedb.org/3/tv/top_rated?api_key=83cf4ee97bb728eeaf9d4a54e64356a1&language=" +
  14913. activeInfo.language +
  14914. "&region=US&page=" +
  14915. page;
  14916. break;
  14917. case "pop-tv":
  14918. url =
  14919. "https://api.themoviedb.org/3/tv/popular?api_key=83cf4ee97bb728eeaf9d4a54e64356a1&language=" +
  14920. activeInfo.language +
  14921. "&region=US&page=" +
  14922. page;
  14923. break;
  14924. case "today-tv":
  14925. url =
  14926. "https://api.themoviedb.org/3/tv/airing_today?api_key=83cf4ee97bb728eeaf9d4a54e64356a1&language=" +
  14927. activeInfo.language +
  14928. "&region=US&page=" +
  14929. page;
  14930. break;
  14931. case "org-mod":
  14932. url =
  14933. "https://api.themoviedb.org/4/list/64438?api_key=83cf4ee97bb728eeaf9d4a54e64356a1&language=" +
  14934. activeInfo.language +
  14935. "&page=" +
  14936. page;
  14937. break;
  14938. default:
  14939. }
  14940. return $.ajax({
  14941. url: url,
  14942. });
  14943. }
  14944. function requestNewID(id) {
  14945. return $.ajax({
  14946. url:
  14947. "https://api.themoviedb.org/3/tv/" +
  14948. id +
  14949. "/external_ids?api_key=83cf4ee97bb728eeaf9d4a54e64356a1&language=en-US",
  14950. });
  14951. }
  14952. function getTmdbImages(id, type) {
  14953. return $.ajax({
  14954. url: `https://api.themoviedb.org/3/${type}/${id}/images?api_key=83cf4ee97bb728eeaf9d4a54e64356a1`,
  14955. });
  14956. }
  14957. function inlineLoad() {
  14958. $(".inline-popups").magnificPopup({
  14959. removalDelay: 500, //delay removal by X to allow out-animation
  14960. closeOnBgClick: true,
  14961. //closeOnContentClick: true,
  14962. callbacks: {
  14963. beforeOpen: function () {
  14964. this.st.mainClass = this.st.el.attr("data-effect");
  14965. this.st.focus = "#request-input";
  14966. },
  14967. close: function () {
  14968. if (typeof player !== "undefined") {
  14969. player.destroy();
  14970. }
  14971. },
  14972. },
  14973. midClick: true, // allow opening popup on middle mouse click. Always set it to true if you don't provide alternative source.
  14974. });
  14975. }
  14976. //Import Users
  14977. function importUsers(type) {
  14978. $(".importUsersButton").attr("disabled", true);
  14979. messageSingle(
  14980. "",
  14981. window.lang.translate("Importing Users"),
  14982. activeInfo.settings.notifications.position,
  14983. "#FFF",
  14984. "success",
  14985. "5000"
  14986. );
  14987. organizrAPI2("POST", "api/v2/users/import/" + type, { type: type })
  14988. .success(function (data) {
  14989. try {
  14990. var response = data.response;
  14991. message(
  14992. "User Import",
  14993. response.message,
  14994. activeInfo.settings.notifications.position,
  14995. "#FFF",
  14996. "success",
  14997. "5000"
  14998. );
  14999. $(".importUsersButton").attr("disabled", false);
  15000. } catch (e) {
  15001. organizrCatchError(e, data);
  15002. }
  15003. })
  15004. .fail(function (xhr) {
  15005. OrganizrApiError(xhr, "Import Error");
  15006. });
  15007. }
  15008. //Settings change auth
  15009. function changeAuth() {
  15010. var type = $("#authSelect").val();
  15011. var service = $("#authBackendSelect").val();
  15012. switch (service) {
  15013. case "plex":
  15014. $(".switchAuth").parent().parent().parent().hide();
  15015. $(".backendAuth").parent().parent().parent().show();
  15016. $(".plexAuth").parent().parent().parent().show();
  15017. break;
  15018. case "emby_local":
  15019. case "emby_connect":
  15020. case "emby_all":
  15021. $(".switchAuth").parent().parent().parent().hide();
  15022. $(".backendAuth").parent().parent().parent().show();
  15023. $(".embyAuth").parent().parent().parent().show();
  15024. break;
  15025. case "jellyfin":
  15026. $(".switchAuth").parent().parent().parent().hide();
  15027. $(".backendAuth").parent().parent().parent().show();
  15028. $(".jellyfinAuth").parent().parent().parent().show();
  15029. break;
  15030. case "ftp":
  15031. $(".switchAuth").parent().parent().parent().hide();
  15032. $(".backendAuth").parent().parent().parent().show();
  15033. $(".ftpAuth").parent().parent().parent().show();
  15034. break;
  15035. case "ldap":
  15036. $(".switchAuth").parent().parent().parent().hide();
  15037. $(".backendAuth").parent().parent().parent().show();
  15038. $(".ldapAuth").parent().parent().parent().show();
  15039. break;
  15040. default:
  15041. $(".switchAuth").parent().parent().parent().hide();
  15042. $(".backendAuth").parent().parent().parent().show();
  15043. }
  15044. if (type == "internal") {
  15045. $(".switchAuth").parent().parent().parent().hide();
  15046. }
  15047. }
  15048. function organizrSpecialSettings(array) {
  15049. //media search
  15050. if (
  15051. array.settings.homepage.search.enabled == true &&
  15052. typeof array.settings.homepage.search.type !== "undefined"
  15053. ) {
  15054. var htmlDOM = `
  15055. <li class=""><a class="waves-effect waves-light inline-popups" href="#mediaSearch-area" data-effect="mfp-zoom-out"> <i class="ti-search"></i></a></li>
  15056. `;
  15057. var searchBoxResults =
  15058. `
  15059. <div id="mediaSearch-area" class="white-popup mfp-with-anim mfp-hide">
  15060. <div class="col-md-8 col-md-offset-2">
  15061. <div class="white-box m-b-0 resultBox-outside">
  15062. <div class="form-group m-b-0">
  15063. <input id="mediaSearchQuery" data-server="` +
  15064. array.settings.homepage.search.type +
  15065. `" lang="en" placeholder="Search My Media" type="text" class="form-control inline-focus">
  15066. <div class="clearfix"></div>
  15067. </div>
  15068. <div class="row el-element-overlay mediaSearch-div resultBox-inside"></div>
  15069. </div>
  15070. </div>
  15071. </div>
  15072. `;
  15073. $(htmlDOM).prependTo(".navbar-right");
  15074. $(searchBoxResults).appendTo($(".organizr-area"));
  15075. }
  15076. }
  15077. function checkLocalForwardStatus(array) {
  15078. if (
  15079. array.settings.login.enableLocalAddressForward == true &&
  15080. typeof array.settings.login.enableLocalAddressForward !== "undefined"
  15081. ) {
  15082. if (
  15083. array.settings.login.wanDomain !== "" &&
  15084. array.settings.login.localAddress !== ""
  15085. ) {
  15086. organizrConsole("Organizr Function", "Local Login Enabled");
  15087. organizrConsole("Organizr Function", "Local Login Testing...");
  15088. let remoteSite = array.settings.login.wanDomain;
  15089. let localSite = array.settings.login.localAddress;
  15090. try {
  15091. let currentURL = decodeURI(window.location.href);
  15092. let currentSite = window.location.host;
  15093. if (
  15094. activeInfo.settings.user.local &&
  15095. currentSite.indexOf(remoteSite) !== -1 &&
  15096. currentURL.indexOf("override") === -1
  15097. ) {
  15098. organizrConsole(
  15099. "Organizr Function",
  15100. "Local Login Status: Local | Forwarding Now"
  15101. );
  15102. window.location = localSite;
  15103. } else {
  15104. organizrConsole(
  15105. "Organizr Function",
  15106. "Local Login Status: Not Local or Override was set - Ignoring Forward Request"
  15107. );
  15108. }
  15109. } catch (e) {
  15110. console.error(e);
  15111. }
  15112. }
  15113. }
  15114. }
  15115. function forceSearch(term) {
  15116. $.magnificPopup.close();
  15117. let tabInfo = findTab("api/v2/page/homepage", "access_url");
  15118. if (tabInformation[tabInfo.id]["loaded"]) {
  15119. if (tabInformation[tabInfo.id]["active"]) {
  15120. setTimeout(function () {
  15121. $("#newRequestButton").trigger("click");
  15122. $("#request-input").val(term);
  15123. doneTyping();
  15124. }, 500);
  15125. } else {
  15126. tabActions("click", tabInfo.id);
  15127. setTimeout(function () {
  15128. $("#newRequestButton").trigger("click");
  15129. $("#request-input").val(term);
  15130. doneTyping();
  15131. }, 1000);
  15132. }
  15133. } else {
  15134. tabActions("click", tabInfo.id);
  15135. setTimeout(function () {
  15136. $("#newRequestButton").trigger("click");
  15137. $("#request-input").val(term);
  15138. doneTyping();
  15139. }, 3000);
  15140. }
  15141. }
  15142. function splitPoster(str) {
  15143. var words = str.split(" ");
  15144. var newWord = "";
  15145. $.each(words, function (i, v) {
  15146. newWord += v + "<br/>";
  15147. });
  15148. return newWord;
  15149. }
  15150. function buildMediaResults(array, source, term) {
  15151. if (array.content.length == 0) {
  15152. var none =
  15153. '<h2 class="text-center" lang="en">No Results for:</h2><h3 class="text-center" lang="en">' +
  15154. term +
  15155. "</h3>";
  15156. none +=
  15157. activeInfo.settings.homepage.ombi.enabled == true ||
  15158. activeInfo.settings.homepage.overseerr.enabled == true
  15159. ? `<button onclick="forceSearch('` +
  15160. term +
  15161. `')" class="btn btn-block btn-info" lang="en">Would you like to Request it?</button>`
  15162. : "";
  15163. return none;
  15164. }
  15165. var results = "";
  15166. var tv = 0;
  15167. var movie = 0;
  15168. var music = 0;
  15169. var total = 0;
  15170. $.each(array.content, function (i, v) {
  15171. total = total + 1;
  15172. tv = v.type == "tv" ? tv + 1 : tv;
  15173. movie = v.type == "movie" ? movie + 1 : movie;
  15174. music = v.type == "music" ? music + 1 : music;
  15175. var bg = v.imageURL;
  15176. var top = v.title;
  15177. var bottom = v.metadata.originallyAvailableAt;
  15178. results +=
  15179. `
  15180. <div id="` +
  15181. v.uid +
  15182. `-metadata-div" class="white-popup mfp-with-anim mfp-hide">
  15183. <div class="col-md-8 col-md-offset-2 ` +
  15184. v.uid +
  15185. `-metadata-info"></div>
  15186. </div>
  15187. <a class="inline-popups ` +
  15188. v.uid +
  15189. ` hidden" href="#` +
  15190. v.uid +
  15191. `-metadata-div" data-effect="mfp-zoom-out"></a>
  15192. <div class="col-lg-3 col-md-4 col-sm-6 col-xs-12 m-t-20 request-result-item request-result-` +
  15193. v.type +
  15194. ` metadata-get mouse" data-source="` +
  15195. source +
  15196. `" data-key="` +
  15197. v.metadataKey +
  15198. `" data-uid="` +
  15199. v.uid +
  15200. `">
  15201. <div class="white-box m-b-10">
  15202. <div class="el-card-item p-b-0">
  15203. <div class="el-card-avatar el-overlay-1 m-b-5"> <img class="lazyload resultImages" data-src="` +
  15204. bg +
  15205. `"></div>
  15206. <div class="el-card-content bg-org">
  15207. <h3 class="box-title elip">` +
  15208. top +
  15209. `</h3> <small>` +
  15210. bottom +
  15211. `</small>
  15212. <br>
  15213. </div>
  15214. </div>
  15215. </div>
  15216. </div>
  15217. `;
  15218. });
  15219. //requests setup?
  15220. if (
  15221. activeInfo.settings.homepage.ombi.enabled == true ||
  15222. activeInfo.settings.homepage.overseerr.enabled == true
  15223. ) {
  15224. results +=
  15225. `
  15226. <div class="col-lg-3 col-md-4 col-sm-6 col-xs-12 m-t-20 request-result-item request-result-movie mouse" onclick="forceSearch('` +
  15227. term +
  15228. `')">
  15229. <div class="white-box m-b-10">
  15230. <div class="el-card-item p-b-0">
  15231. <div class="el-card-avatar el-overlay-1 m-b-5"> <img class="lazyload resultImages mouse" data-src="plugins/images/homepage/no-request.png">
  15232. <div class="customPoster">
  15233. <a href="javascript:void(0);">` +
  15234. splitPoster(term) +
  15235. `</a>
  15236. </div>
  15237. </div>
  15238. <div class="el-card-content bg-org">
  15239. <h3 class="box-title elip">` +
  15240. term +
  15241. `</h3> <small lang="en">Request Me!</small>
  15242. <br>
  15243. </div>
  15244. </div>
  15245. </div>
  15246. </div>
  15247. `;
  15248. }
  15249. var buttons =
  15250. `
  15251. <div class="button-box p-20 text-center p-b-0">
  15252. <button class="btn btn-inverse waves-effect waves-light filter-request-result" data-filter="request-result-all"><span>` +
  15253. total +
  15254. `</span> <i class="fa fa-th-large m-l-5 fa-fw"></i></button>
  15255. <button class="btn btn-primary waves-effect waves-light filter-request-result" data-filter="request-result-movie"><span>` +
  15256. movie +
  15257. `</span> <i class="fa fa-film m-l-5 fa-fw"></i></button>
  15258. <button class="btn btn-info waves-effect waves-light filter-request-result" data-filter="request-result-tv"><span>` +
  15259. tv +
  15260. `</span> <i class="fa fa-tv m-l-5 fa-fw"></i></button>
  15261. <button class="btn btn-info waves-effect waves-light filter-request-result" data-filter="request-result-music"><span>` +
  15262. music +
  15263. `</span> <i class="fa fa-music m-l-5 fa-fw"></i></button>
  15264. </div>
  15265. `;
  15266. results = '<div class="media-results">' + results + "</div>";
  15267. return buttons + results;
  15268. }
  15269. function getPingList(arrayItems) {
  15270. var pingList = [];
  15271. var timeout =
  15272. activeInfo.user.groupID <= 1
  15273. ? activeInfo.settings.homepage.refresh.adminPingRefresh
  15274. : activeInfo.settings.homepage.refresh.otherPingRefresh;
  15275. if (
  15276. Array.isArray(arrayItems["data"]["tabs"]) &&
  15277. arrayItems["data"]["tabs"].length > 0
  15278. ) {
  15279. $.each(arrayItems["data"]["tabs"], function (i, v) {
  15280. if (v.ping && v.ping_url !== null) {
  15281. pingList.push(v.ping_url);
  15282. }
  15283. });
  15284. }
  15285. return pingList.length > 0 ? pingUpdate(pingList, timeout) : false;
  15286. }
  15287. function pingUpdateItem(ping) {
  15288. if (activeInfo.user.groupID > activeInfo.settings.ping.auth) {
  15289. return false;
  15290. }
  15291. organizrAPI2("GET", "api/v2/ping/" + ping)
  15292. .success(function (data) {
  15293. try {
  15294. var response = data.response;
  15295. } catch (e) {
  15296. organizrCatchError(e, data);
  15297. }
  15298. var i = ping;
  15299. var v = response.data;
  15300. var elm = $(".menu-" + cleanClass(i) + "-ping");
  15301. var elmMs = $(".menu-" + cleanClass(i) + "-ping-ms");
  15302. var catElm = elm
  15303. .parent()
  15304. .parent()
  15305. .parent()
  15306. .parent()
  15307. .children("a")
  15308. .find(".menu-category-ping");
  15309. var error =
  15310. '<div class="ping"><span class="heartbit"></span><span class="point"></span></div>';
  15311. var success = "";
  15312. var badCount = 0;
  15313. var goodCount = 0;
  15314. var previousState =
  15315. elm.attr("data-previous-state") == ""
  15316. ? ""
  15317. : elm.attr("data-previous-state");
  15318. var tabName = elm.attr("data-tab-name");
  15319. var status = v == null ? "down" : "up";
  15320. var ms = v == null ? "down" : v + "ms";
  15321. var sendMessage =
  15322. previousState !== status &&
  15323. previousState !== "" &&
  15324. activeInfo.user.groupID <= activeInfo.settings.ping.authMessage
  15325. ? true
  15326. : false;
  15327. var audioDown = sendMessage
  15328. ? new Audio(activeInfo.settings.ping.offlineSound)
  15329. : "";
  15330. var audioUp = sendMessage
  15331. ? new Audio(activeInfo.settings.ping.onlineSound)
  15332. : "";
  15333. elm.attr("data-previous-state", status);
  15334. let listing = elm
  15335. .parent()
  15336. .parent()
  15337. .parent()
  15338. .parent()
  15339. .children("a")
  15340. .find(".menu-category-ping")
  15341. .parent()
  15342. .parent()
  15343. .find("li")
  15344. .find("div[class$='-ping']");
  15345. $.each(listing, function (i, v) {
  15346. let state = $(v).attr("data-previous-state");
  15347. if (state == "up") {
  15348. goodCount = goodCount + 1;
  15349. } else if (state == "down") {
  15350. badCount = badCount + 1;
  15351. }
  15352. });
  15353. if (catElm.length > 0) {
  15354. catElm.attr("data-bad", badCount);
  15355. catElm.attr("data-good", goodCount);
  15356. if (badCount == 0) {
  15357. catElm.html(success);
  15358. }
  15359. }
  15360. if (
  15361. activeInfo.user.groupID <= activeInfo.settings.ping.authMs &&
  15362. activeInfo.settings.ping.ms
  15363. ) {
  15364. elmMs.removeClass("hidden").html(ms);
  15365. }
  15366. switch (status) {
  15367. case "down":
  15368. elm.html(error);
  15369. catElm.html(error);
  15370. elm.parent().find("img").addClass("grayscale");
  15371. var msg = sendMessage
  15372. ? message(
  15373. tabName,
  15374. "Server Down",
  15375. activeInfo.settings.notifications.position,
  15376. "#FFF",
  15377. "error",
  15378. "600000"
  15379. )
  15380. : "";
  15381. var audio =
  15382. sendMessage && activeInfo.settings.ping.statusSounds
  15383. ? audioDown.play()
  15384. : "";
  15385. break;
  15386. default:
  15387. elm.html(success);
  15388. elm.parent().find("img").removeClass("grayscale");
  15389. var msg = sendMessage
  15390. ? message(
  15391. tabName,
  15392. "Server Back Online",
  15393. activeInfo.settings.notifications.position,
  15394. "#FFF",
  15395. "success",
  15396. "600000"
  15397. )
  15398. : "";
  15399. var audio =
  15400. sendMessage && activeInfo.settings.ping.statusSounds
  15401. ? audioUp.play()
  15402. : "";
  15403. }
  15404. })
  15405. .fail(function (xhr) {
  15406. OrganizrApiError(xhr);
  15407. });
  15408. }
  15409. function pingUpdate(pingList, timeout) {
  15410. $.each(pingList, function (i, v) {
  15411. pingUpdateItem(v);
  15412. });
  15413. var timeoutTitle = "ping";
  15414. if (typeof timeouts[timeoutTitle] !== "undefined") {
  15415. clearTimeout(timeouts[timeoutTitle]);
  15416. }
  15417. timeouts[timeoutTitle] = setTimeout(function () {
  15418. pingUpdate(pingList, timeout);
  15419. }, timeout);
  15420. }
  15421. function include(filename) {
  15422. var type = filename.split(".").pop();
  15423. switch (type) {
  15424. case "js":
  15425. var body = document.getElementsByTagName("body")[0];
  15426. var script = document.createElement("script");
  15427. script.src = filename;
  15428. script.type = "text/javascript";
  15429. body.appendChild(script);
  15430. break;
  15431. case "css":
  15432. var head = document.getElementById("style");
  15433. var script = document.createElement("link");
  15434. script.href = filename;
  15435. script.type = "text/css";
  15436. script.rel = "stylesheet";
  15437. head.appendChild(script);
  15438. break;
  15439. default:
  15440. return false;
  15441. }
  15442. return false;
  15443. }
  15444. function defineNotification() {
  15445. var bb =
  15446. typeof activeInfo !== "undefined"
  15447. ? activeInfo.settings.notifications.backbone
  15448. : "izi";
  15449. switch (bb) {
  15450. case "toastr":
  15451. include("plugins/bower_components/toast-master/css/jquery.toast.css");
  15452. include("plugins/bower_components/toast-master/js/jquery.toast.js");
  15453. window.notificationFunction = "$.toast";
  15454. break;
  15455. case "izi":
  15456. include("plugins/bower_components/iziToast/css/iziToast.min.css");
  15457. include("plugins/bower_components/iziToast/js/iziToast.min.js");
  15458. window.notificationFunction = "iziToast";
  15459. break;
  15460. case "alertify":
  15461. include("plugins/bower_components/alertify/alertify.min.css");
  15462. include("plugins/bower_components/alertify/default.min.css");
  15463. include("plugins/bower_components/alertify/alertify.min.js");
  15464. window.notificationFunction = "alertify";
  15465. break;
  15466. case "noty":
  15467. include("plugins/bower_components/noty/noty.min.js");
  15468. include("plugins/bower_components/noty/mo.min.js");
  15469. include("plugins/bower_components/noty/noty.css");
  15470. include("plugins/bower_components/noty/mint.css");
  15471. window.notificationFunction = "Noty";
  15472. break;
  15473. default:
  15474. return false;
  15475. }
  15476. window.notificationsReady = true;
  15477. }
  15478. function messagePositions() {
  15479. return {
  15480. br: {
  15481. toastr: "bottom-right",
  15482. alertify: "bottom-right",
  15483. izi: "bottomRight",
  15484. noty: "bottomRight",
  15485. },
  15486. bl: {
  15487. toastr: "bottom-left",
  15488. alertify: "bottom-left",
  15489. izi: "bottomLeft",
  15490. noty: "bottomLeft",
  15491. },
  15492. bc: {
  15493. toastr: "bottom-center",
  15494. alertify: "bottom-center",
  15495. izi: "bottomCenter",
  15496. noty: "bottomCenter",
  15497. },
  15498. tr: {
  15499. toastr: "top-right",
  15500. alertify: "top-right",
  15501. izi: "topRight",
  15502. noty: "topRight",
  15503. },
  15504. tl: {
  15505. toastr: "top-left",
  15506. alertify: "top-left",
  15507. izi: "topLeft",
  15508. noty: "topLeft",
  15509. },
  15510. tc: {
  15511. toastr: "top-center",
  15512. alertify: "top-center",
  15513. izi: "topCenter",
  15514. noty: "topCenter",
  15515. },
  15516. c: {
  15517. toastr: "center",
  15518. alertify: "bottom-center",
  15519. izi: "center",
  15520. noty: "center",
  15521. },
  15522. };
  15523. }
  15524. function message(
  15525. heading,
  15526. text,
  15527. position,
  15528. color,
  15529. icon,
  15530. timeout,
  15531. single = false
  15532. ) {
  15533. let bb =
  15534. typeof activeInfo !== "undefined"
  15535. ? activeInfo.settings.notifications.backbone
  15536. : "izi";
  15537. let activePosition =
  15538. typeof activeInfo !== "undefined"
  15539. ? activeInfo.settings.notifications.position
  15540. : "bc";
  15541. position = typeof position !== "undefined" ? position : activePosition;
  15542. text = typeof text !== "undefined" ? text : "";
  15543. color = typeof color !== "undefined" ? color : "#FFF";
  15544. icon = typeof icon !== "undefined" ? icon : "info";
  15545. timeout = typeof timeout !== "undefined" ? timeout : 10000;
  15546. switch (bb) {
  15547. case "toastr":
  15548. var ready = eval(notificationFunction) !== undefined ? true : false;
  15549. break;
  15550. case "izi":
  15551. case "alertify":
  15552. case "noty":
  15553. try {
  15554. var ready =
  15555. typeof eval(notificationFunction) !== undefined ? true : false;
  15556. } catch (e) {
  15557. if (e instanceof SyntaxError) {
  15558. setTimeout(function () {
  15559. message(heading, text, position, color, icon, timeout, single);
  15560. }, 100);
  15561. }
  15562. }
  15563. break;
  15564. default:
  15565. var ready = false;
  15566. }
  15567. if (notificationsReady && ready) {
  15568. oldPosition = position;
  15569. position = messagePositions()[position][bb];
  15570. if (typeof activeInfo === "undefined") {
  15571. setTimeout(function () {
  15572. message(heading, text, oldPosition, color, icon, timeout, single);
  15573. }, 100);
  15574. return false;
  15575. }
  15576. if (single) {
  15577. switch (bb) {
  15578. case "toastr":
  15579. $.toast().reset("all");
  15580. break;
  15581. case "izi":
  15582. iziToast.destroy();
  15583. break;
  15584. case "alertify":
  15585. alertify.dismissAll();
  15586. break;
  15587. case "noty":
  15588. Noty.closeAll();
  15589. break;
  15590. default:
  15591. return false;
  15592. }
  15593. }
  15594. switch (bb) {
  15595. case "toastr":
  15596. $.toast({
  15597. heading: heading,
  15598. text: text,
  15599. position: position,
  15600. loaderBg: color,
  15601. icon: icon,
  15602. hideAfter: timeout,
  15603. stack: 6,
  15604. showHideTransition: "slide",
  15605. });
  15606. break;
  15607. case "izi":
  15608. switch (icon) {
  15609. case "success":
  15610. var msg = {
  15611. icon: "mdi mdi-check-circle-outline",
  15612. };
  15613. break;
  15614. case "info":
  15615. var msg = {
  15616. icon: "mdi mdi-information-outline",
  15617. };
  15618. break;
  15619. case "error":
  15620. var msg = {
  15621. icon: "mdi mdi-close-circle-outline",
  15622. };
  15623. break;
  15624. case "warning":
  15625. var msg = {
  15626. icon: "mdi mdi-alert-circle-outline",
  15627. };
  15628. break;
  15629. case "update":
  15630. var msg = {
  15631. icon: "mdi mdi-webpack",
  15632. };
  15633. break;
  15634. default:
  15635. var msg = {
  15636. icon: "mdi mdi-alert-circle-outline",
  15637. };
  15638. }
  15639. iziToast.show({
  15640. close: true,
  15641. progressBar: true,
  15642. progressBarEasing: "ease",
  15643. class: icon + "-notify",
  15644. title: heading,
  15645. message: text,
  15646. position: position,
  15647. timeout: timeout,
  15648. layout: 2,
  15649. transitionIn: "flipInX",
  15650. transitionOut: "flipOutX",
  15651. balloon: false,
  15652. icon: msg["icon"],
  15653. });
  15654. break;
  15655. case "alertify":
  15656. var msgFull = heading !== "" ? heading + "<br/>" + text : text;
  15657. timeout = timeout / 1000;
  15658. alertify.set("notifier", "position", position);
  15659. alertify.notify(msgFull, icon + "-alertify", timeout);
  15660. break;
  15661. case "noty":
  15662. if (typeof mojs == "undefined") {
  15663. setTimeout(function () {
  15664. message(heading, text, oldPosition, color, icon, timeout);
  15665. }, 100);
  15666. return false;
  15667. }
  15668. var msgFull = heading !== "" ? heading + "<br/>" + text : text;
  15669. new Noty({
  15670. type: icon + "-noty",
  15671. layout: position,
  15672. text: msgFull,
  15673. progressBar: true,
  15674. timeout: timeout,
  15675. animation: {
  15676. open: function (promise) {
  15677. var n = this;
  15678. var Timeline = new mojs.Timeline();
  15679. var body = new mojs.Html({
  15680. el: n.barDom,
  15681. x: { 500: 0, delay: 0, duration: 500, easing: "elastic.out" },
  15682. isForce3d: true,
  15683. onComplete: function () {
  15684. promise(function (resolve) {
  15685. resolve();
  15686. });
  15687. },
  15688. });
  15689. var parent = new mojs.Shape({
  15690. parent: n.barDom,
  15691. width: 200,
  15692. height: n.barDom.getBoundingClientRect().height,
  15693. radius: 0,
  15694. x: { [150]: -150 },
  15695. duration: 1.2 * 500,
  15696. isShowStart: true,
  15697. });
  15698. n.barDom.style["overflow"] = "visible";
  15699. parent.el.style["overflow"] = "hidden";
  15700. var burst = new mojs.Burst({
  15701. parent: parent.el,
  15702. count: 10,
  15703. top: n.barDom.getBoundingClientRect().height + 75,
  15704. degree: 90,
  15705. radius: 75,
  15706. angle: { [-90]: 40 },
  15707. children: {
  15708. fill: "#EBD761",
  15709. delay: "stagger(500, -50)",
  15710. radius: "rand(8, 25)",
  15711. direction: -1,
  15712. isSwirl: true,
  15713. },
  15714. });
  15715. var fadeBurst = new mojs.Burst({
  15716. parent: parent.el,
  15717. count: 2,
  15718. degree: 0,
  15719. angle: 75,
  15720. radius: { 0: 100 },
  15721. top: "90%",
  15722. children: {
  15723. fill: "#EBD761",
  15724. pathScale: [0.65, 1],
  15725. radius: "rand(12, 15)",
  15726. direction: [-1, 1],
  15727. delay: 0.8 * 500,
  15728. isSwirl: true,
  15729. },
  15730. });
  15731. Timeline.add(body, burst, fadeBurst, parent);
  15732. Timeline.play();
  15733. },
  15734. close: function (promise) {
  15735. var n = this;
  15736. new mojs.Html({
  15737. el: n.barDom,
  15738. x: { 0: 500, delay: 10, duration: 500, easing: "cubic.out" },
  15739. skewY: { 0: 10, delay: 10, duration: 500, easing: "cubic.out" },
  15740. isForce3d: true,
  15741. onComplete: function () {
  15742. promise(function (resolve) {
  15743. resolve();
  15744. });
  15745. },
  15746. }).play();
  15747. },
  15748. },
  15749. }).show();
  15750. break;
  15751. default:
  15752. organizrConsole("Organizr Function", "Message case not setup");
  15753. }
  15754. } else {
  15755. setTimeout(function () {
  15756. message(heading, text, position, color, icon, timeout, single);
  15757. }, 100);
  15758. }
  15759. }
  15760. function messageSingle(heading, text, position, color, icon, timeout) {
  15761. let activePosition =
  15762. typeof activeInfo !== "undefined"
  15763. ? activeInfo.settings.notifications.position
  15764. : "bc";
  15765. position = typeof position !== "undefined" ? position : activePosition;
  15766. text = typeof text !== "undefined" ? text : "";
  15767. color = typeof color !== "undefined" ? color : "#FFF";
  15768. icon = typeof icon !== "undefined" ? icon : "info";
  15769. timeout = typeof timeout !== "undefined" ? timeout : 10000;
  15770. message(heading, text, position, color, icon, timeout, true);
  15771. }
  15772. function blockDev(e) {
  15773. var evtobj = window.event ? event : e;
  15774. if (evtobj.keyCode == 73 && evtobj.shiftKey && evtobj.ctrlKey) {
  15775. evtobj.preventDefault();
  15776. }
  15777. }
  15778. function authDebugCheck() {
  15779. if (activeInfo.settings.misc.authDebug == true) {
  15780. message(
  15781. "REMINDER",
  15782. "Auth Debug is still enabled",
  15783. activeInfo.settings.notifications.position,
  15784. "#FFF",
  15785. "warning",
  15786. "20000"
  15787. );
  15788. }
  15789. }
  15790. function lock() {
  15791. if (activeInfo.settings.user.oAuthLogin == true) {
  15792. message(
  15793. "Lock Disabled",
  15794. "Lock function disabled if logged in via oAuth",
  15795. activeInfo.settings.notifications.position,
  15796. "#FFF",
  15797. "warning",
  15798. "5000"
  15799. );
  15800. return false;
  15801. }
  15802. organizrAPI2("POST", "api/v2/users/lock", "")
  15803. .success(function (data) {
  15804. try {
  15805. let html = data.response;
  15806. location.reload();
  15807. } catch (e) {
  15808. organizrCatchError(e, data);
  15809. }
  15810. })
  15811. .fail(function (xhr) {
  15812. OrganizrApiError(xhr, "Lock Error");
  15813. });
  15814. }
  15815. function openSettings() {
  15816. let tabInfo = findTab("api/v2/page/settings", "access_url");
  15817. tabActions("click", tabInfo.id);
  15818. }
  15819. function openHomepage() {
  15820. let tabInfo = findTab("api/v2/page/homepage", "access_url");
  15821. tabActions("click", tabInfo.id);
  15822. }
  15823. function toggleFullScreenIcon() {
  15824. $(".fullscreen-icon")
  15825. .toggleClass("ti-fullscreen")
  15826. .toggleClass("mdi mdi-fullscreen-exit");
  15827. }
  15828. function toggleFullScreen() {
  15829. toggleFullScreenIcon();
  15830. if (
  15831. !document.fullscreenElement && // alternative standard method
  15832. !document.mozFullScreenElement &&
  15833. !document.webkitFullscreenElement &&
  15834. !document.msFullscreenElement
  15835. ) {
  15836. // current working methods
  15837. if (document.documentElement.requestFullscreen) {
  15838. document.documentElement.requestFullscreen();
  15839. } else if (document.documentElement.msRequestFullscreen) {
  15840. document.documentElement.msRequestFullscreen();
  15841. } else if (document.documentElement.mozRequestFullScreen) {
  15842. document.documentElement.mozRequestFullScreen();
  15843. } else if (document.documentElement.webkitRequestFullscreen) {
  15844. document.documentElement.webkitRequestFullscreen(
  15845. Element.ALLOW_KEYBOARD_INPUT
  15846. );
  15847. }
  15848. } else {
  15849. if (document.exitFullscreen) {
  15850. document.exitFullscreen();
  15851. } else if (document.msExitFullscreen) {
  15852. document.msExitFullscreen();
  15853. } else if (document.mozCancelFullScreen) {
  15854. document.mozCancelFullScreen();
  15855. } else if (document.webkitExitFullscreen) {
  15856. document.webkitExitFullscreen();
  15857. }
  15858. }
  15859. }
  15860. function orgErrorCode(code) {
  15861. switch (code) {
  15862. case "upgrading":
  15863. window.location.href = "./plugins/static/upgrade.html";
  15864. default:
  15865. }
  15866. }
  15867. function clickPath(type, path = null) {
  15868. switch (type) {
  15869. case "c":
  15870. case "custom":
  15871. if (path !== null) {
  15872. if (typeof path == "object") {
  15873. $.each(path, function (i, v) {
  15874. $(v).trigger("click");
  15875. });
  15876. } else {
  15877. $(path).trigger("click");
  15878. }
  15879. } else {
  15880. return null;
  15881. }
  15882. break;
  15883. case "update":
  15884. $("#settings-main-system-settings-anchor").trigger("click");
  15885. $("#settings-settings-updates-anchor").trigger("click");
  15886. break;
  15887. case "sso":
  15888. $("#settings-main-system-settings-anchor").trigger("click");
  15889. $("#settings-settings-sso-anchor").trigger("click");
  15890. break;
  15891. default:
  15892. return null;
  15893. }
  15894. }
  15895. function toggleWritableFolders() {
  15896. $(".folders-writable").toggleClass("hidden");
  15897. }
  15898. function getAllTabNames() {
  15899. var allTabs = $(".tabEditor");
  15900. var tabList = [];
  15901. $.each(allTabs, function (i, v) {
  15902. tabList[i] = v.getAttribute("data-name").toLowerCase();
  15903. });
  15904. return tabList;
  15905. }
  15906. function checkIfTabNameExists(tabName) {
  15907. if (getAllTabNames().indexOf(tabName.toLowerCase()) == -1) {
  15908. return false;
  15909. } else {
  15910. return true;
  15911. }
  15912. }
  15913. function getLatestBlackberryThemes() {
  15914. return $.ajax({
  15915. url: "https://api.github.com/repos/Archmonger/Blackberry-Themes/contents/Themes",
  15916. });
  15917. }
  15918. function getBlackberryTheme(theme) {
  15919. return $.ajax({
  15920. url:
  15921. "https://api.github.com/repos/Archmonger/Blackberry-Themes/contents/Themes/" +
  15922. theme +
  15923. "/Icons",
  15924. });
  15925. }
  15926. function showBlackberryThemes(target) {
  15927. getLatestBlackberryThemes()
  15928. .success(function (data) {
  15929. try {
  15930. let themes = "";
  15931. $.each(data, function (i, v) {
  15932. if (v.name !== "Beta") {
  15933. themes += `<a href="javascript:selectBlackberryTheme('${v.name}','${target}');" class="list-group-item"><span><img class="themeIcon pull-right" src="https://raw.githubusercontent.com/Archmonger/Blackberry-Themes/master/Themes/${v.name}/Icons/preview.png"></span>${v.name}</a>`;
  15934. }
  15935. });
  15936. themes = `<div class="list-group">${themes}</div>`;
  15937. let html = `
  15938. <div class="panel">
  15939. <div class="bg-org2">
  15940. <div class="panel-heading">Choose a Theme</div>
  15941. <div class="panel-body text-left">${themes}</div>
  15942. </div>
  15943. </div>
  15944. `;
  15945. swal({
  15946. content: createElementFromHTML(html),
  15947. button: "Close",
  15948. className: "orgErrorAlert",
  15949. dangerMode: true,
  15950. });
  15951. } catch (e) {
  15952. organizrCatchError(e, data);
  15953. }
  15954. })
  15955. .fail(function (xhr) {
  15956. OrganizrApiError(xhr);
  15957. });
  15958. }
  15959. function selectBlackberryTheme(theme, target) {
  15960. getBlackberryTheme(theme)
  15961. .success(function (data) {
  15962. try {
  15963. let icons = "";
  15964. $.each(data, function (i, v) {
  15965. v.name = v.name.split(".")[0];
  15966. v.name = cleanClass(v.name);
  15967. icons += `<a href="#" onclick="javascript:swal.close();$('#${target}').val('${v.download_url}')"><img alt="${v.name}" data-toggle="tooltip" data-placement="top" title="" data-original-title="${v.name}"src="${v.download_url}" ></a>`;
  15968. });
  15969. icons = `<div id="gallery-content-center">${icons}</div>`;
  15970. let html = `
  15971. <div class="panel">
  15972. <div class="bg-org2">
  15973. <div class="panel-heading">Choose an Icon</div>
  15974. <div class="panel-body text-left">${icons}</div>
  15975. </div>
  15976. </div>
  15977. `;
  15978. swal({
  15979. content: createElementFromHTML(html),
  15980. buttons: {
  15981. back: {
  15982. text: "Back To Themes",
  15983. value: "back",
  15984. dangerMode: true,
  15985. className: "bg-org-alt",
  15986. },
  15987. },
  15988. className: "orgErrorAlert",
  15989. dangerMode: true,
  15990. }).then((value) => {
  15991. switch (value) {
  15992. case "back":
  15993. showBlackberryThemes();
  15994. break;
  15995. }
  15996. });
  15997. } catch (e) {
  15998. organizrCatchError(e, data);
  15999. }
  16000. })
  16001. .fail(function (xhr) {
  16002. OrganizrApiError(xhr);
  16003. });
  16004. }
  16005. function orgErrorAlert(error) {
  16006. let showError = false;
  16007. if (typeof activeInfo === "undefined") {
  16008. showError = true;
  16009. } else {
  16010. if (activeInfo.settings.misc.debugErrors) {
  16011. showError = true;
  16012. }
  16013. }
  16014. if (showError) {
  16015. let div = `
  16016. <div class="panel">
  16017. <div class="bg-org2">
  16018. <div class="panel-heading">ERROR</div>
  16019. <div class="panel-body text-left">${error}</div>
  16020. </div>
  16021. </div>
  16022. `;
  16023. swal({
  16024. content: createElementFromHTML(div),
  16025. button: "OK",
  16026. className: "orgErrorAlert",
  16027. dangerMode: true,
  16028. });
  16029. }
  16030. }
  16031. function toggleDebug() {
  16032. var div = `
  16033. <div class="white-box m-0">
  16034. <div class="steamline">
  16035. <div class="sl-item">
  16036. <div class="sl-left bg-success"><i class="mdi mdi-code-tags"></i></div>
  16037. <div class="sl-right">
  16038. <div class="form-group">
  16039. <div id="" class="input-group">
  16040. <input id="debug-input" lang="en" placeholder="Input Command" type="text"
  16041. class="form-control inline-focus">
  16042. <div class="input-group-btn">
  16043. <button type="button"
  16044. class="btn waves-effect waves-light btn-info dropdown-toggle"
  16045. data-toggle="dropdown" aria-expanded="false"><span lang="en">Commands</span>
  16046. <span class="caret"></span></button>
  16047. <ul class="dropdown-menu dropdown-menu-right">
  16048. <li><a onclick="orgDebugList('activeInfo.settings.sso');"
  16049. href="javascript:void(0)"
  16050. lang="en">SSO</a></li>
  16051. <li><a onclick="orgDebugList('activeInfo.settings.sso.plex');"
  16052. href="javascript:void(0)"
  16053. lang="en">Plex SSO</a></li>
  16054. <li><a onclick="orgDebugList('activeInfo.settings.sso.tautulli');"
  16055. href="javascript:void(0)"
  16056. lang="en">Tautulli SSO</a></li>
  16057. <li><a onclick="orgDebugList('activeInfo.settings.sso.overseerr');"
  16058. href="javascript:void(0)"
  16059. lang="en">Overseerr SSO</a></li>
  16060. <li><a onclick="orgDebugList('activeInfo.settings.sso.petio');"
  16061. href="javascript:void(0)"
  16062. lang="en">Petio SSO</a></li>
  16063. <li><a onclick="orgDebugList('activeInfo.settings.sso.ombi');"
  16064. href="javascript:void(0)"
  16065. lang="en">Ombi SSO</a></li>
  16066. <li><a onclick="orgDebugList('activeInfo.settings.sso.jellyfin');"
  16067. href="javascript:void(0)"
  16068. lang="en">Jellyfin SSO</a></li>
  16069. <li><a onclick="orgDebugList('activeInfo.settings.sso.komga');"
  16070. href="javascript:void(0)"
  16071. lang="en">Komga SSO</a></li>
  16072. <li><a onclick="orgDebugList('activeInfo.settings.sso.misc');"
  16073. href="javascript:void(0)"
  16074. lang="en">Misc SSO</a></li>
  16075. <li><a onclick="orgDebugList('activeInfo.settings.misc.schema');"
  16076. href="javascript:void(0)"
  16077. lang="en">DB Schema</a></li>
  16078. </ul>
  16079. </div>
  16080. </div>
  16081. <div class="clearfix"></div>
  16082. </div>
  16083. </div>
  16084. </div>
  16085. <div id="debugPreInfoBox" class="sl-item text-left">
  16086. <div class="sl-left bg-info"><i class="mdi mdi-package-variant-closed"></i></div>
  16087. <div class="sl-right">
  16088. <div>
  16089. <span lang="en">Organizr Information:</span>&nbsp;
  16090. </div>
  16091. <div id="debugPreInfo" class="desc"></div>
  16092. </div>
  16093. </div>
  16094. <div id="debugResultsBox" class="sl-item hidden text-left">
  16095. <div class="sl-left bg-info"><i class="mdi mdi-receipt"></i></div>
  16096. <div class="sl-right">
  16097. <div><span lang="en">Results For cmd:</span>&nbsp;<span class="cmdName"></span>
  16098. </div>
  16099. <div id="debugResults" class="desc"></div>
  16100. </div>
  16101. </div>
  16102. </div>
  16103. </div>
  16104. `;
  16105. swal({
  16106. content: createElementFromHTML(div),
  16107. button: "OK",
  16108. className: "orgErrorAlert",
  16109. });
  16110. getDebugPreInfo();
  16111. }
  16112. function toggleCalendarFilter() {
  16113. var div = `
  16114. <div id="calendar-filter-modal" class="panel panel-inverse">
  16115. <div class="panel-heading"><span class="text-uppercase" lang="en">Filter Calendar</span></div>
  16116. <div class="panel-wrapper collapse in" aria-expanded="true">
  16117. <div class="panel-body">
  16118. <div class="row">
  16119. <div class="col-md-12">
  16120. <label class="control-label" lang="en">Choose Media Type</label>
  16121. <select class="form-control form-white" data-placeholder="Choose media type" id="choose-calender-filter">
  16122. <option value="all" lang="en">All</option>
  16123. <option value="tv" lang="en">TV</option>
  16124. <option value="film" lang="en">Movie</option>
  16125. <option value="music" lang="en">Music</option>
  16126. </select>
  16127. </div>
  16128. <div class="col-md-12">
  16129. <label class="control-label" lang="en">Choose Media Status</label>
  16130. <select class="form-control form-white" data-placeholder="Choose media status" id="choose-calender-filter-status">
  16131. <option value="all" lang="en">All</option>
  16132. <option value="text-success" lang="en">Downloaded</option>
  16133. <option value="text-info" lang="en">Unaired</option>
  16134. <option value="text-danger" lang="en">Missing</option>
  16135. <option value="text-primary animated flash" lang="en">Premier</option>
  16136. </select>
  16137. </div>
  16138. </div>
  16139. </div>
  16140. </div>
  16141. </div>
  16142. `;
  16143. swal({
  16144. content: createElementFromHTML(div),
  16145. className: "bg-org",
  16146. button: false,
  16147. });
  16148. }
  16149. function closeOrgError() {
  16150. $("#main-org-error-container").removeClass("show");
  16151. $("#main-org-error").html("");
  16152. }
  16153. function isJSON(data) {
  16154. if (typeof data != "string") {
  16155. data = JSON.stringify(data);
  16156. }
  16157. try {
  16158. JSON.parse(data);
  16159. return true;
  16160. } catch (e) {
  16161. return false;
  16162. }
  16163. }
  16164. function createElementFromHTML(htmlString) {
  16165. var div = document.createElement("div");
  16166. div.innerHTML = htmlString.trim();
  16167. return div.firstChild;
  16168. }
  16169. function addCoordinatesToInput(latitude, longitude) {
  16170. $("#homepage-Weather-Air-form [name=homepageWeatherAndAirLatitude]")
  16171. .val(latitude)
  16172. .change();
  16173. $("#homepage-Weather-Air-form [name=homepageWeatherAndAirLongitude]")
  16174. .val(longitude)
  16175. .change();
  16176. swal.close();
  16177. message(
  16178. "Coordinates Added",
  16179. "Please Save",
  16180. activeInfo.settings.notifications.position,
  16181. "#FFF",
  16182. "success",
  16183. "10000"
  16184. );
  16185. }
  16186. function searchCoordinatesAPI(query) {
  16187. messageSingle(
  16188. "Submitting Query",
  16189. "",
  16190. activeInfo.settings.notifications.position,
  16191. "#FFF",
  16192. "info",
  16193. "5000"
  16194. );
  16195. organizrAPI2("POST", "api/v2/homepage/weather/coordinates", { query: query })
  16196. .success(function (data) {
  16197. try {
  16198. let html = data.response;
  16199. if (html.data.type == "FeatureCollection") {
  16200. var entries = "";
  16201. $.each(html.data.features, function (i, v) {
  16202. entries +=
  16203. '<li class="text-left"><i class="fa fa-caret-right text-info"></i><span class="mouse" onclick="addCoordinatesToInput(\'' +
  16204. v.center[1] +
  16205. "','" +
  16206. v.center[0] +
  16207. "')\">" +
  16208. v.place_name +
  16209. "</span></li>";
  16210. });
  16211. var div =
  16212. `
  16213. <div class="row">
  16214. <div class="col-12">
  16215. <div class="card m-b-0">
  16216. <div class="form-horizontal">
  16217. <div class="card-body">
  16218. <h4 class="card-title" lang="en">Select Place</h4>
  16219. <div class="form-group row">
  16220. <div class="col-sm-12">
  16221. <ul class="list-icons">
  16222. ` +
  16223. entries +
  16224. `
  16225. </ul>
  16226. </div>
  16227. </div>
  16228. </div>
  16229. </div>
  16230. </div>
  16231. </div>
  16232. </div>
  16233. `;
  16234. if (entries !== "") {
  16235. swal.close();
  16236. swal({
  16237. content: createElementFromHTML(div),
  16238. buttons: false,
  16239. className: "bg-org",
  16240. });
  16241. } else {
  16242. message(
  16243. "API Error",
  16244. "No results found...",
  16245. activeInfo.settings.notifications.position,
  16246. "#FFF",
  16247. "warning",
  16248. "10000"
  16249. );
  16250. }
  16251. } else {
  16252. message(
  16253. "API Error",
  16254. "",
  16255. activeInfo.settings.notifications.position,
  16256. "#FFF",
  16257. "warning",
  16258. "10000"
  16259. );
  16260. console.error("Organizr Function: API failed");
  16261. }
  16262. } catch (e) {
  16263. organizrCatchError(e, data);
  16264. }
  16265. })
  16266. .fail(function (xhr) {
  16267. OrganizrApiError(xhr, "API Error");
  16268. });
  16269. }
  16270. function showLookupCoordinatesModal() {
  16271. var div = `
  16272. <div class="row">
  16273. <div class="col-12">
  16274. <div class="card m-b-0">
  16275. <div class="form-horizontal">
  16276. <div class="card-body">
  16277. <h4 class="card-title" lang="en">Enter City or Address</h4>
  16278. <div class="form-group row">
  16279. <div class="col-sm-12">
  16280. <input type="text" class="form-control" id="coordinatesModalCityInput" placeholder="Enter City or Address...">
  16281. </div>
  16282. </div>
  16283. <div class="form-group mb-0 p-r-10 text-right">
  16284. <button type="submit" onclick="searchCoordinatesAPI($('#coordinatesModalCityInput').val())" class="btn btn-info waves-effect waves-light">Submit</button>
  16285. </div>
  16286. </div>
  16287. </div>
  16288. </div>
  16289. </div>
  16290. </div>
  16291. `;
  16292. swal({
  16293. content: createElementFromHTML(div),
  16294. buttons: false,
  16295. className: "bg-org",
  16296. });
  16297. }
  16298. function showLDAPLoginTest() {
  16299. var div = `
  16300. <div class="row">
  16301. <div class="col-12">
  16302. <div class="card m-b-0">
  16303. <div class="form-horizontal">
  16304. <div class="card-body">
  16305. <h4 class="card-title" lang="en">LDAP User Info</h4>
  16306. <div class="form-group row">
  16307. <div class="col-sm-12">
  16308. <input type="text" class="form-control" id="ldapUsernameTest" placeholder="Username">
  16309. </div>
  16310. </div>
  16311. <div class="form-group row">
  16312. <div class="col-sm-12">
  16313. <input type="password" class="form-control" id="ldapPasswordTest" placeholder="Password">
  16314. </div>
  16315. </div>
  16316. <div class="form-group mb-0 p-r-10 text-right">
  16317. <button type="submit" onclick="testAPIConnection('ldap/login', {'username':$('#ldapUsernameTest').val(),'password':$('#ldapPasswordTest').val()})" class="btn btn-info waves-effect waves-light">Test Login</button>
  16318. </div>
  16319. </div>
  16320. </div>
  16321. </div>
  16322. </div>
  16323. </div>
  16324. `;
  16325. swal({
  16326. content: createElementFromHTML(div),
  16327. buttons: false,
  16328. className: "bg-org",
  16329. });
  16330. }
  16331. function showPlexTokenForm(selector = null) {
  16332. var div =
  16333. `
  16334. <form id="get-plex-token-form">
  16335. <h1 lang="en">Get Plex Token</h1>
  16336. <div class="panel plexTokenHeader">
  16337. <div class="panel-heading plexTokenMessage" lang="en">Enter Plex Details</div>
  16338. </div>
  16339. <fieldset style="border:0;">
  16340. <div class="form-group">
  16341. <label class="control-label" for="plex-token-form-username" lang="en">Plex Username</label>
  16342. <input type="text" class="form-control" id="plex-token-form-username" name="username" required="" autofocus>
  16343. </div>
  16344. <div class="form-group">
  16345. <label class="control-label" for="plex-token-form-password" lang="en">Plex Password</label>
  16346. <input type="password" class="form-control" id="plex-token-form-password" name="password" required="">
  16347. </div>
  16348. <div class="form-group">
  16349. <label class="control-label" for="plex-token-form-tfa" lang="en">Plex 2FA (if applicable)</label>
  16350. <input type="text" class="form-control" id="plex-token-form-tfa" name="tfa" >
  16351. </div>
  16352. </fieldset>
  16353. <button class="btn btn-sm btn-info btn-rounded waves-effect waves-light pull-right row b-none" onclick="getPlexToken('` +
  16354. selector +
  16355. `')" type="button"><span class="btn-label"><i class="fa fa-ticket"></i></span><span lang="en">Grab It</span></button>
  16356. <div class="clearfix"></div>
  16357. </form>
  16358. `;
  16359. swal({
  16360. content: createElementFromHTML(div),
  16361. buttons: false,
  16362. className: "bg-org",
  16363. });
  16364. }
  16365. function getPlexToken(selector) {
  16366. $(".plexTokenMessage").text("Grabbing Token");
  16367. $(".plexTokenHeader")
  16368. .addClass("panel-info")
  16369. .removeClass("panel-warning")
  16370. .removeClass("panel-danger");
  16371. var plex_username = $("#get-plex-token-form [name=username]").val().trim();
  16372. var plex_password = $("#get-plex-token-form [name=password]").val().trim();
  16373. var plex_tfa = $("#get-plex-token-form [name=tfa]").val().trim();
  16374. if (plex_password !== "" && plex_password !== "") {
  16375. $.ajax({
  16376. type: "POST",
  16377. headers: {
  16378. "X-Plex-Product": "Organizr",
  16379. "X-Plex-Version": "2.0",
  16380. "X-Plex-Client-Identifier": "01010101-10101010",
  16381. },
  16382. url: "https://plex.tv/users/sign_in.json",
  16383. data: {
  16384. "user[login]": plex_username,
  16385. "user[password]": plex_password + plex_tfa,
  16386. force: true,
  16387. },
  16388. cache: false,
  16389. async: true,
  16390. complete: function (xhr, status) {
  16391. var result = $.parseJSON(xhr.responseText);
  16392. if (xhr.status === 201) {
  16393. $(".plexTokenMessage").text(xhr.statusText);
  16394. $(".plexTokenHeader")
  16395. .addClass("panel-success")
  16396. .removeClass("panel-info")
  16397. .removeClass("panel-warning")
  16398. .removeClass("panel-danger");
  16399. $(selector).val(result.user.authToken);
  16400. $(selector).change();
  16401. messageSingle(
  16402. "Token created",
  16403. "Please save...",
  16404. activeInfo.settings.notifications.position,
  16405. "#FFF",
  16406. "success",
  16407. "5000"
  16408. );
  16409. } else {
  16410. $(".plexTokenMessage").text(xhr.statusText);
  16411. $(".plexTokenHeader")
  16412. .addClass("panel-danger")
  16413. .removeClass("panel-info")
  16414. .removeClass("panel-warning");
  16415. }
  16416. },
  16417. });
  16418. } else {
  16419. $(".plexTokenMessage").text("Enter Username and Password");
  16420. $(".plexTokenHeader")
  16421. .addClass("panel-warning")
  16422. .removeClass("panel-info")
  16423. .removeClass("panel-danger");
  16424. }
  16425. }
  16426. function showPlexMachineForm(selector = null) {
  16427. var div = `
  16428. <form id="get-plex-machine-form">
  16429. <h1 lang="en">Get Plex Machine</h1>
  16430. <div class="panel plexMachineHeader">
  16431. <div class="panel-heading plexMachineMessage" lang="en">Contacting server...</div>
  16432. </div>
  16433. <fieldset style="border:0;">
  16434. <div class="form-group">
  16435. <label class="control-label" for="plex-machine-form-machine" lang="en">Plex Machine</label>
  16436. <div class="plexMachineListing"></div>
  16437. </div>
  16438. </fieldset>
  16439. <div class="clearfix"></div>
  16440. </form>
  16441. `;
  16442. swal({
  16443. content: createElementFromHTML(div),
  16444. buttons: false,
  16445. className: "bg-org",
  16446. }).then(
  16447. organizrAPI2("GET", "api/v2/plex/servers?owned")
  16448. .success(function (data) {
  16449. try {
  16450. let response = data.response;
  16451. $(".plexMachineMessage").text("Choose Plex Server");
  16452. $(".plexMachineHeader")
  16453. .addClass("panel-success")
  16454. .removeClass("panel-info")
  16455. .removeClass("panel-warning");
  16456. let machines = '<option lang="en">Choose Plex Machine</option>';
  16457. $.each(response.data, function (i, v) {
  16458. let name = v.name;
  16459. let machine = v.machineIdentifier;
  16460. name = name + " [" + machine + "]";
  16461. machines += '<option value="' + machine + '">' + name + "</option>";
  16462. });
  16463. let listing =
  16464. '<select class="form-control" id="plexMachineSelector" data-selector="' +
  16465. selector +
  16466. '" data-type="select">' +
  16467. machines +
  16468. "</select>";
  16469. $(".plexMachineListing").html(listing);
  16470. } catch (e) {
  16471. organizrCatchError(e, data);
  16472. }
  16473. })
  16474. .fail(function (xhr) {
  16475. OrganizrApiError(xhr, "API Error");
  16476. $(".plexMachineMessage").text("Plex Token Needed First");
  16477. $(".plexMachineHeader")
  16478. .addClass("panel-warning")
  16479. .removeClass("panel-info")
  16480. .removeClass("panel-danger");
  16481. })
  16482. );
  16483. }
  16484. function bypassLocalLogin() {
  16485. if (activeInfo.settings.user.bypass !== true) {
  16486. return false;
  16487. }
  16488. const bypass = $.urlParam("bypassDisable");
  16489. if (bypass) {
  16490. return false;
  16491. }
  16492. OAuthLoginNeeded = true;
  16493. oAuthLoginNeededCheck("Bypass");
  16494. }
  16495. function oAuthLoginNeededCheck(type = "OAuth") {
  16496. if (OAuthLoginNeeded == false) {
  16497. return false;
  16498. } else {
  16499. if (activeInfo.user.loggedin == true) {
  16500. return false;
  16501. }
  16502. }
  16503. let data = "";
  16504. if (type === "Bypass") {
  16505. const bypass = $.urlParam("bypassDisable");
  16506. if (bypass) {
  16507. data = "bypass";
  16508. }
  16509. }
  16510. message(
  16511. type,
  16512. " Proceeding to login",
  16513. activeInfo.settings.notifications.position,
  16514. "#FFF",
  16515. "info",
  16516. "10000"
  16517. );
  16518. organizrAPI2("POST", "api/v2/login", data)
  16519. .success(function (data) {
  16520. local("set", "message", "Welcome|Login Successful|success");
  16521. local("r", "loggingIn");
  16522. location.reload();
  16523. })
  16524. .fail(function (xhr) {
  16525. $("div.login-box").unblock({});
  16526. switch (xhr.status) {
  16527. case 401:
  16528. if (xhr.responseJSON.response.message == "2FA Code incorrect") {
  16529. $("div.login-box").unblock({});
  16530. $("#tfa-div").removeClass("hidden");
  16531. $("#loginform [name=tfaCode]").focus();
  16532. }
  16533. break;
  16534. case 403:
  16535. $("div.login-box").block({
  16536. message: '<h5><i class="fa fa-close"></i> Locked Out!</h4>',
  16537. css: {
  16538. color: "#fff",
  16539. border: "1px solid #e91e63",
  16540. backgroundColor: "#f44336",
  16541. },
  16542. });
  16543. setTimeout(function () {
  16544. local("r", "loggingIn");
  16545. location.reload();
  16546. }, 10000);
  16547. break;
  16548. case 422:
  16549. $("div.login-box").unblock({});
  16550. $("#tfa-div").removeClass("hidden");
  16551. $("#loginform [name=tfaCode]").focus();
  16552. break;
  16553. default:
  16554. message(
  16555. "Login Error",
  16556. "API Connection Failed",
  16557. activeInfo.settings.notifications.position,
  16558. "#FFF",
  16559. "error",
  16560. "10000"
  16561. );
  16562. console.error("Organizr Function: API Connection Failed");
  16563. }
  16564. message(
  16565. "Login Error",
  16566. xhr.responseJSON.response.message,
  16567. activeInfo.settings.notifications.position,
  16568. "#FFF",
  16569. "warning",
  16570. "10000"
  16571. );
  16572. console.error("Organizr Function: " + xhr.responseJSON.response.message);
  16573. local("r", "loggingIn");
  16574. });
  16575. }
  16576. function ipInfoSpan(ip) {
  16577. return '<span class="ipInfo mouse">' + ip + "</span>";
  16578. }
  16579. function jsFriendlyJSONStringify(s) {
  16580. return JSON.stringify(s)
  16581. .replace("'", "")
  16582. .replace(/\u2028/g, "\\u2028")
  16583. .replace(/\u2029/g, "\\u2029");
  16584. }
  16585. function exportLogs() {
  16586. const query = "api/v2/log/0?filter=NONE&pageSize=1000&offset=0";
  16587. $.get(query, function (data) {
  16588. const logs = data.response.data.results;
  16589. let csvContent =
  16590. "data:text/csv;charset=utf-8,Date,Severity,Function,Message,IP Address,User\n";
  16591. logs.forEach(function (log) {
  16592. const row = [
  16593. log.datetime,
  16594. log.log_level,
  16595. log.channel,
  16596. log.message,
  16597. log.remote_ip_address,
  16598. log.username,
  16599. ].join(",");
  16600. csvContent += row + "\n";
  16601. });
  16602. const encodedUri = encodeURI(csvContent);
  16603. const link = document.createElement("a");
  16604. link.setAttribute("href", encodedUri);
  16605. link.setAttribute("download", "organizr_logs.csv");
  16606. document.body.appendChild(link);
  16607. link.click();
  16608. document.body.removeChild(link);
  16609. });
  16610. }
  16611. function logContext(row) {
  16612. let buttons = "";
  16613. buttons +=
  16614. Object.keys(row).length > 0
  16615. ? '<button data-toggle="tooltip" title="" data-original-title="View Details" class="btn btn-xs btn-primary waves-effect waves-light log-details m-r-5" data-trace="' +
  16616. row.trace_id +
  16617. '"><i class="mdi mdi-file-find"></i></button>'
  16618. : "";
  16619. buttons +=
  16620. Object.keys(row).length > 0
  16621. ? '<button data-toggle="tooltip" title="" data-original-title="Copy Log" class="btn btn-xs btn-info waves-effect waves-light log-details m-r-5" data-trace="' +
  16622. row.trace_id +
  16623. '" data-clipboard="true"><i class="mdi mdi-content-copy"></i></button>'
  16624. : "";
  16625. return buttons;
  16626. }
  16627. function formatLogDetails(details) {
  16628. if (!details) {
  16629. return false;
  16630. }
  16631. let m = moment.tz(details.datetime + "Z", activeInfo.timezone);
  16632. details.datetime = moment(m).format("LLL");
  16633. let items = "";
  16634. items += `<li><div class="bg-inverse"><i class="mdi mdi-calendar-text text-white"></i></div> ${details.datetime}<span class="text-muted" lang="en">Date</span></li>`;
  16635. items += `<li><div class="bg-warning"><i class="mdi mdi-robot text-white"></i></div> ${details.trace_id}<span class="text-muted" lang="en">Trace ID</span></li>`;
  16636. items += `<li><div class="bg-primary"><i class="mdi mdi-account-box-outline text-white"></i></div> ${details.username}<span class="text-muted" lang="en">User</span></li>`;
  16637. items += `<li><div class="bg-info"><i class="mdi mdi-function text-white"></i></div> ${details.channel}<span class="text-muted" lang="en">Function</span></li>`;
  16638. items += `<li><div class="bg-plex"><i class="mdi mdi-language-php text-white"></i></div> ${details.file}<code>#L${details.line}</code><span class="text-muted" lang="en">File</span></li>`;
  16639. let items2 = "";
  16640. items2 +=
  16641. Object.keys(details.context).length > 0
  16642. ? `<div class="sl-item"><div class="sl-left bg-inverse"> <i class="mdi mdi-json"></i></div><div class="sl-right"><div class="p-t-10 desc" lang="en">Context</div></div><pre class="m-5 fc-scroller">${JSON.stringify(
  16643. details.context,
  16644. null,
  16645. 5
  16646. )}</pre></div>`
  16647. : "";
  16648. items2 +=
  16649. typeof details.errors !== "undefined"
  16650. ? `<div class="sl-item"><div class="sl-left bg-danger"> <i class="mdi mdi-code-braces"></i></div><div class="sl-right"><div class="p-t-10 desc" lang="en">Errors</div></div><pre class="m-5 fc-scroller">${JSON.stringify(
  16651. details.errors,
  16652. null,
  16653. 5
  16654. )}</pre></div>`
  16655. : "";
  16656. var div = `
  16657. <div class="col-lg-12">
  16658. <div class="panel panel-default text-left">
  16659. <div class="panel-heading"><i class="mdi mdi-file-find fa-lg fa-2x"></i> <span lang="en">Log Details</span> <span class="pull-right">${logIcon(
  16660. details.log_level,
  16661. true
  16662. )}</span></div>
  16663. <div class="panel-wrapper collapse in">
  16664. <div class="panel-body bg-org">
  16665. <h3>${details.message}</h3>
  16666. <div class="white-box">
  16667. <ul class="feeds">
  16668. ${items}
  16669. </ul>
  16670. </div>
  16671. <div class="steamline">
  16672. ${items2}
  16673. </div>
  16674. </div>
  16675. </div>
  16676. </div>
  16677. </div>`;
  16678. swal({
  16679. content: createElementFromHTML(div),
  16680. buttons: false,
  16681. className: "orgAlertTransparent",
  16682. });
  16683. pageLoad();
  16684. }
  16685. function checkToken(activate = false) {
  16686. if (typeof activeInfo !== "undefined") {
  16687. if (typeof activeInfo.settings.misc.uuid !== "undefined") {
  16688. var token = getCookie("organizr_token_" + activeInfo.settings.misc.uuid);
  16689. if (token) {
  16690. setTimeout(function () {
  16691. checkToken(true);
  16692. }, 5000);
  16693. } else {
  16694. if (activate) {
  16695. local(
  16696. "set",
  16697. "message",
  16698. "Token Expired|You have been logged out|error"
  16699. );
  16700. location.reload();
  16701. }
  16702. }
  16703. }
  16704. }
  16705. }
  16706. function objDiff(obj1, obj2) {
  16707. // Make sure an object to compare is provided
  16708. if (!obj2 || Object.prototype.toString.call(obj2) !== "[object Object]") {
  16709. return obj1;
  16710. }
  16711. //
  16712. // Variables
  16713. //
  16714. var diffs = {};
  16715. var key;
  16716. //
  16717. // Methods
  16718. //
  16719. /**
  16720. * Check if two arrays are equal
  16721. * @param {Array} arr1 The first array
  16722. * @param {Array} arr2 The second array
  16723. * @return {Boolean} If true, both arrays are equal
  16724. */
  16725. var arraysMatch = function (arr1, arr2) {
  16726. // Check if the arrays are the same length
  16727. if (arr1.length !== arr2.length) return false;
  16728. // Check if all items exist and are in the same order
  16729. for (var i = 0; i < arr1.length; i++) {
  16730. if (arr1[i] !== arr2[i]) return false;
  16731. }
  16732. // Otherwise, return true
  16733. return true;
  16734. };
  16735. /**
  16736. * Compare two items and push non-matches to object
  16737. * @param {*} item1 The first item
  16738. * @param {*} item2 The second item
  16739. * @param {String} key The key in our object
  16740. */
  16741. var compare = function (item1, item2, key) {
  16742. // Get the object type
  16743. var type1 = Object.prototype.toString.call(item1);
  16744. var type2 = Object.prototype.toString.call(item2);
  16745. // If type2 is undefined it has been removed
  16746. if (type2 === "[object Undefined]") {
  16747. diffs[key] = null;
  16748. return;
  16749. }
  16750. // If items are different types
  16751. if (type1 !== type2) {
  16752. diffs[key] = item2;
  16753. return;
  16754. }
  16755. // If an object, compare recursively
  16756. if (type1 === "[object Object]") {
  16757. var objDifference = objDiff(item1, item2);
  16758. if (Object.keys(objDifference).length > 1) {
  16759. diffs[key] = objDifference;
  16760. }
  16761. return;
  16762. }
  16763. // If an array, compare
  16764. if (type1 === "[object Array]") {
  16765. if (!arraysMatch(item1, item2)) {
  16766. diffs[key] = item2;
  16767. }
  16768. return;
  16769. }
  16770. // Else if it's a function, convert to a string and compare
  16771. // Otherwise, just compare
  16772. if (type1 === "[object Function]") {
  16773. if (item1.toString() !== item2.toString()) {
  16774. diffs[key] = item2;
  16775. }
  16776. } else {
  16777. if (item1 !== item2) {
  16778. diffs[key] = item2;
  16779. }
  16780. }
  16781. };
  16782. //
  16783. // Compare our objects
  16784. //
  16785. // Loop through the first object
  16786. for (key in obj1) {
  16787. if (obj1.hasOwnProperty(key)) {
  16788. compare(obj1[key], obj2[key], key);
  16789. }
  16790. }
  16791. // Loop through the second object and find missing items
  16792. for (key in obj2) {
  16793. if (obj2.hasOwnProperty(key)) {
  16794. if (!obj1[key] && obj1[key] !== obj2[key]) {
  16795. diffs[key] = obj2[key];
  16796. }
  16797. }
  16798. }
  16799. // Return the object of differences
  16800. return diffs;
  16801. }
  16802. function organizrConsole(subject, msg, type = "info") {
  16803. let color;
  16804. switch (type) {
  16805. case "error":
  16806. color = "#ed2e72";
  16807. break;
  16808. case "warning":
  16809. color = "#272361";
  16810. break;
  16811. default:
  16812. color = "#2cabe3";
  16813. break;
  16814. }
  16815. console.info(
  16816. "%c " + subject + " %c ".concat(msg, " "),
  16817. "color: white; background: " + color + "; font-weight: 700;",
  16818. "color: " + color + "; background: white; font-weight: 700;"
  16819. );
  16820. }
  16821. function organizrCatchError(e, data) {
  16822. organizrConsole("Organizr API Function", data, "warning");
  16823. orgErrorAlert(
  16824. "<h4>" +
  16825. e +
  16826. '</h4><p><mark lang="en">Trace Log has been outputted to Browser Console</mark></p><h5 lang="en">Output of last API call</h5>' +
  16827. formatDebug(data)
  16828. );
  16829. console.trace();
  16830. return false;
  16831. }
  16832. function OrganizrApiError(xhr, secondaryMessage = null) {
  16833. let msg = "";
  16834. if (typeof xhr.responseJSON !== "undefined") {
  16835. msg = xhr.responseJSON.response.message;
  16836. } else if (typeof xhr.statusText !== "undefined") {
  16837. msg = xhr.statusText;
  16838. } else if (typeof xhr.responseText !== "undefined") {
  16839. msg = xhr.responseText;
  16840. } else {
  16841. msg = "Connection Error";
  16842. }
  16843. organizrConsole("Organizr API Function", msg, "error");
  16844. if (msg !== "abort") {
  16845. if (secondaryMessage) {
  16846. messageSingle(
  16847. secondaryMessage,
  16848. msg,
  16849. activeInfo.settings.notifications.position,
  16850. "#FFF",
  16851. "error",
  16852. "10000"
  16853. );
  16854. }
  16855. console.trace();
  16856. }
  16857. return false;
  16858. }
  16859. function checkForUpdates() {
  16860. if (
  16861. activeInfo.user.loggedin &&
  16862. activeInfo.user.groupID <= 1 &&
  16863. activeInfo.settings.misc.checkForUpdate
  16864. ) {
  16865. updateCheck();
  16866. checkCommitLoad();
  16867. checkPluginUpdates();
  16868. }
  16869. }
  16870. function loadJavascript(script = null, defer = false) {
  16871. if (script) {
  16872. organizrConsole("JS Loader", script);
  16873. organizrConsole("JS Loader", "Checking if script is loaded...");
  16874. let loaded = $('script[src="' + script + '"]').length;
  16875. if (!loaded) {
  16876. organizrConsole("JS Loader", "Script is NOT loaded... Loading now...");
  16877. let head = document.getElementsByTagName("head")[0];
  16878. let scriptEl = document.createElement("script");
  16879. scriptEl.type = "text/javascript";
  16880. scriptEl.src = script;
  16881. scriptEl.defer = false;
  16882. head.appendChild(scriptEl);
  16883. } else {
  16884. organizrConsole("JS Loader", "Script already loaded");
  16885. }
  16886. }
  16887. }
  16888. function tabShit() {}
  16889. function msToTime(s) {
  16890. let pad = (n, z = 2) => ("00" + n).slice(-z);
  16891. let hours = pad((s / 3.6e6) | 0) !== "00" ? pad((s / 3.6e6) | 0) + ":" : "";
  16892. let mins = pad(((s % 3.6e6) / 6e4) | 0) + ":";
  16893. let secs = pad(((s % 6e4) / 1000) | 0);
  16894. let ms = pad(s % 1000, 3);
  16895. if (ms >= "500") {
  16896. secs = pad(parseFloat(secs) + 1, 2);
  16897. }
  16898. return hours + mins + secs;
  16899. }
  16900. function clickSettingsTab() {
  16901. let tabs = $(".allTabsList");
  16902. $.each(tabs, function (i, v) {
  16903. let tab = $(v);
  16904. if (tab.attr("data-url") == "api/v2/page/settings") {
  16905. tab.find("a").trigger("click");
  16906. }
  16907. });
  16908. }
  16909. function clickMenuItem(selector) {
  16910. if ($(selector).length >= 1) {
  16911. $(selector).click();
  16912. } else {
  16913. $("body").arrive(selector, { onceOnly: true }, function () {
  16914. $(selector).click();
  16915. });
  16916. }
  16917. }
  16918. function shortcut(selectors = "") {
  16919. let timeout = 200;
  16920. if (typeof selectors == "string") {
  16921. if (selectors == "") {
  16922. selectors = [];
  16923. } else {
  16924. switch (selectors) {
  16925. case "log-settings":
  16926. clickSettingsTab();
  16927. selectors = [
  16928. "#settings-main-system-settings-anchor",
  16929. "#settings-settings-main-anchor",
  16930. 'a[href$="Logs"]',
  16931. ];
  16932. break;
  16933. case "plugin-marketplace":
  16934. clickSettingsTab();
  16935. selectors = [
  16936. "#settings-main-plugins-anchor",
  16937. "#settings-plugins-marketplace-anchor",
  16938. ];
  16939. break;
  16940. case "custom-cert":
  16941. clickSettingsTab();
  16942. selectors = [
  16943. "#settings-main-system-settings-anchor",
  16944. "#settings-settings-main-anchor",
  16945. 'a[href$="Certificate"]',
  16946. ];
  16947. break;
  16948. default:
  16949. clickSettingsTab();
  16950. selectors = ["#settings-main-system-settings-anchor"];
  16951. }
  16952. }
  16953. }
  16954. selectors.forEach(function (selector) {
  16955. timeout = timeout + 200;
  16956. setTimeout(function () {
  16957. clickMenuItem(selector);
  16958. }, timeout);
  16959. });
  16960. }
  16961. function getJournalMode() {
  16962. organizrAPI2("GET", "api/v2/database/journal")
  16963. .success(function (data) {
  16964. try {
  16965. let response = data.response;
  16966. $(".journal-mode").html(response.data.journal_mode);
  16967. } catch (e) {
  16968. organizrCatchError(e, data);
  16969. }
  16970. })
  16971. .fail(function (xhr) {
  16972. OrganizrApiError(xhr);
  16973. });
  16974. }
  16975. function setJournalMode(mode) {
  16976. messageSingle(
  16977. "Setting New Journal Mode",
  16978. "",
  16979. activeInfo.settings.notifications.position,
  16980. "#FFF",
  16981. "info",
  16982. "1500"
  16983. );
  16984. organizrAPI2("PUT", "api/v2/database/journal/" + mode, {})
  16985. .success(function (data) {
  16986. try {
  16987. getJournalMode();
  16988. let response = data.response;
  16989. message(
  16990. "Set New Journal Mode",
  16991. response.data.journal_mode,
  16992. activeInfo.settings.notifications.position,
  16993. "#FFF",
  16994. "success",
  16995. "5000"
  16996. );
  16997. } catch (e) {
  16998. organizrCatchError(e, data);
  16999. }
  17000. })
  17001. .fail(function (xhr) {
  17002. OrganizrApiError(xhr);
  17003. });
  17004. }
  17005. function toggleSideMenuClasses() {
  17006. $("#page-wrapper").toggleClass("sidebar-hidden");
  17007. $(".sidebar").toggleClass("sidebar-hidden");
  17008. $(".navbar").toggleClass("sidebar-hidden");
  17009. }
  17010. function sideMenuCollapsed() {
  17011. if (activeInfo.settings.misc.sideMenuCollapsed) {
  17012. toggleSideMenuClasses();
  17013. }
  17014. }
  17015. function toggleSideMenu() {
  17016. toggleSideMenuClasses();
  17017. $(".sidebar-head .open-close i")
  17018. .first()
  17019. .toggleClass("ti-menu ti-shift-left mouse");
  17020. $(".toggle-side-menu").toggleClass("hidden");
  17021. }
  17022. function toggleTopBarHamburger() {
  17023. toggleSideMenuClasses();
  17024. $(".sidebar-head .hide-menu.hidden-xs").text("Hide Menu");
  17025. $(".sidebar-head .open-close i")
  17026. .first()
  17027. .toggleClass("ti-menu ti-shift-left mouse");
  17028. $(".toggle-side-menu").toggleClass("hidden");
  17029. }
  17030. function toggleLogFilter(filter = "INFO") {
  17031. //choose-organizr-log
  17032. filter = filter.toUpperCase();
  17033. $.each($(".choose-organizr-log").children(), function (i, v) {
  17034. let url = $(v).val();
  17035. let newURL = updateUrlParameter(url, "filter", filter);
  17036. $(v).val(newURL);
  17037. });
  17038. $(".log-filter-text").text(filter);
  17039. $(".log-filter-text").text(filter);
  17040. let currentURL = organizrLogTable.ajax.url();
  17041. let updatedURL = updateUrlParameter(currentURL, "filter", filter);
  17042. organizrLogTable.ajax.url(updatedURL);
  17043. organizrLogTable.clear().draw().ajax.reload(null, false);
  17044. }
  17045. function updateUrlParameter(uri, key, value) {
  17046. // remove the hash part before operating on the uri
  17047. var i = uri.indexOf("#");
  17048. var hash = i === -1 ? "" : uri.substr(i);
  17049. uri = i === -1 ? uri : uri.substr(0, i);
  17050. var re = new RegExp("([?&])" + key + "=.*?(&|$)", "i");
  17051. var separator = uri.indexOf("?") !== -1 ? "&" : "?";
  17052. if (value === null) {
  17053. // remove key-value pair if value is specifically null
  17054. uri = uri.replace(new RegExp("([?&]?)" + key + "=[^&]*", "i"), "");
  17055. if (uri.slice(-1) === "?") {
  17056. uri = uri.slice(0, -1);
  17057. }
  17058. // replace first occurrence of & by ? if no ? is present
  17059. if (uri.indexOf("?") === -1) uri = uri.replace(/&/, "?");
  17060. } else if (uri.match(re)) {
  17061. uri = uri.replace(re, "$1" + key + "=" + value + "$2");
  17062. } else {
  17063. uri = uri + separator + key + "=" + value;
  17064. }
  17065. return uri + hash;
  17066. }
  17067. function launch() {
  17068. console.info(
  17069. "https://docs.organizr.app/help/faq/migration-guide#version-2-0-greater-than-version-2-1"
  17070. );
  17071. organizrConsole(
  17072. "API V2 API",
  17073. "If you see a 404 Error for api/v2/launch below this line, you have not setup the new location block... See URL above this line",
  17074. "error"
  17075. );
  17076. organizrConnect("api/v2/launch")
  17077. .success(function (data) {
  17078. try {
  17079. let json = data.response;
  17080. if (json.data.user == false) {
  17081. location.reload();
  17082. }
  17083. currentVersion = json.data.version;
  17084. activeInfo = {
  17085. tabs: json.data.tabs,
  17086. categories: json.data.categories,
  17087. timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
  17088. offest: new Date().getTimezoneOffset(),
  17089. language: language(moment.locale(navigator.languages[0])),
  17090. browserVersion: bowser.name,
  17091. browserName: bowser.version,
  17092. mobile: bowser.mobile,
  17093. tablet: bowser.tablet,
  17094. osName: bowser.osname,
  17095. osVersion: bowser.osversion,
  17096. serverOS: json.data.status.os,
  17097. phpVersion: json.data.status.php,
  17098. token: json.data.user.token,
  17099. user: json.data.user,
  17100. plugins: json.data.plugins,
  17101. branch: json.data.branch,
  17102. sso: json.data.sso,
  17103. settings: json.data.settings,
  17104. appearance: json.data.appearance,
  17105. theme: json.data.theme,
  17106. style: json.data.style,
  17107. version: json.data.version,
  17108. };
  17109. // Add element to signal activeInfo Ready
  17110. $("#wrapper").after('<div id="activeInfo"></div>');
  17111. console.info(
  17112. "%c Organizr %c ".concat(currentVersion, " "),
  17113. "color: white; background: #66D9EF; font-weight: 700; font-size: 24px; font-family: Monospace;",
  17114. "color: #66D9EF; background: white; font-weight: 700; font-size: 24px; font-family: Monospace;"
  17115. );
  17116. console.info(
  17117. "%c Status %c ".concat("Starting Up...", " "),
  17118. "color: white; background: #F92671; font-weight: 700;",
  17119. "color: #F92671; background: white; font-weight: 700;"
  17120. );
  17121. //local('set','initial',true);
  17122. //setTimeout(function(){ local('r','initial'); }, 300);
  17123. defineNotification();
  17124. checkMessage();
  17125. errorPage();
  17126. uriRedirect();
  17127. changeStyle(activeInfo.style);
  17128. //changeTheme(activeInfo.theme);
  17129. setSSO();
  17130. checkToken();
  17131. switch (json.data.status.status) {
  17132. case "wizard":
  17133. buildWizard();
  17134. buildLanguage("wizard");
  17135. break;
  17136. case "dependencies":
  17137. buildDependencyCheck(json);
  17138. break;
  17139. case "ok":
  17140. loadAppearance(json.data.appearance);
  17141. sideMenuCollapsed();
  17142. if (activeInfo.user.locked == 1) {
  17143. buildLockscreen();
  17144. } else {
  17145. userMenu(json);
  17146. categoryProcess(json);
  17147. tabProcess(json);
  17148. buildSplashScreen(json);
  17149. accountManager(json);
  17150. organizrSpecialSettings(json.data);
  17151. getPingList(json);
  17152. checkLocalForwardStatus(json.data);
  17153. checkForUpdates();
  17154. }
  17155. loadCustomJava(json.data.appearance);
  17156. if (getCookie("lockout")) {
  17157. $(".show-login").click();
  17158. setTimeout(function () {
  17159. $("div.login-box").block({
  17160. message: '<h5><i class="fa fa-close"></i> Locked Out!</h4>',
  17161. css: {
  17162. color: "#fff",
  17163. border: "1px solid #e91e63",
  17164. backgroundColor: "#f44336",
  17165. },
  17166. });
  17167. }, 1000);
  17168. setTimeout(function () {
  17169. location.reload();
  17170. }, 60000);
  17171. }
  17172. break;
  17173. default:
  17174. console.error("Organizr Function: Action not set or defined");
  17175. }
  17176. console.info(
  17177. "%c Organizr %c ".concat("DOM Fully loaded", " "),
  17178. "color: white; background: #AD80FD; font-weight: 700;",
  17179. "color: #AD80FD; background: white; font-weight: 700;"
  17180. );
  17181. oAuthLoginNeededCheck();
  17182. bypassLocalLogin();
  17183. } catch (e) {
  17184. orgErrorCode(data);
  17185. defineNotification();
  17186. message("FATAL ERROR", data, "br", "#FFF", "error", "60000");
  17187. console.warn(data);
  17188. console.warn(e);
  17189. return false;
  17190. }
  17191. })
  17192. .fail(function (xhr) {
  17193. defineNotification();
  17194. if (xhr.status == 404) {
  17195. orgErrorAlert(
  17196. '<h2>Webserver not setup for Organizr v2.1</h2><h4>Please goto <a href="https://docs.organizr.app/help/faq/migration-guide#version-2-0-greater-than-version-2-1">Migration guide to complete the changes...</a></h4><h3>Webserver Error:</h3>' +
  17197. xhr.responseText
  17198. );
  17199. message(
  17200. "FATAL ERROR",
  17201. "You need to update webserver location block... check browser console for migration URL",
  17202. "br",
  17203. "#FFF",
  17204. "error",
  17205. "60000"
  17206. );
  17207. } else {
  17208. orgErrorAlert("<h3>Webserver Error:</h3>" + xhr.responseText);
  17209. }
  17210. });
  17211. }
  17212. function homepageBookmarks(timeout) {
  17213. var timeout =
  17214. typeof timeout !== "undefined"
  17215. ? timeout
  17216. : activeInfo.settings.homepage.refresh.homepageBookmarksRefresh;
  17217. organizrAPI2("GET", "api/v2/plugins/bookmark/page")
  17218. .success(function (data) {
  17219. try {
  17220. let response = data.response;
  17221. document.getElementById("homepageOrderBookmarks").innerHTML = "";
  17222. if (response.data !== null) {
  17223. $("#homepageOrderBookmarks").html(buildBookmarks(response.data));
  17224. }
  17225. } catch (e) {
  17226. organizrCatchError(e, data);
  17227. }
  17228. })
  17229. .fail(function (xhr) {
  17230. OrganizrApiError(xhr);
  17231. });
  17232. let timeoutTitle = "Bookmarks-Homepage";
  17233. if (typeof timeouts[timeoutTitle] !== "undefined") {
  17234. clearTimeout(timeouts[timeoutTitle]);
  17235. }
  17236. timeouts[timeoutTitle] = setTimeout(function () {
  17237. homepageBookmarks(timeout);
  17238. }, timeout);
  17239. delete timeout;
  17240. }
  17241. function buildBookmarks(data) {
  17242. var returnData = data;
  17243. return returnData;
  17244. }