alchemy_cms 2.2.rc13 → 2.2.rc14

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 (106) hide show
  1. data/Rakefile +3 -0
  2. data/alchemy_cms.gemspec +1 -0
  3. data/app/assets/javascripts/alchemy/alchemy.base.js +95 -94
  4. data/app/assets/javascripts/alchemy/alchemy.buttons.js +15 -11
  5. data/app/assets/javascripts/alchemy/alchemy.datepicker.js +18 -18
  6. data/app/assets/javascripts/alchemy/alchemy.dirty.js +20 -20
  7. data/app/assets/javascripts/alchemy/alchemy.dragndrop.js +50 -44
  8. data/app/assets/javascripts/alchemy/alchemy.element_editor_selector.js +15 -12
  9. data/app/assets/javascripts/alchemy/alchemy.elements_window.js +47 -43
  10. data/app/assets/javascripts/alchemy/alchemy.file_progress.js +27 -17
  11. data/app/assets/javascripts/alchemy/alchemy.growler.js +19 -15
  12. data/app/assets/javascripts/alchemy/alchemy.html5.js +1 -2
  13. data/app/assets/javascripts/alchemy/alchemy.image_cropper.js +10 -11
  14. data/app/assets/javascripts/alchemy/alchemy.jquery_loader.js +6 -6
  15. data/app/assets/javascripts/alchemy/alchemy.js_extensions.js +4 -6
  16. data/app/assets/javascripts/alchemy/alchemy.menubar.js +16 -20
  17. data/app/assets/javascripts/alchemy/alchemy.page_sorter.js +18 -16
  18. data/app/assets/javascripts/alchemy/alchemy.preview.js +30 -30
  19. data/app/assets/javascripts/alchemy/alchemy.preview_window.js +50 -42
  20. data/app/assets/javascripts/alchemy/alchemy.routes.js.erb +11 -11
  21. data/app/assets/javascripts/alchemy/alchemy.swf_upload.js +83 -86
  22. data/app/assets/javascripts/alchemy/alchemy.uploader.js +106 -112
  23. data/app/assets/javascripts/alchemy/alchemy.windows.js +158 -130
  24. data/app/assets/stylesheets/alchemy/base.css.scss +7 -1
  25. data/app/assets/stylesheets/alchemy/buttons.css.scss +31 -25
  26. data/app/assets/stylesheets/alchemy/elements.css.scss +4 -0
  27. data/app/controllers/alchemy/admin/base_controller.rb +5 -1
  28. data/app/helpers/alchemy/admin/base_helper.rb +21 -13
  29. data/app/helpers/alchemy/admin/contents_helper.rb +52 -11
  30. data/app/helpers/alchemy/admin/elements_helper.rb +0 -1
  31. data/app/helpers/alchemy/admin/essences_helper.rb +5 -5
  32. data/app/helpers/alchemy/essences_helper.rb +1 -0
  33. data/app/models/alchemy/content.rb +102 -91
  34. data/app/models/alchemy/essence_boolean.rb +8 -0
  35. data/app/models/alchemy/essence_select.rb +7 -0
  36. data/app/sweepers/alchemy/content_sweeper.rb +2 -4
  37. data/app/views/alchemy/admin/clipboard/clear.js.erb +3 -2
  38. data/app/views/alchemy/admin/clipboard/index.html.erb +2 -2
  39. data/app/views/alchemy/admin/contents/create.js.erb +2 -0
  40. data/app/views/alchemy/admin/contents/destroy.js.coffee +4 -0
  41. data/app/views/alchemy/admin/contents/new.html.erb +1 -1
  42. data/app/views/alchemy/admin/elements/_element_foot.html.erb +3 -2
  43. data/app/views/alchemy/admin/elements/create.js.coffee +31 -0
  44. data/app/views/alchemy/admin/elements/fold.js.coffee +37 -0
  45. data/app/views/alchemy/admin/essence_pictures/assign.js.coffee +15 -0
  46. data/app/views/alchemy/admin/essence_pictures/destroy.js.coffee +19 -0
  47. data/app/views/alchemy/admin/essence_pictures/edit.html.erb +12 -2
  48. data/app/views/alchemy/admin/layoutpages/_layoutpage.html.erb +1 -1
  49. data/app/views/alchemy/admin/pages/_page.html.erb +1 -1
  50. data/app/views/alchemy/admin/pages/destroy.js.coffee +19 -0
  51. data/app/views/alchemy/admin/pages/edit.html.erb +5 -5
  52. data/app/views/alchemy/admin/pages/update.js.coffee +36 -0
  53. data/app/views/alchemy/admin/resources/_form.html.erb +12 -1
  54. data/app/views/alchemy/admin/resources/_resource.html.erb +6 -3
  55. data/app/views/alchemy/admin/resources/_table.html.erb +1 -1
  56. data/app/views/alchemy/admin/trash/clear.js.coffee +4 -0
  57. data/app/views/alchemy/admin/trash/index.html.erb +4 -4
  58. data/app/views/alchemy/elements/_article_editor.html.erb +4 -2
  59. data/app/views/alchemy/elements/_article_view.html.erb +7 -7
  60. data/app/views/alchemy/elements/_download_editor.html.erb +4 -1
  61. data/app/views/alchemy/elements/_download_view.html.erb +7 -3
  62. data/app/views/alchemy/elements/_image_mosaic_editor.html.erb +1 -0
  63. data/app/views/alchemy/elements/_image_mosaic_view.html.erb +11 -9
  64. data/app/views/alchemy/essences/_essence_boolean_editor.html.erb +14 -0
  65. data/app/views/alchemy/essences/_essence_boolean_view.html.erb +1 -0
  66. data/app/views/alchemy/essences/_essence_date_editor.html.erb +1 -1
  67. data/app/views/alchemy/essences/_essence_file_editor.html.erb +1 -0
  68. data/app/views/alchemy/essences/_essence_html_editor.html.erb +1 -1
  69. data/app/views/alchemy/essences/_essence_richtext_editor.html.erb +1 -1
  70. data/app/views/alchemy/essences/_essence_select_editor.html.erb +35 -0
  71. data/app/views/alchemy/essences/_essence_select_view.html.erb +1 -0
  72. data/app/views/alchemy/essences/_essence_text_editor.html.erb +29 -77
  73. data/app/views/alchemy/essences/_essence_text_view.html.erb +2 -2
  74. data/config/alchemy/elements.yml +72 -44
  75. data/config/locales/alchemy.de.yml +46 -45
  76. data/config/locales/alchemy.en.yml +90 -89
  77. data/db/migrate/20120608085509_create_alchemy_essence_selects.rb +11 -0
  78. data/db/migrate/20120611221734_create_alchemy_essence_booleans.rb +11 -0
  79. data/lib/alchemy/authentication_helpers.rb +3 -7
  80. data/lib/alchemy/engine.rb +3 -4
  81. data/lib/alchemy/essence.rb +24 -16
  82. data/lib/alchemy/resource.rb +22 -3
  83. data/lib/alchemy/resources_helper.rb +8 -0
  84. data/lib/alchemy/seeder.rb +26 -1
  85. data/lib/alchemy/upgrader.rb +70 -1
  86. data/lib/alchemy/version.rb +1 -1
  87. data/lib/alchemy_cms.rb +1 -0
  88. data/spec/controllers/admin/clipboard_controller_spec.rb +16 -4
  89. data/spec/controllers/admin/contents_controller_spec.rb +21 -4
  90. data/spec/dummy/app/models/event.rb +1 -1
  91. data/spec/dummy/db/schema.rb +18 -1
  92. data/spec/helpers/admin/contents_helper_spec.rb +3 -2
  93. data/spec/models/clipboard_spec.rb +14 -3
  94. data/spec/models/essence_boolean_spec.rb +15 -0
  95. data/spec/models/essence_select_spec.rb +15 -0
  96. data/spec/models/resource_spec.rb +113 -0
  97. metadata +40 -12
  98. data/app/views/alchemy/admin/contents/destroy.js.erb +0 -7
  99. data/app/views/alchemy/admin/elements/create.js.erb +0 -36
  100. data/app/views/alchemy/admin/elements/fold.js.erb +0 -41
  101. data/app/views/alchemy/admin/essence_pictures/assign.js.erb +0 -16
  102. data/app/views/alchemy/admin/essence_pictures/destroy.js.erb +0 -20
  103. data/app/views/alchemy/admin/pages/destroy.js.erb +0 -12
  104. data/app/views/alchemy/admin/pages/update.js.erb +0 -40
  105. data/app/views/alchemy/admin/trash/clear.js.erb +0 -3
  106. data/spec/dummy/app/models/.gitkeep +0 -0
@@ -627,6 +627,10 @@ a.new_content_link {
627
627
  margin-top: 4px;
628
628
  }
629
629
 
630
+ div.content_rtf_editor {
631
+ min-height: 246px;
632
+ }
633
+
630
634
  div.essence_richtext_loader {
631
635
  position: absolute;
632
636
  top: 0;
@@ -61,6 +61,10 @@ module Alchemy
61
61
 
62
62
  def get_clipboard
63
63
  session[:clipboard] ||= Clipboard.new
64
+ rescue NoMethodError => e
65
+ exception_logger(e)
66
+ @notice = "You have an old style clipboard in your session. Please remove your cookies and try again."
67
+ render :action => "error_notice", :layout => false
64
68
  end
65
69
 
66
70
  def clipboard_empty?(category = nil)
@@ -77,7 +81,7 @@ module Alchemy
77
81
  end
78
82
 
79
83
  def set_stamper
80
- User.stamper = self.current_user
84
+ User.stamper = current_user
81
85
  end
82
86
 
83
87
  def reset_stamper
@@ -23,6 +23,7 @@ module Alchemy
23
23
  # :overflow [Boolean] # Should the dialog have overlapping content. If not, it shows scrollbars. Good for select boxes. Default false.
24
24
  # :resizable [Boolean] # Is the dialog window resizable? Default false.
25
25
  # :modal [Boolean] # Show as modal window. Default true.
26
+ # :overflow [Boolean] # Should the window show overflowing content? Default false.
26
27
  #
27
28
  def link_to_overlay_window(content, url, options={}, html_options={})
28
29
  default_options = {
@@ -32,12 +33,17 @@ module Alchemy
32
33
  }
33
34
  options = default_options.merge(options)
34
35
  size = options[:size].to_s.split('x')
35
- size_x = options[:size] ? size[0] : 'auto'
36
- size_y = options[:size] ? size[1] : 'auto'
37
- link_to(
38
- content,
39
- '#',
40
- html_options.merge(:onclick => "Alchemy.openWindow('#{url}', '#{options[:title]}', '#{size}', '#{size_y}', #{options[:resizable]}, #{options[:modal]}, #{options[:overflow]})")
36
+ link_to(content, url,
37
+ html_options.merge(
38
+ 'data-alchemy-overlay' => {
39
+ :size_x => size && size[0] ? size[0] : 'auto',
40
+ :size_y => size && size[1] ? size[1] : 'auto',
41
+ :resizable => options[:resizable],
42
+ :modal => options[:modal],
43
+ :overflow => options[:overflow],
44
+ :title => options[:title]
45
+ }.to_json
46
+ )
41
47
  )
42
48
  end
43
49
 
@@ -113,13 +119,15 @@ module Alchemy
113
119
  # <%= link_to_confirmation_window('delete', 'Do you really want to delete this comment?', '/admin/comments/1') %>
114
120
  #
115
121
  def link_to_confirmation_window(link_string = "", message = "", url = "", html_options = {})
116
- title = t("please_confirm")
117
- ok_lable = t("Yes")
118
- cancel_lable = t("No")
119
- link_to(
120
- link_string,
121
- '#',
122
- html_options.merge(:onclick => "Alchemy.confirmToDeleteWindow('#{url}', '#{title}', '#{message}', '#{ok_lable}', '#{cancel_lable}');")
122
+ link_to(link_string, url,
123
+ html_options.merge(
124
+ 'data-alchemy-confirm' => {
125
+ :title => t("please_confirm"),
126
+ :message => message,
127
+ :ok_label => t("Yes"),
128
+ :cancel_label => t("No")
129
+ }.to_json
130
+ )
123
131
  )
124
132
  end
125
133
 
@@ -32,10 +32,13 @@ module Alchemy
32
32
  content.has_validations? ? "#{content_name}<span class='validation_indicator'>*</span>".html_safe : content_name
33
33
  end
34
34
 
35
- # Renders a link to show the new content overlay
35
+ # Renders a link to show the new content overlay that lets you add additional contents.
36
+ #
37
+ # See +render_create_content_link+ helper for exmaples on how to define additional contents.
38
+ #
36
39
  def render_new_content_link(element)
37
40
  link_to_overlay_window(
38
- render_icon('create') + t('add new content'),
41
+ render_icon(:create) + t('add new content'),
39
42
  alchemy.new_admin_element_content_path(element),
40
43
  {
41
44
  :size => '335x70',
@@ -44,32 +47,70 @@ module Alchemy
44
47
  },
45
48
  {
46
49
  :id => "add_content_for_element_#{element.id}",
47
- :class => 'small button with_icon new_content_link'
50
+ :class => 'button with_icon new_content_link'
48
51
  }
49
52
  )
50
53
  end
51
54
 
52
- # Renders a link to create a new content in element editor
53
- def render_create_content_link(element, options = {})
55
+ # Renders a link that dynamically adds an additional content into your element editor view.
56
+ #
57
+ # NOTE: You have to define additional contents in your elements.yml file first.
58
+ #
59
+ # ==== Example:
60
+ #
61
+ # # config/alchemy/elements.yml
62
+ # - name: downloads:
63
+ # contents:
64
+ # - name: file
65
+ # type: EssenceFile
66
+ # additional_contents:
67
+ # - name: file
68
+ # type: EssenceFile
69
+ #
70
+ # Then add this helper into the elements editor view partial:
71
+ #
72
+ # <%= render_create_content_link(element, 'file') %>
73
+ #
74
+ # Optionally you can pass a label:
75
+ #
76
+ # <%= render_create_content_link(element, 'file', :label => 'Add a file') %>
77
+ #
78
+ def render_create_content_link(element, content_name, options = {})
54
79
  defaults = {
55
- :label => t('add new content')
80
+ :label => t('Add %{name}', :name => t(content_name, :scope => :content_names))
56
81
  }
57
82
  options = defaults.merge(options)
58
- link_to(
59
- options[:label],
60
- alchemy.admin_contents_path(
83
+ link_to(render_icon(:create) + options[:label], alchemy.admin_contents_path(
61
84
  :content => {
62
- :name => options[:content_name],
85
+ :name => content_name,
63
86
  :element_id => element.id
64
87
  }
65
88
  ),
66
- :method => 'post',
89
+ :method => :post,
67
90
  :remote => true,
68
91
  :id => "add_content_for_element_#{element.id}",
69
92
  :class => 'button new_content_link'
70
93
  )
71
94
  end
72
95
 
96
+ # Renders a link for removing that content
97
+ def delete_content_link(content)
98
+ link_to_confirmation_window(
99
+ render_icon('delete-small'),
100
+ t('Do you really want to delete this content?'),
101
+ alchemy.admin_content_path(content),
102
+ :class => 'icon_button small',
103
+ :title => t('Remove this content')
104
+ ) if content.settings[:deletable]
105
+ end
106
+
107
+ # Renders the label and a remove link for a content.
108
+ def label_and_remove_link(content)
109
+ content_tag :label do
110
+ [render_content_name(content).to_s, delete_content_link(content).to_s].join('&nbsp;').html_safe
111
+ end
112
+ end
113
+
73
114
  end
74
115
  end
75
116
  end
@@ -62,7 +62,6 @@ module Alchemy
62
62
  }
63
63
  )
64
64
  end
65
-
66
65
  alias_method :render_picture_editor, :render_picture_gallery_editor
67
66
 
68
67
  # Returns all elements that could be placed on that page because of the pages layout.
@@ -94,14 +94,14 @@ module Alchemy
94
94
  }
95
95
  options = default_options.merge(options)
96
96
  pages = Page.where({
97
- :language_id => session[:language_id],
98
- :layoutpage => options[:global] == true,
99
- :public => options[:global] == false
100
- })
97
+ :language_id => session[:language_id],
98
+ :layoutpage => options[:global] == true,
99
+ :public => options[:global] == false
100
+ })
101
101
  pages = pages.where({:page_layout => options[:only]}) if options[:only].present?
102
102
  content = element.content_by_name(content_name)
103
103
  options.update(
104
- :select_values => pages_for_select(pages, content ? content.essence.body : nil, options[:prompt], options[:page_attribute])
104
+ :select_values => pages_for_select(pages, content ? content.ingredient : nil, options[:prompt], options[:page_attribute])
105
105
  )
106
106
  if content.nil?
107
107
  render_missing_content(element, content_name, options)
@@ -108,6 +108,7 @@ module Alchemy
108
108
  # :for_editor => {}
109
109
  #
110
110
  def render_essence(content, part = :view, options = {}, html_options = {})
111
+ options = {:for_view => {}, :for_editor => {}}.update(options)
111
112
  if content.nil?
112
113
  return part == :view ? "" : warning('Content is nil', t("content_not_found"))
113
114
  elsif content.essence.nil?
@@ -20,36 +20,95 @@ module Alchemy
20
20
  scope :essence_pictures, where(:essence_type => "Alchemy::EssencePicture")
21
21
  scope :essence_texts, where(:essence_type => "Alchemy::EssenceText")
22
22
  scope :essence_richtexts, where(:essence_type => "Alchemy::EssenceRichtext")
23
+ scope :essence_selects, where(:essence_type => "Alchemy::EssenceSelect")
24
+ scope :essence_booleans, where(:essence_type => "Alchemy::EssenceBoolean")
25
+
26
+ class << self
27
+
28
+ # Creates a new Content as descriped in the elements.yml file
29
+ def create_from_scratch(element, essences_hash)
30
+ if essences_hash[:name].blank? && !essences_hash[:essence_type].blank?
31
+ essences_of_same_type = element.contents.where(
32
+ :essence_type => Content.normalize_essence_type(essences_hash[:essence_type])
33
+ )
34
+ description = {
35
+ 'type' => essences_hash[:essence_type],
36
+ 'name' => "#{essences_hash[:essence_type].classify.demodulize.underscore}_#{essences_of_same_type.count + 1}"
37
+ }
38
+ else
39
+ description = element.content_description_for(essences_hash[:name])
40
+ description = element.available_content_description_for(essences_hash[:name]) if description.blank?
41
+ end
42
+ raise "No description found in elements.yml for #{essences_hash.inspect} and #{element.inspect}" if description.blank?
43
+ content = new(:name => description['name'], :element_id => element.id)
44
+ content.create_essence!(description)
45
+ end
23
46
 
24
- # Creates a new Content as descriped in the elements.yml file
25
- def self.create_from_scratch(element, essences_hash)
26
- if essences_hash[:name].blank? && !essences_hash[:essence_type].blank?
27
- essences_of_same_type = element.contents.where(
28
- :essence_type => Content.normalize_essence_type(essences_hash[:essence_type])
29
- )
30
- description = {
31
- 'type' => essences_hash[:essence_type],
32
- 'name' => "#{essences_hash[:essence_type].classify.demodulize.underscore}_#{essences_of_same_type.count + 1}"
33
- }
34
- else
35
- description = element.content_description_for(essences_hash[:name])
36
- description = element.available_content_description_for(essences_hash[:name]) if description.blank?
47
+ # Makes a copy of source and also copies the associated essence.
48
+ #
49
+ # You can pass a differences hash to update the attributes of the copy.
50
+ #
51
+ # === Example
52
+ #
53
+ # @copy = Alchemy::Content.copy(@content, {:element_id => 3})
54
+ # @copy.element_id # => 3
55
+ #
56
+ def copy(source, differences = {})
57
+ attributes = source.attributes.except(
58
+ "position",
59
+ "created_at",
60
+ "updated_at",
61
+ "creator_id",
62
+ "updater_id",
63
+ "id"
64
+ ).merge(differences.stringify_keys)
65
+ content = self.create!(attributes)
66
+ new_essence = content.essence.class.new(content.essence.attributes.except(
67
+ "id",
68
+ "creator_id",
69
+ "updater_id",
70
+ "created_at",
71
+ "updated_at"
72
+ ))
73
+ new_essence.save!
74
+ raise "Essence not cloned" if new_essence.id == content.essence_id
75
+ content.update_attribute(:essence_id, new_essence.id)
76
+ content
37
77
  end
38
- raise "No description found in elements.yml for #{essences_hash.inspect} and #{element.inspect}" if description.blank?
39
- essence_class = Content.normalize_essence_type(description['type']).constantize
40
- content = self.new(:name => description['name'], :element_id => element.id)
41
- if description['type'] == "EssenceRichtext" || description['type'] == "EssenceText"
42
- essence = essence_class.create(:do_not_index => !description['do_not_index'].nil?)
43
- else
44
- essence = essence_class.create
78
+
79
+ # Returns the translated label for a content name.
80
+ #
81
+ # Translate it in your locale yml file:
82
+ #
83
+ # alchemy:
84
+ # content_names:
85
+ # foo: Bar
86
+ #
87
+ # Optionally you can scope your content name to an element:
88
+ #
89
+ # alchemy:
90
+ # content_names:
91
+ # article:
92
+ # foo: Baz
93
+ #
94
+ def translated_label_for(content_name, element_name = nil)
95
+ Alchemy::I18n.t("content_names.#{element_name}.#{content_name}", :default => ["content_names.#{content_name}".to_sym, content_name.capitalize])
45
96
  end
46
- if essence
47
- content.essence = essence
48
- content.save!
49
- else
50
- content = nil
97
+
98
+ # Returns all content descriptions from elements.yml
99
+ def descriptions
100
+ @descriptions ||= Element.descriptions.collect { |e| e['contents'] }.flatten.compact
51
101
  end
52
- return content
102
+
103
+ def normalize_essence_type(essence_type)
104
+ essence_type = essence_type.classify
105
+ if not essence_type.match(/^Alchemy::/)
106
+ essence_type.gsub!(/^Essence/, 'Alchemy::Essence')
107
+ else
108
+ essence_type
109
+ end
110
+ end
111
+
53
112
  end
54
113
 
55
114
  # Settings from the elements.yml definition
@@ -65,38 +124,6 @@ module Alchemy
65
124
  self.element.contents
66
125
  end
67
126
 
68
- # Makes a copy of source and also copies the associated essence.
69
- #
70
- # You can pass a differences hash to update the attributes of the copy.
71
- #
72
- # === Example
73
- #
74
- # @copy = Alchemy::Content.copy(@content, {:element_id => 3})
75
- # @copy.element_id # => 3
76
- #
77
- def self.copy(source, differences = {})
78
- attributes = source.attributes.except(
79
- "position",
80
- "created_at",
81
- "updated_at",
82
- "creator_id",
83
- "updater_id",
84
- "id"
85
- ).merge(differences.stringify_keys)
86
- content = self.create!(attributes)
87
- new_essence = content.essence.class.new(content.essence.attributes.except(
88
- "id",
89
- "creator_id",
90
- "updater_id",
91
- "created_at",
92
- "updated_at"
93
- ))
94
- new_essence.save!
95
- raise "Essence not cloned" if new_essence.id == content.essence_id
96
- content.update_attribute(:essence_id, new_essence.id)
97
- content
98
- end
99
-
100
127
  # Returns my description hash from elements.yml
101
128
  # Returns the description from available_contents if my own description is blank
102
129
  def description
@@ -113,11 +140,6 @@ module Alchemy
113
140
  end
114
141
  end
115
142
 
116
- # Returns all content descriptions from elements.yml
117
- def self.descriptions
118
- @descriptions ||= Element.descriptions.collect { |e| e['contents'] }.flatten.compact
119
- end
120
-
121
143
  # Gets the ingredient from essence
122
144
  def ingredient
123
145
  return nil if self.essence.nil?
@@ -172,25 +194,6 @@ module Alchemy
172
194
  self.class.translated_label_for(self.name, self.element.name)
173
195
  end
174
196
 
175
- # Returns the translated label for a content name.
176
- #
177
- # Translate it in your locale yml file:
178
- #
179
- # alchemy:
180
- # content_names:
181
- # foo: Bar
182
- #
183
- # Optionally you can scope your content name to an element:
184
- #
185
- # alchemy:
186
- # content_names:
187
- # article:
188
- # foo: Baz
189
- #
190
- def self.translated_label_for(content_name, element_name = nil)
191
- Alchemy::I18n.t("content_names.#{element_name}.#{content_name}", :default => ["content_names.#{content_name}".to_sym, content_name.capitalize])
192
- end
193
-
194
197
  def linked?
195
198
  essence && !essence.link.blank?
196
199
  end
@@ -203,15 +206,6 @@ module Alchemy
203
206
  self.class.normalize_essence_type(self.essence_type)
204
207
  end
205
208
 
206
- def self.normalize_essence_type(essence_type)
207
- essence_type = essence_type.classify
208
- if not essence_type.match(/^Alchemy::/)
209
- essence_type.gsub!(/^Essence/, 'Alchemy::Essence')
210
- else
211
- essence_type
212
- end
213
- end
214
-
215
209
  def has_custom_tinymce_config?
216
210
  !settings[:tinymce].nil?
217
211
  end
@@ -226,5 +220,22 @@ module Alchemy
226
220
  end
227
221
  end
228
222
 
223
+ # Creates self.essence from description.
224
+ def create_essence!(description)
225
+ essence_class = self.class.normalize_essence_type(description['type']).constantize
226
+ if description['type'] == "EssenceRichtext" || description['type'] == "EssenceText"
227
+ essence = essence_class.create(:do_not_index => !description['do_not_index'].nil?)
228
+ else
229
+ essence = essence_class.create
230
+ end
231
+ if essence
232
+ self.essence = essence
233
+ save!
234
+ self
235
+ else
236
+ nil
237
+ end
238
+ end
239
+
229
240
  end
230
241
  end