spina 1.0.3 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of spina might be problematic. Click here for more details.

Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/Rakefile +5 -14
  4. data/app/assets/config/spina/manifest.js +5 -0
  5. data/app/assets/config/spina_manifest.js +5 -0
  6. data/app/assets/images/spina/arrow-left.svg +1 -0
  7. data/app/assets/images/spina/arrow-right.svg +1 -0
  8. data/app/assets/images/spina/datepicker.svg +1 -0
  9. data/app/assets/images/spina/divider.svg +1 -0
  10. data/app/assets/images/spina/media_folder_placeholder.svg +1 -0
  11. data/app/assets/images/spina/spina.svg +1 -0
  12. data/app/assets/javascripts/spina/admin/application.js +1 -2
  13. data/app/assets/javascripts/spina/admin/controllers/gallery_select_controller.js +52 -0
  14. data/app/assets/javascripts/spina/admin/controllers/infinite_scroll_controller.js +2 -2
  15. data/app/assets/javascripts/spina/admin/controllers/page_collapse_controller.js +35 -0
  16. data/app/assets/javascripts/spina/admin/media_gallery.coffee +1 -1
  17. data/app/assets/javascripts/spina/admin/trix.coffee.erb +79 -5
  18. data/app/assets/javascripts/spina/admin/uploads.coffee +1 -1
  19. data/app/assets/stylesheets/spina.sass +8 -4
  20. data/app/assets/stylesheets/spina/_buttons.sass +1 -0
  21. data/app/assets/stylesheets/spina/_forms.sass +1 -1
  22. data/app/assets/stylesheets/spina/_gallery.sass +45 -12
  23. data/app/assets/stylesheets/spina/_sortable_lists.sass +7 -0
  24. data/app/assets/stylesheets/spina/_trix_custom.sass +227 -0
  25. data/app/assets/stylesheets/spina/admin/{application.sass → application.css.sass} +0 -0
  26. data/app/controllers/concerns/spina/frontend.rb +5 -5
  27. data/app/controllers/spina/admin/accounts_controller.rb +2 -1
  28. data/app/controllers/spina/admin/images_controller.rb +1 -1
  29. data/app/controllers/spina/admin/media_picker_controller.rb +14 -2
  30. data/app/controllers/spina/admin/navigations_controller.rb +9 -7
  31. data/app/controllers/spina/admin/pages_controller.rb +16 -11
  32. data/app/controllers/spina/admin/password_resets_controller.rb +2 -2
  33. data/app/controllers/spina/admin/resources_controller.rb +9 -7
  34. data/app/controllers/spina/admin/settings_controller.rb +1 -1
  35. data/app/controllers/spina/admin/users_controller.rb +8 -7
  36. data/app/controllers/spina/pages_controller.rb +1 -3
  37. data/app/helpers/spina/admin/pages_helper.rb +2 -2
  38. data/app/helpers/spina/images_helper.rb +1 -1
  39. data/app/models/spina/account.rb +14 -6
  40. data/app/models/spina/attachment.rb +3 -3
  41. data/app/models/spina/image.rb +10 -1
  42. data/app/models/spina/image_collection.rb +3 -3
  43. data/app/models/spina/line.rb +1 -1
  44. data/app/models/spina/navigation_item.rb +2 -1
  45. data/app/models/spina/page.rb +11 -6
  46. data/app/models/spina/resource.rb +11 -0
  47. data/app/models/spina/text.rb +1 -1
  48. data/app/presenters/spina/menu_presenter.rb +74 -0
  49. data/app/views/layouts/spina/admin/admin.html.haml +1 -1
  50. data/app/views/spina/admin/accounts/social.html.haml +18 -0
  51. data/app/views/spina/admin/images/_form.html.haml +1 -1
  52. data/app/views/spina/admin/images/_image.html.haml +3 -5
  53. data/app/views/spina/admin/media_folders/_media_folder.html.haml +2 -2
  54. data/app/views/spina/admin/media_folders/show.html.haml +1 -1
  55. data/app/views/spina/admin/media_picker/_modal.html.haml +51 -14
  56. data/app/views/spina/admin/media_picker/select.js.erb +4 -2
  57. data/app/views/spina/admin/pages/_form.html.haml +1 -1
  58. data/app/views/spina/admin/pages/children.html.haml +4 -0
  59. data/app/views/spina/admin/partables/lines/_form.html.haml +1 -1
  60. data/app/views/spina/admin/partables/texts/_form.html.haml +4 -1
  61. data/app/views/spina/admin/password_resets/edit.html.haml +1 -1
  62. data/app/views/spina/admin/password_resets/new.html.haml +1 -1
  63. data/app/views/spina/admin/resources/edit.html.haml +1 -1
  64. data/app/views/spina/admin/resources/show.html.haml +13 -3
  65. data/app/views/spina/admin/sessions/new.html.haml +1 -1
  66. data/app/views/spina/admin/shared/_primary_navigation.html.haml +1 -1
  67. data/app/views/spina/admin/shared/_rich_text_field.html.haml +1 -32
  68. data/app/views/spina/shared/_admin_bar.html.haml +1 -1
  69. data/app/views/spina/shared/_social.html.haml +2 -2
  70. data/config/locales/de.yml +3 -0
  71. data/config/locales/en.yml +4 -0
  72. data/config/locales/es.yml +3 -0
  73. data/config/locales/fr.yml +3 -0
  74. data/config/locales/it.yml +3 -0
  75. data/config/locales/nl.yml +4 -0
  76. data/config/locales/pt-BR.yml +20 -1
  77. data/config/locales/ru.yml +3 -0
  78. data/config/locales/tr.yml +3 -0
  79. data/config/locales/zh-CN.yml +3 -0
  80. data/config/routes.rb +1 -0
  81. data/lib/generators/spina/install_generator.rb +10 -10
  82. data/lib/generators/spina/templates/app/views/default/shared/_navigation.html.haml +2 -3
  83. data/lib/generators/spina/templates/app/views/demo/pages/demo.html.haml +4 -3
  84. data/lib/generators/spina/templates/app/views/demo/shared/_navigation.html.haml +2 -3
  85. data/lib/generators/spina/templates/app/views/layouts/default/application.html.haml +0 -1
  86. data/lib/generators/spina/templates/app/views/layouts/demo/application.html.haml +0 -1
  87. data/lib/generators/spina/templates/config/initializers/mobility.rb +0 -1
  88. data/lib/spina.rb +1 -0
  89. data/lib/spina/engine.rb +1 -1
  90. data/lib/spina/railtie.rb +9 -0
  91. data/lib/spina/theme.rb +2 -1
  92. data/lib/spina/version.rb +1 -1
  93. data/lib/tasks/spina_tasks.rake +8 -2
  94. data/vendor/assets/javascripts/spina/trix.js +9 -9
  95. data/vendor/assets/stylesheets/spina/_normalize.scss +1 -1
  96. data/vendor/assets/stylesheets/spina/_trix.css +369 -0
  97. metadata +39 -21
  98. data/app/assets/images/spina/arrow-left.png +0 -0
  99. data/app/assets/images/spina/arrow-right.png +0 -0
  100. data/app/assets/images/spina/datepicker.png +0 -0
  101. data/app/assets/images/spina/divider.png +0 -0
  102. data/app/assets/images/spina/media_folder_placeholder.png +0 -0
  103. data/app/assets/images/spina/spina-large.png +0 -0
  104. data/app/assets/javascripts/spina/admin/galleryselect.coffee +0 -20
  105. data/app/assets/stylesheets/spina/_trix.sass +0 -102
  106. data/config/initializers/assets.rb +0 -6
  107. data/config/initializers/time_formats.rb +0 -1
@@ -13,7 +13,7 @@ module Spina
13
13
 
14
14
  if user.present?
15
15
  user.regenerate_password_reset_token
16
- user.update_attributes!(password_reset_sent_at: Time.zone.now)
16
+ user.touch(:password_reset_sent_at)
17
17
  UserMailer.forgot_password(user).deliver_now
18
18
  redirect_to admin_login_path, flash: {success: t('spina.forgot_password.instructions_sent')}
19
19
  else
@@ -31,7 +31,7 @@ module Spina
31
31
 
32
32
  if @user.password_reset_sent_at < 2.hours.ago
33
33
  redirect_to new_admin_password_reset_path, flash: {alert: t('spina.forgot_password.expired')}
34
- elsif @user.update_attributes(user_params)
34
+ elsif @user.update(user_params)
35
35
  redirect_to admin_login_path, flash: {success: t('spina.forgot_password.success')}
36
36
  else
37
37
  render :edit
@@ -2,20 +2,19 @@ module Spina
2
2
  module Admin
3
3
  class ResourcesController < AdminController
4
4
 
5
- def show
6
- @resource = Resource.find(params[:id])
5
+ before_action :set_resource, only: [:show, :edit, :update]
6
+
7
+ def show
7
8
  add_breadcrumb @resource.label
8
9
  end
9
10
 
10
- def edit
11
- @resource = Resource.find(params[:id])
11
+ def edit
12
12
  add_breadcrumb @resource.label, spina.admin_resource_path(@resource)
13
13
  add_breadcrumb t('spina.edit')
14
14
  end
15
15
 
16
- def update
17
- @resource = Resource.find(params[:id])
18
- if @resource.update_attributes(resource_params)
16
+ def update
17
+ if @resource.update(resource_params)
19
18
  redirect_to spina.admin_resource_path(@resource)
20
19
  else
21
20
  render :edit
@@ -28,6 +27,9 @@ module Spina
28
27
  params.require(:resource).permit(:label, :view_template, :order_by, :parent_page_id)
29
28
  end
30
29
 
30
+ def set_resource
31
+ @resource = Resource.find(params[:id])
32
+ end
31
33
  end
32
34
  end
33
35
  end
@@ -10,7 +10,7 @@ module Spina
10
10
  end
11
11
 
12
12
  def update
13
- if @setting.update_attributes(settings_params)
13
+ if @setting.update(settings_params)
14
14
  redirect_to spina.admin_edit_settings_path(plugin.namespace)
15
15
  else
16
16
  add_breadcrumb t("spina.#{plugin.namespace}.title")
@@ -3,6 +3,7 @@ module Spina
3
3
  class UsersController < AdminController
4
4
  before_action :set_breadcrumbs
5
5
  before_action :authorize_admin, except: [:index]
6
+ before_action :set_user, only: [:edit, :update, :destroy]
6
7
 
7
8
  def index
8
9
  @users = User.all
@@ -24,15 +25,13 @@ module Spina
24
25
  end
25
26
  end
26
27
 
27
- def edit
28
- @user = User.find(params[:id])
28
+ def edit
29
29
  add_breadcrumb "#{@user}"
30
30
  end
31
31
 
32
- def update
33
- @user = User.find(params[:id])
32
+ def update
34
33
  add_breadcrumb "#{@user}"
35
- if @user.update_attributes(user_params)
34
+ if @user.update(user_params)
36
35
  redirect_to spina.admin_users_url
37
36
  else
38
37
  flash.now[:alert] = I18n.t('spina.users.cannot_be_created')
@@ -40,8 +39,7 @@ module Spina
40
39
  end
41
40
  end
42
41
 
43
- def destroy
44
- @user = User.find(params[:id])
42
+ def destroy
45
43
  @user.destroy unless @user == current_spina_user
46
44
  redirect_to admin_users_url
47
45
  end
@@ -56,6 +54,9 @@ module Spina
56
54
  params.require(:user).permit(:admin, :email, :name, :password_digest, :password, :password_confirmation, :last_logged_in)
57
55
  end
58
56
 
57
+ def set_user
58
+ @user = User.find(params[:id])
59
+ end
59
60
  end
60
61
  end
61
62
  end
@@ -13,9 +13,7 @@ module Spina
13
13
  private
14
14
 
15
15
  def current_spina_user_can_view_page?
16
- raise ActiveRecord::RecordNotFound if page.nil? || !page.live?
17
-
18
- current_spina_user.present?
16
+ raise ActiveRecord::RecordNotFound unless current_spina_user.present? || page.live?
19
17
  end
20
18
 
21
19
  end
@@ -39,11 +39,11 @@ module Spina
39
39
  pages = Spina::Page.active.regular_pages
40
40
  pages = pages.where.not(id: page.subtree.ids) unless page.new_record? || !page.methods.include?(:subtree)
41
41
 
42
- flatten_nested_hash(pages.arrange(order: :position)).map do |page|
42
+ (flatten_nested_hash(pages.arrange(order: :position)).map do |page|
43
43
  next if page.depth >= Spina.config.max_page_depth - 1
44
44
  page_menu_title = page.depth.zero? ? page.menu_title : " #{page.menu_title}".indent(page.depth, '-')
45
45
  [page_menu_title, page.id]
46
- end.compact
46
+ end << [page.parent&.menu_title, page&.parent_id].compact).uniq.compact
47
47
  end
48
48
 
49
49
  def option_label(part, value)
@@ -5,7 +5,7 @@ module Spina
5
5
  # because the resolve directive in ActiveStorage's routes
6
6
  # doesn't work outside the main app in 5.2.0.rc2
7
7
  def variant(image, options)
8
- if image.attached?
8
+ if image.attached? && image.variable?
9
9
  variant = image.variant(options)
10
10
  main_app.rails_blob_representation_path(variant.blob.signed_id, variant.variation.key, variant.blob.filename)
11
11
  else
@@ -33,15 +33,23 @@ module Spina
33
33
  end
34
34
  end
35
35
 
36
- serialized_attr_accessor :google_analytics, :google_site_verification, :facebook, :twitter, :google_plus, :theme
36
+ serialized_attr_accessor :google_analytics, :google_site_verification, :facebook, :twitter, :instagram, :youtube, :linkedin, :google_plus, :theme
37
37
 
38
38
  private
39
39
 
40
40
  def bootstrap_website
41
41
  theme_config = ::Spina::Theme.find_by_name(theme)
42
42
  if theme_config
43
- bootstrap_pages(theme_config)
43
+
44
44
  bootstrap_navigations(theme_config)
45
+ bootstrap_pages(theme_config)
46
+ bootstrap_resources(theme_config)
47
+ end
48
+ end
49
+
50
+ def bootstrap_navigations(theme)
51
+ theme.navigations.each_with_index do |navigation, index|
52
+ Navigation.where(name: navigation[:name]).first_or_create.update(navigation.merge(position: index))
45
53
  end
46
54
  end
47
55
 
@@ -51,9 +59,9 @@ module Spina
51
59
  activate_used_view_templates(theme)
52
60
  end
53
61
 
54
- def bootstrap_navigations(theme)
55
- theme.navigations.each_with_index do |navigation, index|
56
- Navigation.where(name: navigation[:name]).first_or_create.update_attributes(navigation.merge(position: index))
62
+ def bootstrap_resources(theme)
63
+ theme.resources.each do |resource|
64
+ Resource.where(name: resource[:name]).first_or_create.update(resource)
57
65
  end
58
66
  end
59
67
 
@@ -61,7 +69,7 @@ module Spina
61
69
  theme.custom_pages.each do |page|
62
70
  Page.where(name: page[:name])
63
71
  .first_or_create(title: page[:title])
64
- .update_attributes(view_template: page[:view_template], deletable: page[:deletable])
72
+ .update(view_template: page[:view_template], deletable: page[:deletable])
65
73
  end
66
74
  end
67
75
 
@@ -18,12 +18,12 @@ module Spina
18
18
  file if file.attached?
19
19
  end
20
20
 
21
- alias_method :old_update_attributes, :update_attributes
22
- def update_attributes(attributes)
21
+ alias_method :old_update, :update
22
+ def update(attributes)
23
23
  if attributes["_destroy"] == "1" && attributes["file"].blank?
24
24
  self.page_part.destroy
25
25
  else
26
- old_update_attributes(attributes)
26
+ old_update(attributes)
27
27
  end
28
28
  end
29
29
 
@@ -21,6 +21,15 @@ module Spina
21
21
  def content
22
22
  self
23
23
  end
24
-
24
+
25
+ def thumbnail(size = '100x100', modifier = '^')
26
+ variant(
27
+ combine_options: {
28
+ gravity: 'center',
29
+ thumbnail: "#{size}#{modifier}",
30
+ extent: size
31
+ }
32
+ )
33
+ end
25
34
  end
26
35
  end
@@ -13,10 +13,10 @@ module Spina
13
13
  self
14
14
  end
15
15
 
16
- alias_method :old_update_attributes, :update_attributes
17
- def update_attributes(attributes)
16
+ alias_method :old_update, :update
17
+ def update(attributes)
18
18
  self.images.clear if attributes.reject{|key,value| key == "id" }.blank?
19
- old_update_attributes(attributes)
19
+ old_update(attributes)
20
20
  end
21
21
 
22
22
  end
@@ -1,7 +1,7 @@
1
1
  module Spina
2
2
  class Line < ApplicationRecord
3
3
  extend Mobility
4
- translates :content
4
+ translates :content, fallbacks: true
5
5
 
6
6
  has_many :page_parts, as: :page_partable
7
7
  has_many :layout_parts, as: :layout_partable
@@ -5,6 +5,7 @@ module Spina
5
5
 
6
6
  has_ancestry orphan_strategy: :adopt
7
7
 
8
+ scope :regular_pages, -> { joins(:page).where(spina_pages: {resource_id: nil}) }
8
9
  scope :sorted, -> { order('spina_navigation_items.position') }
9
10
  scope :live, -> { joins(:page).where(spina_pages: {draft: false, active: true}) }
10
11
  scope :in_menu, -> { joins(:page).where(spina_pages: {show_in_menu: true}) }
@@ -12,6 +13,6 @@ module Spina
12
13
 
13
14
  validates :page, uniqueness: {scope: :navigation}
14
15
 
15
- delegate :menu_title, :materialized_path, to: :page
16
+ delegate :menu_title, :materialized_path, :draft?, to: :page
16
17
  end
17
18
  end
@@ -39,13 +39,18 @@ module Spina
39
39
  before_validation :set_materialized_path
40
40
  validates :title, presence: true
41
41
 
42
- translates :title, :description, :materialized_path
42
+ translates :title, fallbacks: true
43
+ translates :description, :materialized_path
43
44
  translates :menu_title, :seo_title, default: -> { title }
44
45
 
45
46
  def to_s
46
47
  name
47
48
  end
48
49
 
50
+ def page_id
51
+ id
52
+ end
53
+
49
54
  def url_title
50
55
  title.try(:parameterize)
51
56
  end
@@ -55,7 +60,7 @@ module Spina
55
60
  end
56
61
 
57
62
  def save_children
58
- self.children.each(&:save)
63
+ children.each(&:save)
59
64
  end
60
65
 
61
66
  def live?
@@ -63,17 +68,17 @@ module Spina
63
68
  end
64
69
 
65
70
  def previous_sibling
66
- self.siblings.where('position < ?', self.position).sorted.last
71
+ siblings.where('position < ?', position).sorted.last
67
72
  end
68
73
 
69
74
  def next_sibling
70
- self.siblings.where('position > ?', self.position).sorted.first
75
+ siblings.where('position > ?', position).sorted.first
71
76
  end
72
77
 
73
78
  def set_materialized_path
74
79
  self.old_path = materialized_path
75
80
  self.materialized_path = localized_materialized_path
76
- self.materialized_path += "-#{self.class.i18n.where(materialized_path: materialized_path).count}" if self.class.i18n.where(materialized_path: materialized_path).where.not(id: id).count > 0
81
+ self.materialized_path = localized_materialized_path + "-#{Page.i18n.where(materialized_path: materialized_path).count}" if Page.i18n.where(materialized_path: materialized_path).where.not(id: id).count > 0
77
82
  materialized_path
78
83
  end
79
84
 
@@ -97,7 +102,7 @@ module Spina
97
102
  end
98
103
 
99
104
  def rewrite_rule
100
- RewriteRule.where(old_path: old_path).first_or_create.update_attributes(new_path: materialized_path) if old_path != materialized_path
105
+ RewriteRule.where(old_path: old_path).first_or_create.update(new_path: materialized_path) if old_path != materialized_path
101
106
  end
102
107
 
103
108
  def localized_materialized_path
@@ -4,6 +4,8 @@ module Spina
4
4
 
5
5
  belongs_to :parent_page, class_name: "Spina::Page", optional: true
6
6
 
7
+ after_save :scope_pages_to_parent_page
8
+
7
9
  def pages
8
10
  case order_by
9
11
  when "title"
@@ -12,5 +14,14 @@ module Spina
12
14
  super.order(created_at: :desc)
13
15
  end
14
16
  end
17
+
18
+ private
19
+
20
+ def scope_pages_to_parent_page
21
+ pages.roots.each do |root_page|
22
+ root_page.update(parent: parent_page)
23
+ end
24
+ end
25
+
15
26
  end
16
27
  end
@@ -1,7 +1,7 @@
1
1
  module Spina
2
2
  class Text < ApplicationRecord
3
3
  extend Mobility
4
- translates :content
4
+ translates :content, fallbacks: true
5
5
 
6
6
  has_many :page_parts, as: :page_partable
7
7
  has_many :layout_parts, as: :layout_partable
@@ -0,0 +1,74 @@
1
+ module Spina
2
+ class MenuPresenter
3
+ include ActionView::Helpers::TagHelper
4
+ include ActionView::Helpers::UrlHelper
5
+ include ActiveSupport::Configurable
6
+
7
+ attr_accessor :collection, :output_buffer
8
+
9
+ # Configuration
10
+ config_accessor :menu_tag, :menu_css,
11
+ :list_tag, :list_css,
12
+ :list_item_tag, :list_item_css,
13
+ :link_tag_css,
14
+ :include_drafts,
15
+ :depth # root nodes are at depth 0
16
+
17
+ # Default configuration
18
+ self.menu_tag = :nav
19
+ self.list_tag = :ul
20
+ self.list_item_tag = :li
21
+ self.include_drafts = false
22
+
23
+ def initialize(collection)
24
+ @collection = collection
25
+ end
26
+
27
+ def to_html
28
+ render_menu(roots)
29
+ end
30
+
31
+ private
32
+
33
+ def roots
34
+ return collection.navigation_items.roots if collection.is_a?(Navigation)
35
+ collection.roots
36
+ end
37
+
38
+ def render_menu(collection)
39
+ content_tag(menu_tag, class: menu_css) do
40
+ render_items(scoped_collection(collection))
41
+ end
42
+ end
43
+
44
+ def render_items(collection)
45
+ content_tag(list_tag, class: list_css) do
46
+ collection.inject(ActiveSupport::SafeBuffer.new) do |buffer, item|
47
+ buffer << render_item(item)
48
+ end
49
+ end
50
+ end
51
+
52
+ def render_item(item)
53
+ children = scoped_collection(item.children)
54
+
55
+ content_tag(list_item_tag, class: list_item_css, data: {page_id: item.page_id, draft: (true if item.draft?) }) do
56
+ buffer = ActiveSupport::SafeBuffer.new
57
+ buffer << link_to(item.menu_title, item.materialized_path, class: link_tag_css)
58
+ buffer << render_items(children) if render_children?(item) && children.any?
59
+ buffer
60
+ end
61
+ end
62
+
63
+ def scoped_collection(collection)
64
+ scoped = collection.regular_pages.active.in_menu.sorted
65
+ include_drafts ? scoped : scoped.live
66
+ end
67
+
68
+ def render_children?(item)
69
+ return true unless depth
70
+ item.depth < depth
71
+ end
72
+
73
+ end
74
+ end
@@ -35,4 +35,4 @@
35
35
  = content_for?(:application) ? yield(:application) : yield
36
36
 
37
37
  = link_to 'http://www.spinacms.com', class: 'spina-logo', target: :blank do
38
- = image_tag('spina/spina.png')
38
+ = image_tag('spina/spina.svg', width: 32, height: 24)
@@ -21,6 +21,24 @@
21
21
  .horizontal-form-content
22
22
  = f.text_field :twitter, placeholder: Spina::Account.human_attribute_name(:twitter)
23
23
 
24
+ .horizontal-form-group
25
+ .horizontal-form-label
26
+ = Spina::Account.human_attribute_name(:instagram)
27
+ .horizontal-form-content
28
+ = f.text_field :instagram, placeholder: Spina::Account.human_attribute_name(:instagram)
29
+
30
+ .horizontal-form-group
31
+ .horizontal-form-label
32
+ = Spina::Account.human_attribute_name(:youtube)
33
+ .horizontal-form-content
34
+ = f.text_field :youtube, placeholder: Spina::Account.human_attribute_name(:youtube)
35
+
36
+ .horizontal-form-group
37
+ .horizontal-form-label
38
+ = Spina::Account.human_attribute_name(:linkedin)
39
+ .horizontal-form-content
40
+ = f.text_field :linkedin, placeholder: Spina::Account.human_attribute_name(:linkedin)
41
+
24
42
  .horizontal-form-group
25
43
  .horizontal-form-label
26
44
  = Spina::Account.human_attribute_name(:google_plus)