cmsimple 0.2.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 (221) hide show
  1. data/.gitignore +31 -0
  2. data/.rspec +1 -0
  3. data/.travis.yml +16 -0
  4. data/Gemfile +20 -0
  5. data/Gemfile.ci +5 -0
  6. data/LICENSE +19 -0
  7. data/README.md +118 -0
  8. data/Rakefile +47 -0
  9. data/app/assets/javascripts/cmsimple.js +61 -0
  10. data/app/assets/javascripts/cmsimple/controllers/editor.coffee +102 -0
  11. data/app/assets/javascripts/cmsimple/lib/namespaces.coffee +3 -0
  12. data/app/assets/javascripts/cmsimple/lib/support.coffee +4 -0
  13. data/app/assets/javascripts/cmsimple/mercury/config.js +462 -0
  14. data/app/assets/javascripts/cmsimple/mercury/handlers.coffee +9 -0
  15. data/app/assets/javascripts/cmsimple/models/image.coffee +49 -0
  16. data/app/assets/javascripts/cmsimple/models/page.coffee +106 -0
  17. data/app/assets/javascripts/cmsimple/models/path.coffee +31 -0
  18. data/app/assets/javascripts/cmsimple/models/version.coffee +29 -0
  19. data/app/assets/javascripts/cmsimple/panels/images/index.coffee +2 -0
  20. data/app/assets/javascripts/cmsimple/panels/images/list.coffee +48 -0
  21. data/app/assets/javascripts/cmsimple/panels/images/panel.coffee +69 -0
  22. data/app/assets/javascripts/cmsimple/panels/images/selection.coffee +52 -0
  23. data/app/assets/javascripts/cmsimple/panels/page_metadata.coffee +42 -0
  24. data/app/assets/javascripts/cmsimple/panels/publish.coffee +32 -0
  25. data/app/assets/javascripts/cmsimple/panels/redirects/form.coffee +51 -0
  26. data/app/assets/javascripts/cmsimple/panels/redirects/index.coffee +2 -0
  27. data/app/assets/javascripts/cmsimple/panels/redirects/list.coffee +34 -0
  28. data/app/assets/javascripts/cmsimple/panels/redirects/panel.coffee +39 -0
  29. data/app/assets/javascripts/cmsimple/panels/sitemap/index.coffee +2 -0
  30. data/app/assets/javascripts/cmsimple/panels/sitemap/panel.coffee +40 -0
  31. data/app/assets/javascripts/cmsimple/panels/sitemap/sortable.coffee +55 -0
  32. data/app/assets/javascripts/cmsimple/panels/sitemap/tree.coffee +61 -0
  33. data/app/assets/javascripts/cmsimple/panels/versions/index.coffee +2 -0
  34. data/app/assets/javascripts/cmsimple/panels/versions/list.coffee +51 -0
  35. data/app/assets/javascripts/cmsimple/panels/versions/panel.coffee +53 -0
  36. data/app/assets/javascripts/cmsimple/views/image_library/_item.jst.hamlc +24 -0
  37. data/app/assets/javascripts/cmsimple/views/image_library/list.jst.hamlc +8 -0
  38. data/app/assets/javascripts/cmsimple/views/redirects/_path.jst.hamlc +6 -0
  39. data/app/assets/javascripts/cmsimple/views/redirects/list.jst.hamlc +19 -0
  40. data/app/assets/javascripts/cmsimple/views/sitemap/_page.jst.hamlc +9 -0
  41. data/app/assets/javascripts/cmsimple/views/sitemap/tree.jst.hamlc +5 -0
  42. data/app/assets/javascripts/cmsimple/views/versions/_item.jst.hamlc +6 -0
  43. data/app/assets/javascripts/cmsimple/views/versions/list.jst.hamlc +4 -0
  44. data/app/assets/stylesheets/cmsimple.css +15 -0
  45. data/app/assets/stylesheets/cmsimple/forms.css +10 -0
  46. data/app/assets/stylesheets/cmsimple/panels.css +399 -0
  47. data/app/assets/stylesheets/cmsimple/toolbar-images.css +27 -0
  48. data/app/assets/stylesheets/mercury_overrides.css +2 -0
  49. data/app/controllers/cmsimple/front_controller.rb +38 -0
  50. data/app/controllers/cmsimple/images_controller.rb +28 -0
  51. data/app/controllers/cmsimple/mercury_controller.rb +7 -0
  52. data/app/controllers/cmsimple/pages_controller.rb +89 -0
  53. data/app/controllers/cmsimple/paths_controller.rb +23 -0
  54. data/app/controllers/cmsimple/snippets_controller.rb +23 -0
  55. data/app/controllers/cmsimple/versions_controller.rb +17 -0
  56. data/app/helpers/cmsimple/regions_helper.rb +38 -0
  57. data/app/models/cmsimple/image.rb +19 -0
  58. data/app/models/cmsimple/page.rb +203 -0
  59. data/app/models/cmsimple/path.rb +63 -0
  60. data/app/models/cmsimple/region.rb +43 -0
  61. data/app/models/cmsimple/snippet.rb +64 -0
  62. data/app/models/cmsimple/version.rb +18 -0
  63. data/app/uploaders/image_attachment_uploader.rb +53 -0
  64. data/app/views/cmsimple/images/_form.html.haml +13 -0
  65. data/app/views/cmsimple/images/new.html.haml +5 -0
  66. data/app/views/cmsimple/pages/_form.html.haml +49 -0
  67. data/app/views/cmsimple/pages/_form_extras.html.haml +2 -0
  68. data/app/views/cmsimple/pages/edit.html.haml +3 -0
  69. data/app/views/cmsimple/pages/new.html.haml +3 -0
  70. data/app/views/cmsimple/pages/publish.html.haml +12 -0
  71. data/app/views/cmsimple/snippets/index.html.haml +5 -0
  72. data/app/views/cmsimple/templates/default.html.haml +4 -0
  73. data/app/views/layouts/editor.html.haml +12 -0
  74. data/app/views/layouts/panel.html.haml +9 -0
  75. data/cmsimple.gemspec +44 -0
  76. data/config.ru +4 -0
  77. data/config/application.rb +1 -0
  78. data/config/cucumber.yml +8 -0
  79. data/config/environment.rb +2 -0
  80. data/config/routes.rb +34 -0
  81. data/db/migrate/20120201221410_create_cmsimple_pages.rb +10 -0
  82. data/db/migrate/20120222185901_add_title_parent_id_and_position_to_pages.rb +10 -0
  83. data/db/migrate/20120229185214_add_slug_to_pages.rb +7 -0
  84. data/db/migrate/20120323200439_add_is_root_to_page.rb +5 -0
  85. data/db/migrate/20120328174339_add_meta_info_to_cmsimple_pages.rb +9 -0
  86. data/db/migrate/20120329172857_create_cmsimple_path.rb +11 -0
  87. data/db/migrate/20120407024752_create_cmsimple_images.rb +13 -0
  88. data/db/migrate/20120410041105_add_timestamps_to_cmsimple_pages.rb +7 -0
  89. data/db/migrate/20120425211937_add_published_at_to_cmsimple_pages.rb +6 -0
  90. data/db/migrate/20120430175047_create_cmsimple_versions.rb +13 -0
  91. data/db/migrate/20120831233927_rename_path_to_current_uri_on_paths.rb +5 -0
  92. data/features/create.feature +18 -0
  93. data/features/delete.feature +12 -0
  94. data/features/edit.feature +54 -0
  95. data/features/publishing.feature +31 -0
  96. data/features/redirects.feature +27 -0
  97. data/features/step_definitions/mercury_steps.rb +440 -0
  98. data/features/step_definitions/page_steps.rb +269 -0
  99. data/features/step_definitions/web_steps.rb +254 -0
  100. data/features/support/env.rb +77 -0
  101. data/features/support/mercury_content.rb +25 -0
  102. data/features/support/mercury_selectors.rb +148 -0
  103. data/features/support/paths.rb +16 -0
  104. data/features/support/selectors.rb +26 -0
  105. data/features/support/utils.rb +18 -0
  106. data/features/versioning.feature +27 -0
  107. data/features/visit.feature +7 -0
  108. data/lib/cmsimple.rb +22 -0
  109. data/lib/cmsimple/configuration.rb +65 -0
  110. data/lib/cmsimple/exts/to_bool.rb +25 -0
  111. data/lib/cmsimple/page_responder.rb +46 -0
  112. data/lib/cmsimple/rails.rb +5 -0
  113. data/lib/cmsimple/regions_proxy.rb +32 -0
  114. data/lib/cmsimple/template_resolver.rb +14 -0
  115. data/lib/cmsimple/template_responder.rb +12 -0
  116. data/lib/cmsimple/version.rb +3 -0
  117. data/lib/generators/cmsimple/install/install_generator.rb +46 -0
  118. data/lib/generators/cmsimple/install/templates/default.html.erb +10 -0
  119. data/lib/generators/cmsimple/install/templates/default.html.haml +6 -0
  120. data/lib/generators/cmsimple/install/templates/initializer.rb +22 -0
  121. data/lib/generators/cmsimple/snippet/snippet_generator.rb +56 -0
  122. data/lib/generators/cmsimple/snippet/templates/cell.rb +18 -0
  123. data/lib/generators/cmsimple/snippet/templates/display.html.erb +14 -0
  124. data/lib/generators/cmsimple/snippet/templates/display.html.haml +11 -0
  125. data/lib/generators/cmsimple/snippet/templates/options.html.erb +18 -0
  126. data/lib/generators/cmsimple/snippet/templates/options.html.haml +12 -0
  127. data/script/app +2 -0
  128. data/script/migrate +2 -0
  129. data/script/rails +8 -0
  130. data/spec/fixtures/rails.png +0 -0
  131. data/spec/helpers/regions_helper_spec.rb +62 -0
  132. data/spec/javascripts/controllers/editor_spec.coffee +57 -0
  133. data/spec/javascripts/models/image_geometry_spec.coffee +64 -0
  134. data/spec/javascripts/models/image_spec.coffee +4 -0
  135. data/spec/javascripts/models/page_spec.coffee +121 -0
  136. data/spec/javascripts/models/path_spec.coffee +39 -0
  137. data/spec/javascripts/models/version_spec.coffee +31 -0
  138. data/spec/javascripts/panels/images/selection_spec.coffee +104 -0
  139. data/spec/javascripts/panels/sitemap/panel_spec.coffee +10 -0
  140. data/spec/javascripts/panels/sitemap/sortable_spec.coffee +63 -0
  141. data/spec/javascripts/panels/sitemap/tree_spec.coffee +62 -0
  142. data/spec/javascripts/spec_helper.coffee +25 -0
  143. data/spec/javascripts/support/stubs.coffee +16 -0
  144. data/spec/lib/page_responder_spec.rb +58 -0
  145. data/spec/lib/regions_proxy_spec.rb +47 -0
  146. data/spec/models/image_spec.rb +46 -0
  147. data/spec/models/page_spec.rb +237 -0
  148. data/spec/models/path_spec.rb +71 -0
  149. data/spec/models/region_spec.rb +14 -0
  150. data/spec/models/snippet_spec.rb +57 -0
  151. data/spec/models/version_spec.rb +7 -0
  152. data/spec/rails_app/.gitignore +33 -0
  153. data/spec/rails_app/Rakefile +7 -0
  154. data/spec/rails_app/app/assets/images/rails.png +0 -0
  155. data/spec/rails_app/app/assets/javascripts/application.js +9 -0
  156. data/spec/rails_app/app/assets/stylesheets/application.css +7 -0
  157. data/spec/rails_app/app/cells/example/display.html.haml +2 -0
  158. data/spec/rails_app/app/cells/example/options.html.haml +15 -0
  159. data/spec/rails_app/app/cells/example_cell.rb +19 -0
  160. data/spec/rails_app/app/cells/image_example/display.html.haml +4 -0
  161. data/spec/rails_app/app/cells/image_example/options.html.haml +15 -0
  162. data/spec/rails_app/app/cells/image_example_cell.rb +18 -0
  163. data/spec/rails_app/app/controllers/application_controller.rb +3 -0
  164. data/spec/rails_app/app/helpers/application_helper.rb +2 -0
  165. data/spec/rails_app/app/mailers/.gitkeep +0 -0
  166. data/spec/rails_app/app/models/.gitkeep +0 -0
  167. data/spec/rails_app/app/views/cmsimple/_snippet_list.html.haml +8 -0
  168. data/spec/rails_app/app/views/cmsimple/templates/default.html.haml +19 -0
  169. data/spec/rails_app/app/views/cmsimple/templates/test.html.haml +2 -0
  170. data/spec/rails_app/app/views/layouts/application.html.haml +13 -0
  171. data/spec/rails_app/config.ru +4 -0
  172. data/spec/rails_app/config/application.rb +65 -0
  173. data/spec/rails_app/config/boot.rb +9 -0
  174. data/spec/rails_app/config/database.example.yml +22 -0
  175. data/spec/rails_app/config/database.travis.yml +8 -0
  176. data/spec/rails_app/config/environment.rb +5 -0
  177. data/spec/rails_app/config/environments/development.rb +30 -0
  178. data/spec/rails_app/config/environments/test.rb +39 -0
  179. data/spec/rails_app/config/initializers/backtrace_silencers.rb +7 -0
  180. data/spec/rails_app/config/initializers/cells.rb +1 -0
  181. data/spec/rails_app/config/initializers/cmsimple.rb +3 -0
  182. data/spec/rails_app/config/initializers/inflections.rb +10 -0
  183. data/spec/rails_app/config/initializers/mime_types.rb +5 -0
  184. data/spec/rails_app/config/initializers/secret_token.rb +7 -0
  185. data/spec/rails_app/config/initializers/session_store.rb +8 -0
  186. data/spec/rails_app/config/initializers/teabag.rb +58 -0
  187. data/spec/rails_app/config/initializers/wrap_parameters.rb +14 -0
  188. data/spec/rails_app/config/locales/en.yml +5 -0
  189. data/spec/rails_app/config/routes.rb +61 -0
  190. data/spec/rails_app/db/seeds.rb +11 -0
  191. data/spec/rails_app/lib/assets/.gitkeep +0 -0
  192. data/spec/rails_app/lib/tasks/.gitkeep +0 -0
  193. data/spec/rails_app/public/404.html +26 -0
  194. data/spec/rails_app/public/422.html +26 -0
  195. data/spec/rails_app/public/500.html +26 -0
  196. data/spec/rails_app/public/robots.txt +5 -0
  197. data/spec/rails_app/script/rails +6 -0
  198. data/spec/rails_app/vendor/assets/stylesheets/.gitkeep +0 -0
  199. data/spec/rails_app/vendor/plugins/.gitkeep +0 -0
  200. data/spec/spec_helper.rb +31 -0
  201. data/spec/support/active_model_lint_example.rb +14 -0
  202. data/spec/teabag_env.rb +28 -0
  203. data/vendor/assets/images/sitemap/has-changes.png +0 -0
  204. data/vendor/assets/images/sitemap/published.png +0 -0
  205. data/vendor/assets/images/sitemap/unpublished.png +0 -0
  206. data/vendor/assets/images/toolbar/metadata.png +0 -0
  207. data/vendor/assets/images/toolbar/publish.png +0 -0
  208. data/vendor/assets/images/toolbar/redirect.png +0 -0
  209. data/vendor/assets/images/toolbar/sitemap.png +0 -0
  210. data/vendor/assets/images/toolbar/snippets.png +0 -0
  211. data/vendor/assets/images/toolbar/unpublished.png +0 -0
  212. data/vendor/assets/images/tree-line-horizontal-last.png +0 -0
  213. data/vendor/assets/images/tree-line-horizontal.png +0 -0
  214. data/vendor/assets/images/tree-line-vertical.png +0 -0
  215. data/vendor/assets/javascripts/jquery-serializeObject.js +107 -0
  216. data/vendor/assets/javascripts/jquery.to-json.js +74 -0
  217. data/vendor/assets/javascripts/jquery.ui.nestedSortable-1.3.4.js +391 -0
  218. data/vendor/assets/javascripts/moment-1.6.2.js +918 -0
  219. data/vendor/assets/javascripts/underscore-1.3.1.js +31 -0
  220. data/vendor/assets/stylesheets/jasmine-modified.css +216 -0
  221. metadata +686 -0
@@ -0,0 +1,64 @@
1
+ #= require cmsimple
2
+
3
+ describe 'CMSimple.Image.Geometry', ->
4
+
5
+ describe 'absolute geometry', ->
6
+ beforeEach ->
7
+ @geometry = new CMSimple.Image.Geometry('200x300')
8
+
9
+ it 'matches if the width and height are the same', ->
10
+ expect(@geometry.inRange(200, 300)).toEqual(true)
11
+
12
+ it 'does not match if the width is not exact', ->
13
+ expect(@geometry.inRange(300, 300)).toEqual(false)
14
+
15
+ it 'does not match if the height is not exact', ->
16
+ expect(@geometry.inRange(300, 500)).toEqual(false)
17
+
18
+ describe 'less than geometry', ->
19
+ beforeEach ->
20
+ @geometry = new CMSimple.Image.Geometry('<300x<300')
21
+
22
+ it 'matches if the width and height matches the geometry', ->
23
+ expect(@geometry.inRange(300, 300)).toEqual(true)
24
+
25
+ it 'matches if the width and height are less than the geometry', ->
26
+ expect(@geometry.inRange(200, 200)).toEqual(true)
27
+
28
+ it 'does no match if the width is greater than the geometry', ->
29
+ expect(@geometry.inRange(400, 200)).toEqual(false)
30
+
31
+ describe 'greater than geometry', ->
32
+ beforeEach ->
33
+ @geometry = new CMSimple.Image.Geometry('>300x>300')
34
+
35
+ it 'matches if the width and height matches the geometry', ->
36
+ expect(@geometry.inRange(300, 300)).toEqual(true)
37
+
38
+ it 'matches if the width and height are greater than the geometry', ->
39
+ expect(@geometry.inRange(400, 400)).toEqual(true)
40
+
41
+ it 'does no match if the width is less than the geometry', ->
42
+ expect(@geometry.inRange(200, 200)).toEqual(false)
43
+
44
+ describe 'mixed geometries', ->
45
+
46
+ it 'matches less than and absolute', ->
47
+ geometry = new CMSimple.Image.Geometry('<300x300')
48
+ expect(geometry.inRange(200, 300)).toEqual(true)
49
+ expect(geometry.inRange(200, 301)).toEqual(false)
50
+
51
+ describe 'bad geometries', ->
52
+ it 'can handle null', ->
53
+ geometry = new CMSimple.Image.Geometry(null)
54
+ expect(geometry.inRange(1, 1)).toEqual(true)
55
+
56
+ it 'can handle empty string', ->
57
+ geometry = new CMSimple.Image.Geometry(' ')
58
+ expect(geometry.inRange(1, 1)).toEqual(true)
59
+
60
+ it 'can handle partial query', ->
61
+ geometry = new CMSimple.Image.Geometry('50')
62
+ expect(geometry.inRange(50, 1)).toEqual(true)
63
+ expect(geometry.inRange(5, 1)).toEqual(false)
64
+
@@ -0,0 +1,4 @@
1
+ #= require cmsimple
2
+
3
+ describe 'CMSimple.Image', ->
4
+
@@ -0,0 +1,121 @@
1
+ #= require cmsimple
2
+ #= require support/stubs
3
+
4
+ describe 'CMSimple.Page', ->
5
+
6
+ describe 'snippets', ->
7
+ beforeEach ->
8
+ @page = new CMSimple.Page
9
+ slug: 'about'
10
+ content:
11
+ example2:
12
+ value: 'HTML'
13
+ snippets:
14
+ snippet_2:
15
+ name: 'example'
16
+ options:
17
+ first_name: 'Barny'
18
+ last_name: 'Rubble'
19
+
20
+ example1:
21
+ value: 'HTML'
22
+ snippets:
23
+ snippet_1:
24
+ name: 'example'
25
+ options:
26
+ first_name: 'Fred'
27
+ last_name: 'Flinstone'
28
+
29
+ it 'return a flattened object of snippets across regions', ->
30
+ expect(@page.snippets().snippet_1.options.first_name).toEqual('Fred')
31
+ expect(@page.snippets().snippet_2.options.first_name).toEqual('Barny')
32
+
33
+ describe 'default slug', ->
34
+ beforeEach ->
35
+ stubs.ajax()
36
+
37
+ it 'sets the slug from the title', ->
38
+ about = CMSimple.Page.create title: 'About'
39
+ expect(about.slug).toEqual('about')
40
+
41
+ it 'does not change the slug if a title is not passed', ->
42
+ about = CMSimple.Page.create title: 'About'
43
+ about.load {}
44
+ expect(about.slug).toEqual('about')
45
+
46
+ it 'does not overrite the slug with the title if there is a slug', ->
47
+ about = CMSimple.Page.create title: 'About', slug: 'something-else'
48
+ about.load {title: 'A Different title'}
49
+ expect(about.slug).toEqual('something-else')
50
+
51
+ it 'removes multiple spaces', ->
52
+ about = CMSimple.Page.create title: 'About a dog'
53
+ expect(about.slug).toEqual('about-a-dog')
54
+
55
+ describe 'is root', ->
56
+ beforeEach ->
57
+ stubs.ajax()
58
+ @about = CMSimple.Page.create title: 'About', is_root: true, id: 1
59
+
60
+ it 'finds the page with is root set to true for the path /', ->
61
+ page = CMSimple.Page.forPath('/')
62
+ expect(@about).toEqual(page)
63
+
64
+ it 'can retrieve the original path when passed options to the path method', ->
65
+ expect(@about.path(ignoreRoot: true)).toEqual('/about')
66
+
67
+ it 'children request a parents path ignoring the root', ->
68
+ @child = CMSimple.Page.create title: 'Child', parent_id: @about.id, id: 2
69
+ expect(@child.path()).toEqual('/about/child')
70
+
71
+
72
+ describe 'acts as a tree', ->
73
+ beforeEach ->
74
+ stubs.ajax()
75
+ CMSimple.Page.destroyAll()
76
+ @single = CMSimple.Page.create title: 'Single', id: 4
77
+ @parent = CMSimple.Page.create title: 'Parent', id: 1
78
+ @child = CMSimple.Page.create title: 'Child', parent_id: @parent.id, id: 2
79
+ @grandchild = CMSimple.Page.create title: 'Grand Child', parent_id: @child.id, id: 3
80
+
81
+ it 'can grab a child', ->
82
+ expect(@parent.children().first()).toEqual(@child)
83
+
84
+ it 'can grab a parent', ->
85
+ expect(@child.parent().id).toEqual(@parent.id)
86
+ expect(@grandchild.parent().id).toEqual(@child.id)
87
+
88
+ it 'can grab all the roots', ->
89
+ roots = CMSimple.Page.roots()
90
+ titles = _.compact(_.pluck(roots, 'title'))
91
+ expect(roots.length).toEqual(2)
92
+ expect(titles).toContain('Parent')
93
+ expect(titles).toContain('Single')
94
+
95
+ describe 'update all positions', ->
96
+ it 'can bulk update to positions', ->
97
+ CMSimple.Page.updatePositions([1,2,3,4])
98
+ expect(@single.position).toEqual(3)
99
+ expect(@parent.position).toEqual(0)
100
+ expect(@child.position).toEqual(1)
101
+ expect(@grandchild.position).toEqual(2)
102
+
103
+ describe 'a pages path', ->
104
+ beforeEach ->
105
+ stubs.ajax()
106
+ CMSimple.Page.destroyAll()
107
+ @child = CMSimple.Page.create title: 'Child', id: 4, parent_id: 1
108
+ @parent = CMSimple.Page.create title: 'Parent', id: 1
109
+
110
+ it 'gets the path from the parent', ->
111
+ spyOn(@child, 'parent').andCallThrough()
112
+ expect(@child.path()).toEqual('/parent/child')
113
+ expect(@child.parent).toHaveBeenCalled()
114
+
115
+ it 'gets the path from the uri', ->
116
+ @child.uri = '/parent/child-path'
117
+ @child.save()
118
+ spyOn(@child, 'parent').andCallFake ->
119
+ return null
120
+ expect(@child.path()).toEqual('/parent/child-path')
121
+
@@ -0,0 +1,39 @@
1
+ #= require cmsimple
2
+ #= require support/stubs
3
+
4
+ describe 'CMSimple.Path', ->
5
+ beforeEach ->
6
+ stubs.ajax()
7
+ CMSimple.Path.destroyAll()
8
+
9
+ describe 'has a unique uri', ->
10
+
11
+ it 'fails validation if there is another path with the same uri', ->
12
+ CMSimple.Path.create uri: '/about', redirect_uri: '/about-us'
13
+ path = new CMSimple.Path uri: '/about', redirect_uri: '/something'
14
+ expect(path.isValid()).toEqual(false)
15
+
16
+ it 'passes validation if there is another path with the same uri', ->
17
+ CMSimple.Path.create uri: '/about', redirect_uri: '/about-us'
18
+ path = new CMSimple.Path uri: '/about-us', redirect_uri: '/something'
19
+ expect(path.isValid()).toEqual(true)
20
+
21
+ it 'does not check itself when checking paths', ->
22
+ path = new CMSimple.Path uri: '/about', redirect_uri: '/about-us'
23
+ path.save(ajax: false)
24
+ expect(path.isValid()).toEqual(true)
25
+
26
+ describe '.allRedirects does not return valid non redirect paths', ->
27
+
28
+ it 'returns just the paths where the uri is not destinationPath', ->
29
+ page = CMSimple.Page.create title: 'About'
30
+ redirect = CMSimple.Path.create uri: '/about', redirect_uri: '/about-us'
31
+ CMSimple.Path.create uri: '/about', page_id: page.id
32
+ expect(CMSimple.Path.allRedirects()).toEqual([redirect])
33
+
34
+ it 'returns just the paths where the associated page is not the root', ->
35
+ page = CMSimple.Page.create title: 'About', is_root: true
36
+ redirect = CMSimple.Path.create uri: '/about', redirect_uri: '/about-us'
37
+ CMSimple.Path.create uri: '/about', page_id: page.id
38
+ expect(CMSimple.Path.allRedirects()).toEqual([redirect])
39
+
@@ -0,0 +1,31 @@
1
+ #= require cmsimple
2
+ #= require support/stubs
3
+
4
+ describe 'CMSimple.Version', ->
5
+ beforeEach ->
6
+ @ajax = stubs.ajax()
7
+ CMSimple.Version.destroyAll()
8
+
9
+ describe 'nested resource urls', ->
10
+ beforeEach ->
11
+ @page = CMSimple.Page.create title: 'About', id: 1
12
+ @ajax.reset()
13
+
14
+ it 'uses the url of the page to request versions via fetch', ->
15
+ CMSimple.Version.fetch(@page)
16
+ expect(@ajax).toHaveBeenCalledWith
17
+ contentType: 'application/json'
18
+ dataType: 'json'
19
+ processData: false
20
+ headers: { 'X-Requested-With': 'XMLHttpRequest' }
21
+ type: 'GET'
22
+ url: '/pages/1/versions'
23
+
24
+ it 'uses the url of the page to create a member url for versions', ->
25
+ version = CMSimple.Version.create page_id: @page.id, id: 1
26
+ expect(version.url()).toEqual("/pages/#{@page.id}/versions/#{version.id}")
27
+
28
+ it 'can append segments to the url', ->
29
+ version = CMSimple.Version.create page_id: @page.id, id: 1
30
+ expect(version.url('revert_to')).toEqual("/pages/#{@page.id}/versions/#{version.id}/revert_to")
31
+
@@ -0,0 +1,104 @@
1
+ #= require cmsimple
2
+
3
+ describe 'CMSimple.Panels.ImageLibrary.Selection', ->
4
+ beforeEach ->
5
+
6
+ html = '''
7
+ <div class="mercury-snippet example-snippet" data-snippet="snippet_3" contenteditable="false" data-version="1">
8
+ <div class="item">
9
+ <img data-image-geometry="&lt;100x&lt;100" data-snippet-image="image_1" src="" style="float: left; padding-right: 5px;">
10
+ <h3>title</h3>
11
+ <p>summary</p>
12
+ </div>
13
+ </div>
14
+ '''
15
+ @snippetHTML = $(html)
16
+ fixture.set @snippetHTML
17
+
18
+ describe 'selecting snippet images', ->
19
+
20
+ beforeEach ->
21
+ @region = {element: @snippetHTML}
22
+ @selection = new CMSimple.Panels.ImageLibrary.Selection()
23
+ @selection.bindRegion(@region)
24
+
25
+
26
+ describe '#setSelection', ->
27
+ beforeEach ->
28
+ @img = @snippetHTML.find('img')
29
+ @selection.bind 'filter', (geometry)=> @geometry = geometry
30
+ @selection.setSelection(@img)
31
+
32
+ it 'sets the img to the selecteImaged', ->
33
+ expect(@selection.selectedImage).toEqual(@img)
34
+
35
+ it 'sets the img class to have .selected-image', ->
36
+ expect(@img.hasClass('selected-image')).toEqual(true)
37
+
38
+ it 'triggers the filter event with the img geometry', ->
39
+ expect(@geometry).toEqual('<100x<100')
40
+
41
+
42
+ describe '#clearSelection', ->
43
+ beforeEach ->
44
+ @img = @snippetHTML.find('img')
45
+ @selection.bind 'filter', (geometry)=> @geometry = geometry
46
+ @selection.setSelection(@img)
47
+ @selection.clearSelection()
48
+
49
+ it 'unsets the img to the selecteImaged', ->
50
+ expect(@selection.selectedImage).toEqual(null)
51
+
52
+ it 'unsets the img class to have .selected-image', ->
53
+ expect(@img.hasClass('selected-image')).toEqual(false)
54
+
55
+ it 'triggers the filter event with null', ->
56
+ expect(@geometry).toEqual(null)
57
+
58
+
59
+ describe '#bindRegion', ->
60
+
61
+ it 'binds to click on the attributed image', ->
62
+ spyOn @selection, 'setSelection'
63
+ @snippetHTML.find('img').click()
64
+ expect(@selection.setSelection).toHaveBeenCalled()
65
+
66
+ it 'clears the selection if a click happens off the image', ->
67
+ spyOn @selection, 'setSelection'
68
+ spyOn @selection, 'clearSelection'
69
+ @snippetHTML.find('div').click()
70
+ expect(@selection.setSelection).wasNotCalled()
71
+ expect(@selection.clearSelection).toHaveBeenCalled()
72
+
73
+
74
+ describe 'setting the image src', ->
75
+ beforeEach ->
76
+ @snippetMock = {options: {snippet: {}}}
77
+ @snippetSpy = spyOn(Mercury.Snippet, 'find').andCallFake(=> @snippetMock)
78
+
79
+ @region = {element: @snippetHTML, type: -> 'full'}
80
+ @img = @snippetHTML.find('img')
81
+
82
+ @selection = new CMSimple.Panels.ImageLibrary.Selection()
83
+ @selection.region = @region
84
+ @selection.selectedImage = @img
85
+
86
+ it 'sets the src on the snippet image', ->
87
+ @selection.set({src: 'foo.png'})
88
+ expect(@img.attr('src')).toEqual('foo.png')
89
+
90
+ it 'finds the snippet the image is in', ->
91
+ @selection.set({src: 'foo.png'})
92
+ expect(@snippetSpy).toHaveBeenCalledWith('snippet_3')
93
+
94
+ it 'sets the src value on the snippet options', ->
95
+ @selection.set({src: 'foo.png'})
96
+ expect(@snippetMock.options.snippet.image_1).toEqual('foo.png')
97
+
98
+ it 'calls the region execCommand if it does not have a selectedImage', ->
99
+ @selection.selectedImage = null
100
+ @region.execCommand = ->
101
+ spyOn @region, 'execCommand'
102
+ @selection.set({src: 'foo.png'})
103
+ expect(@region.execCommand).toHaveBeenCalledWith('insertImage', {value: {src: 'foo.png'}})
104
+
@@ -0,0 +1,10 @@
1
+ #= require cmsimple
2
+ describe 'CMSimple.Panels.Sitemap.Panel', ->
3
+ beforeEach ->
4
+ spyOn(Mercury.Panel.prototype, 'position')
5
+ spyOn(CMSimple.Page, 'bind')
6
+ @refreshSpy = spyOn(CMSimple.Panels.Sitemap.Tree.prototype, 'refresh')
7
+
8
+ fixture.set sandbox(div: 'mercury-toolbar-container')
9
+
10
+
@@ -0,0 +1,63 @@
1
+ #= require cmsimple
2
+
3
+ describe 'CMSimple.Panels.Sitemap.Sortable', ->
4
+ beforeEach ->
5
+ @page1 = CMSimple.Page.create path: '/page1', title: 'Page 1', id: 1
6
+ @page2 = CMSimple.Page.create path: '/page2', title: 'Page 2', id: 2
7
+ @page3 = CMSimple.Page.create path: '/page3', title: 'Page 3', id: 3, parent_id: 2
8
+ @page4 = CMSimple.Page.create path: '/page4', title: 'Page 4', id: 4, parent_id: 3
9
+ @page5 = CMSimple.Page.create path: '/page5', title: 'Page 5', id: 5
10
+
11
+ html = '''
12
+ <ul class='sitemap'>
13
+ <li data-id='1'>
14
+ <article>Page 1</article>
15
+ </li>
16
+ <li data-id='2'>
17
+ <article>Page 2</article>
18
+ <ul class='child'>
19
+ <li data-id='3'>
20
+ <article>Page 3</article>
21
+ <ul class='child'>
22
+ <li data-id='4'>
23
+ <article>Page 4</article>
24
+ <ul class='child'>
25
+ </ul
26
+ </li>
27
+ </ul
28
+ </li>
29
+ </ul
30
+ </li>
31
+ <li data-id='5'>
32
+ <article>Page 5</article>
33
+ <ul class='child'>
34
+ </ul
35
+ </li>
36
+ </ul>
37
+ '''
38
+ fixture.set html
39
+ @treeHTML = $(fixture.el)
40
+
41
+ it 'binds to nestedSortable on initialization', ->
42
+ pluginSpy = spyOn($.fn, 'nestedSortable').andCallThrough()
43
+ selectionSpy = spyOn($.fn, 'disableSelection').andCallThrough()
44
+ new CMSimple.Panels.Sitemap.Sortable(@treeHTML)
45
+ expect(pluginSpy).toHaveBeenCalled()
46
+ expect(selectionSpy).toHaveBeenCalled()
47
+
48
+ describe '#update', ->
49
+ beforeEach ->
50
+ @sortable = new CMSimple.Panels.Sitemap.Sortable(@treeHTML)
51
+
52
+ it 'updates the parent of the element that was moved', ->
53
+ spyOn(CMSimple.Page, 'find').andCallThrough()
54
+ spyOn(CMSimple.Page.prototype, 'updateAttributes')
55
+ @sortable.update({}, item: $("li[data-id='4']"))
56
+ expect(CMSimple.Page.find).toHaveBeenCalledWith(4)
57
+ expect(CMSimple.Page.prototype.updateAttributes).toHaveBeenCalledWith(parent_id: 3)
58
+
59
+ it 'calls updatePositions on CMSimple.Page', ->
60
+ spyOn(CMSimple.Page, 'updatePositions')
61
+ @sortable.update({}, item: $("li[data-id='4']"))
62
+ expect(CMSimple.Page.updatePositions).toHaveBeenCalledWith([1,2,3,4,5])
63
+
@@ -0,0 +1,62 @@
1
+ #= require cmsimple
2
+
3
+ describe 'CMSimple.Panels.Sitemap.Tree', ->
4
+ beforeEach ->
5
+ stubs.ajax()
6
+ CMSimple.Page.unbind()
7
+ CMSimple.Page.destroyAll()
8
+ @single = CMSimple.Page.create path: '/single', title: 'Single', id: 4
9
+ @parent = CMSimple.Page.create path: '/parent', title: 'Parent', id: 1
10
+ @child = CMSimple.Page.create path: '/child', title: 'Child', parent_id: @parent.id, id: 2
11
+ @grandchild = CMSimple.Page.create path: '/grandchild', title: 'grandchild', parent_id: @child.id, id: 3
12
+ html = '''
13
+ <div class='mercury-panel'>
14
+ <button class='add'>Add Page</button>
15
+ <ul class='sitemap'>
16
+ </ul>
17
+ </div>
18
+ '''
19
+ fixture.set html
20
+ @container = $(fixture.el)
21
+
22
+ describe 'rendering', ->
23
+ it 'renders each page in an li', ->
24
+ new CMSimple.Panels.Sitemap.Tree(@container).render()
25
+ expect($('ul.sitemap li').length).toEqual(4)
26
+
27
+ it 'calls renderPages for children', ->
28
+ panel = new CMSimple.Panels.Sitemap.Tree(@container)
29
+ spyOn(panel, 'renderPages').andCallThrough()
30
+ panel.render()
31
+ expect(panel.renderPages.callCount).toEqual(3)
32
+
33
+ it 'calls render when refreshed', ->
34
+ spyOn(CMSimple.Page, 'fetch').andCallFake -> CMSimple.Page.trigger 'refresh'
35
+ panel = new CMSimple.Panels.Sitemap.Tree(@container)
36
+ spyOn(panel, 'render')
37
+ runs ->
38
+ panel.refresh()
39
+ waits 100
40
+ runs ->
41
+ expect(panel.render).toHaveBeenCalled()
42
+
43
+ describe 'event binding and setup', ->
44
+ it 'binds click events to the article element for the page', ->
45
+ panel = new CMSimple.Panels.Sitemap.Tree(@container)
46
+ spyOn(panel, 'pageClick')
47
+ panel.render()
48
+ $('ul.sitemap li article').click()
49
+ expect(panel.pageClick).toHaveBeenCalled()
50
+
51
+ it 'initializes the sortable helper', ->
52
+ panel = new CMSimple.Panels.Sitemap.Tree(@container)
53
+ sortableSpy = spyOn(CMSimple.Panels.Sitemap.Sortable.__super__, 'constructor').andCallThrough()
54
+ panel.render()
55
+ expect(sortableSpy).toHaveBeenCalled()
56
+
57
+ it 'binds the add page event', ->
58
+ spyOn(Mercury, 'trigger')
59
+ panel = new CMSimple.Panels.Sitemap.Tree(@container)
60
+ $('button.add').click()
61
+ expect(Mercury.trigger).toHaveBeenCalledWith('action', action: 'newPage')
62
+