gettext 1.10.0 → 1.90.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (327) hide show
  1. data/ChangeLog +156 -2
  2. data/NEWS +28 -0
  3. data/README +128 -138
  4. data/Rakefile +83 -43
  5. data/data/locale/es/LC_MESSAGES/rails.mo +0 -0
  6. data/data/locale/hu/LC_MESSAGES/rails.mo +0 -0
  7. data/data/locale/hu/LC_MESSAGES/rgettext.mo +0 -0
  8. data/data/locale/ua/LC_MESSAGES/rails.mo +0 -0
  9. data/data/locale/ua/LC_MESSAGES/rgettext.mo +0 -0
  10. data/doc/classes/ActiveRecord/Base.html +360 -0
  11. data/doc/classes/ActiveRecord/ConnectionAdapters/Column.html +182 -0
  12. data/doc/classes/ActiveRecord/Migration.html +118 -0
  13. data/doc/classes/GetText.html +1790 -0
  14. data/doc/classes/GetText/ActiveRecordParser.html +236 -0
  15. data/doc/classes/GetText/Container.html +119 -0
  16. data/doc/classes/GetText/ErbContainer.html +223 -0
  17. data/doc/classes/GetText/ErbParser.html +156 -0
  18. data/doc/classes/GetText/GladeParser.html +133 -0
  19. data/doc/classes/GetText/NoboundTextDomainError.html +119 -0
  20. data/doc/classes/GetText/PoParser.html +169 -0
  21. data/doc/classes/GetText/Rails.html +293 -0
  22. data/doc/classes/GetText/RubyParser.html +123 -0
  23. data/doc/classes/GetText/TextDomain.html +572 -0
  24. data/doc/classes/GetText/TextDomainManager.html +443 -0
  25. data/doc/classes/Iconv.html +257 -0
  26. data/doc/classes/Iconv/Failure.html +105 -0
  27. data/doc/classes/Iconv/IllegalSequence.html +118 -0
  28. data/doc/classes/Iconv/InvalidCharacter.html +118 -0
  29. data/doc/classes/Iconv/InvalidEncoding.html +118 -0
  30. data/doc/classes/Locale.html +839 -0
  31. data/doc/classes/Locale/Object.html +799 -0
  32. data/doc/classes/Locale/SystemBase.html +271 -0
  33. data/doc/classes/Locale/SystemCGI.html +312 -0
  34. data/doc/classes/Locale/SystemJRuby.html +112 -0
  35. data/doc/classes/Locale/SystemPosix.html +113 -0
  36. data/doc/classes/Locale/SystemWin32.html +182 -0
  37. data/doc/classes/MOFile.html +678 -0
  38. data/doc/classes/MOFile/InvalidFormat.html +111 -0
  39. data/doc/classes/Module.html +158 -0
  40. data/doc/classes/String.html +225 -0
  41. data/doc/created.rid +1 -0
  42. data/doc/files/ChangeLog.html +2355 -0
  43. data/doc/files/README.html +510 -0
  44. data/doc/files/lib/gettext/active_record_rb.html +110 -0
  45. data/doc/files/lib/gettext/cgi_rb.html +110 -0
  46. data/doc/files/lib/gettext/container_rb.html +108 -0
  47. data/doc/files/lib/gettext/erb_rb.html +109 -0
  48. data/doc/files/lib/gettext/iconv_rb.html +109 -0
  49. data/doc/files/lib/gettext/mo_rb.html +108 -0
  50. data/doc/files/lib/gettext/parser/active_record_rb.html +119 -0
  51. data/doc/files/lib/gettext/parser/erb_rb.html +109 -0
  52. data/doc/files/lib/gettext/parser/glade_rb.html +109 -0
  53. data/doc/files/lib/gettext/parser/ruby_rb.html +110 -0
  54. data/doc/files/lib/gettext/poparser_rb.html +108 -0
  55. data/doc/files/lib/gettext/rails_compat_rb.html +108 -0
  56. data/doc/files/lib/gettext/rails_rb.html +112 -0
  57. data/doc/files/lib/gettext/rgettext_rb.html +110 -0
  58. data/doc/files/lib/gettext/rmsgfmt_rb.html +112 -0
  59. data/doc/files/lib/gettext/rmsgmerge_rb.html +112 -0
  60. data/doc/files/lib/gettext/string_rb.html +101 -0
  61. data/doc/files/lib/gettext/textdomain_rb.html +109 -0
  62. data/doc/files/lib/gettext/textdomainmanager_rb.html +109 -0
  63. data/doc/files/lib/gettext/utils_rb.html +111 -0
  64. data/doc/files/lib/gettext/version_rb.html +101 -0
  65. data/doc/files/lib/gettext_rb.html +113 -0
  66. data/doc/files/lib/locale/base_rb.html +101 -0
  67. data/doc/files/lib/locale/cgi_rb.html +108 -0
  68. data/doc/files/lib/locale/jruby_rb.html +110 -0
  69. data/doc/files/lib/locale/object_rb.html +101 -0
  70. data/doc/files/lib/locale/posix_rb.html +108 -0
  71. data/doc/files/lib/locale/win32_rb.html +110 -0
  72. data/doc/files/lib/locale/win32_table_rb.html +101 -0
  73. data/doc/files/lib/locale_rb.html +111 -0
  74. data/doc/fr_class_index.html +57 -0
  75. data/doc/fr_file_index.html +58 -0
  76. data/doc/fr_method_index.html +155 -0
  77. data/doc/index.html +24 -0
  78. data/doc/rdoc-style.css +208 -0
  79. data/lib/gettext.rb +102 -50
  80. data/lib/gettext/cgi.rb +2 -27
  81. data/lib/gettext/iconv.rb +76 -62
  82. data/lib/gettext/mo.rb +3 -3
  83. data/lib/gettext/parser/erb.rb +2 -2
  84. data/lib/gettext/rails.rb +69 -48
  85. data/lib/gettext/rgettext.rb +2 -2
  86. data/lib/gettext/rmsgmerge.rb +2 -2
  87. data/lib/gettext/string.rb +9 -5
  88. data/lib/gettext/textdomain.rb +3 -3
  89. data/lib/gettext/textdomainmanager.rb +5 -5
  90. data/lib/gettext/utils.rb +4 -3
  91. data/lib/gettext/version.rb +1 -1
  92. data/lib/{gettext/locale.rb → locale.rb} +11 -58
  93. data/lib/locale/base.rb +60 -0
  94. data/lib/{gettext/locale_cgi.rb → locale/cgi.rb} +30 -28
  95. data/lib/locale/jruby.rb +36 -0
  96. data/lib/{gettext/locale_object.rb → locale/object.rb} +78 -24
  97. data/lib/locale/posix.rb +22 -0
  98. data/lib/locale/win32.rb +48 -0
  99. data/lib/{gettext/locale_table_win32.rb → locale/win32_table.rb} +3 -2
  100. data/po/es/rails.po +1 -2
  101. data/po/hu/rails.po +139 -0
  102. data/po/hu/rgettext.po +126 -0
  103. data/po/ja/rails.po +5 -5
  104. data/po/ua/rails.po +150 -0
  105. data/po/ua/rgettext.po +132 -0
  106. data/pre-setup.rb +2 -4
  107. data/samples/cgi/cookie.cgi +1 -0
  108. data/samples/cgi/helloerb1.cgi +6 -3
  109. data/samples/cgi/helloerb2.cgi +6 -3
  110. data/samples/cgi/http.rb +3 -7
  111. data/samples/cgi/index.cgi +2 -1
  112. data/samples/cgi/locale/hu/LC_MESSAGES/helloerb1.mo +0 -0
  113. data/samples/cgi/locale/hu/LC_MESSAGES/helloerb2.mo +0 -0
  114. data/samples/cgi/locale/hu/LC_MESSAGES/hellolib.mo +0 -0
  115. data/samples/cgi/locale/hu/LC_MESSAGES/main.mo +0 -0
  116. data/samples/cgi/locale/ua/LC_MESSAGES/helloerb1.mo +0 -0
  117. data/samples/cgi/locale/ua/LC_MESSAGES/helloerb2.mo +0 -0
  118. data/samples/cgi/locale/ua/LC_MESSAGES/hellolib.mo +0 -0
  119. data/samples/cgi/locale/ua/LC_MESSAGES/main.mo +0 -0
  120. data/samples/cgi/po/hu/helloerb1.po +59 -0
  121. data/samples/cgi/po/hu/helloerb2.po +51 -0
  122. data/samples/cgi/po/hu/hellolib.po +23 -0
  123. data/samples/cgi/po/hu/main.po +82 -0
  124. data/samples/cgi/po/ua/helloerb1.po +62 -0
  125. data/samples/cgi/po/ua/helloerb2.po +54 -0
  126. data/samples/cgi/po/ua/hellolib.po +26 -0
  127. data/samples/cgi/po/ua/main.po +84 -0
  128. data/samples/locale/hu/LC_MESSAGES/hello.mo +0 -0
  129. data/samples/locale/hu/LC_MESSAGES/hello2.mo +0 -0
  130. data/samples/locale/hu/LC_MESSAGES/hello_noop.mo +0 -0
  131. data/samples/locale/hu/LC_MESSAGES/hello_plural.mo +0 -0
  132. data/samples/locale/hu/LC_MESSAGES/helloglade2.mo +0 -0
  133. data/samples/locale/hu/LC_MESSAGES/hellogtk.mo +0 -0
  134. data/samples/locale/hu/LC_MESSAGES/hellotk.mo +0 -0
  135. data/samples/locale/ua/LC_MESSAGES/hello.mo +0 -0
  136. data/samples/locale/ua/LC_MESSAGES/hello2.mo +0 -0
  137. data/samples/locale/ua/LC_MESSAGES/hello_noop.mo +0 -0
  138. data/samples/locale/ua/LC_MESSAGES/hello_plural.mo +0 -0
  139. data/samples/locale/ua/LC_MESSAGES/helloglade2.mo +0 -0
  140. data/samples/locale/ua/LC_MESSAGES/hellogtk.mo +0 -0
  141. data/samples/locale/ua/LC_MESSAGES/hellotk.mo +0 -0
  142. data/samples/po/hu/hello.po +22 -0
  143. data/samples/po/hu/hello2.po +30 -0
  144. data/samples/po/hu/hello_noop.po +26 -0
  145. data/samples/po/hu/hello_plural.po +25 -0
  146. data/samples/po/hu/helloglade2.po +31 -0
  147. data/samples/po/hu/hellogtk.po +22 -0
  148. data/samples/po/hu/hellotk.po +23 -0
  149. data/samples/po/ua/hello.po +22 -0
  150. data/samples/po/ua/hello2.po +30 -0
  151. data/samples/po/ua/hello_noop.po +26 -0
  152. data/samples/po/ua/hello_plural.po +29 -0
  153. data/samples/po/ua/helloglade2.po +34 -0
  154. data/samples/po/ua/hellogtk.po +22 -0
  155. data/samples/po/ua/hellotk.po +26 -0
  156. data/samples/rails/README +15 -31
  157. data/samples/rails/Rakefile +1 -1
  158. data/samples/rails/app/controllers/application.rb +11 -4
  159. data/samples/rails/app/controllers/articles_controller.rb +96 -0
  160. data/samples/rails/app/helpers/application_helper.rb +1 -1
  161. data/samples/rails/app/helpers/{blog_helper.rb → articles_helper.rb} +6 -7
  162. data/samples/rails/app/views/articles/edit.html.erb +18 -0
  163. data/samples/rails/app/views/articles/index.html.erb +17 -0
  164. data/samples/rails/app/views/articles/new.html.erb +16 -0
  165. data/samples/rails/app/views/articles/show.html.erb +6 -0
  166. data/samples/rails/app/views/layouts/articles.html.erb +26 -0
  167. data/samples/rails/config/boot.rb +104 -13
  168. data/samples/rails/config/database.yml +24 -21
  169. data/samples/rails/config/environment.rb +35 -30
  170. data/samples/rails/config/environments/development.rb +5 -6
  171. data/samples/rails/config/environments/production.rb +2 -3
  172. data/samples/rails/config/environments/test.rb +5 -2
  173. data/samples/rails/config/initializers/inflections.rb +10 -0
  174. data/samples/rails/config/initializers/mime_types.rb +5 -0
  175. data/samples/rails/config/routes.rb +30 -11
  176. data/samples/rails/db/migrate/001_create_articles.rb +14 -0
  177. data/samples/rails/db/schema.rb +16 -5
  178. data/samples/rails/lib/tasks/gettext.rake +2 -2
  179. data/samples/rails/locale/bs/LC_MESSAGES/blog.mo +0 -0
  180. data/samples/rails/locale/ca/LC_MESSAGES/blog.mo +0 -0
  181. data/samples/rails/locale/cs/LC_MESSAGES/blog.mo +0 -0
  182. data/samples/rails/locale/de/LC_MESSAGES/blog.mo +0 -0
  183. data/samples/rails/locale/el/LC_MESSAGES/blog.mo +0 -0
  184. data/samples/rails/locale/en/LC_MESSAGES/blog.mo +0 -0
  185. data/samples/rails/locale/eo/LC_MESSAGES/blog.mo +0 -0
  186. data/samples/rails/locale/es/LC_MESSAGES/blog.mo +0 -0
  187. data/samples/rails/locale/fr/LC_MESSAGES/blog.mo +0 -0
  188. data/samples/rails/locale/hr/LC_MESSAGES/blog.mo +0 -0
  189. data/samples/rails/locale/hu/LC_MESSAGES/blog.mo +0 -0
  190. data/samples/rails/locale/it/LC_MESSAGES/blog.mo +0 -0
  191. data/samples/rails/locale/ja/LC_MESSAGES/blog.mo +0 -0
  192. data/samples/rails/locale/ko/LC_MESSAGES/blog.mo +0 -0
  193. data/samples/rails/locale/nb/LC_MESSAGES/blog.mo +0 -0
  194. data/samples/rails/locale/nl/LC_MESSAGES/blog.mo +0 -0
  195. data/samples/rails/locale/pt_BR/LC_MESSAGES/blog.mo +0 -0
  196. data/samples/rails/locale/ru/LC_MESSAGES/blog.mo +0 -0
  197. data/samples/rails/locale/ua/LC_MESSAGES/blog.mo +0 -0
  198. data/samples/rails/locale/vi/LC_MESSAGES/blog.mo +0 -0
  199. data/samples/rails/locale/zh/LC_MESSAGES/blog.mo +0 -0
  200. data/samples/rails/locale/zh_TW/LC_MESSAGES/blog.mo +0 -0
  201. data/samples/rails/po/blog.pot +24 -24
  202. data/samples/rails/po/bs/blog.po +29 -29
  203. data/samples/rails/po/ca/blog.po +27 -27
  204. data/samples/rails/po/cs/blog.po +27 -27
  205. data/samples/rails/po/de/blog.po +27 -27
  206. data/samples/rails/po/el/blog.po +27 -27
  207. data/samples/rails/po/en/blog.po +24 -24
  208. data/samples/rails/po/eo/blog.po +27 -27
  209. data/samples/rails/po/es/blog.po +27 -27
  210. data/samples/rails/po/fr/blog.po +27 -27
  211. data/samples/rails/po/hr/blog.po +29 -29
  212. data/samples/rails/po/hu/blog.po +105 -0
  213. data/samples/rails/po/it/blog.po +27 -27
  214. data/samples/rails/po/ja/blog.po +27 -27
  215. data/samples/rails/po/ko/blog.po +27 -27
  216. data/samples/rails/po/nb/blog.po +26 -27
  217. data/samples/rails/po/nl/blog.po +27 -27
  218. data/samples/rails/po/pt_BR/blog.po +27 -27
  219. data/samples/rails/po/ru/blog.po +27 -27
  220. data/samples/rails/po/ua/blog.po +108 -0
  221. data/samples/rails/po/vi/blog.po +26 -31
  222. data/samples/rails/po/zh/blog.po +27 -27
  223. data/samples/rails/po/zh_TW/blog.po +27 -27
  224. data/samples/rails/public/404.html +27 -5
  225. data/samples/rails/public/422.html +30 -0
  226. data/samples/rails/public/500.html +27 -5
  227. data/samples/rails/public/index.html +6 -6
  228. data/samples/rails/public/javascripts/application.js +2 -0
  229. data/samples/rails/public/javascripts/controls.js +532 -319
  230. data/samples/rails/public/javascripts/dragdrop.js +521 -133
  231. data/samples/rails/public/javascripts/effects.js +708 -442
  232. data/samples/rails/public/javascripts/prototype.js +3393 -953
  233. data/samples/rails/public/stylesheets/blog.css +4 -0
  234. data/samples/rails/public/stylesheets/scaffold.css +5 -5
  235. data/samples/rails/test/functional/articles_controller_test.rb +51 -0
  236. data/samples/rails/test/test_helper.rb +31 -19
  237. data/samples/rails/test/unit/article_test.rb +2 -9
  238. data/samples/rails/vendor/plugins/gettext/init.rb +5 -3
  239. data/samples/rails/vendor/plugins/gettext/lib/gettext_plugin.rb +9 -10
  240. data/samples/rails/vendor/plugins/gettext/locale/eo/LC_MESSAGES/gettext_plugin.mo +0 -0
  241. data/samples/rails/vendor/plugins/gettext/locale/hu/LC_MESSAGES/gettext_plugin.mo +0 -0
  242. data/samples/rails/vendor/plugins/gettext/locale/ua/LC_MESSAGES/gettext_plugin.mo +0 -0
  243. data/samples/rails/vendor/plugins/gettext/po/eo/gettext_plugin.po +28 -0
  244. data/samples/rails/vendor/plugins/gettext/po/hu/gettext_plugin.po +27 -0
  245. data/samples/rails/vendor/plugins/gettext/po/ua/gettext_plugin.po +30 -0
  246. data/test/Rakefile +2 -1
  247. data/test/benchmark.rb +28 -0
  248. data/test/fixtures/topic.rb +15 -0
  249. data/test/rails/Rakefile +2 -1
  250. data/test/rails/app/controllers/articles_controller.rb +1 -1
  251. data/test/rails/app/controllers/users_controller.rb +10 -0
  252. data/test/rails/app/models/user.rb +2 -1
  253. data/test/rails/app/views/articles/{_form.rhtml → _form.html.erb} +0 -0
  254. data/test/rails/app/views/articles/active_form_error.html.erb +1 -0
  255. data/test/rails/app/views/articles/change_title_error_messages_for.html.erb +21 -0
  256. data/test/rails/app/views/articles/{edit.rhtml → edit.html.erb} +0 -0
  257. data/test/rails/app/views/articles/{list.rhtml → list.html.erb} +0 -3
  258. data/test/rails/app/views/articles/{list_fr.rhtml → list_fr.html.erb} +0 -0
  259. data/test/rails/app/views/articles/{multi_error_messages_for.rhtml → multi_error_messages_for.html.erb} +0 -0
  260. data/test/rails/app/views/articles/{new.rhtml → new.html.erb} +0 -0
  261. data/test/rails/app/views/articles/{show.rhtml → show.html.erb} +0 -0
  262. data/test/rails/app/views/layouts/{application.rhtml → application.html.erb} +0 -0
  263. data/test/rails/app/views/layouts/{mailer.rhtml → mailer.html.erb} +0 -0
  264. data/test/rails/app/views/layouts/users.html.erb +13 -0
  265. data/test/rails/app/views/users/custom_error_message.html.erb +13 -0
  266. data/test/rails/app/views/users/custom_error_message_fr.html.erb +13 -0
  267. data/test/rails/config/environment.rb +6 -1
  268. data/test/rails/config/environments/development.rb +0 -3
  269. data/test/rails/db/schema.rb +17 -10
  270. data/test/rails/locale/ja/LC_MESSAGES/rails_test.mo +0 -0
  271. data/test/rails/log/development.log +136 -29
  272. data/test/rails/log/test.log +2002 -128
  273. data/test/rails/po/ja/rails_test.po +68 -61
  274. data/test/rails/po/rails_test.pot +57 -55
  275. data/test/rails/test/fixtures/users.yml +5 -0
  276. data/test/rails/test/functional/articles_controller_test.rb +6 -1
  277. data/test/rails/test/functional/users_controller_test.rb +65 -0
  278. data/test/rails/test/result/en/custom_error_message.html +83 -0
  279. data/test/rails/test/result/en/custom_error_message_with_plural.html +83 -0
  280. data/test/rails/test/result/en/list.html +0 -3
  281. data/test/rails/test/result/en/multi_error_messages_for.html +1 -1
  282. data/test/rails/test/result/fr/custom_error_message.html +83 -0
  283. data/test/rails/test/result/fr/custom_error_message_with_plural.html +83 -0
  284. data/test/rails/test/result/ja/custom_error_message.html +83 -0
  285. data/test/rails/test/result/ja/custom_error_message_with_plural.html +83 -0
  286. data/test/rails/test/result/ja/list.html +0 -3
  287. data/test/rails/test/result/ja/multi_error_messages_for.html +1 -1
  288. data/test/test.sh +5 -7
  289. data/test/{gettext_test_active_record.rb → test_active_record.rb} +20 -10
  290. data/test/{gettext_test_cgi.rb → test_cgi.rb} +0 -0
  291. data/test/{gettext_test.rb → test_gettext.rb} +91 -9
  292. data/test/test_java.sh +12 -0
  293. data/test/{gettext_test_locale.rb → test_locale.rb} +3 -8
  294. data/test/{gettext_test_multi_textdomain.rb → test_multi_textdomain.rb} +2 -2
  295. data/test/{gettext_test_parser.rb → test_parser.rb} +77 -77
  296. data/test/{gettext_test_rails.rb → test_rails.rb} +0 -0
  297. data/test/{gettext_test_rails_caching.rb → test_rails_caching.rb} +16 -2
  298. data/test/{gettext_test_string.rb → test_string.rb} +1 -0
  299. data/test/{test_rubyparser_N.rb → testlib/N_.rb} +0 -0
  300. data/test/testlib/erb.rhtml +15 -0
  301. data/test/testlib/erb.rxml +16 -0
  302. data/test/{test_rubyparser.rb → testlib/gettext.rb} +0 -0
  303. data/test/testlib/gladeparser.glade +183 -0
  304. data/test/{test_rubyparser_n_.rb → testlib/ngettext.rb} +0 -0
  305. data/test/{test_nsgettext.rb → testlib/nsgettext.rb} +0 -0
  306. data/test/{test_sgettext.rb → testlib/sgettext.rb} +0 -0
  307. data/test/{testlib1.rb → testlib/testlib1.rb} +0 -0
  308. data/test/{testlib2.rb → testlib/testlib2.rb} +1 -1
  309. data/test/{testlib3.rb → testlib/testlib3.rb} +0 -0
  310. data/test/{testlib4.rb → testlib/testlib4.rb} +1 -1
  311. data/test/{testlib5.rb → testlib/testlib5.rb} +0 -0
  312. data/test/{testlib6.rb → testlib/testlib6.rb} +0 -0
  313. metadata +1374 -1171
  314. data/ext/gettext/extconf.rb +0 -20
  315. data/ext/gettext/locale_system.c +0 -83
  316. data/lib/gettext/locale_posix.rb +0 -82
  317. data/lib/gettext/locale_win32.rb +0 -82
  318. data/samples/cgi/ruby.bat +0 -4
  319. data/samples/rails/app/controllers/blog_controller.rb +0 -58
  320. data/samples/rails/app/views/blog/_form.rhtml +0 -25
  321. data/samples/rails/app/views/blog/edit.rhtml +0 -22
  322. data/samples/rails/app/views/blog/list.rhtml +0 -29
  323. data/samples/rails/app/views/blog/new.rhtml +0 -21
  324. data/samples/rails/app/views/blog/show.rhtml +0 -18
  325. data/samples/rails/app/views/layouts/blog.rhtml +0 -36
  326. data/samples/rails/test/functional/blog_controller_test.rb +0 -98
  327. data/test/gettext_runner.rb +0 -22
@@ -1,8 +1,11 @@
1
- // Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
1
+ // Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
2
+ // (c) 2005-2007 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
2
3
  //
3
- // See scriptaculous.js for full license.
4
+ // script.aculo.us is freely distributable under the terms of an MIT-style license.
5
+ // For details, see the script.aculo.us web site: http://script.aculo.us/
4
6
 
5
- /*--------------------------------------------------------------------------*/
7
+ if(Object.isUndefined(Effect))
8
+ throw("dragdrop.js requires including script.aculo.us' effects.js library");
6
9
 
7
10
  var Droppables = {
8
11
  drops: [],
@@ -15,15 +18,15 @@ var Droppables = {
15
18
  element = $(element);
16
19
  var options = Object.extend({
17
20
  greedy: true,
18
- hoverclass: null
19
- }, arguments[1] || {});
21
+ hoverclass: null,
22
+ tree: false
23
+ }, arguments[1] || { });
20
24
 
21
25
  // cache containers
22
26
  if(options.containment) {
23
27
  options._containers = [];
24
28
  var containment = options.containment;
25
- if((typeof containment == 'object') &&
26
- (containment.constructor == Array)) {
29
+ if(Object.isArray(containment)) {
27
30
  containment.each( function(c) { options._containers.push($(c)) });
28
31
  } else {
29
32
  options._containers.push($(containment));
@@ -37,12 +40,27 @@ var Droppables = {
37
40
 
38
41
  this.drops.push(options);
39
42
  },
43
+
44
+ findDeepestChild: function(drops) {
45
+ deepest = drops[0];
46
+
47
+ for (i = 1; i < drops.length; ++i)
48
+ if (Element.isParent(drops[i].element, deepest.element))
49
+ deepest = drops[i];
50
+
51
+ return deepest;
52
+ },
40
53
 
41
54
  isContained: function(element, drop) {
42
- var parentNode = element.parentNode;
43
- return drop._containers.detect(function(c) { return parentNode == c });
55
+ var containmentNode;
56
+ if(drop.tree) {
57
+ containmentNode = element.treeNode;
58
+ } else {
59
+ containmentNode = element.parentNode;
60
+ }
61
+ return drop._containers.detect(function(c) { return containmentNode == c });
44
62
  },
45
-
63
+
46
64
  isAffected: function(point, element, drop) {
47
65
  return (
48
66
  (drop.element!=element) &&
@@ -68,18 +86,24 @@ var Droppables = {
68
86
 
69
87
  show: function(point, element) {
70
88
  if(!this.drops.length) return;
89
+ var drop, affected = [];
71
90
 
72
- if(this.last_active) this.deactivate(this.last_active);
73
91
  this.drops.each( function(drop) {
74
- if(Droppables.isAffected(point, element, drop)) {
75
- if(drop.onHover)
76
- drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
77
- if(drop.greedy) {
78
- Droppables.activate(drop);
79
- throw $break;
80
- }
81
- }
92
+ if(Droppables.isAffected(point, element, drop))
93
+ affected.push(drop);
82
94
  });
95
+
96
+ if(affected.length>0)
97
+ drop = Droppables.findDeepestChild(affected);
98
+
99
+ if(this.last_active && this.last_active != drop) this.deactivate(this.last_active);
100
+ if (drop) {
101
+ Position.within(drop.element, point[0], point[1]);
102
+ if(drop.onHover)
103
+ drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
104
+
105
+ if (drop != this.last_active) Droppables.activate(drop);
106
+ }
83
107
  },
84
108
 
85
109
  fire: function(event, element) {
@@ -87,8 +111,10 @@ var Droppables = {
87
111
  Position.prepare();
88
112
 
89
113
  if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
90
- if (this.last_active.onDrop)
91
- this.last_active.onDrop(element, this.last_active.element, event);
114
+ if (this.last_active.onDrop) {
115
+ this.last_active.onDrop(element, this.last_active.element, event);
116
+ return true;
117
+ }
92
118
  },
93
119
 
94
120
  reset: function() {
@@ -124,11 +150,19 @@ var Draggables = {
124
150
  },
125
151
 
126
152
  activate: function(draggable) {
127
- window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
128
- this.activeDraggable = draggable;
153
+ if(draggable.options.delay) {
154
+ this._timeout = setTimeout(function() {
155
+ Draggables._timeout = null;
156
+ window.focus();
157
+ Draggables.activeDraggable = draggable;
158
+ }.bind(this), draggable.options.delay);
159
+ } else {
160
+ window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
161
+ this.activeDraggable = draggable;
162
+ }
129
163
  },
130
164
 
131
- deactivate: function(draggbale) {
165
+ deactivate: function() {
132
166
  this.activeDraggable = null;
133
167
  },
134
168
 
@@ -139,13 +173,19 @@ var Draggables = {
139
173
  // the same coordinates, prevent needless redrawing (moz bug?)
140
174
  if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
141
175
  this._lastPointer = pointer;
176
+
142
177
  this.activeDraggable.updateDrag(event, pointer);
143
178
  },
144
179
 
145
180
  endDrag: function(event) {
181
+ if(this._timeout) {
182
+ clearTimeout(this._timeout);
183
+ this._timeout = null;
184
+ }
146
185
  if(!this.activeDraggable) return;
147
186
  this._lastPointer = null;
148
187
  this.activeDraggable.endDrag(event);
188
+ this.activeDraggable = null;
149
189
  },
150
190
 
151
191
  keyPress: function(event) {
@@ -168,6 +208,7 @@ var Draggables = {
168
208
  this.observers.each( function(o) {
169
209
  if(o[eventName]) o[eventName](eventName, draggable, event);
170
210
  });
211
+ if(draggable.options[eventName]) draggable.options[eventName](draggable, event);
171
212
  },
172
213
 
173
214
  _cacheObserverCallbacks: function() {
@@ -181,36 +222,61 @@ var Draggables = {
181
222
 
182
223
  /*--------------------------------------------------------------------------*/
183
224
 
184
- var Draggable = Class.create();
185
- Draggable.prototype = {
225
+ var Draggable = Class.create({
186
226
  initialize: function(element) {
187
- var options = Object.extend({
227
+ var defaults = {
188
228
  handle: false,
189
- starteffect: function(element) {
190
- new Effect.Opacity(element, {duration:0.2, from:1.0, to:0.7});
191
- },
192
229
  reverteffect: function(element, top_offset, left_offset) {
193
230
  var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
194
- element._revert = new Effect.MoveBy(element, -top_offset, -left_offset, {duration:dur});
231
+ new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur,
232
+ queue: {scope:'_draggable', position:'end'}
233
+ });
195
234
  },
196
- endeffect: function(element) {
197
- new Effect.Opacity(element, {duration:0.2, from:0.7, to:1.0});
235
+ endeffect: function(element) {
236
+ var toOpacity = Object.isNumber(element._opacity) ? element._opacity : 1.0;
237
+ new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,
238
+ queue: {scope:'_draggable', position:'end'},
239
+ afterFinish: function(){
240
+ Draggable._dragging[element] = false
241
+ }
242
+ });
198
243
  },
199
244
  zindex: 1000,
200
245
  revert: false,
201
- snap: false // false, or xy or [x,y] or function(x,y){ return [x,y] }
202
- }, arguments[1] || {});
246
+ quiet: false,
247
+ scroll: false,
248
+ scrollSensitivity: 20,
249
+ scrollSpeed: 15,
250
+ snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] }
251
+ delay: 0
252
+ };
253
+
254
+ if(!arguments[1] || Object.isUndefined(arguments[1].endeffect))
255
+ Object.extend(defaults, {
256
+ starteffect: function(element) {
257
+ element._opacity = Element.getOpacity(element);
258
+ Draggable._dragging[element] = true;
259
+ new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7});
260
+ }
261
+ });
262
+
263
+ var options = Object.extend(defaults, arguments[1] || { });
203
264
 
204
265
  this.element = $(element);
205
266
 
206
- if(options.handle && (typeof options.handle == 'string'))
207
- this.handle = Element.childrenWithClassName(this.element, options.handle)[0];
267
+ if(options.handle && Object.isString(options.handle))
268
+ this.handle = this.element.down('.'+options.handle, 0);
269
+
208
270
  if(!this.handle) this.handle = $(options.handle);
209
271
  if(!this.handle) this.handle = this.element;
272
+
273
+ if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
274
+ options.scroll = $(options.scroll);
275
+ this._isScrollChild = Element.childOf(this.element, options.scroll);
276
+ }
210
277
 
211
278
  Element.makePositioned(this.element); // fix IE
212
279
 
213
- this.delta = this.currentDelta();
214
280
  this.options = options;
215
281
  this.dragging = false;
216
282
 
@@ -227,25 +293,23 @@ Draggable.prototype = {
227
293
 
228
294
  currentDelta: function() {
229
295
  return([
230
- parseInt(this.element.style.left || '0'),
231
- parseInt(this.element.style.top || '0')]);
296
+ parseInt(Element.getStyle(this.element,'left') || '0'),
297
+ parseInt(Element.getStyle(this.element,'top') || '0')]);
232
298
  },
233
299
 
234
300
  initDrag: function(event) {
301
+ if(!Object.isUndefined(Draggable._dragging[this.element]) &&
302
+ Draggable._dragging[this.element]) return;
235
303
  if(Event.isLeftClick(event)) {
236
304
  // abort on form elements, fixes a Firefox issue
237
305
  var src = Event.element(event);
238
- if(src.tagName && (
239
- src.tagName=='INPUT' ||
240
- src.tagName=='SELECT' ||
241
- src.tagName=='BUTTON' ||
242
- src.tagName=='TEXTAREA')) return;
306
+ if((tag_name = src.tagName.toUpperCase()) && (
307
+ tag_name=='INPUT' ||
308
+ tag_name=='SELECT' ||
309
+ tag_name=='OPTION' ||
310
+ tag_name=='BUTTON' ||
311
+ tag_name=='TEXTAREA')) return;
243
312
 
244
- if(this.element._revert) {
245
- this.element._revert.cancel();
246
- this.element._revert = null;
247
- }
248
-
249
313
  var pointer = [Event.pointerX(event), Event.pointerY(event)];
250
314
  var pos = Position.cumulativeOffset(this.element);
251
315
  this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
@@ -257,6 +321,8 @@ Draggable.prototype = {
257
321
 
258
322
  startDrag: function(event) {
259
323
  this.dragging = true;
324
+ if(!this.delta)
325
+ this.delta = this.currentDelta();
260
326
 
261
327
  if(this.options.zindex) {
262
328
  this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
@@ -265,46 +331,101 @@ Draggable.prototype = {
265
331
 
266
332
  if(this.options.ghosting) {
267
333
  this._clone = this.element.cloneNode(true);
268
- Position.absolutize(this.element);
334
+ this.element._originallyAbsolute = (this.element.getStyle('position') == 'absolute');
335
+ if (!this.element._originallyAbsolute)
336
+ Position.absolutize(this.element);
269
337
  this.element.parentNode.insertBefore(this._clone, this.element);
270
338
  }
271
339
 
340
+ if(this.options.scroll) {
341
+ if (this.options.scroll == window) {
342
+ var where = this._getWindowScroll(this.options.scroll);
343
+ this.originalScrollLeft = where.left;
344
+ this.originalScrollTop = where.top;
345
+ } else {
346
+ this.originalScrollLeft = this.options.scroll.scrollLeft;
347
+ this.originalScrollTop = this.options.scroll.scrollTop;
348
+ }
349
+ }
350
+
272
351
  Draggables.notify('onStart', this, event);
352
+
273
353
  if(this.options.starteffect) this.options.starteffect(this.element);
274
354
  },
275
355
 
276
356
  updateDrag: function(event, pointer) {
277
357
  if(!this.dragging) this.startDrag(event);
278
- Position.prepare();
279
- Droppables.show(pointer, this.element);
358
+
359
+ if(!this.options.quiet){
360
+ Position.prepare();
361
+ Droppables.show(pointer, this.element);
362
+ }
363
+
280
364
  Draggables.notify('onDrag', this, event);
365
+
281
366
  this.draw(pointer);
282
367
  if(this.options.change) this.options.change(this);
283
368
 
369
+ if(this.options.scroll) {
370
+ this.stopScrolling();
371
+
372
+ var p;
373
+ if (this.options.scroll == window) {
374
+ with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }
375
+ } else {
376
+ p = Position.page(this.options.scroll);
377
+ p[0] += this.options.scroll.scrollLeft + Position.deltaX;
378
+ p[1] += this.options.scroll.scrollTop + Position.deltaY;
379
+ p.push(p[0]+this.options.scroll.offsetWidth);
380
+ p.push(p[1]+this.options.scroll.offsetHeight);
381
+ }
382
+ var speed = [0,0];
383
+ if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity);
384
+ if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity);
385
+ if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity);
386
+ if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);
387
+ this.startScrolling(speed);
388
+ }
389
+
284
390
  // fix AppleWebKit rendering
285
- if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
391
+ if(Prototype.Browser.WebKit) window.scrollBy(0,0);
392
+
286
393
  Event.stop(event);
287
394
  },
288
395
 
289
396
  finishDrag: function(event, success) {
290
397
  this.dragging = false;
398
+
399
+ if(this.options.quiet){
400
+ Position.prepare();
401
+ var pointer = [Event.pointerX(event), Event.pointerY(event)];
402
+ Droppables.show(pointer, this.element);
403
+ }
291
404
 
292
405
  if(this.options.ghosting) {
293
- Position.relativize(this.element);
406
+ if (!this.element._originallyAbsolute)
407
+ Position.relativize(this.element);
408
+ delete this.element._originallyAbsolute;
294
409
  Element.remove(this._clone);
295
410
  this._clone = null;
296
411
  }
297
412
 
298
- if(success) Droppables.fire(event, this.element);
413
+ var dropped = false;
414
+ if(success) {
415
+ dropped = Droppables.fire(event, this.element);
416
+ if (!dropped) dropped = false;
417
+ }
418
+ if(dropped && this.options.onDropped) this.options.onDropped(this.element);
299
419
  Draggables.notify('onEnd', this, event);
300
420
 
301
421
  var revert = this.options.revert;
302
- if(revert && typeof revert == 'function') revert = revert(this.element);
422
+ if(revert && Object.isFunction(revert)) revert = revert(this.element);
303
423
 
304
424
  var d = this.currentDelta();
305
425
  if(revert && this.options.reverteffect) {
306
- this.options.reverteffect(this.element,
307
- d[1]-this.delta[1], d[0]-this.delta[0]);
426
+ if (dropped == 0 || revert != 'failure')
427
+ this.options.reverteffect(this.element,
428
+ d[1]-this.delta[1], d[0]-this.delta[0]);
308
429
  } else {
309
430
  this.delta = d;
310
431
  }
@@ -314,40 +435,53 @@ Draggable.prototype = {
314
435
 
315
436
  if(this.options.endeffect)
316
437
  this.options.endeffect(this.element);
317
-
438
+
318
439
  Draggables.deactivate(this);
319
440
  Droppables.reset();
320
441
  },
321
442
 
322
443
  keyPress: function(event) {
323
- if(!event.keyCode==Event.KEY_ESC) return;
444
+ if(event.keyCode!=Event.KEY_ESC) return;
324
445
  this.finishDrag(event, false);
325
446
  Event.stop(event);
326
447
  },
327
448
 
328
449
  endDrag: function(event) {
329
450
  if(!this.dragging) return;
451
+ this.stopScrolling();
330
452
  this.finishDrag(event, true);
331
453
  Event.stop(event);
332
454
  },
333
455
 
334
456
  draw: function(point) {
335
457
  var pos = Position.cumulativeOffset(this.element);
458
+ if(this.options.ghosting) {
459
+ var r = Position.realOffset(this.element);
460
+ pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
461
+ }
462
+
336
463
  var d = this.currentDelta();
337
464
  pos[0] -= d[0]; pos[1] -= d[1];
338
465
 
339
- var p = [0,1].map(function(i){ return (point[i]-pos[i]-this.offset[i]) }.bind(this));
466
+ if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
467
+ pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
468
+ pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
469
+ }
470
+
471
+ var p = [0,1].map(function(i){
472
+ return (point[i]-pos[i]-this.offset[i])
473
+ }.bind(this));
340
474
 
341
475
  if(this.options.snap) {
342
- if(typeof this.options.snap == 'function') {
343
- p = this.options.snap(p[0],p[1]);
476
+ if(Object.isFunction(this.options.snap)) {
477
+ p = this.options.snap(p[0],p[1],this);
344
478
  } else {
345
- if(this.options.snap instanceof Array) {
479
+ if(Object.isArray(this.options.snap)) {
346
480
  p = p.map( function(v, i) {
347
- return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this))
481
+ return (v/this.options.snap[i]).round()*this.options.snap[i] }.bind(this))
348
482
  } else {
349
483
  p = p.map( function(v) {
350
- return Math.round(v/this.options.snap)*this.options.snap }.bind(this))
484
+ return (v/this.options.snap).round()*this.options.snap }.bind(this))
351
485
  }
352
486
  }}
353
487
 
@@ -356,14 +490,88 @@ Draggable.prototype = {
356
490
  style.left = p[0] + "px";
357
491
  if((!this.options.constraint) || (this.options.constraint=='vertical'))
358
492
  style.top = p[1] + "px";
493
+
359
494
  if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
495
+ },
496
+
497
+ stopScrolling: function() {
498
+ if(this.scrollInterval) {
499
+ clearInterval(this.scrollInterval);
500
+ this.scrollInterval = null;
501
+ Draggables._lastScrollPointer = null;
502
+ }
503
+ },
504
+
505
+ startScrolling: function(speed) {
506
+ if(!(speed[0] || speed[1])) return;
507
+ this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];
508
+ this.lastScrolled = new Date();
509
+ this.scrollInterval = setInterval(this.scroll.bind(this), 10);
510
+ },
511
+
512
+ scroll: function() {
513
+ var current = new Date();
514
+ var delta = current - this.lastScrolled;
515
+ this.lastScrolled = current;
516
+ if(this.options.scroll == window) {
517
+ with (this._getWindowScroll(this.options.scroll)) {
518
+ if (this.scrollSpeed[0] || this.scrollSpeed[1]) {
519
+ var d = delta / 1000;
520
+ this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] );
521
+ }
522
+ }
523
+ } else {
524
+ this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
525
+ this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000;
526
+ }
527
+
528
+ Position.prepare();
529
+ Droppables.show(Draggables._lastPointer, this.element);
530
+ Draggables.notify('onDrag', this);
531
+ if (this._isScrollChild) {
532
+ Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
533
+ Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
534
+ Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
535
+ if (Draggables._lastScrollPointer[0] < 0)
536
+ Draggables._lastScrollPointer[0] = 0;
537
+ if (Draggables._lastScrollPointer[1] < 0)
538
+ Draggables._lastScrollPointer[1] = 0;
539
+ this.draw(Draggables._lastScrollPointer);
540
+ }
541
+
542
+ if(this.options.change) this.options.change(this);
543
+ },
544
+
545
+ _getWindowScroll: function(w) {
546
+ var T, L, W, H;
547
+ with (w.document) {
548
+ if (w.document.documentElement && documentElement.scrollTop) {
549
+ T = documentElement.scrollTop;
550
+ L = documentElement.scrollLeft;
551
+ } else if (w.document.body) {
552
+ T = body.scrollTop;
553
+ L = body.scrollLeft;
554
+ }
555
+ if (w.innerWidth) {
556
+ W = w.innerWidth;
557
+ H = w.innerHeight;
558
+ } else if (w.document.documentElement && documentElement.clientWidth) {
559
+ W = documentElement.clientWidth;
560
+ H = documentElement.clientHeight;
561
+ } else {
562
+ W = body.offsetWidth;
563
+ H = body.offsetHeight
564
+ }
565
+ }
566
+ return { top: T, left: L, width: W, height: H };
360
567
  }
361
- }
568
+ });
569
+
570
+ Draggable._dragging = { };
362
571
 
363
572
  /*--------------------------------------------------------------------------*/
364
573
 
365
- var SortableObserver = Class.create();
366
- SortableObserver.prototype = {
574
+ var SortableObserver = Class.create({
367
575
  initialize: function(element, observer) {
368
576
  this.element = $(element);
369
577
  this.observer = observer;
@@ -379,44 +587,68 @@ SortableObserver.prototype = {
379
587
  if(this.lastValue != Sortable.serialize(this.element))
380
588
  this.observer(this.element)
381
589
  }
382
- }
590
+ });
383
591
 
384
592
  var Sortable = {
385
- sortables: new Array(),
593
+ SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,
386
594
 
387
- options: function(element){
388
- element = $(element);
389
- return this.sortables.detect(function(s) { return s.element == element });
595
+ sortables: { },
596
+
597
+ _findRootElement: function(element) {
598
+ while (element.tagName.toUpperCase() != "BODY") {
599
+ if(element.id && Sortable.sortables[element.id]) return element;
600
+ element = element.parentNode;
601
+ }
602
+ },
603
+
604
+ options: function(element) {
605
+ element = Sortable._findRootElement($(element));
606
+ if(!element) return;
607
+ return Sortable.sortables[element.id];
390
608
  },
391
609
 
392
610
  destroy: function(element){
393
- element = $(element);
394
- this.sortables.findAll(function(s) { return s.element == element }).each(function(s){
611
+ var s = Sortable.options(element);
612
+
613
+ if(s) {
395
614
  Draggables.removeObserver(s.element);
396
615
  s.droppables.each(function(d){ Droppables.remove(d) });
397
616
  s.draggables.invoke('destroy');
398
- });
399
- this.sortables = this.sortables.reject(function(s) { return s.element == element });
617
+
618
+ delete Sortable.sortables[s.element.id];
619
+ }
400
620
  },
401
-
621
+
402
622
  create: function(element) {
403
623
  element = $(element);
404
624
  var options = Object.extend({
405
625
  element: element,
406
626
  tag: 'li', // assumes li children, override with tag: 'tagname'
407
627
  dropOnEmpty: false,
408
- tree: false, // fixme: unimplemented
628
+ tree: false,
629
+ treeTag: 'ul',
409
630
  overlap: 'vertical', // one of 'vertical', 'horizontal'
410
631
  constraint: 'vertical', // one of 'vertical', 'horizontal', false
411
632
  containment: element, // also takes array of elements (or id's); or false
412
633
  handle: false, // or a CSS class
413
634
  only: false,
635
+ delay: 0,
414
636
  hoverclass: null,
415
637
  ghosting: false,
416
- format: null,
638
+ quiet: false,
639
+ scroll: false,
640
+ scrollSensitivity: 20,
641
+ scrollSpeed: 15,
642
+ format: this.SERIALIZE_RULE,
643
+
644
+ // these take arrays of elements or ids and can be
645
+ // used for better initialization performance
646
+ elements: false,
647
+ handles: false,
648
+
417
649
  onChange: Prototype.emptyFunction,
418
650
  onUpdate: Prototype.emptyFunction
419
- }, arguments[1] || {});
651
+ }, arguments[1] || { });
420
652
 
421
653
  // clear any old sortable with same element
422
654
  this.destroy(element);
@@ -424,6 +656,11 @@ var Sortable = {
424
656
  // build options for the draggables
425
657
  var options_for_draggable = {
426
658
  revert: true,
659
+ quiet: options.quiet,
660
+ scroll: options.scroll,
661
+ scrollSpeed: options.scrollSpeed,
662
+ scrollSensitivity: options.scrollSensitivity,
663
+ delay: options.delay,
427
664
  ghosting: options.ghosting,
428
665
  constraint: options.constraint,
429
666
  handle: options.handle };
@@ -449,9 +686,16 @@ var Sortable = {
449
686
  var options_for_droppable = {
450
687
  overlap: options.overlap,
451
688
  containment: options.containment,
689
+ tree: options.tree,
452
690
  hoverclass: options.hoverclass,
453
- onHover: Sortable.onHover,
454
- greedy: !options.dropOnEmpty
691
+ onHover: Sortable.onHover
692
+ }
693
+
694
+ var options_for_tree = {
695
+ onHover: Sortable.onEmptyHover,
696
+ overlap: options.overlap,
697
+ containment: options.containment,
698
+ hoverclass: options.hoverclass
455
699
  }
456
700
 
457
701
  // fix for gecko engine
@@ -460,27 +704,32 @@ var Sortable = {
460
704
  options.draggables = [];
461
705
  options.droppables = [];
462
706
 
463
- // make it so
464
-
465
707
  // drop on empty handling
466
- if(options.dropOnEmpty) {
467
- Droppables.add(element,
468
- {containment: options.containment, onHover: Sortable.onEmptyHover, greedy: false});
708
+ if(options.dropOnEmpty || options.tree) {
709
+ Droppables.add(element, options_for_tree);
469
710
  options.droppables.push(element);
470
711
  }
471
712
 
472
- (this.findElements(element, options) || []).each( function(e) {
473
- // handles are per-draggable
474
- var handle = options.handle ?
475
- Element.childrenWithClassName(e, options.handle)[0] : e;
713
+ (options.elements || this.findElements(element, options) || []).each( function(e,i) {
714
+ var handle = options.handles ? $(options.handles[i]) :
715
+ (options.handle ? $(e).select('.' + options.handle)[0] : e);
476
716
  options.draggables.push(
477
717
  new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
478
718
  Droppables.add(e, options_for_droppable);
719
+ if(options.tree) e.treeNode = element;
479
720
  options.droppables.push(e);
480
721
  });
722
+
723
+ if(options.tree) {
724
+ (Sortable.findTreeElements(element, options) || []).each( function(e) {
725
+ Droppables.add(e, options_for_tree);
726
+ e.treeNode = element;
727
+ options.droppables.push(e);
728
+ });
729
+ }
481
730
 
482
731
  // keep reference
483
- this.sortables.push(options);
732
+ this.sortables[element.id] = options;
484
733
 
485
734
  // for onupdate
486
735
  Draggables.addObserver(new SortableObserver(element, options.onUpdate));
@@ -489,23 +738,21 @@ var Sortable = {
489
738
 
490
739
  // return all suitable-for-sortable elements in a guaranteed order
491
740
  findElements: function(element, options) {
492
- if(!element.hasChildNodes()) return null;
493
- var elements = [];
494
- $A(element.childNodes).each( function(e) {
495
- if(e.tagName && e.tagName.toUpperCase()==options.tag.toUpperCase() &&
496
- (!options.only || (Element.hasClassName(e, options.only))))
497
- elements.push(e);
498
- if(options.tree) {
499
- var grandchildren = this.findElements(e, options);
500
- if(grandchildren) elements.push(grandchildren);
501
- }
502
- });
503
-
504
- return (elements.length>0 ? elements.flatten() : null);
741
+ return Element.findChildren(
742
+ element, options.only, options.tree ? true : false, options.tag);
743
+ },
744
+
745
+ findTreeElements: function(element, options) {
746
+ return Element.findChildren(
747
+ element, options.only, options.tree ? true : false, options.treeTag);
505
748
  },
506
749
 
507
750
  onHover: function(element, dropon, overlap) {
508
- if(overlap>0.5) {
751
+ if(Element.isParent(dropon, element)) return;
752
+
753
+ if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) {
754
+ return;
755
+ } else if(overlap>0.5) {
509
756
  Sortable.mark(dropon, 'before');
510
757
  if(dropon.previousSibling != element) {
511
758
  var oldParentNode = element.parentNode;
@@ -528,18 +775,42 @@ var Sortable = {
528
775
  }
529
776
  }
530
777
  },
531
-
532
- onEmptyHover: function(element, dropon) {
533
- if(element.parentNode!=dropon) {
534
- var oldParentNode = element.parentNode;
535
- dropon.appendChild(element);
778
+
779
+ onEmptyHover: function(element, dropon, overlap) {
780
+ var oldParentNode = element.parentNode;
781
+ var droponOptions = Sortable.options(dropon);
782
+
783
+ if(!Element.isParent(dropon, element)) {
784
+ var index;
785
+
786
+ var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only});
787
+ var child = null;
788
+
789
+ if(children) {
790
+ var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);
791
+
792
+ for (index = 0; index < children.length; index += 1) {
793
+ if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) {
794
+ offset -= Element.offsetSize (children[index], droponOptions.overlap);
795
+ } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {
796
+ child = index + 1 < children.length ? children[index + 1] : null;
797
+ break;
798
+ } else {
799
+ child = children[index];
800
+ break;
801
+ }
802
+ }
803
+ }
804
+
805
+ dropon.insertBefore(element, child);
806
+
536
807
  Sortable.options(oldParentNode).onChange(element);
537
- Sortable.options(dropon).onChange(element);
808
+ droponOptions.onChange(element);
538
809
  }
539
810
  },
540
811
 
541
812
  unmark: function() {
542
- if(Sortable._marker) Element.hide(Sortable._marker);
813
+ if(Sortable._marker) Sortable._marker.hide();
543
814
  },
544
815
 
545
816
  mark: function(dropon, position) {
@@ -548,37 +819,154 @@ var Sortable = {
548
819
  if(sortable && !sortable.ghosting) return;
549
820
 
550
821
  if(!Sortable._marker) {
551
- Sortable._marker = $('dropmarker') || document.createElement('DIV');
552
- Element.hide(Sortable._marker);
553
- Element.addClassName(Sortable._marker, 'dropmarker');
554
- Sortable._marker.style.position = 'absolute';
822
+ Sortable._marker =
823
+ ($('dropmarker') || Element.extend(document.createElement('DIV'))).
824
+ hide().addClassName('dropmarker').setStyle({position:'absolute'});
555
825
  document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
556
826
  }
557
827
  var offsets = Position.cumulativeOffset(dropon);
558
- Sortable._marker.style.left = offsets[0] + 'px';
559
- Sortable._marker.style.top = offsets[1] + 'px';
828
+ Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'});
560
829
 
561
830
  if(position=='after')
562
831
  if(sortable.overlap == 'horizontal')
563
- Sortable._marker.style.left = (offsets[0]+dropon.clientWidth) + 'px';
832
+ Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'});
564
833
  else
565
- Sortable._marker.style.top = (offsets[1]+dropon.clientHeight) + 'px';
834
+ Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'});
566
835
 
567
- Element.show(Sortable._marker);
836
+ Sortable._marker.show();
568
837
  },
838
+
839
+ _tree: function(element, options, parent) {
840
+ var children = Sortable.findElements(element, options) || [];
841
+
842
+ for (var i = 0; i < children.length; ++i) {
843
+ var match = children[i].id.match(options.format);
569
844
 
570
- serialize: function(element) {
845
+ if (!match) continue;
846
+
847
+ var child = {
848
+ id: encodeURIComponent(match ? match[1] : null),
849
+ element: element,
850
+ parent: parent,
851
+ children: [],
852
+ position: parent.children.length,
853
+ container: $(children[i]).down(options.treeTag)
854
+ }
855
+
856
+ /* Get the element containing the children and recurse over it */
857
+ if (child.container)
858
+ this._tree(child.container, options, child)
859
+
860
+ parent.children.push (child);
861
+ }
862
+
863
+ return parent;
864
+ },
865
+
866
+ tree: function(element) {
571
867
  element = $(element);
572
868
  var sortableOptions = this.options(element);
573
869
  var options = Object.extend({
574
- tag: sortableOptions.tag,
870
+ tag: sortableOptions.tag,
871
+ treeTag: sortableOptions.treeTag,
575
872
  only: sortableOptions.only,
576
873
  name: element.id,
577
- format: sortableOptions.format || /^[^_]*_(.*)$/
578
- }, arguments[1] || {});
874
+ format: sortableOptions.format
875
+ }, arguments[1] || { });
876
+
877
+ var root = {
878
+ id: null,
879
+ parent: null,
880
+ children: [],
881
+ container: element,
882
+ position: 0
883
+ }
884
+
885
+ return Sortable._tree(element, options, root);
886
+ },
887
+
888
+ /* Construct a [i] index for a particular node */
889
+ _constructIndex: function(node) {
890
+ var index = '';
891
+ do {
892
+ if (node.id) index = '[' + node.position + ']' + index;
893
+ } while ((node = node.parent) != null);
894
+ return index;
895
+ },
896
+
897
+ sequence: function(element) {
898
+ element = $(element);
899
+ var options = Object.extend(this.options(element), arguments[1] || { });
900
+
579
901
  return $(this.findElements(element, options) || []).map( function(item) {
580
- return (encodeURIComponent(options.name) + "[]=" +
581
- encodeURIComponent(item.id.match(options.format) ? item.id.match(options.format)[1] : ''));
582
- }).join("&");
902
+ return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
903
+ });
904
+ },
905
+
906
+ setSequence: function(element, new_sequence) {
907
+ element = $(element);
908
+ var options = Object.extend(this.options(element), arguments[2] || { });
909
+
910
+ var nodeMap = { };
911
+ this.findElements(element, options).each( function(n) {
912
+ if (n.id.match(options.format))
913
+ nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];
914
+ n.parentNode.removeChild(n);
915
+ });
916
+
917
+ new_sequence.each(function(ident) {
918
+ var n = nodeMap[ident];
919
+ if (n) {
920
+ n[1].appendChild(n[0]);
921
+ delete nodeMap[ident];
922
+ }
923
+ });
924
+ },
925
+
926
+ serialize: function(element) {
927
+ element = $(element);
928
+ var options = Object.extend(Sortable.options(element), arguments[1] || { });
929
+ var name = encodeURIComponent(
930
+ (arguments[1] && arguments[1].name) ? arguments[1].name : element.id);
931
+
932
+ if (options.tree) {
933
+ return Sortable.tree(element, arguments[1]).children.map( function (item) {
934
+ return [name + Sortable._constructIndex(item) + "[id]=" +
935
+ encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
936
+ }).flatten().join('&');
937
+ } else {
938
+ return Sortable.sequence(element, arguments[1]).map( function(item) {
939
+ return name + "[]=" + encodeURIComponent(item);
940
+ }).join('&');
941
+ }
583
942
  }
584
- }
943
+ }
944
+
945
+ // Returns true if child is contained within element
946
+ Element.isParent = function(child, element) {
947
+ if (!child.parentNode || child == element) return false;
948
+ if (child.parentNode == element) return true;
949
+ return Element.isParent(child.parentNode, element);
950
+ }
951
+
952
+ Element.findChildren = function(element, only, recursive, tagName) {
953
+ if(!element.hasChildNodes()) return null;
954
+ tagName = tagName.toUpperCase();
955
+ if(only) only = [only].flatten();
956
+ var elements = [];
957
+ $A(element.childNodes).each( function(e) {
958
+ if(e.tagName && e.tagName.toUpperCase()==tagName &&
959
+ (!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
960
+ elements.push(e);
961
+ if(recursive) {
962
+ var grandchildren = Element.findChildren(e, only, recursive, tagName);
963
+ if(grandchildren) elements.push(grandchildren);
964
+ }
965
+ });
966
+
967
+ return (elements.length>0 ? elements.flatten() : []);
968
+ }
969
+
970
+ Element.offsetSize = function (element, type) {
971
+ return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')];
972
+ }