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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +260 -0
- data/MIT-LICENSE +1 -1
- data/README.md +9 -5
- data/app/assets/javascripts/drg_cms/drg_cms.js +35 -19
- data/app/assets/javascripts/drg_cms_application.js +0 -2
- data/app/assets/javascripts/drg_cms_cms.js +2 -3
- data/app/assets/stylesheets/drg_cms/jstree.css +32 -27
- data/app/assets/stylesheets/drg_cms/select-multiple.css +4 -2
- data/app/controllers/dc_application_controller.rb +3 -2
- data/app/controllers/dc_common_controller.rb +7 -7
- data/app/controls/dc_category_control.rb +61 -0
- data/app/forms/cms_menu.yml +3 -2
- data/app/forms/dc_category.yml +17 -8
- data/app/forms/dc_category_as_tree.yml +31 -0
- data/app/forms/help/dc_category_as_tree.en +4 -0
- data/app/forms/help/dc_category_as_tree.sl +5 -0
- data/app/helpers/cms_edit_helper.rb +2 -2
- data/app/helpers/dc_application_helper.rb +31 -49
- data/app/helpers/dc_category_helper.rb +129 -0
- data/app/models/dc_category.rb +50 -24
- data/app/models/drgcms_form_fields/date_picker.rb +10 -12
- data/app/models/drgcms_form_fields/datetime_picker.rb +10 -11
- data/app/models/drgcms_form_fields/drgcms_field.rb +46 -4
- data/app/models/drgcms_form_fields/tree_select.rb +20 -19
- data/app/views/layouts/content.html.erb +1 -1
- data/config/locales/drgcms_en.yml +2 -0
- data/config/locales/drgcms_sl.yml +2 -0
- data/drg_cms.gemspec +2 -2
- data/lib/drg_cms/version.rb +1 -1
- data/lib/tasks/dc_cleanup.rake +20 -42
- metadata +12 -7
- data/History.log +0 -109
@@ -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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
data/app/forms/cms_menu.yml
CHANGED
@@ -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
|
-
|
70
|
+
|
71
|
+
100:
|
71
72
|
caption: helpers.label.dc_poll.tabletitle
|
72
73
|
controller: cmsedit
|
73
74
|
icon: poll-o
|
data/app/forms/dc_category.yml
CHANGED
@@ -3,8 +3,17 @@
|
|
3
3
|
table: dc_category
|
4
4
|
|
5
5
|
index:
|
6
|
-
filter: name, description,
|
7
|
-
actions:
|
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
|
-
|
40
|
-
size: 30
|
48
|
+
size: 30
|
41
49
|
20:
|
42
50
|
name: description
|
43
51
|
type: text_field
|
44
|
-
|
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
|
-
|
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,5 @@
|
|
1
|
+
---
|
2
|
+
index: "<p>Urejanje kategorij v drevesnem pogledu. Poiščite vašo kategorijo
|
3
|
+
in kliknite desni gumb na miški za menu.</p>\r\n"
|
4
|
+
form: "<p>Urejanje kategorij v drevesnem pogledu. Poiščite vašo kategorijo
|
5
|
+
in kliknite desni gumb na miš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 = %
|
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">#{
|
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
|
-
|
339
|
-
|
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:
|
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, :
|
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
|
-
#
|
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
|
-
|
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
|
916
|
-
|
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
|
-
|
924
|
-
|
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
|
-
|
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
|
data/app/models/dc_category.rb
CHANGED
@@ -42,32 +42,60 @@
|
|
42
42
|
# is most useful for grouping news, blog entries ...
|
43
43
|
#####################################################################
|
44
44
|
class DcCategory
|
45
|
-
|
46
|
-
|
45
|
+
include Mongoid::Document
|
46
|
+
include Mongoid::Timestamps
|
47
47
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
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
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
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
|
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
|
-
|
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
|
-
|
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']
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
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 << %
|
84
|
+
@js << %(
|
87
85
|
$(document).ready(function() {
|
88
|
-
$("##{record}_#{@yaml['name']}").datetimepicker(
|
89
|
-
#{hash_to_options(
|
86
|
+
$("##{record}_#{@yaml['name']}").datetimepicker({
|
87
|
+
#{hash_to_options(options)}
|
90
88
|
});
|
91
89
|
});
|
92
|
-
|
90
|
+
) unless @readonly
|
93
91
|
|
94
92
|
self
|
95
93
|
end
|