alchemy_cms 2.2.rc13 → 2.2.rc14

Sign up to get free protection for your applications and to get access to all the features.
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