gettext 1.10.0 → 1.90.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }