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.
Files changed (169) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +142 -0
  3. data/Rakefile +27 -0
  4. data/app/assets/images/smithy/logo.png +0 -0
  5. data/app/assets/images/smithy/logo2.png +0 -0
  6. data/app/assets/javascripts/smithy/application.js +13 -0
  7. data/app/assets/javascripts/smithy/assets.js.coffee +35 -0
  8. data/app/assets/javascripts/smithy/guides.js +23 -0
  9. data/app/assets/javascripts/smithy/jquery-ui.min.js +5 -0
  10. data/app/assets/javascripts/smithy/nested_forms.js +55 -0
  11. data/app/assets/javascripts/smithy/page_contents.js +4 -0
  12. data/app/assets/javascripts/smithy/pages.js +41 -0
  13. data/app/assets/javascripts/smithy/settings.js +0 -0
  14. data/app/assets/javascripts/smithy/templates.js +25 -0
  15. data/app/assets/stylesheets/smithy/application.css.scss +29 -0
  16. data/app/assets/stylesheets/smithy/assets.css.scss +3 -0
  17. data/app/assets/stylesheets/smithy/bootstrap_and_overrides.css.scss +12 -0
  18. data/app/assets/stylesheets/smithy/content_blocks.css.scss +2 -0
  19. data/app/assets/stylesheets/smithy/forms.css.scss +3 -0
  20. data/app/assets/stylesheets/smithy/guides.css.scss +5 -0
  21. data/app/assets/stylesheets/smithy/layout.css.scss +113 -0
  22. data/app/assets/stylesheets/smithy/pages.css.scss +35 -0
  23. data/app/assets/stylesheets/smithy/templates.css.scss +14 -0
  24. data/app/controllers/smithy/assets_controller.rb +50 -0
  25. data/app/controllers/smithy/base_controller.rb +14 -0
  26. data/app/controllers/smithy/caches_controller.rb +13 -0
  27. data/app/controllers/smithy/content_blocks_controller.rb +50 -0
  28. data/app/controllers/smithy/content_pieces_controller.rb +97 -0
  29. data/app/controllers/smithy/contents_controller.rb +41 -0
  30. data/app/controllers/smithy/guides_controller.rb +9 -0
  31. data/app/controllers/smithy/images_controller.rb +41 -0
  32. data/app/controllers/smithy/page_contents_controller.rb +90 -0
  33. data/app/controllers/smithy/pages_controller.rb +110 -0
  34. data/app/controllers/smithy/settings_controller.rb +46 -0
  35. data/app/controllers/smithy/sitemap_controller.rb +13 -0
  36. data/app/controllers/smithy/templates_controller.rb +79 -0
  37. data/app/helpers/smithy/application_helper.rb +36 -0
  38. data/app/helpers/smithy/assets_helper.rb +9 -0
  39. data/app/helpers/smithy/pages_helper.rb +12 -0
  40. data/app/helpers/smithy/settings_helper.rb +4 -0
  41. data/app/helpers/smithy/templates_helper.rb +4 -0
  42. data/app/helpers/smithy/upload_helper.rb +110 -0
  43. data/app/models/smithy/asset.rb +64 -0
  44. data/app/models/smithy/content.rb +35 -0
  45. data/app/models/smithy/content_block.rb +41 -0
  46. data/app/models/smithy/content_block_template.rb +26 -0
  47. data/app/models/smithy/image.rb +41 -0
  48. data/app/models/smithy/page.rb +94 -0
  49. data/app/models/smithy/page_content.rb +62 -0
  50. data/app/models/smithy/page_list.rb +61 -0
  51. data/app/models/smithy/page_proxy.rb +63 -0
  52. data/app/models/smithy/setting.rb +6 -0
  53. data/app/models/smithy/site.rb +30 -0
  54. data/app/models/smithy/template.rb +53 -0
  55. data/app/models/smithy/template_container.rb +16 -0
  56. data/app/views/layouts/smithy/application.html.erb +27 -0
  57. data/app/views/layouts/smithy/guides.html.erb +16 -0
  58. data/app/views/layouts/smithy/modal.html.erb +10 -0
  59. data/app/views/layouts/smithy/shared/_flash.html.erb +6 -0
  60. data/app/views/layouts/smithy/shared/_footer.html.erb +3 -0
  61. data/app/views/layouts/smithy/shared/_head.html.erb +8 -0
  62. data/app/views/layouts/smithy/shared/_nav.html.erb +37 -0
  63. data/app/views/layouts/smithy/shared/_tail.html.erb +4 -0
  64. data/app/views/layouts/smithy/wide.html.erb +24 -0
  65. data/app/views/smithy/assets/_asset.html.erb +10 -0
  66. data/app/views/smithy/assets/_form.html.erb +13 -0
  67. data/app/views/smithy/assets/_upload_form.html.erb +13 -0
  68. data/app/views/smithy/assets/create.js.erb +5 -0
  69. data/app/views/smithy/assets/edit.html.erb +5 -0
  70. data/app/views/smithy/assets/index.html.erb +13 -0
  71. data/app/views/smithy/assets/new.html.erb +13 -0
  72. data/app/views/smithy/caches/show.html.erb +8 -0
  73. data/app/views/smithy/content_blocks/_content_block.html.erb +1 -0
  74. data/app/views/smithy/content_blocks/_secondary_nav.html.erb +12 -0
  75. data/app/views/smithy/content_blocks/_template_fields.html.erb +19 -0
  76. data/app/views/smithy/content_blocks/edit.html.erb +31 -0
  77. data/app/views/smithy/content_blocks/index.html.erb +17 -0
  78. data/app/views/smithy/content_blocks/new.html.erb +12 -0
  79. data/app/views/smithy/content_pieces/edit.html.erb +13 -0
  80. data/app/views/smithy/content_pieces/index.html.erb +21 -0
  81. data/app/views/smithy/content_pieces/new.html.erb +1 -0
  82. data/app/views/smithy/contents/_form.html.erb +6 -0
  83. data/app/views/smithy/contents/_form_fields.html.erb +12 -0
  84. data/app/views/smithy/contents/edit.html.erb +3 -0
  85. data/app/views/smithy/contents/new.html.erb +3 -0
  86. data/app/views/smithy/guides/markdown.html.erb +150 -0
  87. data/app/views/smithy/images/_form.html.erb +6 -0
  88. data/app/views/smithy/images/_form_fields.html.erb +28 -0
  89. data/app/views/smithy/images/edit.html.erb +3 -0
  90. data/app/views/smithy/images/new.html.erb +3 -0
  91. data/app/views/smithy/page_contents/edit.html.erb +18 -0
  92. data/app/views/smithy/page_contents/new.html.erb +28 -0
  93. data/app/views/smithy/page_lists/_form_fields.html.erb +6 -0
  94. data/app/views/smithy/pages/_container.html.erb +24 -0
  95. data/app/views/smithy/pages/_form.html.erb +57 -0
  96. data/app/views/smithy/pages/_page.html.erb +6 -0
  97. data/app/views/smithy/pages/_page_nav.html.erb +6 -0
  98. data/app/views/smithy/pages/_page_related.html.erb +21 -0
  99. data/app/views/smithy/pages/_parent.html.erb +10 -0
  100. data/app/views/smithy/pages/_root.html.erb +5 -0
  101. data/app/views/smithy/pages/edit.html.erb +7 -0
  102. data/app/views/smithy/pages/index.html.erb +17 -0
  103. data/app/views/smithy/pages/new.html.erb +7 -0
  104. data/app/views/smithy/settings/_form.html.erb +7 -0
  105. data/app/views/smithy/settings/_setting.html.erb +6 -0
  106. data/app/views/smithy/settings/edit.html.erb +3 -0
  107. data/app/views/smithy/settings/index.html.erb +9 -0
  108. data/app/views/smithy/settings/new.html.erb +3 -0
  109. data/app/views/smithy/settings/show.html.erb +10 -0
  110. data/app/views/smithy/sitemap/show.xml.erb +10 -0
  111. data/app/views/smithy/templates/_secondary_nav.html.erb +21 -0
  112. data/app/views/smithy/templates/_template.html.erb +1 -0
  113. data/app/views/smithy/templates/edit.html.erb +36 -0
  114. data/app/views/smithy/templates/index.html.erb +17 -0
  115. data/app/views/smithy/templates/new.html.erb +13 -0
  116. data/config/initializers/aws.rb +5 -0
  117. data/config/initializers/dragonfly.rb +48 -0
  118. data/config/initializers/formtastic.rb +77 -0
  119. data/config/initializers/kaminari_config.rb +10 -0
  120. data/config/initializers/liquid.rb +2 -0
  121. data/config/routes.rb +38 -0
  122. data/db/migrate/20120911193140_create_smithy_templates.rb +11 -0
  123. data/db/migrate/20120911203618_create_smithy_settings.rb +10 -0
  124. data/db/migrate/20121018182146_create_smithy_pages.rb +27 -0
  125. data/db/migrate/20121019145543_create_smithy_template_containers.rb +11 -0
  126. data/db/migrate/20121019160426_create_smithy_page_contents.rb +21 -0
  127. data/db/migrate/20121024213357_create_smithy_content_blocks.rb +10 -0
  128. data/db/migrate/20121025011733_create_smithy_content_block_templates.rb +12 -0
  129. data/db/migrate/20121029175812_create_smithy_contents.rb +9 -0
  130. data/db/migrate/20121105222537_create_smithy_assets.rb +16 -0
  131. data/db/migrate/20121115215053_create_smithy_images.rb +15 -0
  132. data/db/migrate/20121127205022_add_external_link_to_smithy_pages.rb +5 -0
  133. data/db/migrate/20130115190505_add_markdown_content_to_smithy_contents.rb +5 -0
  134. data/db/migrate/20130123170918_set_defaults_for_show_in_navigation_and_cache_length.rb +6 -0
  135. data/db/migrate/20130311203806_create_smithy_page_lists.rb +15 -0
  136. data/db/migrate/20130312161116_remove_description_from_content_block.rb +5 -0
  137. data/db/migrate/20130326191051_add_html_attributes_to_images.rb +5 -0
  138. data/db/migrate/20131003210228_add_publishable_to_smithy_page_contents.rb +11 -0
  139. data/db/migrate/20131220160755_add_content_to_images.rb +5 -0
  140. data/db/migrate/20131223145710_add_position_to_smithy_template_containers.rb +5 -0
  141. data/lib/smithy/content_blocks/model.rb +16 -0
  142. data/lib/smithy/content_blocks/registry.rb +30 -0
  143. data/lib/smithy/content_blocks.rb +2 -0
  144. data/lib/smithy/content_pieces/base.rb +10 -0
  145. data/lib/smithy/content_pieces/registry.rb +39 -0
  146. data/lib/smithy/dependencies.rb +19 -0
  147. data/lib/smithy/dragonfly/asset_helper.rb +67 -0
  148. data/lib/smithy/dragonfly/remote_data_store.rb +33 -0
  149. data/lib/smithy/dragonfly.rb +30 -0
  150. data/lib/smithy/engine.rb +48 -0
  151. data/lib/smithy/formatter.rb +46 -0
  152. data/lib/smithy/liquid/database.rb +12 -0
  153. data/lib/smithy/liquid/drops/base.rb +16 -0
  154. data/lib/smithy/liquid/drops/page.rb +78 -0
  155. data/lib/smithy/liquid/filters/asset_tag.rb +33 -0
  156. data/lib/smithy/liquid/filters/resize.rb +12 -0
  157. data/lib/smithy/liquid/rendering.rb +50 -0
  158. data/lib/smithy/liquid/tags/asset.rb +54 -0
  159. data/lib/smithy/liquid/tags/csrf.rb +30 -0
  160. data/lib/smithy/liquid/tags/html.rb +61 -0
  161. data/lib/smithy/liquid/tags/nav.rb +76 -0
  162. data/lib/smithy/liquid.rb +8 -0
  163. data/lib/smithy/logger.rb +12 -0
  164. data/lib/smithy/version.rb +3 -0
  165. data/lib/smithy.rb +21 -0
  166. data/lib/smithycms.rb +1 -0
  167. data/lib/tasks/smithy_tasks.rake +4 -0
  168. data/lib/templates/erb/scaffold/_form.html.erb +11 -0
  169. 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,6 @@
1
+ module Smithy
2
+ class Setting < ActiveRecord::Base
3
+ attr_accessible :name, :value
4
+ validates_presence_of :name, :value
5
+ end
6
+ 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 %>&nbsp;</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,6 @@
1
+ <% flash.each do |name, msg| %>
2
+ <div class="alert alert-<%= name == :notice ? "success" : "error" %>">
3
+ <button type="button" class="close" data-dismiss="alert">&times;</button>
4
+ <%= msg %>
5
+ </div>
6
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <footer id="footer">
2
+ Carefully crafted by <a href="http://www.tag.ca">Tag Solutions</a>
3
+ </footer>
@@ -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 &amp; 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,4 @@
1
+ <%= javascript_include_tag "smithy/application" %>
2
+ <%= yield :javascript %>
3
+ </body>
4
+ </html>
@@ -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,5 @@
1
+ <% if @asset.new_record? %>
2
+ alert("Failed to upload painting: <%= j @asset.errors.full_messages.join(', ').html_safe %>");
3
+ <% else %>
4
+ $("#asset-thumbnails").append("<%= j render(@asset) %>");
5
+ <% end %>
@@ -0,0 +1,5 @@
1
+ <% content_for :title, "Assets" %>
2
+
3
+ <div class="well">
4
+ <%= render :partial => "form" %>
5
+ </div>
@@ -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 &amp; 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 %>