locomotive_cms 2.3.1 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/locomotive/models/content_entry.js.coffee +4 -0
  3. data/app/assets/javascripts/locomotive/views/content_assets/picker_view.js.coffee +0 -2
  4. data/app/assets/javascripts/locomotive/views/content_entries/_form_view.js.coffee +1 -1
  5. data/app/assets/javascripts/locomotive/views/content_entries/_popup_form_view.js.coffee +7 -0
  6. data/app/assets/javascripts/locomotive/views/inline_editor/application_view.js.coffee +1 -1
  7. data/app/assets/javascripts/locomotive/views/pages/_form_view.js.coffee +2 -1
  8. data/app/assets/javascripts/locomotive/views/shared/fields/_relationship_view.js.coffee +45 -0
  9. data/app/assets/javascripts/locomotive/views/shared/fields/belongs_to_view.js.coffee +4 -20
  10. data/app/assets/javascripts/locomotive/views/shared/fields/many_to_many_view.js.coffee +53 -42
  11. data/app/assets/javascripts/locomotive/views/snippets/_form_view.js.coffee +0 -1
  12. data/app/assets/stylesheets/locomotive/backoffice/application.css.scss +31 -0
  13. data/app/assets/stylesheets/locomotive/backoffice/formtastic_changes.css.scss +19 -0
  14. data/app/controllers/locomotive/api/accounts_controller.rb +6 -0
  15. data/app/controllers/locomotive/content_entries_controller.rb +1 -1
  16. data/app/helpers/locomotive/content_entries_helper.rb +22 -0
  17. data/app/models/locomotive/content_entry.rb +16 -47
  18. data/app/models/locomotive/content_type.rb +19 -3
  19. data/app/models/locomotive/editable_text.rb +7 -1
  20. data/app/models/locomotive/extensions/content_entry/localized.rb +62 -0
  21. data/app/models/locomotive/extensions/page/tree.rb +5 -0
  22. data/app/models/locomotive/extensions/shared/slug.rb +33 -0
  23. data/app/models/locomotive/page.rb +4 -11
  24. data/app/models/locomotive/snippet.rb +6 -7
  25. data/app/models/locomotive/translation.rb +2 -2
  26. data/app/presenters/locomotive/account_presenter.rb +1 -1
  27. data/app/views/locomotive/content_entries/_list.html.haml +3 -1
  28. data/app/views/locomotive/custom_fields/types/_boolean.html.haml +1 -1
  29. data/app/views/locomotive/custom_fields/types/_date.html.haml +1 -1
  30. data/app/views/locomotive/custom_fields/types/_date_time.html.haml +1 -1
  31. data/app/views/locomotive/custom_fields/types/_email.html.haml +1 -1
  32. data/app/views/locomotive/custom_fields/types/_file.html.haml +1 -1
  33. data/app/views/locomotive/custom_fields/types/_float.html.haml +1 -1
  34. data/app/views/locomotive/custom_fields/types/_integer.html.haml +1 -1
  35. data/app/views/locomotive/custom_fields/types/_many_to_many.html.haml +1 -5
  36. data/app/views/locomotive/custom_fields/types/_select.html.haml +1 -1
  37. data/app/views/locomotive/custom_fields/types/_string.html.haml +1 -1
  38. data/app/views/locomotive/custom_fields/types/_tags.html.haml +1 -1
  39. data/app/views/locomotive/custom_fields/types/_text.html.haml +1 -1
  40. data/config/locales/admin_ui.de.yml +4 -0
  41. data/config/locales/default.zh-CN.yml +162 -52
  42. data/config/locales/devise.bg.yml +1 -1
  43. data/config/locales/devise.cs.yml +1 -1
  44. data/config/locales/devise.de.yml +1 -1
  45. data/config/locales/devise.en.yml +1 -1
  46. data/config/locales/devise.es.yml +2 -2
  47. data/config/locales/devise.et.yml +1 -1
  48. data/config/locales/devise.fr.yml +1 -1
  49. data/config/locales/devise.it.yml +1 -1
  50. data/config/locales/devise.ja.yml +1 -1
  51. data/config/locales/devise.nb.yml +1 -1
  52. data/config/locales/devise.nl.yml +2 -2
  53. data/config/locales/devise.pl.yml +1 -1
  54. data/config/locales/devise.pt-BR.yml +2 -2
  55. data/config/locales/devise.ru.yml +1 -1
  56. data/config/locales/devise.zh-CN.yml +1 -1
  57. data/config/routes.rb +2 -2
  58. data/features/api/accounts.feature +19 -1
  59. data/features/api/authorization/accounts.feature +52 -12
  60. data/features/backoffice/content_types/has_many.feature +3 -3
  61. data/features/backoffice/content_types/integer.feature +4 -4
  62. data/features/backoffice/content_types/many_to_many.feature +1 -1
  63. data/features/backoffice/my_account.feature +1 -0
  64. data/features/step_definitions/web_steps.rb +7 -0
  65. data/lib/locomotive/action_controller/public_responder.rb +24 -1
  66. data/lib/locomotive/core_ext.rb +8 -2
  67. data/lib/locomotive/devise.rb +21 -0
  68. data/lib/locomotive/httparty/webservice.rb +17 -9
  69. data/lib/locomotive/liquid.rb +1 -0
  70. data/lib/locomotive/liquid/tags/consume.rb +12 -11
  71. data/lib/locomotive/liquid/tags/link_to.rb +6 -60
  72. data/lib/locomotive/liquid/tags/path_helper.rb +82 -0
  73. data/lib/locomotive/liquid/tags/path_to.rb +21 -0
  74. data/lib/locomotive/liquid/tags/snippet.rb +1 -1
  75. data/lib/locomotive/render.rb +2 -1
  76. data/lib/locomotive/version.rb +1 -1
  77. data/spec/lib/locomotive/liquid/tags/consume_spec.rb +12 -0
  78. data/spec/lib/locomotive/liquid/tags/path_to_spec.rb +111 -0
  79. data/spec/models/locomotive/content_entry_spec.rb +2 -2
  80. data/spec/models/locomotive/snippet_spec.rb +21 -0
  81. metadata +13 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b5296380d468cf4e5522e01268698e14df1be493
4
- data.tar.gz: f55fa2c7671c33d05b6d93c12cd6a33034b69b61
3
+ metadata.gz: 2213955e65720bed32b9918ab1d4ec4bd270c7cc
4
+ data.tar.gz: 621fef84725a59a1c6f53163e9f51e2231477845
5
5
  SHA512:
6
- metadata.gz: 3c1bfd20751c88557fe805ba6b3e2292c4c9f03c71e8034f5cb6cd3ad5f2120b830b9fedcdb03eda475b34c97b6fc752d93cefd9f5c4f09286d9a392b33bc295
7
- data.tar.gz: 7db9d6cb249af95f012abb14833df09945373194d487515c84a879611ed3605707992069a4011ab8bf3a3a13bfb173c3a24c90c3485c735ca5a629ea06e0a585
6
+ metadata.gz: 605e58bc0eecf723829454e04fda1b2061df9762b99d7e51142be34072b7641a32f947c8d462f17aaa488f86f267175ea7fb876f1522736003be987cf2cb43a2
7
+ data.tar.gz: 305ea2476b38f3309272d24a9cb055f66781bd76b22da0c36417122b7e8f4c0ac1a9bd1d7af1c600d35bb1beccb23f23e7256bced8821d2b0fc9820a8e995698
@@ -29,6 +29,10 @@ class Locomotive.Models.ContentEntry extends Backbone.Model
29
29
  @set_attribute attribute, attributes[attribute]
30
30
  @set_attribute "remove_#{field}", false
31
31
 
32
+ reset_attributes: ->
33
+ _.each _.keys(@attributes), (name) =>
34
+ @set_attribute name, null
35
+
32
36
  toMinJSON: ->
33
37
  _.tap {}, (hash) =>
34
38
  _.each @attributes, (val, key) =>
@@ -20,8 +20,6 @@ class Locomotive.Views.ContentAssets.PickerView extends Locomotive.Views.Shared.
20
20
  build_uploader: (el, link) ->
21
21
  link.bind 'click', (event) ->
22
22
  event.stopPropagation() & event.preventDefault()
23
- console.log(el)
24
- window.foo = el
25
23
  el.click()
26
24
 
27
25
  el.bind 'change', (event) =>
@@ -159,7 +159,7 @@ class Locomotive.Views.ContentEntries.FormView extends Locomotive.Views.Shared.F
159
159
 
160
160
  refresh: ->
161
161
  @$('li.input.toggle input[type=checkbox]').checkToggle('sync')
162
- _.each @_file_field_views, (view) => view.refresh()
162
+ @refresh_file_fields()
163
163
 
164
164
  reset: ->
165
165
  @$('li.input.string input[type=text], li.input.text textarea, li.input.date input[type=text]').val('').trigger('change')
@@ -15,6 +15,8 @@ class Locomotive.Views.ContentEntries.PopupFormView extends Locomotive.Views.Con
15
15
  return @
16
16
 
17
17
  save: (event) ->
18
+ @touch_richtexteditor()
19
+
18
20
  @save_in_ajax event,
19
21
  headers: { 'X-Flash': true }
20
22
  on_success: (response, xhr) =>
@@ -70,6 +72,7 @@ class Locomotive.Views.ContentEntries.PopupFormView extends Locomotive.Views.Con
70
72
  $(@el).dialog('option', 'position', 'center')
71
73
 
72
74
  reset: (entry) =>
75
+ @model.reset_attributes()
73
76
  @model.set entry.attributes
74
77
 
75
78
  if entry.isNew()
@@ -87,5 +90,9 @@ class Locomotive.Views.ContentEntries.PopupFormView extends Locomotive.Views.Con
87
90
  enable_many_to_many_fields: ->
88
91
  # disabled in a popup form
89
92
 
93
+ touch_richtexteditor: ->
94
+ _.each @$('li.input.rte textarea.html'), (textarea) =>
95
+ $(textarea).tinymce().save()
96
+
90
97
  tinyMCE_settings: ->
91
98
  window.Locomotive.tinyMCE.popupSettings
@@ -84,7 +84,7 @@ class Locomotive.Views.InlineEditor.ApplicationView extends Backbone.View
84
84
  _window = @_window()
85
85
 
86
86
  _jQuery('a[class!="ui-tabs-anchor"]').live 'click', (event) ->
87
- link = _jQuery(event.target)
87
+ link = _jQuery(this)
88
88
  url = link.attr('href')
89
89
 
90
90
  if url? && url.indexOf('#') != 0 && /^(www|http)/.exec(url) == null && /(\/_edit)$/.exec(url) == null && /^\/sites\//.exec(url) == null
@@ -159,4 +159,5 @@ class Locomotive.Views.Pages.FormView extends Locomotive.Views.Shared.FormView
159
159
  @$('li#page_redirect_url_input, li#page_redirect_type_input').hide()
160
160
 
161
161
  enable_other_checkboxes: ->
162
- @$('li.toggle input[type=checkbox].simple-toggle').checkToggle()
162
+ @$('li.toggle input[type=checkbox].simple-toggle').checkToggle()
163
+ @$('li.toggle.simple-toggle input[type=checkbox]').checkToggle()
@@ -0,0 +1,45 @@
1
+ Locomotive.Views.Shared ||= {}
2
+ Locomotive.Views.Shared.Fields ||= {}
3
+
4
+ class Locomotive.Views.Shared.Fields.RelationshipView extends Backbone.View
5
+
6
+ enable_select2: (element, options) ->
7
+ options ||= {}
8
+ options.init_selection_fn ||= (element, callback) -> null
9
+
10
+ element.select2
11
+ width: '50%'
12
+ minimumInputLength: 1
13
+ quietMillis: 100
14
+ allowClear: true
15
+ placeholder: ' '
16
+ initSelection: options.init_selection_fn
17
+ ajax:
18
+ url: options.url
19
+ data: (term, page) ->
20
+ q: term
21
+ page: page
22
+ results: (data, page) =>
23
+ results: @build_results(data, options.groupBy)
24
+ more: data.length == options.perPage
25
+
26
+ build_results: (raw_data, group_by) ->
27
+ _.tap [], (list) =>
28
+ _.each raw_data, (data) =>
29
+ if !@collection? || !@collection.get(data._id)?
30
+ data.text = data._label
31
+
32
+ if group_by?
33
+ group_name = _.result(data, group_by)
34
+
35
+ # does the group exist?
36
+ group = _.find list, (_group) -> _group.text == group_name
37
+
38
+ unless group?
39
+ # build a new group
40
+ group = { text: group_name, children: [] }
41
+ list.push(group)
42
+
43
+ group.children.push(data)
44
+ else
45
+ list.push(data)
@@ -1,7 +1,7 @@
1
1
  Locomotive.Views.Shared ||= {}
2
2
  Locomotive.Views.Shared.Fields ||= {}
3
3
 
4
- class Locomotive.Views.Shared.Fields.BelongsToView extends Backbone.View
4
+ class Locomotive.Views.Shared.Fields.BelongsToView extends Locomotive.Views.Shared.Fields.RelationshipView
5
5
 
6
6
  render: ->
7
7
  @enable_select2()
@@ -10,25 +10,9 @@ class Locomotive.Views.Shared.Fields.BelongsToView extends Backbone.View
10
10
 
11
11
  enable_select2: ->
12
12
  options = $(@el).data()
13
+ options.init_selection_fn = (el, callback) -> callback(id: el.val(), text: options.value)
13
14
 
14
- $(@el).select2
15
- width: '50%'
16
- minimumInputLength: 1
17
- quietMillis: 100
18
- allowClear: true
19
- placeholder: ' '
20
- ajax:
21
- url: options.url
22
- data: (term, page) ->
23
- q: term
24
- page: page
25
- results: (data, page) ->
26
- results: data.map (item) -> { id: item._id, text: item._label || '' }
27
- more: data.length == options.perPage
28
-
29
- initSelection: (el, callback) -> callback(id: el.val(), text: options.value)
15
+ super($(@el), options)
30
16
 
31
17
  $(@el).on 'select2-selecting', (el) =>
32
- @model.set "#{@options.name}_id", el.val
33
-
34
-
18
+ @model.set "#{@options.name}_id", el.val
@@ -1,16 +1,16 @@
1
1
  Locomotive.Views.Shared ||= {}
2
2
  Locomotive.Views.Shared.Fields ||= {}
3
3
 
4
- class Locomotive.Views.Shared.Fields.ManyToManyView extends Backbone.View
4
+ class Locomotive.Views.Shared.Fields.ManyToManyView extends Locomotive.Views.Shared.Fields.RelationshipView
5
5
 
6
6
  tagName: 'div'
7
7
 
8
8
  className: 'list'
9
9
 
10
10
  events:
11
- 'click .new-entry a.add': 'add_entry'
12
- 'keypress .new-entry select': 'add_entry'
13
- 'click ul span.actions a.remove': 'remove_entry'
11
+ 'click .new-entry a.add': 'add_entry'
12
+ 'keypress .new-entry input.selected-entry': 'add_entry'
13
+ 'click ul span.actions a.remove': 'remove_entry'
14
14
 
15
15
  template: ->
16
16
  ich["#{@options.name}_list"]
@@ -22,7 +22,6 @@ class Locomotive.Views.Shared.Fields.ManyToManyView extends Backbone.View
22
22
  _.bindAll(@, 'refresh_position_entries')
23
23
 
24
24
  @collection = @model.get(@options.name)
25
- @all_entries = @options.all_entries
26
25
 
27
26
  render: ->
28
27
  $(@el).html(@template()()).attr('id', "#{@model.paramRoot}_#{@options.name}_ids")
@@ -31,7 +30,7 @@ class Locomotive.Views.Shared.Fields.ManyToManyView extends Backbone.View
31
30
 
32
31
  @make_entries_sortable()
33
32
 
34
- @refresh_select_field()
33
+ @enable_select2()
35
34
 
36
35
  return @
37
36
 
@@ -69,13 +68,17 @@ class Locomotive.Views.Shared.Fields.ManyToManyView extends Backbone.View
69
68
  add_entry: (event) ->
70
69
  event.stopPropagation() & event.preventDefault()
71
70
 
72
- entry_id = @$('.new-entry select').val()
73
- entry = @get_entry_from_id(entry_id)
71
+ # get the raw data of the selected entry
72
+ data = @$('.new-entry .selected-entry').select2('data')
74
73
 
75
- return unless entry?
74
+ return if !data? || _.isArray(data)
75
+
76
+ # build a new instance of a content entry
77
+ entry = new Locomotive.Models.ContentEntry(data)
76
78
 
77
79
  @insert_entry(entry)
78
- @refresh_select_field()
80
+
81
+ @$('.new-entry .selected-entry').select2('val', '')
79
82
 
80
83
  remove_entry: (event) ->
81
84
  event.stopPropagation() & event.preventDefault()
@@ -87,45 +90,53 @@ class Locomotive.Views.Shared.Fields.ManyToManyView extends Backbone.View
87
90
  $(event.target).closest('li').remove()
88
91
  @$('.empty').show() if @$('> ul > li').size() == 0
89
92
 
90
- @refresh_position_entries() & @refresh_select_field()
93
+ @refresh_position_entries()
91
94
 
92
- refresh_select_field: ->
93
- @$('.new-entry select optgroup, .new-entry select option').remove()
95
+ enable_select2: ->
96
+ $input = @$('.new-entry .selected-entry')
97
+ options = $input.data()
94
98
 
95
- _.each @all_entries, (entry_or_group) =>
96
- if _.isArray(entry_or_group.entries)
97
- group_html = $('<optgroup/>').attr('label', entry_or_group.name)
99
+ super($input, options)
98
100
 
99
- _.each entry_or_group.entries, (entry) =>
100
- unless @collection.get(entry._id)?
101
- option = new Option(entry._label, entry._id, false)
102
- group_html.append(option)
101
+ # $input.select2
102
+ # width: '50%'
103
+ # minimumInputLength: 1
104
+ # quietMillis: 100
105
+ # allowClear: true
106
+ # placeholder: ' '
107
+ # ajax:
108
+ # url: options.url
109
+ # data: (term, page) ->
110
+ # q: term
111
+ # page: page
112
+ # results: (data, page) =>
113
+ # results: @build_results(data, options.groupBy)
114
+ # more: data.length == options.perPage
103
115
 
104
- @$('.new-entry select').append(group_html)
105
- else
106
- unless @collection.get(entry_or_group._id)?
107
- option = new Option(entry_or_group._label, entry_or_group._id, false)
108
- @$('.new-entry select').append(option)
116
+ # initSelection: (element, callback) -> null
109
117
 
110
- get_entry_from_element: (element) ->
111
- entry_html = $(element).closest('li')
112
- id = $(entry_html).data('data-entry-id')
113
- @collection.get(id)
118
+ # build_results: (raw_data, group_by) ->
119
+ # _.tap [], (list) =>
120
+ # _.each raw_data, (data) =>
121
+ # unless @collection.get(data._id)?
122
+ # data.text = data._label
114
123
 
115
- get_entry_from_id: (id) ->
116
- entry = null
117
-
118
- _.each @all_entries, (entry_or_group) =>
119
- if _.isArray(entry_or_group.entries)
120
- entry ||= _.detect(entry_or_group.entries, (_entry) => _entry._id == id)
121
- else
122
- entry = entry_or_group if entry_or_group._id == id
123
-
124
- if entry?
125
- new Locomotive.Models.ContentEntry(entry)
126
- else
127
- null
124
+ # if group_by?
125
+ # group_name = _.result(data, group_by)
128
126
 
127
+ # # does the group exist?
128
+ # group = _.find list, (_group) -> _group.text == group_name
129
129
 
130
+ # unless group?
131
+ # # build a new group
132
+ # group = { text: group_name, children: [] }
133
+ # list.push(group)
130
134
 
135
+ # group.children.push(data)
136
+ # else
137
+ # list.push(data)
131
138
 
139
+ get_entry_from_element: (element) ->
140
+ entry_html = $(element).closest('li')
141
+ id = $(entry_html).data('data-entry-id')
142
+ @collection.get(id)
@@ -39,7 +39,6 @@ class Locomotive.Views.Snippets.FormView extends Locomotive.Views.Shared.FormVie
39
39
  @$('#snippet_name').slugify
40
40
  target: @$('#snippet_slug')
41
41
  url: window.permalink_service_url
42
- underscore: true
43
42
 
44
43
  open_image_picker: (event) ->
45
44
  event.stopPropagation() & event.preventDefault()
@@ -96,6 +96,37 @@ ul.list {
96
96
  } // ul.list li
97
97
  }
98
98
 
99
+ #entries-list.grouped {
100
+
101
+ li.item {
102
+ span.handle {
103
+ display: none;
104
+ }
105
+ } // li.item
106
+
107
+ &.sortable {
108
+
109
+ li.item {
110
+ span.handle {
111
+ @include icon-button;
112
+
113
+ margin: 0px;
114
+ top: -1px !important;
115
+
116
+ i {
117
+ font-size: 9px;
118
+ }
119
+ }
120
+
121
+ a {
122
+ margin-left: 0px;
123
+ }
124
+ } // .sortable li.item
125
+
126
+ }
127
+
128
+ }
129
+
99
130
  #entries-list.list {
100
131
 
101
132
  li.item {
@@ -182,6 +182,24 @@ form.formtastic {
182
182
  float: left;
183
183
  margin: -3px 10px 0 0;
184
184
  }
185
+
186
+ .localized-icon {
187
+ margin-right: 8px;
188
+ padding: 2px;
189
+
190
+ background-color: #6D6D6B;
191
+ @include border-radius(8px);
192
+
193
+ font-size: 10px;
194
+ color: #fff;
195
+ @include single-text-shadow(transparent, 0px, 0px, 0px, 0px);
196
+ text-shadow: none;
197
+
198
+ &.untranslated {
199
+ background-color: #f2af00;
200
+ }
201
+ }
202
+
185
203
  }
186
204
 
187
205
  p.inline-hints {
@@ -195,6 +213,7 @@ form.formtastic {
195
213
  color: #5E5F64;
196
214
  @include single-text-shadow(rgba(255, 255, 255, 0.8), 0px, 1px, 1px);
197
215
  }
216
+
198
217
  } // p.inline-hints
199
218
 
200
219
  .actions {
@@ -19,6 +19,12 @@ module Locomotive
19
19
  respond_with(@account)
20
20
  end
21
21
 
22
+ def update
23
+ @account.from_presenter(params[:account])
24
+ @account.save
25
+ respond_with(@account)
26
+ end
27
+
22
28
  def destroy
23
29
  @account.destroy
24
30
  respond_with(@account)
@@ -64,7 +64,7 @@ module Locomotive
64
64
  end
65
65
 
66
66
  def sort
67
- @content_type.klass_with_custom_fields(:entries).sort_entries!(params[:entries])
67
+ @content_type.klass_with_custom_fields(:entries).sort_entries!(params[:entries], @content_type.sortable_column)
68
68
  respond_with @content_type
69
69
  end
70
70
 
@@ -37,5 +37,27 @@ module Locomotive
37
37
  end
38
38
  end
39
39
 
40
+ # Display the label related to a field of a content entry.
41
+ # If the field is not localized, we just display the label.
42
+ # If the field is localized, then we display a nice flag icon
43
+ # to let the end-user know about it.
44
+ #
45
+ # @param [ Object ] content_entry The content entry
46
+ # @param [ Object ] field The custom field
47
+ #
48
+ # @return [ String ] The label with or without the icon
49
+ #
50
+ def label_for_custom_field(content_entry, field)
51
+ if field.localized?
52
+ translated_css = content_entry.translated_field?(field) ? '' : 'untranslated'
53
+
54
+ icon = content_tag(:i, '', class: 'icon-flag')
55
+ tag = content_tag(:span, icon, class: "localized-icon #{translated_css}")
56
+ "#{tag}#{field.label}"
57
+ else
58
+ field.label
59
+ end
60
+ end
61
+
40
62
  end
41
63
  end