alchemy_cms 3.0.0.rc7 → 3.0.0.rc8

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 (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