sproutcore 1.5.0.pre.3 → 1.5.0.pre.4

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 (308) hide show
  1. data/.rspec +1 -0
  2. data/CHANGELOG +42 -0
  3. data/README.txt +25 -0
  4. data/VERSION.yml +1 -1
  5. data/bin/sc-build +1 -1
  6. data/bin/sc-build-number +1 -1
  7. data/bin/sc-docs +1 -1
  8. data/bin/sc-gen +1 -1
  9. data/bin/sc-init +1 -1
  10. data/bin/sc-manifest +1 -1
  11. data/bin/sc-server +1 -1
  12. data/bin/sproutcore +1 -1
  13. data/lib/buildtasks/build.rake +5 -0
  14. data/lib/buildtasks/manifest.rake +20 -1
  15. data/lib/frameworks/sproutcore/Buildfile +12 -9
  16. data/lib/frameworks/sproutcore/CHANGELOG.md +48 -0
  17. data/lib/frameworks/sproutcore/apps/greenhouse/README +2 -9
  18. data/lib/frameworks/sproutcore/apps/greenhouse/TODO +11 -27
  19. data/lib/frameworks/sproutcore/apps/greenhouse/controllers/library.js +3 -10
  20. data/lib/frameworks/sproutcore/apps/greenhouse/english.lproj/css/main-page.css +4 -31
  21. data/lib/frameworks/sproutcore/apps/greenhouse/english.lproj/dialogs.js +5 -4
  22. data/lib/frameworks/sproutcore/apps/greenhouse/models/dir.js +3 -3
  23. data/lib/frameworks/sproutcore/apps/greenhouse/models/file.js +2 -2
  24. data/lib/frameworks/sproutcore/apps/greenhouse/states/main.js +31 -14
  25. data/lib/frameworks/sproutcore/apps/greenhouse/states/modals.js +2 -1
  26. data/lib/frameworks/sproutcore/apps/greenhouse/states/ready.js +27 -1
  27. data/lib/frameworks/sproutcore/apps/greenhouse/tests/views/list_item.js +1 -0
  28. data/lib/frameworks/sproutcore/apps/greenhouse/tests/views/plist_item.js +20 -0
  29. data/lib/frameworks/sproutcore/apps/greenhouse/theme.js +25 -0
  30. data/lib/frameworks/sproutcore/apps/greenhouse/views/plist_item.js +161 -24
  31. data/lib/frameworks/sproutcore/apps/greenhouse/views/tear_off_picker.js +1 -1
  32. data/lib/frameworks/sproutcore/frameworks/bootstrap/system/browser.js +37 -25
  33. data/lib/frameworks/sproutcore/frameworks/bootstrap/tests/system/browser.js +135 -26
  34. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/controllers/array.js +0 -0
  35. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/controllers/controller.js +0 -0
  36. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/controllers/object.js +1 -1
  37. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/core.js +0 -0
  38. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/ext/object.js +0 -0
  39. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/ext/run_loop.js +1 -0
  40. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/mixins/delegate_support.js +0 -0
  41. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/mixins/responder_context.js +0 -0
  42. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/mixins/selection_support.js +0 -0
  43. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/mixins/string.js +0 -0
  44. data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/keyboard.js +68 -0
  45. data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/layout.js +108 -0
  46. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/panes/main.js +2 -2
  47. data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/manipulation.js +27 -0
  48. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/panes/pane.js +215 -505
  49. data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/template.js +24 -0
  50. data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/visibility.js +11 -0
  51. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/protocols/observable_protocol.js +0 -0
  52. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/protocols/sparse_array_delegate.js +0 -0
  53. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/resources/core.css +0 -0
  54. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/resources/view.css +0 -0
  55. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/system/application.js +0 -0
  56. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/system/browser.js +1 -0
  57. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/system/builder.js +0 -0
  58. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/system/core_query.js +1 -1
  59. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/system/cursor.js +0 -0
  60. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/device.js +210 -0
  61. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/system/event.js +5 -5
  62. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/system/json.js +0 -0
  63. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/system/locale.js +0 -0
  64. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/system/page.js +0 -0
  65. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/system/platform.js +31 -5
  66. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/system/ready.js +1 -1
  67. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/system/render_context.js +0 -0
  68. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/system/responder.js +0 -0
  69. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/system/root_responder.js +83 -110
  70. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/system/selection_set.js +7 -4
  71. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/system/sparse_array.js +0 -0
  72. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/system/theme.js +0 -0
  73. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/system/timer.js +0 -0
  74. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/system/utils/rect.js +0 -0
  75. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/utils.js +151 -0
  76. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/controllers/array/array_case.js +0 -0
  77. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/controllers/array/enum_case.js +0 -0
  78. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/controllers/array/null_case.js +0 -0
  79. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/controllers/array/selection_support.js +26 -0
  80. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/controllers/array/single_case.js +0 -0
  81. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/controllers/object/empty_case.js +0 -0
  82. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/controllers/object/multiple_case.js +0 -0
  83. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/controllers/object/single_case.js +0 -0
  84. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/controllers/object/single_enumerable_case.js +0 -0
  85. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/mixins/responder_context.js +0 -0
  86. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/mixins/string.js +0 -0
  87. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/panes/template.js +14 -0
  88. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/builder.js +0 -0
  89. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/core_query/within.js +0 -0
  90. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/json.js +0 -0
  91. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/locale.js +0 -0
  92. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/render_context/begin.js +0 -0
  93. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/render_context/element.js +0 -0
  94. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/render_context/end.js +0 -0
  95. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/render_context/get.js +0 -0
  96. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/render_context/helpers_attr.js +0 -0
  97. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/render_context/helpers_basic.js +0 -0
  98. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/render_context/helpers_className.js +0 -0
  99. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/render_context/helpers_style.js +0 -0
  100. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/render_context/init.js +0 -0
  101. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/render_context/join.js +0 -0
  102. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/render_context/push_text.js +0 -0
  103. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/render_context/tag.js +0 -0
  104. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/render_context/update.js +0 -0
  105. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/root_responder/makeKeyPane.js +0 -0
  106. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/root_responder/makeMainPane.js +0 -0
  107. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/root_responder/makeMenuPane.js +0 -0
  108. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/root_responder/root_responder.js +0 -0
  109. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/root_responder/targetForAction.js +0 -0
  110. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/selection_set/add.js +0 -0
  111. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/selection_set/copy.js +0 -0
  112. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/selection_set/indexSetForSource.js +0 -0
  113. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/selection_set/isEqual.js +0 -0
  114. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/selection_set/remove.js +0 -0
  115. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/sparse_array.js +0 -0
  116. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/theme.js +0 -0
  117. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/timer/invalidate.js +0 -0
  118. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/timer/invokeLater.js +0 -0
  119. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/timer/isPaused.js +0 -0
  120. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/timer/performAction.js +0 -0
  121. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/timer/schedule.js +0 -0
  122. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/utils/normalizeURL.js +0 -0
  123. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/utils/offset.js +268 -0
  124. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/system/utils/rect.js +0 -0
  125. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/main_pane.js +43 -0
  126. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/pane/append_remove.js +107 -18
  127. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/pane/child_view.js +20 -0
  128. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/pane/firstResponder.js +0 -0
  129. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/pane/keyPane.js +0 -0
  130. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/pane/layout.js +0 -0
  131. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/pane/sendEvent.js +0 -0
  132. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/template/checkbox_support.js +32 -0
  133. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/template/text_field_support.js +73 -0
  134. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/template_view/collection.js +65 -0
  135. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/template_view/core.js +67 -0
  136. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/template_view/handlebars.js +295 -0
  137. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/view/animation.js +19 -18
  138. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/view/build.js +0 -0
  139. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/view/build_children.js +0 -0
  140. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/view/clippingFrame.js +0 -0
  141. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/view/convertFrames.js +0 -0
  142. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/view/convertLayouts.js +0 -0
  143. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/view/createChildViews.js +18 -15
  144. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/view/createLayer.js +0 -0
  145. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/view/destroyLayer.js +0 -0
  146. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/view/didAppendToDocument.js +11 -8
  147. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/view/findLayerInParentLayer.js +0 -0
  148. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/view/init.js +0 -0
  149. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/view/insertBefore.js +0 -0
  150. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/view/isVisible.js +28 -0
  151. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/view/isVisibleInWindow.js +0 -0
  152. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/keyboard.js +22 -0
  153. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/view/layer.js +0 -0
  154. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/view/layoutChildViews.js +0 -0
  155. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/layoutDidChange.js +180 -0
  156. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/layoutStyle.js +640 -0
  157. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/view/parentViewDidChange.js +0 -0
  158. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/view/prepareContext.js +0 -0
  159. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/view/removeChild.js +0 -0
  160. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/render.js +125 -0
  161. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/view/render_delegate_support.js +0 -0
  162. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/view/replaceChild.js +0 -0
  163. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/static_layout.js +21 -0
  164. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/view/theme.js +0 -0
  165. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/view/updateLayer.js +0 -0
  166. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/view/updateLayerLocation.js +0 -0
  167. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/view/view.js +0 -0
  168. data/lib/frameworks/sproutcore/frameworks/{amber → core_foundation}/tests/views/view/viewDidResize.js +0 -0
  169. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/template/checkbox_support.js +20 -0
  170. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/template/collection.js +99 -0
  171. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/template/text_field_support.js +35 -0
  172. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/template.js +77 -0
  173. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/animation.js +187 -0
  174. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/base.js +1 -0
  175. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/cursor.js +41 -0
  176. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/enabled.js +57 -0
  177. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/keyboard.js +223 -0
  178. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/layout.js +1150 -0
  179. data/lib/frameworks/sproutcore/frameworks/{amber/views → core_foundation/views/view}/layout_style.js +93 -1
  180. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/manipulation.js +489 -0
  181. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/theming.js +362 -0
  182. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/touch.js +67 -0
  183. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/visibility.js +113 -0
  184. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view.js +1280 -0
  185. data/lib/frameworks/sproutcore/frameworks/datastore/models/child_attribute.js +27 -53
  186. data/lib/frameworks/sproutcore/frameworks/datastore/models/children_attribute.js +13 -19
  187. data/lib/frameworks/sproutcore/frameworks/datastore/models/many_attribute.js +1 -0
  188. data/lib/frameworks/sproutcore/frameworks/datastore/models/record.js +183 -71
  189. data/lib/frameworks/sproutcore/frameworks/datastore/models/record_attribute.js +1 -2
  190. data/lib/frameworks/sproutcore/frameworks/datastore/system/child_array.js +26 -46
  191. data/lib/frameworks/sproutcore/frameworks/datastore/system/nested_store.js +25 -4
  192. data/lib/frameworks/sproutcore/frameworks/datastore/system/store.js +139 -21
  193. data/lib/frameworks/sproutcore/frameworks/datastore/tests/data_sources/fixtures.js +6 -1
  194. data/lib/frameworks/sproutcore/frameworks/datastore/tests/integration/cyclical_relationship.js +1 -1
  195. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/nested_records/{parentless.js → data_store.js} +62 -16
  196. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/nested_records/nested_record.js +51 -17
  197. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/nested_records/nested_record_array.js +36 -10
  198. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/nested_records/nested_record_array_complex.js +11 -11
  199. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/nested_records/nested_record_complex.js +8 -8
  200. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/record/normalize.js +2 -2
  201. data/lib/frameworks/sproutcore/frameworks/{foundation/english.lproj → datetime/resources}/strings.js +1 -0
  202. data/lib/frameworks/sproutcore/frameworks/{foundation → datetime}/system/datetime.js +5 -37
  203. data/lib/frameworks/sproutcore/frameworks/{foundation → datetime}/tests/system/datetime.js +1 -0
  204. data/lib/frameworks/sproutcore/frameworks/debug/core.js +1 -1
  205. data/lib/frameworks/sproutcore/frameworks/designer/controllers/designs.js +1 -2
  206. data/lib/frameworks/sproutcore/frameworks/designer/designers/object_designer.js +3 -3
  207. data/lib/frameworks/sproutcore/frameworks/designer/designers/view_designer.js +3 -3
  208. data/lib/frameworks/sproutcore/frameworks/designer/views/designer_drop_target.js +9 -3
  209. data/lib/frameworks/sproutcore/frameworks/desktop/english.lproj/segmented.css +71 -70
  210. data/lib/frameworks/sproutcore/frameworks/desktop/mixins/collection_row_delegate.js +10 -2
  211. data/lib/frameworks/sproutcore/frameworks/desktop/render_delegates/segment.js +4 -19
  212. data/lib/frameworks/sproutcore/frameworks/desktop/render_delegates/segmented.js +33 -14
  213. data/lib/frameworks/sproutcore/frameworks/desktop/system/drag.js +25 -0
  214. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/date_field/ui.js +1 -1
  215. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/segmented/methods.js +25 -103
  216. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/segmented/ui.js +102 -92
  217. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/tab/ui.js +22 -25
  218. data/lib/frameworks/sproutcore/frameworks/desktop/views/collection.js +38 -25
  219. data/lib/frameworks/sproutcore/frameworks/desktop/views/date_field.js +1 -1
  220. data/lib/frameworks/sproutcore/frameworks/desktop/views/scroll.js +1 -1
  221. data/lib/frameworks/sproutcore/frameworks/desktop/views/segment.js +42 -22
  222. data/lib/frameworks/sproutcore/frameworks/desktop/views/segmented.js +513 -230
  223. data/lib/frameworks/sproutcore/frameworks/desktop/views/select_field.js +0 -2
  224. data/lib/frameworks/sproutcore/frameworks/experimental/README.md +23 -0
  225. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/device_motion/README.md +11 -0
  226. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/device_motion/device.js +215 -0
  227. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/device_motion/platform.js +67 -0
  228. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/polymorphism/README.md +34 -0
  229. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/polymorphism/models/polymorphic_single_attribute.js +183 -0
  230. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/polymorphism/models/record.js +23 -0
  231. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/polymorphism/tests/models/polymorphic/single.js +124 -0
  232. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/auto_resize.js +0 -2
  233. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/inner_frame.js +151 -0
  234. data/lib/frameworks/sproutcore/frameworks/foundation/render_delegates/canvas_image.js +27 -17
  235. data/lib/frameworks/sproutcore/frameworks/foundation/system/image_queue.js +6 -3
  236. data/lib/frameworks/sproutcore/frameworks/foundation/system/logger.js +163 -0
  237. data/lib/frameworks/sproutcore/frameworks/foundation/system/user_defaults.js +6 -3
  238. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/inline_text_field/beginEditing.js +1 -0
  239. data/lib/frameworks/sproutcore/frameworks/foundation/tests/system/logger.js +44 -0
  240. data/lib/frameworks/sproutcore/frameworks/foundation/tests/views/image/ui.js +200 -167
  241. data/lib/frameworks/sproutcore/frameworks/foundation/tests/views/text_field/ui.js +1 -1
  242. data/lib/frameworks/sproutcore/frameworks/foundation/views/image.js +52 -137
  243. data/lib/frameworks/sproutcore/frameworks/foundation/views/text_field.js +7 -11
  244. data/lib/frameworks/sproutcore/frameworks/handlebars/extensions.js +138 -0
  245. data/lib/frameworks/sproutcore/frameworks/handlebars/handlebars.js +1338 -0
  246. data/lib/frameworks/sproutcore/frameworks/runtime/core.js +32 -26
  247. data/lib/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/base.js +162 -3
  248. data/lib/frameworks/sproutcore/frameworks/runtime/mixins/array.js +10 -5
  249. data/lib/frameworks/sproutcore/frameworks/runtime/mixins/enumerable.js +123 -3
  250. data/lib/frameworks/sproutcore/frameworks/runtime/mixins/observable.js +12 -5
  251. data/lib/frameworks/sproutcore/frameworks/runtime/private/chain_observer.js +50 -13
  252. data/lib/frameworks/sproutcore/frameworks/runtime/system/logger.js +163 -333
  253. data/lib/frameworks/sproutcore/frameworks/runtime/system/object.js +58 -8
  254. data/lib/frameworks/sproutcore/frameworks/runtime/system/run_loop.js +2 -0
  255. data/lib/frameworks/sproutcore/frameworks/runtime/tests/core/itemType.js +9 -6
  256. data/lib/frameworks/sproutcore/frameworks/runtime/tests/core/makeArray.js +15 -1
  257. data/lib/frameworks/sproutcore/frameworks/runtime/tests/mixins/array.js +2 -0
  258. data/lib/frameworks/sproutcore/frameworks/runtime/tests/mixins/observable/chained.js +31 -0
  259. data/lib/frameworks/sproutcore/frameworks/runtime/tests/mixins/observable/observable.js +18 -0
  260. data/lib/frameworks/sproutcore/frameworks/runtime/tests/system/logger.js +31 -143
  261. data/lib/frameworks/sproutcore/frameworks/runtime/tests/system/object/concatenated_properties.js +71 -0
  262. data/lib/frameworks/sproutcore/frameworks/runtime/tests/system/object/enhance.js +177 -0
  263. data/lib/frameworks/sproutcore/frameworks/table/views/table.js +5 -4
  264. data/lib/frameworks/sproutcore/frameworks/table/views/table_header.js +5 -3
  265. data/lib/frameworks/sproutcore/themes/ace/resources/button/button.js +8 -2
  266. data/lib/frameworks/sproutcore/themes/ace/resources/menu/menu.css +2 -3
  267. data/lib/frameworks/sproutcore/themes/ace/resources/segmented/18px/segmented.css +1 -1
  268. data/lib/frameworks/sproutcore/themes/ace/resources/segmented/24px/segmented.css +1 -1
  269. data/lib/frameworks/sproutcore/themes/ace/resources/segmented/30px/segmented.css +1 -1
  270. data/lib/frameworks/sproutcore/themes/ace/resources/segmented/44px/segmented.css +1 -1
  271. data/lib/frameworks/sproutcore/themes/ace/resources/segmented/segmented.css +2 -2
  272. data/lib/frameworks/sproutcore/themes/standard_theme/english.lproj/segmented.css +62 -62
  273. data/lib/gen/html_app/Buildfile +36 -0
  274. data/lib/gen/html_app/README +1 -0
  275. data/lib/gen/html_app/USAGE +15 -0
  276. data/lib/gen/html_app/templates/apps/@target_name@/@target_name@.js +14 -0
  277. data/lib/gen/html_app/templates/apps/@target_name@/resources/images/.gitkeep +0 -0
  278. data/lib/gen/html_app/templates/apps/@target_name@/resources/stylesheets/@target_name@.css +0 -0
  279. data/lib/gen/html_app/templates/apps/@target_name@/resources/templates/@target_name@.handlebars +1 -0
  280. data/lib/gen/html_project/Buildfile +45 -0
  281. data/lib/gen/html_project/INIT +3 -0
  282. data/lib/gen/html_project/README +1 -0
  283. data/lib/gen/html_project/USAGE +2 -0
  284. data/lib/gen/html_project/templates/@filename@/Buildfile +8 -0
  285. data/lib/gen/html_project/templates/@filename@/README +7 -0
  286. data/lib/sproutcore/builders/handlebars.rb +30 -0
  287. data/lib/sproutcore/builders.rb +1 -1
  288. data/lib/sproutcore/helpers/static_helper.rb +3 -3
  289. data/lib/sproutcore/tools/init.rb +25 -9
  290. data/spec/buildtasks/manifest/prepare_build_tasks/handlebars_spec.rb +39 -0
  291. data/spec/fixtures/builder_tests/apps/handlebars_test/template.handlebars +5 -0
  292. data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/templates/demo.handlebars +4 -0
  293. data/spec/lib/builders/handlebars_spec.rb +29 -0
  294. data/vendor/chance/lib/chance/imagers/data_url.rb +20 -7
  295. data/vendor/chance/lib/chance/instance.rb +4 -1
  296. data/vendor/chance/lib/chance/parser.rb +31 -31
  297. data/vendor/chance/lib/chance/slicing.rb +38 -8
  298. metadata +195 -225
  299. data/lib/frameworks/sproutcore/frameworks/amber/system/device.js +0 -143
  300. data/lib/frameworks/sproutcore/frameworks/amber/system/utils.js +0 -174
  301. data/lib/frameworks/sproutcore/frameworks/amber/tests/views/main_pane.js +0 -31
  302. data/lib/frameworks/sproutcore/frameworks/amber/tests/views/pane/sendTouchEvent.js +0 -267
  303. data/lib/frameworks/sproutcore/frameworks/amber/tests/views/view/layoutDidChange.js +0 -149
  304. data/lib/frameworks/sproutcore/frameworks/amber/tests/views/view/layoutStyle.js +0 -602
  305. data/lib/frameworks/sproutcore/frameworks/amber/tests/views/view/render.js +0 -115
  306. data/lib/frameworks/sproutcore/frameworks/amber/views/base.js +0 -1
  307. data/lib/frameworks/sproutcore/frameworks/amber/views/view.js +0 -4003
  308. data/lib/frameworks/sproutcore/frameworks/datastore/models/child_record.js +0 -105
@@ -10,24 +10,24 @@
10
10
 
11
11
  SegmentedView is a special type of button that can display multiple
12
12
  segments. Each segment has a value assigned to it. When the user clicks
13
- on the segment, the value of that segment will become the new value of
13
+ on the segment, the value of that segment will become the new value of
14
14
  the control.
15
-
15
+
16
16
  You can also optionally configure a target/action that will fire whenever
17
17
  the user clicks on an item. This will give your code an opportunity to take
18
18
  some action depending on the new value. (of course, you can always bind to
19
19
  the value as well, which is generally the preferred approach.)
20
-
20
+
21
21
  h1. Defining Your Segments
22
-
22
+
23
23
  You define your segments by providing a items array, much like you provide
24
- to a RadioView. Your items array can be as simple as an array of strings
24
+ to a RadioView. Your items array can be as simple as an array of strings
25
25
  or as complex as full model objects. Based on how you configure your
26
- itemKey properties, the segmented view will read the properties it needs
26
+ itemKey properties, the segmented view will read the properties it needs
27
27
  from the array and construct the button.
28
-
28
+
29
29
  You can define the following properties on objects you pass in:
30
-
30
+
31
31
  | *itemTitleKey* | the title of the button |
32
32
  | *itemValueKey* | the value of the button |
33
33
  | *itemWidthKey* | the preferred width. if omitted, it autodetects |
@@ -40,19 +40,19 @@
40
40
  */
41
41
  SC.SegmentedView = SC.View.extend(SC.Control,
42
42
  /** @scope SC.SegmentedView.prototype */ {
43
-
43
+
44
44
  classNames: ['sc-segmented-view'],
45
-
45
+
46
46
  theme: 'square',
47
-
47
+
48
48
  /**
49
49
  The value of the segmented view.
50
-
50
+
51
51
  The SegmentedView's value will always be the value of the currently
52
- selected button. Setting this value will change the selected button.
52
+ selected button. Setting this value will change the selected button.
53
53
  If you set this value to something that has no matching button, then
54
54
  no buttons will be selected.
55
-
55
+
56
56
  @field {Object}
57
57
  */
58
58
  value: null,
@@ -60,14 +60,14 @@ SC.SegmentedView = SC.View.extend(SC.Control,
60
60
  /**
61
61
  Set to YES to enabled the segmented view, NO to disabled it.
62
62
  */
63
- isEnabled: YES,
63
+ isEnabled: YES,
64
64
 
65
65
  /**
66
66
  If YES, clicking a selected button again will deselect it, setting the
67
67
  segmented views value to null. Defaults to NO.
68
68
  */
69
- allowsEmptySelection: NO,
70
-
69
+ allowsEmptySelection: NO,
70
+
71
71
  /**
72
72
  If YES, then clicking on a tab will not deselect the other segments, it
73
73
  will simply add or remove it from the selection.
@@ -78,124 +78,163 @@ SC.SegmentedView = SC.View.extend(SC.Control,
78
78
  If YES, titles will be localized before display.
79
79
  */
80
80
  localize: YES,
81
-
81
+
82
+ /**
83
+ Aligns the segments of the segmented view within its frame horizontally.
84
+ */
82
85
  align: SC.ALIGN_CENTER,
83
-
86
+
84
87
  /**
85
88
  Change the layout direction to make this a vertical set of tabs instead
86
89
  of horizontal ones.
87
90
  */
88
91
  layoutDirection: SC.LAYOUT_HORIZONTAL,
89
-
92
+
90
93
  // ..........................................................
91
94
  // SEGMENT DEFINITION
92
95
  //
93
-
96
+
94
97
  /**
95
98
  The array of items to display. This may be a simple array of strings, objects
96
99
  or SC.Objects. If you pass objects or SC.Objects, you must also set the
97
100
  various itemKey properties to tell the SegmentedView how to extract the
98
101
  information it needs.
99
-
100
- Note: only SC.Object items support key-value coding and therefore can be
101
- observered by the view for changes to titles, values, icons, widths,
102
+
103
+ Note: only SC.Object items support key-value coding and therefore may be
104
+ observed by the view for changes to titles, values, icons, widths,
102
105
  isEnabled values & tooltips.
103
-
104
- TODO: explain how to notify the view of changes to String & Object items
105
-
106
+
106
107
  @property {Array}
107
108
  */
108
109
  items: null,
109
110
 
110
- /**
111
+ /**
111
112
  The key that contains the title for each item.
112
-
113
+
113
114
  @property {String}
114
115
  */
115
116
  itemTitleKey: null,
116
-
117
- /**
117
+
118
+ /**
118
119
  The key that contains the value for each item.
119
-
120
+
120
121
  @property {String}
121
122
  */
122
123
  itemValueKey: null,
123
-
124
- /**
124
+
125
+ /**
125
126
  A key that determines if this item in particular is enabled. Note if the
126
127
  control in general is not enabled, no items will be enabled, even if the
127
128
  item's enabled property returns YES.
128
-
129
+
129
130
  @property {String}
130
131
  */
131
132
  itemIsEnabledKey: null,
132
133
 
133
- /**
134
+ /**
134
135
  The key that contains the icon for each item. If omitted, no icons will
135
136
  be displayed.
136
-
137
+
137
138
  @property {String}
138
139
  */
139
140
  itemIconKey: null,
140
141
 
141
- /**
142
+ /**
142
143
  The key that contains the desired width for each item. If omitted, the
143
144
  width will autosize.
144
-
145
+
145
146
  @property {String}
146
147
  */
147
148
  itemWidthKey: null,
148
-
149
- /**
150
- The key that contains the action for this item. If defined, then
151
- selecting this item will fire the action in addition to changing the
149
+
150
+ /**
151
+ The key that contains the action for this item. If defined, then
152
+ selecting this item will fire the action in addition to changing the
152
153
  value. See also itemTargetKey.
153
-
154
+
154
155
  @property {String}
155
156
  */
156
157
  itemActionKey: null,
157
158
 
158
- /**
159
+ /**
159
160
  The key that contains the target for this item. If this and itemActionKey
160
- are defined, then this will be the target of the action fired.
161
-
161
+ are defined, then this will be the target of the action fired.
162
+
162
163
  @property {String}
163
164
  */
164
165
  itemTargetKey: null,
165
166
 
166
- /**
167
+ /**
167
168
  The key that contains the key equivalent for each item. If defined then
168
- pressing that key equivalent will be like selecting the tab. Also,
169
- pressing the Alt or Option key for 3 seconds will display the key
169
+ pressing that key equivalent will be like selecting the tab. Also,
170
+ pressing the Alt or Option key for 3 seconds will display the key
170
171
  equivalent in the tab.
171
172
  */
172
173
  itemKeyEquivalentKey: null,
173
-
174
+
175
+ /**
176
+ The title to use for the overflow segment if it appears.
177
+
178
+ @property {String}
179
+ */
180
+ overflowTitle: '»',
181
+
182
+ /**
183
+ The toolTip to use for the overflow segment if it appears.
184
+
185
+ @property {String}
186
+ */
187
+ overflowToolTip: 'More…',
188
+
189
+ /**
190
+ The icon to use for the overflow segment if it appears.
191
+
192
+ @property {String}
193
+ */
194
+ overflowIcon: null,
195
+
174
196
  /** @private
175
197
  The following properties are used to map items to child views. Item keys
176
- are looked up on the item based on this view's value for each 'itemKey'.
198
+ are looked up on the item based on this view's value for each 'itemKey'.
177
199
  If a value in the item is found, then that value is mapped to a child
178
200
  view using the matching viewKey.
179
-
201
+
180
202
  @property {Array}
181
203
  */
182
204
  itemKeys: 'itemTitleKey itemValueKey itemIsEnabledKey itemIconKey itemWidthKey itemToolTipKey itemKeyEquivalentKey'.w(),
183
205
  viewKeys: 'title value isEnabled icon width toolTip keyEquivalent'.w(),
184
-
206
+
185
207
  /**
186
208
  Call itemsDidChange once to initialize segment child views for the items that exist at
187
209
  creation time.
188
210
  */
189
211
  init: function() {
190
212
  sc_super();
191
-
213
+
214
+ var title = this.get('overflowTitle'),
215
+ toolTip = this.get('overflowToolTip'),
216
+ icon = this.get('overflowIcon'),
217
+ overflowView;
218
+
219
+ overflowView = SC.SegmentView.create({
220
+ controlSize: this.get('controlSize'),
221
+ localize: this.get('localize'),
222
+ title: title,
223
+ toolTip: toolTip,
224
+ icon: icon,
225
+ isLastSegment: YES,
226
+ isOverflowSegment: YES
227
+ });
228
+
229
+ this.appendChild(overflowView);
230
+
192
231
  this.itemsDidChange();
193
232
  },
194
-
233
+
195
234
  /**
196
235
  Called whenever the number of items changes. This method populates SegmentedView's childViews, taking
197
236
  care to re-use existing childViews if possible.
198
-
237
+
199
238
  */
200
239
  itemsDidChange: function() {
201
240
  var items = this.get('items') || [],
@@ -203,21 +242,22 @@ SC.SegmentedView = SC.View.extend(SC.Control,
203
242
  localItem, // Used to avoid altering the original items
204
243
  childViews = this.get('childViews'),
205
244
  childView,
245
+ overflowView = childViews.lastObject(),
206
246
  value = this.get('value'), // The value can change if items that were once selected are removed
207
247
  isSelected,
208
248
  itemKeys = this.get('itemKeys'),
209
- itemKey,
249
+ itemKey,
210
250
  viewKeys = this.get('viewKeys'),
211
251
  viewKey,
212
252
  i, j;
213
-
214
- // Update childViews
215
- if (childViews.get('length') > items.get('length')) { // We've lost segments (ie. childViews)
216
-
253
+
254
+ // Update childViews
255
+ if (childViews.get('length') - 1 > items.get('length')) { // We've lost segments (ie. childViews)
256
+
217
257
  // Remove unneeded segments from the end back
218
- for (i = childViews.get('length') - 1; i >= items.get('length'); i--) {
258
+ for (i = childViews.get('length') - 2; i >= items.get('length'); i--) {
219
259
  childView = childViews.objectAt(i);
220
-
260
+
221
261
  // If a selected childView has been removed then update our value
222
262
  if (SC.isArray(value)) {
223
263
  value.removeObject(childView.get('value'));
@@ -227,58 +267,58 @@ SC.SegmentedView = SC.View.extend(SC.Control,
227
267
 
228
268
  this.removeChild(childView);
229
269
  }
230
-
270
+
231
271
  // Update our value which may have changed
232
272
  this.set('value', value);
233
-
234
- } else if (childViews.get('length') < items.get('length')) { // We've gained segments
273
+
274
+ } else if (childViews.get('length') - 1 < items.get('length')) { // We've gained segments
235
275
 
236
276
  // Create the new segments
237
- for (i = childViews.get('length'); i < items.get('length'); i++) {
238
-
277
+ for (i = childViews.get('length') - 1; i < items.get('length'); i++) {
278
+
239
279
  // We create a default SC.ButtonView-like object for each segment
240
280
  childView = SC.SegmentView.create({
241
281
  controlSize: this.get('controlSize'),
242
282
  localize: this.get('localize')
243
283
  });
244
-
284
+
245
285
  // Attach the child
246
- this.appendChild(childView);
247
- }
286
+ this.insertBefore(childView, overflowView);
287
+ }
248
288
  }
249
-
250
- // Because the items array can be altered with insertAt or removeAt, we can't be sure that the items
251
- // continue to match 1-to-1 the existing views, so once we have the correct number of childViews,
289
+
290
+ // Because the items array can be altered with insertAt or removeAt, we can't be sure that the items
291
+ // continue to match 1-to-1 the existing views, so once we have the correct number of childViews,
252
292
  // simply update them all
253
293
  childViews = this.get('childViews');
254
-
294
+
255
295
  for (i = 0; i < items.get('length'); i++) {
256
296
  localItem = items.objectAt(i);
257
297
  childView = childViews.objectAt(i);
258
-
298
+
259
299
  // Skip null/undefined items (but don't skip empty strings)
260
300
  if (SC.none(localItem)) continue;
261
-
301
+
262
302
  // Normalize the item (may be a String, Object or SC.Object)
263
303
  if (SC.typeOf(localItem) === SC.T_STRING) {
264
-
304
+
265
305
  localItem = SC.Object.create({
266
306
  'title': localItem.humanize().titleize(),
267
307
  'value': localItem
268
308
  });
269
-
309
+
270
310
  // Update our keys accordingly
271
311
  this.set('itemTitleKey', 'title');
272
312
  this.set('itemValueKey', 'value');
273
313
  } else if (SC.typeOf(localItem) === SC.T_HASH) {
274
-
314
+
275
315
  localItem = SC.Object.create(localItem);
276
316
  } else if (localItem instanceof SC.Object) {
277
-
317
+
278
318
  // We don't need to make any changes to SC.Object items, but we can observe them
279
319
  for (j = itemKeys.get('length') - 1; j >= 0; j--) {
280
320
  itemKey = this.get(itemKeys.objectAt(j));
281
-
321
+
282
322
  if (itemKey) {
283
323
  localItem.removeObserver(itemKey, this, this.itemContentDidChange);
284
324
  localItem.addObserver(itemKey, this, this.itemContentDidChange, i);
@@ -287,26 +327,33 @@ SC.SegmentedView = SC.View.extend(SC.Control,
287
327
  } else {
288
328
  SC.Logger.error('SC.SegmentedView items may be Strings, Objects (ie. Hashes) or SC.Objects only');
289
329
  }
290
-
330
+
291
331
  // Determine whether this segment is selected based on the view's existing value(s)
292
332
  isSelected = NO;
293
333
  if (SC.isArray(value) ? value.indexOf(localItem.get(this.get('itemValueKey'))) >= 0 : value === localItem.get(this.get('itemValueKey'))) {
294
334
  isSelected = YES;
295
335
  }
296
336
  childView.set('isSelected', isSelected);
297
-
337
+
298
338
  // Assign segment specific properties based on position
299
339
  childView.set('index', i);
300
340
  childView.set('isFirstSegment', i === 0);
301
341
  childView.set('isMiddleSegment', i < items.get('length') - 1 && i > 0);
302
342
  childView.set('isLastSegment', i === items.get('length') - 1);
303
-
343
+
304
344
  // Be sure to update the view's properties for the (possibly new) matched item
305
345
  childView.updateItem(this, localItem);
306
346
  }
307
-
347
+
348
+ // Force a segment remeasure to check overflow
349
+ this.invokeLast(this.remeasure);
308
350
  }.observes('*items.[]'),
309
-
351
+
352
+ /**
353
+ This observer method is called whenever any of the relevant properties of an item change. This only applies
354
+ to SC.Object based items that may be observed.
355
+
356
+ */
310
357
  itemContentDidChange: function(item, key, alwaysNull, index) {
311
358
  var items = this.get('items'),
312
359
  childViews = this.get('childViews'),
@@ -314,27 +361,136 @@ SC.SegmentedView = SC.View.extend(SC.Control,
314
361
 
315
362
  childView = childViews.objectAt(index);
316
363
  if (childView) {
317
-
364
+
318
365
  // Update the childView
319
366
  childView.updateItem(this, item);
320
367
  } else {
321
368
  SC.Logger.warn("Item content change was observed on item without matching segment child view.");
322
369
  }
370
+
371
+ // Reset our measurements (which depend on width or title) and adjust visible views
372
+ this.invokeLast(this.remeasure);
373
+ },
374
+
375
+ /**
376
+ Whenever the view resizes, we need to check to see if we're overflowing.
377
+
378
+ */
379
+ viewDidResize: function() {
380
+ var visibleWidth = this.$().width();
381
+
382
+ // Only overflow if we've gone below the minimum width required to fit all the segments
383
+ if (this.isOverflowing || visibleWidth <= this.cachedMinimumWidth) this.adjustOverflow();
323
384
  },
324
-
385
+
386
+ /**
387
+ Whenever visibility changes, we need to check to see if we're overflowing.
388
+
389
+ */
390
+ isVisibleInWindowDidChange: function() {
391
+ this.invokeLast(this.remeasure);
392
+ }.observes('isVisibleInWindow'),
393
+
394
+ /** @private
395
+ Calling this method forces the segments to be remeasured and will also adjust the
396
+ segments for overflow if necessary.
397
+
398
+ */
399
+ remeasure: function() {
400
+ var renderDelegate = this.get('renderDelegate'),
401
+ childViews = this.get('childViews'),
402
+ overflowView;
403
+
404
+ if (this.get('isVisibleInWindow')) {
405
+ // Make all the views visible so that they can be measured
406
+ overflowView = childViews.lastObject();
407
+ overflowView.set('isVisible', YES);
408
+
409
+ for (var i = childViews.get('length') - 1; i >= 0; i--){
410
+ childViews.objectAt(i).set('isVisible', YES);
411
+ }
412
+
413
+ this.cachedWidths = renderDelegate.segmentWidths(this);
414
+ this.cachedOverflowWidth = renderDelegate.overflowSegmentWidth(this);
415
+
416
+ this.adjustOverflow();
417
+ }
418
+ },
419
+
420
+ /** @private
421
+ This method is called to adjust the segment views for overflow.
422
+
423
+ */
424
+ adjustOverflow: function() {
425
+ var childViews = this.get('childViews'),
426
+ childView,
427
+ value = this.get('value'),
428
+ overflowView = childViews.lastObject(),
429
+ visibleWidth = this.$().width(), // The inner width of the div
430
+ curElementsWidth = 0,
431
+ widthToFit,
432
+ length, i;
433
+
434
+ // This variable is useful to optimize when we are overflowing
435
+ this.isOverflowing = NO;
436
+ overflowView.set('isSelected', NO);
437
+
438
+ // Clear out the overflow items (these are the items not currently visible)
439
+ this.overflowItems = [];
440
+
441
+ length = this.cachedWidths.length;
442
+ for (i=0; i < length; i++) {
443
+ childView = childViews.objectAt(i);
444
+ curElementsWidth += this.cachedWidths[i];
445
+
446
+ // check for an overflow (leave room for the overflow segment except for with the last segment)
447
+ widthToFit = (i === length - 1) ? curElementsWidth : curElementsWidth + this.cachedOverflowWidth;
448
+
449
+ if (widthToFit > visibleWidth) {
450
+ // Add the localItem to the overflowItems
451
+ this.overflowItems.pushObject(childView.get('localItem'));
452
+
453
+ // Record that we're now overflowing
454
+ this.isOverflowing = YES;
455
+
456
+ childView.set('isVisible', NO);
457
+
458
+ // If the first item is already overflowed, make the overflowView first segment
459
+ if (i === 0) overflowView.set('isFirstSegment', YES);
460
+
461
+ // If the overflowed segment was selected, show the overflowView as selected instead
462
+ if (SC.isArray(value) ? value.indexOf(childView.get('value')) >= 0 : value === childView.get('value')) {
463
+ overflowView.set('isSelected', YES);
464
+ }
465
+ } else {
466
+ childView.set('isVisible', YES);
467
+
468
+ // If the first item is not overflowed, don't make the overflowView first segment
469
+ if (i === 0) overflowView.set('isFirstSegment', NO);
470
+ }
471
+ }
472
+
473
+ // Show/hide the overflow view if we have overflowed
474
+ if (this.isOverflowing) overflowView.set('isVisible', YES);
475
+ else overflowView.set('isVisible', NO);
476
+
477
+ // Store the minimum width before overflow
478
+ this.cachedMinimumWidth = curElementsWidth + this.cachedOverflowWidth;
479
+ },
480
+
325
481
  // ..........................................................
326
482
  // RENDERING/DISPLAY SUPPORT
327
- //
328
-
483
+ //
484
+
329
485
  displayProperties: ['align'],
330
-
486
+
331
487
  renderDelegateName: 'segmentedRenderDelegate',
332
-
488
+
333
489
  // ..........................................................
334
490
  // EVENT HANDLING
335
- //
336
-
337
- /**
491
+ //
492
+
493
+ /**
338
494
  Determines the index into the displayItems array where the passed mouse
339
495
  event occurred.
340
496
  */
@@ -345,186 +501,224 @@ SC.SegmentedView = SC.View.extend(SC.Control,
345
501
  return renderDelegate.indexForClientPosition(this, evt.clientX, evt.clientY);
346
502
  }
347
503
  },
348
-
504
+
349
505
  keyDown: function(evt) {
506
+ var childViews,
507
+ childView,
508
+ i, length,
509
+ value, isArray;
510
+
350
511
  // handle tab key
351
- var i, item, items, len, value, isArray;
352
512
  if (evt.which === 9 || evt.keyCode === 9) {
353
513
  var view = evt.shiftKey ? this.get('previousValidKeyView') : this.get('nextValidKeyView');
354
514
  if(view) view.becomeFirstResponder();
355
515
  else evt.allowDefault();
356
516
  return YES ; // handled
357
- }
358
- if (!this.get('allowsMultipleSelection') && !this.get('allowsEmptySelection')){
359
- items = this.get('displayItems').slice(0);
360
-
361
- len = items.get('length');
517
+ }
518
+
519
+ // handle arrow keys
520
+ if (!this.get('allowsMultipleSelection')) {
521
+ childViews = this.get('childViews');
522
+
523
+ length = childViews.get('length');
362
524
  value = this.get('value');
363
525
  isArray = SC.isArray(value);
364
- if (evt.which === 39 || evt.which === 40) {
365
- for(i=0; i< len-1; i++){
366
- item=items.objectAt(i);
367
- if( isArray ? (value.indexOf(item.get('value'))>=0) : (item.get('value')===value)){
368
- this.triggerItemAtIndex(i+1);
526
+
527
+ // Select from the left to the right
528
+ if (evt.which === 39 || evt.which === 40) {
529
+
530
+ if (value) {
531
+ for(i = 0; i < length - 2; i++){
532
+ childView = childViews.objectAt(i);
533
+ if ( isArray ? (value.indexOf(childView.get('value'))>=0) : (childView.get('value')===value)){
534
+ this.triggerItemAtIndex(i + 1);
535
+ }
369
536
  }
537
+ } else {
538
+ this.triggerItemAtIndex(0);
370
539
  }
371
540
  return YES ; // handled
372
- }
373
- else if (evt.which === 37 || evt.which === 38) {
374
- for(i=1; i< len; i++){
375
- item=items.objectAt(i);
376
- if( isArray ? (value.indexOf(item.get('value'))>=0) : (item.get('value')===value)){
377
- this.triggerItemAtIndex(i-1);
541
+
542
+ // Select from the right to the left
543
+ } else if (evt.which === 37 || evt.which === 38) {
544
+
545
+ if (value) {
546
+ for(i = 1; i < length - 1; i++) {
547
+ childView = childViews.objectAt(i);
548
+ if ( isArray ? (value.indexOf(childView.get('value'))>=0) : (childView.get('value')===value)){
549
+ this.triggerItemAtIndex(i - 1);
550
+ }
378
551
  }
552
+ } else {
553
+ this.triggerItemAtIndex(length - 2);
379
554
  }
380
- return YES ; // handled
555
+
556
+ return YES; // handled
381
557
  }
382
558
  }
383
- return YES;
559
+
560
+ return NO;
384
561
  },
385
-
562
+
386
563
  mouseDown: function(evt) {
387
564
  var childViews = this.get('childViews'),
388
565
  childView,
566
+ overflowIndex = childViews.get('length') - 1,
389
567
  index;
390
-
568
+
391
569
  if (!this.get('isEnabled')) return YES; // nothing to do
392
-
570
+
393
571
  index = this.displayItemIndexForEvent(evt);
394
- if (index >= 0) {
395
-
396
- childView = childViews[index];
572
+
573
+ if (index >= 0) {
574
+ childView = childViews.objectAt(index);
397
575
  childView.set('isActive', YES);
398
-
399
576
  this.activeChildView = childView;
400
-
401
- // if mouse was pressed on a button, then start detecting pressed events
402
- this._isMouseDown = YES;
577
+
578
+ // if mouse was pressed on the overflow segment, popup the menu
579
+ if (index === overflowIndex) this.showOverflowMenu();
580
+ else this._isMouseDown = YES;
403
581
  }
404
-
405
- return YES ;
582
+
583
+ return YES;
406
584
  },
407
-
585
+
408
586
  mouseUp: function(evt) {
409
587
  var activeChildView,
410
588
  index;
411
-
589
+
412
590
  index = this.displayItemIndexForEvent(evt);
413
-
591
+
414
592
  if (this._isMouseDown && (index >= 0)) {
415
-
416
- // Clean up
593
+
417
594
  this.triggerItemAtIndex(index);
418
-
595
+
596
+ // Clean up
419
597
  activeChildView = this.activeChildView;
420
598
  activeChildView.set('isActive', NO);
421
599
  this.activeChildView = null;
422
-
600
+
423
601
  this._isMouseDown = NO;
424
602
  }
425
-
426
- return YES ;
603
+
604
+ return YES;
427
605
  },
428
-
606
+
429
607
  mouseMoved: function(evt) {
430
608
  var childViews = this.get('childViews'),
609
+ overflowIndex = childViews.get('length') - 1,
431
610
  activeChildView,
432
611
  childView,
433
612
  index;
434
-
613
+
435
614
  if (this._isMouseDown) {
436
615
  // Update the last segment
437
616
  index = this.displayItemIndexForEvent(evt);
438
-
617
+
439
618
  activeChildView = this.activeChildView;
440
- childView = childViews[index];
441
-
619
+ childView = childViews.objectAt(index);
620
+
442
621
  if (childView && childView !== activeChildView) {
443
622
  // Changed
444
623
  if (activeChildView) activeChildView.set('isActive', NO);
445
624
  childView.set('isActive', YES);
446
-
625
+
447
626
  this.activeChildView = childView;
627
+
628
+ if (index === overflowIndex) {
629
+ this.showOverflowMenu();
630
+ this._isMouseDown = NO;
631
+ }
448
632
  }
449
633
  }
450
634
  return YES;
451
635
  },
452
-
636
+
453
637
  mouseEntered: function(evt) {
454
638
  var childViews = this.get('childViews'),
455
639
  childView,
640
+ overflowIndex = childViews.get('length') - 1,
456
641
  index;
457
-
642
+
458
643
  // if mouse was pressed down initially, start detection again
459
644
  if (this._isMouseDown) {
460
645
  index = this.displayItemIndexForEvent(evt);
461
-
462
- if (index >= 0) {
463
- childView = childViews[index];
646
+
647
+ // if mouse was pressed on the overflow segment, popup the menu
648
+ if (index === overflowIndex) {
649
+ this.showOverflowMenu();
650
+ this._isMouseDown = NO;
651
+ } else if (index >= 0) {
652
+ childView = childViews.objectAt(index);
464
653
  childView.set('isActive', YES);
465
-
654
+
466
655
  this.activeChildView = childView;
467
656
  }
468
657
  }
469
658
  return YES;
470
659
  },
471
-
660
+
472
661
  mouseExited: function(evt) {
473
662
  var activeChildView;
474
-
663
+
475
664
  // if mouse was down, hide active index
476
665
  if (this._isMouseDown) {
477
666
  activeChildView = this.activeChildView;
478
667
  if (activeChildView) activeChildView.set('isActive', NO);
479
-
668
+
480
669
  this.activeChildView = null;
481
670
  }
482
-
671
+
483
672
  return YES;
484
673
  },
485
-
674
+
486
675
  touchStart: function(touch) {
487
676
  var childViews = this.get('childViews'),
488
677
  childView,
678
+ overflowIndex = childViews.get('length') - 1,
489
679
  index;
490
-
680
+
491
681
  if (!this.get('isEnabled')) return YES; // nothing to do
492
-
682
+
493
683
  index = this.displayItemIndexForEvent(touch);
494
-
495
- if (index >= 0) {
496
- childView = childViews[index];
684
+
685
+ if (index >= 0) {
686
+ childView = childViews.objectAt(index);
497
687
  childView.set('isActive', YES);
498
688
  this.activeChildView = childView;
499
-
500
- this._isTouching = YES;
689
+
690
+ // if touch was on the overflow segment, popup the menu
691
+ if (index === overflowIndex) this.showOverflowMenu();
692
+ else this._isTouching = YES;
501
693
  }
502
-
694
+
503
695
  return YES ;
504
696
  },
505
-
697
+
506
698
  touchEnd: function(touch) {
507
699
  var activeChildView,
508
700
  index;
509
-
701
+
510
702
  index = this.displayItemIndexForEvent(touch);
511
- // if mouse was pressed on a button then detect where we where when we
512
- // release and use that one.
513
- if (this._isTouching && (index >= 0)) this.triggerItemAtIndex(index);
514
-
515
- // cleanup
516
- activeChildView = this.activeChildView;
517
- activeChildView.set('isActive', NO);
518
- this.activeChildView = null;
519
-
520
- this._isTouching = NO;
521
-
522
- return YES ;
703
+
704
+ if (this._isTouching && (index >= 0)) {
705
+ this.triggerItemAtIndex(index);
706
+
707
+ // Clean up
708
+ activeChildView = this.activeChildView;
709
+ activeChildView.set('isActive', NO);
710
+ this.activeChildView = null;
711
+
712
+ this._isTouching = NO;
713
+ }
714
+
715
+ return YES;
523
716
  },
524
-
717
+
525
718
  touchesDragged: function(evt, touches) {
526
719
  var isTouching = this.touchIsInBoundary(evt),
527
720
  childViews = this.get('childViews'),
721
+ overflowIndex = childViews.get('length') - 1,
528
722
  activeChildView,
529
723
  childView,
530
724
  index;
@@ -534,53 +728,64 @@ SC.SegmentedView = SC.View.extend(SC.Control,
534
728
  this._touchDidEnter(evt);
535
729
  }
536
730
  index = this.displayItemIndexForEvent(evt);
537
-
731
+
538
732
  activeChildView = this.activeChildView;
539
733
  childView = childViews[index];
540
-
734
+
541
735
  if (childView && childView !== activeChildView) {
542
736
  // Changed
543
737
  if (activeChildView) activeChildView.set('isActive', NO);
544
738
  childView.set('isActive', YES);
545
-
739
+
546
740
  this.activeChildView = childView;
741
+
742
+ if (index === overflowIndex) {
743
+ this.showOverflowMenu();
744
+ this._isMouseDown = NO;
745
+ }
547
746
  }
548
747
  } else {
549
748
  if (this._isTouching) this._touchDidExit(evt);
550
749
  }
551
-
750
+
552
751
  this._isTouching = isTouching;
553
-
752
+
554
753
  return YES;
555
754
  },
556
-
755
+
557
756
  _touchDidExit: function(evt) {
558
757
  var activeChildView;
559
-
560
- activeChildView = this.activeChildView;
561
- activeChildView.set('isActive', NO);
562
- this.activeChildView = null;
758
+
759
+ if (this.isTouching) {
760
+ activeChildView = this.activeChildView;
761
+ activeChildView.set('isActive', NO);
762
+ this.activeChildView = null;
763
+ }
563
764
 
564
765
  return YES;
565
766
  },
566
-
767
+
567
768
  _touchDidEnter: function(evt) {
568
769
  var childViews = this.get('childViews'),
569
770
  childView,
771
+ overflowIndex = childViews.get('length') - 1,
570
772
  index;
571
-
773
+
572
774
  index = this.displayItemIndexForEvent(evt);
573
-
574
- if (index >= 0) {
575
- childView = childViews[index];
775
+
776
+ if (index === overflowIndex) {
777
+ this.showOverflowMenu();
778
+ this._isTouching = NO;
779
+ } else if (index >= 0) {
780
+ childView = childViews.objectAt(index);
576
781
  childView.set('isActive', YES);
577
782
  this.activeChildView = childView;
578
783
  }
579
-
784
+
580
785
  return YES;
581
786
  },
582
787
 
583
- /**
788
+ /**
584
789
  Simulates the user clicking on the segment at the specified index. This
585
790
  will update the value if possible and fire the action.
586
791
  */
@@ -588,25 +793,24 @@ SC.SegmentedView = SC.View.extend(SC.Control,
588
793
  var childViews = this.get('childViews'),
589
794
  childView,
590
795
  sel, value, val, empty, mult;
591
-
592
- childView = childViews[index];
593
-
796
+
797
+ childView = childViews.objectAt(index);
798
+
594
799
  if (!childView.get('isEnabled')) return this; // nothing to do!
595
800
 
596
801
  empty = this.get('allowsEmptySelection');
597
802
  mult = this.get('allowsMultipleSelection');
598
-
599
-
803
+
600
804
  // get new value... bail if not enabled. Also save original for later.
601
805
  sel = childView.get('value');
602
806
  value = val = this.get('value') ;
603
-
807
+
604
808
  if (SC.empty(value)) {
605
809
  value = [];
606
810
  } else if (!SC.isArray(value)) {
607
811
  value = [value]; // force to array
608
812
  }
609
-
813
+
610
814
  // if we do not allow multiple selection, either replace the current
611
815
  // selection or deselect it
612
816
  if (!mult) {
@@ -614,10 +818,10 @@ SC.SegmentedView = SC.View.extend(SC.Control,
614
818
  // the selected value, then deselect it.
615
819
  if (empty && (value.get('length')===1) && (value.objectAt(0)===sel)) {
616
820
  value = [];
617
-
821
+
618
822
  // otherwise, simply replace the value.
619
823
  } else value = [sel] ;
620
-
824
+
621
825
  // if we do allow multiple selection, then add or remove item to the array.
622
826
  } else {
623
827
  if (value.indexOf(sel) >= 0) {
@@ -626,7 +830,7 @@ SC.SegmentedView = SC.View.extend(SC.Control,
626
830
  }
627
831
  } else value = value.concat([sel]) ;
628
832
  }
629
-
833
+
630
834
  // normalize back to non-array form
631
835
  switch(value.get('length')) {
632
836
  case 0:
@@ -638,7 +842,7 @@ SC.SegmentedView = SC.View.extend(SC.Control,
638
842
  default:
639
843
  break;
640
844
  }
641
-
845
+
642
846
  // also, trigger target if needed.
643
847
  var actionKey = this.get('itemActionKey'),
644
848
  targetKey = this.get('itemTargetKey'),
@@ -646,7 +850,7 @@ SC.SegmentedView = SC.View.extend(SC.Control,
646
850
  resp = this.getPath('pane.rootResponder'),
647
851
  item;
648
852
 
649
- if (actionKey && (item = this.get('items').objectAt(item.index))) {
853
+ if (actionKey && (item = this.get('items').objectAt(index))) {
650
854
  // get the source item from the item array. use the index stored...
651
855
  action = item.get ? item.get(actionKey) : item[actionKey];
652
856
  if (targetKey) {
@@ -659,51 +863,130 @@ SC.SegmentedView = SC.View.extend(SC.Control,
659
863
  if(!action && val !== undefined) {
660
864
  this.set('value', value);
661
865
  }
662
-
866
+
663
867
  // if an action/target is defined on self use that also
664
868
  action =this.get('action');
665
869
  if (action && resp) {
666
870
  resp.sendAction(action, this.get('target'), this, this.get('pane'));
667
871
  }
668
872
  },
669
-
873
+
874
+ /** @private
875
+ Invoked whenever an item is selected in the overflow menu.
876
+ */
877
+ selectOverflowItem: function(menu) {
878
+ var item = menu.get('selectedItem');
879
+
880
+ this.triggerItemAtIndex(item.get('index'));
881
+
882
+ // Cleanup
883
+ menu.removeObserver('selectedItem', this, 'selectOverflowItem');
884
+
885
+ this.activeChildView.set('isActive', NO);
886
+ this.activeChildView = null;
887
+ },
888
+
889
+ /** @private
890
+ Presents the popup menu containing overflowed segments.
891
+ */
892
+ showOverflowMenu: function() {
893
+ var childViews = this.get('childViews'),
894
+ overflowViewIndex = childViews.get('length') - 1,
895
+ overflowItems = this.overflowItems,
896
+ overflowItemsLength,
897
+ startIndex,
898
+ isArray, value;
899
+
900
+ // Check the currently selected item if it is in overflowItems
901
+ overflowItemsLength = overflowItems.get('length');
902
+ startIndex = childViews.get('length') - 1 - overflowItemsLength;
903
+
904
+ value = this.get('value');
905
+ isArray = SC.isArray(value);
906
+ for (var i = 0; i < overflowItemsLength; i++) {
907
+ var item = overflowItems.objectAt(i),
908
+ itemValueKey = this.get('itemValueKey');
909
+
910
+ if (isArray ? value.indexOf(item.get(itemValueKey)) >= 0 : value === item.get(itemValueKey)) {
911
+ item.set('isChecked', YES);
912
+ } else {
913
+ item.set('isChecked', NO);
914
+ }
915
+
916
+ // Track the matching segment index
917
+ item.set('index', startIndex + i);
918
+ }
919
+
920
+ // TODO: we can't pass a shortcut key to the menu, because it isn't a property of SegmentedView (yet?)
921
+ var self = this;
922
+
923
+ var menu = SC.MenuPane.create({
924
+ layout: { width: 200 },
925
+ items: overflowItems,
926
+ itemTitleKey: this.get('itemTitleKey'),
927
+ itemIconKey: this.get('itemIconKey'),
928
+ itemIsEnabledKey: this.get('itemIsEnabledKey'),
929
+ itemKeyEquivalentKey: this.get('itemKeyEquivalentKey'),
930
+ itemCheckboxKey: 'isChecked',
931
+
932
+ // We need to be able to update our overflow segment even if the user clicks outside of the menu. Since
933
+ // there is no callback method or observable property when the menu closes, override modalPaneDidClick().
934
+ modalPaneDidClick: function() {
935
+ sc_super();
936
+
937
+ // Cleanup
938
+ this.removeObserver('selectedItem', self, 'selectOverflowItem');
939
+
940
+ self.activeChildView.set('isActive', NO);
941
+ self.activeChildView = null;
942
+ }
943
+ });
944
+
945
+ var layer = this.get('layer');
946
+ var overflowElement = layer.childNodes[layer.childNodes.length - 1];
947
+ menu.popup(overflowElement);
948
+
949
+ menu.addObserver("selectedItem", this, 'selectOverflowItem');
950
+ },
951
+
670
952
  /** @private
671
953
  Whenever the value changes, update the segments accordingly.
672
954
  */
673
955
  valueDidChange: function() {
674
956
  var value = this.get('value'),
957
+ overflowItemsLength,
675
958
  childViews = this.get('childViews'),
676
- childView;
677
-
678
- for (var i = childViews.get('length') - 1; i >= 0; i--) {
959
+ overflowIndex = Infinity,
960
+ overflowView = childViews.lastObject(),
961
+ childView,
962
+ isSelected;
963
+
964
+ // The index where childViews are all overflowed
965
+ if (this.overflowItems) {
966
+ overflowItemsLength = this.overflowItems.get('length');
967
+ overflowIndex = childViews.get('length') - 1 - overflowItemsLength;
968
+
969
+ // Clear out the selected value of the overflowView (if it's set)
970
+ overflowView.set('isSelected', NO);
971
+ }
972
+
973
+ for (var i = childViews.get('length') - 2; i >= 0; i--) {
679
974
  childView = childViews.objectAt(i);
680
975
  if (SC.isArray(value) ? value.indexOf(childView.get('value')) >= 0 : value === childView.get('value')) {
681
976
  childView.set('isSelected', YES);
977
+
978
+ // If we've gone over the overflow index, the child view is represented in overflow items
979
+ if (i >= overflowIndex) overflowView.set('isSelected', YES);
682
980
  } else {
683
981
  childView.set('isSelected', NO);
684
982
  }
685
983
  }
686
984
  }.observes('value'),
687
-
985
+
688
986
  /** tied to the isEnabled state */
689
987
  acceptsFirstResponder: function() {
690
988
  if(!SC.SAFARI_FOCUS_BEHAVIOR) return this.get('isEnabled');
691
989
  else return NO;
692
- }.property('isEnabled'),
693
-
694
- willBecomeKeyResponderFrom: function(keyView) {
695
- // focus the text field.
696
- if (!this._isFocused) {
697
- this._isFocused = YES ;
698
- this.becomeFirstResponder();
699
- if (this.get('isVisibleInWindow')) {
700
- this.$()[0].focus();
701
- }
702
- }
703
- },
704
-
705
- willLoseKeyResponderTo: function(responder) {
706
- if (this._isFocused) this._isFocused = NO ;
707
- }
708
-
990
+ }.property('isEnabled').cacheable()
991
+
709
992
  });