spontaneous 0.1.0.alpha1 → 0.2.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (413) hide show
  1. data/Gemfile +40 -35
  2. data/LICENSE +20 -0
  3. data/Rakefile +39 -42
  4. data/Readme.markdown +155 -0
  5. data/application/css/definitions.scss +3 -0
  6. data/application/css/editing.scss +9 -4
  7. data/application/css/min/565d4c25e82148acb01c45c8d675b37a08676d77.css +1 -0
  8. data/application/css/min/84dbe894ea96eafd321c30823d630817bfc4b03b.css +1 -0
  9. data/application/css/min/d1b54ff4847c613618267ca1c15658e2aee0a4e5.css +1 -0
  10. data/application/css/v2.scss +144 -50
  11. data/application/js/add_alias_dialogue.js +18 -8
  12. data/application/js/ajax.js +1 -1
  13. data/application/js/authentication.js +8 -1
  14. data/application/js/box.js +37 -7
  15. data/application/js/box_container.js +1 -1
  16. data/application/js/compatibility.js +7 -0
  17. data/application/js/content.js +7 -0
  18. data/application/js/content_area.js +4 -0
  19. data/application/js/edit_panel.js +44 -18
  20. data/application/js/editing.js +12 -0
  21. data/application/js/event_source.js +17 -0
  22. data/application/js/extensions.js +2 -0
  23. data/application/js/field_types/file_field.js +2 -1
  24. data/application/js/field_types/image_field.js +35 -48
  25. data/application/js/field_types/long_string_field.js +12 -0
  26. data/application/js/field_types/markdown_field.js +2 -5
  27. data/application/js/field_types/string_field.js +5 -1
  28. data/application/js/field_types/webvideo_field.js +15 -0
  29. data/application/js/init.js +1 -0
  30. data/application/js/location.js +30 -19
  31. data/application/js/login.js +1 -2
  32. data/application/js/min/2a0c2962537a3181fedfff5c92596ba6d3122dc9.js +3 -0
  33. data/application/js/min/4cf1c493d3379ecba5287758c61238034c0893f9.js +2 -0
  34. data/application/js/min/78ac6b99d96750bb6b9f9aad4cb9cd91cd03f391.js +3 -0
  35. data/application/js/min/c8efb9b9f7c3f6613fcebc6be60f605b6570a382.js +90 -0
  36. data/application/js/page.js +1 -0
  37. data/application/js/page_entry.js +6 -40
  38. data/application/js/preview.js +2 -3
  39. data/application/js/top_bar.js +76 -31
  40. data/application/js/upload.js +5 -2
  41. data/application/js/upload_manager.js +2 -81
  42. data/application/js/vendor/jquery-1.7.1.min.js +4 -0
  43. data/application/js/vendor/jquery-ui-1.8.16.custom.min.js +791 -0
  44. data/application/js/views.js +3 -3
  45. data/application/js/views/box_view.js +164 -83
  46. data/application/js/views/page_piece_view.js +2 -2
  47. data/application/js/views/page_view.js +46 -15
  48. data/application/js/views/piece_view.js +29 -8
  49. data/application/static/diagonal-texture.png +0 -0
  50. data/application/static/item-buttons-highlight.png +0 -0
  51. data/application/static/plus-box.png +0 -0
  52. data/application/static/plus_alt.svg +8 -0
  53. data/application/static/slot-up-arrow.png +0 -0
  54. data/application/views/{index.erubis → index.erb} +9 -5
  55. data/application/views/{login.erubis → login.erb} +14 -10
  56. data/application/views/schema_modification_error.html.erb +18 -6
  57. data/application/views/{unsupported.erubis → unsupported.erb} +0 -0
  58. data/bin/spot +15 -2
  59. data/db/migrations/20100610142136_init.rb +2 -2
  60. data/db/migrations/20101130104334_timestamps.rb +2 -2
  61. data/db/migrations/20110209152710_users_and_groups.rb +11 -11
  62. data/db/migrations/20120106171423_visibility_path.rb +19 -0
  63. data/db/migrations/20120107124541_owner_id.rb +19 -0
  64. data/docs/recipe-interface-screenshot.png +0 -0
  65. data/lib/cutaneous.rb +11 -10
  66. data/lib/cutaneous/context_helper.rb +119 -14
  67. data/lib/cutaneous/preview_context.rb +4 -3
  68. data/lib/cutaneous/preview_renderer.rb +1 -6
  69. data/lib/cutaneous/publish_context.rb +1 -0
  70. data/lib/cutaneous/{first_pass_renderer.rb → publish_renderer.rb} +2 -6
  71. data/lib/cutaneous/publish_template.rb +62 -0
  72. data/lib/cutaneous/publish_token_parser.rb +8 -0
  73. data/lib/cutaneous/renderer.rb +4 -2
  74. data/lib/cutaneous/request_context.rb +1 -0
  75. data/lib/cutaneous/{second_pass_renderer.rb → request_renderer.rb} +2 -5
  76. data/lib/cutaneous/request_template.rb +11 -0
  77. data/lib/cutaneous/request_token_parser.rb +9 -0
  78. data/lib/cutaneous/token_parser.rb +125 -0
  79. data/lib/sequel/plugins/content_table_inheritance.rb +19 -12
  80. data/lib/sequel/plugins/scoped_table_name.rb +45 -0
  81. data/lib/spontaneous.rb +123 -126
  82. data/lib/spontaneous/box.rb +127 -47
  83. data/lib/spontaneous/box_style.rb +39 -22
  84. data/lib/spontaneous/change.rb +2 -2
  85. data/lib/spontaneous/cli.rb +1 -0
  86. data/lib/spontaneous/cli/base.rb +12 -4
  87. data/lib/spontaneous/cli/console.rb +72 -0
  88. data/lib/spontaneous/cli/server.rb +36 -12
  89. data/lib/spontaneous/cli/site.rb +175 -1
  90. data/lib/spontaneous/collections/box_set.rb +19 -1
  91. data/lib/spontaneous/collections/entry_set.rb +70 -22
  92. data/lib/spontaneous/collections/field_set.rb +3 -3
  93. data/lib/spontaneous/collections/prototype_set.rb +28 -0
  94. data/lib/spontaneous/config.rb +14 -5
  95. data/lib/spontaneous/content.rb +23 -24
  96. data/lib/spontaneous/errors.rb +20 -4
  97. data/lib/spontaneous/extensions/array.rb +2 -2
  98. data/lib/spontaneous/extensions/json.rb +1 -1
  99. data/lib/spontaneous/extensions/nil.rb +13 -0
  100. data/lib/spontaneous/facet.rb +61 -7
  101. data/lib/spontaneous/field_types.rb +1 -3
  102. data/lib/spontaneous/field_types/date_field.rb +1 -0
  103. data/lib/spontaneous/field_types/field.rb +32 -15
  104. data/lib/spontaneous/field_types/image_field.rb +138 -69
  105. data/lib/spontaneous/field_types/location_field.rb +59 -0
  106. data/lib/spontaneous/field_types/long_string_field.rb +13 -0
  107. data/lib/spontaneous/field_types/markdown_field.rb +2 -1
  108. data/lib/spontaneous/field_types/string_field.rb +2 -2
  109. data/lib/spontaneous/field_types/webvideo_field.rb +255 -0
  110. data/lib/spontaneous/generators/page/inline.html.cut +1 -1
  111. data/lib/spontaneous/generators/page/page.html.cut.tt +5 -4
  112. data/lib/spontaneous/generators/page/page.rb.tt +1 -5
  113. data/lib/spontaneous/generators/site.rb +1 -0
  114. data/lib/spontaneous/generators/site/.gitignore +2 -0
  115. data/lib/spontaneous/generators/site/Gemfile.tt +3 -5
  116. data/lib/spontaneous/generators/site/config/environment.rb.tt +1 -0
  117. data/lib/spontaneous/generators/site/config/environments/development.rb.tt +3 -1
  118. data/lib/spontaneous/generators/site/config/environments/production.rb.tt +3 -1
  119. data/lib/spontaneous/generators/site/config/indexes.rb.tt +23 -0
  120. data/lib/spontaneous/generators/site/public/css/{site.css → site.scss} +0 -0
  121. data/lib/spontaneous/generators/site/schema/box.rb.tt +5 -0
  122. data/lib/spontaneous/generators/site/templates/layouts/standard.html.cut.tt +11 -5
  123. data/lib/spontaneous/image_size.rb +0 -1
  124. data/lib/spontaneous/loader.rb +335 -218
  125. data/lib/spontaneous/logger.rb +7 -2
  126. data/lib/spontaneous/media.rb +64 -59
  127. data/lib/spontaneous/media/file.rb +74 -0
  128. data/lib/spontaneous/page.rb +47 -18
  129. data/lib/spontaneous/page_piece.rb +29 -27
  130. data/lib/spontaneous/paths.rb +0 -1
  131. data/lib/spontaneous/permissions.rb +3 -21
  132. data/lib/spontaneous/permissions/user.rb +5 -1
  133. data/lib/spontaneous/permissions/user_level.rb +6 -7
  134. data/lib/spontaneous/piece.rb +12 -7
  135. data/lib/spontaneous/plugins/aliases.rb +76 -31
  136. data/lib/spontaneous/plugins/allowed_types.rb +36 -37
  137. data/lib/spontaneous/plugins/application/facets.rb +7 -10
  138. data/lib/spontaneous/plugins/application/features.rb +17 -0
  139. data/lib/spontaneous/plugins/application/paths.rb +25 -31
  140. data/lib/spontaneous/plugins/application/render.rb +1 -5
  141. data/lib/spontaneous/plugins/application/serialisation.rb +2 -0
  142. data/lib/spontaneous/plugins/application/state.rb +6 -9
  143. data/lib/spontaneous/plugins/boxes.rb +65 -40
  144. data/lib/spontaneous/plugins/controllers.rb +22 -22
  145. data/lib/spontaneous/plugins/entries.rb +149 -150
  146. data/lib/spontaneous/plugins/entry.rb +50 -35
  147. data/lib/spontaneous/plugins/field/editor_class.rb +13 -0
  148. data/lib/spontaneous/plugins/fields.rb +41 -33
  149. data/lib/spontaneous/plugins/instance_code.rb +9 -9
  150. data/lib/spontaneous/plugins/layouts.rb +31 -35
  151. data/lib/spontaneous/plugins/media.rb +31 -32
  152. data/lib/spontaneous/plugins/page/formats.rb +56 -31
  153. data/lib/spontaneous/plugins/page/request.rb +15 -9
  154. data/lib/spontaneous/plugins/page_search.rb +30 -31
  155. data/lib/spontaneous/plugins/page_tree.rb +59 -12
  156. data/lib/spontaneous/plugins/paths.rb +84 -79
  157. data/lib/spontaneous/plugins/permissions.rb +26 -28
  158. data/lib/spontaneous/plugins/prototypes.rb +42 -37
  159. data/lib/spontaneous/plugins/publishing.rb +50 -94
  160. data/lib/spontaneous/plugins/render.rb +8 -16
  161. data/lib/spontaneous/plugins/schema_hierarchy.rb +20 -21
  162. data/lib/spontaneous/plugins/schema_id.rb +33 -25
  163. data/lib/spontaneous/plugins/schema_title.rb +3 -4
  164. data/lib/spontaneous/plugins/serialisation.rb +32 -35
  165. data/lib/spontaneous/plugins/site/features.rb +32 -0
  166. data/lib/spontaneous/plugins/site/instance.rb +3 -2
  167. data/lib/spontaneous/plugins/site/level.rb +18 -0
  168. data/lib/spontaneous/plugins/site/map.rb +2 -1
  169. data/lib/spontaneous/plugins/site/publishing.rb +56 -59
  170. data/lib/spontaneous/plugins/site/revisions.rb +24 -19
  171. data/lib/spontaneous/plugins/site/schema.rb +33 -0
  172. data/lib/spontaneous/plugins/site/search.rb +43 -0
  173. data/lib/spontaneous/plugins/site/selectors.rb +35 -30
  174. data/lib/spontaneous/plugins/site/storage.rb +63 -0
  175. data/lib/spontaneous/plugins/site_map.rb +23 -25
  176. data/lib/spontaneous/plugins/styles.rb +35 -43
  177. data/lib/spontaneous/plugins/supertype.rb +3 -1
  178. data/lib/spontaneous/plugins/visibility.rb +90 -83
  179. data/lib/spontaneous/prototypes/box_prototype.rb +55 -25
  180. data/lib/spontaneous/prototypes/field_prototype.rb +66 -19
  181. data/lib/spontaneous/prototypes/style_prototype.rb +2 -2
  182. data/lib/spontaneous/publishing.rb +1 -1
  183. data/lib/spontaneous/publishing/immediate.rb +128 -49
  184. data/lib/spontaneous/publishing/simultaneous.rb +70 -0
  185. data/lib/spontaneous/rack.rb +38 -26
  186. data/lib/spontaneous/rack/around_back.rb +3 -23
  187. data/lib/spontaneous/rack/around_preview.rb +3 -8
  188. data/lib/spontaneous/rack/assets.rb +7 -6
  189. data/lib/spontaneous/rack/authentication.rb +21 -0
  190. data/lib/spontaneous/rack/back.rb +310 -331
  191. data/lib/spontaneous/rack/cacheable_file.rb +27 -0
  192. data/lib/spontaneous/rack/cookie_authentication.rb +38 -0
  193. data/lib/spontaneous/rack/css.rb +43 -0
  194. data/lib/spontaneous/rack/event_source.rb +31 -0
  195. data/lib/spontaneous/rack/front.rb +30 -8
  196. data/lib/spontaneous/rack/helpers.rb +31 -0
  197. data/lib/spontaneous/rack/media.rb +22 -21
  198. data/lib/spontaneous/rack/public.rb +2 -1
  199. data/lib/spontaneous/rack/query_authentication.rb +35 -0
  200. data/lib/spontaneous/rack/reloader.rb +6 -3
  201. data/lib/spontaneous/rack/user_helpers.rb +28 -0
  202. data/lib/spontaneous/render.rb +64 -23
  203. data/lib/spontaneous/render/context_base.rb +143 -0
  204. data/lib/spontaneous/render/format.rb +24 -19
  205. data/lib/spontaneous/render/helpers.rb +14 -0
  206. data/lib/spontaneous/render/helpers/html_helper.rb +69 -0
  207. data/lib/spontaneous/render/helpers/script_helper.rb +17 -0
  208. data/lib/spontaneous/render/helpers/stylesheet_helper.rb +16 -0
  209. data/lib/spontaneous/render/preview_context.rb +8 -0
  210. data/lib/spontaneous/render/preview_renderer.rb +6 -0
  211. data/lib/spontaneous/render/publish_context.rb +22 -0
  212. data/lib/spontaneous/render/published_renderer.rb +12 -13
  213. data/lib/spontaneous/render/publishing_renderer.rb +3 -0
  214. data/lib/spontaneous/render/render_cache.rb +26 -0
  215. data/lib/spontaneous/render/renderer.rb +5 -1
  216. data/lib/spontaneous/render/request_context.rb +8 -0
  217. data/lib/spontaneous/schema.rb +56 -24
  218. data/lib/spontaneous/schema/schema_modification.rb +2 -2
  219. data/lib/spontaneous/schema/uid.rb +22 -106
  220. data/lib/spontaneous/schema/uid_map.rb +120 -0
  221. data/lib/spontaneous/search.rb +11 -0
  222. data/lib/spontaneous/search/compound_indexer.rb +26 -0
  223. data/lib/spontaneous/search/database.rb +72 -0
  224. data/lib/spontaneous/search/field.rb +95 -0
  225. data/lib/spontaneous/search/index.rb +184 -0
  226. data/lib/spontaneous/search/results.rb +34 -0
  227. data/lib/spontaneous/server.rb +5 -1
  228. data/lib/spontaneous/site.rb +56 -16
  229. data/lib/spontaneous/storage.rb +22 -0
  230. data/lib/spontaneous/storage/backend.rb +10 -0
  231. data/lib/spontaneous/storage/cloud.rb +104 -0
  232. data/lib/spontaneous/storage/local.rb +52 -0
  233. data/lib/spontaneous/style.rb +27 -9
  234. data/lib/spontaneous/version.rb +1 -1
  235. data/spontaneous.gemspec +719 -0
  236. data/test/disabled/test_slots.rb +1 -1
  237. data/test/experimental/test_cutaneous.rb +309 -0
  238. data/test/experimental/test_features.rb +129 -0
  239. data/test/fixtures/application/views/{index.erubis → index.erb} +0 -0
  240. data/test/fixtures/back/public/css/sass_include.scss +5 -0
  241. data/test/fixtures/back/public/css/sass_template.scss +4 -0
  242. data/test/fixtures/example_application/templates/client_project.html.cut +4 -4
  243. data/test/fixtures/example_application/templates/client_project/images.html.cut +1 -1
  244. data/test/fixtures/example_application/templates/client_projects.html.cut +2 -2
  245. data/test/fixtures/example_application/templates/inline_image.html.cut +1 -1
  246. data/test/fixtures/example_application/templates/layouts/home.html.cut +7 -7
  247. data/test/fixtures/example_application/templates/layouts/info.html.cut +1 -1
  248. data/test/fixtures/example_application/templates/layouts/project.html.cut +4 -4
  249. data/test/fixtures/example_application/templates/layouts/projects.html.cut +2 -2
  250. data/test/fixtures/example_application/templates/project.html.cut +2 -2
  251. data/test/fixtures/example_application/templates/project/inline.html.cut +3 -3
  252. data/test/fixtures/example_application/templates/project_image.html.cut +1 -1
  253. data/test/fixtures/example_application/templates/text.html.cut +1 -1
  254. data/test/fixtures/fields/youtube_api_response.xml +102 -0
  255. data/test/fixtures/layouts/layouts/custom4.html.cut +0 -0
  256. data/test/fixtures/plugins/schema_plugin/public/css/plugin.css +1 -0
  257. data/test/fixtures/plugins/schema_plugin/public/js/plugin.js +1 -0
  258. data/test/fixtures/plugins/schema_plugin/public/static.html +1 -0
  259. data/test/fixtures/plugins/schema_plugin/public/subdir/image.gif +1 -0
  260. data/test/fixtures/plugins/schema_plugin/public/subdir/include1.scss +3 -0
  261. data/test/fixtures/plugins/schema_plugin/public/subdir/sass.scss +4 -0
  262. data/test/fixtures/plugins/schema_plugin/public/subdir/sass/include2.scss +4 -0
  263. data/test/fixtures/public/templates/layouts/default.html.cut +1 -1
  264. data/test/fixtures/public/templates/layouts/default.pdf.cut +1 -1
  265. data/test/fixtures/public/templates/layouts/default.rss.cut +1 -1
  266. data/test/fixtures/public/templates/layouts/dynamic.html.cut +1 -1
  267. data/test/fixtures/schema_modification/config/database.yml +0 -0
  268. data/test/fixtures/schema_modification/config/environment.rb +2 -0
  269. data/test/fixtures/schema_modification/schema/box.rb +1 -0
  270. data/test/fixtures/schema_modification/schema/custom_box.rb +1 -0
  271. data/test/fixtures/schema_modification/schema/page.rb +6 -0
  272. data/test/fixtures/schema_modification/schema/piece.rb +1 -0
  273. data/test/fixtures/search/config/database.yml +1 -0
  274. data/test/fixtures/search/config/indexes.rb +4 -0
  275. data/test/fixtures/serialisation/root_hash.yaml.erb +16 -20
  276. data/test/fixtures/storage/cloud/environment.rb +12 -0
  277. data/test/fixtures/storage/default/environment.rb +1 -0
  278. data/test/fixtures/templates/aliases/layouts/c_alias.html.cut +1 -1
  279. data/test/fixtures/templates/content/include.html.cut +1 -1
  280. data/test/fixtures/templates/content/include_dir.html.cut +1 -1
  281. data/test/fixtures/templates/content/included.epub.cut +1 -1
  282. data/test/fixtures/templates/content/included.html.cut +1 -1
  283. data/test/fixtures/templates/content/partial/included.html.cut +1 -1
  284. data/test/fixtures/templates/content/preprocess.html.cut +1 -1
  285. data/test/fixtures/templates/content/second.html.cut +1 -1
  286. data/test/fixtures/templates/content/template.epub.cut +1 -1
  287. data/test/fixtures/templates/content/template.html.cut +1 -1
  288. data/test/fixtures/templates/default_style_class.html.cut +1 -1
  289. data/test/fixtures/templates/engine/braces.html.cut +6 -0
  290. data/test/fixtures/templates/engine/multiline.html.cut +5 -0
  291. data/test/fixtures/templates/extended/grandparent.html.cut +7 -7
  292. data/test/fixtures/templates/extended/main.html.cut +5 -5
  293. data/test/fixtures/templates/extended/parent.html.cut +10 -8
  294. data/test/fixtures/templates/extended/partial.html.cut +1 -0
  295. data/test/fixtures/templates/extended/partial_with_locals.html.cut +1 -0
  296. data/test/fixtures/templates/extended/with_includes.html.cut +9 -0
  297. data/test/fixtures/templates/extended/with_includes_and_locals.html.cut +9 -0
  298. data/test/fixtures/templates/layouts/entries.html.cut +7 -7
  299. data/test/fixtures/templates/layouts/page_style.html.cut +1 -1
  300. data/test/fixtures/templates/layouts/params.html.cut +1 -1
  301. data/test/fixtures/templates/layouts/preview_render.html.cut +2 -2
  302. data/test/fixtures/templates/layouts/standard_page.html.cut +1 -1
  303. data/test/fixtures/templates/layouts/subdir_style.html.cut +1 -1
  304. data/test/fixtures/templates/layouts/template_params.html.cut +1 -1
  305. data/test/fixtures/templates/layouts/variables.html.cut +7 -0
  306. data/test/fixtures/templates/page_class/inline_style.html.cut +1 -1
  307. data/test/fixtures/templates/preview_render/variables.html.cut +1 -0
  308. data/test/fixtures/templates/publishing/templates/layouts/dynamic.html.cut +1 -0
  309. data/test/fixtures/templates/publishing/templates/layouts/dynamic.rtf.cut +1 -0
  310. data/test/fixtures/templates/publishing/templates/layouts/static.html.cut +1 -0
  311. data/test/fixtures/templates/template_class/anonymous_style.html.cut +2 -2
  312. data/test/fixtures/templates/template_class/complex_template.html.cut +4 -4
  313. data/test/fixtures/templates/template_class/complex_template.pdf.cut +4 -4
  314. data/test/fixtures/templates/template_class/default_template_style.html.cut +2 -2
  315. data/test/fixtures/templates/template_class/images_with_template.html.cut +3 -3
  316. data/test/fixtures/templates/template_class/slots_template.html.cut +3 -3
  317. data/test/fixtures/templates/template_class/slots_template.pdf.cut +3 -3
  318. data/test/fixtures/templates/template_class/this_template.epub.cut +1 -1
  319. data/test/fixtures/templates/template_class/this_template.html.cut +1 -1
  320. data/test/fixtures/templates/template_class/this_template.pdf.cut +1 -1
  321. data/test/fixtures/templates/with_default_style_class.html.cut +1 -1
  322. data/test/functional/test_application.rb +19 -15
  323. data/test/functional/test_back.rb +130 -98
  324. data/test/functional/test_front.rb +72 -28
  325. data/test/javascript/test_dom.rb +1 -1
  326. data/test/javascript/test_markdown.rb +1 -1
  327. data/test/slow/test_publishing.rb +94 -75
  328. data/test/slow/test_visibility.rb +47 -14
  329. data/test/test_helper.rb +30 -3
  330. data/test/ui/test_page_editing.rb +1 -1
  331. data/test/unit/test_alias.rb +200 -16
  332. data/test/unit/test_authentication.rb +26 -28
  333. data/test/unit/test_boxes.rb +146 -75
  334. data/test/unit/test_config.rb +42 -20
  335. data/test/unit/test_content.rb +156 -37
  336. data/test/unit/test_content_inheritance.rb +4 -2
  337. data/test/unit/test_extensions.rb +7 -1
  338. data/test/unit/test_fields.rb +558 -290
  339. data/test/{experimental → unit}/test_formats.rb +42 -3
  340. data/test/unit/test_generators.rb +3 -2
  341. data/test/unit/test_helpers.rb +54 -0
  342. data/test/unit/test_image_size.rb +1 -1
  343. data/test/unit/test_images.rb +51 -40
  344. data/test/unit/test_layouts.rb +21 -4
  345. data/test/unit/test_logger.rb +1 -1
  346. data/test/unit/test_media.rb +165 -7
  347. data/test/unit/test_page.rb +158 -27
  348. data/test/unit/test_permissions.rb +170 -187
  349. data/test/unit/test_piece.rb +27 -9
  350. data/test/unit/test_plugins.rb +153 -0
  351. data/test/unit/test_prototype_set.rb +60 -2
  352. data/test/unit/test_prototypes.rb +81 -20
  353. data/test/unit/test_render.rb +97 -9
  354. data/test/unit/test_schema.rb +167 -120
  355. data/test/unit/test_search.rb +588 -0
  356. data/test/unit/test_serialisation.rb +26 -10
  357. data/test/unit/test_site.rb +42 -25
  358. data/test/unit/test_storage.rb +88 -0
  359. data/test/unit/test_structure.rb +11 -5
  360. data/test/unit/test_styles.rb +64 -3
  361. data/test/unit/test_table_scoping.rb +76 -0
  362. data/test/unit/test_templates.rb +69 -31
  363. data/test/unit/test_type_hierarchy.rb +9 -1
  364. metadata +274 -208
  365. data/Gemfile.lock +0 -146
  366. data/application/css/min/54ee0ed3c7fac7632bd5c020d69e9a2503e0c88c.css +0 -1
  367. data/application/css/min/c256adc144e2bdd0b0539356b04eb62db01e1dc3.css +0 -1
  368. data/application/js/edit_dialogue.js +0 -137
  369. data/application/js/min/492a209de8ee955fa9c729a765377495001e11b1.js +0 -17
  370. data/application/js/min/80f684d77c940887a1d4a63e3a96102e993baa98.js +0 -88
  371. data/application/js/min/c7140ec9475e5bf868b901e0621338d7d162358b.js +0 -3
  372. data/application/js/min/f07f2bd6630ee31e1c2288ec223383d8f0658ba6.js +0 -2
  373. data/application/js/vendor/.DS_Store +0 -0
  374. data/application/js/vendor/JS.Class-2.1.5/src/command.js +0 -93
  375. data/application/js/vendor/JS.Class-2.1.5/src/comparable.js +0 -37
  376. data/application/js/vendor/JS.Class-2.1.5/src/constant_scope.js +0 -48
  377. data/application/js/vendor/JS.Class-2.1.5/src/core.js +0 -1060
  378. data/application/js/vendor/JS.Class-2.1.5/src/decorator.js +0 -50
  379. data/application/js/vendor/JS.Class-2.1.5/src/enumerable.js +0 -505
  380. data/application/js/vendor/JS.Class-2.1.5/src/forwardable.js +0 -22
  381. data/application/js/vendor/JS.Class-2.1.5/src/hash.js +0 -334
  382. data/application/js/vendor/JS.Class-2.1.5/src/linked_list.js +0 -114
  383. data/application/js/vendor/JS.Class-2.1.5/src/loader.js +0 -553
  384. data/application/js/vendor/JS.Class-2.1.5/src/method_chain.js +0 -172
  385. data/application/js/vendor/JS.Class-2.1.5/src/observable.js +0 -55
  386. data/application/js/vendor/JS.Class-2.1.5/src/package.js +0 -472
  387. data/application/js/vendor/JS.Class-2.1.5/src/proxy.js +0 -58
  388. data/application/js/vendor/JS.Class-2.1.5/src/ruby.js +0 -44
  389. data/application/js/vendor/JS.Class-2.1.5/src/set.js +0 -332
  390. data/application/js/vendor/JS.Class-2.1.5/src/stack_trace.js +0 -151
  391. data/application/js/vendor/JS.Class-2.1.5/src/state.js +0 -95
  392. data/application/js/vendor/JS.Class-2.1.5/src/stdlib.js +0 -2612
  393. data/application/js/vendor/jquery-1.4.2.min.js +0 -154
  394. data/application/js/vendor/jquery-1.4.3.min.js +0 -166
  395. data/application/js/vendor/jquery-1.5.1.min.js +0 -16
  396. data/application/js/vendor/jquery-1.5.1rc1.min.js +0 -24
  397. data/application/js/vendor/jquery-ui-1.8.6.custom.min.js +0 -265
  398. data/application/js/vendor/jquery-ui-1.8.custom.min.js +0 -106
  399. data/application/js/vendor/jquery.hotkeys-0.7.9.js +0 -248
  400. data/application/js/vendor/jquery.hotkeys-0.7.9.min.js +0 -19
  401. data/application/js/vendor/jsdiff.js +0 -169
  402. data/lib/cutaneous/first_pass_parser.rb +0 -23
  403. data/lib/cutaneous/parser_core.rb +0 -18
  404. data/lib/cutaneous/second_pass_parser.rb +0 -23
  405. data/lib/sequel/plugins/yajl_serialization.rb +0 -154
  406. data/lib/spontaneous/plugins.rb +0 -20
  407. data/lib/spontaneous/proxy_object.rb +0 -12
  408. data/lib/spontaneous/publishing/fire_and_forget.rb +0 -57
  409. data/lib/spontaneous/render/context.rb +0 -100
  410. data/spontaneous.gemspec.tmpl +0 -66
  411. data/test/experimental/test_plugins.rb +0 -64
  412. data/test/fixtures/templates/publishing/layouts/dynamic.html.cut +0 -1
  413. data/test/fixtures/templates/publishing/layouts/static.html.cut +0 -1
@@ -1,95 +0,0 @@
1
- JS.State = new JS.Module('State', {
2
- __getState__: function(state) {
3
- return (typeof state === 'object' && state) ||
4
- (typeof state === 'string' && ((this.states || {})[state] || {})) ||
5
- {};
6
- },
7
-
8
- setState: function(state) {
9
- this.__state__ = this.__getState__(state);
10
- JS.State.addMethods(this.__state__, this.klass);
11
- },
12
-
13
- inState: function() {
14
- var i = arguments.length;
15
- while (i--) {
16
- if (this.__state__ === this.__getState__(arguments[i])) return true;
17
- }
18
- return false;
19
- },
20
-
21
- extend: {
22
- stub: function() { return this; },
23
-
24
- buildStubs: function(stubs, collection, states) {
25
- var state, method;
26
- for (state in states) {
27
- collection[state] = {};
28
- for (method in states[state]) stubs[method] = this.stub;
29
- } },
30
-
31
- findStates: function(collections, name) {
32
- var i = collections.length, results = [];
33
- while (i--) {
34
- if (collections[i].hasOwnProperty(name))
35
- results.push(collections[i][name]);
36
- }
37
- return results;
38
- },
39
-
40
- buildCollection: function(module, states) {
41
- var stubs = {},
42
- collection = {},
43
- superstates = module.lookup('states'),
44
- state, klass, methods, name, mixins, i, n;
45
-
46
- this.buildStubs(stubs, collection, states);
47
-
48
- for (i = 0, n = superstates.length; i < n; i++)
49
- this.buildStubs(stubs, collection, superstates[i]);
50
-
51
- for (state in collection) {
52
- klass = new JS.Class(states[state]);
53
- mixins = this.findStates(superstates, state);
54
-
55
- i = mixins.length;
56
- while (i--) klass.include(mixins[i].klass);
57
-
58
- methods = {};
59
- for (name in stubs) { if (!klass.prototype[name]) methods[name] = stubs[name]; }
60
- klass.include(methods);
61
- collection[state] = new klass;
62
- }
63
- if (module.__res__) this.addMethods(stubs, module.__res__.klass);
64
- return collection;
65
- },
66
-
67
- addMethods: function(state, klass) {
68
- if (!klass) return;
69
-
70
- var methods = {},
71
- p = klass.prototype,
72
- method;
73
-
74
- for (method in state) {
75
- if (p[method]) continue;
76
- p[method] = klass.__mod__.__fns__[method] = this.wrapped(method);
77
- }
78
- },
79
-
80
- wrapped: function(method) {
81
- return function() {
82
- var func = (this.__state__ || {})[method];
83
- return func ? func.apply(this, arguments): this;
84
- };
85
- }
86
- }
87
- });
88
-
89
- JS.Module.include({define: (function(wrapped) {
90
- return function(name, block) {
91
- if (name === 'states' && typeof block === 'object')
92
- arguments[1] = JS.State.buildCollection(this, block);
93
- return wrapped.apply(this, arguments);
94
- };
95
- })(JS.Module.prototype.define)}, true);
@@ -1,2612 +0,0 @@
1
- JS.MethodChain = function(base) {
2
- var queue = [],
3
- baseObject = base || {};
4
-
5
- this.____ = function(method, args) {
6
- queue.push({func: method, args: args});
7
- };
8
-
9
- this.fire = function(base) {
10
- return JS.MethodChain.fire(queue, base || baseObject);
11
- };
12
- };
13
-
14
- JS.MethodChain.fire = function(queue, object) {
15
- var method, property, i, n;
16
- loop: for (i = 0, n = queue.length; i < n; i++) {
17
- method = queue[i];
18
- if (object instanceof JS.MethodChain) {
19
- object.____(method.func, method.args);
20
- continue;
21
- }
22
- switch (typeof method.func) {
23
- case 'string': property = object[method.func]; break;
24
- case 'function': property = method.func; break;
25
- case 'object': object = method.func; continue loop; break;
26
- }
27
- object = (typeof property === 'function')
28
- ? property.apply(object, method.args)
29
- : property;
30
- }
31
- return object;
32
- };
33
-
34
- JS.MethodChain.prototype = {
35
- _: function() {
36
- var base = arguments[0],
37
- args, i, n;
38
-
39
- switch (typeof base) {
40
- case 'object': case 'function':
41
- args = [];
42
- for (i = 1, n = arguments.length; i < n; i++) args.push(arguments[i]);
43
- this.____(base, args);
44
- }
45
- return this;
46
- },
47
-
48
- toFunction: function() {
49
- var chain = this;
50
- return function(object) { return chain.fire(object); };
51
- }
52
- };
53
-
54
- JS.MethodChain.reserved = (function() {
55
- var names = [], key;
56
- for (key in new JS.MethodChain) names.push(key);
57
- return new RegExp('^(?:' + names.join('|') + ')$');
58
- })();
59
-
60
- JS.MethodChain.addMethod = function(name) {
61
- if (this.reserved.test(name)) return;
62
- var func = this.prototype[name] = function() {
63
- this.____(name, arguments);
64
- return this;
65
- };
66
- func.displayName = 'MethodChain#' + name;
67
- };
68
-
69
- JS.MethodChain.displayName = 'MethodChain';
70
-
71
- JS.MethodChain.addMethods = function(object) {
72
- var methods = [], property, i;
73
-
74
- for (property in object)
75
- Number(property) !== property && methods.push(property);
76
-
77
- if (object instanceof Array) {
78
- i = object.length;
79
- while (i--)
80
- typeof object[i] === 'string' && methods.push(object[i]);
81
- }
82
- i = methods.length;
83
- while (i--) this.addMethod(methods[i]);
84
-
85
- object.__fns__ && this.addMethods(object.__fns__);
86
- object.prototype && this.addMethods(object.prototype);
87
- };
88
-
89
- it = its = function() { return new JS.MethodChain; };
90
-
91
- JS.Module.methodAdded(function(name) {
92
- JS.MethodChain.addMethod(name);
93
- });
94
-
95
- JS.Kernel.include({
96
- wait: function(time) {
97
- var chain = new JS.MethodChain;
98
-
99
- typeof time === 'number' &&
100
- setTimeout(chain.fire.bind(chain, this), time * 1000);
101
-
102
- this.forEach && typeof time === 'function' &&
103
- this.forEach(function() {
104
- setTimeout(chain.fire.bind(chain, arguments[0]), time.apply(this, arguments) * 1000);
105
- });
106
-
107
- return chain;
108
- },
109
-
110
- _: function() {
111
- var base = arguments[0],
112
- args = [],
113
- i, n;
114
-
115
- for (i = 1, n = arguments.length; i < n; i++) args.push(arguments[i]);
116
- return (typeof base === 'object' && base) ||
117
- (typeof base === 'function' && base.apply(this, args)) ||
118
- this;
119
- }
120
- }, true);
121
-
122
- (function() {
123
- var queue = JS.Module.__chainq__,
124
- n = queue.length;
125
-
126
- while (n--) JS.MethodChain.addMethods(queue[n]);
127
- JS.Module.__chainq__ = null;
128
- })();
129
-
130
- JS.MethodChain.addMethods([
131
- "abbr", "abs", "accept", "acceptCharset", "accesskey", "acos", "action", "addEventListener",
132
- "adjacentNode", "align", "alignWithTop", "alink", "alt", "anchor", "appendChild", "appendedNode",
133
- "apply", "archive", "arguments", "arity", "asin", "atan", "atan2", "attrNode", "attributes",
134
- "axis", "background", "bgcolor", "big", "blink", "blur", "bold", "border", "call", "caller",
135
- "ceil", "cellpadding", "cellspacing", "char", "charAt", "charCodeAt", "charoff", "charset",
136
- "checked", "childNodes", "cite", "className", "classid", "clear", "click", "clientHeight",
137
- "clientLeft", "clientTop", "clientWidth", "cloneNode", "code", "codebase", "codetype", "color",
138
- "cols", "colspan", "compact", "concat", "content", "coords", "cos", "data", "datetime", "declare",
139
- "deep", "defer", "dir", "disabled", "dispatchEvent", "enctype", "event", "every", "exec", "exp",
140
- "face", "filter", "firstChild", "fixed", "floor", "focus", "fontcolor", "fontsize", "forEach",
141
- "frame", "frameborder", "fromCharCode", "getAttribute", "getAttributeNS", "getAttributeNode",
142
- "getAttributeNodeNS", "getDate", "getDay", "getElementsByTagName", "getElementsByTagNameNS",
143
- "getFullYear", "getHours", "getMilliseconds", "getMinutes", "getMonth", "getSeconds", "getTime",
144
- "getTimezoneOffset", "getUTCDate", "getUTCDay", "getUTCFullYear", "getUTCHours",
145
- "getUTCMilliseconds", "getUTCMinutes", "getUTCMonth", "getUTCSeconds", "getYear", "global",
146
- "handler", "hasAttribute", "hasAttributeNS", "hasAttributes", "hasChildNodes", "hasOwnProperty",
147
- "headers", "height", "href", "hreflang", "hspace", "htmlFor", "httpEquiv", "id", "ignoreCase",
148
- "index", "indexOf", "innerHTML", "input", "insertBefore", "insertedNode", "isPrototypeOf", "ismap",
149
- "italics", "join", "label", "lang", "language", "lastChild", "lastIndex", "lastIndexOf", "length",
150
- "link", "listener", "localName", "log", "longdesc", "map", "marginheight", "marginwidth", "match",
151
- "max", "maxlength", "media", "method", "min", "multiline", "multiple", "name", "namespace",
152
- "namespaceURI", "nextSibling", "node", "nodeName", "nodeType", "nodeValue", "nohref", "noresize",
153
- "normalize", "noshade", "now", "nowrap", "object", "offsetHeight", "offsetLeft", "offsetParent",
154
- "offsetTop", "offsetWidth", "onblur", "onchange", "onclick", "ondblclick", "onfocus", "onkeydown",
155
- "onkeypress", "onkeyup", "onload", "onmousedown", "onmousemove", "onmouseout", "onmouseover",
156
- "onmouseup", "onreset", "onselect", "onsubmit", "onunload", "ownerDocument", "parentNode", "parse",
157
- "pop", "pow", "prefix", "previousSibling", "profile", "prompt", "propertyIsEnumerable", "push",
158
- "random", "readonly", "reduce", "reduceRight", "rel", "removeAttribute", "removeAttributeNS",
159
- "removeAttributeNode", "removeChild", "removeEventListener", "removedNode", "replace",
160
- "replaceChild", "replacedNode", "rev", "reverse", "round", "rows", "rowspan", "rules", "scheme",
161
- "scope", "scrollHeight", "scrollIntoView", "scrollLeft", "scrollTop", "scrollWidth", "scrolling",
162
- "search", "selected", "setAttribute", "setAttributeNS", "setAttributeNode", "setAttributeNodeNS",
163
- "setDate", "setFullYear", "setHours", "setMilliseconds", "setMinutes", "setMonth", "setSeconds",
164
- "setTime", "setUTCDate", "setUTCFullYear", "setUTCHours", "setUTCMilliseconds", "setUTCMinutes",
165
- "setUTCMonth", "setUTCSeconds", "setYear", "shape", "shift", "sin", "size", "slice", "small",
166
- "some", "sort", "source", "span", "splice", "split", "sqrt", "src", "standby", "start", "strike",
167
- "style", "sub", "substr", "substring", "summary", "sup", "tabIndex", "tabindex", "tagName", "tan",
168
- "target", "test", "text", "textContent", "title", "toArray", "toFunction", "toGMTString",
169
- "toLocaleDateString", "toLocaleFormat", "toLocaleString", "toLocaleTimeString", "toLowerCase",
170
- "toSource", "toString", "toUTCString", "toUpperCase", "type", "unshift", "unwatch", "useCapture",
171
- "usemap", "valign", "value", "valueOf", "valuetype", "version", "vlink", "vspace", "watch", "width"
172
- ]);
173
-
174
-
175
- JS = (typeof JS === 'undefined') ? {} : JS;
176
-
177
- JS.Package = function(loader) {
178
- var Set = JS.Package.OrderedSet;
179
- JS.Package._index(this);
180
-
181
- this._loader = loader;
182
- this._names = new Set();
183
- this._deps = new Set();
184
- this._uses = new Set();
185
- this._observers = {};
186
- this._events = {};
187
- };
188
-
189
- (function(klass) {
190
- //================================================================
191
- // Ordered list of unique elements, for storing dependencies
192
-
193
- var Set = klass.OrderedSet = function(list, transform) {
194
- this._members = this.list = [];
195
- this._index = {};
196
- if (!list) return;
197
-
198
- for (var i = 0, n = list.length; i < n; i++)
199
- this.push(transform ? transform(list[i]) : list[i]);
200
- };
201
-
202
- Set.prototype.push = function(item) {
203
- var key = (item.id !== undefined) ? item.id : item,
204
- index = this._index;
205
-
206
- if (index.hasOwnProperty(key)) return;
207
- index[key] = this._members.length;
208
- this._members.push(item);
209
- };
210
-
211
- //================================================================
212
- // Environment settings
213
-
214
- klass._env = this;
215
-
216
- if ((this.document || {}).getElementsByTagName) {
217
- var script = document.getElementsByTagName('script')[0];
218
- klass._isIE = (script.readyState !== undefined);
219
- }
220
-
221
-
222
- //================================================================
223
- // Configuration methods, called by the DSL
224
-
225
- var instance = klass.prototype;
226
-
227
- instance.addDependency = function(pkg) {
228
- this._deps.push(pkg);
229
- };
230
-
231
- instance.addSoftDependency = function(pkg) {
232
- this._uses.push(pkg);
233
- };
234
-
235
- instance.addName = function(name) {
236
- this._names.push(name);
237
- klass.getFromCache(name).pkg = this;
238
- };
239
-
240
- instance.onload = function(block) {
241
- this._onload = block;
242
- };
243
-
244
- //================================================================
245
- // Event dispatchers, for communication between packages
246
-
247
- instance.on = function(eventType, block, scope) {
248
- if (this._events[eventType]) return block.call(scope);
249
- var list = this._observers[eventType] = this._observers[eventType] || [];
250
- list.push([block, scope]);
251
- };
252
-
253
- instance.fire = function(eventType) {
254
- if (this._events[eventType]) return false;
255
- this._events[eventType] = true;
256
-
257
- var list = this._observers[eventType];
258
- if (!list) return true;
259
- delete this._observers[eventType];
260
-
261
- for (var i = 0, n = list.length; i < n; i++)
262
- list[i][0].call(list[i][1]);
263
-
264
- return true;
265
- };
266
-
267
- //================================================================
268
- // Loading frontend and other miscellany
269
-
270
- instance.isLoaded = function(withExceptions) {
271
- if (!withExceptions && this._isLoaded !== undefined) return this._isLoaded;
272
-
273
- var names = this._names.list,
274
- i = names.length,
275
- name, object;
276
-
277
- while (i--) { name = names[i];
278
- object = klass.getObject(name);
279
- if (object !== undefined) continue;
280
- if (withExceptions)
281
- throw new Error('Expected package at ' + this._loader + ' to define ' + name);
282
- else
283
- return this._isLoaded = false;
284
- }
285
- return this._isLoaded = true;
286
- };
287
-
288
- instance.load = function() {
289
- if (!this.fire('request')) return;
290
-
291
- var allDeps = this._deps.list.concat(this._uses.list),
292
- startEvent = 'load', // could potentially use 'download' event in
293
- listener = {}; // browsers that guarantee execution order
294
-
295
- listener[startEvent] = this._deps.list;
296
-
297
- klass.when(listener, function() {
298
- klass.when({complete: allDeps, load: [this]}, function() {
299
- this.fire('complete');
300
- }, this);
301
-
302
- var self = this, fireOnLoad = function() {
303
- if (self._onload) self._onload();
304
- self.isLoaded(true);
305
- self.fire('load');
306
- };
307
-
308
- if (this.isLoaded()) {
309
- this.fire('download');
310
- return this.fire('load');
311
- }
312
-
313
- if (this._loader === undefined)
314
- throw new Error('No load path found for ' + this._names.list[0]);
315
-
316
- typeof this._loader === 'function'
317
- ? this._loader(fireOnLoad)
318
- : klass.Loader.loadFile(this._loader, fireOnLoad);
319
-
320
- this.fire('download');
321
- }, this);
322
- };
323
-
324
- instance.toString = function() {
325
- return 'Package:' + this._names.list.join(',');
326
- };
327
-
328
- //================================================================
329
- // Class-level event API, handles group listeners
330
-
331
- klass.when = function(eventTable, block, scope) {
332
- var eventList = [], event, packages, i;
333
- for (event in eventTable) {
334
- if (!eventTable.hasOwnProperty(event)) continue;
335
- packages = new klass.OrderedSet(eventTable[event], function(name) { return klass.getByName(name) });
336
- i = packages.list.length;
337
- while (i--) eventList.push([event, packages.list[i]]);
338
- }
339
-
340
- var waiting = i = eventList.length;
341
- if (waiting === 0) return block && block.call(scope);
342
-
343
- while (i--) {
344
- eventList[i][1].on(eventList[i][0], function() {
345
- waiting -= 1;
346
- if (waiting === 0 && block) block.call(scope);
347
- });
348
- eventList[i][1].load();
349
- }
350
- };
351
-
352
- //================================================================
353
- // Indexes for fast lookup by path and name, and assigning IDs
354
-
355
- klass._autoIncrement = 1;
356
- klass._indexByPath = {};
357
- klass._indexByName = {};
358
- klass._autoloaders = [];
359
-
360
- klass._index = function(pkg) {
361
- pkg.id = this._autoIncrement;
362
- this._autoIncrement += 1;
363
- };
364
-
365
- klass.getByPath = function(loader) {
366
- var path = loader.toString();
367
- return this._indexByPath[path] = this._indexByPath[path] || new this(loader);
368
- };
369
-
370
- klass.getByName = function(name) {
371
- if (typeof name !== 'string') return name;
372
- var cached = this.getFromCache(name);
373
- if (cached.pkg) return cached.pkg;
374
-
375
- var autoloaded = this._manufacture(name);
376
- if (autoloaded) return autoloaded;
377
-
378
- var placeholder = new this();
379
- placeholder.addName(name);
380
- return placeholder;
381
- };
382
-
383
- //================================================================
384
- // Auotloading API, generates packages from naming patterns
385
-
386
- klass.autoload = function(pattern, options) {
387
- this._autoloaders.push([pattern, options]);
388
- };
389
-
390
- klass._manufacture = function(name) {
391
- var autoloaders = this._autoloaders,
392
- n = autoloaders.length,
393
- i, autoloader, path;
394
-
395
- for (i = 0; i < n; i++) {
396
- autoloader = autoloaders[i];
397
- if (!autoloader[0].test(name)) continue;
398
-
399
- path = autoloader[1].from + '/' +
400
- name.replace(/([a-z])([A-Z])/g, function(m,a,b) { return a + '_' + b })
401
- .replace(/\./g, '/')
402
- .toLowerCase() + '.js';
403
-
404
- pkg = new this(path);
405
- pkg.addName(name);
406
-
407
- if (path = autoloader[1].require)
408
- pkg.addDependency(name.replace(autoloader[0], path));
409
-
410
- return pkg;
411
- }
412
- return null;
413
- };
414
-
415
- //================================================================
416
- // Cache for named packages and runtime objects
417
-
418
- klass.getFromCache = function(name) {
419
- return this._indexByName[name] = this._indexByName[name] || {};
420
- };
421
-
422
- klass.getObject = function(name) {
423
- var cached = this.getFromCache(name);
424
- if (cached.obj !== undefined) return cached.obj;
425
-
426
- var object = this._env,
427
- parts = name.split('.'), part;
428
-
429
- while (part = parts.shift()) object = object && object[part];
430
-
431
- return this.getFromCache(name).obj = object;
432
- };
433
-
434
- })(JS.Package);
435
-
436
-
437
- JS.Package.DomLoader = {
438
- usable: function() {
439
- return !!JS.Package.getObject('window.document.getElementsByTagName');
440
- },
441
-
442
- __FILE__: function() {
443
- var scripts = document.getElementsByTagName('script');
444
- return scripts[scripts.length - 1].src;
445
- },
446
-
447
- loadFile: function(path, fireCallbacks) {
448
- var self = this,
449
- tag = document.createElement('script');
450
-
451
- tag.type = 'text/javascript';
452
- tag.src = path;
453
-
454
- tag.onload = tag.onreadystatechange = function() {
455
- var state = tag.readyState, status = tag.status;
456
- if ( !state || state === 'loaded' || state === 'complete' || (state === 4 && status === 200) ) {
457
- fireCallbacks();
458
- tag.onload = tag.onreadystatechange = self._K;
459
- tag = null;
460
- }
461
- };
462
-
463
- if (window.console && console.info)
464
- console.info('Loading ' + path);
465
-
466
- document.getElementsByTagName('head')[0].appendChild(tag);
467
- },
468
-
469
- _K: function() {}
470
- };
471
-
472
- JS.Package.CommonJSLoader = {
473
- usable: function() {
474
- return typeof require === 'function' &&
475
- typeof exports === 'object';
476
- },
477
-
478
- setup: function() {
479
- var self = this;
480
- require = (function(oridRequire) {
481
- return function() {
482
- self._currentPath = arguments[0] + '.js';
483
- return oridRequire.apply(JS.Package._env, arguments);
484
- };
485
- })(require);
486
- },
487
-
488
- __FILE__: function() {
489
- return this._currentPath;
490
- },
491
-
492
- loadFile: function(path, fireCallbacks) {
493
- var node = (typeof process === 'object'),
494
- cwd = node ? process.cwd() : require('file').cwd(),
495
- module = path.replace(/\.[^\.]+$/g, ''),
496
- file = node ? require('path') : require('file');
497
-
498
- require(file.join(cwd, module));
499
- fireCallbacks();
500
- }
501
- };
502
-
503
- JS.Package.ServerLoader = {
504
- usable: function() {
505
- return typeof JS.Package.getObject('load') === 'function' &&
506
- typeof JS.Package.getObject('version') === 'function';
507
- },
508
-
509
- setup: function() {
510
- var self = this;
511
- load = (function(origLoad) {
512
- return function() {
513
- self._currentPath = arguments[0];
514
- return origLoad.apply(JS.Package._env, arguments);
515
- };
516
- })(load);
517
- },
518
-
519
- __FILE__: function() {
520
- return this._currentPath;
521
- },
522
-
523
- loadFile: function(path, fireCallbacks) {
524
- load(path);
525
- fireCallbacks();
526
- }
527
- };
528
-
529
- JS.Package.WshLoader = {
530
- usable: function() {
531
- return !!JS.Package.getObject('ActiveXObject') &&
532
- !!JS.Package.getObject('WScript');
533
- },
534
-
535
- __FILE__: function() {
536
- return this._currentPath;
537
- },
538
-
539
- loadFile: function(path, fireCallbacks) {
540
- this._currentPath = path;
541
- var fso = new ActiveXObject('Scripting.FileSystemObject'), file, runner;
542
- try {
543
- file = fso.OpenTextFile(path);
544
- runner = function() { eval(file.ReadAll()) };
545
- runner();
546
- fireCallbacks();
547
- } finally {
548
- try { if (file) file.Close() } catch (e) {}
549
- }
550
- }
551
- };
552
-
553
- (function() {
554
- var candidates = [ JS.Package.DomLoader,
555
- JS.Package.CommonJSLoader,
556
- JS.Package.ServerLoader,
557
- JS.Package.WshLoader ],
558
-
559
- n = candidates.length,
560
- i, candidate;
561
-
562
- for (i = 0; i < n; i++) {
563
- candidate = candidates[i];
564
- if (candidate.usable()) {
565
- JS.Package.Loader = candidate;
566
- if (candidate.setup) candidate.setup();
567
- break;
568
- }
569
- }
570
- })();
571
-
572
-
573
- JS.Package.DSL = {
574
- __FILE__: function() {
575
- return JS.Package.Loader.__FILE__();
576
- },
577
-
578
- pkg: function(name, path) {
579
- var pkg = path
580
- ? JS.Package.getByPath(path)
581
- : JS.Package.getByName(name);
582
- pkg.addName(name);
583
- return new JS.Package.Description(pkg);
584
- },
585
-
586
- file: function(path) {
587
- var pkg = JS.Package.getByPath(path);
588
- return new JS.Package.Description(pkg);
589
- },
590
-
591
- load: function(path, fireCallbacks) {
592
- JS.Package.Loader.loadFile(path, fireCallbacks);
593
- },
594
-
595
- autoload: function(pattern, options) {
596
- JS.Package.autoload(pattern, options);
597
- }
598
- };
599
-
600
- JS.Package.Description = function(pkg) {
601
- this._pkg = pkg;
602
- };
603
-
604
- (function(klass) {
605
-
606
- klass._batch = function(method, args) {
607
- var n = args.length, method = this._pkg[method], i;
608
- for (i = 0; i < n; i++) method.call(this._pkg, args[i]);
609
- return this;
610
- };
611
-
612
- klass.provides = function() {
613
- return this._batch('addName', arguments);
614
- };
615
-
616
- klass.requires = function() {
617
- return this._batch('addDependency', arguments);
618
- };
619
-
620
- klass.uses = function() {
621
- return this._batch('addSoftDependency', arguments);
622
- };
623
-
624
- klass.setup = function(block) {
625
- this._pkg.onload(block);
626
- return this;
627
- };
628
-
629
- })(JS.Package.Description.prototype);
630
-
631
- JS.Package.DSL.loader = JS.Package.DSL.file;
632
-
633
- JS.Packages = function(declaration) {
634
- declaration.call(JS.Package.DSL);
635
- };
636
-
637
- JS.require = function() {
638
- var requirements = [], i = 0;
639
-
640
- while (typeof arguments[i] === 'string'){
641
- requirements.push(arguments[i]);
642
- i += 1;
643
- }
644
-
645
- JS.Package.when({complete: requirements}, arguments[i], arguments[i+1]);
646
- };
647
-
648
-
649
- JS.Comparable = new JS.Module('Comparable', {
650
- extend: {
651
- ClassMethods: new JS.Module({
652
- compare: function(one, another) {
653
- return one.compareTo(another);
654
- }
655
- }),
656
-
657
- included: function(base) {
658
- base.extend(this.ClassMethods);
659
- }
660
- },
661
-
662
- lt: function(other) {
663
- return this.compareTo(other) < 0;
664
- },
665
-
666
- lte: function(other) {
667
- return this.compareTo(other) < 1;
668
- },
669
-
670
- gt: function(other) {
671
- return this.compareTo(other) > 0;
672
- },
673
-
674
- gte: function(other) {
675
- return this.compareTo(other) > -1;
676
- },
677
-
678
- eq: function(other) {
679
- return this.compareTo(other) === 0;
680
- },
681
-
682
- between: function(a, b) {
683
- return this.gte(a) && this.lte(b);
684
- }
685
- });
686
-
687
-
688
- JS.Enumerable = new JS.Module('Enumerable', {
689
- extend: {
690
- forEach: function(block, context) {
691
- if (!block) return new JS.Enumerator(this, 'forEach');
692
- for (var i = 0, n = this.length; i < n; i++) {
693
- if (this[i] !== undefined)
694
- block.call(context || null, this[i]);
695
- }
696
- return this;
697
- },
698
-
699
- isComparable: function(list) {
700
- return list.all(function(item) { return JS.isFn(item.compareTo) });
701
- },
702
-
703
- areEqual: function(one, another) {
704
- return one.equals
705
- ? one.equals(another)
706
- : (one === another);
707
- },
708
-
709
- Collection: new JS.Class({
710
- initialize: function(array) {
711
- this.length = 0;
712
- var push = Array.prototype.push;
713
- JS.Enumerable.forEach.call(array, function(item) {
714
- push.call(this, item);
715
- }, this);
716
- }
717
- })
718
- },
719
-
720
- all: function(block, context) {
721
- block = JS.Enumerable.toFn(block);
722
- var truth = true;
723
- this.forEach(function(item) {
724
- truth = truth && (block ? block.apply(context || null, arguments) : item);
725
- });
726
- return !!truth;
727
- },
728
-
729
- any: function(block, context) {
730
- block = JS.Enumerable.toFn(block);
731
- var truth = false;
732
- this.forEach(function(item) {
733
- truth = truth || (block ? block.apply(context || null, arguments) : item);
734
- });
735
- return !!truth;
736
- },
737
-
738
- count: function(block, context) {
739
- if (JS.isFn(this.size)) return this.size();
740
- var count = 0, object = block;
741
-
742
- if (block && !JS.isFn(block))
743
- block = function(x) { return JS.Enumerable.areEqual(x, object) };
744
-
745
- this.forEach(function() {
746
- if (!block || block.apply(context || null, arguments))
747
- count += 1;
748
- });
749
- return count;
750
- },
751
-
752
- cycle: function(n, block, context) {
753
- if (!block) return this.enumFor('cycle', n);
754
- block = JS.Enumerable.toFn(block);
755
- while (n--) this.forEach(block, context);
756
- },
757
-
758
- drop: function(n) {
759
- var entries = [];
760
- this.forEachWithIndex(function(item, i) {
761
- if (i >= n) entries.push(item);
762
- });
763
- return entries;
764
- },
765
-
766
- dropWhile: function(block, context) {
767
- if (!block) return this.enumFor('dropWhile');
768
- block = JS.Enumerable.toFn(block);
769
-
770
- var entries = [],
771
- drop = true;
772
-
773
- this.forEach(function(item) {
774
- if (drop) drop = drop && block.apply(context || null, arguments);
775
- if (!drop) entries.push(item);
776
- });
777
- return entries;
778
- },
779
-
780
- forEachCons: function(n, block, context) {
781
- if (!block) return this.enumFor('forEachCons', n);
782
- block = JS.Enumerable.toFn(block);
783
-
784
- var entries = this.toArray(),
785
- size = entries.length,
786
- limit = size - n,
787
- i;
788
-
789
- for (i = 0; i <= limit; i++)
790
- block.call(context || null, entries.slice(i, i+n));
791
-
792
- return this;
793
- },
794
-
795
- forEachSlice: function(n, block, context) {
796
- if (!block) return this.enumFor('forEachSlice', n);
797
- block = JS.Enumerable.toFn(block);
798
-
799
- var entries = this.toArray(),
800
- size = entries.length,
801
- m = Math.ceil(size/n),
802
- i;
803
-
804
- for (i = 0; i < m; i++)
805
- block.call(context || null, entries.slice(i*n, (i+1)*n));
806
-
807
- return this;
808
- },
809
-
810
- forEachWithIndex: function(offset, block, context) {
811
- if (JS.isFn(offset)) {
812
- context = block;
813
- block = offset;
814
- offset = 0;
815
- }
816
- offset = offset || 0;
817
-
818
- if (!block) return this.enumFor('forEachWithIndex', offset);
819
- block = JS.Enumerable.toFn(block);
820
-
821
- return this.forEach(function(item) {
822
- var result = block.call(context || null, item, offset);
823
- offset += 1;
824
- return result;
825
- });
826
- },
827
-
828
- forEachWithObject: function(object, block, context) {
829
- if (!block) return this.enumFor('forEachWithObject', object);
830
- block = JS.Enumerable.toFn(block);
831
-
832
- this.forEach(function() {
833
- var args = [object].concat(JS.array(arguments));
834
- block.apply(context || null, args);
835
- });
836
- return object;
837
- },
838
-
839
- find: function(block, context) {
840
- if (!block) return this.enumFor('find');
841
- block = JS.Enumerable.toFn(block);
842
-
843
- var needle = {}, K = needle;
844
- this.forEach(function(item) {
845
- if (needle !== K) return;
846
- needle = block.apply(context || null, arguments) ? item : needle;
847
- });
848
- return needle === K ? null : needle;
849
- },
850
-
851
- findIndex: function(needle, context) {
852
- if (needle === undefined) return this.enumFor('findIndex');
853
-
854
- var index = null,
855
- block = JS.isFn(needle);
856
-
857
- this.forEachWithIndex(function(item, i) {
858
- if (index !== null) return;
859
- if (JS.Enumerable.areEqual(needle, item) || (block && needle.apply(context || null, arguments)))
860
- index = i;
861
- });
862
- return index;
863
- },
864
-
865
- first: function(n) {
866
- var entries = this.toArray();
867
- return (n === undefined) ? entries[0] : entries.slice(0,n);
868
- },
869
-
870
- grep: function(pattern, block, context) {
871
- block = JS.Enumerable.toFn(block);
872
- var results = [];
873
- this.forEach(function(item) {
874
- var match = JS.isFn(pattern.match) ? pattern.match(item) : pattern(item);
875
- if (!match) return;
876
- if (block) item = block.apply(context || null, arguments);
877
- results.push(item);
878
- });
879
- return results;
880
- },
881
-
882
- groupBy: function(block, context) {
883
- if (!block) return this.enumFor('groupBy');
884
- block = JS.Enumerable.toFn(block);
885
-
886
- var hash = new JS.Hash();
887
- this.forEach(function(item) {
888
- var value = block.apply(context || null, arguments);
889
- if (!hash.hasKey(value)) hash.store(value, []);
890
- hash.get(value).push(item);
891
- });
892
- return hash;
893
- },
894
-
895
- inject: function(memo, block, context) {
896
- var args = JS.array(arguments),
897
- counter = 0,
898
- K = {};
899
-
900
- switch (args.length) {
901
- case 1: memo = K;
902
- block = args[0];
903
- break;
904
-
905
- case 2: if (JS.isFn(memo)) {
906
- memo = K;
907
- block = args[0];
908
- context = args[1];
909
- }
910
- }
911
- block = JS.Enumerable.toFn(block);
912
-
913
- this.forEach(function(item) {
914
- if (!counter++ && memo === K) return memo = item;
915
- var args = [memo].concat(JS.array(arguments));
916
- memo = block.apply(context || null, args);
917
- });
918
- return memo;
919
- },
920
-
921
- map: function(block, context) {
922
- if (!block) return this.enumFor('map');
923
- block = JS.Enumerable.toFn(block);
924
-
925
- var map = [];
926
- this.forEach(function() {
927
- map.push(block.apply(context || null, arguments));
928
- });
929
- return map;
930
- },
931
-
932
- max: function(block, context) {
933
- return this.minmax(block, context)[1];
934
- },
935
-
936
- maxBy: function(block, context) {
937
- if (!block) return this.enumFor('maxBy');
938
- return this.minmaxBy(block, context)[1];
939
- },
940
-
941
- member: function(needle) {
942
- return this.any(function(item) { return JS.Enumerable.areEqual(item, needle) });
943
- },
944
-
945
- min: function(block, context) {
946
- return this.minmax(block, context)[0];
947
- },
948
-
949
- minBy: function(block, context) {
950
- if (!block) return this.enumFor('minBy');
951
- return this.minmaxBy(block, context)[0];
952
- },
953
-
954
- minmax: function(block, context) {
955
- var list = this.sort(block, context);
956
- return [list[0], list[list.length - 1]];
957
- },
958
-
959
- minmaxBy: function(block, context) {
960
- if (!block) return this.enumFor('minmaxBy');
961
- var list = this.sortBy(block, context);
962
- return [list[0], list[list.length - 1]];
963
- },
964
-
965
- none: function(block, context) {
966
- return !this.any(block, context);
967
- },
968
-
969
- one: function(block, context) {
970
- block = JS.Enumerable.toFn(block);
971
- var count = 0;
972
- this.forEach(function(item) {
973
- if (block ? block.apply(context || null, arguments) : item) count += 1;
974
- });
975
- return count === 1;
976
- },
977
-
978
- partition: function(block, context) {
979
- if (!block) return this.enumFor('partition');
980
- block = JS.Enumerable.toFn(block);
981
-
982
- var ayes = [], noes = [];
983
- this.forEach(function(item) {
984
- (block.apply(context || null, arguments) ? ayes : noes).push(item);
985
- });
986
- return [ayes, noes];
987
- },
988
-
989
- reject: function(block, context) {
990
- if (!block) return this.enumFor('reject');
991
- block = JS.Enumerable.toFn(block);
992
-
993
- var map = [];
994
- this.forEach(function(item) {
995
- if (!block.apply(context || null, arguments)) map.push(item);
996
- });
997
- return map;
998
- },
999
-
1000
- reverseForEach: function(block, context) {
1001
- if (!block) return this.enumFor('reverseForEach');
1002
- block = JS.Enumerable.toFn(block);
1003
-
1004
- var entries = this.toArray(),
1005
- n = entries.length;
1006
-
1007
- while (n--) block.call(context || null, entries[n]);
1008
- return this;
1009
- },
1010
-
1011
- select: function(block, context) {
1012
- if (!block) return this.enumFor('select');
1013
- block = JS.Enumerable.toFn(block);
1014
-
1015
- var map = [];
1016
- this.forEach(function(item) {
1017
- if (block.apply(context || null, arguments)) map.push(item);
1018
- });
1019
- return map;
1020
- },
1021
-
1022
- sort: function(block, context) {
1023
- var comparable = JS.Enumerable.isComparable(this),
1024
- entries = this.toArray();
1025
-
1026
- block = block || (comparable
1027
- ? function(a,b) { return a.compareTo(b); }
1028
- : null);
1029
- return block
1030
- ? entries.sort(function(a,b) { return block.call(context || null, a, b); })
1031
- : entries.sort();
1032
- },
1033
-
1034
- sortBy: function(block, context) {
1035
- if (!block) return this.enumFor('sortBy');
1036
- block = JS.Enumerable.toFn(block);
1037
-
1038
- var util = JS.Enumerable,
1039
- map = new util.Collection(this.map(block, context)),
1040
- comparable = util.isComparable(map);
1041
-
1042
- return new util.Collection(map.zip(this).sort(function(a, b) {
1043
- a = a[0]; b = b[0];
1044
- return comparable ? a.compareTo(b) : (a < b ? -1 : (a > b ? 1 : 0));
1045
- })).map(function(item) { return item[1]; });
1046
- },
1047
-
1048
- take: function(n) {
1049
- var entries = [];
1050
- this.forEachWithIndex(function(item, i) {
1051
- if (i < n) entries.push(item);
1052
- });
1053
- return entries;
1054
- },
1055
-
1056
- takeWhile: function(block, context) {
1057
- if (!block) return this.enumFor('takeWhile');
1058
- block = JS.Enumerable.toFn(block);
1059
-
1060
- var entries = [],
1061
- take = true;
1062
- this.forEach(function(item) {
1063
- if (take) take = take && block.apply(context || null, arguments);
1064
- if (take) entries.push(item);
1065
- });
1066
- return entries;
1067
- },
1068
-
1069
- toArray: function() {
1070
- return this.drop(0);
1071
- },
1072
-
1073
- zip: function() {
1074
- var util = JS.Enumerable,
1075
- args = [],
1076
- counter = 0,
1077
- n = arguments.length,
1078
- block, context;
1079
-
1080
- if (JS.isFn(arguments[n-1])) {
1081
- block = arguments[n-1]; context = {};
1082
- }
1083
- if (JS.isFn(arguments[n-2])) {
1084
- block = arguments[n-2]; context = arguments[n-1];
1085
- }
1086
- util.forEach.call(arguments, function(arg) {
1087
- if (arg === block || arg === context) return;
1088
- if (arg.toArray) arg = arg.toArray();
1089
- if (JS.isType(arg, Array)) args.push(arg);
1090
- });
1091
- var results = this.map(function(item) {
1092
- var zip = [item];
1093
- util.forEach.call(args, function(arg) {
1094
- zip.push(arg[counter] === undefined ? null : arg[counter]);
1095
- });
1096
- return ++counter && zip;
1097
- });
1098
- if (!block) return results;
1099
- util.forEach.call(results, block, context);
1100
- }
1101
- });
1102
-
1103
- // http://developer.mozilla.org/en/docs/index.php?title=Core_JavaScript_1.5_Reference:Global_Objects:Array&oldid=58326
1104
- JS.Enumerable.include({
1105
- forEach: JS.Enumerable.forEach,
1106
- collect: JS.Enumerable.instanceMethod('map'),
1107
- detect: JS.Enumerable.instanceMethod('find'),
1108
- entries: JS.Enumerable.instanceMethod('toArray'),
1109
- every: JS.Enumerable.instanceMethod('all'),
1110
- findAll: JS.Enumerable.instanceMethod('select'),
1111
- filter: JS.Enumerable.instanceMethod('select'),
1112
- some: JS.Enumerable.instanceMethod('any'),
1113
-
1114
- extend: {
1115
- toFn: function(object) {
1116
- if (!object) return object;
1117
- if (object.toFunction) return object.toFunction();
1118
- if (this.OPS[object]) return this.OPS[object];
1119
- if (JS.isType(object, 'string') || JS.isType(object, String))
1120
- return function() {
1121
- var args = JS.array(arguments),
1122
- target = args.shift(),
1123
- method = target[object];
1124
- return JS.isFn(method) ? method.apply(target, args) : method;
1125
- };
1126
- return object;
1127
- },
1128
-
1129
- OPS: {
1130
- '+': function(a,b) { return a + b },
1131
- '-': function(a,b) { return a - b },
1132
- '*': function(a,b) { return a * b },
1133
- '/': function(a,b) { return a / b },
1134
- '%': function(a,b) { return a % b },
1135
- '^': function(a,b) { return a ^ b },
1136
- '&': function(a,b) { return a & b },
1137
- '&&': function(a,b) { return a && b },
1138
- '|': function(a,b) { return a | b },
1139
- '||': function(a,b) { return a || b },
1140
- '==': function(a,b) { return a == b },
1141
- '!=': function(a,b) { return a != b },
1142
- '>': function(a,b) { return a > b },
1143
- '>=': function(a,b) { return a >= b },
1144
- '<': function(a,b) { return a < b },
1145
- '<=': function(a,b) { return a <= b },
1146
- '===': function(a,b) { return a === b },
1147
- '!==': function(a,b) { return a !== b },
1148
- '[]': function(a,b) { return a[b] },
1149
- '()': function(a,b) { return a(b) }
1150
- },
1151
-
1152
- Enumerator: new JS.Class({
1153
- include: JS.Enumerable,
1154
-
1155
- extend: {
1156
- DEFAULT_METHOD: 'forEach'
1157
- },
1158
-
1159
- initialize: function(object, method, args) {
1160
- this._object = object;
1161
- this._method = method || this.klass.DEFAULT_METHOD;
1162
- this._args = (args || []).slice();
1163
- },
1164
-
1165
- forEach: function(block, context) {
1166
- if (!block) return this;
1167
- var args = this._args.slice();
1168
- args.push(block);
1169
- if (context) args.push(context);
1170
- return this._object[this._method].apply(this._object, args);
1171
- },
1172
-
1173
- cons: JS.Enumerable.instanceMethod('forEachCons'),
1174
- reverse: JS.Enumerable.instanceMethod('reverseForEach'),
1175
- slice: JS.Enumerable.instanceMethod('forEachSlice'),
1176
- withIndex: JS.Enumerable.instanceMethod('forEachWithIndex'),
1177
- withObject: JS.Enumerable.instanceMethod('forEachWithObject')
1178
- })
1179
- }
1180
- }, false);
1181
-
1182
- JS.Enumerable.Collection.include(JS.Enumerable, true);
1183
-
1184
- JS.Kernel.include({
1185
- enumFor: function(method) {
1186
- var args = JS.array(arguments),
1187
- method = args.shift();
1188
- return new JS.Enumerable.Enumerator(this, method, args);
1189
- }
1190
- }, false);
1191
-
1192
- JS.Kernel.define('toEnum', JS.Kernel.instanceMethod('enumFor'), true);
1193
-
1194
-
1195
- JS.LinkedList = new JS.Class('LinkedList', {
1196
- include: JS.Enumerable || {},
1197
-
1198
- initialize: function(array, useNodes) {
1199
- this.length = 0;
1200
- this.first = this.last = null;
1201
- if (!array) return;
1202
- for (var i = 0, n = array.length; i < n; i++)
1203
- this.push( useNodes ? new this.klass.Node(array[i]) : array[i] );
1204
- },
1205
-
1206
- forEach: function(block, context) {
1207
- if (!block) return this.enumFor('forEach');
1208
- block = JS.Enumerable.toFn(block);
1209
-
1210
- var node = this.first,
1211
- next, i, n;
1212
-
1213
- for (i = 0, n = this.length; i < n; i++) {
1214
- next = node.next;
1215
- block.call(context || null, node, i);
1216
- if (node === this.last) break;
1217
- node = next;
1218
- }
1219
- return this;
1220
- },
1221
-
1222
- at: function(n) {
1223
- if (n < 0 || n >= this.length) return undefined;
1224
- var node = this.first;
1225
- while (n--) node = node.next;
1226
- return node;
1227
- },
1228
-
1229
- pop: function() {
1230
- return this.length ? this.remove(this.last) : undefined;
1231
- },
1232
-
1233
- shift: function() {
1234
- return this.length ? this.remove(this.first) : undefined;
1235
- },
1236
-
1237
- // stubs - should be implemented by concrete list types
1238
- insertAfter: function() {},
1239
- push: function() {},
1240
- remove: function() {},
1241
-
1242
- extend: {
1243
- Node: new JS.Class({
1244
- initialize: function(data) {
1245
- this.data = data;
1246
- this.prev = this.next = this.list = null;
1247
- }
1248
- })
1249
- }
1250
- });
1251
-
1252
- JS.LinkedList.Doubly = new JS.Class('LinkedList.Doubly', JS.LinkedList, {
1253
- insertAt: function(n, newNode) {
1254
- if (n < 0 || n >= this.length) return;
1255
- this.insertBefore(this.at(n), newNode);
1256
- },
1257
-
1258
- unshift: function(newNode) {
1259
- this.length > 0
1260
- ? this.insertBefore(this.first, newNode)
1261
- : this.push(newNode);
1262
- },
1263
-
1264
- insertBefore: function() {}
1265
- });
1266
-
1267
- JS.LinkedList.insertTemplate = function(prev, next, pos) {
1268
- return function(node, newNode) {
1269
- if (node.list !== this) return;
1270
- newNode[prev] = node;
1271
- newNode[next] = node[next];
1272
- node[next] = (node[next][prev] = newNode);
1273
- if (newNode[prev] === this[pos]) this[pos] = newNode;
1274
- newNode.list = this;
1275
- this.length++;
1276
- };
1277
- };
1278
-
1279
- JS.LinkedList.Doubly.Circular = new JS.Class('LinkedList.Doubly.Circular', JS.LinkedList.Doubly, {
1280
- insertAfter: JS.LinkedList.insertTemplate('prev', 'next', 'last'),
1281
- insertBefore: JS.LinkedList.insertTemplate('next', 'prev', 'first'),
1282
-
1283
- push: function(newNode) {
1284
- if (this.length)
1285
- return this.insertAfter(this.last, newNode);
1286
-
1287
- this.first = this.last =
1288
- newNode.prev = newNode.next = newNode;
1289
-
1290
- newNode.list = this;
1291
- this.length = 1;
1292
- },
1293
-
1294
- remove: function(removed) {
1295
- if (removed.list !== this || this.length === 0) return null;
1296
- if (this.length > 1) {
1297
- removed.prev.next = removed.next;
1298
- removed.next.prev = removed.prev;
1299
- if (removed === this.first) this.first = removed.next;
1300
- if (removed === this.last) this.last = removed.prev;
1301
- } else {
1302
- this.first = this.last = null;
1303
- }
1304
- removed.prev = removed.next = removed.list = null;
1305
- this.length--;
1306
- return removed;
1307
- }
1308
- });
1309
-
1310
-
1311
- JS.Hash = new JS.Class('Hash', {
1312
- include: JS.Enumerable || {},
1313
-
1314
- extend: {
1315
- Pair: new JS.Class({
1316
- include: JS.Comparable || {},
1317
-
1318
- setKey: function(key) {
1319
- this[0] = this.key = key;
1320
- },
1321
-
1322
- hasKey: function(key) {
1323
- var my = this.key;
1324
- return my.equals ? my.equals(key) : my === key;
1325
- },
1326
-
1327
- setValue: function(value) {
1328
- this[1] = this.value = value;
1329
- },
1330
-
1331
- hasValue: function(value) {
1332
- var my = this.value;
1333
- return my.equals ? my.equals(value) : my === value;
1334
- },
1335
-
1336
- compareTo: function(other) {
1337
- return this.key.compareTo
1338
- ? this.key.compareTo(other.key)
1339
- : (this.key < other.key ? -1 : (this.key > other.key ? 1 : 0));
1340
- },
1341
-
1342
- hash: function() {
1343
- var key = JS.Hash.codeFor(this.key),
1344
- value = JS.Hash.codeFor(this.value);
1345
-
1346
- return [key, value].sort().join('');
1347
- }
1348
- }),
1349
-
1350
- codeFor: function(object) {
1351
- if (typeof object !== 'object') return String(object);
1352
- return JS.isFn(object.hash)
1353
- ? object.hash()
1354
- : object.toString();
1355
- }
1356
- },
1357
-
1358
- initialize: function(object) {
1359
- this.clear();
1360
- if (!JS.isType(object, Array)) return this.setDefault(object);
1361
- for (var i = 0, n = object.length; i < n; i += 2)
1362
- this.store(object[i], object[i+1]);
1363
- },
1364
-
1365
- forEach: function(block, context) {
1366
- if (!block) return this.enumFor('forEach');
1367
- block = JS.Enumerable.toFn(block);
1368
-
1369
- var hash, bucket, i;
1370
-
1371
- for (hash in this._buckets) {
1372
- if (!this._buckets.hasOwnProperty(hash)) continue;
1373
- bucket = this._buckets[hash];
1374
- i = bucket.length;
1375
- while (i--) block.call(context || null, bucket[i]);
1376
- }
1377
- return this;
1378
- },
1379
-
1380
- _bucketForKey: function(key, createIfAbsent) {
1381
- var hash = this.klass.codeFor(key),
1382
- bucket = this._buckets[hash];
1383
-
1384
- if (!bucket && createIfAbsent)
1385
- bucket = this._buckets[hash] = [];
1386
-
1387
- return bucket;
1388
- },
1389
-
1390
- _indexInBucket: function(bucket, key) {
1391
- var i = bucket.length,
1392
- ident = !!this._compareByIdentity;
1393
-
1394
- while (i--) {
1395
- if (ident ? (bucket[i].key === key) : bucket[i].hasKey(key))
1396
- return i;
1397
- }
1398
- return -1;
1399
- },
1400
-
1401
- assoc: function(key, createIfAbsent) {
1402
- var bucket, index, pair;
1403
-
1404
- bucket = this._bucketForKey(key, createIfAbsent);
1405
- if (!bucket) return null;
1406
-
1407
- index = this._indexInBucket(bucket, key);
1408
- if (index > -1) return bucket[index];
1409
- if (!createIfAbsent) return null;
1410
-
1411
- this.size += 1; this.length += 1;
1412
- pair = new this.klass.Pair;
1413
- pair.setKey(key);
1414
- bucket.push(pair);
1415
- return pair;
1416
- },
1417
-
1418
- rassoc: function(value) {
1419
- var key = this.key(value);
1420
- return key ? this.assoc(key) : null;
1421
- },
1422
-
1423
- clear: function() {
1424
- this._buckets = {};
1425
- this.length = this.size = 0;
1426
- },
1427
-
1428
- compareByIdentity: function() {
1429
- this._compareByIdentity = true;
1430
- },
1431
-
1432
- comparesByIdentity: function() {
1433
- return !!this._compareByIdentity;
1434
- },
1435
-
1436
- setDefault: function(value) {
1437
- this._default = value;
1438
- return this;
1439
- },
1440
-
1441
- getDefault: function(key) {
1442
- return JS.isFn(this._default)
1443
- ? this._default(this, key)
1444
- : (this._default || null);
1445
- },
1446
-
1447
- equals: function(other) {
1448
- if (!JS.isType(other, JS.Hash) || this.length !== other.length)
1449
- return false;
1450
- var result = true;
1451
- this.forEach(function(pair) {
1452
- if (!result) return;
1453
- var otherPair = other.assoc(pair.key);
1454
- if (otherPair === null || !otherPair.hasValue(pair.value)) result = false;
1455
- });
1456
- return result;
1457
- },
1458
-
1459
- hash: function() {
1460
- var hashes = [];
1461
- this.forEach(function(pair) { hashes.push(pair.hash()) });
1462
- return hashes.sort().join('');
1463
- },
1464
-
1465
- fetch: function(key, defaultValue) {
1466
- var pair = this.assoc(key);
1467
- if (pair) return pair.value;
1468
-
1469
- if (defaultValue === undefined) throw new Error('key not found');
1470
- if (JS.isFn(defaultValue)) return defaultValue(key);
1471
- return defaultValue;
1472
- },
1473
-
1474
- forEachKey: function(block, context) {
1475
- if (!block) return this.enumFor('forEachKey');
1476
- block = JS.Enumerable.toFn(block);
1477
-
1478
- this.forEach(function(pair) {
1479
- block.call(context || null, pair.key);
1480
- });
1481
- return this;
1482
- },
1483
-
1484
- forEachPair: function(block, context) {
1485
- if (!block) return this.enumFor('forEachPair');
1486
- block = JS.Enumerable.toFn(block);
1487
-
1488
- this.forEach(function(pair) {
1489
- block.call(context || null, pair.key, pair.value);
1490
- });
1491
- return this;
1492
- },
1493
-
1494
- forEachValue: function(block, context) {
1495
- if (!block) return this.enumFor('forEachValue');
1496
- block = JS.Enumerable.toFn(block);
1497
-
1498
- this.forEach(function(pair) {
1499
- block.call(context || null, pair.value);
1500
- });
1501
- return this;
1502
- },
1503
-
1504
- get: function(key) {
1505
- var pair = this.assoc(key);
1506
- return pair ? pair.value : this.getDefault(key);
1507
- },
1508
-
1509
- hasKey: function(key) {
1510
- return !!this.assoc(key);
1511
- },
1512
-
1513
- hasValue: function(value) {
1514
- var has = false, ident = !!this._compareByIdentity;
1515
- this.forEach(function(pair) {
1516
- if ((value.equals && !ident) ? value.equals(pair.value) : value === pair.value)
1517
- has = true;
1518
- });
1519
- return has;
1520
- },
1521
-
1522
- invert: function() {
1523
- var hash = new this.klass;
1524
- this.forEach(function(pair) {
1525
- hash.store(pair.value, pair.key);
1526
- });
1527
- return hash;
1528
- },
1529
-
1530
- isEmpty: function() {
1531
- for (var hash in this._buckets) {
1532
- if (this._buckets.hasOwnProperty(hash) && this._buckets[hash].length > 0)
1533
- return false;
1534
- }
1535
- return true;
1536
- },
1537
-
1538
- key: function(value) {
1539
- var result = null;
1540
- this.forEach(function(pair) {
1541
- if (value.equals ? value.equals(pair.value) : (value === pair.value))
1542
- result = pair.key;
1543
- });
1544
- return result;
1545
- },
1546
-
1547
- keys: function() {
1548
- var keys = [];
1549
- this.forEach(function(pair) { keys.push(pair.key) });
1550
- return keys;
1551
- },
1552
-
1553
- merge: function(hash, block, context) {
1554
- var newHash = new this.klass;
1555
- newHash.update(this);
1556
- newHash.update(hash, block, context);
1557
- return newHash;
1558
- },
1559
-
1560
- rehash: function() {
1561
- var temp = new this.klass;
1562
- temp._buckets = this._buckets;
1563
- this.clear();
1564
- this.update(temp);
1565
- },
1566
-
1567
- remove: function(key, block) {
1568
- if (block === undefined) block = null;
1569
- var bucket, index, result;
1570
-
1571
- bucket = this._bucketForKey(key);
1572
- if (!bucket) return JS.isFn(block) ? this.fetch(key, block) : this.getDefault(key);
1573
-
1574
- index = this._indexInBucket(bucket, key);
1575
- if (index < 0) return JS.isFn(block) ? this.fetch(key, block) : this.getDefault(key);
1576
-
1577
- result = bucket[index].value;
1578
- bucket.splice(index, 1);
1579
- this.size -= 1;
1580
- this.length -= 1;
1581
-
1582
- if (bucket.length === 0)
1583
- delete this._buckets[this.klass.codeFor(key)];
1584
-
1585
- return result;
1586
- },
1587
-
1588
- removeIf: function(block, context) {
1589
- if (!block) return this.enumFor('removeIf');
1590
- block = JS.Enumerable.toFn(block);
1591
-
1592
- this.forEach(function(pair) {
1593
- if (block.call(context || null, pair))
1594
- this.remove(pair.key);
1595
- }, this);
1596
- return this;
1597
- },
1598
-
1599
- replace: function(hash) {
1600
- this.clear();
1601
- this.update(hash);
1602
- },
1603
-
1604
- shift: function() {
1605
- var keys = this.keys();
1606
- if (keys.length === 0) return this.getDefault();
1607
- var pair = this.assoc(keys[0]);
1608
- this.remove(pair.key);
1609
- return pair;
1610
- },
1611
-
1612
- store: function(key, value) {
1613
- this.assoc(key, true).setValue(value);
1614
- return value;
1615
- },
1616
-
1617
- update: function(hash, block, context) {
1618
- var blockGiven = JS.isFn(block);
1619
- hash.forEach(function(pair) {
1620
- var key = pair.key, value = pair.value;
1621
- if (blockGiven && this.hasKey(key))
1622
- value = block.call(context || null, key, this.get(key), value);
1623
- this.store(key, value);
1624
- }, this);
1625
- },
1626
-
1627
- values: function() {
1628
- var values = [];
1629
- this.forEach(function(pair) { values.push(pair.value) });
1630
- return values;
1631
- },
1632
-
1633
- valuesAt: function() {
1634
- var i = arguments.length, results = [];
1635
- while (i--) results.push(this.get(arguments[i]));
1636
- return results;
1637
- }
1638
- });
1639
-
1640
- JS.Hash.include({
1641
- includes: JS.Hash.instanceMethod('hasKey'),
1642
- index: JS.Hash.instanceMethod('key'),
1643
- put: JS.Hash.instanceMethod('store')
1644
- }, true);
1645
-
1646
-
1647
- JS.Set = new JS.Class('Set', {
1648
- extend: {
1649
- forEach: function(list, block, context) {
1650
- if (!list || !block) return;
1651
- if (list.forEach) return list.forEach(block, context);
1652
- for (var i = 0, n = list.length; i < n; i++) {
1653
- if (list[i] !== undefined)
1654
- block.call(context || null, list[i], i);
1655
- }
1656
- }
1657
- },
1658
-
1659
- include: JS.Enumerable || {},
1660
-
1661
- initialize: function(list, block, context) {
1662
- this.clear();
1663
- if (block) this.klass.forEach(list, function(item) {
1664
- this.add(block.call(context || null, item));
1665
- }, this);
1666
- else this.merge(list);
1667
- },
1668
-
1669
- forEach: function(block, context) {
1670
- if (!block) return this.enumFor('forEach');
1671
- block = JS.Enumerable.toFn(block);
1672
-
1673
- this.klass.forEach(this._members, block, context);
1674
- return this;
1675
- },
1676
-
1677
- add: function(item) {
1678
- if (this.contains(item)) return false;
1679
- this._members.push(item);
1680
- this.length = this.size = this._members.length;
1681
- return true;
1682
- },
1683
-
1684
- classify: function(block, context) {
1685
- if (!block) return this.enumFor('classify');
1686
- block = JS.Enumerable.toFn(block);
1687
-
1688
- var classes = new JS.Hash();
1689
- this.forEach(function(item) {
1690
- var value = block.call(context || null, item);
1691
- if (!classes.hasKey(value)) classes.store(value, new this.klass);
1692
- classes.get(value).add(item);
1693
- }, this);
1694
- return classes;
1695
- },
1696
-
1697
- clear: function() {
1698
- this._members = [];
1699
- this.length = this.size = 0;
1700
- },
1701
-
1702
- complement: function(other) {
1703
- var set = new this.klass;
1704
- this.klass.forEach(other, function(item) {
1705
- if (!this.contains(item)) set.add(item);
1706
- }, this);
1707
- return set;
1708
- },
1709
-
1710
- contains: function(item) {
1711
- return this._indexOf(item) !== -1;
1712
- },
1713
-
1714
- difference: function(other) {
1715
- other = JS.isType(other, JS.Set) ? other : new JS.Set(other);
1716
- var set = new this.klass;
1717
- this.forEach(function(item) {
1718
- if (!other.contains(item)) set.add(item);
1719
- });
1720
- return set;
1721
- },
1722
-
1723
- divide: function(block, context) {
1724
- if (!block) return this.enumFor('divide');
1725
- block = JS.Enumerable.toFn(block);
1726
-
1727
- var classes = this.classify(block, context),
1728
- sets = new this.klass;
1729
-
1730
- classes.forEachValue(sets.method('add'));
1731
- return sets;
1732
- },
1733
-
1734
- equals: function(other) {
1735
- if (this.length !== other.length || !JS.isType(other, JS.Set)) return false;
1736
- var result = true;
1737
- this.forEach(function(item) {
1738
- if (!result) return;
1739
- if (!other.contains(item)) result = false;
1740
- });
1741
- return result;
1742
- },
1743
-
1744
- hash: function() {
1745
- var hashes = [];
1746
- this.forEach(function(object) { hashes.push(JS.Hash.codeFor(object)) });
1747
- return hashes.sort().join('');
1748
- },
1749
-
1750
- flatten: function(set) {
1751
- var copy = new this.klass;
1752
- copy._members = this._members;
1753
- if (!set) { set = this; set.clear(); }
1754
- copy.forEach(function(item) {
1755
- if (JS.isType(item, JS.Set)) item.flatten(set);
1756
- else set.add(item);
1757
- });
1758
- return set;
1759
- },
1760
-
1761
- intersection: function(other) {
1762
- var set = new this.klass;
1763
- this.klass.forEach(other, function(item) {
1764
- if (this.contains(item)) set.add(item);
1765
- }, this);
1766
- return set;
1767
- },
1768
-
1769
- isEmpty: function() {
1770
- return this._members.length === 0;
1771
- },
1772
-
1773
- isProperSubset: function(other) {
1774
- return this._members.length < other._members.length && this.isSubset(other);
1775
- },
1776
-
1777
- isProperSuperset: function(other) {
1778
- return this._members.length > other._members.length && this.isSuperset(other);
1779
- },
1780
-
1781
- isSubset: function(other) {
1782
- var result = true;
1783
- this.forEach(function(item) {
1784
- if (!result) return;
1785
- if (!other.contains(item)) result = false;
1786
- });
1787
- return result;
1788
- },
1789
-
1790
- isSuperset: function(other) {
1791
- return other.isSubset(this);
1792
- },
1793
-
1794
- merge: function(list) {
1795
- this.klass.forEach(list, function(item) { this.add(item) }, this);
1796
- },
1797
-
1798
- product: function(other) {
1799
- var pairs = new JS.Set;
1800
- this.forEach(function(item) {
1801
- this.klass.forEach(other, function(partner) {
1802
- pairs.add([item, partner]);
1803
- });
1804
- }, this);
1805
- return pairs;
1806
- },
1807
-
1808
- rebuild: function() {
1809
- var members = this._members;
1810
- this.clear();
1811
- this.merge(members);
1812
- },
1813
-
1814
- remove: function(item) {
1815
- var index = this._indexOf(item);
1816
- if (index === -1) return;
1817
- this._members.splice(index, 1);
1818
- this.length = this.size = this._members.length;
1819
- },
1820
-
1821
- removeIf: function(block, context) {
1822
- if (!block) return this.enumFor('removeIf');
1823
- block = JS.Enumerable.toFn(block);
1824
-
1825
- var members = this._members,
1826
- i = members.length;
1827
-
1828
- while (i--) {
1829
- if (block.call(context || null, members[i]))
1830
- this.remove(members[i]);
1831
- }
1832
- return this;
1833
- },
1834
-
1835
- replace: function(other) {
1836
- this.clear();
1837
- this.merge(other);
1838
- },
1839
-
1840
- subtract: function(list) {
1841
- this.klass.forEach(list, function(item) {
1842
- this.remove(item);
1843
- }, this);
1844
- },
1845
-
1846
- union: function(other) {
1847
- var set = new this.klass;
1848
- set.merge(this);
1849
- set.merge(other);
1850
- return set;
1851
- },
1852
-
1853
- xor: function(other) {
1854
- var set = new JS.Set(other);
1855
- this.forEach(function(item) {
1856
- set[set.contains(item) ? 'remove' : 'add'](item);
1857
- });
1858
- return set;
1859
- },
1860
-
1861
- _indexOf: function(item) {
1862
- var i = this._members.length,
1863
- equal = JS.Enumerable.areEqual;
1864
-
1865
- while (i--) {
1866
- if (equal(item, this._members[i])) return i;
1867
- }
1868
- return -1;
1869
- }
1870
- });
1871
-
1872
- JS.Set.include({
1873
- n: JS.Set.instanceMethod('intersection'),
1874
- u: JS.Set.instanceMethod('union'),
1875
- x: JS.Set.instanceMethod('product')
1876
- }, false);
1877
-
1878
- JS.SortedSet = new JS.Class('SortedSet', JS.Set, {
1879
- extend: {
1880
- compare: function(one, another) {
1881
- return JS.isType(one, Object)
1882
- ? one.compareTo(another)
1883
- : (one < another ? -1 : (one > another ? 1 : 0));
1884
- }
1885
- },
1886
-
1887
- add: function(item) {
1888
- var point = this._indexOf(item, true);
1889
- if (point === null) return;
1890
- this._members.splice(point, 0, item);
1891
- this.length = this.size = this._members.length;
1892
- },
1893
-
1894
- _indexOf: function(item, insertionPoint) {
1895
- var items = this._members,
1896
- n = items.length,
1897
- i = 0,
1898
- d = n,
1899
- compare = this.klass.compare,
1900
- equal = JS.Enumerable.areEqual,
1901
- found;
1902
-
1903
- if (n === 0) return insertionPoint ? 0 : -1;
1904
-
1905
- if (compare(item, items[0]) < 1) { d = 0; i = 0; }
1906
- if (compare(item, items[n-1]) > 0) { d = 0; i = n; }
1907
-
1908
- while (!equal(item, items[i]) && d > 0.5) {
1909
- d = d / 2;
1910
- i += (compare(item, items[i]) > 0 ? 1 : -1) * Math.round(d);
1911
- if (i > 0 && compare(item, items[i-1]) > 0 && compare(item, items[i]) < 1) d = 0;
1912
- }
1913
-
1914
- // The pointer will end up at the start of any homogenous section. Step
1915
- // through the section until we find the needle or until the section ends.
1916
- while (items[i] && !equal(item, items[i]) &&
1917
- compare(item, items[i]) === 0) i += 1;
1918
-
1919
- found = equal(item, items[i]);
1920
- return insertionPoint
1921
- ? (found ? null : i)
1922
- : (found ? i : -1);
1923
- }
1924
- });
1925
-
1926
- JS.HashSet = new JS.Class('HashSet', JS.Set, {
1927
- forEach: function(block, context) {
1928
- if (!block) return this.enumFor('forEach');
1929
- block = JS.Enumerable.toFn(block);
1930
-
1931
- this._members.forEachKey(block, context);
1932
- return this;
1933
- },
1934
-
1935
- add: function(item) {
1936
- if (this.contains(item)) return false;
1937
- this._members.store(item, true);
1938
- this.length = this.size = this._members.length;
1939
- return true;
1940
- },
1941
-
1942
- clear: function() {
1943
- this._members = new JS.Hash();
1944
- this.size = this.length = 0;
1945
- },
1946
-
1947
- contains: function(item) {
1948
- return this._members.hasKey(item);
1949
- },
1950
-
1951
- rebuild: function() {
1952
- this._members.rehash();
1953
- this.length = this.size = this._members.length;
1954
- },
1955
-
1956
- remove: function(item) {
1957
- this._members.remove(item);
1958
- this.length = this.size = this._members.length;
1959
- },
1960
-
1961
- removeIf: function(block, context) {
1962
- if (!block) return this.enumFor('removeIf');
1963
- block = JS.Enumerable.toFn(block);
1964
-
1965
- this._members.removeIf(function(pair) {
1966
- return block.call(context || null, pair.key);
1967
- });
1968
- this.length = this.size = this._members.length;
1969
- return this;
1970
- }
1971
- });
1972
-
1973
- JS.Enumerable.include({
1974
- toSet: function(klass, block, context) {
1975
- klass = klass || JS.Set;
1976
- return new klass(this, block, context);
1977
- }
1978
- }, true);
1979
-
1980
-
1981
- JS.Observable = new JS.Module('Observable', {
1982
- extend: {
1983
- DEFAULT_METHOD: 'update'
1984
- },
1985
-
1986
- addObserver: function(observer, context) {
1987
- (this.__observers__ = this.__observers__ || []).push({_block: observer, _context: context || null});
1988
- },
1989
-
1990
- removeObserver: function(observer, context) {
1991
- this.__observers__ = this.__observers__ || [];
1992
- context = context || null;
1993
- var i = this.countObservers();
1994
- while (i--) {
1995
- if (this.__observers__[i]._block === observer && this.__observers__[i]._context === context) {
1996
- this.__observers__.splice(i,1);
1997
- return;
1998
- }
1999
- }
2000
- },
2001
-
2002
- removeObservers: function() {
2003
- this.__observers__ = [];
2004
- },
2005
-
2006
- countObservers: function() {
2007
- return (this.__observers__ = this.__observers__ || []).length;
2008
- },
2009
-
2010
- notifyObservers: function() {
2011
- if (!this.isChanged()) return;
2012
- var i = this.countObservers(), observer, block, context;
2013
- while (i--) {
2014
- observer = this.__observers__[i];
2015
- block = observer._block;
2016
- context = observer._context;
2017
- if (JS.isFn(block)) block.apply(context || null, arguments);
2018
- else block[context || JS.Observable.DEFAULT_METHOD].apply(block, arguments);
2019
- }
2020
- },
2021
-
2022
- setChanged: function(state) {
2023
- this.__changed__ = !(state === false);
2024
- },
2025
-
2026
- isChanged: function() {
2027
- if (this.__changed__ === undefined) this.__changed__ = true;
2028
- return !!this.__changed__;
2029
- }
2030
- });
2031
-
2032
- JS.Observable.include({
2033
- subscribe: JS.Observable.instanceMethod('addObserver'),
2034
- unsubscribe: JS.Observable.instanceMethod('removeObserver')
2035
- }, true);
2036
-
2037
-
2038
- JS.Forwardable = new JS.Module('Forwardable', {
2039
- defineDelegator: function(subject, method, alias, resolve) {
2040
- alias = alias || method;
2041
- this.define(alias, function() {
2042
- var object = this[subject],
2043
- property = object[method];
2044
-
2045
- return JS.isFn(property)
2046
- ? property.apply(object, arguments)
2047
- : property;
2048
- }, resolve !== false);
2049
- },
2050
-
2051
- defineDelegators: function() {
2052
- var methods = JS.array(arguments),
2053
- subject = methods.shift(),
2054
- i = methods.length;
2055
-
2056
- while (i--) this.defineDelegator(subject, methods[i], methods[i], false);
2057
- this.resolve();
2058
- }
2059
- });
2060
-
2061
-
2062
- JS.ConstantScope = new JS.Module('ConstantScope', {
2063
- extend: {
2064
- included: function(base) {
2065
- base.__consts__ = new JS.Module();
2066
- base.extend(this.ClassMethods);
2067
-
2068
- base.include(base.__consts__);
2069
- base.extend(base.__consts__);
2070
-
2071
- base.include(base.__mod__.__fns__);
2072
- base.extend(base.__eigen__().__fns__);
2073
- },
2074
-
2075
- ClassMethods: new JS.Module({
2076
- extend: function() {
2077
- var constants = JS.ConstantScope.extract(arguments[0], this);
2078
- this.__consts__.include(constants);
2079
- this.callSuper();
2080
- },
2081
-
2082
- include: function() {
2083
- var constants = JS.ConstantScope.extract(arguments[0], this);
2084
- this.__consts__.include(constants);
2085
- this.callSuper();
2086
- }
2087
- }),
2088
-
2089
- extract: function(inclusions, base) {
2090
- if (!inclusions) return null;
2091
- if (JS.isType(inclusions, JS.Module)) return null;
2092
- var constants = {}, key, object;
2093
- for (key in inclusions) {
2094
-
2095
- if (!/^[A-Z]/.test(key)) continue;
2096
-
2097
- object = inclusions[key];
2098
- constants[key] = object;
2099
- delete inclusions[key];
2100
-
2101
- if (JS.isType(object, JS.Module)) {
2102
- object.include(this);
2103
- object.__consts__.include(base.__consts__);
2104
- }
2105
- }
2106
- return constants;
2107
- }
2108
- }
2109
- });
2110
-
2111
-
2112
- JS.Decorator = new JS.Class('Decorator', {
2113
- initialize: function(decoree, methods) {
2114
- var decorator = new JS.Class(),
2115
- delegators = {},
2116
- method, func;
2117
-
2118
- for (method in decoree.prototype) {
2119
- func = decoree.prototype[method];
2120
- if (JS.isFn(func) && func !== decoree) func = this.klass.delegate(method);
2121
- delegators[method] = func;
2122
- }
2123
-
2124
- decorator.include(new JS.Module(delegators), false);
2125
- decorator.include(this.klass.InstanceMethods, false);
2126
- decorator.include(methods, true);
2127
- return decorator;
2128
- },
2129
-
2130
- extend: {
2131
- delegate: function(name) {
2132
- return function() {
2133
- return this.component[name].apply(this.component, arguments);
2134
- };
2135
- },
2136
-
2137
- InstanceMethods: new JS.Module({
2138
- initialize: function(component) {
2139
- this.component = component;
2140
- this.klass = this.constructor = component.klass;
2141
- var method, func;
2142
- for (method in component) {
2143
- if (this[method]) continue;
2144
- func = component[method];
2145
- if (JS.isFn(func)) func = JS.Decorator.delegate(method);
2146
- this[method] = func;
2147
- }
2148
- },
2149
-
2150
- extend: function(source) {
2151
- this.component.extend(source);
2152
- var method, func;
2153
- for (method in source) {
2154
- func = source[method];
2155
- if (JS.isFn(func)) func = JS.Decorator.delegate(method);
2156
- this[method] = func;
2157
- }
2158
- }
2159
- })
2160
- }
2161
- });
2162
-
2163
-
2164
- if (JS.Proxy === undefined) JS.Proxy = {};
2165
-
2166
- JS.Proxy.Virtual = new JS.Class('Proxy.Virtual', {
2167
- initialize: function(klass) {
2168
- var bridge = function() {},
2169
- proxy = new JS.Class(),
2170
- delegators = {},
2171
- method, func;
2172
-
2173
- bridge.prototype = klass.prototype;
2174
-
2175
- for (method in klass.prototype) {
2176
- func = klass.prototype[method];
2177
- if (JS.isFn(func) && func !== klass) func = this.klass.forward(method);
2178
- delegators[method] = func;
2179
- }
2180
-
2181
- proxy.include({
2182
- initialize: function() {
2183
- var args = arguments,
2184
- subject = null;
2185
-
2186
- this.__getSubject__ = function() {
2187
- subject = new bridge;
2188
- klass.apply(subject, args);
2189
- return (this.__getSubject__ = function() { return subject; })();
2190
- };
2191
- },
2192
- klass: klass,
2193
- constructor: klass
2194
- }, false);
2195
-
2196
- proxy.include(new JS.Module(delegators), false);
2197
- proxy.include(this.klass.InstanceMethods, true);
2198
- return proxy;
2199
- },
2200
-
2201
- extend: {
2202
- forward: function(name) {
2203
- return function() {
2204
- var subject = this.__getSubject__();
2205
- return subject[name].apply(subject, arguments);
2206
- };
2207
- },
2208
-
2209
- InstanceMethods: new JS.Module({
2210
- extend: function(source) {
2211
- this.__getSubject__().extend(source);
2212
- var method, func;
2213
- for (method in source) {
2214
- func = source[method];
2215
- if (JS.isFn(func)) func = JS.Proxy.Virtual.forward(method);
2216
- this[method] = func;
2217
- }
2218
- }
2219
- })
2220
- }
2221
- });
2222
-
2223
-
2224
- JS.Command = new JS.Class('Command', {
2225
- initialize: function(functions) {
2226
- if (JS.isFn(functions))
2227
- functions = {execute: functions};
2228
- this._functions = functions;
2229
- this._stack = this._functions.stack || null;
2230
- },
2231
-
2232
- execute: function(push) {
2233
- if (this._stack) this._stack._restart();
2234
- var exec = this._functions.execute;
2235
- if (exec) exec.apply(this);
2236
- if (this._stack && push !== false) this._stack.push(this);
2237
- },
2238
-
2239
- undo: function() {
2240
- var exec = this._functions.undo;
2241
- if (exec) exec.apply(this);
2242
- },
2243
-
2244
- extend: {
2245
- Stack: new JS.Class({
2246
- include: [JS.Observable || {}, JS.Enumerable || {}],
2247
-
2248
- initialize: function(options) {
2249
- options = options || {};
2250
- this._redo = options.redo || null;
2251
- this.clear();
2252
- },
2253
-
2254
- forEach: function(block, context) {
2255
- if (!block) return this.enumFor('forEach');
2256
- block = JS.Enumerable.toFn(block);
2257
-
2258
- for (var i = 0, n = this._stack.length; i < n; i++) {
2259
- if (this._stack[i] !== undefined)
2260
- block.call(context || null, this._stack[i], i);
2261
- }
2262
- return this;
2263
- },
2264
-
2265
- clear: function() {
2266
- this._stack = [];
2267
- this.length = this.pointer = 0;
2268
- },
2269
-
2270
- _restart: function() {
2271
- if (this.pointer === 0 && this._redo && this._redo.execute)
2272
- this._redo.execute();
2273
- },
2274
-
2275
- push: function(command) {
2276
- this._stack.splice(this.pointer, this.length);
2277
- this._stack.push(command);
2278
- this.length = this.pointer = this._stack.length;
2279
- if (this.notifyObservers) this.notifyObservers(this);
2280
- },
2281
-
2282
- stepTo: function(position) {
2283
- if (position < 0 || position > this.length) return;
2284
- var i, n;
2285
-
2286
- switch (true) {
2287
- case position > this.pointer :
2288
- for (i = this.pointer, n = position; i < n; i++)
2289
- this._stack[i].execute(false);
2290
- break;
2291
-
2292
- case position < this.pointer :
2293
- if (this._redo && this._redo.execute) {
2294
- this._redo.execute();
2295
- for (i = 0, n = position; i < n; i++)
2296
- this._stack[i].execute(false);
2297
- } else {
2298
- for (i = 0, n = this.pointer - position; i < n; i++)
2299
- this._stack[this.pointer - i - 1].undo();
2300
- }
2301
- break;
2302
- }
2303
- this.pointer = position;
2304
- if (this.notifyObservers) this.notifyObservers(this);
2305
- },
2306
-
2307
- undo: function() {
2308
- this.stepTo(this.pointer - 1);
2309
- },
2310
-
2311
- redo: function() {
2312
- this.stepTo(this.pointer + 1);
2313
- }
2314
- })
2315
- }
2316
- });
2317
-
2318
-
2319
- JS.State = new JS.Module('State', {
2320
- __getState__: function(state) {
2321
- return (typeof state === 'object' && state) ||
2322
- (typeof state === 'string' && ((this.states || {})[state] || {})) ||
2323
- {};
2324
- },
2325
-
2326
- setState: function(state) {
2327
- this.__state__ = this.__getState__(state);
2328
- JS.State.addMethods(this.__state__, this.klass);
2329
- },
2330
-
2331
- inState: function() {
2332
- var i = arguments.length;
2333
- while (i--) {
2334
- if (this.__state__ === this.__getState__(arguments[i])) return true;
2335
- }
2336
- return false;
2337
- },
2338
-
2339
- extend: {
2340
- stub: function() { return this; },
2341
-
2342
- buildStubs: function(stubs, collection, states) {
2343
- var state, method;
2344
- for (state in states) {
2345
- collection[state] = {};
2346
- for (method in states[state]) stubs[method] = this.stub;
2347
- } },
2348
-
2349
- findStates: function(collections, name) {
2350
- var i = collections.length, results = [];
2351
- while (i--) {
2352
- if (collections[i].hasOwnProperty(name))
2353
- results.push(collections[i][name]);
2354
- }
2355
- return results;
2356
- },
2357
-
2358
- buildCollection: function(module, states) {
2359
- var stubs = {},
2360
- collection = {},
2361
- superstates = module.lookup('states'),
2362
- state, klass, methods, name, mixins, i, n;
2363
-
2364
- this.buildStubs(stubs, collection, states);
2365
-
2366
- for (i = 0, n = superstates.length; i < n; i++)
2367
- this.buildStubs(stubs, collection, superstates[i]);
2368
-
2369
- for (state in collection) {
2370
- klass = new JS.Class(states[state]);
2371
- mixins = this.findStates(superstates, state);
2372
-
2373
- i = mixins.length;
2374
- while (i--) klass.include(mixins[i].klass);
2375
-
2376
- methods = {};
2377
- for (name in stubs) { if (!klass.prototype[name]) methods[name] = stubs[name]; }
2378
- klass.include(methods);
2379
- collection[state] = new klass;
2380
- }
2381
- if (module.__res__) this.addMethods(stubs, module.__res__.klass);
2382
- return collection;
2383
- },
2384
-
2385
- addMethods: function(state, klass) {
2386
- if (!klass) return;
2387
-
2388
- var methods = {},
2389
- p = klass.prototype,
2390
- method;
2391
-
2392
- for (method in state) {
2393
- if (p[method]) continue;
2394
- p[method] = klass.__mod__.__fns__[method] = this.wrapped(method);
2395
- }
2396
- },
2397
-
2398
- wrapped: function(method) {
2399
- return function() {
2400
- var func = (this.__state__ || {})[method];
2401
- return func ? func.apply(this, arguments): this;
2402
- };
2403
- }
2404
- }
2405
- });
2406
-
2407
- JS.Module.include({define: (function(wrapped) {
2408
- return function(name, block) {
2409
- if (name === 'states' && typeof block === 'object')
2410
- arguments[1] = JS.State.buildCollection(this, block);
2411
- return wrapped.apply(this, arguments);
2412
- };
2413
- })(JS.Module.prototype.define)}, true);
2414
-
2415
-
2416
- JS.StackTrace = new JS.Module('StackTrace', {
2417
- extend: {
2418
- included: function(base) {
2419
- var module = base.__mod__ || base,
2420
- self = this,
2421
- method;
2422
-
2423
- module.extend({define: function(name, func) {
2424
- if (!JS.isFn(func)) return this.callSuper();
2425
- var wrapper = self.wrap(func, module, name);
2426
- return this.callSuper(name, wrapper);
2427
- } });
2428
-
2429
- for (method in module.__fns__)
2430
- module.define(method, module.__fns__[method], false);
2431
- module.resolve();
2432
-
2433
- if (!module.__nom__) setTimeout(function() {
2434
- module.__nom__ = self.nameOf(base);
2435
- }, 1);
2436
- },
2437
-
2438
- nameOf: function(object, root) {
2439
- var results = [], i, n, field, l;
2440
-
2441
- if (JS.isType(object, Array)) {
2442
- for (i = 0, n = object.length; i < n; i++)
2443
- results.push(this.nameOf(object[i]));
2444
- return results;
2445
- }
2446
-
2447
- if (object.__nom__) return object.__nom__;
2448
-
2449
- field = [{name: null, o: root || this.root}];
2450
- l = 0;
2451
- while (typeof field === 'object' && l < this.maxDepth) {
2452
- l += 1;
2453
- field = this.descend(field, object);
2454
- }
2455
- if (typeof field == 'string') {
2456
- field = field.replace(/\.prototype\./g, '#');
2457
- object.__nom__ = field;
2458
- if (object.__meta__) object.__meta__.__nom__ = field + '.__meta__';
2459
- }
2460
- return object.__nom__;
2461
- },
2462
-
2463
- descend: function(list, needle) {
2464
- var results = [],
2465
- n = list.length,
2466
- i = n,
2467
- key, item, name;
2468
-
2469
- while (i--) {
2470
- item = list[i];
2471
- if (n > 1 && JS.indexOf(this.excluded, item.o) !== -1) continue;
2472
- if (JS.isType(item.o, Array)) continue;
2473
- name = item.name ? item.name + '.' : '';
2474
- for (key in item.o) {
2475
- if (needle && item.o[key] === needle) return name + key;
2476
- results.push({name: name + key, o: item.o[key]});
2477
- }
2478
- }
2479
- return results;
2480
- },
2481
-
2482
- root: this,
2483
- excluded: [],
2484
- maxDepth: 8,
2485
- logLevel: 'full',
2486
-
2487
- stack: new JS.Singleton({
2488
- _list: [],
2489
-
2490
- indent: function() {
2491
- var indent = '',
2492
- n = this._list.length;
2493
-
2494
- while (n--) indent += '| ';
2495
- return indent;
2496
- },
2497
-
2498
- push: function(name, object, args) {
2499
- if (JS.StackTrace.logLevel === 'full') window.console &&
2500
- console.log(this.indent() + name + '(', args, ')');
2501
- this._list.push({name: name, object: object, args: args});
2502
- },
2503
-
2504
- pop: function(result) {
2505
- var name = this._list.pop().name;
2506
- if (JS.StackTrace.logLevel === 'full') window.console &&
2507
- console.log(this.indent() + name + '() --> ', result);
2508
- return name;
2509
- },
2510
-
2511
- top: function() {
2512
- return this._list[this._list.length - 1] || {};
2513
- },
2514
-
2515
- backtrace: function() {
2516
- var i = this._list.length, item;
2517
- while (i--) {
2518
- item = this._list[i];
2519
- window.console && console.log(item.name, 'in', item.object, '(', item.args, ')');
2520
- }
2521
- }
2522
- }),
2523
-
2524
- flush: function() {
2525
- this.stack._list = [];
2526
- },
2527
-
2528
- print: function() {
2529
- this.stack.backtrace();
2530
- },
2531
-
2532
- wrap: function(func, module, name) {
2533
- var self = JS.StackTrace;
2534
- var wrapper = function() {
2535
- var result, fullName = self.nameOf(module) + '#' + name;
2536
- self.stack.push(fullName, this, arguments);
2537
-
2538
- if (self.logLevel === 'errors') {
2539
- try { result = func.apply(this, arguments); }
2540
- catch (e) {
2541
- if (e.logged) throw e;
2542
- e.logged = true;
2543
- window.console && console.error(e, 'thrown by', self.stack.top().name + '. Backtrace:');
2544
- self.print();
2545
- self.flush();
2546
- throw e;
2547
- }
2548
- } else {
2549
- result = func.apply(this, arguments);
2550
- }
2551
-
2552
- self.stack.pop(result);
2553
- return result;
2554
- };
2555
- wrapper.toString = function() { return func.toString() };
2556
- return wrapper;
2557
- }
2558
- }
2559
- });
2560
-
2561
- (function() {
2562
- var module = JS.StackTrace, key;
2563
- for (key in module.root) {
2564
- if (key !== 'JS') module.excluded.push(module.root[key]);
2565
- }
2566
- })();
2567
-
2568
-
2569
- JS.Ruby = function(klass, define) {
2570
- define.call(new JS.Ruby.ClassBuilder(klass));
2571
- };
2572
-
2573
- JS.extend(JS.Ruby, {
2574
- extendDSL: function(builder, source) {
2575
- for (var method in source) {
2576
- if (builder[method] || !JS.isFn(source[method])) continue;
2577
- this.addMethod(builder, source, method);
2578
- }
2579
- },
2580
-
2581
- addMethod: function(builder, source, method) {
2582
- builder[method] = function() {
2583
- var result = source[method].apply(source, arguments);
2584
- JS.Ruby.extendDSL(builder, source);
2585
- return result;
2586
- };
2587
- },
2588
-
2589
- alias: function(object, builder) {
2590
- return function(newName, oldName) {
2591
- var old = object[oldName];
2592
- if (old !== undefined) this.def(newName, old);
2593
- if (builder) JS.Ruby.extendDSL(builder, object);
2594
- };
2595
- },
2596
-
2597
- ClassBuilder: function(klass) {
2598
- this.def = klass.method('define');
2599
- this.alias = JS.Ruby.alias(klass.prototype);
2600
-
2601
- this.self = {
2602
- def: JS.bind(function(name, method) {
2603
- var def = {}; def[name] = method;
2604
- klass.extend(def);
2605
- JS.Ruby.extendDSL(this, klass);
2606
- }, this),
2607
- alias: JS.Ruby.alias(klass, this)
2608
- };
2609
-
2610
- JS.Ruby.extendDSL(this, klass);
2611
- }
2612
- });