symphonia 2.1.7

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 (188) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +674 -0
  3. data/README.md +16 -0
  4. data/Rakefile +44 -0
  5. data/app/assets/images/bg-checker.png +0 -0
  6. data/app/assets/images/bullet.gif +0 -0
  7. data/app/assets/images/close.png +0 -0
  8. data/app/assets/images/loading.gif +0 -0
  9. data/app/assets/images/next.png +0 -0
  10. data/app/assets/images/prev.png +0 -0
  11. data/app/assets/javascripts/ckeditor/plugins/autogrow/plugin.js +232 -0
  12. data/app/assets/javascripts/ckeditor/plugins/autogrow/samples/autogrow.html +102 -0
  13. data/app/assets/javascripts/ckeditor/plugins/image_chooser/icons/addimage.png +0 -0
  14. data/app/assets/javascripts/ckeditor/plugins/image_chooser/plugin.js +15 -0
  15. data/app/assets/javascripts/symphonia/Sortable.js +1249 -0
  16. data/app/assets/javascripts/symphonia/_core.js +45 -0
  17. data/app/assets/javascripts/symphonia/application.js.erb +147 -0
  18. data/app/assets/javascripts/symphonia/filters.js +44 -0
  19. data/app/assets/javascripts/symphonia/symphonia_bootstrap_dialog.js +136 -0
  20. data/app/assets/javascripts/symphonia/symphonia_ckeditor.js +55 -0
  21. data/app/assets/stylesheets/symphonia/application.css +4 -0
  22. data/app/assets/stylesheets/symphonia/basic.scss +218 -0
  23. data/app/assets/stylesheets/symphonia/filters.scss +19 -0
  24. data/app/assets/stylesheets/symphonia/symphonia_bootstrap.scss +56 -0
  25. data/app/channels/application_cable/channel.rb +5 -0
  26. data/app/controllers/symphonia/accounts_controller.rb +169 -0
  27. data/app/controllers/symphonia/admin_controller.rb +22 -0
  28. data/app/controllers/symphonia/api_controller.rb +64 -0
  29. data/app/controllers/symphonia/application_controller.rb +8 -0
  30. data/app/controllers/symphonia/attachments_controller.rb +37 -0
  31. data/app/controllers/symphonia/filters_controller.rb +23 -0
  32. data/app/controllers/symphonia/images_controller.rb +16 -0
  33. data/app/controllers/symphonia/login_controller.rb +80 -0
  34. data/app/controllers/symphonia/roles_controller.rb +100 -0
  35. data/app/controllers/symphonia/user_sessions_controller.rb +16 -0
  36. data/app/controllers/symphonia/users_controller.rb +168 -0
  37. data/app/helpers/symphonia/application_helper.rb +422 -0
  38. data/app/helpers/symphonia/bootstrap_modal_helper.rb +59 -0
  39. data/app/helpers/symphonia/form_helper.rb +50 -0
  40. data/app/helpers/symphonia/renderer_helper.rb +85 -0
  41. data/app/mailers/symphonia/application_mailer.rb +6 -0
  42. data/app/mailers/symphonia/notifier.rb +42 -0
  43. data/app/models/symphonia/admin_module.rb +18 -0
  44. data/app/models/symphonia/application_record.rb +14 -0
  45. data/app/models/symphonia/attachment.rb +16 -0
  46. data/app/models/symphonia/common_file.rb +9 -0
  47. data/app/models/symphonia/email_preference.rb +5 -0
  48. data/app/models/symphonia/image.rb +46 -0
  49. data/app/models/symphonia/preference.rb +12 -0
  50. data/app/models/symphonia/role.rb +55 -0
  51. data/app/models/symphonia/swagger/error_model.rb +19 -0
  52. data/app/models/symphonia/swagger/responses.rb +27 -0
  53. data/app/models/symphonia/user.rb +141 -0
  54. data/app/models/symphonia/user_session.rb +19 -0
  55. data/app/views/common/403.html.erb +5 -0
  56. data/app/views/common/404.html.erb +2 -0
  57. data/app/views/layouts/symphonia/_modal.html.erb +19 -0
  58. data/app/views/layouts/symphonia/_query.html.erb +51 -0
  59. data/app/views/layouts/symphonia/application.html.erb +45 -0
  60. data/app/views/layouts/symphonia/application.pdf.erb +15 -0
  61. data/app/views/layouts/symphonia/mailer.html.erb +13 -0
  62. data/app/views/symphonia/accounts/_detail.html.erb +65 -0
  63. data/app/views/symphonia/accounts/_form.html.erb +14 -0
  64. data/app/views/symphonia/accounts/edit.html.erb +9 -0
  65. data/app/views/symphonia/accounts/edit.js.erb +5 -0
  66. data/app/views/symphonia/accounts/lost_password.html.erb +6 -0
  67. data/app/views/symphonia/accounts/lost_password.js.erb +3 -0
  68. data/app/views/symphonia/accounts/new_activation.html.erb +11 -0
  69. data/app/views/symphonia/accounts/new_activation.js.erb +6 -0
  70. data/app/views/symphonia/accounts/register.html.erb +20 -0
  71. data/app/views/symphonia/accounts/reset_password.html.erb +18 -0
  72. data/app/views/symphonia/accounts/update.js.erb +1 -0
  73. data/app/views/symphonia/admin/index.html.erb +15 -0
  74. data/app/views/symphonia/attachments/destroy.js.erb +1 -0
  75. data/app/views/symphonia/common/_editable_images_grid.html.erb +12 -0
  76. data/app/views/symphonia/common/_filters.html.erb +23 -0
  77. data/app/views/symphonia/common/_locale_chooser.html.erb +16 -0
  78. data/app/views/symphonia/common/_share_links.html.erb +5 -0
  79. data/app/views/symphonia/filters/options.html.erb +36 -0
  80. data/app/views/symphonia/filters/options.js.erb +9 -0
  81. data/app/views/symphonia/filters/table.html.erb +21 -0
  82. data/app/views/symphonia/login/_form.html.erb +19 -0
  83. data/app/views/symphonia/login/new.html.erb +11 -0
  84. data/app/views/symphonia/login_sessions/new.html.erb +1 -0
  85. data/app/views/symphonia/notifier/activation_user.html.erb +7 -0
  86. data/app/views/symphonia/notifier/activation_user.text.erb +3 -0
  87. data/app/views/symphonia/notifier/reset_password_user.html.erb +7 -0
  88. data/app/views/symphonia/notifier/reset_password_user.text.erb +3 -0
  89. data/app/views/symphonia/notifier/test_mail.html.erb +2 -0
  90. data/app/views/symphonia/notifier/test_mail.text.erb +3 -0
  91. data/app/views/symphonia/notifier/user_change_to_active.html.erb +3 -0
  92. data/app/views/symphonia/notifier/user_change_to_active.text.erb +1 -0
  93. data/app/views/symphonia/notifier/user_registered.html.erb +13 -0
  94. data/app/views/symphonia/notifier/user_registered.text.erb +8 -0
  95. data/app/views/symphonia/roles/_form.html.erb +30 -0
  96. data/app/views/symphonia/roles/edit.html.erb +5 -0
  97. data/app/views/symphonia/roles/index.html.erb +6 -0
  98. data/app/views/symphonia/roles/new.html.erb +4 -0
  99. data/app/views/symphonia/roles/show.html.erb +5 -0
  100. data/app/views/symphonia/users/_form.html.erb +13 -0
  101. data/app/views/symphonia/users/edit.html.erb +26 -0
  102. data/app/views/symphonia/users/edit.js.erb +3 -0
  103. data/app/views/symphonia/users/edit_current.html.erb +7 -0
  104. data/app/views/symphonia/users/index.html.erb +5 -0
  105. data/app/views/symphonia/users/new.html.erb +8 -0
  106. data/app/views/symphonia/users/show.html.erb +63 -0
  107. data/config/locales/cs.yml +233 -0
  108. data/config/locales/en.yml +47 -0
  109. data/config/routes.rb +52 -0
  110. data/db/migrate/20130714140500_create_users.rb +49 -0
  111. data/db/migrate/20130714140501_create_roles.rb +16 -0
  112. data/db/migrate/20130714140502_create_preferences.rb +26 -0
  113. data/db/migrate/20130828175114_create_attachments.rb +20 -0
  114. data/db/migrate/20141213204351_create_admin_modules.rb +20 -0
  115. data/db/seeds.rb +12 -0
  116. data/lib/generators/symphonia/entity_controller/entity_controller_generator.rb +48 -0
  117. data/lib/generators/symphonia/entity_controller/templates/controller.rb +100 -0
  118. data/lib/generators/symphonia/query/query_generator.rb +37 -0
  119. data/lib/generators/symphonia/setup/setup_generator.rb +52 -0
  120. data/lib/generators/symphonia/setup/templates/404.html +26 -0
  121. data/lib/generators/symphonia/setup/templates/500.html +37 -0
  122. data/lib/generators/symphonia/setup/templates/Gemfile +18 -0
  123. data/lib/generators/symphonia/setup/templates/base_layout.html.erb +46 -0
  124. data/lib/generators/symphonia/setup/templates/design.scss +4 -0
  125. data/lib/generators/symphonia/setup/templates/settings.rb +65 -0
  126. data/lib/generators/symphonia/setup/templates/spec_helper.rb +18 -0
  127. data/lib/symphonia/action_cable/connection.rb +31 -0
  128. data/lib/symphonia/admin_constraint.rb +9 -0
  129. data/lib/symphonia/attachable.rb +35 -0
  130. data/lib/symphonia/base_controller.rb +96 -0
  131. data/lib/symphonia/bootstrap_link_render.rb +69 -0
  132. data/lib/symphonia/controller_extensions.rb +200 -0
  133. data/lib/symphonia/engine.rb +137 -0
  134. data/lib/symphonia/form_builder.rb +137 -0
  135. data/lib/symphonia/menu_manager.rb +23 -0
  136. data/lib/symphonia/model_attributes/attribute.rb +137 -0
  137. data/lib/symphonia/model_attributes.rb +102 -0
  138. data/lib/symphonia/model_filters/base.rb +82 -0
  139. data/lib/symphonia/model_filters/boolean_filter.rb +26 -0
  140. data/lib/symphonia/model_filters/date_filter.rb +81 -0
  141. data/lib/symphonia/model_filters/integer_filter.rb +18 -0
  142. data/lib/symphonia/model_filters/select_filter.rb +48 -0
  143. data/lib/symphonia/model_filters/string_filter.rb +18 -0
  144. data/lib/symphonia/model_filters.rb +10 -0
  145. data/lib/symphonia/object.rb +31 -0
  146. data/lib/symphonia/permissions.rb +93 -0
  147. data/lib/symphonia/query.rb +275 -0
  148. data/lib/symphonia/query_columns/attribute_column.rb +43 -0
  149. data/lib/symphonia/query_columns/generic_column.rb +165 -0
  150. data/lib/symphonia/query_columns.rb +8 -0
  151. data/lib/symphonia/spec_helper.rb +4 -0
  152. data/lib/symphonia/user_management.rb +58 -0
  153. data/lib/symphonia/version.rb +4 -0
  154. data/lib/symphonia.rb +20 -0
  155. data/spec/controllers/account_controller_spec.rb +90 -0
  156. data/spec/controllers/admin_controller_spec.rb +35 -0
  157. data/spec/controllers/api_controller_spec.rb +9 -0
  158. data/spec/controllers/filters_controller_spec.rb +35 -0
  159. data/spec/controllers/images_controller_spec.rb +5 -0
  160. data/spec/controllers/login_controller_spec.rb +20 -0
  161. data/spec/controllers/roles_controller_spec.rb +12 -0
  162. data/spec/controllers/users_controller_spec.rb +47 -0
  163. data/spec/factories/factories.rb +52 -0
  164. data/spec/helpers/symphonia/application_helper_spec.rb +62 -0
  165. data/spec/mailers/previews/symphonia/notifier_preview.rb +27 -0
  166. data/spec/mailers/symphonia/notifier_spec.rb +76 -0
  167. data/spec/models/attachment_spec.rb +22 -0
  168. data/spec/models/query/attribute_spec.rb +8 -0
  169. data/spec/models/query/symphonia_query_spec.rb +70 -0
  170. data/spec/models/role_spec.rb +13 -0
  171. data/spec/models/user_spec.rb +10 -0
  172. data/spec/rails_helper.rb +13 -0
  173. data/spec/requests/accounts_spec.rb +118 -0
  174. data/spec/requests/attachments_controller_spec.rb +23 -0
  175. data/spec/requests/login_spec.rb +26 -0
  176. data/spec/requests/roles_spec.rb +10 -0
  177. data/spec/requests/users_spec.rb +50 -0
  178. data/spec/spec_helper.rb +101 -0
  179. data/spec/support/common_file.txt +2 -0
  180. data/spec/support/query.rb +36 -0
  181. data/spec/support/shared.rb +62 -0
  182. data/spec/support/shared_controllers.rb +31 -0
  183. data/spec/support/stub_users.rb +32 -0
  184. data/spec/support/symphonia.jpg +0 -0
  185. data/spec/support/wait_for_ajax.rb +15 -0
  186. data/spec/version_spec.rb +5 -0
  187. data/spec/views/filters/options.html.erb_spec.rb +14 -0
  188. metadata +697 -0
@@ -0,0 +1,168 @@
1
+ module Symphonia
2
+ class UsersController < ApplicationController
3
+ include Swagger::Blocks
4
+
5
+ swagger_path '/admin/users/{id}.json' do
6
+ operation :get do
7
+ key :summary, 'Find User by ID'
8
+ key :description, 'Returns a single user if the user has access'
9
+ # key :operationId, 'findPetById'
10
+ # key :tags, [
11
+ # 'pet'
12
+ # ]
13
+ parameter do
14
+ key :name, :id
15
+ key :in, :path
16
+ key :description, 'ID of user to fetch'
17
+ key :required, true
18
+ key :type, :integer
19
+ key :format, :int64
20
+ end
21
+ extend Symphonia::Swagger::Responses
22
+ response 200 do
23
+ key :description, 'user response'
24
+ schema do
25
+ key :'$ref', :User
26
+ end
27
+ end
28
+ # response :default do
29
+ # key :description, 'unexpected error'
30
+ # schema do
31
+ # key :'$ref', :ErrorModel
32
+ # end
33
+ # end
34
+ end
35
+ end
36
+
37
+ helper Symphonia::RendererHelper
38
+
39
+ before_action :find_user, except: %i[index new create show]
40
+ before_action :authorize, except: [:show]
41
+ before_action -> { menu_item(:my_account) }, only: %i[current edit_current update_current]
42
+
43
+ def index
44
+ @query = Symphonia::User.query.new
45
+ @query.from_params params
46
+ @entities = @query.entities
47
+ respond_to do |format|
48
+ format.html do
49
+ @entities = @entities.page(params[:page])
50
+ render layout: !request.xhr?
51
+ end
52
+ format.json { render json: @entities.all, only: %i[id]+Symphonia::User.registered_attributes.keys }
53
+ end
54
+ end
55
+
56
+ def show
57
+ @user = Symphonia::User.find(params[:id]) if params[:id]
58
+ @user ||= Symphonia::User.current
59
+ authorize
60
+ respond_to do |format|
61
+ format.html
62
+ format.json { render json: @user, except: %w[crypted_password password_salt persistence_token perishable_token] }
63
+ end
64
+ end
65
+
66
+ def new
67
+ @user = Symphonia::User.new
68
+ @roles = Symphonia::Role.sorted
69
+ respond_to do |format|
70
+ format.html
71
+ end
72
+ end
73
+
74
+ def create
75
+ @user = Symphonia::User.new(user_params)
76
+ respond_to do |format|
77
+ if @user.save
78
+ format.html { redirect_to @user, notice: t(:text_created) }
79
+ format.xml { render xml: @user, status: :created, location: @user }
80
+ format.json { render json: @user, status: :created, location: @user }
81
+ else
82
+ format.html do
83
+ @roles = Symphonia::Role.sorted
84
+ render action: 'new'
85
+ end
86
+ format.xml { render xml: @user.errors, status: :unprocessable_entity }
87
+ format.json { render json: @user.errors, status: :unprocessable_entity }
88
+ end
89
+ end
90
+ end
91
+
92
+ def edit
93
+ @roles = Role.all
94
+ end
95
+
96
+ def update
97
+ @user.attributes = user_params
98
+ @user.admin = params[:admin] if params[:admin] && Symphonia::User.current.admin?
99
+ if params[:role_id].present? && Symphonia::User.current.admin?
100
+ @role = Role.find(params[:role_id])
101
+ @user.role = @role
102
+ end
103
+ respond_to do |format|
104
+ @user.edited_by = current_user
105
+ @user.edited_at = DateTime.now
106
+ if @user.save
107
+ format.html { redirect_back_or_default user_path(@user), notice: t(:text_updated) }
108
+ format.any(:json ,:xml) { head :no_content }
109
+ else
110
+ format.html do
111
+ @roles = Symphonia::Role.all
112
+ render action: 'edit'
113
+ end
114
+ format.xml { render xml: @user.errors, status: :unprocessable_entity }
115
+ format.json { render json: @user.errors, status: :unprocessable_entity }
116
+ end
117
+ end
118
+ end
119
+
120
+ def destroy
121
+ @user.destroy
122
+
123
+ respond_to do |format|
124
+ format.html { redirect_to params[:back_url] || users_url }
125
+ format.js { render js: "Symphonia.filters.removeRow('#{view_context.dom_id(@user)}')"}
126
+ format.json { head :no_content }
127
+ end
128
+ end
129
+
130
+ def archive
131
+ @user.archive!
132
+ respond_to do |format|
133
+ format.html { redirect_to params[:back_url] || users_url }
134
+ format.json { head :no_content }
135
+ end
136
+ end
137
+
138
+ def unarchive
139
+ Notifier.user_change_to_active(@user).deliver_later
140
+ @user.unarchive!
141
+
142
+ respond_to do |format|
143
+ format.html { redirect_to params[:back_url] || users_url }
144
+ format.xml { head :no_content }
145
+ end
146
+ end
147
+
148
+ private
149
+
150
+ def find_user
151
+ @user = Symphonia::User.find(params[:id])
152
+ end
153
+
154
+ def authorize
155
+ if User.current.id == @user.try!(:id)
156
+ true
157
+ else
158
+ super
159
+ end
160
+ end
161
+
162
+ def user_params
163
+ allowed = [:login, :first_name, :last_name, :password, :password_confirmation, :email, :mail, preference_ids: []]
164
+ allowed.concat(%i[admin role_id]) if Symphonia::User.current.admin?
165
+ params.require(:user).permit(allowed)
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,422 @@
1
+ # require 'symphonia/bootstrap_link_render'
2
+ module Symphonia
3
+ module ApplicationHelper
4
+ include FontAwesome::Rails::IconHelper
5
+ include FormHelper
6
+
7
+ def bootstrap_class_for(flash_type)
8
+ case flash_type.to_sym
9
+ when :notice
10
+ 'alert-success'
11
+ when :error, :alert
12
+ 'alert-danger'
13
+ when :warning
14
+ 'alert-warning'
15
+ when :info
16
+ 'alert-info'
17
+ else
18
+ flash_type.to_s
19
+ end
20
+ end
21
+
22
+ # Renders flash messages
23
+ def render_flash_messages(flash_messages = nil)
24
+ s = ''
25
+ Array(flash_messages || flash).each do |type, message|
26
+ s << content_tag(:div, class: "alert #{bootstrap_class_for(type)}") do
27
+ content_tag(:button, '', class: 'fa fa-times-circle-o close', data: { dismiss: 'alert' }) + Array.wrap(message).collect { |m| fa_icon(type, text: m) }.join("<br>").html_safe
28
+ end
29
+ end
30
+
31
+ return s.html_safe
32
+ end
33
+
34
+ def render_menu(menu, options = {})
35
+ s = ''
36
+ Symphonia::MenuManager.menu(menu).each do |name, item|
37
+ s << render_menu_node(name, item).to_s
38
+ end
39
+ options[:container_class] ||= 'mr-auto'
40
+
41
+ return content_tag(:ul, s.html_safe, itemscope: '', itemtype: 'http://data-vocabulary.org/BreadcrumbList', class: "navbar-nav #{options[:container_class]}", id: menu.to_s)
42
+ end
43
+
44
+ def render_menu_node(menu, item, options = {})
45
+ condition = item[:if] ? item[:if].call : true
46
+ selected = @menu_item.to_sym == menu
47
+ label = case item[:label].class.name
48
+ when 'NilClass'
49
+ '&nbsp;'.html_safe
50
+ when 'String'
51
+ item[:label]
52
+ when 'Symbol'
53
+ t(item[:label])
54
+ when 'Proc'
55
+ item[:label].call(controller)
56
+ else
57
+ raise "MenuManager error: Label is unknown type: #{item[:label].class}"
58
+ end
59
+ if item[:children].blank?
60
+ return content_tag(:li, render_menu_link(item, label, options), class: "nav-item #{menu} #{'active' if selected} #{options[:class]}", id: item[:id]) if condition
61
+ else
62
+ children = ''
63
+ item[:children].each do |child, subitem|
64
+ children << render_menu_node(menu, subitem, class: 'dropdown-item').to_s
65
+ end
66
+ unless children.blank?
67
+ return content_tag(:li, class: "nav-item dropdown #{menu}") do
68
+ concat render_menu_link(item.merge({ class: 'dropdown-toggle', data: { toggle: 'dropdown' } }), label, { is_submenu: true })
69
+ concat content_tag(:ul, children.html_safe, class: 'dropdown-menu')
70
+ end
71
+ end
72
+ end
73
+ end
74
+
75
+ def render_menu_link(item, label, _options = {})
76
+ url = case item[:url].class.name
77
+ when 'Symbol'
78
+ if item[:url].to_s.include?('.')
79
+ endpoint, path = item[:url].to_s.split('.')
80
+ send(endpoint).send(path)
81
+ else
82
+ main_app.send item[:url]
83
+ end
84
+ when 'Proc'
85
+ item[:url].call(self)
86
+ else
87
+ item[:url]
88
+ end
89
+ link_to(
90
+ (content_tag(:i, '', class: "#{item[:icon]}") + "\n" + content_tag(:span, label, itemprop: 'title')).html_safe,
91
+ url,
92
+ class: "nav-link #{item[:class]}",
93
+ data: item[:data],
94
+ method: item[:method],
95
+ itemprop: 'url'
96
+ )
97
+ end
98
+
99
+ def html_title(*args)
100
+ if args.empty?
101
+ title = @html_title || []
102
+ title << t(:meta_title)
103
+ title.reject(&:blank?).join(' — ')
104
+ else
105
+ @html_title ||= []
106
+ @html_title += args
107
+ end
108
+ end
109
+
110
+ def html_description(*args)
111
+ if args.empty?
112
+ desc = @html_description
113
+ desc ||= t(:meta_description)
114
+ desc.to_s
115
+ else
116
+ @html_description ||= []
117
+ @html_description += args
118
+ end
119
+ end
120
+
121
+ def title(*args, &block)
122
+ options = args.extract_options!
123
+ header = args.shift
124
+ small = args.shift || ''
125
+ header_text = if header.is_a?(Symbol)
126
+ t(header, default: header.to_s.humanize)
127
+ else
128
+ header.to_s.dup
129
+ end
130
+ if @symphonia_modal_dialog
131
+ ActiveSupport::Deprecation.warn "@symphonia_modal_dialog is no used anymore !"
132
+ @symphonia_modal_dialog.title ||= header_text
133
+ ''
134
+ else
135
+ html_title(header_text.dup)
136
+ header_text << "\n" + content_tag(:small, small, class: 'text-muted') if small.present?
137
+ s = ''
138
+ if options[:back] && !request.xhr?
139
+ back_url = options[:back] unless options[:back].is_a? TrueClass
140
+ s << link_to_back(back_url)
141
+ end
142
+ s << capture(&block).to_s if block_given?
143
+ header_tag = content_tag request.xhr? && :h5 || :h1, id: 'page_header', class: s.present? && "col-6" || nil do
144
+ header_text.html_safe
145
+ end
146
+ return header_tag if s.blank?
147
+
148
+ content_tag :div, class: "row" do
149
+ header_tag + content_tag(:div, s.html_safe, class: "col-6 text-right")
150
+ end
151
+ end
152
+ end
153
+
154
+ alias_method :page_header, :title
155
+
156
+ def render_no_data(message = nil)
157
+ content_tag(:div, message || t(:text_no_data), class: 'nodata')
158
+ end
159
+
160
+ def content_for(name, content = nil, &block)
161
+ @has_content ||= {}
162
+ @has_content[name] = true
163
+ super(name, content, &block)
164
+ end
165
+
166
+ def has_content?(name)
167
+ !!(@has_content && @has_content[name])
168
+ end
169
+
170
+ def format_text(text, _options = {})
171
+ return '' if text.nil?
172
+
173
+ markdown = RDiscount.new(text, :smart, :filter_html)
174
+ markdown.to_html.html_safe
175
+ end
176
+
177
+ def format_html(text)
178
+ content_tag(:div, (defined?(Ckeditor) ? text.html_safe : format_text(text)), class: 'formatted-text')
179
+ end
180
+
181
+ def format_price(value, options = {})
182
+ number_to_currency(value, { precision: 1, strip_insignificant_zeros: true }.merge(options))
183
+ end
184
+
185
+ def multiselect_toggler(id = nil)
186
+ link_to(fa_icon(:plus), 'javascript:void(0);', onclick: "toggleMultiSelect(#{id || 'this'});return false", class: 'btn fa fa-border')
187
+ end
188
+
189
+ def link_to_back(url = nil)
190
+ link_to(icon(:back, t(:button_back)), (params[:back_url] || url || :back), class: 'btn btn-link back')
191
+ end
192
+
193
+ def link_to_new_entity(options = {})
194
+ return '' unless User.current.allowed_to?(:"manage_#{controller_name}")
195
+
196
+ anchor = options.has_key?(:anchor) ? options.delete(:anchor) : 'page_header'
197
+ label = options.delete(:label) || t("label_#{controller_name.singularize}_new")
198
+ url = options.delete(:url) || new_polymorphic_path(controller_name.singularize, anchor: anchor)
199
+ link = link_to(fa_icon('add', text: label), url, { class: 'btn btn-primary' }.merge(options))
200
+
201
+ # content_tag(:div, link, class: 'contextual')
202
+ end
203
+
204
+ # change the default link renderer for will_paginate
205
+ def will_paginate(collection_or_options = nil, options = {})
206
+ if collection_or_options.is_a? Hash
207
+ options, collection_or_options = collection_or_options, nil
208
+ end
209
+ unless options[:renderer]
210
+ options = options.merge renderer: Symphonia::BootstrapLinkRender
211
+ end
212
+ options[:query] ||= @query if @query
213
+ super *[collection_or_options, options].compact
214
+ end
215
+
216
+ def ckeditor_for(field_id, options = {})
217
+ return '' unless !!defined?(Ckeditor)
218
+
219
+ inline = options.delete(:inline)
220
+ opts = options.inject({}) do |mem, var|
221
+ key = var[0].to_s.camelcase(:lower)
222
+ key[0].downcase!
223
+ mem[key] = var[1]
224
+
225
+ mem
226
+ end
227
+ opts['toolbar'] ||= 'Basic'
228
+ # opts['customConfig'] ||= 'Basic'
229
+ js = if inline
230
+ "CKEDITOR.inline('#{field_id}', {toolbar: 'Basic'});"
231
+ else
232
+ "
233
+ var ta_editor = CKEDITOR.instances['#{field_id}'];
234
+ if (ta_editor) {CKEDITOR.remove(ta_editor);}
235
+ CKEDITOR.replace('#{field_id}', #{opts.to_json.html_safe});
236
+ "
237
+ end
238
+ javascript_tag("$(document).ready(function() {#{js.html_safe}})".html_safe)
239
+ end
240
+
241
+ def icon(fa, text = nil)
242
+ fa_icon(fa, text && { text: content_tag(:span, text, class: 'd-none d-sm-inline') } || {})
243
+ end
244
+
245
+ def render_symphonia_dialog(*args, &block)
246
+ ActiveSupport::Deprecation.warn "Use `render_modal` instead"
247
+ options = args.extract_options!
248
+ title = options[:title] || args.shift # first arg possible `title`
249
+ body = args.shift
250
+ options[:form_disabled] = true
251
+ size = options.delete(:size)
252
+ size ||= '90%' if options.delete(:large)
253
+ if size.to_s.match(%r(^\d+$))
254
+ size = size.to_s + '%'
255
+ end
256
+ @symphonia_modal_dialog = SymphoniaModalDialog.new(self, options)
257
+ @symphonia_modal_dialog.size = size
258
+ if block_given?
259
+ yield @symphonia_modal_dialog
260
+ else
261
+ raise ArgumentError if body.nil?
262
+ end
263
+ @symphonia_modal_dialog.title ||= title
264
+ if @symphonia_modal_dialog.body.blank?
265
+ if body.is_a?(Hash)
266
+ body.merge!(formats: [:html])
267
+ else
268
+ body = { partial: body, formats: [:html] }
269
+ end
270
+ @symphonia_modal_dialog.body = render(body)
271
+ end
272
+ html = @symphonia_modal_dialog.to_html
273
+ if options[:render_only]
274
+ html
275
+ else
276
+ js = %Q(
277
+ $('##{@symphonia_modal_dialog.modal_id}').modal('hide').remove();
278
+ $('body').append('#{j html}');
279
+ showModal('##{@symphonia_modal_dialog.modal_id}');
280
+ $("##{@symphonia_modal_dialog.modal_id} .modal-dialog input:text").first().focus();
281
+ $("##{@symphonia_modal_dialog.modal_id} .modal-dialog .modal-body div.buttons").remove();
282
+ )
283
+ js.concat("$('##{@symphonia_modal_dialog.modal_id} .modal-dialog').css({width: '#{size}'});") if size.present?
284
+ js.html_safe
285
+ end
286
+ end
287
+
288
+ # def render_modal_dialog(show = true, options = {}, &block)
289
+ # tags = SymphoniaModalDialog.new(self, options)
290
+ # yield tags if block_given?
291
+ # html = tags.to_html
292
+ # if show
293
+ # "$('##{tags.modal_id}').remove();$('body').append('#{j html}'); showModal('##{tags.modal_id}');".html_safe
294
+ # else
295
+ # html
296
+ # end
297
+ # end
298
+
299
+ class SymphoniaModalDialog
300
+
301
+ attr_writer :title, :body, :footer
302
+ attr_reader :modal_id, :title
303
+
304
+ attr_accessor :size
305
+
306
+ def initialize(controller, options = {})
307
+ @c = controller
308
+ @title = options.delete(:title)
309
+ @modal_id = options.delete(:id) || 'modal-dialog'
310
+ @form_options = options.delete(:form_options) || {}
311
+ @options = options
312
+ end
313
+
314
+ alias_attribute :id, :modal_id
315
+
316
+ def to_html
317
+ html = "<div id='#{@modal_id}' style='' class='modal fade' role='dialog'><div class='modal-dialog #{'modal-lg' if size.present?}'><div class='modal-content'>"
318
+ html << @c.content_tag(:div, class: 'modal-header') do
319
+ @c.content_tag(:button, '', class: 'close fa fa-times', data: { dismiss: 'modal' }, 'aria-hidden' => true) + @c.content_tag(:h4, @title, class: 'modal-title') + @header.to_s
320
+ end
321
+ content = @c.content_tag(:div, @c.content_tag(:div, body.html_safe, class: 'modal-content-inner-container container-fluid'), class: 'modal-body')
322
+ content << @c.content_tag(:div, footer.html_safe, class: 'modal-footer')
323
+
324
+ html << content.html_safe
325
+ html << '</div></div></div>'
326
+ html.html_safe
327
+ end
328
+
329
+ def header(&block)
330
+ if block_given?
331
+ @header = @c.capture(&block)
332
+ else
333
+ @header = (@header.is_a?(Proc) ? @header.call.to_s : @header.to_s)
334
+ end
335
+ end
336
+
337
+ def body(&block)
338
+ if block_given?
339
+ @body = @c.capture(&block)
340
+ else
341
+ @body = (@body.is_a?(Proc) ? @body.call.to_s : @body.to_s)
342
+ end
343
+ end
344
+
345
+ def footer(&block)
346
+ if block_given?
347
+ @footer = @c.capture(&block)
348
+ else
349
+ @footer = (@footer.is_a?(Proc) ? @footer.call.to_s : @footer.to_s)
350
+ end
351
+ end
352
+
353
+ def submit(name = nil, options = {})
354
+ name ||= @c.t(:button_save)
355
+ @footer = footer.to_s + @c.link_to(name, 'javascript:void(0)', { onclick: "$('##{@modal_id}').find('form').submit()", class: 'btn btn-primary' }.merge(options)).html_safe
356
+ end
357
+
358
+ end
359
+
360
+ # Example of use
361
+ # <%=
362
+ # table_header_tag_for(User) do |t|
363
+ # t.th :login
364
+ # t.th :email
365
+ # end
366
+ # %>
367
+ # options:
368
+ # => column : DB full name of column
369
+ #
370
+ # def table_header_tag_for(model, &block)
371
+ # tags = TableHeaderTag.new(model, self)
372
+ # yield tags
373
+ # tags.to_html
374
+ # end
375
+ #
376
+ # class TableHeaderTag
377
+ #
378
+ # attr_reader :view, :model
379
+ #
380
+ # def initialize(model, view)
381
+ # @model = model
382
+ # @tags = Array.new
383
+ # @view = view
384
+ # end
385
+ #
386
+ # def th(*args)
387
+ # options = args.extract_options!
388
+ # attribute = args.first
389
+ # label = args[1]
390
+ # raise ArgumentError if attribute.nil?
391
+ #
392
+ # sort_options = options.delete(:sort_options) || {}
393
+ # html_options = options.delete(:html_options) || {}
394
+ #
395
+ # label ||= @model.send(:human_attribute_name, attribute, options[:i18n] || {})
396
+ # @tags << @view.content_tag(:th, html_options) do
397
+ # if options[:sort] === false
398
+ # label
399
+ # else
400
+ # sort_options[:column] ||= options.delete(:column)
401
+ # sort_options[:column] ||= "#{@model.send(:table_name)}.#{attribute}"
402
+ # # @view.sortable_column(label, sort_options) # TODO: Rails 5 error
403
+ # label
404
+ # end
405
+ # end
406
+ #
407
+ # end
408
+ #
409
+ # def to_html
410
+ # @tags.join("\n").html_safe
411
+ # end
412
+ #
413
+ # end
414
+
415
+ # def render_share_buttons(url, name, options = {})
416
+ # options[:icon_css] ||= ''
417
+ # render(partial: 'common/share_links', locals: options.merge({ url: url, name: name }))
418
+ # end
419
+ end
420
+ end
421
+
422
+ #ApplicationHelper.send :include, Symphonia::ApplicationHelperExtension
@@ -0,0 +1,59 @@
1
+ module Symphonia
2
+ module BootstrapModalHelper
3
+
4
+ # Ruby shortcut for generate modals
5
+ #
6
+ # <%= render_modal title: t(:title) do %>
7
+ # <% render(template: 'path_to_template_or_partial', formats: [:html]) %>
8
+ # <% end %>
9
+
10
+ # template_or_partial example:
11
+
12
+ # <%= title(@entity, back: !request.xhr?) %>
13
+ #
14
+ # <%= symphonia_form_for(@entity, remote: request.xhr?) do |f| %>
15
+ #
16
+ # <%= render(partial: 'form', locals: { f: f }) %>
17
+ #
18
+ # <%= f.primary unless request.xhr? %>
19
+ # <% end -%>
20
+
21
+
22
+
23
+ #
24
+ def render_modal(options = {}, &block)
25
+ opts = options.slice(:id, :title, :submit, :large)
26
+ opts[:submit] = t(:button_submit) unless opts.has_key?(:submit)
27
+
28
+ id = options.delete(:id) || 'ad_hoc_modal'
29
+
30
+
31
+ script = <<SCRIPT
32
+ if (typeof(renderModal) == "undefined")
33
+ var renderModal = {}
34
+ if (renderModal["#{id}"])
35
+ renderModal["#{id}"].destroy();
36
+
37
+ renderModal["#{id}"] = new SymphoniaDialog("#{id}", #{raw opts.to_json});
38
+ renderModal["#{id}"].body.innerHTML = "#{j(capture(&block))}";
39
+ var submitButton = renderModal["#{id}"].body.querySelector("input[type=submit]")
40
+ if (submitButton)
41
+ submitButton.remove()
42
+ SCRIPT
43
+ unless opts[:title]
44
+ script.concat <<EOF
45
+ var title = document.getElementById(renderModal["#{id}"].id).querySelector("#page_header");
46
+ if (title) {
47
+ title.className = 'modal-title'; title.id = null;
48
+ $(renderModal["#{id}"].title).replaceWith($(title));
49
+ renderModal["#{id}"].title = title;
50
+ }
51
+ EOF
52
+ end
53
+ # script << %q{}
54
+ script << %Q{renderModal["#{id}"].show();} unless opts.has_key?(:render_only)
55
+ script.html_safe
56
+ end
57
+
58
+ end
59
+ end
@@ -0,0 +1,50 @@
1
+ module Symphonia
2
+ module FormHelper
3
+
4
+ def symphonia_form_for(object, options={}, &block)
5
+ options.reverse_merge!(builder: Symphonia::FormBuilder)
6
+
7
+ options = process_options(options)
8
+
9
+ unless options[:remote] && options[:local].nil?
10
+ options[:local] = true
11
+ end
12
+ if (as = options[:as])
13
+ options[:scope] ||= as
14
+ end
15
+
16
+ with_bootstrap_form_field_error_proc do
17
+ form_for(object, options, &block)
18
+ end
19
+ end
20
+
21
+ # def symphonia_form_for(object, options = {}, &block)
22
+ # options.reverse_merge!({ builder: Symphonia::FormBuilder })
23
+ #
24
+ # options[:html] ||= {}
25
+ # options[:html][:role] ||= 'form'
26
+ #
27
+ # if options[:layout] == :inline
28
+ # options[:html][:class] = [options[:html][:class], 'form-inline'].compact.join(' ')
29
+ # end
30
+ #
31
+ # unless options[:remote] && options[:local].nil?
32
+ # options[:local] = true
33
+ # end
34
+ # if (as = options[:as])
35
+ # options[:scope] ||= as
36
+ # end
37
+ #
38
+ # temporarily_disable_field_error_proc do
39
+ # form_for(object, options, &block)
40
+ # end
41
+ #
42
+ # end
43
+
44
+ def symphonia_form_tag(options = {}, &block)
45
+ options[:acts_like_form_tag] = true
46
+
47
+ symphonia_form_for("", options, &block)
48
+ end
49
+ end
50
+ end