locomotive_cms 2.4.1 → 2.5.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/README.textile +3 -3
  4. data/app/assets/images/locomotive/icons/flags/sk.png +0 -0
  5. data/app/assets/javascripts/aloha/plugins/custom/locomotive_media/lib/locomotive_media-plugin.js +1 -1
  6. data/app/assets/javascripts/locomotive/models/content_asset.js.coffee +7 -1
  7. data/app/assets/javascripts/locomotive/utils/aloha_settings.js.coffee +1 -1
  8. data/app/assets/javascripts/locomotive/utils/core_ext.js +1 -1
  9. data/app/assets/javascripts/locomotive/views/content_assets/picker_item_view.js.coffee +12 -0
  10. data/app/assets/javascripts/locomotive/views/content_assets/picker_view.js.coffee +149 -15
  11. data/app/assets/javascripts/locomotive/views/shared/asset_picker_view.js.coffee +16 -4
  12. data/app/assets/javascripts/locomotive/views/shared/form_view.js.coffee +1 -1
  13. data/app/assets/javascripts/locomotive/views/shared/list_item_view.js.coffee +1 -1
  14. data/app/assets/javascripts/tinymce/plugins/locomotive_media/editor_plugin.js +1 -1
  15. data/app/assets/stylesheets/locomotive/backoffice/_buttons.css.scss +56 -0
  16. data/app/assets/stylesheets/locomotive/backoffice/application.css.scss +6 -0
  17. data/app/assets/stylesheets/locomotive/backoffice/content_assets.css.scss +74 -4
  18. data/app/assets/stylesheets/locomotive/backoffice/dialog_changes.css.scss +4 -0
  19. data/app/assets/stylesheets/locomotive/shared/common.css.scss +7 -0
  20. data/app/controllers/locomotive/api/documentation_controller.rb +8 -2
  21. data/app/controllers/locomotive/api/pages_controller.rb +1 -1
  22. data/app/controllers/locomotive/content_assets_controller.rb +4 -0
  23. data/app/models/locomotive/content_asset.rb +5 -1
  24. data/app/models/locomotive/content_entry.rb +7 -2
  25. data/app/models/locomotive/content_type.rb +1 -1
  26. data/app/models/locomotive/editable_element.rb +1 -0
  27. data/app/models/locomotive/extensions/asset/types.rb +9 -4
  28. data/app/models/locomotive/extensions/asset/vignette.rb +2 -0
  29. data/app/models/locomotive/extensions/content_entry/csv.rb +2 -2
  30. data/app/models/locomotive/extensions/content_entry/localized.rb +18 -0
  31. data/app/models/locomotive/page.rb +2 -2
  32. data/app/models/locomotive/snippet.rb +8 -7
  33. data/app/models/locomotive/theme_asset.rb +12 -6
  34. data/app/models/locomotive/translation.rb +1 -1
  35. data/app/views/locomotive/content_assets/_picker.html.haml +23 -2
  36. data/app/views/locomotive/pages/_page.html.haml +2 -0
  37. data/app/views/locomotive/shared/_header.html.haml +3 -1
  38. data/app/views/locomotive/shared/_main_app_header.html.haml +1 -0
  39. data/app/views/locomotive/translations/index.html.haml +1 -1
  40. data/config/locales/admin_ui.bg.yml +1 -0
  41. data/config/locales/admin_ui.cs.yml +1 -0
  42. data/config/locales/admin_ui.de.yml +1 -0
  43. data/config/locales/admin_ui.en.yml +7 -0
  44. data/config/locales/admin_ui.es.yml +1 -0
  45. data/config/locales/admin_ui.et.yml +1 -0
  46. data/config/locales/admin_ui.fr.yml +12 -2
  47. data/config/locales/admin_ui.it.yml +1 -0
  48. data/config/locales/admin_ui.ja.yml +1 -0
  49. data/config/locales/admin_ui.nb.yml +1 -0
  50. data/config/locales/admin_ui.nl.yml +1 -0
  51. data/config/locales/admin_ui.pl.yml +1 -0
  52. data/config/locales/admin_ui.pt-BR.yml +1 -0
  53. data/config/locales/admin_ui.ru.yml +8 -4
  54. data/config/locales/admin_ui.sk.yml +360 -0
  55. data/config/locales/admin_ui.zh-CN.yml +1 -0
  56. data/config/locales/carrierwave.sk.yml +4 -0
  57. data/config/locales/default.fr.yml +3 -0
  58. data/config/locales/default.ru.yml +18 -7
  59. data/config/locales/default.sk.yml +249 -0
  60. data/config/locales/devise.sk.yml +64 -0
  61. data/config/locales/flash.sk.yml +115 -0
  62. data/config/locales/formtastic.fr.yml +7 -1
  63. data/config/locales/formtastic.sk.yml +125 -0
  64. data/config/routes.rb +2 -0
  65. data/lib/generators/locomotive/install/install_generator.rb +6 -0
  66. data/lib/generators/locomotive/install/templates/dragonfly.rb +16 -13
  67. data/lib/generators/locomotive/install/templates/locomotive.rb +7 -2
  68. data/lib/locomotive.rb +3 -15
  69. data/lib/locomotive/action_controller/responder.rb +8 -1
  70. data/lib/locomotive/carrierwave/asset.rb +0 -4
  71. data/lib/locomotive/configuration.rb +4 -3
  72. data/lib/locomotive/dragonfly.rb +20 -5
  73. data/lib/locomotive/liquid/drops/content_entry.rb +1 -1
  74. data/lib/locomotive/liquid/filters/base.rb +4 -0
  75. data/lib/locomotive/liquid/filters/translate.rb +4 -0
  76. data/lib/locomotive/liquid/tags/path_helper.rb +5 -2
  77. data/lib/locomotive/middlewares.rb +2 -1
  78. data/lib/locomotive/misc/api_documentation.rb +3 -1
  79. data/lib/locomotive/render.rb +7 -6
  80. data/lib/locomotive/version.rb +1 -1
  81. data/lib/tasks/development.rake +21 -0
  82. data/spec/dummy/config/initializers/dragonfly.rb +16 -13
  83. data/spec/dummy/config/initializers/locomotive.rb +9 -5
  84. data/spec/fixtures/assets/specs.pdf +0 -0
  85. data/spec/lib/locomotive/liquid/filters/html_spec.rb +22 -13
  86. data/spec/models/locomotive/content_asset_spec.rb +9 -0
  87. data/spec/models/locomotive/content_entry_spec.rb +57 -6
  88. data/spec/models/locomotive/extensions/content_entry/csv_spec.rb +30 -0
  89. data/spec/support/locomotive.rb +2 -1
  90. data/vendor/assets/javascripts/locomotive/ICanHandlebarz.js +1 -1
  91. data/vendor/assets/javascripts/locomotive/backbone.sync.js +14 -1
  92. metadata +34 -9
  93. data/lib/locomotive/middlewares/cache.rb +0 -27
@@ -10,6 +10,7 @@ ul.content-assets {
10
10
  list-style: none;
11
11
  margin: 0px;
12
12
  padding: 0px;
13
+ background: transparent;
13
14
 
14
15
  li.asset {
15
16
  position: relative;
@@ -41,15 +42,34 @@ ul.content-assets {
41
42
  @include background-image(linear-gradient(#ebedf4, #d7dbe7));
42
43
  border-bottom: 1px solid #ccced7;
43
44
 
45
+ padding-left: 5px;
46
+ font-size: 11px;
47
+ color: #333;
48
+ font-weight: bold;
49
+
44
50
  a {
45
51
  @include hover-link;
46
52
 
47
- margin-left: 5px;
48
53
  outline: none;
49
-
50
- font-size: 11px;
51
54
  color: #1f82bc;
52
- font-weight: bold;
55
+ }
56
+ }
57
+
58
+ .uploading {
59
+ margin: 54px 10px 0 10px;
60
+ padding: 2px;
61
+ height: 14px;
62
+ background: #333;
63
+ border-bottom: 1px solid #fff;
64
+ @include border-radius(10px);
65
+
66
+ .progress-bar {
67
+ display: inline-block;
68
+ width: 20%;
69
+ height: 13px;
70
+ border-top: 1px solid #d6f6ff;
71
+ @include background-image(linear-gradient(#65c3ff, #008ced));
72
+ @include border-radius(10px);
53
73
  }
54
74
  }
55
75
 
@@ -127,4 +147,54 @@ ul.content-assets {
127
147
 
128
148
  } // li.asset
129
149
 
150
+ }
151
+
152
+ .content-asset-picker-dialog {
153
+
154
+ .ui-dialog-content {
155
+ padding: 0px !important;
156
+ }
157
+
158
+ .ui-dialog-titlebar {
159
+ border-bottom: 1px solid transparent !important;
160
+ }
161
+
162
+ .filter-and-search {
163
+ @include background-image(linear-gradient(#55565c, #45454a));
164
+ padding: 10px 10px;
165
+ border-bottom: 1px solid #000;
166
+
167
+ .search-bar {
168
+ position: relative;
169
+ float: right;
170
+
171
+ input {
172
+ @include border-radius(20px);
173
+ outline: none;
174
+ border: 0px;
175
+ font-size: 12px;
176
+ padding: 3px 10px 3px 30px;
177
+ line-height: 20px;
178
+ z-index: 100;
179
+ width: 150px;
180
+ }
181
+
182
+ i.icon-search {
183
+ position: absolute;
184
+ left: 10px;
185
+ top: 2px;
186
+ font-size: 18px;
187
+ z-index: 101;
188
+ }
189
+ }
190
+ }
191
+
192
+ ul.content-assets {
193
+ padding: 10px;
194
+ margin: 0px;
195
+ }
196
+
197
+ .no-items {
198
+ margin: 50px 10px 0px;
199
+ }
130
200
  }
@@ -72,6 +72,10 @@
72
72
  height: 360px;
73
73
  }
74
74
 
75
+ &.hovered {
76
+ background: rgba(224, 237, 253, 1);
77
+ }
78
+
75
79
  form.formtastic {
76
80
  fieldset {
77
81
  legend, ol {
@@ -33,3 +33,10 @@ p.no-items {
33
33
  color: #ff2900;
34
34
  }
35
35
  }
36
+
37
+ /* ___ stop window scrolling (when an ui-dialog is open) ___ */
38
+
39
+ .stop-scrolling {
40
+ height: 100%;
41
+ overflow: hidden;
42
+ }
@@ -2,14 +2,20 @@ require 'locomotive/misc/api_documentation'
2
2
 
3
3
  module Locomotive
4
4
  module Api
5
-
6
5
  class DocumentationController < ApplicationController
7
6
 
7
+ before_filter :require_account
8
+
8
9
  def show
9
10
  render text: Locomotive::Misc::ApiDocumentation.generate
10
11
  end
11
12
 
12
- end
13
+ protected
13
14
 
15
+ def require_account
16
+ authenticate_locomotive_account!
17
+ end
18
+
19
+ end
14
20
  end
15
21
  end
@@ -2,7 +2,7 @@ module Locomotive
2
2
  module Api
3
3
  class PagesController < BaseController
4
4
 
5
- load_and_authorize_resource class: Locomotive::Page, through: :current_site
5
+ load_and_authorize_resource class: ::Locomotive::Page, through: :current_site
6
6
 
7
7
  def index
8
8
  @pages = @pages.order_by(:depth.asc, :position.asc)
@@ -5,6 +5,10 @@ module Locomotive
5
5
 
6
6
  def index
7
7
  @content_assets = current_site.content_assets
8
+ .ordered
9
+ .by_content_types(params[:types])
10
+ .by_filename(params[:query])
11
+ .page(params[:page] || 1).per(params[:per_page] || Locomotive.config.ui[:per_page])
8
12
  respond_with(@content_assets)
9
13
  end
10
14
 
@@ -15,7 +15,7 @@ module Locomotive
15
15
  field :position, type: Integer, default: 0
16
16
 
17
17
  ## associations ##
18
- belongs_to :site, class_name: 'Locomotive::Site'
18
+ belongs_to :site, class_name: 'Locomotive::Site', validate: false, autosave: false
19
19
 
20
20
  ## validations ##
21
21
  validates_presence_of :source
@@ -23,6 +23,10 @@ module Locomotive
23
23
  ## behaviours ##
24
24
  mount_uploader :source, ContentAssetUploader, mount_on: :source_filename
25
25
 
26
+ ## scopes ##
27
+ scope :ordered, order_by(created_at: :desc)
28
+ scope :by_filename, ->(query) { where(source_filename: /.*#{query}.*/i) }
29
+
26
30
  ## methods ##
27
31
 
28
32
  alias :name :source_filename
@@ -20,7 +20,7 @@ module Locomotive
20
20
  validates_uniqueness_of :_slug, scope: :content_type_id, allow_blank: true
21
21
 
22
22
  ## associations ##
23
- belongs_to :site, class_name: 'Locomotive::Site'
23
+ belongs_to :site, class_name: 'Locomotive::Site', validate: false, autosave: false
24
24
  belongs_to :content_type, class_name: 'Locomotive::ContentType', inverse_of: :entries, custom_fields_parent_klass: true
25
25
 
26
26
  ## callbacks ##
@@ -130,7 +130,12 @@ module Locomotive
130
130
  # @return [ Object ] The next or previous content entry or nil if none
131
131
  #
132
132
  def next_or_previous(matcher = :gt)
133
- attribute, direction = self.content_type.order_by_definition(matcher == :lt)
133
+ # the matchers is supposed to be fine for the default direction, meaning 'asc'
134
+ # if the direction is not ascending, we need to reverse the matcher
135
+ matcher = matcher == :gt ? :lt : :gt if self.content_type.order_direction != 'asc'
136
+
137
+ attribute = self.content_type.order_by_attribute
138
+ direction = matcher == :gt ? 'asc' : 'desc'
134
139
 
135
140
  criterion = attribute.to_sym.send(matcher)
136
141
  value = self.send(attribute.to_sym)
@@ -22,7 +22,7 @@ module Locomotive
22
22
  field :public_submission_accounts, type: Array
23
23
 
24
24
  ## associations ##
25
- belongs_to :site, class_name: 'Locomotive::Site'
25
+ belongs_to :site, class_name: 'Locomotive::Site', validate: false
26
26
  has_many :entries, class_name: 'Locomotive::ContentEntry', dependent: :destroy do
27
27
 
28
28
  def find_by_id_or_permalink(id_or_permalink)
@@ -34,6 +34,7 @@ module Locomotive
34
34
 
35
35
  def disabled_in_all_translations?
36
36
  return self.disabled_translations if self.disabled_translations.is_a?(Boolean)
37
+ return false if disabled_translations.blank?
37
38
  self.disabled_translations.all? { |_, v| v == true }
38
39
  end
39
40
 
@@ -6,7 +6,10 @@ module Locomotive
6
6
  extend ActiveSupport::Concern
7
7
 
8
8
  included do
9
- %w{media image stylesheet javascript font pdf}.each do |type|
9
+ scope :by_content_type, ->(content_type) { content_type.blank? ? all : where(content_type: content_type.to_s) }
10
+ scope :by_content_types, ->(content_types) { content_types.blank? ? all : where(:content_type.in => [*content_types]) }
11
+
12
+ all_types.each do |type|
10
13
  scope :"only_#{type}", where(content_type: type)
11
14
 
12
15
  define_method("#{type}?") do
@@ -17,10 +20,12 @@ module Locomotive
17
20
 
18
21
  module ClassMethods
19
22
 
20
- def by_content_type(content_type)
21
- return self.all if content_type.blank?
23
+ def all_types
24
+ %w{image pdf media stylesheet javascript font}
25
+ end
22
26
 
23
- self.all.where(content_type: content_type.to_s)
27
+ def types_for_content_editing
28
+ all_types - %w(stylesheet javascript font)
24
29
  end
25
30
 
26
31
  end
@@ -10,6 +10,8 @@ module Locomotive
10
10
  else
11
11
  Locomotive::Dragonfly.resize_url(self.source, '85x85#')
12
12
  end
13
+ elsif self.pdf?
14
+ Locomotive::Dragonfly.thumbnail_pdf(self.source, '85x85#')
13
15
  end
14
16
  end
15
17
 
@@ -43,7 +43,7 @@ module Locomotive
43
43
  when :tags
44
44
  [*value].join(', ')
45
45
  else
46
- value
46
+ value == nil ? '' : value
47
47
  end
48
48
  end
49
49
 
@@ -79,4 +79,4 @@ module Locomotive
79
79
  end
80
80
  end
81
81
  end
82
- end
82
+ end
@@ -3,6 +3,18 @@ module Locomotive
3
3
  module ContentEntry
4
4
  module Localized
5
5
 
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+
10
+ ## fields ##
11
+ field :_translated, type: Boolean, localize: true
12
+
13
+ ## callbacks ##
14
+ before_save :persist_translated_status
15
+
16
+ end
17
+
6
18
  # Tell if the content entry has been translated or not.
7
19
  # It just checks if the field used for the label has been translated.
8
20
  # It assumes the entry is localized.
@@ -56,6 +68,12 @@ module Locomotive
56
68
  self.respond_to?(:"#{self._label_field_name}_translations")
57
69
  end
58
70
 
71
+ protected
72
+
73
+ def persist_translated_status
74
+ self._translated = self.translated?
75
+ end
76
+
59
77
  end
60
78
  end
61
79
  end
@@ -3,7 +3,7 @@ module Locomotive
3
3
 
4
4
  include Locomotive::Mongoid::Document
5
5
 
6
- MINIMAL_ATTRIBUTES = %w(_id title slug fullpath position depth published templatized redirect listed response_type parent_id parent_ids site_id created_at updated_at)
6
+ MINIMAL_ATTRIBUTES = %w(_id title slug fullpath position depth published templatized target_klass_name redirect listed response_type parent_id parent_ids site_id created_at updated_at)
7
7
 
8
8
  ## Extensions ##
9
9
  include Extensions::Page::Tree
@@ -28,7 +28,7 @@ module Locomotive
28
28
  field :response_type, default: 'text/html'
29
29
 
30
30
  ## associations ##
31
- belongs_to :site, class_name: 'Locomotive::Site', autosave: false
31
+ belongs_to :site, class_name: 'Locomotive::Site', validate: false, autosave: false
32
32
 
33
33
  ## indexes ##
34
34
  index site_id: 1
@@ -10,7 +10,7 @@ module Locomotive
10
10
  field :template, localize: true
11
11
 
12
12
  ## associations ##
13
- belongs_to :site, class_name: 'Locomotive::Site'
13
+ belongs_to :site, class_name: 'Locomotive::Site', validate: false, autosave: false
14
14
 
15
15
  ## callbacks ##
16
16
  after_save :update_templates
@@ -33,17 +33,18 @@ module Locomotive
33
33
  return unless (self.site rescue false) # not run if the site is being destroyed
34
34
 
35
35
  pages = ::I18n.with_locale(::Mongoid::Fields::I18n.locale) do
36
- pages = self.site.pages.any_in(snippet_dependencies: [self.slug]).to_a
36
+ self.site.pages.any_in(snippet_dependencies: [self.slug]).to_a
37
37
  end
38
38
 
39
- pages.each do |page|
39
+ pages.each_with_index do |page, index|
40
+ # make direct changes directly in the Liquid template
40
41
  self._change_snippet_inside_template(page.template.root)
41
42
 
42
- page.send(:_serialize_template)
43
+ # serialize it
44
+ serialized_template = page.send(:_serialize_template)
43
45
 
44
- Page.without_callback(:save, :after, :update_template_descendants) do
45
- page.save(validate: false)
46
- end
46
+ # persist the change to MongoDB by bypassing the validation and the callbacks
47
+ page.set("serialized_template.#{::Mongoid::Fields::I18n.locale}", serialized_template)
47
48
  end
48
49
  end
49
50
 
@@ -18,7 +18,7 @@ module Locomotive
18
18
  mount_uploader :source, ThemeAssetUploader, mount_on: :source_filename, validate_integrity: true
19
19
 
20
20
  ## associations ##
21
- belongs_to :site, class_name: 'Locomotive::Site', autosave: false
21
+ belongs_to :site, class_name: 'Locomotive::Site', validate: false, autosave: false
22
22
 
23
23
  ## indexes ##
24
24
  index site_id: 1
@@ -40,6 +40,7 @@ module Locomotive
40
40
 
41
41
  ## named scopes ##
42
42
 
43
+
43
44
  ## accessors ##
44
45
  attr_accessor :plain_text_name, :plain_text, :plain_text_type, :performing_plain_text
45
46
  attr_accessible :folder, :source, :plain_text_type, :performing_plain_text, :plain_text_name, :plain_text
@@ -72,11 +73,8 @@ module Locomotive
72
73
  end
73
74
 
74
75
  def plain_text
75
- if RUBY_VERSION =~ /1\.9/
76
- @plain_text ||= (self.source.read.force_encoding('UTF-8') rescue nil)
77
- else
78
- @plain_text ||= self.source.read
79
- end
76
+ # only for ruby >= 1.9.x. Forget about ruby 1.8
77
+ @plain_text ||= (self.source.read.force_encoding('UTF-8') rescue nil)
80
78
  end
81
79
 
82
80
  def plain_text_type
@@ -111,6 +109,14 @@ module Locomotive
111
109
  assets.group_by { |a| a.folder.split('/').first.to_sym }
112
110
  end
113
111
 
112
+ def self.checksums
113
+ {}.tap do |hash|
114
+ self.only(:local_path, :checksum).each do |asset|
115
+ hash[asset.local_path] = asset.checksum
116
+ end
117
+ end
118
+ end
119
+
114
120
  def to_liquid
115
121
  { url: self.source.url }.merge(self.attributes).stringify_keys
116
122
  end
@@ -7,7 +7,7 @@ class Locomotive::Translation
7
7
  field :values, type: Hash, default: {}
8
8
 
9
9
  ## associations ##
10
- belongs_to :site, class_name: 'Locomotive::Site'
10
+ belongs_to :site, class_name: 'Locomotive::Site', validate: false, autosave: false
11
11
 
12
12
  ## validations ##
13
13
  validates_uniqueness_of :key, scope: :site_id
@@ -2,6 +2,16 @@
2
2
 
3
3
  %h2!= t('.title')
4
4
 
5
+ .filter-and-search
6
+ .button-groups.asset-types
7
+ - Locomotive::ContentAsset.types_for_content_editing.each do |type|
8
+ %button.btn{ data: { type: type } }= t(".types.#{type}")
9
+ %button.btn{ data: { type: 'other'} }= t('.types.others')
10
+
11
+ .search-bar
12
+ %input{ type: 'text', name: 'query', placeholder: t('.placeholder_search') }
13
+ %i.icon-search
14
+
5
15
  %p.no-items{ style: 'display: none' }!= t('.no_items')
6
16
 
7
17
  %ul.list.content-assets{ style: 'display: none' }
@@ -17,9 +27,18 @@
17
27
 
18
28
  %script{ type: 'text/html', id: 'content_asset' }
19
29
 
30
+ {{#if uploading}}
31
+ %h4 {{filename}}
32
+ .uploading
33
+ .progress-bar
34
+ &nbsp;
35
+
36
+ {{else}}
37
+
20
38
  %h4
21
39
  = link_to '{{filename}}', '{{url}}', alt: '{{full_filename}}', title: '{{full_filename}}'
22
- {{#if image}}
40
+
41
+ {{#if with_thumbnail}}
23
42
  .image
24
43
  .inside
25
44
  %img{ src: '{{vignette_url}}' }
@@ -30,4 +49,6 @@
30
49
  {{/if}}
31
50
 
32
51
  .actions
33
- = link_to_icon :trash, '#', class: 'remove', :'data-confirm' => t('locomotive.messages.confirm')
52
+ = link_to_icon :trash, '#', class: 'remove', data: { confirm: t('locomotive.messages.confirm') }
53
+
54
+ {{/if}}