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,90 @@
1
+ require_dependency "smithy/base_controller"
2
+
3
+ module Smithy
4
+ class PageContentsController < BaseController
5
+ before_filter :load_page
6
+ before_filter :load_page_content, :only => [ :edit, :update, :destroy, :preview ]
7
+ before_filter :build_content_block, :only => [ :edit, :update ]
8
+ before_filter :load_content_blocks, :only => [ :new, :create ]
9
+ respond_to :html, :json
10
+
11
+ def new
12
+ @page_content = Smithy::PageContent.new(params[:page_content])
13
+ @page_content.label = [@page.title, @page_content.container.titleize].join(' - ') unless @page_content.label?
14
+ end
15
+
16
+ def create
17
+ @page_content = Smithy::PageContent.new
18
+ # we have to ensure that the content_block_type gets added before the content_block_attributes
19
+ # see PageContent#content_block_attributes=
20
+ @page_content.content_block_type = params[:page_content][:content_block_type]
21
+ @page_content.attributes = params[:page_content]
22
+ @page_content.page = @page
23
+ @page_content.save
24
+ respond_with @page_content do |format|
25
+ format.html { @page_content.persisted? ? redirect_to(edit_page_content_path(@page.id, @page_content)) : render(:action => 'new') }
26
+ end
27
+ end
28
+
29
+ def edit
30
+ respond_with @page_content
31
+ end
32
+
33
+ def update
34
+ @page_content = Smithy::PageContent.find(params[:id])
35
+ @saved = @page_content.update_attributes(params[:page_content])
36
+ flash.notice = "Your content was saved" if @saved
37
+ respond_with @page_content do |format|
38
+ format.html { @saved ? redirect_to(edit_page_path(@page.id)) : render(:action => "edit") }
39
+ end
40
+ end
41
+
42
+ def destroy
43
+ @page_content.destroy
44
+ respond_with @page_content do |format|
45
+ format.html { redirect_to edit_page_path(@page.id), :notice => "Your content was deleted from the page" }
46
+ end
47
+ end
48
+
49
+ def preview
50
+ respond_with @page_content do |format|
51
+ format.html { render :text => @page_content.render, :layout => 'smithy/modal' }
52
+ end
53
+ end
54
+
55
+ def order
56
+ params[:order].each_with_index do |page_content_id, index|
57
+ page_content = @page.contents.find(page_content_id)
58
+ page_content.update_attribute(:position, index)
59
+ end
60
+ if request.xhr?
61
+ render :nothing => true, :status => 200
62
+ else
63
+ redirect_to edit_page_path(@page.id)
64
+ end
65
+ end
66
+
67
+ private
68
+ def build_content_block
69
+ unless @page_content.content_block.present?
70
+ klass = "Smithy::#{@page_content.content_block_type.classify}".safe_constantize || @page_content.content_block_type.classify.safe_constantize
71
+ if klass
72
+ @page_content.content_block = klass.new
73
+ end
74
+ end
75
+ end
76
+
77
+ def load_content_blocks
78
+ @content_blocks = Smithy::ContentBlock.all
79
+ end
80
+
81
+ def load_page
82
+ @page = Smithy::Page.find(params[:page_id])
83
+ end
84
+
85
+ def load_page_content
86
+ @page_content = Smithy::PageContent.find(params[:id])
87
+ end
88
+
89
+ end
90
+ end
@@ -0,0 +1,110 @@
1
+ require_dependency "smithy/base_controller"
2
+
3
+ module Smithy
4
+ class PagesController < BaseController
5
+ skip_before_filter :authenticate_smithy_admin, :only => [ :show ]
6
+ include Smithy::Liquid::Rendering
7
+ before_filter :load_page_from_path, :only => [ :show ]
8
+ before_filter :initialize_page, :only => [ :new, :create ]
9
+ before_filter :load_page, :only => [ :edit, :update, :destroy ]
10
+ before_filter :load_parent, :except => [ :index, :show, :order ]
11
+ before_filter :load_root, :only => [ :index ]
12
+ respond_to :html, :json
13
+
14
+ def index
15
+ respond_with @root
16
+ end
17
+
18
+ def show
19
+ render_page and return if smithy_current_user # no caching if you're editing
20
+ # adding :public param allow Rack::Cache to cache the result
21
+ @page.cache_length == 0 ? expires_now : expires_in(@page.cache_length.to_i.seconds, :public => true)
22
+ render_page if stale?(:etag => @page, :last_modified => @page.updated_at.utc, :public => true)
23
+ end
24
+
25
+ def new
26
+ respond_with @page
27
+ end
28
+
29
+ def create
30
+ @page.save
31
+ flash.notice = "Your page was created #{@page.published? ? 'and published' : 'as a draft'}" if @page.persisted?
32
+ respond_with @page do |format|
33
+ format.html { @page.persisted? ? redirect_to(edit_page_path(@page.id)) : render(:action => 'new') }
34
+ end
35
+ end
36
+
37
+ def edit
38
+ respond_with @page
39
+ end
40
+
41
+ def update
42
+ flash.notice = "Your page was saved #{@page.published? ? 'and published' : 'as a draft'}" if @page.update_attributes(params[:page])
43
+ respond_with @page do |format|
44
+ format.html { redirect_to edit_page_path(@page.id) }
45
+ end
46
+ end
47
+
48
+ def destroy
49
+ @page.destroy
50
+ respond_with @page.parent ? @page.parent : @page
51
+ end
52
+
53
+ def order
54
+ first = Smithy::Page.find(params[:order].shift)
55
+ @parent = first.parent
56
+ if @parent && @parent.children.count > 1 # Only need to order if there are multiple children.
57
+ left = first.id
58
+ params[:order].each do |page_id|
59
+ page = Smithy::Page.find(page_id)
60
+ page.move_to_right_of(left)
61
+ left = page.id
62
+ end
63
+ end
64
+ render :nothing => true, :status => 200 and return if request.xhr?
65
+ redirect_to pages_path
66
+ end
67
+
68
+ private
69
+ def initialize_page
70
+ @page = Page.new(params[:page])
71
+ set_publish
72
+ end
73
+
74
+ def load_page
75
+ @page = Page.find(params[:id])
76
+ @root = @page if Page.root == @page
77
+ set_publish
78
+ end
79
+
80
+ def load_page_from_path
81
+ @page = Page.find(page_path)
82
+ redirect_to @page.external_link and return false if @page.external_link?
83
+ end
84
+
85
+ def load_parent
86
+ @parent = @page.parent
87
+ end
88
+
89
+ def load_root
90
+ @root = Page.root
91
+ end
92
+
93
+ def page_path
94
+ params[:path] = '' if params[:id].nil? && params[:path].nil? # sets the root path when nothing else is passed
95
+ params[:path].nil? ? params[:id] : "/#{params[:path]}"
96
+ end
97
+
98
+ def render_page
99
+ respond_with @page do |format|
100
+ format.html { render_smithy_page }
101
+ end
102
+ end
103
+
104
+ def set_publish
105
+ @page.publish = true if params[:publish].present?
106
+ @page.publish = false if params[:draft].present?
107
+ end
108
+
109
+ end
110
+ end
@@ -0,0 +1,46 @@
1
+ require_dependency "smithy/base_controller"
2
+
3
+ module Smithy
4
+ class SettingsController < BaseController
5
+ respond_to :html, :json
6
+
7
+ def index
8
+ @settings = Setting.all
9
+ respond_with @settings
10
+ end
11
+
12
+ def show
13
+ @setting = Setting.find(params[:id])
14
+ respond_with @setting
15
+ end
16
+
17
+ def new
18
+ @setting = Setting.new(params[:setting])
19
+ respond_with @setting
20
+ end
21
+
22
+ def create
23
+ @setting = Setting.new(params[:setting])
24
+ @setting.save
25
+ flash.notice = "Your setting was created" if @setting.persisted?
26
+ respond_with @setting
27
+ end
28
+
29
+ def edit
30
+ @setting = Setting.find(params[:id])
31
+ respond_with @setting
32
+ end
33
+
34
+ def update
35
+ @setting = Setting.find(params[:id])
36
+ flash.notice = "Your setting was saved" if @setting.update_attributes(params[:setting])
37
+ respond_with @setting
38
+ end
39
+
40
+ def destroy
41
+ @setting = Setting.find(params[:id])
42
+ @setting.destroy
43
+ respond_with @setting
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,13 @@
1
+ require_dependency "smithy/base_controller"
2
+
3
+ module Smithy
4
+ class SitemapController < BaseController
5
+ respond_to :xml
6
+ skip_before_filter :authenticate_smithy_admin
7
+
8
+ def show
9
+ @pages = Smithy::Page.root.self_and_descendants
10
+ respond_with @pages
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,79 @@
1
+ require_dependency "smithy/base_controller"
2
+
3
+ module Smithy
4
+ class TemplatesController < BaseController
5
+ skip_before_filter :authenticate_smithy_admin, :only => [ :javascript, :stylesheet ]
6
+ before_filter :load_templates
7
+ respond_to :html, :json
8
+
9
+ def index
10
+ respond_with @templates
11
+ end
12
+
13
+ def new
14
+ @template = Template.new(params[:template])
15
+ respond_with @template
16
+ end
17
+
18
+ def create
19
+ @template = Template.new(params[:template])
20
+ @template.save
21
+ flash.notice = "Your template was created" if @template.persisted?
22
+ respond_with @template do |format|
23
+ format.html { redirect_to [:edit, @template] }
24
+ end
25
+ end
26
+
27
+ def edit
28
+ @template = Template.find(params[:id])
29
+ @template_editor_type = case @template.template_type
30
+ when 'javascript'
31
+ 'javascript'
32
+ when 'stylesheet'
33
+ 'css'
34
+ else
35
+ 'liquid'
36
+ end
37
+ respond_with @template
38
+ end
39
+
40
+ def update
41
+ @template = Template.find(params[:id])
42
+ flash.notice = "Your template was saved" if @template.update_attributes(params[:template])
43
+ respond_with @template do |format|
44
+ format.html { redirect_to [:edit, @template] }
45
+ end
46
+ end
47
+
48
+ def destroy
49
+ @template = Template.find(params[:id])
50
+ @template.destroy
51
+ respond_with @template
52
+ end
53
+
54
+ def javascript
55
+ @javascript = Template.javascripts.find_by_name(params[:javascript].sub(/\.js$/, ''))
56
+ render_asset_template(@javascript, params[:javascript], 'text/javascript')
57
+ end
58
+
59
+ def stylesheet
60
+ @stylesheet = Template.stylesheets.find_by_name(params[:stylesheet].sub(/\.css$/, ''))
61
+ render_asset_template(@stylesheet, params[:stylesheet], 'text/css')
62
+ end
63
+
64
+ private
65
+ def load_templates
66
+ @templates = Template.templates
67
+ @includes = Template.partials
68
+ @javascripts = Template.javascripts
69
+ @stylesheets = Template.stylesheets
70
+ end
71
+
72
+ def render_asset_template(template, template_name, content_type)
73
+ raise ActiveRecord::RecordNotFound, "No such stylesheet '#{template_name}'" unless template.present?
74
+ expires_in(2592000.seconds, :public => true) # cache for 30 days
75
+ headers['X-Content-Digest'] = Digest::SHA1.hexdigest(template.content) # digest of the content for cache control when the template changes
76
+ render :text => template.content, :content_type => content_type
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,36 @@
1
+ module Smithy
2
+ module ApplicationHelper
3
+ def link_to_add_fields(name, association, form_builder)
4
+ html = content_tag(:div, :id => "#{association}_fields_blueprint", :style => "display:none;") do
5
+ form_builder.semantic_fields_for(association, model_object(form_builder, association), :child_index => "new_#{association}") do |builder|
6
+ form_builder.template.concat(raw render("#{form_builder.object.class.to_s.tableize}/#{association.to_s.singularize}_fields", :f => builder))
7
+ end
8
+ end
9
+ form_builder.template.concat(html)
10
+ form_builder.template.link_to(name, "javascript:void(0)", :class => "add_nested_fields", "data-association" => association)
11
+ end
12
+
13
+ def link_to_remove_fields(name, form_builder)
14
+ form_builder.hidden_field(:_destroy) + @template.link_to(name, "javascript:void(0)", :class => "remove_nested_fields")
15
+ end
16
+
17
+ def render_markdown_input(fieldname, editor_name, form_builder)
18
+ content_for(:javascript) do
19
+ javascript_tag do
20
+ raw("var editor = ace_edit('#{form_builder.object.id || 'new'}', 'markdown', '#{editor_name}');\n") +
21
+ raw("editor.renderer.setShowGutter(false);")
22
+ end
23
+ end
24
+ hint = "Use markdown syntax for formatting. You can also use HTML directly. <a href=\"#{guide_path('markdown')}\" data-toggle=\"remote-load\" data-target=\"#content-guide\">See our markdown syntax reference</a>".html_safe
25
+ form_builder.input(fieldname, :as => :text, :input_html => { :class => "span12", :id => "#{editor_name}-#{form_builder.object.id || 'new'}" }, :hint => hint) +
26
+ content_tag(:div, nil, :id => "#{editor_name}_editor-#{form_builder.object.id || 'new'}", :class => "#{editor_name}_editor ace_editor") +
27
+ content_tag(:div, nil, :id => 'content-guide')
28
+ end
29
+
30
+ private
31
+ def model_object(form_builder, association)
32
+ model_object = form_builder.object.class.reflect_on_association(association).klass.new
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,9 @@
1
+ module Smithy
2
+ module AssetsHelper
3
+ def asset_image_tag(asset_id)
4
+ asset = Smithy::Asset.find_by_id(asset_id)
5
+ return unless asset
6
+ image_tag(asset.file.url(:host => "#{request.protocol}#{request.host_with_port}"), :alt => asset.name)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ module Smithy
2
+ module PagesHelper
3
+ def tree_for_select
4
+ tree_for_select = []
5
+ Smithy::Page.each_with_level(Smithy::Page.root.self_and_descendants) do |page, level|
6
+ prepend = level == 0 ? '' : "#{'-' * level} "
7
+ tree_for_select << [ "#{prepend}#{page.title}", page.id]
8
+ end if Smithy::Page.root.present?
9
+ tree_for_select
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,4 @@
1
+ module Smithy
2
+ module SettingsHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Smithy
2
+ module TemplatesHelper
3
+ end
4
+ end
@@ -0,0 +1,110 @@
1
+ module Smithy
2
+ module UploadHelper
3
+ def uploader_form(object, options = {}, &block)
4
+ # s3_uploader = S3Uploader.new(options)
5
+ # uploader = s3_uploader.s3_available? ? s3_uploader : FileUploader.new(options)
6
+ uploader = S3Uploader.new(options)
7
+ form_tag(uploader.url, uploader.form_options) do
8
+ uploader.fields.map do |name, value|
9
+ hidden_field_tag(name, value)
10
+ end.join.html_safe + capture(&block)
11
+ end
12
+ end
13
+
14
+ class Base
15
+ def form_options
16
+ {
17
+ id: @options[:id],
18
+ method: "post",
19
+ authenticity_token: false,
20
+ multipart: true,
21
+ data: {
22
+ post: @options[:post],
23
+ as: @options[:as]
24
+ }
25
+ }
26
+ end
27
+ end
28
+
29
+ class FileUploader < Base
30
+ def initialize(options)
31
+ @options = options.reverse_merge( id: "fileupload" )
32
+ end
33
+
34
+ def fields
35
+ { :key => key }
36
+ end
37
+
38
+ def key
39
+ @key ||= "uploads/assets/${filename}"
40
+ end
41
+
42
+ def url
43
+ @options[:post]
44
+ end
45
+ end
46
+
47
+ class S3Uploader < Base
48
+ def initialize(options)
49
+ @options = options.reverse_merge(
50
+ id: "fileupload",
51
+ aws_access_key_id: ENV["AWS_ACCESS_KEY_ID"],
52
+ aws_secret_access_key: ENV["AWS_SECRET_ACCESS_KEY"],
53
+ bucket: ENV["AWS_S3_BUCKET"],
54
+ acl: "public-read",
55
+ expiration: 10.hours.from_now,
56
+ max_file_size: 500.megabytes,
57
+ as: "file"
58
+ )
59
+ end
60
+
61
+ def fields
62
+ {
63
+ :key => key,
64
+ :acl => @options[:acl],
65
+ :policy => policy,
66
+ :signature => signature,
67
+ "AWSAccessKeyId" => @options[:aws_access_key_id],
68
+ }
69
+ end
70
+
71
+ def key
72
+ @key ||= "uploads/assets/#{SecureRandom.hex}/${filename}"
73
+ end
74
+
75
+ def url
76
+ "https://#{@options[:bucket]}.s3.amazonaws.com/"
77
+ end
78
+
79
+ def policy
80
+ Base64.encode64(policy_data.to_json).gsub("\n", "")
81
+ end
82
+
83
+ def policy_data
84
+ {
85
+ expiration: @options[:expiration].utc.iso8601,
86
+ conditions: [
87
+ ["starts-with", "$utf8", ""],
88
+ ["starts-with", "$key", ""],
89
+ ["content-length-range", 0, @options[:max_file_size]],
90
+ {bucket: @options[:bucket]},
91
+ {acl: @options[:acl]}
92
+ ]
93
+ }
94
+ end
95
+
96
+ def signature
97
+ Base64.encode64(
98
+ OpenSSL::HMAC.digest(
99
+ OpenSSL::Digest::Digest.new('sha1'),
100
+ @options[:aws_secret_access_key], policy
101
+ )
102
+ ).gsub("\n", "")
103
+ end
104
+
105
+ def s3_available?
106
+ @options[:aws_access_key_id].present? && @options[:aws_secret_access_key].present? && @options[:bucket].present?
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,64 @@
1
+ module Smithy
2
+ class Asset < ActiveRecord::Base
3
+ attr_accessible :name, :file, :file_name, :file_url, :retained_file, :uploaded_file_url
4
+
5
+ validates_presence_of :file, :name
6
+
7
+ has_many :images, :dependent => :destroy
8
+
9
+ file_accessor :file
10
+ include Smithy::Dragonfly::AssetHelper
11
+
12
+ before_validation :set_name
13
+ before_save :set_file_uid_manually
14
+
15
+ default_scope order(:name)
16
+
17
+ def file
18
+ # check for the jquery uploaded file first, just in case one got past the manual check. Also keeps backwards-compatibility
19
+ if self.uploaded_file_url?
20
+ dragonfly_attachments[:file].app.datastore = self.class.dragonfly_remote_datastore
21
+ self.file_url = URI.escape(self.uploaded_file_url)
22
+ elsif dragonfly_attachments[:file].to_value
23
+ dragonfly_attachments[:file].app.datastore = self.class.dragonfly_datastore
24
+ end
25
+ dragonfly_attachments[:file].to_value
26
+ end
27
+
28
+ def to_liquid
29
+ {
30
+ 'id' => self.id,
31
+ 'name' => self.name,
32
+ 'content_type' => self.content_type,
33
+ 'file' => self.file,
34
+ 'file_name' => self.file_name,
35
+ 'file_width' => self.file_width,
36
+ 'file_height' => self.file_height,
37
+ 'file_size' => self.file_size,
38
+ 'url' => self.file.url
39
+ }
40
+ end
41
+
42
+ private
43
+ def set_content_types
44
+ set_content_type(self.file, :content_type)
45
+ end
46
+
47
+ # this allows dragonfly to take over management of the uploaded file. We are
48
+ # assuming that jquery-upload and dragonfly are using the same data storage...
49
+ def set_file_uid_manually
50
+ if self.uploaded_file_url? # this means it was uploaded via jquery-upload
51
+ self.file_uid = URI.parse(self.uploaded_file_url).path.sub(/^\//, '')
52
+ self.uploaded_file_url = nil
53
+ end
54
+ end
55
+
56
+ def set_name
57
+ if self.uploaded_file_url?
58
+ self.name = File.basename(self.uploaded_file_url, '.*').titleize unless self.name?
59
+ elsif self.file.present?
60
+ self.name = File.basename(self.file.name, '.*').titleize unless self.name?
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,35 @@
1
+ module Smithy
2
+ class Content < ActiveRecord::Base
3
+ include Smithy::ContentBlocks::Model
4
+
5
+ attr_accessible :content
6
+
7
+ validates_presence_of :content
8
+
9
+ before_save :render_markdown_content
10
+
11
+ class << self
12
+ def content_block_description
13
+ "Content is primarily used for adding text-based content to your pages"
14
+ end
15
+ end
16
+
17
+ def formatted_content
18
+ self.markdown_content
19
+ end
20
+
21
+ def to_liquid
22
+ {
23
+ 'id' => self.id,
24
+ 'content' => self.content,
25
+ 'formatted_content' => self.formatted_content
26
+ }
27
+ end
28
+
29
+ private
30
+ def render_markdown_content
31
+ formatter = Smithy::Formatter.new(self.content)
32
+ self.markdown_content = formatter.render
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,41 @@
1
+ module Smithy
2
+ class ContentBlock < ActiveRecord::Base
3
+ attr_accessible :name, :templates_attributes
4
+
5
+ validates_presence_of :name
6
+
7
+ has_many :templates, :class_name => "ContentBlockTemplate"
8
+ has_many :page_contents
9
+
10
+ after_save :touch_page_contents
11
+
12
+ accepts_nested_attributes_for :templates, :reject_if => lambda {|a| a['name'].blank? || a['content'].blank? }, :allow_destroy => true
13
+
14
+ default_scope order(:name)
15
+
16
+ def description
17
+ klass.content_block_description if klass
18
+ end
19
+
20
+ def content_field_names
21
+ unless @content_field_names
22
+ if klass.new.respond_to?(:to_liquid)
23
+ @content_field_names = klass.new.to_liquid.keys
24
+ else
25
+ @content_field_names = klass.column_names.delete_if{|column_name| ["id", "created_at", "updated_at"].include?(column_name) }
26
+ end
27
+ end
28
+ @content_field_names
29
+ end
30
+
31
+ private
32
+ def klass
33
+ @klass ||= "#{self.name}".safe_constantize || "Smithy::#{self.name}".safe_constantize
34
+ end
35
+
36
+ def touch_page_contents
37
+ self.page_contents.each(&:touch)
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,26 @@
1
+ module Smithy
2
+ class ContentBlockTemplate < ActiveRecord::Base
3
+ attr_accessible :content, :name
4
+
5
+ belongs_to :content_block, :touch => true
6
+ has_many :page_contents
7
+
8
+ validates_presence_of :name
9
+ validates_uniqueness_of :name, :scope => :content_block_id
10
+ validates_presence_of :content
11
+
12
+ after_save :touch_page_contents
13
+
14
+ default_scope order(:name)
15
+
16
+ def liquid_template
17
+ @liquid_template ||= ::Liquid::Template.parse(self.content)
18
+ end
19
+
20
+ private
21
+ def touch_page_contents
22
+ self.page_contents.each(&:touch)
23
+ end
24
+
25
+ end
26
+ end