locomotive_cms 2.0.0.rc9 → 2.0.0.rc10

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 (50) hide show
  1. data/Gemfile +6 -5
  2. data/app/assets/javascripts/locomotive/inline_editor.js.coffee +1 -1
  3. data/app/assets/javascripts/locomotive/models/custom_field_select_option.js.coffee +3 -0
  4. data/app/assets/javascripts/locomotive/models/site.js.coffee +2 -1
  5. data/app/assets/javascripts/locomotive/views/content_entries/_form_view.js.coffee +27 -0
  6. data/app/assets/javascripts/locomotive/views/content_entries/_popup_form_view.js.coffee +7 -1
  7. data/app/assets/javascripts/locomotive/views/content_types/_form_view.js.coffee +4 -1
  8. data/app/assets/javascripts/locomotive/views/content_types/select_options_view.js.coffee +5 -1
  9. data/app/assets/javascripts/locomotive/views/inline_editor/toolbar_view.js.coffee +0 -2
  10. data/app/assets/javascripts/locomotive/views/pages/edit_view.js.coffee +3 -0
  11. data/app/assets/javascripts/locomotive/views/shared/fields/select_view.js.coffee +83 -0
  12. data/app/assets/stylesheets/locomotive/backoffice/application.css.scss +13 -0
  13. data/app/assets/stylesheets/locomotive/backoffice/formtastic_changes.css.scss +25 -95
  14. data/app/assets/stylesheets/locomotive/inline_editor/toolbar.css.scss +1 -1
  15. data/app/assets/stylesheets/locomotive/shared/_helpers.css.scss +98 -0
  16. data/app/assets/stylesheets/locomotive/shared/common.css.scss +1 -1
  17. data/app/controllers/locomotive/current_site_controller.rb +6 -0
  18. data/app/helpers/locomotive/base_helper.rb +14 -0
  19. data/app/models/locomotive/content_entry.rb +42 -3
  20. data/app/models/locomotive/content_type.rb +6 -1
  21. data/app/models/locomotive/editable_element.rb +9 -0
  22. data/app/models/locomotive/editable_short_text.rb +9 -0
  23. data/app/models/locomotive/extensions/page/tree.rb +3 -4
  24. data/app/presenters/locomotive/content_entry_presenter.rb +4 -2
  25. data/app/views/locomotive/content_entries/_form.html.haml +2 -1
  26. data/app/views/locomotive/custom_fields/_form.html.haml +4 -18
  27. data/app/views/locomotive/custom_fields/_select_templates.html.haml +16 -0
  28. data/app/views/locomotive/custom_fields/types/_has_many.html.haml +3 -3
  29. data/app/views/locomotive/custom_fields/types/_select.html.haml +30 -1
  30. data/app/views/locomotive/notifications/new_content_entry.html.haml +3 -1
  31. data/app/views/locomotive/public/pages/show_toolbar.html.haml +4 -1
  32. data/config/locales/admin_ui.de.yml +3 -4
  33. data/config/locales/admin_ui.en.yml +1 -1
  34. data/config/locales/admin_ui.fr.yml +4 -4
  35. data/config/locales/admin_ui.nb.yml +0 -1
  36. data/config/locales/admin_ui.ru.yml +0 -1
  37. data/lib/locomotive/custom_fields.rb +12 -0
  38. data/lib/locomotive/liquid/drops/content_entry.rb +2 -2
  39. data/lib/locomotive/liquid/drops/content_types.rb +2 -0
  40. data/lib/locomotive/liquid/tags/editable/short_text.rb +4 -0
  41. data/lib/locomotive/liquid/tags/inline_editor.rb +14 -12
  42. data/lib/locomotive/middlewares/inline_editor.rb +20 -15
  43. data/lib/locomotive/render.rb +94 -40
  44. data/lib/locomotive/version.rb +1 -1
  45. data/vendor/assets/javascripts/locomotive/form_submit_notification.js +1 -1
  46. data/vendor/assets/javascripts/locomotive/toggle.js +9 -8
  47. data/vendor/assets/stylesheets/locomotive/liquid_mode.css +3 -5
  48. data/vendor/assets/stylesheets/locomotive/toggle.css.scss +33 -10
  49. metadata +13 -12
  50. data/app/assets/stylesheets/locomotive/backoffice/formtastic_changes.css.css +0 -0
@@ -20,7 +20,9 @@
20
20
  - when 'string', 'text', 'boolean', 'date'
21
21
  = value
22
22
  - when 'file'
23
- = link_to File.basename(value.to_s), value.to_s
23
+ - url = value.guess_url
24
+ - url = url =~ /^http/ ? url : URI.join("http://#{@entry.site.domains.first}", url).to_s # Amazon S3 (http/https) or local files ?
25
+ = link_to File.basename(url), url
24
26
  - when 'select'
25
27
  = value
26
28
  - when 'belongs_to'
@@ -11,6 +11,10 @@
11
11
  %meta{ :name => 'key-param', :content => Rails.application.config.session_options[:key] }
12
12
  %meta{ :name => 'key-token', :content => cookies[key] }
13
13
 
14
+ %script{ :type => 'text/javascript' }
15
+ :plain
16
+ window.Locomotive = { mounted_on: '#{Locomotive.mounted_on}' };
17
+
14
18
  = stylesheet_link_tag 'locomotive/inline_editor', :media => 'screen'
15
19
  = javascript_include_tag 'locomotive/inline_editor'
16
20
 
@@ -19,7 +23,6 @@
19
23
  window.locale = '#{I18n.locale}';
20
24
  window.content_locale = '#{::Mongoid::Fields::I18n.locale}';
21
25
 
22
- Locomotive.mounted_on = '#{Locomotive.mounted_on}';
23
26
  Locomotive.current_site = new Locomotive.Models.Site(#{j current_site.to_json.html_safe});
24
27
  Locomotive.current_account = new Locomotive.Models.Account(#{j current_locomotive_account.to_json.html_safe});
25
28
 
@@ -9,7 +9,7 @@ de:
9
9
  title: Seite nicht gefunden
10
10
  notice: "Die angefragte Seite existiert nicht."
11
11
  link: "→ Zurück zur Anwendung"
12
-
12
+
13
13
  locales:
14
14
  en: Englisch
15
15
  de: Deutsch
@@ -20,7 +20,7 @@ de:
20
20
  nb: Norwegisch
21
21
  es: Spanisch
22
22
  ru: Russisch
23
-
23
+
24
24
  buttons:
25
25
  login: Einloggen
26
26
  send_password: Senden
@@ -91,7 +91,6 @@ de:
91
91
 
92
92
  form:
93
93
  required: Pflichtfeld
94
- optional: Optional
95
94
  default_label: Feldname
96
95
  select_options:
97
96
  ask_name: "Geben Sie den Namen der Auswahloption an."
@@ -295,7 +294,7 @@ de:
295
294
  explanations: "Es ist fast geschafft. Bitte geben Sie Ihrer ersten Webseite einen Namen und wählen Sie eine Sprache aus."
296
295
  default_site_locale: Sprachauswahl
297
296
  default_site_locales_hints: Sie können später weitere Sprachen im Einstellungsdialog vornehmen.
298
- next: Webseite erstellen
297
+ next: Webseite erstellen
299
298
  back_to_default_template: "Klicken Sie <a href='#'>hier</a> um die Standardeinstellungen wieder herzustellen"
300
299
 
301
300
 
@@ -91,7 +91,6 @@ en:
91
91
 
92
92
  form:
93
93
  required: Required
94
- optional: Optional
95
94
  default_label: Field name
96
95
  select_options:
97
96
  ask_name: "Type the label of the option"
@@ -267,6 +266,7 @@ en:
267
266
  edit:
268
267
  title: '%{type} &mdash; editing entry'
269
268
  form:
269
+ edit_select_options: edit options
270
270
  has_many:
271
271
  new_entry: New entry
272
272
 
@@ -85,11 +85,10 @@ fr:
85
85
  empty: La liste est vide. Ajouter une entrée depuis la liste ci-dessous.
86
86
 
87
87
  form:
88
- required: Required
89
- optional: Optional
90
- default_label: Field name
88
+ required: Requis
89
+ default_label: Nom du champ
91
90
  select_options:
92
- ask_name: "Type the label of the option"
91
+ ask_name: "Tapez le nom de l'option"
93
92
 
94
93
  sessions:
95
94
  new:
@@ -263,6 +262,7 @@ fr:
263
262
  edit:
264
263
  title: '%{type} &mdash; édition élément'
265
264
  form:
265
+ edit_select_options: éditer options
266
266
  has_many:
267
267
  new_item: Nouvel élément
268
268
 
@@ -91,7 +91,6 @@ nb:
91
91
 
92
92
  form:
93
93
  required: Nødvendig
94
- optional: Valgfri
95
94
  default_label: Feltnavn
96
95
  select_options:
97
96
  ask_name: "Skriv inn etiketten for dette valget"
@@ -90,7 +90,6 @@ ru:
90
90
  empty: Список пуст. Добавьте элемент из селекта ниже.
91
91
  form:
92
92
  required: Обязательное
93
- optional: Опциональное
94
93
  default_label: Название поля
95
94
  select_options:
96
95
  ask_name: "Введите название элемента"
@@ -30,6 +30,18 @@ module CustomFields
30
30
  "sites/#{model.site_id}/content_#{model.class.model_name.demodulize.underscore}/#{model.id}/files"
31
31
  end
32
32
 
33
+ # In some situations, for instance, for the notification email when a content entry is created,
34
+ # we need to know the url of the file without breaking the upload process.
35
+ # Actually, the uploaded file will be written on the filesystem after the email is sent.
36
+ #
37
+ # @return [ String ] The url to the soon uploaded file
38
+ #
39
+ def guess_url
40
+ this = self.class.new(model, mounted_as)
41
+ this.retrieve_from_store!(model.read_uploader(mounted_as))
42
+ this.url.to_s
43
+ end
44
+
33
45
  def cache_dir
34
46
  "#{Rails.root}/tmp/uploads"
35
47
  end
@@ -23,7 +23,7 @@ module Locomotive
23
23
  # {% endif %}
24
24
  #
25
25
  def next
26
- self._source.next.to_liquid
26
+ @next ||= self._source.next.to_liquid
27
27
  end
28
28
 
29
29
  # Returns the previous content for the parent content type.
@@ -36,7 +36,7 @@ module Locomotive
36
36
  # {% endif %}
37
37
  #
38
38
  def previous
39
- self._source.previous.to_liquid
39
+ @previous ||= self._source.previous.to_liquid
40
40
  end
41
41
 
42
42
  def before_method(meth)
@@ -31,6 +31,8 @@ module Locomotive
31
31
 
32
32
  if (meth.to_s =~ /^group_by_(.+)$/) == 0
33
33
  klass.send(:group_by_select_option, $1, @content_type.order_by_definition)
34
+ elsif (meth.to_s =~ /^(.+)_options$/) == 0
35
+ klass.send(:"#{$1}_options").map { |option| option['name'] }
34
36
  else
35
37
  Locomotive.log :warn, "[Liquid template] trying to call #{meth} on a content_type object"
36
38
  end
@@ -28,6 +28,10 @@ module Locomotive
28
28
  context.registers[:inline_editor] && (!element.fixed? || (element.fixed? && !element.from_parent?))
29
29
  end
30
30
 
31
+ def default_element_attributes
32
+ super.merge(:content_from_default => self.render_default_content(nil))
33
+ end
34
+
31
35
  end
32
36
 
33
37
  ::Liquid::Template.register_tag('editable_short_text', ShortText)
@@ -6,23 +6,25 @@ module Liquid
6
6
  def render(context)
7
7
  if context.registers[:current_locomotive_account] && context.registers[:inline_editor]
8
8
 
9
- controller = context.registers[:controller]
10
-
11
9
  plugins = 'common/format,common/table,common/list,common/link,common/highlighteditables,common/block,common/undo,common/contenthandler,common/paste,common/commands,common/abbr,common/align,common/horizontalruler,custom/locomotive_media'
12
10
 
13
- %{
14
- <meta content="true" name="inline-editor" />
11
+ controller = context.registers[:controller]
12
+ controller.instance_variable_set(:@plugins, plugins)
13
+
14
+ html = <<-HTML
15
+ %meta{ :content => true, :name => 'inline-editor' }
15
16
 
16
- #{controller.view_context.stylesheet_link_tag 'aloha/css/aloha.css'}
17
- #{controller.view_context.javascript_include_tag 'locomotive/aloha', :'data-aloha-plugins' => plugins}
17
+ = stylesheet_link_tag 'aloha/css/aloha.css'
18
+ = javascript_include_tag 'locomotive/aloha', :'data-aloha-plugins' => @plugins
18
19
 
19
- <script type="text/javascript">
20
- Aloha.ready(function() \{
21
- window.parent.application_view.set_page(#{context.registers[:page].to_presenter.as_json_for_html_view.to_json});
22
- \});
23
- </script>
20
+ %script{ :type => 'text/javascript' }
21
+ :plain
22
+ Aloha.ready(function() \{
23
+ window.parent.application_view.set_page(#{controller.view_context.j context.registers[:page].to_presenter.as_json_for_html_view.to_json.html_safe});
24
+ \});
25
+ HTML
24
26
 
25
- }
27
+ Haml::Engine.new(html.gsub(/\n+/, "\n").gsub(/^\s{14}/, ''), :escape_html => true).render(controller.view_context)
26
28
  else
27
29
  ''
28
30
  end
@@ -7,22 +7,27 @@ module Locomotive
7
7
  end
8
8
 
9
9
  def call(env)
10
- response = @app.call(env)
10
+ status, headers, response = @app.call(env)
11
11
 
12
- unless response[1]['Editable'].blank?
13
- html = response.last.body.to_s.gsub '</body>', %(
14
- <a href="_admin"
15
- onmouseout="this.style.backgroundPosition='0px 0px'"
16
- onmouseover="this.style.backgroundPosition='0px -45px'"
17
- onmousedown="this.style.backgroundPosition='0px -90px'"
18
- onmouseup="this.style.backgroundPosition='0px 0px'"
19
- style="display: block;z-index: 1031;position: fixed;top: 10px; right: 10px;width: 48px; height: 45px;text-indent:-9999px;text-decoration:none;background: transparent url\('/assets/locomotive/icons/start.png'\) no-repeat 0 0;">
20
- Admin</a>
21
- </body>
22
- )
23
- [response[0], response[1], [html]]
24
- else
25
- response
12
+ response = modify(response) unless headers['Editable'].blank?
13
+
14
+ [status, headers, response]
15
+ end
16
+
17
+ def modify(response)
18
+ [].tap do |parts|
19
+ response.each do |part|
20
+ parts << part.to_s.gsub('</body>', %(
21
+ <a href="_admin"
22
+ onmouseout="this.style.backgroundPosition='0px 0px'"
23
+ onmouseover="this.style.backgroundPosition='0px -45px'"
24
+ onmousedown="this.style.backgroundPosition='0px -90px'"
25
+ onmouseup="this.style.backgroundPosition='0px 0px'"
26
+ style="display: block;z-index: 1031;position: fixed;top: 10px; right: 10px;width: 48px; height: 45px;text-indent:-9999px;text-decoration:none;background: transparent url\('/assets/locomotive/icons/start.png'\) no-repeat 0 0;">
27
+ Admin</a>
28
+ </body>
29
+ ))
30
+ end
26
31
  end
27
32
  end
28
33
 
@@ -5,6 +5,9 @@ module Locomotive
5
5
 
6
6
  protected
7
7
 
8
+ # Render a Locomotive page from the request fullpath and the current site.
9
+ # If the page corresponds to a redirect, then a 301 redirection is made.
10
+ #
8
11
  def render_locomotive_page
9
12
  if request.fullpath =~ /^\/#{Locomotive.mounted_on}\//
10
13
  render :template => '/locomotive/errors/404', :layout => '/locomotive/layouts/not_logged_in', :status => :not_found
@@ -21,14 +24,69 @@ module Locomotive
21
24
  end
22
25
  end
23
26
 
27
+ # Render the page which tells that no page exists.
28
+ # This case should not happen since all the sites contains
29
+ # the "Page Not Found" page.
30
+ #
24
31
  def render_no_page_error
25
32
  render :template => '/locomotive/errors/no_page', :layout => false
26
33
  end
27
34
 
35
+ # Prepare and set the response object for the Locomotive page retrieved
36
+ # from the path. The caching (with Varnish for instance) if defined is done here.
37
+ # It is also here that the content type of the request is set (html or json).
38
+ # Behind the scene, it just calls simply the Rails render method.
39
+ #
40
+ # @param [ String ] The rendered Locomotive page
41
+ #
42
+ def prepare_and_set_response(output)
43
+ flash.discard
44
+
45
+ response.headers['Content-Type'] = "#{@page.response_type}; charset=utf-8"
46
+ response.headers['Editable'] = 'true' unless self.editing_page? || current_locomotive_account.nil?
47
+
48
+ if @page.with_cache?
49
+ fresh_when :etag => @page, :last_modified => @page.updated_at.utc, :public => true
50
+
51
+ if @page.cache_strategy != 'simple' # varnish
52
+ response.headers['Editable'] = ''
53
+ response.cache_control[:max_age] = @page.cache_strategy
54
+ end
55
+ end
56
+
57
+ render :text => output, :layout => false, :status => page_status unless performed?
58
+ end
59
+
60
+ # Tell if the current Locomotive page is being edited.
61
+ #
62
+ # @return [ Boolean ] True if being edited.
63
+ #
64
+ def editing_page?
65
+ !!@editing
66
+ end
67
+
68
+ # Get the symbol matching the status of the current Locomotive page.
69
+ # It can be either :ok or :not_found (404)
70
+ #
71
+ # @return [ Symbol ] :ok if the page is not the "Page not found" one.
72
+ #
73
+ def page_status
74
+ @page.not_found? ? :not_found : :ok
75
+ end
76
+
77
+ # Get the Locomotive page matching the request and scoped by the current Locomotive site
78
+ #
79
+ # @return [ Object ] The Locomotive::Page
80
+ #
28
81
  def locomotive_page
29
82
  current_site.fetch_page self.locomotive_page_path, current_locomotive_account.present?
30
83
  end
31
84
 
85
+ # Build the path that can be understood by Locomotive in order to retrieve
86
+ # the matching Locomotive page (see the locomotive_page method)
87
+ #
88
+ # @return [ String ] The path to the Locomotive page
89
+ #
32
90
  def locomotive_page_path
33
91
  path = (params[:path] || params[:page_path] || request.fullpath).clone # TODO: params[:path] is more consistent
34
92
  path = path.split('?').first # take everything before the query string or the lookup fails
@@ -40,9 +98,36 @@ module Locomotive
40
98
  path
41
99
  end
42
100
 
101
+ # Build the Liquid context used to render the Locomotive page. It
102
+ # stores both assigns and registers.
103
+ #
104
+ # @return [ Object ] A Liquid::Context object.
105
+ #
43
106
  def locomotive_context
44
- assigns = {
45
- 'site' => current_site,
107
+ assigns = self.locomotive_default_assigns
108
+
109
+ assigns.merge!(Locomotive.config.context_assign_extensions)
110
+
111
+ assigns.merge!(flash.to_hash.stringify_keys) # data from public submissions
112
+
113
+ if @page.templatized? # add instance from content type
114
+ content_entry = @page.content_entry.to_liquid
115
+ ['content_entry', 'entry', @page.target_entry_name].each do |key|
116
+ assigns[key] = content_entry
117
+ end
118
+ end
119
+
120
+ # Tip: switch from false to true to enable the re-thrown exception flag
121
+ ::Liquid::Context.new({}, assigns, self.locomotive_default_registers, false)
122
+ end
123
+
124
+ # Return the default Liquid assigns used inside the Locomotive Liquid context
125
+ #
126
+ # @return [ Hash ] The default liquid assigns object
127
+ #
128
+ def locomotive_default_assigns
129
+ {
130
+ 'site' => current_site.to_liquid,
46
131
  'page' => @page,
47
132
  'models' => Locomotive::Liquid::Drops::ContentTypes.new,
48
133
  'contents' => Locomotive::Liquid::Drops::ContentTypes.new, # DEPRECATED
@@ -58,51 +143,20 @@ module Locomotive
58
143
  'locales' => current_site.locales,
59
144
  'current_user' => Locomotive::Liquid::Drops::CurrentUser.new(current_locomotive_account)
60
145
  }
146
+ end
61
147
 
62
- assigns.merge!(Locomotive.config.context_assign_extensions)
63
-
64
- assigns.merge!(flash.to_hash.stringify_keys) # data from public submissions
65
-
66
- if @page.templatized? # add instance from content type
67
- assigns['content_entry'] = assigns['entry'] = @page.content_entry
68
- assigns[@page.target_entry_name] = @page.content_entry # just here to help to write readable liquid code
69
- end
70
-
71
- registers = {
148
+ # Return the default Liquid registers used inside the Locomotive Liquid context
149
+ #
150
+ # @return [ Hash ] The default liquid registers object
151
+ #
152
+ def locomotive_default_registers
153
+ {
72
154
  :controller => self,
73
155
  :site => current_site,
74
156
  :page => @page,
75
157
  :inline_editor => self.editing_page?,
76
158
  :current_locomotive_account => current_locomotive_account
77
159
  }
78
-
79
- ::Liquid::Context.new({}, assigns, registers, false) # switch from false to true to enable the re-thrown exception flag
80
- end
81
-
82
- def prepare_and_set_response(output)
83
- flash.discard
84
-
85
- response.headers['Content-Type'] = "#{@page.response_type}; charset=utf-8"
86
- response.headers['Editable'] = 'true' unless self.editing_page? || current_locomotive_account.nil?
87
-
88
- if @page.with_cache?
89
- fresh_when :etag => @page, :last_modified => @page.updated_at.utc, :public => true
90
-
91
- if @page.cache_strategy != 'simple' # varnish
92
- response.headers['Editable'] = ''
93
- response.cache_control[:max_age] = @page.cache_strategy
94
- end
95
- end
96
-
97
- render :text => output, :layout => false, :status => page_status unless performed?
98
- end
99
-
100
- def editing_page?
101
- !!@editing
102
- end
103
-
104
- def page_status
105
- @page.not_found? ? :not_found : :ok
106
160
  end
107
161
 
108
162
  end
@@ -1,3 +1,3 @@
1
1
  module Locomotive #:nodoc
2
- VERSION = '2.0.0.rc9'
2
+ VERSION = '2.0.0.rc10'
3
3
  end
@@ -22,7 +22,7 @@ $.fn.formSubmitNotification = function(settings) {
22
22
 
23
23
  return this.each(function() {
24
24
  var form = $(this);
25
- var message = form.attr('data-sending-form-message');
25
+ var message = form.attr('data-sending-form-message') || form.attr('data-sending_form_message');
26
26
 
27
27
  if (typeof(message) == 'undefined')
28
28
  message = form.find('input[type=submit]').attr('data-sending-form-message');