slices 1.0.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 (215) hide show
  1. data/CHANGELOG.md +3 -0
  2. data/README.md +51 -0
  3. data/Rakefile +9 -0
  4. data/app/assets/images/slices/ajax-loader.gif +0 -0
  5. data/app/assets/images/slices/asset-background.png +0 -0
  6. data/app/assets/images/slices/asset-spinner.gif +0 -0
  7. data/app/assets/images/slices/bg_header.gif +0 -0
  8. data/app/assets/images/slices/black-Linen.png +0 -0
  9. data/app/assets/images/slices/calendar.svg +68 -0
  10. data/app/assets/images/slices/chosen-sprite.png +0 -0
  11. data/app/assets/images/slices/drag-handle.svg +9 -0
  12. data/app/assets/images/slices/icon_admins.png +0 -0
  13. data/app/assets/images/slices/icon_app.png +0 -0
  14. data/app/assets/images/slices/icon_assets.png +0 -0
  15. data/app/assets/images/slices/icon_collapse.png +0 -0
  16. data/app/assets/images/slices/icon_drag.png +0 -0
  17. data/app/assets/images/slices/icon_files.png +0 -0
  18. data/app/assets/images/slices/icon_generic_file.png +0 -0
  19. data/app/assets/images/slices/icon_images.png +0 -0
  20. data/app/assets/images/slices/icon_padlock.png +0 -0
  21. data/app/assets/images/slices/icon_page.png +0 -0
  22. data/app/assets/images/slices/icon_search.png +0 -0
  23. data/app/assets/images/slices/icon_set-link.png +0 -0
  24. data/app/assets/images/slices/icon_set.png +0 -0
  25. data/app/assets/images/slices/icon_sitemap.png +0 -0
  26. data/app/assets/images/slices/icon_snippets.png +0 -0
  27. data/app/assets/images/slices/icon_template.jpg +0 -0
  28. data/app/assets/images/slices/icon_upload_happy.png +0 -0
  29. data/app/assets/images/slices/icon_upload_sad.png +0 -0
  30. data/app/assets/images/slices/icon_upload_thinking.png +0 -0
  31. data/app/assets/images/slices/noise.png +0 -0
  32. data/app/assets/images/slices/sitemap_icon_ghost.png +0 -0
  33. data/app/assets/images/slices/sitemap_icon_home.png +0 -0
  34. data/app/assets/images/slices/sitemap_icon_page.png +0 -0
  35. data/app/assets/images/slices/sitemap_icon_set_page.png +0 -0
  36. data/app/assets/images/slices/sitemap_icon_virtual_page.png +0 -0
  37. data/app/assets/images/slices/sitemap_overlay.png +0 -0
  38. data/app/assets/images/slices/spinner.gif +0 -0
  39. data/app/assets/images/slices/trash.png +0 -0
  40. data/app/assets/javascripts/admin.js.erb +18 -0
  41. data/app/assets/javascripts/slices/app/backbones/admins.js +114 -0
  42. data/app/assets/javascripts/slices/app/backbones/entries.js +172 -0
  43. data/app/assets/javascripts/slices/app/backbones/generic.js +101 -0
  44. data/app/assets/javascripts/slices/app/backbones/snippets.js +113 -0
  45. data/app/assets/javascripts/slices/app/helpers/assets.js +61 -0
  46. data/app/assets/javascripts/slices/app/helpers/breadcrumbs.js +30 -0
  47. data/app/assets/javascripts/slices/app/helpers/composer.js +26 -0
  48. data/app/assets/javascripts/slices/app/helpers/date_field.js +16 -0
  49. data/app/assets/javascripts/slices/app/helpers/get_value.js +31 -0
  50. data/app/assets/javascripts/slices/app/helpers/icon_upload_names.js.erb +5 -0
  51. data/app/assets/javascripts/slices/app/helpers/layout.js +20 -0
  52. data/app/assets/javascripts/slices/app/helpers/sitemap.js +150 -0
  53. data/app/assets/javascripts/slices/app/helpers/slice_preview.js +48 -0
  54. data/app/assets/javascripts/slices/app/helpers/tagging.js +73 -0
  55. data/app/assets/javascripts/slices/app/helpers/token_field.js +17 -0
  56. data/app/assets/javascripts/slices/app/helpers/upload_icons.js.erb +5 -0
  57. data/app/assets/javascripts/slices/app/helpers/uploader.js +127 -0
  58. data/app/assets/javascripts/slices/app/models/asset.js +29 -0
  59. data/app/assets/javascripts/slices/app/models/asset_collection.js +41 -0
  60. data/app/assets/javascripts/slices/app/models/attachment.js +29 -0
  61. data/app/assets/javascripts/slices/app/models/attachment_collection.js +7 -0
  62. data/app/assets/javascripts/slices/app/models/composer_item.js +1 -0
  63. data/app/assets/javascripts/slices/app/models/composer_item_collection.js +3 -0
  64. data/app/assets/javascripts/slices/app/models/file.js +103 -0
  65. data/app/assets/javascripts/slices/app/models/page.js +186 -0
  66. data/app/assets/javascripts/slices/app/models/s3_file.js +64 -0
  67. data/app/assets/javascripts/slices/app/slices.js +661 -0
  68. data/app/assets/javascripts/slices/app/views/asset_editor_view.js.erb +209 -0
  69. data/app/assets/javascripts/slices/app/views/asset_library_view.js +720 -0
  70. data/app/assets/javascripts/slices/app/views/asset_thumb_view.js.erb +191 -0
  71. data/app/assets/javascripts/slices/app/views/attachment_composer_view.js +350 -0
  72. data/app/assets/javascripts/slices/app/views/attachment_view.js +101 -0
  73. data/app/assets/javascripts/slices/app/views/calendar_view.js +198 -0
  74. data/app/assets/javascripts/slices/app/views/composer_item_view.js +54 -0
  75. data/app/assets/javascripts/slices/app/views/composer_view.js +130 -0
  76. data/app/assets/javascripts/slices/app/views/date_field_view.js +177 -0
  77. data/app/assets/javascripts/slices/app/views/file_view.js +142 -0
  78. data/app/assets/javascripts/slices/app/views/token_field_view.js +253 -0
  79. data/app/assets/javascripts/slices/lib/freeze.js +14 -0
  80. data/app/assets/javascripts/slices/lib/human_file_size.js +16 -0
  81. data/app/assets/javascripts/slices/lib/json_patch.js +9 -0
  82. data/app/assets/javascripts/slices/lib/moment.js +47 -0
  83. data/app/assets/javascripts/slices/lib/plugins.js +101 -0
  84. data/app/assets/javascripts/slices/lib/sortable.js +14 -0
  85. data/app/assets/javascripts/slices/slices.js +27 -0
  86. data/app/assets/javascripts/slices/vendor/autoscroll.js +188 -0
  87. data/app/assets/javascripts/slices/vendor/backbone.js +38 -0
  88. data/app/assets/javascripts/slices/vendor/handlebars.js +1920 -0
  89. data/app/assets/javascripts/slices/vendor/jqmodal.js +69 -0
  90. data/app/assets/javascripts/slices/vendor/jquery-ui.js +274 -0
  91. data/app/assets/javascripts/slices/vendor/jquery-ui_nested-sortable.js +357 -0
  92. data/app/assets/javascripts/slices/vendor/jquery.ajaxprogress.js +76 -0
  93. data/app/assets/javascripts/slices/vendor/jquery.js +2 -0
  94. data/app/assets/javascripts/slices/vendor/livefield.js +459 -0
  95. data/app/assets/javascripts/slices/vendor/moment.js +6 -0
  96. data/app/assets/javascripts/slices/vendor/rails.js +315 -0
  97. data/app/assets/javascripts/slices/vendor/underscore-string.js +1 -0
  98. data/app/assets/javascripts/slices/vendor/underscore.js +5 -0
  99. data/app/assets/stylesheets/admin.css +1 -0
  100. data/app/assets/stylesheets/slices/admin.css.erb +2237 -0
  101. data/app/assets/stylesheets/slices/reset_html5.css +106 -0
  102. data/app/assets/stylesheets/slices/slices.css +7 -0
  103. data/app/controllers/admin/admin_controller.rb +10 -0
  104. data/app/controllers/admin/admins_controller.rb +76 -0
  105. data/app/controllers/admin/assets_controller.rb +53 -0
  106. data/app/controllers/admin/auth/omniauth_callbacks_controller.rb +15 -0
  107. data/app/controllers/admin/auth/passwords_controller.rb +4 -0
  108. data/app/controllers/admin/auth/sessions_controller.rb +4 -0
  109. data/app/controllers/admin/entries_controller.rb +88 -0
  110. data/app/controllers/admin/page_search_controller.rb +12 -0
  111. data/app/controllers/admin/pages_controller.rb +103 -0
  112. data/app/controllers/admin/site_maps_controller.rb +15 -0
  113. data/app/controllers/admin/snippets_controller.rb +33 -0
  114. data/app/controllers/application_controller.rb +4 -0
  115. data/app/controllers/pages_controller.rb +45 -0
  116. data/app/controllers/slices_controller.rb +63 -0
  117. data/app/controllers/static_assets_controller.rb +52 -0
  118. data/app/helpers/admin/admin_helper.rb +63 -0
  119. data/app/helpers/admin/assets_helper.rb +36 -0
  120. data/app/helpers/admin/entries_helper.rb +13 -0
  121. data/app/helpers/admin/site_maps_helper.rb +104 -0
  122. data/app/helpers/assets_helper.rb +64 -0
  123. data/app/helpers/navigation_helper.rb +195 -0
  124. data/app/helpers/pages_helper.rb +119 -0
  125. data/app/models/admin.rb +34 -0
  126. data/app/models/asset.rb +211 -0
  127. data/app/models/attachment.rb +11 -0
  128. data/app/models/layout.rb +44 -0
  129. data/app/models/page.rb +214 -0
  130. data/app/models/placeholder_slice.rb +8 -0
  131. data/app/models/set_page.rb +12 -0
  132. data/app/models/set_slice.rb +57 -0
  133. data/app/models/site_map.rb +24 -0
  134. data/app/models/slice.rb +80 -0
  135. data/app/models/snippet.rb +21 -0
  136. data/app/observers/asset_observer.rb +6 -0
  137. data/app/observers/page_observer.rb +37 -0
  138. data/app/presenters/entry_presenter.rb +17 -0
  139. data/app/presenters/page_presenter.rb +67 -0
  140. data/app/presenters/presenter.rb +9 -0
  141. data/app/presenters/set_page_presenter.rb +2 -0
  142. data/app/views/admin/admins/index.html.erb +26 -0
  143. data/app/views/admin/admins/show.html.erb +27 -0
  144. data/app/views/admin/assets/index.html.erb +1 -0
  145. data/app/views/admin/auth/passwords/edit.html.erb +20 -0
  146. data/app/views/admin/auth/passwords/new.html.erb +14 -0
  147. data/app/views/admin/auth/sessions/_form.html.erb +35 -0
  148. data/app/views/admin/auth/sessions/new.html.erb +14 -0
  149. data/app/views/admin/entries/index.html.erb +32 -0
  150. data/app/views/admin/pages/_breadcrumbs.html.erb +32 -0
  151. data/app/views/admin/pages/_slices.html.erb +27 -0
  152. data/app/views/admin/pages/new.html.erb +14 -0
  153. data/app/views/admin/pages/show.html.erb +50 -0
  154. data/app/views/admin/shared/_asset_storage.html.erb +17 -0
  155. data/app/views/admin/shared/_custom_links.html.erb +1 -0
  156. data/app/views/admin/shared/_custom_navigation.html.erb +1 -0
  157. data/app/views/admin/shared/_navigation.html.erb +5 -0
  158. data/app/views/admin/site_maps/_page_li.html.erb +20 -0
  159. data/app/views/admin/site_maps/_set_page_li.html.erb +23 -0
  160. data/app/views/admin/site_maps/index.html.erb +29 -0
  161. data/app/views/admin/snippets/form.html.erb +12 -0
  162. data/app/views/admin/snippets/index.html.erb +20 -0
  163. data/app/views/admin/snippets/update.html.erb +0 -0
  164. data/app/views/layouts/admin.html.erb +72 -0
  165. data/lib/ext/file_store_cache.rb +18 -0
  166. data/lib/generators/humans/USAGE +8 -0
  167. data/lib/generators/humans/humans_generator.rb +10 -0
  168. data/lib/generators/humans/templates/humans.txt +6 -0
  169. data/lib/generators/slice/USAGE +28 -0
  170. data/lib/generators/slice/slice_generator.rb +123 -0
  171. data/lib/generators/slice/templates/main_fields.hbs +11 -0
  172. data/lib/generators/slice/templates/meta_fields.hbs +11 -0
  173. data/lib/generators/slice/templates/page.rb +19 -0
  174. data/lib/generators/slice/templates/presenter.rb +53 -0
  175. data/lib/generators/slice/templates/set.html.erb +8 -0
  176. data/lib/generators/slice/templates/set_slice.rb +14 -0
  177. data/lib/generators/slice/templates/set_slice_fields.hbs +5 -0
  178. data/lib/generators/slice/templates/show.html.erb +48 -0
  179. data/lib/generators/slice/templates/show_slice.rb +20 -0
  180. data/lib/generators/slice/templates/slice.rb +58 -0
  181. data/lib/generators/slice/templates/slice_fields.hbs +74 -0
  182. data/lib/generators/templates/slices.rb +211 -0
  183. data/lib/mongo_search.rb +84 -0
  184. data/lib/paperclip_validator.rb +5 -0
  185. data/lib/rack_utf8_fix.rb +10 -0
  186. data/lib/sRGB.icc +0 -0
  187. data/lib/set_link_renderer.rb +31 -0
  188. data/lib/slices.rb +68 -0
  189. data/lib/slices/asset/maker.rb +55 -0
  190. data/lib/slices/asset/rename.rb +67 -0
  191. data/lib/slices/available_slices.rb +43 -0
  192. data/lib/slices/cms_form_builder.rb +42 -0
  193. data/lib/slices/config.rb +93 -0
  194. data/lib/slices/container_parser.rb +70 -0
  195. data/lib/slices/generator_macros.rb +36 -0
  196. data/lib/slices/has_attachments.rb +111 -0
  197. data/lib/slices/has_slices.rb +88 -0
  198. data/lib/slices/i18n.rb +6 -0
  199. data/lib/slices/i18n/backend.rb +32 -0
  200. data/lib/slices/i18n_backend.rb +24 -0
  201. data/lib/slices/paperclip.rb +13 -0
  202. data/lib/slices/position_helper.rb +98 -0
  203. data/lib/slices/renderer.rb +52 -0
  204. data/lib/slices/slices_engine.rb +51 -0
  205. data/lib/slices/split_date_time_field.rb +14 -0
  206. data/lib/slices/tasks/assets.rake +35 -0
  207. data/lib/slices/tasks/db.rake +50 -0
  208. data/lib/slices/tasks/seeds.rake +93 -0
  209. data/lib/slices/tasks/validate.rake +62 -0
  210. data/lib/slices/tree.rb +306 -0
  211. data/lib/slices/version.rb +4 -0
  212. data/lib/slices/will_paginate.rb +12 -0
  213. data/lib/slices/will_paginate_mongoid.rb +45 -0
  214. data/lib/standard_tree.rb +193 -0
  215. metadata +483 -0
@@ -0,0 +1,11 @@
1
+ class Attachment
2
+ include Mongoid::Document
3
+
4
+ belongs_to :asset
5
+
6
+ def as_json *args
7
+ attributes.as_json.merge asset: asset.as_json
8
+ end
9
+
10
+ end
11
+
@@ -0,0 +1,44 @@
1
+ class Layout
2
+ def self.all
3
+ files.map do |layout|
4
+ layout = layout.split('/').last.gsub(file_extension, '')
5
+ [layout.titleize, layout]
6
+ end
7
+ end
8
+
9
+ def self.files
10
+ files = []
11
+ SlicesController.view_paths.each do |resolver|
12
+ next if ignore_layout?(resolver.to_path)
13
+ query = File.join(resolver, 'layouts', "*#{file_extension}")
14
+ files.concat(Dir.glob(query))
15
+ end
16
+ files.reject do |file|
17
+ file.include?('admin.html.erb')
18
+ end.uniq.sort
19
+ end
20
+
21
+ def self.file_extension
22
+ '.html.erb'
23
+ end
24
+
25
+ def self.ignore_layout?(layout)
26
+ layout.include?(Slices.gem_path) && Rails.root.to_s != Slices.gem_path
27
+ end
28
+
29
+ def initialize(name)
30
+ @name = name
31
+ end
32
+
33
+ def path
34
+ self.class.files.select do |path|
35
+ path.split('/').last == @name + self.class.file_extension
36
+ end.first
37
+ end
38
+
39
+ def containers
40
+ parser = Slices::ContainerParser.new(path)
41
+ parser.parse
42
+ end
43
+
44
+ end
@@ -0,0 +1,214 @@
1
+ class Page
2
+ include Mongoid::Document
3
+ include Mongoid::Timestamps
4
+ include MongoSearch::Searchable
5
+
6
+ include Slices::Tree
7
+ include Slices::HasSlices
8
+ include Slices::HasAttachments::PageInstanceMethods
9
+
10
+ field :name
11
+ field :role # only relevant for virtual pages
12
+ field :active, type: Boolean, default: false
13
+ field :layout, type: String, default: 'default'
14
+ field :meta_description
15
+ field :title
16
+ field :has_content, type: Boolean, default: false
17
+
18
+ index :_keywords, background: true
19
+
20
+ has_slices :slices
21
+ has_and_belongs_to_many :assets
22
+
23
+ text_search_in :introduction, :extended, :name
24
+
25
+ scope :entries, all
26
+
27
+ def self.available_layouts
28
+ Layout.all.map do |human_name, machine_name|
29
+ { human_name: human_name, machine_name: machine_name }
30
+ end
31
+ end
32
+
33
+ scope :virtual, where(:role.ne => nil).asc(:name)
34
+ validates_presence_of :name
35
+
36
+ before_save :update_has_content
37
+ before_destroy :destroy_children
38
+ after_save :cache_virtual_page
39
+
40
+ class NotFound < RuntimeError; end
41
+
42
+ CACHED_VIRTUAL_PAGES = {
43
+ 'not_found' => '404',
44
+ 'error' => '500'
45
+ }
46
+
47
+ def self.role_for_status(status)
48
+ if CACHED_VIRTUAL_PAGES.has_value?(status)
49
+ CACHED_VIRTUAL_PAGES.detect { |k, v| v == status }[0]
50
+ else
51
+ nil
52
+ end
53
+ end
54
+
55
+ # Virtual pages don't live in the and are not associated with a
56
+ # specific URL. Instead, they can be rendered at any path, depending
57
+ # on the circumstances (e.g. when a page isn't found, or when an error
58
+ # occurs). Consequently they aren't created with a :parent attribute.
59
+ def self.make(attributes = {})
60
+ attributes = attributes.symbolize_keys
61
+ parent = parent_from_attributes(attributes)
62
+ attributes[:path] ||= path_from_attributes(attributes, parent)
63
+
64
+ new(attributes).tap do |page|
65
+ yield(page) if block_given?
66
+ page.parent = parent unless attributes.include?(:role)
67
+ if parent.present?
68
+ page.position = parent.children.count
69
+ page.layout = parent.layout if page.entry?
70
+ end
71
+ page.save
72
+ end
73
+ end
74
+
75
+ def self.find_by_id(id)
76
+ find(id)
77
+ rescue BSON::InvalidObjectId, Mongoid::Errors::DocumentNotFound
78
+ nil
79
+ end
80
+
81
+ def self.find_by_id!(id)
82
+ find_by_id(id) || (raise NotFound)
83
+ end
84
+
85
+ def self.find_virtual(role)
86
+ first(conditions: { role: role })
87
+ end
88
+
89
+ def cacheable_virtual_page?
90
+ CACHED_VIRTUAL_PAGES.has_key?(role)
91
+ end
92
+
93
+ def cache_virtual_page
94
+ if cacheable_virtual_page? && (! Rails.env.test?)
95
+ fork do
96
+ script = File.join(Slices.gem_path, 'script', 'request-local-page')
97
+ rails = File.join(Rails.root, 'script', 'rails')
98
+ path = "/#{CACHED_VIRTUAL_PAGES[role]}.html"
99
+ FileUtils.rm_f(File.join(Rails.root, 'public', path))
100
+ exec(rails, 'runner', '-e', Rails.env, script, path)
101
+ end
102
+ end
103
+ end
104
+
105
+ def virtual?
106
+ role.present?
107
+ end
108
+
109
+ def entry?
110
+ false
111
+ end
112
+
113
+ def set_page?
114
+ kind_of?(SetPage)
115
+ end
116
+
117
+ def sets
118
+ slices.select { |slice| slice.kind_of?(SetSlice) }
119
+ end
120
+
121
+ def set_slice(kind)
122
+ slice_class = Object.const_get("#{kind.to_s}SetSlice".camelize)
123
+ slices.detect { |slice| slice.kind_of?(slice_class) }
124
+ end
125
+
126
+ def template
127
+ "pages/show"
128
+ end
129
+
130
+ def update_attributes(attributes)
131
+ attributes = attributes.symbolize_keys
132
+
133
+ unless home?
134
+ if attributes.has_key?(:name) || attributes.has_key?(:permalink)
135
+ new_path = self.class.path_from_attributes(attributes, parent)
136
+ attributes[:path] = new_path if new_path != path
137
+ end
138
+ if attributes.has_key?(:path) && attributes[:path].blank?
139
+ attributes.delete(:path)
140
+ end
141
+ end
142
+
143
+ super
144
+ if valid?
145
+ update_path_for_children if attributes.has_key?(:path)
146
+ end
147
+ end
148
+
149
+ def as_json(options = {})
150
+ options ||= {}
151
+
152
+ hash = attributes.symbolize_keys.except(:_id, :_type, :_keywords, :set_slices, :site_id).merge(
153
+ id: id,
154
+ permalink: permalink,
155
+ slices: ordered_slices_for(options[:slice_embed]).map {|slice| slice.as_json },
156
+ available_layouts: available_layouts
157
+ )
158
+
159
+ keys = options[:only]
160
+ keys ? hash.slice(keys) : hash
161
+ end
162
+
163
+ # Added in merge or page & content
164
+ def set_keywords
165
+ super
166
+ slices.each do |slice|
167
+ self._keywords += MongoSearch::KeywordsExtractor.extract(slice.search_text)
168
+ end
169
+ self._keywords.uniq!
170
+ end
171
+
172
+ def available_layouts
173
+ self.class.available_layouts
174
+ end
175
+
176
+ # End of added
177
+
178
+ def description
179
+ ActiveSupport::Deprecation::warn "Page#description is now meta_description. If you are upgrading, run 'rake slices:migrate:meta_description' to update."
180
+ meta_description
181
+ end
182
+
183
+ def description=(value)
184
+ ActiveSupport::Deprecation::warn "Page#description is now meta_description. If you are upgrading, run 'rake slices:migrate:meta_description' to update."
185
+ self.meta_description = value
186
+ end
187
+
188
+ private
189
+ def self.parent_from_attributes(attributes)
190
+ if attributes.has_key?(:parent_path)
191
+ Page.find_by_path(attributes.delete(:parent_path))
192
+ elsif attributes.has_key?(:parent_id)
193
+ Page.find_by_id(attributes.delete(:parent_id))
194
+ else
195
+ attributes.delete(:parent)
196
+ end
197
+ end
198
+
199
+ def self.page_exists?(path)
200
+ Page.find_by_path(path)
201
+ rescue NotFound
202
+ false
203
+ end
204
+
205
+ def update_has_content
206
+ self.has_content = slices.any?
207
+ true # must be true otherwise save will fail
208
+ end
209
+
210
+ def destroy_children
211
+ children.each { |child| child.destroy }
212
+ end
213
+
214
+ end
@@ -0,0 +1,8 @@
1
+ class PlaceholderSlice < Slice
2
+ restricted_slice
3
+
4
+ def render
5
+ renderer.render_container(self.container, current_page.ordered_slices)
6
+ end
7
+ end
8
+
@@ -0,0 +1,12 @@
1
+ class SetPage < Page
2
+
3
+ has_slices :set_slices
4
+
5
+ def entry_types
6
+ sets.map { |set| set.entry_type }
7
+ end
8
+
9
+ def entries(type)
10
+ children.criteria.where(_type: type.to_s.classify)
11
+ end
12
+ end
@@ -0,0 +1,57 @@
1
+ class SetSlice < Slice
2
+ include Mongoid::Document
3
+
4
+ DEFAULT_SORT_FIELD = :created_at
5
+ DEFAULT_SORT_DIRECTION = :desc
6
+
7
+ field :per_page, type: Integer, default: 5
8
+ field :sort_field, type: String, default: DEFAULT_SORT_FIELD
9
+ field :sort_direction, type: String, default: DEFAULT_SORT_DIRECTION
10
+
11
+ def prepare(params)
12
+ @page_num = params[:page] || 1
13
+ end
14
+
15
+ def addable_entries?
16
+ true
17
+ end
18
+
19
+ def editable_entries?
20
+ true
21
+ end
22
+
23
+ def entry_type
24
+ self.class.name.sub('SetSlice', '').underscore.to_sym
25
+ end
26
+
27
+ def entries
28
+ sorted selected_by_type normal_or_set_page.children
29
+ end
30
+
31
+ def page_entries(params = {})
32
+ entries.paginate(paginate_options(params))
33
+ end
34
+
35
+ def paginate_options(params)
36
+ params.reverse_merge(page: @page_num, per_page: per_page)
37
+ end
38
+
39
+ def sort_field
40
+ read_attribute(:sort_field) || DEFAULT_SORT_FIELD
41
+ end
42
+
43
+ def sort_direction
44
+ read_attribute(:sort_direction) || DEFAULT_SORT_DIRECTION
45
+ end
46
+
47
+
48
+ private
49
+
50
+ def sorted entries
51
+ entries.send sort_direction, sort_field
52
+ end
53
+
54
+ def selected_by_type entries
55
+ entries.where _type: entry_type.to_s.classify
56
+ end
57
+ end
@@ -0,0 +1,24 @@
1
+ class SiteMap
2
+
3
+ def self.rebuild(tree)
4
+ set_children_for(tree.first['id'], tree.first['children'])
5
+ end
6
+
7
+ def permalink
8
+ '{root}'
9
+ end
10
+
11
+ private
12
+
13
+ def self.set_children_for(parent_id, data)
14
+ parent = Page.find(parent_id)
15
+ data.each_with_index do |child_data, i|
16
+ child = Page.find(child_data['id'])
17
+ child.position = i
18
+ child.parent = parent
19
+ child.path = child.generate_path
20
+ child.save!
21
+ set_children_for(child_data['id'], child_data['children']) if child_data['children']
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,80 @@
1
+ class Slice
2
+ include Mongoid::Document
3
+ include Slices::PositionHelper
4
+
5
+ field :container
6
+ field :position, type: Integer, default: 999
7
+
8
+ class_attribute :restricted
9
+ embedded_in :normal_page, class_name: 'Page', inverse_of: :slices
10
+ embedded_in :set_page, inverse_of: :set_slices
11
+
12
+ attr_accessor :renderer, :current_page
13
+ alias :page :current_page
14
+
15
+ def self.restricted_slice
16
+ self.restricted = true
17
+ end
18
+
19
+ def self.restricted?
20
+ self.restricted == true
21
+ end
22
+
23
+ def setup(options)
24
+ self.renderer = options[:renderer]
25
+ self.current_page = options[:current_page]
26
+ end
27
+
28
+ def prepare(params)
29
+ end
30
+
31
+ def render
32
+ renderer.render_to_string(template_path, locals: {
33
+ slice: self
34
+ })
35
+ end
36
+
37
+ def normal_or_set_page
38
+ normal_page || set_page
39
+ end
40
+
41
+ def template_path
42
+ template = (type =~ /_(set|show)$/) ? $1 : 'show'
43
+ File.join type.sub(/_show$/, '_set'), 'views', template
44
+ end
45
+
46
+ def type
47
+ _type.to_s.underscore.gsub(/_slice$/, '')
48
+ end
49
+
50
+ def reference
51
+ [_type, id].join(':')
52
+ end
53
+
54
+ def client_id?
55
+ attributes.include?('client_id')
56
+ end
57
+
58
+ def id_or_client_id
59
+ client_id? ? client_id : id
60
+ end
61
+
62
+ def to_delete?
63
+ attributes.include?('_deleted')
64
+ end
65
+
66
+ def as_json(*args)
67
+ attributes.symbolize_keys.except(:_id, :_type).tap do |result|
68
+ result.merge!(id: id, type: type)
69
+ result.merge!(client_id: client_id) if client_id? && new_record?
70
+ end
71
+ end
72
+
73
+ def search_text
74
+ text_fields = fields.values.select do |field|
75
+ (field.type == String) && (field.name !~ /^container$|_id$/)
76
+ end
77
+ text_fields.map { |field| self[field.name.to_sym] }.join(" ")
78
+ end
79
+ end
80
+