├── i ├── about │ ├── box.png │ ├── dots.png │ ├── info.png │ ├── pass.png │ ├── top.png │ ├── wild.png │ ├── bottom.png │ ├── corner.png │ ├── empty.png │ ├── start.png │ ├── influence.png │ └── white_to_play.png ├── dot_clear.gif ├── ghost-black.png ├── ghost-white.png ├── in_progress.gif ├── simple-black.png ├── simple-white.png ├── tools │ ├── help_20.png │ ├── help_30.png │ ├── home_20.png │ ├── home_30.png │ ├── info_20.png │ ├── info_30.png │ ├── update_20.png │ ├── update_30.png │ ├── hey-text-green.png │ ├── subscribe_20.png │ ├── subscribe_30.png │ └── empty-text-green.png ├── ajax-loader-black.gif ├── board │ └── temporary │ │ ├── tile0.png │ │ ├── tile0c.png │ │ ├── tile0e.png │ │ ├── tile0n.png │ │ ├── tile0s.png │ │ ├── tile0w.png │ │ ├── tile1.png │ │ ├── tile1d.png │ │ ├── tile1e.png │ │ ├── tile1l.png │ │ ├── tile1n.png │ │ ├── tile1s.png │ │ ├── tile1w.png │ │ ├── tile2.png │ │ ├── tile2d.png │ │ ├── tile2e.png │ │ ├── tile2l.png │ │ ├── tile2n.png │ │ ├── tile2s.png │ │ ├── tile2w.png │ │ ├── tile0ne.png │ │ ├── tile0nw.png │ │ ├── tile0se.png │ │ ├── tile0sw.png │ │ ├── tile1ed.png │ │ ├── tile1el.png │ │ ├── tile1nd.png │ │ ├── tile1ne.png │ │ ├── tile1ned.png │ │ ├── tile1nel.png │ │ ├── tile1nl.png │ │ ├── tile1nw.png │ │ ├── tile1nwd.png │ │ ├── tile1nwl.png │ │ ├── tile1sd.png │ │ ├── tile1se.png │ │ ├── tile1sed.png │ │ ├── tile1sel.png │ │ ├── tile1sl.png │ │ ├── tile1sw.png │ │ ├── tile1swd.png │ │ ├── tile1swl.png │ │ ├── tile1wd.png │ │ ├── tile1wl.png │ │ ├── tile2ed.png │ │ ├── tile2el.png │ │ ├── tile2nd.png │ │ ├── tile2ne.png │ │ ├── tile2ned.png │ │ ├── tile2nel.png │ │ ├── tile2nl.png │ │ ├── tile2nw.png │ │ ├── tile2nwd.png │ │ ├── tile2nwl.png │ │ ├── tile2sd.png │ │ ├── tile2se.png │ │ ├── tile2sed.png │ │ ├── tile2sel.png │ │ ├── tile2sl.png │ │ ├── tile2sw.png │ │ ├── tile2swd.png │ │ ├── tile2swl.png │ │ ├── tile2wd.png │ │ └── tile2wl.png └── themes │ └── jqt │ └── img │ ├── button.png │ ├── chevron.png │ ├── loading.gif │ ├── on_off.png │ ├── rowhead.png │ ├── toggle.png │ ├── toolbar.png │ ├── grayButton.png │ ├── toggleOn.png │ ├── back_button.png │ ├── whiteButton.png │ ├── button_clicked.png │ ├── chevron_circle.png │ └── back_button_clicked.png ├── .gitignore ├── .gitmodules ├── j ├── jquery.combinators.js ├── load.images.js ├── jquery.timers-1.2.js ├── history.js ├── start.js ├── dragscrollable.js ├── to-function.js ├── md5.js ├── ui.js ├── go.js └── igesture.jquery.mobile_safari.js ├── c ├── application.css ├── sass │ ├── application.sass │ ├── board.iphone.sass │ ├── jqtouch.ipad.customized.sass │ └── board.ipad.sass ├── jqtouch.min.css ├── jqtouch.css └── jqtouch.ipad.customized.css ├── cache.manifest ├── haml └── index.html.haml ├── index.html └── readme.md /i/about/box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/about/box.png -------------------------------------------------------------------------------- /i/about/dots.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/about/dots.png -------------------------------------------------------------------------------- /i/about/info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/about/info.png -------------------------------------------------------------------------------- /i/about/pass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/about/pass.png -------------------------------------------------------------------------------- /i/about/top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/about/top.png -------------------------------------------------------------------------------- /i/about/wild.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/about/wild.png -------------------------------------------------------------------------------- /i/dot_clear.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/dot_clear.gif -------------------------------------------------------------------------------- /i/about/bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/about/bottom.png -------------------------------------------------------------------------------- /i/about/corner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/about/corner.png -------------------------------------------------------------------------------- /i/about/empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/about/empty.png -------------------------------------------------------------------------------- /i/about/start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/about/start.png -------------------------------------------------------------------------------- /i/ghost-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/ghost-black.png -------------------------------------------------------------------------------- /i/ghost-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/ghost-white.png -------------------------------------------------------------------------------- /i/in_progress.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/in_progress.gif -------------------------------------------------------------------------------- /i/simple-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/simple-black.png -------------------------------------------------------------------------------- /i/simple-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/simple-white.png -------------------------------------------------------------------------------- /i/about/influence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/about/influence.png -------------------------------------------------------------------------------- /i/tools/help_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/tools/help_20.png -------------------------------------------------------------------------------- /i/tools/help_30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/tools/help_30.png -------------------------------------------------------------------------------- /i/tools/home_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/tools/home_20.png -------------------------------------------------------------------------------- /i/tools/home_30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/tools/home_30.png -------------------------------------------------------------------------------- /i/tools/info_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/tools/info_20.png -------------------------------------------------------------------------------- /i/tools/info_30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/tools/info_30.png -------------------------------------------------------------------------------- /i/tools/update_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/tools/update_20.png -------------------------------------------------------------------------------- /i/tools/update_30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/tools/update_30.png -------------------------------------------------------------------------------- /i/ajax-loader-black.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/ajax-loader-black.gif -------------------------------------------------------------------------------- /i/about/white_to_play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/about/white_to_play.png -------------------------------------------------------------------------------- /i/tools/hey-text-green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/tools/hey-text-green.png -------------------------------------------------------------------------------- /i/tools/subscribe_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/tools/subscribe_20.png -------------------------------------------------------------------------------- /i/tools/subscribe_30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/tools/subscribe_30.png -------------------------------------------------------------------------------- /i/board/temporary/tile0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile0.png -------------------------------------------------------------------------------- /i/board/temporary/tile0c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile0c.png -------------------------------------------------------------------------------- /i/board/temporary/tile0e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile0e.png -------------------------------------------------------------------------------- /i/board/temporary/tile0n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile0n.png -------------------------------------------------------------------------------- /i/board/temporary/tile0s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile0s.png -------------------------------------------------------------------------------- /i/board/temporary/tile0w.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile0w.png -------------------------------------------------------------------------------- /i/board/temporary/tile1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile1.png -------------------------------------------------------------------------------- /i/board/temporary/tile1d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile1d.png -------------------------------------------------------------------------------- /i/board/temporary/tile1e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile1e.png -------------------------------------------------------------------------------- /i/board/temporary/tile1l.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile1l.png -------------------------------------------------------------------------------- /i/board/temporary/tile1n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile1n.png -------------------------------------------------------------------------------- /i/board/temporary/tile1s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile1s.png -------------------------------------------------------------------------------- /i/board/temporary/tile1w.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile1w.png -------------------------------------------------------------------------------- /i/board/temporary/tile2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile2.png -------------------------------------------------------------------------------- /i/board/temporary/tile2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile2d.png -------------------------------------------------------------------------------- /i/board/temporary/tile2e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile2e.png -------------------------------------------------------------------------------- /i/board/temporary/tile2l.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile2l.png -------------------------------------------------------------------------------- /i/board/temporary/tile2n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile2n.png -------------------------------------------------------------------------------- /i/board/temporary/tile2s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile2s.png -------------------------------------------------------------------------------- /i/board/temporary/tile2w.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile2w.png -------------------------------------------------------------------------------- /i/themes/jqt/img/button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/themes/jqt/img/button.png -------------------------------------------------------------------------------- /i/themes/jqt/img/chevron.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/themes/jqt/img/chevron.png -------------------------------------------------------------------------------- /i/themes/jqt/img/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/themes/jqt/img/loading.gif -------------------------------------------------------------------------------- /i/themes/jqt/img/on_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/themes/jqt/img/on_off.png -------------------------------------------------------------------------------- /i/themes/jqt/img/rowhead.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/themes/jqt/img/rowhead.png -------------------------------------------------------------------------------- /i/themes/jqt/img/toggle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/themes/jqt/img/toggle.png -------------------------------------------------------------------------------- /i/themes/jqt/img/toolbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/themes/jqt/img/toolbar.png -------------------------------------------------------------------------------- /i/tools/empty-text-green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/tools/empty-text-green.png -------------------------------------------------------------------------------- /i/board/temporary/tile0ne.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile0ne.png -------------------------------------------------------------------------------- /i/board/temporary/tile0nw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile0nw.png -------------------------------------------------------------------------------- /i/board/temporary/tile0se.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile0se.png -------------------------------------------------------------------------------- /i/board/temporary/tile0sw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile0sw.png -------------------------------------------------------------------------------- /i/board/temporary/tile1ed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile1ed.png -------------------------------------------------------------------------------- /i/board/temporary/tile1el.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile1el.png -------------------------------------------------------------------------------- /i/board/temporary/tile1nd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile1nd.png -------------------------------------------------------------------------------- /i/board/temporary/tile1ne.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile1ne.png -------------------------------------------------------------------------------- /i/board/temporary/tile1ned.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile1ned.png -------------------------------------------------------------------------------- /i/board/temporary/tile1nel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile1nel.png -------------------------------------------------------------------------------- /i/board/temporary/tile1nl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile1nl.png -------------------------------------------------------------------------------- /i/board/temporary/tile1nw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile1nw.png -------------------------------------------------------------------------------- /i/board/temporary/tile1nwd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile1nwd.png -------------------------------------------------------------------------------- /i/board/temporary/tile1nwl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile1nwl.png -------------------------------------------------------------------------------- /i/board/temporary/tile1sd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile1sd.png -------------------------------------------------------------------------------- /i/board/temporary/tile1se.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile1se.png -------------------------------------------------------------------------------- /i/board/temporary/tile1sed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile1sed.png -------------------------------------------------------------------------------- /i/board/temporary/tile1sel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile1sel.png -------------------------------------------------------------------------------- /i/board/temporary/tile1sl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile1sl.png -------------------------------------------------------------------------------- /i/board/temporary/tile1sw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile1sw.png -------------------------------------------------------------------------------- /i/board/temporary/tile1swd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile1swd.png -------------------------------------------------------------------------------- /i/board/temporary/tile1swl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile1swl.png -------------------------------------------------------------------------------- /i/board/temporary/tile1wd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile1wd.png -------------------------------------------------------------------------------- /i/board/temporary/tile1wl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile1wl.png -------------------------------------------------------------------------------- /i/board/temporary/tile2ed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile2ed.png -------------------------------------------------------------------------------- /i/board/temporary/tile2el.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile2el.png -------------------------------------------------------------------------------- /i/board/temporary/tile2nd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile2nd.png -------------------------------------------------------------------------------- /i/board/temporary/tile2ne.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile2ne.png -------------------------------------------------------------------------------- /i/board/temporary/tile2ned.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile2ned.png -------------------------------------------------------------------------------- /i/board/temporary/tile2nel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile2nel.png -------------------------------------------------------------------------------- /i/board/temporary/tile2nl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile2nl.png -------------------------------------------------------------------------------- /i/board/temporary/tile2nw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile2nw.png -------------------------------------------------------------------------------- /i/board/temporary/tile2nwd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile2nwd.png -------------------------------------------------------------------------------- /i/board/temporary/tile2nwl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile2nwl.png -------------------------------------------------------------------------------- /i/board/temporary/tile2sd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile2sd.png -------------------------------------------------------------------------------- /i/board/temporary/tile2se.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile2se.png -------------------------------------------------------------------------------- /i/board/temporary/tile2sed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile2sed.png -------------------------------------------------------------------------------- /i/board/temporary/tile2sel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile2sel.png -------------------------------------------------------------------------------- /i/board/temporary/tile2sl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile2sl.png -------------------------------------------------------------------------------- /i/board/temporary/tile2sw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile2sw.png -------------------------------------------------------------------------------- /i/board/temporary/tile2swd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile2swd.png -------------------------------------------------------------------------------- /i/board/temporary/tile2swl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile2swl.png -------------------------------------------------------------------------------- /i/board/temporary/tile2wd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile2wd.png -------------------------------------------------------------------------------- /i/board/temporary/tile2wl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/board/temporary/tile2wl.png -------------------------------------------------------------------------------- /i/themes/jqt/img/grayButton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/themes/jqt/img/grayButton.png -------------------------------------------------------------------------------- /i/themes/jqt/img/toggleOn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/themes/jqt/img/toggleOn.png -------------------------------------------------------------------------------- /i/themes/jqt/img/back_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/themes/jqt/img/back_button.png -------------------------------------------------------------------------------- /i/themes/jqt/img/whiteButton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/themes/jqt/img/whiteButton.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | log/*.log 2 | db/*.sqlite3 3 | tmp/**/* 4 | doc/api 5 | doc/app 6 | doc/plugins 7 | config/environments/development.rb 8 | -------------------------------------------------------------------------------- /i/themes/jqt/img/button_clicked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/themes/jqt/img/button_clicked.png -------------------------------------------------------------------------------- /i/themes/jqt/img/chevron_circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/themes/jqt/img/chevron_circle.png -------------------------------------------------------------------------------- /i/themes/jqt/img/back_button_clicked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raganwald/wood_and_stones/HEAD/i/themes/jqt/img/back_button_clicked.png -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "./vendor/plugins/rewrite_rails"] 2 | path = ./vendor/plugins/rewrite_rails 3 | url = git://github.com/raganwald/rewrite_rails.git 4 | [submodule "vendor/plugins/shoulda"] 5 | path = vendor/plugins/shoulda 6 | url = git://github.com/thoughtbot/shoulda.git 7 | [submodule "vendor/plugins/haml"] 8 | path = vendor/plugins/haml 9 | url = git://github.com/nex3/haml.git 10 | [submodule "vendor/plugins/state_machine"] 11 | path = vendor/plugins/state_machine 12 | url = git://github.com/pluginaweek/state_machine.git 13 | [submodule "vendor/plugins/delayed_job"] 14 | path = vendor/plugins/delayed_job 15 | url = git://github.com/tobi/delayed_job.git 16 | [submodule "vendor/plugins/mocha"] 17 | path = vendor/plugins/mocha 18 | url = git://github.com/floehopper/mocha.git 19 | -------------------------------------------------------------------------------- /j/jquery.combinators.js: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License 3 | 4 | Copyright (c) 2010 Reginald Braithwaite http://reginald.braythwayt.com 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | 26 | ;(function ($) { 27 | $.fn.K = function (fn) { 28 | fn(this); 29 | return this; 30 | }; 31 | $.fn.T = function (fn) { 32 | return fn(this); 33 | }; 34 | })(jQuery); -------------------------------------------------------------------------------- /c/application.css: -------------------------------------------------------------------------------- 1 | .invisible { 2 | visibility: hidden; } 3 | 4 | .slideback.in { 5 | -webkit-animation-name: slideinfromleft; } 6 | 7 | .slideback.out { 8 | -webkit-animation-name: slideouttoright; } 9 | 10 | .slideback.in.reverse { 11 | -webkit-animation-name: slideouttoright; } 12 | 13 | .slideback.out.reverse { 14 | -webkit-animation-name: slideinfromleft; } 15 | 16 | .in_progress:before { 17 | content: url(../i/in_progress.gif); } 18 | 19 | .profile .foot .toolbar { 20 | -webkit-transform: rotate(180deg); 21 | -moz-transform: rotate(180deg); } 22 | 23 | .landscape .foot .toolbar { 24 | display: none; } 25 | 26 | .head.triangle-right { 27 | left: 25%; 28 | margin-left: -12.5%; 29 | width: 25%; 30 | margin-bottom: 10px; 31 | z-index: 1; } 32 | 33 | .foot.triangle-right { 34 | left: 75%; 35 | margin-left: -12.5%; 36 | width: 25%; 37 | z-index: 1; 38 | margin-top: 10px; } 39 | 40 | .new_game ul li { 41 | position: relative !important; } 42 | .new_game ul li .label { 43 | position: absolute; 44 | left: 10px; } 45 | .new_game .email { 46 | height: 40px !important; } 47 | .new_game .size { 48 | padding-left: 70px !important; } 49 | .new_game .you_play { 50 | padding-left: 100px !important; } 51 | .new_game .you_play .toggle { 52 | display: block; 53 | position: relative; 54 | float: right; } 55 | .new_game .you_play .toggle input[type="checkbox"] { 56 | background: white url(../i/black_white.png) 0 0 no-repeat !important; } 57 | .new_game .setup { 58 | padding-left: 80px !important; } 59 | .new_game .rules { 60 | padding-left: 80px !important; } 61 | 62 | .move .toolbar .button img { 63 | margin-top: 5px; } 64 | 65 | .progress .ui-dialog-titlebar { 66 | display: none; } 67 | 68 | .board .head .captured, .board .foot .captured { 69 | height: 30px; 70 | width: 30px; 71 | line-height: 30px; 72 | text-align: center; } 73 | .board .head .captured:empty, .board .foot .captured:empty { 74 | background-color: transparent; } 75 | .board .head .captured.black:not(:empty), .board .foot .captured.black:not(:empty) { 76 | color: white; 77 | background: url(../i/ghost-black.png); } 78 | .board .head .captured.white:not(:empty), .board .foot .captured.white:not(:empty) { 79 | color: black; 80 | background: url(../i/ghost-white.png); } 81 | -------------------------------------------------------------------------------- /c/sass/application.sass: -------------------------------------------------------------------------------- 1 | $black: #000 2 | $white: #fff 3 | $lightgrey: #333 4 | 5 | .invisible 6 | :visibility hidden 7 | 8 | .slideback.in 9 | -webkit-animation-name: slideinfromleft 10 | .slideback.out 11 | -webkit-animation-name: slideouttoright 12 | .slideback.in.reverse 13 | -webkit-animation-name: slideouttoright 14 | .slideback.out.reverse 15 | -webkit-animation-name: slideinfromleft 16 | 17 | .in_progress:before 18 | content: url(../i/in_progress.gif) 19 | 20 | .profile 21 | .foot 22 | .toolbar 23 | -webkit-transform: rotate(180deg) 24 | -moz-transform: rotate(180deg) 25 | 26 | .landscape 27 | .foot 28 | .toolbar 29 | display: none 30 | 31 | 32 | $messagewidth: 200px 33 | $bubblefrom: #f3961c 34 | $bubbleto: #f9d835 35 | 36 | $separation_between_board_and_bubble: 10px 37 | 38 | .head.triangle-right 39 | left: 25% 40 | margin-left: -12.5% 41 | width: 25% 42 | margin-bottom: $separation_between_board_and_bubble 43 | z-index: 1 44 | 45 | .foot.triangle-right 46 | left: 75% 47 | margin-left: -12.5% 48 | width: 25% 49 | z-index: 1 50 | margin-top: $separation_between_board_and_bubble 51 | 52 | .new_game 53 | ul 54 | li 55 | :position relative !important 56 | .label 57 | :position absolute 58 | :left 10px 59 | .email 60 | :height 40px !important 61 | .size 62 | :padding-left 70px !important 63 | .you_play 64 | :padding-left 100px !important 65 | .toggle 66 | :display block 67 | :position relative 68 | :float right 69 | input[type="checkbox"] 70 | :background #fff url(../i/black_white.png) 0 0 no-repeat !important 71 | .setup 72 | :padding-left 80px !important 73 | .rules 74 | :padding-left 80px !important 75 | 76 | .move 77 | .toolbar 78 | .button 79 | img 80 | :margin 81 | :top 5px 82 | 83 | .progress 84 | .ui-dialog-titlebar 85 | :display none 86 | 87 | .board 88 | .head,.foot 89 | .captured 90 | height: 30px 91 | width: 30px 92 | line-height: 30px 93 | text-align: center 94 | &:empty 95 | background-color: transparent 96 | &.black:not(:empty) 97 | color: white 98 | background: url(../i/ghost-black.png) 99 | &.white:not(:empty) 100 | color: black 101 | background: url(../i/ghost-white.png) -------------------------------------------------------------------------------- /j/load.images.js: -------------------------------------------------------------------------------- 1 | // (c) 2010 Reg Braithwaite. All rights to the entirety of the program and its parts are reserved with 2 | // the exception of specific files otherwise licensed. Other licenses apply only to the files where 3 | // they appear. 4 | 5 | ;(function ($, undefined) { 6 | $.each( [ '../i/board/temporary/tile1nw.png', '../i/board/temporary/tile1nwd.png', '../i/board/temporary/tile1nwd.png', 7 | '../i/board/temporary/tile2nw.png', '../i/board/temporary/tile2nwd.png', '../i/board/temporary/tile2nwd.png', 8 | '../i/board/temporary/tile0nw.png', '../i/board/temporary/tile1n.png', '../i/board/temporary/tile1nd.png', 9 | '../i/board/temporary/tile1nd.png', '../i/board/temporary/tile2n.png', '../i/board/temporary/tile2nd.png', 10 | '../i/board/temporary/tile2nd.png', '../i/board/temporary/tile0n.png', '../i/board/temporary/tile1ne.png', 11 | '../i/board/temporary/tile1ned.png', '../i/board/temporary/tile1ned.png', '../i/board/temporary/tile2ne.png', 12 | '../i/board/temporary/tile2ned.png', '../i/board/temporary/tile2ned.png', '../i/board/temporary/tile0ne.png', 13 | '../i/board/temporary/tile1w.png', '../i/board/temporary/tile1wd.png', '../i/board/temporary/tile1wd.png', 14 | '../i/board/temporary/tile2w.png', '../i/board/temporary/tile2wd.png', '../i/board/temporary/tile2wd.png', 15 | '../i/board/temporary/tile0w.png', '../i/board/temporary/tile1.png', '../i/board/temporary/tile1d.png', 16 | '../i/board/temporary/tile1d.png', '../i/board/temporary/tile2.png', '../i/board/temporary/tile2d.png', 17 | '../i/board/temporary/tile2d.png', '../i/board/temporary/tile1e.png', '../i/board/temporary/tile1ed.png', 18 | '../i/board/temporary/tile1ed.png', '../i/board/temporary/tile2e.png', '../i/board/temporary/tile2ed.png', 19 | '../i/board/temporary/tile2ed.png', '../i/board/temporary/tile0e.png', '../i/board/temporary/tile1sw.png', 20 | '../i/board/temporary/tile1swd.png', '../i/board/temporary/tile1swd.png', '../i/board/temporary/tile2sw.png', 21 | '../i/board/temporary/tile2swd.png', '../i/board/temporary/tile2swd.png', '../i/board/temporary/tile0sw.png', 22 | '../i/board/temporary/tile1s.png', '../i/board/temporary/tile1sd.png', '../i/board/temporary/tile1sd.png', 23 | '../i/board/temporary/tile2s.png', '../i/board/temporary/tile2sd.png', '../i/board/temporary/tile2sd.png', 24 | '../i/board/temporary/tile0s.png', '../i/board/temporary/tile1se.png', '../i/board/temporary/tile1sed.png', 25 | '../i/board/temporary/tile1sed.png', '../i/board/temporary/tile2se.png', '../i/board/temporary/tile2sed.png', 26 | '../i/board/temporary/tile2sed.png', '../i/board/temporary/tile0se.png', '../i/board/temporary/tile1.png', 27 | '../i/board/temporary/tile1d.png', '../i/board/temporary/tile1d.png', '../i/board/temporary/tile2.png', 28 | '../i/board/temporary/tile2d.png', '../i/board/temporary/tile2d.png', '../i/board/temporary/tile0c.png', 29 | '../i/board/temporary/tile0c.png', '../i/board/temporary/tile0c.png', '../i/board/temporary/tile0.png', 30 | '../i/board/temporary/tile0.png' ], function (path) { 31 | (new Image(30,30)).src = path; 32 | }); 33 | })(jQuery); -------------------------------------------------------------------------------- /cache.manifest: -------------------------------------------------------------------------------- 1 | CACHE MANIFEST 2 | # This is a comment. 3 | # Cache manifest version 5 4 | # If you change the version number in this comment, 5 | # the cache manifest is no longer byte-for-byte 6 | # identical. 7 | # 8 | # See: http://developer.apple.com/safari/library/documentation/iPhone/Conceptual/SafariJSDatabaseGuide/OfflineApplicationCache/OfflineApplicationCache.html 9 | 10 | NETWORK: 11 | 12 | CACHE: 13 | 14 | # board images 15 | 16 | i/board/temporary/tile1nw.png 17 | i/board/temporary/tile1nwd.png 18 | i/board/temporary/tile1nwd.png 19 | i/board/temporary/tile2nw.png 20 | i/board/temporary/tile2nwd.png 21 | i/board/temporary/tile2nwd.png 22 | i/board/temporary/tile0nw.png 23 | i/board/temporary/tile1n.png 24 | i/board/temporary/tile1nd.png 25 | i/board/temporary/tile1nd.png 26 | i/board/temporary/tile2n.png 27 | i/board/temporary/tile2nd.png 28 | i/board/temporary/tile2nd.png 29 | i/board/temporary/tile0n.png 30 | i/board/temporary/tile1ne.png 31 | i/board/temporary/tile1ned.png 32 | i/board/temporary/tile1ned.png 33 | i/board/temporary/tile2ne.png 34 | i/board/temporary/tile2ned.png 35 | i/board/temporary/tile2ned.png 36 | i/board/temporary/tile0ne.png 37 | i/board/temporary/tile1w.png 38 | i/board/temporary/tile1wd.png 39 | i/board/temporary/tile1wd.png 40 | i/board/temporary/tile2w.png 41 | i/board/temporary/tile2wd.png 42 | i/board/temporary/tile2wd.png 43 | i/board/temporary/tile0w.png 44 | i/board/temporary/tile1.png 45 | i/board/temporary/tile1d.png 46 | i/board/temporary/tile1d.png 47 | i/board/temporary/tile2.png 48 | i/board/temporary/tile2d.png 49 | i/board/temporary/tile2d.png 50 | i/board/temporary/tile1e.png 51 | i/board/temporary/tile1ed.png 52 | i/board/temporary/tile1ed.png 53 | i/board/temporary/tile2e.png 54 | i/board/temporary/tile2ed.png 55 | i/board/temporary/tile2ed.png 56 | i/board/temporary/tile0e.png 57 | i/board/temporary/tile1sw.png 58 | i/board/temporary/tile1swd.png 59 | i/board/temporary/tile1swd.png 60 | i/board/temporary/tile2sw.png 61 | i/board/temporary/tile2swd.png 62 | i/board/temporary/tile2swd.png 63 | i/board/temporary/tile0sw.png 64 | i/board/temporary/tile1s.png 65 | i/board/temporary/tile1sd.png 66 | i/board/temporary/tile1sd.png 67 | i/board/temporary/tile2s.png 68 | i/board/temporary/tile2sd.png 69 | i/board/temporary/tile2sd.png 70 | i/board/temporary/tile0s.png 71 | i/board/temporary/tile1se.png 72 | i/board/temporary/tile1sed.png 73 | i/board/temporary/tile1sed.png 74 | i/board/temporary/tile2se.png 75 | i/board/temporary/tile2sed.png 76 | i/board/temporary/tile2sed.png 77 | i/board/temporary/tile0se.png 78 | i/board/temporary/tile1.png 79 | i/board/temporary/tile1d.png 80 | i/board/temporary/tile1d.png 81 | i/board/temporary/tile2.png 82 | i/board/temporary/tile2d.png 83 | i/board/temporary/tile2d.png 84 | i/board/temporary/tile0c.png 85 | i/board/temporary/tile0c.png 86 | i/board/temporary/tile0c.png 87 | i/board/temporary/tile0.png 88 | i/board/temporary/tile0.png 89 | 90 | # coming soon: other jQTouch images and themes 91 | 92 | i/ajax-loader-black.gif 93 | i/dot_clear.gif 94 | i/in_progress.gif 95 | i/simple-black.png 96 | i/simple-white.png 97 | 98 | i/themes/jqt/img/back_button.png 99 | i/themes/jqt/img/back_button_clicked.png 100 | i/themes/jqt/img/button.png 101 | i/themes/jqt/img/button_clicked.png 102 | i/themes/jqt/img/chevron.png 103 | i/themes/jqt/img/chevron_circle.png 104 | i/themes/jqt/img/grayButton.png 105 | i/themes/jqt/img/loading.gif 106 | i/themes/jqt/img/on_off.png 107 | i/themes/jqt/img/rowhead.png 108 | i/themes/jqt/img/toggle.png 109 | i/themes/jqt/img/toggleOn.png 110 | i/themes/jqt/img/toolbar.png 111 | i/themes/jqt/img/whiteButton.png 112 | 113 | # common JS 114 | 115 | j/jquery.1.4.2.js 116 | j/jquery.timers-1.2.js 117 | j/jqtouch.customized.js 118 | j/md5.js 119 | j/to-function.js 120 | j/functional.js 121 | j/igesture.jquery.mobile_safari.js 122 | j/jquery.combinators.js 123 | j/dragscrollable.js 124 | 125 | # common CSS 126 | 127 | c/jqtouch.css 128 | c/jqtouch.ipad.customized.css -------------------------------------------------------------------------------- /j/jquery.timers-1.2.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jQuery.timers - Timer abstractions for jQuery 3 | * Written by Blair Mitchelmore (blair DOT mitchelmore AT gmail DOT com) 4 | * Licensed under the WTFPL (http://sam.zoy.org/wtfpl/). 5 | * Date: 2009/10/16 6 | * 7 | * @author Blair Mitchelmore 8 | * @version 1.2 9 | * 10 | **/ 11 | 12 | jQuery.fn.extend({ 13 | everyTime: function(interval, label, fn, times) { 14 | return this.each(function() { 15 | jQuery.timer.add(this, interval, label, fn, times); 16 | }); 17 | }, 18 | oneTime: function(interval, label, fn) { 19 | return this.each(function() { 20 | jQuery.timer.add(this, interval, label, fn, 1); 21 | }); 22 | }, 23 | stopTime: function(label, fn) { 24 | return this.each(function() { 25 | jQuery.timer.remove(this, label, fn); 26 | }); 27 | } 28 | }); 29 | 30 | jQuery.extend({ 31 | timer: { 32 | global: [], 33 | guid: 1, 34 | dataKey: "jQuery.timer", 35 | regex: /^([0-9]+(?:\.[0-9]*)?)\s*(.*s)?$/, 36 | powers: { 37 | // Yeah this is major overkill... 38 | 'ms': 1, 39 | 'cs': 10, 40 | 'ds': 100, 41 | 's': 1000, 42 | 'das': 10000, 43 | 'hs': 100000, 44 | 'ks': 1000000 45 | }, 46 | timeParse: function(value) { 47 | if (value == undefined || value == null) 48 | return null; 49 | var result = this.regex.exec(jQuery.trim(value.toString())); 50 | if (result[2]) { 51 | var num = parseFloat(result[1]); 52 | var mult = this.powers[result[2]] || 1; 53 | return num * mult; 54 | } else { 55 | return value; 56 | } 57 | }, 58 | add: function(element, interval, label, fn, times) { 59 | var counter = 0; 60 | 61 | if (jQuery.isFunction(label)) { 62 | if (!times) 63 | times = fn; 64 | fn = label; 65 | label = interval; 66 | } 67 | 68 | interval = jQuery.timer.timeParse(interval); 69 | 70 | if (typeof interval != 'number' || isNaN(interval) || interval < 0) 71 | return; 72 | 73 | if (typeof times != 'number' || isNaN(times) || times < 0) 74 | times = 0; 75 | 76 | times = times || 0; 77 | 78 | var timers = jQuery.data(element, this.dataKey) || jQuery.data(element, this.dataKey, {}); 79 | 80 | if (!timers[label]) 81 | timers[label] = {}; 82 | 83 | fn.timerID = fn.timerID || this.guid++; 84 | 85 | var handler = function() { 86 | if ((++counter > times && times !== 0) || fn.call(element, counter) === false) 87 | jQuery.timer.remove(element, label, fn); 88 | }; 89 | 90 | handler.timerID = fn.timerID; 91 | 92 | if (!timers[label][fn.timerID]) 93 | timers[label][fn.timerID] = window.setInterval(handler,interval); 94 | 95 | this.global.push( element ); 96 | 97 | }, 98 | remove: function(element, label, fn) { 99 | var timers = jQuery.data(element, this.dataKey), ret; 100 | 101 | if ( timers ) { 102 | 103 | if (!label) { 104 | for ( label in timers ) 105 | this.remove(element, label, fn); 106 | } else if ( timers[label] ) { 107 | if ( fn ) { 108 | if ( fn.timerID ) { 109 | window.clearInterval(timers[label][fn.timerID]); 110 | delete timers[label][fn.timerID]; 111 | } 112 | } else { 113 | for ( var fn in timers[label] ) { 114 | window.clearInterval(timers[label][fn]); 115 | delete timers[label][fn]; 116 | } 117 | } 118 | 119 | for ( ret in timers[label] ) break; 120 | if ( !ret ) { 121 | ret = null; 122 | delete timers[label]; 123 | } 124 | } 125 | 126 | for ( ret in timers ) break; 127 | if ( !ret ) 128 | jQuery.removeData(element, this.dataKey); 129 | } 130 | } 131 | } 132 | }); 133 | 134 | jQuery(window).bind("unload", function() { 135 | jQuery.each(jQuery.timer.global, function(index, item) { 136 | jQuery.timer.remove(item); 137 | }); 138 | }); -------------------------------------------------------------------------------- /j/history.js: -------------------------------------------------------------------------------- 1 | // (c) 2010 Reg Braithwaite. All rights to the entirety of the program and its parts are reserved with 2 | // the exception of specific files otherwise licensed. Other licenses apply only to the files where 3 | // they appear. 4 | 5 | ;(function ($, undefined) { 6 | 7 | var last_move_index = function () { 8 | return go.sgf.floor(go.sgf.current.length-1); 9 | }; 10 | 11 | var this_history_index = function () { 12 | return $('.move.history.this .board') 13 | .data('index'); 14 | } 15 | 16 | var forwards_in_history = function (event) { 17 | 18 | var this_page = $('.move.history.this'); 19 | var that_page; 20 | 21 | var this_index = $('.move.history.this .board') 22 | .data('index'); 23 | var that_index = go.sgf.ceiling(this_index + 1); 24 | 25 | var last_index = go.sgf.floor(go.sgf.current.length - 1); 26 | 27 | if (that_index == -1) 28 | return; // may be a fencepost error when dealing with the start position 29 | else if (that_index == last_index) { 30 | that_page = $('.move.play'); 31 | } 32 | else { 33 | that_page = $('.move.history.that'); 34 | $('.move.history.that .board') 35 | .empty() 36 | .append( 37 | $('.move.history.this .board') 38 | .children() 39 | .clone(false) 40 | ) 41 | .data('index', that_index); 42 | 43 | go.sgf.doit($('.move.history.that .board'), go.sgf.current[that_index]); 44 | 45 | this_page 46 | .addClass('that') 47 | .removeClass('this'); 48 | that_page 49 | .addClass('this') 50 | .removeClass('that') 51 | .find('.toolbar h1') 52 | .text("Move " + go.sgf.current[that_index]["MN"]) 53 | .end(); 54 | } 55 | 56 | jQT.swapPages(this_page, that_page, 'slide'); 57 | 58 | }; 59 | 60 | var backwards_in_history = function (event) { 61 | 62 | var this_page = $('.move.history.this'); 63 | var that_page = $('.move.history.that'); 64 | 65 | var this_index = $('.move.history.this .board') 66 | .data('index'); 67 | if (this_index == -1) return; 68 | var that_index = go.sgf.floor(this_index - 1); 69 | 70 | $('.move.history.that .board') 71 | .empty() 72 | .append( 73 | $('.move.history.this .board') 74 | .children() 75 | .clone(false) 76 | ) 77 | .data('index', that_index); 78 | 79 | 80 | go.sgf.undoit($('.move.history.that .board'), go.sgf.current[this_index], go.sgf.current[that_index]); 81 | 82 | this_page 83 | .addClass('that') 84 | .removeClass('this'); 85 | that_page 86 | .addClass('this') 87 | .removeClass('that') 88 | .find('.toolbar h1') 89 | .text(that_index >= 0 ? ("Move " + go.sgf.current[that_index]["MN"]) : 'Initial Position') 90 | .end(); 91 | 92 | jQT.swapPages(this_page, that_page, 'slide.backwards'); 93 | }; 94 | 95 | var enter_history = function() { 96 | $('.move.history.this .intersection.black') 97 | .removeClass('black'); 98 | $('.move.history.this .intersection.white') 99 | .removeClass('white'); 100 | $('.move.history.this .intersection.last') 101 | .removeClass('last'); 102 | $.each(['black', 'white'], function (i, colour) { 103 | $('.move.history.this') 104 | .find( 105 | $.map($('.move.play .intersection.'+colour), '"#"+$(_).attr("id")'.lambda()).join(',') 106 | ) 107 | .addClass(colour); 108 | }); 109 | $('.move.history.this') 110 | .find('.board') 111 | .data('index', last_move_index()) 112 | .end(); 113 | if (last_move_index() >= 0) { 114 | jQT.swapPages($('.move.play'), $('.move.history.this'), ''); 115 | backwards_in_history(); 116 | } 117 | } 118 | 119 | var initialize_history_support = function() { 120 | $('.move.play .board.zoomout') 121 | .live('gesture_right', enter_history); 122 | $('.move.history.this .board.zoomout') 123 | .live('gesture_left', forwards_in_history) 124 | .live('gesture_right', backwards_in_history); 125 | }; 126 | 127 | go.on_document_ready(initialize_history_support); 128 | 129 | })(jQuery); -------------------------------------------------------------------------------- /j/start.js: -------------------------------------------------------------------------------- 1 | // (c) 2010 Reg Braithwaite. All rights to the entirety of the program and its parts are reserved with 2 | // the exception of specific files otherwise licensed. Other licenses apply only to the files where 3 | // they appear. 4 | 5 | ;(function ($, undefined) { 6 | 7 | var game_specific_options = function (event) { 8 | var game_setup = $.parseJSON($('form.new_game #rules').val()); 9 | var setup_text = $('form.new_game #setup').val(); 10 | $('form.new_game #setup') 11 | .empty(); 12 | $.each(go.referee.rules.setups[game_setup.setups], function (index, setup) { 13 | $('') 14 | .text(setup.text) 15 | .attr('value', setup.text) 16 | .appendTo($('form.new_game #setup')); 17 | } 18 | ); 19 | if ($('form.new_game #setup').has('option:text('+setup_text+')').size() > 0) 20 | $('form.new_game #setup') 21 | .val(setup_text); 22 | else if (setup_text) 23 | $('form.new_game #setup') 24 | .val($('form.new_game #setup option:first').text()); 25 | $('form.new_game #dimension') 26 | .empty(); 27 | $.each(game_setup.sizes, function (index, size) { 28 | $('') 29 | .text('' + size + 'x' + size) 30 | .attr('value', size) 31 | .appendTo($('form.new_game #dimension')); 32 | } 33 | ); 34 | }; 35 | 36 | var setup_new_game = function () { 37 | $('form.new_game .rules select') 38 | .each(game_specific_options) 39 | .blur(game_specific_options) 40 | .change(game_specific_options); 41 | $('form.new_game #start') 42 | .click(function () { $('form.new_game').submit(); return false; }); 43 | $('form.new_game').submit(function (e) { 44 | go.sgf.game_info = { 45 | FF: 4, 46 | SZ: $('form.new_game #dimension').val(), 47 | AP: "World of Go", 48 | PH: $('form.new_game #black').val() || 'Black', // custom: 'player host' 49 | PG: $('form.new_game #white').val() || 'White', // custom: 'player guest' 50 | GR: $('form.new_game #rules option:selected').text(), 51 | GS: $('form.new_game #setup option:selected').text() 52 | }; 53 | go.sgf.game_info.PB = go.sgf.game_info.PH; // TODO: restore picking black or white 54 | go.sgf.game_info.PW = go.sgf.game_info.PG; 55 | go.sgf.root = [go.sgf.game_info]; 56 | go.sgf.current = go.sgf.root; 57 | go.letters = go.letters.slice(0, go.sgf.game_info.SZ); 58 | $('.move') 59 | .removeClass('black white') 60 | .find('.board') 61 | .removeClass('size9 size11 size13 size15 size17 size19') 62 | .addClass('size' + go.sgf.game_info.SZ) 63 | .find('.intersections') 64 | .empty(); 65 | $.each(go.letters, function (down_index, down_letter) { 66 | $('
') 67 | .addClass('row') 68 | .K(function (row) { 69 | $.each(go.letters, function (across_index, across_letter) { 70 | $('') 71 | .addClass('intersection playable_black playable_white') 72 | .attr('id', across_letter + down_letter) 73 | .attr('src', 'i/dot_clear.gif') 74 | .appendTo(row); 75 | }); 76 | }) 77 | .appendTo($('.move .board .intersections')); 78 | }); 79 | var game_setup = $.parseJSON($('form.new_game #rules').val()); 80 | go.sgf.game_info.GM = game_setup.GM; 81 | go.referee.set_rules(game_setup); 82 | var setup_text = $('form.new_game #setup').val(); 83 | var setup; 84 | $.each(go.referee.rules.setups[game_setup.setups], function (i, each_setup) { 85 | if (each_setup.text == setup_text) 86 | setup = each_setup; 87 | }); 88 | $.extend(go.sgf.game_info, setup.sgf); 89 | if (setup.setup) setup.setup(); 90 | go.sgf.doit($('.move.play .board'), go.sgf.game_info); 91 | $('#info') 92 | .find('.players .black') 93 | .text(go.sgf.game_info.PB) 94 | .end() 95 | .find('.players .white') 96 | .text(go.sgf.game_info.PW) 97 | .end() 98 | .find('h1') 99 | .text(go.sgf.game_info.GR) 100 | .end() 101 | .find('.game .setup') 102 | .text(go.sgf.game_info.GS) 103 | .end(); 104 | go.set_titles(); 105 | jQT.swapPages($('#new'), $('.move.play')); 106 | return false; 107 | }); 108 | }; 109 | 110 | go.on_document_ready(setup_new_game); 111 | 112 | })(jQuery); -------------------------------------------------------------------------------- /haml/index.html.haml: -------------------------------------------------------------------------------- 1 | // (c) 2010 Reg Braithwaite. All rights to the entirety of the program and its parts are reserved with 2 | // the exception of specific files otherwise licensed. Other licenses apply only to the files where 3 | // they appear. 4 | 5 | !!!Strict 6 | %html{html_attrs('en').merge(:manifest=>"cache.manifest")} 7 | %head 8 | 9 | %title World of Go 10 | 11 | %meta{:name=>"apple-mobile-web-app-status-bar-style", :content=>"black"}/ 12 | %meta{:name=>"viewport", :content=>"user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0"}/ 13 | 14 | // their stuff 15 | 16 | %script{:src=>"j/jquery.1.4.2.js", :type=>"text/javascript", :charset=>"utf-8"} 17 | %script{:src=>"j/jquery.timers-1.2.js", :type=>"text/javascript", :charset=>"utf-8"} 18 | %script{:src=>"j/jqtouch.customized.js", :type=>"text/javascript", :charset=>"utf-8"} 19 | 20 | %script{:src=>"j/md5.js", :type=>"text/javascript", :charset=>"utf-8"} 21 | 22 | %script{:src=>"j/to-function.js", :type=>"text/javascript", :charset=>"utf-8"} 23 | %script{:src=>"j/functional.js", :type=>"text/javascript", :charset=>"utf-8"} 24 | 25 | // my open stuff 26 | 27 | %script{:src=>"j/igesture.jquery.mobile_safari.js", :type=>"text/javascript", :charset=>"utf-8"} 28 | %script{:src=>"j/jquery.combinators.js", :type=>"text/javascript", :charset=>"utf-8"} 29 | %script{:src=>"j/dragscrollable.js", :type=>"text/javascript", :charset=>"utf-8"} 30 | 31 | // my proprietary stuff 32 | 33 | %script{:src=>"j/go.js", :type=>"text/javascript", :charset=>"utf-8"} 34 | %script{:src=>"j/adjacency.js", :type=>"text/javascript", :charset=>"utf-8"} 35 | %script{:src=>"j/referee.js", :type=>"text/javascript", :charset=>"utf-8"} 36 | %script{:src=>"j/start.js", :type=>"text/javascript", :charset=>"utf-8"} 37 | %script{:src=>"j/ui.js", :type=>"text/javascript", :charset=>"utf-8"} 38 | %script{:src=>"j/history.js", :type=>"text/javascript", :charset=>"utf-8"} 39 | 40 | %style{:type=>"text/css", :media=>"screen"} @import "c/jqtouch.css"; 41 | %style{:type=>"text/css", :media=>"screen"} @import "c/jqtouch.ipad.customized.css"; 42 | %style{:type=>"text/css", :media=>"screen"} @import "c/application.css"; 43 | %style{:type=>"text/css", :media=>"screen"} @import "c/board.ipad.css"; 44 | %style{:type=>"text/css", :media=>"screen"} @import "c/bubbles.css"; 45 | 46 | %style{:id=>'toolbar_titles'} 47 | %style{:id=>'bubbles'} 48 | 49 | :javascript 50 | // (c) 2010 Reg Braithwaite. All rights to the entirety of the program and its parts are reserved with 51 | // the exception of specific files otherwise licensed. Other licenses apply only to the files where 52 | // they appear. 53 | var jQT = new $.jQTouch({ 54 | icon: 'i/black_white.png', 55 | statusBar: 'black-translucent', 56 | touchSelector: '.board .intersection, .board, .touch' 57 | }); 58 | $(function(){ 59 | jQT.addAnimation({ 60 | name: 'slideback', 61 | selector: '.slideback' 62 | }); 63 | }); 64 | %body 65 | 66 | %div#useful_stuff 67 | .ajax_load 68 | %img{:src=>'i/ajax-loader-black.gif',:height=>66,:width=>66} 69 | 70 | #new.current 71 | .toolbar 72 | %h1 Start 73 | %form#form.new_game 74 | %ul.edit.rounded 75 | %li.email 76 | %input#black{:name=>'black', :placeholder=>"Black's name", :type=>'text'}/ 77 | %li.email 78 | %input#white{:name=>'white', :placeholder=>"White's name", :type=>'text'}/ 79 | %li.rules 80 | .label Game: 81 | %select#rules{:name=>'rules'} 82 | %li.size 83 | .label Size: 84 | %select#dimension{:name=>'dimension'} 85 | %li.setup 86 | .label Setup: 87 | %select#setup{:name=>'setup'} 88 | %a.whiteButton#start{:style=>"margin:0 10px;color:rgba(0,0,0,.9)", :href=>"#"} Play 89 | 90 | #info 91 | .toolbar 92 | %h1 Game Info 93 | %h2 Players 94 | %ul.rounded.players 95 | %li.black 96 | %li.white 97 | %h2 Setup 98 | %ul.rounded.game 99 | %li.setup 100 | %h2 Captures 101 | %ul.rounded 102 | %li 103 | Black has captured 104 | %span.captured_whites 105 | %li 106 | White has captured 107 | %span.captured_blacks 108 | 109 | .move.history.this 110 | .toolbar 111 | %h1 112 | %span.playing 113 | .board.zoomout.scrub 114 | .intersections 115 | 116 | .move.history.that 117 | .toolbar 118 | %h1 119 | .board.zoomout.scrub 120 | .intersections 121 | 122 | .move.play 123 | .head 124 | .toolbar 125 | %h1 126 | .board.zoomout.scrub.pass.play 127 | .head 128 | .guest.black.captured 129 | .intersections 130 | .foot 131 | .guest.black.captured 132 | .host.white.captured 133 | .foot 134 | .toolbar 135 | %h1 -------------------------------------------------------------------------------- /c/jqtouch.min.css: -------------------------------------------------------------------------------- 1 | *{margin:0;padding:0;}a{-webkit-tap-highlight-color:rgba(0,0,0,0);}body{overflow-x:hidden;-webkit-user-select:none;-webkit-text-size-adjust:none;font-family:Helvetica;-webkit-perspective:800;-webkit-transform-style:preserve-3d;}.selectable,input,textarea{-webkit-user-select:auto;}body>*{-webkit-backface-visibility:hidden;-webkit-box-sizing:border-box;display:none;position:absolute;left:0;width:100%;-webkit-transform:translate3d(0,0,0) rotate(0) scale(1);min-height:420px!important;}body.fullscreen>*{min-height:460px!important;}body.fullscreen.black-translucent>*{min-height:480px!important;}body.landscape>*{min-height:320px;}body>.current{display:block!important;}.in,.out{-webkit-animation-timing-function:ease-in-out;-webkit-animation-duration:350ms;}.slide.in{-webkit-animation-name:slideinfromright;}.slide.out{-webkit-animation-name:slideouttoleft;}.slide.in.reverse{-webkit-animation-name:slideinfromleft;}.slide.out.reverse{-webkit-animation-name:slideouttoright;}@-webkit-keyframes slideinfromright{from{-webkit-transform:translateX(100%);}to{-webkit-transform:translateX(0);}}@-webkit-keyframes slideinfromleft{from{-webkit-transform:translateX(-100%);}to{-webkit-transform:translateX(0);}}@-webkit-keyframes slideouttoleft{from{-webkit-transform:translateX(0);}to{-webkit-transform:translateX(-100%);}}@-webkit-keyframes slideouttoright{from{-webkit-transform:translateX(0);}to{-webkit-transform:translateX(100%);}}@-webkit-keyframes fadein{from{opacity:0;}to{opacity:1;}}@-webkit-keyframes fadeout{from{opacity:1;}to{opacity:0;}}.fade.in{z-index:10;-webkit-animation-name:fadein;}.fade.out{z-index:0;}.dissolve.in{-webkit-animation-name:fadein;}.dissolve.out{-webkit-animation-name:fadeout;}.flip{-webkit-animation-duration:.65s;}.flip.in{-webkit-animation-name:flipinfromleft;}.flip.out{-webkit-animation-name:flipouttoleft;}.flip.in.reverse{-webkit-animation-name:flipinfromright;}.flip.out.reverse{-webkit-animation-name:flipouttoright;}@-webkit-keyframes flipinfromright{from{-webkit-transform:rotateY(-180deg) scale(.8);}to{-webkit-transform:rotateY(0) scale(1);}}@-webkit-keyframes flipinfromleft{from{-webkit-transform:rotateY(180deg) scale(.8);}to{-webkit-transform:rotateY(0) scale(1);}}@-webkit-keyframes flipouttoleft{from{-webkit-transform:rotateY(0) scale(1);}to{-webkit-transform:rotateY(-180deg) scale(.8);}}@-webkit-keyframes flipouttoright{from{-webkit-transform:rotateY(0) scale(1);}to{-webkit-transform:rotateY(180deg) scale(.8);}}.slideup.in{-webkit-animation-name:slideup;z-index:10;}.slideup.out{-webkit-animation-name:dontmove;z-index:0;}.slideup.out.reverse{z-index:10;-webkit-animation-name:slidedown;}.slideup.in.reverse{z-index:0;-webkit-animation-name:dontmove;}@-webkit-keyframes slideup{from{-webkit-transform:translateY(100%);}to{-webkit-transform:translateY(0);}}@-webkit-keyframes slidedown{from{-webkit-transform:translateY(0);}to{-webkit-transform:translateY(100%);}}@-webkit-keyframes dontmove{from{opacity:1;}to{opacity:1;}}.swap{-webkit-transform:perspective(800);-webkit-animation-duration:.7s;}.swap.out{-webkit-animation-name:swapouttoleft;}.swap.in{-webkit-animation-name:swapinfromright;}.swap.out.reverse{-webkit-animation-name:swapouttoright;}.swap.in.reverse{-webkit-animation-name:swapinfromleft;}@-webkit-keyframes swapouttoright{0%{-webkit-transform:translate3d(0px,0px,0px) rotateY(0deg);-webkit-animation-timing-function:ease-in-out;}50%{-webkit-transform:translate3d(-180px,0px,-400px) rotateY(20deg);-webkit-animation-timing-function:ease-in;}100%{-webkit-transform:translate3d(0px,0px,-800px) rotateY(70deg);}}@-webkit-keyframes swapouttoleft{0%{-webkit-transform:translate3d(0px,0px,0px) rotateY(0deg);-webkit-animation-timing-function:ease-in-out;}50%{-webkit-transform:translate3d(180px,0px,-400px) rotateY(-20deg);-webkit-animation-timing-function:ease-in;}100%{-webkit-transform:translate3d(0px,0px,-800px) rotateY(-70deg);}}@-webkit-keyframes swapinfromright{0%{-webkit-transform:translate3d(0px,0px,-800px) rotateY(70deg);-webkit-animation-timing-function:ease-out;}50%{-webkit-transform:translate3d(-180px,0px,-400px) rotateY(20deg);-webkit-animation-timing-function:ease-in-out;}100%{-webkit-transform:translate3d(0px,0px,0px) rotateY(0deg);}}@-webkit-keyframes swapinfromleft{0%{-webkit-transform:translate3d(0px,0px,-800px) rotateY(-70deg);-webkit-animation-timing-function:ease-out;}50%{-webkit-transform:translate3d(180px,0px,-400px) rotateY(-20deg);-webkit-animation-timing-function:ease-in-out;}100%{-webkit-transform:translate3d(0px,0px,0px) rotateY(0deg);}}.cube{-webkit-animation-duration:.55s;}.cube.in{-webkit-animation-name:cubeinfromright;-webkit-transform-origin:0 50%;}.cube.out{-webkit-animation-name:cubeouttoleft;-webkit-transform-origin:100% 50%;}.cube.in.reverse{-webkit-animation-name:cubeinfromleft;-webkit-transform-origin:100% 50%;}.cube.out.reverse{-webkit-animation-name:cubeouttoright;-webkit-transform-origin:0 50%;}@-webkit-keyframes cubeinfromleft{from{-webkit-transform:rotateY(-90deg) translateZ(320px);opacity:.5;}to{-webkit-transform:rotateY(0deg) translateZ(0);opacity:1;}}@-webkit-keyframes cubeouttoright{from{-webkit-transform:rotateY(0deg) translateX(0);opacity:1;}to{-webkit-transform:rotateY(90deg) translateZ(320px);opacity:.5;}}@-webkit-keyframes cubeinfromright{from{-webkit-transform:rotateY(90deg) translateZ(320px);opacity:.5;}to{-webkit-transform:rotateY(0deg) translateZ(0);opacity:1;}}@-webkit-keyframes cubeouttoleft{from{-webkit-transform:rotateY(0deg) translateZ(0);opacity:1;}to{-webkit-transform:rotateY(-90deg) translateZ(320px);opacity:.5;}}.pop{-webkit-transform-origin:50% 50%;}.pop.in{-webkit-animation-name:popin;z-index:10;}.pop.out.reverse{-webkit-animation-name:popout;z-index:10;}.pop.in.reverse{z-index:0;-webkit-animation-name:dontmove;}@-webkit-keyframes popin{from{-webkit-transform:scale(.2);opacity:0;}to{-webkit-transform:scale(1);opacity:1;}}@-webkit-keyframes popout{from{-webkit-transform:scale(1);opacity:1;}to{-webkit-transform:scale(.2);opacity:0;}} -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | World of Go 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 53 | 54 | 55 |
56 |
57 | 58 |
59 |
60 |
61 |
62 |

Start

63 |
64 |
65 | 85 | Play 86 |
87 |
88 |
89 |
90 |

Game Info

91 |
92 |

Players

93 | 97 |

Setup

98 | 101 |

Captures

102 | 112 |
113 |
114 |
115 |

116 | 117 |

118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |

126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |

135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |

150 |
151 |
152 |
153 | 154 | 155 | -------------------------------------------------------------------------------- /j/dragscrollable.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery dragscrollable Plugin 3 | * version: 1.0 (25-Jun-2009) 4 | * Copyright (c) 2009 Miquel Herrera 5 | * 6 | * Portions Copyright (c) 2010 Reg Braithwaite 7 | * 8 | * Dual licensed under the MIT and GPL licenses: 9 | * http://www.opensource.org/licenses/mit-license.php 10 | * http://www.gnu.org/licenses/gpl.html 11 | * 12 | */ 13 | ;(function($){ // secure $ jQuery alias 14 | 15 | /** 16 | * Adds the ability to manage elements scroll by dragging 17 | * one or more of its descendant elements. Options parameter 18 | * allow to specifically select which inner elements will 19 | * respond to the drag events. 20 | * 21 | * options properties: 22 | * ------------------------------------------------------------------------ 23 | * dragSelector | jquery selector to apply to each wrapped element 24 | * | to find which will be the dragging elements. 25 | * | Defaults to '>:first' which is the first child of 26 | * | scrollable element 27 | * ------------------------------------------------------------------------ 28 | * acceptPropagatedEvent| Will the dragging element accept propagated 29 | * | events? default is yes, a propagated mouse event 30 | * | on a inner element will be accepted and processed. 31 | * | If set to false, only events originated on the 32 | * | draggable elements will be processed. 33 | * ------------------------------------------------------------------------ 34 | * preventDefault | Prevents the event to propagate further effectivey 35 | * | dissabling other default actions. Defaults to true 36 | * ------------------------------------------------------------------------ 37 | * 38 | * usage examples: 39 | * 40 | * To add the scroll by drag to the element id=viewport when dragging its 41 | * first child accepting any propagated events 42 | * $('#viewport').dragscrollable(); 43 | * 44 | * To add the scroll by drag ability to any element div of class viewport 45 | * when dragging its first descendant of class dragMe responding only to 46 | * evcents originated on the '.dragMe' elements. 47 | * $('div.viewport').dragscrollable({dragSelector:'.dragMe:first', 48 | * acceptPropagatedEvent: false}); 49 | * 50 | * Notice that some 'viewports' could be nested within others but events 51 | * would not interfere as acceptPropagatedEvent is set to false. 52 | * 53 | */ 54 | 55 | var append_namespace = function (string_of_events, ns) { 56 | return string_of_events 57 | .split(' ') 58 | .map(function (name) { return name + ns; }) 59 | .join(' '); 60 | }; 61 | 62 | var left_top = function(event) { 63 | 64 | var x; 65 | var y; 66 | if (typeof(event.clientX) != 'undefined') { 67 | x = event.clientX; 68 | y = event.clientY; 69 | } 70 | else if (typeof(event.screenX) != 'undefined') { 71 | x = event.screenX; 72 | y = event.screenY; 73 | } 74 | else if (typeof(event.targetTouches) != 'undefined') { 75 | x = event.targetTouches[0].pageX; 76 | y = event.targetTouches[0].pageY; 77 | } 78 | else if (typeof(event.originalEvent) == 'undefined') { 79 | var str = ''; 80 | for (i in event) { 81 | str += ', ' + i + ': ' + event[i]; 82 | } 83 | console.error("don't understand x and y for " + event.type + ' event: ' + str); 84 | } 85 | else if (typeof(event.originalEvent.clientX) != 'undefined') { 86 | x = event.originalEvent.clientX; 87 | y = event.originalEvent.clientY; 88 | } 89 | else if (typeof(event.originalEvent.screenX) != 'undefined') { 90 | x = event.originalEvent.screenX; 91 | y = event.originalEvent.screenY; 92 | } 93 | else if (typeof(event.originalEvent.targetTouches) != 'undefined') { 94 | x = event.originalEvent.targetTouches[0].pageX; 95 | y = event.originalEvent.targetTouches[0].pageY; 96 | } 97 | 98 | return {left: x, top:y}; 99 | }; 100 | 101 | $.fn.dragscrollable = function( options ) { 102 | 103 | var handling_element = $(this); 104 | 105 | var settings = $.extend( 106 | { 107 | dragSelector:'>:first', 108 | acceptPropagatedEvent: true, 109 | preventDefault: true, 110 | dragstart: 'mousedown touchstart', 111 | dragcontinue: 'mousemove touchmove', 112 | dragend: 'mouseup touchend', 113 | namespace: '.ds' 114 | },options || {}); 115 | 116 | settings.dragstart = append_namespace(settings.dragstart, settings.namespace); 117 | settings.dragcontinue = append_namespace(settings.dragcontinue, settings.namespace); 118 | settings.dragend = append_namespace(settings.dragend, settings.namespace); 119 | 120 | var dragscroll= { 121 | dragStartHandler : function(event) { 122 | 123 | // mousedown, left click, check propagation 124 | if (event.which > 1 || 125 | (!event.data.acceptPropagatedEvent && event.target != this)){ 126 | return false; 127 | } 128 | 129 | // Initial coordinates will be the last when dragging 130 | event.data.lastCoord = left_top(event); 131 | 132 | handling_element 133 | .bind(settings.dragcontinue, event.data, dragscroll.dragContinueHandler) 134 | .bind(settings.dragend, event.data, dragscroll.dragEndHandler); 135 | 136 | if (event.data.preventDefault) { 137 | event.preventDefault(); 138 | return false; 139 | } 140 | }, 141 | dragContinueHandler : function(event) { // User is dragging 142 | 143 | var lt = left_top(event); 144 | 145 | // How much did the mouse move? 146 | var delta = {left: (lt.left - event.data.lastCoord.left), 147 | top: (lt.top - event.data.lastCoord.top)}; 148 | 149 | // Set the scroll position relative to what ever the scroll is now 150 | event.data.scrollable.scrollLeft( 151 | event.data.scrollable.scrollLeft() - delta.left); 152 | event.data.scrollable.scrollTop( 153 | event.data.scrollable.scrollTop() - delta.top); 154 | 155 | // Save where the cursor is 156 | event.data.lastCoord = lt; 157 | 158 | if (event.data.preventDefault) { 159 | event.preventDefault(); 160 | return false; 161 | } 162 | 163 | }, 164 | dragEndHandler : function(event) { // Stop scrolling 165 | handling_element 166 | .unbind(settings.dragcontinue) 167 | .unbind(settings.dragend); 168 | if (event.data.preventDefault) { 169 | event.preventDefault(); 170 | return false; 171 | } 172 | } 173 | } 174 | 175 | // set up the initial events 176 | return this.each(function() { 177 | // closure object data for each scrollable element 178 | var data = {scrollable : $(this), 179 | acceptPropagatedEvent : settings.acceptPropagatedEvent, 180 | preventDefault : settings.preventDefault } 181 | // Set mouse initiating event on the desired descendant 182 | $(this).find(settings.dragSelector). 183 | bind(settings.dragstart, data, dragscroll.dragStartHandler); 184 | }); 185 | }; //end plugin dragscrollable 186 | 187 | $.fn.removedragscrollable = function (namespace) { 188 | if (typeof(namespace) == 'undefined') 189 | namespace = '.ds'; 190 | return this.each(function() { 191 | var x = $(document).find('*').andSelf().unbind(namespace); 192 | }); 193 | }; 194 | 195 | })( jQuery ); // confine scope 196 | -------------------------------------------------------------------------------- /j/to-function.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Oliver Steele 3 | * Copyright: Copyright 2007 by Oliver Steele. All rights reserved. 4 | * License: MIT License 5 | * Homepage: http://osteele.com/javascripts/functional 6 | * Created: 2007-07-11 7 | * Version: 1.0.2 8 | * 9 | * 10 | * This defines "string lambdas", that allow strings such as `x+1` and 11 | * `x -> x+1` to be used in some contexts as functions. 12 | */ 13 | 14 | 15 | /// ^ String lambdas 16 | 17 | /** 18 | * Turns a string that contains a JavaScript expression into a 19 | * `Function` that returns the value of that expression. 20 | * 21 | * If the string contains a `->`, this separates the parameters from the body: 22 | * >> 'x -> x + 1'.lambda()(1) -> 2 23 | * >> 'x y -> x + 2*y'.lambda()(1, 2) -> 5 24 | * >> 'x, y -> x + 2*y'.lambda()(1, 2) -> 5 25 | * 26 | * Otherwise, if the string contains a `_`, this is the parameter: 27 | * >> '_ + 1'.lambda()(1) -> 2 28 | * 29 | * Otherwise if the string begins or ends with an operator or relation, 30 | * prepend or append a parameter. (The documentation refers to this type 31 | * of string as a "section".) 32 | * >> '/2'.lambda()(4) -> 2 33 | * >> '2/'.lambda()(4) -> 0.5 34 | * >> '/'.lambda()(2,4) -> 0.5 35 | * Sections can end, but not begin with, `-`. (This is to avoid interpreting 36 | * e.g. `-2*x` as a section). On the other hand, a string that either begins 37 | * or ends with `/` is a section, so an expression that begins or ends with a 38 | * regular expression literal needs an explicit parameter. 39 | * 40 | * Otherwise, each variable name is an implicit parameter: 41 | * >> 'x + 1'.lambda()(1) -> 2 42 | * >> 'x + 2*y'.lambda()(1, 2) -> 5 43 | * >> 'y + 2*x'.lambda()(1, 2) -> 5 44 | * 45 | * Implicit parameter detection ignores strings literals, variable names that 46 | * start with capitals, and identifiers that precede `:` or follow `.`: 47 | * >> map('"im"+root', ["probable", "possible"]) -> ["improbable", "impossible"] 48 | * >> 'Math.cos(angle)'.lambda()(Math.PI) -> -1 49 | * >> 'point.x'.lambda()({x:1, y:2}) -> 1 50 | * >> '({x:1, y:2})[key]'.lambda()('x') -> 1 51 | * 52 | * Implicit parameter detection mistakenly looks inside regular expression 53 | * literals for variable names. It also doesn't know to ignore JavaScript 54 | * keywords and bound variables. (The only way you can get these last two is 55 | * with a function literal inside the string. This is outside the intended use 56 | * case for string lambdas.) 57 | * 58 | * Use `_` (to define a unary function) or `->`, if the string contains anything 59 | * that looks like a free variable but shouldn't be used as a parameter, or 60 | * to specify parameters that are ordered differently from their first 61 | * occurrence in the string. 62 | * 63 | * Chain `->`s to create a function in uncurried form: 64 | * >> 'x -> y -> x + 2*y'.lambda()(1)(2) -> 5 65 | * >> 'x -> y -> z -> x + 2*y+3*z'.lambda()(1)(2)(3) -> 14 66 | * 67 | * `this` and `arguments` are special: 68 | * >> 'this'.call(1) -> 1 69 | * >> '[].slice.call(arguments, 0)'.call(null,1,2) -> [1, 2] 70 | */ 71 | String.prototype.lambda = function() { 72 | var params = [], 73 | expr = this, 74 | sections = expr.ECMAsplit(/\s*->\s*/m); 75 | if (sections.length > 1) { 76 | while (sections.length) { 77 | expr = sections.pop(); 78 | params = sections.pop().split(/\s*,\s*|\s+/m); 79 | sections.length && sections.push('(function('+params+'){return ('+expr+')})'); 80 | } 81 | } else if (expr.match(/\b_\b/)) { 82 | params = '_'; 83 | } else { 84 | // test whether an operator appears on the left (or right), respectively 85 | var leftSection = expr.match(/^\s*(?:[+*\/%&|\^\.=<>]|!=)/m), 86 | rightSection = expr.match(/[+\-*\/%&|\^\.=<>!]\s*$/m); 87 | if (leftSection || rightSection) { 88 | if (leftSection) { 89 | params.push('$1'); 90 | expr = '$1' + expr; 91 | } 92 | if (rightSection) { 93 | params.push('$2'); 94 | expr = expr + '$2'; 95 | } 96 | } else { 97 | // `replace` removes symbols that are capitalized, follow '.', 98 | // precede ':', are 'this' or 'arguments'; and also the insides of 99 | // strings (by a crude test). `match` extracts the remaining 100 | // symbols. 101 | var vars = this.replace(/(?:\b[A-Z]|\.[a-zA-Z_$])[a-zA-Z_$\d]*|[a-zA-Z_$][a-zA-Z_$\d]*\s*:|this|arguments|'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"/g, '').match(/([a-z_$][a-z_$\d]*)/gi) || []; // ' 102 | for (var i = 0, v; v = vars[i++]; ) 103 | params.indexOf(v) >= 0 || params.push(v); 104 | } 105 | } 106 | return new Function(params, 'return (' + expr + ')'); 107 | } 108 | 109 | /// Turn on caching for `string` -> `Function` conversion. 110 | String.prototype.lambda.cache = function() { 111 | var proto = String.prototype, 112 | cache = {}, 113 | uncached = proto.lambda, 114 | cached = function() { 115 | var key = '#' + this; // avoid hidden properties on Object.prototype 116 | return cache[key] || (cache[key] = uncached.call(this)); 117 | }; 118 | cached.cached = function(){}; 119 | cached.uncache = function(){proto.lambda = uncached}; 120 | proto.lambda = cached; 121 | } 122 | 123 | /** 124 | * ^^ Duck-Typing 125 | * 126 | * Strings support `call` and `apply`. This duck-types them as 127 | * functions, to some callers. 128 | */ 129 | 130 | /** 131 | * Coerce the string to a function and then apply it. 132 | * >> 'x+1'.apply(null, [2]) -> 3 133 | * >> '/'.apply(null, [2, 4]) -> 0.5 134 | */ 135 | String.prototype.apply = function(thisArg, args) { 136 | return this.toFunction().apply(thisArg, args); 137 | } 138 | 139 | /** 140 | * Coerce the string to a function and then call it. 141 | * >> 'x+1'.call(null, 2) -> 3 142 | * >> '/'.call(null, 2, 4) -> 0.5 143 | */ 144 | String.prototype.call = function() { 145 | return this.toFunction().apply(arguments[0], 146 | Array.prototype.slice.call(arguments, 1)); 147 | } 148 | 149 | /// ^^ Coercion 150 | 151 | /** 152 | * Returns a `Function` that perfoms the action described by this 153 | * string. If the string contains a `return`, applies 154 | * `new Function` to it. Otherwise, this function returns 155 | * the result of `this.lambda()`. 156 | * >> '+1'.toFunction()(2) -> 3 157 | * >> 'return 1'.toFunction()(1) -> 1 158 | */ 159 | String.prototype.toFunction = function() { 160 | var body = this; 161 | if (body.match(/\breturn\b/)) 162 | return new Function(this); 163 | return this.lambda(); 164 | } 165 | 166 | /** 167 | * Returns this function. `Function.toFunction` calls this. 168 | * >> '+1'.lambda().toFunction()(2) -> 3 169 | */ 170 | Function.prototype.toFunction = function() { 171 | return this; 172 | } 173 | 174 | /** 175 | * Coerces `fn` into a function if it is not already one, 176 | * by calling its `toFunction` method. 177 | * >> Function.toFunction(function() {return 1})() -> 1 178 | * >> Function.toFunction('+1')(2) -> 3 179 | * 180 | * `Function.toFunction` requires an argument that can be 181 | * coerced to a function. A nullary version can be 182 | * constructed via `guard`: 183 | * >> Function.toFunction.guard()('1+') -> function() 184 | * >> Function.toFunction.guard()(null) -> null 185 | * 186 | * `Function.toFunction` doesn't coerce arbitrary values to functions. 187 | * It might seem convenient to treat 188 | * `Function.toFunction(value)` as though it were the 189 | * constant function that returned `value`, but it's rarely 190 | * useful and it hides errors. Use `Functional.K(value)` instead, 191 | * or a lambda string when the value is a compile-time literal: 192 | * >> Functional.K('a string')() -> "a string" 193 | * >> Function.toFunction('"a string"')() -> "a string" 194 | */ 195 | Function.toFunction = function(value) { 196 | return value.toFunction(); 197 | } 198 | 199 | // Utilities 200 | 201 | // IE6 split is not ECMAScript-compliant. This breaks '->1'.lambda(). 202 | // ECMAsplit is an ECMAScript-compliant `split`, although only for 203 | // one argument. 204 | String.prototype.ECMAsplit = 205 | // The test is from the ECMAScript reference. 206 | ('ab'.split(/a*/).length > 1 207 | ? String.prototype.split 208 | : function(separator, limit) { 209 | if (typeof limit != 'undefined') 210 | throw "ECMAsplit: limit is unimplemented"; 211 | var result = this.split.apply(this, arguments), 212 | re = RegExp(separator), 213 | savedIndex = re.lastIndex, 214 | match = re.exec(this); 215 | if (match && match.index == 0) 216 | result.unshift(''); 217 | // in case `separator` was already a RegExp: 218 | re.lastIndex = savedIndex; 219 | return result; 220 | }); -------------------------------------------------------------------------------- /c/jqtouch.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | a { 6 | -webkit-tap-highlight-color: rgba(0,0,0,0); 7 | } 8 | 9 | body { 10 | overflow-x: hidden; 11 | -webkit-user-select: none; 12 | -webkit-text-size-adjust: none; 13 | font-family: Helvetica; 14 | -webkit-perspective: 800; 15 | -webkit-transform-style: preserve-3d; 16 | } 17 | .selectable, input, textarea { 18 | -webkit-user-select: auto; 19 | } 20 | body > * { 21 | -webkit-backface-visibility: hidden; 22 | -webkit-box-sizing: border-box; 23 | display: none; 24 | position: absolute; 25 | left: 0; 26 | width: 100%; 27 | -webkit-transform: translate3d(0,0,0) rotate(0) scale(1); 28 | min-height: 420px !important; 29 | } 30 | body.fullscreen > * { 31 | min-height: 460px !important; 32 | } 33 | body.fullscreen.black-translucent > * { 34 | min-height: 480px !important; 35 | } 36 | body.landscape > * { 37 | min-height: 320px; 38 | } 39 | body > .current { 40 | display: block !important; 41 | } 42 | 43 | .in, .out { 44 | -webkit-animation-timing-function: ease-in-out; 45 | -webkit-animation-duration: 350ms; 46 | } 47 | 48 | .slide.in { 49 | -webkit-animation-name: slideinfromright; 50 | } 51 | 52 | .slide.out { 53 | -webkit-animation-name: slideouttoleft; 54 | } 55 | 56 | .slide.in.reverse { 57 | -webkit-animation-name: slideinfromleft; 58 | } 59 | 60 | .slide.out.reverse { 61 | -webkit-animation-name: slideouttoright; 62 | } 63 | 64 | @-webkit-keyframes slideinfromright { 65 | from { -webkit-transform: translateX(100%); } 66 | to { -webkit-transform: translateX(0); } 67 | } 68 | 69 | @-webkit-keyframes slideinfromleft { 70 | from { -webkit-transform: translateX(-100%); } 71 | to { -webkit-transform: translateX(0); } 72 | } 73 | 74 | @-webkit-keyframes slideouttoleft { 75 | from { -webkit-transform: translateX(0); } 76 | to { -webkit-transform: translateX(-100%); } 77 | } 78 | 79 | @-webkit-keyframes slideouttoright { 80 | from { -webkit-transform: translateX(0); } 81 | to { -webkit-transform: translateX(100%); } 82 | } 83 | 84 | @-webkit-keyframes fadein { 85 | from { opacity: 0; } 86 | to { opacity: 1; } 87 | } 88 | 89 | @-webkit-keyframes fadeout { 90 | from { opacity: 1; } 91 | to { opacity: 0; } 92 | } 93 | 94 | .fade.in { 95 | z-index: 10; 96 | -webkit-animation-name: fadein; 97 | } 98 | .fade.out { 99 | z-index: 0; 100 | } 101 | 102 | .dissolve.in { 103 | -webkit-animation-name: fadein; 104 | } 105 | 106 | .dissolve.out { 107 | -webkit-animation-name: fadeout; 108 | } 109 | 110 | 111 | 112 | .flip { 113 | -webkit-animation-duration: .65s; 114 | } 115 | 116 | .flip.in { 117 | -webkit-animation-name: flipinfromleft; 118 | } 119 | 120 | .flip.out { 121 | -webkit-animation-name: flipouttoleft; 122 | } 123 | 124 | /* Shake it all about */ 125 | 126 | .flip.in.reverse { 127 | -webkit-animation-name: flipinfromright; 128 | } 129 | 130 | .flip.out.reverse { 131 | -webkit-animation-name: flipouttoright; 132 | } 133 | 134 | @-webkit-keyframes flipinfromright { 135 | from { -webkit-transform: rotateY(-180deg) scale(.8); } 136 | to { -webkit-transform: rotateY(0) scale(1); } 137 | } 138 | 139 | @-webkit-keyframes flipinfromleft { 140 | from { -webkit-transform: rotateY(180deg) scale(.8); } 141 | to { -webkit-transform: rotateY(0) scale(1); } 142 | } 143 | 144 | @-webkit-keyframes flipouttoleft { 145 | from { -webkit-transform: rotateY(0) scale(1); } 146 | to { -webkit-transform: rotateY(-180deg) scale(.8); } 147 | } 148 | 149 | @-webkit-keyframes flipouttoright { 150 | from { -webkit-transform: rotateY(0) scale(1); } 151 | to { -webkit-transform: rotateY(180deg) scale(.8); } 152 | } 153 | 154 | .slideup.in { 155 | -webkit-animation-name: slideup; 156 | z-index: 10; 157 | } 158 | 159 | .slideup.out { 160 | -webkit-animation-name: dontmove; 161 | z-index: 0; 162 | } 163 | 164 | .slideup.out.reverse { 165 | z-index: 10; 166 | -webkit-animation-name: slidedown; 167 | } 168 | 169 | .slideup.in.reverse { 170 | z-index: 0; 171 | -webkit-animation-name: dontmove; 172 | } 173 | 174 | 175 | @-webkit-keyframes slideup { 176 | from { -webkit-transform: translateY(100%); } 177 | to { -webkit-transform: translateY(0); } 178 | } 179 | 180 | @-webkit-keyframes slidedown { 181 | from { -webkit-transform: translateY(0); } 182 | to { -webkit-transform: translateY(100%); } 183 | } 184 | 185 | 186 | 187 | /* Hackish, but reliable. */ 188 | 189 | @-webkit-keyframes dontmove { 190 | from { opacity: 1; } 191 | to { opacity: 1; } 192 | } 193 | 194 | .swap { 195 | -webkit-transform: perspective(800); 196 | -webkit-animation-duration: .7s; 197 | } 198 | .swap.out { 199 | -webkit-animation-name: swapouttoleft; 200 | } 201 | .swap.in { 202 | -webkit-animation-name: swapinfromright; 203 | } 204 | .swap.out.reverse { 205 | -webkit-animation-name: swapouttoright; 206 | } 207 | .swap.in.reverse { 208 | -webkit-animation-name: swapinfromleft; 209 | } 210 | 211 | 212 | @-webkit-keyframes swapouttoright { 213 | 0% { 214 | -webkit-transform: translate3d(0px, 0px, 0px) rotateY(0deg); 215 | -webkit-animation-timing-function: ease-in-out; 216 | } 217 | 50% { 218 | -webkit-transform: translate3d(-180px, 0px, -400px) rotateY(20deg); 219 | -webkit-animation-timing-function: ease-in; 220 | } 221 | 100% { 222 | -webkit-transform: translate3d(0px, 0px, -800px) rotateY(70deg); 223 | } 224 | } 225 | 226 | @-webkit-keyframes swapouttoleft { 227 | 0% { 228 | -webkit-transform: translate3d(0px, 0px, 0px) rotateY(0deg); 229 | -webkit-animation-timing-function: ease-in-out; 230 | } 231 | 50% { 232 | -webkit-transform: translate3d(180px, 0px, -400px) rotateY(-20deg); 233 | -webkit-animation-timing-function: ease-in; 234 | } 235 | 100% { 236 | -webkit-transform: translate3d(0px, 0px, -800px) rotateY(-70deg); 237 | } 238 | } 239 | 240 | @-webkit-keyframes swapinfromright { 241 | 0% { 242 | -webkit-transform: translate3d(0px, 0px, -800px) rotateY(70deg); 243 | -webkit-animation-timing-function: ease-out; 244 | } 245 | 50% { 246 | -webkit-transform: translate3d(-180px, 0px, -400px) rotateY(20deg); 247 | -webkit-animation-timing-function: ease-in-out; 248 | } 249 | 100% { 250 | -webkit-transform: translate3d(0px, 0px, 0px) rotateY(0deg); 251 | } 252 | } 253 | 254 | @-webkit-keyframes swapinfromleft { 255 | 0% { 256 | -webkit-transform: translate3d(0px, 0px, -800px) rotateY(-70deg); 257 | -webkit-animation-timing-function: ease-out; 258 | } 259 | 50% { 260 | -webkit-transform: translate3d(180px, 0px, -400px) rotateY(-20deg); 261 | -webkit-animation-timing-function: ease-in-out; 262 | } 263 | 100% { 264 | -webkit-transform: translate3d(0px, 0px, 0px) rotateY(0deg); 265 | } 266 | } 267 | 268 | .cube { 269 | -webkit-animation-duration: .55s; 270 | } 271 | 272 | .cube.in { 273 | -webkit-animation-name: cubeinfromright; 274 | -webkit-transform-origin: 0% 50%; 275 | } 276 | .cube.out { 277 | -webkit-animation-name: cubeouttoleft; 278 | -webkit-transform-origin: 100% 50%; 279 | } 280 | .cube.in.reverse { 281 | -webkit-animation-name: cubeinfromleft; 282 | -webkit-transform-origin: 100% 50%; 283 | } 284 | .cube.out.reverse { 285 | -webkit-animation-name: cubeouttoright; 286 | -webkit-transform-origin: 0% 50%; 287 | 288 | } 289 | 290 | @-webkit-keyframes cubeinfromleft { 291 | from { 292 | -webkit-transform: rotateY(-90deg) translateZ(320px); 293 | opacity: .5; 294 | } 295 | to { 296 | -webkit-transform: rotateY(0deg) translateZ(0); 297 | opacity: 1; 298 | } 299 | } 300 | @-webkit-keyframes cubeouttoright { 301 | from { 302 | -webkit-transform: rotateY(0deg) translateX(0); 303 | opacity: 1; 304 | } 305 | to { 306 | -webkit-transform: rotateY(90deg) translateZ(320px); 307 | opacity: .5; 308 | } 309 | } 310 | @-webkit-keyframes cubeinfromright { 311 | from { 312 | -webkit-transform: rotateY(90deg) translateZ(320px); 313 | opacity: .5; 314 | } 315 | to { 316 | -webkit-transform: rotateY(0deg) translateZ(0); 317 | opacity: 1; 318 | } 319 | } 320 | @-webkit-keyframes cubeouttoleft { 321 | from { 322 | -webkit-transform: rotateY(0deg) translateZ(0); 323 | opacity: 1; 324 | } 325 | to { 326 | -webkit-transform: rotateY(-90deg) translateZ(320px); 327 | opacity: .5; 328 | } 329 | } 330 | 331 | 332 | 333 | 334 | .pop { 335 | -webkit-transform-origin: 50% 50%; 336 | } 337 | 338 | .pop.in { 339 | -webkit-animation-name: popin; 340 | z-index: 10; 341 | } 342 | 343 | .pop.out.reverse { 344 | -webkit-animation-name: popout; 345 | z-index: 10; 346 | } 347 | 348 | .pop.in.reverse { 349 | z-index: 0; 350 | -webkit-animation-name: dontmove; 351 | } 352 | 353 | @-webkit-keyframes popin { 354 | from { 355 | -webkit-transform: scale(.2); 356 | opacity: 0; 357 | } 358 | to { 359 | -webkit-transform: scale(1); 360 | opacity: 1; 361 | } 362 | } 363 | 364 | @-webkit-keyframes popout { 365 | from { 366 | -webkit-transform: scale(1); 367 | opacity: 1; 368 | } 369 | to { 370 | -webkit-transform: scale(.2); 371 | opacity: 0; 372 | } 373 | } -------------------------------------------------------------------------------- /j/md5.js: -------------------------------------------------------------------------------- 1 | /* 2 | * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message 3 | * Digest Algorithm, as defined in RFC 1321. 4 | * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002. 5 | * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet 6 | * Distributed under the BSD License 7 | * See http://pajhome.org.uk/crypt/md5 for more info. 8 | */ 9 | 10 | /* 11 | * Configurable variables. You may need to tweak these to be compatible with 12 | * the server-side, but the defaults work in most cases. 13 | */ 14 | var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ 15 | var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */ 16 | var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */ 17 | 18 | /* 19 | * These are the functions you'll usually want to call 20 | * They take string arguments and return either hex or base-64 encoded strings 21 | */ 22 | function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));} 23 | function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));} 24 | function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));} 25 | function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); } 26 | function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); } 27 | function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); } 28 | 29 | /* 30 | * Perform a simple self-test to see if the VM is working 31 | */ 32 | function md5_vm_test() 33 | { 34 | return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72"; 35 | } 36 | 37 | /* 38 | * Calculate the MD5 of an array of little-endian words, and a bit length 39 | */ 40 | function core_md5(x, len) 41 | { 42 | /* append padding */ 43 | x[len >> 5] |= 0x80 << ((len) % 32); 44 | x[(((len + 64) >>> 9) << 4) + 14] = len; 45 | 46 | var a = 1732584193; 47 | var b = -271733879; 48 | var c = -1732584194; 49 | var d = 271733878; 50 | 51 | for(var i = 0; i < x.length; i += 16) 52 | { 53 | var olda = a; 54 | var oldb = b; 55 | var oldc = c; 56 | var oldd = d; 57 | 58 | a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936); 59 | d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586); 60 | c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819); 61 | b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330); 62 | a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897); 63 | d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426); 64 | c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341); 65 | b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983); 66 | a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416); 67 | d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417); 68 | c = md5_ff(c, d, a, b, x[i+10], 17, -42063); 69 | b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162); 70 | a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682); 71 | d = md5_ff(d, a, b, c, x[i+13], 12, -40341101); 72 | c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290); 73 | b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329); 74 | 75 | a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510); 76 | d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632); 77 | c = md5_gg(c, d, a, b, x[i+11], 14, 643717713); 78 | b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302); 79 | a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691); 80 | d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083); 81 | c = md5_gg(c, d, a, b, x[i+15], 14, -660478335); 82 | b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848); 83 | a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438); 84 | d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690); 85 | c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961); 86 | b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501); 87 | a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467); 88 | d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784); 89 | c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473); 90 | b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734); 91 | 92 | a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558); 93 | d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463); 94 | c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562); 95 | b = md5_hh(b, c, d, a, x[i+14], 23, -35309556); 96 | a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060); 97 | d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353); 98 | c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632); 99 | b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640); 100 | a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174); 101 | d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222); 102 | c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979); 103 | b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189); 104 | a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487); 105 | d = md5_hh(d, a, b, c, x[i+12], 11, -421815835); 106 | c = md5_hh(c, d, a, b, x[i+15], 16, 530742520); 107 | b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651); 108 | 109 | a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844); 110 | d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415); 111 | c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905); 112 | b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055); 113 | a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571); 114 | d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606); 115 | c = md5_ii(c, d, a, b, x[i+10], 15, -1051523); 116 | b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799); 117 | a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359); 118 | d = md5_ii(d, a, b, c, x[i+15], 10, -30611744); 119 | c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380); 120 | b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649); 121 | a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070); 122 | d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379); 123 | c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259); 124 | b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551); 125 | 126 | a = safe_add(a, olda); 127 | b = safe_add(b, oldb); 128 | c = safe_add(c, oldc); 129 | d = safe_add(d, oldd); 130 | } 131 | return Array(a, b, c, d); 132 | 133 | } 134 | 135 | /* 136 | * These functions implement the four basic operations the algorithm uses. 137 | */ 138 | function md5_cmn(q, a, b, x, s, t) 139 | { 140 | return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b); 141 | } 142 | function md5_ff(a, b, c, d, x, s, t) 143 | { 144 | return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); 145 | } 146 | function md5_gg(a, b, c, d, x, s, t) 147 | { 148 | return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); 149 | } 150 | function md5_hh(a, b, c, d, x, s, t) 151 | { 152 | return md5_cmn(b ^ c ^ d, a, b, x, s, t); 153 | } 154 | function md5_ii(a, b, c, d, x, s, t) 155 | { 156 | return md5_cmn(c ^ (b | (~d)), a, b, x, s, t); 157 | } 158 | 159 | /* 160 | * Calculate the HMAC-MD5, of a key and some data 161 | */ 162 | function core_hmac_md5(key, data) 163 | { 164 | var bkey = str2binl(key); 165 | if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz); 166 | 167 | var ipad = Array(16), opad = Array(16); 168 | for(var i = 0; i < 16; i++) 169 | { 170 | ipad[i] = bkey[i] ^ 0x36363636; 171 | opad[i] = bkey[i] ^ 0x5C5C5C5C; 172 | } 173 | 174 | var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz); 175 | return core_md5(opad.concat(hash), 512 + 128); 176 | } 177 | 178 | /* 179 | * Add integers, wrapping at 2^32. This uses 16-bit operations internally 180 | * to work around bugs in some JS interpreters. 181 | */ 182 | function safe_add(x, y) 183 | { 184 | var lsw = (x & 0xFFFF) + (y & 0xFFFF); 185 | var msw = (x >> 16) + (y >> 16) + (lsw >> 16); 186 | return (msw << 16) | (lsw & 0xFFFF); 187 | } 188 | 189 | /* 190 | * Bitwise rotate a 32-bit number to the left. 191 | */ 192 | function bit_rol(num, cnt) 193 | { 194 | return (num << cnt) | (num >>> (32 - cnt)); 195 | } 196 | 197 | /* 198 | * Convert a string to an array of little-endian words 199 | * If chrsz is ASCII, characters >255 have their hi-byte silently ignored. 200 | */ 201 | function str2binl(str) 202 | { 203 | var bin = Array(); 204 | var mask = (1 << chrsz) - 1; 205 | for(var i = 0; i < str.length * chrsz; i += chrsz) 206 | bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32); 207 | return bin; 208 | } 209 | 210 | /* 211 | * Convert an array of little-endian words to a string 212 | */ 213 | function binl2str(bin) 214 | { 215 | var str = ""; 216 | var mask = (1 << chrsz) - 1; 217 | for(var i = 0; i < bin.length * 32; i += chrsz) 218 | str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask); 219 | return str; 220 | } 221 | 222 | /* 223 | * Convert an array of little-endian words to a hex string. 224 | */ 225 | function binl2hex(binarray) 226 | { 227 | var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; 228 | var str = ""; 229 | for(var i = 0; i < binarray.length * 4; i++) 230 | { 231 | str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) + 232 | hex_tab.charAt((binarray[i>>2] >> ((i%4)*8 )) & 0xF); 233 | } 234 | return str; 235 | } 236 | 237 | /* 238 | * Convert an array of little-endian words to a base-64 string 239 | */ 240 | function binl2b64(binarray) 241 | { 242 | var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 243 | var str = ""; 244 | for(var i = 0; i < binarray.length * 4; i += 3) 245 | { 246 | var triplet = (((binarray[i >> 2] >> 8 * ( i %4)) & 0xFF) << 16) 247 | | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 ) 248 | | ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF); 249 | for(var j = 0; j < 4; j++) 250 | { 251 | if(i * 8 + j * 6 > binarray.length * 32) str += b64pad; 252 | else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); 253 | } 254 | } 255 | return str; 256 | } 257 | -------------------------------------------------------------------------------- /j/ui.js: -------------------------------------------------------------------------------- 1 | // (c) 2010 Reg Braithwaite. All rights to the entirety of the program and its parts are reserved with 2 | // the exception of specific files otherwise licensed. Other licenses apply only to the files where 3 | // they appear. 4 | 5 | ;(function ($, F, undefined) { 6 | 7 | var validate = function (move) { 8 | 9 | }; 10 | 11 | go.ui = { 12 | validate: validate 13 | }; 14 | 15 | var initialize_ui_support = (function () { 16 | 17 | var do_undo = function (event) { 18 | var to_play; 19 | var was_playing; 20 | 21 | var this_index = go.sgf.current.length - 1; 22 | var penultimate_index = go.sgf.floor(go.sgf.current.length - 2); 23 | 24 | go.sgf.undoit($('.move.play .board'), go.sgf.current[this_index], go.sgf.current[penultimate_index]); 25 | 26 | go.sgf.current.pop(); 27 | 28 | }; 29 | 30 | var do_pass = function() { 31 | if (go.sgf.game_info['RE']) return; 32 | 33 | var to_play = go.playing(); 34 | var was_playing = go.opponent(); 35 | var was_playing_index = was_playing[0].toUpperCase(); 36 | var last_move_index = go.sgf.floor(go.sgf.current.length - 1); 37 | 38 | var really_pass = function () { 39 | 40 | var annotation = {}; 41 | annotation[to_play[0].toUpperCase()] = ''; 42 | annotation['MN'] = (last_move_index >= 0 && go.sgf.current[last_move_index]['MN']) ? go.sgf.current[last_move_index]['MN']+ 1 : 1; 43 | go.sgf.push(annotation); 44 | }; 45 | 46 | if (last_move_index >= 0) { 47 | var last_move = go.sgf.current[last_move_index]; 48 | var position = last_move[was_playing_index]; 49 | if (position != undefined && (position == '' || !$('.move.play .board').has('#' + position))) { 50 | go.dialog({ 51 | title: "End Game", 52 | message: "End the game with a second consecutive pass?", 53 | yes_button: "Pass", 54 | no_button: "No", 55 | yes_callback: really_pass 56 | }); 57 | } 58 | else really_pass(); 59 | } 60 | else really_pass(); 61 | }; 62 | 63 | var annotate = function (event_data, key) { 64 | target = $(event_data.target); 65 | if (!target.is('.intersection')) target = target.closest('.intersection'); 66 | if (target.is('.black,.white')) console.error(target.attr('id') + ' is already occupied'); 67 | var killed_stones = $('.move.play .intersection.'+go.opponent()+'.last_liberty_is_'+target.attr('id')); 68 | 69 | var annotation = {}; 70 | annotation[key] = target.attr('id'); 71 | if (killed_stones.size() > 0) { 72 | annotation['K'] = $.map(killed_stones, 'x -> $(x).attr("id")'.lambda()).join(','); 73 | } 74 | var last_move_index = go.sgf.floor(go.sgf.current.length - 1); 75 | annotation['MN'] = (last_move_index >= 0 && go.sgf.current[last_move_index]['MN']) ? go.sgf.current[last_move_index]['MN'] + 1 : 1; 76 | go.sgf.push(annotation); 77 | }; 78 | 79 | var do_play = function (event_data) { 80 | annotate(event_data, go.playing()[0].toUpperCase()); 81 | return false; 82 | }; 83 | 84 | var do_reject_swap = function (event_data) { 85 | var opponent_name = go.sgf.game_info['P' + go.opponent()[0].toUpperCase()]; 86 | var player_name = go.sgf.game_info['P' + go.playing()[0].toUpperCase()]; 87 | $('.move.play') 88 | .removeClass('swap'); 89 | do_play(event_data); 90 | go.sgf.current[go.sgf.current.length - 1].C = player_name + " declines to swap places with " + opponent_name; 91 | return false; 92 | }; 93 | 94 | var do_accept_swap = function (event_data) { 95 | var opponent_name = go.sgf.game_info['P' + go.opponent()[0].toUpperCase()]; 96 | var player_name = go.sgf.game_info['P' + go.playing()[0].toUpperCase()]; 97 | 98 | if (opponent_name.match(/white|black/i) || player_name.match(/white|black/i)) { 99 | if ($('body').is('landscape')) 100 | go.message("Since you've decided to swap, it's your opponent's turn to play " + go.playing()); 101 | $.extend(go.sgf.game_info, { 102 | PH: go.sgf.game_info.PW, 103 | PG: go.sgf.game_info.PB 104 | }); 105 | } 106 | else { 107 | if ($('body').is('landscape')) 108 | go.message("Since you've decided to swap, " + opponent_name + " will play " + go.playing() + ' (this changes PB and PW.)'); 109 | $.extend(go.sgf.game_info, { 110 | PB: go.sgf.game_info.PG, 111 | PW: go.sgf.game_info.PH 112 | }); 113 | } 114 | go.sgf.current.push({ C: player_name + " swaps places with " + opponent_name }); 115 | 116 | $('.move.play') 117 | .removeClass('swap'); 118 | 119 | $('.play .guest.captured') 120 | .removeClass('black') 121 | .addClass('white'); 122 | 123 | $('.board .host.captured') 124 | .removeClass('white') 125 | .addClass('black'); 126 | 127 | go.set_titles(); 128 | return false; 129 | }; 130 | 131 | var do_place = function (event_data) { 132 | annotate(event_data, 'AB'); 133 | return false; 134 | } 135 | 136 | var zoomed_out_p = function() { 137 | return $('.board:last').is('.zoomout'); 138 | }; 139 | 140 | var remove_zoomout = function(selection) { 141 | return $(selection) 142 | .removeClass('zoomout') 143 | .unbind('.zoomout'); 144 | }; 145 | 146 | var remove_zoomin = function(selection) { 147 | return $(selection) 148 | .removeClass('zoomin') 149 | .unbind('.zoomin') 150 | .removedragscrollable(); 151 | }; 152 | 153 | var really_zoomout = function(selection) { 154 | return $(selection) 155 | .filter('.board:not(.zoomout)') 156 | .K(remove_zoomin) 157 | .addClass('zoomout'); 158 | }; 159 | 160 | var really_zoomin = function (target) { 161 | var across; 162 | var down; 163 | var board; 164 | if (typeof(target) == 'undefined') { 165 | across = 0; 166 | down = 0; 167 | board = null; 168 | } 169 | else { 170 | down = $(target) 171 | .closest('.row') 172 | .prevAll('.row') 173 | .size(); 174 | across = $(target) 175 | .prevAll('.intersection') 176 | .size(); 177 | board = $(target).closest('.board'); 178 | } 179 | return function(selection) { 180 | $(selection) 181 | .filter('.board:not(.zoomin)') 182 | .K(remove_zoomout) 183 | .addClass('zoomin') 184 | .dragscrollable({ preventDefault: false }); 185 | if (typeof(board) != 'undefined') { 186 | var new_target = (across == 0 && down == 0) ? null : board.find('.row:nth-child('+down+') .intersection:nth-child('+across+')'); 187 | board 188 | .scrollLeft(across == 0 ? 0 : (new_target.width() * across) - (board.width() / 2)) // handles min and max for us 189 | .scrollTop(down == 0 ? 0 : (new_target.height() * down) - (board.height() / 2)); 190 | } 191 | }; 192 | }; 193 | 194 | var do_zoomin = function(event) { 195 | $('.board') 196 | .K(really_zoomin(event.target)); 197 | $(this) 198 | .children(':first') 199 | .trigger(event.gesture_data.originalEvent); 200 | return false; 201 | }; 202 | 203 | var do_zoomout = function(event) { 204 | $('.board') 205 | .K(really_zoomout); 206 | return false; 207 | }; 208 | 209 | var do_scale = function(event, data) { 210 | if (event.scale <= 0.75) 211 | $('.board') 212 | .K(really_zoomout); 213 | else if (event.scale >= 1.5) 214 | $('.board') 215 | .K(really_zoomin(event.target)); 216 | return false; 217 | }; 218 | 219 | var show_play_info = function (event) { 220 | var whites = 0; 221 | var blacks = 0; 222 | $.each(go.sgf.current, function (index, properties) { 223 | if (properties.W && properties.K) 224 | blacks = blacks + 1 + ((properties.K.length - 2) / 3); 225 | else if (properties.W && properties.K) 226 | whites = whites + 1 + ((properties.K.length - 2) / 3); 227 | }); 228 | $('#info') 229 | .find('.captured_blacks') 230 | .text(blacks == 0 ? 'no stones' : (blacks == 1 ? 'one stone' : '' + blacks + ' stones')) 231 | .end() 232 | .find('.captured_whites') 233 | .text(whites == 0 ? 'no stones' : (whites == 1 ? 'one stone' : '' + whites + ' stones')) 234 | .end(); 235 | jQT.goTo($('#info'), 'slideup.reverse'); 236 | return false; 237 | }; 238 | 239 | return function() { 240 | $('.move.play') 241 | .gesture(['click', 'circle', 'close']); 242 | $('.move') 243 | .gesture([ 244 | 'bottom', 'hold', 'scale', 'left', 'right', 'open', 245 | { scrub: function(target) { 246 | return $(target) 247 | .parents('body > *') 248 | .find('.scrub'); 249 | } 250 | } 251 | ]); 252 | $('.move.play:has(.zoomout)') 253 | .live('gesture_open', 254 | function () { 255 | go.dialog({ 256 | title: "New Game", 257 | message: "Start a new game from scratch?", 258 | yes_button: "New", 259 | yes_callback: function () { jQT.swapPages( $('.move.play'), $('#new'), 'dissolve'); } 260 | }); 261 | return false; 262 | } 263 | ); 264 | 265 | $('.board') 266 | .live('gesture_scale', do_scale); 267 | 268 | $('.board.zoomout') 269 | .live('gesture_hold', do_zoomin); 270 | $('.board.zoomin') 271 | .live('gesture_hold', do_zoomout); 272 | 273 | $('.move.play .board.pass:not(:has(.playable_black.black,.playable_white.white))') 274 | .live('gesture_close', do_pass); 275 | 276 | $('.move.play .board:not(.pass):not(:has(.playable_black.black,.playable_white.white))') 277 | .live('gesture_close', function () {go.message("Sorry, the rules prohibit passing at this time");}); 278 | 279 | $('.move.play .board') 280 | .live('gesture_scrub', do_undo) 281 | .live('gesture_bottom', show_play_info); 282 | 283 | $('#info') 284 | .gesture(['top']) 285 | .bind('gesture_top', function(event) { jQT.goBack(); }); 286 | 287 | $('.move.play.black:not(.swap) .board.play .playable_black') 288 | .live('gesture_click', do_play); 289 | $('.move.play.white:not(.swap) .board.play .playable_white') 290 | .live('gesture_click', do_play); 291 | 292 | $('.move.play.black .board.place .playable_black') 293 | .live('gesture_click', do_place); 294 | $('.move.play.white .board.place .playable_white') 295 | .live('gesture_click', do_place); 296 | 297 | $('.move.play.black.swap .board.play .playable_black') 298 | .live('gesture_click', do_reject_swap); 299 | $('.move.play.white.swap .board.play .playable_white') 300 | .live('gesture_click', do_reject_swap); 301 | 302 | $('.move.play.swap .board.play') 303 | .live('gesture_circle', do_accept_swap); 304 | 305 | }; 306 | })(); 307 | 308 | go.on_document_ready(initialize_ui_support); 309 | 310 | })(jQuery, Functional); -------------------------------------------------------------------------------- /c/sass/board.iphone.sass: -------------------------------------------------------------------------------- 1 | .board.size19 2 | $full_cells: 19 3 | $zoom_out_size: 14px 4 | $zoom_out_cells: $full_cells 5 | $zoom_in_size: 30px 6 | $zoom_in_cells: 9 7 | &.zoomin 8 | width: $zoom_in_size * $zoom_in_cells 9 | height: $zoom_in_size * $zoom_in_cells 10 | .row 11 | height: $zoom_in_size 12 | width: $zoom_in_size * $full_cells 13 | img 14 | height: $zoom_in_size 15 | width: $zoom_in_size 16 | &.zoomout 17 | width: $zoom_out_size * $full_cells 18 | height: $zoom_out_size * $full_cells 19 | .row 20 | height: $zoom_out_size 21 | width: $zoom_out_size * $zoom_out_cells 22 | img 23 | height: $zoom_out_size 24 | width: $zoom_out_size 25 | 26 | .board.size17 27 | $full_cells: 17 28 | $zoom_out_size: 15px 29 | $zoom_out_cells: $full_cells 30 | $zoom_in_size: 30px 31 | $zoom_in_cells: 9 32 | &.zoomin 33 | width: $zoom_in_size * $zoom_in_cells 34 | height: $zoom_in_size * $zoom_in_cells 35 | .row 36 | height: $zoom_in_size 37 | width: $zoom_in_size * $full_cells 38 | img 39 | height: $zoom_in_size 40 | width: $zoom_in_size 41 | &.zoomout 42 | width: $zoom_out_size * $full_cells 43 | height: $zoom_out_size * $full_cells 44 | .row 45 | height: $zoom_out_size 46 | width: $zoom_out_size * $zoom_out_cells 47 | img 48 | height: $zoom_out_size 49 | width: $zoom_out_size 50 | 51 | .board.size15 52 | $full_cells: 15 53 | $zoom_out_size: 18px 54 | $zoom_out_cells: $full_cells 55 | $zoom_in_size: 30px 56 | $zoom_in_cells: 9 57 | &.zoomin 58 | width: $zoom_in_size * $zoom_in_cells 59 | height: $zoom_in_size * $zoom_in_cells 60 | .row 61 | height: $zoom_in_size 62 | width: $zoom_in_size * $full_cells 63 | img 64 | height: $zoom_in_size 65 | width: $zoom_in_size 66 | &.zoomout 67 | width: $zoom_out_size * $full_cells 68 | height: $zoom_out_size * $full_cells 69 | .row 70 | height: $zoom_out_size 71 | width: $zoom_out_size * $zoom_out_cells 72 | img 73 | height: $zoom_out_size 74 | width: $zoom_out_size 75 | 76 | .board.size13 77 | $full_cells: 13 78 | $zoom_out_size: 20px 79 | $zoom_out_cells: $full_cells 80 | $zoom_in_size: 30px 81 | $zoom_in_cells: 9 82 | &.zoomin 83 | width: $zoom_in_size * $zoom_in_cells 84 | height: $zoom_in_size * $zoom_in_cells 85 | .row 86 | height: $zoom_in_size 87 | width: $zoom_in_size * $full_cells 88 | img 89 | height: $zoom_in_size 90 | width: $zoom_in_size 91 | &.zoomout 92 | width: $zoom_out_size * $full_cells 93 | height: $zoom_out_size * $full_cells 94 | .row 95 | height: $zoom_out_size 96 | width: $zoom_out_size * $zoom_out_cells 97 | img 98 | height: $zoom_out_size 99 | width: $zoom_out_size 100 | 101 | .board.size11 102 | $full_cells: 11 103 | $zoom_out_size: 24px 104 | $zoom_out_cells: $full_cells 105 | $zoom_in_size: 30px 106 | $zoom_in_cells: 9 107 | &.zoomin 108 | width: $zoom_in_size * $zoom_in_cells 109 | height: $zoom_in_size * $zoom_in_cells 110 | .row 111 | height: $zoom_in_size 112 | width: $zoom_in_size * $full_cells 113 | img 114 | height: $zoom_in_size 115 | width: $zoom_in_size 116 | &.zoomout 117 | width: $zoom_out_size * $full_cells 118 | height: $zoom_out_size * $full_cells 119 | .row 120 | height: $zoom_out_size 121 | width: $zoom_out_size * $zoom_out_cells 122 | img 123 | height: $zoom_out_size 124 | width: $zoom_out_size 125 | 126 | .board.size9 127 | $full_cells: 9 128 | $zoom_out_size: 30px 129 | $zoom_out_cells: $full_cells 130 | $zoom_in_size: 30px 131 | $zoom_in_cells: 9 132 | &.zoomin 133 | width: $zoom_in_size * $zoom_in_cells 134 | height: $zoom_in_size * $zoom_in_cells 135 | .row 136 | height: $zoom_in_size 137 | width: $zoom_in_size * $full_cells 138 | img 139 | height: $zoom_in_size 140 | width: $zoom_in_size 141 | &.zoomout 142 | width: $zoom_out_size * $full_cells 143 | height: $zoom_out_size * $full_cells 144 | .row 145 | height: $zoom_out_size 146 | width: $zoom_out_size * $zoom_out_cells 147 | img 148 | height: $zoom_out_size 149 | width: $zoom_out_size 150 | 151 | .board 152 | overflow: hidden 153 | position: relative 154 | left: 50% 155 | :margin 156 | :left -135px 157 | :top 10px 158 | .intersections 159 | position: relative 160 | background: black 161 | .intersection 162 | :display inline-block 163 | .row 164 | &:first-child 165 | .intersection 166 | &:first-child 167 | &.black 168 | background: url('../i/board/temporary/tile1nw.png') 169 | &.playable_black,&.playable_white 170 | background: url('../i/board/temporary/tile1nwd.png') !important 171 | &.latest 172 | background: url('../i/board/temporary/tile1nwd.png') !important 173 | &.white 174 | background: url('../i/board/temporary/tile2nw.png') 175 | &.playable_black,&.playable_white 176 | background: url('../i/board/temporary/tile2nwd.png') !important 177 | &.latest 178 | background: url('../i/board/temporary/tile2nwd.png') !important 179 | &:not(.black):not(.white) 180 | background: url('../i/board/temporary/tile0nw.png') 181 | &:not(:first-child):not(:last-child) 182 | &.black 183 | background: url('../i/board/temporary/tile1n.png') 184 | &.playable_black,&.playable_white 185 | background: url('../i/board/temporary/tile1nd.png') !important 186 | &.latest 187 | background: url('../i/board/temporary/tile1nd.png') !important 188 | &.white 189 | background: url('../i/board/temporary/tile2n.png') 190 | &.playable_black,&.playable_white 191 | background: url('../i/board/temporary/tile2nd.png') !important 192 | &.latest 193 | background: url('../i/board/temporary/tile2nd.png') !important 194 | &:not(.black):not(.white) 195 | background: url('../i/board/temporary/tile0n.png') 196 | &:last-child 197 | &.black 198 | background: url('../i/board/temporary/tile1ne.png') 199 | &.playable_black,&.playable_white 200 | background: url('../i/board/temporary/tile1ned.png') !important 201 | &.latest 202 | background: url('../i/board/temporary/tile1ned.png') !important 203 | &.white 204 | background: url('../i/board/temporary/tile2ne.png') 205 | &.playable_black,&.playable_white 206 | background: url('../i/board/temporary/tile2ned.png') !important 207 | &.latest 208 | background: url('../i/board/temporary/tile2ned.png') !important 209 | &:not(.black):not(.white) 210 | background: url('../i/board/temporary/tile0ne.png') 211 | &:not(:first-child):not(:last-child) 212 | .intersection 213 | &:first-child 214 | &.black 215 | background: url('../i/board/temporary/tile1w.png') 216 | &.playable_black,&.playable_white 217 | background: url('../i/board/temporary/tile1wd.png') !important 218 | &.latest 219 | background: url('../i/board/temporary/tile1wd.png') !important 220 | &.white 221 | background: url('../i/board/temporary/tile2w.png') 222 | &.playable_black,&.playable_white 223 | background: url('../i/board/temporary/tile2wd.png') !important 224 | &.latest 225 | background: url('../i/board/temporary/tile2wd.png') !important 226 | &:not(.black):not(.white) 227 | background: url('../i/board/temporary/tile0w.png') 228 | &:not(:first-child):not(:last-child) 229 | &.black 230 | background: url('../i/board/temporary/tile1.png') 231 | &.playable_black,&.playable_white 232 | background: url('../i/board/temporary/tile1d.png') !important 233 | &.latest 234 | background: url('../i/board/temporary/tile1d.png') !important 235 | &.white 236 | background: url('../i/board/temporary/tile2.png') 237 | &.playable_black,&.playable_white 238 | background: url('../i/board/temporary/tile2d.png') !important 239 | &.latest 240 | background: url('../i/board/temporary/tile2d.png') !important 241 | &:last-child 242 | &.black 243 | background: url('../i/board/temporary/tile1e.png') 244 | &.playable_black,&.playable_white 245 | background: url('../i/board/temporary/tile1ed.png') !important 246 | &.latest 247 | background: url('../i/board/temporary/tile1ed.png') !important 248 | &.white 249 | background: url('../i/board/temporary/tile2e.png') 250 | &.playable_black,&.playable_white 251 | background: url('../i/board/temporary/tile2ed.png') !important 252 | &.latest 253 | background: url('../i/board/temporary/tile2ed.png') !important 254 | &:not(.black):not(.white) 255 | background: url('../i/board/temporary/tile0e.png') 256 | &:last-child 257 | .intersection 258 | &:first-child 259 | &.black 260 | background: url('../i/board/temporary/tile1sw.png') 261 | &.playable_black,&.playable_white 262 | background: url('../i/board/temporary/tile1swd.png') !important 263 | &.latest 264 | background: url('../i/board/temporary/tile1swd.png') !important 265 | &.white 266 | background: url('../i/board/temporary/tile2sw.png') 267 | &.playable_black,&.playable_white 268 | background: url('../i/board/temporary/tile2swd.png') !important 269 | &.latest 270 | background: url('../i/board/temporary/tile2swd.png') !important 271 | &:not(.black):not(.white) 272 | background: url('../i/board/temporary/tile0sw.png') 273 | &:not(:first-child):not(:last-child) 274 | &.black 275 | background: url('../i/board/temporary/tile1s.png') 276 | &.playable_black,&.playable_white 277 | background: url('../i/board/temporary/tile1sd.png') !important 278 | &.latest 279 | background: url('../i/board/temporary/tile1sd.png') !important 280 | &.white 281 | background: url('../i/board/temporary/tile2s.png') 282 | &.playable_black,&.playable_white 283 | background: url('../i/board/temporary/tile2sd.png') !important 284 | &.latest 285 | background: url('../i/board/temporary/tile2sd.png') !important 286 | &:not(.black):not(.white) 287 | background: url('../i/board/temporary/tile0s.png') 288 | &:last-child 289 | &.black 290 | background: url('../i/board/temporary/tile1se.png') 291 | &.playable_black,&.playable_white 292 | background: url('../i/board/temporary/tile1sed.png') !important 293 | &.latest 294 | background: url('../i/board/temporary/tile1sed.png') !important 295 | &.white 296 | background: url('../i/board/temporary/tile2se.png') 297 | &.playable_black,&.playable_white 298 | background: url('../i/board/temporary/tile2sed.png') !important 299 | &.latest 300 | background: url('../i/board/temporary/tile2sed.png') !important 301 | &:not(.black):not(.white) 302 | background: url('../i/board/temporary/tile0se.png') 303 | .star 304 | &.black 305 | background: url('../i/board/temporary/tile1.png') 306 | &.playable_black,&.playable_white 307 | background: url('../i/board/temporary/tile1d.png') !important 308 | &.latest 309 | background: url('../i/board/temporary/tile1d.png') !important 310 | &.white 311 | background: url('../i/board/temporary/tile2.png') 312 | &.playable_black,&.playable_white 313 | background: url('../i/board/temporary/tile2d.png') !important 314 | &.latest 315 | background: url('../i/board/temporary/tile2d.png') !important 316 | &:not(.black):not(.white) 317 | background: url('../i/board/temporary/tile0c.png') 318 | &.playable_black,&.playable_white 319 | BEFORE: URL('../i/board/temporary/tile0c.png') 320 | 321 | @mixin interior($corner,$middle) 322 | .row 323 | &:nth-child(#{$corner}),&:nth-child(#{$middle}),&:nth-last-child(#{$corner}) 324 | .intersection:not(.black):not(.white) 325 | &:nth-child(#{$corner}),&:nth-child(#{$middle}),&:nth-last-child(#{$corner}) 326 | background: url('../i/board/temporary/tile0c.png') 327 | &:not(:nth-child(#{$corner})):not(:nth-child(#{$middle})):not(:nth-last-child(#{$corner})):not(:first-child):not(:last-child) 328 | background: url('../i/board/temporary/tile0.png') 329 | &:not(:nth-child(#{$corner})):not(:nth-child(#{$middle})):not(:nth-last-child(#{$corner})):not(:first-child):not(:last-child) 330 | .intersection:not(.black):not(.white):not(:first-child):not(:last-child) 331 | background: url('../i/board/temporary/tile0.png') 332 | 333 | .board 334 | &.size9 335 | @include interior(3,5) 336 | &.size11 337 | @include interior(3,6) 338 | &.size13 339 | @include interior(4,7) 340 | &.size15 341 | @include interior(4,8) 342 | &.size17 343 | @include interior(4,9) 344 | &.size19 345 | @include interior(4,10) 346 | 347 | .intersection 348 | &.playable_black,&.playable_white 349 | cursor: pointer 350 | 351 | .move 352 | .actions 353 | .send 354 | :display none 355 | 356 | .move.playing 357 | .actions 358 | .send 359 | :display inline !important 360 | 361 | .intersection 362 | -o-background-size: 100% 363 | -webkit-background-size: 100% 364 | -khtml-background-size: 100% 365 | -moz-background-size: 100% -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | Wood & Stones 2 | === 3 | 4 | Go is "an ancient oriental board game for two players that is noted for being rich in strategy despite its simple rules." [I tried to learn Go](http://github.com/raganwald/homoiconic/blob/master/2009-10-20/high_anxiety.md#readme "High Anxiety") recently, and it was a rich and rewarding personal experience to struggle with my inability to play at even a novice level. I received a lot of [great feedback][hn] about that post, including a nice comment from Dave Peck, who pointed me to his weekend project, [Dave Peck's Go](http://github.com/davepeck/appengine-go "[Dave Peck's Go]"). 5 | 6 | The sense of adventure in finding things out can be experienced in many different ways. Learning to play less poorly is one way. Another is to write a game playing algorithm, something that has fascinated me since I wrote a [Maharajah and the Sepoys](http://en.wikipedia.org/wiki/Maharajah_and_the_Sepoys) playing game in BASIC back at St. Andrews' College in 1977. A third is to write a server that adjudicates play between two humans. This is clearly less difficult but still provides opportunities for creativity and expression, which is why it is a [favourite interview question](http://weblog.raganwald.com/2006/06/my-favourite-interview-question.html "My favourite interview question"). 7 | 8 | So, here is "[Wood & Stones][index]," a pass and play local web application that adjudicates a game of Go between two players. This is an ongoing work, with both feature design, UX design, and software design changing on an almost daily basis. That is a long-winded way of saying that IMHO the code is nearly complete crap. It is as if you picked up an architect's sketch pad and looked at a page to find it covered with scribbles and cross-outs. 9 | 10 | > This is written *specifically* for the iPad at this time. I also test it on OS X Safari. Updated stylesheets for the iPhone/iPod Touch are in the works. I have made no attempt to test it on any other OS or browser. This is a pass-and-play application: It's for playing face-to-face with someone, not for playing the computer or playing with someone over the Internet ([Issue 250][igs]). It turns an iPad into a portable go board that knows something about legal moves, can set up pieces for you, and allows you to go back and review the game. 11 | 12 | help with playing 13 | --- 14 | 15 | To start a new game, open [Wood & Stones][index] using your iPad (it used to work just fine on iPhone, but I haven't gotten around to selecting the correct style sheet depending on whether you're on an iPhone or an iPad. [Issue 275][styles]!): 16 | 17 | ![Start][start] 18 | 19 | If you want, you can give nicknames for each player. If you don't, you will be "Black" and "White" respectively. 20 | 21 | Choose game to play, a board size, and setup. "Classic Go" is exactly what you think it is. The other options are why I had the stones to call this "Wood & Stones." Click "play" and you can start your game. 22 | 23 | ![White to Play][white_to_play] 24 | 25 | In direct violation of [The Design of Everyday Things](http://www.amazon.com/gp/product/0465067107?ie=UTF8&tag=raganwald001-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=0465067107 "Amazon.com: The Design of Everyday Things (9780465067107): Donald A. Norman: Books"), Wood & Stones is an experiment with *removing* the visible affordances in the User Interface. I am trying to make as much as possible work with gestures like swiping the screen or drawing simple symbols. 26 | 27 | When it's your turn to play, tap the intersection where you wish to play a stone. If your play kills any of your opponent's stones, they will fade from sight. If you like your play, pass the iPad to your opponent and it's their turn. If you don't like your play, "scrub" the board by swiping rapidly from left to right to left three or more times. It will be your turn again and you can tap a different intersection. You can undo multiple times if you want. 28 | 29 | To pass, draw an "X" using three continuous strokes of your finger: 30 | 31 | ![Pass Gesture][pass] 32 | 33 | If it is the second pass, you will be asked to confirm that you wish to end the game. Yes, you can scrub to undo a pass. If a game ends with two passes, it's up to you and your opponent to figure out who won. 34 | 35 | **history and info** 36 | 37 | If you would like to see a history of the game, you move backwards in time by swiping from left to right. This is like moving the film so that the past becomes visible. Each swipe from left to right moves back one move. You can move forward in the history by swiping from right to left. Once you have returned to the current move, swiping right to left does nothing further. 38 | 39 | You can see the game's current status by swiping towards the bottom of the screen: 40 | 41 | ![Show Info][bottom] 42 | 43 | The game info will slide down from the top of the screen: 44 | 45 | ![Game Info][info] 46 | 47 | To go back to the play of the game, swipe towards the top of the screen: 48 | 49 | ![Return to Play][top] 50 | 51 | **zooming and dragging** 52 | 53 | With larger boards, it can be a challenge to tap the correct stone location on an iPhone or iPod Touch. To zoom in, hold your finger or mouse down on the board. After a moment, the board will zoom. While zoomed in, you can tap to place a stone or drag the board to pan it around. When zoomed in, you cannot go back or forward in the history as the swipe becomes a pan. To zoom back out, hold your finger or mouse down again. 54 | 55 | On multi-touch devices, you can also use the pinch gesture to zoom in or out. 56 | 57 | games with standard rules and victory conditions 58 | --- 59 | 60 | The application is specifically written to support other games, most of which are documented on [Sensei's Go Variant Page][sgv]. Each game offers a variety of setup options. The most 'normal' games to the Go player are those that have the exact same rules and victory conditions, namely territory plus captures. They differ only in how the board is set up at the beginning of play. 61 | 62 | **Classic**: This is the standard game of Go with the standard options for setup: Either black plays first, or black is awarded a handicap of between two and nine stones and white plays first. Handicap stones are placed on the Hoshi points in the conventional manner. Wood & Stones does not score the game but it will end the game after two consecutive passes. 63 | 64 | **Free Placement**: This is also the standard rules for Go, however if black is granted a handicap, black plays the stones wherever he likes rather than having them placed on the standard Hoshi points. For example, if black is given a handicap of three stones, he will play the first three moves in a row and then white will play and the turns will alternate in the normal fashion for the remainder of the game. 65 | 66 | **More Setups**: Once again the rules are the standard rules of Go, however the initial setup differs radically from tranditional Go. The options include: 67 | 68 | * [Pie Rule][pie]: Black plays a single stone first. White has two choices. If he plays a stone, the game continues normally. However, white can also *swap* places by drawing a circle on the board with his finger. The two players switch colours, and the player who was originally black is now white and the player who was originally white is now black. The effect of this rule is that Black does not wish to make too strong an opening play for fear that white will choose to swap. Likewise, black does not wish to make too weak a play either, so he should make a play that ideally is perfectly balanced. 69 | 70 | * [Wild Fuskeki][wild]: This is a standard game, however the first three moves are randomly chosen for each player. Black can have up to six randomly placed handicap stones. Initial positions will never include dead stones, ataris, or stones placed in either of the two edge rows or columns. Wild Fuseki discourages extensive memorization of opening play sequences and encourages strong fundamental style. (*Really Wild Fuseki* is exactly the same thing, however *twelve* stones are placed for each player.) 71 | 72 | ![Wild Fuseki][iwild] 73 | 74 | * [Influence Go][influence] gives each player opposing edges of the board. This game usually involves a fight to secure the center and establish a connection to your strong sides. 75 | 76 | ![Influence Go][iinfluence] 77 | 78 | * [Dots Go][dots] consists of stones on alternate intersections of the board. Games evolve very differently than standard Go. 79 | 80 | ![Dots Go][idots] 81 | 82 | * [Sunjang Baduk][baduk] is an archaic Korean version of Go. There is a prescribed opening position, and the scoring is a little different from Japanese or Chinese go. Even if you don't care to play with different scoring, you might find games with the Sunjang Baduk opening setup a refreshing change of pace. 83 | 84 | * [Classical Chinese Opening][classical] go players started each game with two stones each on corner Hoshi points, leading to fighting. Classical Chinese rules were also different, however choosing this option starts a standard game of Go with the Classical Chinese Opening. 85 | 86 | games where white is trying to live 87 | --- 88 | 89 | Some games have standard rules but different victory conditions. A number of these games share the common theme of a struggle for white to survive against crushing odds. In these games, white wins if he can create life. Black wins the moment there are no white stones on the board. 90 | 91 | * [Corner Go][corner] is a corner invasion exercise: Only one corner is available to White. Corner Go works well on small boards. 92 | 93 | ![Corner Go][icorner] 94 | 95 | * [Shape Go][shape] gives Black unkillable stones all the way around the board, and white has to try to make life with no corners or edges. Best on larger boards. 96 | 97 | ![Shape Go][ibox] 98 | 99 | * In the [Kill-all][killall] game, black is given a large number of free placements and white simply tries to survive. An even game is thought to be seventeen placements on a 19x19 board, however you can choose more or fewer to establish a handicap. You may also choose a smaller board and fewer placements. 100 | 101 | other games with non-standard victory conditions 102 | --- 103 | 104 | * [Atari Go][atari] uses normal rules on a 9x9 board, however the winner is the first to capture an opponent's stone. There is a progression of teaching setups given with the student playing black. The final setup, Cross-cutting, should lead to successive draws. When a student can always draw in this situation, they can move up to Capture Five. 105 | 106 | * *Capture Five* uses normal rules on a small board, however the winner is the first to capture five stones. This introduces the idea of sacrifice into the game. It is a natural progression from Atari Go. 107 | 108 | * [Irensei][irensei] is a game with standard Go rules, however captures and territory are irrelevant to scoring. The winner is the first player to make an unbroken line of seven stones in a row, although a line with stones within two intersections of the edge does not count. Black plays first, and to counter this advantage there is a special rule that black loses if he makes a line of eight or more stones. White can make a line of any length. 109 | 110 | games with slightly different rules 111 | --- 112 | 113 | * In [Gonnect][gonnect], the winner is the first to connect either pair of opposite sides of the board with a single group *or* a player loses when he has no legal move available. *Passing is not allowed*. This difference from normal Go is crucial, as it prevents a deadlock where neither player can connect: each player must eventually fill in their territory until they are vulnerable to capture or have no legal moves available. 114 | 115 | * In [One Eyed Go][oneeye], suicide is never allowed, even if your play would otherwise capture stones. One consequence of this simplification of the rules is that a single eye is enough to make a group safe. 116 | 117 | code confessions, a/k/a estimating the WTFs per LOC 118 | --- 119 | 120 | This is my first [jQuery](http://jquery.com/ "jQuery: The Write Less, Do More, JavaScript Library") project, and it shows. I'm also using [jQTouch](http://www.jqtouch.com/), although I'm using less and less of it as I get more comfortable with Mobile Safari. I've picked up a few other jQuery plugins, including my own [iGesture][igesture] for gestures like swipes and scrubs. 121 | 122 | **license terms** 123 | 124 | (c) 2010 Reg Braithwaite. All rights to the entirety of the program and the parts I have written are reserved with the exception of specific files otherwise licensed. Other licenses apply only to the files where they appear. This may change in time, check back. 125 | 126 | Exemptions include iGesture and Dragscrollable, which I have licensed under the MIT license, plus various jquery plugins written by others. 127 | 128 | All of the images used in the main game board are modified versions of files Dave Peck found on the Wikimedia Commons. These 129 | are distributed with the Creative Commons Attribution 2.0 ShareAlike license. Some other images were hand-drawn by Dave Peck, who put them under the Creative Commons Attribution ShareAlike 2.0 license: http://creativecommons.org/licenses/by-sa/2.0/ 130 | 131 | [igesture]: http://github.com/raganwald/iGesture 132 | [index]: http://raganwald.github.com/wood_and_stones/index.html 133 | [start]: http://raganwald.github.com/wood_and_stones/i/about/start.png 134 | [white_to_play]: http://raganwald.github.com/wood_and_stones/i/about/white_to_play.png 135 | [pass]: http://raganwald.github.com/wood_and_stones/i/about/pass.png 136 | [oneeye]: http://senseis.xmp.net/?OneEyedGo 137 | [atari]: http://senseis.xmp.net/?AtariGo 138 | [gonnect]: http://senseis.xmp.net/?Gonnect 139 | [sgv]: http://senseis.xmp.net/?GoVariant 140 | [wild]: http://senseis.xmp.net/?WildFuseki 141 | [corner]: http://senseis.xmp.net/?BiggestCorner 142 | [shape]: http://senseis.xmp.net/?ShapeGameSolid 143 | [influence]: http://senseis.xmp.net/?InfluenceGo 144 | [dots]: http://senseis.xmp.net/?DotsGo 145 | [ibox]: http://raganwald.github.com/wood_and_stones/i/about/box.png 146 | [idots]: http://raganwald.github.com/wood_and_stones/i/about/dots.png 147 | [iinfluence]: http://raganwald.github.com/wood_and_stones/i/about/influence.png 148 | [icorner]: http://raganwald.github.com/wood_and_stones/i/about/corner.png 149 | [iwild]: http://raganwald.github.com/wood_and_stones/i/about/wild.png 150 | [info]: http://raganwald.github.com/wood_and_stones/i/about/info.png 151 | [bottom]: http://raganwald.github.com/wood_and_stones/i/about/bottom.png 152 | [top]: http://raganwald.github.com/wood_and_stones/i/about/top.png 153 | [baduk]: http://senseis.xmp.net/?SunjangBaduk 154 | [classical]: http://senseis.xmp.net/?ChineseClassicalOpening 155 | [killall]: http://senseis.xmp.net/?KillAllGame 156 | [pie]: http://en.wikipedia.org/wiki/Pie_rule 157 | [irensei]: http://en.wikipedia.org/wiki/Irensei 158 | [igs]: http://github.com/raganwald/wood_and_stones/issues/#issue/250 159 | [styles]: http://github.com/raganwald/wood_and_stones/issues/#issue/275 160 | [hn]: http://news.ycombinator.com/item?id=904765 -------------------------------------------------------------------------------- /c/sass/jqtouch.ipad.customized.sass: -------------------------------------------------------------------------------- 1 | body 2 | background: #000 3 | color: #ddd 4 | > * 5 | background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#333333), to(#5e5e65)) 6 | 7 | h1, h2 8 | font: bold 18px Helvetica 9 | text-shadow: rgba(255, 255, 255, 0.2) 0 1px 1px 10 | color: #000 11 | margin: 10px 20px 5px 12 | 13 | /* @group Toolbar 14 | 15 | .toolbar 16 | -webkit-box-sizing: border-box 17 | border-bottom: 1px solid #000 18 | padding: 10px 19 | height: 45px 20 | background: url(../i/themes/jqt/img/toolbar.png) black repeat-x 21 | position: relative 22 | 23 | .black-translucent .toolbar 24 | margin-top: 20px 25 | 26 | .toolbar > h1 27 | position: absolute 28 | overflow: hidden 29 | left: 50% 30 | top: 10px 31 | line-height: 1em 32 | margin: 1px 0 0 -192px 33 | height: 40px 34 | font-size: 20px 35 | width: 384px 36 | font-weight: bold 37 | text-shadow: rgba(0, 0, 0, 1) 0 -1px 1px 38 | text-align: center 39 | text-overflow: ellipsis 40 | white-space: nowrap 41 | color: #fff 42 | 43 | body.landscape .toolbar > h1 44 | margin-left: -256px 45 | width: 512px 46 | 47 | .button, .back, .cancel, .add 48 | position: absolute 49 | overflow: hidden 50 | top: 8px 51 | right: 10px 52 | margin: 0 53 | border-width: 0 5px 54 | padding: 0 3px 55 | width: auto 56 | height: 30px 57 | line-height: 30px 58 | font-family: inherit 59 | font-size: 12px 60 | font-weight: bold 61 | color: #fff 62 | text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0 63 | text-overflow: ellipsis 64 | text-decoration: none 65 | white-space: nowrap 66 | background: none 67 | -webkit-border-image: url(../i/themes/jqt/img/button.png) 0 5 0 5 68 | 69 | .blueButton 70 | -webkit-border-image: url(../i/themes/jqt/img/blueButton.png) 0 5 0 5 71 | border-width: 0 5px 72 | 73 | .back 74 | left: 6px 75 | right: auto 76 | padding: 0 77 | max-width: 55px 78 | border-width: 0 8px 0 14px 79 | -webkit-border-image: url(../i/themes/jqt/img/back_button.png) 0 8 0 14 80 | &.active 81 | -webkit-border-image: url(../i/themes/jqt/img/back_button_clicked.png) 0 8 0 14 82 | color: #aaa 83 | 84 | .leftButton, .cancel 85 | left: 6px 86 | right: auto 87 | 88 | .add 89 | font-size: 24px 90 | line-height: 24px 91 | font-weight: bold 92 | 93 | .whiteButton, .grayButton 94 | display: block 95 | border-width: 0 12px 96 | padding: 10px 97 | text-align: center 98 | font-size: 20px 99 | font-weight: bold 100 | text-decoration: inherit 101 | color: inherit 102 | 103 | .whiteButton 104 | -webkit-border-image: url(../i/themes/jqt/img/whiteButton.png) 0 12 0 12 105 | text-shadow: rgba(255, 255, 255, 0.7) 0 1px 0 106 | 107 | .grayButton 108 | -webkit-border-image: url(../i/themes/jqt/img/grayButton.png) 0 12 0 12 109 | color: #FFFFFF 110 | 111 | /* @end 112 | /* @group Lists 113 | 114 | h1 + ul, h2 + ul, h3 + ul, h4 + ul, h5 + ul, h6 + ul 115 | margin-top: 0 116 | 117 | ul 118 | color: #aaa 119 | border: 1px solid #333333 120 | font: bold 18px Helvetica 121 | padding: 0 122 | margin: 15px 10px 17px 10px 123 | &.rounded 124 | -webkit-border-radius: 8px 125 | -webkit-box-shadow: rgba(0, 0, 0, 0.3) 1px 1px 3px 126 | li 127 | &:first-child 128 | border-top: 0 129 | -webkit-border-top-left-radius: 8px 130 | -webkit-border-top-right-radius: 8px 131 | a 132 | border-top: 0 133 | -webkit-border-top-left-radius: 8px 134 | -webkit-border-top-right-radius: 8px 135 | &:last-child 136 | -webkit-border-bottom-left-radius: 8px 137 | -webkit-border-bottom-right-radius: 8px 138 | a 139 | -webkit-border-bottom-left-radius: 8px 140 | -webkit-border-bottom-right-radius: 8px 141 | li 142 | color: #666 143 | border-top: 1px solid #333 144 | border-bottom: #555858 145 | list-style-type: none 146 | padding: 10px 10px 10px 10px 147 | background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#4c4d4e), to(#404142)) 148 | overflow: hidden 149 | &.arrow 150 | background-image: url(../i/themes/jqt/img/chevron.png), -webkit-gradient(linear, 0% 0%, 0% 100%, from(#4c4d4e), to(#404142)) 151 | background-position: right center 152 | background-repeat: no-repeat 153 | &.forward 154 | background-image: url(../i/themes/jqt/img/chevron_circle.png), -webkit-gradient(linear, 0% 0%, 0% 100%, from(#4c4d4e), to(#404142)) 155 | background-position: right center 156 | background-repeat: no-repeat 157 | a 158 | color: #fff 159 | text-decoration: none 160 | text-overflow: ellipsis 161 | white-space: nowrap 162 | overflow: hidden 163 | display: block 164 | padding: 12px 10px 12px 10px 165 | margin: -10px 166 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0) 167 | text-shadow: rgba(0, 0, 0, 0.2) 0 1px 1px 168 | 169 | /* universal links on list 170 | 171 | li.img a + a 172 | color: #fff 173 | text-decoration: none 174 | text-overflow: ellipsis 175 | white-space: nowrap 176 | overflow: hidden 177 | display: block 178 | padding: 12px 10px 12px 10px 179 | margin: -10px 180 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0) 181 | text-shadow: rgba(0, 0, 0, 0.2) 0 1px 1px 182 | 183 | ul 184 | li 185 | a 186 | &.active, &.button 187 | background-color: #53b401 188 | color: #fff 189 | &.active.loading 190 | background-image: url(../i/themes/jqt/img/loading.gif) 191 | background-position: 95% center 192 | background-repeat: no-repeat 193 | &.arrow a.active 194 | background-image: url(../i/themes/jqt/img/chevron.png) 195 | background-position: right center 196 | background-repeat: no-repeat 197 | &.forward a.active 198 | background-image: url(../i/themes/jqt/img/chevron_circle.png) 199 | background-position: right center 200 | background-repeat: no-repeat 201 | &.img a + 202 | a 203 | margin: -10px 10px -20px -5px 204 | font-size: 17px 205 | font-weight: bold 206 | + a 207 | font-size: 14px 208 | font-weight: normal 209 | margin-left: -10px 210 | margin-bottom: -10px 211 | margin-top: 0 212 | small + a 213 | margin-left: -5px 214 | + a 215 | margin-left: -10px 216 | margin-top: -20px 217 | margin-bottom: -10px 218 | font-size: 14px 219 | font-weight: normal 220 | + a 221 | margin-left: 0px !important 222 | margin-bottom: 0 223 | a + a 224 | color: #000 225 | font: 14px Helvetica 226 | text-overflow: ellipsis 227 | white-space: nowrap 228 | overflow: hidden 229 | display: block 230 | margin: 0 231 | padding: 0 232 | + a 233 | color: #666 234 | font: 13px Helvetica 235 | margin: 0 236 | text-overflow: ellipsis 237 | white-space: nowrap 238 | overflow: hidden 239 | display: block 240 | padding: 0 241 | &.img a + 242 | a + a + a, small + a + a + a 243 | color: #666 244 | font: 13px Helvetica 245 | margin: 0 246 | text-overflow: ellipsis 247 | white-space: nowrap 248 | overflow: hidden 249 | display: block 250 | padding: 0 251 | &.form li 252 | padding: 7px 10px 253 | &.error 254 | border: 2px solid red 255 | + li.error 256 | border-top: 0 257 | li 258 | input 259 | &[type="text"], &[type="password"] 260 | color: #777 261 | background: transparent url(../.png) 262 | border: 0 263 | font: normal 17px Helvetica 264 | padding: 0 265 | display: inline-block 266 | margin-left: 0px 267 | width: 100% 268 | -webkit-appearance: textarea 269 | textarea, select 270 | color: #777 271 | background: transparent url(../.png) 272 | border: 0 273 | font: normal 17px Helvetica 274 | padding: 0 275 | display: inline-block 276 | margin-left: 0px 277 | width: 100% 278 | -webkit-appearance: textarea 279 | textarea 280 | height: 120px 281 | padding: 0 282 | text-indent: -2px 283 | select 284 | text-indent: 0px 285 | background: transparent url(../i/themes/jqt/img/chevron.png) no-repeat right center 286 | -webkit-appearance: textfield 287 | margin-left: -6px 288 | width: 104% 289 | input 290 | &[type="checkbox"], &[type="radio"] 291 | margin: 0 292 | padding: 10px 10px 293 | &[type="checkbox"]:after, &[type="radio"]:after 294 | content: attr(title) 295 | font: 17px Helvetica 296 | display: block 297 | width: 246px 298 | color: #777 299 | margin: -12px 0 0 17px 300 | small 301 | color: #64c114 302 | font: 17px Helvetica 303 | text-align: right 304 | text-overflow: ellipsis 305 | white-space: nowrap 306 | overflow: hidden 307 | display: block 308 | width: 23% 309 | float: right 310 | padding: 0 311 | &.arrow small 312 | padding: 0 15px 313 | small.counter 314 | font-size: 17px 315 | line-height: 13px 316 | font-weight: bold 317 | background: rgba(0, 0, 0, 0.15) 318 | color: #fff 319 | -webkit-border-radius: 11px 320 | padding: 4px 10px 5px 10px 321 | display: block 322 | width: auto 323 | margin-top: -22px 324 | -webkit-box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0 325 | &.arrow small.counter 326 | margin-right: 15px 327 | &.individual 328 | border: 0 329 | background: none 330 | clear: both 331 | overflow: hidden 332 | padding-bottom: 3px 333 | -webkit-box-shadow: none 334 | li 335 | background: #4c4d4e 336 | border: 1px solid #333 337 | font-size: 14px 338 | text-align: center 339 | -webkit-border-radius: 8px 340 | -webkit-box-sizing: border-box 341 | width: 48% 342 | float: left 343 | display: block 344 | padding: 11px 10px 14px 10px 345 | -webkit-box-shadow: rgba(0, 0, 0, 0.2) 1px 1px 3px 346 | background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#4c4d4e), to(#404142)) 347 | + li 348 | float: right 349 | a 350 | color: #fff 351 | line-height: 16px 352 | margin: -11px -10px -14px -10px 353 | padding: 11px 10px 14px 10px 354 | -webkit-border-radius: 8px 355 | 356 | /* 357 | *@end 358 | /* @group Forms 359 | 360 | /* @end 361 | /* @group Mini Label 362 | 363 | /* @end 364 | /* @group Individual 365 | 366 | /* @end 367 | /* @group Toggle 368 | 369 | .toggle 370 | width: 94px 371 | position: relative 372 | height: 27px 373 | display: block 374 | overflow: hidden 375 | float: right 376 | input[type="checkbox"] 377 | &:checked 378 | left: 0px 379 | -webkit-appearance: textarea 380 | -webkit-border-radius: 5px 381 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0) 382 | -webkit-transition: left .15s 383 | background-color: transparent 384 | background: white url(../i/themes/jqt/img/on_off.png) 0 0 no-repeat 385 | border: 0 386 | height: 27px 387 | left: -55px 388 | margin: 0 389 | overflow: hidden 390 | position: absolute 391 | top: 0 392 | width: 149px 393 | 394 | /* @end 395 | /* @group Info 396 | 397 | .info 398 | background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#cccccc), to(#aaaaaa), color-stop(0.6, #cccccc)) 399 | font-size: 12px 400 | line-height: 16px 401 | text-align: center 402 | text-shadow: rgba(255, 255, 255, 0.8) 0 1px 0 403 | color: #444 404 | padding: 15px 405 | border-top: 1px solid rgba(255, 255, 255, 0.2) 406 | font-weight: bold 407 | 408 | /* @end 409 | /* @group Edge to edge 410 | 411 | ul.edgetoedge 412 | border-width: 1px 0 413 | margin: 0 414 | padding: 0 415 | li 416 | background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#1e1f21), to(#272729)) 417 | border-bottom: 2px solid #000 418 | border-top: 1px solid #4a4b4d 419 | font-size: 20px 420 | margin-bottom: -1px 421 | &.sep 422 | background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(0, 0, 0, 0)), to(rgba(0, 0, 0, 0.5))) 423 | border-bottom: 1px solid #111113 424 | border-top: 1px solid #666 425 | color: #3e9ac3 426 | font-size: 16px 427 | margin: 1px 0 0 0 428 | padding: 2px 10px 429 | text-shadow: #000 0 1px 0 430 | em 431 | font-weight: normal 432 | font-style: normal 433 | 434 | /* @end 435 | /* @group Plastic 436 | 437 | #plastic 438 | background: #17181a 439 | 440 | ul 441 | &.plastic 442 | background: #17181a 443 | color: #aaa 444 | font: bold 18px Helvetica 445 | margin: 0 446 | padding: 0 447 | border-width: 0 0 1px 0 448 | li 449 | border-width: 1px 0 450 | border-style: solid 451 | border-top-color: #222 452 | border-bottom-color: #000 453 | color: #666 454 | list-style-type: none 455 | overflow: hidden 456 | padding: 10px 10px 10px 10px 457 | a.active.loading 458 | background-image: url(../i/themes/jqt/img/loading.gif) 459 | background-position: 95% center 460 | background-repeat: no-repeat 461 | small 462 | color: #888 463 | font-size: 13px 464 | font-weight: bold 465 | line-height: 24px 466 | text-transform: uppercase 467 | &:nth-child(odd) 468 | background-color: #1c1c1f 469 | &.arrow 470 | background-image: url(../i/themes/jqt/img/chevron.png) 471 | background-position: right center 472 | background-repeat: no-repeat 473 | a.active 474 | background-image: url(../i/themes/jqt/img/chevron.png) 475 | background-position: right center 476 | background-repeat: no-repeat 477 | &.forward 478 | background-image: url(../i/themes/jqt/img/chevron_circle.png) 479 | background-position: right center 480 | background-repeat: no-repeat 481 | a.active 482 | background-image: url(../i/themes/jqt/img/chevron_circle.png) 483 | background-position: right center 484 | background-repeat: no-repeat 485 | &.metal 486 | border-bottom: 0 487 | border-left: 0 488 | border-right: 0 489 | border-top: 0 490 | margin: 0 491 | li 492 | background-image: none 493 | border-top: 1px solid #fff 494 | border-bottom: 1px solid #666 495 | font-size: 26px 496 | background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(238, 238, 238, 1)), to(rgba(156, 158, 160, 1))) 497 | a 498 | line-height: 26px 499 | margin: 0 500 | text-shadow: #fff 0 1px 0 501 | padding: 13px 0 502 | em 503 | display: block 504 | font-size: 14px 505 | font-style: normal 506 | color: #444 507 | width: 50% 508 | line-height: 14px 509 | &.active 510 | color: rgb(0, 0, 0) 511 | small 512 | float: right 513 | position: relative 514 | margin-top: 10px 515 | font-weight: bold 516 | &.arrow 517 | background-image: url(../i/themes/jqt/img/chevron.png) 518 | background-position: right center 519 | background-repeat: no-repeat 520 | background-image: url(../i/themes/jqt/img/chevron.png), -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(238, 238, 238, 1)), to(rgba(156, 158, 160, 1))) 521 | background-repeat: no-repeat 522 | background-position: right center 523 | a small 524 | padding-right: 15px 525 | line-height: 17px 526 | 527 | /* @group Metal 528 | 529 | /* @end 530 | -------------------------------------------------------------------------------- /c/sass/board.ipad.sass: -------------------------------------------------------------------------------- 1 | $large: 45px 2 | $medium: 30px 3 | $small: 15px 4 | 5 | $zoom_in_size: $large 6 | 7 | .board.size19 8 | $full_cells: 19 9 | $zoom_out_size: $medium 10 | $zoom_out_cells: $full_cells 11 | $zoom_in_cells: 12 12 | &.zoomin 13 | margin-left: -0.5 * $zoom_in_cells * $zoom_in_size 14 | width: $zoom_in_size * $zoom_in_cells 15 | .intersections 16 | height: $zoom_in_size * $zoom_in_cells 17 | .row 18 | height: $zoom_in_size 19 | width: $zoom_in_size * $full_cells 20 | img 21 | height: $zoom_in_size 22 | width: $zoom_in_size 23 | &.zoomout 24 | margin-left: -0.5 * $zoom_out_cells *$zoom_out_size 25 | width: $zoom_in_size * $zoom_in_cells 26 | .intersections 27 | height: $zoom_in_size * $zoom_in_cells 28 | .row 29 | height: $zoom_out_size 30 | width: $zoom_out_size * $zoom_out_cells 31 | img 32 | height: $zoom_out_size 33 | width: $zoom_out_size 34 | 35 | .board.size17 36 | $full_cells: 17 37 | $zoom_out_size: $large 38 | $zoom_out_cells: $full_cells 39 | $zoom_in_cells: 17 40 | &.zoomin 41 | margin-left: -0.5 * $zoom_in_cells * $zoom_in_size 42 | width: $zoom_in_size * $zoom_in_cells 43 | .intersections 44 | height: $zoom_in_size * $zoom_in_cells 45 | .row 46 | height: $zoom_in_size 47 | width: $zoom_in_size * $full_cells 48 | img 49 | height: $zoom_in_size 50 | width: $zoom_in_size 51 | &.zoomout 52 | margin-left: -0.5 * $zoom_out_cells *$zoom_out_size 53 | width: $zoom_in_size * $zoom_in_cells 54 | .intersections 55 | height: $zoom_in_size * $zoom_in_cells 56 | .row 57 | height: $zoom_out_size 58 | width: $zoom_out_size * $zoom_out_cells 59 | img 60 | height: $zoom_out_size 61 | width: $zoom_out_size 62 | 63 | .board.size15 64 | $full_cells: 15 65 | $zoom_out_size: $large 66 | $zoom_out_cells: $full_cells 67 | $zoom_in_cells: 15 68 | &.zoomin 69 | margin-left: -0.5 * $zoom_in_cells * $zoom_in_size 70 | width: $zoom_in_size * $zoom_in_cells 71 | .intersections 72 | height: $zoom_in_size * $zoom_in_cells 73 | .row 74 | height: $zoom_in_size 75 | width: $zoom_in_size * $full_cells 76 | img 77 | height: $zoom_in_size 78 | width: $zoom_in_size 79 | &.zoomout 80 | margin-left: -0.5 * $zoom_out_cells *$zoom_out_size 81 | width: $zoom_in_size * $zoom_in_cells 82 | .intersections 83 | height: $zoom_in_size * $zoom_in_cells 84 | .row 85 | height: $zoom_out_size 86 | width: $zoom_out_size * $zoom_out_cells 87 | img 88 | height: $zoom_out_size 89 | width: $zoom_out_size 90 | 91 | .board.size13 92 | $full_cells: 13 93 | $zoom_out_size: $large 94 | $zoom_out_cells: $full_cells 95 | $zoom_in_cells: 13 96 | &.zoomin 97 | margin-left: -0.5 * $zoom_in_cells * $zoom_in_size 98 | width: $zoom_in_size * $zoom_in_cells 99 | .intersections 100 | height: $zoom_in_size * $zoom_in_cells 101 | .row 102 | height: $zoom_in_size 103 | width: $zoom_in_size * $full_cells 104 | img 105 | height: $zoom_in_size 106 | width: $zoom_in_size 107 | &.zoomout 108 | margin-left: -0.5 * $zoom_out_cells *$zoom_out_size 109 | width: $zoom_in_size * $zoom_in_cells 110 | .intersections 111 | height: $zoom_in_size * $zoom_in_cells 112 | .row 113 | height: $zoom_out_size 114 | width: $zoom_out_size * $zoom_out_cells 115 | img 116 | height: $zoom_out_size 117 | width: $zoom_out_size 118 | 119 | .board.size11 120 | $full_cells: 11 121 | $zoom_out_size: $large 122 | $zoom_out_cells: $full_cells 123 | $zoom_in_cells: 11 124 | &.zoomin 125 | margin-left: -0.5 * $zoom_in_cells * $zoom_in_size 126 | width: $zoom_in_size * $zoom_in_cells 127 | .intersections 128 | height: $zoom_in_size * $zoom_in_cells 129 | .row 130 | height: $zoom_in_size 131 | width: $zoom_in_size * $full_cells 132 | img 133 | height: $zoom_in_size 134 | width: $zoom_in_size 135 | &.zoomout 136 | margin-left: -0.5 * $zoom_out_cells *$zoom_out_size 137 | width: $zoom_in_size * $zoom_in_cells 138 | .intersections 139 | height: $zoom_in_size * $zoom_in_cells 140 | .row 141 | height: $zoom_out_size 142 | width: $zoom_out_size * $zoom_out_cells 143 | img 144 | height: $zoom_out_size 145 | width: $zoom_out_size 146 | 147 | .board.size9 148 | $full_cells: 9 149 | $zoom_out_size: $large 150 | $zoom_out_cells: $full_cells 151 | $zoom_in_cells: 9 152 | &.zoomin 153 | margin-left: -0.5 * $zoom_in_cells * $zoom_in_size 154 | width: $zoom_in_size * $zoom_in_cells 155 | .intersections 156 | height: $zoom_in_size * $zoom_in_cells 157 | .row 158 | height: $zoom_in_size 159 | width: $zoom_in_size * $full_cells 160 | img 161 | height: $zoom_in_size 162 | width: $zoom_in_size 163 | &.zoomout 164 | margin-left: -0.5 * $zoom_out_cells *$zoom_out_size 165 | width: $zoom_in_size * $zoom_in_cells 166 | .intersections 167 | height: $zoom_in_size * $zoom_in_cells 168 | .row 169 | height: $zoom_out_size 170 | width: $zoom_out_size * $zoom_out_cells 171 | img 172 | height: $zoom_out_size 173 | width: $zoom_out_size 174 | 175 | .board 176 | overflow: hidden 177 | position: relative 178 | left: 50% 179 | .intersections 180 | position: relative 181 | background: black 182 | .intersection 183 | :display inline-block 184 | .row 185 | &:first-child 186 | .intersection 187 | &:first-child 188 | &.black 189 | background: url('../i/board/temporary/tile1nw.png') 190 | &.playable_black,&.playable_white 191 | background: url('../i/board/temporary/tile1nwd.png') !important 192 | &.latest 193 | background: url('../i/board/temporary/tile1nwd.png') !important 194 | &.white 195 | background: url('../i/board/temporary/tile2nw.png') 196 | &.playable_black,&.playable_white 197 | background: url('../i/board/temporary/tile2nwd.png') !important 198 | &.latest 199 | background: url('../i/board/temporary/tile2nwd.png') !important 200 | &:not(.black):not(.white) 201 | background: url('../i/board/temporary/tile0nw.png') 202 | &:not(:first-child):not(:last-child) 203 | &.black 204 | background: url('../i/board/temporary/tile1n.png') 205 | &.playable_black,&.playable_white 206 | background: url('../i/board/temporary/tile1nd.png') !important 207 | &.latest 208 | background: url('../i/board/temporary/tile1nd.png') !important 209 | &.white 210 | background: url('../i/board/temporary/tile2n.png') 211 | &.playable_black,&.playable_white 212 | background: url('../i/board/temporary/tile2nd.png') !important 213 | &.latest 214 | background: url('../i/board/temporary/tile2nd.png') !important 215 | &:not(.black):not(.white) 216 | background: url('../i/board/temporary/tile0n.png') 217 | &:last-child 218 | &.black 219 | background: url('../i/board/temporary/tile1ne.png') 220 | &.playable_black,&.playable_white 221 | background: url('../i/board/temporary/tile1ned.png') !important 222 | &.latest 223 | background: url('../i/board/temporary/tile1ned.png') !important 224 | &.white 225 | background: url('../i/board/temporary/tile2ne.png') 226 | &.playable_black,&.playable_white 227 | background: url('../i/board/temporary/tile2ned.png') !important 228 | &.latest 229 | background: url('../i/board/temporary/tile2ned.png') !important 230 | &:not(.black):not(.white) 231 | background: url('../i/board/temporary/tile0ne.png') 232 | &:not(:first-child):not(:last-child) 233 | .intersection 234 | &:first-child 235 | &.black 236 | background: url('../i/board/temporary/tile1w.png') 237 | &.playable_black,&.playable_white 238 | background: url('../i/board/temporary/tile1wd.png') !important 239 | &.latest 240 | background: url('../i/board/temporary/tile1wd.png') !important 241 | &.white 242 | background: url('../i/board/temporary/tile2w.png') 243 | &.playable_black,&.playable_white 244 | background: url('../i/board/temporary/tile2wd.png') !important 245 | &.latest 246 | background: url('../i/board/temporary/tile2wd.png') !important 247 | &:not(.black):not(.white) 248 | background: url('../i/board/temporary/tile0w.png') 249 | &:not(:first-child):not(:last-child) 250 | &.black 251 | background: url('../i/board/temporary/tile1.png') 252 | &.playable_black,&.playable_white 253 | background: url('../i/board/temporary/tile1d.png') !important 254 | &.latest 255 | background: url('../i/board/temporary/tile1d.png') !important 256 | &.white 257 | background: url('../i/board/temporary/tile2.png') 258 | &.playable_black,&.playable_white 259 | background: url('../i/board/temporary/tile2d.png') !important 260 | &.latest 261 | background: url('../i/board/temporary/tile2d.png') !important 262 | &:last-child 263 | &.black 264 | background: url('../i/board/temporary/tile1e.png') 265 | &.playable_black,&.playable_white 266 | background: url('../i/board/temporary/tile1ed.png') !important 267 | &.latest 268 | background: url('../i/board/temporary/tile1ed.png') !important 269 | &.white 270 | background: url('../i/board/temporary/tile2e.png') 271 | &.playable_black,&.playable_white 272 | background: url('../i/board/temporary/tile2ed.png') !important 273 | &.latest 274 | background: url('../i/board/temporary/tile2ed.png') !important 275 | &:not(.black):not(.white) 276 | background: url('../i/board/temporary/tile0e.png') 277 | &:last-child 278 | .intersection 279 | &:first-child 280 | &.black 281 | background: url('../i/board/temporary/tile1sw.png') 282 | &.playable_black,&.playable_white 283 | background: url('../i/board/temporary/tile1swd.png') !important 284 | &.latest 285 | background: url('../i/board/temporary/tile1swd.png') !important 286 | &.white 287 | background: url('../i/board/temporary/tile2sw.png') 288 | &.playable_black,&.playable_white 289 | background: url('../i/board/temporary/tile2swd.png') !important 290 | &.latest 291 | background: url('../i/board/temporary/tile2swd.png') !important 292 | &:not(.black):not(.white) 293 | background: url('../i/board/temporary/tile0sw.png') 294 | &:not(:first-child):not(:last-child) 295 | &.black 296 | background: url('../i/board/temporary/tile1s.png') 297 | &.playable_black,&.playable_white 298 | background: url('../i/board/temporary/tile1sd.png') !important 299 | &.latest 300 | background: url('../i/board/temporary/tile1sd.png') !important 301 | &.white 302 | background: url('../i/board/temporary/tile2s.png') 303 | &.playable_black,&.playable_white 304 | background: url('../i/board/temporary/tile2sd.png') !important 305 | &.latest 306 | background: url('../i/board/temporary/tile2sd.png') !important 307 | &:not(.black):not(.white) 308 | background: url('../i/board/temporary/tile0s.png') 309 | &:last-child 310 | &.black 311 | background: url('../i/board/temporary/tile1se.png') 312 | &.playable_black,&.playable_white 313 | background: url('../i/board/temporary/tile1sed.png') !important 314 | &.latest 315 | background: url('../i/board/temporary/tile1sed.png') !important 316 | &.white 317 | background: url('../i/board/temporary/tile2se.png') 318 | &.playable_black,&.playable_white 319 | background: url('../i/board/temporary/tile2sed.png') !important 320 | &.latest 321 | background: url('../i/board/temporary/tile2sed.png') !important 322 | &:not(.black):not(.white) 323 | background: url('../i/board/temporary/tile0se.png') 324 | .star 325 | &.black 326 | background: url('../i/board/temporary/tile1.png') 327 | &.playable_black,&.playable_white 328 | background: url('../i/board/temporary/tile1d.png') !important 329 | &.latest 330 | background: url('../i/board/temporary/tile1d.png') !important 331 | &.white 332 | background: url('../i/board/temporary/tile2.png') 333 | &.playable_black,&.playable_white 334 | background: url('../i/board/temporary/tile2d.png') !important 335 | &.latest 336 | background: url('../i/board/temporary/tile2d.png') !important 337 | &:not(.black):not(.white) 338 | background: url('../i/board/temporary/tile0c.png') 339 | &.playable_black,&.playable_white 340 | BEFORE: URL('../i/board/temporary/tile0c.png') 341 | 342 | @mixin interior($corner,$middle) 343 | .row 344 | &:nth-child(#{$corner}),&:nth-child(#{$middle}),&:nth-last-child(#{$corner}) 345 | .intersection:not(.black):not(.white) 346 | &:nth-child(#{$corner}),&:nth-child(#{$middle}),&:nth-last-child(#{$corner}) 347 | background: url('../i/board/temporary/tile0c.png') 348 | &:not(:nth-child(#{$corner})):not(:nth-child(#{$middle})):not(:nth-last-child(#{$corner})):not(:first-child):not(:last-child) 349 | background: url('../i/board/temporary/tile0.png') 350 | &:not(:nth-child(#{$corner})):not(:nth-child(#{$middle})):not(:nth-last-child(#{$corner})):not(:first-child):not(:last-child) 351 | .intersection:not(.black):not(.white):not(:first-child):not(:last-child) 352 | background: url('../i/board/temporary/tile0.png') 353 | 354 | .board 355 | &.size9 356 | @include interior(3,5) 357 | &.size11 358 | @include interior(3,6) 359 | &.size13 360 | @include interior(4,7) 361 | &.size15 362 | @include interior(4,8) 363 | &.size17 364 | @include interior(4,9) 365 | &.size19 366 | @include interior(4,10) 367 | 368 | .move.play.black 369 | .intersection.playable_black 370 | cursor: pointer 371 | .move.play.white 372 | .intersection.playable_white 373 | cursor: pointer 374 | 375 | .intersection 376 | -o-background-size: 100% 377 | -webkit-background-size: 100% 378 | -khtml-background-size: 100% 379 | -moz-background-size: 100% 380 | 381 | .board 382 | .head 383 | .guest 384 | display: inline 385 | left: 100% 386 | margin-left: -100% 387 | 388 | $stonediameter: 30px 389 | 390 | .head,.foot 391 | height: $stonediameter 392 | padding: 5px 5px 5px 5px 393 | 394 | .profile 395 | .move.play 396 | .board 397 | .head 398 | .guest 399 | display: inline 400 | float: right 401 | -webkit-transform: rotate(180deg) 402 | .foot 403 | .host 404 | display: inline 405 | float: right 406 | .guest 407 | display: none 408 | 409 | .landscape 410 | .move.play 411 | .board 412 | .guest 413 | display: none 414 | .foot 415 | .host 416 | display: inline 417 | float: left 418 | .guest 419 | display: inline 420 | float: right -------------------------------------------------------------------------------- /c/jqtouch.ipad.customized.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: black; 3 | color: #dddddd; } 4 | body > * { 5 | background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#333333), to(#5e5e65)); } 6 | 7 | h1, h2 { 8 | font: bold 18px Helvetica; 9 | text-shadow: rgba(255, 255, 255, 0.2) 0 1px 1px; 10 | color: black; 11 | margin: 10px 20px 5px; } 12 | 13 | /* @group Toolbar */ 14 | .toolbar { 15 | -webkit-box-sizing: border-box; 16 | border-bottom: 1px solid black; 17 | padding: 10px; 18 | height: 45px; 19 | background: url(../i/themes/jqt/img/toolbar.png) black repeat-x; 20 | position: relative; } 21 | 22 | .black-translucent .toolbar { 23 | margin-top: 20px; } 24 | 25 | .toolbar > h1 { 26 | position: absolute; 27 | overflow: hidden; 28 | left: 50%; 29 | top: 10px; 30 | line-height: 1em; 31 | margin: 1px 0 0 -192px; 32 | height: 40px; 33 | font-size: 20px; 34 | width: 384px; 35 | font-weight: bold; 36 | text-shadow: black 0 -1px 1px; 37 | text-align: center; 38 | text-overflow: ellipsis; 39 | white-space: nowrap; 40 | color: white; } 41 | 42 | body.landscape .toolbar > h1 { 43 | margin-left: -256px; 44 | width: 512px; } 45 | 46 | .button, .back, .cancel, .add { 47 | position: absolute; 48 | overflow: hidden; 49 | top: 8px; 50 | right: 10px; 51 | margin: 0; 52 | border-width: 0 5px; 53 | padding: 0 3px; 54 | width: auto; 55 | height: 30px; 56 | line-height: 30px; 57 | font-family: inherit; 58 | font-size: 12px; 59 | font-weight: bold; 60 | color: white; 61 | text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0; 62 | text-overflow: ellipsis; 63 | text-decoration: none; 64 | white-space: nowrap; 65 | background: none; 66 | -webkit-border-image: url(../i/themes/jqt/img/button.png) 0 5 0 5; } 67 | 68 | .blueButton { 69 | -webkit-border-image: url(../i/themes/jqt/img/blueButton.png) 0 5 0 5; 70 | border-width: 0 5px; } 71 | 72 | .back { 73 | left: 6px; 74 | right: auto; 75 | padding: 0; 76 | max-width: 55px; 77 | border-width: 0 8px 0 14px; 78 | -webkit-border-image: url(../i/themes/jqt/img/back_button.png) 0 8 0 14; } 79 | .back.active { 80 | -webkit-border-image: url(../i/themes/jqt/img/back_button_clicked.png) 0 8 0 14; 81 | color: #aaaaaa; } 82 | 83 | .leftButton, .cancel { 84 | left: 6px; 85 | right: auto; } 86 | 87 | .add { 88 | font-size: 24px; 89 | line-height: 24px; 90 | font-weight: bold; } 91 | 92 | .whiteButton, .grayButton { 93 | display: block; 94 | border-width: 0 12px; 95 | padding: 10px; 96 | text-align: center; 97 | font-size: 20px; 98 | font-weight: bold; 99 | text-decoration: inherit; 100 | color: inherit; } 101 | 102 | .whiteButton { 103 | -webkit-border-image: url(../i/themes/jqt/img/whiteButton.png) 0 12 0 12; 104 | text-shadow: rgba(255, 255, 255, 0.7) 0 1px 0; } 105 | 106 | .grayButton { 107 | -webkit-border-image: url(../i/themes/jqt/img/grayButton.png) 0 12 0 12; 108 | color: white; } 109 | 110 | /* @end */ 111 | /* @group Lists */ 112 | h1 + ul, h2 + ul, h3 + ul, h4 + ul, h5 + ul, h6 + ul { 113 | margin-top: 0; } 114 | 115 | ul { 116 | color: #aaaaaa; 117 | border: 1px solid #333333; 118 | font: bold 18px Helvetica; 119 | padding: 0; 120 | margin: 15px 10px 17px 10px; } 121 | ul.rounded { 122 | -webkit-border-radius: 8px; 123 | -webkit-box-shadow: rgba(0, 0, 0, 0.3) 1px 1px 3px; } 124 | ul.rounded li:first-child { 125 | border-top: 0; 126 | -webkit-border-top-left-radius: 8px; 127 | -webkit-border-top-right-radius: 8px; } 128 | ul.rounded li:first-child a { 129 | border-top: 0; 130 | -webkit-border-top-left-radius: 8px; 131 | -webkit-border-top-right-radius: 8px; } 132 | ul.rounded li:last-child { 133 | -webkit-border-bottom-left-radius: 8px; 134 | -webkit-border-bottom-right-radius: 8px; } 135 | ul.rounded li:last-child a { 136 | -webkit-border-bottom-left-radius: 8px; 137 | -webkit-border-bottom-right-radius: 8px; } 138 | ul li { 139 | color: #666666; 140 | border-top: 1px solid #333333; 141 | border-bottom: #555858; 142 | list-style-type: none; 143 | padding: 10px 10px 10px 10px; 144 | background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#4c4d4e), to(#404142)); 145 | overflow: hidden; } 146 | ul li.arrow { 147 | background-image: url(../i/themes/jqt/img/chevron.png), -webkit-gradient(linear, 0% 0%, 0% 100%, from(#4c4d4e), to(#404142)); 148 | background-position: right center; 149 | background-repeat: no-repeat; } 150 | ul li.forward { 151 | background-image: url(../i/themes/jqt/img/chevron_circle.png), -webkit-gradient(linear, 0% 0%, 0% 100%, from(#4c4d4e), to(#404142)); 152 | background-position: right center; 153 | background-repeat: no-repeat; } 154 | ul li a { 155 | color: white; 156 | text-decoration: none; 157 | text-overflow: ellipsis; 158 | white-space: nowrap; 159 | overflow: hidden; 160 | display: block; 161 | padding: 12px 10px 12px 10px; 162 | margin: -10px; 163 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 164 | text-shadow: rgba(0, 0, 0, 0.2) 0 1px 1px; } 165 | 166 | /* universal links on list */ 167 | li.img a + a { 168 | color: white; 169 | text-decoration: none; 170 | text-overflow: ellipsis; 171 | white-space: nowrap; 172 | overflow: hidden; 173 | display: block; 174 | padding: 12px 10px 12px 10px; 175 | margin: -10px; 176 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 177 | text-shadow: rgba(0, 0, 0, 0.2) 0 1px 1px; } 178 | 179 | ul li a.active, ul li a.button { 180 | background-color: #53b401; 181 | color: white; } 182 | ul li a.active.loading { 183 | background-image: url(../i/themes/jqt/img/loading.gif); 184 | background-position: 95% center; 185 | background-repeat: no-repeat; } 186 | ul li.arrow a.active { 187 | background-image: url(../i/themes/jqt/img/chevron.png); 188 | background-position: right center; 189 | background-repeat: no-repeat; } 190 | ul li.forward a.active { 191 | background-image: url(../i/themes/jqt/img/chevron_circle.png); 192 | background-position: right center; 193 | background-repeat: no-repeat; } 194 | ul li.img a + a { 195 | margin: -10px 10px -20px -5px; 196 | font-size: 17px; 197 | font-weight: bold; } 198 | ul li.img a + a + a { 199 | font-size: 14px; 200 | font-weight: normal; 201 | margin-left: -10px; 202 | margin-bottom: -10px; 203 | margin-top: 0; } 204 | ul li.img a + small + a { 205 | margin-left: -5px; } 206 | ul li.img a + small + a + a { 207 | margin-left: -10px; 208 | margin-top: -20px; 209 | margin-bottom: -10px; 210 | font-size: 14px; 211 | font-weight: normal; } 212 | ul li.img a + small + a + a + a { 213 | margin-left: 0px !important; 214 | margin-bottom: 0; } 215 | ul li a + a { 216 | color: black; 217 | font: 14px Helvetica; 218 | text-overflow: ellipsis; 219 | white-space: nowrap; 220 | overflow: hidden; 221 | display: block; 222 | margin: 0; 223 | padding: 0; } 224 | ul li a + a + a { 225 | color: #666666; 226 | font: 13px Helvetica; 227 | margin: 0; 228 | text-overflow: ellipsis; 229 | white-space: nowrap; 230 | overflow: hidden; 231 | display: block; 232 | padding: 0; } 233 | ul li.img a + a + a + a, ul li.img a + small + a + a + a { 234 | color: #666666; 235 | font: 13px Helvetica; 236 | margin: 0; 237 | text-overflow: ellipsis; 238 | white-space: nowrap; 239 | overflow: hidden; 240 | display: block; 241 | padding: 0; } 242 | ul.form li { 243 | padding: 7px 10px; } 244 | ul.form li.error { 245 | border: 2px solid red; } 246 | ul.form li.error + li.error { 247 | border-top: 0; } 248 | ul li input[type="text"], ul li input[type="password"] { 249 | color: #777777; 250 | background: transparent /* url(../.png) */; 251 | border: 0; 252 | font: normal 17px Helvetica; 253 | padding: 0; 254 | display: inline-block; 255 | margin-left: 0px; 256 | width: 100%; 257 | -webkit-appearance: textarea; } 258 | ul li textarea, ul li select { 259 | color: #777777; 260 | background: transparent /* url(../.png) */; 261 | border: 0; 262 | font: normal 17px Helvetica; 263 | padding: 0; 264 | display: inline-block; 265 | margin-left: 0px; 266 | width: 100%; 267 | -webkit-appearance: textarea; } 268 | ul li textarea { 269 | height: 120px; 270 | padding: 0; 271 | text-indent: -2px; } 272 | ul li select { 273 | text-indent: 0px; 274 | background: transparent url(../i/themes/jqt/img/chevron.png) no-repeat right center; 275 | -webkit-appearance: textfield; 276 | margin-left: -6px; 277 | width: 104%; } 278 | ul li input[type="checkbox"], ul li input[type="radio"] { 279 | margin: 0; 280 | padding: 10px 10px; } 281 | ul li input[type="checkbox"]:after, ul li input[type="radio"]:after { 282 | content: attr(title); 283 | font: 17px Helvetica; 284 | display: block; 285 | width: 246px; 286 | color: #777777; 287 | margin: -12px 0 0 17px; } 288 | ul li small { 289 | color: #64c114; 290 | font: 17px Helvetica; 291 | text-align: right; 292 | text-overflow: ellipsis; 293 | white-space: nowrap; 294 | overflow: hidden; 295 | display: block; 296 | width: 23%; 297 | float: right; 298 | padding: 0; } 299 | ul li.arrow small { 300 | padding: 0 15px; } 301 | ul li small.counter { 302 | font-size: 17px; 303 | line-height: 13px; 304 | font-weight: bold; 305 | background: rgba(0, 0, 0, 0.15); 306 | color: white; 307 | -webkit-border-radius: 11px; 308 | padding: 4px 10px 5px 10px; 309 | display: block; 310 | width: auto; 311 | margin-top: -22px; 312 | -webkit-box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0; } 313 | ul li.arrow small.counter { 314 | margin-right: 15px; } 315 | ul.individual { 316 | border: 0; 317 | background: none; 318 | clear: both; 319 | overflow: hidden; 320 | padding-bottom: 3px; 321 | -webkit-box-shadow: none; } 322 | ul.individual li { 323 | background: #4c4d4e; 324 | border: 1px solid #333333; 325 | font-size: 14px; 326 | text-align: center; 327 | -webkit-border-radius: 8px; 328 | -webkit-box-sizing: border-box; 329 | width: 48%; 330 | float: left; 331 | display: block; 332 | padding: 11px 10px 14px 10px; 333 | -webkit-box-shadow: rgba(0, 0, 0, 0.2) 1px 1px 3px; 334 | background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#4c4d4e), to(#404142)); } 335 | ul.individual li + li { 336 | float: right; } 337 | ul.individual li a { 338 | color: white; 339 | line-height: 16px; 340 | margin: -11px -10px -14px -10px; 341 | padding: 11px 10px 14px 10px; 342 | -webkit-border-radius: 8px; } 343 | 344 | /* *@end */ 345 | /* @group Forms */ 346 | /* @end */ 347 | /* @group Mini Label */ 348 | /* @end */ 349 | /* @group Individual */ 350 | /* @end */ 351 | /* @group Toggle */ 352 | .toggle { 353 | width: 94px; 354 | position: relative; 355 | height: 27px; 356 | display: block; 357 | overflow: hidden; 358 | float: right; } 359 | .toggle input[type="checkbox"] { 360 | -webkit-appearance: textarea; 361 | -webkit-border-radius: 5px; 362 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 363 | -webkit-transition: left 0.15s; 364 | background-color: transparent; 365 | background: white url(../i/themes/jqt/img/on_off.png) 0 0 no-repeat; 366 | border: 0; 367 | height: 27px; 368 | left: -55px; 369 | margin: 0; 370 | overflow: hidden; 371 | position: absolute; 372 | top: 0; 373 | width: 149px; } 374 | .toggle input[type="checkbox"]:checked { 375 | left: 0px; } 376 | 377 | /* @end */ 378 | /* @group Info */ 379 | .info { 380 | background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#cccccc), to(#aaaaaa), color-stop(0.6, #cccccc)); 381 | font-size: 12px; 382 | line-height: 16px; 383 | text-align: center; 384 | text-shadow: rgba(255, 255, 255, 0.8) 0 1px 0; 385 | color: #444444; 386 | padding: 15px; 387 | border-top: 1px solid rgba(255, 255, 255, 0.2); 388 | font-weight: bold; } 389 | 390 | /* @end */ 391 | /* @group Edge to edge */ 392 | ul.edgetoedge { 393 | border-width: 1px 0; 394 | margin: 0; 395 | padding: 0; } 396 | ul.edgetoedge li { 397 | background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#1e1f21), to(#272729)); 398 | border-bottom: 2px solid black; 399 | border-top: 1px solid #4a4b4d; 400 | font-size: 20px; 401 | margin-bottom: -1px; } 402 | ul.edgetoedge li.sep { 403 | background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(0, 0, 0, 0)), to(rgba(0, 0, 0, 0.5))); 404 | border-bottom: 1px solid #111113; 405 | border-top: 1px solid #666666; 406 | color: #3e9ac3; 407 | font-size: 16px; 408 | margin: 1px 0 0 0; 409 | padding: 2px 10px; 410 | text-shadow: black 0 1px 0; } 411 | ul.edgetoedge li em { 412 | font-weight: normal; 413 | font-style: normal; } 414 | 415 | /* @end */ 416 | /* @group Plastic */ 417 | #plastic { 418 | background: #17181a; } 419 | 420 | ul.plastic { 421 | background: #17181a; 422 | color: #aaaaaa; 423 | font: bold 18px Helvetica; 424 | margin: 0; 425 | padding: 0; 426 | border-width: 0 0 1px 0; } 427 | ul.plastic li { 428 | border-width: 1px 0; 429 | border-style: solid; 430 | border-top-color: #222222; 431 | border-bottom-color: black; 432 | color: #666666; 433 | list-style-type: none; 434 | overflow: hidden; 435 | padding: 10px 10px 10px 10px; } 436 | ul.plastic li a.active.loading { 437 | background-image: url(../i/themes/jqt/img/loading.gif); 438 | background-position: 95% center; 439 | background-repeat: no-repeat; } 440 | ul.plastic li small { 441 | color: #888888; 442 | font-size: 13px; 443 | font-weight: bold; 444 | line-height: 24px; 445 | text-transform: uppercase; } 446 | ul.plastic li:nth-child(odd) { 447 | background-color: #1c1c1f; } 448 | ul.plastic li.arrow { 449 | background-image: url(../i/themes/jqt/img/chevron.png); 450 | background-position: right center; 451 | background-repeat: no-repeat; } 452 | ul.plastic li.arrow a.active { 453 | background-image: url(../i/themes/jqt/img/chevron.png); 454 | background-position: right center; 455 | background-repeat: no-repeat; } 456 | ul.plastic li.forward { 457 | background-image: url(../i/themes/jqt/img/chevron_circle.png); 458 | background-position: right center; 459 | background-repeat: no-repeat; } 460 | ul.plastic li.forward a.active { 461 | background-image: url(../i/themes/jqt/img/chevron_circle.png); 462 | background-position: right center; 463 | background-repeat: no-repeat; } 464 | ul.metal { 465 | border-bottom: 0; 466 | border-left: 0; 467 | border-right: 0; 468 | border-top: 0; 469 | margin: 0; } 470 | ul.metal li { 471 | background-image: none; 472 | border-top: 1px solid white; 473 | border-bottom: 1px solid #666666; 474 | font-size: 26px; 475 | background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#eeeeee), to(#9c9ea0)); } 476 | ul.metal li a { 477 | line-height: 26px; 478 | margin: 0; 479 | text-shadow: white 0 1px 0; 480 | padding: 13px 0; } 481 | ul.metal li a em { 482 | display: block; 483 | font-size: 14px; 484 | font-style: normal; 485 | color: #444444; 486 | width: 50%; 487 | line-height: 14px; } 488 | ul.metal li a.active { 489 | color: black; } 490 | ul.metal li small { 491 | float: right; 492 | position: relative; 493 | margin-top: 10px; 494 | font-weight: bold; } 495 | ul.metal li.arrow { 496 | background-image: url(../i/themes/jqt/img/chevron.png); 497 | background-position: right center; 498 | background-repeat: no-repeat; 499 | background-image: url(../i/themes/jqt/img/chevron.png), -webkit-gradient(linear, 0% 0%, 0% 100%, from(#eeeeee), to(#9c9ea0)); 500 | background-repeat: no-repeat; 501 | background-position: right center; } 502 | ul.metal li.arrow a small { 503 | padding-right: 15px; 504 | line-height: 17px; } 505 | 506 | /* @group Metal */ 507 | /* @end */ 508 | -------------------------------------------------------------------------------- /j/go.js: -------------------------------------------------------------------------------- 1 | // (c) 2010 Reg Braithwaite. All rights to the entirety of the program and its parts are reserved with 2 | // the exception of specific files otherwise licensed. Other licenses apply only to the files where 3 | // they appear. 4 | 5 | ;(function ($, F, undefined) { 6 | 7 | var document_ready = function () { 8 | go.dialog = function(options) { 9 | options = $.extend( 10 | {}, 11 | { 12 | title: 'hey!', 13 | yes_button: 'Ok', 14 | no_button: 'Cancel', 15 | yes_callback: F.I, 16 | no_callback: F.I 17 | }, 18 | (options || {}) 19 | ); 20 | if (!options.no_button) { 21 | alert(options.message); 22 | options.yes_callback(); 23 | } 24 | else if (confirm(options.message)) 25 | options.yes_callback(); 26 | else options.no_callback(); 27 | }; 28 | go.message = function (say, optional_button_name) { 29 | go.dialog({ 30 | message: say, 31 | no_button: null 32 | }); 33 | }; 34 | }; 35 | 36 | var playing = function (optional_board) { 37 | var move = optional_board ? optional_board.closest('.move') : $('.move.play'); 38 | return move.is('.black') ? 'black' : ( 39 | move.is('.white') ? 'white' : null 40 | ); 41 | }; 42 | 43 | var opponent = function (optional_board) { 44 | var move = optional_board ? optional_board.closest('.move') : $('.move.play'); 45 | return move.is('.white') ? 'black' : ( 46 | move.is('.black') ? 'white' : null 47 | ); 48 | }; 49 | 50 | var switch_maker = function (board) { 51 | return function(new_player) { 52 | if (new_player == undefined) new_player = opponent(board); 53 | board 54 | .closest('.move') 55 | .addClass(new_player) 56 | .removeClass(new_player == 'white' ? 'black' : 'white'); 57 | }; 58 | }; 59 | 60 | var set_titles = function () { 61 | // $('style:last') 62 | // .text('.move.black:has(.board.play) .toolbar span.playing:before{ content: "' + go.sgf.game_info.PB + ' to play"; } ' + 63 | // '.move.white .toolbar span.playing:before{ content: "' + go.sgf.game_info.PW + ' to play"; }' ); 64 | $('style#toolbar_titles') 65 | .text([ 66 | '.move.re_black .toolbar h1:before{ content: "' + go.sgf.game_info.PB + ' wins"; } ', 67 | '.move.re_white .toolbar h1:before{ content: "' + go.sgf.game_info.PW + ' wins"; } ', 68 | '.move.re_draw .toolbar h1:before{ content: "Game Ended"; }', 69 | 70 | '.landscape .move.black:not(.swap):not(re_black):not(re_white):not(re_draw) .head .toolbar h1:before{ content: "' 71 | + (go.sgf.game_info.PB.match(/black/i) ? 'Black to play' : go.sgf.game_info.PB + ' to play black') + '"; } ', 72 | '.landscape .move.white:not(.swap) .head .toolbar h1:before{ content: "' 73 | + (go.sgf.game_info.PW.match(/white/i) ? 'White to play' : go.sgf.game_info.PW + ' to play white') + '"; } ', 74 | '.landscape .move.black.swap .head .toolbar h1:before{ content: "' 75 | + (go.sgf.game_info.PB.match(/black/i) ? 'Black to play or swap' : go.sgf.game_info.PB + ' to play black or swap') + '"; } ', 76 | '.landscape .move.white.swap .head .toolbar h1:before{ content: "' 77 | + (go.sgf.game_info.PW.match(/white/i) ? 'White to play or swap' : go.sgf.game_info.PW + ' to play white or swap') + '"; } ' 78 | ].concat( 79 | go.sgf.game_info.PB == go.sgf.game_info.PH ? [ 80 | '.profile .move.black:not(.swap):not(re_black):not(re_white):not(re_draw) .head .toolbar h1:before{ content: "' 81 | + (go.sgf.game_info.PB.match(/black/i) ? 'Black to play' : go.sgf.game_info.PB + ' to play black') + '"; } ', 82 | '.profile .move.white:not(.swap) .foot .toolbar h1:before{ content: "' 83 | + (go.sgf.game_info.PW.match(/white/i) ? 'White to play' : go.sgf.game_info.PW + ' to play white') + '"; } ', 84 | '.profile .move.black.swap .head .toolbar h1:before{ content: "' 85 | + (go.sgf.game_info.PB.match(/black/i) ? 'Black to play or swap' : go.sgf.game_info.PB + ' to play black or swap') + '"; } ', 86 | '.profile .move.white.swap .foot .toolbar h1:before{ content: "' 87 | + (go.sgf.game_info.PW.match(/white/i) ? 'White to play or swap' : go.sgf.game_info.PW + ' to play white or swap') + '"; } ' 88 | ] : [ 89 | '.profile .move.black:not(.swap):not(re_black):not(re_white):not(re_draw) .foot .toolbar h1:before{ content: "' 90 | + (go.sgf.game_info.PB.match(/black/i) ? 'Black to play' : go.sgf.game_info.PB + ' to play black') + '"; } ', 91 | '.profile .move.white:not(.swap) .head .toolbar h1:before{ content: "' 92 | + (go.sgf.game_info.PW.match(/white/i) ? 'White to play' : go.sgf.game_info.PW + ' to play white') + '"; } ', 93 | '.profile .move.black.swap .foot .toolbar h1:before{ content: "' 94 | + (go.sgf.game_info.PB.match(/black/i) ? 'Black to play or swap' : go.sgf.game_info.PB + ' to play black or swap') + '"; } ', 95 | '.profile .move.white.swap .head .toolbar h1:before{ content: "' 96 | + (go.sgf.game_info.PW.match(/white/i) ? 'White to play or swap' : go.sgf.game_info.PW + ' to play white or swap') + '"; } ' 97 | ] 98 | ).join(' ')); 99 | // $('style#bubbles') 100 | // .text([ 101 | // '.landscape .move.play .board .toolbar h1:before{ } ', 102 | // '.landscape .move.white:not(.swap) .head .toolbar h1:before{ content: "' 103 | // + (go.sgf.game_info.PW.match(/white/i) ? 'White to play' : go.sgf.game_info.PW + ' to play white') + '"; } ', 104 | // '.landscape .move.black.swap .head .toolbar h1:before{ content: "' 105 | // + (go.sgf.game_info.PB.match(/black/i) ? 'Black to play or swap' : go.sgf.game_info.PB + ' to play black or swap') + '"; } ', 106 | // '.landscape .move.white.swap .head .toolbar h1:before{ content: "' 107 | // + (go.sgf.game_info.PW.match(/white/i) ? 'White to play or swap' : go.sgf.game_info.PW + ' to play white or swap') + '"; } ' 108 | // ].concat( 109 | // go.sgf.game_info.PB == go.sgf.game_info.PH ? [ 110 | // '.profile .move.black:not(.swap):not(re_black):not(re_white):not(re_draw) .head .toolbar h1:before{ content: "' 111 | // + (go.sgf.game_info.PB.match(/black/i) ? 'Black to play' : go.sgf.game_info.PB + ' to play black') + '"; } ', 112 | // '.profile .move.white:not(.swap) .foot .toolbar h1:before{ content: "' 113 | // + (go.sgf.game_info.PW.match(/white/i) ? 'White to play' : go.sgf.game_info.PW + ' to play white') + '"; } ', 114 | // '.profile .move.black.swap .head .toolbar h1:before{ content: "' 115 | // + (go.sgf.game_info.PB.match(/black/i) ? 'Black to play or swap' : go.sgf.game_info.PB + ' to play black or swap') + '"; } ', 116 | // '.profile .move.white.swap .foot .toolbar h1:before{ content: "' 117 | // + (go.sgf.game_info.PW.match(/white/i) ? 'White to play or swap' : go.sgf.game_info.PW + ' to play white or swap') + '"; } ' 118 | // ] : [ 119 | // '.profile .move.black:not(.swap):not(re_black):not(re_white):not(re_draw) .foot .toolbar h1:before{ content: "' 120 | // + (go.sgf.game_info.PB.match(/black/i) ? 'Black to play' : go.sgf.game_info.PB + ' to play black') + '"; } ', 121 | // '.profile .move.white:not(.swap) .head .toolbar h1:before{ content: "' 122 | // + (go.sgf.game_info.PW.match(/white/i) ? 'White to play' : go.sgf.game_info.PW + ' to play white') + '"; } ', 123 | // '.profile .move.black.swap .foot .toolbar h1:before{ content: "' 124 | // + (go.sgf.game_info.PB.match(/black/i) ? 'Black to play or swap' : go.sgf.game_info.PB + ' to play black or swap') + '"; } ', 125 | // '.profile .move.white.swap .head .toolbar h1:before{ content: "' 126 | // + (go.sgf.game_info.PW.match(/white/i) ? 'White to play or swap' : go.sgf.game_info.PW + ' to play white or swap') + '"; } ' 127 | // ] 128 | // ).join(' ')); 129 | }; 130 | 131 | var predoit = function (board, this_move) { 132 | return board 133 | .find('.intersection.changd') 134 | .removeClass('changed') 135 | .end(); 136 | }; 137 | 138 | var postdoit = function(board, this_move) { 139 | 140 | if (board.closest('.move').is(':not(.history)')) { 141 | 142 | board 143 | .K(go.referee.validate); 144 | 145 | if (!sgf.game_info.RE) { 146 | board 147 | .closest('.move') 148 | .removeClass('re_black re_white re_draw'); 149 | } 150 | else if ('B' == sgf.game_info.RE[0]) { 151 | board 152 | .closest('.move') 153 | .removeClass('black white') 154 | .addClass('re_black'); 155 | } 156 | else if ('W' == sgf.game_info.RE[0]) { 157 | board 158 | .closest('.move') 159 | .removeClass('black white') 160 | .addClass('re_white'); 161 | } 162 | else { 163 | board 164 | .closest('.move') 165 | .removeClass('black white') 166 | .addClass('re_draw'); 167 | } 168 | 169 | } 170 | 171 | return board; 172 | }; 173 | 174 | var floor = function(index) { 175 | while (index >= 0 && (go.sgf.current[index]['MN'] == undefined)) { 176 | --index; 177 | } 178 | return index; 179 | }; 180 | 181 | var ceiling = function(index) { 182 | while (go.sgf.current[index] && (go.sgf.current[index]['MN'] == undefined)) { 183 | ++index; 184 | } 185 | return index; 186 | }; 187 | 188 | var push = function (this_move) { 189 | go.sgf.current.push(this_move); 190 | doit($('.move.play .board'), this_move); 191 | return this_move; 192 | } 193 | 194 | var pop = function () { 195 | console.error('implement me!'); 196 | } 197 | 198 | var blank_stone = $('') 199 | .attr('src', 'i/dot_clear.gif'); 200 | 201 | var doit = function (board, this_move) { 202 | 203 | board = predoit(board, this_move); 204 | 205 | var switch_turns = switch_maker(board); 206 | 207 | var to_play = this_move.PL; 208 | 209 | board 210 | .find('.latest') 211 | .removeClass('latest'); 212 | 213 | if (this_move.B != undefined || this_move.AB != undefined || this_move.W != undefined || this_move.AW != undefined) 214 | board 215 | .find('.changed') 216 | .removeClass('changed'); 217 | 218 | var play = this_move.B; 219 | if (play && play != '') { 220 | board 221 | .find('#' + play) 222 | .addClass('black latest changed'); 223 | switch_turns(); 224 | } 225 | else if (play == '') { 226 | switch_turns(); 227 | } 228 | else { 229 | play = this_move.W; 230 | if (play && play != '') { 231 | board 232 | .find('#' + play) 233 | .addClass('white latest changed'); 234 | switch_turns(); 235 | } 236 | else if (play == '') { 237 | switch_turns(); 238 | } 239 | } 240 | 241 | var placements = this_move.AB; 242 | if (placements) { 243 | board 244 | .find($.map(placements.split(','), "'#' + _".lambda()).join(',')) 245 | .addClass('black changed' + (this_move != go.sgf.game_info ? ' latest' : '')); 246 | } 247 | placements = this_move.AW; 248 | if (placements) { 249 | board 250 | .find($.map(placements.split(','), "'#' + _".lambda()).join(',')) 251 | .addClass('white changed' + (this_move != go.sgf.game_info ? ' latest' : '')); 252 | } 253 | if (this_move.K && (this_move.W || this_move.B)) // TODO: figure out undo and stones! 254 | board 255 | .find($.map(this_move['K'].split(','), '"#" + _'.lambda()).join(',')) 256 | .filter('.white') 257 | .removeClass('white') 258 | .K(function (whites) { 259 | var z = whites.size(); 260 | if (z > 0) { 261 | var c = board.find('.white.captured:visible'); 262 | if (c.size() > 0) { 263 | var n = parseInt(c.text()); 264 | c.text('' + (n ? n + z : z)); 265 | } 266 | else board.find('.white.captured').text(z); 267 | } 268 | }) 269 | .end() 270 | .filter('.black') 271 | .removeClass('black') 272 | .K(function (blacks) { 273 | var z = blacks.size(); 274 | if (z > 0) { 275 | var c = board.find('.black.captured:visible'); 276 | if (c.size() > 0) { 277 | var n = parseInt(c.text()); 278 | c.text('' + (n ? n + z : z)); 279 | } 280 | else board.find('.black.captured').text(z); 281 | } 282 | }) 283 | .end() 284 | .addClass('changed'); 285 | 286 | if (to_play) 287 | board 288 | .closest('.move') 289 | .addClass(to_play); 290 | 291 | if (go.sgf.game_info.HA) { 292 | var placed = 0; 293 | $.each(go.sgf.current, function (i, that_move) { 294 | if (that_move.AB) 295 | placed = placed + that_move.AB.split(',').length; 296 | }); 297 | if (placed < go.sgf.game_info.HA) { 298 | board 299 | .removeClass('play') 300 | .addClass('place') 301 | .end(); 302 | } 303 | else if (this_move.AB || this_move.AW) { 304 | // this is the last play 305 | board 306 | .removeClass('place') 307 | .addClass('play') 308 | .closest('.move') 309 | .addClass(go.sgf.game_info.PI ? 'swap' : '') 310 | .end() 311 | switch_turns(); 312 | } 313 | } 314 | if (this_move.PL) 315 | switch_turns(this_move.PL); // wins over all other considerations 316 | 317 | return postdoit(board, this_move); 318 | }; 319 | 320 | var undoit = function (board, this_move, optional_previous_move) { 321 | 322 | board = predoit(board, this_move); 323 | 324 | // TODO: Handle other undoables such as placements 325 | // optional previous move is only useful for hilighting the dot to play at this point 326 | // it could be eliminated if we use a comment to annotate it. 327 | 328 | var to_play; 329 | var was_playing; 330 | 331 | var switch_turns = switch_maker(board); 332 | 333 | if (this_move['B'] != undefined) { 334 | to_play = 'white'; 335 | was_playing = 'black'; 336 | switch_turns(was_playing); 337 | } 338 | else if (this_move['W'] != undefined) { 339 | to_play = 'black'; 340 | was_playing = 'white'; 341 | switch_turns(was_playing); 342 | } 343 | else return; // not undoable 344 | 345 | var was_playing_index = was_playing[0].toUpperCase(); 346 | if (this_move != undefined) { 347 | var position = this_move[was_playing_index]; 348 | if (position != undefined) { 349 | if (position) { 350 | board 351 | .find('#' + position) 352 | .removeClass('latest') 353 | .removeClass(was_playing) 354 | .addClass('changed') 355 | .end() 356 | .find( 357 | $.map( 358 | (this_move['K'] && this_move['K'].split(',')) || [], 359 | '"#" + _'.lambda()).join(',') 360 | ) 361 | .K(function (removed) { 362 | var z = removed.size(); 363 | if (z > 0) { 364 | var restore_colour = (was_playing == 'black' ? 'white' : 'black'); 365 | removed.addClass(restore_colour + ' changed'); 366 | var c = board.find('.'+restore_colour+'.captured:visible'); 367 | if (c.size() > 0) { 368 | var n = parseInt(c.text()); 369 | c.text(n == z ? '' : '' + (n - z)); 370 | } 371 | else console.error(restore_colour+' should have stones!'); 372 | } 373 | }) 374 | .end(); 375 | } 376 | var to_play_index = to_play[0].toUpperCase(); 377 | if (optional_previous_move != undefined) { 378 | var previous_position = optional_previous_move[to_play_index]; 379 | if (previous_position) 380 | board 381 | .find('#' + previous_position) 382 | .addClass('latest'); 383 | } 384 | // TODO: Deal with titles 385 | } 386 | } 387 | 388 | return postdoit(board, this_move); 389 | }; 390 | 391 | var sgf = { 392 | 393 | game_info: undefined, 394 | 395 | current: undefined, 396 | 397 | root: undefined, 398 | 399 | floor: floor, 400 | 401 | ceiling: ceiling, 402 | 403 | doit: doit, 404 | 405 | undoit: undoit, 406 | 407 | push: push, 408 | 409 | pop: pop 410 | 411 | }; 412 | 413 | go = { 414 | letters: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's'], 415 | playing: playing, 416 | opponent: opponent, 417 | sgf: sgf, 418 | set_titles: set_titles, 419 | on_document_ready: function (new_document_ready) { 420 | document_ready = (function (old_document_ready) { 421 | return function () { 422 | old_document_ready(); 423 | new_document_ready(); 424 | } 425 | })(document_ready); 426 | } 427 | }; 428 | 429 | $(document).ready(function () { document_ready(); }); 430 | 431 | })(jQuery, Functional); -------------------------------------------------------------------------------- /j/igesture.jquery.mobile_safari.js: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Reginald Braithwaite, Portions Copyright 2008 Nico Goeminne 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // This code modified from jGesture, http://web.siruna.com/nico/jgesture/documentation.html, 16 | // (c) 2008 Nico Goeminne and released under Apache License 2.0 17 | // See: http://www.apache.org/licenses/LICENSE-2.0 18 | // 19 | // Mods (so far) include support for mobile touch events under Mobile Safari, 20 | // storing the target for creating custom events, and expanding the predefined 21 | // events so that things like "close" can be written with eight different 22 | // symmetric gestures. 23 | // 24 | // Warning: May Contain Underscores 25 | // http://ozmm.org/posts/javascript_style.html 26 | // 27 | jQuery.fn.removegesture = function (optional_namespace) { 28 | var namespace = typeof(optional_namespace) == 'undefined' ? '.g' : optional_namespace; 29 | this.unbind(namespace); 30 | return this; 31 | }; 32 | 33 | jQuery.fn.gesture = function (events) { 34 | 35 | var handling_element = $(this); 36 | 37 | var return_target = function (target) { return target; }; 38 | 39 | var selector_maker = function (selector) { 40 | return function () { return $(selector); }; 41 | }; 42 | 43 | var stroke_events = {}; 44 | var gesture_events = {}; 45 | var default_gestures = { 46 | scrub: /^(4([^48]*8[^48]*4)([^48]*8)?)|(8([^48]*4[^48]*8)([^48]*4)?)$/, 47 | open: /^(4.*7.*2)|(4.*1.*6)|(8.*5.*2)|(8.*3.*6)|(2.*7.*4)|(6.*1.*4)|(2.*5.*8)|(6.*3.*8)$/, 48 | close: /^(5.*2.*7)|(1.*6.*3)|(5.*8.*3)|(1.*4.*7)|(7.*2.*5)|(3.*6.*1)|(3.*8.*5)|(7.*4.*1)$/ 49 | }; 50 | var default_settings = { 51 | startStroke: "touchstart mousedown", 52 | stopStroke: "touchend mouseup", 53 | continueStroke: "touchmove mousemove", 54 | startGesture: "gesturestart", 55 | stopGesture: "gestureend", 56 | continueGesture: "gesturechange", 57 | button: "012", 58 | minDistance: 10, 59 | minScale: 0.25, 60 | minRotation: 22.5, 61 | continuesmode: false, 62 | repeat: false, 63 | disablecontextmenu: true, 64 | hold_time: '2s', 65 | gestures: {}, 66 | namespace: '.g', 67 | preventDefault: true 68 | }; 69 | var settings = { 70 | gestures: {} 71 | }; 72 | 73 | jQuery.each(events, function (i, e) { 74 | if (e == 'scale' || e == 'rotate') { 75 | gesture_events[e] = return_target; 76 | } 77 | else if (typeof(e) == 'string') { 78 | stroke_events[e] = return_target; 79 | } 80 | else { 81 | for (i in e) { 82 | if (typeof(default_settings[i]) == 'undefined') { 83 | var h = (i == 'scale' || i == 'rotate') ? gesture_events : stroke_events; 84 | if (typeof(e[i]) == 'function') { 85 | if (typeof(e[i]).prototype == 'undefined') { 86 | settings.gestures[i] = e[i]; 87 | h[i] = return_target; 88 | } 89 | else h[i] = e[i]; 90 | } 91 | else if (typeof(e[i]) == 'string'){ 92 | h[i] = selector_maker(e[i]); 93 | } 94 | } 95 | else { 96 | settings[i] = e[i]; 97 | } 98 | } 99 | } 100 | }); 101 | 102 | var care_about_holds_in_general = typeof(stroke_events['hold']) != 'undefined'; 103 | var timers_loaded = typeof(handling_element.oneTime) == 'undefined'; 104 | 105 | if (care_about_holds_in_general && timers_loaded) { 106 | console.error("You must include jQuery Timers to use gesture_hold: http://plugins.jquery.com/project/timers"); 107 | care_about_holds_in_general = false; 108 | stroke_events['hold'] = null; 109 | } 110 | 111 | settings = jQuery.extend(default_settings, settings); 112 | settings.gestures = jQuery.extend(default_gestures, settings.gestures); 113 | 114 | if (!jQuery.isEmptyObject(stroke_events)) { 115 | 116 | var topleft = 1; 117 | var top = 2; 118 | var topright = 3; 119 | var right = 4; 120 | var bottomright = 5; 121 | var bottom = 6; 122 | var bottomleft = 7; 123 | var left = 8; 124 | 125 | var stroke_handler = function (e) { 126 | 127 | if (settings.preventDefault) e.preventDefault(); 128 | if (settings.preventDefault) e.stopPropagation(); 129 | 130 | var gesture = { 131 | target: $(e.target), 132 | originalEvent: e, 133 | moves: "", 134 | x: -1, 135 | y: -1, 136 | lastmove: "", 137 | continuesmode: settings.continuesmode, 138 | getMoveNameAt: function (i) { 139 | switch (Number(this.moves.charAt(i))) { 140 | case 1: 141 | return "topleft"; 142 | case 2: 143 | return "top"; 144 | case 3: 145 | return "topright"; 146 | case 4: 147 | return "right"; 148 | case 5: 149 | return "bottomright"; 150 | case 6: 151 | return "bottom"; 152 | case 7: 153 | return "bottomleft"; 154 | case 8: 155 | return "left"; 156 | default: 157 | return "unknown"; 158 | } 159 | }, 160 | getName: function () { 161 | 162 | if (this.moves.length == 0) { 163 | return 'click'; 164 | } 165 | 166 | if (this.continuesmode || this.moves.length == 1) { 167 | return this.getMoveNameAt(this.moves.length - 1); 168 | } 169 | 170 | if (this.moves.length == 2) { 171 | return this.getMoveNameAt(0) + "_" + this.getMoveNameAt(1); 172 | } 173 | 174 | if (this.moves.length < 7) { 175 | 176 | for (var gesture_name in settings.gestures) { 177 | if (this.moves.match(settings.gestures[gesture_name])) { 178 | return gesture_name; 179 | } 180 | } 181 | 182 | } 183 | else { 184 | if ((function (str) { 185 | for (var i = 1; i < 8; i++) { 186 | var pre = Number(str.charAt(i - 1)); 187 | var cur = Number(str.charAt(i)); 188 | if ((pre + 1 == cur) || (pre == cur + 7)) { 189 | continue; 190 | } 191 | return false; 192 | } 193 | return true; 194 | })(this.moves)) return "circleclockwise"; 195 | 196 | if ((function (str) { 197 | for (var i = 1; i < 8; i++) { 198 | var pre = Number(str.charAt(i - 1)); 199 | var cur = Number(str.charAt(i)); 200 | if ((pre == cur + 1) || (pre + 7 == cur)) { 201 | continue; 202 | } 203 | return false; 204 | } 205 | return true; 206 | })(this.moves)) return "circlecounterclockwise"; 207 | } 208 | 209 | return "unknown"; 210 | } 211 | }; 212 | 213 | if (e.button != null && settings.button.indexOf("" + e.button) == -1) return; 214 | 215 | // disable browser context menu. 216 | if (settings.disablecontextmenu) { 217 | handling_element.bind("contextmenu" + settings.namespace, function (e) { return false; }); 218 | } 219 | 220 | gesture.moves = ""; 221 | gesture.x = -1; 222 | gesture.y = -1; 223 | gesture.continuesmode = settings.continuesmode; 224 | 225 | var stroke_stopper; 226 | var stroke_continuer; 227 | 228 | var trigger_events = function () { 229 | 230 | var canonical_name = gesture.getName(); 231 | 232 | if (typeof(canonical_name) == 'undefined') { 233 | return; 234 | } 235 | 236 | var all_names = [canonical_name]; 237 | 238 | if (canonical_name != 'unknown') { 239 | all_names.push('any'); 240 | if (gesture.moves.length == 1) 241 | all_names.push('swipe'); 242 | if (gesture.moves.length == 2) 243 | all_names.push('elbow'); 244 | if (canonical_name == 'circlecounterclockwise' || canonical_name == 'circleclockwise') 245 | all_names.push('circle'); 246 | if (canonical_name == 'close') { 247 | all_names.push('no'); 248 | all_names.push('reject'); 249 | all_names.push('dismiss'); 250 | } 251 | if (canonical_name == 'bottomright_topright') { 252 | all_names.push('ok'); 253 | all_names.push('accept'); 254 | all_names.push('dismiss'); 255 | } 256 | } 257 | 258 | jQuery.each(all_names, function (index, gesture_name) { 259 | if (stroke_events[gesture_name]) { 260 | var gesture_event = jQuery.Event("gesture_" + gesture_name); 261 | gesture_event.gesture_data = gesture; 262 | stroke_events[gesture_name](gesture.target).trigger(gesture_event); 263 | } 264 | }); 265 | 266 | }; 267 | 268 | stroke_continuer = function (e) { 269 | 270 | if (checking_for_hold_on_this_stroke && gesture.moves.length > 0) { 271 | checking_for_hold_on_this_stroke = false; 272 | gesture.target.stopTime('hold_detection'); 273 | } 274 | var x; 275 | var y; 276 | if (typeof(e.screenX) != 'undefined') { 277 | x = e.screenX; 278 | y = e.screenY; 279 | } 280 | else if (typeof(e.targetTouches) != 'undefined') { 281 | x = e.targetTouches[0].pageX; 282 | y = e.targetTouches[0].pageY; 283 | } 284 | else if (typeof(e.originalEvent) == 'undefined') { 285 | var str = ''; 286 | for (i in e) { 287 | str += ', ' + i + ': ' + e[i]; 288 | } 289 | console.error("don't understand x and y for " + e.type + ' event: ' + str); 290 | } 291 | else if (typeof(e.originalEvent.screenX) != 'undefined') { 292 | x = e.originalEvent.screenX; 293 | y = e.originalEvent.screenY; 294 | } 295 | else if (typeof(e.originalEvent.targetTouches) != 'undefined') { 296 | if (typeof(e.originalEvent.targetTouches[0]) == 'undefined') { 297 | var str = ''; 298 | for (i in e.originalEvent) { 299 | str += ', ' + i + ': ' + e.originalEvent[i]; 300 | } 301 | console.error("don't understand x and y for " + e.originalEvent.type + ' event: ' + str); 302 | } 303 | x = e.originalEvent.targetTouches[0].pageX; 304 | y = e.originalEvent.targetTouches[0].pageY; 305 | if (e.originalEvent.targetTouches.length > 1) { 306 | handling_element.unbind(settings.continueStroke + settings.namespace); 307 | handling_element.unbind(settings.stopStroke + settings.namespace); 308 | return; 309 | } 310 | } 311 | 312 | if ((gesture.x == -1) && (gesture.y == -1)) { 313 | gesture.x = x; 314 | gesture.y = y; 315 | return; 316 | } 317 | var distance = Math.sqrt(Math.pow(x - gesture.x, 2) + Math.pow(y - gesture.y, 2)); 318 | if (distance > settings.minDistance) { 319 | var angle = Math.atan2(x - gesture.x, y - gesture.y) / Math.PI + 1; 320 | var dir = 0; 321 | if (3 / 8 < angle && angle < 5 / 8) dir = 8; 322 | if (5 / 8 < angle && angle < 7 / 8) dir = 7; 323 | if (7 / 8 < angle && angle < 9 / 8) dir = 6; 324 | if (9 / 8 < angle && angle < 11 / 8) dir = 5; 325 | if (11 / 8 < angle && angle < 13 / 8) dir = 4; 326 | if (13 / 8 < angle && angle < 15 / 8) dir = 3; 327 | if (15 / 8 < angle || angle < 1 / 8) dir = 2; 328 | if (1 / 8 < angle && angle < 3 / 8) dir = 1; 329 | 330 | gesture.x = x; 331 | gesture.y = y; 332 | 333 | if (gesture.moves.length == 0) { 334 | gesture.moves += dir; 335 | gesture.lastmove = "" + dir; 336 | } 337 | else { 338 | if (settings.repeat || (gesture.moves.charAt(gesture.moves.length - 1) != dir)) { 339 | gesture.moves += dir; 340 | gesture.lastmove = "" + dir; 341 | } 342 | } 343 | if (settings.continuesmode) 344 | trigger_events(); // I believe this is broken and that we only care about the last stroke. 345 | } 346 | 347 | }; 348 | 349 | stroke_stopper = function (e) { 350 | 351 | if (checking_for_hold_on_this_stroke) { 352 | gesture.target.stopTime('hold_detection'); 353 | } 354 | 355 | if (e.button != null && settings.button.indexOf("" + e.button) == -1) { 356 | return; 357 | } 358 | 359 | if (!settings.disablecontextmenu) { 360 | handling_element.unbind("contextmenu" + settings.namespace); 361 | } 362 | handling_element.unbind(settings.continueStroke + settings.namespace, stroke_continuer); 363 | handling_element.unbind(e); 364 | 365 | trigger_events(); 366 | 367 | if (settings.preventDefault) return false; 368 | }; 369 | 370 | handling_element 371 | .bind(settings.continueStroke + settings.namespace, stroke_continuer) 372 | .bind(settings.stopStroke + settings.namespace, stroke_stopper); 373 | 374 | var checking_for_hold_on_this_stroke = care_about_holds_in_general; 375 | 376 | if (checking_for_hold_on_this_stroke) { 377 | gesture.target.oneTime(settings.hold_time, 'hold_detection', function () { 378 | handling_element.unbind(settings.continueStroke + settings.namespace, stroke_continuer); 379 | handling_element.unbind(settings.stopStroke + settings.namespace, stroke_stopper); 380 | gesture.getName = function () { return 'hold'; }; 381 | trigger_events(); 382 | }); 383 | } 384 | 385 | if (settings.preventDefault) return false; 386 | 387 | }; 388 | 389 | this.bind(settings.startStroke + settings.namespace, stroke_handler); 390 | 391 | }; 392 | 393 | if (!jQuery.isEmptyObject(gesture_events)) { 394 | 395 | var gesture_handler = function (e) { 396 | 397 | var gesture = { 398 | target: $(e.target), 399 | originalEvent: e, 400 | continuesmode: settings.continuesmode 401 | }; 402 | 403 | // disable browser context menu. 404 | if (settings.disablecontextmenu) { 405 | handling_element.bind("contextmenu" + settings.namespace, function (e) { return false; }); 406 | } 407 | 408 | gesture.moves = ""; 409 | gesture.x = -1; 410 | gesture.y = -1; 411 | gesture.continuesmode = settings.continuesmode; 412 | 413 | gesture.scale = 1.0; 414 | gesture.rotation = 0; 415 | 416 | handling_element 417 | .filter(':not(.in_gesture)') 418 | .addClass('in_gesture') 419 | .bind(settings.continueGesture + settings.namespace, function (e) { 420 | if (settings.preventDefault) e.preventDefault(); 421 | if (settings.preventDefault) e.stopPropagation(); 422 | var scale_diff = e.originalEvent.scale - 1.0; 423 | gesture.scale += scale_diff; 424 | var rotation_diff = e.originalEvent.rotation - gesture.rotation 425 | gesture.rotation = e.originalEvent.rotation 426 | if (settings.continuesmode) { 427 | if (Math.abs(gesture.scale - 1.0) >= settings.minScale && gesture_events['scale']) { 428 | var gesture_event = jQuery.Event('gesture_scale'); 429 | gesture_event.gesture_data = jQuery.extend(gesture, { name: 'scale' }); 430 | gesture_event.scale = gesture.scale; 431 | gesture_events['scale'](gesture.target).trigger(gesture_event); 432 | gesture.scale = 1.0; 433 | } 434 | if (Math.abs(rotation_diff % 360) >= settings.minRotation && gesture_events['rotate']) { 435 | var gesture_event = jQuery.Event('gesture_rotate'); 436 | gesture_event.gesture_data = jQuery.extend(gesture, { name: 'rotate' }); 437 | gesture_event.rotation = rotation_diff; 438 | gesture_events['rotate'](gesture.target).trigger(gesture_event); 439 | gesture.rotation = 0; 440 | } 441 | } 442 | if (settings.preventDefault) e.preventDefault(); 443 | }) 444 | .bind(settings.stopGesture + settings.namespace, function (e) { 445 | if (Math.abs(gesture.scale - 1.0) >= settings.minScale && gesture_events['scale']) { 446 | var gesture_event = jQuery.Event('gesture_scale'); 447 | gesture_event.gesture_data = jQuery.extend(gesture, { name: 'scale' }); 448 | gesture_event.scale = gesture.scale; 449 | gesture_events['scale'](gesture.target).trigger(gesture_event); 450 | } 451 | if (Math.abs(gesture.rotation % 360) >= settings.minRotation && gesture_events['rotate']) { 452 | var gesture_event = jQuery.Event('gesture_rotate'); 453 | gesture_event.gesture_data = jQuery.extend(gesture, { name: 'rotate' }); 454 | gesture_event.rotation = gesture.rotation; 455 | gesture_events['rotate'](gesture.target).trigger(gesture_event); 456 | } 457 | if (settings.preventDefault) e.preventDefault(); 458 | if (settings.preventDefault) e.stopPropagation(); 459 | handling_element 460 | .unbind(settings.continueGesture + settings.namespace) 461 | .unbind(settings.stopGesture + settings.namespace) 462 | .removeClass('in_gesture'); 463 | }); 464 | 465 | }; 466 | 467 | this 468 | .bind(settings.startGesture + settings.namespace, gesture_handler); 469 | 470 | }; 471 | 472 | return this; 473 | 474 | }; --------------------------------------------------------------------------------