fae-rails 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -1
  3. data/app/assets/javascripts/fae/form/_ajax.js +21 -1
  4. data/app/assets/javascripts/fae/form/_cancel.js +1 -0
  5. data/app/assets/javascripts/fae/form/_validator.js +22 -12
  6. data/app/assets/javascripts/fae/form/inputs/_color.js +2 -1
  7. data/app/assets/javascripts/fae/vendor/jqColorPicker.min.js +0 -1
  8. data/app/controllers/fae/application_controller.rb +15 -1
  9. data/app/controllers/fae/users_controller.rb +8 -0
  10. data/app/helpers/fae/form_helper.rb +13 -4
  11. data/app/helpers/fae/view_helper.rb +76 -31
  12. data/app/models/concerns/fae/user_concern.rb +10 -1
  13. data/app/models/fae/static_page.rb +7 -2
  14. data/app/models/fae/user.rb +2 -3
  15. data/app/uploaders/fae/file_uploader.rb +1 -1
  16. data/app/uploaders/fae/image_uploader.rb +1 -1
  17. data/app/views/fae/application/_file_uploader.html.slim +4 -1
  18. data/app/views/fae/application/_global_search_results.html.slim +1 -1
  19. data/app/views/fae/application/_header.slim +8 -8
  20. data/app/views/fae/application/_markdown_helper.slim +17 -17
  21. data/app/views/fae/application/_mobilenav.slim +6 -6
  22. data/app/views/fae/application/_user_log.html.slim +2 -2
  23. data/app/views/fae/images/_image_uploader.html.slim +1 -1
  24. data/app/views/fae/options/_form.html.slim +6 -6
  25. data/app/views/fae/pages/activity_log.html.slim +11 -11
  26. data/app/views/fae/pages/disabled_environment.html.slim +2 -2
  27. data/app/views/fae/pages/error404.html.slim +5 -3
  28. data/app/views/fae/pages/home.html.slim +9 -8
  29. data/app/views/fae/setup/first_user.html.slim +3 -3
  30. data/app/views/fae/shared/_form_header.html.slim +3 -3
  31. data/app/views/fae/shared/_index_header.html.slim +3 -2
  32. data/app/views/fae/shared/_nested_table.html.slim +1 -1
  33. data/app/views/fae/shared/_recent_changes.html.slim +6 -6
  34. data/app/views/fae/shared/_shared_nested_table.html.slim +1 -1
  35. data/app/views/fae/static_pages/index.html.slim +2 -2
  36. data/app/views/fae/users/_form.html.slim +8 -12
  37. data/app/views/fae/users/index.html.slim +6 -6
  38. data/config/locales/devise.cs.yml +59 -0
  39. data/config/locales/fae.cs.yml +125 -0
  40. data/config/locales/fae.en.yml +109 -0
  41. data/config/locales/fae.zh-CN.yml +109 -0
  42. data/lib/fae/version.rb +1 -1
  43. data/lib/generators/fae/base_generator.rb +46 -3
  44. data/lib/generators/fae/nested_index_scaffold_generator.rb +1 -0
  45. data/lib/generators/fae/nested_scaffold_generator.rb +1 -0
  46. data/lib/generators/fae/page_generator.rb +8 -0
  47. data/lib/generators/fae/scaffold_generator.rb +1 -0
  48. data/lib/generators/fae/templates/graphql/graphql_page_type.rb +17 -0
  49. data/lib/generators/fae/templates/graphql/graphql_type.rb +13 -0
  50. metadata +9 -5
@@ -1 +1,10 @@
1
- module Fae::UserConcern; end
1
+ module Fae
2
+ module UserConcern
3
+ extend ActiveSupport::Concern
4
+ module ClassMethods
5
+ def available_languages
6
+ [:en]
7
+ end
8
+ end
9
+ end
10
+ end
@@ -42,7 +42,7 @@ module Fae
42
42
  languages.each do |lang|
43
43
  # Save with suffix for form fields
44
44
  define_association("#{name}_#{lang}", type)
45
- define_validations("#{name}_#{lang}", type, value[:validates]) if value.try(:[], :validates).present?
45
+ define_validations("#{name}_#{lang}", type, value[:validates]) if supports_validation(type, value)
46
46
  end
47
47
  # Save with lookup to have default language return in front-end use (don't need to worry about validations here)
48
48
  default_language = Rails.application.config.i18n.default_locale || languages.first
@@ -50,7 +50,7 @@ module Fae
50
50
  else
51
51
  # Normal content_blocks
52
52
  define_association(name, type)
53
- define_validations(name, type, value[:validates]) if value.try(:[], :validates).present?
53
+ define_validations(name, type, value[:validates]) if supports_validation(type, value)
54
54
  end
55
55
  end
56
56
 
@@ -75,6 +75,11 @@ module Fae
75
75
  end
76
76
  end
77
77
 
78
+ def self.supports_validation(type, value)
79
+ # validations are only supported on Fae::TextField and Fae::TextArea
80
+ poly_sym(type) == :contentable && value.try(:[], :validates).present?
81
+ end
82
+
78
83
  def self.poly_sym(assoc)
79
84
  case assoc.name
80
85
  when 'Fae::TextField', 'Fae::TextArea'
@@ -16,9 +16,8 @@ module Fae
16
16
  presence: true,
17
17
  uniqueness: { message: 'That email address is already in use. Give another one a go.' },
18
18
  format: {
19
- with: /^\s*(([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})[\s\/,;]*)+$/i,
20
- message: 'is invalid',
21
- multiline: true
19
+ with: Fae.validation_helpers.email_regex,
20
+ message: 'is invalid'
22
21
  }
23
22
  validates :password,
24
23
  presence: { on: :create },
@@ -18,7 +18,7 @@ module Fae
18
18
 
19
19
  # Add a white list of extensions which are allowed to be uploaded.
20
20
  # For images you might use something like this:
21
- def extension_white_list
21
+ def extension_whitelist
22
22
  %w(jpg jpeg gif png pdf)
23
23
  end
24
24
 
@@ -10,7 +10,7 @@ module Fae
10
10
  model.file_size = file.size
11
11
  end
12
12
 
13
- def extension_white_list
13
+ def extension_whitelist
14
14
  %w(jpg jpeg gif png ico)
15
15
  end
16
16
 
@@ -28,7 +28,10 @@ ruby:
28
28
  .asset-actions.-files
29
29
  a.asset-title href=the_file.asset.url target="_blank" = the_file.asset.file.filename
30
30
 
31
- = link_to '', fae.delete_file_path(the_file.id), class: 'asset-delete js-asset-delete', remote: true, method: :delete, data: { confirm: t('fae.delete_confirmation') }
31
+ - if the_file.id.present?
32
+ = link_to '', fae.delete_file_path(the_file.id), class: 'asset-delete js-asset-delete', remote: true, method: :delete, data: { confirm: t('fae.delete_confirmation') }
33
+ - else
34
+ a.js-file-clear.asset-delete.js-asset-delete
32
35
 
33
36
  .asset-inputs style="#{'display: none;' unless the_file.asset.blank?}"
34
37
  = i.input :asset, as: :file, label: false, input_html: { data: { limit: Fae.max_file_upload_size, exceeded: t('fae.exceeded_upload_limit') } }
@@ -34,4 +34,4 @@ ul.search-results.js-search-results
34
34
 
35
35
  - else
36
36
 
37
- li No results
37
+ li = t('fae.navbar.no_results')
@@ -19,22 +19,22 @@ header.main-header#js-main-header
19
19
  a.grabatar-link href="#"
20
20
  img.grabatar src=fae_avatar alt=current_user.full_name
21
21
  ul
22
- li: a href=fae.destroy_user_session_path Log Out
23
- li: a href=fae.settings_path Your Settings
22
+ li: a href=fae.destroy_user_session_path = t('fae.navbar.logout')
23
+ li: a href=fae.settings_path = t('fae.navbar.your_settings')
24
24
 
25
25
  li.utility-dropdown.js-utility-dropdown
26
26
  a href="#"
27
27
  i.icon-settings
28
28
  ul
29
29
  - if current_user.super_admin_or_admin?
30
- li: a href=fae.users_path Users
31
- li: a href=fae.activity_log_path Activity Log
30
+ li: a href=fae.users_path = t('fae.navbar.users')
31
+ li: a href=fae.activity_log_path = t('fae.navbar.activity_log')
32
32
  - if current_user.super_admin?
33
- li: a href=fae.option_path Root Settings
33
+ li: a href=fae.option_path = t('fae.navbar.root_settings')
34
34
  - if @option.live_url.present?
35
- li: a href=@option.live_url target="_blank" Live Site
35
+ li: a href=@option.live_url target="_blank" = t('fae.application.live_site')
36
36
  - if @option.stage_url.present?
37
- li: a href=@option.stage_url target="_blank" Stage Site
37
+ li: a href=@option.stage_url target="_blank" = t('fae.application.stage_site')
38
38
 
39
39
  li
40
40
  a href=fae.help_path
@@ -45,6 +45,6 @@ header.main-header#js-main-header
45
45
 
46
46
  .utility-search-hit-area#js-utility-search-wrapper
47
47
  .utility-search-wrapper
48
- input#js-global-search type="text" placeholder="Jump to..."
48
+ input#js-global-search type="text" placeholder=t('fae.navbar.jump_to')
49
49
 
50
50
  == render 'global_search_results', show_nav: true
@@ -1,41 +1,41 @@
1
1
  .markdown-hint
2
2
  .markdown-hint-wrapper
3
- h3 Markdown Options
3
+ h3 = t('fae.application.markdown_opts')
4
4
 
5
- h4 Links
5
+ h4 = t('fae.application.links')
6
6
  p
7
- | To link text, place a [bracket] around the link title and use a (/url) to house the url.
7
+ = t('fae.application.links_help')
8
8
  br
9
9
  | Internal Link: [link to about](/about)
10
10
  br
11
11
  | External link: [link to about](http://www.google.com/about)
12
12
 
13
- h4 Formatting
13
+ h4 = t('fae.application.formatting')
14
14
  p
15
- | Emphasize text in a variety of ways by placing **asterisks** to bold, _underscores_ to italicize.
15
+ = t('fae.application.formatting_help')
16
16
  br
17
- | Bold **bold**
17
+ = t('fae.application.bold')
18
18
  br
19
- | Italicize _italic
19
+ = t('fae.application.italic')
20
20
 
21
- h4 Headers
21
+ h4 = t('fae.application.headers')
22
22
  p
23
- | Use up to six hashtags to identify the importance of the section header.
23
+ = t('fae.application.headers_help')
24
24
  br
25
- | Page Header: # Page Header
25
+ = t('fae.apllication.headers_example')
26
26
  br
27
- | Sub Header: ## Sub Header
27
+ = t('fae.application.subheaders_example')
28
28
 
29
- h4 List
29
+ h4 = t('fae.application.list')
30
30
  p
31
- | Format lists by swapping out the characters that lead the list item.
31
+ = t('fae.application.list_help')
32
32
  br
33
- span Bulleted List:
33
+ span = t('fae.application.bulleted_list')
34
34
  br
35
35
  == ['* bullet', '* bullet 2'].join('<br />')
36
36
  br
37
- span Numbered List
37
+ span = t('fae.application.numbered_list')
38
38
  == ['1. line item', '2. line item'].join('<br />')
39
39
 
40
- h4 Paragraph break
41
- p Adding a blank line in between your paragraphs makes a paragraph break.
40
+ h4 = t('fae.application.paragraph_break')
41
+ p = t('fae.application.paragraph_break_help')
@@ -55,12 +55,12 @@ nav.nav.mobilenav
55
55
  - if @option.stage_url.present? || @option.live_url.present?
56
56
  li class=view_site_class
57
57
  - if site_urls_are_present
58
- a href="#" View Site
58
+ a href="#" = t('fae.application.view_site')
59
59
  ul.subnav.js-subnav
60
- li: span.mobilenav-subheader.js-mobile-back View Site
61
- li: a.-viewsite href=@option.stage_url target="_blank" Preview Site
62
- li: a.-viewsite href=@option.live_url target="_blank" Live Site
60
+ li: span.mobilenav-subheader.js-mobile-back = t('fae.application.view_site')
61
+ li: a.-viewsite href=@option.stage_url target="_blank" = t('fae.application.preview_site')
62
+ li: a.-viewsite href=@option.live_url target="_blank" = t('fae.application.live_site')
63
63
  - elsif @option.stage_url.present?
64
- a.-viewsite href=@option.stage_url target="_blank" Preview Site
64
+ a.-viewsite href=@option.stage_url target="_blank" = t('fae.application.preview_site')
65
65
  - elsif @option.live_url.present?
66
- a.-viewsite href=@option.live_url target="_blank" Live Site
66
+ a.-viewsite href=@option.live_url target="_blank" = t('fae.application.live_site')
@@ -28,9 +28,9 @@
28
28
  - if changed.present?
29
29
  tr
30
30
  td = version.created_at
31
- td = version.user.present? ? version.user.full_name : content_tag(:em, "user no longer exists")
31
+ td = version.user.present? ? version.user.full_name : content_tag(:em, t('fae.application.user_absent'))
32
32
  td = changed.join(', ')
33
33
 
34
34
  - else
35
35
  tr
36
- td colspan="3" No logs available.
36
+ td colspan="3" = t('fae.application.no_logs')
@@ -7,7 +7,7 @@ ruby:
7
7
  alt_label ||= "#{label} Alt Text"
8
8
  caption_label ||= "#{label} Caption"
9
9
  helper_text ||= ""
10
- alt_helper_text ||= 'Brief description of image contents, used in hover text and by visually impaired users.'
10
+ alt_helper_text ||= t('fae.images.alt_helper')
11
11
  caption_helper_text ||= ""
12
12
  show_alt = true if show_alt.nil?
13
13
  show_caption ||= false
@@ -2,15 +2,15 @@
2
2
  header.content-header.js-content-header
3
3
  h1 Root Settings
4
4
  .content-header-buttons
5
- a.button#js-header-cancel href=fae.root_path(cancelled: true) Cancel
6
- = f.submit 'Save'
5
+ a.button#js-header-cancel href=fae.root_path(cancelled: true) = t('fae.form.cancel')
6
+ = f.submit t('fae.form.save')
7
7
 
8
8
  == render 'flash_messages'
9
9
 
10
10
  section.content
11
- = fae_input f, :title, label: 'Project Name'
11
+ = fae_input f, :title, label: t('fae.options.project.name')
12
12
  = fae_input f, :time_zone, wrapper_class: 'select'
13
- = fae_input f, :live_url, label: 'Live URL', helper_text: 'Include http:// for external links.'
14
- = fae_input f, :stage_url, label: 'Stage URL', helper_text: 'Include http:// for external links.'
15
- = fae_image_form f, :logo, helper_text: 'Used on login page, 300x300px .jpg'
13
+ = fae_input f, :live_url, label: t('fae.options.live_url'), helper_text: t('fae.options.url_helper')
14
+ = fae_input f, :stage_url, label: t('fae.options.stage_url'), helper_text: t('fae.options.url_helper')
15
+ = fae_image_form f, :logo, helper_text: t('fae.options.logo_helper')
16
16
  = fae_image_form f, :favicon
@@ -2,20 +2,20 @@
2
2
 
3
3
  main.content
4
4
 
5
- == fae_filter_form title: 'Search Changes', action: fae.activity_log_filter_path do
6
- == fae_filter_select :user, options: Fae::User.all.map { |u| [u.full_name, u.id] }
7
- == fae_filter_select :model, options: Fae::Change.unique_changeable_types
8
- == fae_filter_select :type, options: ['created', 'updated', 'deleted']
9
- == fae_filter_select :date, options: ['Last Hour', 'Last Day', 'Last Week', 'Last Month'], placeholder: 'All Time'
5
+ == fae_filter_form title: t('fae.changes.title'), action: fae.activity_log_filter_path do
6
+ == fae_filter_select :user, options: Fae::User.all.map { |u| [u.full_name, u.id] }, translation_path: 'fae.changes.models'
7
+ == fae_filter_select :model, options: Fae::Change.unique_changeable_types, translation_path: 'fae.changes.models'
8
+ == fae_filter_select :type, options: [t('fae.changes.created'), t('fae.changes.updated'), t('fae.changes.deleted')], translation_path: 'fae.changes.models'
9
+ == fae_filter_select :date, options: [t('fae.changes.last_hour'), t('fae.changes.last_day'), t('fae.changes.last_week'), t('fae.changes.last_month')], placeholder: t('fae.changes.all_time')
10
10
 
11
11
  table.js-results-table
12
12
  thead
13
13
  tr
14
- th data-sort="user.first_name" User
15
- th data-sort="changeable_type" Item
16
- th data-sort="change_type" Type
17
- th Attribute(s) Updated
18
- th data-sort="updated_at" Modified
14
+ th data-sort="user.first_name" = t('fae.changes.user')
15
+ th data-sort="changeable_type" = t('fae.changes.item')
16
+ th data-sort="change_type" = t('fae.changes.type')
17
+ th = t('fae.changes.attrs')
18
+ th data-sort="updated_at" = t('fae.changes.modified')
19
19
  tbody
20
20
  - if @items.present?
21
21
  - @items.each do |change|
@@ -27,6 +27,6 @@ main.content
27
27
  td = fae_datetime_format(change.updated_at)
28
28
  - else
29
29
  tr
30
- td colspan=5 No changes recorded
30
+ td colspan=5 = t('fae.changes.no_changes')
31
31
 
32
32
  == fae_paginate @items
@@ -1,4 +1,4 @@
1
1
  .center
2
2
  .sad_face
3
- h1 Disabled Admin
4
- p The admin on this domain has been disabled. This usually occurs on a staging domain where content is managed in production. Contact application support for more information.
3
+ h1 = t('fae.page.disabled_title')
4
+ p = t('fae.page.disabled_text')
@@ -2,6 +2,8 @@
2
2
  .sad_face
3
3
  h1 Oops!
4
4
  p
5
- | The page you requested can not be found. Please&nbsp;
6
- a href=fae.root_path click here
7
- | &nbsp;to be taken to our home page.
5
+ = t('fae.page.error_start')
6
+ |&nbsp;
7
+ a href=fae.root_path = t('fae.page.click')
8
+ | &nbsp;
9
+ = t('fae.page.error_end')
@@ -1,7 +1,8 @@
1
1
  header.content-header.js-content-header.-dashboard
2
2
  div
3
3
  i.icon-home>
4
- | &nbsp;&nbsp;Hello
4
+ | &nbsp;&nbsp;
5
+ = t('fae.page.hello')
5
6
  strong< = current_user.full_name
6
7
 
7
8
  == render 'flash_messages'
@@ -11,9 +12,9 @@ header.content-header.js-content-header.-dashboard
11
12
  table.js-sort-column
12
13
  thead
13
14
  tr
14
- th Name
15
- th Type
16
- th.-action-wide Modified
15
+ th = t('fae.common.name')
16
+ th = t('fae.changes.type')
17
+ th.-action-wide = t('fae.changes.modified')
17
18
  tbody
18
19
  - @list.each do |item|
19
20
  - begin
@@ -28,9 +29,9 @@ header.content-header.js-content-header.-dashboard
28
29
  - else
29
30
  section.help-section
30
31
  article.content
31
- h2 Welcome to Fae
32
+ h2 = t('fae.page.welcome')
32
33
  p
33
- ' You don'thave any objects setup to manage. If you need help getting started, check out the
34
+ = t('fae.page.no_objs_start')
34
35
  br
35
- a href="https://www.faecms.com/documentation/quickstart-guide" target="_blank" Quickstart Guide and Documentation site
36
- ' .
36
+ a href="https://www.faecms.com/documentation/quickstart-guide" target="_blank"
37
+ = t('fae.page.no_objs.end')
@@ -1,11 +1,11 @@
1
1
  .first_user-form
2
- p Please create your super admin user.
2
+ p = t('fae.setup.prompt')
3
3
 
4
4
  = simple_form_for(@user, html: { multipart: true, novalidate: true }, url: fae.first_user_path) do |f|
5
5
  = fae_input f, :first_name
6
6
  = fae_input f, :last_name
7
7
  = fae_input f, :email
8
- = fae_input f, :password, helper_text: 'Passwords must contain at least 8 characters.'
8
+ = fae_input f, :password, helper_text: t('fae.setup.password')
9
9
  = fae_input f, :password_confirmation
10
10
  .login-form-actions
11
- = f.button :submit, "Submit"
11
+ input name="commit" type="submit" value=t('fae.form.save')
@@ -1,9 +1,9 @@
1
1
  ruby:
2
2
  require_locals ['header'], local_assigns
3
- save_button_text ||= 'Save'
4
- cancel_button_text ||= 'Cancel'
3
+ save_button_text ||= t('fae.form.save')
4
+ cancel_button_text ||= t('fae.form.cancel')
5
5
  cloneable ||= false
6
- clone_button_text ||= 'Clone'
6
+ clone_button_text ||= t('fae.form.clone')
7
7
  subnav ||= []
8
8
  header_as_string = header.is_a?(String) ? header : header.class.name.split('::').last
9
9
  header_as_string = header_as_string.singularize
@@ -3,7 +3,8 @@ ruby:
3
3
  title ||= @klass_humanized.pluralize.titleize
4
4
  new_button = !local_assigns[:new_button].eql?(false)
5
5
  new_path ||= "new_#{fae_path}_#{@klass_singular}_path"
6
- button_text ||= "Add #{title.singularize}"
6
+ button_text ||= t('fae.common.add', title: title.singularize)
7
+ export_text ||= t('fae.common.csv_export')
7
8
  csv ||= false
8
9
  breadcrumb = !local_assigns[:breadcrumbs].eql?(false)
9
10
 
@@ -15,7 +16,7 @@ header.content-header.js-content-header
15
16
 
16
17
  .content-header-buttons
17
18
  - if csv && @items.present?
18
- a.button href="#{@index_path}.csv" Export to CSV
19
+ a.button href="#{@index_path}.csv" = export_text
19
20
 
20
21
  - if new_button
21
22
  - if nested
@@ -10,7 +10,7 @@ ruby:
10
10
  # optional locals
11
11
  assoc_name ||= assoc.to_s # 'restaurant_bars'
12
12
  title ||= assoc_name.titleize # 'Restaurant Bars'
13
- add_button_text ||= "Add #{title.singularize}"
13
+ add_button_text ||= t('fae.common.add', title: title.singularize)
14
14
  ordered ||= false
15
15
  has_thumb ||= false
16
16
  edit_column ||= false
@@ -1,14 +1,14 @@
1
1
  - unless params[:action] == 'new'
2
2
  .content#recent_changes
3
- h2 Recent Changes
3
+ h2 = t('fae.changes.recent')
4
4
  section.addedit-form.js-addedit-form
5
5
  table
6
6
  thead
7
7
  tr
8
- th User
9
- th Type
10
- th Attribute(s) Updated
11
- th.-action-wide Modified
8
+ th = t('fae.changes.user')
9
+ th = t('fae.changes.type')
10
+ th = t('fae.changes.attrs')
11
+ th.-action-wide t('fea.changes.modified')
12
12
  tbody
13
13
  - if @item.try(:tracked_changes).present?
14
14
  - @item.tracked_changes.each do |change|
@@ -19,4 +19,4 @@
19
19
  td = fae_datetime_format(change.updated_at)
20
20
  - else
21
21
  tr
22
- td colspan="4" No changes recorded
22
+ td colspan="4" = t('fae.changes.no_changes')
@@ -33,7 +33,7 @@ table class=table_class
33
33
  = td_columns(options_for_td)
34
34
  - if edit_column
35
35
  td
36
- a.js-edit-link.js-tooltip.table-action title="Edit" href=self.send(edit_path, item)
36
+ a.js-edit-link.js-tooltip.table-action title=t('fae.common.edit') href=self.send(edit_path, item)
37
37
  i.icon-edit
38
38
  td = fae_delete_button item, "/#{fae_path}/#{assoc_name}/#{item.id.to_s}", class: 'js-tooltip table-action js-delete-link', remote: true
39
39