alchemy_cms 2.1.5 → 2.1.6

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 (55) hide show
  1. data/.travis.yml +1 -0
  2. data/app/assets/javascripts/alchemy/alchemy.base.js +1 -1
  3. data/app/assets/javascripts/alchemy/alchemy.buttons.js +5 -5
  4. data/app/assets/javascripts/alchemy/alchemy.dragndrop.js +1 -1
  5. data/app/assets/javascripts/alchemy/alchemy.element_editor_selector.js +2 -2
  6. data/app/assets/javascripts/alchemy/alchemy.windows.js +1 -1
  7. data/app/assets/stylesheets/alchemy/base.css.scss +22 -13
  8. data/app/assets/stylesheets/alchemy/buttons.css.scss +14 -14
  9. data/app/assets/stylesheets/alchemy/elements.css.scss +79 -46
  10. data/app/controllers/alchemy/admin/elements_controller.rb +1 -1
  11. data/app/helpers/alchemy/admin/base_helper.rb +4 -3
  12. data/app/helpers/alchemy/admin/elements_helper.rb +2 -2
  13. data/app/helpers/alchemy/admin/essences_helper.rb +7 -14
  14. data/app/models/alchemy/element.rb +13 -10
  15. data/app/models/alchemy/message.rb +2 -2
  16. data/app/models/alchemy/page.rb +1 -1
  17. data/app/views/alchemy/admin/clipboard/index.html.erb +4 -3
  18. data/app/views/alchemy/admin/clipboard/insert.js.erb +2 -2
  19. data/app/views/alchemy/admin/contents/create.js.erb +48 -13
  20. data/app/views/alchemy/admin/contents/new.html.erb +1 -1
  21. data/app/views/alchemy/admin/elements/_element.html.erb +1 -1
  22. data/app/views/alchemy/admin/elements/_elements_select.html.erb +1 -1
  23. data/app/views/alchemy/admin/elements/create.js.erb +9 -5
  24. data/app/views/alchemy/admin/elements/fold.js.erb +9 -7
  25. data/app/views/alchemy/admin/elements/trash.js.erb +13 -11
  26. data/app/views/alchemy/admin/elements/update.js.erb +10 -7
  27. data/app/views/alchemy/admin/essence_files/edit.html.erb +1 -1
  28. data/app/views/alchemy/admin/essence_pictures/edit.html.erb +3 -3
  29. data/app/views/alchemy/admin/pages/_contactform_links.html.erb +1 -1
  30. data/app/views/alchemy/admin/pages/_create_language_form.html.erb +1 -1
  31. data/app/views/alchemy/admin/pages/_external_link.html.erb +1 -1
  32. data/app/views/alchemy/admin/pages/_file_link.html.erb +2 -2
  33. data/app/views/alchemy/admin/pages/_internal_link.html.erb +1 -1
  34. data/app/views/alchemy/admin/pages/_new_page_form.html.erb +1 -1
  35. data/app/views/alchemy/admin/partials/_language_tree_select.html.erb +1 -1
  36. data/app/views/alchemy/admin/partials/_upload_form.html.erb +2 -2
  37. data/app/views/alchemy/admin/resources/destroy.js.erb +1 -1
  38. data/app/views/alchemy/admin/users/_table.html.erb +3 -3
  39. data/app/views/alchemy/elements/_contactform_editor.html.erb +1 -4
  40. data/app/views/alchemy/essences/_essence_date_editor.html.erb +2 -3
  41. data/app/views/alchemy/essences/_essence_date_view.html.erb +4 -6
  42. data/app/views/alchemy/essences/_essence_text_editor.html.erb +2 -2
  43. data/app/views/layouts/alchemy/admin.html.erb +1 -1
  44. data/config/alchemy/elements.yml +2 -0
  45. data/config/locales/alchemy.de.yml +8 -3
  46. data/config/locales/alchemy.en.yml +4 -3
  47. data/lib/alchemy/capistrano.rb +6 -6
  48. data/lib/alchemy/essence.rb +9 -4
  49. data/lib/alchemy/version.rb +1 -1
  50. data/spec/helpers/admin/elements_helper_spec.rb +1 -1
  51. data/spec/integration/security_spec.rb +2 -2
  52. data/spec/models/page_spec.rb +28 -1
  53. data/spec/support/alchemy/specs_helpers.rb +1 -1
  54. metadata +33 -34
  55. data/app/views/alchemy/admin/elements/destroy.js.erb +0 -6
data/.travis.yml CHANGED
@@ -1,3 +1,4 @@
1
+ language: ruby
1
2
  bundler_args: --without development
2
3
  rvm:
3
4
  - 1.8.7
@@ -133,7 +133,7 @@ if (typeof(Alchemy) === 'undefined') {
133
133
  setElementSaved : function(selector) {
134
134
  var $element = $(selector);
135
135
  Alchemy.setElementClean(selector);
136
- Alchemy.enableButton(selector + ' button.button');
136
+ Alchemy.enableButton('button.button', $element);
137
137
  },
138
138
 
139
139
  resizeFrame : function() {
@@ -7,17 +7,17 @@ if (typeof(Alchemy) === 'undefined') {
7
7
  $.extend(Alchemy, {
8
8
 
9
9
  ButtonObserver: function (selector) {
10
- $(selector).click(function(event) {
10
+ $(selector).not('.no-spinner').click(function(event) {
11
11
  Alchemy.disableButton(this);
12
12
  });
13
13
  },
14
14
 
15
15
  disableButton: function (button) {
16
16
  var $button = $(button), $clone = $button.clone(), width = $button.outerWidth(), text = $button.text();
17
- $button.hide();
17
+ $button.hide().addClass('disabled');
18
18
  $button.parent().append($clone);
19
19
  $clone.attr({disabled: true, href: 'javascript:void(0)'})
20
- .addClass('disabled cloned-button')
20
+ .addClass('cloned-button')
21
21
  .css({width: width})
22
22
  .html('<img src="/assets/alchemy/ajax_loader.gif" style="width: 16px; height: 16px">')
23
23
  .show();
@@ -25,8 +25,8 @@ if (typeof(Alchemy) === 'undefined') {
25
25
  },
26
26
 
27
27
  enableButton: function (button) {
28
- var $button = $(button);
29
- $button.show();
28
+ var $button = $(button).not('.no-spinner');
29
+ $button.show().removeClass('disabled');
30
30
  $button.parent().find('.cloned-button').remove();
31
31
  return true;
32
32
  }
@@ -22,7 +22,7 @@ if (typeof(Alchemy) === 'undefined') {
22
22
  return $(child).attr('data-element-id');
23
23
  });
24
24
  var params_string = '';
25
- var cell_id = $(event.target).attr('data-cell-id');
25
+ var cell_id = $(this).attr('data-cell-id');
26
26
  // Is the trash window open?
27
27
  if ($('#alchemyTrashWindow').length > 0) {
28
28
  // updating the trash icon
@@ -18,8 +18,8 @@ if (typeof(Alchemy) === 'undefined') {
18
18
  reinit : function(elements) {
19
19
  var self = Alchemy.ElementEditorSelector;
20
20
  var $elements = $(elements);
21
- $elements.each(function () {
22
- self.bindEvent(this, $elements);
21
+ $elements.each(function() {
22
+ self.bindEvent(this);
23
23
  });
24
24
  $elements.find('.element_head').click(self.onClickElement);
25
25
  $elements.find('.element_head').dblclick(function() {
@@ -170,7 +170,7 @@ if (typeof(Alchemy) === 'undefined') {
170
170
  Alchemy.AjaxErrorHandler($dialog, XMLHttpRequest.status, textStatus, errorThrown);
171
171
  },
172
172
  complete: function(jqXHR, textStatus) {
173
- Alchemy.enableButton('.button');
173
+ Alchemy.enableButton('.disabled.button');
174
174
  }
175
175
  });
176
176
  },
@@ -1469,19 +1469,28 @@ div#overlay_toolbar a.button:active {
1469
1469
  margin: 1px 0 0 -12px;
1470
1470
  }
1471
1471
 
1472
- #clipboard_items ul {
1473
- list-style-type: none;
1474
- margin: 0 0 16px;
1475
- padding: 0;
1476
- height: 180px;
1477
- overflow-y: auto;
1478
- overflow-x: hidden;
1479
- }
1480
-
1481
- #clipboard_items ul li {
1482
- padding: $default-padding;
1483
- background: white;
1484
- }
1472
+ #clipboard_items {
1473
+
1474
+ ul {
1475
+ list-style-type: none;
1476
+ margin: 0 0 8px;
1477
+ padding: 0;
1478
+ height: 220px;
1479
+ overflow-y: auto;
1480
+ overflow-x: hidden;
1481
+
1482
+ li {
1483
+ padding: 2*$default-padding;
1484
+ border: $default-border;
1485
+ background-color: white;
1486
+ @include rounded-corner;
1487
+ &.element {
1488
+ background-color: #E5DCCA;
1489
+ border: 1px solid #BBA589;
1490
+ }
1491
+ }
1492
+ }
1493
+ }
1485
1494
 
1486
1495
  .mceEditor table {
1487
1496
  border-spacing: 0 !important;
@@ -1,6 +1,6 @@
1
1
  @import "alchemy/defaults";
2
2
 
3
- a.button.small.disabled img {
3
+ a.button.small.cloned-button img {
4
4
  display: inline-block;
5
5
  float: none;
6
6
  position: relative;
@@ -82,15 +82,15 @@ a.button:active {
82
82
  background-color: #e5e5e5;
83
83
  }
84
84
 
85
- a.button.disabled,
86
- a.button.disabled:hover,
87
- a.button.disabled:active,
88
- input.button.disabled,
89
- input.button.disabled:hover,
90
- input.button.disabled:active,
91
- button.button.disabled,
92
- button.button.disabled:hover,
93
- button.button.disabled:active {
85
+ a.button.cloned-button,
86
+ a.button.cloned-button:hover,
87
+ a.button.cloned-button:active,
88
+ input.button.cloned-button,
89
+ input.button.cloned-button:hover,
90
+ input.button.cloned-button:active,
91
+ button.button.cloned-button,
92
+ button.button.cloned-button:hover,
93
+ button.button.cloned-button:active {
94
94
  color: $text-color;
95
95
  text-shadow: none;
96
96
  border-color: #ccc;
@@ -101,15 +101,15 @@ button.button.disabled:active {
101
101
  line-height: 15px;
102
102
  }
103
103
 
104
- a.button.disabled,
105
- a.button.disabled:hover,
106
- a.button.disabled:active {
104
+ a.button.cloned-button,
105
+ a.button.cloned-button:hover,
106
+ a.button.cloned-button:active {
107
107
  padding: 2px 0 !important;
108
108
  line-height: 13px !important;
109
109
  text-align: center;
110
110
  }
111
111
 
112
- a.button.disabled img {
112
+ a.button.cloned-button img {
113
113
  display: inline-block;
114
114
  float: none;
115
115
  }
@@ -437,6 +437,17 @@ a.icon_button.linked {
437
437
  cursor: default;
438
438
  }
439
439
 
440
+ div.content_editor.essence_date {
441
+ float: none;
442
+ display: inline;
443
+ display: inline-block;
444
+ vertical-align: top;
445
+
446
+ input.date {
447
+ width: 154px;
448
+ }
449
+ }
450
+
440
451
  div.essence_picture_editor {
441
452
  float: left;
442
453
  height: 126px;
@@ -613,12 +624,6 @@ table.content_editor_table {
613
624
  width: 210px;
614
625
  }
615
626
 
616
- div.content_editor label.inline {
617
- display: inline-block;
618
- min-width: 90px;
619
- margin-right: 4px;
620
- }
621
-
622
627
  a.new_content_link {
623
628
  float: none;
624
629
  display: inline-block;
@@ -649,10 +654,6 @@ div.content_text_editor.text_short {
649
654
  display: inline;
650
655
  }
651
656
 
652
- div.content_editor input.thin_border {
653
- width: 97%;
654
- }
655
-
656
657
  input.long,
657
658
  input.text_long {
658
659
  width: 363px;
@@ -671,53 +672,85 @@ div.content_text_editor input.text_short {
671
672
  padding: 2px;
672
673
  }
673
674
 
675
+ #alchemy .ui-dialog-content div.content_editor input.auto_resize {
676
+ width: 100%;
677
+ }
678
+
679
+ // div.element_content {
680
+ // white-space: nowrap;
681
+
682
+ // p, div {
683
+ // white-space: normal;
684
+ // }
685
+ // }
686
+
674
687
  div.content_editor {
675
688
  margin-bottom: 8px;
676
689
  margin-top: 8px;
677
690
  position: relative;
678
- }
679
691
 
680
- div.content_editor.missing p {
681
- line-height: 25px;
682
- padding: 2*$default-padding;
683
- border: 1px solid #f5b04e;
684
- background-color: #f5dea9;
685
- @include rounded-corner;
686
- font-size: 11px;
687
- }
692
+ input.thin_border {
693
+ width: 97%;
694
+ }
688
695
 
689
- div.content_editor.missing p span.icon.warning {
690
- position: relative;
691
- top: 2px;
692
- left: 2px;
693
- margin-right: 8px;
694
- }
696
+ &.missing p {
697
+ line-height: 25px;
698
+ padding: 2*$default-padding;
699
+ border: 1px solid #f5b04e;
700
+ background-color: #f5dea9;
701
+ @include rounded-corner;
702
+ font-size: 11px;
703
+
704
+ span.icon.warning {
705
+ position: relative;
706
+ top: 2px;
707
+ left: 2px;
708
+ margin-right: 8px;
709
+ }
710
+ }
695
711
 
696
- #alchemy .ui-dialog-content div.content_editor input.auto_resize {
697
- width: 100%;
698
- }
712
+ &.display_inline {
713
+ display: inline;
714
+ display: inline-block;
715
+ margin-right: 4px;
716
+ vertical-align: top;
717
+
718
+ input.thin_border {
719
+ width: 170px;
720
+ }
721
+ }
699
722
 
700
- div.content_editor.validation_failed label {
701
- color: #931f23;
702
- }
723
+ &.validation_failed {
703
724
 
704
- div.content_editor.validation_failed input {
705
- border: 1px solid #931f23;
706
- background-color: #f9e8e9;
707
- }
725
+ label {
726
+ color: #931f23;
727
+ }
708
728
 
709
- div.content_editor label {
710
- display: block;
711
- margin-bottom: 0.5em;
712
- font-size: 10px;
713
- text-shadow: #fff5e1 1px 1px 0;
714
- line-height: 15px;
715
- text-indent: 1px;
716
- }
729
+ input {
730
+ border: 1px solid #931f23;
731
+ background-color: #f9e8e9;
732
+ }
733
+ }
717
734
 
718
- div.content_editor label span.warning.icon {
719
- position: relative;
720
- top: 2px;
735
+ label {
736
+ display: block;
737
+ margin-bottom: 0.5em;
738
+ font-size: 10px;
739
+ text-shadow: #fff5e1 1px 1px 0;
740
+ line-height: 15px;
741
+ text-indent: 1px;
742
+
743
+ span.warning.icon {
744
+ position: relative;
745
+ top: 2px;
746
+ }
747
+
748
+ &.inline {
749
+ display: inline-block;
750
+ min-width: 90px;
751
+ margin-right: 4px;
752
+ }
753
+ }
721
754
  }
722
755
 
723
756
  .element_editor div.error {
@@ -70,7 +70,7 @@ module Alchemy
70
70
  else
71
71
  @element_validated = false
72
72
  @notice = t('Validation failed')
73
- @error_message = "<h2>#{@notice}</h2><p>#{t('Please check contents below.')}</p>".html_safe
73
+ @error_message = "<h2>#{@notice}</h2><p>#{t(:content_validations_headline)}</p>".html_safe
74
74
  end
75
75
  end
76
76
 
@@ -189,7 +189,8 @@ module Alchemy
189
189
  select_options = options_for_select(select_options, content.essence.content)
190
190
  select_tag(
191
191
  "contents[content_#{content.id}]",
192
- select_options
192
+ select_options,
193
+ :class => 'alchemy_selectbox'
193
194
  )
194
195
  end
195
196
 
@@ -301,13 +302,13 @@ module Alchemy
301
302
  def clipboard_select_tag(items, html_options = {})
302
303
  options = [[t('Please choose'), ""]]
303
304
  items.each do |item|
304
- options << [item.class.to_s == 'Element' ? item.display_name_with_preview_text : item.name, item.id]
305
+ options << [item.class.to_s == 'Alchemy::Element' ? item.display_name_with_preview_text : item.name, item.id]
305
306
  end
306
307
  select_tag(
307
308
  'paste_from_clipboard',
308
309
  !@page.new_record? && @page.can_have_cells? ? grouped_elements_for_select(items, :id) : options_for_select(options),
309
310
  {
310
- :class => html_options[:class],
311
+ :class => [html_options[:class], 'alchemy_selectbox'].join(' '),
311
312
  :style => html_options[:style]
312
313
  }
313
314
  )
@@ -99,14 +99,14 @@ module Alchemy
99
99
  end
100
100
 
101
101
  def element_array_for_options(e, object_method, cell = nil)
102
- if e.class.name == 'Element'
102
+ if e.class.name == 'Alchemy::Element'
103
103
  [
104
104
  e.display_name_with_preview_text,
105
105
  e.send(object_method).to_s + (cell ? "##{cell['name']}" : "")
106
106
  ]
107
107
  else
108
108
  [
109
- t(e['name'], :scope => :element_names),
109
+ Alchemy::I18n.t(e['name'], :scope => :element_names),
110
110
  e[object_method] + (cell ? "##{cell['name']}" : "")
111
111
  ]
112
112
  end
@@ -78,28 +78,21 @@ module Alchemy
78
78
  end
79
79
 
80
80
  # Renders the EssenceText editor partial with a form select for storing page urlnames
81
- # Options:
82
- # * element - element the Content find via content_name to store the pages urlname in.
83
- # * content_name - the name of the content from element to store the pages urlname in.
84
- # * options (Hash)
85
- # ** :only (Hash) - pass page_layout names to :page_layout => [""] so only pages with this page_layout will be displayed inside the select.
86
- # ** :except (Hash) - pass page_layout names to :page_layout => [""] so all pages except these with this page_layout will be displayed inside the select.
87
- # ** :page_attribute (Symbol) - The Page attribute which will be stored.
81
+ #
82
+ # === Options:
83
+ #
84
+ # :only [Hash] # Pagelayout names. Only pages with this page_layout will be displayed inside the select.
85
+ # :page_attribute [Symbol] # The Page attribute which will be stored.
86
+ #
88
87
  def page_selector(element, content_name, options = {}, select_options = {})
89
88
  default_options = {
90
- :except => {
91
- :page_layout => [""]
92
- },
93
- :only => {
94
- :page_layout => [""]
95
- },
96
89
  :page_attribute => :id,
97
90
  :prompt => t('Choose page')
98
91
  }
99
92
  options = default_options.merge(options)
100
93
  pages = Page.where({
101
94
  :language_id => session[:language_id],
102
- :page_layout => options[:only][:page_layout],
95
+ :page_layout => options[:only],
103
96
  :public => true
104
97
  })
105
98
  content = element.content_by_name(content_name)
@@ -372,7 +372,7 @@ module Alchemy
372
372
  end
373
373
 
374
374
  def has_ingredient?(name)
375
- !self.ingredient(name).blank?
375
+ self.ingredient(name).present?
376
376
  end
377
377
 
378
378
  def save_contents(params)
@@ -400,14 +400,17 @@ module Alchemy
400
400
  def essence_errors
401
401
  essence_errors = {}
402
402
  essences.each do |essence|
403
- unless essence.essence_errors.blank?
404
- essence_errors[essence.content.name] = essence.essence_errors
403
+ unless essence.errors.blank?
404
+ essence_errors[essence.content.name] = essence.validation_errors
405
405
  end
406
406
  end
407
407
  essence_errors
408
408
  end
409
409
 
410
- # Essence validation errors messages are translated via ::I18n.
410
+ # Essence validation errors
411
+ #
412
+ # Messages are translated via I18n.
413
+ #
411
414
  # Inside your translation file add translations like:
412
415
  #
413
416
  # alchemy:
@@ -422,12 +425,12 @@ module Alchemy
422
425
  # * taken
423
426
  # * wrong_format
424
427
  #
425
- # Example:
428
+ # === Example:
426
429
  #
427
430
  # de:
428
431
  # alchemy:
429
432
  # content_validations:
430
- # contact:
433
+ # contactform:
431
434
  # email:
432
435
  # wrong_format: 'Die Email hat nicht das richtige Format'
433
436
  #
@@ -435,11 +438,11 @@ module Alchemy
435
438
  messages = []
436
439
  essence_errors.each do |content_name, errors|
437
440
  errors.each do |error|
438
- messages << I18n.t(
439
- "content_validations.#{self.name}.#{content_name}.#{error}",
441
+ messages << I18n.t(error,
442
+ :scope => [:content_validations, self.name, content_name],
440
443
  :default => [
441
- "content_validations.fields.#{content_name}.#{error}".to_sym,
442
- "content_validations.errors.#{error}".to_sym
444
+ "alchemy.content_validations.fields.#{content_name}.#{error}".to_sym,
445
+ "alchemy.content_validations.errors.#{error}".to_sym
443
446
  ],
444
447
  :field => Content.translated_label_for(content_name)
445
448
  )