From 2f86da0d09c7f4c9d6ede9471c2173462ea8b7e8 Mon Sep 17 00:00:00 2001 From: Fraxy V Date: Thu, 23 Nov 2023 08:49:47 +0200 Subject: [PATCH] chess.wasm: add chessboard --- examples/chess.wasm/CMakeLists.txt | 14 +- .../chessboardjs-1.0.0/CHANGELOG.md | 32 + .../chess.wasm/chessboardjs-1.0.0/LICENSE.md | 20 + .../chess.wasm/chessboardjs-1.0.0/README.md | 82 + .../css/chessboard-1.0.0.css | 54 + .../css/chessboard-1.0.0.min.css | 2 + .../img/chesspieces/wikipedia/bB.png | Bin 0 -> 1405 bytes .../img/chesspieces/wikipedia/bK.png | Bin 0 -> 3009 bytes .../img/chesspieces/wikipedia/bN.png | Bin 0 -> 1875 bytes .../img/chesspieces/wikipedia/bP.png | Bin 0 -> 777 bytes .../img/chesspieces/wikipedia/bQ.png | Bin 0 -> 2648 bytes .../img/chesspieces/wikipedia/bR.png | Bin 0 -> 748 bytes .../img/chesspieces/wikipedia/wB.png | Bin 0 -> 2374 bytes .../img/chesspieces/wikipedia/wK.png | Bin 0 -> 2823 bytes .../img/chesspieces/wikipedia/wN.png | Bin 0 -> 2388 bytes .../img/chesspieces/wikipedia/wP.png | Bin 0 -> 1571 bytes .../img/chesspieces/wikipedia/wQ.png | Bin 0 -> 3812 bytes .../img/chesspieces/wikipedia/wR.png | Bin 0 -> 1097 bytes .../chessboardjs-1.0.0/js/chessboard-1.0.0.js | 1817 +++++++++++++++++ .../js/chessboard-1.0.0.min.js | 2 + .../chessboardjs-1.0.0/package.json | 29 + examples/chess.wasm/index-tmpl.html | 27 +- examples/chess.wasm/jquery-3.7.1.min.js | 2 + 23 files changed, 2077 insertions(+), 4 deletions(-) create mode 100644 examples/chess.wasm/chessboardjs-1.0.0/CHANGELOG.md create mode 100644 examples/chess.wasm/chessboardjs-1.0.0/LICENSE.md create mode 100644 examples/chess.wasm/chessboardjs-1.0.0/README.md create mode 100644 examples/chess.wasm/chessboardjs-1.0.0/css/chessboard-1.0.0.css create mode 100644 examples/chess.wasm/chessboardjs-1.0.0/css/chessboard-1.0.0.min.css create mode 100644 examples/chess.wasm/chessboardjs-1.0.0/img/chesspieces/wikipedia/bB.png create mode 100644 examples/chess.wasm/chessboardjs-1.0.0/img/chesspieces/wikipedia/bK.png create mode 100644 examples/chess.wasm/chessboardjs-1.0.0/img/chesspieces/wikipedia/bN.png create mode 100644 examples/chess.wasm/chessboardjs-1.0.0/img/chesspieces/wikipedia/bP.png create mode 100644 examples/chess.wasm/chessboardjs-1.0.0/img/chesspieces/wikipedia/bQ.png create mode 100644 examples/chess.wasm/chessboardjs-1.0.0/img/chesspieces/wikipedia/bR.png create mode 100644 examples/chess.wasm/chessboardjs-1.0.0/img/chesspieces/wikipedia/wB.png create mode 100644 examples/chess.wasm/chessboardjs-1.0.0/img/chesspieces/wikipedia/wK.png create mode 100644 examples/chess.wasm/chessboardjs-1.0.0/img/chesspieces/wikipedia/wN.png create mode 100644 examples/chess.wasm/chessboardjs-1.0.0/img/chesspieces/wikipedia/wP.png create mode 100644 examples/chess.wasm/chessboardjs-1.0.0/img/chesspieces/wikipedia/wQ.png create mode 100644 examples/chess.wasm/chessboardjs-1.0.0/img/chesspieces/wikipedia/wR.png create mode 100644 examples/chess.wasm/chessboardjs-1.0.0/js/chessboard-1.0.0.js create mode 100644 examples/chess.wasm/chessboardjs-1.0.0/js/chessboard-1.0.0.min.js create mode 100644 examples/chess.wasm/chessboardjs-1.0.0/package.json create mode 100644 examples/chess.wasm/jquery-3.7.1.min.js diff --git a/examples/chess.wasm/CMakeLists.txt b/examples/chess.wasm/CMakeLists.txt index 06a625ec..4488134d 100644 --- a/examples/chess.wasm/CMakeLists.txt +++ b/examples/chess.wasm/CMakeLists.txt @@ -25,7 +25,7 @@ if (WHISPER_WASM_SINGLE_FILE) TARGET ${TARGET} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/bin/libchess.js - ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/chess.wasm/chess.js + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/chess.wasm/js/chess.js ) endif() @@ -40,6 +40,16 @@ set_target_properties(${TARGET} PROPERTIES LINK_FLAGS " \ ${EXTRA_FLAGS} \ ") + +add_custom_command( + TARGET ${TARGET} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_CURRENT_SOURCE_DIR}/chessboardjs-1.0.0 + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/chess.wasm/ + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/jquery-3.7.1.min.js + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/chess.wasm/js/ + ) # # chess.wasm # @@ -47,4 +57,4 @@ set_target_properties(${TARGET} PROPERTIES LINK_FLAGS " \ set(TARGET chess.wasm) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/index-tmpl.html ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TARGET}/index.html @ONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../helpers.js ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TARGET}/helpers.js @ONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../helpers.js ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TARGET}/js/helpers.js @ONLY) diff --git a/examples/chess.wasm/chessboardjs-1.0.0/CHANGELOG.md b/examples/chess.wasm/chessboardjs-1.0.0/CHANGELOG.md new file mode 100644 index 00000000..c0c6b2fe --- /dev/null +++ b/examples/chess.wasm/chessboardjs-1.0.0/CHANGELOG.md @@ -0,0 +1,32 @@ +# chessboard.js Change Log + +All notable changes to this project will be documented in this file. + +## [1.0.0] - 2019-06-11 +- Orientation methods now return current orientation. [Issue #64] +- Drop support for IE8 +- Do not check for `window.JSON` (Error #1004) +- Rename `ChessBoard` to `Chessboard` (`ChessBoard` is still supported, however) +- id query selectors are now supported as the first argument to `Chessboard()` +- Remove Error #1002 +- Format code according to [StandardJS] +- Bump minimum jQuery version to 1.8.3 +- Throttle piece drag functions + +## [0.3.0] - 2013-08-10 +- Added `appearSpeed` animation config property +- Added `onSnapbackEnd` event +- Added `onMoveEnd` event + +## [0.2.0] - 2013-08-05 +- Added `onMouseoverSquare` and `onMouseoutSquare` events +- Added `onSnapEnd` event +- Added square code as CSS class on the squares +- Added [chess.js] integration examples + +## [0.1.0] - 2013-05-21 +- Initial release + +[chess.js]:https://github.com/jhlywa/chess.js +[Issue #64]:https://github.com/oakmac/chessboardjs/issues/64 +[StandardJS]:https://standardjs.com/ diff --git a/examples/chess.wasm/chessboardjs-1.0.0/LICENSE.md b/examples/chess.wasm/chessboardjs-1.0.0/LICENSE.md new file mode 100644 index 00000000..20b7d615 --- /dev/null +++ b/examples/chess.wasm/chessboardjs-1.0.0/LICENSE.md @@ -0,0 +1,20 @@ +Copyright 2019 Chris Oakman + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/examples/chess.wasm/chessboardjs-1.0.0/README.md b/examples/chess.wasm/chessboardjs-1.0.0/README.md new file mode 100644 index 00000000..60c8997e --- /dev/null +++ b/examples/chess.wasm/chessboardjs-1.0.0/README.md @@ -0,0 +1,82 @@ +# chessboard.js + +chessboard.js is a JavaScript chessboard component. It depends on [jQuery]. + +Please see [chessboardjs.com] for documentation and examples. + +## What is chessboard.js? + +chessboard.js is a JavaScript chessboard component with a flexible "just a +board" API that + +chessboard.js is a standalone JavaScript Chess Board. It is designed to be "just +a board" and expose a powerful API so that it can be used in different ways. +Here's a non-exhaustive list of things you can do with chessboard.js: + +- Use chessboard.js to show game positions alongside your expert commentary. +- Use chessboard.js to have a tactics website where users have to guess the best + move. +- Integrate chessboard.js and [chess.js] with a PGN database and allow people to + search and playback games (see [Example 5000]) +- Build a chess server and have users play their games out using the + chessboard.js board. + +chessboard.js is flexible enough to handle any of these situations with relative +ease. + +## What can chessboard.js **not** do? + +The scope of chessboard.js is limited to "just a board." This is intentional and +makes chessboard.js flexible for handling a multitude of chess-related problems. + +This is a common source of confusion for new users. [remove?] + +Specifically, chessboard.js does not understand anything about how the game of +chess is played: how a knight moves, who's turn is it, is White in check?, etc. + +Fortunately, the powerful [chess.js] library deals with exactly this sort of +problem domain and plays nicely with chessboard.js's flexible API. Some examples +of chessboard.js combined with chess.js: 5000, 5001, 5002 + +Please see the powerful [chess.js] library for an API to deal with these sorts +of questions. + + +This logic is distinct from the logic of the board. Please see the powerful +[chess.js] library for this aspect of your application. + + + +Here is a list of things that chessboard.js is **not**: + +- A chess engine +- A legal move validator +- A PGN parser + +chessboard.js is designed to work well with any of those things, but the idea +behind chessboard.js is that the logic that controls the board should be +independent of those other problems. + +## Docs and Examples + +- Docs - +- Examples - + +## Developer Tools + +```sh +# create a build in the build/ directory +npm run build + +# re-build the website +npm run website +``` + +## License + +[MIT License](LICENSE.md) + +[jQuery]:https://jquery.com/ +[chessboardjs.com]:http://chessboardjs.com +[chess.js]:https://github.com/jhlywa/chess.js +[Example 5000]:http://chessboardjs.com/examples#5000 diff --git a/examples/chess.wasm/chessboardjs-1.0.0/css/chessboard-1.0.0.css b/examples/chess.wasm/chessboardjs-1.0.0/css/chessboard-1.0.0.css new file mode 100644 index 00000000..8de95f47 --- /dev/null +++ b/examples/chess.wasm/chessboardjs-1.0.0/css/chessboard-1.0.0.css @@ -0,0 +1,54 @@ +/*! chessboard.js v1.0.0 | (c) 2019 Chris Oakman | MIT License chessboardjs.com/license */ + +.clearfix-7da63 { + clear: both; +} + +.board-b72b1 { + border: 2px solid #404040; + box-sizing: content-box; +} + +.square-55d63 { + float: left; + position: relative; + + /* disable any native browser highlighting */ + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.white-1e1d7 { + background-color: #f0d9b5; + color: #b58863; +} + +.black-3c85d { + background-color: #b58863; + color: #f0d9b5; +} + +.highlight1-32417, .highlight2-9c5d2 { + box-shadow: inset 0 0 3px 3px yellow; +} + +.notation-322f9 { + cursor: default; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; + position: absolute; +} + +.alpha-d2270 { + bottom: 1px; + right: 3px; +} + +.numeric-fc462 { + top: 2px; + left: 2px; +} diff --git a/examples/chess.wasm/chessboardjs-1.0.0/css/chessboard-1.0.0.min.css b/examples/chess.wasm/chessboardjs-1.0.0/css/chessboard-1.0.0.min.css new file mode 100644 index 00000000..73f844a8 --- /dev/null +++ b/examples/chess.wasm/chessboardjs-1.0.0/css/chessboard-1.0.0.min.css @@ -0,0 +1,2 @@ +/*! chessboard.js v1.0.0 | (c) 2019 Chris Oakman | MIT License chessboardjs.com/license */ +.clearfix-7da63{clear:both}.board-b72b1{border:2px solid #404040;box-sizing:content-box}.square-55d63{float:left;position:relative;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.white-1e1d7{background-color:#f0d9b5;color:#b58863}.black-3c85d{background-color:#b58863;color:#f0d9b5}.highlight1-32417,.highlight2-9c5d2{box-shadow:inset 0 0 3px 3px #ff0}.notation-322f9{cursor:default;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;position:absolute}.alpha-d2270{bottom:1px;right:3px}.numeric-fc462{top:2px;left:2px} \ No newline at end of file diff --git a/examples/chess.wasm/chessboardjs-1.0.0/img/chesspieces/wikipedia/bB.png b/examples/chess.wasm/chessboardjs-1.0.0/img/chesspieces/wikipedia/bB.png new file mode 100644 index 0000000000000000000000000000000000000000..be3007dd0cdc7662268e103458b30a035da1cebf GIT binary patch literal 1405 zcmV-@1%mpCP);OAg&;29>pXtLFL9VGS_o&_2gy))=`i$DX3vw-9Gh)}RQ7JcwuWkdbRXt|A`xA>c4EW@MX> zj1K`bMy|`TiE&}qk z)5K?tT>s;C;y#C_DqWhf#67pwvT!jB9HSn^b1L&UY}D79cyZ!hpTfBbxfeETrsfTo zDW224pVh+TdWo{)C`Y)3gggu%T4E{j;}FCv7V#rpMSR#zUWI`}!j4;@#o3 zwq!Dyxf++t==OPfWGs*%U_4=RzH(`}WqAcL=rA~|k z8bl;wh$ODZe5|BZM;X(Y;=zPth-6yGt$ruZ0ZgQw$T8d!)h(;@rPja_mvT-ukYl(u zs?GS<5H=0`@|P$NBKsGCfS*QLz?~s(UwK`PycA^t`CY|i6-2asO<*4~(nwcPz*lwH zOyD`#=M@yu_Hk5blorehk!O_$wBqr2etHrF*_N1}&3aa7n1s2Jc$^=wp`pRbX0!Q? zf^xw&*cRJ_c;ARZQo5G7nMF*cQgUo;Oa=wE#Wo>cLTHTVxt7$`)ybx&CfU{1CA+)3 z%OcxgTWk|G@Ht(@yARWfFb5I~K9ahL$MeAh6&Q)t7fM>?%RDUH^ZtS+=Mk>cNx)rI zSjxSui+C~W>_5P$Ysv6ov9F$kz?Yr25HN<*lqbT}EQgl6svu9+Hr%txLo=goZiOOR&&?PZU1ak|MYyb7l^<6GG!O zUsX)rSl|~ve_;JO<3qd|+{5<{VFMxZqVewU3gVr_)x>+TsJ|bZn-3D#ibCe-dTAJ#4RquQl+UL@cWj+ls}qQ@x6~8_nh*F-!cKc!KyX@f7g~ z;u+#k#B;>oh$F-?G&xy9Q+6togUu26I0v6+5W^|NbOJGEvAMyqKU-C93njH_WNeCt*&$TPie{tCooB3#mtf7LOCfFK8;> zLZ3-&4stj7of;6YSj2aO+|}j}oF}i)8Rt-D9IFA9~G_GA#Y&zMRQ2aT?G3jCO<1$YN-Hcm_$1rNmBAD+);Xe%ck8oZgZpVBqMSKWM zVSdJQwJpSL#3qGX(M52%yNJtNVpxVUDcrNQ$ksOa*Z`ku9P1F<4#c_#v44+eu}9=% z=trP|Z1_lNO1_lNO2I1mAaAmM>MWmh600000 LNkvXXu0mjfilMA( literal 0 HcmV?d00001 diff --git a/examples/chess.wasm/chessboardjs-1.0.0/img/chesspieces/wikipedia/bK.png b/examples/chess.wasm/chessboardjs-1.0.0/img/chesspieces/wikipedia/bK.png new file mode 100644 index 0000000000000000000000000000000000000000..de9880ce6390d6a53464f1b028bff7be0fd0f131 GIT binary patch literal 3009 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 DNo%uI literal 0 HcmV?d00001 diff --git a/examples/chess.wasm/chessboardjs-1.0.0/img/chesspieces/wikipedia/bN.png b/examples/chess.wasm/chessboardjs-1.0.0/img/chesspieces/wikipedia/bN.png new file mode 100644 index 0000000000000000000000000000000000000000..e31a6d0224819791210e91218fc99b7cd3b848ed GIT binary patch literal 1875 zcmV-Z2dwysP)9wVNxLjD`@*iP6__$6VA8`tL&-X#RW zUP5D_3pg!{fgB^uc5!V9p(tNV|Gp5&;zh}#i3&mRJj2PgnS>Jx@#yvSfh=IOEEuS) zYKSmaaa{!A4~pxQ{4vmn@SiF{sCCuL0>==(p%PfhDZ)^~NW!o{6tLqymZi2z(Zy#! z%lA1-SS~L#j}it2f`CuC5C&X`M>(%N&&tYzef##^$h?u1g{eeo%(*%pyZ{SquvcgUrlKsIIPto}M0{~GzX|xd+VWPeTnQG71|}zqobjzsYw#CySp0~m(fM`;oP82 zZGH9i^^$O+D2*(Lii*-?NRv4b8X6j;u1}sk2@w$yzwz!f78Cxfe2Mkz*MkzBot>J_ zi$Os_*r&8Y@7}!|&wt@nJdE3Qsb2tBLnYGF(?RRS1y|{tH*doH{Jgkk%^Ga`oJRp) zC0tNHd~4?}Qpu;v0H3knLPDTMfpq8zX-;z>M=lnglY`8ICc2#t-6uxHO6 zAgiHI#6#j2ck0wB>5DX*&Di!WX?utl0V`cS{E8JTd}et{CMPGu?c29ucz77%;^MHa zln3!*eJ#vVSXWmkt;&ZE9m4ZIfrFgO7g}uByhWqYh>HnayLL@P=bp6X`BJ~~C=smv@?6opVFtPUR>}+XoJUKZDX=!QL z_9n}8C}!Edak8(JfX7~NQ$BXm?*>+LZc6k$(}ExzT4cYhRPPGX4GiQjkGTO)$&%e&+@8x)lE1V!?_D)&d?pcu*4X z)~#Do`hm1nvvgw`Jbd8K1owWrfWeB(TI_gm7lOb_FRVS3Lv+kw5|&?W)h)RHyN^1- zz2ZxcSyWWy@FcLVMvDOJnI#NYdORYyUnNzhWsnw~X^NdYcVgS$TI`2w2?u3sqz`jP z6?RgFqTCG?y{z8pux3U^hC{%;d-qC}3|d8H(4scW3F-pDUbxfi5PVpenWuQT8-)38?k({PSnyS@n8IqcN|mpqeVyP(DAH=daK^;M zM2CPUPMnb9go6E7Q+|Q%EOH)8Ar>A{U_GH+ep2WU;yo{~cs@;wDg``u?i|(-V*4w+ zi}x_$Fb^qCOlwkLh#!kGNxPYM0lyYFNysbbK%31*1>DcGc&`Z@RWm3BymaXj74U6d z#WQ#q(P1hemLJRY+f}>@xJ}-%a8pY|>ts|GXyH}BPkFLFWJ*fPJ!uJ9z#1OKi;*KT zTnUIp?-ZCHmfe{5c@%IR>->hN(U_K&7V1d9$D@Ex^5Xjms_K1;)2C0k zj|cA9vBM$Y@#DwoUie)e1$>6^55fLVBzWQEu3fukF|m#%9#*S$E-WkzW1I(g6fjn{ z!sj^Rvu3k-^T5DB!QkLvfyH9kLIlLP<|Bd*9XfRA(4j+z4jnq!;y-|v529HMk23%O N002ovPDHLkV1nn}h0*{3 literal 0 HcmV?d00001 diff --git a/examples/chess.wasm/chessboardjs-1.0.0/img/chesspieces/wikipedia/bP.png b/examples/chess.wasm/chessboardjs-1.0.0/img/chesspieces/wikipedia/bP.png new file mode 100644 index 0000000000000000000000000000000000000000..afa0c9d4459e4d04648ca413ba90690bfdd49a02 GIT binary patch literal 777 zcmV+k1NQuhP)tA2x4L(iq(~Zq9_3y8^IJ7 zR@wv#f-DBk0z<$E@CkSWTm#xw&(tgcx`1)O)S_AolZ!r}Np<}zuip`8oXEfS09dZt zCg_?*-ee+gY9>ysdE+ybmyhqjUeyQZ3dqaeThT1EzqY1eya1M^E^uU)*_V%RK${9w zfpzh+jz{=4(3-ly%LT;cOPS`>1-2Hf5(Uff~@=BM$xBp4(OG)6{lH}#%9k4M4d51j6%dT}ESQxv&rzMJW1wIFs#w>3I z@VVsdb0g|w|9!w$PXe=R9*kMwQQ(Ki>@&dWm<1jOetH&oF=l~>u}ASf1)hvq;8x&^ zCvn*txGQFX4Zuf_+4q|S4p{GbETkU-EwKyS;6Y#($5Pn~-}NBz8L%o9fo;J166KB6 z_Si|$iS4SDA@E9S@>T-_B?=q_I#Q9h-#Jhy>p*o3=#E`p4^z+ml_Ak!2QeFBl-CRV z@mNIXzmz+`l9=S3s_hbd)qj&^;|*X@ENh;bBYAH0VB4p`(vJTV=;_wPO`*zb!uD(D zBlGf~IZUAQGY972@N_nltU=KNJf6qwb7K@(ACkZhLGrTuxE_+gC&C08;1#eo1bOQO zNps^!2m&htvoE`sfe?!84}vpr6yZIS&DgG6RiM1=p0-IA*o~cCHi89Sl`Qa<;Kw(M zA*u43fky!dtV$KQ2HP2vF3;3j3L@*j;Q%tw06QfL+#)YvxKsG(*p#a(D{gVEMi@v&KK zcqG~aIc%A#7 z^Z)0Y^FL>}g5bb`0|yQqIB?*=fxR$-@q5G(jvUtTHsj}v4~Y0V@w+I*EXECt$&3>@ zZGOqv!w4$kwO@Q!gd4?pg0iQZ_?U5riQOxV{Un&E5KsQxPi4%2H|y7o@6t{5Dg-bd zRb`K;5Wz^qbsFNSMOXgM+UyBV;jNvP?ha!Uvs=cz#S$T)J+qM9vTeBz#9g3KPTTt;{VnY zg7`9yVI0pG%+U>gqI37<&z+1j4eY}iztynCYd?I!0tQly<0)oeSH&Ak8C64#yUm!- z_=d?$TCNiS@>7m_zt336*h?&=YewMd!m|zRF{T2Fv72JvK|&6BHa(-$4I4~EjAT5o z5kM|2ad;5V*hP%zwE3gKBy!TA_q?GPI@ClB{D&goZ|Lsp4eI$O-T4)|blZG`Zr@85Yu0v}ERWgq37 zbuXsLL$0ffuJK@#s+~OJX1YPLJY`%m)R{O_=Vat73*Awjxj*2r*`QJ92G07LEea@S z;a3`UqIemut_7D;3gemF6>@yZU{*5|@J|-TFy)#qhhr9BqR|z35JE8l#rQeJyhIpA z;0zk2XjrC&F05p$N%oFp{8Gd2OZv_Tl^S+DT{u%wK5962AUuNL`s_7}0?K2`Mw3aP zO+$z_`c4mX=={;DfUi+3Rx;KlD94!UA!H!3)Zi|^YOtJm)u5gOi~~auuv$^J*&PBF ztHznMAqd#QI9I29iorodijGYf<3DujGD4clf3Z6Rd|%bTc9U~9y=;0{XAI3Vu*uV@ zBSHAzqX1q3=TO^~W#4y)fJ-%I$TJ4}V!eg<-*gTZ>J0>}*V#24H?Yy$|DMr^W2rj? z4AW>N-u-thW+3v%7R!T9d-^O2_>NA-hPgw)U|Nc(GYYdKlv5Dd<}+2<$63+g0cUmp6orQXUe#$5H-0mH!Tl8Jnjgc!hRz!;4+pOT#vliTnk#zvEdpR*uf9Ua^E za+Jj-3qINVJEw1f+G13ukz#TiLREW6y$K?LGsr%Z!&|Lx-^1xUfn%bn7Ci9o%vlZr z+c^b+A(F?ooulko!2|f1W59P+AXmxL29aWMJGNQqMs{Wo#o~7SOc;Ds&D#ZhOtH8f zubV7oyoDG;geL?HpaEL+V(~~M?5t<%TE_Q2HbpK(m2_* zyLfUtFS+voK@YgGukxZSl-pP-@VzDB7T{~SHR{HOg@wWV`SW4jx^Lv(9+TZZEbDOc=zsIO)ATv4cej)^mY35Y03Bg{rjc5u+Dk& z=1FbP5b>&D{JOA5Fn`pjQJok-ZEdXx8tCuuhn}7u=hc<=x^Iy#`e zy&dk~zyFN)?%jKi%I~l&+Mq4^Kwsz+ePbP3sHv$D4<0-S!NI|u8jl6+fn l`)^ z-n=PRR8&Y=QBY6-yLRn@ZQHiN`t|E!<;sAcp zw%QWGCeI%Jk3K#=;OpxPetv$>x@|x}z;l$ZV;L-qHWmf^#$AssUBz<`-r2+glP6CG z>_T(r&V{(RIEasrhgGXq!P>QJVbi8fuzmY>$jZus-Me?gzJ2>3CnpCEA3h96j~SgBFX6i=n){9A`ir z#HFPO&Xg|-=o{<6x~^WmD%Fi`z_y^^(b3Vi|D)|m85tRE>cCoCTcNtTS_%f25@~5^ zkdl%DD^{$K)@n0n&V)&mCP8Rus6?D)wJ3j&Wzh!LnCJt2q0d8y4oP)jU0A0YnVFgY z5%}M%^~l)wFE;yP_Y&ER2N4kw9-lmLse^4{OB)f}CJerjZ%cfnx1Ga5AJ=dbCQN`S zQ>IA5PM(V}NuxNxC#9lytNSe|u9X$^>eP$cv_ zapFW6GiHo5(Fn$G-M?kKu8Z3v9K5khZP~H~_UzdM`T6;9>eMMHEiHu$7cRi%%a@_9 zt`2V8xPgmpX*-6yjE4^&O1p_CPo7BQSZ{Byw4)dp7?9Z4*C$=a@8ul~?nv(3xdXRu z-GYXO2FWjO>n>ir2xVnuQdcf4EQGy#_d;rFDkLT*!i*U+ASfsZp8#grO1<3N+@D^% zcC8n;R!^Tk1yR)8$w^x<9N^hj52~uF;M}=$P*hYT1)7(a2S<(^k!D<+Z87ld>}=^@ z{6AhtVmZ7qY%M3<7~EyxB-PZ^B#CM?!QhR$efze!dGqFv?4;ia)~!l0yBZrCMHFP` z&Yh5)oGf)Y?5^ytyLH^dbz^vVIK;-r!kRT}aPoi?Cr-fi>(`}>UA}yIt(^`NLcH-L znk~eW9RXcC58P}Q0r4H>Prd9|A72ewX17`RufpI%>V9E(U(Fa!AN|zEPw1(lt$@F; z@GHhYPy@?IR2;DJ?WY!c2HX1rGpm>CXrVf5sSRb+rajbkz2f&{@Gp_Z({Vq(Iu^~i zKp6b}gH?=4!r<>@;qT1gd(Zf)?{3Bqg~7i%!h_FT;$gb>A(hD{n^f|VL_XuGj%cbg zoZ8?kyyUPnW0000+NjA?5IGAHvP4t z54%KWsa~*up#S25g4PyUJ-=B#vU8SfOkVC3u;J1>CCN>xZx>V_Sh(vMyUFU{q&A(T z%a1H=@4r>w>!lpyyYBwP?~T)?JD%6QuQd^xTrI;6v+VaXtCeeiy8Wc6`Rl~%4ZC%_?Pl1m|0#bk z^7R^V?ErQbHRi&f$MXc79yDCv;r+Zw?g6KO{)aj8(mb3yc@;lQyRI|;dChg!RlNKE z2Rz^KOH@NqfTL01M}LIQvs-Etth*oXd|r8f`Q??<_)3?oyAnC+!1AR*FSp!&`>Jlg ze_+iNk^RBzuU~#z^mB@p_ivL;)4i7N+qG`>cNAB`UCr7Rwbo5)mgnY` z%;g)qY$tQOpL?4le&-}t+^m}H?YFCJM3nTCehM|;g7cR zGA+F`RWxmJzeVFD=0;#pu4Yve;?#ZdEzbUm=b{7K&po<#$IEQ?)x!@1Zt*^=Q-AeL z=bfkBqwE`8`967bj@It5w>>Ys`)K2?z~f8Lnb+t}{M^W$ak}{Ubs@{GvO*EfV88O5 ze8_iV_VWU1rp*0s-6soA?ptd4F#E=>dx^Ko-DaPg7dgu!o*9yi7XDzq)Gu?~A%9jq ONWjz8&t;ucLK6U+JX?nV literal 0 HcmV?d00001 diff --git a/examples/chess.wasm/chessboardjs-1.0.0/img/chesspieces/wikipedia/wB.png b/examples/chess.wasm/chessboardjs-1.0.0/img/chesspieces/wikipedia/wB.png new file mode 100644 index 0000000000000000000000000000000000000000..70e0e14088f6ea09b84b728df6aaae6d4776ab4e GIT binary patch literal 2374 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 Z{12-kJ&=_`^N#=k002ovPDHLkV1l3JS(E?( literal 0 HcmV?d00001 diff --git a/examples/chess.wasm/chessboardjs-1.0.0/img/chesspieces/wikipedia/wN.png b/examples/chess.wasm/chessboardjs-1.0.0/img/chesspieces/wikipedia/wN.png new file mode 100644 index 0000000000000000000000000000000000000000..237250c164f652f0ea61f5e8f65c9b4cb83489b7 GIT binary patch literal 2388 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 V@B7wJo3#J{002ovPDHLkV1iHz`5piO literal 0 HcmV?d00001 diff --git a/examples/chess.wasm/chessboardjs-1.0.0/img/chesspieces/wikipedia/wQ.png b/examples/chess.wasm/chessboardjs-1.0.0/img/chesspieces/wikipedia/wQ.png new file mode 100644 index 0000000000000000000000000000000000000000..c3dfc15e556cbbeb546374aa9ee5e6bf121e929d GIT binary patch literal 3812 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 minimum + function validSemanticVersion (version, minimum) { + version = parseSemVer(version) + minimum = parseSemVer(minimum) + + var versionNum = (version.major * 100000 * 100000) + + (version.minor * 100000) + + version.patch + var minimumNum = (minimum.major * 100000 * 100000) + + (minimum.minor * 100000) + + minimum.patch + + return versionNum >= minimumNum + } + + function interpolateTemplate (str, obj) { + for (var key in obj) { + if (!obj.hasOwnProperty(key)) continue + var keyTemplateStr = '{' + key + '}' + var value = obj[key] + while (str.indexOf(keyTemplateStr) !== -1) { + str = str.replace(keyTemplateStr, value) + } + } + return str + } + + if (RUN_ASSERTS) { + console.assert(interpolateTemplate('abc', {a: 'x'}) === 'abc') + console.assert(interpolateTemplate('{a}bc', {}) === '{a}bc') + console.assert(interpolateTemplate('{a}bc', {p: 'q'}) === '{a}bc') + console.assert(interpolateTemplate('{a}bc', {a: 'x'}) === 'xbc') + console.assert(interpolateTemplate('{a}bc{a}bc', {a: 'x'}) === 'xbcxbc') + console.assert(interpolateTemplate('{a}{a}{b}', {a: 'x', b: 'y'}) === 'xxy') + } + + // --------------------------------------------------------------------------- + // Predicates + // --------------------------------------------------------------------------- + + function isString (s) { + return typeof s === 'string' + } + + function isFunction (f) { + return typeof f === 'function' + } + + function isInteger (n) { + return typeof n === 'number' && + isFinite(n) && + Math.floor(n) === n + } + + function validAnimationSpeed (speed) { + if (speed === 'fast' || speed === 'slow') return true + if (!isInteger(speed)) return false + return speed >= 0 + } + + function validThrottleRate (rate) { + return isInteger(rate) && + rate >= 1 + } + + function validMove (move) { + // move should be a string + if (!isString(move)) return false + + // move should be in the form of "e2-e4", "f6-d5" + var squares = move.split('-') + if (squares.length !== 2) return false + + return validSquare(squares[0]) && validSquare(squares[1]) + } + + function validSquare (square) { + return isString(square) && square.search(/^[a-h][1-8]$/) !== -1 + } + + if (RUN_ASSERTS) { + console.assert(validSquare('a1')) + console.assert(validSquare('e2')) + console.assert(!validSquare('D2')) + console.assert(!validSquare('g9')) + console.assert(!validSquare('a')) + console.assert(!validSquare(true)) + console.assert(!validSquare(null)) + console.assert(!validSquare({})) + } + + function validPieceCode (code) { + return isString(code) && code.search(/^[bw][KQRNBP]$/) !== -1 + } + + if (RUN_ASSERTS) { + console.assert(validPieceCode('bP')) + console.assert(validPieceCode('bK')) + console.assert(validPieceCode('wK')) + console.assert(validPieceCode('wR')) + console.assert(!validPieceCode('WR')) + console.assert(!validPieceCode('Wr')) + console.assert(!validPieceCode('a')) + console.assert(!validPieceCode(true)) + console.assert(!validPieceCode(null)) + console.assert(!validPieceCode({})) + } + + function validFen (fen) { + if (!isString(fen)) return false + + // cut off any move, castling, etc info from the end + // we're only interested in position information + fen = fen.replace(/ .+$/, '') + + // expand the empty square numbers to just 1s + fen = expandFenEmptySquares(fen) + + // FEN should be 8 sections separated by slashes + var chunks = fen.split('/') + if (chunks.length !== 8) return false + + // check each section + for (var i = 0; i < 8; i++) { + if (chunks[i].length !== 8 || + chunks[i].search(/[^kqrnbpKQRNBP1]/) !== -1) { + return false + } + } + + return true + } + + if (RUN_ASSERTS) { + console.assert(validFen(START_FEN)) + console.assert(validFen('8/8/8/8/8/8/8/8')) + console.assert(validFen('r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R')) + console.assert(validFen('3r3r/1p4pp/2nb1k2/pP3p2/8/PB2PN2/p4PPP/R4RK1 b - - 0 1')) + console.assert(!validFen('3r3z/1p4pp/2nb1k2/pP3p2/8/PB2PN2/p4PPP/R4RK1 b - - 0 1')) + console.assert(!validFen('anbqkbnr/8/8/8/8/8/PPPPPPPP/8')) + console.assert(!validFen('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/')) + console.assert(!validFen('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBN')) + console.assert(!validFen('888888/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR')) + console.assert(!validFen('888888/pppppppp/74/8/8/8/PPPPPPPP/RNBQKBNR')) + console.assert(!validFen({})) + } + + function validPositionObject (pos) { + if (!$.isPlainObject(pos)) return false + + for (var i in pos) { + if (!pos.hasOwnProperty(i)) continue + + if (!validSquare(i) || !validPieceCode(pos[i])) { + return false + } + } + + return true + } + + if (RUN_ASSERTS) { + console.assert(validPositionObject(START_POSITION)) + console.assert(validPositionObject({})) + console.assert(validPositionObject({e2: 'wP'})) + console.assert(validPositionObject({e2: 'wP', d2: 'wP'})) + console.assert(!validPositionObject({e2: 'BP'})) + console.assert(!validPositionObject({y2: 'wP'})) + console.assert(!validPositionObject(null)) + console.assert(!validPositionObject('start')) + console.assert(!validPositionObject(START_FEN)) + } + + function isTouchDevice () { + return 'ontouchstart' in document.documentElement + } + + function validJQueryVersion () { + return typeof window.$ && + $.fn && + $.fn.jquery && + validSemanticVersion($.fn.jquery, MINIMUM_JQUERY_VERSION) + } + + // --------------------------------------------------------------------------- + // Chess Util Functions + // --------------------------------------------------------------------------- + + // convert FEN piece code to bP, wK, etc + function fenToPieceCode (piece) { + // black piece + if (piece.toLowerCase() === piece) { + return 'b' + piece.toUpperCase() + } + + // white piece + return 'w' + piece.toUpperCase() + } + + // convert bP, wK, etc code to FEN structure + function pieceCodeToFen (piece) { + var pieceCodeLetters = piece.split('') + + // white piece + if (pieceCodeLetters[0] === 'w') { + return pieceCodeLetters[1].toUpperCase() + } + + // black piece + return pieceCodeLetters[1].toLowerCase() + } + + // convert FEN string to position object + // returns false if the FEN string is invalid + function fenToObj (fen) { + if (!validFen(fen)) return false + + // cut off any move, castling, etc info from the end + // we're only interested in position information + fen = fen.replace(/ .+$/, '') + + var rows = fen.split('/') + var position = {} + + var currentRow = 8 + for (var i = 0; i < 8; i++) { + var row = rows[i].split('') + var colIdx = 0 + + // loop through each character in the FEN section + for (var j = 0; j < row.length; j++) { + // number / empty squares + if (row[j].search(/[1-8]/) !== -1) { + var numEmptySquares = parseInt(row[j], 10) + colIdx = colIdx + numEmptySquares + } else { + // piece + var square = COLUMNS[colIdx] + currentRow + position[square] = fenToPieceCode(row[j]) + colIdx = colIdx + 1 + } + } + + currentRow = currentRow - 1 + } + + return position + } + + // position object to FEN string + // returns false if the obj is not a valid position object + function objToFen (obj) { + if (!validPositionObject(obj)) return false + + var fen = '' + + var currentRow = 8 + for (var i = 0; i < 8; i++) { + for (var j = 0; j < 8; j++) { + var square = COLUMNS[j] + currentRow + + // piece exists + if (obj.hasOwnProperty(square)) { + fen = fen + pieceCodeToFen(obj[square]) + } else { + // empty space + fen = fen + '1' + } + } + + if (i !== 7) { + fen = fen + '/' + } + + currentRow = currentRow - 1 + } + + // squeeze the empty numbers together + fen = squeezeFenEmptySquares(fen) + + return fen + } + + if (RUN_ASSERTS) { + console.assert(objToFen(START_POSITION) === START_FEN) + console.assert(objToFen({}) === '8/8/8/8/8/8/8/8') + console.assert(objToFen({a2: 'wP', 'b2': 'bP'}) === '8/8/8/8/8/8/Pp6/8') + } + + function squeezeFenEmptySquares (fen) { + return fen.replace(/11111111/g, '8') + .replace(/1111111/g, '7') + .replace(/111111/g, '6') + .replace(/11111/g, '5') + .replace(/1111/g, '4') + .replace(/111/g, '3') + .replace(/11/g, '2') + } + + function expandFenEmptySquares (fen) { + return fen.replace(/8/g, '11111111') + .replace(/7/g, '1111111') + .replace(/6/g, '111111') + .replace(/5/g, '11111') + .replace(/4/g, '1111') + .replace(/3/g, '111') + .replace(/2/g, '11') + } + + // returns the distance between two squares + function squareDistance (squareA, squareB) { + var squareAArray = squareA.split('') + var squareAx = COLUMNS.indexOf(squareAArray[0]) + 1 + var squareAy = parseInt(squareAArray[1], 10) + + var squareBArray = squareB.split('') + var squareBx = COLUMNS.indexOf(squareBArray[0]) + 1 + var squareBy = parseInt(squareBArray[1], 10) + + var xDelta = Math.abs(squareAx - squareBx) + var yDelta = Math.abs(squareAy - squareBy) + + if (xDelta >= yDelta) return xDelta + return yDelta + } + + // returns the square of the closest instance of piece + // returns false if no instance of piece is found in position + function findClosestPiece (position, piece, square) { + // create array of closest squares from square + var closestSquares = createRadius(square) + + // search through the position in order of distance for the piece + for (var i = 0; i < closestSquares.length; i++) { + var s = closestSquares[i] + + if (position.hasOwnProperty(s) && position[s] === piece) { + return s + } + } + + return false + } + + // returns an array of closest squares from square + function createRadius (square) { + var squares = [] + + // calculate distance of all squares + for (var i = 0; i < 8; i++) { + for (var j = 0; j < 8; j++) { + var s = COLUMNS[i] + (j + 1) + + // skip the square we're starting from + if (square === s) continue + + squares.push({ + square: s, + distance: squareDistance(square, s) + }) + } + } + + // sort by distance + squares.sort(function (a, b) { + return a.distance - b.distance + }) + + // just return the square code + var surroundingSquares = [] + for (i = 0; i < squares.length; i++) { + surroundingSquares.push(squares[i].square) + } + + return surroundingSquares + } + + // given a position and a set of moves, return a new position + // with the moves executed + function calculatePositionFromMoves (position, moves) { + var newPosition = deepCopy(position) + + for (var i in moves) { + if (!moves.hasOwnProperty(i)) continue + + // skip the move if the position doesn't have a piece on the source square + if (!newPosition.hasOwnProperty(i)) continue + + var piece = newPosition[i] + delete newPosition[i] + newPosition[moves[i]] = piece + } + + return newPosition + } + + // TODO: add some asserts here for calculatePositionFromMoves + + // --------------------------------------------------------------------------- + // HTML + // --------------------------------------------------------------------------- + + function buildContainerHTML (hasSparePieces) { + var html = '
' + + if (hasSparePieces) { + html += '
' + } + + html += '
' + + if (hasSparePieces) { + html += '
' + } + + html += '
' + + return interpolateTemplate(html, CSS) + } + + // --------------------------------------------------------------------------- + // Config + // --------------------------------------------------------------------------- + + function expandConfigArgumentShorthand (config) { + if (config === 'start') { + config = {position: deepCopy(START_POSITION)} + } else if (validFen(config)) { + config = {position: fenToObj(config)} + } else if (validPositionObject(config)) { + config = {position: deepCopy(config)} + } + + // config must be an object + if (!$.isPlainObject(config)) config = {} + + return config + } + + // validate config / set default options + function expandConfig (config) { + // default for orientation is white + if (config.orientation !== 'black') config.orientation = 'white' + + // default for showNotation is true + if (config.showNotation !== false) config.showNotation = true + + // default for draggable is false + if (config.draggable !== true) config.draggable = false + + // default for dropOffBoard is 'snapback' + if (config.dropOffBoard !== 'trash') config.dropOffBoard = 'snapback' + + // default for sparePieces is false + if (config.sparePieces !== true) config.sparePieces = false + + // draggable must be true if sparePieces is enabled + if (config.sparePieces) config.draggable = true + + // default piece theme is wikipedia + if (!config.hasOwnProperty('pieceTheme') || + (!isString(config.pieceTheme) && !isFunction(config.pieceTheme))) { + config.pieceTheme = 'img/chesspieces/wikipedia/{piece}.png' + } + + // animation speeds + if (!validAnimationSpeed(config.appearSpeed)) config.appearSpeed = DEFAULT_APPEAR_SPEED + if (!validAnimationSpeed(config.moveSpeed)) config.moveSpeed = DEFAULT_MOVE_SPEED + if (!validAnimationSpeed(config.snapbackSpeed)) config.snapbackSpeed = DEFAULT_SNAPBACK_SPEED + if (!validAnimationSpeed(config.snapSpeed)) config.snapSpeed = DEFAULT_SNAP_SPEED + if (!validAnimationSpeed(config.trashSpeed)) config.trashSpeed = DEFAULT_TRASH_SPEED + + // throttle rate + if (!validThrottleRate(config.dragThrottleRate)) config.dragThrottleRate = DEFAULT_DRAG_THROTTLE_RATE + + return config + } + + // --------------------------------------------------------------------------- + // Dependencies + // --------------------------------------------------------------------------- + + // check for a compatible version of jQuery + function checkJQuery () { + if (!validJQueryVersion()) { + var errorMsg = 'Chessboard Error 1005: Unable to find a valid version of jQuery. ' + + 'Please include jQuery ' + MINIMUM_JQUERY_VERSION + ' or higher on the page' + + '\n\n' + + 'Exiting' + ELLIPSIS + window.alert(errorMsg) + return false + } + + return true + } + + // return either boolean false or the $container element + function checkContainerArg (containerElOrString) { + if (containerElOrString === '') { + var errorMsg1 = 'Chessboard Error 1001: ' + + 'The first argument to Chessboard() cannot be an empty string.' + + '\n\n' + + 'Exiting' + ELLIPSIS + window.alert(errorMsg1) + return false + } + + // convert containerEl to query selector if it is a string + if (isString(containerElOrString) && + containerElOrString.charAt(0) !== '#') { + containerElOrString = '#' + containerElOrString + } + + // containerEl must be something that becomes a jQuery collection of size 1 + var $container = $(containerElOrString) + if ($container.length !== 1) { + var errorMsg2 = 'Chessboard Error 1003: ' + + 'The first argument to Chessboard() must be the ID of a DOM node, ' + + 'an ID query selector, or a single DOM node.' + + '\n\n' + + 'Exiting' + ELLIPSIS + window.alert(errorMsg2) + return false + } + + return $container + } + + // --------------------------------------------------------------------------- + // Constructor + // --------------------------------------------------------------------------- + + function constructor (containerElOrString, config) { + // first things first: check basic dependencies + if (!checkJQuery()) return null + var $container = checkContainerArg(containerElOrString) + if (!$container) return null + + // ensure the config object is what we expect + config = expandConfigArgumentShorthand(config) + config = expandConfig(config) + + // DOM elements + var $board = null + var $draggedPiece = null + var $sparePiecesTop = null + var $sparePiecesBottom = null + + // constructor return object + var widget = {} + + // ------------------------------------------------------------------------- + // Stateful + // ------------------------------------------------------------------------- + + var boardBorderSize = 2 + var currentOrientation = 'white' + var currentPosition = {} + var draggedPiece = null + var draggedPieceLocation = null + var draggedPieceSource = null + var isDragging = false + var sparePiecesElsIds = {} + var squareElsIds = {} + var squareElsOffsets = {} + var squareSize = 16 + + // ------------------------------------------------------------------------- + // Validation / Errors + // ------------------------------------------------------------------------- + + function error (code, msg, obj) { + // do nothing if showErrors is not set + if ( + config.hasOwnProperty('showErrors') !== true || + config.showErrors === false + ) { + return + } + + var errorText = 'Chessboard Error ' + code + ': ' + msg + + // print to console + if ( + config.showErrors === 'console' && + typeof console === 'object' && + typeof console.log === 'function' + ) { + console.log(errorText) + if (arguments.length >= 2) { + console.log(obj) + } + return + } + + // alert errors + if (config.showErrors === 'alert') { + if (obj) { + errorText += '\n\n' + JSON.stringify(obj) + } + window.alert(errorText) + return + } + + // custom function + if (isFunction(config.showErrors)) { + config.showErrors(code, msg, obj) + } + } + + function setInitialState () { + currentOrientation = config.orientation + + // make sure position is valid + if (config.hasOwnProperty('position')) { + if (config.position === 'start') { + currentPosition = deepCopy(START_POSITION) + } else if (validFen(config.position)) { + currentPosition = fenToObj(config.position) + } else if (validPositionObject(config.position)) { + currentPosition = deepCopy(config.position) + } else { + error( + 7263, + 'Invalid value passed to config.position.', + config.position + ) + } + } + } + + // ------------------------------------------------------------------------- + // DOM Misc + // ------------------------------------------------------------------------- + + // calculates square size based on the width of the container + // got a little CSS black magic here, so let me explain: + // get the width of the container element (could be anything), reduce by 1 for + // fudge factor, and then keep reducing until we find an exact mod 8 for + // our square size + function calculateSquareSize () { + var containerWidth = parseInt($container.width(), 10) + + // defensive, prevent infinite loop + if (!containerWidth || containerWidth <= 0) { + return 0 + } + + // pad one pixel + var boardWidth = containerWidth - 1 + + while (boardWidth % 8 !== 0 && boardWidth > 0) { + boardWidth = boardWidth - 1 + } + + return boardWidth / 8 + } + + // create random IDs for elements + function createElIds () { + // squares on the board + for (var i = 0; i < COLUMNS.length; i++) { + for (var j = 1; j <= 8; j++) { + var square = COLUMNS[i] + j + squareElsIds[square] = square + '-' + uuid() + } + } + + // spare pieces + var pieces = 'KQRNBP'.split('') + for (i = 0; i < pieces.length; i++) { + var whitePiece = 'w' + pieces[i] + var blackPiece = 'b' + pieces[i] + sparePiecesElsIds[whitePiece] = whitePiece + '-' + uuid() + sparePiecesElsIds[blackPiece] = blackPiece + '-' + uuid() + } + } + + // ------------------------------------------------------------------------- + // Markup Building + // ------------------------------------------------------------------------- + + function buildBoardHTML (orientation) { + if (orientation !== 'black') { + orientation = 'white' + } + + var html = '' + + // algebraic notation / orientation + var alpha = deepCopy(COLUMNS) + var row = 8 + if (orientation === 'black') { + alpha.reverse() + row = 1 + } + + var squareColor = 'white' + for (var i = 0; i < 8; i++) { + html += '
' + for (var j = 0; j < 8; j++) { + var square = alpha[j] + row + + html += '
' + + if (config.showNotation) { + // alpha notation + if ((orientation === 'white' && row === 1) || + (orientation === 'black' && row === 8)) { + html += '
' + alpha[j] + '
' + } + + // numeric notation + if (j === 0) { + html += '
' + row + '
' + } + } + + html += '
' // end .square + + squareColor = (squareColor === 'white') ? 'black' : 'white' + } + html += '
' + + squareColor = (squareColor === 'white') ? 'black' : 'white' + + if (orientation === 'white') { + row = row - 1 + } else { + row = row + 1 + } + } + + return interpolateTemplate(html, CSS) + } + + function buildPieceImgSrc (piece) { + if (isFunction(config.pieceTheme)) { + return config.pieceTheme(piece) + } + + if (isString(config.pieceTheme)) { + return interpolateTemplate(config.pieceTheme, {piece: piece}) + } + + // NOTE: this should never happen + error(8272, 'Unable to build image source for config.pieceTheme.') + return '' + } + + function buildPieceHTML (piece, hidden, id) { + var html = '' + + return interpolateTemplate(html, CSS) + } + + function buildSparePiecesHTML (color) { + var pieces = ['wK', 'wQ', 'wR', 'wB', 'wN', 'wP'] + if (color === 'black') { + pieces = ['bK', 'bQ', 'bR', 'bB', 'bN', 'bP'] + } + + var html = '' + for (var i = 0; i < pieces.length; i++) { + html += buildPieceHTML(pieces[i], false, sparePiecesElsIds[pieces[i]]) + } + + return html + } + + // ------------------------------------------------------------------------- + // Animations + // ------------------------------------------------------------------------- + + function animateSquareToSquare (src, dest, piece, completeFn) { + // get information about the source and destination squares + var $srcSquare = $('#' + squareElsIds[src]) + var srcSquarePosition = $srcSquare.offset() + var $destSquare = $('#' + squareElsIds[dest]) + var destSquarePosition = $destSquare.offset() + + // create the animated piece and absolutely position it + // over the source square + var animatedPieceId = uuid() + $('body').append(buildPieceHTML(piece, true, animatedPieceId)) + var $animatedPiece = $('#' + animatedPieceId) + $animatedPiece.css({ + display: '', + position: 'absolute', + top: srcSquarePosition.top, + left: srcSquarePosition.left + }) + + // remove original piece from source square + $srcSquare.find('.' + CSS.piece).remove() + + function onFinishAnimation1 () { + // add the "real" piece to the destination square + $destSquare.append(buildPieceHTML(piece)) + + // remove the animated piece + $animatedPiece.remove() + + // run complete function + if (isFunction(completeFn)) { + completeFn() + } + } + + // animate the piece to the destination square + var opts = { + duration: config.moveSpeed, + complete: onFinishAnimation1 + } + $animatedPiece.animate(destSquarePosition, opts) + } + + function animateSparePieceToSquare (piece, dest, completeFn) { + var srcOffset = $('#' + sparePiecesElsIds[piece]).offset() + var $destSquare = $('#' + squareElsIds[dest]) + var destOffset = $destSquare.offset() + + // create the animate piece + var pieceId = uuid() + $('body').append(buildPieceHTML(piece, true, pieceId)) + var $animatedPiece = $('#' + pieceId) + $animatedPiece.css({ + display: '', + position: 'absolute', + left: srcOffset.left, + top: srcOffset.top + }) + + // on complete + function onFinishAnimation2 () { + // add the "real" piece to the destination square + $destSquare.find('.' + CSS.piece).remove() + $destSquare.append(buildPieceHTML(piece)) + + // remove the animated piece + $animatedPiece.remove() + + // run complete function + if (isFunction(completeFn)) { + completeFn() + } + } + + // animate the piece to the destination square + var opts = { + duration: config.moveSpeed, + complete: onFinishAnimation2 + } + $animatedPiece.animate(destOffset, opts) + } + + // execute an array of animations + function doAnimations (animations, oldPos, newPos) { + if (animations.length === 0) return + + var numFinished = 0 + function onFinishAnimation3 () { + // exit if all the animations aren't finished + numFinished = numFinished + 1 + if (numFinished !== animations.length) return + + drawPositionInstant() + + // run their onMoveEnd function + if (isFunction(config.onMoveEnd)) { + config.onMoveEnd(deepCopy(oldPos), deepCopy(newPos)) + } + } + + for (var i = 0; i < animations.length; i++) { + var animation = animations[i] + + // clear a piece + if (animation.type === 'clear') { + $('#' + squareElsIds[animation.square] + ' .' + CSS.piece) + .fadeOut(config.trashSpeed, onFinishAnimation3) + + // add a piece with no spare pieces - fade the piece onto the square + } else if (animation.type === 'add' && !config.sparePieces) { + $('#' + squareElsIds[animation.square]) + .append(buildPieceHTML(animation.piece, true)) + .find('.' + CSS.piece) + .fadeIn(config.appearSpeed, onFinishAnimation3) + + // add a piece with spare pieces - animate from the spares + } else if (animation.type === 'add' && config.sparePieces) { + animateSparePieceToSquare(animation.piece, animation.square, onFinishAnimation3) + + // move a piece from squareA to squareB + } else if (animation.type === 'move') { + animateSquareToSquare(animation.source, animation.destination, animation.piece, onFinishAnimation3) + } + } + } + + // calculate an array of animations that need to happen in order to get + // from pos1 to pos2 + function calculateAnimations (pos1, pos2) { + // make copies of both + pos1 = deepCopy(pos1) + pos2 = deepCopy(pos2) + + var animations = [] + var squaresMovedTo = {} + + // remove pieces that are the same in both positions + for (var i in pos2) { + if (!pos2.hasOwnProperty(i)) continue + + if (pos1.hasOwnProperty(i) && pos1[i] === pos2[i]) { + delete pos1[i] + delete pos2[i] + } + } + + // find all the "move" animations + for (i in pos2) { + if (!pos2.hasOwnProperty(i)) continue + + var closestPiece = findClosestPiece(pos1, pos2[i], i) + if (closestPiece) { + animations.push({ + type: 'move', + source: closestPiece, + destination: i, + piece: pos2[i] + }) + + delete pos1[closestPiece] + delete pos2[i] + squaresMovedTo[i] = true + } + } + + // "add" animations + for (i in pos2) { + if (!pos2.hasOwnProperty(i)) continue + + animations.push({ + type: 'add', + square: i, + piece: pos2[i] + }) + + delete pos2[i] + } + + // "clear" animations + for (i in pos1) { + if (!pos1.hasOwnProperty(i)) continue + + // do not clear a piece if it is on a square that is the result + // of a "move", ie: a piece capture + if (squaresMovedTo.hasOwnProperty(i)) continue + + animations.push({ + type: 'clear', + square: i, + piece: pos1[i] + }) + + delete pos1[i] + } + + return animations + } + + // ------------------------------------------------------------------------- + // Control Flow + // ------------------------------------------------------------------------- + + function drawPositionInstant () { + // clear the board + $board.find('.' + CSS.piece).remove() + + // add the pieces + for (var i in currentPosition) { + if (!currentPosition.hasOwnProperty(i)) continue + + $('#' + squareElsIds[i]).append(buildPieceHTML(currentPosition[i])) + } + } + + function drawBoard () { + $board.html(buildBoardHTML(currentOrientation, squareSize, config.showNotation)) + drawPositionInstant() + + if (config.sparePieces) { + if (currentOrientation === 'white') { + $sparePiecesTop.html(buildSparePiecesHTML('black')) + $sparePiecesBottom.html(buildSparePiecesHTML('white')) + } else { + $sparePiecesTop.html(buildSparePiecesHTML('white')) + $sparePiecesBottom.html(buildSparePiecesHTML('black')) + } + } + } + + function setCurrentPosition (position) { + var oldPos = deepCopy(currentPosition) + var newPos = deepCopy(position) + var oldFen = objToFen(oldPos) + var newFen = objToFen(newPos) + + // do nothing if no change in position + if (oldFen === newFen) return + + // run their onChange function + if (isFunction(config.onChange)) { + config.onChange(oldPos, newPos) + } + + // update state + currentPosition = position + } + + function isXYOnSquare (x, y) { + for (var i in squareElsOffsets) { + if (!squareElsOffsets.hasOwnProperty(i)) continue + + var s = squareElsOffsets[i] + if (x >= s.left && + x < s.left + squareSize && + y >= s.top && + y < s.top + squareSize) { + return i + } + } + + return 'offboard' + } + + // records the XY coords of every square into memory + function captureSquareOffsets () { + squareElsOffsets = {} + + for (var i in squareElsIds) { + if (!squareElsIds.hasOwnProperty(i)) continue + + squareElsOffsets[i] = $('#' + squareElsIds[i]).offset() + } + } + + function removeSquareHighlights () { + $board + .find('.' + CSS.square) + .removeClass(CSS.highlight1 + ' ' + CSS.highlight2) + } + + function snapbackDraggedPiece () { + // there is no "snapback" for spare pieces + if (draggedPieceSource === 'spare') { + trashDraggedPiece() + return + } + + removeSquareHighlights() + + // animation complete + function complete () { + drawPositionInstant() + $draggedPiece.css('display', 'none') + + // run their onSnapbackEnd function + if (isFunction(config.onSnapbackEnd)) { + config.onSnapbackEnd( + draggedPiece, + draggedPieceSource, + deepCopy(currentPosition), + currentOrientation + ) + } + } + + // get source square position + var sourceSquarePosition = $('#' + squareElsIds[draggedPieceSource]).offset() + + // animate the piece to the target square + var opts = { + duration: config.snapbackSpeed, + complete: complete + } + $draggedPiece.animate(sourceSquarePosition, opts) + + // set state + isDragging = false + } + + function trashDraggedPiece () { + removeSquareHighlights() + + // remove the source piece + var newPosition = deepCopy(currentPosition) + delete newPosition[draggedPieceSource] + setCurrentPosition(newPosition) + + // redraw the position + drawPositionInstant() + + // hide the dragged piece + $draggedPiece.fadeOut(config.trashSpeed) + + // set state + isDragging = false + } + + function dropDraggedPieceOnSquare (square) { + removeSquareHighlights() + + // update position + var newPosition = deepCopy(currentPosition) + delete newPosition[draggedPieceSource] + newPosition[square] = draggedPiece + setCurrentPosition(newPosition) + + // get target square information + var targetSquarePosition = $('#' + squareElsIds[square]).offset() + + // animation complete + function onAnimationComplete () { + drawPositionInstant() + $draggedPiece.css('display', 'none') + + // execute their onSnapEnd function + if (isFunction(config.onSnapEnd)) { + config.onSnapEnd(draggedPieceSource, square, draggedPiece) + } + } + + // snap the piece to the target square + var opts = { + duration: config.snapSpeed, + complete: onAnimationComplete + } + $draggedPiece.animate(targetSquarePosition, opts) + + // set state + isDragging = false + } + + function beginDraggingPiece (source, piece, x, y) { + // run their custom onDragStart function + // their custom onDragStart function can cancel drag start + if (isFunction(config.onDragStart) && + config.onDragStart(source, piece, deepCopy(currentPosition), currentOrientation) === false) { + return + } + + // set state + isDragging = true + draggedPiece = piece + draggedPieceSource = source + + // if the piece came from spare pieces, location is offboard + if (source === 'spare') { + draggedPieceLocation = 'offboard' + } else { + draggedPieceLocation = source + } + + // capture the x, y coords of all squares in memory + captureSquareOffsets() + + // create the dragged piece + $draggedPiece.attr('src', buildPieceImgSrc(piece)).css({ + display: '', + position: 'absolute', + left: x - squareSize / 2, + top: y - squareSize / 2 + }) + + if (source !== 'spare') { + // highlight the source square and hide the piece + $('#' + squareElsIds[source]) + .addClass(CSS.highlight1) + .find('.' + CSS.piece) + .css('display', 'none') + } + } + + function updateDraggedPiece (x, y) { + // put the dragged piece over the mouse cursor + $draggedPiece.css({ + left: x - squareSize / 2, + top: y - squareSize / 2 + }) + + // get location + var location = isXYOnSquare(x, y) + + // do nothing if the location has not changed + if (location === draggedPieceLocation) return + + // remove highlight from previous square + if (validSquare(draggedPieceLocation)) { + $('#' + squareElsIds[draggedPieceLocation]).removeClass(CSS.highlight2) + } + + // add highlight to new square + if (validSquare(location)) { + $('#' + squareElsIds[location]).addClass(CSS.highlight2) + } + + // run onDragMove + if (isFunction(config.onDragMove)) { + config.onDragMove( + location, + draggedPieceLocation, + draggedPieceSource, + draggedPiece, + deepCopy(currentPosition), + currentOrientation + ) + } + + // update state + draggedPieceLocation = location + } + + function stopDraggedPiece (location) { + // determine what the action should be + var action = 'drop' + if (location === 'offboard' && config.dropOffBoard === 'snapback') { + action = 'snapback' + } + if (location === 'offboard' && config.dropOffBoard === 'trash') { + action = 'trash' + } + + // run their onDrop function, which can potentially change the drop action + if (isFunction(config.onDrop)) { + var newPosition = deepCopy(currentPosition) + + // source piece is a spare piece and position is off the board + // if (draggedPieceSource === 'spare' && location === 'offboard') {...} + // position has not changed; do nothing + + // source piece is a spare piece and position is on the board + if (draggedPieceSource === 'spare' && validSquare(location)) { + // add the piece to the board + newPosition[location] = draggedPiece + } + + // source piece was on the board and position is off the board + if (validSquare(draggedPieceSource) && location === 'offboard') { + // remove the piece from the board + delete newPosition[draggedPieceSource] + } + + // source piece was on the board and position is on the board + if (validSquare(draggedPieceSource) && validSquare(location)) { + // move the piece + delete newPosition[draggedPieceSource] + newPosition[location] = draggedPiece + } + + var oldPosition = deepCopy(currentPosition) + + var result = config.onDrop( + draggedPieceSource, + location, + draggedPiece, + newPosition, + oldPosition, + currentOrientation + ) + if (result === 'snapback' || result === 'trash') { + action = result + } + } + + // do it! + if (action === 'snapback') { + snapbackDraggedPiece() + } else if (action === 'trash') { + trashDraggedPiece() + } else if (action === 'drop') { + dropDraggedPieceOnSquare(location) + } + } + + // ------------------------------------------------------------------------- + // Public Methods + // ------------------------------------------------------------------------- + + // clear the board + widget.clear = function (useAnimation) { + widget.position({}, useAnimation) + } + + // remove the widget from the page + widget.destroy = function () { + // remove markup + $container.html('') + $draggedPiece.remove() + + // remove event handlers + $container.unbind() + } + + // shorthand method to get the current FEN + widget.fen = function () { + return widget.position('fen') + } + + // flip orientation + widget.flip = function () { + return widget.orientation('flip') + } + + // move pieces + // TODO: this method should be variadic as well as accept an array of moves + widget.move = function () { + // no need to throw an error here; just do nothing + // TODO: this should return the current position + if (arguments.length === 0) return + + var useAnimation = true + + // collect the moves into an object + var moves = {} + for (var i = 0; i < arguments.length; i++) { + // any "false" to this function means no animations + if (arguments[i] === false) { + useAnimation = false + continue + } + + // skip invalid arguments + if (!validMove(arguments[i])) { + error(2826, 'Invalid move passed to the move method.', arguments[i]) + continue + } + + var tmp = arguments[i].split('-') + moves[tmp[0]] = tmp[1] + } + + // calculate position from moves + var newPos = calculatePositionFromMoves(currentPosition, moves) + + // update the board + widget.position(newPos, useAnimation) + + // return the new position object + return newPos + } + + widget.orientation = function (arg) { + // no arguments, return the current orientation + if (arguments.length === 0) { + return currentOrientation + } + + // set to white or black + if (arg === 'white' || arg === 'black') { + currentOrientation = arg + drawBoard() + return currentOrientation + } + + // flip orientation + if (arg === 'flip') { + currentOrientation = currentOrientation === 'white' ? 'black' : 'white' + drawBoard() + return currentOrientation + } + + error(5482, 'Invalid value passed to the orientation method.', arg) + } + + widget.position = function (position, useAnimation) { + // no arguments, return the current position + if (arguments.length === 0) { + return deepCopy(currentPosition) + } + + // get position as FEN + if (isString(position) && position.toLowerCase() === 'fen') { + return objToFen(currentPosition) + } + + // start position + if (isString(position) && position.toLowerCase() === 'start') { + position = deepCopy(START_POSITION) + } + + // convert FEN to position object + if (validFen(position)) { + position = fenToObj(position) + } + + // validate position object + if (!validPositionObject(position)) { + error(6482, 'Invalid value passed to the position method.', position) + return + } + + // default for useAnimations is true + if (useAnimation !== false) useAnimation = true + + if (useAnimation) { + // start the animations + var animations = calculateAnimations(currentPosition, position) + doAnimations(animations, currentPosition, position) + + // set the new position + setCurrentPosition(position) + } else { + // instant update + setCurrentPosition(position) + drawPositionInstant() + } + } + + widget.resize = function () { + // calulate the new square size + squareSize = calculateSquareSize() + + // set board width + $board.css('width', squareSize * 8 + 'px') + + // set drag piece size + $draggedPiece.css({ + height: squareSize, + width: squareSize + }) + + // spare pieces + if (config.sparePieces) { + $container + .find('.' + CSS.sparePieces) + .css('paddingLeft', squareSize + boardBorderSize + 'px') + } + + // redraw the board + drawBoard() + } + + // set the starting position + widget.start = function (useAnimation) { + widget.position('start', useAnimation) + } + + // ------------------------------------------------------------------------- + // Browser Events + // ------------------------------------------------------------------------- + + function stopDefault (evt) { + evt.preventDefault() + } + + function mousedownSquare (evt) { + // do nothing if we're not draggable + if (!config.draggable) return + + // do nothing if there is no piece on this square + var square = $(this).attr('data-square') + if (!validSquare(square)) return + if (!currentPosition.hasOwnProperty(square)) return + + beginDraggingPiece(square, currentPosition[square], evt.pageX, evt.pageY) + } + + function touchstartSquare (e) { + // do nothing if we're not draggable + if (!config.draggable) return + + // do nothing if there is no piece on this square + var square = $(this).attr('data-square') + if (!validSquare(square)) return + if (!currentPosition.hasOwnProperty(square)) return + + e = e.originalEvent + beginDraggingPiece( + square, + currentPosition[square], + e.changedTouches[0].pageX, + e.changedTouches[0].pageY + ) + } + + function mousedownSparePiece (evt) { + // do nothing if sparePieces is not enabled + if (!config.sparePieces) return + + var piece = $(this).attr('data-piece') + + beginDraggingPiece('spare', piece, evt.pageX, evt.pageY) + } + + function touchstartSparePiece (e) { + // do nothing if sparePieces is not enabled + if (!config.sparePieces) return + + var piece = $(this).attr('data-piece') + + e = e.originalEvent + beginDraggingPiece( + 'spare', + piece, + e.changedTouches[0].pageX, + e.changedTouches[0].pageY + ) + } + + function mousemoveWindow (evt) { + if (isDragging) { + updateDraggedPiece(evt.pageX, evt.pageY) + } + } + + var throttledMousemoveWindow = throttle(mousemoveWindow, config.dragThrottleRate) + + function touchmoveWindow (evt) { + // do nothing if we are not dragging a piece + if (!isDragging) return + + // prevent screen from scrolling + evt.preventDefault() + + updateDraggedPiece(evt.originalEvent.changedTouches[0].pageX, + evt.originalEvent.changedTouches[0].pageY) + } + + var throttledTouchmoveWindow = throttle(touchmoveWindow, config.dragThrottleRate) + + function mouseupWindow (evt) { + // do nothing if we are not dragging a piece + if (!isDragging) return + + // get the location + var location = isXYOnSquare(evt.pageX, evt.pageY) + + stopDraggedPiece(location) + } + + function touchendWindow (evt) { + // do nothing if we are not dragging a piece + if (!isDragging) return + + // get the location + var location = isXYOnSquare(evt.originalEvent.changedTouches[0].pageX, + evt.originalEvent.changedTouches[0].pageY) + + stopDraggedPiece(location) + } + + function mouseenterSquare (evt) { + // do not fire this event if we are dragging a piece + // NOTE: this should never happen, but it's a safeguard + if (isDragging) return + + // exit if they did not provide a onMouseoverSquare function + if (!isFunction(config.onMouseoverSquare)) return + + // get the square + var square = $(evt.currentTarget).attr('data-square') + + // NOTE: this should never happen; defensive + if (!validSquare(square)) return + + // get the piece on this square + var piece = false + if (currentPosition.hasOwnProperty(square)) { + piece = currentPosition[square] + } + + // execute their function + config.onMouseoverSquare(square, piece, deepCopy(currentPosition), currentOrientation) + } + + function mouseleaveSquare (evt) { + // do not fire this event if we are dragging a piece + // NOTE: this should never happen, but it's a safeguard + if (isDragging) return + + // exit if they did not provide an onMouseoutSquare function + if (!isFunction(config.onMouseoutSquare)) return + + // get the square + var square = $(evt.currentTarget).attr('data-square') + + // NOTE: this should never happen; defensive + if (!validSquare(square)) return + + // get the piece on this square + var piece = false + if (currentPosition.hasOwnProperty(square)) { + piece = currentPosition[square] + } + + // execute their function + config.onMouseoutSquare(square, piece, deepCopy(currentPosition), currentOrientation) + } + + // ------------------------------------------------------------------------- + // Initialization + // ------------------------------------------------------------------------- + + function addEvents () { + // prevent "image drag" + $('body').on('mousedown mousemove', '.' + CSS.piece, stopDefault) + + // mouse drag pieces + $board.on('mousedown', '.' + CSS.square, mousedownSquare) + $container.on('mousedown', '.' + CSS.sparePieces + ' .' + CSS.piece, mousedownSparePiece) + + // mouse enter / leave square + $board + .on('mouseenter', '.' + CSS.square, mouseenterSquare) + .on('mouseleave', '.' + CSS.square, mouseleaveSquare) + + // piece drag + var $window = $(window) + $window + .on('mousemove', throttledMousemoveWindow) + .on('mouseup', mouseupWindow) + + // touch drag pieces + if (isTouchDevice()) { + $board.on('touchstart', '.' + CSS.square, touchstartSquare) + $container.on('touchstart', '.' + CSS.sparePieces + ' .' + CSS.piece, touchstartSparePiece) + $window + .on('touchmove', throttledTouchmoveWindow) + .on('touchend', touchendWindow) + } + } + + function initDOM () { + // create unique IDs for all the elements we will create + createElIds() + + // build board and save it in memory + $container.html(buildContainerHTML(config.sparePieces)) + $board = $container.find('.' + CSS.board) + + if (config.sparePieces) { + $sparePiecesTop = $container.find('.' + CSS.sparePiecesTop) + $sparePiecesBottom = $container.find('.' + CSS.sparePiecesBottom) + } + + // create the drag piece + var draggedPieceId = uuid() + $('body').append(buildPieceHTML('wP', true, draggedPieceId)) + $draggedPiece = $('#' + draggedPieceId) + + // TODO: need to remove this dragged piece element if the board is no + // longer in the DOM + + // get the border size + boardBorderSize = parseInt($board.css('borderLeftWidth'), 10) + + // set the size and draw the board + widget.resize() + } + + // ------------------------------------------------------------------------- + // Initialization + // ------------------------------------------------------------------------- + + setInitialState() + initDOM() + addEvents() + + // return the widget object + return widget + } // end constructor + + // TODO: do module exports here + window['Chessboard'] = constructor + + // support legacy ChessBoard name + window['ChessBoard'] = window['Chessboard'] + + // expose util functions + window['Chessboard']['fenToObj'] = fenToObj + window['Chessboard']['objToFen'] = objToFen +})() // end anonymous wrapper diff --git a/examples/chess.wasm/chessboardjs-1.0.0/js/chessboard-1.0.0.min.js b/examples/chess.wasm/chessboardjs-1.0.0/js/chessboard-1.0.0.min.js new file mode 100644 index 00000000..73ea2870 --- /dev/null +++ b/examples/chess.wasm/chessboardjs-1.0.0/js/chessboard-1.0.0.min.js @@ -0,0 +1,2 @@ +/*! chessboard.js v1.0.0 | (c) 2019 Chris Oakman | MIT License chessboardjs.com/license */ +!function(){"use strict";var z=window.jQuery,F="abcdefgh".split(""),r=20,A="…",W="1.8.3",e="rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR",G=pe(e),n=200,t=200,o=60,a=30,i=100,H={};function V(e,r,n){function t(){o=0,a&&(a=!1,s())}var o=0,a=!1,i=[],s=function(){o=window.setTimeout(t,r),e.apply(n,i)};return function(e){i=arguments,o?a=!0:s()}}function Z(){return"xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx".replace(/x/g,function(e){return(16*Math.random()|0).toString(16)})}function _(e){return JSON.parse(JSON.stringify(e))}function s(e){var r=e.split(".");return{major:parseInt(r[0],10),minor:parseInt(r[1],10),patch:parseInt(r[2],10)}}function ee(e,r){for(var n in r)if(r.hasOwnProperty(n))for(var t="{"+n+"}",o=r[n];-1!==e.indexOf(t);)e=e.replace(t,o);return e}function re(e){return"string"==typeof e}function ne(e){return"function"==typeof e}function p(e){return"number"==typeof e&&isFinite(e)&&Math.floor(e)===e}function c(e){return"fast"===e||"slow"===e||!!p(e)&&0<=e}function te(e){if(!re(e))return!1;var r=e.split("-");return 2===r.length&&(oe(r[0])&&oe(r[1]))}function oe(e){return re(e)&&-1!==e.search(/^[a-h][1-8]$/)}function u(e){return re(e)&&-1!==e.search(/^[bw][KQRNBP]$/)}function ae(e){if(!re(e))return!1;var r=(e=function(e){return e.replace(/8/g,"11111111").replace(/7/g,"1111111").replace(/6/g,"111111").replace(/5/g,"11111").replace(/4/g,"1111").replace(/3/g,"111").replace(/2/g,"11")}(e=e.replace(/ .+$/,""))).split("/");if(8!==r.length)return!1;for(var n=0;n<8;n++)if(8!==r[n].length||-1!==r[n].search(/[^kqrnbpKQRNBP1]/))return!1;return!0}function ie(e){if(!z.isPlainObject(e))return!1;for(var r in e)if(e.hasOwnProperty(r)&&(!oe(r)||!u(e[r])))return!1;return!0}function se(){return typeof window.$&&z.fn&&z.fn.jquery&&function(e,r){e=s(e),r=s(r);var n=1e5*e.major*1e5+1e5*e.minor+e.patch;return 1e5*r.major*1e5+1e5*r.minor+r.patch<=n}(z.fn.jquery,W)}function pe(e){if(!ae(e))return!1;for(var r,n=(e=e.replace(/ .+$/,"")).split("/"),t={},o=8,a=0;a<8;a++){for(var i=n[a].split(""),s=0,p=0;p';for(var i=0;i<8;i++){var s=n[i]+t;r+='
',f.showNotation&&(("white"===e&&1===t||"black"===e&&8===t)&&(r+='
'+n[i]+"
"),0===i&&(r+='
'+t+"
")),r+="
",o="white"===o?"black":"white"}r+='
',o="white"===o?"black":"white","white"===e?t-=1:t+=1}return ee(r,H)}(p,f.showNotation)),T(),f.sparePieces&&("white"===p?(t.html(x("black")),o.html(x("white"))):(t.html(x("white")),o.html(x("black"))))}function k(e){var r=_(c),n=_(e);ce(r)!==ce(n)&&(ne(f.onChange)&&f.onChange(r,n),c=e)}function E(e,r){for(var n in w)if(w.hasOwnProperty(n)){var t=w[n];if(e>=t.left&&e=t.top&&r (http://chrisoakman.com/)", + "name": "@chrisoakman/chessboardjs", + "description": "JavaScript chessboard widget", + "homepage": "https://chessboardjs.com", + "license": "MIT", + "version": "1.0.0", + "repository": { + "type": "git", + "url": "git://github.com/oakmac/chessboardjs.git" + }, + "files": ["dist/"], + "dependencies": { + "jquery": ">=3.4.1" + }, + "devDependencies": { + "csso": "3.5.1", + "fs-plus": "3.1.1", + "kidif": "1.1.0", + "mustache": "2.3.0", + "standard": "10.0.2", + "uglify-js": "3.6.0" + }, + "scripts": { + "build": "standard lib/chessboard.js && node scripts/build.js", + "standard": "standard --fix lib/*.js website/js/*.js", + "website": "node scripts/website.js" + } +} diff --git a/examples/chess.wasm/index-tmpl.html b/examples/chess.wasm/index-tmpl.html index e16d7908..6cb16fd0 100644 --- a/examples/chess.wasm/index-tmpl.html +++ b/examples/chess.wasm/index-tmpl.html @@ -24,6 +24,7 @@ overflow-x: scroll; } +
@@ -71,6 +72,14 @@
[The recognized voice commands will be displayed here]
+

+
+ + + +
Debug output: @@ -101,7 +110,7 @@ - + - + diff --git a/examples/chess.wasm/jquery-3.7.1.min.js b/examples/chess.wasm/jquery-3.7.1.min.js new file mode 100644 index 00000000..7f37b5d9 --- /dev/null +++ b/examples/chess.wasm/jquery-3.7.1.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.7.1 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(ie,e){"use strict";var oe=[],r=Object.getPrototypeOf,ae=oe.slice,g=oe.flat?function(e){return oe.flat.call(e)}:function(e){return oe.concat.apply([],e)},s=oe.push,se=oe.indexOf,n={},i=n.toString,ue=n.hasOwnProperty,o=ue.toString,a=o.call(Object),le={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},C=ie.document,u={type:!0,src:!0,nonce:!0,noModule:!0};function m(e,t,n){var r,i,o=(n=n||C).createElement("script");if(o.text=e,t)for(r in u)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e}var t="3.7.1",l=/HTML$/i,ce=function(e,t){return new ce.fn.init(e,t)};function c(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+ge+")"+ge+"*"),x=new RegExp(ge+"|>"),j=new RegExp(g),A=new RegExp("^"+t+"$"),D={ID:new RegExp("^#("+t+")"),CLASS:new RegExp("^\\.("+t+")"),TAG:new RegExp("^("+t+"|[*])"),ATTR:new RegExp("^"+p),PSEUDO:new RegExp("^"+g),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ge+"*(even|odd|(([+-]|)(\\d*)n|)"+ge+"*(?:([+-]|)"+ge+"*(\\d+)|))"+ge+"*\\)|)","i"),bool:new RegExp("^(?:"+f+")$","i"),needsContext:new RegExp("^"+ge+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ge+"*((?:-\\d)?\\d*)"+ge+"*\\)|)(?=[^-]|$)","i")},N=/^(?:input|select|textarea|button)$/i,q=/^h\d$/i,L=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,H=/[+~]/,O=new RegExp("\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\([^\\r\\n\\f])","g"),P=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},M=function(){V()},R=J(function(e){return!0===e.disabled&&fe(e,"fieldset")},{dir:"parentNode",next:"legend"});try{k.apply(oe=ae.call(ye.childNodes),ye.childNodes),oe[ye.childNodes.length].nodeType}catch(e){k={apply:function(e,t){me.apply(e,ae.call(t))},call:function(e){me.apply(e,ae.call(arguments,1))}}}function I(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(V(e),e=e||T,C)){if(11!==p&&(u=L.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return k.call(n,a),n}else if(f&&(a=f.getElementById(i))&&I.contains(e,a)&&a.id===i)return k.call(n,a),n}else{if(u[2])return k.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&e.getElementsByClassName)return k.apply(n,e.getElementsByClassName(i)),n}if(!(h[t+" "]||d&&d.test(t))){if(c=t,f=e,1===p&&(x.test(t)||m.test(t))){(f=H.test(t)&&U(e.parentNode)||e)==e&&le.scope||((s=e.getAttribute("id"))?s=ce.escapeSelector(s):e.setAttribute("id",s=S)),o=(l=Y(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+Q(l[o]);c=l.join(",")}try{return k.apply(n,f.querySelectorAll(c)),n}catch(e){h(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return re(t.replace(ve,"$1"),e,n,r)}function W(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function F(e){return e[S]=!0,e}function $(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function B(t){return function(e){return fe(e,"input")&&e.type===t}}function _(t){return function(e){return(fe(e,"input")||fe(e,"button"))&&e.type===t}}function z(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&R(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function X(a){return F(function(o){return o=+o,F(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function U(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function V(e){var t,n=e?e.ownerDocument||e:ye;return n!=T&&9===n.nodeType&&n.documentElement&&(r=(T=n).documentElement,C=!ce.isXMLDoc(T),i=r.matches||r.webkitMatchesSelector||r.msMatchesSelector,r.msMatchesSelector&&ye!=T&&(t=T.defaultView)&&t.top!==t&&t.addEventListener("unload",M),le.getById=$(function(e){return r.appendChild(e).id=ce.expando,!T.getElementsByName||!T.getElementsByName(ce.expando).length}),le.disconnectedMatch=$(function(e){return i.call(e,"*")}),le.scope=$(function(){return T.querySelectorAll(":scope")}),le.cssHas=$(function(){try{return T.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),le.getById?(b.filter.ID=function(e){var t=e.replace(O,P);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(O,P);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},b.find.CLASS=function(e,t){if("undefined"!=typeof t.getElementsByClassName&&C)return t.getElementsByClassName(e)},d=[],$(function(e){var t;r.appendChild(e).innerHTML="",e.querySelectorAll("[selected]").length||d.push("\\["+ge+"*(?:value|"+f+")"),e.querySelectorAll("[id~="+S+"-]").length||d.push("~="),e.querySelectorAll("a#"+S+"+*").length||d.push(".#.+[+~]"),e.querySelectorAll(":checked").length||d.push(":checked"),(t=T.createElement("input")).setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),r.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&d.push(":enabled",":disabled"),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||d.push("\\["+ge+"*name"+ge+"*="+ge+"*(?:''|\"\")")}),le.cssHas||d.push(":has"),d=d.length&&new RegExp(d.join("|")),l=function(e,t){if(e===t)return a=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!le.sortDetached&&t.compareDocumentPosition(e)===n?e===T||e.ownerDocument==ye&&I.contains(ye,e)?-1:t===T||t.ownerDocument==ye&&I.contains(ye,t)?1:o?se.call(o,e)-se.call(o,t):0:4&n?-1:1)}),T}for(e in I.matches=function(e,t){return I(e,null,null,t)},I.matchesSelector=function(e,t){if(V(e),C&&!h[t+" "]&&(!d||!d.test(t)))try{var n=i.call(e,t);if(n||le.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){h(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(O,P),e[3]=(e[3]||e[4]||e[5]||"").replace(O,P),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||I.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&I.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return D.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&j.test(n)&&(t=Y(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(O,P).toLowerCase();return"*"===e?function(){return!0}:function(e){return fe(e,t)}},CLASS:function(e){var t=s[e+" "];return t||(t=new RegExp("(^|"+ge+")"+e+"("+ge+"|$)"))&&s(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=I.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function T(e,n,r){return v(n)?ce.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?ce.grep(e,function(e){return e===n!==r}):"string"!=typeof n?ce.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(ce.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||k,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:S.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof ce?t[0]:t,ce.merge(this,ce.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:C,!0)),w.test(r[1])&&ce.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=C.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(ce):ce.makeArray(e,this)}).prototype=ce.fn,k=ce(C);var E=/^(?:parents|prev(?:Until|All))/,j={children:!0,contents:!0,next:!0,prev:!0};function A(e,t){while((e=e[t])&&1!==e.nodeType);return e}ce.fn.extend({has:function(e){var t=ce(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,Ce=/^$|^module$|\/(?:java|ecma)script/i;xe=C.createDocumentFragment().appendChild(C.createElement("div")),(be=C.createElement("input")).setAttribute("type","radio"),be.setAttribute("checked","checked"),be.setAttribute("name","t"),xe.appendChild(be),le.checkClone=xe.cloneNode(!0).cloneNode(!0).lastChild.checked,xe.innerHTML="",le.noCloneChecked=!!xe.cloneNode(!0).lastChild.defaultValue,xe.innerHTML="",le.option=!!xe.lastChild;var ke={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function Se(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&fe(e,t)?ce.merge([e],n):n}function Ee(e,t){for(var n=0,r=e.length;n",""]);var je=/<|&#?\w+;/;function Ae(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function Re(e,t){return fe(e,"table")&&fe(11!==t.nodeType?t:t.firstChild,"tr")&&ce(e).children("tbody")[0]||e}function Ie(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function We(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Fe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(_.hasData(e)&&(s=_.get(e).events))for(i in _.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),C.head.appendChild(r[0])},abort:function(){i&&i()}}});var Jt,Kt=[],Zt=/(=)\?(?=&|$)|\?\?/;ce.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Kt.pop()||ce.expando+"_"+jt.guid++;return this[e]=!0,e}}),ce.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Zt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Zt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=v(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Zt,"$1"+r):!1!==e.jsonp&&(e.url+=(At.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||ce.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=ie[r],ie[r]=function(){o=arguments},n.always(function(){void 0===i?ce(ie).removeProp(r):ie[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Kt.push(r)),o&&v(i)&&i(o[0]),o=i=void 0}),"script"}),le.createHTMLDocument=((Jt=C.implementation.createHTMLDocument("").body).innerHTML="
",2===Jt.childNodes.length),ce.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(le.createHTMLDocument?((r=(t=C.implementation.createHTMLDocument("")).createElement("base")).href=C.location.href,t.head.appendChild(r)):t=C),o=!n&&[],(i=w.exec(e))?[t.createElement(i[1])]:(i=Ae([e],t,o),o&&o.length&&ce(o).remove(),ce.merge([],i.childNodes)));var r,i,o},ce.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(ce.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},ce.expr.pseudos.animated=function(t){return ce.grep(ce.timers,function(e){return t===e.elem}).length},ce.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=ce.css(e,"position"),c=ce(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=ce.css(e,"top"),u=ce.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),v(t)&&(t=t.call(e,n,ce.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},ce.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ce.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===ce.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===ce.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=ce(e).offset()).top+=ce.css(e,"borderTopWidth",!0),i.left+=ce.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-ce.css(r,"marginTop",!0),left:t.left-i.left-ce.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===ce.css(e,"position"))e=e.offsetParent;return e||J})}}),ce.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;ce.fn[t]=function(e){return M(this,function(e,t,n){var r;if(y(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),ce.each(["top","left"],function(e,n){ce.cssHooks[n]=Ye(le.pixelPosition,function(e,t){if(t)return t=Ge(e,n),_e.test(t)?ce(e).position()[n]+"px":t})}),ce.each({Height:"height",Width:"width"},function(a,s){ce.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){ce.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return M(this,function(e,t,n){var r;return y(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?ce.css(e,t,i):ce.style(e,t,n,i)},s,n?e:void 0,n)}})}),ce.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){ce.fn[t]=function(e){return this.on(t,e)}}),ce.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.on("mouseenter",e).on("mouseleave",t||e)}}),ce.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){ce.fn[n]=function(e,t){return 0