smithycms 0.0.1
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/MIT-LICENSE +20 -0
- data/README.md +142 -0
- data/Rakefile +27 -0
- data/app/assets/images/smithy/logo.png +0 -0
- data/app/assets/images/smithy/logo2.png +0 -0
- data/app/assets/javascripts/smithy/application.js +13 -0
- data/app/assets/javascripts/smithy/assets.js.coffee +35 -0
- data/app/assets/javascripts/smithy/guides.js +23 -0
- data/app/assets/javascripts/smithy/jquery-ui.min.js +5 -0
- data/app/assets/javascripts/smithy/nested_forms.js +55 -0
- data/app/assets/javascripts/smithy/page_contents.js +4 -0
- data/app/assets/javascripts/smithy/pages.js +41 -0
- data/app/assets/javascripts/smithy/settings.js +0 -0
- data/app/assets/javascripts/smithy/templates.js +25 -0
- data/app/assets/stylesheets/smithy/application.css.scss +29 -0
- data/app/assets/stylesheets/smithy/assets.css.scss +3 -0
- data/app/assets/stylesheets/smithy/bootstrap_and_overrides.css.scss +12 -0
- data/app/assets/stylesheets/smithy/content_blocks.css.scss +2 -0
- data/app/assets/stylesheets/smithy/forms.css.scss +3 -0
- data/app/assets/stylesheets/smithy/guides.css.scss +5 -0
- data/app/assets/stylesheets/smithy/layout.css.scss +113 -0
- data/app/assets/stylesheets/smithy/pages.css.scss +35 -0
- data/app/assets/stylesheets/smithy/templates.css.scss +14 -0
- data/app/controllers/smithy/assets_controller.rb +50 -0
- data/app/controllers/smithy/base_controller.rb +14 -0
- data/app/controllers/smithy/caches_controller.rb +13 -0
- data/app/controllers/smithy/content_blocks_controller.rb +50 -0
- data/app/controllers/smithy/content_pieces_controller.rb +97 -0
- data/app/controllers/smithy/contents_controller.rb +41 -0
- data/app/controllers/smithy/guides_controller.rb +9 -0
- data/app/controllers/smithy/images_controller.rb +41 -0
- data/app/controllers/smithy/page_contents_controller.rb +90 -0
- data/app/controllers/smithy/pages_controller.rb +110 -0
- data/app/controllers/smithy/settings_controller.rb +46 -0
- data/app/controllers/smithy/sitemap_controller.rb +13 -0
- data/app/controllers/smithy/templates_controller.rb +79 -0
- data/app/helpers/smithy/application_helper.rb +36 -0
- data/app/helpers/smithy/assets_helper.rb +9 -0
- data/app/helpers/smithy/pages_helper.rb +12 -0
- data/app/helpers/smithy/settings_helper.rb +4 -0
- data/app/helpers/smithy/templates_helper.rb +4 -0
- data/app/helpers/smithy/upload_helper.rb +110 -0
- data/app/models/smithy/asset.rb +64 -0
- data/app/models/smithy/content.rb +35 -0
- data/app/models/smithy/content_block.rb +41 -0
- data/app/models/smithy/content_block_template.rb +26 -0
- data/app/models/smithy/image.rb +41 -0
- data/app/models/smithy/page.rb +94 -0
- data/app/models/smithy/page_content.rb +62 -0
- data/app/models/smithy/page_list.rb +61 -0
- data/app/models/smithy/page_proxy.rb +63 -0
- data/app/models/smithy/setting.rb +6 -0
- data/app/models/smithy/site.rb +30 -0
- data/app/models/smithy/template.rb +53 -0
- data/app/models/smithy/template_container.rb +16 -0
- data/app/views/layouts/smithy/application.html.erb +27 -0
- data/app/views/layouts/smithy/guides.html.erb +16 -0
- data/app/views/layouts/smithy/modal.html.erb +10 -0
- data/app/views/layouts/smithy/shared/_flash.html.erb +6 -0
- data/app/views/layouts/smithy/shared/_footer.html.erb +3 -0
- data/app/views/layouts/smithy/shared/_head.html.erb +8 -0
- data/app/views/layouts/smithy/shared/_nav.html.erb +37 -0
- data/app/views/layouts/smithy/shared/_tail.html.erb +4 -0
- data/app/views/layouts/smithy/wide.html.erb +24 -0
- data/app/views/smithy/assets/_asset.html.erb +10 -0
- data/app/views/smithy/assets/_form.html.erb +13 -0
- data/app/views/smithy/assets/_upload_form.html.erb +13 -0
- data/app/views/smithy/assets/create.js.erb +5 -0
- data/app/views/smithy/assets/edit.html.erb +5 -0
- data/app/views/smithy/assets/index.html.erb +13 -0
- data/app/views/smithy/assets/new.html.erb +13 -0
- data/app/views/smithy/caches/show.html.erb +8 -0
- data/app/views/smithy/content_blocks/_content_block.html.erb +1 -0
- data/app/views/smithy/content_blocks/_secondary_nav.html.erb +12 -0
- data/app/views/smithy/content_blocks/_template_fields.html.erb +19 -0
- data/app/views/smithy/content_blocks/edit.html.erb +31 -0
- data/app/views/smithy/content_blocks/index.html.erb +17 -0
- data/app/views/smithy/content_blocks/new.html.erb +12 -0
- data/app/views/smithy/content_pieces/edit.html.erb +13 -0
- data/app/views/smithy/content_pieces/index.html.erb +21 -0
- data/app/views/smithy/content_pieces/new.html.erb +1 -0
- data/app/views/smithy/contents/_form.html.erb +6 -0
- data/app/views/smithy/contents/_form_fields.html.erb +12 -0
- data/app/views/smithy/contents/edit.html.erb +3 -0
- data/app/views/smithy/contents/new.html.erb +3 -0
- data/app/views/smithy/guides/markdown.html.erb +150 -0
- data/app/views/smithy/images/_form.html.erb +6 -0
- data/app/views/smithy/images/_form_fields.html.erb +28 -0
- data/app/views/smithy/images/edit.html.erb +3 -0
- data/app/views/smithy/images/new.html.erb +3 -0
- data/app/views/smithy/page_contents/edit.html.erb +18 -0
- data/app/views/smithy/page_contents/new.html.erb +28 -0
- data/app/views/smithy/page_lists/_form_fields.html.erb +6 -0
- data/app/views/smithy/pages/_container.html.erb +24 -0
- data/app/views/smithy/pages/_form.html.erb +57 -0
- data/app/views/smithy/pages/_page.html.erb +6 -0
- data/app/views/smithy/pages/_page_nav.html.erb +6 -0
- data/app/views/smithy/pages/_page_related.html.erb +21 -0
- data/app/views/smithy/pages/_parent.html.erb +10 -0
- data/app/views/smithy/pages/_root.html.erb +5 -0
- data/app/views/smithy/pages/edit.html.erb +7 -0
- data/app/views/smithy/pages/index.html.erb +17 -0
- data/app/views/smithy/pages/new.html.erb +7 -0
- data/app/views/smithy/settings/_form.html.erb +7 -0
- data/app/views/smithy/settings/_setting.html.erb +6 -0
- data/app/views/smithy/settings/edit.html.erb +3 -0
- data/app/views/smithy/settings/index.html.erb +9 -0
- data/app/views/smithy/settings/new.html.erb +3 -0
- data/app/views/smithy/settings/show.html.erb +10 -0
- data/app/views/smithy/sitemap/show.xml.erb +10 -0
- data/app/views/smithy/templates/_secondary_nav.html.erb +21 -0
- data/app/views/smithy/templates/_template.html.erb +1 -0
- data/app/views/smithy/templates/edit.html.erb +36 -0
- data/app/views/smithy/templates/index.html.erb +17 -0
- data/app/views/smithy/templates/new.html.erb +13 -0
- data/config/initializers/aws.rb +5 -0
- data/config/initializers/dragonfly.rb +48 -0
- data/config/initializers/formtastic.rb +77 -0
- data/config/initializers/kaminari_config.rb +10 -0
- data/config/initializers/liquid.rb +2 -0
- data/config/routes.rb +38 -0
- data/db/migrate/20120911193140_create_smithy_templates.rb +11 -0
- data/db/migrate/20120911203618_create_smithy_settings.rb +10 -0
- data/db/migrate/20121018182146_create_smithy_pages.rb +27 -0
- data/db/migrate/20121019145543_create_smithy_template_containers.rb +11 -0
- data/db/migrate/20121019160426_create_smithy_page_contents.rb +21 -0
- data/db/migrate/20121024213357_create_smithy_content_blocks.rb +10 -0
- data/db/migrate/20121025011733_create_smithy_content_block_templates.rb +12 -0
- data/db/migrate/20121029175812_create_smithy_contents.rb +9 -0
- data/db/migrate/20121105222537_create_smithy_assets.rb +16 -0
- data/db/migrate/20121115215053_create_smithy_images.rb +15 -0
- data/db/migrate/20121127205022_add_external_link_to_smithy_pages.rb +5 -0
- data/db/migrate/20130115190505_add_markdown_content_to_smithy_contents.rb +5 -0
- data/db/migrate/20130123170918_set_defaults_for_show_in_navigation_and_cache_length.rb +6 -0
- data/db/migrate/20130311203806_create_smithy_page_lists.rb +15 -0
- data/db/migrate/20130312161116_remove_description_from_content_block.rb +5 -0
- data/db/migrate/20130326191051_add_html_attributes_to_images.rb +5 -0
- data/db/migrate/20131003210228_add_publishable_to_smithy_page_contents.rb +11 -0
- data/db/migrate/20131220160755_add_content_to_images.rb +5 -0
- data/db/migrate/20131223145710_add_position_to_smithy_template_containers.rb +5 -0
- data/lib/smithy/content_blocks/model.rb +16 -0
- data/lib/smithy/content_blocks/registry.rb +30 -0
- data/lib/smithy/content_blocks.rb +2 -0
- data/lib/smithy/content_pieces/base.rb +10 -0
- data/lib/smithy/content_pieces/registry.rb +39 -0
- data/lib/smithy/dependencies.rb +19 -0
- data/lib/smithy/dragonfly/asset_helper.rb +67 -0
- data/lib/smithy/dragonfly/remote_data_store.rb +33 -0
- data/lib/smithy/dragonfly.rb +30 -0
- data/lib/smithy/engine.rb +48 -0
- data/lib/smithy/formatter.rb +46 -0
- data/lib/smithy/liquid/database.rb +12 -0
- data/lib/smithy/liquid/drops/base.rb +16 -0
- data/lib/smithy/liquid/drops/page.rb +78 -0
- data/lib/smithy/liquid/filters/asset_tag.rb +33 -0
- data/lib/smithy/liquid/filters/resize.rb +12 -0
- data/lib/smithy/liquid/rendering.rb +50 -0
- data/lib/smithy/liquid/tags/asset.rb +54 -0
- data/lib/smithy/liquid/tags/csrf.rb +30 -0
- data/lib/smithy/liquid/tags/html.rb +61 -0
- data/lib/smithy/liquid/tags/nav.rb +76 -0
- data/lib/smithy/liquid.rb +8 -0
- data/lib/smithy/logger.rb +12 -0
- data/lib/smithy/version.rb +3 -0
- data/lib/smithy.rb +21 -0
- data/lib/smithycms.rb +1 -0
- data/lib/tasks/smithy_tasks.rake +4 -0
- data/lib/templates/erb/scaffold/_form.html.erb +11 -0
- metadata +871 -0
@@ -0,0 +1,41 @@
|
|
1
|
+
module Smithy
|
2
|
+
class Image < ActiveRecord::Base
|
3
|
+
include Smithy::ContentBlocks::Model
|
4
|
+
|
5
|
+
attr_accessible :alternate_text, :asset_id, :height, :html_attributes, :image_scaling, :link_url, :width, :content
|
6
|
+
|
7
|
+
validates_presence_of :asset
|
8
|
+
|
9
|
+
belongs_to :asset
|
10
|
+
has_many :page_contents, :as => :content_block, :dependent => :destroy
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def content_block_description
|
14
|
+
"Images are primarily used for adding image-based content to your pages"
|
15
|
+
end
|
16
|
+
|
17
|
+
def image_scaling_options
|
18
|
+
[
|
19
|
+
['Keep to Scale', ''],
|
20
|
+
['Force Exact Dimensions (this may crop the image)', '#']
|
21
|
+
]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def formatted_content
|
26
|
+
@formatted_content ||= markdown_formatter.render
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_liquid
|
30
|
+
attributes.tap do |a|
|
31
|
+
a['asset'] = asset.to_liquid if asset.present?
|
32
|
+
a['formatted_content'] = formatted_content
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
def markdown_formatter
|
38
|
+
@markdown_formatter ||= Smithy::Formatter.new(self.content)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Smithy
|
2
|
+
class Page < ActiveRecord::Base
|
3
|
+
attr_accessible :browser_title, :cache_length, :description, :external_link, :keywords, :permalink, :publish, :published_at, :show_in_navigation, :title, :parent_id, :template_id
|
4
|
+
|
5
|
+
validates_presence_of :template, :title
|
6
|
+
validate :validate_one_root
|
7
|
+
validate :validate_exclusion_of_reserved_words
|
8
|
+
|
9
|
+
belongs_to :template
|
10
|
+
has_many :containers, :through => :template
|
11
|
+
has_many :contents, :class_name => "PageContent"
|
12
|
+
|
13
|
+
acts_as_nested_set :dependent => :destroy
|
14
|
+
extend FriendlyId
|
15
|
+
friendly_id :title, :use => [:slugged, :scoped], :slug_column => 'path', :scope => :parent_id
|
16
|
+
|
17
|
+
before_save :build_permalink
|
18
|
+
before_save :set_published_at
|
19
|
+
|
20
|
+
accepts_nested_attributes_for :contents, :reject_if => lambda {|a| a['label'].blank? || a['container'].blank? || a['content_block'].blank? }, :allow_destroy => true
|
21
|
+
|
22
|
+
scope :included_in_navigation, lambda{ where("show_in_navigation=? AND published_at <= ?", true, Time.now) }
|
23
|
+
|
24
|
+
attr_accessor :publish
|
25
|
+
|
26
|
+
def container?(container_name)
|
27
|
+
containers.where(:name => container_name).count > 0
|
28
|
+
end
|
29
|
+
|
30
|
+
def contents_for_container_name(container_name)
|
31
|
+
self.contents.publishable.for_container(container_name)
|
32
|
+
end
|
33
|
+
|
34
|
+
def normalize_friendly_id(value) # normalize_friendly_id overrides the default creator for friendly_id
|
35
|
+
return "/" if self.parent.blank?
|
36
|
+
value = self.permalink? ? self.permalink.parameterize : value.to_s.parameterize
|
37
|
+
[(self.parent.present? && !self.parent.root? ? self.parent.path : nil), value].join('/')
|
38
|
+
end
|
39
|
+
|
40
|
+
def published?
|
41
|
+
self.published_at?
|
42
|
+
end
|
43
|
+
|
44
|
+
def render_container(container_name)
|
45
|
+
return '' unless container?(container_name)
|
46
|
+
Rails.cache.fetch(self.container_cache_key(container_name)) do
|
47
|
+
self.contents_for_container_name(container_name).map(&:render).join("\n\n")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def site
|
52
|
+
@site ||= Smithy::Site.new
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_liquid
|
56
|
+
Smithy::Liquid::Drops::Page.new(self)
|
57
|
+
end
|
58
|
+
|
59
|
+
def url
|
60
|
+
self.external_link.present? ? self.external_link : self.path
|
61
|
+
end
|
62
|
+
|
63
|
+
protected
|
64
|
+
def container_cache_key(container_name)
|
65
|
+
# fetch the most recently adjusted content and add the updated_at timestamp to the cache_key
|
66
|
+
content_last_updated = if self.contents_for_container_name(container_name).count > 0
|
67
|
+
self.contents_for_container_name(container_name).order(nil).order('created_at DESC').first.updated_at
|
68
|
+
else
|
69
|
+
self.updated_at
|
70
|
+
end
|
71
|
+
"#{self.cache_key}/#{container_name}-container/#{content_last_updated.utc.to_s(cache_timestamp_format)}"
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
def build_permalink
|
76
|
+
self.permalink = self.root? ? title.parameterize : path.split('/').last unless self.permalink?
|
77
|
+
end
|
78
|
+
|
79
|
+
def set_published_at
|
80
|
+
self.published_at = Time.now if self.publish.present?
|
81
|
+
self.published_at = nil if self.publish == false
|
82
|
+
end
|
83
|
+
|
84
|
+
def validate_exclusion_of_reserved_words
|
85
|
+
reserved = %w(index new edit session login logout users smithy)
|
86
|
+
errors.add(:title, "cannot contain reserved words (#{reserved.join(', ')})") if reserved.include?(self.title.to_s.parameterize)
|
87
|
+
end
|
88
|
+
|
89
|
+
def validate_one_root
|
90
|
+
errors.add(:parent_id, 'must have a parent') if self.class.root && self.class.root != self && self.parent_id.blank?
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Smithy
|
2
|
+
class PageContent < ActiveRecord::Base
|
3
|
+
attr_accessible :label, :container, :content_block_type, :content_block_attributes, :content_block_template_id, :position
|
4
|
+
|
5
|
+
validates_presence_of :content_block, :content_block_template, :on => :update
|
6
|
+
validates_presence_of :content_block_type, :on => :create
|
7
|
+
validates_presence_of :label, :container, :page
|
8
|
+
|
9
|
+
belongs_to :page, :touch => true
|
10
|
+
belongs_to :content_block, :polymorphic => true
|
11
|
+
belongs_to :content_block_template
|
12
|
+
|
13
|
+
before_update :set_publishable
|
14
|
+
|
15
|
+
accepts_nested_attributes_for :content_block, :allow_destroy => true
|
16
|
+
|
17
|
+
default_scope order(:position).order(:id)
|
18
|
+
scope :for_container, lambda {|container| where(:container => container) }
|
19
|
+
scope :publishable, lambda { where(:publishable => true) }
|
20
|
+
|
21
|
+
def attributes=(attributes = {})
|
22
|
+
self.content_block_type = attributes[:content_block_type]
|
23
|
+
super
|
24
|
+
end
|
25
|
+
|
26
|
+
def content_block_attributes=(attributes)
|
27
|
+
klass = content_block_type.safe_constantize || "Smithy::#{content_block_type}".safe_constantize
|
28
|
+
if klass
|
29
|
+
self.content_block = klass.find_or_initialize_by_id(attributes.delete(:id))
|
30
|
+
self.content_block.attributes = attributes
|
31
|
+
self.content_block
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def render
|
36
|
+
content_block_template.liquid_template.render(self.to_liquid)
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_liquid
|
40
|
+
if content_block.respond_to?(:to_liquid)
|
41
|
+
content_block.to_liquid
|
42
|
+
else
|
43
|
+
content_block.attributes
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def templates
|
48
|
+
unless @templates
|
49
|
+
@templates = []
|
50
|
+
if Smithy::ContentBlock.find_by_name(self.content_block_type.demodulize)
|
51
|
+
@templates = Smithy::ContentBlock.find_by_name(self.content_block_type.demodulize).templates
|
52
|
+
end
|
53
|
+
end
|
54
|
+
@templates
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
def set_publishable
|
59
|
+
self.publishable = true if self.content_block
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Smithy
|
2
|
+
class PageList < ActiveRecord::Base
|
3
|
+
include Smithy::ContentBlocks::Model
|
4
|
+
|
5
|
+
attr_accessible :count, :page_template_id, :parent_id, :include_children, :sort
|
6
|
+
|
7
|
+
validates_presence_of :parent_id
|
8
|
+
|
9
|
+
belongs_to :parent, :class_name => "Page"
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def content_block_description
|
13
|
+
"Page Lists are primarily used to provide a sub-navigation for parent pages or cross-navigation to other sections of your website."
|
14
|
+
end
|
15
|
+
|
16
|
+
def sort_options
|
17
|
+
[
|
18
|
+
['Sitemap Order', 'sitemap'],
|
19
|
+
['Most Recently Created First', 'created_desc'],
|
20
|
+
['Earliest Created First', 'created_asc'],
|
21
|
+
['Alphabetical Order', 'title_asc'],
|
22
|
+
['Reverse Alphabetical Order', 'title_desc']
|
23
|
+
]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def pages
|
28
|
+
unless @pages
|
29
|
+
return unless self.parent
|
30
|
+
@pages = self.parent.children
|
31
|
+
@pages = @pages.except(:order).order(sort_sql) unless sort_sql.nil?
|
32
|
+
@pages = @pages.limit(self.count) if self.count?
|
33
|
+
@pages = @pages.where(:template_id => self.page_template_id) if self.page_template_id?
|
34
|
+
end
|
35
|
+
@pages
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_liquid
|
39
|
+
{
|
40
|
+
'id' => self.id,
|
41
|
+
'parent' => self.parent,
|
42
|
+
'pages' => self.pages
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
def sort_sql
|
48
|
+
case self.sort
|
49
|
+
when 'created_desc'
|
50
|
+
'created_at DESC'
|
51
|
+
when 'created_asc'
|
52
|
+
'created_at ASC'
|
53
|
+
when 'title_asc'
|
54
|
+
'title ASC'
|
55
|
+
when 'title_desc'
|
56
|
+
'title DESC'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
module Smithy
|
3
|
+
class PageProxy
|
4
|
+
# The PageProxy class is a way for a developer to use an already existing
|
5
|
+
# template in their own controllers and views.
|
6
|
+
# Simply instantiate the object and set the appropriate attributes.
|
7
|
+
# You can even render your views in erb and pass the results along for the
|
8
|
+
# Smithy template containers you've already created from within Smithy
|
9
|
+
# Eg:
|
10
|
+
# class ExamplesController < ApplicationController
|
11
|
+
# respond_to :html
|
12
|
+
# layout false
|
13
|
+
# include Smithy::Liquid::Rendering
|
14
|
+
# def index
|
15
|
+
# @page = Smithy::PageProxy.new(:path => request.path, :title => "Test")
|
16
|
+
# @page.add_to_container(:main_content, render_to_string(:action => 'index'))
|
17
|
+
# respond_with @page do |format|
|
18
|
+
# format.html { render_as_smithy_page('Default') }
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
|
23
|
+
|
24
|
+
attr_accessor :id, :browser_title, :title, :path, :keywords, :description
|
25
|
+
|
26
|
+
def initialize(attributes = {})
|
27
|
+
@containers = {}
|
28
|
+
[:id, :browser_title, :title, :path, :keywords, :description].each do |k|
|
29
|
+
self.send("#{k}=".to_sym, attributes[k]) if attributes[k].present?
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def id
|
34
|
+
@id ||= Digest::MD5.hexdigest(path)
|
35
|
+
end
|
36
|
+
|
37
|
+
def containers
|
38
|
+
@containers
|
39
|
+
end
|
40
|
+
|
41
|
+
def add_to_container(container_name, content)
|
42
|
+
@containers[container_name.to_s] ||= ''
|
43
|
+
@containers[container_name.to_s] << content
|
44
|
+
@containers
|
45
|
+
end
|
46
|
+
|
47
|
+
def site
|
48
|
+
@site ||= Smithy::Site.new
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_liquid
|
52
|
+
{
|
53
|
+
'id' => self.id,
|
54
|
+
'browser_title' => (self.browser_title.present? ? self.browser_title : self.title),
|
55
|
+
'title' => title,
|
56
|
+
'path' => path,
|
57
|
+
'meta_description' => description,
|
58
|
+
'meta_keywords' => keywords,
|
59
|
+
'container' => containers
|
60
|
+
}
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Smithy
|
2
|
+
class Site
|
3
|
+
@@title = nil
|
4
|
+
|
5
|
+
class << self
|
6
|
+
def title
|
7
|
+
@@title
|
8
|
+
end
|
9
|
+
|
10
|
+
def title=(str)
|
11
|
+
@@title = str
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def title
|
16
|
+
self.class.title
|
17
|
+
end
|
18
|
+
|
19
|
+
def root
|
20
|
+
@root ||= Smithy::Page.root
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_liquid
|
24
|
+
{
|
25
|
+
'title' => self.title,
|
26
|
+
'root' => self.root.to_liquid
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Smithy
|
2
|
+
class Template < ActiveRecord::Base
|
3
|
+
attr_accessible :name, :content, :template_type
|
4
|
+
|
5
|
+
validates_presence_of :name
|
6
|
+
validates_uniqueness_of :name, :scope => :template_type
|
7
|
+
validates_presence_of :content, :on => :update
|
8
|
+
|
9
|
+
has_many :pages
|
10
|
+
has_many :containers, :class_name => "TemplateContainer"
|
11
|
+
|
12
|
+
before_save :uncache_liquid_template_if_content_changed
|
13
|
+
after_save :load_containers
|
14
|
+
after_save :touch_pages
|
15
|
+
|
16
|
+
default_scope order(:name)
|
17
|
+
scope :javascripts, where(:template_type => "javascript")
|
18
|
+
scope :partials, where(:template_type => "include")
|
19
|
+
scope :stylesheets, where(:template_type => "stylesheet")
|
20
|
+
scope :templates, where(:template_type => "template")
|
21
|
+
|
22
|
+
class << self
|
23
|
+
def types
|
24
|
+
%w(template include javascript stylesheet)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
validates_inclusion_of :template_type, :in => types # has to be after the class method definition
|
28
|
+
|
29
|
+
def liquid_template
|
30
|
+
@liquid_template ||= Rails.cache.fetch("#{self.cache_key}-liquid_template") do
|
31
|
+
::Liquid::Template.parse(self.content)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
def load_containers
|
37
|
+
return unless self.template_type == 'template'
|
38
|
+
container_names = liquid_template.root.nodelist.select{|n| n.is_a?(::Liquid::Variable) && n.name.match(/^page\.container\.(.*)/) }.map{|n| n.name.match(/^page\.container\.(.*)/)[1] }
|
39
|
+
# self.containers = container_names.map{|container_name| Smithy::TemplateContainer.new(:name => container_name) }
|
40
|
+
self.containers = container_names.inject([]) do |containers, container_name|
|
41
|
+
containers.push Smithy::TemplateContainer.new(:name => container_name, :position => containers.size)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def touch_pages
|
46
|
+
self.pages.each(&:touch)
|
47
|
+
end
|
48
|
+
|
49
|
+
def uncache_liquid_template_if_content_changed
|
50
|
+
@liquid_template = nil if self.content_changed?
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Smithy
|
2
|
+
class TemplateContainer < ActiveRecord::Base
|
3
|
+
validates_presence_of :name, :template
|
4
|
+
|
5
|
+
belongs_to :template
|
6
|
+
has_many :pages, :through => :template
|
7
|
+
|
8
|
+
attr_accessible :name, :position
|
9
|
+
|
10
|
+
default_scope :order => [:position, :name]
|
11
|
+
|
12
|
+
def display_name
|
13
|
+
name.titleize
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
<%= render :partial => "layouts/smithy/shared/head" %>
|
2
|
+
<body>
|
3
|
+
<%= render :partial => "layouts/smithy/shared/nav" %>
|
4
|
+
|
5
|
+
<nav id="side">
|
6
|
+
<%= yield :secondary_nav %>
|
7
|
+
</nav>
|
8
|
+
<div id="main">
|
9
|
+
<% if content_for? :title %><h1><%= yield :title %></h1><% end %>
|
10
|
+
<%= render :partial => "layouts/smithy/shared/flash", :locals => { flash: flash } %>
|
11
|
+
<%= yield :top_content %>
|
12
|
+
<div class="container-fluid">
|
13
|
+
<section class="row-fluid" id="content-container">
|
14
|
+
|
15
|
+
<article id="content" class="span9">
|
16
|
+
<%= yield %>
|
17
|
+
</article>
|
18
|
+
|
19
|
+
<aside id="related" class="span3">
|
20
|
+
<%= yield :related %>
|
21
|
+
</aside>
|
22
|
+
|
23
|
+
</section>
|
24
|
+
</div>
|
25
|
+
</div>
|
26
|
+
<%= render :partial => "layouts/smithy/shared/footer" %>
|
27
|
+
<%= render :partial => "layouts/smithy/shared/tail" %>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<%= render :partial => "layouts/smithy/shared/head" %>
|
2
|
+
<body>
|
3
|
+
|
4
|
+
<div id="main-wide">
|
5
|
+
<% if content_for? :title %><h1><%= yield :title %></h1><% end %>
|
6
|
+
<%= render :partial => "layouts/smithy/shared/flash", :locals => { flash: flash } %>
|
7
|
+
<%= yield :top_content %>
|
8
|
+
<div class="container-fluid">
|
9
|
+
<section class="row-fluid" id="content-container">
|
10
|
+
<article id="content" class="span12">
|
11
|
+
<%= yield %>
|
12
|
+
</article>
|
13
|
+
</section>
|
14
|
+
</div>
|
15
|
+
</div>
|
16
|
+
<%= render :partial => "layouts/smithy/shared/tail" %>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<div class="modal-header">
|
2
|
+
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
3
|
+
<h3><%= yield :title %> </h3>
|
4
|
+
</div>
|
5
|
+
<div class="modal-body">
|
6
|
+
<%= yield %>
|
7
|
+
</div>
|
8
|
+
<div class="modal-footer">
|
9
|
+
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
|
10
|
+
</div>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title><% if content_for?(:browser_title) %><%= yield :browser_title %><% else %><%= yield :title %><% end %><%= " | " if content_for?(:browser_title) || content_for?(:title) %>Smithy</title>
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6
|
+
<%= stylesheet_link_tag "smithy/application", :media => "all" %>
|
7
|
+
<%= csrf_meta_tags %>
|
8
|
+
</head>
|
@@ -0,0 +1,37 @@
|
|
1
|
+
<header id="header">
|
2
|
+
<h1><%= image_tag "smithy/logo2.png", alt:'' %></h1>
|
3
|
+
</header>
|
4
|
+
<div id="main-nav" class="navbar navbar-inverse">
|
5
|
+
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
|
6
|
+
<span class="icon-bar"></span>
|
7
|
+
<span class="icon-bar"></span>
|
8
|
+
<span class="icon-bar"></span>
|
9
|
+
</a>
|
10
|
+
<div class="navbar-inner">
|
11
|
+
<div class="container">
|
12
|
+
<div class="nav-collapse clearfix">
|
13
|
+
<%- if smithy_current_user -%>
|
14
|
+
<ul class="nav">
|
15
|
+
<li><%= link_to "<i class=\"icon-sitemap\"></i> Manage Content".html_safe, pages_path %></li>
|
16
|
+
<li><%= link_to "<i class=\"icon-file\"></i> Images & Files".html_safe, assets_path %></li>
|
17
|
+
</ul>
|
18
|
+
<ul class="nav pull-right">
|
19
|
+
<li><%= link_to "<i class=\"icon-arrow-right\"></i> View Site".html_safe, root_path %></li>
|
20
|
+
<li class="dropdown">
|
21
|
+
<a class="dropdown-toggle" data-toggle="dropdown" href="#"><i class="icon-cogs"></i> Admin<b class="caret"></b></a>
|
22
|
+
<ul class="dropdown-menu">
|
23
|
+
<li><%= link_to "<i class=\"icon-book\"></i> Templates".html_safe, templates_path %></li>
|
24
|
+
<li><%= link_to "<i class=\"icon-list-alt\"></i> Content Blocks".html_safe, content_blocks_path %></li>
|
25
|
+
<li><%= link_to "<i class=\"icon-cog\"></i> Settings".html_safe, settings_path %></li>
|
26
|
+
</ul>
|
27
|
+
</li>
|
28
|
+
<% if respond_to?(:logout_path) %>
|
29
|
+
<li><%= link_to "<i class=\"icon-signout\"></i> Logout".html_safe, logout_path, :method => :delete %></li>
|
30
|
+
<% end %>
|
31
|
+
</ul>
|
32
|
+
<% end %>
|
33
|
+
</div>
|
34
|
+
</div>
|
35
|
+
</div>
|
36
|
+
</div>
|
37
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<%= render :partial => "layouts/smithy/shared/head" %>
|
2
|
+
<body class="wide">
|
3
|
+
<%= render :partial => "layouts/smithy/shared/nav" %>
|
4
|
+
|
5
|
+
<nav id="side">
|
6
|
+
<%= yield :secondary_nav %>
|
7
|
+
</nav>
|
8
|
+
<div id="main">
|
9
|
+
<% if content_for? :title %><h1><%= yield :title %></h1><% end %>
|
10
|
+
<%= render :partial => "layouts/smithy/shared/flash", :locals => { flash: flash } %>
|
11
|
+
<%= yield :top_content %>
|
12
|
+
<div class="container-fluid">
|
13
|
+
<section class="row-fluid" id="content-container">
|
14
|
+
<article id="content" class="span12">
|
15
|
+
<%= yield %>
|
16
|
+
|
17
|
+
<aside id="related">
|
18
|
+
<%= yield :related %>
|
19
|
+
</aside>
|
20
|
+
</article>
|
21
|
+
</section>
|
22
|
+
</div>
|
23
|
+
</div>
|
24
|
+
<%= render :partial => "layouts/smithy/shared/tail" %>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<li>
|
2
|
+
<div class="thumbnail clearfix">
|
3
|
+
<%= link_to "<img src=\"#{asset.file.thumb("170x114#").url}\" width=\"170\" height=\"114\" alt=\"\">".html_safe, asset.file.url %>
|
4
|
+
<p class="name"><strong><%= asset.name %></strong></p>
|
5
|
+
<div class="pull-right">
|
6
|
+
<%= link_to "Edit", [:edit, asset], :class => "btn btn-mini" %>
|
7
|
+
<%= link_to "Delete", asset, :class => "btn btn-mini btn-danger", :method => :delete, :confirm => "Are you sure?" %>
|
8
|
+
</div>
|
9
|
+
</div>
|
10
|
+
</li>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<%= semantic_form_for @asset do |f| %>
|
2
|
+
<%= f.inputs do %>
|
3
|
+
<%= f.input :name, :label => 'Name (Alernative text)' %>
|
4
|
+
<%= f.input :file, :as => :file %>
|
5
|
+
<%= f.input :retained_file, :as => :hidden %>
|
6
|
+
<% if @asset.file %>
|
7
|
+
<div>
|
8
|
+
<img src="<%= @asset.file.thumb("300x300").url %>" alt="">
|
9
|
+
</div>
|
10
|
+
<% end %>
|
11
|
+
<% end %>
|
12
|
+
<%= f.actions :submit %>
|
13
|
+
<% end %>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<%= uploader_form Smithy::Asset.new, post: assets_url, as: "asset[uploaded_file_url]" do %>
|
2
|
+
<fieldset class="inputs">
|
3
|
+
<%= file_field_tag :file, multiple: true %>
|
4
|
+
<%= submit_tag "Upload File(s)", class: 'btn' %>
|
5
|
+
</fieldset>
|
6
|
+
<% end %>
|
7
|
+
|
8
|
+
<script id="template-upload" type="text/x-tmpl">
|
9
|
+
<div class="upload">
|
10
|
+
{%=o.name%}
|
11
|
+
<div class="progress"><div class="bar" style="width: 0%"></div></div>
|
12
|
+
</div>
|
13
|
+
</script>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<% content_for :title, "Assets" %>
|
2
|
+
|
3
|
+
<div class="well">
|
4
|
+
<h2>Upload files</h2>
|
5
|
+
<%= render :partial => "upload_form" %>
|
6
|
+
<p>If you are using Firefox, Safari or Chrome, you can just drag and drop some files onto this page</p>
|
7
|
+
</div>
|
8
|
+
|
9
|
+
<%= paginate @assets %>
|
10
|
+
|
11
|
+
<ul class="thumbnails" id="asset-thumbnails">
|
12
|
+
<%= render @assets %>
|
13
|
+
</ul>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<% content_for :title, "Images & Files" %>
|
2
|
+
|
3
|
+
<%= semantic_form_for @template, :html => { :class => 'form-horizontal' } do |f| %>
|
4
|
+
<%= f.inputs "New #{@template.template_type.capitalize}" do %>
|
5
|
+
<%= f.input :name %>
|
6
|
+
<%= f.input :template_type, :as => :hidden %>
|
7
|
+
<% end %>
|
8
|
+
<%= f.actions :submit %>
|
9
|
+
<% end %>
|
10
|
+
|
11
|
+
<%= render :partial => "secondary_nav" %>
|
12
|
+
|
13
|
+
<% content_for :related, nil %>
|