drg_cms 0.6.1.11 → 0.7.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -116,7 +116,7 @@ def toggle_edit_mode
116
116
  end
117
117
  url << (url.match(/\?/) ? '&' : '?')
118
118
  url << "return_to_ypos=#{ypos}"
119
- redirect_to url
119
+ redirect_to(url, allow_other_host: true)
120
120
  end
121
121
 
122
122
  ####################################################################
@@ -128,15 +128,15 @@ def process_login
128
128
 
129
129
  unless params[:record][:password].blank? #password must not be empty
130
130
  user = DcUser.find_by(username: params[:record][:username], active: true)
131
- if user and user.authenticate(params[:record][:password])
131
+ if user && user.authenticate(params[:record][:password])
132
132
  fill_login_data(user, params[:record][:remember_me].to_i == 1)
133
- return redirect_to params[:return_to] || '/'
133
+ return redirect_to(params[:return_to] || '/', allow_other_host: true)
134
134
  else
135
135
  clear_login_data # on the safe side
136
136
  end
137
137
  end
138
138
  flash[:error] = t('drgcms.invalid_username')
139
- redirect_to params[:return_to_error] || '/'
139
+ redirect_to(params[:return_to] || '/', allow_other_host: true)
140
140
  end
141
141
 
142
142
  ####################################################################
@@ -144,7 +144,7 @@ end
144
144
  ####################################################################
145
145
  def logout
146
146
  clear_login_data
147
- redirect_to params[:return_to] || '/'
147
+ redirect_to(params[:return_to] || '/', allow_other_host: true)
148
148
  end
149
149
 
150
150
  ####################################################################
@@ -156,14 +156,14 @@ def login
156
156
  user = DcUser.find(cookies.signed[:remember_me])
157
157
  if user and user.active
158
158
  fill_login_data(user, true)
159
- return redirect_to params[:return_to]
159
+ return(redirect_to params[:return_to], allow_other_host: true)
160
160
  else
161
161
  clear_login_data # on the safe side
162
162
  end
163
163
  end
164
164
  # Display login
165
165
  route = params[:route] || 'poll'
166
- redirect_to "/#{route}?poll_id=login&return_to=#{params[:return_to]}"
166
+ redirect_to("/#{route}?poll_id=login&return_to=#{params[:return_to]}", allow_other_host: true)
167
167
  end
168
168
 
169
169
  ####################################################################
@@ -0,0 +1,61 @@
1
+ #--
2
+ # Copyright (c) 2014+ Damjan Rems
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+ ######################################################################
25
+ # DrgcmsControls for DcPage model.
26
+ ######################################################################
27
+ module DcCategoryControl
28
+
29
+ ######################################################################
30
+ # Called when new empty record is created
31
+ ######################################################################
32
+ def dc_new_record
33
+ if params[:selected]
34
+
35
+ end
36
+ if params[:from_menu]
37
+ # find menu and submenu. Menu class is defined in Site.
38
+ menu_a = params[:id].split(';')
39
+ menu = dc_get_site.menu_klass.find(menu_a.shift)
40
+ menu_items_method = "#{dc_get_site.menu_class}_items".underscore
41
+ menu_i = menu.send(menu_items_method).find(menu_a.shift)
42
+ while menu_a.size > 0 do menu_i = menu_i.send(menu_items_method).find(menu_a.shift) end
43
+ # Fill values for form
44
+ @record.subject = menu_i.caption
45
+ @record.dc_site_id = menu.dc_site_id
46
+ @record.menu_id = params[:id]
47
+ # set update_menu on save parameter
48
+ params['p__update_menu'] = '1'
49
+ else
50
+ @record.design_id = params[:design_id] if params[:design_id]
51
+ return unless params[:page_id]
52
+ # inherit some values from currently active page
53
+ if page = DcPage.find(params[:page_id])
54
+ @record.design_id = page.design_id
55
+ @record.menu = page.menu
56
+ @record.dc_site_id = page.dc_site_id
57
+ end
58
+ end
59
+ end
60
+
61
+ end
@@ -62,12 +62,13 @@ menu:
62
62
  controller: cmsedit
63
63
  icon: more_horiz-o
64
64
  table: dc_simple_menu
65
- 90:
65
+ 90:
66
66
  caption: helpers.label.dc_category.tabletitle
67
67
  controller: cmsedit
68
68
  icon: list
69
69
  table: dc_category
70
- 100:
70
+
71
+ 100:
71
72
  caption: helpers.label.dc_poll.tabletitle
72
73
  controller: cmsedit
73
74
  icon: poll-o
@@ -3,8 +3,17 @@
3
3
  table: dc_category
4
4
 
5
5
  index:
6
- filter: name, description, ctype, parent
7
- actions: standard
6
+ filter: name, description, dc_site_id, parent
7
+ actions:
8
+ 1: new
9
+ 2: filter
10
+ 10:
11
+ type: link
12
+ icon: account_tree-o
13
+ caption: drgcms.category_as_tree
14
+ table: dc_category
15
+ form_name: dc_category_as_tree
16
+ # controller: cmsedit
8
17
 
9
18
  result_set:
10
19
  actions:
@@ -36,13 +45,11 @@ form:
36
45
  10:
37
46
  name: name
38
47
  type: text_field
39
- html:
40
- size: 30
48
+ size: 30
41
49
  20:
42
50
  name: description
43
51
  type: text_field
44
- html:
45
- size: 100
52
+ size: 100
46
53
  30:
47
54
  name: ctype
48
55
  type: select
@@ -51,8 +58,7 @@ form:
51
58
  40:
52
59
  name: order
53
60
  type: text_field
54
- html:
55
- size: 5
61
+ size: 5
56
62
  50:
57
63
  name: dc_site_id
58
64
  type: select
@@ -65,4 +71,7 @@ form:
65
71
  eval: DcCategory.values_for_parent
66
72
  html:
67
73
  include_blank: true
74
+ 70:
75
+ name: active
76
+ type: check_box
68
77
 
@@ -0,0 +1,31 @@
1
+ ## YAML Template for page
2
+ ---
3
+ extend: dc_category
4
+
5
+ index:
6
+ actions:
7
+ 10: /
8
+
9
+ result_set:
10
+ type: method
11
+ eval: categories_as_tree
12
+
13
+ form:
14
+ actions:
15
+ standard: /
16
+ 1:
17
+ type: link
18
+ caption: drgcms.back
19
+ icon: arrow-back
20
+ form_name: dc_category_as_tree
21
+ table: dc_category
22
+ params:
23
+ ids:
24
+ object: params
25
+ method: ids
26
+
27
+ 10:
28
+ type: submit
29
+ caption: 'drgcms.save&back'
30
+ form_name: dc_category_as_tree
31
+ table: dc_category
@@ -0,0 +1,4 @@
1
+ ---
2
+ index: "<p>Updates categories in a Tree view. For edit menu click right mouse button
3
+ over selected category.</p>\r\n"
4
+ form: ''
@@ -0,0 +1,5 @@
1
+ ---
2
+ index: "<p>Urejanje kategorij v drevesnem pogledu. Poi&scaron;čite va&scaron;o kategorijo
3
+ in kliknite desni gumb na mi&scaron;ki za menu.</p>\r\n"
4
+ form: "<p>Urejanje kategorij v drevesnem pogledu. Poi&scaron;čite va&scaron;o kategorijo
5
+ in kliknite desni gumb na mi&scaron;ki za menu.</p>\r\n"
@@ -137,7 +137,7 @@ def dc_actions_for_form(position)
137
137
  actions.delete('standard')
138
138
  actions = actions.to_a.sort { |x, y| x[0] <=> y[0] }
139
139
  # Add spinner to the beginning
140
- html = %Q[<span class="dc-spinner">#{fa_icon('settings-o spin')}</span><ul class="dc-menu #{position}">]
140
+ html = %(<span class="dc-spinner">#{mi_icon('settings-o spin')}</span><ul class="dc-menu #{position}">)
141
141
 
142
142
  actions.each do |key, options|
143
143
  session[:form_processing] = "form:actions: #{key} #{options}"
@@ -211,7 +211,7 @@ def dc_actions_for_form(position)
211
211
  dc_submit_tag(caption, icon, { data: parameters, title: options['title'] }) +
212
212
  '</li>'
213
213
  else
214
- %(<li><div class="dc-link-no">#{fa_icon(icon)} #{caption}</div></li>)
214
+ %(<li><div class="dc-link-no">#{mi_icon(icon)} #{caption}</div></li>)
215
215
  end
216
216
 
217
217
  # delete with some sugar added
@@ -314,50 +314,22 @@ def dc_new_title
314
314
  end
315
315
  end
316
316
 
317
- ####################################################################
318
- # Formats label and html input code for display on edit form.
319
- #
320
- # Parameters:
321
- # [input_html] String. HTML code for data input field.
322
- # [label] String. Input field label.
323
- ####################################################################
324
- def dc_label_for(input_html, label)
325
- c =<<eot
326
- <tr>
327
- <td class="dc-edit-label">#{label}</td>
328
- <td class="dc-edit-field">#{input_html}</td>
329
- </tr>
330
- eot
331
- c.html_safe
332
- end
333
-
334
317
  ############################################################################
335
318
  # Similar to rails submit_tag, but also takes care of link icon, translation, ...
336
319
  ############################################################################
337
- def dc_submit_tag(caption, icon, parms, rest={})
338
- parms['class'] ||= 'dc-link'
339
- if icon
340
- icon_image = if icon.match(/\./)
341
- image_tag(icon)
342
- elsif icon.match('<i')
343
- icon
344
- else
345
- fa_icon(icon)
346
- end
347
- end
348
- html = icon_image || ''
349
- #html << submit_tag(t(caption, caption), parms)
350
- %Q[<button type="submit" class="dc-submit" name="commit" value="#{t(caption, caption)}">#{icon_image} #{t(caption, caption)}</button>].html_safe
320
+ def dc_submit_tag(caption, icon, parms, rest = {})
321
+ icon_image = dc_icon_for_link(icon, nil)
322
+ %(<button type="submit" class="dc-submit" name="commit" value="#{t(caption, caption)}">#{icon_image} #{t(caption, caption)}</button>).html_safe
351
323
  end
352
324
 
353
325
  ############################################################################
354
326
  # Returns icon code if icon is specified
355
327
  ############################################################################
356
- def dc_icon_for_link(icon)
328
+ def dc_icon_for_link(icon, clas = 'dc-link-img')
357
329
  return '' if icon.blank?
358
330
 
359
331
  if icon.match(/\./)
360
- _origin.image_tag(icon, class: 'dc-link-img')
332
+ _origin.image_tag(icon, class: clas)
361
333
  elsif icon.match('<i')
362
334
  icon
363
335
  else
@@ -619,7 +591,7 @@ def dc_page_edit_menu(opts = @opts)
619
591
  opts[:editparams] ||= {}
620
592
  dc_link_menu_tag(title) do |html|
621
593
  opts[:editparams].merge!( controller: 'cmsedit', action: 'edit', 'icon' => 'edit-o' )
622
- opts[:editparams].merge!( :id => page.id, :t => _origin.site.page_class.underscore, f: opts[:form_name], edit_only: 'body' )
594
+ opts[:editparams].merge!( :id => page.id, :table => _origin.site.page_class.underscore, form_name: opts[:form_name], edit_only: 'body' )
623
595
  html << dc_link_for_edit1( opts[:editparams], t('drgcms.edit_content') )
624
596
 
625
597
  opts[:editparams].merge!( edit_only: nil, 'icon' => 'edit-o' )
@@ -867,7 +839,7 @@ end
867
839
  #
868
840
  # Parameters:
869
841
  # [ctrl] Controller object or object which holds methods to access session object. For example @parent
870
- # variable when called from renderer.
842
+ # when called from renderer.
871
843
  # [policy_id] Document or documents policy_id field value required to view data. Method will automatically
872
844
  # check if parameter send has policy_id field defined and use value of that field.
873
845
  #
@@ -882,9 +854,11 @@ end
882
854
  # False and message from policy that is blocking view if access is not allowed.
883
855
  ############################################################################
884
856
  def dc_user_can_view(ctrl, policy_id)
885
- policy_id = policy_id.policy_id if policy_id and policy_id.respond_to?(:policy_id)
857
+ @can_view_cache ||= {}
858
+ policy_id = policy_id.policy_id if policy_id&.respond_to?(:policy_id)
886
859
  # Eventualy object without policy_id will be checked. This is to prevent error
887
860
  policy_id = nil unless policy_id.class == BSON::ObjectId
861
+ return @can_view_cache[policy_id] if @can_view_cache[policy_id]
888
862
 
889
863
  site = ctrl.site
890
864
  policies = if site.inherit_policy.blank?
@@ -894,7 +868,7 @@ def dc_user_can_view(ctrl, policy_id)
894
868
  end
895
869
  # permission defined by default policy
896
870
  default_policy = Mongoid::QueryCache.cache { policies.find_by(is_default: true) }
897
- return false, 'Default access policy not found for the site!' unless default_policy
871
+ return cache_add(policy_id, false, 'Default access policy not found for the site!') unless default_policy
898
872
 
899
873
  permissions = {}
900
874
  default_policy.dc_policy_rules.to_a.each { |v| permissions[v.dc_policy_role_id] = v.permission }
@@ -902,28 +876,29 @@ def dc_user_can_view(ctrl, policy_id)
902
876
  part_policy = nil
903
877
  if policy_id
904
878
  part_policy = Mongoid::QueryCache.cache { policies.find(policy_id) }
905
- return false, 'Access policy not found for part!' unless part_policy
879
+ return cache_add(policy_id, false, 'Access policy not found for part!') unless part_policy
880
+
906
881
  part_policy.dc_policy_rules.to_a.each { |v| permissions[v.dc_policy_role_id] = v.permission }
907
882
  end
908
883
  # apply guest role if no roles defined
909
884
  if ctrl.session[:user_roles].nil?
910
885
  role = Mongoid::QueryCache.cache { DcPolicyRole.find_by(system_name: 'guest', active: true) }
911
- return false, 'System guest role not defined!' unless role
886
+ return cache_add(policy_id, false, 'System guest role not defined!') unless role
887
+
912
888
  ctrl.session[:user_roles] = [role.id]
913
889
  end
914
890
  # Check if user has any role that allows him to view part
915
- can_view, msg = false,''
916
- ctrl.session[:user_roles].each do |role|
917
- next unless permissions[role] # role not yet defined. Will die in next line.
918
- if permissions[role] > 0
919
- can_view = true
920
- break
921
- end
891
+ can_view = ctrl.session[:user_roles].reduce(false) do |result, role|
892
+ break true if permissions[role] && permissions[role] > 0
922
893
  end
923
- msg = if !can_view
924
- part_policy ? t(part_policy.message,part_policy.message) : t(default_policy.message,default_policy.message)
894
+
895
+ msg = ''
896
+ unless can_view
897
+ msg = part_policy ? t(part_policy.message, part_policy.message) : t(default_policy.message, default_policy.message)
898
+ # message may have variable content
899
+ msg = _origin.render(inline: msg, layout: nil) if msg.match('<%=')
925
900
  end
926
- return can_view, msg
901
+ cache_add(policy_id, can_view, msg)
927
902
  end
928
903
 
929
904
  ####################################################################
@@ -1234,5 +1209,12 @@ def dc_img_alt(file_name, text=nil)
1234
1209
  name[0,name.index('.')].downcase rescue name
1235
1210
  end
1236
1211
 
1212
+ private
1213
+
1214
+ # will cache dc_user_can_view response
1215
+ def cache_add(id, can_view, msg)
1216
+ @can_view_cache[id] = [can_view, msg]
1217
+ end
1218
+
1237
1219
 
1238
1220
  end
@@ -0,0 +1,129 @@
1
+ #--
2
+ # Copyright (c) 2012+ Damjan Rems
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+
25
+ ####################################################################
26
+ # Helper for editing categories as tree view.
27
+ ####################################################################
28
+ module DcCategoryHelper
29
+
30
+ ####################################################################
31
+ #
32
+ ####################################################################
33
+ def categories_as_tree
34
+ html = '<div id="catagories-as-tree"><ul><li data-id="nil"><span class="mi-o mi-home"></span>'
35
+ data = DcCategory.where(parent: nil).order_by(order: 1).to_a
36
+ html_for_category_tree(html, data)
37
+ (html << '</li></ul></div>' << js_for_category_tree).html_safe
38
+ end
39
+
40
+ private
41
+
42
+ ####################################################################
43
+ #
44
+ ####################################################################
45
+ def html_for_category_tree(html, data)
46
+ html << '<ul>'
47
+ data.each do |category|
48
+ icon = category.active ? 'check_box' : 'check_box_outline_blank'
49
+ html << %(<li id="#{category.id}" data-parent="#{category.parent}"><span class="mi-o mi-#{icon} mi-18"></span>#{category.name}\n)
50
+ children = DcCategory.where(parent: category.id).order_by(order: 1).to_a
51
+
52
+ html_for_category_tree(html, children) if children.size > 0
53
+ html << '</li>'
54
+ end
55
+ html << '</ul>'
56
+ end
57
+
58
+ ####################################################################
59
+ #
60
+ ####################################################################
61
+ def js_for_category_tree
62
+ %(<script>
63
+ $(function() {
64
+ $("#catagories-as-tree").jstree( {
65
+ core: { themes: { icons: false },
66
+ multiple: false
67
+ },
68
+ plugins: ["types", "contextmenu"],
69
+ contextmenu: {
70
+ items: function ($node) {
71
+ return {
72
+ edit: {
73
+ label: "<span class='dc-result-submenu'>#{t('drgcms.edit')}</span>",
74
+ icon: "mi-o mi-edit",
75
+ action: function (obj) {
76
+ let id = $('#catagories-as-tree').jstree('get_selected', true)[0].id;
77
+ let params = "&ids=" + id;
78
+ location.href = "/cmsedit/" + id + "/edit?t=dc_category&f=dc_category_as_tree" + params;
79
+ }
80
+ },
81
+
82
+ new_child: {
83
+ label: "<span class='dc-result-submenu'>#{t('drgcms.new')}</span>",
84
+ icon: "mi-o mi-plus",
85
+ action: function (obj) {
86
+ let id = $('#catagories-as-tree').jstree('get_selected', true)[0].id;
87
+ let params = "&ids=" + id + "&p_parent=" + id;
88
+ location.href = "/cmsedit/new?t=dc_category&f=dc_category_as_tree" + params
89
+ }
90
+ },
91
+
92
+ delete: {
93
+ label: "<span class='dc-result-submenu'>#{t('drgcms.delete')}</span>",
94
+ icon: "mi-o mi-delete",
95
+ action: function (obj) {
96
+ if (confirmation_is_cancled("#{t('drgcms.confirm_delete')}") === true) return false;
97
+
98
+ let id = $('#catagories-as-tree').jstree('get_selected', true)[0].id;
99
+ let id_return = $('#catagories-as-tree').jstree('get_selected', true)[0].data["parent"];
100
+
101
+ $.ajax({
102
+ url: "/cmsedit/" + id + "?t=dc_category",
103
+ type: 'DELETE',
104
+ success: function(data) {
105
+ let error = data.match("#{I18n.t('drgcms.category_has_subs')}");
106
+ if (error !== null) {
107
+ alert(error[0]);
108
+ params = "?t=dc_category&f=dc_category_as_tree&ids=" + id;
109
+ location.href = "/cmsedit" + params;
110
+ return true;
111
+ }
112
+ }
113
+ });
114
+
115
+ let params = "?t=dc_category&f=dc_category_as_tree&ids=" + id_return;
116
+ location.href = "/cmsedit" + params;
117
+ }
118
+ },
119
+ }
120
+ },
121
+ },
122
+ });
123
+ $("#catagories-as-tree").jstree(true).select_node("#{params[:ids]}");
124
+ });
125
+
126
+ </script>)
127
+ end
128
+
129
+ end
@@ -42,32 +42,60 @@
42
42
  # is most useful for grouping news, blog entries ...
43
43
  #####################################################################
44
44
  class DcCategory
45
- include Mongoid::Document
46
- include Mongoid::Timestamps
45
+ include Mongoid::Document
46
+ include Mongoid::Timestamps
47
47
 
48
- field :name, type: String
49
- field :description, type: String
50
- field :ctype, type: Integer, default: 1
51
- field :parent, type: BSON::ObjectId
52
- field :active, type: Boolean, default: true
53
- field :order, type: Integer, default: 0
54
- field :created_by, type: BSON::ObjectId
55
- field :updated_by, type: BSON::ObjectId
56
- field :dc_site_id, type: BSON::ObjectId
48
+ field :name, type: String
49
+ field :description, type: String
50
+ field :ctype, type: Integer, default: 1
51
+ field :parent, type: BSON::ObjectId
52
+ field :active, type: Boolean, default: true
53
+ field :order, type: Integer, default: 0
54
+ field :created_by, type: BSON::ObjectId
55
+ field :updated_by, type: BSON::ObjectId
56
+ field :dc_site_id, type: BSON::ObjectId
57
57
 
58
- validates :name, :presence => true
59
-
60
- index name: 1
61
- index ctype: 1
62
- index site_id: 1
58
+ index name: 1
59
+ index ctype: 1
60
+ index site_id: 1
61
+
62
+ validates :name, presence: true
63
+
64
+ before_destroy :can_destroy?
65
+
66
+ private
67
+
68
+ #########################################################################
69
+ # Can't delete if category document has children documents
70
+ #########################################################################
71
+ def can_destroy?
72
+ if DcCategory.where(parent: id).count > 0
73
+ errors.add(:base, I18n.t('drgcms.category_has_subs'))
74
+ throw :abort
75
+ end
76
+ end
63
77
 
64
78
  #########################################################################
65
- # Returns all values vhich can be used as parent select field.
79
+ # Returns all values for use as parent select field.
66
80
  #########################################################################
67
- def self.values_for_parent(site_id=nil) #:nodoc:
81
+ def self.values_for_parent(site_id = nil) #:nodoc:
68
82
  qry = where(active: true)
69
83
  qry = qry.and(dc_site_id: site_id.id) if site_id
70
- qry.sort(name: 1).inject([]) {|r,v| r << [v.name, v._id]}
84
+ parents = {} # cache parent names to minimize database usage
85
+ qry.inject([]) do |r, v|
86
+ if parents[v.parent].nil?
87
+ name = ''
88
+ parent = v.parent
89
+ until parent.nil?
90
+ doc = find(parent)
91
+ name = doc.name + ' / ' + name
92
+ parent = doc.parent
93
+ end
94
+ parents[v.parent] = name
95
+ end
96
+ name = v.parent ? parents[v.parent] + v.name : v.name
97
+ r << [name, v._id]
98
+ end.sort { |a, b| a.first <=> b.first }
71
99
  end
72
100
 
73
101
  #########################################################################
@@ -80,8 +108,8 @@ def self.choices4_ctype(site_id=nil)
80
108
  DcBigTable.choices4('dc_category_type', site_id)
81
109
  else
82
110
  opts = I18n.t('helpers.label.dc_category.choices4_ctype')
83
- # not defined
84
- return [] if opts.blank?
111
+ return [] if opts.blank? # not defined
112
+
85
113
  opts.split(',').inject([]) {|result, e| result << e.split(':')}
86
114
  end
87
115
  end
@@ -89,13 +117,11 @@ end
89
117
  #########################################################################
90
118
  # Returns choices for all categories, prepared for tree_select input field
91
119
  #########################################################################
92
- def self.choices4_categories(site_id=nil)
120
+ def self.choices4_categories(site_id = nil)
93
121
  qry = where(active: true)
94
- #
95
122
  ar = [nil]
96
123
  ar << site_id.id if site_id
97
124
  qry = qry.in(dc_site_id: ar)
98
- #
99
125
  qry.inject([]) { |result, category| result << [category.name, category.id, category.parent, category.order] }
100
126
  end
101
127
 
@@ -66,30 +66,28 @@ class DatePicker < DrgcmsField
66
66
  ###########################################################################
67
67
  def render
68
68
  value = @record.try(@yaml['name']) ? I18n.localize(@record[@yaml['name']].to_date) : nil
69
- #return ro_standard( @parent.dc_format_value(value)) if @readonly
70
-
71
- @yaml['options'] ||= {}
72
69
  set_initial_value
73
70
  @yaml['html']['size'] ||= @yaml['size'] || 10
74
71
  @yaml['html']['value'] ||= value
75
72
  @yaml['html']['autocomplete'] ||= 'off'
76
73
  @yaml['html']['class'] = @yaml['html']['class'].to_s + ' date-picker'
77
74
 
78
- @yaml['options']['lang'] ||= "'#{I18n.locale}'"
79
- @yaml['options']['format'] ||= "'#{t('datetimepicker.formats.date')}'"
80
- @yaml['options']['timepicker'] = false
81
- @yaml['options']['scrollMonth'] ||= false
82
- @yaml['options']['scrollInput'] ||= false
75
+ options = options_to_hash(@yaml['options'])
76
+ options['lang'] ||= I18n.locale.to_s
77
+ options['format'] ||= t('datetimepicker.formats.date')
78
+ options['timepicker'] = false
79
+ options['scrollMonth'] ||= false
80
+ options['scrollInput'] ||= false
83
81
 
84
82
  record = record_text_for(@yaml['name'])
85
83
  @html << @parent.text_field(record, @yaml['name'], @yaml['html'])
86
- @js << %Q[
84
+ @js << %(
87
85
  $(document).ready(function() {
88
- $("##{record}_#{@yaml['name']}").datetimepicker( {
89
- #{hash_to_options(@yaml['options'])}
86
+ $("##{record}_#{@yaml['name']}").datetimepicker({
87
+ #{hash_to_options(options)}
90
88
  });
91
89
  });
92
- ] unless @readonly
90
+ ) unless @readonly
93
91
 
94
92
  self
95
93
  end