alchemy_cms 2.0.rc6 → 2.0

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 (39) hide show
  1. data/.travis.yml +2 -1
  2. data/LICENSE +24 -619
  3. data/README.md +38 -36
  4. data/alchemy_cms.gemspec +1 -1
  5. data/app/controllers/admin/elements_controller.rb +3 -2
  6. data/app/controllers/admin/pages_controller.rb +20 -14
  7. data/app/controllers/admin/trash_controller.rb +4 -0
  8. data/app/controllers/pages_controller.rb +27 -16
  9. data/app/helpers/admin/elements_helper.rb +55 -0
  10. data/app/helpers/alchemy_helper.rb +0 -45
  11. data/app/helpers/elements_helper.rb +8 -1
  12. data/app/helpers/pages_helper.rb +0 -10
  13. data/app/models/element.rb +39 -5
  14. data/app/models/page.rb +27 -7
  15. data/app/sweepers/pages_sweeper.rb +0 -9
  16. data/app/views/admin/pages/update.js.erb +15 -1
  17. data/app/views/admin/partials/_upload_form.html.erb +2 -2
  18. data/app/views/elements/_contactform_view.html.erb +10 -23
  19. data/app/views/elements/_searchresult_view.html.erb +47 -40
  20. data/app/views/essences/_essence_html_view.html.erb +1 -1
  21. data/app/views/pages/show.rss.builder +20 -25
  22. data/assets/javascripts/alchemy.js +2 -2
  23. data/assets/stylesheets/elements.css +1 -1
  24. data/assets/stylesheets/standard_set.css +84 -14
  25. data/config/alchemy/elements.yml +2 -0
  26. data/config/alchemy/page_layouts.yml +1 -0
  27. data/config/locales/de.yml +5 -5
  28. data/lib/alchemy/version.rb +1 -1
  29. data/lib/rails/generators/alchemy/plugin/templates/config.yml +3 -3
  30. data/spec/controllers/admin/trash_controller_spec.rb +22 -0
  31. data/spec/controllers/pages_controller_spec.rb +39 -0
  32. data/spec/dummy/db/schema.rb +10 -9
  33. data/spec/factories.rb +5 -0
  34. data/spec/helpers/elements_helper_spec.rb +7 -0
  35. data/spec/integration/pages_controller_spec.rb +1 -1
  36. data/spec/models/element_spec.rb +51 -5
  37. data/spec/models/page_spec.rb +70 -10
  38. metadata +10 -7
  39. data/TODO.txt +0 -1
@@ -428,10 +428,10 @@ if (typeof(Alchemy) === 'undefined') {
428
428
 
429
429
  openLicencseWindow : function() {
430
430
  var height = $(window).height() - 150;
431
- var $iframe = $('<iframe src="http://www.gnu.org/licenses/gpl-3.0.txt"></iframe>');
431
+ var $iframe = $('<iframe src="https://raw.github.com/magiclabs/alchemy_cms/master/LICENSE"></iframe>');
432
432
  $iframe.dialog({
433
433
  bgiframe: true,
434
- title: 'GNU GPL License',
434
+ title: 'Alchemy CMS License',
435
435
  width: 650,
436
436
  height: height,
437
437
  autoResize: true,
@@ -469,7 +469,7 @@ div.essence_picture_css_class {
469
469
  position: absolute;
470
470
  z-index: 1;
471
471
  bottom: 24px;
472
- width: 102px;
472
+ width: 99px;
473
473
  background-color: white;
474
474
  background-color: rgba(255,254,255,0.7);
475
475
  padding: 4px 8px;
@@ -1,3 +1,5 @@
1
+ /* @override http://localhost:3000/stylesheets/alchemy/standard_set.css */
2
+
1
3
  body {
2
4
  margin: 0;
3
5
  padding: 0;
@@ -128,11 +130,10 @@ div#header_image {
128
130
  #navigation {
129
131
  font-family: "Lucida Grande", Lucida, Verdana, sans-serif;
130
132
  color: #fdfdfd;
131
- position: relative;
132
- top: 40%;
133
133
  text-transform: uppercase;
134
- float: left;
135
- clear: both;
134
+ position: absolute;
135
+ top: 215px;
136
+ z-index: 100;
136
137
  }
137
138
 
138
139
  #navigation ul {
@@ -333,36 +334,62 @@ input.field {
333
334
  margin: 0;
334
335
  font: 12px "Lucida Grande", Lucida, Verdana, sans-serif;
335
336
  border: 1px solid silver;
336
- width: 290px;
337
+ width: 310px;
338
+ }
339
+
340
+ td.field {
341
+ white-space: nowrap;
337
342
  }
338
343
 
339
344
  input.field.short {
340
- width: 100px;
345
+ width: 105px;
341
346
  }
342
347
 
343
348
  input.field.medium {
344
- width: 186px;
349
+ width: 200px;
345
350
  }
346
351
 
347
352
  td.label {
348
- width: 100px;
353
+ width: 130px;
349
354
  }
350
355
 
351
356
  textarea {
352
- width: 290px;
357
+ width: 310px;
353
358
  padding: 2px;
354
359
  font: 12px "Lucida Grande", Lucida, Verdana, sans-serif;
355
360
  border: 1px solid silver;
356
- margin-left: 107px;
361
+ margin-left: 137px;
357
362
  height: 10em;
358
363
  margin-top: 2em;
359
364
  margin-bottom: 1em;
360
365
  }
361
366
 
367
+ div.field_with_errors {
368
+ color: #fe1b15;
369
+ }
370
+
371
+ div.field_with_errors input.field {
372
+ border-color: #fe1b15;
373
+ }
374
+
375
+ p.foot_notice {
376
+ font-size: 0.8em;
377
+ }
378
+
362
379
  form#contact {
363
- padding: 10px;
364
- width: 400px;
365
- margin-left: 200px;
380
+ padding: 0 0 0 12px;
381
+ width: 450px;
382
+ }
383
+
384
+ #errorExplanation {
385
+ color: #fe1d16;
386
+ margin-bottom: 20px;
387
+ margin-top: 20px;
388
+ }
389
+
390
+ #errorExplanation ul {
391
+ list-style-type: disc;
392
+ padding: 0 0 0 1.5em;
366
393
  }
367
394
 
368
395
  label {
@@ -371,4 +398,47 @@ label {
371
398
 
372
399
  p.right {
373
400
  text-align: right;
374
- }
401
+ }
402
+
403
+ .searchresult {
404
+ margin-top: 1em;
405
+ margin-bottom: 1em;
406
+ }
407
+
408
+ .searchresult form {
409
+ padding-left: 12px;
410
+ }
411
+
412
+ .searchresult h2 {
413
+ padding-left: 12px;
414
+ margin-bottom: 2em;
415
+ margin-top: 1em;
416
+ }
417
+
418
+ .search_results ul {
419
+ list-style-type: none;
420
+ padding: 0 0 0 12px;
421
+ }
422
+
423
+ .search_results ul li {
424
+ margin-bottom: 2em;
425
+ }
426
+
427
+ .search_results ul li p {
428
+ margin-top: 0.5em;
429
+ margin-bottom: 0.5em;
430
+ }
431
+
432
+ .search_results ul li h3 {
433
+ margin-bottom: 0.5em;
434
+ margin-top: 0.5em;
435
+ }
436
+
437
+ .search_results ul li h4 {
438
+ margin-top: 0.5em;
439
+ margin-bottom: 0.5em;
440
+ }
441
+
442
+ .search_results em {
443
+ font-weight: bold;
444
+ }
@@ -196,8 +196,10 @@
196
196
  type: EssenceDate
197
197
  - name: news_headline
198
198
  type: EssenceText
199
+ rss_title: true
199
200
  - name: body
200
201
  type: EssenceRichtext
202
+ rss_description: true
201
203
 
202
204
  - name: searchresult
203
205
  unique: true
@@ -47,6 +47,7 @@
47
47
  unique: true
48
48
  elements: [headline, news]
49
49
  autogenerate: [news]
50
+ feed_elements: [news]
50
51
 
51
52
  - name: search
52
53
  unique: true
@@ -85,7 +85,7 @@ de:
85
85
  # == Translations for the build in full text search.
86
86
  search:
87
87
  no_results: 'Ihre Suche ergab kein Ergebnis.'
88
- result_heading: 'Ihre Suche nach %{query} ergab %{count} Ergebnisse'
88
+ result_heading: "Ihre Suche nach '%{query}' hat %{count} Ergebnisse"
89
89
 
90
90
  # == Contactform translations
91
91
  contactform:
@@ -102,7 +102,7 @@ de:
102
102
  email: 'Email'
103
103
  message: 'Nachricht'
104
104
  send: 'Nachricht absenden!'
105
- mandatory_fields: 'Pflichtfelder. Vielen Dank!'
105
+ mandatory_fields: 'Pflichtfelder. Bitte füllen Sie diese Felder aus. Vielen Dank!'
106
106
  success_page: 'Folgeseite'
107
107
  # Translations for the contactform validations.
108
108
  # Validations are set in the config/alchemy/config.yml mailer section.
@@ -323,9 +323,9 @@ de:
323
323
  errors:
324
324
  template:
325
325
  header:
326
- one: "Konnte dieses Formular nicht speichern: 1 Fehler."
327
- other: "Konnte dieses Formular nicht speichern: %{count} Fehler."
328
- body: "Bitte überprüfen Sie:"
326
+ one: "Konnte nicht fortfahren, da 1 Fehler auftrat."
327
+ other: "Konnte nicht fortfahren, da %{count} Fehler auftraten."
328
+ body: "Fehler:"
329
329
  messages:
330
330
  inclusion: "%{attribute} ist kein gültiger Wert"
331
331
  exclusion: "%{attribute} ist nicht verfügbar"
@@ -1,5 +1,5 @@
1
1
  module Alchemy
2
2
 
3
- VERSION = "2.0.rc6"
3
+ VERSION = "2.0"
4
4
 
5
5
  end
@@ -1,4 +1,4 @@
1
- # These is your plugin configuration file.
1
+ # This is your plugin configuration file.
2
2
  # ========================================
3
3
  #
4
4
  # Options:
@@ -9,9 +9,9 @@
9
9
  # settings: # [Optional] Put your own settings in YAML format into here. You can access them with plugin_conf('<%= @plugin_name.underscore %>')['settings'] [YAML]
10
10
  # navigation:
11
11
  # name: # The name is used in the Alchemy mainnavi. [String]
12
- # controller: # The name of the controller to be called when clicking the mainnavi button [String]
12
+ # controller: # The name of the controller to be called when clicking the mainnavi button. Example usage: 'admin/controllername' [String]
13
13
  # action: # The name of the action from the controller to be called when clicking the mainnavi button [String]
14
- # image: # Path to an image inside your public folder used for the icon in the alchemy mainnavi. [String]
14
+ # icon: # CSS classname for the link in the alchemy mainnavi. [String]
15
15
  # sub_navigation: # Your plugins sub navigation. Put as much as sub navi entries as you want into here
16
16
  # - name: # [String]
17
17
  # controller: # Typically your controller and action you set for mainnavi entry.
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe Admin::TrashController do
4
+
5
+ before(:each) do
6
+ activate_authlogic
7
+ UserSession.create Factory(:admin_user)
8
+ end
9
+
10
+ it "should hold trashed elements" do
11
+ pending "The controller behaves correct, the test not."
12
+ @page = Factory(:page, :parent_id => Page.rootpage.id)
13
+ @element = Factory(:element, :page => @page)
14
+ # Rails, RSpec and co. are sucking
15
+ @element.reload
16
+ @element.trash
17
+ @element.reload
18
+ get :index, :page_id => @page.id
19
+ response.body.should have_selector('#trash_items #element_4.element_editor')
20
+ end
21
+
22
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe PagesController do
4
+
5
+ before(:each) do
6
+ @default_language = Language.get_default
7
+ @default_language_root = Factory(:language_root_page, :language => @default_language, :name => 'Home', :public => true)
8
+ end
9
+
10
+ context "requested for a page containing a feed" do
11
+
12
+ before(:each) do
13
+ @page = Factory(:public_page, :parent_id => @default_language_root.id, :page_layout => 'news', :name => 'News', :language => @default_language)
14
+ end
15
+
16
+ it "should render a rss feed" do
17
+ get :show, :urlname => 'news', :format => :rss
18
+ response.content_type.should == 'application/rss+xml'
19
+ end
20
+
21
+ it "should include content" do
22
+ pending "I didn't figured out how to test XML response bodies"
23
+ @page.elements.first.content_by_name('news_headline').essence.update_attributes({:body => 'Peters Petshop'})
24
+ get :show, :urlname => 'news', :format => :rss
25
+ response.body.should match /Peters Petshop/
26
+ end
27
+
28
+ end
29
+
30
+ context "requested for a page that does not contain a feed" do
31
+
32
+ it "should render xml 404 error" do
33
+ get :show, :urlname => 'home', :format => :rss
34
+ response.status.should == 404
35
+ end
36
+
37
+ end
38
+
39
+ end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  # This file is auto-generated from the current state of the database. Instead
2
3
  # of editing this file, please use the migrations feature of Active Record to
3
4
  # incrementally modify your database, and then regenerate this schema definition.
@@ -197,7 +198,7 @@ ActiveRecord::Schema.define(:version => 20110919110451) do
197
198
  t.string "urlname"
198
199
  t.string "title"
199
200
  t.string "language_code"
200
- t.boolean "language_root"
201
+ t.boolean "language_root", :limit => 255
201
202
  t.string "page_layout"
202
203
  t.text "meta_keywords"
203
204
  t.text "meta_description"
@@ -205,15 +206,15 @@ ActiveRecord::Schema.define(:version => 20110919110451) do
205
206
  t.integer "rgt"
206
207
  t.integer "parent_id"
207
208
  t.integer "depth"
208
- t.boolean "visible", :default => false
209
- t.boolean "public", :default => false
210
- t.boolean "locked", :default => false
209
+ t.boolean "visible", :default => false
210
+ t.boolean "public", :default => false
211
+ t.boolean "locked", :default => false
211
212
  t.integer "locked_by"
212
- t.boolean "restricted", :default => false
213
- t.boolean "robot_index", :default => true
214
- t.boolean "robot_follow", :default => true
215
- t.boolean "sitemap", :default => true
216
- t.boolean "layoutpage", :default => false
213
+ t.boolean "restricted", :default => false
214
+ t.boolean "robot_index", :default => true
215
+ t.boolean "robot_follow", :default => true
216
+ t.boolean "sitemap", :default => true
217
+ t.boolean "layoutpage", :default => false
217
218
  t.datetime "created_at"
218
219
  t.datetime "updated_at"
219
220
  t.integer "creator_id"
@@ -54,6 +54,11 @@ FactoryGirl.define do
54
54
 
55
55
  end
56
56
 
57
+ factory :cell do
58
+ page { Page.find_by_language_root(true) || Factory(:language_root_page) }
59
+ name "A Cell"
60
+ end
61
+
57
62
  factory :element do
58
63
  name 'article'
59
64
  end
@@ -23,6 +23,13 @@ describe ElementsHelper do
23
23
  helper.element_dom_id(@element).should == "#{@element.name}_#{@element.id}"
24
24
  end
25
25
 
26
+ it "should render elements for a cell", :focus => true do
27
+ cell = Factory(:cell)
28
+ Factory(:element, :cell_id => cell.id)
29
+ helper.stub(:configuration).and_return(true)
30
+ helper.render_cell_elements(cell).should match(/id="article_7"/)
31
+ end
32
+
26
33
  context "in preview mode" do
27
34
 
28
35
  it "should return the data-alchemy-element HTML attribute for element" do
@@ -27,7 +27,7 @@ describe PagesController do
27
27
  visit '/'
28
28
  within('div#navigation ul') { page.should have_selector('li a[href="/page-1"], li a[href="/page-2"]') }
29
29
  end
30
-
30
+
31
31
  end
32
32
 
33
33
  context "performing a fulltext search" do
@@ -33,10 +33,10 @@ describe Element do
33
33
  definitions.first.fetch("name").should == 'article'
34
34
  end
35
35
 
36
- it "should always return an array calling all_definitions_for()" do
36
+ it "should always return an array calling all_definitions_for()" do
37
37
  definitions = Element.all_definitions_for(nil)
38
38
  definitions.should == []
39
- end
39
+ end
40
40
 
41
41
  it "should raise an error if no descriptions are found" do
42
42
  FileUtils.mv(File.join(File.dirname(__FILE__), '..', '..', 'config', 'alchemy', 'elements.yml'), File.join(File.dirname(__FILE__), '..', '..', 'config', 'alchemy', 'elements.yml.bak'))
@@ -44,9 +44,55 @@ describe Element do
44
44
  FileUtils.mv(File.join(File.dirname(__FILE__), '..', '..', 'config', 'alchemy', 'elements.yml.bak'), File.join(File.dirname(__FILE__), '..', '..', 'config', 'alchemy', 'elements.yml'))
45
45
  end
46
46
 
47
- it "should return an ingredient by name" do
48
- element = Factory(:element)
49
- element.ingredient('intro').should == EssenceText.first.ingredient
47
+ context "retrieving contents, essences and ingredients" do
48
+
49
+ before(:each) do
50
+ @element = Factory(:element, :name => 'news')
51
+ end
52
+
53
+ it "should return an ingredient by name" do
54
+ @element.ingredient('news_headline').should == EssenceText.first.ingredient
55
+ end
56
+
57
+ it "should return the content for rss title" do
58
+ @element.content_for_rss_title.should == @element.contents.find_by_name('news_headline')
59
+ end
60
+
61
+ it "should return the content for rss description" do
62
+ @element.content_for_rss_description.should == @element.contents.find_by_name('body')
63
+ end
64
+
65
+ end
66
+
67
+ it "should return a collection of trashed elements" do
68
+ @element = Factory(:element)
69
+ @element.trash
70
+ Element.trashed.should include(@element)
71
+ end
72
+
73
+ context "trashed" do
74
+
75
+ before(:each) do
76
+ @element = Factory(:element)
77
+ @element.trash
78
+ end
79
+
80
+ it "should be not public" do
81
+ @element.public.should be_false
82
+ end
83
+
84
+ it "should have no page" do
85
+ @element.page.should == nil
86
+ end
87
+
88
+ it "should be folded" do
89
+ @element.folded.should == true
90
+ end
91
+
92
+ end
93
+
94
+ it "should raise error if all_for_page method has no page" do
95
+ expect { Element.all_for_page(nil) }.should raise_error(TypeError)
50
96
  end
51
97
 
52
98
  end