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.
- data/CHANGELOG.md +3 -0
- data/README.md +51 -0
- data/Rakefile +9 -0
- data/app/assets/images/slices/ajax-loader.gif +0 -0
- data/app/assets/images/slices/asset-background.png +0 -0
- data/app/assets/images/slices/asset-spinner.gif +0 -0
- data/app/assets/images/slices/bg_header.gif +0 -0
- data/app/assets/images/slices/black-Linen.png +0 -0
- data/app/assets/images/slices/calendar.svg +68 -0
- data/app/assets/images/slices/chosen-sprite.png +0 -0
- data/app/assets/images/slices/drag-handle.svg +9 -0
- data/app/assets/images/slices/icon_admins.png +0 -0
- data/app/assets/images/slices/icon_app.png +0 -0
- data/app/assets/images/slices/icon_assets.png +0 -0
- data/app/assets/images/slices/icon_collapse.png +0 -0
- data/app/assets/images/slices/icon_drag.png +0 -0
- data/app/assets/images/slices/icon_files.png +0 -0
- data/app/assets/images/slices/icon_generic_file.png +0 -0
- data/app/assets/images/slices/icon_images.png +0 -0
- data/app/assets/images/slices/icon_padlock.png +0 -0
- data/app/assets/images/slices/icon_page.png +0 -0
- data/app/assets/images/slices/icon_search.png +0 -0
- data/app/assets/images/slices/icon_set-link.png +0 -0
- data/app/assets/images/slices/icon_set.png +0 -0
- data/app/assets/images/slices/icon_sitemap.png +0 -0
- data/app/assets/images/slices/icon_snippets.png +0 -0
- data/app/assets/images/slices/icon_template.jpg +0 -0
- data/app/assets/images/slices/icon_upload_happy.png +0 -0
- data/app/assets/images/slices/icon_upload_sad.png +0 -0
- data/app/assets/images/slices/icon_upload_thinking.png +0 -0
- data/app/assets/images/slices/noise.png +0 -0
- data/app/assets/images/slices/sitemap_icon_ghost.png +0 -0
- data/app/assets/images/slices/sitemap_icon_home.png +0 -0
- data/app/assets/images/slices/sitemap_icon_page.png +0 -0
- data/app/assets/images/slices/sitemap_icon_set_page.png +0 -0
- data/app/assets/images/slices/sitemap_icon_virtual_page.png +0 -0
- data/app/assets/images/slices/sitemap_overlay.png +0 -0
- data/app/assets/images/slices/spinner.gif +0 -0
- data/app/assets/images/slices/trash.png +0 -0
- data/app/assets/javascripts/admin.js.erb +18 -0
- data/app/assets/javascripts/slices/app/backbones/admins.js +114 -0
- data/app/assets/javascripts/slices/app/backbones/entries.js +172 -0
- data/app/assets/javascripts/slices/app/backbones/generic.js +101 -0
- data/app/assets/javascripts/slices/app/backbones/snippets.js +113 -0
- data/app/assets/javascripts/slices/app/helpers/assets.js +61 -0
- data/app/assets/javascripts/slices/app/helpers/breadcrumbs.js +30 -0
- data/app/assets/javascripts/slices/app/helpers/composer.js +26 -0
- data/app/assets/javascripts/slices/app/helpers/date_field.js +16 -0
- data/app/assets/javascripts/slices/app/helpers/get_value.js +31 -0
- data/app/assets/javascripts/slices/app/helpers/icon_upload_names.js.erb +5 -0
- data/app/assets/javascripts/slices/app/helpers/layout.js +20 -0
- data/app/assets/javascripts/slices/app/helpers/sitemap.js +150 -0
- data/app/assets/javascripts/slices/app/helpers/slice_preview.js +48 -0
- data/app/assets/javascripts/slices/app/helpers/tagging.js +73 -0
- data/app/assets/javascripts/slices/app/helpers/token_field.js +17 -0
- data/app/assets/javascripts/slices/app/helpers/upload_icons.js.erb +5 -0
- data/app/assets/javascripts/slices/app/helpers/uploader.js +127 -0
- data/app/assets/javascripts/slices/app/models/asset.js +29 -0
- data/app/assets/javascripts/slices/app/models/asset_collection.js +41 -0
- data/app/assets/javascripts/slices/app/models/attachment.js +29 -0
- data/app/assets/javascripts/slices/app/models/attachment_collection.js +7 -0
- data/app/assets/javascripts/slices/app/models/composer_item.js +1 -0
- data/app/assets/javascripts/slices/app/models/composer_item_collection.js +3 -0
- data/app/assets/javascripts/slices/app/models/file.js +103 -0
- data/app/assets/javascripts/slices/app/models/page.js +186 -0
- data/app/assets/javascripts/slices/app/models/s3_file.js +64 -0
- data/app/assets/javascripts/slices/app/slices.js +661 -0
- data/app/assets/javascripts/slices/app/views/asset_editor_view.js.erb +209 -0
- data/app/assets/javascripts/slices/app/views/asset_library_view.js +720 -0
- data/app/assets/javascripts/slices/app/views/asset_thumb_view.js.erb +191 -0
- data/app/assets/javascripts/slices/app/views/attachment_composer_view.js +350 -0
- data/app/assets/javascripts/slices/app/views/attachment_view.js +101 -0
- data/app/assets/javascripts/slices/app/views/calendar_view.js +198 -0
- data/app/assets/javascripts/slices/app/views/composer_item_view.js +54 -0
- data/app/assets/javascripts/slices/app/views/composer_view.js +130 -0
- data/app/assets/javascripts/slices/app/views/date_field_view.js +177 -0
- data/app/assets/javascripts/slices/app/views/file_view.js +142 -0
- data/app/assets/javascripts/slices/app/views/token_field_view.js +253 -0
- data/app/assets/javascripts/slices/lib/freeze.js +14 -0
- data/app/assets/javascripts/slices/lib/human_file_size.js +16 -0
- data/app/assets/javascripts/slices/lib/json_patch.js +9 -0
- data/app/assets/javascripts/slices/lib/moment.js +47 -0
- data/app/assets/javascripts/slices/lib/plugins.js +101 -0
- data/app/assets/javascripts/slices/lib/sortable.js +14 -0
- data/app/assets/javascripts/slices/slices.js +27 -0
- data/app/assets/javascripts/slices/vendor/autoscroll.js +188 -0
- data/app/assets/javascripts/slices/vendor/backbone.js +38 -0
- data/app/assets/javascripts/slices/vendor/handlebars.js +1920 -0
- data/app/assets/javascripts/slices/vendor/jqmodal.js +69 -0
- data/app/assets/javascripts/slices/vendor/jquery-ui.js +274 -0
- data/app/assets/javascripts/slices/vendor/jquery-ui_nested-sortable.js +357 -0
- data/app/assets/javascripts/slices/vendor/jquery.ajaxprogress.js +76 -0
- data/app/assets/javascripts/slices/vendor/jquery.js +2 -0
- data/app/assets/javascripts/slices/vendor/livefield.js +459 -0
- data/app/assets/javascripts/slices/vendor/moment.js +6 -0
- data/app/assets/javascripts/slices/vendor/rails.js +315 -0
- data/app/assets/javascripts/slices/vendor/underscore-string.js +1 -0
- data/app/assets/javascripts/slices/vendor/underscore.js +5 -0
- data/app/assets/stylesheets/admin.css +1 -0
- data/app/assets/stylesheets/slices/admin.css.erb +2237 -0
- data/app/assets/stylesheets/slices/reset_html5.css +106 -0
- data/app/assets/stylesheets/slices/slices.css +7 -0
- data/app/controllers/admin/admin_controller.rb +10 -0
- data/app/controllers/admin/admins_controller.rb +76 -0
- data/app/controllers/admin/assets_controller.rb +53 -0
- data/app/controllers/admin/auth/omniauth_callbacks_controller.rb +15 -0
- data/app/controllers/admin/auth/passwords_controller.rb +4 -0
- data/app/controllers/admin/auth/sessions_controller.rb +4 -0
- data/app/controllers/admin/entries_controller.rb +88 -0
- data/app/controllers/admin/page_search_controller.rb +12 -0
- data/app/controllers/admin/pages_controller.rb +103 -0
- data/app/controllers/admin/site_maps_controller.rb +15 -0
- data/app/controllers/admin/snippets_controller.rb +33 -0
- data/app/controllers/application_controller.rb +4 -0
- data/app/controllers/pages_controller.rb +45 -0
- data/app/controllers/slices_controller.rb +63 -0
- data/app/controllers/static_assets_controller.rb +52 -0
- data/app/helpers/admin/admin_helper.rb +63 -0
- data/app/helpers/admin/assets_helper.rb +36 -0
- data/app/helpers/admin/entries_helper.rb +13 -0
- data/app/helpers/admin/site_maps_helper.rb +104 -0
- data/app/helpers/assets_helper.rb +64 -0
- data/app/helpers/navigation_helper.rb +195 -0
- data/app/helpers/pages_helper.rb +119 -0
- data/app/models/admin.rb +34 -0
- data/app/models/asset.rb +211 -0
- data/app/models/attachment.rb +11 -0
- data/app/models/layout.rb +44 -0
- data/app/models/page.rb +214 -0
- data/app/models/placeholder_slice.rb +8 -0
- data/app/models/set_page.rb +12 -0
- data/app/models/set_slice.rb +57 -0
- data/app/models/site_map.rb +24 -0
- data/app/models/slice.rb +80 -0
- data/app/models/snippet.rb +21 -0
- data/app/observers/asset_observer.rb +6 -0
- data/app/observers/page_observer.rb +37 -0
- data/app/presenters/entry_presenter.rb +17 -0
- data/app/presenters/page_presenter.rb +67 -0
- data/app/presenters/presenter.rb +9 -0
- data/app/presenters/set_page_presenter.rb +2 -0
- data/app/views/admin/admins/index.html.erb +26 -0
- data/app/views/admin/admins/show.html.erb +27 -0
- data/app/views/admin/assets/index.html.erb +1 -0
- data/app/views/admin/auth/passwords/edit.html.erb +20 -0
- data/app/views/admin/auth/passwords/new.html.erb +14 -0
- data/app/views/admin/auth/sessions/_form.html.erb +35 -0
- data/app/views/admin/auth/sessions/new.html.erb +14 -0
- data/app/views/admin/entries/index.html.erb +32 -0
- data/app/views/admin/pages/_breadcrumbs.html.erb +32 -0
- data/app/views/admin/pages/_slices.html.erb +27 -0
- data/app/views/admin/pages/new.html.erb +14 -0
- data/app/views/admin/pages/show.html.erb +50 -0
- data/app/views/admin/shared/_asset_storage.html.erb +17 -0
- data/app/views/admin/shared/_custom_links.html.erb +1 -0
- data/app/views/admin/shared/_custom_navigation.html.erb +1 -0
- data/app/views/admin/shared/_navigation.html.erb +5 -0
- data/app/views/admin/site_maps/_page_li.html.erb +20 -0
- data/app/views/admin/site_maps/_set_page_li.html.erb +23 -0
- data/app/views/admin/site_maps/index.html.erb +29 -0
- data/app/views/admin/snippets/form.html.erb +12 -0
- data/app/views/admin/snippets/index.html.erb +20 -0
- data/app/views/admin/snippets/update.html.erb +0 -0
- data/app/views/layouts/admin.html.erb +72 -0
- data/lib/ext/file_store_cache.rb +18 -0
- data/lib/generators/humans/USAGE +8 -0
- data/lib/generators/humans/humans_generator.rb +10 -0
- data/lib/generators/humans/templates/humans.txt +6 -0
- data/lib/generators/slice/USAGE +28 -0
- data/lib/generators/slice/slice_generator.rb +123 -0
- data/lib/generators/slice/templates/main_fields.hbs +11 -0
- data/lib/generators/slice/templates/meta_fields.hbs +11 -0
- data/lib/generators/slice/templates/page.rb +19 -0
- data/lib/generators/slice/templates/presenter.rb +53 -0
- data/lib/generators/slice/templates/set.html.erb +8 -0
- data/lib/generators/slice/templates/set_slice.rb +14 -0
- data/lib/generators/slice/templates/set_slice_fields.hbs +5 -0
- data/lib/generators/slice/templates/show.html.erb +48 -0
- data/lib/generators/slice/templates/show_slice.rb +20 -0
- data/lib/generators/slice/templates/slice.rb +58 -0
- data/lib/generators/slice/templates/slice_fields.hbs +74 -0
- data/lib/generators/templates/slices.rb +211 -0
- data/lib/mongo_search.rb +84 -0
- data/lib/paperclip_validator.rb +5 -0
- data/lib/rack_utf8_fix.rb +10 -0
- data/lib/sRGB.icc +0 -0
- data/lib/set_link_renderer.rb +31 -0
- data/lib/slices.rb +68 -0
- data/lib/slices/asset/maker.rb +55 -0
- data/lib/slices/asset/rename.rb +67 -0
- data/lib/slices/available_slices.rb +43 -0
- data/lib/slices/cms_form_builder.rb +42 -0
- data/lib/slices/config.rb +93 -0
- data/lib/slices/container_parser.rb +70 -0
- data/lib/slices/generator_macros.rb +36 -0
- data/lib/slices/has_attachments.rb +111 -0
- data/lib/slices/has_slices.rb +88 -0
- data/lib/slices/i18n.rb +6 -0
- data/lib/slices/i18n/backend.rb +32 -0
- data/lib/slices/i18n_backend.rb +24 -0
- data/lib/slices/paperclip.rb +13 -0
- data/lib/slices/position_helper.rb +98 -0
- data/lib/slices/renderer.rb +52 -0
- data/lib/slices/slices_engine.rb +51 -0
- data/lib/slices/split_date_time_field.rb +14 -0
- data/lib/slices/tasks/assets.rake +35 -0
- data/lib/slices/tasks/db.rake +50 -0
- data/lib/slices/tasks/seeds.rake +93 -0
- data/lib/slices/tasks/validate.rake +62 -0
- data/lib/slices/tree.rb +306 -0
- data/lib/slices/version.rb +4 -0
- data/lib/slices/will_paginate.rb +12 -0
- data/lib/slices/will_paginate_mongoid.rb +45 -0
- data/lib/standard_tree.rb +193 -0
- metadata +483 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
module Slices
|
|
2
|
+
class ContainerParser
|
|
3
|
+
class MissingLayoutError < StandardError; end
|
|
4
|
+
|
|
5
|
+
def initialize(path)
|
|
6
|
+
raise MissingLayoutError if path.nil?
|
|
7
|
+
@path = path
|
|
8
|
+
@containers = {}
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def parse
|
|
12
|
+
@page = Page.new
|
|
13
|
+
erb_template = File.read(@path)
|
|
14
|
+
@erb = ActionView::Template::Handlers::Erubis.new(erb_template)
|
|
15
|
+
parse_with_block {}
|
|
16
|
+
@containers
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Define a +container+ in a layout, a container holds slices on a page.
|
|
20
|
+
#
|
|
21
|
+
# This container is called Title and only allows title and You Tube slices
|
|
22
|
+
#
|
|
23
|
+
# container "title", :only => [TitleSlice, YouTubeSlice]
|
|
24
|
+
#
|
|
25
|
+
# Here's a container called body which is the primary and does not allow
|
|
26
|
+
# title slices.
|
|
27
|
+
#
|
|
28
|
+
# container "body", :primary => true, :except => TitleSlice
|
|
29
|
+
#
|
|
30
|
+
# @param [String] name Name of container
|
|
31
|
+
# @param [Hash] options
|
|
32
|
+
# @option options [Boolean] :primary (false) Is this container the primary
|
|
33
|
+
# @option options [Class,Array] :except Disallow these slice(s) from this container
|
|
34
|
+
# @option options [Class,Array] :only Only allow these slice(s) from this container
|
|
35
|
+
# @return [String]
|
|
36
|
+
#
|
|
37
|
+
def container(name, options = {})
|
|
38
|
+
[:except, :only].each do |type|
|
|
39
|
+
if options.has_key? type
|
|
40
|
+
options[type] = convert_slice_classes_to_symbols(options[type])
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
@containers[name] = options.reverse_merge name: name.titleize
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def method_missing(meth, *args, &block)
|
|
48
|
+
yield if block_given?
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def parse_with_block(&block)
|
|
54
|
+
@erb.result(binding)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def convert_slice_classes_to_symbols(options = [])
|
|
58
|
+
[options].flatten.select do |klass|
|
|
59
|
+
klass.is_a?(Class)
|
|
60
|
+
end.map do |klass|
|
|
61
|
+
convert_slice_class_to_symbol(klass)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def convert_slice_class_to_symbol(klass)
|
|
66
|
+
klass.name.underscore.split('_')[0 .. -2].join('_').to_sym
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module Slices
|
|
2
|
+
module GeneratorMacros
|
|
3
|
+
# Defines a generator method.
|
|
4
|
+
#
|
|
5
|
+
# e.g.
|
|
6
|
+
#
|
|
7
|
+
# generator :home do
|
|
8
|
+
# Page.where(path: '/').first || Page.make(
|
|
9
|
+
# name: 'Home'
|
|
10
|
+
# )
|
|
11
|
+
# end
|
|
12
|
+
#
|
|
13
|
+
# Results in:
|
|
14
|
+
#
|
|
15
|
+
# MyStandardTree.home
|
|
16
|
+
#
|
|
17
|
+
#
|
|
18
|
+
# @param [Symbol] name
|
|
19
|
+
# @param [Proc] block macro body
|
|
20
|
+
#
|
|
21
|
+
def generator name, &block
|
|
22
|
+
define_singleton_method name, &block
|
|
23
|
+
generators << name
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Simple catalogue of generators.
|
|
27
|
+
def generators
|
|
28
|
+
@generators ||= []
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Invokes all generators.
|
|
32
|
+
def generate!
|
|
33
|
+
generators.map { |m| send m }
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
module Slices
|
|
2
|
+
module HasAttachments
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
module ClassMethods
|
|
6
|
+
|
|
7
|
+
def has_attachments(embed_name = :attachments, options = {})
|
|
8
|
+
klass = if options.has_key?(:class_name)
|
|
9
|
+
options[:class_name].constantize
|
|
10
|
+
else
|
|
11
|
+
Attachment
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
default = options[:default] || options[:singular] ? nil : []
|
|
15
|
+
type = options[:singular] ? Hash : Array
|
|
16
|
+
|
|
17
|
+
if options[:singular]
|
|
18
|
+
define_method embed_name do
|
|
19
|
+
if embed = read_attribute(embed_name)
|
|
20
|
+
klass.new embed
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
else
|
|
24
|
+
define_method embed_name do
|
|
25
|
+
(read_attribute(embed_name) || []).collect do |embed|
|
|
26
|
+
klass.new embed
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
attachment_fields << embed_name
|
|
32
|
+
|
|
33
|
+
field embed_name, type: type, default: default
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def attachment_fields
|
|
37
|
+
@attachment_fields ||= if superclass.respond_to?(:attachment_fields)
|
|
38
|
+
superclass.attachment_fields.dup
|
|
39
|
+
else
|
|
40
|
+
[]
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
module PageInstanceMethods
|
|
47
|
+
|
|
48
|
+
def attachment_assets
|
|
49
|
+
attachment_asset_ids.inject([]) do |memo, asset_id|
|
|
50
|
+
begin
|
|
51
|
+
memo << ::Asset.find(asset_id)
|
|
52
|
+
rescue Mongoid::Errors::DocumentNotFound
|
|
53
|
+
end
|
|
54
|
+
memo
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def slice_attachment_asset_ids
|
|
59
|
+
[].tap do |asset_ids|
|
|
60
|
+
self.class.slice_embeds.each do |slice_embed|
|
|
61
|
+
slices_for(slice_embed).each do |slice|
|
|
62
|
+
if slice.respond_to? :attachment_asset_ids
|
|
63
|
+
asset_ids.concat slice.attachment_asset_ids
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
alias :attachment_asset_ids :slice_attachment_asset_ids
|
|
70
|
+
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def as_json options = nil
|
|
74
|
+
super.merge(attachments_as_json)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def attachments_as_json
|
|
78
|
+
self.class.attachment_fields.inject({}) do |hash, name|
|
|
79
|
+
value = send name
|
|
80
|
+
|
|
81
|
+
hash[name] = if value.respond_to?(:map)
|
|
82
|
+
value.map &:as_json
|
|
83
|
+
else
|
|
84
|
+
value.as_json
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
hash
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def attachment_asset_ids
|
|
92
|
+
_attachment_asset_ids.tap do |asset_ids|
|
|
93
|
+
if respond_to? :slice_attachment_asset_ids
|
|
94
|
+
asset_ids.concat slice_attachment_asset_ids
|
|
95
|
+
end
|
|
96
|
+
asset_ids.uniq!
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def _attachment_asset_ids
|
|
101
|
+
attachment_asset_ids = self.class.attachment_fields.collect do |attachments|
|
|
102
|
+
[send(attachments)].flatten.collect do |attachment|
|
|
103
|
+
attachment.asset_id
|
|
104
|
+
end.reject {|i| i.nil? }
|
|
105
|
+
end.flat_map {|i| i }
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
end
|
|
111
|
+
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
module Slices
|
|
2
|
+
module HasSlices
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
included do
|
|
6
|
+
validate :validate_slices
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
module ClassMethods
|
|
10
|
+
def has_slices(embed_name)
|
|
11
|
+
embeds_many embed_name, class_name: 'Slice', validate: false
|
|
12
|
+
accepts_nested_attributes_for embed_name, allow_destroy: true
|
|
13
|
+
|
|
14
|
+
class_attribute :slice_embeds if self == Page
|
|
15
|
+
if slice_embeds.nil?
|
|
16
|
+
self.slice_embeds = [embed_name]
|
|
17
|
+
else
|
|
18
|
+
self.slice_embeds = slice_embeds + [embed_name]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
22
|
+
def ordered_#{embed_name} # def orderd_slices
|
|
23
|
+
#{embed_name}.ascending(:position) # slices.ascending(:position)
|
|
24
|
+
end # end
|
|
25
|
+
RUBY
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def update_attributes(attributes)
|
|
30
|
+
[:slices, :set_slices].each do |type|
|
|
31
|
+
next if attributes[type].nil?
|
|
32
|
+
|
|
33
|
+
attributes[type] = attributes[type].map { |slice|
|
|
34
|
+
slice = slice.symbolize_keys
|
|
35
|
+
next if slice[:_destroy]
|
|
36
|
+
slice.delete :_new
|
|
37
|
+
klass = (slice[:type] + '_slice').camelize.constantize
|
|
38
|
+
klass.new(slice)
|
|
39
|
+
}.compact
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
super
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def slices_for(embed_name)
|
|
46
|
+
send(embed_name)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def ordered_slices_for(embed_name=nil)
|
|
50
|
+
embed_name = self.class.slice_embeds.first if embed_name.nil?
|
|
51
|
+
send("ordered_#{embed_name}")
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def validate_slices
|
|
55
|
+
embeded_slices do |embed_name|
|
|
56
|
+
_slice_errors = slice_errors_for(embed_name)
|
|
57
|
+
if _slice_errors.any?
|
|
58
|
+
errors.add(embed_name, _slice_errors)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def slice_errors_for(embed_name)
|
|
64
|
+
Hash.new.tap do |message|
|
|
65
|
+
slices_for(embed_name).each do |slice|
|
|
66
|
+
if ! slice.valid? && ! slice.to_delete?
|
|
67
|
+
message[slice.id_or_client_id] = messages_from_errors(slice.errors)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def embeded_slices(&block)
|
|
74
|
+
self.class.slice_embeds.each do |embed_name|
|
|
75
|
+
yield(embed_name)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def messages_from_errors(errors)
|
|
80
|
+
if errors.respond_to?(:messages)
|
|
81
|
+
errors.messages
|
|
82
|
+
else
|
|
83
|
+
errors
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
end
|
|
88
|
+
end
|
data/lib/slices/i18n.rb
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module Slices
|
|
2
|
+
module I18n
|
|
3
|
+
|
|
4
|
+
class Backend
|
|
5
|
+
module Implementation
|
|
6
|
+
include ::I18n::Backend::Base, ::I18n::Backend::Flatten
|
|
7
|
+
|
|
8
|
+
# This method receives a locale, a data hash and options for storing translations.
|
|
9
|
+
# Should be implemented
|
|
10
|
+
def store_translations(locale, data, options = {})
|
|
11
|
+
raise NotImplementedError
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def available_locales
|
|
15
|
+
raise NotImplementedError
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
protected
|
|
19
|
+
|
|
20
|
+
def lookup(locale, key, scope = [], options = {})
|
|
21
|
+
key = normalize_flat_keys(locale, key, scope, options[:separator])
|
|
22
|
+
Snippet.find_value_by_key("#{locale}.#{key}")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
include Implementation
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
saise 'aaaaa'
|
|
2
|
+
module Slices
|
|
3
|
+
|
|
4
|
+
class I18nBackend
|
|
5
|
+
include I18n::Backend::Simple::Implementation
|
|
6
|
+
|
|
7
|
+
# Translates the given local and key. See the I18n API documentation for details.
|
|
8
|
+
#
|
|
9
|
+
# @return [Object] the translated key (usually a String)
|
|
10
|
+
def translate(locale, key, options = {})
|
|
11
|
+
content = super(locale, key, options.merge(fallback: true))
|
|
12
|
+
if content.respond_to?(:html_safe)
|
|
13
|
+
content.html_safe
|
|
14
|
+
else
|
|
15
|
+
content
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
I18n.backend = I18n::Backend::Chain.new(
|
|
22
|
+
Slices::I18n::Backend.new,
|
|
23
|
+
I18n.backend
|
|
24
|
+
)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Paperclip.options[:log] = true
|
|
2
|
+
require 'paperclip_validator'
|
|
3
|
+
|
|
4
|
+
Paperclip.interpolates :mon_year do |attachment, style|
|
|
5
|
+
attachment.instance.id.generation_time.strftime("%m%Y")
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
#This is a hack used to access Paperclip's internal cache
|
|
9
|
+
#of attributes it reads from the attachment. Used as part
|
|
10
|
+
#of the file renaming code.
|
|
11
|
+
class Paperclip::Attachment
|
|
12
|
+
attr_accessor :_file_file_name
|
|
13
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
module Slices
|
|
2
|
+
module PositionHelper
|
|
3
|
+
|
|
4
|
+
# Returns an array of slices in the same container, including self.
|
|
5
|
+
#
|
|
6
|
+
# @return [Array]
|
|
7
|
+
#
|
|
8
|
+
def peers
|
|
9
|
+
@peers ||= normal_or_set_page.ordered_slices.select do |slice|
|
|
10
|
+
slice.container == self.container
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Returns the previous slice in the container, or +nil+ if this is the
|
|
15
|
+
# first slice.
|
|
16
|
+
#
|
|
17
|
+
# @return [Slice]
|
|
18
|
+
#
|
|
19
|
+
def previous_slice
|
|
20
|
+
index = peers.index(self) - 1
|
|
21
|
+
index < 0 ? nil : peers[index]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Returns the next slice in the container, or +nil+ if this is the
|
|
25
|
+
# last slice.
|
|
26
|
+
#
|
|
27
|
+
# @return [Slice]
|
|
28
|
+
#
|
|
29
|
+
def next_slice
|
|
30
|
+
peers[peers.index(self) + 1]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Is this the first slice in the container?
|
|
34
|
+
#
|
|
35
|
+
def first_in_container?
|
|
36
|
+
self == peers.first
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Is the previous slice of the same type?
|
|
40
|
+
#
|
|
41
|
+
def first_adjacent_of_type?
|
|
42
|
+
previous_slice.try(:class) != self.class
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Is this the last slice in the container?
|
|
46
|
+
#
|
|
47
|
+
def last_in_container?
|
|
48
|
+
self == peers.last
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Is the next slice the same type?
|
|
52
|
+
#
|
|
53
|
+
def last_adjacent_of_type?
|
|
54
|
+
next_slice.try(:class) != self.class
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Is this the only slice in the container?
|
|
58
|
+
#
|
|
59
|
+
def alone_in_container?
|
|
60
|
+
peers.size == 1
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Are both the next and previous slices different types?
|
|
64
|
+
#
|
|
65
|
+
def alone_in_adjacent_of_type?
|
|
66
|
+
first_adjacent_of_type? && last_adjacent_of_type?
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# The position of the slice in the container, the first slice has a position
|
|
70
|
+
# of 1
|
|
71
|
+
#
|
|
72
|
+
# @return [Integer]
|
|
73
|
+
#
|
|
74
|
+
def position_in_container
|
|
75
|
+
peers.index(self) + 1
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# The position of the slice in a group of the same slices
|
|
79
|
+
#
|
|
80
|
+
# For example, given the following slices
|
|
81
|
+
# [TitleSlice, CopySlice, CopySlice, CopySlice]
|
|
82
|
+
#
|
|
83
|
+
# The second +CopySlice+ would have a +position_in_adjacent_of_type+ of 2
|
|
84
|
+
#
|
|
85
|
+
# @return [Integer]
|
|
86
|
+
#
|
|
87
|
+
def position_in_adjacent_of_type
|
|
88
|
+
slices = []
|
|
89
|
+
reversed = peers.reverse
|
|
90
|
+
reversed[reversed.index(self)..-1].each do |slice|
|
|
91
|
+
break unless slice.class == self.class
|
|
92
|
+
slices << slice
|
|
93
|
+
end
|
|
94
|
+
slices.length
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
end
|