sproutcore 1.7.1.beta → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (445) hide show
  1. data/CHANGELOG +44 -0
  2. data/README.rdoc +20 -20
  3. data/VERSION.yml +3 -3
  4. data/lib/Buildfile +1 -1
  5. data/lib/buildtasks/build.rake +5 -0
  6. data/lib/buildtasks/manifest.rake +19 -1
  7. data/lib/frameworks/sproutcore/Buildfile +19 -17
  8. data/lib/frameworks/sproutcore/CHANGELOG.md +163 -29
  9. data/lib/frameworks/sproutcore/README.md +29 -8
  10. data/lib/frameworks/sproutcore/apps/statechart_routing/Buildfile +12 -0
  11. data/lib/frameworks/sproutcore/apps/statechart_routing/controllers/login_controller.js +11 -0
  12. data/lib/frameworks/sproutcore/apps/statechart_routing/controllers/main_controller.js +7 -0
  13. data/lib/frameworks/sproutcore/apps/statechart_routing/controllers/statechart_controller.js +17 -0
  14. data/lib/frameworks/sproutcore/apps/statechart_routing/core.js +25 -0
  15. data/lib/frameworks/sproutcore/apps/statechart_routing/main.js +15 -0
  16. data/lib/frameworks/sproutcore/apps/statechart_routing/resources/_theme.css +18 -0
  17. data/lib/frameworks/sproutcore/apps/statechart_routing/resources/bar_page.js +14 -0
  18. data/lib/frameworks/sproutcore/apps/statechart_routing/resources/foo_page.js +14 -0
  19. data/lib/frameworks/sproutcore/apps/statechart_routing/resources/loading.rhtml +9 -0
  20. data/lib/frameworks/sproutcore/apps/statechart_routing/resources/login_page.js +61 -0
  21. data/lib/frameworks/sproutcore/apps/statechart_routing/resources/main_page.js +46 -0
  22. data/lib/frameworks/sproutcore/apps/statechart_routing/statechart.js +76 -0
  23. data/lib/frameworks/sproutcore/apps/statechart_routing/theme.js +27 -0
  24. data/lib/frameworks/sproutcore/apps/tests/controllers/targets.js +1 -1
  25. data/lib/frameworks/sproutcore/apps/tests/states/no_targets.js +1 -1
  26. data/lib/frameworks/sproutcore/apps/tests/states/ready_detail.js +1 -1
  27. data/lib/frameworks/sproutcore/apps/tests/states/ready_empty.js +1 -1
  28. data/lib/frameworks/sproutcore/apps/tests/states/ready_list.js +1 -1
  29. data/lib/frameworks/sproutcore/apps/tests/states/ready_no_tests.js +1 -1
  30. data/lib/frameworks/sproutcore/apps/welcome/controllers/targets.js +1 -1
  31. data/lib/frameworks/sproutcore/frameworks/ajax/system/request.js +14 -1
  32. data/lib/frameworks/sproutcore/frameworks/ajax/system/response.js +15 -15
  33. data/lib/frameworks/sproutcore/frameworks/ajax/tests/system/request.js +1 -1
  34. data/lib/frameworks/sproutcore/frameworks/animation/core.js +8 -5
  35. data/lib/frameworks/sproutcore/frameworks/bootstrap/system/browser.js +302 -70
  36. data/lib/frameworks/sproutcore/frameworks/bootstrap/system/loader.js +19 -14
  37. data/lib/frameworks/sproutcore/frameworks/bootstrap/tests/system/browser.js +471 -149
  38. data/lib/frameworks/sproutcore/frameworks/core_foundation/controllers/array.js +3 -3
  39. data/lib/frameworks/sproutcore/frameworks/core_foundation/ext/object.js +42 -0
  40. data/lib/frameworks/sproutcore/frameworks/core_foundation/ext/run_loop.js +3 -2
  41. data/lib/frameworks/sproutcore/frameworks/core_foundation/ext/string.js +7 -0
  42. data/lib/frameworks/sproutcore/frameworks/core_foundation/mixins/action_support.js +1 -1
  43. data/lib/frameworks/sproutcore/frameworks/core_foundation/mixins/delegate_support.js +2 -2
  44. data/lib/frameworks/sproutcore/frameworks/core_foundation/mixins/responder_context.js +3 -3
  45. data/lib/frameworks/sproutcore/frameworks/core_foundation/mixins/selection_support.js +1 -1
  46. data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/body_overflow.js +63 -0
  47. data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/keyboard.js +1 -1
  48. data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/layout.js +37 -2
  49. data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/main.js +28 -6
  50. data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/pane.js +10 -3
  51. data/lib/frameworks/sproutcore/frameworks/core_foundation/protocols/sparse_array_delegate.js +2 -2
  52. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/browser.js +66 -2
  53. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/builder.js +1 -1
  54. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/cursor.js +1 -1
  55. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/event.js +58 -57
  56. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/locale.js +1 -1
  57. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/locale.js.orig +445 -0
  58. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/platform.js +51 -31
  59. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/ready.js +5 -1
  60. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/render_context.js +53 -69
  61. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/responder.js +1 -1
  62. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/root_responder.js +98 -72
  63. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/string.js +37 -3
  64. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/timer.js +7 -4
  65. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/controllers/array/array_case.js +21 -0
  66. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/controllers/object/content_destroyed.js +7 -7
  67. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/mixins/string.js +23 -1
  68. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/browser.js +66 -0
  69. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/event.js +22 -0
  70. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/locale.js +11 -11
  71. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/render_context/end.js +4 -4
  72. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/render_context/escape_html.js +41 -0
  73. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/render_context/helpers_className.js +1 -1
  74. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/render_context/helpers_style.js +8 -8
  75. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/render_context/update.js +17 -16
  76. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/selection_set/remove.js +1 -1
  77. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/build_children.js +1 -1
  78. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/class_name_bindings_test.js +15 -0
  79. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/createChildViews.js +5 -5
  80. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view.js +50 -30
  81. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/acceleration.js +46 -0
  82. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/animation.js +1 -43
  83. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/keyboard.js +8 -34
  84. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/layout.js +3 -2
  85. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/layout_style.js +10 -1
  86. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/manipulation.js +6 -5
  87. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/theming.js +22 -2
  88. data/lib/frameworks/sproutcore/frameworks/datastore/data_sources/data_source.js +2 -2
  89. data/lib/frameworks/sproutcore/frameworks/datastore/mixins/relationship_support.js +1 -1
  90. data/lib/frameworks/sproutcore/frameworks/datastore/models/child_attribute.js +0 -2
  91. data/lib/frameworks/sproutcore/frameworks/datastore/models/children_attribute.js +35 -0
  92. data/lib/frameworks/sproutcore/frameworks/datastore/models/record.js +46 -19
  93. data/lib/frameworks/sproutcore/frameworks/datastore/models/record_attribute.js +23 -9
  94. data/lib/frameworks/sproutcore/frameworks/datastore/models/single_attribute.js +2 -3
  95. data/lib/frameworks/sproutcore/frameworks/datastore/system/many_array.js +1 -1
  96. data/lib/frameworks/sproutcore/frameworks/datastore/system/nested_store.js +2 -2
  97. data/lib/frameworks/sproutcore/frameworks/datastore/system/query.js +294 -302
  98. data/lib/frameworks/sproutcore/frameworks/datastore/system/query.js.orig +1531 -0
  99. data/lib/frameworks/sproutcore/frameworks/datastore/system/record_array.js +4 -2
  100. data/lib/frameworks/sproutcore/frameworks/datastore/system/store.js +14 -11
  101. data/lib/frameworks/sproutcore/frameworks/datastore/tests/integration/many_array.js +63 -0
  102. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/many_attribute.js +1 -1
  103. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/nested_records/nested_record.js +4 -4
  104. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/nested_records/nested_record_array.js +50 -10
  105. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/nested_records/nested_record_array_complex.js +4 -4
  106. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/nested_records/nested_record_complex.js +3 -3
  107. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/record/destroy.js +1 -1
  108. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/record/refresh.js +1 -1
  109. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/record_attribute.js +1 -1
  110. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/single_attribute.js +114 -67
  111. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/commitChangesFromNestedStore.js +1 -1
  112. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/readDataHash.js +1 -1
  113. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/query/compare.js +54 -1
  114. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/query/evaluation.js +29 -9
  115. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/query/parse.js +1 -1
  116. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/record_array/core_methods.js +1 -1
  117. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/record_array/flush.js +1 -1
  118. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/cancelRecord.js +1 -1
  119. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/commitChangesFromNestedStore.js +1 -1
  120. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/commitRecord.js +37 -45
  121. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/find.js +127 -127
  122. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/pushChanges.js +16 -0
  123. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/pushRelationships.js +42 -4
  124. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/readDataHash.js +1 -1
  125. data/lib/frameworks/sproutcore/frameworks/datetime/frameworks/core/system/datetime.js +13 -7
  126. data/lib/frameworks/sproutcore/frameworks/datetime/frameworks/core/tests/system/datetime.js +8 -0
  127. data/lib/frameworks/sproutcore/frameworks/datetime/frameworks/localized/resources/strings.js +2 -1
  128. data/lib/frameworks/sproutcore/frameworks/datetime/frameworks/localized/system/datetime.js +1 -0
  129. data/lib/frameworks/sproutcore/frameworks/debug/core.js +3 -3
  130. data/lib/frameworks/sproutcore/frameworks/desktop/core.js +1 -1
  131. data/lib/frameworks/sproutcore/frameworks/desktop/mixins/collection_row_delegate.js +1 -1
  132. data/lib/frameworks/sproutcore/frameworks/desktop/mixins/collection_view_delegate.js +1 -1
  133. data/lib/frameworks/sproutcore/frameworks/desktop/panes/alert.js +1 -4
  134. data/lib/frameworks/sproutcore/frameworks/desktop/panes/menu.js +19 -6
  135. data/lib/frameworks/sproutcore/frameworks/desktop/panes/modal.js +30 -1
  136. data/lib/frameworks/sproutcore/frameworks/desktop/panes/palette.js +1 -1
  137. data/lib/frameworks/sproutcore/frameworks/desktop/panes/panel.js +24 -1
  138. data/lib/frameworks/sproutcore/frameworks/desktop/panes/picker.js +121 -28
  139. data/lib/frameworks/sproutcore/frameworks/desktop/panes/sheet.js +15 -15
  140. data/lib/frameworks/sproutcore/frameworks/desktop/protocols/drag_data_source.js +1 -1
  141. data/lib/frameworks/sproutcore/frameworks/desktop/protocols/drop_target.js +2 -2
  142. data/lib/frameworks/sproutcore/frameworks/desktop/protocols/responder.js +2 -2
  143. data/lib/frameworks/sproutcore/frameworks/desktop/render_delegates/button.js +39 -15
  144. data/lib/frameworks/sproutcore/frameworks/desktop/render_delegates/collection.js +3 -3
  145. data/lib/frameworks/sproutcore/frameworks/desktop/render_delegates/disclosure.js +2 -2
  146. data/lib/frameworks/sproutcore/frameworks/desktop/render_delegates/image_button.js +2 -2
  147. data/lib/frameworks/sproutcore/frameworks/desktop/render_delegates/panel.js +14 -6
  148. data/lib/frameworks/sproutcore/frameworks/desktop/render_delegates/popup_button.js +3 -3
  149. data/lib/frameworks/sproutcore/frameworks/desktop/render_delegates/progress.js +11 -11
  150. data/lib/frameworks/sproutcore/frameworks/desktop/render_delegates/segment.js +4 -3
  151. data/lib/frameworks/sproutcore/frameworks/desktop/render_delegates/segmented.js +1 -51
  152. data/lib/frameworks/sproutcore/frameworks/desktop/render_delegates/slider.js +11 -16
  153. data/lib/frameworks/sproutcore/frameworks/desktop/resources/images/icons/sc-icon-error-48.png +0 -0
  154. data/lib/frameworks/sproutcore/frameworks/desktop/resources/slider.css +0 -2
  155. data/lib/frameworks/sproutcore/frameworks/desktop/system/drag.js +3 -3
  156. data/lib/frameworks/sproutcore/frameworks/desktop/system/undo_manager.js +3 -3
  157. data/lib/frameworks/sproutcore/frameworks/desktop/tests/panes/alert/ui.js +9 -9
  158. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/button/content.js +11 -11
  159. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/button/ui.js +2 -1
  160. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/collection/reload.js +1 -1
  161. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/date_field/ui.js +107 -81
  162. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/list/rowDelegate.js +3 -3
  163. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/progress/ui.js +68 -60
  164. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/radio/methods.js +57 -12
  165. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/scroll/integration.js +21 -19
  166. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/scroller.js +5 -0
  167. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/segmented/ui.js +2 -2
  168. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/select/ui.js +32 -3
  169. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/split/methods.js +12 -0
  170. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/stacked/ui_comments.js +12 -0
  171. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/tab/methods.js +0 -8
  172. data/lib/frameworks/sproutcore/frameworks/desktop/views/button.js +77 -132
  173. data/lib/frameworks/sproutcore/frameworks/desktop/views/checkbox.js +5 -6
  174. data/lib/frameworks/sproutcore/frameworks/desktop/views/collection.js +16 -15
  175. data/lib/frameworks/sproutcore/frameworks/desktop/views/date_field.js +52 -52
  176. data/lib/frameworks/sproutcore/frameworks/desktop/views/disclosure.js +1 -1
  177. data/lib/frameworks/sproutcore/frameworks/desktop/views/grid.js +1 -1
  178. data/lib/frameworks/sproutcore/frameworks/desktop/views/list.js +147 -147
  179. data/lib/frameworks/sproutcore/frameworks/desktop/views/list_item.js +11 -2
  180. data/lib/frameworks/sproutcore/frameworks/desktop/views/menu_item.js +2 -2
  181. data/lib/frameworks/sproutcore/frameworks/desktop/views/menu_scroll.js +5 -5
  182. data/lib/frameworks/sproutcore/frameworks/desktop/views/popup_button.js +22 -12
  183. data/lib/frameworks/sproutcore/frameworks/desktop/views/radio.js +13 -7
  184. data/lib/frameworks/sproutcore/frameworks/desktop/views/scene.js +2 -2
  185. data/lib/frameworks/sproutcore/frameworks/desktop/views/scroll.js +462 -441
  186. data/lib/frameworks/sproutcore/frameworks/desktop/views/scroller.js +48 -62
  187. data/lib/frameworks/sproutcore/frameworks/desktop/views/segment.js +22 -2
  188. data/lib/frameworks/sproutcore/frameworks/desktop/views/segmented.js +150 -32
  189. data/lib/frameworks/sproutcore/frameworks/desktop/views/select.js +104 -45
  190. data/lib/frameworks/sproutcore/frameworks/desktop/views/select_button.js +42 -20
  191. data/lib/frameworks/sproutcore/frameworks/desktop/views/slider.js +24 -24
  192. data/lib/frameworks/sproutcore/frameworks/desktop/views/split.js +148 -154
  193. data/lib/frameworks/sproutcore/frameworks/desktop/views/stacked.js +2 -2
  194. data/lib/frameworks/sproutcore/frameworks/desktop/views/static_content.js +2 -2
  195. data/lib/frameworks/sproutcore/frameworks/desktop/views/tab.js +8 -7
  196. data/lib/frameworks/sproutcore/frameworks/desktop/views/web.js +2 -2
  197. data/lib/frameworks/sproutcore/frameworks/experimental/Buildfile +2 -0
  198. data/lib/frameworks/sproutcore/frameworks/experimental/apps/greenhouse/controllers/files.js +1 -1
  199. data/lib/frameworks/sproutcore/frameworks/experimental/apps/greenhouse/controllers/library.js +1 -1
  200. data/lib/frameworks/sproutcore/frameworks/experimental/apps/greenhouse/controllers/targets.js +1 -1
  201. data/lib/frameworks/sproutcore/frameworks/experimental/apps/greenhouse/controllers/view_configs.js +1 -1
  202. data/lib/frameworks/sproutcore/frameworks/experimental/apps/greenhouse/mixins/drop_down.js +1 -1
  203. data/lib/frameworks/sproutcore/frameworks/experimental/apps/greenhouse/states/ready.js +1 -1
  204. data/lib/frameworks/sproutcore/frameworks/experimental/apps/greenhouse/views/plist_item.js +1 -1
  205. data/lib/frameworks/sproutcore/frameworks/experimental/apps/greenhouse/views/web.js +1 -1
  206. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/designer/controllers/page_design.js +2 -2
  207. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/designer/css/css_style_sheet.js +2 -2
  208. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/designer/designers/object_designer.js +1 -1
  209. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/designer/designers/view_designer.js +2 -2
  210. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/designer/mixins/snap_lines.js +3 -3
  211. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/designer/views/designer_drop_target.js +1 -1
  212. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/designer/views/drawing.js +21 -21
  213. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/designer/views/page_item_view.js +1 -1
  214. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/forms/views/form.js +59 -53
  215. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/menu/views/menu/scroll.js +2 -2
  216. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/polymorphism/tests/models/polymorphism/simple.js +1 -1
  217. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/core_scroll.js +6 -6
  218. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/desktop/scroll.js +2 -2
  219. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/touch/scroll.js +2 -2
  220. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/select_view/ext/menu.js +14 -10
  221. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/select_view/ext/menu_item.js +17 -6
  222. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/select_view/views/popup_button.js +38 -14
  223. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/select_view/views/select.js +5 -13
  224. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/split_view/mixins/split_child.js +1 -1
  225. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/split_view/mixins/split_thumb.js +5 -3
  226. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/split_view/tests/children.js +19 -0
  227. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/split_view/tests/methods.js +20 -2
  228. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/split_view/tests/split_thumb.js +1 -1
  229. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/split_view/views/split.js +35 -12
  230. data/lib/frameworks/sproutcore/frameworks/formatters/README +6 -0
  231. data/lib/frameworks/sproutcore/frameworks/formatters/english.lproj/strings.js +174 -0
  232. data/lib/frameworks/sproutcore/frameworks/formatters/formatters/date_formatter.js +351 -0
  233. data/lib/frameworks/sproutcore/frameworks/formatters/tests/date_formatter.js +517 -0
  234. data/lib/frameworks/sproutcore/frameworks/foundation/core.js +1 -1
  235. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/auto_resize.js +345 -138
  236. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/button.js +5 -3
  237. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/content_value_support.js +176 -42
  238. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/editable.js +1 -1
  239. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/flowed_layout.js +137 -105
  240. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/gestureable.js +2 -2
  241. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/inline_editable.js +2 -2
  242. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/inline_editor.js +16 -1
  243. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/static_layout.js +1 -1
  244. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/validatable.js +47 -47
  245. data/lib/frameworks/sproutcore/frameworks/foundation/private/tree_item_observer.js +3 -3
  246. data/lib/frameworks/sproutcore/frameworks/foundation/render_delegates/helpers/sizing.js +1 -1
  247. data/lib/frameworks/sproutcore/frameworks/foundation/render_delegates/label.js +28 -6
  248. data/lib/frameworks/sproutcore/frameworks/foundation/render_delegates/render_delegate.js +1 -1
  249. data/lib/frameworks/sproutcore/frameworks/foundation/resources/benchmark.css +0 -5
  250. data/lib/frameworks/sproutcore/frameworks/foundation/resources/bootstrap.rhtml +34 -19
  251. data/lib/frameworks/sproutcore/frameworks/foundation/resources/button_view.css +0 -2
  252. data/lib/frameworks/sproutcore/frameworks/foundation/resources/label.css +1 -5
  253. data/lib/frameworks/sproutcore/frameworks/foundation/resources/text_field.css +8 -9
  254. data/lib/frameworks/sproutcore/frameworks/foundation/system/benchmark.js +2 -2
  255. data/lib/frameworks/sproutcore/frameworks/foundation/system/module.js +179 -47
  256. data/lib/frameworks/sproutcore/frameworks/foundation/system/task_queue.js +34 -1
  257. data/lib/frameworks/sproutcore/frameworks/foundation/system/text_selection.js +1 -1
  258. data/lib/frameworks/sproutcore/frameworks/foundation/system/user_defaults.js +26 -12
  259. data/lib/frameworks/sproutcore/frameworks/foundation/system/utils/misc.js +7 -7
  260. data/lib/frameworks/sproutcore/frameworks/foundation/system/utils/string_measurement.js +12 -4
  261. data/lib/frameworks/sproutcore/frameworks/foundation/system/utils/string_metric_optimization.js +202 -0
  262. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/content_value_support/content.js +77 -8
  263. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/flowed_layout/tests.js +1 -0
  264. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/inline_editable/beginEditing.js +2 -2
  265. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/inline_editable/commitEditing.js +4 -3
  266. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/inline_editable/discardEditing.js +4 -2
  267. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/inline_editor/beginEditing.js +2 -2
  268. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/inline_editor/commitEditing.js +4 -2
  269. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/inline_editor/discardEditing.js +4 -2
  270. data/lib/frameworks/sproutcore/frameworks/foundation/tests/system/utils/pointInElement.js +2 -2
  271. data/lib/frameworks/sproutcore/frameworks/foundation/tests/views/label/ui.js +0 -8
  272. data/lib/frameworks/sproutcore/frameworks/foundation/tests/views/text_field/ui.js +163 -149
  273. data/lib/frameworks/sproutcore/frameworks/foundation/validators/credit_card.js +1 -1
  274. data/lib/frameworks/sproutcore/frameworks/foundation/validators/date.js +1 -1
  275. data/lib/frameworks/sproutcore/frameworks/foundation/validators/date_time.js +1 -1
  276. data/lib/frameworks/sproutcore/frameworks/foundation/validators/password.js +1 -1
  277. data/lib/frameworks/sproutcore/frameworks/foundation/validators/validator.js +3 -3
  278. data/lib/frameworks/sproutcore/frameworks/foundation/views/field.js +16 -43
  279. data/lib/frameworks/sproutcore/frameworks/foundation/views/image.js +4 -3
  280. data/lib/frameworks/sproutcore/frameworks/foundation/views/inline_text_field.js +67 -54
  281. data/lib/frameworks/sproutcore/frameworks/foundation/views/label.js +49 -38
  282. data/lib/frameworks/sproutcore/frameworks/foundation/views/text_field.js +285 -242
  283. data/lib/frameworks/sproutcore/frameworks/jquery/jquery-buffer.js +13 -13
  284. data/lib/frameworks/sproutcore/frameworks/jquery/jquery-buffered.js +19 -22
  285. data/lib/frameworks/sproutcore/frameworks/jquery/jquery-sc.js +9 -3
  286. data/lib/frameworks/sproutcore/frameworks/jquery/jquery.js +231 -186
  287. data/lib/frameworks/sproutcore/frameworks/media/views/audio.js +145 -143
  288. data/lib/frameworks/sproutcore/frameworks/media/views/video.js +156 -154
  289. data/lib/frameworks/sproutcore/frameworks/qunit/qunit/qunit.js +5 -5
  290. data/lib/frameworks/sproutcore/frameworks/routing/system/routes.js +3 -3
  291. data/lib/frameworks/sproutcore/frameworks/routing/system/routes.js.orig +540 -0
  292. data/lib/frameworks/sproutcore/frameworks/routing/tests/system/routes.js +2 -2
  293. data/lib/frameworks/sproutcore/frameworks/runtime/core.js +15 -8
  294. data/lib/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/base.js +5 -5
  295. data/lib/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/replace.js +12 -0
  296. data/lib/frameworks/sproutcore/frameworks/runtime/ext/function.js +2 -2
  297. data/lib/frameworks/sproutcore/frameworks/runtime/mixins/array.js +1 -1
  298. data/lib/frameworks/sproutcore/frameworks/runtime/mixins/copyable.js +1 -1
  299. data/lib/frameworks/sproutcore/frameworks/runtime/mixins/enumerable.js +7 -7
  300. data/lib/frameworks/sproutcore/frameworks/runtime/mixins/observable.js +98 -32
  301. data/lib/frameworks/sproutcore/frameworks/runtime/private/chain_observer.js +7 -2
  302. data/lib/frameworks/sproutcore/frameworks/runtime/private/observer_queue.js +14 -3
  303. data/lib/frameworks/sproutcore/frameworks/runtime/private/observer_set.js +98 -13
  304. data/lib/frameworks/sproutcore/frameworks/runtime/system/binding.js +8 -14
  305. data/lib/frameworks/sproutcore/frameworks/runtime/system/enumerator.js +1 -1
  306. data/lib/frameworks/sproutcore/frameworks/runtime/system/error.js +2 -2
  307. data/lib/frameworks/sproutcore/frameworks/runtime/system/index_set.js +23 -6
  308. data/lib/frameworks/sproutcore/frameworks/runtime/system/logger.js +69 -18
  309. data/lib/frameworks/sproutcore/frameworks/runtime/system/object.js +57 -31
  310. data/lib/frameworks/sproutcore/frameworks/runtime/system/run_loop.js +189 -14
  311. data/lib/frameworks/sproutcore/frameworks/runtime/system/string.js +82 -22
  312. data/lib/frameworks/sproutcore/frameworks/runtime/tests/mixins/observable/chained.js +20 -0
  313. data/lib/frameworks/sproutcore/frameworks/runtime/tests/mixins/observable/observable.js +125 -4
  314. data/lib/frameworks/sproutcore/frameworks/runtime/tests/private/observer_queue.js +1 -1
  315. data/lib/frameworks/sproutcore/frameworks/runtime/tests/system/binding.js +2 -2
  316. data/lib/frameworks/sproutcore/frameworks/runtime/tests/system/index_set/rangeStartForIndex.js +37 -0
  317. data/lib/frameworks/sproutcore/frameworks/runtime/tests/system/index_set/remove.js +2 -2
  318. data/lib/frameworks/sproutcore/frameworks/runtime/tests/system/logger.js +16 -0
  319. data/lib/frameworks/sproutcore/frameworks/runtime/tests/system/run_loop.js +75 -4
  320. data/lib/frameworks/sproutcore/frameworks/runtime/tests/system/string.js +41 -0
  321. data/lib/frameworks/sproutcore/frameworks/statechart/mixins/statechart_delegate.js +113 -0
  322. data/lib/frameworks/sproutcore/frameworks/statechart/private/state_path_matcher.js +312 -0
  323. data/lib/frameworks/sproutcore/frameworks/statechart/system/async.js +18 -22
  324. data/lib/frameworks/sproutcore/frameworks/statechart/system/state.js +508 -131
  325. data/lib/frameworks/sproutcore/frameworks/statechart/system/state_route_handler_context.js +78 -0
  326. data/lib/frameworks/sproutcore/frameworks/statechart/system/statechart.js +265 -44
  327. data/lib/frameworks/sproutcore/frameworks/statechart/tests/event_handling/basic/with_concurrent_states.js +16 -0
  328. data/lib/frameworks/sproutcore/frameworks/statechart/tests/event_handling/responder/responder_chain.js +11 -3
  329. data/lib/frameworks/sproutcore/frameworks/statechart/tests/private/state_path_matcher.js +116 -0
  330. data/lib/frameworks/sproutcore/frameworks/statechart/tests/state/methods/add_substate.js +108 -0
  331. data/lib/frameworks/sproutcore/frameworks/statechart/tests/state/methods/find_first_relative_current_state/with_concurrent.js +179 -0
  332. data/lib/frameworks/sproutcore/frameworks/statechart/tests/state/methods/find_first_relative_current_state/without_concurrent.js +74 -0
  333. data/lib/frameworks/sproutcore/frameworks/statechart/tests/state/methods/get_state.js +141 -0
  334. data/lib/frameworks/sproutcore/frameworks/statechart/tests/state/methods/get_substate.js +340 -0
  335. data/lib/frameworks/sproutcore/frameworks/statechart/tests/state/methods/route_triggered.js +161 -0
  336. data/lib/frameworks/sproutcore/frameworks/statechart/tests/state/methods/try_to_handle_event.js +288 -0
  337. data/lib/frameworks/sproutcore/frameworks/statechart/tests/state_transitioning/history_state/standard/without_concurrent_states/context.js +5 -33
  338. data/lib/frameworks/sproutcore/frameworks/statechart/tests/state_transitioning/routing/with_concurrent_states/basic.js +213 -0
  339. data/lib/frameworks/sproutcore/frameworks/statechart/tests/state_transitioning/routing/without_concurrent_states/basic.js +212 -0
  340. data/lib/frameworks/sproutcore/frameworks/statechart/tests/state_transitioning/standard/without_concurrent_states/core.js +8 -0
  341. data/lib/frameworks/sproutcore/frameworks/statechart/tests/{state/namespacing.js → statechart/methods/get_state.js} +3 -41
  342. data/lib/frameworks/sproutcore/frameworks/statechart/tests/statechart/{invoke_state_method.js → methods/invoke_state_method.js} +1 -1
  343. data/lib/frameworks/sproutcore/frameworks/statechart/tests/{event_handling/advanced → statechart}/respond_to_event.js +1 -1
  344. data/lib/frameworks/sproutcore/frameworks/statechart/tests/system/state_route_handler_context/methods/retry.js +64 -0
  345. data/lib/frameworks/sproutcore/frameworks/table/core.js +2 -0
  346. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/controls/button.js +0 -1
  347. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/ext/handlebars.js +29 -5
  348. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/ext/handlebars/bind.js +4 -3
  349. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/ext/handlebars/collection.js +0 -0
  350. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/ext/handlebars/localization.js +0 -0
  351. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/ext/handlebars/view.js +0 -0
  352. data/lib/frameworks/sproutcore/frameworks/{handlebars → template_view}/handlebars.js +493 -357
  353. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/mixins/template_helpers/checkbox_support.js +0 -0
  354. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/mixins/template_helpers/text_field_support.js +13 -2
  355. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/panes/template.js +0 -0
  356. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/tests/controls/button.js +0 -0
  357. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/tests/mixins/template_helpers/checkbox_support.js +0 -0
  358. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/tests/mixins/template_helpers/text_field_support.js +0 -0
  359. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/tests/panes/template.js +0 -0
  360. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/tests/views/template/collection.js +39 -14
  361. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/tests/views/template/core.js +0 -0
  362. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/tests/views/template/handlebars.js +57 -6
  363. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/views/bindable_span.js +21 -6
  364. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/views/template.js +9 -3
  365. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/views/template_collection.js +55 -26
  366. data/lib/frameworks/sproutcore/frameworks/testing/system/equiv.js +1 -1
  367. data/lib/frameworks/sproutcore/frameworks/testing/system/plan.js +122 -122
  368. data/lib/frameworks/sproutcore/frameworks/testing/system/runner.js +2 -2
  369. data/lib/frameworks/sproutcore/frameworks/testing/system/suite.js +4 -4
  370. data/lib/frameworks/sproutcore/frameworks/yuireset/resources/base.css +1 -1
  371. data/lib/frameworks/sproutcore/frameworks/yuireset/resources/reset.css +0 -1
  372. data/lib/frameworks/sproutcore/frameworks/yuireset/resources/view.css +4 -4
  373. data/lib/frameworks/sproutcore/lib/index.rhtml +55 -32
  374. data/lib/frameworks/sproutcore/license.js +2 -4
  375. data/lib/frameworks/sproutcore/themes/ace/resources/body.css +5 -1
  376. data/lib/frameworks/sproutcore/themes/ace/resources/button/ace/18px/button.css +2 -2
  377. data/lib/frameworks/sproutcore/themes/ace/resources/button/ace/24px/button.css +21 -13
  378. data/lib/frameworks/sproutcore/themes/ace/resources/button/ace/30px/button.css +17 -10
  379. data/lib/frameworks/sproutcore/themes/ace/resources/button/ace/44px/button.css +4 -3
  380. data/lib/frameworks/sproutcore/themes/ace/resources/button/dark/24px/button.css +20 -12
  381. data/lib/frameworks/sproutcore/themes/ace/resources/button/dark/30px/button.css +16 -8
  382. data/lib/frameworks/sproutcore/themes/ace/resources/button/dark/jumbo/button.css +17 -0
  383. data/lib/frameworks/sproutcore/themes/ace/resources/button/dark/small/button.css +17 -0
  384. data/lib/frameworks/sproutcore/themes/ace/resources/disclosure/ace/disclosure.css +2 -2
  385. data/lib/frameworks/sproutcore/themes/ace/resources/master-detail/master-detail.css +2 -2
  386. data/lib/frameworks/sproutcore/themes/ace/resources/picker/popover/popover.css +5 -3
  387. data/lib/frameworks/sproutcore/themes/iphone_theme/english.lproj/core.css +1 -1
  388. data/lib/frameworks/sproutcore/themes/legacy_theme/english.lproj/toolbar.css +1 -1
  389. data/lib/gen/app/USAGE +17 -4
  390. data/lib/gen/language/Buildfile +4 -4
  391. data/lib/gen/language/USAGE +4 -4
  392. data/lib/gen/page/templates/pages/@target_name@/Buildfile +7 -7
  393. data/lib/gen/{html_app → statechart_app}/Buildfile +0 -0
  394. data/lib/gen/{html_app → statechart_app}/README +0 -0
  395. data/lib/gen/statechart_app/USAGE +21 -0
  396. data/lib/gen/statechart_app/templates/apps/@target_name@/Buildfile +9 -0
  397. data/lib/gen/statechart_app/templates/apps/@target_name@/core.js +24 -0
  398. data/lib/gen/statechart_app/templates/apps/@target_name@/main.js +26 -0
  399. data/lib/gen/statechart_app/templates/apps/@target_name@/resources/_theme.css +18 -0
  400. data/lib/gen/statechart_app/templates/apps/@target_name@/resources/loading.rhtml +9 -0
  401. data/lib/gen/statechart_app/templates/apps/@target_name@/resources/main_page.js +21 -0
  402. data/lib/gen/statechart_app/templates/apps/@target_name@/statechart.js +8 -0
  403. data/lib/gen/statechart_app/templates/apps/@target_name@/states/ready_state.js +12 -0
  404. data/lib/gen/statechart_app/templates/apps/@target_name@/theme.js +24 -0
  405. data/lib/sproutcore/builders.rb +1 -0
  406. data/lib/sproutcore/builders/base.rb +19 -1
  407. data/lib/sproutcore/builders/chance_file.rb +6 -1
  408. data/lib/sproutcore/builders/handlebars.rb +1 -9
  409. data/lib/sproutcore/builders/javascript.rb +1 -10
  410. data/lib/sproutcore/builders/json.rb +25 -0
  411. data/lib/sproutcore/builders/less.rb +1 -1
  412. data/lib/sproutcore/builders/sass.rb +1 -1
  413. data/lib/sproutcore/builders/stylesheet.rb +1 -9
  414. data/lib/sproutcore/helpers/html5_manifest.rb +1 -1
  415. data/lib/sproutcore/helpers/static_helper.rb +42 -0
  416. data/lib/sproutcore/rack/proxy.rb +21 -3
  417. data/lib/sproutcore/rack/service.rb +3 -2
  418. data/lib/sproutcore/tools.rb +18 -25
  419. data/lib/sproutcore/tools/gen.rb +10 -3
  420. data/lib/sproutcore/tools/init.rb +11 -10
  421. data/spec/buildtasks/manifest/prepare_build_tasks/json_spec.rb +62 -0
  422. data/spec/fixtures/builder_tests/apps/handlebars_test/Buildfile +1 -1
  423. data/spec/fixtures/builder_tests/apps/json_test/sc_static.json +2 -0
  424. data/spec/lib/builders/json_spec.rb +53 -0
  425. data/sproutcore.gemspec +2 -2
  426. data/vendor/chance/lib/chance/parser.rb +1 -1
  427. metadata +222 -177
  428. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/datetime.js +0 -0
  429. data/lib/frameworks/sproutcore/frameworks/debug/invoke_once_last_debugging.js +0 -259
  430. data/lib/frameworks/sproutcore/frameworks/documentation/core.js +0 -0
  431. data/lib/frameworks/sproutcore/frameworks/foundation/system/chance.js +0 -69
  432. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/editable/ui.js +0 -44
  433. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/inline_text_field/ui.js +0 -64
  434. data/lib/frameworks/sproutcore/frameworks/mini/license.js +0 -30
  435. data/lib/gen/html_app/USAGE +0 -15
  436. data/lib/gen/html_app/templates/apps/@target_name@/@target_name@.js +0 -11
  437. data/lib/gen/html_app/templates/apps/@target_name@/resources/images/.gitkeep +0 -0
  438. data/lib/gen/html_app/templates/apps/@target_name@/resources/stylesheets/@target_name@.css +0 -6
  439. data/lib/gen/html_app/templates/apps/@target_name@/resources/templates/@target_name@.handlebars +0 -1
  440. data/lib/gen/html_project/Buildfile +0 -45
  441. data/lib/gen/html_project/INIT +0 -3
  442. data/lib/gen/html_project/README +0 -1
  443. data/lib/gen/html_project/USAGE +0 -2
  444. data/lib/gen/html_project/templates/@filename@/Buildfile +0 -5
  445. data/lib/gen/html_project/templates/@filename@/README +0 -4
@@ -0,0 +1,1531 @@
1
+ // ==========================================================================
2
+ // Project: SproutCore - JavaScript Application Framework
3
+ // Copyright: ©2006-2011 Strobe Inc. and contributors.
4
+ // Portions ©2008-2011 Apple Inc. All rights reserved.
5
+ // License: Licensed under MIT license (see license.js)
6
+ // ==========================================================================
7
+
8
+ sc_require('core') ;
9
+ sc_require('models/record');
10
+
11
+ /**
12
+ @class
13
+
14
+ This permits you to perform queries on your data store,
15
+ written in a SQL-like language. Here is a simple example:
16
+
17
+ q = SC.Query.create({
18
+ conditions: "firstName = 'Jonny' AND lastName = 'Cash'"
19
+ })
20
+
21
+ You can check if a certain record matches the query by calling
22
+
23
+ q.contains(record)
24
+
25
+ To find all records of your store, that match query q, use findAll with
26
+ query q as argument:
27
+
28
+ r = MyApp.store.findAll(q)
29
+
30
+ `r` will be a record array containing all matching records.
31
+ To limit the query to a record type of `MyApp.MyModel`,
32
+ you can specify the type as a property of the query like this:
33
+
34
+ q = SC.Query.create({
35
+ conditions: "firstName = 'Jonny' AND lastName = 'Cash'",
36
+ recordType: MyApp.MyModel
37
+ })
38
+
39
+ Calling `find()` like above will now return only records of type t.
40
+ It is recommended to limit your query to a record type, since the query will
41
+ have to look for matching records in the whole store, if no record type
42
+ is given.
43
+
44
+ You can give an order, which the resulting records should follow, like this:
45
+
46
+ q = SC.Query.create({
47
+ conditions: "firstName = 'Jonny' AND lastName = 'Cash'",
48
+ recordType: MyApp.MyModel,
49
+ orderBy: "lastName, year DESC"
50
+ });
51
+
52
+ The default order direction is ascending. You can change it to descending
53
+ by writing `'DESC'` behind the property name like in the example above.
54
+ If no order is given, or records are equal in respect to a given order,
55
+ records will be ordered by guid.
56
+
57
+ SproutCore Query Language
58
+ =====
59
+
60
+ Features of the query language:
61
+
62
+ Primitives:
63
+
64
+ - record properties
65
+ - `null`, `undefined`
66
+ - `true`, `false`
67
+ - numbers (integers and floats)
68
+ - strings (double or single quoted)
69
+
70
+ Parameters:
71
+
72
+ - `%@` (wild card)
73
+ - `{parameterName}` (named parameter)
74
+
75
+ Wild cards are used to identify parameters by the order in which they appear
76
+ in the query string. Named parameters can be used when tracking the order
77
+ becomes difficult. Both types of parameters can be used by giving the
78
+ parameters as a property to your query object:
79
+
80
+ yourQuery.parameters = yourParameters
81
+
82
+ where yourParameters should have one of the following formats:
83
+
84
+ * for wild cards: `[firstParam, secondParam, thirdParam]`
85
+ * for named params: `{name1: param1, mane2: parma2}`
86
+
87
+ You cannot use both types of parameters in a single query!
88
+
89
+ Operators:
90
+
91
+ - `=`
92
+ - `!=`
93
+ - `<`
94
+ - `<=`
95
+ - `>`
96
+ - `>=`
97
+ - `BEGINS_WITH` -- (checks if a string starts with another one)
98
+ - `ENDS_WITH` -- (checks if a string ends with another one)
99
+ - `CONTAINS` -- (checks if a string contains another one, or if an
100
+ object is in an array)
101
+ - `MATCHES` -- (checks if a string is matched by a regexp,
102
+ you will have to use a parameter to insert the regexp)
103
+ - `ANY` -- (checks if the thing on its left is contained in the array
104
+ on its right, you will have to use a parameter
105
+ to insert the array)
106
+ - `TYPE_IS` -- (unary operator expecting a string containing the name
107
+ of a Model class on its right side, only records of this
108
+ type will match)
109
+
110
+ Boolean Operators:
111
+
112
+ - `AND`
113
+ - `OR`
114
+ - `NOT`
115
+
116
+ Parenthesis for grouping:
117
+
118
+ - `(` and `)`
119
+
120
+
121
+ Adding Your Own Query Handlers
122
+ ---
123
+
124
+ You can extend the query language with your own operators by calling:
125
+
126
+ SC.Query.registerQueryExtension('your_operator', your_operator_definition);
127
+
128
+ See details below. As well you can provide your own comparison functions
129
+ to control ordering of specific record properties like this:
130
+
131
+ SC.Query.registerComparison(property_name, comparison_for_this_property);
132
+
133
+ Examples
134
+
135
+ Some example queries:
136
+
137
+ TODO add examples
138
+
139
+ @extends SC.Object
140
+ @extends SC.Copyable
141
+ @extends SC.Freezable
142
+ @since SproutCore 1.0
143
+ */
144
+
145
+ SC.Query = SC.Object.extend(SC.Copyable, SC.Freezable,
146
+ /** @scope SC.Query.prototype */ {
147
+
148
+ // ..........................................................
149
+ // PROPERTIES
150
+ //
151
+
152
+ /**
153
+ Walk like a duck.
154
+
155
+ @type Boolean
156
+ */
157
+ isQuery: YES,
158
+
159
+ /**
160
+ Unparsed query conditions. If you are handling a query yourself, then
161
+ you will find the base query string here.
162
+
163
+ @type String
164
+ */
165
+ conditions: null,
166
+
167
+ /**
168
+ Optional orderBy parameters. This can be a string of keys, optionally
169
+ beginning with the strings `"DESC "` or `"ASC "` to select descending or
170
+ ascending order.
171
+
172
+ Alternatively, you can specify a comparison function, in which case the
173
+ two records will be sent to it. Your comparison function, as with any
174
+ other, is expected to return -1, 0, or 1.
175
+
176
+ @type String | Function
177
+ */
178
+ orderBy: null,
179
+
180
+ /**
181
+ The base record type or types for the query. This must be specified to
182
+ filter the kinds of records this query will work on. You may either
183
+ set this to a single record type or to an array or set of record types.
184
+
185
+ @type SC.Record
186
+ */
187
+ recordType: null,
188
+
189
+ /**
190
+ Optional array of multiple record types. If the query accepts multiple
191
+ record types, this is how you can check for it.
192
+
193
+ @type SC.Enumerable
194
+ */
195
+ recordTypes: null,
196
+
197
+ /**
198
+ Returns the complete set of `recordType`s matched by this query. Includes
199
+ any named `recordType`s plus their subclasses.
200
+
201
+ @property
202
+ @type SC.Enumerable
203
+ */
204
+ expandedRecordTypes: function() {
205
+ var ret = SC.CoreSet.create(), rt, q ;
206
+
207
+ if (rt = this.get('recordType')) this._scq_expandRecordType(rt, ret);
208
+ else if (rt = this.get('recordTypes')) {
209
+ rt.forEach(function(t) { this._scq_expandRecordType(t, ret); }, this);
210
+ } else this._scq_expandRecordType(SC.Record, ret);
211
+
212
+ // save in queue. if a new recordtype is defined, we will be notified.
213
+ q = SC.Query._scq_queriesWithExpandedRecordTypes;
214
+ if (!q) {
215
+ q = SC.Query._scq_queriesWithExpandedRecordTypes = SC.CoreSet.create();
216
+ }
217
+ q.add(this);
218
+
219
+ return ret.freeze() ;
220
+ }.property('recordType', 'recordTypes').cacheable(),
221
+
222
+ /** @private
223
+ expands a single record type into the set. called recursively
224
+ */
225
+ _scq_expandRecordType: function(recordType, set) {
226
+ if (set.contains(recordType)) return; // nothing to do
227
+ set.add(recordType);
228
+
229
+ if (SC.typeOf(recordType)===SC.T_STRING) {
230
+ recordType = SC.objectForPropertyPath(recordType);
231
+ }
232
+
233
+ recordType.subclasses.forEach(function(t) {
234
+ this._scq_expandRecordType(t, set);
235
+ }, this);
236
+ },
237
+
238
+ /**
239
+ Optional hash of parameters. These parameters may be interpolated into
240
+ the query conditions. If you are handling the query manually, these
241
+ parameters will not be used.
242
+
243
+ @type Hash
244
+ */
245
+ parameters: null,
246
+
247
+ /**
248
+ Indicates the location where the result set for this query is stored.
249
+ Currently the available options are:
250
+
251
+ - `SC.Query.LOCAL` -- indicates that the query results will be
252
+ automatically computed from the in-memory store.
253
+ - `SC.Query.REMOTE` -- indicates that the query results are kept on a
254
+ remote server and hence must be loaded from the `DataSource`.
255
+
256
+ The default setting for this property is `SC.Query.LOCAL`.
257
+
258
+ Note that even if a query location is `LOCAL`, your `DataSource` will
259
+ still have its `fetch()` method called for the query. For `LOCAL`
260
+ queries, you won't need to explicitly provide the query result set; you
261
+ can just load records into the in-memory store as needed and let the query
262
+ recompute automatically.
263
+
264
+ If your query location is `REMOTE`, then your `DataSource` will need to
265
+ provide the actual set of query results manually. Usually you will only
266
+ need to use a `REMOTE` query if you are retrieving a large data set and you
267
+ don't want to pay the cost of computing the result set client side.
268
+
269
+ @type String
270
+ */
271
+ location: 'local', // SC.Query.LOCAL
272
+
273
+ /**
274
+ Another query that will optionally limit the search of records. This is
275
+ usually configured for you when you do `find()` from another record array.
276
+
277
+ @type SC.Query
278
+ */
279
+ scope: null,
280
+
281
+
282
+ /**
283
+ Returns `YES` if query location is Remote. This is sometimes more
284
+ convenient than checking the location.
285
+
286
+ @property
287
+ @type Boolean
288
+ */
289
+ isRemote: function() {
290
+ return this.get('location') === SC.Query.REMOTE;
291
+ }.property('location').cacheable(),
292
+
293
+ /**
294
+ Returns `YES` if query location is Local. This is sometimes more
295
+ convenient than checking the location.
296
+
297
+ @property
298
+ @type Boolean
299
+ */
300
+ isLocal: function() {
301
+ return this.get('location') === SC.Query.LOCAL;
302
+ }.property('location').cacheable(),
303
+
304
+ /**
305
+ Indicates whether a record is editable or not. Defaults to `NO`. Local
306
+ queries should never be made editable. Remote queries may be editable or
307
+ not depending on the data source.
308
+ */
309
+ isEditable: NO,
310
+
311
+ // ..........................................................
312
+ // PRIMITIVE METHODS
313
+ //
314
+
315
+ /**
316
+ Returns `YES` if record is matched by the query, `NO` otherwise. This is
317
+ used when computing a query locally.
318
+
319
+ @param {SC.Record} record the record to check
320
+ @param {Hash} parameters optional override parameters
321
+ @returns {Boolean} YES if record belongs, NO otherwise
322
+ */
323
+ contains: function(record, parameters) {
324
+
325
+ // check the recordType if specified
326
+ var rtype, ret = YES ;
327
+ if (rtype = this.get('recordTypes')) { // plural form
328
+ ret = rtype.find(function(t) { return SC.kindOf(record, t); });
329
+ } else if (rtype = this.get('recordType')) { // singular
330
+ ret = SC.kindOf(record, rtype);
331
+ }
332
+
333
+ if (!ret) return NO ; // if either did not pass, does not contain
334
+
335
+ // if we have a scope - check for that as well
336
+ var scope = this.get('scope');
337
+ if (scope && !scope.contains(record)) return NO ;
338
+
339
+ // now try parsing
340
+ if (!this._isReady) this.parse(); // prepare the query if needed
341
+ if (!this._isReady) return NO ;
342
+ if (parameters === undefined) parameters = this.parameters || this;
343
+
344
+ // if parsing worked we check if record is contained
345
+ // if parsing failed no record will be contained
346
+ return this._tokenTree.evaluate(record, parameters);
347
+ },
348
+
349
+ /**
350
+ Returns `YES` if the query matches one or more of the record types in the
351
+ passed set.
352
+
353
+ @param {SC.Set} types set of record types
354
+ @returns {Boolean} YES if record types match
355
+ */
356
+ containsRecordTypes: function(types) {
357
+ var rtype = this.get('recordType');
358
+ if (rtype) {
359
+ return !!types.find(function(t) { return SC.kindOf(t, rtype); });
360
+
361
+ } else if (rtype = this.get('recordTypes')) {
362
+ return !!rtype.find(function(t) {
363
+ return !!types.find(function(t2) { return SC.kindOf(t2,t); });
364
+ });
365
+
366
+ } else return YES; // allow anything through
367
+ },
368
+
369
+ /**
370
+ Returns the sort order of the two passed records, taking into account the
371
+ orderBy property set on this query. This method does not verify that the
372
+ two records actually belong in the query set or not; this is checked using
373
+ `contains()`.
374
+
375
+ @param {SC.Record} record1 the first record
376
+ @param {SC.Record} record2 the second record
377
+ @returns {Number} -1 if record1 < record2,
378
+ +1 if record1 > record2,
379
+ 0 if equal
380
+ */
381
+ compare: function(record1, record2) {
382
+ // IMPORTANT: THIS CODE IS ALSO INLINED INSIDE OF THE 'compareStoreKeys'
383
+ // CLASS METHOD. IF YOU CHANGE THIS IMPLEMENTATION, BE SURE
384
+ // TO UPDATE IT THERE, TOO.
385
+ //
386
+ // (Any clients overriding this method will have their version called,
387
+ // however. That's why we'll keep this here; clients might want to
388
+ // override it and call sc_super()).
389
+
390
+ var result = 0,
391
+ propertyName, order, len, i;
392
+
393
+ // fast cases go here
394
+ if (record1 === record2) return 0;
395
+
396
+ // if called for the first time we have to build the order array
397
+ if (!this._isReady) this.parse();
398
+ if (!this._isReady) { // can't parse. guid is wrong but consistent
399
+ return SC.compare(record1.get('id'),record2.get('id'));
400
+ }
401
+
402
+ // For every property specified in orderBy until non-eql result is found.
403
+ // Or, if orderBy is a comparison function, simply invoke it with the
404
+ // records.
405
+ order = this._order;
406
+ if (SC.typeOf(order) === SC.T_FUNCTION) {
407
+ result = order.call(null, record1, record2);
408
+ }
409
+ else {
410
+ len = order ? order.length : 0;
411
+ for (i=0; result===0 && (i < len); i++) {
412
+ propertyName = order[i].propertyName;
413
+ // if this property has a registered comparison use that
414
+ if (SC.Query.comparisons[propertyName]) {
415
+ result = SC.Query.comparisons[propertyName](
416
+ record1.get(propertyName),record2.get(propertyName));
417
+
418
+ // if not use default SC.compare()
419
+ } else {
420
+ result = SC.compare(
421
+ record1.get(propertyName), record2.get(propertyName) );
422
+ }
423
+
424
+ if ((result!==0) && order[i].descending) result = (-1) * result;
425
+ }
426
+ }
427
+
428
+ // return result or compare by guid
429
+ if (result !== 0) return result ;
430
+ else return SC.compare(record1.get('id'),record2.get('id'));
431
+ },
432
+
433
+ /** @private
434
+ Becomes YES once the query has been successfully parsed
435
+ */
436
+ _isReady: NO,
437
+
438
+ /**
439
+ This method has to be called before the query object can be used.
440
+ You will normaly not have to do this; it will be called automatically
441
+ if you try to evaluate a query.
442
+ You can, however, use this function for testing your queries.
443
+
444
+ @returns {Boolean} true if parsing succeeded, false otherwise
445
+ */
446
+ parse: function() {
447
+ var conditions = this.get('conditions'),
448
+ lang = this.get('queryLanguage'),
449
+ tokens, tree;
450
+
451
+ tokens = this._tokenList = this.tokenizeString(conditions, lang);
452
+ tree = this._tokenTree = this.buildTokenTree(tokens, lang);
453
+ this._order = this.buildOrder(this.get('orderBy'));
454
+
455
+ this._isReady = !!tree && !tree.error;
456
+ if (tree && tree.error) throw tree.error;
457
+ return this._isReady;
458
+ },
459
+
460
+ /**
461
+ Returns the same query but with the scope set to the passed record array.
462
+ This will copy the receiver. It also stores these queries in a cache to
463
+ reuse them if possible.
464
+
465
+ @param {SC.RecordArray} recordArray the scope
466
+ @returns {SC.Query} new query
467
+ */
468
+ queryWithScope: function(recordArray) {
469
+ // look for a cached query on record array.
470
+ var key = SC.keyFor('__query__', SC.guidFor(this)),
471
+ ret = recordArray[key];
472
+
473
+ if (!ret) {
474
+ recordArray[key] = ret = this.copy();
475
+ ret.set('scope', recordArray);
476
+ ret.freeze();
477
+ }
478
+
479
+ return ret ;
480
+ },
481
+
482
+ // ..........................................................
483
+ // PRIVATE SUPPORT
484
+ //
485
+
486
+ /** @private
487
+ Properties that need to be copied when cloning the query.
488
+ */
489
+ copyKeys: ['conditions', 'orderBy', 'recordType', 'recordTypes', 'parameters', 'location', 'scope'],
490
+
491
+ /** @private */
492
+ concatenatedProperties: ['copyKeys'],
493
+
494
+ /** @private
495
+ Implement the Copyable API to clone a query object once it has been
496
+ created.
497
+ */
498
+ copy: function() {
499
+ var opts = {},
500
+ keys = this.get('copyKeys'),
501
+ loc = keys ? keys.length : 0,
502
+ key, value, ret;
503
+
504
+ while(--loc >= 0) {
505
+ key = keys[loc];
506
+ value = this.get(key);
507
+ if (value !== undefined) opts[key] = value ;
508
+ }
509
+
510
+ ret = this.constructor.create(opts);
511
+ opts = null;
512
+ return ret ;
513
+ },
514
+
515
+ // ..........................................................
516
+ // QUERY LANGUAGE DEFINITION
517
+ //
518
+
519
+
520
+ /**
521
+ This is the definition of the query language. You can extend it
522
+ by using `SC.Query.registerQueryExtension()`.
523
+ */
524
+ queryLanguage: {
525
+
526
+ 'UNKNOWN': {
527
+ firstCharacter: /[^\s'"\w\d\(\)\{\}]/,
528
+ notAllowed: /[\-\s'"\w\d\(\)\{\}]/
529
+ },
530
+
531
+ 'PROPERTY': {
532
+ firstCharacter: /[a-zA-Z_]/,
533
+ notAllowed: /[^a-zA-Z_0-9\.]/,
534
+ evalType: 'PRIMITIVE',
535
+
536
+ /** @ignore */
537
+ evaluate: function (r,w) {
538
+ var tokens = this.tokenValue.split('.');
539
+
540
+ var len = tokens.length;
541
+ if (len < 2) return r.get(this.tokenValue);
542
+
543
+ var ret = r;
544
+ for (var i = 0; i < len; i++) {
545
+ if (!ret) return;
546
+ if (ret.get) {
547
+ ret = ret.get(tokens[i]);
548
+ } else {
549
+ ret = ret[tokens[i]];
550
+ }
551
+ }
552
+ return ret;
553
+ }
554
+ },
555
+
556
+ 'NUMBER': {
557
+ firstCharacter: /[\d\-]/,
558
+ notAllowed: /[^\d\-\.]/,
559
+ format: /^-?\d+$|^-?\d+\.\d+$/,
560
+ evalType: 'PRIMITIVE',
561
+
562
+ /** @ignore */
563
+ evaluate: function (r,w) { return parseFloat(this.tokenValue); }
564
+ },
565
+
566
+ 'STRING': {
567
+ firstCharacter: /['"]/,
568
+ delimited: true,
569
+ evalType: 'PRIMITIVE',
570
+
571
+ /** @ignore */
572
+ evaluate: function (r,w) { return this.tokenValue; }
573
+ },
574
+
575
+ 'PARAMETER': {
576
+ firstCharacter: /\{/,
577
+ lastCharacter: '}',
578
+ delimited: true,
579
+ evalType: 'PRIMITIVE',
580
+
581
+ /** @ignore */
582
+ evaluate: function (r,w) { return w[this.tokenValue]; }
583
+ },
584
+
585
+ '%@': {
586
+ rememberCount: true,
587
+ reservedWord: true,
588
+ evalType: 'PRIMITIVE',
589
+
590
+ /** @ignore */
591
+ evaluate: function (r,w) { return w[this.tokenValue]; }
592
+ },
593
+
594
+ 'OPEN_PAREN': {
595
+ firstCharacter: /\(/,
596
+ singleCharacter: true
597
+ },
598
+
599
+ 'CLOSE_PAREN': {
600
+ firstCharacter: /\)/,
601
+ singleCharacter: true
602
+ },
603
+
604
+ 'AND': {
605
+ reservedWord: true,
606
+ leftType: 'BOOLEAN',
607
+ rightType: 'BOOLEAN',
608
+ evalType: 'BOOLEAN',
609
+
610
+ /** @ignore */
611
+ evaluate: function (r,w) {
612
+ var left = this.leftSide.evaluate(r,w);
613
+ var right = this.rightSide.evaluate(r,w);
614
+ return left && right;
615
+ }
616
+ },
617
+
618
+ 'OR': {
619
+ reservedWord: true,
620
+ leftType: 'BOOLEAN',
621
+ rightType: 'BOOLEAN',
622
+ evalType: 'BOOLEAN',
623
+
624
+ /** @ignore */
625
+ evaluate: function (r,w) {
626
+ var left = this.leftSide.evaluate(r,w);
627
+ var right = this.rightSide.evaluate(r,w);
628
+ return left || right;
629
+ }
630
+ },
631
+
632
+ 'NOT': {
633
+ reservedWord: true,
634
+ rightType: 'BOOLEAN',
635
+ evalType: 'BOOLEAN',
636
+
637
+ /** @ignore */
638
+ evaluate: function (r,w) {
639
+ var right = this.rightSide.evaluate(r,w);
640
+ return !right;
641
+ }
642
+ },
643
+
644
+ '=': {
645
+ reservedWord: true,
646
+ leftType: 'PRIMITIVE',
647
+ rightType: 'PRIMITIVE',
648
+ evalType: 'BOOLEAN',
649
+
650
+ /** @ignore */
651
+ evaluate: function (r,w) {
652
+ var left = this.leftSide.evaluate(r,w);
653
+ var right = this.rightSide.evaluate(r,w);
654
+ return SC.isEqual(left, right);
655
+ }
656
+ },
657
+
658
+ '!=': {
659
+ reservedWord: true,
660
+ leftType: 'PRIMITIVE',
661
+ rightType: 'PRIMITIVE',
662
+ evalType: 'BOOLEAN',
663
+
664
+ /** @ignore */
665
+ evaluate: function (r,w) {
666
+ var left = this.leftSide.evaluate(r,w);
667
+ var right = this.rightSide.evaluate(r,w);
668
+ return !SC.isEqual(left, right);
669
+ }
670
+ },
671
+
672
+ '<': {
673
+ reservedWord: true,
674
+ leftType: 'PRIMITIVE',
675
+ rightType: 'PRIMITIVE',
676
+ evalType: 'BOOLEAN',
677
+
678
+ /** @ignore */
679
+ evaluate: function (r,w) {
680
+ var left = this.leftSide.evaluate(r,w);
681
+ var right = this.rightSide.evaluate(r,w);
682
+ return SC.compare(left, right) == -1; //left < right;
683
+ }
684
+ },
685
+
686
+ '<=': {
687
+ reservedWord: true,
688
+ leftType: 'PRIMITIVE',
689
+ rightType: 'PRIMITIVE',
690
+ evalType: 'BOOLEAN',
691
+
692
+ /** @ignore */
693
+ evaluate: function (r,w) {
694
+ var left = this.leftSide.evaluate(r,w);
695
+ var right = this.rightSide.evaluate(r,w);
696
+ return SC.compare(left, right) != 1; //left <= right;
697
+ }
698
+ },
699
+
700
+ '>': {
701
+ reservedWord: true,
702
+ leftType: 'PRIMITIVE',
703
+ rightType: 'PRIMITIVE',
704
+ evalType: 'BOOLEAN',
705
+
706
+ /** @ignore */
707
+ evaluate: function (r,w) {
708
+ var left = this.leftSide.evaluate(r,w);
709
+ var right = this.rightSide.evaluate(r,w);
710
+ return SC.compare(left, right) == 1; //left > right;
711
+ }
712
+ },
713
+
714
+ '>=': {
715
+ reservedWord: true,
716
+ leftType: 'PRIMITIVE',
717
+ rightType: 'PRIMITIVE',
718
+ evalType: 'BOOLEAN',
719
+
720
+ /** @ignore */
721
+ evaluate: function (r,w) {
722
+ var left = this.leftSide.evaluate(r,w);
723
+ var right = this.rightSide.evaluate(r,w);
724
+ return SC.compare(left, right) != -1; //left >= right;
725
+ }
726
+ },
727
+
728
+ 'BEGINS_WITH': {
729
+ reservedWord: true,
730
+ leftType: 'PRIMITIVE',
731
+ rightType: 'PRIMITIVE',
732
+ evalType: 'BOOLEAN',
733
+
734
+ /** @ignore */
735
+ evaluate: function (r,w) {
736
+ var all = this.leftSide.evaluate(r,w);
737
+ var start = this.rightSide.evaluate(r,w);
738
+ return ( all && all.indexOf(start) === 0 );
739
+ }
740
+ },
741
+
742
+ 'ENDS_WITH': {
743
+ reservedWord: true,
744
+ leftType: 'PRIMITIVE',
745
+ rightType: 'PRIMITIVE',
746
+ evalType: 'BOOLEAN',
747
+
748
+ /** @ignore */
749
+ evaluate: function (r,w) {
750
+ var all = this.leftSide.evaluate(r,w);
751
+ var end = this.rightSide.evaluate(r,w);
752
+ return ( all && all.length >= end.length && all.lastIndexOf(end) === (all.length - end.length));
753
+ }
754
+ },
755
+
756
+ 'CONTAINS': {
757
+ reservedWord: true,
758
+ leftType: 'PRIMITIVE',
759
+ rightType: 'PRIMITIVE',
760
+ evalType: 'BOOLEAN',
761
+
762
+ /** @ignore */
763
+ evaluate: function (r,w) {
764
+ var all = this.leftSide.evaluate(r,w) || [];
765
+ var value = this.rightSide.evaluate(r,w);
766
+
767
+ var allType = SC.typeOf(all);
768
+ if (allType === SC.T_STRING) {
769
+ return (all.indexOf(value) !== -1);
770
+ } else if (allType === SC.T_ARRAY || all.toArray) {
771
+ if (allType !== SC.T_ARRAY) all = all.toArray();
772
+ var found = false;
773
+ var i = 0;
774
+ while ( found===false && i<all.length ) {
775
+ if ( value == all[i] ) found = true;
776
+ i++;
777
+ }
778
+ return found;
779
+ }
780
+ }
781
+ },
782
+
783
+ 'ANY': {
784
+ reservedWord: true,
785
+ leftType: 'PRIMITIVE',
786
+ rightType: 'PRIMITIVE',
787
+ evalType: 'BOOLEAN',
788
+
789
+ /** @ignore */
790
+ evaluate: function (r,w) {
791
+ var prop = this.leftSide.evaluate(r,w);
792
+ var values = this.rightSide.evaluate(r,w);
793
+ var found = false;
794
+ var i = 0;
795
+ while ( found===false && i<values.length ) {
796
+ if ( prop == values[i] ) found = true;
797
+ i++;
798
+ }
799
+ return found;
800
+ }
801
+ },
802
+
803
+ 'MATCHES': {
804
+ reservedWord: true,
805
+ leftType: 'PRIMITIVE',
806
+ rightType: 'PRIMITIVE',
807
+ evalType: 'BOOLEAN',
808
+
809
+ /** @ignore */
810
+ evaluate: function (r,w) {
811
+ var toMatch = this.leftSide.evaluate(r,w);
812
+ var matchWith = this.rightSide.evaluate(r,w);
813
+ return matchWith.test(toMatch);
814
+ }
815
+ },
816
+
817
+ 'TYPE_IS': {
818
+ reservedWord: true,
819
+ rightType: 'PRIMITIVE',
820
+ evalType: 'BOOLEAN',
821
+
822
+ /** @ignore */
823
+ evaluate: function (r,w) {
824
+ var actualType = SC.Store.recordTypeFor(r.storeKey);
825
+ var right = this.rightSide.evaluate(r,w);
826
+ var expectType = SC.objectForPropertyPath(right);
827
+ return actualType == expectType;
828
+ }
829
+ },
830
+
831
+ 'null': {
832
+ reservedWord: true,
833
+ evalType: 'PRIMITIVE',
834
+
835
+ /** @ignore */
836
+ evaluate: function (r,w) { return null; }
837
+ },
838
+
839
+ 'undefined': {
840
+ reservedWord: true,
841
+ evalType: 'PRIMITIVE',
842
+
843
+ /** @ignore */
844
+ evaluate: function (r,w) { return undefined; }
845
+ },
846
+
847
+ 'false': {
848
+ reservedWord: true,
849
+ evalType: 'PRIMITIVE',
850
+
851
+ /** @ignore */
852
+ evaluate: function (r,w) { return false; }
853
+ },
854
+
855
+ 'true': {
856
+ reservedWord: true,
857
+ evalType: 'PRIMITIVE',
858
+
859
+ /** @ignore */
860
+ evaluate: function (r,w) { return true; }
861
+ },
862
+
863
+ 'YES': {
864
+ reservedWord: true,
865
+ evalType: 'PRIMITIVE',
866
+
867
+ /** @ignore */
868
+ evaluate: function (r,w) { return true; }
869
+ },
870
+
871
+ 'NO': {
872
+ reservedWord: true,
873
+ evalType: 'PRIMITIVE',
874
+
875
+ /** @ignore */
876
+ evaluate: function (r,w) { return false; }
877
+ }
878
+
879
+ },
880
+
881
+
882
+ // ..........................................................
883
+ // TOKENIZER
884
+ //
885
+
886
+
887
+ /**
888
+ Takes a string and tokenizes it based on the grammar definition
889
+ provided. Called by `parse()`.
890
+
891
+ @param {String} inputString the string to tokenize
892
+ @param {Object} grammar the grammar definition (normally queryLanguage)
893
+ @returns {Array} list of tokens
894
+ */
895
+ tokenizeString: function (inputString, grammar) {
896
+
897
+
898
+ var tokenList = [],
899
+ c = null,
900
+ t = null,
901
+ token = null,
902
+ tokenType = null,
903
+ currentToken = null,
904
+ currentTokenType = null,
905
+ currentTokenValue = null,
906
+ currentDelimiter = null,
907
+ endOfString = false,
908
+ endOfToken = false,
909
+ belongsToToken = false,
910
+ skipThisCharacter = false,
911
+ rememberCount = {};
912
+
913
+
914
+ // helper function that adds tokens to the tokenList
915
+
916
+ function addToken (tokenType, tokenValue) {
917
+ t = grammar[tokenType];
918
+ //tokenType = t.tokenType;
919
+
920
+ // handling of special cases
921
+ // check format
922
+ if (t.format && !t.format.test(tokenValue)) tokenType = "UNKNOWN";
923
+ // delimited token (e.g. by ")
924
+ if (t.delimited) skipThisCharacter = true;
925
+
926
+ // reserved words
927
+ if ( !t.delimited ) {
928
+ for ( var anotherToken in grammar ) {
929
+ if ( grammar[anotherToken].reservedWord
930
+ && anotherToken == tokenValue ) {
931
+ tokenType = anotherToken;
932
+ }
933
+ }
934
+ }
935
+
936
+ // reset t
937
+ t = grammar[tokenType];
938
+ // remembering count type
939
+ if ( t && t.rememberCount ) {
940
+ if (!rememberCount[tokenType]) rememberCount[tokenType] = 0;
941
+ tokenValue = rememberCount[tokenType];
942
+ rememberCount[tokenType] += 1;
943
+ }
944
+
945
+ // push token to list
946
+ tokenList.push( {tokenType: tokenType, tokenValue: tokenValue} );
947
+
948
+ // and clean up currentToken
949
+ currentToken = null;
950
+ currentTokenType = null;
951
+ currentTokenValue = null;
952
+ }
953
+
954
+
955
+ // stepping through the string:
956
+
957
+ if (!inputString) return [];
958
+
959
+ var iStLength = inputString.length;
960
+
961
+ for (var i=0; i < iStLength; i++) {
962
+
963
+ // end reached?
964
+ endOfString = (i===iStLength-1);
965
+
966
+ // current character
967
+ c = inputString.charAt(i);
968
+
969
+ <<<<<<< HEAD
970
+ // set true after end of delimeted token so that
971
+ // final delimeter is not caught again
972
+ =======
973
+ // set true after end of delimited token so that
974
+ // final delimiter is not catched again
975
+ >>>>>>> Fixed called_buildInDidFinsih in a test, delimeter to delimiter in code and comments, raidus to radius in css, stylsheet to stylesheet in css comments, and added several missing .png extensions in css image references
976
+ skipThisCharacter = false;
977
+
978
+
979
+ // if currently inside a token
980
+
981
+ if ( currentToken ) {
982
+
983
+ // some helpers
984
+ t = grammar[currentToken];
985
+ endOfToken = t.delimited ? c===currentDelimiter : t.notAllowed.test(c);
986
+
987
+ // if still in token
988
+ if ( !endOfToken ) currentTokenValue += c;
989
+
990
+ // if end of token reached
991
+ if (endOfToken || endOfString) {
992
+ addToken(currentToken, currentTokenValue);
993
+ }
994
+
995
+ // if end of string don't check again
996
+ if ( endOfString && !endOfToken ) skipThisCharacter = true;
997
+ }
998
+
999
+ // if not inside a token, look for next one
1000
+
1001
+ if ( !currentToken && !skipThisCharacter ) {
1002
+ // look for matching tokenType
1003
+ for ( token in grammar ) {
1004
+ t = grammar[token];
1005
+ if (t.firstCharacter && t.firstCharacter.test(c)) {
1006
+ currentToken = token;
1007
+ }
1008
+ }
1009
+
1010
+ // if tokenType found
1011
+ if ( currentToken ) {
1012
+ t = grammar[currentToken];
1013
+ currentTokenValue = c;
1014
+ // handling of special cases
1015
+ if ( t.delimited ) {
1016
+ currentTokenValue = "";
1017
+ if ( t.lastCharacter ) currentDelimiter = t.lastCharacter;
1018
+ else currentDelimiter = c;
1019
+ }
1020
+
1021
+ if ( t.singleCharacter || endOfString ) {
1022
+ addToken(currentToken, currentTokenValue);
1023
+ }
1024
+ }
1025
+ }
1026
+ }
1027
+
1028
+ return tokenList;
1029
+ },
1030
+
1031
+
1032
+
1033
+ // ..........................................................
1034
+ // BUILD TOKEN TREE
1035
+ //
1036
+
1037
+ /**
1038
+ Takes an array of tokens and returns a tree, depending on the
1039
+ specified tree logic. The returned object will have an error property
1040
+ if building of the tree failed. Check it to get some information
1041
+ about what happend.
1042
+ If everything worked, the tree can be evaluated by calling
1043
+
1044
+ tree.evaluate(record, parameters)
1045
+
1046
+ If `tokenList` is empty, a single token will be returned which will
1047
+ evaluate to true for all records.
1048
+
1049
+ @param {Array} tokenList the list of tokens
1050
+ @param {Object} treeLogic the logic definition (normally queryLanguage)
1051
+ @returns {Object} token tree
1052
+ */
1053
+ buildTokenTree: function (tokenList, treeLogic) {
1054
+
1055
+ var l = tokenList.slice();
1056
+ var i = 0;
1057
+ var openParenthesisStack = [];
1058
+ var shouldCheckAgain = false;
1059
+ var error = [];
1060
+
1061
+
1062
+ // empty tokenList is a special case
1063
+ if (!tokenList || tokenList.length === 0) {
1064
+ return { evaluate: function(){ return true; } };
1065
+ }
1066
+
1067
+
1068
+ // some helper functions
1069
+
1070
+ function tokenLogic (position) {
1071
+ var p = position;
1072
+ if ( p < 0 ) return false;
1073
+
1074
+ var tl = treeLogic[l[p].tokenType];
1075
+
1076
+ if ( ! tl ) {
1077
+ error.push("logic for token '"+l[p].tokenType+"' is not defined");
1078
+ return false;
1079
+ }
1080
+
1081
+ // save evaluate in token, so that we don't have
1082
+ // to look it up again when evaluating the tree
1083
+ l[p].evaluate = tl.evaluate;
1084
+ return tl;
1085
+ }
1086
+
1087
+ function expectedType (side, position) {
1088
+ var p = position;
1089
+ var tl = tokenLogic(p);
1090
+ if ( !tl ) return false;
1091
+ if (side == 'left') return tl.leftType;
1092
+ if (side == 'right') return tl.rightType;
1093
+ }
1094
+
1095
+ function evalType (position) {
1096
+ var p = position;
1097
+ var tl = tokenLogic(p);
1098
+ if ( !tl ) return false;
1099
+ else return tl.evalType;
1100
+ }
1101
+
1102
+ function removeToken (position) {
1103
+ l.splice(position, 1);
1104
+ if ( position <= i ) i--;
1105
+ }
1106
+
1107
+ function preceedingTokenExists (position) {
1108
+ var p = position || i;
1109
+ if ( p > 0 ) return true;
1110
+ else return false;
1111
+ }
1112
+
1113
+ function tokenIsMissingChilds (position) {
1114
+ var p = position;
1115
+ if ( p < 0 ) return true;
1116
+ return (expectedType('left',p) && !l[p].leftSide)
1117
+ || (expectedType('right',p) && !l[p].rightSide);
1118
+ }
1119
+
1120
+ function typesAreMatching (parent, child) {
1121
+ var side = (child < parent) ? 'left' : 'right';
1122
+ if ( parent < 0 || child < 0 ) return false;
1123
+ if ( !expectedType(side,parent) ) return false;
1124
+ if ( !evalType(child) ) return false;
1125
+ if ( expectedType(side,parent) == evalType(child) ) return true;
1126
+ else return false;
1127
+ }
1128
+
1129
+ function preceedingTokenCanBeMadeChild (position) {
1130
+ var p = position;
1131
+ if ( !tokenIsMissingChilds(p) ) return false;
1132
+ if ( !preceedingTokenExists(p) ) return false;
1133
+ if ( typesAreMatching(p,p-1) ) return true;
1134
+ else return false;
1135
+ }
1136
+
1137
+ function preceedingTokenCanBeMadeParent (position) {
1138
+ var p = position;
1139
+ if ( tokenIsMissingChilds(p) ) return false;
1140
+ if ( !preceedingTokenExists(p) ) return false;
1141
+ if ( !tokenIsMissingChilds(p-1) ) return false;
1142
+ if ( typesAreMatching(p-1,p) ) return true;
1143
+ else return false;
1144
+ }
1145
+
1146
+ function makeChild (position) {
1147
+ var p = position;
1148
+ if (p<1) return false;
1149
+ l[p].leftSide = l[p-1];
1150
+ removeToken(p-1);
1151
+ }
1152
+
1153
+ function makeParent (position) {
1154
+ var p = position;
1155
+ if (p<1) return false;
1156
+ l[p-1].rightSide = l[p];
1157
+ removeToken(p);
1158
+ }
1159
+
1160
+ function removeParenthesesPair (position) {
1161
+ removeToken(position);
1162
+ removeToken(openParenthesisStack.pop());
1163
+ }
1164
+
1165
+ // step through the tokenList
1166
+
1167
+ for (i=0; i < l.length; i++) {
1168
+ shouldCheckAgain = false;
1169
+
1170
+ if ( l[i].tokenType == 'UNKNOWN' ) {
1171
+ error.push('found unknown token: '+l[i].tokenValue);
1172
+ }
1173
+
1174
+ if ( l[i].tokenType == 'OPEN_PAREN' ) openParenthesisStack.push(i);
1175
+ if ( l[i].tokenType == 'CLOSE_PAREN' ) removeParenthesesPair(i);
1176
+
1177
+ if ( preceedingTokenCanBeMadeChild(i) ) makeChild(i);
1178
+
1179
+ if ( preceedingTokenCanBeMadeParent(i) ){
1180
+ makeParent(i);
1181
+ shouldCheckAgain = true;
1182
+ }
1183
+
1184
+ if ( shouldCheckAgain ) i--;
1185
+
1186
+ }
1187
+
1188
+ // error if tokenList l is not a single token now
1189
+ if (l.length == 1) l = l[0];
1190
+ else error.push('string did not resolve to a single tree');
1191
+
1192
+ // error?
1193
+ if (error.length > 0) return {error: error.join(',\n'), tree: l};
1194
+ // everything fine - token list is now a tree and can be returned
1195
+ else return l;
1196
+
1197
+ },
1198
+
1199
+
1200
+ // ..........................................................
1201
+ // ORDERING
1202
+ //
1203
+
1204
+ /**
1205
+ Takes a string containing an order statement and returns an array
1206
+ describing this order for easier processing.
1207
+ Called by `parse()`.
1208
+
1209
+ @param {String | Function} orderOp the string containing the order statement, or a comparison function
1210
+ @returns {Array | Function} array of order statement, or a function if a function was specified
1211
+ */
1212
+ buildOrder: function (orderOp) {
1213
+ if (!orderOp) {
1214
+ return [];
1215
+ }
1216
+ else if (SC.typeOf(orderOp) === SC.T_FUNCTION) {
1217
+ return orderOp;
1218
+ }
1219
+ else {
1220
+ var o = orderOp.split(',');
1221
+ for (var i=0; i < o.length; i++) {
1222
+ var p = o[i];
1223
+ p = p.replace(/^\s+|\s+$/,'');
1224
+ p = p.replace(/\s+/,',');
1225
+ p = p.split(',');
1226
+ o[i] = {propertyName: p[0]};
1227
+ if (p[1] && p[1] == 'DESC') o[i].descending = true;
1228
+ }
1229
+
1230
+ return o;
1231
+ }
1232
+
1233
+ }
1234
+
1235
+ });
1236
+
1237
+
1238
+ // Class Methods
1239
+ SC.Query.mixin( /** @scope SC.Query */ {
1240
+
1241
+ /**
1242
+ Constant used for `SC.Query#location`
1243
+
1244
+ @type String
1245
+ */
1246
+ LOCAL: 'local',
1247
+
1248
+ /**
1249
+ Constant used for `SC.Query#location`
1250
+
1251
+ @type String
1252
+ */
1253
+ REMOTE: 'remote',
1254
+
1255
+ /**
1256
+ Given a query, returns the associated `storeKey`. For the inverse of this
1257
+ method see `SC.Store.queryFor()`.
1258
+
1259
+ @param {SC.Query} query the query
1260
+ @returns {Number} a storeKey.
1261
+ */
1262
+ storeKeyFor: function(query) {
1263
+ return query ? query.get('storeKey') : null;
1264
+ },
1265
+
1266
+ /**
1267
+ Will find which records match a give `SC.Query` and return an array of
1268
+ store keys. This will also apply the sorting for the query.
1269
+
1270
+ @param {SC.Query} query to apply
1271
+ @param {SC.RecordArray} records to search within
1272
+ @param {SC.Store} store to materialize record from
1273
+ @returns {Array} array instance of store keys matching the SC.Query (sorted)
1274
+ */
1275
+ containsRecords: function(query, records, store) {
1276
+ var ret = [];
1277
+ for(var idx=0,len=records.get('length');idx<len;idx++) {
1278
+ var record = records.objectAt(idx);
1279
+ if(record && query.contains(record)) {
1280
+ ret.push(record.get('storeKey'));
1281
+ }
1282
+ }
1283
+
1284
+ ret = SC.Query.orderStoreKeys(ret, query, store);
1285
+
1286
+ return ret;
1287
+ },
1288
+
1289
+ /**
1290
+ Sorts a set of store keys according to the orderBy property
1291
+ of the `SC.Query`.
1292
+
1293
+ @param {Array} storeKeys to sort
1294
+ @param {SC.Query} query to use for sorting
1295
+ @param {SC.Store} store to materialize records from
1296
+ @returns {Array} sorted store keys. may be same instance as passed value
1297
+ */
1298
+ orderStoreKeys: function(storeKeys, query, store) {
1299
+ // apply the sort if there is one
1300
+ if (storeKeys) {
1301
+ var res = storeKeys.sort(function(a, b) {
1302
+ return SC.Query.compareStoreKeys(query, store, a, b);
1303
+ });
1304
+ }
1305
+
1306
+ return storeKeys;
1307
+ },
1308
+
1309
+ /**
1310
+ Default sort method that is used when calling `containsStoreKeys()`
1311
+ or `containsRecords()` on this query. Simply materializes two records
1312
+ based on `storekey`s before passing on to `compare()`.
1313
+
1314
+ @param {Number} storeKey1 a store key
1315
+ @param {Number} storeKey2 a store key
1316
+ @returns {Number} -1 if record1 < record2, +1 if record1 > record2, 0 if equal
1317
+ */
1318
+ compareStoreKeys: function(query, store, storeKey1, storeKey2) {
1319
+ var record1 = store.materializeRecord(storeKey1),
1320
+ record2 = store.materializeRecord(storeKey2);
1321
+
1322
+ return query.compare(record1, record2);
1323
+ },
1324
+
1325
+ /**
1326
+ Returns a `SC.Query` instance reflecting the passed properties. Where
1327
+ possible this method will return cached query instances so that multiple
1328
+ calls to this method will return the same instance. This is not possible
1329
+ however, when you pass custom parameters or set ordering. All returned
1330
+ queries are frozen.
1331
+
1332
+ Usually you will not call this method directly. Instead use the more
1333
+ convenient `SC.Query.local()` and `SC.Query.remote()`.
1334
+
1335
+ Examples
1336
+
1337
+ There are a number of different ways you can call this method.
1338
+
1339
+ The following return local queries selecting all records of a particular
1340
+ type or types, including any subclasses:
1341
+
1342
+ var people = SC.Query.local(Ab.Person);
1343
+ var peopleAndCompanies = SC.Query.local([Ab.Person, Ab.Company]);
1344
+
1345
+ var people = SC.Query.local('Ab.Person');
1346
+ var peopleAndCompanies = SC.Query.local('Ab.Person Ab.Company'.w());
1347
+
1348
+ var allRecords = SC.Query.local(SC.Record);
1349
+
1350
+ The following will match a particular type of condition:
1351
+
1352
+ var married = SC.Query.local(Ab.Person, "isMarried=YES");
1353
+ var married = SC.Query.local(Ab.Person, "isMarried=%@", [YES]);
1354
+ var married = SC.Query.local(Ab.Person, "isMarried={married}", {
1355
+ married: YES
1356
+ });
1357
+
1358
+ You can also pass a hash of options as the second parameter. This is
1359
+ how you specify an order, for example:
1360
+
1361
+ var orderedPeople = SC.Query.local(Ab.Person, { orderBy: "firstName" });
1362
+
1363
+ @param {String} location the query location.
1364
+ @param {SC.Record|Array} recordType the record type or types.
1365
+ @param {String} conditions optional conditions
1366
+ @param {Hash} params optional params. or pass multiple args.
1367
+ @returns {SC.Query}
1368
+ */
1369
+ build: function(location, recordType, conditions, params) {
1370
+
1371
+ var opts = null,
1372
+ ret, cache, key, tmp;
1373
+
1374
+ // fast case for query objects.
1375
+ if (recordType && recordType.isQuery) {
1376
+ if (recordType.get('location') === location) return recordType;
1377
+ else return recordType.copy().set('location', location).freeze();
1378
+ }
1379
+
1380
+ // normalize recordType
1381
+ if (typeof recordType === SC.T_STRING) {
1382
+ ret = SC.objectForPropertyPath(recordType);
1383
+ if (!ret) throw "%@ did not resolve to a class".fmt(recordType);
1384
+ recordType = ret ;
1385
+ } else if (recordType && recordType.isEnumerable) {
1386
+ ret = [];
1387
+ recordType.forEach(function(t) {
1388
+ if (typeof t === SC.T_STRING) t = SC.objectForPropertyPath(t);
1389
+ if (!t) throw "cannot resolve record types: %@".fmt(recordType);
1390
+ ret.push(t);
1391
+ }, this);
1392
+ recordType = ret ;
1393
+ } else if (!recordType) recordType = SC.Record; // find all records
1394
+
1395
+ if (params === undefined) params = null;
1396
+ if (conditions === undefined) conditions = null;
1397
+
1398
+ // normalize other params. if conditions is just a hash, treat as opts
1399
+ if (!params && (typeof conditions !== SC.T_STRING)) {
1400
+ opts = conditions;
1401
+ conditions = null ;
1402
+ }
1403
+
1404
+ // special case - easy to cache.
1405
+ if (!params && !opts) {
1406
+
1407
+ tmp = SC.Query._scq_recordTypeCache;
1408
+ if (!tmp) tmp = SC.Query._scq_recordTypeCache = {};
1409
+ cache = tmp[location];
1410
+ if (!cache) cache = tmp[location] = {};
1411
+
1412
+ if (recordType.isEnumerable) {
1413
+ key = recordType.map(function(k) { return SC.guidFor(k); });
1414
+ key = key.sort().join(':');
1415
+ } else key = SC.guidFor(recordType);
1416
+
1417
+ if (conditions) key = [key, conditions].join('::');
1418
+
1419
+ ret = cache[key];
1420
+ if (!ret) {
1421
+ if (recordType.isEnumerable) {
1422
+ opts = { recordTypes: recordType.copy() };
1423
+ } else opts = { recordType: recordType };
1424
+
1425
+ opts.location = location ;
1426
+ opts.conditions = conditions ;
1427
+ ret = cache[key] = SC.Query.create(opts).freeze();
1428
+ }
1429
+ // otherwise parse extra conditions and handle them
1430
+ } else {
1431
+
1432
+ if (!opts) opts = {};
1433
+ if (!opts.location) opts.location = location ; // allow override
1434
+
1435
+ // pass one or more recordTypes.
1436
+ if (recordType && recordType.isEnumerable) {
1437
+ opts.recordTypes = recordType;
1438
+ } else opts.recordType = recordType;
1439
+
1440
+ // set conditions and params if needed
1441
+ if (conditions) opts.conditions = conditions;
1442
+ if (params) opts.parameters = params;
1443
+
1444
+ ret = SC.Query.create(opts).freeze();
1445
+ }
1446
+
1447
+ return ret ;
1448
+ },
1449
+
1450
+ /**
1451
+ Returns a `LOCAL` query with the passed options. For a full description of
1452
+ the parameters you can pass to this method, see `SC.Query.build()`.
1453
+
1454
+ @param {SC.Record|Array} recordType the record type or types.
1455
+ @param {String} conditions optional conditions
1456
+ @param {Hash} params optional params. or pass multiple args.
1457
+ @returns {SC.Query}
1458
+ */
1459
+ local: function(recordType, conditions, params) {
1460
+ return this.build(SC.Query.LOCAL, recordType, conditions, params);
1461
+ },
1462
+
1463
+ /**
1464
+ Returns a `REMOTE` query with the passed options. For a full description of
1465
+ the parameters you can pass to this method, see `SC.Query.build()`.
1466
+
1467
+ @param {SC.Record|Array} recordType the record type or types.
1468
+ @param {String} conditions optional conditions
1469
+ @param {Hash} params optional params. or pass multiple args.
1470
+ @returns {SC.Query}
1471
+ */
1472
+ remote: function(recordType, conditions, params) {
1473
+ return this.build(SC.Query.REMOTE, recordType, conditions, params);
1474
+ },
1475
+
1476
+ /** @private
1477
+ called by `SC.Record.extend()`. invalidates `expandedRecordTypes`
1478
+ */
1479
+ _scq_didDefineRecordType: function() {
1480
+ var q = SC.Query._scq_queriesWithExpandedRecordTypes;
1481
+ if (q) {
1482
+ q.forEach(function(query) {
1483
+ query.notifyPropertyChange('expandedRecordTypes');
1484
+ }, this);
1485
+ q.clear();
1486
+ }
1487
+ }
1488
+
1489
+ });
1490
+
1491
+
1492
+ /** @private
1493
+ Hash of registered comparisons by property name.
1494
+ */
1495
+ SC.Query.comparisons = {};
1496
+
1497
+ /**
1498
+ Call to register a comparison for a specific property name.
1499
+ The function you pass should accept two values of this property
1500
+ and return -1 if the first is smaller than the second,
1501
+ 0 if they are equal and 1 if the first is greater than the second.
1502
+
1503
+ @param {String} name of the record property
1504
+ @param {Function} custom comparison function
1505
+ @returns {SC.Query} receiver
1506
+ */
1507
+ SC.Query.registerComparison = function(propertyName, comparison) {
1508
+ SC.Query.comparisons[propertyName] = comparison;
1509
+ };
1510
+
1511
+
1512
+ /**
1513
+ Call to register an extension for the query language.
1514
+ You should provide a name for your extension and a definition
1515
+ specifying how it should be parsed and evaluated.
1516
+
1517
+ Have a look at `queryLanguage` for examples of definitions.
1518
+
1519
+ TODO add better documentation here
1520
+
1521
+ @param {String} tokenName name of the operator
1522
+ @param {Object} token extension definition
1523
+ @returns {SC.Query} receiver
1524
+ */
1525
+ SC.Query.registerQueryExtension = function(tokenName, token) {
1526
+ SC.Query.prototype.queryLanguage[tokenName] = token;
1527
+ };
1528
+
1529
+ // shorthand
1530
+ SC.Q = SC.Query.from ;
1531
+