rad_kit 0.0.9 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/Rakefile +3 -2
  2. data/app/controllers/app.rb +5 -0
  3. data/app/controllers/base.rb +47 -0
  4. data/app/controllers/base_app.rb +18 -0
  5. data/app/controllers/comments.rb +49 -0
  6. data/app/controllers/items.rb +208 -0
  7. data/app/helpers/kit/authorization.rb +121 -0
  8. data/app/helpers/kit/captcha.rb +10 -0
  9. data/app/helpers/kit/controller_helper.rb +76 -0
  10. data/app/helpers/kit/item_helper.rb +110 -0
  11. data/app/helpers/kit/navigation_helper.rb +15 -0
  12. data/app/helpers/kit/pagination.rb +62 -0
  13. data/app/models/_item/attachments.rb +15 -0
  14. data/app/models/_item/container.rb +30 -0
  15. data/app/models/_item/slug.rb +28 -0
  16. data/app/models/attachment.rb +9 -0
  17. data/app/models/comment.rb +30 -0
  18. data/app/models/item.rb +136 -0
  19. data/app/models/secure_token.rb +45 -0
  20. data/app/models/tag.rb +71 -0
  21. data/app/static/kit/highlight.css +48 -0
  22. data/app/static/kit.css +3 -0
  23. data/app/static/kit.js +0 -0
  24. data/app/static/themes/default/objects.less +28 -0
  25. data/app/views/controllers/comments/_embedded.html.haml +13 -0
  26. data/app/views/controllers/comments/_form.html.haml +8 -0
  27. data/app/views/controllers/comments/actions.js.haml +22 -0
  28. data/app/views/controllers/comments/show.html.haml +11 -0
  29. data/app/views/controllers/items/_items.html.haml +2 -0
  30. data/app/views/controllers/items/actions.js.haml +23 -0
  31. data/app/views/controllers/items/all.html.haml +4 -0
  32. data/app/views/controllers/items/inherited_action.html.haml +1 -0
  33. data/app/views/kit/_bottom_panel.html.haml +9 -0
  34. data/app/views/kit/_debug.html.haml +13 -0
  35. data/app/views/kit/_messages.html.haml +4 -0
  36. data/app/views/kit/_navigation.html.haml +19 -0
  37. data/app/views/kit/_not_found.html.haml +1 -0
  38. data/app/views/kit/_top_panel.html.haml +19 -0
  39. data/app/views/kit/_web_analytics.html.erb +14 -0
  40. data/app/views/kit/aspects/_comments.html.haml +8 -0
  41. data/app/views/kit/captcha/_action.js.haml +2 -0
  42. data/app/views/kit/captcha/_form.html.haml +10 -0
  43. data/app/views/kit/layout.html.haml +22 -0
  44. data/app/views/kit/layout.js.haml +15 -0
  45. data/app/views/previews/_line.html.haml +8 -0
  46. data/app/views/previews/_thumb.html.haml +5 -0
  47. data/app/views/themes/default/file.html.haml +19 -0
  48. data/app/views/themes/default/folder.html.haml +15 -0
  49. data/app/views/themes/default/layout_definitions/default.yml +27 -0
  50. data/app/views/themes/default/list.html.haml +21 -0
  51. data/app/views/themes/default/list_item.html.haml +14 -0
  52. data/app/views/themes/default/page.html.haml +23 -0
  53. data/app/views/tools/_access.html.haml +12 -0
  54. data/app/views/tools/_buttons.html.haml +11 -0
  55. data/app/views/tools/_context_menu.html.haml +12 -0
  56. data/app/views/tools/_search.html.haml +5 -0
  57. data/app/views/tools/_tags.html.haml +10 -0
  58. data/config/locales/en.yml +136 -0
  59. data/config/locales/ru.yml +142 -0
  60. data/config/routes.rb +44 -0
  61. metadata +82 -23
data/Rakefile CHANGED
@@ -2,9 +2,10 @@ require 'rake_ext'
2
2
 
3
3
  project(
4
4
  name: "kit",
5
- official_name: 'rad_kit',
6
- gem: true,
5
+ official_name: 'rad_kit',
7
6
  summary: "Rapid Application Development Kit for Rad Framework",
7
+ dirs: ['app', 'config'],
8
+ gem: true,
8
9
 
9
10
  author: "Alexey Petrushin",
10
11
  homepage: "http://github.com/alexeypetrushin/rad_kit"
@@ -0,0 +1,5 @@
1
+ class App < Controllers::BaseApp
2
+ inherit Rad::Controller::Captcha
3
+
4
+ rad.extension :kit_app, self
5
+ end
@@ -0,0 +1,47 @@
1
+ class Base
2
+ inherit Rad::Controller::Http
3
+
4
+ def smoke_test
5
+ render inline: 'ok'
6
+ end
7
+
8
+ protected
9
+ allow_get_for %()
10
+
11
+ inherit Rad::Controller::Localized
12
+
13
+ before :prepare_current_user
14
+
15
+ inherit Rad::Controller::Authorized
16
+
17
+ helper Helpers::Kit::NavigationHelper
18
+
19
+ #
20
+ # User Error
21
+ #
22
+ def catch_user_error
23
+ begin
24
+ yield
25
+ rescue UserError => e
26
+ msg = e.message || ""
27
+ flash.error = msg
28
+ flash.sticky_error = msg
29
+
30
+ if request.xhr? or params.format == 'js'
31
+ render inline: %(rad.error("#{msg.js_escape.html_escape}");), layout: false
32
+ else
33
+ dont_persist_params{redirect_to default_path}
34
+ end
35
+ end
36
+ end
37
+ around :catch_user_error
38
+
39
+
40
+ #
41
+ # Interface Builder
42
+ #
43
+ def set_theme
44
+ theme.name = params.theme || rad.face.theme # || 'default'
45
+ end
46
+ before :set_theme
47
+ end
@@ -0,0 +1,18 @@
1
+ class BaseApp < Controllers::Base
2
+ inherit Helpers::Kit::ControllerHelper
3
+
4
+ helper Helpers::Kit::Authorization, Helpers::Kit::Captcha, Helpers::Kit::Pagination
5
+
6
+ def prepare_general_params
7
+ if params._tags
8
+ @selected_tags = params._tags.split('-').select{|tag| Models::Tag.valid_name?(tag)}
9
+ else
10
+ @selected_tags = []
11
+ end
12
+ @selected_tags.freeze
13
+ @selected_tags
14
+ end
15
+ before :prepare_general_params
16
+ attr_reader :selected_tags
17
+ helper_method :selected_tags
18
+ end
@@ -0,0 +1,49 @@
1
+ class Comments < Items
2
+ # prepare_model Comment, finder: :by_slug!, only: %w(show edit update destroy)
3
+
4
+ allow_get_for :show, :new, :edit
5
+
6
+ def show
7
+ require_permission :view, @model
8
+ end
9
+
10
+ def new
11
+ require_permission :create_comment
12
+ params.item_id.must_not_be.nil
13
+ @model = Models::Comment.new
14
+ end
15
+
16
+ def create
17
+ require_permission :create_comment
18
+ @item = Models::Item.by_param! params.item_id
19
+ @model = Models::Comment.new params.model
20
+ @model.item = @item
21
+ @model.owner = Models::User.current
22
+ if @model.save
23
+ flash.info = t :comment_created
24
+ # render action: :new
25
+ else
26
+ render action: :new
27
+ end
28
+ end
29
+
30
+ def edit
31
+ require_permission :update_comment, @model
32
+ end
33
+
34
+ def update
35
+ require_permission :update_comment, @model
36
+ if @model.set(params.model).save
37
+ flash.info = t :comment_updated
38
+ # render action: :update
39
+ else
40
+ render action: :edit
41
+ end
42
+ end
43
+
44
+ def destroy
45
+ require_permission :destroy_comment, @model
46
+ @model.destroy
47
+ flash.info = t :comment_destroyed
48
+ end
49
+ end
@@ -0,0 +1,208 @@
1
+ class Items < Controllers::App
2
+ persist_params
3
+
4
+ before do |c|
5
+ model = workspace.model
6
+ model ||= Models::Item.by_param workspace.params.id if workspace.params.id?
7
+ c.instance_variable_set '@model', model
8
+ end
9
+
10
+ partials do
11
+ show :buttons, only: [:all, :show]
12
+ show :search, only: [:all, :show]
13
+ show :tags, only: [:all, :show]
14
+ show :context_menu, only: :show
15
+
16
+ show :comments, only: :show
17
+ end
18
+
19
+ helper Helpers::Kit::ItemHelper
20
+
21
+ layout '/kit/layout'
22
+
23
+ allow_get_for :redirect, :all
24
+ protect_from_forgery
25
+
26
+ allow_get_for :show, :new, :edit, :redirect
27
+
28
+ def redirect
29
+ url = rad.router.default_url
30
+ url = url_for(:all) if url == '/' or url.blank?
31
+ redirect_to url
32
+ end
33
+
34
+ def show
35
+ respond_to do |f|
36
+ if @model
37
+ require_permission :view, @model
38
+
39
+ f.html{@html_title = @model.name}
40
+ f.json{render json: @model}
41
+ else
42
+ f.html{render :not_found}
43
+ f.json{render :not_found}
44
+ end
45
+ end
46
+ end
47
+
48
+ def new
49
+ require_permission :create
50
+ @model = model_class.new
51
+
52
+ respond_to do |f|
53
+ f.js
54
+ f.json{render json: @model}
55
+ end
56
+ end
57
+
58
+ def create
59
+ require_permission :create
60
+ @model = model_class.new params.model
61
+
62
+ respond_to do |f|
63
+ if @model.save
64
+ flash.info = t :"#{model_class.alias.underscore}_created"
65
+
66
+ f.js{redirect_to(path(@model))}
67
+ f.json{render json: @model}
68
+ else
69
+ f.js{render action: :new}
70
+ f.json{render json: {errors: @model.errors}, status: :failed}
71
+ end
72
+ end
73
+ end
74
+
75
+ def edit
76
+ require_permission :update, @model
77
+
78
+ respond_to do |f|
79
+ f.js
80
+ end
81
+ end
82
+
83
+ def update
84
+ require_permission :update, @model
85
+
86
+ respond_to do |f|
87
+ if @model.set(params.model).save
88
+ flash.info = t :"#{model_class.alias.underscore}_updated"
89
+
90
+ f.js
91
+ f.json{render :ok}
92
+ else
93
+ f.js{render action: :edit}
94
+ f.json{render json: {errors: @model.errors}, status: :failed}
95
+ end
96
+ end
97
+ end
98
+
99
+ def destroy
100
+ require_permission :destroy, @model
101
+ @model.destroy
102
+ flash.info = t :"#{model_class.alias.underscore}_destroyed"
103
+
104
+ respond_to do |f|
105
+ f.js{redirect_to(default_path)}
106
+ f.json{render :ok}
107
+ end
108
+ end
109
+
110
+ def all
111
+ respond_to do |f|
112
+ @page, @per_page = (params.page || 1).to_i, Models::Item::PER_PAGE
113
+
114
+ query = self.class.model_class.where(viewers: {_in: rad.user.major_roles}, dependent: {_exists: false})
115
+ query = query.where tags: {_all: selected_tags} unless selected_tags.empty?
116
+ @models = query.sort([:created_at, -1]).paginate(@page, @per_page).all
117
+
118
+ f.html{@html_title = rad.config.title}
119
+ f.json{render json: @models}
120
+ end
121
+ end
122
+
123
+
124
+ #
125
+ # Viewers and Collaborators
126
+ #
127
+ def viewers
128
+ require_permission :update_access, @model
129
+ remove_roles = (params.remove_roles || '').split("\n")
130
+ add_roles = (params.add_roles || '').split("\n")
131
+ partials.show :context_menu
132
+
133
+ remove_roles.each{|role| @model.remove_viewer role}
134
+ add_roles.each{|role| @model.add_viewer role}
135
+
136
+ respond_to do |format|
137
+ if @model.save
138
+ flash.info = t :viewers_updated
139
+
140
+ format.js{render action: :access} # "models/access"
141
+ format.json{render :ok}
142
+ else
143
+ flash.info = t :failed
144
+
145
+ format.js{render action: :access} # "models/access"
146
+ format.json{render :failed}
147
+ end
148
+ end
149
+ end
150
+
151
+ def collaborators
152
+ require_permission :update_access, @model
153
+ remove_roles = (params.remove_roles || '').split("\n")
154
+ add_roles = (params.add_roles || '').split("\n")
155
+ partials.show :context_menu
156
+
157
+ remove_roles.each{|role| @model.remove_collaborator role}
158
+ add_roles.each{|role| @model.add_collaborator role}
159
+
160
+ respond_to do |format|
161
+ if @model.save
162
+ flash.info = t :collaborators_updated
163
+
164
+ format.js{render action: :access} # "models/access"
165
+ format.json{render :ok}
166
+ else
167
+ flash.info = t :failed
168
+
169
+ format.js{render action: :access} # "models/access"
170
+ format.json{render :failed}
171
+ end
172
+ end
173
+ end
174
+
175
+
176
+ #
177
+ # Layout
178
+ #
179
+ def layout
180
+ require_permission :update, @model
181
+
182
+ @model.layout = params.value
183
+
184
+ respond_to do |format|
185
+ if @model.save
186
+ flash.info = t :layout_updated
187
+
188
+ format.js{reload_page}
189
+ format.json{render :ok}
190
+ else
191
+ flash.info = t :failed
192
+
193
+ format.js{}
194
+ format.json{render :failed}
195
+ end
196
+ end
197
+ end
198
+
199
+
200
+ #
201
+ # model_class
202
+ #
203
+ def self.model_class
204
+ @model_class ||= "Models::#{self.alias.singularize}".constantize
205
+ end
206
+ def model_class; self.class.model_class end
207
+ helper_method :model_class
208
+ end
@@ -0,0 +1,121 @@
1
+ module Authorization
2
+ def viewers_controls_for object
3
+ object.must_not_be.nil
4
+
5
+ all_selected_roles = []
6
+ all_avaliable_roles = []
7
+
8
+ # Ordinary Roles
9
+ controls = {
10
+ 'member' => link_to(
11
+ t(:member_role),
12
+ viewers_path(object, remove_roles: 'user', add_roles: 'member', format: :js), method: :post
13
+ ),
14
+ 'user' => link_to(
15
+ t(:user_role),
16
+ viewers_path(object, remove_roles: 'member', add_roles: 'user', format: :js), method: :post
17
+ ),
18
+ }
19
+
20
+ selected_role = Role.lower_role object.viewers
21
+ selected_role = nil if selected_role == 'manager'
22
+ avaliable_roles = Role::ORDERED_ROLES.select{|role| role != selected_role and role != 'manager'}
23
+ avaliable_roles = avaliable_roles.collect{|role| controls[role]}
24
+
25
+ all_selected_roles << t("#{selected_role}_role") if selected_role
26
+ all_avaliable_roles.push *avaliable_roles
27
+
28
+ # Custom Roles
29
+ custom_roles = rad.config.custom_roles
30
+ selected_roles = custom_roles.select{|role| object.viewers.include? role}
31
+ avaliable_roles = custom_roles - selected_roles
32
+
33
+ # selected_roles.collect! do |role|
34
+ # link_to(role, viewers_path(object, remove_roles: role, format: :js), method: :post)
35
+ # end
36
+ avaliable_roles.collect! do |role|
37
+ link_to(role, viewers_path(object, add_roles: role, format: :js), method: :post)
38
+ end
39
+
40
+ all_selected_roles.push *selected_roles
41
+ all_avaliable_roles.push *avaliable_roles
42
+
43
+ # Clear All
44
+ if all_selected_roles.blank?
45
+ all_selected_roles << t(:only_owner)
46
+ else
47
+ current_roles = object.viewers.select{|r| r != 'manager' and r != "user:#{object.owner_name}"}
48
+ all_avaliable_roles.unshift(
49
+ link_to(
50
+ t(:only_owner),
51
+ viewers_path(object, remove_roles: current_roles.join("\n"), format: :js), method: :post
52
+ )
53
+ )
54
+ end
55
+
56
+ [
57
+ %[#{t(:viewers)}: <span class='m_bold'>#{all_selected_roles.join(', ')}</span>],
58
+ %[<span class='m_tiny'>(#{all_avaliable_roles.join(', ')})</span>]
59
+ ]
60
+ end
61
+
62
+ def collaborators_controls_for object
63
+ object.must_not_be.nil
64
+
65
+ all_selected_roles = []
66
+ all_avaliable_roles = []
67
+
68
+ # Ordinary Roles
69
+ controls = {
70
+ 'member' => link_to(
71
+ t(:member_role),
72
+ collaborators_path(object, remove_roles: 'user', add_roles: 'member', format: :js), method: :post
73
+ ),
74
+ 'user' => link_to(
75
+ t(:user_role),
76
+ collaborators_path(object, remove_roles: 'member', add_roles: 'user', format: :js), method: :post
77
+ ),
78
+ }
79
+
80
+ selected_role = Role.lower_role object.collaborators
81
+ selected_role = nil if selected_role == 'manager'
82
+ avaliable_roles = Role::ORDERED_ROLES.select{|role| role != selected_role and role != 'manager'}
83
+ avaliable_roles = avaliable_roles.collect{|role| controls[role]}
84
+
85
+ all_selected_roles << t("#{selected_role}_role") if selected_role
86
+ all_avaliable_roles.push *avaliable_roles
87
+
88
+ # Custom Roles
89
+ custom_roles = rad.config.custom_roles
90
+ selected_roles = custom_roles.select{|role| object.collaborators.include? role}
91
+ avaliable_roles = custom_roles - selected_roles
92
+
93
+ # selected_roles.collect! do |role|
94
+ # link_to(role, collaborators_path(object, remove_roles: role, format: :js), method: :post)
95
+ # end
96
+ avaliable_roles.collect! do |role|
97
+ link_to(role, collaborators_path(object, add_roles: role, format: :js), method: :post)
98
+ end
99
+
100
+ all_selected_roles.push *selected_roles
101
+ all_avaliable_roles.push *avaliable_roles
102
+
103
+ # Clear All
104
+ if all_selected_roles.blank?
105
+ all_selected_roles << t(:only_owner)
106
+ else
107
+ current_roles = object.collaborators.select{|r| r != 'manager' and r != "user:#{object.owner_name}"}
108
+ all_avaliable_roles.unshift(
109
+ link_to(
110
+ t(:only_owner),
111
+ collaborators_path(object, remove_roles: current_roles.join("\n"), format: :js), method: :post
112
+ )
113
+ )
114
+ end
115
+
116
+ [
117
+ %[#{t(:collaborators)}: <span class='m_bold'>#{all_selected_roles.join(', ')}</span>],
118
+ %[<span class='m_tiny'>(#{all_avaliable_roles.join(', ')})</span>]
119
+ ]
120
+ end
121
+ end
@@ -0,0 +1,10 @@
1
+ module Captcha
2
+ def captcha_tag
3
+ return "" if rad.test?
4
+
5
+ captcha_html = recaptcha_tags public_key: config.recaptcha[:public_key],
6
+ display: {theme: :custom, custom_theme_widget: 'recaptcha_widget'}
7
+
8
+ render "/kit/captcha", locals: {captcha_html: captcha_html}
9
+ end
10
+ end
@@ -0,0 +1,76 @@
1
+ module ControllerHelper
2
+ inherited do
3
+ helper_method :partials
4
+ end
5
+
6
+ class Partials
7
+ attr_reader :controller
8
+
9
+ def initialize controller
10
+ @controller = controller
11
+ end
12
+
13
+ def show? name
14
+ partials.include? name
15
+ end
16
+
17
+ def hide? name
18
+ !show?(name)
19
+ end
20
+
21
+ def show name
22
+ partials[name] = true
23
+ end
24
+
25
+ def hide name
26
+ partials.delete name
27
+ end
28
+
29
+ protected
30
+ def partials; controller.send(:_partials) end
31
+ end
32
+
33
+ def _partials
34
+ @_partials ||= {}
35
+ end
36
+ protected :_partials
37
+
38
+ def partials &block
39
+ if block
40
+ partials.instance_eval &block
41
+ else
42
+ @partials ||= ::Helpers::Kit::ControllerHelper::Partials.new self
43
+ end
44
+ end
45
+ protected :partials
46
+
47
+ module ClassMethods
48
+ class Partials
49
+ attr_reader :controller_class
50
+
51
+ def initialize controller_class
52
+ @controller_class = controller_class
53
+ end
54
+
55
+ def show name, options = {}
56
+ controller_class.send :before, options do |controller|
57
+ controller.send(:_partials)[name] = true
58
+ end
59
+ end
60
+
61
+ def hide name, options = {}
62
+ controller_class.send :before, options do |controller|
63
+ controller.send(:_partials).delete name
64
+ end
65
+ end
66
+ end
67
+
68
+ def partials &block
69
+ if block
70
+ partials.instance_eval &block
71
+ else
72
+ @partials ||= ::Helpers::Kit::ControllerHelper::ClassMethods::Partials.new self
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,110 @@
1
+ module ItemHelper
2
+
3
+ #
4
+ # Tag Selector
5
+ #
6
+ def add_tag name
7
+ (selected_tags + [name]).join('-')
8
+ end
9
+
10
+ def remove_tag name
11
+ list = (selected_tags - [name]).join('-')
12
+ return nil if list.empty?
13
+ list
14
+ end
15
+
16
+ def render_item_tags item
17
+ # Tags
18
+
19
+ tags = item.tags.topic.collect{|tag_name| tag_link tag_name}
20
+
21
+ # Visibility
22
+ viewers = item.minor_viewers
23
+ owner_role = "user:#{item.owner_name}"
24
+ viewers = viewers.select{|role| role != owner_role}
25
+ if viewers.blank? # visible only to owner
26
+ tags << tag(:div, t(:owner_visibility), class: :m_owner_visibility)
27
+ else
28
+ viewers.each do |role|
29
+ if role == 'user'
30
+ # don't show public visibility
31
+ elsif role == 'member'
32
+ tags << tag(:div, t(:member_visibility), class: :m_member_visibility)
33
+ else
34
+ tags << tag(:div, role, class: :m_custom_visibility)
35
+ end
36
+ end
37
+ end
38
+
39
+ tags
40
+ end
41
+
42
+ def tag_link tag_name, count = nil
43
+ # link = if current_item and current_item.is_a?(Selector)
44
+ # url_for(action_name, _tags: tag_name)
45
+ # else
46
+ # items_path(_tags: tag_name)
47
+ # end
48
+
49
+ link = items_path(_tags: tag_name)
50
+
51
+ if count
52
+ link_to(tag_name, link, title: t(:tags_count, count: count))
53
+ else
54
+ link_to(tag_name, link)
55
+ end
56
+ end
57
+
58
+ def render_item_details item, opt = {}
59
+ skip = Array(opt[:skip])
60
+
61
+ item.must_be.a Models::Item
62
+ details = []
63
+ details << item.created_at.time_ago_in_words unless skip.include? :created_at
64
+ details << t(:created_by, owner: link_to(item.owner_name, user_path(item.owner_name))) unless skip.include? :owner
65
+ details << t(:comments_count, count: item.comments_count) if item.comments_count > 0 and !skip.include?(:comments)
66
+ details
67
+ end
68
+
69
+ def form_title_for item
70
+ # return if embedded? or !item.new_record?
71
+ return unless item.new_record?
72
+
73
+ model_name = item.class.alias.underscore
74
+ t "create_#{model_name}"
75
+ end
76
+
77
+ def common_fields_for_item form, opt = {}, &extra_fields
78
+ object = form.model #instance_variable_get '@object'
79
+ skip = Array(opt[:skip])
80
+
81
+ html = ""
82
+ html << form.text_field(:topics_as_string, label: t(:tags)) unless skip.include? :tags
83
+ more = ""
84
+ unless skip.include? :slug
85
+ slug_opt = object.new_record? ? {label: t(:slug)} : {label: t(:slug), description: t(:slug_description)}
86
+ # more << form.text_field(:slug, (object.new_record? ? '' : object.slug), slug_opt)
87
+ more << form.text_field(:slug, slug_opt)
88
+ end
89
+ more << capture(&extra_fields) if extra_fields
90
+ html << b.more(id: "form_for_#{object.class.name.underscore}", name: t(:show_more), 'content' => more)
91
+ # if extra_fields
92
+ # html << capture{b.more(id: "form_for_#{object.class.name.underscore}", name: t(:show_more), &extra_fields)}
93
+ # else
94
+
95
+ if extra_fields
96
+ concat html
97
+ else
98
+ html
99
+ end
100
+ end
101
+
102
+ def item_layout_selector
103
+ current = (@model.layout || :default).to_sym
104
+ layouts = rad.face.availiable_layouts[theme.name] || []
105
+ layouts << current unless layouts.include? current
106
+
107
+ html_options = {class: 'm_autosubmit_on_change', 'data-action' => layout_path(@model, format: :js), 'data-remote' => true}
108
+ "#{t(:layout)}: #{select_tag(:layout, current, layouts.collect{|l| [l, l]}, html_options)}"
109
+ end
110
+ end
@@ -0,0 +1,15 @@
1
+ module NavigationHelper
2
+ #
3
+ # [
4
+ # ['Users', user_path],
5
+ # ['Roles']
6
+ # ]
7
+ #
8
+ def breadcrumb
9
+ Array(@breadcrumb).collect{|item| item.is_a?(Array) ? link_to(*item) : item}
10
+ end
11
+
12
+ def breadcrumb?
13
+ breadcrumb.empty?
14
+ end
15
+ end