alchemy_cms 3.0.0 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/README.md +3 -6
  4. data/alchemy_cms.gemspec +1 -1
  5. data/app/assets/stylesheets/alchemy/buttons.scss +4 -4
  6. data/app/assets/stylesheets/alchemy/sitemap.scss +1 -1
  7. data/app/controllers/alchemy/pages_controller.rb +5 -5
  8. data/app/helpers/alchemy/admin/elements_helper.rb +3 -3
  9. data/app/helpers/alchemy/admin/navigation_helper.rb +2 -1
  10. data/app/models/alchemy/cell.rb +1 -1
  11. data/app/models/alchemy/element.rb +10 -0
  12. data/app/models/alchemy/page/page_naming.rb +10 -3
  13. data/app/models/alchemy/picture.rb +6 -2
  14. data/app/views/alchemy/admin/pages/_page.html.erb +1 -1
  15. data/app/views/alchemy/admin/pages/edit.html.erb +1 -1
  16. data/app/views/alchemy/admin/pages/info.html.erb +10 -1
  17. data/app/views/alchemy/base/leave.html.erb +1 -1
  18. data/config/locales/alchemy.de.yml +1 -1
  19. data/config/locales/alchemy.en.yml +3 -3
  20. data/config/locales/alchemy.fr.yml +1 -1
  21. data/config/locales/alchemy.nl.yml +1 -1
  22. data/lib/alchemy/test_support/factories.rb +4 -4
  23. data/lib/alchemy/version.rb +1 -1
  24. data/lib/rails/generators/alchemy/essence/essence_generator.rb +1 -1
  25. data/lib/rails/generators/alchemy/essence/templates/editor.html.erb +1 -1
  26. data/spec/features/page_feature_spec.rb +20 -0
  27. data/spec/helpers/admin/elements_helper_spec.rb +11 -2
  28. data/spec/helpers/admin/navigation_helper_spec.rb +30 -0
  29. data/spec/models/element_spec.rb +27 -4
  30. data/spec/models/page_spec.rb +10 -7
  31. data/spec/models/picture_spec.rb +19 -0
  32. data/vendor/assets/javascripts/tinymce/langs/fr.js +184 -0
  33. metadata +5 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 611a1e37fe56a17099be81544930085f61508212
4
- data.tar.gz: cd2ec040d0c1099bd916761ff305f976b20c7908
3
+ metadata.gz: 22899ddac5bccee25b1e3438bcec28374381edc6
4
+ data.tar.gz: 92792959062f3873ff293a491a7c981e83ed2797
5
5
  SHA512:
6
- metadata.gz: 7345ebd721ad3d3823c25d0ea98f768684fd8187df860bba180967060a272d7f03a08b0c7d0b68bf610d38da1a268909857f080b0bb9196be2322fd61d615f58
7
- data.tar.gz: c957bfb8d7512694346a4213c91c7e0714365ad1593dd34ecf9252937b2767f258792f45f6b543862a143a0fa2f4d41e353bf596f2e59c7fd6dc26ec746cbb1d
6
+ metadata.gz: ec3084ada69925e12a6458ed3768d4f63e23c3b20def9ebe63543946b05ad3d4288fd040ef20c88fa2857a0c123daa8462ef2f87d2facaa8b78ff7dd4926eea7
7
+ data.tar.gz: 8f0f74f54d0b903c5d02c445107ea8358927c5faa2ff4ab30ac37f0b1612f92ef63ed00d9b4bdbe6cb856200d43664e82754e4d197200a044fe84e797b8dc2c3
@@ -5,7 +5,7 @@ rvm:
5
5
  - 2.1
6
6
  branches:
7
7
  only:
8
- - master
8
+ - 3.0-stable
9
9
  script: rake
10
10
  env:
11
11
  - DB=mysql
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  ![Alchemy CMS](http://alchemy-cms.com/assets/alchemy_logo.svg)
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/alchemy_cms.png)](http://badge.fury.io/rb/alchemy_cms)
4
- [![Build Status](https://travis-ci.org/magiclabs/alchemy_cms.svg?branch=master)](https://travis-ci.org/magiclabs/alchemy_cms) [![Code Climate](https://codeclimate.com/github/magiclabs/alchemy_cms.png)](https://codeclimate.com/github/magiclabs/alchemy_cms) [![Coverage Status](https://coveralls.io/repos/magiclabs/alchemy_cms/badge.png?branch=master)](https://coveralls.io/r/magiclabs/alchemy_cms?branch=master)
4
+ [![Build Status](https://travis-ci.org/magiclabs/alchemy_cms.svg?branch=3.0-stable)](https://travis-ci.org/magiclabs/alchemy_cms) [![Code Climate](https://codeclimate.com/github/magiclabs/alchemy_cms.png)](https://codeclimate.com/github/magiclabs/alchemy_cms) [![Coverage Status](https://coveralls.io/repos/magiclabs/alchemy_cms/badge.png?branch=3.0-stable)](https://coveralls.io/r/magiclabs/alchemy_cms?branch=3.0-stable)
5
5
 
6
6
  About
7
7
  -----
@@ -10,9 +10,6 @@ Alchemy is the most powerful, userfriendly and flexible Rails CMS.
10
10
 
11
11
  Read more on the [website](http://alchemy-cms.com) and in the [guidelines](http://guides.alchemy-cms.com).
12
12
 
13
- **This master branch is a development branch that can contain bugs. For productive environments you should use the [current Ruby gem version](http://rubygems.org/gems/alchemy_cms/versions/3.0.0),
14
- or the [latest stable branch (3.0-stable)](https://github.com/magiclabs/alchemy_cms/tree/3.0-stable).**
15
-
16
13
  Features
17
14
  --------
18
15
 
@@ -60,7 +57,7 @@ Installation
60
57
 
61
58
  #### 1. Use the installer:
62
59
 
63
- gem install alchemy_cms --pre
60
+ gem install alchemy_cms
64
61
  alchemy new my_magicpage
65
62
  cd my_magicpage
66
63
 
@@ -84,7 +81,7 @@ Open `http://localhost:3000` and follow the on screen instructions.
84
81
 
85
82
  In your App's Gemfile:
86
83
 
87
- gem 'alchemy_cms', github: 'magiclabs/alchemy_cms', branch: 'master'
84
+ gem 'alchemy_cms', github: 'magiclabs/alchemy_cms', branch: '3.0-stable'
88
85
 
89
86
  #### 2. Install Alchemy into your app:
90
87
 
@@ -25,7 +25,7 @@ Gem::Specification.new do |gem|
25
25
  gem.add_runtime_dependency 'acts-as-taggable-on', '~> 3.1'
26
26
  gem.add_runtime_dependency 'cancan', '~> 1.6.10'
27
27
  gem.add_runtime_dependency 'dragonfly', '~> 1.0.1'
28
- gem.add_runtime_dependency 'kaminari', '~> 0.15.0'
28
+ gem.add_runtime_dependency 'kaminari', '~> 0.15'
29
29
  gem.add_runtime_dependency 'acts_as_list', '~> 0.3.0'
30
30
  gem.add_runtime_dependency 'magiclabs-userstamp', '~> 2.1.0'
31
31
  gem.add_runtime_dependency 'simple_form', '~> 3.0.1'
@@ -117,12 +117,12 @@ button, input[type="submit"], a.button, input.button {
117
117
  border: $default-border-width $default-border-style $button-hover-border-color;
118
118
  @include border-radius($default-border-radius);
119
119
  background: $button-hover-bg-color;
120
- top: 0px;
121
- right: 0px;
120
+ top: -1px;
121
+ right: -1px;
122
122
 
123
123
  .icon {
124
- left: 0px;
125
- top: 2px;
124
+ left: 1px;
125
+ top: 3px;
126
126
  }
127
127
  }
128
128
  }
@@ -262,7 +262,7 @@ div.page_infos {
262
262
  }
263
263
 
264
264
  .alchemy-dialog .page_status {
265
- margin: 4px 4px 0 0;
265
+ margin: 2px 4px 0 0;
266
266
  }
267
267
 
268
268
  #sitemap {
@@ -8,20 +8,20 @@ module Alchemy
8
8
 
9
9
  rescue_from ActionController::RoutingError, :with => :render_404
10
10
 
11
- before_filter :enforce_primary_host_for_site
12
- before_filter :render_page_or_redirect, :only => [:show]
13
- before_filter :load_page
14
- authorize_resource only: 'show'
11
+ before_action :enforce_primary_host_for_site
12
+ before_action :render_page_or_redirect, only: [:show]
15
13
 
16
14
  # Showing page from params[:urlname]
17
15
  #
18
16
  def show
17
+ authorize! :show, @page
18
+
19
19
  if render_fresh_page?
20
20
  respond_to do |format|
21
21
  format.html { render layout: !request.xhr? }
22
22
  format.rss do
23
23
  if @page.contains_feed?
24
- render action: 'show', layout: false, handlers: [:builder]
24
+ render layout: false, handlers: [:builder]
25
25
  else
26
26
  render xml: {error: 'Not found'}, status: 404
27
27
  end
@@ -72,12 +72,12 @@ module Alchemy
72
72
  end
73
73
  other_elements = elements - celled_elements
74
74
  unless other_elements.blank?
75
- optgroup_label = _t(:main_content)
76
- options[optgroup_label] = other_elements.map do |e|
75
+ options[_t(:main_content)] = other_elements.map do |e|
77
76
  element_array_for_options(e, object_method)
78
77
  end
79
78
  end
80
- options
79
+ # We don't want to show empty cells
80
+ options.delete_if { |cell, elements| elements.blank? }
81
81
  end
82
82
 
83
83
  def element_array_for_options(e, object_method, cell = nil)
@@ -163,7 +163,8 @@ module Alchemy
163
163
  {
164
164
  controller: entry['controller'],
165
165
  action: entry['action'],
166
- only_path: true
166
+ only_path: true,
167
+ params: entry['params']
167
168
  }
168
169
  end
169
170
 
@@ -19,7 +19,7 @@
19
19
  #
20
20
  # Render cells with the +render_cell+ helper
21
21
  #
22
- # Views for cells are inside the +app/views/cells+ folder in you project.
22
+ # Views for cells are inside the +app/views/cells+ folder in your project.
23
23
  #
24
24
  module Alchemy
25
25
  class Cell < ActiveRecord::Base
@@ -47,6 +47,7 @@ module Alchemy
47
47
 
48
48
  after_create :create_contents, :unless => proc { |e| e.create_contents_after_create == false }
49
49
  after_update :touch_pages
50
+ after_update :touch_cell, unless: -> { self.cell.nil? }
50
51
 
51
52
  scope :trashed, -> { where(position: nil).order('updated_at DESC') }
52
53
  scope :not_trashed, -> { where(Element.arel_table[:position].not_eq(nil)) }
@@ -461,5 +462,14 @@ module Alchemy
461
462
  available_page_cells(page).collect(&:name).uniq
462
463
  end
463
464
 
465
+ # If element has a +cell+ associated,
466
+ # it updates it's timestamp.
467
+ #
468
+ # Called after_update
469
+ #
470
+ def touch_cell
471
+ self.cell.touch
472
+ end
473
+
464
474
  end
465
475
  end
@@ -72,11 +72,11 @@ module Alchemy
72
72
  def set_urlname
73
73
  if Config.get(:url_nesting)
74
74
  url_name = [
75
- parent.nil? || parent.language_root? ? nil : parent.urlname,
76
- convert_url_name((urlname.blank? ? name : slug))
75
+ parent_urlname,
76
+ convert_url_name(urlname.blank? ? name : slug)
77
77
  ].compact.join('/')
78
78
  else
79
- url_name = convert_url_name((urlname.blank? ? name : urlname))
79
+ url_name = convert_url_name(urlname.blank? ? name : urlname)
80
80
  end
81
81
  write_attribute :urlname, url_name
82
82
  end
@@ -98,5 +98,12 @@ module Alchemy
98
98
  url_name
99
99
  end
100
100
  end
101
+
102
+ # Urlname of parent page.
103
+ # Returns nil, if the parent is either a language root page or the root page itself
104
+ def parent_urlname
105
+ return if parent.nil? || parent.language_root? || parent.root?
106
+ parent.urlname
107
+ end
101
108
  end
102
109
  end
@@ -39,9 +39,13 @@ module Alchemy
39
39
  raise PictureInUseError, I18n.t(:cannot_delete_picture_notice) % { name: name }
40
40
  end
41
41
 
42
+ # Enables Dragonfly image processing
42
43
  dragonfly_accessor :image_file, app: :alchemy_pictures do
43
- if Config.get(:preprocess_image_resize).present?
44
- after_assign { |a| a.process!(:resize, "#{Config.get(:preprocess_image_resize)}>") }
44
+ # Preprocess after uploading the picture
45
+ after_assign do |p|
46
+ if Config.get(:preprocess_image_resize).present?
47
+ p.thumb!("#{Config.get(:preprocess_image_resize)}>")
48
+ end
45
49
  end
46
50
  end
47
51
 
@@ -12,7 +12,7 @@
12
12
  alchemy.info_admin_page_path(page),
13
13
  {
14
14
  title: _t(:page_infos),
15
- size: '480x290'
15
+ size: '520x290'
16
16
  },
17
17
  {
18
18
  title: _t(:page_infos),
@@ -32,7 +32,7 @@
32
32
  alchemy.info_admin_page_path(@page),
33
33
  {
34
34
  title: _t(:page_infos),
35
- size: '480x320'
35
+ size: '520x320'
36
36
  },
37
37
  {
38
38
  class: 'icon_button',
@@ -5,9 +5,18 @@
5
5
  <% end %>
6
6
  <% end %>
7
7
  <div class="value">
8
- <label><%= _t(:page_type) %></label>
8
+ <label><%= Alchemy::Page.human_attribute_name(:page_layout) %></label>
9
9
  <p><%= @page.layout_display_name %></p>
10
10
  </div>
11
+ <div class="value">
12
+ <% if @page.redirects_to_external? %>
13
+ <label><%= Alchemy::Page.human_attribute_name(:urlname) %></label>
14
+ <p><%= @page.urlname %></p>
15
+ <% else %>
16
+ <label><%= Alchemy::LegacyPageUrl.human_attribute_name(:urlname) %></label>
17
+ <p><%= "/#{@page.urlname}" %></p>
18
+ <% end %>
19
+ </div>
11
20
  <div class="value">
12
21
  <label><%= _t(:page_status) %></label>
13
22
  <p><%= combined_page_status(@page) %></p>
@@ -6,6 +6,6 @@
6
6
  <%= link_to _t('stay logged in'), alchemy.root_path, class: 'button' %>
7
7
  </p>
8
8
  <%= form_tag Alchemy.logout_path, method: 'delete', class: 'buttons' do %>
9
- <label><%= _t('or to completly') %></label>
9
+ <label><%= _t('or to completely') %></label>
10
10
  <%= button _t(:logout), autofocus: true %>
11
11
  <% end %>
@@ -579,7 +579,7 @@ de:
579
579
  "You are about to leave Alchemy": "Sie sind dabei Alchemy zu verlassen"
580
580
  "Do you want to": "Wollen Sie dabei"
581
581
  "stay logged in": "angemeldet bleiben"
582
- "or to completly": "oder Sich komplett"
582
+ "or to completely": "oder Sich komplett"
583
583
  "Are you sure?": "Sind Sie sicher?"
584
584
  "Create": "Hinzufügen"
585
585
  "Edit": "Bearbeiten"
@@ -201,7 +201,7 @@ en:
201
201
  "Hide Elements": "Hide Elements"
202
202
  "If you have any problems using the Flash uploader you can switch to": "If you have any problems using the Flash uploader you can switch to %{link}"
203
203
  "Image missing": "Image missing"
204
- "Image size": "Imagesize"
204
+ "Image size": "Image size"
205
205
  "Language successfully created": "Language successfully created."
206
206
  "Language successfully removed": "Language successfully removed."
207
207
  "Language successfully updated": "Language successfully updated."
@@ -244,7 +244,7 @@ en:
244
244
  "Please enter a new password": "Please enter a new password."
245
245
  "Please enter your email address": "Please enter your email address."
246
246
  "Please log in": "Please log in."
247
- "Please seperate the tags with commata": "* Please seperate the tags with commata."
247
+ "Please seperate the tags with commata": "* Please seperate the tags with commas."
248
248
  "Properties": "Properties"
249
249
  "Publish page": "Publish page"
250
250
  "Read the License": "Read the License"
@@ -579,7 +579,7 @@ en:
579
579
  "You are about to leave Alchemy": "You are about to leave Alchemy"
580
580
  "Do you want to": "Do you want to"
581
581
  "stay logged in": "stay logged in"
582
- "or to completly": "or to completly"
582
+ "or to completely": "or to completely"
583
583
  "Are you sure?": "Are you sure?"
584
584
  "Create": "Create"
585
585
  "Edit": "Edit"
@@ -605,7 +605,7 @@ fr:
605
605
  "You are about to leave Alchemy": "Vous êtes sur le point de quitter l'Alchimie"
606
606
  "Do you want to": "Voulez-vous "
607
607
  "stay logged in": "rester connecté"
608
- "or to completly": "ou vous-même complètement"
608
+ "or to completely": "ou vous-même complètement"
609
609
  "Please wait. Flash® is loading...": "S'il vous plaît attendre. Uploader Flash ® est en cours de chargement..."
610
610
  "Are you sure?": "Etes-vous sûr?"
611
611
  "Create": "ajouter"
@@ -579,7 +579,7 @@ nl:
579
579
  "You are about to leave Alchemy": "U staat op het punt de NVM Regiosite te verlaten"
580
580
  "Do you want to": "Wilt u"
581
581
  "stay logged in": "ingelogd blijven"
582
- "or to completly": "of compleet"
582
+ "or to completely": "of compleet"
583
583
  "Are you sure?": "Weet u het zeker?"
584
584
  "Create": "Aanmaken"
585
585
  "Edit": "Aanpassen"
@@ -5,19 +5,19 @@ FactoryGirl.define do
5
5
  password 's3cr3t'
6
6
 
7
7
  factory :admin_user do
8
- alchemy_roles 'admin'
8
+ alchemy_roles ['admin']
9
9
  end
10
10
 
11
11
  factory :member_user do
12
- alchemy_roles 'member'
12
+ alchemy_roles ['member']
13
13
  end
14
14
 
15
15
  factory :author_user do
16
- alchemy_roles 'author'
16
+ alchemy_roles ['author']
17
17
  end
18
18
 
19
19
  factory :editor_user do
20
- alchemy_roles 'editor'
20
+ alchemy_roles ['editor']
21
21
  end
22
22
  end
23
23
 
@@ -1,5 +1,5 @@
1
1
  module Alchemy
2
- VERSION = "3.0.0"
2
+ VERSION = "3.0.1"
3
3
 
4
4
  def self.version
5
5
  VERSION
@@ -36,7 +36,7 @@ CLASSMETHOD
36
36
  end
37
37
 
38
38
  def copy_templates
39
- essence_name = @essence_name.classify.demodulize
39
+ essence_name = @essence_name.classify.demodulize.underscore
40
40
  template "view.html.erb", "#{@essence_view_path}/_#{essence_name}_view.html.erb"
41
41
  template "editor.html.erb", "#{@essence_view_path}/_#{essence_name}_editor.html.erb"
42
42
  end
@@ -6,7 +6,7 @@
6
6
  Please consult Alchemy::Content.rb docs for further methods on the content object
7
7
  %>
8
8
  <%% cache(content) do %>
9
- <div class="content_editor <%= @essence_name.classify.demodulize %>" id="<%%= content.dom_id %>">
9
+ <div class="content_editor <%= @essence_name.classify.demodulize.underscore %>" id="<%%= content.dom_id %>" data-content-id="<%%= content.id %>">
10
10
  <%%= label_and_remove_link(content) %>
11
11
  <%%= text_field_tag(
12
12
  content.form_field_name,
@@ -234,5 +234,25 @@ module Alchemy
234
234
  end
235
235
  end
236
236
 
237
+ describe 'accessing restricted pages' do
238
+ let!(:restricted_page) { create(:restricted_page, public: true) }
239
+
240
+ context 'as a guest user' do
241
+ it "I am not able to visit the page" do
242
+ visit restricted_page.urlname
243
+ current_path.should == Alchemy.login_path
244
+ end
245
+ end
246
+
247
+ context 'as a member user' do
248
+ before { authorize_as_admin(create(:member_user)) }
249
+
250
+ it "I am able to visit the page" do
251
+ visit restricted_page.urlname
252
+ current_path.should == "/#{restricted_page.urlname}"
253
+ end
254
+ end
255
+ end
256
+
237
257
  end
238
258
  end
@@ -26,8 +26,11 @@ module Alchemy
26
26
  }
27
27
 
28
28
  before do
29
- page.stub(layout_description: {'name' => "foo", 'cells' => ["foo_cell"]})
30
- cell_descriptions = [{'name' => "foo_cell", 'elements' => ["1", "2"]}]
29
+ page.stub(layout_description: {'name' => "foo", 'cells' => ["foo_cell", "empty_cell"]})
30
+ cell_descriptions = [
31
+ {'name' => "foo_cell", 'elements' => ["1", "2"]},
32
+ {'name' => 'empty_cell', 'elements' => []}
33
+ ]
31
34
  Cell.stub(:definitions).and_return(cell_descriptions)
32
35
  helper.instance_variable_set('@page', page)
33
36
  end
@@ -48,6 +51,12 @@ module Alchemy
48
51
  helper.grouped_elements_for_select(elements).should == ""
49
52
  end
50
53
  end
54
+
55
+ context "with cell having no elements" do
56
+ it "should remove that cell from hash" do
57
+ expect(helper.grouped_elements_for_select(elements)['Empty cell']).to be_nil
58
+ end
59
+ end
51
60
  end
52
61
 
53
62
  describe "#elements_for_select" do
@@ -27,6 +27,24 @@ describe Alchemy::Admin::NavigationHelper do
27
27
  }
28
28
  } }
29
29
 
30
+ let(:event_module_with_params) { {
31
+ 'navigation' => {
32
+ 'controller' => '/admin/events',
33
+ 'action' => 'index',
34
+ 'params' => {
35
+ 'key' => 'value'
36
+ },
37
+ 'sub_navigation' => [{
38
+ 'controller' => '/admin/events',
39
+ 'action' => 'index',
40
+ 'params' => {
41
+ 'key' => 'value',
42
+ 'key2' => 'value2'
43
+ }
44
+ }]
45
+ }
46
+ } }
47
+
30
48
  let(:navigation) { alchemy_module['navigation'] }
31
49
 
32
50
  describe '#alchemy_main_navigation_entry' do
@@ -180,6 +198,10 @@ describe Alchemy::Admin::NavigationHelper do
180
198
  it "returns correct url string" do
181
199
  helper.url_for_module(event_module).should == '/admin/events'
182
200
  end
201
+
202
+ it "returns correct url string with params" do
203
+ helper.url_for_module(event_module_with_params).should == '/admin/events?key=value'
204
+ end
183
205
  end
184
206
  end
185
207
 
@@ -209,6 +231,14 @@ describe Alchemy::Admin::NavigationHelper do
209
231
  end
210
232
  end
211
233
 
234
+ context "with module within host app with params" do
235
+ let(:current_module) { event_module_with_params }
236
+
237
+ it "returns correct url string with params" do
238
+ should == '/admin/events?key2=value2&key=value'
239
+ end
240
+ end
241
+
212
242
  context 'without module found' do
213
243
  before do
214
244
  helper.stub(module_definition_for: nil)
@@ -422,16 +422,20 @@ module Alchemy
422
422
  end
423
423
 
424
424
  describe '.after_update' do
425
+ let(:page) { create(:page) }
426
+ let(:element) { create(:element, page: page) }
427
+ let(:now) { Time.now }
428
+
429
+ before do
430
+ Time.stub(now: now)
431
+ end
432
+
425
433
  context 'with touchable pages' do
426
434
  let(:locker) { mock_model('DummyUser') }
427
- let(:page) { create(:page) }
428
- let(:element) { create(:element, page: page) }
429
- let(:now) { Time.now }
430
435
  let(:pages) { [page] }
431
436
 
432
437
  before do
433
438
  Alchemy.user_class.stub(:stamper).and_return(locker.id)
434
- Time.stub(now: now)
435
439
  end
436
440
 
437
441
  it "updates page timestamps" do
@@ -446,6 +450,25 @@ module Alchemy
446
450
  page.updater_id.should eq(locker.id)
447
451
  end
448
452
  end
453
+
454
+ context 'with cell associated' do
455
+ let(:cell) { mock_model('Cell') }
456
+
457
+ before do
458
+ element.stub(cell: cell)
459
+ end
460
+
461
+ it "updates timestamp of cell" do
462
+ element.cell.should_receive(:touch)
463
+ element.save
464
+ end
465
+ end
466
+
467
+ context 'without cell associated' do
468
+ it "does not update timestamp of cell" do
469
+ expect { element.save }.to_not raise_error
470
+ end
471
+ end
449
472
  end
450
473
 
451
474
  describe '#taggable?' do
@@ -1203,12 +1203,13 @@ module Alchemy
1203
1203
  end
1204
1204
 
1205
1205
  context 'urlname updating' do
1206
- let(:parentparent) { FactoryGirl.create(:page, name: 'parentparent', visible: true) }
1207
- let(:parent) { FactoryGirl.create(:page, parent_id: parentparent.id, name: 'parent', visible: true) }
1208
- let(:page) { FactoryGirl.create(:page, parent_id: parent.id, name: 'page', visible: true) }
1209
- let(:invisible) { FactoryGirl.create(:page, parent_id: page.id, name: 'invisible', visible: false) }
1210
- let(:contact) { FactoryGirl.create(:page, parent_id: invisible.id, name: 'contact', visible: true) }
1211
- let(:external) { FactoryGirl.create(:page, parent_id: parent.id, name: 'external', page_layout: 'external', urlname: 'http://google.com') }
1206
+ let(:parentparent) { FactoryGirl.create(:page, name: 'parentparent', visible: true) }
1207
+ let(:parent) { FactoryGirl.create(:page, parent_id: parentparent.id, name: 'parent', visible: true) }
1208
+ let(:page) { FactoryGirl.create(:page, parent_id: parent.id, name: 'page', visible: true) }
1209
+ let(:invisible) { FactoryGirl.create(:page, parent_id: page.id, name: 'invisible', visible: false) }
1210
+ let(:contact) { FactoryGirl.create(:page, parent_id: invisible.id, name: 'contact', visible: true) }
1211
+ let(:external) { FactoryGirl.create(:page, parent_id: parent.id, name: 'external', page_layout: 'external', urlname: 'http://google.com') }
1212
+ let(:language_root) { parentparent.parent }
1212
1213
 
1213
1214
  context "with activated url_nesting" do
1214
1215
  before { Config.stub(:get).and_return(true) }
@@ -1218,7 +1219,9 @@ module Alchemy
1218
1219
  end
1219
1220
 
1220
1221
  it "should not include the root page" do
1221
- page.urlname.should_not =~ /root/
1222
+ Page.root.update_column(:urlname, 'root')
1223
+ language_root.update(urlname: 'new-urlname')
1224
+ language_root.urlname.should_not =~ /root/
1222
1225
  end
1223
1226
 
1224
1227
  it "should not include the language root page" do
@@ -32,6 +32,25 @@ module Alchemy
32
32
  picture.should be_valid
33
33
  end
34
34
 
35
+ context 'with enabled preprocess_image_resize config option' do
36
+ let(:image_file) do
37
+ File.new(File.expand_path('../../fixtures/80x60.png', __FILE__))
38
+ end
39
+
40
+ before do
41
+ Config.stub(:get) do |arg|
42
+ if arg == :preprocess_image_resize
43
+ '10x10'
44
+ end
45
+ end
46
+ end
47
+
48
+ it "it resizes the image after upload" do
49
+ picture = Picture.new(image_file: image_file)
50
+ expect(picture.image_file.data[0x10..0x18].unpack('NN')).to eq([10, 8])
51
+ end
52
+ end
53
+
35
54
  describe '#suffix' do
36
55
  it "should return the suffix of original filename" do
37
56
  pic = stub_model(Picture, image_file_name: 'kitten.JPG')
@@ -0,0 +1,184 @@
1
+ tinymce.addI18n('fr',{
2
+ "Cut": "Couper",
3
+ "Header 2": "Titre 2",
4
+ "Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Votre navigateur ne supporte pas la copie directe. Merci d'utiliser les touches Ctrl+X\/C\/V.",
5
+ "Div": "Div",
6
+ "Paste": "Coller",
7
+ "Close": "Fermer",
8
+ "Font Family": "Polices de caract\u00e8res",
9
+ "Pre": "Pre",
10
+ "Align right": "Aligner \u00e0 droite",
11
+ "New document": "Nouveau document",
12
+ "Blockquote": "Citation",
13
+ "Numbered list": "Num\u00e9rotation",
14
+ "Increase indent": "Augmenter le retrait",
15
+ "Formats": "Formats",
16
+ "Headers": "Titres",
17
+ "Select all": "Tout s\u00e9lectionner",
18
+ "Header 3": "Titre 3",
19
+ "Blocks": "Blocs",
20
+ "Undo": "Annuler",
21
+ "Strikethrough": "Barr\u00e9",
22
+ "Bullet list": "Puces",
23
+ "Header 1": "Titre 1",
24
+ "Superscript": "Exposant",
25
+ "Clear formatting": "Effacer la mise en forme",
26
+ "Font Sizes": "Tailles de la police",
27
+ "Subscript": "Indice",
28
+ "Header 6": "Titre 6",
29
+ "Redo": "R\u00e9tablir",
30
+ "Paragraph": "Paragraphe",
31
+ "Ok": "Ok",
32
+ "Bold": "Gras",
33
+ "Code": "Code",
34
+ "Italic": "Italique",
35
+ "Align center": "Aligner au centre",
36
+ "Header 5": "Titre 5",
37
+ "Decrease indent": "Diminuer le retrait",
38
+ "Header 4": "Titre 4",
39
+ "Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Le presse-papiers est maintenant en mode \"texte plein\". Les contenus seront coll\u00e9s sans retenir les formatages jusqu'\u00e0 ce que vous d\u00e9sactiviez cette option.",
40
+ "Underline": "Soulign\u00e9",
41
+ "Cancel": "Annuler",
42
+ "Justify": "Justifi\u00e9",
43
+ "Inline": "En ligne",
44
+ "Copy": "Copier",
45
+ "Align left": "Aligner \u00e0 gauche",
46
+ "Visual aids": "Aides visuelle",
47
+ "Lower Greek": "Grec minuscule",
48
+ "Square": "Carr\u00e9",
49
+ "Default": "Par d\u00e9faut",
50
+ "Lower Alpha": "Alpha minuscule",
51
+ "Circle": "Cercle",
52
+ "Disc": "Disque",
53
+ "Upper Alpha": "Alpha majuscule",
54
+ "Upper Roman": "Romain majuscule",
55
+ "Lower Roman": "Romain minuscule",
56
+ "Name": "Nom",
57
+ "Anchor": "Ancre",
58
+ "You have unsaved changes are you sure you want to navigate away?": "Vous avez des modifications non enregistr\u00e9es, \u00eates-vous s\u00fbr de quitter la page?",
59
+ "Restore last draft": "Restaurer le dernier brouillon",
60
+ "Special character": "Caract\u00e8res sp\u00e9ciaux",
61
+ "Source code": "Code source",
62
+ "Right to left": "Droite \u00e0 gauche",
63
+ "Left to right": "Gauche \u00e0 droite",
64
+ "Emoticons": "Emotic\u00f4nes",
65
+ "Robots": "Robots",
66
+ "Document properties": "Propri\u00e9t\u00e9 du document",
67
+ "Title": "Titre",
68
+ "Keywords": "Mots-cl\u00e9s",
69
+ "Encoding": "Encodage",
70
+ "Description": "Description",
71
+ "Author": "Auteur",
72
+ "Fullscreen": "Plein \u00e9cran",
73
+ "Horizontal line": "Ligne horizontale",
74
+ "Horizontal space": "Espacement horizontal",
75
+ "Insert\/edit image": "Ins\u00e9rer\/\u00e9diter une image",
76
+ "General": "G\u00e9n\u00e9ral",
77
+ "Advanced": "Avanc\u00e9",
78
+ "Source": "Source",
79
+ "Border": "Bordure",
80
+ "Constrain proportions": "Contraindre les proportions",
81
+ "Vertical space": "Espacement vertical",
82
+ "Image description": "Description de l'image",
83
+ "Style": "Style",
84
+ "Dimensions": "Dimensions",
85
+ "Insert image": "Ins\u00e9rer une image",
86
+ "Insert date\/time": "Ins\u00e9rer date\/heure",
87
+ "Remove link": "Enlever le lien",
88
+ "Url": "Url",
89
+ "Text to display": "Texte \u00e0 afficher",
90
+ "Anchors": "Ancres",
91
+ "Insert link": "Ins\u00e9rer un lien",
92
+ "New window": "Nouvelle fen\u00eatre",
93
+ "None": "n\/a",
94
+ "The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?": "L'URL que vous avez entr\u00e9e semble \u00eatre un lien externe. Voulez-vous ajouter le pr\u00e9fixe http:\/\/ n\u00e9cessaire?",
95
+ "Target": "Cible",
96
+ "The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "L'URL que vous avez entr\u00e9e semble \u00eatre une adresse e-mail. Voulez-vous ajouter le pr\u00e9fixe mailto: n\u00e9cessaire?",
97
+ "Insert\/edit link": "Ins\u00e9rer\/\u00e9diter un lien",
98
+ "Insert\/edit video": "Ins\u00e9rer\/\u00e9diter une vid\u00e9o",
99
+ "Poster": "Publier",
100
+ "Alternative source": "Source alternative",
101
+ "Paste your embed code below:": "Collez votre code d'int\u00e9gration ci-dessous :",
102
+ "Insert video": "Ins\u00e9rer une vid\u00e9o",
103
+ "Embed": "Ins\u00e9rer",
104
+ "Nonbreaking space": "Espace ins\u00e9cable",
105
+ "Page break": "Saut de page",
106
+ "Paste as text": "Coller comme texte",
107
+ "Preview": "Pr\u00e9visualiser",
108
+ "Print": "Imprimer",
109
+ "Save": "Enregistrer",
110
+ "Could not find the specified string.": "Impossible de trouver la cha\u00eene sp\u00e9cifi\u00e9e.",
111
+ "Replace": "Remplacer",
112
+ "Next": "Suiv",
113
+ "Whole words": "Mots entiers",
114
+ "Find and replace": "Trouver et remplacer",
115
+ "Replace with": "Remplacer par",
116
+ "Find": "Chercher",
117
+ "Replace all": "Tout remplacer",
118
+ "Match case": "Respecter la casse",
119
+ "Prev": "Pr\u00e9c ",
120
+ "Spellcheck": "V\u00e9rification orthographique",
121
+ "Finish": "Finie",
122
+ "Ignore all": "Tout ignorer",
123
+ "Ignore": "Ignorer",
124
+ "Insert row before": "Ins\u00e9rer une ligne avant",
125
+ "Rows": "Lignes",
126
+ "Height": "Hauteur",
127
+ "Paste row after": "Coller la ligne apr\u00e8s",
128
+ "Alignment": "Alignement",
129
+ "Column group": "Groupe de colonnes",
130
+ "Row": "Ligne",
131
+ "Insert column before": "Ins\u00e9rer une colonne avant",
132
+ "Split cell": "Diviser la cellule",
133
+ "Cell padding": "Espacement interne cellule",
134
+ "Cell spacing": "Espacement inter-cellulles",
135
+ "Row type": "Type de ligne",
136
+ "Insert table": "Ins\u00e9rer un tableau",
137
+ "Body": "Corps",
138
+ "Caption": "Titre",
139
+ "Footer": "Pied",
140
+ "Delete row": "Effacer la ligne",
141
+ "Paste row before": "Coller la ligne avant",
142
+ "Scope": "Etendue",
143
+ "Delete table": "Supprimer le tableau",
144
+ "H Align": "Alignement H",
145
+ "Top": "Haut",
146
+ "Header cell": "Cellule d'en-t\u00eate",
147
+ "Column": "Colonne",
148
+ "Row group": "Groupe de lignes",
149
+ "Cell": "Cellule",
150
+ "Middle": "Milieu",
151
+ "Cell type": "Type de cellule",
152
+ "Copy row": "Copier la ligne",
153
+ "Row properties": "Propri\u00e9t\u00e9s de la ligne",
154
+ "Table properties": "Propri\u00e9t\u00e9s du tableau",
155
+ "Bottom": "Bas",
156
+ "V Align": "Alignement V",
157
+ "Header": "En-t\u00eate",
158
+ "Right": "Droite",
159
+ "Insert column after": "Ins\u00e9rer une colonne apr\u00e8s",
160
+ "Cols": "Colonnes",
161
+ "Insert row after": "Ins\u00e9rer une ligne apr\u00e8s",
162
+ "Width": "Largeur",
163
+ "Cell properties": "Propri\u00e9t\u00e9s de la cellule",
164
+ "Left": "Gauche",
165
+ "Cut row": "Couper la ligne",
166
+ "Delete column": "Effacer la colonne",
167
+ "Center": "Centr\u00e9",
168
+ "Merge cells": "Fusionner les cellules",
169
+ "Insert template": "Ajouter un th\u00e8me",
170
+ "Templates": "Th\u00e8mes",
171
+ "Background color": "Couleur d'arri\u00e8re-plan",
172
+ "Text color": "Couleur du texte",
173
+ "Show blocks": "Afficher les blocs",
174
+ "Show invisible characters": "Afficher les caract\u00e8res invisibles",
175
+ "Words: {0}": "Mots : {0}",
176
+ "Insert": "Ins\u00e9rer",
177
+ "File": "Fichier",
178
+ "Edit": "Editer",
179
+ "Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Zone Texte Riche. Appuyer sur ALT-F9 pour le menu. Appuyer sur ALT-F10 pour la barre d'outils. Appuyer sur ALT-0 pour de l'aide.",
180
+ "Tools": "Outils",
181
+ "View": "Voir",
182
+ "Table": "Tableau",
183
+ "Format": "Format"
184
+ });
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: alchemy_cms
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas von Deyen
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2014-07-03 00:00:00.000000000 Z
15
+ date: 2014-09-11 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: rails
@@ -110,14 +110,14 @@ dependencies:
110
110
  requirements:
111
111
  - - "~>"
112
112
  - !ruby/object:Gem::Version
113
- version: 0.15.0
113
+ version: '0.15'
114
114
  type: :runtime
115
115
  prerelease: false
116
116
  version_requirements: !ruby/object:Gem::Requirement
117
117
  requirements:
118
118
  - - "~>"
119
119
  - !ruby/object:Gem::Version
120
- version: 0.15.0
120
+ version: '0.15'
121
121
  - !ruby/object:Gem::Dependency
122
122
  name: acts_as_list
123
123
  requirement: !ruby/object:Gem::Requirement
@@ -1075,6 +1075,7 @@ files:
1075
1075
  - vendor/assets/javascripts/requestAnimationFrame.js
1076
1076
  - vendor/assets/javascripts/spin.min.js
1077
1077
  - vendor/assets/javascripts/tinymce/langs/de.js
1078
+ - vendor/assets/javascripts/tinymce/langs/fr.js
1078
1079
  - vendor/assets/javascripts/tinymce/langs/nl.js
1079
1080
  - vendor/assets/javascripts/tinymce/license.txt
1080
1081
  - vendor/assets/javascripts/tinymce/plugins/anchor/plugin.min.js