alchemy_cms 2.1.rc6 → 2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/app/assets/images/alchemy/lupe.cur +0 -0
  2. data/app/assets/javascripts/alchemy/alchemy.buttons.js +1 -1
  3. data/app/assets/javascripts/alchemy/alchemy.page_sorter.js +1 -0
  4. data/app/assets/stylesheets/alchemy/alchemy.css +11 -0
  5. data/app/assets/stylesheets/alchemy/base.css.scss +447 -2446
  6. data/app/assets/stylesheets/alchemy/buttons.css.scss +354 -0
  7. data/app/assets/stylesheets/alchemy/dashboard.css.scss +76 -0
  8. data/app/assets/stylesheets/alchemy/flags.css.scss +1 -1
  9. data/app/assets/stylesheets/alchemy/flash.css.scss +54 -0
  10. data/app/assets/stylesheets/alchemy/frame.css.scss +287 -0
  11. data/app/assets/stylesheets/alchemy/icons.css.scss +300 -0
  12. data/app/assets/stylesheets/alchemy/jquery-ui.alchemy.css.scss +3 -2
  13. data/app/assets/stylesheets/alchemy/jquery.sb.css.scss +1 -1
  14. data/app/assets/stylesheets/alchemy/login.css.scss +53 -0
  15. data/app/assets/stylesheets/alchemy/menubar.css.scss +26 -11
  16. data/app/assets/stylesheets/alchemy/modules.css.scss +31 -0
  17. data/app/assets/stylesheets/alchemy/pagination.css.scss +56 -0
  18. data/app/assets/stylesheets/alchemy/sitemap.css.scss +285 -0
  19. data/app/assets/stylesheets/alchemy/tables.css.scss +150 -0
  20. data/app/assets/stylesheets/alchemy/upload.css.scss +92 -0
  21. data/app/controllers/alchemy/admin/dashboard_controller.rb +1 -1
  22. data/app/controllers/alchemy/admin/pages_controller.rb +1 -1
  23. data/app/controllers/alchemy/admin/resources_controller.rb +35 -2
  24. data/app/controllers/alchemy/user_sessions_controller.rb +3 -0
  25. data/app/helpers/alchemy/admin/attachments_helper.rb +1 -1
  26. data/app/helpers/alchemy/admin/base_helper.rb +69 -20
  27. data/app/helpers/alchemy/pages_helper.rb +0 -55
  28. data/app/views/alchemy/admin/attachments/_attachment.html.erb +1 -1
  29. data/app/views/alchemy/admin/clipboard/index.html.erb +4 -1
  30. data/app/views/alchemy/admin/dashboard/index.html.erb +16 -11
  31. data/app/views/alchemy/admin/elements/_new_element_form.html.erb +4 -1
  32. data/app/views/alchemy/admin/layoutpages/_layoutpage.html.erb +1 -20
  33. data/app/views/alchemy/admin/layoutpages/index.html.erb +1 -1
  34. data/app/views/alchemy/admin/pages/index.html.erb +3 -3
  35. data/app/views/alchemy/admin/partials/_search_form.html.erb +7 -1
  36. data/app/views/alchemy/admin/resources/_form.html.erb +1 -1
  37. data/app/views/alchemy/admin/resources/_resource.html.erb +8 -5
  38. data/app/views/alchemy/admin/resources/_table.html.erb +1 -1
  39. data/app/views/alchemy/admin/resources/index.html.erb +4 -3
  40. data/app/views/alchemy/admin/trash/index.html.erb +3 -2
  41. data/app/views/alchemy/user_sessions/login.html.erb +2 -1
  42. data/app/views/layouts/alchemy/admin.html.erb +3 -4
  43. data/app/views/layouts/alchemy/login.html.erb +9 -8
  44. data/config/authorization_rules.rb +0 -1
  45. data/config/locales/alchemy.de.yml +1 -0
  46. data/config/locales/alchemy.en.yml +1 -0
  47. data/lib/alchemy/seeder.rb +1 -1
  48. data/lib/alchemy/version.rb +1 -1
  49. data/spec/integration/admin/pages_controller_spec.rb +45 -57
  50. data/spec/integration/admin/resources_spec.rb +19 -0
  51. data/spec/models/content_spec.rb +6 -5
  52. data/spec/support/alchemy/controller_hacks.rb +41 -0
  53. data/spec/support/alchemy/specs_helpers.rb +32 -0
  54. data/vendor/assets/javascripts/tiny_mce/plugins/autoresize/editor_plugin.js +137 -1
  55. metadata +55 -37
  56. data/app/views/alchemy/admin/languages/_language.html.erb +0 -36
  57. data/spec/support/controller_hacks.rb +0 -37
@@ -0,0 +1,150 @@
1
+ @import "alchemy/defaults";
2
+
3
+ table {
4
+ border-style: none;
5
+ border-spacing: 0 $default-padding;
6
+ padding: 0;
7
+ font-size: inherit;
8
+ width: 100%;
9
+
10
+ td, th {
11
+ padding: $default-padding;
12
+ }
13
+
14
+ th {
15
+ text-align: left;
16
+ height: 22px;
17
+ vertical-align: top;
18
+ }
19
+ }
20
+
21
+ table tr td.tools {
22
+ width: 40px;
23
+ background-color: $light-gray;
24
+ white-space: nowrap;
25
+ }
26
+
27
+ td.input, td.label {
28
+ padding-top: 2px;
29
+ vertical-align: top;
30
+ }
31
+
32
+ td.input, td.submit, td.select {
33
+ text-align: right;
34
+ padding-right: 0;
35
+ }
36
+
37
+ td.value {
38
+ padding-left: 2*$default-padding;
39
+ }
40
+
41
+ td.label {
42
+ white-space: nowrap;
43
+ width: 80px;
44
+ padding: $default-padding 2*$default-padding 0 0;
45
+ line-height: 6*$default-padding;
46
+ }
47
+
48
+ td.label.mandatory:after {
49
+ content: '*';
50
+ }
51
+
52
+ td.heading {
53
+ padding: $default-padding 0;
54
+ font-weight: bold;
55
+ text-decoration: underline;
56
+ }
57
+
58
+ td.input input[type="checkbox"], td.input input[type="radio"] {
59
+ margin-top: 6px;
60
+ }
61
+
62
+ td.label.long {
63
+ width: 140px;
64
+ }
65
+
66
+ td.label.very_long {
67
+ width: 230px;
68
+ }
69
+
70
+ table tr td.tools a {
71
+ width: 19px;
72
+ height: 19px;
73
+ margin-right: 2px;
74
+ }
75
+
76
+ table tr td.tools.long {
77
+ width: 60px;
78
+ }
79
+
80
+ table tr td.icon {
81
+ background-color: $light-gray;
82
+ width: 20px;
83
+ text-align: center;
84
+ }
85
+
86
+ table.list tr:hover td {
87
+ background-color: #fffdef;
88
+ }
89
+
90
+ td.file_type {
91
+ width: 130px;
92
+ white-space: nowrap;
93
+ }
94
+
95
+ td.file_size {
96
+ width: 80px;
97
+ }
98
+
99
+ td.date {
100
+ width: 150px;
101
+ }
102
+
103
+ table td.right, table th.right {
104
+ text-align: right;
105
+ }
106
+
107
+ table td.center, table th.center {
108
+ text-align: center;
109
+ }
110
+
111
+ td.login {
112
+ width: 100px;
113
+ }
114
+
115
+ td.email {
116
+ width: 270px;
117
+ }
118
+
119
+ td.role {
120
+ width: 70px;
121
+ padding-right: 4px;
122
+ }
123
+
124
+ table td.rights {
125
+ width: 60px;
126
+ }
127
+ table.window_form {
128
+ width: 100%;
129
+ }
130
+
131
+ th.login_status {
132
+ width: 16px;
133
+ }
134
+
135
+ table tr.odd td {
136
+ background-color: #eaf3f9;
137
+ }
138
+
139
+ table tr.even td {
140
+ background-color: white;
141
+ }
142
+
143
+ td.label.middle {
144
+ padding-left: 2*$default-padding;
145
+ }
146
+
147
+ th.icon, td.icon {
148
+ background: none;
149
+ display: table-cell;
150
+ }
@@ -0,0 +1,92 @@
1
+ @import "alchemy/defaults";
2
+
3
+ a#uploadswitcher, a.underline {
4
+ text-decoration: underline;
5
+ }
6
+
7
+ #uploadProgressContainer {
8
+ overflow-x: hidden;
9
+ overflow-y: auto;
10
+ height: 234px;
11
+ }
12
+
13
+ #uploadProgressContainer .progressWrapper {
14
+ padding: 2*$default-padding;
15
+ background-color: $medium-gray;
16
+ position: relative;
17
+ margin-bottom: 8px;
18
+ border: 1px solid #9e9e9e;
19
+ @include rounded-corner;
20
+ }
21
+
22
+ #uploadProgressContainer .progressName,
23
+ #uploadProgressContainer .progressBarStatus {
24
+ margin-bottom: 4px;
25
+ }
26
+
27
+ #uploadProgressContainer .progressBarStatus {
28
+ font-size: 10px;
29
+ }
30
+
31
+ #uploadProgressContainer .progressName {
32
+ text-shadow: 0 1px 2px #FFFFFF;
33
+ }
34
+
35
+ #uploadProgressContainer .progressBarContainer {
36
+ background: #F9F9F9 image-url('alchemy/shading.png') repeat-x 0 0;
37
+ border:1px solid #9E9E9E;
38
+ @include rounded-corner;
39
+ height:16px;
40
+ overflow: hidden;
41
+ width:100%;
42
+ }
43
+
44
+ #uploadProgressContainer .progressBarInProgress {
45
+ background: #77AAD5 image-url('alchemy/shading.png') repeat-x 0 -75px;
46
+ height: 16px;
47
+ width: 0;
48
+ }
49
+
50
+ #uploadProgressContainer .progressBarComplete {
51
+ background: #00D827 image-url('alchemy/shading.png') repeat-x 0 -75px;
52
+ height: 16px;
53
+ width: 0;
54
+ }
55
+
56
+ #uploadProgressContainer .progressBarError {
57
+ background: #F00 image-url('alchemy/shading.png') repeat-x 0 -75px;
58
+ height: 16px;
59
+ width: 0;
60
+ }
61
+
62
+ #uploadProgressContainer .progressBarCanceled {
63
+ background: #E4E4E4 image-url('alchemy/shading.png') repeat-x 0 -75px;
64
+ height: 16px;
65
+ width: 0;
66
+ }
67
+
68
+ #uploadProgressContainer .progressCancel {
69
+ background: #f1f1f1 image-url('alchemy/icons.png') no-repeat -1px -72px;
70
+ border: 1px solid #9e9e9e;
71
+ @include rounded-corner;
72
+ width: 15px;
73
+ height: 16px;
74
+ position: absolute;
75
+ top: 8px;
76
+ right: 8px;
77
+ }
78
+
79
+ #swf_upload_container {
80
+ height: 60px;
81
+ }
82
+
83
+ #swf_upload_container .button {
84
+ float: right;
85
+ margin-top: 4*$default-margin;
86
+ font-size: 11px;
87
+ }
88
+
89
+ object.swfupload {
90
+ margin-top: 16px;
91
+ margin-bottom: 16px;
92
+ }
@@ -7,7 +7,7 @@ module Alchemy
7
7
  @clipboard_items = session[:clipboard]
8
8
  @last_edited_pages = Page.all_last_edited_from(current_user)
9
9
  @locked_pages = Page.all_locked
10
- @online_users = User.all_online
10
+ @online_users = User.all_online.to_a.delete_if { |u| u == current_user }
11
11
  end
12
12
 
13
13
  end
@@ -27,7 +27,7 @@ module Alchemy
27
27
  @root_page = Page.language_root_for(session[:language_id])
28
28
  # Setting the locale to pages language. so the page content has its correct translation
29
29
  ::I18n.locale = @page.language_code
30
- render :layout => params[:layout].blank? ? 'alchemy/pages' : params[:layout] == 'none' ? false : params[:layout]
30
+ render :layout => layout_for_page
31
31
  end
32
32
 
33
33
  def new
@@ -6,7 +6,20 @@ module Alchemy
6
6
 
7
7
  before_filter :load_resource, :only => [:show, :edit, :update, :destroy]
8
8
 
9
- helper_method :resource_attributes, :resource_window_size, :resources_name, :resource_model, :resource_model_name, :resource_instance_variable, :resources_instance_variable, :namespaced_resources_name, :resource_namespaced?
9
+ helper_method(
10
+ :resource_attributes,
11
+ :resource_window_size,
12
+ :resources_name,
13
+ :resource_model,
14
+ :resource_model_name,
15
+ :resource_instance_variable,
16
+ :resources_instance_variable,
17
+ :namespaced_resources_name,
18
+ :resource_namespaced?,
19
+ :resources_permission,
20
+ :resource_url_scope,
21
+ :is_alchemy_module?
22
+ )
10
23
 
11
24
  def index
12
25
  if !params[:query].blank?
@@ -84,7 +97,7 @@ module Alchemy
84
97
  if resource_namespaced?
85
98
  @namespaced_resources_name ||= "#{resource_namespace}_#{resources_name}".underscore
86
99
  else
87
- @namespaced_resources_name ||= resource_model_name
100
+ @namespaced_resources_name ||= resources_name
88
101
  end
89
102
  end
90
103
 
@@ -129,6 +142,26 @@ module Alchemy
129
142
  @resource_namespace ||= self.class.to_s.split("::").first
130
143
  end
131
144
 
145
+ def resource_url_scope
146
+ if is_alchemy_module?
147
+ eval(alchemy_module['engine_name'])
148
+ else
149
+ main_app
150
+ end
151
+ end
152
+
153
+ def is_alchemy_module?
154
+ !alchemy_module.nil? && !alchemy_module['engine_name'].blank?
155
+ end
156
+
157
+ def alchemy_module
158
+ @alchemy_module ||= module_definition_for(:controller => params[:controller], :action => 'index')
159
+ end
160
+
161
+ def resources_permission
162
+ (resource_namespaced? ? "#{resource_namespace.underscore}_admin_#{resources_name}" : "admin_#{resources_name}").to_sym
163
+ end
164
+
132
165
  end
133
166
  end
134
167
  end
@@ -1,6 +1,8 @@
1
1
  module Alchemy
2
2
  class UserSessionsController < Alchemy::BaseController
3
+
3
4
  before_filter :check_user_count, :only => :login
5
+
4
6
  layout 'alchemy/login'
5
7
 
6
8
  helper 'Alchemy::Admin::Base'
@@ -49,6 +51,7 @@ module Alchemy
49
51
  end
50
52
 
51
53
  def leave
54
+ ::I18n.locale = current_user.language.to_sym
52
55
  render :layout => false
53
56
  end
54
57
 
@@ -3,7 +3,7 @@ module Alchemy
3
3
  module AttachmentsHelper
4
4
 
5
5
  def mime_to_human mime
6
- Alchemy::I18n.t("alchemy.mime_types.#{mime}", :default => t('document'))
6
+ Alchemy::I18n.t(mime, :scope => :mime_types, :default => t('document'))
7
7
  end
8
8
 
9
9
  end
@@ -1,11 +1,22 @@
1
1
  module Alchemy
2
2
  module Admin
3
+
4
+ # This module contains helper methods for rendering overlay windows, toolbar buttons and confirmation windows.
5
+ #
6
+ # The most important helpers for module developers are:
7
+ #
8
+ # * toolbar
9
+ # * toolbar_button
10
+ # * link_to_overlay_window
11
+ # * link_to_confirmation_window
12
+ #
3
13
  module BaseHelper
4
14
 
5
15
  # This helper renders the link for an overlay window.
16
+ #
6
17
  # We use this for our fancy modal overlay windows in the Alchemy cockpit.
7
18
  #
8
- # Options:
19
+ # === Options:
9
20
  #
10
21
  # :size [String] # String with format of "WidthxHeight". I.E. ("420x280")
11
22
  # :title [String] # Text for the overlay title bar.
@@ -35,7 +46,7 @@ module Alchemy
35
46
  )
36
47
  end
37
48
 
38
- # Used for rendering the folder link in Admin::Pages.index sitemap.
49
+ # (internal) Used for rendering the folder link in +Admin::Pages#index+ sitemap.
39
50
  def sitemapFolderLink(page)
40
51
  return '' if page.level == 1
41
52
  if page.folded?(current_user.id)
@@ -94,6 +105,19 @@ module Alchemy
94
105
  filter_field.html_safe
95
106
  end
96
107
 
108
+ # Returns a link that opens a modal confirmation window.
109
+ #
110
+ # === Parameters:
111
+ #
112
+ # 1. The content inside the <a> tag
113
+ # 2. The message that is displayed in the overlay window
114
+ # 3. The url that gets opened after confirmation (Note: This is an Ajax request with a method of DELETE!)
115
+ # 4. html options get passed to the link
116
+ #
117
+ # === Example:
118
+ #
119
+ # <%= link_to_confirmation_window('delete', 'Do you really want to delete this comment?', '/admin/comments/1') %>
120
+ #
97
121
  def link_to_confirmation_window(link_string = "", message = "", url = "", html_options = {})
98
122
  title = t("please_confirm")
99
123
  ok_lable = t("Yes")
@@ -107,9 +131,12 @@ module Alchemy
107
131
 
108
132
  # Returns an Array build for passing it to the options_for_select helper inside an essence editor partial.
109
133
  # Usefull for the select_values options from the render_essence_editor helpers.
110
- # Options:
111
- # * :from_page (String, Page) - Return only elements from this page. You can either pass a Page instance, or a page_layout name
112
- # * :elements_with_name (Array, String) - Return only elements with this name(s).
134
+ #
135
+ # == Options:
136
+ #
137
+ # :from_page [String, Page] # Return only elements from this page. You can either pass a Page instance, or a page_layout name
138
+ # :elements_with_name [Array, String] # Return only elements with this name(s).
139
+ #
113
140
  def elements_for_essence_editor_select(options={})
114
141
  defaults = {
115
142
  :from_page => nil,
@@ -132,9 +159,13 @@ module Alchemy
132
159
  select_options
133
160
  end
134
161
 
135
- # Returns all Pages found in the database as an array for the rails select_tag helper.
136
- # You can pass a collection of pages to only returns these pages as array.
137
- # Pass an Page.name or Page.id as second parameter to pass as selected for the options_for_select helper.
162
+ # Returns all public pages found in the database as an Array suitable or the Rails +select_tag+ helper.
163
+ #
164
+ # * You can pass a collection of pages so it only returns these pages and does not query the database.
165
+ # * Pass a +Page#name+ or +Page#id+ as second parameter to be passed as selected item to the +options_for_select+ helper.
166
+ # * The trhird parameter is used as prompt message in the select tag
167
+ # * The last parameter is the method that is called on the page object to get the value that is passed with the params of the form.
168
+ #
138
169
  def pages_for_select(pages = nil, selected = nil, prompt = "", page_attribute = :id)
139
170
  result = [[prompt.blank? ? t('Choose page') : prompt, ""]]
140
171
  if pages.blank?
@@ -241,11 +272,12 @@ module Alchemy
241
272
  ['main_navi_entry', admin_mainnavi_active?(navigation) ? 'active' : nil].compact.join(" ")
242
273
  end
243
274
 
275
+ # (internal) Checks if all options we need for the image cropper are provided
244
276
  def necessary_options_for_cropping_provided?(options)
245
277
  options[:crop].to_s == 'true' && !options[:image_size].blank?
246
278
  end
247
279
 
248
- # Renders translated Module Names for html title element.
280
+ # (internal) Renders translated Module Names for html title element.
249
281
  def render_alchemy_title
250
282
  if content_for?(:title)
251
283
  title = content_for(:title)
@@ -255,7 +287,7 @@ module Alchemy
255
287
  "Alchemy CMS - #{title}"
256
288
  end
257
289
 
258
- # Returns max image count as integer or nil. Used for the picture editor in element editor views.
290
+ # (internal) Returns max image count as integer or nil. Used for the picture editor in element editor views.
259
291
  def max_image_count
260
292
  return nil if !@options
261
293
  if @options[:maximum_amount_of_images].blank?
@@ -270,6 +302,7 @@ module Alchemy
270
302
  end
271
303
  end
272
304
 
305
+ # (internal) Renders a select tag for all items in the clipboard
273
306
  def clipboard_select_tag(items, html_options = {})
274
307
  options = [[t('Please choose'), ""]]
275
308
  items.each do |item|
@@ -287,7 +320,7 @@ module Alchemy
287
320
 
288
321
  # Renders a toolbar button for the Alchemy toolbar
289
322
  #
290
- # Options:
323
+ # == Options:
291
324
  #
292
325
  # :icon [String] # Icon class. See base.css.sccs for available icons, or make your own.
293
326
  # :label [String] # Text for button label.
@@ -304,7 +337,8 @@ module Alchemy
304
337
  :overlay => true,
305
338
  :skip_permission_check => false,
306
339
  :active => false,
307
- :link_options => {}
340
+ :link_options => {},
341
+ :overlay_options => {}
308
342
  }
309
343
  options = defaults.merge(options)
310
344
  button = content_tag('div', :class => 'button_with_label' + (options[:active] ? ' active' : '')) do
@@ -340,12 +374,12 @@ module Alchemy
340
374
  end
341
375
  end
342
376
 
343
- # Renders the alchemy backend toolbar
377
+ # Renders the Alchemy backend toolbar
344
378
  #
345
- # Options are:
379
+ # == Options
346
380
  #
347
- # buttons [Array] # Pass an Array with button options. They will be passed to toolbar_button helper. For options see +toolbar_button+
348
- # search [Boolean] # Show searchfield. Default true.
381
+ # :buttons [Array] # Pass an Array with button options. They will be passed to toolbar_button helper. For options see toolbar_button
382
+ # :search [Boolean] # Show searchfield. Default true.
349
383
  #
350
384
  def toolbar(options = {})
351
385
  defaults = {
@@ -362,16 +396,31 @@ module Alchemy
362
396
  end
363
397
  end
364
398
 
365
- # Renders the partial for a resource record in the resources table.
366
- # This helper has a nice fallback. If your resource has a partial for a single record named like the resouce model name (i.e. language) then this partial will be rendered.
367
- # Otherwise the resource parital from +resources/resource+
399
+ # Renders the row for a resource record in the resources table.
400
+ #
401
+ # This helper has a nice fallback. If you create a partial for your record then this partial will be rendered.
402
+ #
403
+ # Otherwise the default +app/views/alchemy/admin/resources/_resource.html.erb+ partial gets rendered.
404
+ #
405
+ # == Example
406
+ #
407
+ # For a resource named +Comment+ you can create a partial named +_comment.html.erb+
408
+ #
409
+ # # app/views/admin/comments/_comment.html.erb
410
+ # <tr>
411
+ # <td><%= comment.title %></td>
412
+ # <td><%= comment.body %></td>
413
+ # </tr>
414
+ #
415
+ # NOTE: Alchemy gives you a local variable named like your resource
416
+ #
368
417
  def render_resources
369
418
  render resources_instance_variable
370
419
  rescue ActionView::MissingTemplate
371
420
  render :partial => 'resource', :collection => resources_instance_variable
372
421
  end
373
422
 
374
- # Used by upload form
423
+ # (internal) Used by upload form
375
424
  def new_asset_path_with_session_information(asset_type)
376
425
  session_key = Rails.application.config.session_options[:key]
377
426
  if asset_type == "picture"