From f7a82e727d21ffb8676947a8136a49871bc15554 Mon Sep 17 00:00:00 2001 From: Achilles Rasquinha Date: Mon, 25 Sep 2017 21:41:40 +0530 Subject: [PATCH] updated README.md, we need better readmes --- .github/logo.png | Bin 0 -> 12673 bytes README.md | 15 +++- frappe/public/build.json | 14 +++- .../js/frappe/form/controls/text_editor.js | 19 ++++- frappe/public/js/frappe/ui/camera.js | 67 ++++++++++++++++++ frappe/public/js/lib/webcam.min.js | 2 + 6 files changed, 114 insertions(+), 3 deletions(-) create mode 100644 .github/logo.png create mode 100644 frappe/public/js/frappe/ui/camera.js create mode 100644 frappe/public/js/lib/webcam.min.js diff --git a/.github/logo.png b/.github/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..258408edfa524a4b4dfd968b70344cb257ade492 GIT binary patch literal 12673 zcmdUWcT|%>ux|tfK@d@CD$+}&_a;T9g)TiHpi)8yL+@Asksf+gBtcLjN+<#bP?S!P zfFNCkfOP2{?gsBW_nmw0Iq&`X-r)qY`|ZxoH#s|9%!P;k|#C;$SMD!GMB4yTJHHY887cLY$F;?eT+9E(3e@~5P2I}nl4bcKnysDD%){uxdMSaHAi+G&4*5fG+Mj$jFd+S)c)4D zu=8|mFxPcF4}qADMJ?(QmKMg=eoIxYqw!XOsKVZeqO22;ND17oI#$`ST(e;2RJa$iH3q4~N*YW?ADT3i|~_~#yR6mG1@<+q_t+1h>*P;~9mmKsTrJd|Ek z5l4rr@LueIOSfoe+6v+i?w6JpZX*iQ3nsWc_EY+m)HETGcubnjn*Xd{dCGM$=9iAdLQS!`Z0O7~sBl)vrZPexx24gTq(;NK zyH!*8mmUtp2G0-o3lIM^zj4Ugi$R)qR74ST#jYGITj$1or3de{MbJenNNFAI#q~Td z1fLs5X}DgSK-(Qh^YUxqK$Z}`j;IuZok@6Y=eT_CJ3&NI?swa8wu#K*niM7o1S9QW zfLC{xUYl_^9fvfp3)D#Y+fECKMD2AvwUg81FX1{C+kcay5m35+LVb~U0s@imnvLzT z5J?xc66(%}@|j>VJ@T0sB~$~krl;o+k*qwk=|0b+jPV90Ay&-h6&b>9kAw}JR_2oS z{qmxCvlR)S;{yM@!t#|K?PU+9-{F5=qZsI5$#8uD(;DGdCW`c}$YbNNS(BY5p1F4P z%o6Z&jxs#?7WYzE?7HO_~ z9!3QeOjMVDtYPShk6S>QVF!ur0|fG+&B|r@Ay)@nqAS)Gk0^;49+Ozq`(kl^Z z?zV)tQ}oU{K?jM{txI&=AdM*I+ZhUU4rv?g{>Bn-H6}-Eu>!vOH^Y_t!&H@Csvhhi zzE5u7mTLdSMp2YH)x1j7^>h)52ZaR<;aOxnwkcyonBS`L-fVd#{r8`PjUo3V!`fL@DmIFm@iWeWFaF~EQmiu-*P&$mq9)?3zl>IU%$BWwA!6T=LwYqVq z^igNoQ)QL;JVvxsnk>Di=maMhG>9?bx2$|$X2DQ1Oh@}g7P`3M_R||!3~aZ}j5y3B z#v%pFQL+hM9>J{jaPt6pnQHU%;rEQ&w=|FT+{D6aD^G0vc^!utD3&_PPx1Y#VLT#@ zq!2`?ohq}v{gF_XRx5=*<$iXQPmAF2m?qXi1m3U9oRIC@DU!nzw*MHD zNpq|8jbU(bZojfo?&N1(&C4w9RIOX-3G1gihA!$jp)Wo*Kurz)`~#PC^~z)W z9-r}>AyUdsTeovM-OlqX#Vq}dw(3s$`kVZ-jS-6BldglEGY*rL)9p#u)qmCvVTs>U zjk+MFfvr=pWlI4OM}pN>06scjj8tZNZsA@2R*TQG3*wX|QTf%rv$az{4;wNs-Bb`- zgVB3hOUBVfT1nRA^NcMmhYal)6O0D40@+GLG>xyp&c4X|E;877`_$|Y2pgozL0*8~ zvHjCxn3$4X2b|`f8r9p8k1=3+g`*rt-q^%e^b<7&q26&e4nl})Ol5uCl}M{^-vyLc zuPeyg5pMc7q)GMfJ5^;i*6;9@rxI+94<#ZR;K82tBa@#EVeP&Z>jILM2tsT;408BL$y)N0TF#AUWnp@s2eBI9VskhYJJ5G9~ zaC&#~ga$Q*+?zX$P`Rn?7uwf|65sc=7ncH&sKl*IJI{>{=cIt`lJ!yZnpTZEn2uIp zbN5-Dp-Eufy0qyTi#IzMY8x+Xa*y9y-+s4O&Zx@hL6t4Od>GE#BVxqAS;tKQEWv*n z0kX4-e7!Sear9>pN_P4Zy^6R4soaI)oSpN$WV0dP9XP#UPpPY-PPQ{oW53Nw1#rlJ zvpmz2PBu4r2=q>Eaf+ca*~8uctRpuu)aXS;p2&ICs;olJh~Lg#oH8lJHA!~z1}F@J&DQ3Z!e$29rl*GB@_C#0T} z*FMKE8`|)fhWs{acUTXWum{$NV?KTtLOoI=wEs~OI{4L6kni!2k~4i+Sp4za3$k=a z-uN-p%j2aVN}Sn0jNUpnhxb2Qjk#lGjwi^AD|+3sn;{)HKCDX>ss7{pRlz|^w0*wY zKbg58bpA~K8}csrXtx31cig}7?N9b-1ST&%7*(*sCIErl?XXUdGQmQR z!8YhAhkVUHP$Im{%l8iHNu0m<`0^(JLj}FgjyrGf3*}EVm@FtI+8Nu`YfK=3HIlk_@ zdz4i?`Mi{njZap4DH{U@?eQA1@@0R6!t$S2x7;BVQ~xe^%<7E}1HIFPMsbS=r6N(8E0Jj%7=yx*f7|L9@0PCrlNd6LlkGzzUxV=%xTkZ<+4C&i# zSQN?^LP+fmtMa|6a<>DrwvQKBJMpSxh#g;_X>EV_$m0wI;#&DUtjWqP4~i(HY2YkP zp(pqCSI|=`iTc0H8yl}#!)w+(^8ithYxeu`5Z8u0tZH@9_qOnYZm@kXQUlT zU2ENTIys%yCn1otS($%ERt9oJ5CRRz-3Qe?5Qw+NAALe;H#B>DGl+>8(Ui!WoUFI^YS)7E~IsdL5&Mqf(oBs`P%njXfXgK$?O zv}94StGxp{11no`E{u)iG7%Z;BaZ&|wQ7n;z2Q+PJ4flKd%s}e*E%jor)k$Ji{{Kv zxka?hwQTrza`PGQC|r^(yPbgP3Siy-eUWgHW1^Y zv*XW}LipEU5$!4|(gUH1HGG`5m->kGnWha{C(@G*v@IHMoYQaA|$i!Li)exkKuUw&)Zfti-IPkX|BDXu4(UYMkI$Z`*^2^il zOU!OU1Eu_!JU)-#J$zODrt|cHDKEmWH^$JNix69we2km_{4F7*o7II7#FXcT`~ANiLXoMTp$cb4hjy&yZCFN-PLKZfNxI%`J0TH% ztCGl`q+=Mse02F~D&ZCp%b?wyM^yKyC0JRf=>8B2ri`tpQkt2f4C^9IQP*R}n>~}> z`r21s?wU^2je0Z!zsS9GrQ(+Ha^bLbPQDDSb6nUG%V_6E#|y%Njl0%i97YC4=0|$SNh#3QA)` ziye|vjfM~+rXDTu+&|e8~- zl_NdLYm-B7gl-eA`CF|K4#T7z)|G%+E@?&b+nB|+mRc&{I>L;J(y}0iEHNo>bbIIX zxn}3BwnF`0(?d-+zY8Pa?Db2Cu?!2@-zHS(^Khg{KlT6==CWz<0cQBT{0}@!9Pbr? zlU(d-ShKAcvH6ayuB%y-(H#?oX5wmqrcEON0>R z%VSmU9i2nF_DWXR-Uu%8h#Q>B+j_H(b;0OvC4gGLW`?zs6Vpey(#v+n_|upW>Blt8z_o)ovEuFG`3K*KAA@ivZrP{$|d&u;ZHXO!(|9 z``02jwK0j!MY{?^UN1?O=~rlAye4*>;8?C8NR#d+JM<8e%v)8-P-(|I`|JH-^Mm{W z=|UCtY4GNJyC|7S#VUnqWcB!xM{;k1`dMHtU*;vO)!`&Er5aTOuxMs(kb4lE-H%uv z8&jDjb#;U$mjNWvv1($wodFX;kRgE`aiskch=i`&H{0d*BQwONCV1KfTmim0T~-@v z+?nm5s11+;r>h?^hpf?hI>5b!jNF8=q(}m%w;r4!d24^vPiiGMr>Q!i(xGlti85mwKpa2pMpSGIe5yEq^{*28`07fOYkl&tsQUc z-^@o%KTDJ9gz5vfV^@9J`@b?l5hy(BIvBy*t8tHL z#8`a*C-rXG=-Mf;J4P$v{=He9*$9fn96&-(Q${Md8MGb7)qMex)Zc#gq6p3D`$zy^ zvM$CAGPvi;4BHjRMl}W3^EvJ<22D{xo_1_u2A}g_ZA7bTw1@KggN%Z=Er{<=te!9s zy8E!vfSAOSF4b7>k|1;M*$1u%X>7@th-nlS;72@QiLp;MAG zN#+CtC9DhnE_=!e$jji?c|#GWR~Kv0zRixt{Q6)Fo4po(X<;4dL=VvAIT*hP*4ivM zyQOly4%bc_nEr>g={}>%$9&P_8~0#>7n_=Zig%M@kc$JeD2IW-V9Ao$#MJ3pWC7> z#H@V=p-a=aUJ*B=8Pa8@i*YOW4!Of>C>g#(auC6--EH-U#p0z5EPs-Rn z!~<(>ow~jhhgR@N4;$6MJyUIh@_FX?!oFDNF`U)i+P^s*(m!?`Mepgg98J}-&)P8r zFF(Ykj*V?w>8PuPX$xR3i(x}0D6ieKdhC0^N7VC-O;o(AlP(3vp$nQLmfnFB8?2ALZ&BmmMi}Q7Hkz z3Z0w$)1`!-h1zg2?w{%5Ls0fPF6u9X-sZt~&yXWg3jYR_1KxYqg(STGh4e{{orYp| zQwzOF-A=LM^TA@5@R-G#X=H<8e2NImKxzy-v58}(AuOYhW7557(LvQS~js+PFH?%H3xcAXnPVg)x)OTM- z@{NsEfcXxoZV&USKn&mIZJ;`+b!j~p^l8^4~7`yftBAbAIy3zMecZEC+_Ka zSL8wa?=-w+?QV;dp4y##VGd=yM~g}chd#&T!M=)`>MT2~Md1 z3#+Afgb{_qW*ZGhb(#sB%;5Z7qp6xoLpt#~{Q!of#7ZtCND{LAh2uDKd;JAx6{@2k zV@=l6J;bUG)Wno2bZ~UCek>X$3RUP z#U}(|72@e8+fQ3jgfY*1h@fM@m(l`%4o>idy4)?0bOp9LU_Gy^gQAHvKI;z?TN1)| zB_0qPcpOeaCV$QNtnsy*4EoT2Il=jCS(%re)$wfaV=YVq1Bww6pDVG(3oVQ`eSC8j zVl-}KzB|l-1~zL@IHg!d=kYD#fHKi!1kK6G17Q^tQZhlEFU@Pec>W{>XAWm_!Kl^# z35Y2wn+s-}C7m|_&_;>BjFQA)t$@AB7hrFVY|Nd4-{&!1e=ZMf#cSc~53F#U_S!&3 zFX{{m2G$c+o*sWMGZjXdpCHH5FNWi-_}Zm3{}Bt8>yw79mR(OIhr_1X={bDuXB93`=%{&DL=*8}(NBz=0xGTq@_Tx}V_f5T@56I?= zlj>uW+xqJ4Nv-1q0H^dlqKWwD6mq(ORr`r738VFh@g*Qv((r8?wwx)|qaqp`l7GCm z%spcL*DNEV`0?uS7ij`8^Gloncty^w#%Hecw*T8}QR#cXF|Z!$*yH!Q-rnFlbsX6n zITn8W`$Yy({7({{IDy1G*e2^SvCMR3IHB&}jCkMGO8#R(bO4x}?2q(nL?8O4-^g=OSZvsl{ z(y9N~Ds%4vt*r&o`(U3+&KH>^gz!qlTmVOv$?{F}t27)#t|JfXEF;*irhX~O z7(VEOIS$v%^l8SPKa$hP-z!rM>*i9>HkO<`RMZqflv0%jIVIqOiZMcB$r(M^ zg-Ov|i~SP@P=p9kN%UFuLT~tNft|KZ*x88Fp1vU=ax&u6t%HB#5aM`~*V!xnDRe&@ zo{0I~vD&#$W%{{`c^2=LVRgBkVuLSqLk59zaHtvdfN!u}Ea8|bPj;$7QT`T6MUB@* zU%4~0w-9OvH9O5vU{1I>`!$&UOCTL>f0CJ=LE@!%$bzZ0@rCV%O#1zfOBuNZ$_H)P z8(r0P?3`VfpDId<+@gA_Iw5wX!Srs~FS?3ascUZ3g;ZugTyYDvJ12Fa<f+x&n!A|7t2KiXDT%VT)b4#b;7PpkW!`3$r%FyVIv5=> zCMc3GAd<&}=^XVA=)L2zvap&|U!yxbx$R;y3FH6F4*6dQ1myHP#0I4Vl?UO|ex}KZ z>)K*V*zUgUmQ)m@XM^kG-yz_p=1SPTuF2Mqp;l{^Ht%S+o73(KvHL^&)Bs-?RAOICHvmA(I0Y&91tO zo6d74mCa{Wu23hkpq}(g7wseO*&|NO^DqK zYmNXi(+6Y%Dp?eo!&cRKrwR)A$UqT#E=vSF%*ph~{4VZ7UgfoWz~1}SS29ZRG!E-@ zK_?(OY_Wm3UdE-6Q+X*VL!qg);&#<}Ohb0(*&r{{9^3RTO*fXul|@PoV*B<6N=RLn zNx;wvy6_4p!<{szCwYi{*6ptqXKe=pFtv4ltOXK?{gV5YXvW`U|9^#t9sl0( zYobIZ?krAGAV2&F7#>Lc^Yp7SEk8i#g`+%^T+ow_MdWJk<(?+R&y)Spwe~aJVGX%2 z-a{aa6y#cfNl`=#|G#*t??7*)0?}$ic8>v$T_%iFGu}t8*`=qW5cC>(1RyntDUkp4Q zgpWcee-)u9P~_;5T5LZY{q?1aZRqYv1=C2@+!R@_uga5Eu zK{_R1$X-1@MP~S%-;hK)&Q$g&5`CQ!2vFVp9sdWRxzG035QANc2sL7=190Bw64GV; zq|4`WKrWdHVJzSTsF#pn^Q{%zAfmhZRtd~}>decSMQ^`D4ff{%JKl`aY$HeCS8yxC zn~wNYD}su9Mnc=4nI~XFjB?U<1}u*fZmie67$#GvGW~wbt8Vz4`+}Jxq!)jB{%-?{xWW$6RWnc zQ?ft>O6>FRtr6=%l1R~tgA@e>`L0eyPn%iGt}l*q4Kcm-iZm@s^Yjm4zrfaRsM+~h zw>Cd&MypGh1VA=-gY|a1VqgMq5nj_>Q>XLb0VCg;(zCWaww1#1GvUmo#lfyl{zrG; zYt8bt$?oJ-2dw!l5`u*pjB0u*Myf49cc%#L9d*-C>~^Vv_ZHq`&UpQL-6FFc6%esW`-L#mMnNr${UV^t zbn=FX%3{5jyY)(6`~E2=F~pdNvT8Z@kP^V`rLx{R++N zU|ULGh1cK&)$cSeB=1dfbF3T=*52E~kz=fZ)7kW}=C=`9y1M!vy|%iy@QH|&mLS0nUVc6YCy=z0YF(ySu`?IDfLQ zQZA^6k^lL=ySuYd#jMet=-KV2zs=#U3$}EU*0v2%EHHck;&T-58*9g>4qc-rafi zX|vBt@f^zzZ3Az6#SVDT^=xQT%R2GE?@mEaS~|{c#C%cQoIw%iu)cx9$a95f{mcN;`!@@y4h?$K} z6{c?;&W~g+C(d73e|;gYp$+89ASOMB-3eITh;uUt%XB1jwdm1X^cdYaU|#+3UEu*f zovV${_WH_nj<=qv<~w=H_pXA=G@lv9?(1nQT-NwQZI>ba`7Y3u)RE2w3Hu8ct@p;e zEHiP5(`Gg(S@HY8UOLRFd|P`sKa$})(6P4hdZ+W&?2$N#HJTiDXC`)Lv|ML*%&YSJ zDn%nkwHc(`!6NsKfJ?o!rXUNBmYQD2(DXEBB6Xc27q~)BD$)Y8{Z07ZDY9Ov(RF0= zVqz{e+(Q?+1Gk{25clxSOb-WYUF<)bu}{jyI$X2#!Bjzngm-r(DF)lySOEj8kc9bB zQGX*~9q)ms1TCs?pOy}M#q@|fh-m>O8oQ_-oonx0{ylu_VO`bSCds7;Y;N9Hji2*4 zlyELJ5G~>U3;W?`2y8FA`_+H*-1d*Spm#3-p>)9Me5J*L2--F8WB;v45mocl%M)y8|-PHl85pWWBQ&jbH@xM{;Mw0=1 z|5J_5e=F;Wv_f${dJl6#n-)zz=H}apb%wJx$_`58r%iXI89NT(unNPI-PzFmkm`}i z`P86iwNu^=y@U3q4c|UhMd7sIa3J>>9J)=3{)WZts$dgLYp3HytXm_R0_V z@IFCAniMDPM5gBlbu0PD!uM~dh0VUip|eGZEn0k?*Eu1av2FwdN#0){*D_7Iemj4? zdMvX$!d#p%I`&6~h zg2Nhda-{752ID3R7IY+R0QwG%BBj^P-DSZyD3A5r0b5;7;d8(fq6=V;*t> zl=NkQfWii6!N;A{; zX?Ef_?ODf7j`Xuv9;n6<@Wl6$0rkslY1PY)qvVCMc!xe#u5dwFNonKXp01C@@B(!^ zS?D`M`Bjg=o0%!AA|7l`E>1CGRNB1t_xd3c4qx9RSj zGBGYB&QTxr*=V@haCdGC6J`_70?88OSE1(4KzSV)>F}Xj;-%&92s>~5aenSQVu(?{ z=}OS1!LXpH|a}KYOw!^hei2#F*bE zxYkq>9R32)Q-vehj>WL>x_#tOrDD1P-<#x!|}DQ^Hk9q>i(T!QAqZgU1d-*p5+>a+u!4=m%?M zyuysngVjo>TbjEETe>XeZ`>t-FEA0yUiY1yN6dM7sTfL)m=Ma#Q%MW2JJGdLY+azJ z)Il>uhhq=Rl!miP)zM+e>x582nl$DK9zKVEvVBNpcrzX3HISDQVB-YtzHD4+%s=v6`AT}8yi7Kn2ePkp{H@~X?X-zq(Awn`v{4~>m z4|9Qly`DszxG8JD3;5onni6Gth2@4(CY-e=_2`+f`?+f+Bf@$s2WuGN&qg;2!z;A6 zHRD*)8l4-@SuPH#nj+aQTd^xDzKpr5`dUD4u+@)bU^ub94+>`+@v6j%qqS)nMK}14 zf_B3;mOc2v41@#JrLcZouTE=NA3D<^I;fgF`08khjUr?tMui*Lfd5lfX%{r=Q9|V% zQI7M#P4R7&_HL%{Q0$q4a=bkT2CZw}G4-0K&p;y2Qzf$Wt7eJSk2c(DexjjpdF&v` zzdb`CaC6Ph-%bAVIr3~v>(O$}p{++q+1D%qXVdb8@$;7Ec8&Hd0Ggir6dkhVGT1O# zba?PMDPZ>ft9qJeNb}(uxut)fOO=ziPK^Z*UJYBhJknY4{N(hMeX2-_0v%dcV$N6KePk z5JU@)<>;ti9@5;!yzwr%H2=Xi>0oQZ&O}Za8;f*uR1u5aI}Pyed%x3eDi&@%L*O3) zhUx?6mo~p5I5OAIes3!Sfbm6L{JNo1gufigeU)}NPSwpOl<>Gf+L}lQqo-4XK>l7k p(Arp{6lwVD{#L>l3&0HoreUD|_U7G3{{cE>2O$6e literal 0 HcmV?d00001 diff --git a/README.md b/README.md index 9621b58b46..5e3c1f83e0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,17 @@ -## Frappé Framework + [![Build Status](https://travis-ci.org/frappe/frappe.png)](https://travis-ci.org/frappe/frappe) diff --git a/frappe/public/build.json b/frappe/public/build.json index cf6e784ba5..410f398ab2 100755 --- a/frappe/public/build.json +++ b/frappe/public/build.json @@ -23,6 +23,9 @@ "public/js/frappe/misc/rating_icons.html" ], "js/control.min.js": [ + + "public/js/frappe/ui/camera.js", + "public/js/frappe/form/controls/base_control.js", "public/js/frappe/form/controls/base_input.js", "public/js/frappe/form/controls/data.js", @@ -55,12 +58,17 @@ "js/dialog.min.js": [ "public/js/frappe/dom.js", "public/js/frappe/ui/modal.html", + + "public/js/frappe/form/formatters.js", "public/js/frappe/form/layout.js", "public/js/frappe/ui/field_group.js", "public/js/frappe/form/link_selector.js", "public/js/frappe/form/multi_select_dialog.js", "public/js/frappe/ui/dialog.js", + + "public/js/frappe/ui/camera.js", + "public/js/frappe/form/controls/base_control.js", "public/js/frappe/form/controls/base_input.js", "public/js/frappe/form/controls/data.js", @@ -131,7 +139,8 @@ "public/js/frappe/translate.js", "public/js/lib/datepicker/datepicker.min.js", "public/js/lib/datepicker/locale-all.js", - "public/js/lib/jquery.jrumble.min.js" + "public/js/lib/jquery.jrumble.min.js", + "public/js/lib/webcam.min.js" ], "js/desk.min.js": [ "public/js/frappe/class.js", @@ -169,6 +178,9 @@ "public/js/frappe/form/link_selector.js", "public/js/frappe/form/multi_select_dialog.js", "public/js/frappe/ui/dialog.js", + + "public/js/frappe/ui/camera.js", + "public/js/frappe/ui/app_icon.js", "public/js/frappe/model/model.js", diff --git a/frappe/public/js/frappe/form/controls/text_editor.js b/frappe/public/js/frappe/form/controls/text_editor.js index 00af468754..3a82a7af6d 100644 --- a/frappe/public/js/frappe/form/controls/text_editor.js +++ b/frappe/public/js/frappe/form/controls/text_editor.js @@ -7,6 +7,19 @@ frappe.ui.form.ControlTextEditor = frappe.ui.form.ControlCode.extend({ this.setup_image_dialog(); this.setting_count = 0; }, + render_camera_button: (context) => { + var ui = $.summernote.ui; + var button = ui.button({ + contents: '', + tooltip: 'Camera', + click: () => { + const camera = new frappe.ui.Camera(); + camera.show(); + } + }); + + return button.render(); + }, make_editor: function() { var me = this; this.editor = $("
").appendTo(this.input_area); @@ -25,9 +38,12 @@ frappe.ui.form.ControlTextEditor = frappe.ui.form.ControlCode.extend({ ['color', ['color']], ['para', ['ul', 'ol', 'paragraph', 'hr']], //['height', ['height']], - ['media', ['link', 'picture', 'video', 'table']], + ['media', ['link', 'picture', 'camera', 'video', 'table']], ['misc', ['fullscreen', 'codeview']] ], + buttons: { + camera: this.render_camera_button, + }, keyMap: { pc: { 'CTRL+ENTER': '' @@ -80,6 +96,7 @@ frappe.ui.form.ControlTextEditor = frappe.ui.form.ControlCode.extend({ 'outdent': 'fa fa-outdent', 'arrowsAlt': 'fa fa-arrows-alt', 'bold': 'fa fa-bold', + 'camera': 'fa fa-camera', 'caret': 'caret', 'circle': 'fa fa-circle', 'close': 'fa fa-close', diff --git a/frappe/public/js/frappe/ui/camera.js b/frappe/public/js/frappe/ui/camera.js new file mode 100644 index 0000000000..733471d86e --- /dev/null +++ b/frappe/public/js/frappe/ui/camera.js @@ -0,0 +1,67 @@ +frappe.ui.Camera = class +{ + constructor (options) + { + this.dialog = new frappe.ui.Dialog(); + + this.template = + ` +
+ +
+ ` + + this.show = this.show.bind(this); + this.hide = this.hide.bind(this); + this.on = this.on.bind(this); + this.attach = this.attach.bind(this); + + Webcam.set({ + width: 320, + height: 240, + flip_horiz: true, + }) + } + + show ( ) + { + this.attach((err) => { + if ( err ) + throw Error('Unable to attach webcamera.'); + + this.dialog.set_primary_action(__('Click'), () => { + this.click(); + }); + + this.dialog.show(); + }); + } + + hide ( ) + { + this.dialog.hide(); + } + + on (event, callback) + { + if ( event == 'attach' ) { + this.attach(callback); + } + } + + click (callback) + { + Webcam.snap((data) => { + console.log(data); + }); + } + + attach (callback) + { + $(this.dialog.body).append(this.template); + + Webcam.attach('#frappe-camera'); + + callback(); + } +}; \ No newline at end of file diff --git a/frappe/public/js/lib/webcam.min.js b/frappe/public/js/lib/webcam.min.js new file mode 100644 index 0000000000..3325ccfd05 --- /dev/null +++ b/frappe/public/js/lib/webcam.min.js @@ -0,0 +1,2 @@ +// WebcamJS v1.0.22 - http://github.com/jhuckaby/webcamjs - MIT Licensed +(function(e){var t;function a(){var e=Error.apply(this,arguments);e.name=this.name="FlashError";this.stack=e.stack;this.message=e.message}function i(){var e=Error.apply(this,arguments);e.name=this.name="WebcamError";this.stack=e.stack;this.message=e.message}IntermediateInheritor=function(){};IntermediateInheritor.prototype=Error.prototype;a.prototype=new IntermediateInheritor;i.prototype=new IntermediateInheritor;var Webcam={version:"1.0.22",protocol:location.protocol.match(/https/i)?"https":"http",loaded:false,live:false,userMedia:true,iOS:/iPad|iPhone|iPod/.test(navigator.userAgent)&&!e.MSStream,params:{width:0,height:0,dest_width:0,dest_height:0,image_format:"jpeg",jpeg_quality:90,enable_flash:true,force_flash:false,flip_horiz:false,fps:30,upload_name:"webcam",constraints:null,swfURL:"",flashNotDetectedText:"ERROR: No Adobe Flash Player detected. Webcam.js relies on Flash for browsers that do not support getUserMedia (like yours).",noInterfaceFoundText:"No supported webcam interface found.",unfreeze_snap:true,iosPlaceholderText:"Click here to open camera.",user_callback:null,user_canvas:null},errors:{FlashError:a,WebcamError:i},hooks:{},init:function(){var t=this;this.mediaDevices=navigator.mediaDevices&&navigator.mediaDevices.getUserMedia?navigator.mediaDevices:navigator.mozGetUserMedia||navigator.webkitGetUserMedia?{getUserMedia:function(e){return new Promise(function(t,a){(navigator.mozGetUserMedia||navigator.webkitGetUserMedia).call(navigator,e,t,a)})}}:null;e.URL=e.URL||e.webkitURL||e.mozURL||e.msURL;this.userMedia=this.userMedia&&!!this.mediaDevices&&!!e.URL;if(navigator.userAgent.match(/Firefox\D+(\d+)/)){if(parseInt(RegExp.$1,10)<21)this.userMedia=null}if(this.userMedia){e.addEventListener("beforeunload",function(e){t.reset()})}},exifOrientation:function(e){var t=new DataView(e);if(t.getUint8(0)!=255||t.getUint8(1)!=216){console.log("Not a valid JPEG file");return 0}var a=2;var i=null;while(a8){console.log("Invalid EXIF orientation value ("+p+")");return 0}return p}}}else{a+=2+t.getUint16(a+2)}}return 0},fixOrientation:function(e,t,a){var i=new Image;i.addEventListener("load",function(e){var s=document.createElement("canvas");var r=s.getContext("2d");if(t<5){s.width=i.width;s.height=i.height}else{s.width=i.height;s.height=i.width}switch(t){case 2:r.transform(-1,0,0,1,i.width,0);break;case 3:r.transform(-1,0,0,-1,i.width,i.height);break;case 4:r.transform(1,0,0,-1,0,i.height);break;case 5:r.transform(0,1,1,0,0,0);break;case 6:r.transform(0,1,-1,0,i.height,0);break;case 7:r.transform(0,-1,-1,0,i.height,i.width);break;case 8:r.transform(0,-1,1,0,0,i.width);break}r.drawImage(i,0,0);a.src=s.toDataURL()},false);i.src=e},attach:function(a){if(typeof a=="string"){a=document.getElementById(a)||document.querySelector(a)}if(!a){return this.dispatch("error",new i("Could not locate DOM element to attach to."))}this.container=a;a.innerHTML="";var s=document.createElement("div");a.appendChild(s);this.peg=s;if(!this.params.width)this.params.width=a.offsetWidth;if(!this.params.height)this.params.height=a.offsetHeight;if(!this.params.width||!this.params.height){return this.dispatch("error",new i("No width and/or height for webcam. Please call set() first, or attach to a visible element."))}if(!this.params.dest_width)this.params.dest_width=this.params.width;if(!this.params.dest_height)this.params.dest_height=this.params.height;this.userMedia=t===undefined?this.userMedia:t;if(this.params.force_flash){t=this.userMedia;this.userMedia=null}if(typeof this.params.fps!=="number")this.params.fps=30;var r=this.params.width/this.params.dest_width;var o=this.params.height/this.params.dest_height;if(this.userMedia){var n=document.createElement("video");n.setAttribute("autoplay","autoplay");n.style.width=""+this.params.dest_width+"px";n.style.height=""+this.params.dest_height+"px";if(r!=1||o!=1){a.style.overflow="hidden";n.style.webkitTransformOrigin="0px 0px";n.style.mozTransformOrigin="0px 0px";n.style.msTransformOrigin="0px 0px";n.style.oTransformOrigin="0px 0px";n.style.transformOrigin="0px 0px";n.style.webkitTransform="scaleX("+r+") scaleY("+o+")";n.style.mozTransform="scaleX("+r+") scaleY("+o+")";n.style.msTransform="scaleX("+r+") scaleY("+o+")";n.style.oTransform="scaleX("+r+") scaleY("+o+")";n.style.transform="scaleX("+r+") scaleY("+o+")"}a.appendChild(n);this.video=n;var h=this;this.mediaDevices.getUserMedia({audio:false,video:this.params.constraints||{mandatory:{minWidth:this.params.dest_width,minHeight:this.params.dest_height}}}).then(function(t){n.onloadedmetadata=function(e){h.stream=t;h.loaded=true;h.live=true;h.dispatch("load");h.dispatch("live");h.flip()};n.src=e.URL.createObjectURL(t)||t}).catch(function(e){if(h.params.enable_flash&&h.detectFlash()){setTimeout(function(){h.params.force_flash=1;h.attach(a)},1)}else{h.dispatch("error",e)}})}else if(this.iOS){var l=document.createElement("div");l.id=this.container.id+"-ios_div";l.className="webcamjs-ios-placeholder";l.style.width=""+this.params.width+"px";l.style.height=""+this.params.height+"px";l.style.textAlign="center";l.style.display="table-cell";l.style.verticalAlign="middle";l.style.backgroundRepeat="no-repeat";l.style.backgroundSize="contain";l.style.backgroundPosition="center";var c=document.createElement("span");c.className="webcamjs-ios-text";c.innerHTML=this.params.iosPlaceholderText;l.appendChild(c);var d=document.createElement("img");d.id=this.container.id+"-ios_img";d.style.width=""+this.params.dest_width+"px";d.style.height=""+this.params.dest_height+"px";d.style.display="none";l.appendChild(d);var f=document.createElement("input");f.id=this.container.id+"-ios_input";f.setAttribute("type","file");f.setAttribute("accept","image/*");f.setAttribute("capture","camera");var h=this;var m=this.params;f.addEventListener("change",function(e){if(e.target.files.length>0&&e.target.files[0].type.indexOf("image/")==0){var t=URL.createObjectURL(e.target.files[0]);var a=new Image;a.addEventListener("load",function(e){var t=document.createElement("canvas");t.width=m.dest_width;t.height=m.dest_height;var i=t.getContext("2d");ratio=Math.min(a.width/m.dest_width,a.height/m.dest_height);var s=m.dest_width*ratio;var r=m.dest_height*ratio;var o=(a.width-s)/2;var n=(a.height-r)/2;i.drawImage(a,o,n,s,r,0,0,m.dest_width,m.dest_height);var h=t.toDataURL();d.src=h;l.style.backgroundImage="url('"+h+"')"},false);var i=new FileReader;i.addEventListener("load",function(e){var i=h.exifOrientation(e.target.result);if(i>1){h.fixOrientation(t,i,a)}else{a.src=t}},false);var s=new XMLHttpRequest;s.open("GET",t,true);s.responseType="blob";s.onload=function(e){if(this.status==200||this.status===0){i.readAsArrayBuffer(this.response)}};s.send()}},false);f.style.display="none";a.appendChild(f);l.addEventListener("click",function(e){if(m.user_callback){h.snap(m.user_callback,m.user_canvas)}else{f.style.display="block";f.focus();f.click();f.style.display="none"}},false);a.appendChild(l);this.loaded=true;this.live=true}else if(this.params.enable_flash&&this.detectFlash()){e.Webcam=Webcam;var l=document.createElement("div");l.innerHTML=this.getSWFHTML();a.appendChild(l)}else{this.dispatch("error",new i(this.params.noInterfaceFoundText))}if(this.params.crop_width&&this.params.crop_height){var p=Math.floor(this.params.crop_width*r);var u=Math.floor(this.params.crop_height*o);a.style.width=""+p+"px";a.style.height=""+u+"px";a.style.overflow="hidden";a.scrollLeft=Math.floor(this.params.width/2-p/2);a.scrollTop=Math.floor(this.params.height/2-u/2)}else{a.style.width=""+this.params.width+"px";a.style.height=""+this.params.height+"px"}},reset:function(){if(this.preview_active)this.unfreeze();this.unflip();if(this.userMedia){if(this.stream){if(this.stream.getVideoTracks){var e=this.stream.getVideoTracks();if(e&&e[0]&&e[0].stop)e[0].stop()}else if(this.stream.stop){this.stream.stop()}}delete this.stream;delete this.video}if(this.userMedia!==true&&this.loaded&&!this.iOS){var t=this.getMovie();if(t&&t._releaseCamera)t._releaseCamera()}if(this.container){this.container.innerHTML="";delete this.container}this.loaded=false;this.live=false},set:function(){if(arguments.length==1){for(var e in arguments[0]){this.params[e]=arguments[0][e]}}else{this.params[arguments[0]]=arguments[1]}},on:function(e,t){e=e.replace(/^on/i,"").toLowerCase();if(!this.hooks[e])this.hooks[e]=[];this.hooks[e].push(t)},off:function(e,t){e=e.replace(/^on/i,"").toLowerCase();if(this.hooks[e]){if(t){var a=this.hooks[e].indexOf(t);if(a>-1)this.hooks[e].splice(a,1)}else{this.hooks[e]=[]}}},dispatch:function(){var t=arguments[0].replace(/^on/i,"").toLowerCase();var s=Array.prototype.slice.call(arguments,1);if(this.hooks[t]&&this.hooks[t].length){for(var r=0,o=this.hooks[t].length;rERROR: the Webcam.js Flash fallback does not work from local disk. Please run it from a web server.'}if(!this.detectFlash()){this.dispatch("error",new a("Adobe Flash Player not found. Please install from get.adobe.com/flashplayer and try again."));return'

'+this.params.flashNotDetectedText+"

"}if(!i){var s="";var r=document.getElementsByTagName("script");for(var o=0,n=r.length;o';return t},getMovie:function(){if(!this.loaded)return this.dispatch("error",new a("Flash Movie is not loaded yet"));var e=document.getElementById("webcam_movie_obj");if(!e||!e._snap)e=document.getElementById("webcam_movie_embed");if(!e)this.dispatch("error",new a("Cannot locate Flash movie in DOM"));return e},freeze:function(){var e=this;var t=this.params;if(this.preview_active)this.unfreeze();var a=this.params.width/this.params.dest_width;var i=this.params.height/this.params.dest_height;this.unflip();var s=t.crop_width||t.dest_width;var r=t.crop_height||t.dest_height;var o=document.createElement("canvas");o.width=s;o.height=r;var n=o.getContext("2d");this.preview_canvas=o;this.preview_context=n;if(a!=1||i!=1){o.style.webkitTransformOrigin="0px 0px";o.style.mozTransformOrigin="0px 0px";o.style.msTransformOrigin="0px 0px";o.style.oTransformOrigin="0px 0px";o.style.transformOrigin="0px 0px";o.style.webkitTransform="scaleX("+a+") scaleY("+i+")";o.style.mozTransform="scaleX("+a+") scaleY("+i+")";o.style.msTransform="scaleX("+a+") scaleY("+i+")";o.style.oTransform="scaleX("+a+") scaleY("+i+")";o.style.transform="scaleX("+a+") scaleY("+i+")"}this.snap(function(){o.style.position="relative";o.style.left=""+e.container.scrollLeft+"px";o.style.top=""+e.container.scrollTop+"px";e.container.insertBefore(o,e.peg);e.container.style.overflow="hidden";e.preview_active=true},o)},unfreeze:function(){if(this.preview_active){this.container.removeChild(this.preview_canvas);delete this.preview_context;delete this.preview_canvas;this.preview_active=false;this.flip()}},flip:function(){if(this.params.flip_horiz){var e=this.container.style;e.webkitTransform="scaleX(-1)";e.mozTransform="scaleX(-1)";e.msTransform="scaleX(-1)";e.oTransform="scaleX(-1)";e.transform="scaleX(-1)";e.filter="FlipH";e.msFilter="FlipH"}},unflip:function(){if(this.params.flip_horiz){var e=this.container.style;e.webkitTransform="scaleX(1)";e.mozTransform="scaleX(1)";e.msTransform="scaleX(1)";e.oTransform="scaleX(1)";e.transform="scaleX(1)";e.filter="";e.msFilter=""}},savePreview:function(e,t){var a=this.params;var i=this.preview_canvas;var s=this.preview_context;if(t){var r=t.getContext("2d");r.drawImage(i,0,0)}e(t?null:i.toDataURL("image/"+a.image_format,a.jpeg_quality/100),i,s);if(this.params.unfreeze_snap)this.unfreeze()},snap:function(e,t){if(!e)e=this.params.user_callback;if(!t)t=this.params.user_canvas;var a=this;var s=this.params;if(!this.loaded)return this.dispatch("error",new i("Webcam is not loaded yet"));if(!e)return this.dispatch("error",new i("Please provide a callback function or canvas to snap()"));if(this.preview_active){this.savePreview(e,t);return null}var r=document.createElement("canvas");r.width=this.params.dest_width;r.height=this.params.dest_height;var o=r.getContext("2d");if(this.params.flip_horiz){o.translate(s.dest_width,0);o.scale(-1,1)}var n=function(){if(this.src&&this.width&&this.height){o.drawImage(this,0,0,s.dest_width,s.dest_height)}if(s.crop_width&&s.crop_height){var a=document.createElement("canvas");a.width=s.crop_width;a.height=s.crop_height;var i=a.getContext("2d");i.drawImage(r,Math.floor(s.dest_width/2-s.crop_width/2),Math.floor(s.dest_height/2-s.crop_height/2),s.crop_width,s.crop_height,0,0,s.crop_width,s.crop_height);o=i;r=a}if(t){var n=t.getContext("2d");n.drawImage(r,0,0)}e(t?null:r.toDataURL("image/"+s.image_format,s.jpeg_quality/100),r,o)};if(this.userMedia){o.drawImage(this.video,0,0,this.params.dest_width,this.params.dest_height);n()}else if(this.iOS){var h=document.getElementById(this.container.id+"-ios_div");var l=document.getElementById(this.container.id+"-ios_img");var c=document.getElementById(this.container.id+"-ios_input");iFunc=function(e){n.call(l);l.removeEventListener("load",iFunc);h.style.backgroundImage="none";l.removeAttribute("src");c.value=null};if(!c.value){l.addEventListener("load",iFunc);c.style.display="block";c.focus();c.click();c.style.display="none"}else{iFunc(null)}}else{var d=this.getMovie()._snap();var l=new Image;l.onload=n;l.src="data:image/"+this.params.image_format+";base64,"+d}return null},configure:function(e){if(!e)e="camera";this.getMovie()._configure(e)},flashNotify:function(e,t){switch(e){case"flashLoadComplete":this.loaded=true;this.dispatch("load");break;case"cameraLive":this.live=true;this.dispatch("live");break;case"error":this.dispatch("error",new a(t));break;default:break}},b64ToUint6:function(e){return e>64&&e<91?e-65:e>96&&e<123?e-71:e>47&&e<58?e+4:e===43?62:e===47?63:0},base64DecToArr:function(e,t){var a=e.replace(/[^A-Za-z0-9\+\/]/g,""),i=a.length,s=t?Math.ceil((i*3+1>>2)/t)*t:i*3+1>>2,r=new Uint8Array(s);for(var o,n,h=0,l=0,c=0;c>>(16>>>o&24)&255}h=0}}return r},upload:function(e,t,a){var i=this.params.upload_name||"webcam";var s="";if(e.match(/^data\:image\/(\w+)/))s=RegExp.$1;else throw"Cannot locate image format in Data URI";var r=e.replace(/^data\:image\/\w+\;base64\,/,"");var o=new XMLHttpRequest;o.open("POST",t,true);if(o.upload&&o.upload.addEventListener){o.upload.addEventListener("progress",function(e){if(e.lengthComputable){var t=e.loaded/e.total;Webcam.dispatch("uploadProgress",t,e)}},false)}var n=this;o.onload=function(){if(a)a.apply(n,[o.status,o.responseText,o.statusText]);Webcam.dispatch("uploadComplete",o.status,o.responseText,o.statusText)};var h=new Blob([this.base64DecToArr(r)],{type:"image/"+s});var l=new FormData;l.append(i,h,i+"."+s.replace(/e/,""));o.send(l)}};Webcam.init();if(typeof define==="function"&&define.amd){define(function(){return Webcam})}else if(typeof module==="object"&&module.exports){module.exports=Webcam}else{e.Webcam=Webcam}})(window); \ No newline at end of file