diff --git a/app/assets/javascripts/discourse/controllers/preferences/interface.js.es6 b/app/assets/javascripts/discourse/controllers/preferences/interface.js.es6
index 97cab16b0db..c9b8d796e71 100644
--- a/app/assets/javascripts/discourse/controllers/preferences/interface.js.es6
+++ b/app/assets/javascripts/discourse/controllers/preferences/interface.js.es6
@@ -20,6 +20,8 @@ const USER_HOMES = {
5: "top"
};
+const TEXT_SIZES = ["normal", "larger", "largest"];
+
export default Ember.Controller.extend(PreferencesTabController, {
@computed("makeThemeDefault")
saveAttrNames(makeDefault) {
@@ -32,7 +34,8 @@ export default Ember.Controller.extend(PreferencesTabController, {
"automatically_unpin_topics",
"allow_private_messages",
"homepage_id",
- "hide_profile_and_presence"
+ "hide_profile_and_presence",
+ "text_size"
];
if (makeDefault) {
@@ -55,6 +58,13 @@ export default Ember.Controller.extend(PreferencesTabController, {
return currentThemeId();
},
+ @computed
+ textSizes() {
+ return TEXT_SIZES.map(value => {
+ return { name: I18n.t(`user.text_size.${value}`), value };
+ });
+ },
+
userSelectableThemes: function() {
return listThemes(this.site);
}.property(),
@@ -114,6 +124,22 @@ export default Ember.Controller.extend(PreferencesTabController, {
this.homeChanged();
})
.catch(popupAjaxError);
+ },
+
+ selectTextSize(newSize) {
+ const classList = document.documentElement.classList;
+
+ TEXT_SIZES.forEach(name => {
+ const className = `text-size-${name}`;
+ if (newSize === name) {
+ classList.add(className);
+ } else {
+ classList.remove(className);
+ }
+ });
+
+ // Force refresh when leaving this screen
+ Discourse.set("assetVersion", "forceRefresh");
}
}
});
diff --git a/app/assets/javascripts/discourse/models/user.js.es6 b/app/assets/javascripts/discourse/models/user.js.es6
index 9b7d28e1ac4..70b6dbc7acd 100644
--- a/app/assets/javascripts/discourse/models/user.js.es6
+++ b/app/assets/javascripts/discourse/models/user.js.es6
@@ -285,7 +285,8 @@ const User = RestModel.extend({
"theme_ids",
"allow_private_messages",
"homepage_id",
- "hide_profile_and_presence"
+ "hide_profile_and_presence",
+ "text_size"
];
if (fields) {
diff --git a/app/assets/javascripts/discourse/templates/preferences/interface.hbs b/app/assets/javascripts/discourse/templates/preferences/interface.hbs
index da84c8c605a..1be49ff9b54 100644
--- a/app/assets/javascripts/discourse/templates/preferences/interface.hbs
+++ b/app/assets/javascripts/discourse/templates/preferences/interface.hbs
@@ -10,6 +10,13 @@
{{/if}}
+
+
+
+ {{combo-box valueAttribute="value" content=textSizes value=model.user_option.text_size onSelect=(action "selectTextSize")}}
+
+
+
{{#if siteSettings.allow_user_locale}}
diff --git a/app/assets/stylesheets/common/foundation/base.scss b/app/assets/stylesheets/common/foundation/base.scss
index 03fa374c22e..adf847650bc 100644
--- a/app/assets/stylesheets/common/foundation/base.scss
+++ b/app/assets/stylesheets/common/foundation/base.scss
@@ -13,6 +13,14 @@ html {
background-color: $secondary;
overflow-y: scroll;
direction: ltr;
+
+ &.text-size-larger {
+ font-size: $base-font-size-larger;
+ }
+
+ &.text-size-largest {
+ font-size: $base-font-size-largest;
+ }
}
// Links
diff --git a/app/assets/stylesheets/common/foundation/variables.scss b/app/assets/stylesheets/common/foundation/variables.scss
index e0da4fcdaf3..b2090ddd3f8 100644
--- a/app/assets/stylesheets/common/foundation/variables.scss
+++ b/app/assets/stylesheets/common/foundation/variables.scss
@@ -33,6 +33,8 @@ $bronze: #cd7f32 !default;
// --------------------------------------------------
$base-font-size: 14px !default;
+$base-font-size-larger: 16px !default;
+$base-font-size-largest: 18px !default;
$base-font-family: Helvetica, Arial, sans-serif !default;
// Font-size defintions, multiplier ^ (step / interval)
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 82a5d5fbae6..d4a60fe613e 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -109,7 +109,12 @@ module ApplicationHelper
end
def html_classes
- "#{mobile_view? ? 'mobile-view' : 'desktop-view'} #{mobile_device? ? 'mobile-device' : 'not-mobile-device'} #{rtl_class} #{current_user ? '' : 'anon'}"
+ list = []
+ list << (mobile_view? ? 'mobile-view' : 'desktop-view')
+ list << (mobile_device? ? 'mobile-device' : 'not-mobile-device')
+ list << 'rtl' if rtl?
+ list << text_size_class
+ list.join(' ')
end
def body_classes
@@ -126,8 +131,9 @@ module ApplicationHelper
result.join(' ')
end
- def rtl_class
- rtl? ? 'rtl' : ''
+ def text_size_class
+ size = current_user&.user_option&.text_size || SiteSetting.default_text_size
+ "text-size-#{size}"
end
def escape_unicode(javascript)
diff --git a/app/models/user_option.rb b/app/models/user_option.rb
index 4f2ba155c89..95b0d75795e 100644
--- a/app/models/user_option.rb
+++ b/app/models/user_option.rb
@@ -28,6 +28,12 @@ class UserOption < ActiveRecord::Base
@like_notification_frequency_type ||= Enum.new(always: 0, first_time_and_daily: 1, first_time: 2, never: 3)
end
+ def self.text_sizes
+ @text_sizes ||= Enum.new(normal: 0, larger: 1, largest: 2)
+ end
+
+ validates :text_size_key, inclusion: { in: UserOption.text_sizes.values }
+
def set_defaults
self.email_always = SiteSetting.default_email_always
self.mailing_list_mode = SiteSetting.default_email_mailing_list_mode
@@ -58,6 +64,8 @@ class UserOption < ActiveRecord::Base
self.include_tl0_in_digests = SiteSetting.default_include_tl0_in_digests
+ self.text_size = SiteSetting.default_text_size
+
true
end
@@ -146,6 +154,14 @@ class UserOption < ActiveRecord::Base
end
end
+ def text_size
+ UserOption.text_sizes[text_size_key]
+ end
+
+ def text_size=(value)
+ self.text_size_key = UserOption.text_sizes[value.to_sym]
+ end
+
private
def update_tracked_topics
@@ -185,6 +201,7 @@ end
# homepage_id :integer
# theme_ids :integer default([]), not null, is an Array
# hide_profile_and_presence :boolean default(FALSE), not null
+# text_size_key :integer default(0), not null
#
# Indexes
#
diff --git a/app/serializers/user_option_serializer.rb b/app/serializers/user_option_serializer.rb
index 9df725e84cb..0a0e7048fab 100644
--- a/app/serializers/user_option_serializer.rb
+++ b/app/serializers/user_option_serializer.rb
@@ -23,7 +23,8 @@ class UserOptionSerializer < ApplicationSerializer
:theme_key_seq,
:allow_private_messages,
:homepage_id,
- :hide_profile_and_presence
+ :hide_profile_and_presence,
+ :text_size
def auto_track_topics_after_msecs
object.auto_track_topics_after_msecs || SiteSetting.default_other_auto_track_topics_after_msecs
diff --git a/app/services/user_updater.rb b/app/services/user_updater.rb
index 558f08953c4..3828b1da433 100644
--- a/app/services/user_updater.rb
+++ b/app/services/user_updater.rb
@@ -37,7 +37,8 @@ class UserUpdater
:theme_ids,
:allow_private_messages,
:homepage_id,
- :hide_profile_and_presence
+ :hide_profile_and_presence,
+ :text_size
]
def initialize(actor, user)
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index b6d65d54138..a0ab970a488 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -909,6 +909,13 @@ en:
website: "Web Site"
email_settings: "Email"
hide_profile_and_presence: "Hide my public profile and presence features"
+
+ text_size:
+ title: "Text Size"
+ normal: "Normal"
+ larger: "Larger"
+ largest: "Largest"
+
like_notification_frequency:
title: "Notify when liked"
always: "Always"
diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index 4e3f1224165..8b1742fb678 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -1877,6 +1877,8 @@ en:
default_categories_muted: "List of categories that are muted by default."
default_categories_watching_first_post: "List of categories in which first post in each new topic will be watched by default."
+ default_text_size: "Text size which is selected by default"
+
retain_web_hook_events_period_days: "Number of days to retain web hook event records."
retry_web_hook_events: "Automatically retry failed web hook events for 4 times. Time gaps between the retries are 1, 5, 25 and 125 minutes."
diff --git a/config/site_settings.yml b/config/site_settings.yml
index 46f838f1cc1..a22ce2a8008 100644
--- a/config/site_settings.yml
+++ b/config/site_settings.yml
@@ -1811,6 +1811,14 @@ user_preferences:
default_categories_watching_first_post:
type: category_list
default: ''
+
+ default_text_size:
+ type: enum
+ default: normal
+ choices:
+ - normal
+ - larger
+ - largest
api:
retain_web_hook_events_period_days:
diff --git a/db/migrate/20190108110630_add_text_size_key_to_user_options.rb b/db/migrate/20190108110630_add_text_size_key_to_user_options.rb
new file mode 100644
index 00000000000..61edee561e6
--- /dev/null
+++ b/db/migrate/20190108110630_add_text_size_key_to_user_options.rb
@@ -0,0 +1,5 @@
+class AddTextSizeKeyToUserOptions < ActiveRecord::Migration[5.2]
+ def change
+ add_column :user_options, :text_size_key, :integer, null: false, default: 0
+ end
+end
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index f838326f972..0b1aa0ee6c3 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -147,15 +147,29 @@ describe ApplicationHelper do
end
end
- describe '#rtl_class' do
- it "returns 'rtl' when the I18n.locale is rtl" do
+ describe '#html_classes' do
+ it "includes 'rtl' when the I18n.locale is rtl" do
I18n.stubs(:locale).returns(:he)
- expect(helper.rtl_class).to eq('rtl')
+ expect(helper.html_classes.split(" ")).to include('rtl')
end
it 'returns an empty string when the I18n.locale is not rtl' do
I18n.stubs(:locale).returns(:zh_TW)
- expect(helper.rtl_class).to eq('')
+ expect(helper.html_classes.split(" ")).not_to include('rtl')
+ end
+
+ it 'includes the user specified text size' do
+ user = Fabricate(:user)
+ user.user_option.text_size = "larger"
+ user.user_option.save!
+ helper.request.env[Auth::DefaultCurrentUserProvider::CURRENT_USER_KEY] = user
+ expect(helper.html_classes.split(" ")).to include('text-size-larger')
+ end
+
+ it 'falls back to the default text size for anon' do
+ expect(helper.html_classes.split(" ")).to include('text-size-normal')
+ SiteSetting.default_text_size = "largest"
+ expect(helper.html_classes.split(" ")).to include('text-size-largest')
end
end