alchemy_cms 2.0.rc6 → 2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +2 -1
- data/LICENSE +24 -619
- data/README.md +38 -36
- data/alchemy_cms.gemspec +1 -1
- data/app/controllers/admin/elements_controller.rb +3 -2
- data/app/controllers/admin/pages_controller.rb +20 -14
- data/app/controllers/admin/trash_controller.rb +4 -0
- data/app/controllers/pages_controller.rb +27 -16
- data/app/helpers/admin/elements_helper.rb +55 -0
- data/app/helpers/alchemy_helper.rb +0 -45
- data/app/helpers/elements_helper.rb +8 -1
- data/app/helpers/pages_helper.rb +0 -10
- data/app/models/element.rb +39 -5
- data/app/models/page.rb +27 -7
- data/app/sweepers/pages_sweeper.rb +0 -9
- data/app/views/admin/pages/update.js.erb +15 -1
- data/app/views/admin/partials/_upload_form.html.erb +2 -2
- data/app/views/elements/_contactform_view.html.erb +10 -23
- data/app/views/elements/_searchresult_view.html.erb +47 -40
- data/app/views/essences/_essence_html_view.html.erb +1 -1
- data/app/views/pages/show.rss.builder +20 -25
- data/assets/javascripts/alchemy.js +2 -2
- data/assets/stylesheets/elements.css +1 -1
- data/assets/stylesheets/standard_set.css +84 -14
- data/config/alchemy/elements.yml +2 -0
- data/config/alchemy/page_layouts.yml +1 -0
- data/config/locales/de.yml +5 -5
- data/lib/alchemy/version.rb +1 -1
- data/lib/rails/generators/alchemy/plugin/templates/config.yml +3 -3
- data/spec/controllers/admin/trash_controller_spec.rb +22 -0
- data/spec/controllers/pages_controller_spec.rb +39 -0
- data/spec/dummy/db/schema.rb +10 -9
- data/spec/factories.rb +5 -0
- data/spec/helpers/elements_helper_spec.rb +7 -0
- data/spec/integration/pages_controller_spec.rb +1 -1
- data/spec/models/element_spec.rb +51 -5
- data/spec/models/page_spec.rb +70 -10
- metadata +10 -7
- 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="
|
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: '
|
434
|
+
title: 'Alchemy CMS License',
|
435
435
|
width: 650,
|
436
436
|
height: height,
|
437
437
|
autoResize: true,
|
@@ -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
|
-
|
135
|
-
|
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:
|
337
|
+
width: 310px;
|
338
|
+
}
|
339
|
+
|
340
|
+
td.field {
|
341
|
+
white-space: nowrap;
|
337
342
|
}
|
338
343
|
|
339
344
|
input.field.short {
|
340
|
-
width:
|
345
|
+
width: 105px;
|
341
346
|
}
|
342
347
|
|
343
348
|
input.field.medium {
|
344
|
-
width:
|
349
|
+
width: 200px;
|
345
350
|
}
|
346
351
|
|
347
352
|
td.label {
|
348
|
-
width:
|
353
|
+
width: 130px;
|
349
354
|
}
|
350
355
|
|
351
356
|
textarea {
|
352
|
-
width:
|
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:
|
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:
|
364
|
-
width:
|
365
|
-
|
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
|
+
}
|
data/config/alchemy/elements.yml
CHANGED
data/config/locales/de.yml
CHANGED
@@ -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:
|
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
|
327
|
-
other: "Konnte
|
328
|
-
body: "
|
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"
|
data/lib/alchemy/version.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
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
|
-
#
|
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
|
data/spec/dummy/db/schema.rb
CHANGED
@@ -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",
|
209
|
-
t.boolean "public",
|
210
|
-
t.boolean "locked",
|
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",
|
213
|
-
t.boolean "robot_index",
|
214
|
-
t.boolean "robot_follow",
|
215
|
-
t.boolean "sitemap",
|
216
|
-
t.boolean "layoutpage",
|
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"
|
data/spec/factories.rb
CHANGED
@@ -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
|
data/spec/models/element_spec.rb
CHANGED
@@ -33,10 +33,10 @@ describe Element do
|
|
33
33
|
definitions.first.fetch("name").should == 'article'
|
34
34
|
end
|
35
35
|
|
36
|
-
|
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
|
-
|
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
|
-
|
48
|
-
|
49
|
-
|
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
|