locomotive_cms 2.3.1 → 2.4.0

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