From 294904321cb6de535237a6a156d5c4ec462bc117 Mon Sep 17 00:00:00 2001 From: SohnyBohny Date: Tue, 27 Nov 2018 16:18:26 +0100 Subject: [PATCH] Create Progressive Web App (#4730) * Create manifest and serviceworker * Create templates and add AppSubUrl * Add JSRenderer * fix ctx type * Add JSRenderer to static.go * Complete adding {{AppSubUrl}} * Add more fonts to urlsToCache * Add 512px and 192px icons * Hardcode font MD5 * Default theme doesn't have a specific CSS file --- Makefile | 2 + modules/templates/dynamic.go | 12 +++++ modules/templates/static.go | 9 ++++ public/img/gitea-192.png | Bin 0 -> 8738 bytes public/img/gitea-512.png | Bin 0 -> 25737 bytes routers/routes/routes.go | 9 ++++ templates/base/head.tmpl | 17 +++++++ templates/pwa/manifest_json.tmpl | 31 ++++++++++++ templates/pwa/serviceworker_js.tmpl | 72 ++++++++++++++++++++++++++++ 9 files changed, 152 insertions(+) create mode 100644 public/img/gitea-192.png create mode 100644 public/img/gitea-512.png create mode 100644 templates/pwa/manifest_json.tmpl create mode 100644 templates/pwa/serviceworker_js.tmpl diff --git a/Makefile b/Makefile index 6f3779e30b..5e7e72df0b 100644 --- a/Makefile +++ b/Makefile @@ -347,6 +347,8 @@ update-translations: generate-images: mkdir -p $(TMPDIR)/images inkscape -f $(PWD)/assets/logo.svg -w 880 -h 880 -e $(PWD)/public/img/gitea-lg.png + inkscape -f $(PWD)/assets/logo.svg -w 512 -h 512 -e $(PWD)/public/img/gitea-512.png + inkscape -f $(PWD)/assets/logo.svg -w 192 -h 192 -e $(PWD)/public/img/gitea-192.png inkscape -f $(PWD)/assets/logo.svg -w 120 -h 120 -jC -i layer1 -e $(TMPDIR)/images/sm-1.png inkscape -f $(PWD)/assets/logo.svg -w 120 -h 120 -jC -i layer2 -e $(TMPDIR)/images/sm-2.png composite -compose atop $(TMPDIR)/images/sm-2.png $(TMPDIR)/images/sm-1.png $(PWD)/public/img/gitea-sm.png diff --git a/modules/templates/dynamic.go b/modules/templates/dynamic.go index d70a465c1c..dbd75221d2 100644 --- a/modules/templates/dynamic.go +++ b/modules/templates/dynamic.go @@ -45,6 +45,18 @@ func JSONRenderer() macaron.Handler { }) } +// JSRenderer implements the macaron handler for serving JS templates. +func JSRenderer() macaron.Handler { + return macaron.Renderer(macaron.RenderOptions{ + Funcs: NewFuncMap(), + Directory: path.Join(setting.StaticRootPath, "templates"), + AppendDirectories: []string{ + path.Join(setting.CustomPath, "templates"), + }, + HTMLContentType: "application/javascript", + }) +} + // Mailer provides the templates required for sending notification mails. func Mailer() *template.Template { for _, funcs := range NewFuncMap() { diff --git a/modules/templates/static.go b/modules/templates/static.go index 6fd4d245e1..e69e1cae48 100644 --- a/modules/templates/static.go +++ b/modules/templates/static.go @@ -129,6 +129,15 @@ func JSONRenderer() macaron.Handler { }) } +// JSRenderer implements the macaron handler for serving JS templates. +func JSRenderer() macaron.Handler { + return macaron.Renderer(macaron.RenderOptions{ + Funcs: NewFuncMap(), + TemplateFileSystem: NewTemplateFileSystem(), + HTMLContentType: "application/javascript", + }) +} + // Mailer provides the templates required for sending notification mails. func Mailer() *template.Template { for _, funcs := range NewFuncMap() { diff --git a/public/img/gitea-192.png b/public/img/gitea-192.png new file mode 100644 index 0000000000000000000000000000000000000000..63f963e846a9cdb153e8131179e7d347400c412e GIT binary patch literal 8738 zcmcgyg;yLuw4PmjS==ebp-|il6fG2YExIgTw76?=m*TPo3KaL!VvD=GTY&;CUZmLL zcizA7&dW(ACz&%dcaq$DzxyRo>Z)=$5K0ID05}TrGMY~{^1p(K{&dw`vB!9-P+g@J zv@xHOAErg*Qya@!{+%lTphf*xKn^y!|DHN2++_9Lw4AKmJk4Az0Z&g)PFqJiS93FG zOHL;j>+GY~lmI{rD9A`@d*%FD_4d=AU6nW)zgiK^{Edx&Y5Wlt^_|gyW*90OnX`BF zY*W*0$!tL-`_jMi_A>py^Y1GO3~3rWE^C*fb?qCg?6GK@iDd=rYX<1ECFSLrGymqD z-`^*Np(c;4i1H1hj@@=-3h%A(@$Ienj(@iX@vBV#Kjel>4LxgwnBHr#u0K3lnzw(K zG+VCG2dc&rJl-EnL7Z=n`~Eh?ZrlL57{NR}yqFSy z7E@C|UAwzSK>37RSs+@rlJ-nLd>tjz?_*Gs0?#suSF|7J&Hpxw`!akm9chrAe=zU;-pn?&;Nyx4Yj-=#e21@(9AOIgC z0|}F7=0-54XhXR}iEBZ{&g);PgVH6b!S6}5Nh04zZfXQY1c~66z3W5?7STMx43UFW zp}XeVBDeo`oo}`oik;qmQhiP)CiwDA(SXG_VhZKdDp(Qu2n950G;tqQ(Og=DTo_t} zBLBjfGSUS(P#m6OM#;wu6a~|Yh)@&wV@;^^x++P;F$U&pf;b;noB8)4s{;_v5bj_k z@8U;!5@p9uZqYl%OK!|)3aBIxLQ*|;cODv)Nhx7hp&gVA{X$tFC56wIO+ZzJ`%#2t zCRiO?S|Fnwq=E7FdE{Z#!Y~40^OCeDhyaWG1sJ6J1R~*O%4X%(<~97ui#C-h2^~TQz}7FVLM6Y_Hg^ty5|t6e z=+-DXP}=9p!uaw`#oFk+zz#YKQ}P`qk{-@Xj~RqoODl;9$Us3Mv_VMxt?R+0NGV!O zI6k06Q1-?mj5rw0)PT2StI)YW-VQCJ6=uV0SvYp^ViES~2%bbwZZrE+`oU=Pek;6VMh!7tq$mKhUT96SqiXX~k?U z^jL6sSy6lByX_$Xkf9veBrJQelR~4ytCzKD71XXgy6dLC~3h(O$!+*v04X)SZA zK5B^E$4?(xH9`GOdl}D$s@@am<|eZ9AwOR1&O>18R&RCN8Rf$3 zhE(A$8dM$5Lee%OqJnLc7cH;u{SAnhNR2|0Z1dVXzAJHSqIFuI8gV~N`1RVqQ63-A zB8}%vP1ATOuYA0(JK)at8M|YSWJ;Nt8Jexh@8c%73D*TdqR;jS%fC3jvAj@9vda35 z9bmobwWjH&<=6@Eq^N6&K*&-c++SE8c>q}o^k;3WL-_wHs@-{{BnhR!ZW>9gmVmI$9pDGh6MnJ8 zZbQ^hEY_d^p5>2J&O77Sck3=qz4px{YIZ&+^Q3Ylh?6UC209y!GT4~MK8>l8vPzh! z4to7Ew)vwl5b8x|!c9IXmLgodTACc3NUsl-XO_2W@YBz==hk#TPA2_aJeGm5v}z>l z^FU+K&$wdXHeTrFNRXKL5Dn^}_hRaN!OBQcwL6YE+p}c{1ot6tP@CP+Cg^9~JOnfN zmaxss!O8(}3of`1{j7y5Pmbp`3qY-eB%)X1QKnz&hd70JbgW0@0D za5qc3O<2ez|C3%+PM%3l3en%3d*r6UE8`4>AfE=G6;gTS? z^#lK@N3@7G3BZ*l$d6=l%LCz={&&29<$gF5vpo!*%E89<@Vy@ zQ*Ll1vop}Q$ohOK9@7lQoJd$Hrf*5nV?>ESVPta7ATCZ_F>W6Fjh z{{2{JDlXAVlQ#A>qklQ36)52o0;f)LYzSnvRnt)~O(dkY9qig_Vap*20HR~tB)cnU zRAOYNb0B8wEh%vNGC=brE<~Ss`FF^LK3H6#XXCi?hqYl?<-m&%f6xK8A2JQo^3wzS z(U%YyzHvSrsk^Mlv#B4+j{oSs(|YFVAmcDy=KU-ItKhv7S7L!|Y3-lke$5q~KVevg zpkguM;t05S_t9d<7#OLpsE@Z0y#VTM<*<0<{GD2|htif2wsCs_;yVsruWcVif!Z?wXU=S4_*PWR8jst)423(^|aPy8CfthT^ zTi)@OiWLmCPnk#uIC$&KC~|P~1;Q!;nfDD!3v6xy3P5wb-EDx)3zJtP4aPhanx?0X znEE&j80`lv%GVHp@;#=n@i7QX7BO2+S`oef2SVh40x0PP5&fbm;z$FNFRW=~VEP2x z)YzUEGhikI4ozfit;7uKszD^$tM9$(DzOK`!-kZ>$G=#NBA9IF?6@&!GQ$I0e zsLpgE>j9hM9$w>6qLxiUEA2zwJ{OFS0-fDlq`~B)6-0vxOhw12P8gUp=rf5dXP>B%l(fUmcT&C$)Fjn(%W%-<| zU!-jUs2%wXddRP7Y1MM+2*SBf>xUmB%lpN^uU19%%T?sV8O{`AIX&*rXn+;hF;KnE#<+)ZsSBB?UvL$m| ze89KQc{v*7lq*DIjd$dXGp{?9Qvcyz*!AT0xT0sK-tldjC{b`C*>Hy!)>XTYaI}(X zytyNhX-zHm3@yWNK?MS67`}i4y~{em``F{M(B~?pWVXXso0b zL4Q{-#Y+yv(6#l^iV0&psEalIHYQqD_TZC}1xkH-bEa@3qyPdPfU3qm@4X6~yKwJk zfB!`z86R(6!-Wcf5mJI=g6)1>#P50+u^9j6nR>tmk-Vjunk6eLfn)o%)P;P4(s}tZ zrXmad-+cM5@Jb-sy9Len_JUdHA-{`>p`&WK=Hc=$9atQfl@DeuFsAR;1<*a-L7E_0Qcx{g8N^qQ zt;H_*cTy)&3;_T4ox!jMo|rF{U*Ne&s-cK#iubaGPI7s3DVKmBcNh*_v`brFXESe_pMVVj|Q1d&_HU%eKsz!bT;}ZVX z>J%ptzjdlw=9@2dVs2JUjGXcDs|Ukp4<)mU9k3D4q@)!F``6&j-6W$)cS_Ujn!!UKwvh*SLHe(`}^i^XCh9u8Gv+oxif}dv9(d@EBk>OE;;t zZo}B67rzt4UE|RIj&wiQBHP+@YKx0`Yl2NsqVeZ+BVE0xVYjD^NrX@X&Fl8^uSw8a zS^DL(9CXkk^E2qf=}f_0h6EW*!HKUM(=Als4cD_<6vmb*dfdQhL=3tMR9EoJd(U(wzR;X}ZwI|NOA z}3+J~G*v)g_WU2+*A( z>TD;MK9VA1lqHeZF)oM9ZzY@>#QCNmS!I|7Gs@UGZ+~^zNX~h#wxxrW5#{sjr=S-1 zsFa>%eg)mH{OL{cae(rNywGpf&TgkM>B;2fEnR|t7C4=i>Ee{>4TU@DjCAU)*XX|6 zbN0DoIO#sRJQ{7?CDo3g3wcd&?6dOAy*A2nHmPyYmvS`co@|6#SV`;y?o>*y805Rv zmYPG@`rYjN*LS<@cSoy+TbcxYc&x}saUyu0BR{!hA|1fl^lV-iP5-jKvIVKHZH_g( z&(gr3GC5p{i8!opUEAs^89Uf!|FTWG4h)V|dvPQ=$Mi8}4rYiS>Gq#`QZLTz-iAPp zvV^etUaUo>7G0!>b1gp-PzSh@<{6w3Y0n4#xxRMzZu8TfM}^Da31bi?aoevxqTqT& z3qkJ;g1-tz*E^JT4yfpM0mjG*K^1S_W6l030lLp6^h}gZJyGbz9 zxsk{+CBjUPy9WiFj7FR+#0{TzD^Yj4@2!OOI~fK4XSu$y{Vn1b^lv1@yE~^$J&IZ7 zt+c+Nps8U>vH+(D-Ckp3> zQEy7N!@AC$wF z8~FLHq5}Ksne@zlkD?B;hWuiv3Ol~lL8z*bGZ(Sknosw>{LQ3Tut4Ob&^roYPFWd0 zB~99f@{PgPN7p9;LU!%l+DGKbU7cRCa;gIO37JrfP2Y+}8`6{t+d3Z45(P||=l%aTiTwyt{3NPoGe2vwr70i zs*d})u-VqBxDcBNJ&*eZ1oqnzNylAUxexxGA{8w6hUHgP)a$2<9UKh*l#y+EkCi&h z8}-IY1ooabvKHd2Hv!tG=7V-gy~vI~&_Em3G6BKCuw~-u&qLw9H8#obcL`&u6(A^@ zpOPHv%qaPvBV_4W*sx>H(p6Z8ZY?{zTCtZ8rFAMEj=n{2jW|Uko7$GPSw2Fa&v)S7xN#;Ym z;=qbHg2QE6tD*~fS7mU64Xuw2obRFeqJBTNy_-S95l<8H{_omIl&8$6e8&2}E1`&; z(tHqb@=z?%ogA;)#Iu(IMnxS_pCT-=m1!Gtc^dz5lIg3qG)Wy=@vF6Bpw1|EZBP-a zsPQ)6BFdg<(6JK@<`a}*qL*m7Xi}|L8)Hd$&r@2$f6}NRh*7_kOPa*AosggS^{pd+BX&l|5$^ zI%hjy2}yq4jB+Vf63~v+wuQty*c)SE*yN%xXsjql5h@#)0{`ZH1V76T~t5@rq%EJRg-!0Wp{L1G;M5yr3 z+?Gc_tRR%=kIG&rF@<^sPUjo8d5-po7LH9XIaDr35JiY&Cx3u{v)3#CrXN!4vwt^L z>OmiUqflpI(rc;^#R^i;F}+nD&WF7r+G5SBf6S_UlySd570Zpdpp2^xEi}}yGMyE) z7xnTB@X~$H75mI0a7Mv!wa$1DPRkMoqCHUV-QoP~6|k6v@7%=Lc;uYe+()?TmgWBQ z>^2a^`ZCu-bZv7<>>74>cs*~8ZP+H^x|ORj-epjC!&S-LZ0fe#7_VC(T5H%;?#%&? zL~-nPxw!cDCBrFk(qgprEHouApI>-*?{>77cDx#oqOQa+>qyJZvzmg)dKq$zGq=@? zM~y5IP0wk7yveWloPoci$u#@dbX!7n%^|=6lPJu*-C8s^Xs5f5gX`_5bp3PvF7S5T z)$tO6du6QM2cy8-f9iuPb-o$1-lXTdZ^ThPfjUbJmJv>K>OU9tEfi~ew3HnCf8-v2 z`;Mw$jG&|rbl3Ja__0%6V*rh8f%PcMmA|cKH~jd6<(yDSN;VOiBK&WehIWhuF<5qE zDA7_>yk!(*<;(OM!!NuHH%iN@|4N~|c=3nvjm>RG?fv2S@_p-?Y3Mhh*N3kp+F{Sd zOTF4|1cIqX6)*>ZG)L7OjeJ1engFxZLM=a|0(HVxh!LAq^3w>HZ@dwCRR;CxM|D>u z*R_p$&FbH9!qFhiVveSZ#j%seRcq07kx^X5A<|B=3;qsj(Q88JFS9`M3k;GNL-%11 zf!-iJY2L|vJq~@66yc5B06CMp>FB~IT@foyjtwrd$yD36YNVEK80Ng-S>L5dYvhTzzG#KMtJ8eRi<=2 z)8FGnvuFqJ13Dw_rDwxSy}upH=p8nG<1tQXIH{McpY{u~=@x4drj#sty_a~}eqZIYnJ59zKd-%QBG$Sz^}El7hJ-DLFrYp_4W0TsdQAxO>U1@0xd#<>+yb z@n*Nb2;gm{JU?#uF;BC2MRn&jwEgQ7K>%+KJgTG8zjU_eCe4bBbhDMOD)yBcfUIzS z+$vY4lv?^kOmuns5q$cl*Oe{c`EWyv3YyLE6L|g3`#O&=GIrDA1ki=k2HyrJ;?O=r z*u%%bbfLikZ7Yz|9PY;_l+^ddTWBF#Ykx7}d4zZbQz-e09Y6ZjNW!Zl32|>KCBbj& z)U8%s&zmn-gqzOl9rtd%JbH}`KWtSB%9LV7AsJ9$mb{+9W_2l}|Fe^V!^aK>I?>%)H#Dql)_$gvBOgqqh%bWUM zW^0%OPwMuCoQq_f?eSQ@WPK-YW2^vSQub|NvMxRe&b_vF!hU4xCm_CZX%!L1XRvcC zftwvLab~_ePvDdm64#_1$p0Ze!n83#2>3dJlDI3B?M@0Z3(eJOD4a2Lpvt1>HOXY+A0T$b2zcuioz-9m|2I9jY)wuYR!HnP>T zv-s)rKoEU^B+o`t?ro!;|0n&{Bdq_Pe>8dQ*X<_G89EFMSjZ~~SnU4r_PCxwk&E;Y zt=Axqi9JYyJ*`)uM`0aWR^61N_{&1D?KV;hcJlz(Pi{m&UX?P?U^Jeb7c9`!# z(1T3Rsc4)eLPqXpYwGTuv~nTi$R=#KD}B|B%VZg&epud=#cLV@Bu zhlr`|@DVLDr~t(3j)j}g>q>a|uPP#^yv_dJKShf5{&!wwP|7s;TCPiz5%TAgA>Il`84b1P}yZ1;)A zN}2nn75}c`r=b1A%Pj}@?RXH?1w~r#oz!4!bXN^QK`M7(fc4VlSm(rvZ5tc=hE-@# z5o$98zHUm{$j8Q8<%fEySJYhDphXXx^gSH>Azv^j=B47anoa7c_Q%AC z@2&K=eTGsBB_~BXrH-(19mJY54}7n-V^LcBLi>7FYLX;oAgs6IWPgmQIq+0Rzu8Uj zQai1W{SV5lD4|u-GIM_jIQla*WqawwVZWgb3?Ppz<=VQ7cc^iBs@w?@F>$th*+H~7Fe-L>!`D!i~WGB$|^^^_WapU1pqa6`$=)# z)dQpFtUpV#*ke(Dkcd!hZ`9`M8$VEbP%p-=#0JOf`YhCxpgILyx>23&txO^krHZ>b zhuyc+hw;L?`Xl3}+n>Zqv_*+QD?dgfo|;xxE!vfA!JYlxnN?YBemj3S$=4PrbB+PP z_BK_nyX!;^IWnha4>+VNnNX1u?CmZ50WJRDK8xPX=N6oN<=NvcPvBJ+bWJ9#Q<(V7 zcdObJi&f9#F(I^kx1vdxn#$RAco;yF-s!EXfR6hw%%ab?_xz=m$K|Ozn$2f~&4n23 z!Pv1*S~27|zpdVS#phR7v1~l0{VYY_`7{niqmAX7Hl}lx3@XL4SmIGXo+)T3F`h;5 z1x)T!%#a|M&`C&l+AyTFZkd#(XF61kX5WEzq`;AmESZLLOrlPV_8oHRv^ClXRxBc3 z3r=oJHT%;Vkyx{I^7O4sI$<;uBpZz7M~k`&jK%MQ9&Oa!`rUsJQu8_YaIt^+RnAD@ z(w+^2{(?+|lbpA+Sog(=D`-ETkwAiK;Z4g`ckm5QhWuCh?pK4i3&kn_POoYtl`H41b~_F z1U3Q-%Fj`LnIIyGiFe3A8QI&K1J3)p!9)QHuc+`xHe}iMbXTB?u_~b#!W>{G*Wo?B zUxNpUk`D6ue80~Wx{`v_VW}5oJdP@;~$AVrKBJItD#eHA9 zhphV^<0N^PHW(991>maq^Ey?4OvwtCR4v4^qL34fV#jd@IY( zX9$cz1>D;=3SUjCt0OxlR0$J>6^7hmrt2N>H9wk5X^P8&Hxh89B=p5g{CxHH*r<#_ zaM(c?4;h>8co5H+L(K^HqCC%a>f?uJf|U$2O39!YDE(3ixo35bUel{2A0H8yvPZdG ztEZidGThj9tcqRkUsUvI3OLj3YTx70v7FVDnMjP{(EK@g9%bkLJ=VVObPUwn8^<*U zZ6TgQJ9^A?o^3FAjCq3fi3{=~V_h4NF(mftE%PR6X%SJ&Dz^PU%ve7kQHpls=U5#W S9-hu~01C3IGF8&BkpBS!?Tk49 literal 0 HcmV?d00001 diff --git a/public/img/gitea-512.png b/public/img/gitea-512.png new file mode 100644 index 0000000000000000000000000000000000000000..59d1fed7d976bfae5b710aa04d983329641e8898 GIT binary patch literal 25737 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 literal 0 HcmV?d00001 diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 06292557b3..1c1bcd8f95 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -791,6 +791,15 @@ func RegisterRoutes(m *macaron.Macaron) { } }) + // Progressive Web App + m.Get("/manifest.json", templates.JSONRenderer(), func(ctx *context.Context) { + ctx.HTML(200, "pwa/manifest_json") + }) + + m.Get("/serviceworker.js", templates.JSRenderer(), func(ctx *context.Context) { + ctx.HTML(200, "pwa/serviceworker_js") + }) + // prometheus metrics endpoint if setting.Metrics.Enabled { c := metrics.NewCollector() diff --git a/templates/base/head.tmpl b/templates/base/head.tmpl index bb6a8a981b..47c0d6b473 100644 --- a/templates/base/head.tmpl +++ b/templates/base/head.tmpl @@ -5,6 +5,23 @@ {{if .Title}}{{.Title}} - {{end}}{{AppName}} + + + + diff --git a/templates/pwa/manifest_json.tmpl b/templates/pwa/manifest_json.tmpl new file mode 100644 index 0000000000..557bee5d76 --- /dev/null +++ b/templates/pwa/manifest_json.tmpl @@ -0,0 +1,31 @@ +{ + "short_name": "Gitea", + "name": "Gitea - Git with a cup of tea", + "icons": [ + { + "src": "{{AppSubUrl}}/img/gitea-lg.png", + "type": "image/png", + "sizes": "880x880" + }, + { + "src": "{{AppSubUrl}}/img/gitea-sm.png", + "type": "image/png", + "sizes": "120x120" + }, + { + "src": "{{AppSubUrl}}/img/gitea-512.png", + "type": "image/png", + "sizes": "512x512" + }, + { + "src": "{{AppSubUrl}}/img/gitea-192.png", + "type": "image/png", + "sizes": "192x192" + } + ], + "start_url": "{{AppSubUrl}}/", + "scope": "{{AppSubUrl}}/", + "background_color": "#FAFAFA", + "display": "standalone", + "theme_color": "{{ThemeColorMetaTag}}" + } \ No newline at end of file diff --git a/templates/pwa/serviceworker_js.tmpl b/templates/pwa/serviceworker_js.tmpl new file mode 100644 index 0000000000..5e5860ebb0 --- /dev/null +++ b/templates/pwa/serviceworker_js.tmpl @@ -0,0 +1,72 @@ +var STATIC_CACHE = 'static-cache-v1'; +var urlsToCache = [ + // js + '{{AppSubUrl}}/vendor/plugins/jquery.areyousure/jquery.are-you-sure.js', + '{{AppSubUrl}}/vendor/plugins/jquery/jquery.min.js', + '{{AppSubUrl}}/vendor/plugins/semantic/semantic.min.js', + '{{AppSubUrl}}/js/index.js?v={{MD5 AppVer}}', + '{{AppSubUrl}}/js/draw.js', + '{{AppSubUrl}}/vendor/plugins/clipboard/clipboard.min.js', + '{{AppSubUrl}}/vendor/plugins/gitgraph/gitgraph.js', + '{{AppSubUrl}}/vendor/plugins/vue/vue.min.js', + '{{AppSubUrl}}/vendor/plugins/emojify/emojify.min.js', + '{{AppSubUrl}}/vendor/plugins/cssrelpreload/loadCSS.min.js', + '{{AppSubUrl}}/vendor/plugins/cssrelpreload/cssrelpreload.min.js', + '{{AppSubUrl}}/vendor/plugins/dropzone/dropzone.js', + '{{AppSubUrl}}/vendor/plugins/highlight/highlight.pack.js', + '{{AppSubUrl}}/vendor/plugins/jquery.datetimepicker/jquery.datetimepicker.js', + '{{AppSubUrl}}/vendor/plugins/jquery.minicolors/jquery.minicolors.min.js', + '{{AppSubUrl}}/vendor/plugins/codemirror/addon/mode/loadmode.js', + '{{AppSubUrl}}/vendor/plugins/codemirror/mode/meta.js', + '{{AppSubUrl}}/vendor/plugins/simplemde/simplemde.min.js', + + // css + '{{AppSubUrl}}/vendor/assets/font-awesome/css/font-awesome.min.css', + '{{AppSubUrl}}/vendor/assets/octicons/octicons.min.css', + '{{AppSubUrl}}/vendor/plugins/simplemde/simplemde.min.css', + '{{AppSubUrl}}/vendor/plugins/gitgraph/gitgraph.css', + '{{AppSubUrl}}/vendor/plugins/tribute/tribute.css', + '{{AppSubUrl}}/vendor/plugins/semantic/semantic.min.css', + '{{AppSubUrl}}/css/index.css?v={{MD5 AppVer}}', + '{{AppSubUrl}}/vendor/plugins/highlight/github.css', + '{{AppSubUrl}}/vendor/plugins/jquery.minicolors/jquery.minicolors.css', + '{{AppSubUrl}}/vendor/plugins/jquery.datetimepicker/jquery.datetimepicker.css', + '{{AppSubUrl}}/vendor/plugins/dropzone/dropzone.css', +{{if ne DefaultTheme "gitea"}} + '{{AppSubUrl}}/css/theme-{{DefaultTheme}}.css', +{{end}} + + // img + '{{AppSubUrl}}/img/gitea-sm.png', + '{{AppSubUrl}}/img/gitea-lg.png', + + // fonts + '{{AppSubUrl}}/vendor/plugins/semantic/themes/default/assets/fonts/icons.woff2', + '{{AppSubUrl}}/vendor/assets/octicons/octicons.woff2?ef21c39f0ca9b1b5116e5eb7ac5eabe6', + '{{AppSubUrl}}/vendor/assets/lato-fonts/lato-v14-latin-regular.woff2', + '{{AppSubUrl}}/vendor/assets/lato-fonts/lato-v14-latin-700.woff2' +]; + +self.addEventListener('install', function (event) { + // Perform install steps + event.waitUntil( + caches.open(STATIC_CACHE) + .then(function (cache) { + return cache.addAll(urlsToCache); + }) + ); +}); + +self.addEventListener('fetch', function (event) { + event.respondWith( + caches.match(event.request) + .then(function (response) { + // Cache hit - return response + if (response) { + return response; + } + return fetch(event.request); + } + ) + ); +});