locomotive_cms 2.0.0.rc9 → 2.0.0.rc10

Sign up to get free protection for your applications and to get access to all the features.
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');