cmsimple 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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
+