alchemy_cms 2.2.rc11 → 2.2.rc13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/.travis.yml +4 -1
  2. data/Gemfile +10 -9
  3. data/alchemy_cms.gemspec +8 -4
  4. data/app/assets/javascripts/alchemy/alchemy.base.js +0 -13
  5. data/app/assets/javascripts/alchemy/alchemy.dirty.js +6 -4
  6. data/app/assets/javascripts/alchemy/alchemy.dragndrop.js +2 -2
  7. data/app/assets/stylesheets/alchemy/elements.css.scss +4 -7
  8. data/app/controllers/alchemy/admin/base_controller.rb +2 -3
  9. data/app/controllers/alchemy/admin/clipboard_controller.rb +10 -10
  10. data/app/controllers/alchemy/admin/elements_controller.rb +4 -4
  11. data/app/controllers/alchemy/admin/pages_controller.rb +1 -2
  12. data/app/controllers/alchemy/base_controller.rb +1 -15
  13. data/app/helpers/alchemy/admin/base_helper.rb +15 -21
  14. data/app/helpers/alchemy/admin/contents_helper.rb +0 -6
  15. data/app/helpers/alchemy/admin/pages_helper.rb +62 -27
  16. data/app/helpers/alchemy/base_helper.rb +0 -9
  17. data/app/models/alchemy/clipboard.rb +74 -0
  18. data/app/models/alchemy/clipboard_spec.rb +0 -0
  19. data/app/models/alchemy/content.rb +19 -0
  20. data/app/views/alchemy/admin/contents/create.js.erb +1 -1
  21. data/app/views/alchemy/admin/elements/_element.html.erb +0 -1
  22. data/app/views/alchemy/admin/elements/_element_head.html.erb +4 -5
  23. data/app/views/alchemy/admin/essence_pictures/assign.js.erb +3 -2
  24. data/app/views/alchemy/admin/essence_pictures/crop.html.erb +3 -4
  25. data/app/views/alchemy/admin/essence_pictures/edit.html.erb +1 -1
  26. data/app/views/alchemy/admin/essence_pictures/update.js.erb +1 -10
  27. data/app/views/alchemy/admin/pages/_contactform_links.html.erb +3 -9
  28. data/app/views/alchemy/admin/pages/_external_link.html.erb +3 -12
  29. data/app/views/alchemy/admin/pages/_file_link.html.erb +3 -12
  30. data/app/views/alchemy/admin/pages/_internal_link.html.erb +5 -14
  31. data/app/views/alchemy/admin/pages/_page_for_links.html.erb +3 -9
  32. data/app/views/alchemy/admin/pages/edit.html.erb +16 -17
  33. data/app/views/alchemy/admin/pictures/_picture.html.erb +3 -2
  34. data/app/views/alchemy/admin/pictures/_picture_to_assign.html.erb +1 -0
  35. data/app/views/alchemy/essences/_essence_picture_tools.html.erb +6 -8
  36. data/app/views/alchemy/essences/_essence_richtext_editor.html.erb +9 -3
  37. data/lib/alchemy/authentication_helpers.rb +26 -0
  38. data/lib/alchemy/engine.rb +4 -0
  39. data/lib/alchemy/tinymce.rb +4 -0
  40. data/lib/alchemy/version.rb +1 -1
  41. data/spec/controllers/admin/clipboard_controller_spec.rb +35 -35
  42. data/spec/controllers/admin/elements_controller_spec.rb +71 -14
  43. data/spec/controllers/admin/pages_controller_spec.rb +79 -33
  44. data/spec/models/clipboard_spec.rb +100 -0
  45. data/spec/models/element_spec.rb +17 -7
  46. metadata +77 -8
data/.travis.yml CHANGED
@@ -1,10 +1,10 @@
1
1
  language: ruby
2
- bundler_args: --without development
3
2
  rvm:
4
3
  - 1.8.7
5
4
  - 1.9.2
6
5
  - 1.9.3
7
6
  - ree
7
+ - rbx-19mode
8
8
  branches:
9
9
  only:
10
10
  - master
@@ -15,3 +15,6 @@ env:
15
15
  - DB=mysql
16
16
  - DB=postgresql
17
17
  - DB=sqlite
18
+ matrix:
19
+ allow_failures:
20
+ - rvm: rbx-19mode
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source "http://rubygems.org"
1
+ source 'http://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
@@ -10,12 +10,10 @@ group :test do
10
10
  gem 'sqlite3' if ENV['DB'].nil? || ENV['DB'] == 'sqlite'
11
11
  gem 'mysql2' if ENV['DB'] == 'mysql'
12
12
  gem 'pg' if ENV['DB'] == 'postgresql'
13
- gem 'rspec-rails'
14
- gem 'factory_girl_rails', '~> 1.7.0'
15
- gem "capybara"
16
- gem 'capybara-webkit' unless ENV['CI']
17
- gem "launchy" unless ENV['CI']
18
- gem "database_cleaner"
13
+ unless ENV['CI']
14
+ gem 'capybara-webkit'
15
+ gem 'launchy'
16
+ end
19
17
  end
20
18
 
21
19
  group :assets do
@@ -25,6 +23,9 @@ group :assets do
25
23
  end
26
24
 
27
25
  group :development do
28
- gem 'guard-spork'
29
- gem 'yard'
26
+ unless ENV['CI']
27
+ gem 'guard-spork'
28
+ gem 'ruby-debug19', :require => 'ruby-debug', :platform => :ruby_19
29
+ gem 'ruby-debug', :platform => :ruby_18
30
+ end
30
31
  end
data/alchemy_cms.gemspec CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
20
20
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
21
  s.require_paths = ["lib"]
22
22
 
23
- s.add_runtime_dependency(%q<rails>, ["~> 3.2.1"])
23
+ s.add_runtime_dependency(%q<rails>, ["~> 3.2.5"])
24
24
  s.add_runtime_dependency(%q<authlogic>)
25
25
  s.add_runtime_dependency(%q<awesome_nested_set>, ["~> 2.0"])
26
26
  s.add_runtime_dependency(%q<declarative_authorization>, ["~> 0.5.4"])
@@ -32,10 +32,14 @@ Gem::Specification.new do |s|
32
32
  s.add_runtime_dependency(%q<dynamic_form>, ["~> 1.1"])
33
33
  s.add_runtime_dependency(%q<jquery-rails>, ["~> 2.0.0"])
34
34
  s.add_runtime_dependency(%q<attachment_magic>, ["~> 0.2.1"])
35
- s.add_runtime_dependency('sass-rails', ['~> 3.2.3'])
35
+ s.add_runtime_dependency(%q<sass-rails>, ['~> 3.2.3'])
36
36
 
37
- s.add_development_dependency(%q<rspec-rails>, ["~> 2.8"])
37
+ s.add_development_dependency(%q<bumpy>)
38
+ s.add_development_dependency(%q<capybara>)
39
+ s.add_development_dependency(%q<database_cleaner>)
40
+ s.add_development_dependency(%q<factory_girl_rails>, ['~> 1.7.0'])
41
+ s.add_development_dependency(%q<rspec-rails>)
38
42
  s.add_development_dependency(%q<sqlite3>)
39
- s.add_development_dependency(%q<jasminerice>)
43
+ s.add_development_dependency(%q<yard>)
40
44
 
41
45
  end
@@ -118,19 +118,6 @@ if (typeof(Alchemy) === 'undefined') {
118
118
  }
119
119
  },
120
120
 
121
- saveElement:function (form) {
122
- // disabled for now. I think we don't need this.
123
- return true;
124
- // remove this comment if you have problems with saving tinymce content
125
- // var $rtf_contents = $(form).find('div.content_rtf_editor');
126
- // if ($rtf_contents.size() > 0) {
127
- // $rtf_contents.each(function() {
128
- // var id = $(this).children('textarea.tinymce').attr('id');
129
- // tinymce.get(id).save();
130
- // });
131
- // }
132
- },
133
-
134
121
  setElementSaved:function (selector) {
135
122
  var $element = $(selector);
136
123
  Alchemy.setElementClean(selector);
@@ -8,12 +8,14 @@ if (typeof(Alchemy) === 'undefined') {
8
8
 
9
9
  ElementDirtyObserver:function (selector) {
10
10
  var $elements = $(selector);
11
- $elements.find('textarea.tinymce').map(function () {
11
+ $elements.find('textarea.default_tinymce').map(function () {
12
12
  var $this = $(this);
13
13
  var ed = tinymce.get(this.id);
14
- ed.onChange.add(function (ed, l) {
15
- Alchemy.setElementDirty($this.parents('.element_editor'));
16
- });
14
+ if (ed) {
15
+ ed.onChange.add(function (ed, l) {
16
+ Alchemy.setElementDirty($this.parents('.element_editor'));
17
+ });
18
+ }
17
19
  });
18
20
  $elements.find('input[type="text"]').bind('change', function () {
19
21
  $(this).addClass('dirty');
@@ -47,13 +47,13 @@ if (typeof(Alchemy) === 'undefined') {
47
47
  });
48
48
  },
49
49
  start:function (event, ui) {
50
- var $textareas = ui.item.find('textarea.tinymce');
50
+ var $textareas = ui.item.find('textarea.default_tinymce, textarea.custom_tinymce');
51
51
  $textareas.each(function () {
52
52
  tinymce.get(this.id).remove();
53
53
  });
54
54
  },
55
55
  stop:function (event, ui) {
56
- var $textareas = ui.item.find('textarea.tinymce');
56
+ var $textareas = ui.item.find('textarea.default_tinymce, textarea.custom_tinymce');
57
57
  $textareas.each(function () {
58
58
  Alchemy.Tinymce.addEditor(this.id);
59
59
  });
@@ -634,8 +634,8 @@ div.essence_richtext_loader {
634
634
  z-index: 1;
635
635
  width: 100%;
636
636
  height: 100%;
637
- background-color: #ededed;
638
- @include opacity(75);
637
+ background-color: #F0E8D7;
638
+ @include opacity(90);
639
639
  }
640
640
 
641
641
  div.essence_richtext_loader img {
@@ -828,11 +828,8 @@ textarea {
828
828
  height: 140px;
829
829
  }
830
830
 
831
- textarea.tinymce {
832
- padding: 0;
833
- margin: 0;
834
- width: 100%;
835
- border: 0 none;
831
+ textarea.default_tinymce, textarea.custom_tinymce {
832
+ visibility: hidden;
836
833
  }
837
834
 
838
835
  .text_short_float_left {
@@ -59,9 +59,8 @@ module Alchemy
59
59
  end
60
60
  end
61
61
 
62
- def get_clipboard(category = nil)
63
- clipboard = (session[:clipboard] ||= {})
64
- clipboard[category.to_s.pluralize] ||= [] if category
62
+ def get_clipboard
63
+ session[:clipboard] ||= Clipboard.new
65
64
  end
66
65
 
67
66
  def clipboard_empty?(category = nil)
@@ -4,18 +4,18 @@ module Alchemy
4
4
  class ClipboardController < Alchemy::Admin::BaseController
5
5
 
6
6
  def index
7
- clipboard = get_clipboard(params[:remarkable_type])
8
- @clipboard_items = model_class.all_from_clipboard(clipboard)
7
+ @clipboard = get_clipboard
8
+ @clipboard_items = model_class.all_from_clipboard(@clipboard.all(params[:remarkable_type]))
9
9
  respond_to do |format|
10
10
  format.html { render :layout => false }
11
11
  end
12
12
  end
13
13
 
14
14
  def insert
15
- @clipboard = get_clipboard(params[:remarkable_type])
15
+ @clipboard = get_clipboard
16
16
  @item = model_class.find(params[:remarkable_id])
17
- unless @clipboard.collect { |i| i[:id].to_s }.include?(params[:remarkable_id])
18
- @clipboard.push({:id => params[:remarkable_id], :action => params[:remove] ? 'cut' : 'copy'})
17
+ unless @clipboard.contains? params[:remarkable_type], params[:remarkable_id]
18
+ @clipboard.push params[:remarkable_type], {:id => params[:remarkable_id], :action => params[:remove] ? 'cut' : 'copy'}
19
19
  end
20
20
  respond_to do |format|
21
21
  format.js
@@ -23,19 +23,19 @@ module Alchemy
23
23
  end
24
24
 
25
25
  def remove
26
- @clipboard = get_clipboard(params[:remarkable_type])
26
+ @clipboard = get_clipboard
27
27
  @item = model_class.find(params[:remarkable_id])
28
- @clipboard.delete_if { |i| i[:id].to_s == params[:remarkable_id] }
28
+ @clipboard.remove params[:remarkable_type], params[:remarkable_id]
29
29
  respond_to do |format|
30
30
  format.js
31
31
  end
32
32
  end
33
33
 
34
34
  def clear
35
- session[:clipboard] = {}
35
+ session[:clipboard].clear(params[:remarkable_type])
36
36
  end
37
37
 
38
- private
38
+ private
39
39
 
40
40
  def model_class
41
41
  "alchemy/#{params[:remarkable_type]}".classify.constantize
@@ -43,4 +43,4 @@ module Alchemy
43
43
 
44
44
  end
45
45
  end
46
- end
46
+ end
@@ -27,7 +27,7 @@ module Alchemy
27
27
  @page = Page.find_by_id(params[:page_id])
28
28
  @element = @page.elements.build
29
29
  @elements = Element.all_for_page(@page)
30
- clipboard_elements = get_clipboard('elements')
30
+ clipboard_elements = get_clipboard[:elements]
31
31
  unless clipboard_elements.blank?
32
32
  @clipboard_items = Element.all_from_clipboard_for_page(clipboard_elements, @page)
33
33
  end
@@ -43,7 +43,7 @@ module Alchemy
43
43
  @element = Element.copy(source_element, {:page_id => @page.id})
44
44
  if element_from_clipboard[:action] == 'cut'
45
45
  @cutted_element_id = source_element.id
46
- @clipboard.delete_if { |i| i[:id].to_i == source_element.id }
46
+ @clipboard.remove :elements, source_element.id
47
47
  source_element.destroy
48
48
  end
49
49
  else
@@ -115,8 +115,8 @@ module Alchemy
115
115
  end
116
116
 
117
117
  def element_from_clipboard
118
- @clipboard = get_clipboard(:elements)
119
- @clipboard.detect { |i| i[:id].to_i == params[:paste_from_clipboard].to_i }
118
+ @clipboard = get_clipboard
119
+ @clipboard.get(:elements, params[:paste_from_clipboard])
120
120
  end
121
121
 
122
122
  end
@@ -39,7 +39,7 @@ module Alchemy
39
39
  def new
40
40
  @page = Page.new(:layoutpage => params[:layoutpage] == 'true', :parent_id => params[:parent_id])
41
41
  @page_layouts = PageLayout.get_layouts_for_select(session[:language_id], @page.layoutpage?)
42
- @clipboard_items = Page.all_from_clipboard_for_select(get_clipboard('pages'), session[:language_id], @page.layoutpage?)
42
+ @clipboard_items = Page.all_from_clipboard_for_select(get_clipboard[:pages], session[:language_id], @page.layoutpage?)
43
43
  render :layout => false
44
44
  end
45
45
 
@@ -104,7 +104,6 @@ module Alchemy
104
104
  session[:language_id] = @page.language_id
105
105
  if @page.destroy
106
106
  @page_root = Page.language_root_for(session[:language_id])
107
- get_clipboard('pages').delete(@page.id)
108
107
  @message = t("Page deleted", :name => name)
109
108
  flash[:notice] = @message
110
109
  respond_to do |format|
@@ -9,7 +9,7 @@ module Alchemy
9
9
  before_filter :set_language
10
10
  before_filter :mailer_set_url_options
11
11
 
12
- helper_method :current_server, :current_user, :t
12
+ helper_method :current_server, :t
13
13
 
14
14
  # Returns a host string with the domain the app is running on.
15
15
  def current_server
@@ -30,20 +30,6 @@ module Alchemy
30
30
  Language.published.count > 1
31
31
  end
32
32
 
33
- def current_user
34
- return @current_user if defined?(@current_user)
35
- @current_user = current_user_session && current_user_session.record
36
- end
37
-
38
- def current_user_session
39
- return @current_user_session if defined?(@current_user_session)
40
- @current_user_session = UserSession.find
41
- end
42
-
43
- def logged_in?
44
- !current_user.blank?
45
- end
46
-
47
33
  def raise_not_found_error
48
34
  raise ActionController::RoutingError.new('Not Found')
49
35
  end
@@ -31,18 +31,13 @@ module Alchemy
31
31
  :resizable => false
32
32
  }
33
33
  options = default_options.merge(options)
34
- link_to_function(
34
+ 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(
35
38
  content,
36
- "Alchemy.openWindow(
37
- \'#{url}\',
38
- \'#{options[:title]}\',
39
- \'#{options[:size] ? options[:size].split('x')[0].to_s : 'auto'}\',
40
- \'#{options[:size] ? options[:size].split('x')[1].to_s : 'auto'}\',
41
- #{options[:resizable]},
42
- #{options[:modal]},
43
- #{options[:overflow]}
44
- )",
45
- html_options
39
+ '#',
40
+ html_options.merge(:onclick => "Alchemy.openWindow('#{url}', '#{options[:title]}', '#{size}', '#{size_y}', #{options[:resizable]}, #{options[:modal]}, #{options[:overflow]})")
46
41
  )
47
42
  end
48
43
 
@@ -90,18 +85,17 @@ module Alchemy
90
85
  }
91
86
  options = default_options.merge(options)
92
87
  options[:onkeyup] << ";jQuery('#search_field').val().length >= 1 ? jQuery('.js_filter_field_clear').show() : jQuery('.js_filter_field_clear').hide();"
93
- filter_field = "<div class=\"js_filter_field_box\">"
88
+ filter_field = '<div class="js_filter_field_box">'
94
89
  filter_field << text_field_tag("filter", '', options)
95
90
  filter_field << content_tag('span', '', :class => 'icon search')
96
- filter_field << link_to_function(
97
- "",
98
- "jQuery('##{options[:id]}').val('');#{options[:onkeyup]}",
91
+ filter_field << link_to('', '#', {
92
+ :onclick => "jQuery('##{options[:id]}').val('');#{options[:onkeyup]}",
99
93
  :class => "js_filter_field_clear",
100
94
  :style => "display:none",
101
95
  :title => t("click_to_show_all")
102
- )
103
- filter_field << "<label for=\"search_field\">" + t("search") + "</label>"
104
- filter_field << "</div>"
96
+ })
97
+ filter_field << %(<label for="search_field">#{t(:search)}</label>)
98
+ filter_field << '</div>'
105
99
  filter_field.html_safe
106
100
  end
107
101
 
@@ -122,10 +116,10 @@ module Alchemy
122
116
  title = t("please_confirm")
123
117
  ok_lable = t("Yes")
124
118
  cancel_lable = t("No")
125
- link_to_function(
119
+ link_to(
126
120
  link_string,
127
- "Alchemy.confirmToDeleteWindow('#{url}', '#{title}', '#{message}', '#{ok_lable}', '#{cancel_lable}');",
128
- html_options
121
+ '#',
122
+ html_options.merge(:onclick => "Alchemy.confirmToDeleteWindow('#{url}', '#{title}', '#{message}', '#{ok_lable}', '#{cancel_lable}');")
129
123
  )
130
124
  end
131
125
 
@@ -70,12 +70,6 @@ module Alchemy
70
70
  )
71
71
  end
72
72
 
73
- # Returns a textarea ready to use with tinymce
74
- def tinymce_tag(name, content = '', options = {})
75
- append_class_name(options, 'tinymce')
76
- text_area_tag(name, content, options)
77
- end
78
-
79
73
  end
80
74
  end
81
75
  end
@@ -11,34 +11,69 @@ module Alchemy
11
11
  end
12
12
  end
13
13
  init = init.collect { |key, value| "#{key} : #{value.to_json}" }.join(', ')
14
-
15
14
  setup = "init.setup = #{Alchemy::Tinymce.setup};" if Alchemy::Tinymce.setup
16
- return "
17
- <script type='text/javascript'>
18
- jQuery(function(){
19
- if (typeof(Alchemy) !== 'object') { Alchemy = {}; };
20
- Alchemy.Tinymce = {
21
- init : function(callback) {
22
- var init = { #{init} };
23
- init.mode = 'specific_textareas';
24
- init.editor_selector = 'tinymce';
25
- init.plugins = '#{Alchemy::Tinymce.plugins.join(',')}';
26
- init.language = '#{::I18n.locale.to_s.split('-')[0].downcase }';
27
- init.init_instance_callback = function(inst) {
28
- jQuery('#' + inst.editorId).prev('.essence_richtext_loader').hide();
29
- }
30
- if (callback)
31
- init.oninit = callback;
32
- #{setup}
33
- tinymce.init(init);
34
- },
35
- addEditor : function(dom_id) {
36
- tinymce.execCommand('mceAddControl', true, dom_id);
37
- }
38
- };
39
- Alchemy.Tinymce.init();
40
- });
41
- </script>".html_safe
15
+ tinymce_javascript_string = "
16
+ <script type='text/javascript'>
17
+ jQuery(function($) {
18
+ if (typeof(Alchemy) !== 'object') { Alchemy = {}; };
19
+ Alchemy.Tinymce = {
20
+ init : function(callback) {
21
+ var init = { #{init} };
22
+ init.mode = 'specific_textareas';
23
+ init.editor_selector = 'default_tinymce';
24
+ init.plugins = '#{Alchemy::Tinymce.plugins.join(',')}';
25
+ init.language = '#{::I18n.locale.to_s.split('-')[0].downcase }';
26
+ init.init_instance_callback = function(inst) {
27
+ $('#' + inst.editorId).prev('.essence_richtext_loader').hide();
28
+ }
29
+ if (callback)
30
+ init.oninit = callback;
31
+ #{setup}
32
+ tinymce.init(init);
33
+ },
34
+ addEditor : function(dom_id) {
35
+ tinymce.execCommand('mceAddControl', true, dom_id);
36
+ }
37
+ };
38
+ });
39
+ </script>"
40
+ if Alchemy::Tinymce.custom_config_contents.any?
41
+ (tinymce_javascript_string + custom_tinymce_javascript_tags).html_safe
42
+ else
43
+ tinymce_javascript_string.html_safe
44
+ end
45
+ end
46
+
47
+ def custom_tinymce_javascript_tags
48
+ custom_config_string = "
49
+ <script type='text/javascript'>
50
+ jQuery(function($) {
51
+ Alchemy.Tinymce.customInits = [];"
52
+ Alchemy::Tinymce.custom_config_contents.each do |content|
53
+ next unless content['settings']['tinymce']
54
+ config = Alchemy::Tinymce.init.merge(content['settings']['tinymce'].symbolize_keys)
55
+ config = config.collect { |key, value| "#{key} : #{value.to_json}" }.join(', ')
56
+ custom_config_string += "
57
+ Alchemy.Tinymce.customInits.push(function(callback) {
58
+ var init = { #{config} };
59
+ init.mode = 'specific_textareas';
60
+ init.editor_selector = /custom_tinymce #{Regexp.escape(content['name'])}/;
61
+ init.plugins = '#{Alchemy::Tinymce.plugins.join(',')}';
62
+ init.language = '#{::I18n.locale.to_s.split('-')[0].downcase }';
63
+ init.init_instance_callback = function(inst) {
64
+ var $this = $('#' + inst.editorId);
65
+ $this.prev('.essence_richtext_loader').hide();
66
+ inst.onChange.add(function (ed, l) {
67
+ Alchemy.setElementDirty($this.parents('.element_editor'));
68
+ });
69
+ }
70
+ tinymce.init(init);
71
+ });"
72
+ end
73
+ custom_config_string += "
74
+ });
75
+ </script>"
76
+ custom_config_string.html_safe
42
77
  end
43
78
 
44
79
  end