alchemy_cms 3.0.0.rc7 → 3.0.0.rc8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -1
  3. data/README.md +1 -1
  4. data/app/assets/javascripts/alchemy/alchemy.dragndrop.js.coffee +0 -2
  5. data/app/assets/javascripts/alchemy/alchemy.element_editors.js.coffee +1 -1
  6. data/app/assets/javascripts/alchemy/alchemy.elements_window.js.coffee +26 -2
  7. data/app/assets/javascripts/alchemy/alchemy.preview_window.js.coffee +1 -1
  8. data/app/assets/javascripts/alchemy/alchemy.translations.js.coffee +22 -0
  9. data/app/assets/stylesheets/alchemy/base.scss +1 -5
  10. data/app/assets/stylesheets/alchemy/elements.scss +11 -61
  11. data/app/assets/stylesheets/alchemy/frame.scss +1 -1
  12. data/app/assets/stylesheets/tinymce/skins/alchemy/skin.min.css.scss +1 -1
  13. data/app/controllers/alchemy/admin/attachments_controller.rb +1 -1
  14. data/app/controllers/alchemy/admin/base_controller.rb +7 -13
  15. data/app/controllers/alchemy/admin/clipboard_controller.rb +15 -10
  16. data/app/controllers/alchemy/admin/elements_controller.rb +15 -11
  17. data/app/controllers/alchemy/admin/essence_pictures_controller.rb +8 -1
  18. data/app/controllers/alchemy/admin/pages_controller.rb +95 -22
  19. data/app/controllers/alchemy/admin/tags_controller.rb +1 -1
  20. data/app/controllers/alchemy/pictures_controller.rb +33 -32
  21. data/app/helpers/alchemy/admin/base_helper.rb +3 -16
  22. data/app/models/alchemy/element.rb +1 -1
  23. data/app/models/alchemy/page/page_naming.rb +4 -2
  24. data/app/models/alchemy/page/page_natures.rb +1 -1
  25. data/app/models/alchemy/page.rb +20 -1
  26. data/app/models/alchemy/picture.rb +1 -0
  27. data/app/models/alchemy/tree_node.rb +4 -0
  28. data/app/views/alchemy/admin/contents/destroy.js.erb +4 -0
  29. data/app/views/alchemy/admin/dashboard/index.html.erb +1 -1
  30. data/app/views/alchemy/admin/elements/_element.html.erb +11 -12
  31. data/app/views/alchemy/admin/elements/_new_element_form.html.erb +0 -3
  32. data/app/views/alchemy/admin/elements/create.js.erb +3 -3
  33. data/app/views/alchemy/admin/elements/index.html.erb +4 -19
  34. data/app/views/alchemy/admin/elements/new.html.erb +0 -3
  35. data/app/views/alchemy/admin/elements/trash.js.erb +12 -16
  36. data/app/views/alchemy/admin/pages/_page.html.erb +1 -1
  37. data/app/views/alchemy/admin/pages/edit.html.erb +36 -30
  38. data/app/views/alchemy/admin/pictures/edit_multiple.html.erb +1 -1
  39. data/app/views/alchemy/admin/trash/clear.js.erb +4 -0
  40. data/config/locales/alchemy.de.yml +56 -84
  41. data/config/locales/alchemy.en.yml +326 -105
  42. data/config/locales/alchemy.fr.yml +942 -0
  43. data/config/locales/alchemy.nl.yml +111 -137
  44. data/config/locales/simple_form.fr.yml +26 -0
  45. data/lib/alchemy/engine.rb +7 -1
  46. data/lib/alchemy/i18n.rb +7 -1
  47. data/lib/alchemy/middleware/rescue_old_cookies.rb +27 -0
  48. data/lib/alchemy/permissions.rb +1 -1
  49. data/lib/alchemy/version.rb +1 -1
  50. data/spec/controllers/admin/clipboard_controller_spec.rb +16 -19
  51. data/spec/controllers/admin/elements_controller_spec.rb +20 -23
  52. data/spec/controllers/admin/essence_pictures_controller_spec.rb +22 -6
  53. data/spec/controllers/admin/pages_controller_spec.rb +94 -5
  54. data/spec/controllers/pictures_controller_spec.rb +44 -3
  55. data/spec/features/admin/link_overlay_spec.rb +1 -0
  56. data/spec/features/admin/locale_select_feature_spec.rb +22 -0
  57. data/spec/libraries/i18n_spec.rb +30 -0
  58. data/spec/libraries/permissions_spec.rb +1 -1
  59. data/spec/models/element_spec.rb +5 -4
  60. data/spec/models/page_spec.rb +137 -8
  61. data/spec/spec_helper.rb +23 -19
  62. data/vendor/assets/javascripts/jquery_plugins/jquery.ui.nestedSortable.js +9 -3
  63. metadata +12 -10
  64. data/app/models/alchemy/clipboard.rb +0 -74
  65. data/app/views/alchemy/admin/contents/destroy.js.coffee +0 -4
  66. data/app/views/alchemy/admin/elements/_add_element_button.html.erb +0 -18
  67. data/app/views/alchemy/admin/trash/clear.js.coffee +0 -4
  68. data/spec/models/clipboard_spec.rb +0 -111
  69. data/spec/support/phantomjs_mavericks_fix.rb +0 -32
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 02135f0ba23a59280b20309cec71a326a544ff42
4
- data.tar.gz: 053e8ad503e06ae42a9c07435c41ef161828161e
3
+ metadata.gz: dcb7647a1797d45f8881a956cde924671bc30f2d
4
+ data.tar.gz: 7b9dee0e4b299543fe51364f7c3be41b70e6e2e5
5
5
  SHA512:
6
- metadata.gz: 19c8cb6b48175d8b27345fff351ff9d5acea1e7a95af065e2c2094a44f6428474f79b6d1d5a8be2ac7aaf78068295c4a41131d4a9a6d1cdff975046a53462e47
7
- data.tar.gz: e182d4b3f9a33a1e2c148e83b8b0824df7474d5c952cfdc3ab42c7c3bf612d8992df8dc4eab8ddd6db0ba614f214e3e2edd8a94469a568fbf829296d7a88a894
6
+ metadata.gz: 3d184d7e8aac2c27eea62560fa1ff1140500ee0b59a07a6009fbcf4ec33ca2926c5a789953e7bb70bd9ed8bc0da662394bde3d8692ba9e6afacac8107fcd08a8
7
+ data.tar.gz: ec05398a5321e6a0e709329aec857b6bc4b3031eb8f160a59ea39d66b0e95ac1b52c7fa0043aa4751dbc0ce4dd52bed366444ceaf18570ce5b5052e3376ea90d
data/Gemfile CHANGED
@@ -12,12 +12,13 @@ gem 'coveralls', require: false
12
12
  # Fixes issues with wrong exit codes. See: https://github.com/colszowka/simplecov/issues/269
13
13
  gem 'simplecov', '0.7.1'
14
14
 
15
+ gem 'database_cleaner'
16
+
15
17
  group :test do
16
18
  gem 'sqlite3' if ENV['DB'].nil? || ENV['DB'] == 'sqlite'
17
19
  gem 'mysql2' if ENV['DB'] == 'mysql'
18
20
  gem 'pg' if ENV['DB'] == 'postgresql'
19
21
  gem 'poltergeist'
20
- gem 'connection_pool' # https://gist.github.com/mperham/3049152
21
22
  unless ENV['CI']
22
23
  gem 'launchy'
23
24
  end
data/README.md CHANGED
@@ -60,7 +60,7 @@ Installation
60
60
 
61
61
  #### 1. Use the installer:
62
62
 
63
- gem install alchemy_cms
63
+ gem install alchemy_cms --pre
64
64
  alchemy new my_magicpage
65
65
  cd my_magicpage
66
66
 
@@ -47,11 +47,9 @@ $.extend Alchemy,
47
47
  Alchemy.TrashWindow.refresh page_id
48
48
 
49
49
  start: (event, ui) ->
50
- ui.helper.find('.insert-element-button').hide()
51
50
  Alchemy.Tinymce.remove getTinymceIDs(ui)
52
51
 
53
52
  stop: (event, ui) ->
54
- ui.item.find('.insert-element-button').show()
55
53
  Alchemy.Tinymce.init getTinymceIDs(ui)
56
54
 
57
55
  SortableContents: (selector, token) ->
@@ -39,7 +39,7 @@ Alchemy.ElementEditors =
39
39
  #
40
40
  onClickElement: (e) ->
41
41
  self = Alchemy.ElementEditors
42
- $element = $(this).parents(".element_editor")
42
+ $element = $(this).parent(".element_editor")
43
43
  id = $element.attr("id").replace(/\D/g, "")
44
44
  e.preventDefault()
45
45
  $("#element_area .element_editor").removeClass "selected"
@@ -1,5 +1,22 @@
1
1
  window.Alchemy = {} if typeof(window.Alchemy) is 'undefined'
2
2
 
3
+ # Adds buttons into a toolbar inside of overlay windows
4
+ Alchemy.ToolbarButton = (options) ->
5
+ $btn = $('<div class="button_with_label" />')
6
+ if options.buttonId
7
+ $btn.attr(id: options.buttonId)
8
+ $lnk = $("<a title='#{options.title}' class='icon_button' href='#' />")
9
+ if options.hotkey
10
+ $lnk.attr('data-alchemy-hotkey', options.hotkey)
11
+ $lnk.click (e) ->
12
+ e.preventDefault()
13
+ options.onClick(e)
14
+ false
15
+ $lnk.append "<span class='icon #{options.iconClass}' />"
16
+ $btn.append $lnk
17
+ $btn.append "<br><label>#{options.label}</label>"
18
+ $btn
19
+
3
20
  Alchemy.ElementsWindow =
4
21
 
5
22
  init: (url, options, callback) ->
@@ -9,6 +26,7 @@ Alchemy.ElementsWindow =
9
26
  @url = url
10
27
  @options = options
11
28
  @callback = callback
29
+ @element_window.append @createToolbar(options.toolbarButtons)
12
30
  @element_window.append @element_area
13
31
  @button = $('#element_window_button')
14
32
  @button.click =>
@@ -21,12 +39,18 @@ Alchemy.ElementsWindow =
21
39
  $('#main_content').append(@element_window)
22
40
  @reload()
23
41
 
42
+ createToolbar: (buttons) ->
43
+ @toolbar = $('<div id="overlay_toolbar"/>')
44
+ for btn in buttons
45
+ @toolbar.append Alchemy.ToolbarButton(btn)
46
+ @toolbar
47
+
24
48
  resize: ->
25
- height = $(window).height() - 75
49
+ height = $(window).height() - 73
26
50
  @element_window.css
27
51
  height: height
28
52
  @element_area.css
29
- height: height
53
+ height: height - 46
30
54
  height
31
55
 
32
56
  reload: ->
@@ -19,7 +19,7 @@ Alchemy.PreviewWindow =
19
19
  width = $window.width() - 64
20
20
  else
21
21
  width = $window.width() - 466
22
- height = $window.height() - 75
22
+ height = $window.height() - 73
23
23
  width = 240 if width < 240
24
24
  @currentWidth = width
25
25
  @currentWindow.css
@@ -66,3 +66,25 @@ Alchemy.translations =
66
66
  'File type not allowed': 'File type not allowed'
67
67
  'Maximum number of files exceeded': 'Uploadlimiet bereikt.'
68
68
  'Uploaded bytes exceed file size': 'Uploaded bytes exceed file size'
69
+
70
+
71
+ # French
72
+ fr:
73
+ allowed_chars: 'von %{count} signes'
74
+ cancel: 'abandonner'
75
+ cancelled: 'annulé'
76
+ click_to_edit: 'Cliquez pour modifier'
77
+ complete: 'terminé'
78
+ element_dirty_notice: 'Cet élément a des modifications non enregistrées. Souhaitez-vous vraiment plier?'
79
+ help: 'Aide'
80
+ ok: 'Ok'
81
+ page_dirty_notice: 'Vous avez des modifications non enregistrées sur la page. Ce sera perdue si vous continuez.'
82
+ page_found: 'page trouvée'
83
+ pages_found: 'pages trouvées'
84
+ url_validation_failed: "L'URL n'est pas correctement formatée."
85
+ warning: 'Attention!'
86
+ 'File is too large': 'Le fichier est trop grand.'
87
+ 'File is too small': 'Le fichier est trop petit.'
88
+ 'File type not allowed': 'Type de document non autorisé.'
89
+ 'Maximum number of files exceeded': 'Le nombre maximum de fichiers est atteint.'
90
+ 'Uploaded bytes exceed file size': 'Taille de fichier maximale autorisée atteint.'
@@ -542,10 +542,6 @@ select#url_protocol.medium {
542
542
  overflow-x: hidden;
543
543
  overflow-y: auto;
544
544
  margin-bottom: 1em;
545
-
546
- .insert-element-button {
547
- display: none;
548
- }
549
545
  }
550
546
 
551
547
  .mceEditor table {
@@ -560,7 +556,7 @@ div.browse {
560
556
  @include box-sizing(border-box);
561
557
  position: absolute;
562
558
  left: 66px;
563
- top: 75px;
559
+ top: 73px;
564
560
  width: auto;
565
561
  height: auto;
566
562
  border: 0 none;
@@ -2,7 +2,7 @@
2
2
  @include box-sizing(border-box);
3
3
  position: absolute;
4
4
  right: 0;
5
- top: 75px;
5
+ top: 73px;
6
6
  width: 400px;
7
7
  height: auto;
8
8
  border-left: $default-border;
@@ -25,50 +25,6 @@
25
25
  }
26
26
  }
27
27
 
28
- .insert-element-button {
29
- display: block;
30
- text-align: center;
31
- margin-bottom: 2 * $default-margin;
32
- background-color: transparent;
33
- border: 1px solid $medium-gray;
34
- height: 20px;
35
- line-height: 20px;
36
- @extend %rounded-border;
37
- @include transition(all 100ms ease-in-out);
38
-
39
- &:hover, &.expanded {
40
- height: 30px;
41
- line-height: 30px;
42
- background-color: darken($medium-gray, 2%);
43
- text-decoration: none;
44
- cursor: pointer;
45
- border-color: darken($medium-gray, 2%);
46
-
47
- label { display: inline-block; }
48
- .icon { @include opacity(1) }
49
- }
50
-
51
- &.expanded:hover {
52
- background-color: darken($medium-gray, 5%);
53
-
54
- label { color: #000 }
55
- }
56
-
57
- label {
58
- display: inline-block;
59
- vertical-align: middle;
60
- cursor: pointer;
61
- display: none;
62
- }
63
-
64
- .icon {
65
- display: inline-block;
66
- vertical-align: text-top;
67
- @include opacity(0.7);
68
- @include transition(opacity 100ms ease-in-out);
69
- }
70
- }
71
-
72
28
  .element_heading {
73
29
  padding: 0;
74
30
  z-index: 0;
@@ -165,7 +121,10 @@ span.preview_text_element_name {
165
121
  }
166
122
 
167
123
  .element_editor {
124
+ border: 1px solid $default-border-color;
125
+ @extend %rounded-border;
168
126
  background-color: $light-gray;
127
+ margin-bottom: 2*$default-margin;
169
128
 
170
129
  &.not-draggable {
171
130
  @include opacity(0.5);
@@ -179,17 +138,14 @@ span.preview_text_element_name {
179
138
  }
180
139
  }
181
140
 
182
- &.selected > .edit_element {
141
+ &.selected {
183
142
  border-color: $blue;
184
143
  @include box-shadow(0 0 4px $blue);
185
144
  }
186
145
 
187
146
  form {
188
147
  margin: 0;
189
- padding: 0 8px;
190
- margin-bottom: 2*$default-margin;
191
- border: $default-border;
192
- @include border-radius($default-border-radius);
148
+ padding: 8px 8px 0 8px;
193
149
  }
194
150
 
195
151
  .validation_notice {
@@ -246,22 +202,14 @@ span.preview_text_element_name {
246
202
 
247
203
  .element_head, .element_foot {
248
204
  position: relative;
249
- background-color: $medium-gray;
250
- margin-left: -8px;
251
- margin-right: -8px;
252
205
  }
253
206
 
254
207
  .element_head {
255
208
  padding: 8px 0 6px;
256
- margin-bottom: 2*$default-margin;
209
+ margin-bottom: 0;
257
210
  height: 20px;
211
+ background-color: $medium-gray;
258
212
  @extend .disable-user-select;
259
- @include border-top-radius($default-border-radius);
260
-
261
- .folded & {
262
- margin-bottom: 0;
263
- @include border-bottom-radius($default-border-radius);
264
- }
265
213
 
266
214
  .spinner {
267
215
  top: 9px;
@@ -273,7 +221,9 @@ span.preview_text_element_name {
273
221
  padding: 2*$default-padding;
274
222
  width: 100%;
275
223
  height: 29px;
276
- @include border-bottom-radius($default-border-radius);
224
+ margin-left: -8px;
225
+ margin-right: -8px;
226
+ background-color: $medium-gray;
277
227
 
278
228
  .element_tools {
279
229
  float: left;
@@ -142,7 +142,7 @@ div#overlay_text_box {
142
142
  #main_content {
143
143
  @include box-sizing(border-box);
144
144
  background-color: $light-gray;
145
- padding: 83px 8px 8px 74px;
145
+ padding: 73px 8px 8px 74px;
146
146
  z-index: 0;
147
147
  width: 100%;
148
148
  height: 100%;
@@ -21,7 +21,7 @@
21
21
  line-height: normal;
22
22
  font-weight: normal;
23
23
  text-align: left;
24
- @include box-sizing(border-box);
24
+ @include box-sizing(content-box);
25
25
  direction: ltr;
26
26
  }
27
27
 
@@ -58,7 +58,7 @@ module Alchemy
58
58
  page: params[:page],
59
59
  query: params[:query]
60
60
  )
61
- flash[:notice] = _t("File: '%{name}' deleted successfully", name: name)
61
+ flash[:notice] = _t('File deleted successfully', name: name)
62
62
  end
63
63
 
64
64
  def download
@@ -59,21 +59,15 @@ module Alchemy
59
59
  end
60
60
  end
61
61
 
62
- def get_clipboard
63
- session[:clipboard] ||= Clipboard.new
64
- rescue NoMethodError => e
65
- exception_logger(e)
66
- @notice = "You have an old style clipboard in your session. Please remove your cookies and try again."
67
- render :action => "error_notice", :layout => false
62
+ # Returns clipboard items for given category
63
+ def get_clipboard(category)
64
+ session[:alchemy_clipboard] ||= {}
65
+ session[:alchemy_clipboard][category.to_s] ||= []
68
66
  end
69
67
 
70
- def clipboard_empty?(category = nil)
71
- return true if session[:clipboard].blank?
72
- if category
73
- session[:clipboard][category.pluralize].blank?
74
- else
75
- false
76
- end
68
+ # Checks if clipboard for given category is blank
69
+ def clipboard_empty?(category)
70
+ get_clipboard(category).blank?
77
71
  end
78
72
 
79
73
  def trash_empty?(category)
@@ -1,21 +1,23 @@
1
1
  module Alchemy
2
2
  module Admin
3
3
  class ClipboardController < Alchemy::Admin::BaseController
4
- authorize_resource class: Alchemy::Clipboard
4
+ authorize_resource class: :alchemy_admin_clipboard
5
+ before_filter :set_clipboard
5
6
 
6
7
  def index
7
- @clipboard = get_clipboard
8
- @clipboard_items = model_class.all_from_clipboard(@clipboard.all(params[:remarkable_type]))
8
+ @clipboard_items = model_class.all_from_clipboard(@clipboard)
9
9
  respond_to do |format|
10
10
  format.html
11
11
  end
12
12
  end
13
13
 
14
14
  def insert
15
- @clipboard = get_clipboard
16
15
  @item = model_class.find(params[:remarkable_id])
17
- unless @clipboard.contains? params[:remarkable_type], params[:remarkable_id]
18
- @clipboard.push params[:remarkable_type], {:id => params[:remarkable_id], :action => params[:remove] ? 'cut' : 'copy'}
16
+ unless @clipboard.detect { |item| item['id'] == params[:remarkable_id] }
17
+ @clipboard << {
18
+ 'id' => params[:remarkable_id],
19
+ 'action' => params[:remove] ? 'cut' : 'copy'
20
+ }
19
21
  end
20
22
  respond_to do |format|
21
23
  format.js
@@ -23,19 +25,22 @@ module Alchemy
23
25
  end
24
26
 
25
27
  def remove
26
- @clipboard = get_clipboard
27
28
  @item = model_class.find(params[:remarkable_id])
28
- @clipboard.remove params[:remarkable_type], params[:remarkable_id]
29
+ @clipboard.delete_if { |item| item['id'] == params[:remarkable_id] }
29
30
  respond_to do |format|
30
31
  format.js
31
32
  end
32
33
  end
33
34
 
34
35
  def clear
35
- session[:clipboard].clear(params[:remarkable_type])
36
+ @clipboard.clear
36
37
  end
37
38
 
38
- private
39
+ private
40
+
41
+ def set_clipboard
42
+ @clipboard = get_clipboard(params[:remarkable_type])
43
+ end
39
44
 
40
45
  def model_class
41
46
  "alchemy/#{params[:remarkable_type]}".classify.constantize
@@ -26,7 +26,8 @@ module Alchemy
26
26
  @page = Page.find_by_id(params[:page_id])
27
27
  @element = @page.elements.build
28
28
  @elements = @page.available_element_definitions
29
- @clipboard_items = Element.all_from_clipboard_for_page(get_clipboard[:elements], @page)
29
+ @clipboard = get_clipboard('elements')
30
+ @clipboard_items = Element.all_from_clipboard_for_page(@clipboard, @page)
30
31
  end
31
32
 
32
33
  # Creates a element as discribed in config/alchemy/elements.yml on page via AJAX.
@@ -44,10 +45,8 @@ module Alchemy
44
45
  end
45
46
  @element.save
46
47
  end
47
- if params[:insert_after].present?
48
- @element_before = Element.find(params[:insert_after])
49
- @element.insert_at(@element_before.position + 1)
50
- else
48
+ if @page.definition['insert_elements_at'] == 'top'
49
+ @insert_at_top = true
51
50
  @element.move_to_top
52
51
  end
53
52
  end
@@ -57,7 +56,8 @@ module Alchemy
57
56
  else
58
57
  @element.page = @page
59
58
  @elements = @page.available_element_definitions
60
- @clipboard_items = Element.all_from_clipboard_for_page(get_clipboard[:elements], @page)
59
+ @clipboard = get_clipboard('elements')
60
+ @clipboard_items = Element.all_from_clipboard_for_page(@clipboard, @page)
61
61
  render :new
62
62
  end
63
63
  end
@@ -128,24 +128,28 @@ module Alchemy
128
128
  end
129
129
 
130
130
  def element_from_clipboard
131
- @clipboard = get_clipboard
132
- @clipboard.get(:elements, params[:paste_from_clipboard])
131
+ @element_from_clipboard ||= begin
132
+ @clipboard = get_clipboard('elements')
133
+ @clipboard.detect { |item| item['id'].to_i == params[:paste_from_clipboard].to_i }
134
+ end
133
135
  end
134
136
 
135
137
  def paste_element_from_clipboard
136
- @source_element = Element.find(element_from_clipboard[:id])
138
+ @source_element = Element.find(element_from_clipboard['id'])
137
139
  new_attributes = {:page_id => @page.id}
138
140
  if @page.can_have_cells?
139
141
  new_attributes = new_attributes.merge({:cell_id => find_or_create_cell.try(:id)})
140
142
  end
141
143
  element = Element.copy(@source_element, new_attributes)
142
- cut_element if element_from_clipboard[:action] == 'cut'
144
+ if element_from_clipboard['action'] == 'cut'
145
+ cut_element
146
+ end
143
147
  element
144
148
  end
145
149
 
146
150
  def cut_element
147
151
  @cutted_element_id = @source_element.id
148
- @clipboard.remove :elements, @source_element.id
152
+ @clipboard.delete_if { |item| item['id'] == @source_element.id.to_s }
149
153
  @source_element.destroy
150
154
  end
151
155