From 1beed456ccaeb68095572081ab7d3cb84952c257 Mon Sep 17 00:00:00 2001 From: Brian Pilati <brian.pilati@domo.com> Date: Sat, 8 Mar 2014 00:46:59 -0700 Subject: [PATCH] updates to add "ask" functionality --- .gitignore | 1 + img/ask-bottom.png | Bin 0 -> 909 bytes img/ask-button.png | Bin 0 -> 1933 bytes img/playerStartFlag.png | Bin 8076 -> 4829 bytes js/Reporter.js | 11 +- js/Sprite.js | 70 +++++- js/Stage.js | 1 + js/primitives/LooksPrims.js | 14 ++ player.css | 47 ++++- test/artifacts/IOMock.js | 25 +++ test/artifacts/TargetMock.js | 4 +- test/artifacts/ask-artifact.js | 16 +- test/artifacts/reporterValues.js | 91 ++++++++ test/unit/looksPrimitiveSpec.js | 54 ++++- test/unit/reporterSpec.js | 96 +++++++++ test/unit/spriteSpec.js | 352 +++++++++++++++++++++++++++++++ test/unit/stageSpec.js | 51 +++++ 17 files changed, 809 insertions(+), 24 deletions(-) create mode 100644 img/ask-bottom.png create mode 100644 img/ask-button.png create mode 100644 test/artifacts/IOMock.js create mode 100644 test/artifacts/reporterValues.js create mode 100644 test/unit/reporterSpec.js create mode 100644 test/unit/spriteSpec.js create mode 100644 test/unit/stageSpec.js diff --git a/.gitignore b/.gitignore index ca4d940..1d5cbb2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ *.swp test/lib/* +.DS_Store logs diff --git a/img/ask-bottom.png b/img/ask-bottom.png new file mode 100644 index 0000000000000000000000000000000000000000..9823a430aa3477e626d124c5d8fa0e78997a1875 GIT binary patch literal 909 zcmV;819JR{P)<h;3K|Lk000e1NJLTq001fg000sQ1^@s6E$U3000004XF*Lt006JZ zHwB960000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU#A4x<(RCwBA zy!HOae-36Q23cNKMg}yn>gI?43$MNhv*Wb|8N$>B7-$7ve*Mj`=g}92J0E^AoO=EZ zLmnW2SX2er8L?@6^Zn2N6HpB@ysQk4vOF|#;LUeG8BPN2IrZWj!?!>G7`RxN;Bq=5 z91QHtj12ZNJPZH<#DdF!<Ilc<4FLgXIUWX4E*7de?#r*g3};_`XE^rs8^eQ7zZjl; z{*5B9B*4aCB*w{LD#^v5Bg_E~NPqysYWvsU|Nes<3IdYctPD<a)CtY&?|v{`e*J^t z7|`t7?|-7mX$f;MaI!!`PhX6KK?KA>0ssNTf-5vHzWxqon@DhiG*J|Kr(S*sr@IFq ze=$5p3q2J9b_O*;HU@iOV8B8T8vqC(7Hpxp?fxe)Tb!GP?9jaS77}`(wD<AnKZfUD zf1{+mzyJO-*aOqOr4$!N=wSl@0fgbu3$K2_)24|y7tputB!%8ZpySQ}Ll6|T_kkgZ z4Ag;UsQ^RIOoAH}Q;ei|93X%&9J=e_XLxA3$rBfv_dot*IPv^D!*yUNzWnwFC3Ap6 z?>~^XmF6Zo^soVd077x-*_Yq{gF*!a<apVDzGuf9dgp<mclO11aLz@~9NNIl0m{9g zSRpm^umOMoLUHKEJ0BTtK%?D9nHQ^udmny+b1kS~egzD@ho4ZR*GQa`K^GW`mQvhU zD-m)5Kmf5IhbAy1f!T(@G7J<F$YB5DFAO)|{$#ifbm$kLI`rt3045b%V9}x}#LmFY z%EU<RiUA;i;0`_U>?=Gp16BFp)!Ko_UxDS{PlmTY{s2Q0HS~;up$BrL6)^N<s2F<K z06+kN9SRJk|M#Fd6c`!|-+%vSm~`$nFx37qd;+G$$5=wo4j6hGGzvXz03d)E|NsBb zFyZX$|GOW4!K)CIIY5O!C=IIMXdloL00a=r9bjnQL5ou4(Bo%k23KnaVjTRy(EG$N zKmZ_sST^7Ngi$bq90*E(0~LDM06+k-h;y;RIo7~J85(**z|ecoFo*y^0D;mdJR>Rb jvvB~apA3T#00bBSHz77eF$;b_00000NkvXXu0mjf{(^|| literal 0 HcmV?d00001 diff --git a/img/ask-button.png b/img/ask-button.png new file mode 100644 index 0000000000000000000000000000000000000000..713927add0c1ba49aef6172c49b7243b04106660 GIT binary patch literal 1933 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 J*Bm1(`#-kDcuoKS literal 0 HcmV?d00001 diff --git a/img/playerStartFlag.png b/img/playerStartFlag.png index 11a8e72b970d14beda936bcd68e7acb1be7da02a..f2211d1ddad2a80ee4c4ad703a8df910fdbe2c2b 100644 GIT binary patch literal 4829 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 literal 8076 zcmV;7A9LV|P)<h;3K|Lk000e1NJLTq002w?002w~1^@s6$Cptn00009a7bBm000&x z000&x0ZCFM@Bjb|0%=1-P*7-ZbZ>KLZ*U+<Lqi~Na&Km7Y-Iodc-pO3XH-<@7TveZ z3}t30Gaw*k=uMO&O{8~0K{~|3Ff+iwFbu<hirp9z!PrF<OGKk0MiY&I#Db{7LJ;i6 z^01&1i9roERNfDYc`xt%cx%0Ht$Wv5``c%qea>C?#{szQLWM#`Y6E$4l`<|oNRX16 zCSctG0X}r$4RxWYP!Sj#8;$>b2;kK<5CCx5NvKfB@V^}$v7}H05U~I<#D$_ffcO!h z8bk`E3Sh_pSj|!?Q~+ZY0KPIMH4R|w1i;T4j2i&(GX~>U0DNUaTrj}s1k~6<p)w2L z^Z*bPi?UPzmkq#KE|$sx?nD57qHLiU;LZauCND2v3~=`Vu*>+1PS(F@W{hYGg;^u< zU@rgwwGe5cLMEJp|M$t06%E%g1;8%MjgJDL4-m6O!q9jC1^}@lTM`*Pgzr+Qg5rko zqf%950suZhT*)qqNF0iv6y+uc0x$-M_qq8|aRAr=X&}#-5(7XNAgx4&!D)k<q(@11 zLh=wNS}X|(1)vR(Da!n~VSaXDar`h|Qj#4!Wtg8MoD>Uy3y@_(B{1lLtdz*Y;{aFy z<UWNeHesk%n_M<!s2B2KrZOyUD1Ij?42>VIrOHl-7}Te<Rmz08K~2gyQyLaI=z((1 zRz?it0SZ}c^k6QPpe%|@1YiYFnG$*8kS0|o7KTI(&V<^GFbJW91R0Q{8v;Zl7$HM% z0VI$^01@&bLq3!Ot>GKSBSr_~KI1B*lW}u|9X!l~6k_C$;G)0a@hHLXkVAsP;cB!I z?MM62(X<~OK>N|Iv={9?eAm`f-!tNB&}$YXa2i5_hTIoJjt|4UnbIZ7f6K`j$@sgc zFg%13S;GwHTIX)(_rv+0I%bA4LzofFFs42A6?KSep-xigsH0Rp1k?$tfoi3WQT2bD zpKxd@N=Q(MD99i|5tNWX{vRC`jWC8#t^?N{agaccT*x3DsgQ(+P(u1Ql_Cg`fqdjZ zil~tuhbL`AyVCA-5baC*(cTcy`m_<8=<&1{9Z37rKD0aS{g<!!uiZEy6GA9a3<(O6 zi$_o*PbHbH0)XIr#T=zHD_bQ9R48PUF@i|BXzUn)tFwz6Qc}|dgTMAmeGmW${qvu& zf+oPb3?Q;TVM0sb$RmLF>Jw)90${HKj<t)5l*NM>4FC*iKnr{r!W5RUgA-ig0Urb) z6q68x1f*gHM94-Sl$eEiSd3DXV-?n86SiRo_TW1lL_Ln;B!0#PwBssnp%Yzrie9`z zKS2;If<y2KL&A)(CL9S@!i(@DLWyW1jz}fai7Y}+6cO`?&xvwk4Y7&XPSg-T5J!lU z#5tmaxJle2x``LWJCY*VB%d@PZOCz?7a2%KkqP8<GK(xAOUR|<3bK-{Cijtb<Vo@Z zd6n!WpOSqPC{0SAGN+s<FDjUdq0*>KN=YrC%BTven%Yk_QZ3YFs*~!W-qK8(M+;~t z+J}yy6KN4$Krf(|)0^l$bRB(~zD(bvd+Co14#Sw?$e6&0WTY^%7_%6qj0(ms#$m=8 z##Kfa;}w(1)Mwf<J(&^ARAvryE^|3^3-bW8iP^z?!0cnOScWV|mM<%YC1j~srL2vt zeXJ9#ORO%|8#PTeGc{MWFts!_x!Mx73bnmz$JH*WJyz>i*H*VypP(M2E>@qTzEXXs zdZYS9^)B^(4IK?z4PT7}jU0`|8kHLRHO^?<)_AF@scE6<tvOXws<}wBQuBMwvzqrb z-?DYt4(wp|G<Fet1$#HUiG7p(lEdNHZ~{1K92I8;r-pNibC>gm%j1saMsmg6h1@D` z9rqIVnU=biwN{|k46PEa3avw07qxn{)wON3gSCa)3$&}Wk7!@l?$hDvxah>_<moKe z*{gF-=ZP*$*G4x~SFF2KcZcpN-3L61XUPlZiFlv$cJj{fy7)}KEkBZ<!!PH5$8Y2J z>gno@*GtlytyiUYOs`X)(znr%)R*b6)IX?yP5<2}lTm@AB%_v%+CS>jsMiLg4FU`# z24w~Z46YiyGZYwx8s-|VHmo<iV?-M{7)>>rWwh1kj8V^M{%D`kqS0le503uTm^5}U zjx(NXyu-NFxX;AYB-}({veD#}Nsp<%X@F^t={nQnrrl;dGe0w_**dcmX1@va1c3sX zpi*#J&}(jN9${W&zTLddyx+psBGF=r#Q}>umKv5`mYJ68ESoKRt<0<@Tg|howffas z-P+4K+j@g_i}h<8TbpE?FKy~=p4b}LM%tFx*4o~-<JkGz71&kVU9o4{d)epOZ?SK8 zARXKtvK^`%E;^Eq9*$DSEsh;y7-PK0$j4NVx$eYv3Un%Vs&%?IR)1{t*d=4@$37cp zH7;%3>TxaOK03QQ%ba&Q-*VA)ndGv>rP1YutAne^waWF18^<loZJ}F(+w<{`<0a#_ zj=$l~bD!+~rF*mc2M<pVrN@4cZci)EbkEJ6*S+{&v0lr)&U!PvgS;1dAN77a!DE7I z!odlD_&E9G`t0?2GSPOTWa7?=4}2|rg}&Q;JN*QH>3-k%b^4q83;nD8?*~{0hy!*7 zJPx!E%n95V_$<gdNEviE=ymXf;Q7H#Ayi0sNLff*sBUOt=%&!SVHROoVYOks;qKvc z!<!-)5m6DVBd$l9M2aG7B6}x!PMSaIbQC)(K5A3c{b+}1Wpv|Ya`L3fYbW2HVm(DZ zr9K8Rkuhsy?!?;07R3HEl{qzbYSq+7aV~N5;#%T)@iXK1#=lAkN?4h2E72~oD6u(7 zD`{F%P15V+kmNPVohjo|=BHdpHA<DHHl(rAlG1ji^?erl+4|4Arnyfmopx=y?ey8x z&&@EJA)9e*rq)d1%tPsn^yKut>F<Rx!fIh(Mr6k3j9yW&XoKjfI6%Bk+%55ytdTs< z^vzt8`6SCXYi(9{wtsd-c8@ezx=H#xCn9HC&g<Nm+}*hYvSitTJhi;^yd!d5d9M6) zzG?pK{0@bqqEyjYFri?5L9a4OxvP*UoL<<V;;R&@)*`#2FN*FJ`xRFeznPUZ>(FeS z+49+~a~$R@oAbCNtmNCd^jy*0=6UAx7SFpkKXCr`1;m1k1<eaB7cO1cwJ3bip2ZrA za~J=z#Cge@C4YXN{CVS2lckH6KKLU1i`r6dsj~F?mp)%^`-=Wb`c>O9w`CibeJm4~ zoiBGTuPA@NT(tcB*DhaIem$@vb4A-qkCj_jF;~e~U0dzHde0i2H6?2vtew2JZk=FV z*}6a1&s=}5VtmE64H_GYHgr}-S2k?4+PG@t`%T%Ku2uzA9oTHVdD-UITf|!~Z4KDE zf1Am+@@?<Fk$!Vyd-(RcYMbhc9n2lYJ09&!+S&50*S9shjCPgp`mkHRyK_(6p3^m+ zH8p#U_pYoZYl~{T_f6Z^{$0p-4f~z;Z$F@ap!|D$U-bQNKcxR~?O@cw=0jeG_Wx-8 z<L1M>!)0|u-JH7K`t177hSY|RBa@CaH~KUl{%Pz_yN{Y5tvaT6Y~^u{<4cbZoG3Zb z*Q99bIhl3xLG#S!Tc=V^T{%7VblaJzGiQGe`}tH$V9SZKzGsh~n{e*Pd9U;J7d$T1 zwYs++{>A;5!)+dIbr(G^Hne-UH+D?yIDX0h(#gvqmw&zzdF8^@DOWqLC0@I6ecJWT z8{!*JZpv;x|F!tn{#%P~Gj5mN(Y{l0*Z6MrKkWZ;pwpxC*u9W@t@q>a-+CZ=@bqEf z!}ncFA8{U4JT`k=^ThSZ(eAMB_TN7Ht?Q}cX@5`Y?>fJ4erEUV$3Fu8Xzfku?Ru_! zKJa4sOT(AD{~Z5kb6;%V-B)?9`d^p5F?_S<t=HR@cggP__s@FIdSCg${zK!(sE@Y? z@&*PJLZuJ@Kmi~#Gl3Vo0ZuBwYX>yAgS*ktPDgy&?*3amxIX~^Jb>K+K;j}Gx(V3Y z1XwQu*iAqzfP?^$Zf+yb&?(Gxa~;%TD*?uvfq|DM0IL!Bpd1+J-!d@pVJAS{1eyv4 zcQOEAY6IVB0l>Mo<%|A(H~J@hIbd=_%z3f^001CkNK#Dz0Bv;u0CS)K0Q}tm0E1)z z0C4C40PJW005CoP01%Mm?3wBS022gBL_t(|+SFWYjATc3{!UfhcR!|gW_D-SYsU!l zP7p~1h5$);L`q10#3)jbBKZdx#kLG2!H%Ou76KGx0wE70uy_h0P>_P0AC@8o2Swx$ zMv4?f0ywep?!t~|XL`4%d%F9+s_Nv&z17n*JG(oNp52|2uCzNnedpG9&-u=y&N+1E z%o%K7)>;HXfJUPM&+|Y;Afm}<%#5-uvA(_zW=5;kg4P;A5WpA%-}fPeK$@l)4u@D; zT0+0y$E8b`u(Y&<Mx%l8c#O5RwciTE@SR~8wv|#1DWxx^jD!%1nYFc6Gc%WExlxwo zAkXuDmSx{Oe*E~q#c_<mV1VW2Wh^W#U~X;>=g*%<tJQ+<`v8DE&!LpUa5zL9$7r|P zSXo(tloE|b14=0fApl^qr{Qpjq9`Um-@X(MX%P{uwXoL07=thj5d^_q0N!hi>BMoY zPoF-0Co_A~FJ$`r?x8);12cn}A%wU`2=TNrMgdq2g5a?zik{M1PyQYefte3wUxxx1 zGs75zAPA7>`Q2LUyW=<xgCKYv0MCIbgg~_~o@~$o<3Ou$q-g*>Yweqe2uYG4Ns@O+ zDW4t=hXddDKOctS6I$ylO2|zG7&F6K3n?YE)_)a-;jaWia3=s&OUFbCilTrq8pc!- zSbf(_J_i6HM14sR5u}umQb0;IQF|g%%>2eEiV(-~Zvc3DI2`_~QtBgFmd#w!)GQ@R zDFtiohoqEmS4zDefN~&dtx*&O@;pOP6ca9V-`{q}314nk(`j|}eIG#(UIt#H(YVtX z^XpQ|Cq2*mlrd(asy7rc2bAY|FvdI}rF>_j(Rj1FuQ3LBo+HaLl;u{CcH+FL|Lyp< zrU7;@Ax%>VA>esF!Z1J(gpg7yDdk(*?e?!)Yu_QI{8A7EUpL0wIKZ6hG4t>EzW;$J zir&i1f{0*@MV6%)k4Gqq;u_%W-iTZYL}Lt$Ns(nKeBVbLCy1g5Qc4NnZ6{8gcncA| z*%))5<Id{}n0wPv6#Yq(B##OqJoob~%P<;^kmvbCwH$FDh9#a>V`iWz3KT_&G)<8t z34$Pis1W)?B6@|C^2<`nuk4rG_6?Zld7p^m_=8ePVrJxdhT(98JkP*vCzkE{EoV`y z=gadHMUf*2LNpo)f*>Rz<gYC(EW9zxvXcNFy>5UBA^uKE`F<%SjIl`5F*Y{((Aw0l zfWVDh)r+cpu{0f{EORuQZA4KFrId=I=woGB&NK5vhYlDKeO3r@uMiT(7;J0|FdB^} zR_OXl)$UYQYlD7&9a@)YHd~NV5`YJ-wG9CG9SUH~3?lj>5xrXo0b@$6ulJE<DF8k+ zM{yRQRi3}aa5#k426J<5NT~qe-kQtqI}8c?41jkFAy5<r`u%m}d45x<;O>AE6BV`A zpxvH>@B6UU-fOL8X1;$n+97r$S<L(yBDzlqfjrOA>s^`xi*Qtyd*10i)X~Jf*4mF7 zW3IU$v5VmO<Bqem)))->D9h4$);Ma*MG0kDVle1KYYizSDWx8?);^@Q-r^)*2AKPB z`&E`DthEm*r5==0lC=i?e!qSzM-QmWEqx_v{eIs?D<X=bzXb3urPLLLfzF;iyQ5Po zg!ui1g@u3cJkPV%Vle1qI2`WVQ@<IP+iRoIK&#b86{VOTODSK`@At93z7D0f(!7eI z=(3Q<^E^aR^yf+`kC`zZk1-mJW&#$GfJZ(U3~dWA_=c({Gh;LwK`9SO5<@AqWUc*l zp63s22euX@f$6J8^kFIGsVZxkVPj)3lW3nnAOK@Cz*rA&8cws;Vq;_A4B4D9=Dk|$ zyFAa^Vl0RV)a&&w3#h{|{Gkxy70ecwF7=S6<C?eV0ALA7p|CuD4*&APmyxIj-f{9h zX#0yOZ8?cMZ;*1rT1FJbICiW9A_1-S_xt_+Ys#{8Nrua<WR(Hsj{-Oj09lqH&$CIW zagZfRLE92P?0*+)={c;7&!S&;K_G}5&WX<5$dF~3OIDr&aF64#i55yJp_Fo_6;TxZ zo)BW*7=zJh4CdJ+-UJC4F0qpS1VjR%Y@qEe!V^9`3gC$Vl2om<H;T_JMx!xme{6AX zZti`)??Xxn&-37UUL|2QKQVy61+Z9gSB|2{XOfm75EzW1UdM)Bhk!)GYoV{Z`04l= z^vjFL%@~#ql<?sR9|UnjB&{f_gl7%nDI)r_I+I+5hbt>9u-3x&eKecR{~@ARYOT@h zT|!Y5Gm<U|0C=YVJ$(DZH=u0+Uxpw^FbtFk(D6>-miP|5r1gvF_{X8h2Z3N%!?4~r zZ-P*#n|AMN_`Z)$=NObyVCMh6aN)u)j7B3!DWRO_tF``PW?pci!%msfeFFx8l1sdh zJrBzUL=uJ#v`s6w!i+I4`&dq&#SePl!R^gg;Z^N7;COf&6#4K)2nNHlfrY&)0D=Sv zV)Bv<>ph#3>g*wRXA}!rmc3mF@e~n(hQp!DH2g?P`Eq7Puh&DCr8CQv`XWSXhWO^W zzsG8J7E1V+aTUYDvVma(K>{9ySO`zyrLAAai<4I)QY{b($SE+UeK>bN%LbMWN-l7* zcmc+iSPE~45Nel_R%LF(FhZx(0TE#|8hsbQ8;A(1*Xtn&0?f_Lb=|>5Sr%73jMy)K zjr9P7vI_?9NbCdwNdl5QST@LQiskW7a3MX1|5V??srbb>9^QsU|1{=<Q}Bep4KRVi zjImZMV>LU6^W*=+^7uL262An$eak&i<e}tzS5FM^<j_V+i6lwbalNVu{yo;(J6!5! z`|;L6J$uUrE7>_1))2cOb3qb5NiZ13Y7ELt7!3ya$;J;V=@TIustqY*rGAjmTw+jO zL}Bwv!fX!12BD0r)Xp9i)1940Q3N6~<M9|}SweL>9RPSA5iMD3>zq8#l)nsXtfbGw zvfWeej6hJr15inw<`QfzGBd`o>}@ef%#~VKeq9A*C<C<pMG(ZE_vFqgq9}s3_GMb@ zM*w_Otgo-b_x-+$s~p+SD!{J%FO3V?*-FA{{@IVERph}F0elfc2_F(_aw*}#7vZKq zM^zvesYdM>^B%N<CgfkcT#Hc@{Xvo>5TnuPt;U!;h-mieh$=!D>kX_IYZD2W)xC+t z=C%F4%pekoWwVm7eS}_4Edjvuyn#{*B1w|_iRe^yAgX7ojx>?3-SgM%qQlC#M50lH zx%YiJOzM@ct*t=>L0~pNv@?C^34i6!!@^wG+&|Y+=*#dx<xj>~mnXX;P1D~MN~zf0 z&{fgQ+(M>jVXTI@0f!|Ap@3;ji0D+3B=-oVRJc7+HXFjPNH;ShtQV^_e_emT7<Qj8 zn<ki4xDb5b&xMpSavxZ0W~Yudf30TcV7R>QV9}In9%MO8hyW>NEL<UpvkEikuk0*r z9q!zq+~5HL+bq#iN=0H?9V@_iw)~Zyx$YKnM^W1sm+=<Bgb<!MtfwRpax=!IV&#e+ zK7$Xfc=sSMU2Umpl5^#iv*NF{>}Sxnm^hBic9Nn2xXxD*xc-|}T1G(9>`HI7)u=gp zAId{p4y>)UrLxwRRiPecR!|}!ptt0|2-+49q~OUA0s>0-NMsXIdKebHDrkm<u_X$d zL6AI9%9=p1uo#(*NrbT<S)K+=Yn>`%Oe&?UB}~qazpTYdb`GU2AxPj@u!LLUm*RB% z5-bL{Ad<~G*+<aUU}$<+FV?V}K8NQv{tF}BM`;TX2$JO9V^AVk))<r*VPW^pp$-#f zz!)=DTI<YpPE7kA2l2%Sgu<k_n4L#qQ!IwJ;;z&0L(89sWdlhP)qxdPmlR06CKiL! zcyaU9_@!fS!H@gj!;c2v!$#SIVGV6d2nZ0#I*y!_8&>MR$%<gMRc3<}#=2i0<m?Ub zt-S)1#6+O9)?){dleB{nam8N-Yx#K;oI#Sp@$fb@y$(F`kg-O&!-=;GrX>{SyhXfr z{x|XSb8o`A(U0-$#`m$DK8wO+Rc01ullO=~5Szg`1V{+P)Wk7=3G@CfwL02;Xv!ug z*4pLKX!He@=ecY)oArlc23ASJvc^jGJhUz0ivTC1pM!xxZZlXmR}7Y!4J-`61W5`F zHHVkAUW+@Lufa&K<J{;OtmZ$%NcS+*128iJ86%Q0LJ?R0Rte_)Q&{j%Z^n^e7~Y># zE@hQVlTtn#MbSU2(P;FU`T6-b5YZ_q)l4KzTZ0SPS(Kb37A-6VFM@=E!ER4~7=}w2 zE+I(569GE@5}MvTUe3C*wy;wUjF{xVDk-fvuR1u<`v$8LqKU<h78e(xk|g=Il=4|- zKIJ+p4&qu62!+kj&CbKJK_n9#^H0`5?)|>*Py-;yx{!s$X8wz79-Q<nfni~wZFz8O zUw4}TKv|Y8B7&Nmn?q3)ZP(`K`#xMz*<OiX)ZYDCb{?4>SNs*-3MIUK2f<sV&Hyln zUWVZ`%n1-Pucc}FHD-qB^?K;_dXF*liVy-p5boPTQXM~D$j`uV2~PxA3SI<35|%BF z(jp=RLFgpy8Ku-mQQLL|LGVQ(#Iw_=?l<pV<-g9Lv^f-cI1$|rNpiwDM`cZ`BQwh= zimIm6PN(Bez89pFlSU_F(n;QOFZ@;765Z^l)e)D9F&~_SAUP9Gxt{3_&)XE7(P%`I z@NqO6VK5kAFc^G}nOB7n2*YsV-R?Czaj{rNW>ZK~SPX83N3-Cs>j+o9=P(SN0bJ>J zyN|4`t)biPRz<<qS}3LdhKRbgicZ9F&-t(P47B5~@b)9gUsWGw;8e34hT&5#&7<Nt zcD>XnisD<I=bcbW%_m6%W!c-cwXEER0xQ|`C~b~VHgF=m9g<Y#j2;Q;s`i>B4OfWL z9gRj`i{ltU5L7DZ2#%Qvz#jov+my0k*Etb_Kw&dn$bJgLC43685S%(<62|cTV2YA> znVBDTJ>*0LVT^&+8par|J6!+CT6?i7!iXm=C)Xl-1~9f880j7~mpC4sMj*o*S|z=A z=@Lki*wwVIt*@^?R`sSElx0~pbZpOG6VW38RvqyLL0ALES9veh=ZS1#F}M{Se+jQ_ zzaEmjeHX)BZ^>e21VM-}4BheCGJr2=ttZ%6YeC&^cPFRq;YOqJAQ3I(d4^uEhuw@e zAP{mphPEXV)dE8RN5DeXMh~4%2T>HGD2ifrb@g2Up4hHk!Xf9b8qtr}2qOqWG@C8Q zbJz4>5;cc8|9G8$vPVJ{g%D^qTL^*x%)Bn8{Jc`?iLxvwzcU#$lBOx9uPn>3v9W<} zxBD@zbxA~s;}}VjY>Bh31X*eGNsZP~01E(;Btaa<00>&^6(V}TxfRn%L?VLPDKk-X z**DTOy^V+-RZ59wvjwdU(saCwQcgZHycI>U>(WJ06lJ&D{jdXbCtp--X$zUUJkNs= z;uBiyPa0!b2#I#PjUWhM?a{D&SLZE85Cmwq+mKSCEK8fF>0bc&N0+VH*+IXCZVMqE zw$?swZ8iC%)oR1@ysHlFxY^avHK4UxZ78LjOZ7=1#3x+q-<6#8Yo;aYFW=A1pLJuh zI-O&VAdeJi?s=#8P#e3)g%A%<_Y_?@1l;|)AHbJf6U4D&#}Gwv{UArd8dlF(HDDcc z{oY{a$BF3v-KOSu4OlIr?_uW0t8#1)olXahMq_dgc{56zQ$ZquMx%jFrvs(DiDcoh z#xP7hz<t)*0>JyFlxQ~FP|BMO`j`Uurcptq<Ydr?lmf;WF3a+-iRdAB>VIf})o#ZJ zYS2C?rKBWDpp?A9qhz-GS5<5nhLIa317<*Lt+On9goqw>4Wx$-SY2`bP?lvcBuVn9 zl+p`=5T55F&-2N!qRrFeYx!-n@~bw3v>*tlhZO+;TWh}4?RLMcl={l{*6l+F3;@zJ z{nW<B#{Zr?dGZ5N%C{1ch@uF-A8Z+i<&MC%e}7h<`u61C)Hp21RhEc8$ISP+*%bSI zhJDu+RpVp~thG-TMe$^oWe+r)&38&E-z)?vmvq}{;Mz_bz19Y<HmGfffoqOBjJ5XP zS65fR)NZ%G?$XW&d0_`C#B#L<Wm&=)^J!zur_(h3P?98XC!*I&DOHjruKnbyBmK4l z!V}fn3Dhf%^qWc$Xk*NO42Q!fgCO{no0R9`;e)K1RIWMT>d~MdHpYC|4UM$c-U&b{ zrJ$6W<eO$VG;$LEGP6cKG}8C|kGRC2I}MwK+cVQCo9@jUV<3e1(=5v{7!2-iwOV(_ zaU2?BUI)N)CsUQPxETm<m$vO=NvF%PrhZpTDW6W$bkOhjKR-7&_XGe;r<G^94rPw3 zlZG@+QI_Rbl~P|FkH@%p@#0;bPUpQ*6m_JO+8A@$;M*&0&^e$&h|&$d9gRk-7cX9X z?D+BHPbsBP6a})Z>OebEgKxJ5?~qbrI2<C+^Ctj2A*GzjXl0;k=1<cUb8~asdF)Wu a{|^A`{-UaIXEC4v0000<MNUMnLSTZ6SUZLQ diff --git a/js/Reporter.js b/js/Reporter.js index a6acd66..c55f0d2 100644 --- a/js/Reporter.js +++ b/js/Reporter.js @@ -19,7 +19,6 @@ var Reporter = function(data) { this.cmd = data.cmd; this.color = data.color; this.isDiscrete = data.isDiscrete; - this.label = data.label; this.mode = data.mode; this.param = data.param; this.sliderMin = data.sliderMin; @@ -35,11 +34,19 @@ var Reporter = function(data) { this.slider = null; // slider jQ element }; +Reporter.prototype.determineReporterLabel = function() { + if (this.target === 'Stage') { + return this.param; + } else { + return this.target + ': ' + this.param; + } +} + Reporter.prototype.attach = function(scene) { switch (this.mode) { case 1: // Normal case 3: // Slider - this.el = $('<div class="reporter-normal">' + this.label + '</div>'); + this.el = $('<div class="reporter-normal">' + this.determineReporterLabel() + '</div>'); this.valueEl = $('<div class="reporter-inset">null</div>'); this.el.append(this.valueEl); if (this.mode == 3) { diff --git a/js/Sprite.js b/js/Sprite.js index 026d17e..07d7621 100644 --- a/js/Sprite.js +++ b/js/Sprite.js @@ -73,7 +73,14 @@ var Sprite = function(data) { this.talkBubbleStyler = null; this.talkBubbleOn = false; + // HTML element for the ask bubbles + this.askInput = null; + this.askInputField = null; + this.askInputButton = null; + this.askInputOn = false; + // Internal variables used for rendering meshes. + this.askAnswer = null; //this is a private variable this.textures = []; this.materials = []; this.geometries = []; @@ -142,14 +149,26 @@ Sprite.prototype.attach = function(scene) { this.updateVisible(); this.updateTransform(); - this.talkBubble = $('<div class="bubble-container"></div>'); - this.talkBubble.css('display', 'none'); - this.talkBubbleBox = $('<div class="bubble"></div>'); - this.talkBubbleStyler = $('<div class="bubble-say"></div>'); - this.talkBubble.append(this.talkBubbleBox); - this.talkBubble.append(this.talkBubbleStyler); + if (! this.isStage) { + this.talkBubble = $('<div class="bubble-container"></div>'); + this.talkBubble.css('display', 'none'); + this.talkBubbleBox = $('<div class="bubble"></div>'); + this.talkBubbleStyler = $('<div class="bubble-say"></div>'); + this.talkBubble.append(this.talkBubbleBox); + this.talkBubble.append(this.talkBubbleStyler); + } + + this.askInput = $('<div class="ask-container"></div>'); + this.askInput.css('display', 'none'); + this.askInputField = $('<div class="ask-field"></div>'); + this.askInputTextField = $('<input class="ask-text-field"></input>'); + this.askInputField.append(this.askInputTextField); + this.askInputButton = $('<div class="ask-button"></div>'); + this.askInput.append(this.askInputField); + this.askInput.append(this.askInputButton); runtime.scene.append(this.talkBubble); + runtime.scene.append(this.askInput); }; // Load sounds from the server and buffer them @@ -254,20 +273,22 @@ Sprite.prototype.onClick = function(evt) { }; Sprite.prototype.setVisible = function(v) { + if (v === true || v === false) { this.visible = v; this.updateVisible(); + } }; Sprite.prototype.updateLayer = function() { $(this.mesh).css('z-index', this.z); - if (this.talkBubble) this.talkBubble.css('z-index', this.z); + if (this.talkBubble) $(this.talkBubble).css('z-index', this.z); + if (this.askInput) this.askInput.css('z-index', this.z); }; Sprite.prototype.updateVisible = function() { $(this.mesh).css('display', this.visible ? 'inline' : 'none'); - if (this.talkBubbleOn) { - this.talkBubble.css('display', this.visible ? 'inline-block' : 'none'); - } + if (this.talkBubbleOn) this.talkBubble.css('display', this.visible ? 'inline-block' : 'none'); + if (this.askInputOn) this.askInput.css('display', this.visible ? 'inline-block' : 'none'); }; Sprite.prototype.updateTransform = function() { @@ -347,13 +368,21 @@ Sprite.prototype.showBubble = function(text, type) { this.talkBubble.css('left', xy[0] + 'px'); this.talkBubble.css('top', xy[1] + 'px'); - + this.talkBubble.removeClass('say-think-border'); + this.talkBubble.removeClass('ask-border'); + this.talkBubbleStyler.removeClass('bubble-say'); this.talkBubbleStyler.removeClass('bubble-think'); + this.talkBubbleStyler.removeClass('bubble-ask'); if (type == 'say') { + this.talkBubbleBox.addClass('say-think-border'); this.talkBubbleStyler.addClass('bubble-say'); } else if (type == 'think') { + this.talkBubbleBox.addClass('say-think-border'); this.talkBubbleStyler.addClass('bubble-think'); + } else if (type == 'doAsk') { + this.talkBubbleBox.addClass('ask-border'); + this.talkBubbleStyler.addClass('bubble-ask'); } if (this.visible) { @@ -367,6 +396,25 @@ Sprite.prototype.hideBubble = function() { this.talkBubble.css('display', 'none'); }; +Sprite.prototype.showAsk = function() { + this.askInputOn = true; + this.askInput.css('z-index', this.z); + this.askInput.css('left', '15px'); + this.askInput.css('right', '15px'); + this.askInput.css('bottom', '7px'); + this.askInput.css('height', '25px'); + + if (this.visible) { + this.askInput.css('display', 'inline-block'); + this.askInputTextField.focus(); + } +}; + +Sprite.prototype.hideAsk = function() { + this.askInputOn = false; + this.askInput.css('display', 'none'); +}; + Sprite.prototype.setXY = function(x, y) { this.scratchX = x; this.scratchY = y; diff --git a/js/Stage.js b/js/Stage.js index c425e10..8146e93 100644 --- a/js/Stage.js +++ b/js/Stage.js @@ -33,6 +33,7 @@ var Stage = function(data) { this.lineCanvas.width = 480; this.lineCanvas.height = 360; this.lineCache = this.lineCanvas.getContext('2d'); + this.isStage = true; Sprite.call(this, data); }; diff --git a/js/primitives/LooksPrims.js b/js/primitives/LooksPrims.js index e56f646..b63c7f2 100644 --- a/js/primitives/LooksPrims.js +++ b/js/primitives/LooksPrims.js @@ -43,6 +43,9 @@ LooksPrims.prototype.addPrimsTo = function(primTable) { primTable['setGraphicEffect:to:'] = this.primSetEffect; primTable['filterReset'] = this.primClearEffects; + primTable['doAsk'] = this.primDoAsk; + primTable['answer'] = this.primAnswer; + primTable['say:'] = function(b) { showBubble(b, 'say'); }; primTable['say:duration:elapsed:from:'] = function(b) { showBubbleAndWait(b, 'say'); }; primTable['think:'] = function(b) { showBubble(b, 'think'); }; @@ -170,6 +173,17 @@ LooksPrims.prototype.primClearEffects = function(b) { s.updateFilters(); }; +LooksPrims.prototype.primDoAsk= function(b) { + showBubble(b, "doAsk"); + var s = interp.targetSprite(); + if (s != null) s.showAsk(); +}; + +LooksPrims.prototype.primAnswer = function() { + var s = interp.targetSprite(); + return ((s != null) ? s.answer : undefined); +}; + var showBubble = function(b, type) { var s = interp.targetSprite(); if (s != null) s.showBubble(interp.arg(b, 0), type); diff --git a/player.css b/player.css index 3fcff6c..40ca47e 100644 --- a/player.css +++ b/player.css @@ -398,7 +398,7 @@ button#trigger-stop:hover { } /* Say/think bubble styles */ - .bubble-container { +.bubble-container { position: absolute; } .bubble { @@ -407,7 +407,6 @@ button#trigger-stop:hover { max-width: 120px; min-width: 40px; padding: 6px 11px 6px 11px; - border: 3px solid rgb(160, 160, 160); border-radius: 10px; background: #fff; font-family: sans-serif; @@ -416,6 +415,20 @@ button#trigger-stop:hover { color: #000; text-align: center; } +.bubble.say-think-border { + border: 3px solid rgb(160, 160, 160); +} +.bubble.ask-border, .ask-container { + border: 3px solid rgb(74, 173, 222); +} +.bubble-ask { + position: absolute; + margin-top: -3px; + margin-left: 8px; + width: 44px; + height: 18px; + background: url(img/ask-bottom.png) transparent no-repeat; +} .bubble-say { position: absolute; margin-top: -3px; @@ -432,3 +445,33 @@ button#trigger-stop:hover { height: 19px; background: url(img/think-bottom.png) transparent no-repeat; } +.ask-container { + position: absolute; + display: inline-block; + padding: 5px 0px 0px 5px; + border-radius: 5px; + background: #fff; + font-family: sans-serif; + font-weight: bold; + font-size: 14px; + color: #000; +} +.ask-container .ask-field .ask-text-field { + width: 405px; + height: 16px; + font-family: sans-serif; + font-weight: light; + font-size: 12px; + background: #EAEAEA; +} + +.ask-container .ask-button { + position: absolute; + right: 2px; + top: 2px; + width: 25px; + height: 25px; + background: url(img/ask-button.png) transparent no-repeat; +} + + diff --git a/test/artifacts/IOMock.js b/test/artifacts/IOMock.js new file mode 100644 index 0000000..6a7a118 --- /dev/null +++ b/test/artifacts/IOMock.js @@ -0,0 +1,25 @@ +'use strict'; + +var ioMock = function() { + var args = createArgs(arguments); + + function getArgs(argKey) { + return ((argKey in args) ? args[argKey] : null); + } + + function createArgs(methodArgs) { + var args = {}; + if (methodArgs.length) { + _.each(methodArgs, function(newObject) { + _.each(newObject, function(value, key) { + args[key] = value; + }); + }); + } + return args; + } + + return { + 'getCount' : function() { return getArgs('getCount'); } + } +}; diff --git a/test/artifacts/TargetMock.js b/test/artifacts/TargetMock.js index 9121a00..8071a39 100644 --- a/test/artifacts/TargetMock.js +++ b/test/artifacts/TargetMock.js @@ -2,7 +2,9 @@ var targetMock = function() { return { - 'showBubble' : function() {} + 'showBubble' : function() {}, + 'showAsk' : function() {}, + 'answer' : 22 }; } diff --git a/test/artifacts/ask-artifact.js b/test/artifacts/ask-artifact.js index 4f0852a..654a07d 100644 --- a/test/artifacts/ask-artifact.js +++ b/test/artifacts/ask-artifact.js @@ -1,7 +1,10 @@ -'use strict'; - var sensingData = { "objName": "Stage", + "variables": [{ + "name": "myAnswer", + "value": 0, + "isPersistent": false + }], "costumes": [{ "costumeName": "backdrop1", "baseLayerID": -1, @@ -16,6 +19,15 @@ var sensingData = { "videoAlpha": 0.5, "children": [{ "objName": "Sprite1", + "variables": [{ + "name": "myAnswer2", + "value": 0, + "isPersistent": false + }, { + "name": "answer", + "value": 0, + "isPersistent": false + }], "scripts": [[42, 40.5, [["whenGreenFlag"], ["doAsk", "What's your name?"]]], [44.5, 155.5, diff --git a/test/artifacts/reporterValues.js b/test/artifacts/reporterValues.js new file mode 100644 index 0000000..484b990 --- /dev/null +++ b/test/artifacts/reporterValues.js @@ -0,0 +1,91 @@ +'use Strict;' + +var ReporterValues = function() { + return { + 'getStageVariables': function() { + return { + 'cmd' : "getVar:", + 'color' : 15629590, + 'isDiscrete' : true, + 'mode' : 1, + 'param' : "myAnswer", + 'sliderMax' : 100, + 'sliderMin' : 0, + 'target' : "Stage", + 'visible' : true, + 'x' : 5, + 'y' : 5, + }; + } + } +}; +/* +cmd + "getVar:" + +color + 15629590 + +isDiscrete + true + +mode + 1 + +param + "myAnswer2" + +sliderMax + 100 + +sliderMin + 0 + +target + "Sprite1" + +visible + true + +x + 5 + +y + 32 +*/ + +/* + +cmd + "getVar:" + +color + 15629590 + +isDiscrete + true + +mode + 1 + +param + "answer" + +sliderMax + 100 + +sliderMin + 0 + +target + "Sprite1" + +visible + true + +x + 5 + +y + 59 +*/ diff --git a/test/unit/looksPrimitiveSpec.js b/test/unit/looksPrimitiveSpec.js index cadbc6e..a46f747 100644 --- a/test/unit/looksPrimitiveSpec.js +++ b/test/unit/looksPrimitiveSpec.js @@ -1,23 +1,65 @@ /* jasmine specs for primitives/LooksPrims.js go here */ describe ('LooksPrims', function() { - var looksPrims; + var looksPrims, targetSpriteMock; beforeEach(function() { looksPrims = LooksPrims; + targetSpriteMock = targetMock(); }); - describe('showBubble', function(){ - var sayBlock, targetSpriteMock; + describe('showBubble for Say', function(){ + var sayBlock; beforeEach(function() { sayBlock = {'args': ['what to say']}; - targetSpriteMock = targetMock(); interp = interpreterMock({'targetSprite': targetSpriteMock }, {'arg': sayBlock}); - }); - it('should return do something', function() { + + it('should call the showBubble method on the targetedSprite', function() { spyOn(targetSpriteMock, "showBubble"); showBubble(sayBlock, "say"); expect(targetSpriteMock.showBubble).toHaveBeenCalled; }); }); + + describe('showBubble for Think', function(){ + var thinkBlock; + beforeEach(function() { + thinkBlock = {'args': ['what to think']}; + interp = interpreterMock({'targetSprite': targetSpriteMock }, {'arg': thinkBlock}); + }); + + it('should call the showBubble method on the targetedSprite', function() { + spyOn(targetSpriteMock, "showBubble"); + showBubble(thinkBlock, "think"); + expect(targetSpriteMock.showBubble).toHaveBeenCalled; + }); + }); + + + describe('showBubble for Ask', function(){ + var askBlock; + beforeEach(function() { + askBlock = {'args': 'what to ask'}; + interp = interpreterMock({'targetSprite': targetSpriteMock }, {'arg': askBlock}); + + }); + + it('should call the showBubble method on the targetedSprite', function() { + spyOn(targetSpriteMock, "showBubble"); + spyOn(targetSpriteMock, "showAsk"); + looksPrims.prototype.primDoAsk(askBlock); + expect(targetSpriteMock.showBubble).toHaveBeenCalled; + expect(targetSpriteMock.showAsk).toHaveBeenCalled; + }); + }); + + describe('primAnswer', function(){ + beforeEach(function() { + interp = interpreterMock({'targetSprite': targetSpriteMock }); + }); + + it('should return the answer variable from the targetedSprite', function() { + expect(looksPrims.prototype.primAnswer()).toBe(22); + }); + }); }); diff --git a/test/unit/reporterSpec.js b/test/unit/reporterSpec.js new file mode 100644 index 0000000..c879f58 --- /dev/null +++ b/test/unit/reporterSpec.js @@ -0,0 +1,96 @@ +/* jasmine specs for Reporter.js go here */ + +describe ('Reporter', function() { + var reporter, reporterValues; + + beforeEach(function() { + reporter = Reporter; + reporterValues = new ReporterValues(); + }); + + describe('Instantization variables', function() { + var initReporter; + beforeEach(function() { + io = new ioMock({'getCount': 4}); + initReporter = new reporter(reporterValues.getStageVariables()); + }); + + describe('Reporter Variables', function() { + it('should have a cmd variable', function() { + expect(initReporter.cmd).toBe('getVar:'); + }); + + it('should have a color variable', function() { + expect(initReporter.color).toBe(15629590); + }); + + it('should have a isDiscrete variable', function() { + expect(initReporter.isDiscrete).toBe(true); + }); + + it('should have a mode variable', function() { + expect(initReporter.mode).toBe(1); + }); + + it('should have a param variable', function() { + expect(initReporter.param).toBe('myAnswer'); + }); + + it('should have a sliderMax variable', function() { + expect(initReporter.sliderMax).toBe(100); + }); + + it('should have a sliderMin variable', function() { + expect(initReporter.sliderMin).toBe(0); + }); + + it('should have a target variable', function() { + expect(initReporter.target).toBe('Stage'); + }); + + it('should have a visible variable', function() { + expect(initReporter.visible).toBe(true); + }); + + it('should have a x variable', function() { + expect(initReporter.x).toBe(5); + }); + + it('should have a y variable', function() { + expect(initReporter.y).toBe(5); + }); + + it('should have a z variable', function() { + expect(initReporter.z).toBe(4); + }); + + it('should have an el variable', function() { + expect(initReporter.el).toBe(null); + }); + + it('should have an valueEl variable', function() { + expect(initReporter.valueEl).toBe(null); + }); + + it('should have an slider variable', function() { + expect(initReporter.slider).toBe(null); + }); + }); + }); + describe('determineReporterLabel', function() { + + it('should return a stage variable', function() { + reporter.prototype.target = "Stage"; + reporter.prototype.param = "myAnswer"; + expect(reporter.prototype.determineReporterLabel()).toBe('myAnswer'); + }); + + it('should return a sprite variable', function() { + reporter.prototype.target = "Sprite 1"; + reporter.prototype.param = "localAnswer"; + expect(reporter.prototype.determineReporterLabel()).toBe('Sprite 1: localAnswer'); + + }); + + }); +}); diff --git a/test/unit/spriteSpec.js b/test/unit/spriteSpec.js new file mode 100644 index 0000000..feeb11c --- /dev/null +++ b/test/unit/spriteSpec.js @@ -0,0 +1,352 @@ +/* jasmine specs for Sprite.js go here */ + +describe ('Sprite', function() { + var sprite; + + + beforeEach(function() { + sprite = Sprite; + }); + + describe('Instantization variables', function() { + var initSprite; + beforeEach(function() { + var spriteObject = sensingData.children[0]; + initSprite = new sprite(spriteObject); + }); + + describe('Sprite Variables', function() { + it('should have a visible variable', function() { + expect(initSprite.visible).toBe(true); + }); + }); + + describe('Pen Variables', function() { + it('should have a penIsDown variable', function() { + expect(initSprite.penIsDown).toBe(false); + }); + + it('should have a penWidth variable', function() { + expect(initSprite.penWidth).toBe(1); + }); + + it('should have a penHue variable', function() { + expect(initSprite.penHue).toBe(120); + }); + + it('should have a penShade variable', function() { + expect(initSprite.penShade).toBe(50); + }); + + it('should have a penColorCache variable', function() { + expect(initSprite.penColorCache).toBe(0x0000FF); + }); + }); + + describe('Ask Bubble', function() { + it('should have an askInput variable', function() { + expect(initSprite.askInput).toBe(null); + }); + + it('should have an askInputBox variable', function() { + expect(initSprite.askInputField).toBe(null); + }); + + it('should have an askInputStyler variable', function() { + expect(initSprite.askInputButton).toBe(null); + }); + + it('should have an askInputOn variable', function() { + expect(initSprite.askInputOn).toBe(false); + }); + + it('should have an answer variable', function() { + expect(initSprite.askAnswer).toBe(null); + }); + }); + }) + + describe('showBubble', function() { + var spriteProto; + beforeEach(function() { + spriteProto = sprite.prototype; + spriteProto.visible = true; + setFixtures('<div class="bubble-container"></div>'); + spriteProto.talkBubble = $('.bubble-container'); + spriteProto.talkBubble.css('display', 'none'); + spriteProto.talkBubbleBox = $('<div class="bubble"></div>'); + spriteProto.talkBubbleStyler = $('<div class="bubble-say"></div>'); + spriteProto.talkBubble.append(spriteProto.talkBubbleBox); + spriteProto.talkBubble.append(spriteProto.talkBubbleStyler); + }); + + describe('Say', function(){ + it('should call the showBubble method on the Sprite', function() { + var text = "What to say"; + spyOn(spriteProto, "getTalkBubbleXY").andReturn([50,50]);; + spriteProto.showBubble(text, "say"); + expect($('.bubble').html()).toBe(text); + expect($('.bubble-say').hasClass('bubble-say')).toBe(true); + expect($('.bubble').hasClass('say-think-border')).toBe(true); + expect($('.bubble-container').css('display')).toBe('inline-block'); + }); + }); + + describe('Think', function(){ + it('should call the showBubble method on the Sprite', function() { + var text = "What to think"; + spyOn(spriteProto, "getTalkBubbleXY").andReturn([50,50]);; + spriteProto.showBubble(text, "think"); + expect($('.bubble').html()).toBe(text); + expect($('.bubble-think').hasClass('bubble-think')).toBe(true); + expect($('.bubble').hasClass('say-think-border')).toBe(true); + expect($('.bubble-container').css('display')).toBe('inline-block'); + }); + }); + + describe('Ask', function(){ + it('should call the showBubble method on the Sprite', function() { + var text = "What to Ask"; + spyOn(spriteProto, "getTalkBubbleXY").andReturn([50,50]);; + spriteProto.showBubble(text, "doAsk"); + expect($('.bubble').html()).toBe(text); + expect($('.bubble-ask').hasClass('bubble-ask')).toBe(true); + expect($('.bubble').hasClass('ask-border')).toBe(true); + expect($('.bubble-container').css('display')).toBe('inline-block'); + }); + }); + + describe('Any Bubble with visible false', function(){ + it('should call the showBubble method on the Sprite and not display it', function() { + spriteProto.visible = false; + var text = "What to Ask"; + spyOn(spriteProto, "getTalkBubbleXY").andReturn([50,50]);; + spriteProto.showBubble(text, "doAsk"); + expect($('.bubble').html()).toBe(text); + expect($('.bubble-ask').hasClass('bubble-ask')).toBe(true); + expect($('.bubble').hasClass('ask-border')).toBe(true); + expect($('.bubble-container').css('display')).toBe('none'); + }); + }); + }); + + describe('hideBubble', function() { + var spriteProto; + beforeEach(function() { + spriteProto = sprite.prototype; + setFixtures('<div class="bubble-container"></div>'); + spriteProto.talkBubble = $('.bubble-container'); + spriteProto.talkBubble.css('display', 'inline'); + }); + + it('should hide the bubble', function() { + spriteProto.hideBubble(); + expect($('.bubble-container').css('display')).toBe('none'); + expect(spriteProto.talkBubbleOn).toBe(false); + + }); + }); + + describe('showAsk', function() { + var spriteProto; + beforeEach(function() { + spriteProto = sprite.prototype; + spriteProto.visible = true; + spriteProto.z = 22; + setFixtures('<div class="ask-container"></div>'); + spriteProto.askInput= $('.ask-container'); + spriteProto.askInput.css('display','none'); + spriteProto.askInput.css('position','relative'); + spriteProto.askInputField = $('<div class="ask-input"></div>'); + spriteProto.askInputTextField = $('<input class="ask-text-field"></input>'); + spriteProto.askInputField.append(spriteProto.askInputTextField); + spriteProto.askInputButton = $('<div class="ask-button"></div>'); + spriteProto.askInput.append(spriteProto.askInputField); + spriteProto.askInput.append(spriteProto.askInputButton); + }); + + it('should show the ask input if visible is true', function() { + spriteProto.showAsk(); + expect($('.ask-container').css('display')).toBe('inline-block'); + expect($('.ask-container').css('z-index')).toBe('22'); + expect($('.ask-container').css('left')).toBe('15px'); + expect($('.ask-container').css('right')).toBe('15px'); + expect($('.ask-container').css('bottom')).toBe('7px'); + expect($('.ask-container').css('height')).toBe('25px'); + expect($('.ask-container').css('height')).toBe('25px'); + expect($('.ask-text-field').is(':focus')).toBe(true); + expect(spriteProto.askInputOn).toBe(true); + }); + + it('should not show the ask input if visible is false', function() { + spriteProto.visible = false; + spriteProto.showAsk(); + expect($('.ask-container').css('display')).toBe('none'); + expect($('.ask-text-field').is(':focus')).toBe(false); + }); + }); + + describe('hideAsk', function() { + var spriteProto; + beforeEach(function() { + spriteProto = sprite.prototype; + setFixtures('<div class="ask-container"></div>'); + spriteProto.askInput = $('.ask-container'); + spriteProto.askInput.css('display', 'inline'); + }); + + it('should hide the ask input', function() { + spriteProto.hideAsk(); + expect($('.ask-container').css('display')).toBe('none'); + expect(spriteProto.askInputOn).toBe(false); + + }); + }); + + describe('updateLayer', function() { + var spriteProto; + beforeEach(function() { + spriteProto = sprite.prototype; + setFixtures('<img class="mesh"></img><div class="bubble-container"></div><div class="ask-container"></div>'); + spriteProto.talkBubble = $('.bubble-container'); + spriteProto.talkBubble.css('position', 'relative'); + spriteProto.askInput = $('.ask-container'); + spriteProto.askInput.css('position', 'relative'); + spriteProto.mesh = $('.mesh'); + spriteProto.mesh.css('position', 'relative'); + spriteProto.z = 22; + }); + + it('should update the mesh z-index', function() { + expect($('.mesh').css('z-index')).toBe('auto'); + spriteProto.updateLayer(); + expect($('.mesh').css('z-index')).toBe('22'); + }); + + it('should update the talkBubble z-index', function() { + expect($('.bubble-container').css('z-index')).toBe('auto'); + spriteProto.updateLayer(); + expect($('.bubble-container').css('z-index')).toBe('22'); + }); + + it('should update the askInput z-index', function() { + expect($('.ask-container').css('z-index')).toBe('auto'); + spriteProto.updateLayer(); + expect($('.ask-container').css('z-index')).toBe('22'); + }); + }); + + describe('updateVisible', function() { + var spriteProto; + beforeEach(function() { + spriteProto = sprite.prototype; + setFixtures('<img class="mesh"></img><div class="bubble-container"></div><div class="ask-container"></div>'); + spriteProto.talkBubble = $('.bubble-container'); + spriteProto.talkBubble.css('display', 'none'); + spriteProto.askInput = $('.ask-container'); + spriteProto.askInput.css('display', 'none'); + spriteProto.mesh = $('.mesh'); + spriteProto.mesh.css('display', 'none'); + }); + + describe('mesh', function() { + it('should update the mesh display on false', function() { + expect($('.mesh').css('display')).toBe('none'); + spriteProto.visible = false; + spriteProto.updateVisible(); + expect($('.mesh').css('display')).toBe('none'); + }); + + it('should update the mesh display on true', function() { + expect($('.mesh').css('display')).toBe('none'); + spriteProto.visible = true; + spriteProto.updateVisible(); + expect($('.mesh').css('display')).toBe('inline'); + }); + + }); + + describe('talkBubble', function() { + it('should update the talkBubble on talkBubble true and visible true', function() { + expect($('.bubble-container').css('display')).toBe('none'); + spriteProto.talkBubbleOn = true; + spriteProto.visible = true; + spriteProto.updateVisible(); + expect($('.bubble-container').css('display')).toBe('inline-block'); + }); + + it('should update the talkBubble on talkBubble false and visible true', function() { + expect($('.bubble-container').css('display')).toBe('none'); + spriteProto.talkBubbleOn = false; + spriteProto.visible = true; + spriteProto.updateVisible(); + expect($('.bubble-container').css('display')).toBe('none'); + }); + + it('should update the talkBubble on talkBubble true and visible false', function() { + expect($('.bubble-container').css('display')).toBe('none'); + spriteProto.talkBubbleOn = true; + spriteProto.visible = false; + spriteProto.updateVisible(); + expect($('.bubble-container').css('display')).toBe('none'); + }); + }); + + describe('askContainer', function() { + it('should update the askInput on askInput true and visible true', function() { + expect($('.ask-container').css('display')).toBe('none'); + spriteProto.askInputOn = true; + spriteProto.visible = true; + spriteProto.updateVisible(); + expect($('.ask-container').css('display')).toBe('inline-block'); + }); + + it('should update the askInput on askInput false and visible true', function() { + expect($('.ask-container').css('display')).toBe('none'); + spriteProto.askInputOn = false; + spriteProto.visible = true; + spriteProto.updateVisible(); + expect($('.ask-container').css('display')).toBe('none'); + }); + + it('should update the askInput on askInput true and visible false', function() { + expect($('.ask-container').css('display')).toBe('none'); + spriteProto.askInputOn = true; + spriteProto.visible = false; + spriteProto.updateVisible(); + expect($('.ask-container').css('display')).toBe('none'); + }); + }); + + }); + + describe('setVisible', function() { + var spriteProto; + beforeEach(function() { + spriteProto = sprite.prototype; + spyOn(spriteProto, "updateVisible"); + }); + + it('should set visible to true', function() { + expect(spriteProto.visible).toBe(false); + spriteProto.setVisible(true); + expect(spriteProto.visible).toBe(true); + expect(spriteProto.updateVisible).toHaveBeenCalled(); + }); + + it('should set visible to false', function() { + spriteProto.visible = true; + spriteProto.setVisible(false); + expect(spriteProto.visible).toBe(false); + expect(spriteProto.updateVisible).toHaveBeenCalled(); + }); + + it('should set take no action on an invalid character', function() { + spriteProto.visible = true; + spriteProto.setVisible('hello'); + expect(spriteProto.visible).toBe(true); + expect(spriteProto.updateVisible).not.toHaveBeenCalled(); + }); + + }); +}); diff --git a/test/unit/stageSpec.js b/test/unit/stageSpec.js new file mode 100644 index 0000000..330a451 --- /dev/null +++ b/test/unit/stageSpec.js @@ -0,0 +1,51 @@ +/* jasmine specs for Stage.js go here */ + +describe ('Stage', function() { + var stage; + + beforeEach(function() { + stage = Stage; + }); + + describe('Instantization variables', function() { + var initStage, lineCanvas; + beforeEach(function() { + spyOn(Sprite, "call"); + initStage = new stage(sensingData); + }); + + describe('Stage Variables', function() { + it('should have a z variable', function() { + expect(initStage.z).toBe(-2); + }); + + it('should have a penLayerLoaded variable', function() { + expect(initStage.penLayerLoaded).toBe(false); + }); + + it('should have a lineCanvas element', function() { + expect(initStage.lineCanvas).toBeDefined(); + }); + + it('should have a lineCanvas width', function() { + expect(initStage.lineCanvas.width).toBe(480); + }); + + it('should have a lineCanvas height', function() { + expect(initStage.lineCanvas.height).toBe(360); + }); + + it('should have a lineCache variable', function() { + expect(initStage.lineCache).toBeDefined(); + }); + + it('should have a isStage variable', function() { + expect(initStage.isStage).toBe(true); + }); + + it('should have called Sprite.call', function() { + expect(Sprite.call).toHaveBeenCalled(); + }); + }); + }); +});