thredded 0.7.0 → 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +119 -17
  3. data/app/assets/javascripts/thredded/components/currently_online.es6 +3 -3
  4. data/app/assets/javascripts/thredded/components/flash_messages.es6 +11 -0
  5. data/app/assets/javascripts/thredded/components/post_form.es6 +21 -4
  6. data/app/assets/javascripts/thredded/components/time_stamps.es6 +8 -6
  7. data/app/assets/javascripts/thredded/components/topic_form.es6 +14 -3
  8. data/app/assets/javascripts/thredded/components/topics.es6 +3 -3
  9. data/app/assets/javascripts/thredded/components/turboforms.es6 +15 -0
  10. data/app/assets/javascripts/thredded/components/user_preferences_form.es6 +47 -20
  11. data/app/assets/javascripts/thredded/components/users_select.es6 +25 -9
  12. data/app/assets/javascripts/thredded/core/hide_soft_keyboard.es6 +6 -0
  13. data/app/assets/javascripts/thredded/core/mention_autocompletion.es6 +54 -0
  14. data/app/assets/javascripts/thredded/core/on_page_load.es6 +46 -0
  15. data/app/assets/javascripts/thredded/dependencies.js +2 -1
  16. data/app/assets/javascripts/thredded/dependencies/jquery.js +1 -0
  17. data/app/assets/javascripts/thredded/thredded.es6 +1 -0
  18. data/app/assets/stylesheets/thredded/_thredded.scss +1 -0
  19. data/app/assets/stylesheets/thredded/base/_alerts.scss +5 -1
  20. data/app/assets/stylesheets/thredded/base/_grid.scss +8 -0
  21. data/app/assets/stylesheets/thredded/base/_nav.scss +0 -5
  22. data/app/assets/stylesheets/thredded/components/_following.scss +0 -3
  23. data/app/assets/stylesheets/thredded/components/_mention-autocomplete.scss +35 -0
  24. data/app/assets/stylesheets/thredded/components/_topic-header.scss +37 -17
  25. data/app/assets/stylesheets/thredded/components/_topics.scss +13 -0
  26. data/app/assets/stylesheets/thredded/layout/_main-navigation.scss +57 -14
  27. data/app/assets/stylesheets/thredded/layout/_moderation.scss +5 -0
  28. data/app/assets/stylesheets/thredded/layout/_navigation.scss +14 -17
  29. data/app/assets/stylesheets/thredded/layout/_search-navigation.scss +15 -3
  30. data/app/assets/stylesheets/thredded/layout/_user-navigation.scss +3 -11
  31. data/app/commands/thredded/at_notification_extractor.rb +2 -2
  32. data/app/commands/thredded/autofollow_mentioned_users.rb +2 -2
  33. data/app/commands/thredded/create_messageboard.rb +45 -0
  34. data/app/commands/thredded/notify_following_users.rb +10 -0
  35. data/app/controllers/thredded/autocomplete_users_controller.rb +2 -3
  36. data/app/controllers/thredded/messageboards_controller.rb +1 -24
  37. data/app/controllers/thredded/moderation_controller.rb +1 -1
  38. data/app/controllers/thredded/post_permalinks_controller.rb +1 -1
  39. data/app/controllers/thredded/preferences_controller.rb +4 -2
  40. data/app/controllers/thredded/private_post_permalinks_controller.rb +1 -1
  41. data/app/controllers/thredded/theme_previews_controller.rb +1 -1
  42. data/app/controllers/thredded/topics_controller.rb +0 -1
  43. data/app/forms/thredded/user_preferences_form.rb +4 -2
  44. data/app/helpers/thredded/application_helper.rb +5 -0
  45. data/app/helpers/thredded/nav_helper.rb +41 -0
  46. data/app/mailer_previews/thredded/base_mailer_preview.rb +0 -1
  47. data/app/mailers/thredded/post_mailer.rb +0 -1
  48. data/app/mailers/thredded/private_topic_mailer.rb +0 -1
  49. data/app/models/concerns/thredded/user_topic_read_state_common.rb +2 -2
  50. data/app/models/thredded/messageboard.rb +0 -1
  51. data/app/models/thredded/null_preference.rb +5 -1
  52. data/app/models/thredded/private_post.rb +2 -2
  53. data/app/policies/thredded/messageboard_group_policy.rb +1 -1
  54. data/app/view_hooks/thredded/all_view_hooks.rb +68 -0
  55. data/app/view_models/thredded/post_view.rb +3 -3
  56. data/app/view_models/thredded/topic_email_view.rb +0 -4
  57. data/app/view_models/thredded/topics_page_view.rb +12 -1
  58. data/app/views/layouts/thredded/application.html.erb +5 -2
  59. data/app/views/thredded/messageboard_groups/new.html.erb +3 -1
  60. data/app/views/thredded/messageboards/edit.html.erb +3 -1
  61. data/app/views/thredded/messageboards/new.html.erb +3 -1
  62. data/app/views/thredded/moderation/_users_search_form.html.erb +4 -1
  63. data/app/views/thredded/moderation/user.html.erb +34 -28
  64. data/app/views/thredded/posts_common/_form.html.erb +6 -1
  65. data/app/views/thredded/posts_common/form/_content_field.html.erb +5 -3
  66. data/app/views/thredded/preferences/_form.html.erb +30 -12
  67. data/app/views/thredded/private_topics/_form.html.erb +4 -3
  68. data/app/views/thredded/private_topics/index.html.erb +5 -5
  69. data/app/views/thredded/search/_form.html.erb +2 -1
  70. data/app/views/thredded/shared/_flash_messages.html.erb +1 -1
  71. data/app/views/thredded/shared/_page.html.erb +10 -1
  72. data/app/views/thredded/shared/nav/_moderation.html.erb +3 -2
  73. data/app/views/thredded/shared/nav/_notification_preferences.html.erb +5 -3
  74. data/app/views/thredded/shared/nav/_private_topics.html.erb +3 -2
  75. data/app/views/thredded/topics/_form.html.erb +6 -1
  76. data/app/views/thredded/topics/_header.html.erb +8 -5
  77. data/config/locales/en.yml +15 -7
  78. data/config/locales/pt-BR.yml +21 -13
  79. data/config/routes.rb +4 -2
  80. data/db/migrate/20160329231848_create_thredded.rb +5 -5
  81. data/db/upgrade_migrations/20161019150201_upgrade_v0_7_to_v0_8.rb +31 -0
  82. data/lib/generators/thredded/install/templates/initializer.rb +20 -8
  83. data/lib/tasks/thredded_tasks.rake +0 -7
  84. data/lib/thredded.rb +19 -5
  85. data/lib/thredded/content_formatter.rb +43 -8
  86. data/lib/thredded/database_seeder.rb +7 -1
  87. data/lib/thredded/engine.rb +2 -21
  88. data/lib/{html/pipeline → thredded/html_pipeline}/at_mention_filter.rb +4 -4
  89. data/lib/thredded/html_pipeline/autolink_filter.rb +14 -0
  90. data/lib/thredded/html_pipeline/kramdown_filter.rb +34 -0
  91. data/lib/thredded/version.rb +1 -1
  92. data/lib/thredded/view_hooks/config.rb +36 -0
  93. data/lib/thredded/view_hooks/renderer.rb +29 -0
  94. data/vendor/assets/javascripts/jquery.textcomplete.js +1488 -0
  95. metadata +65 -52
  96. data/app/commands/thredded/messageboard_destroyer.rb +0 -65
  97. data/lib/html/pipeline/bbcode_filter.rb +0 -33
  98. data/lib/thredded/main_app_route_delegator.rb +0 -25
@@ -26,7 +26,7 @@
26
26
  }
27
27
  };
28
28
 
29
- let init = $el => {
29
+ let initOne = $el => {
30
30
  $el.select2({
31
31
  ajax: {
32
32
  cache: true,
@@ -38,19 +38,35 @@
38
38
  containerCssClass: 'thredded--select2-container',
39
39
  dropdownCssClass: 'thredded--select2-drop',
40
40
  initSelection: initSelection,
41
- minimumInputLength: 2,
41
+ minimumInputLength: $el.data('autocompleteMinLength'),
42
42
  multiple: true,
43
43
  formatResult: formatUser,
44
44
  formatSelection: formatUserSelection
45
45
  });
46
46
  };
47
47
 
48
- $(function() {
49
- var $nodes = $(COMPONENT_SELECTOR);
50
- if ($nodes.length) {
51
- $nodes.each(function() {
52
- init($(this));
53
- });
54
- }
48
+ let init = () => {
49
+ $(COMPONENT_SELECTOR).each(function() {
50
+ initOne($(this));
51
+ });
52
+ };
53
+
54
+ let destroy = () => {
55
+ $(COMPONENT_SELECTOR).each(function() {
56
+ $(this).select2('destroy');
57
+ });
58
+ $('.select2-drop, .select2-drop-mask').remove();
59
+ };
60
+
61
+ window.Thredded.onPageLoad(() => {
62
+ init()
55
63
  });
64
+
65
+ document.addEventListener('turbolinks:before-cache', () => {
66
+ // Turbolinks 5 clones the body node for caching, losing all the bound
67
+ // events. Undo the select2 transformation before storing to cache,
68
+ // so that it applies cleanly on restore.
69
+ destroy()
70
+ });
71
+
56
72
  })(jQuery);
@@ -0,0 +1,6 @@
1
+ window.Thredded = window.Thredded || {};
2
+ window.Thredded.hideSoftKeyboard = () => {
3
+ const activeElement = document.activeElement;
4
+ if (!activeElement || !activeElement.blur) return;
5
+ activeElement.blur();
6
+ };
@@ -0,0 +1,54 @@
1
+ class ThreddedMentionAutocompletion {
2
+ constructor($) {
3
+ this.$ = $;
4
+ this.textareaSelector = 'textarea';
5
+ }
6
+ init($nodes){
7
+ const $textarea = $nodes.find(this.textareaSelector);
8
+ this.autocompleteMinLength = parseInt($nodes.data('autocompleteMinLength'), 10);
9
+ this.automentionCompletion($textarea, $nodes.data('autocompleteUrl'));
10
+ }
11
+
12
+ escapeHtml(text) {
13
+ return this.$('<div/>').text(text).html();
14
+ }
15
+
16
+ formatUser({avatar_url, name, escapeHtml}) {
17
+ return "<div class='thredded--select2-user-result'>" +
18
+ `<img class='thredded--select2-user-result__avatar' src='${this.escapeHtml(avatar_url)}' >` +
19
+ `<span class='thredded--select2-user-result__name'>${this.escapeHtml(name)}</span>` +
20
+ '</div>';
21
+ }
22
+
23
+
24
+ automentionCompletion($textarea, autocompleteUrl) {
25
+ let mentionAC = this;
26
+ $textarea.textcomplete([{
27
+ match: ThreddedMentionAutocompletion.MATCH_RE,
28
+ search (term, callback, match) {
29
+ if(term.length < this.autocompleteMinLength){
30
+ return callback({});
31
+ }
32
+ let termsUrl = `${autocompleteUrl}?q=${term}`;
33
+ $.ajax({url: termsUrl}).done(function (response) {
34
+ callback($.map(response.results, function ({avatar_url, id, name}) {
35
+ return {avatar_url, id, name, match};
36
+ }));
37
+ });
38
+ },
39
+ template ({avatar_url, name}) {
40
+ return mentionAC.formatUser({avatar_url, name});
41
+ },
42
+ replace ({name, match}) {
43
+ let prefix = match[1];
44
+ if (name.indexOf(" ") > -1) {
45
+ return `${prefix}"${name}" `
46
+ } else {
47
+ return `${prefix}${name} `
48
+ }
49
+ }
50
+ }], {dropdownClassName: 'thredded--textcomplete-dropdown'});
51
+ }
52
+ }
53
+
54
+ ThreddedMentionAutocompletion.MATCH_RE = /(^@|\s@)"?((?:\w| )+)$/;
@@ -0,0 +1,46 @@
1
+ (() => {
2
+ const isTurbolinks = 'Turbolinks' in window && window.Turbolinks.supported;
3
+ const isTurbolinks5 = isTurbolinks && 'clearCache' in window.Turbolinks;
4
+
5
+ let onPageLoadFiredOnce = false;
6
+ const pageLoadCallbacks = [];
7
+ const triggerOnPageLoad = () => {
8
+ pageLoadCallbacks.forEach((callback) => {
9
+ callback();
10
+ });
11
+ onPageLoadFiredOnce = true;
12
+ };
13
+
14
+ window.Thredded = window.Thredded || {};
15
+
16
+ // Fires the callback on DOMContentLoaded or a Turbolinks page load.
17
+ // If called from an async script on the first page load, and the DOMContentLoad event
18
+ // has already fired, will execute the callback immediately.
19
+ window.Thredded.onPageLoad = (callback) => {
20
+ pageLoadCallbacks.push(callback);
21
+ // With async script loading, a callback may be added after the DOMContentLoaded event has already triggered.
22
+ // This means we will receive neither a DOMContentLoaded event, nor a turbolinks:load event on Turbolinks 5.
23
+ if (!onPageLoadFiredOnce && window.Thredded.DOMContentLoadedFired) {
24
+ callback();
25
+ }
26
+ };
27
+
28
+ if (isTurbolinks5) {
29
+ document.addEventListener('turbolinks:load', () => {
30
+ triggerOnPageLoad();
31
+ });
32
+ } else {
33
+ // Turbolinks Classic (with or without jQuery.Turbolinks), or no Turbolinks:
34
+ if (!window.Thredded.DOMContentLoadedFired) {
35
+ document.addEventListener('DOMContentLoaded', () => {
36
+ triggerOnPageLoad();
37
+ });
38
+ }
39
+ if (isTurbolinks) {
40
+ document.addEventListener('page:load', () => {
41
+ triggerOnPageLoad();
42
+ })
43
+ }
44
+ }
45
+ })();
46
+
@@ -1,6 +1,7 @@
1
- //= require jquery
1
+ //= require thredded/dependencies/jquery
2
2
  //= require jquery_ujs
3
3
  //= require jquery.autosize
4
+ //= require jquery.textcomplete
4
5
  //= require rails-timeago
5
6
  //= require select2
6
7
 
@@ -0,0 +1 @@
1
+ //= require jquery3
@@ -1 +1,2 @@
1
+ //= require_tree ./core
1
2
  //= require_tree ./components
@@ -20,6 +20,7 @@
20
20
  @import "components/following";
21
21
  @import "components/form-list";
22
22
  @import "components/main-section";
23
+ @import "components/mention-autocomplete";
23
24
  @import "components/messageboard";
24
25
  @import "components/pagination";
25
26
  @import "components/post";
@@ -17,9 +17,13 @@
17
17
  %thredded--alert {
18
18
  border: solid 1px;
19
19
  border-radius: 3px;
20
- margin-bottom: $thredded-base-spacing;
20
+ margin-bottom: $thredded-small-spacing;
21
21
  padding: $thredded-small-spacing;
22
22
  text-decoration: none;
23
+
24
+ @include thredded-media-desktop-and-up {
25
+ margin-bottom: $thredded-base-spacing;
26
+ }
23
27
  }
24
28
 
25
29
  %thredded--alert--success {
@@ -16,6 +16,14 @@
16
16
  }
17
17
  }
18
18
 
19
+ @mixin thredded-media-tablet {
20
+ @include thredded-media-tablet-and-up {
21
+ @include thredded-media-tablet-and-down {
22
+ @content;
23
+ }
24
+ }
25
+ }
26
+
19
27
  @mixin thredded-media-desktop-and-up {
20
28
  @media screen and (min-width: map-get($thredded-grid-breakpoint-max-widths, tablet) + 0.00001rem) {
21
29
  @content;
@@ -27,13 +27,8 @@
27
27
  border-bottom: $thredded-base-border;
28
28
  font-size: $thredded-font-size-small;
29
29
  margin-left: 0;
30
- margin-bottom: 1rem;
31
30
  text-align: left;
32
31
  list-style-type: none;
33
-
34
- @include thredded-media-tablet-and-up {
35
- margin-bottom: 0;
36
- }
37
32
  }
38
33
 
39
34
  %thredded--nav-tabs--item {
@@ -5,9 +5,6 @@
5
5
  font-size: 1em;
6
6
  width: 1.4rem;
7
7
  height: 1.4rem;
8
- position: absolute;
9
- top: 0;
10
- right: -1.6rem;
11
8
  opacity: 0.4;
12
9
  }
13
10
 
@@ -0,0 +1,35 @@
1
+ ul.thredded--textcomplete-dropdown {
2
+ background: inherit;
3
+ border-color: $thredded-form-border-focus-color;
4
+ border-top: $thredded-base-border;
5
+ box-shadow: 0 1px 1px $thredded-form-border-focus-color;
6
+ font-family: $thredded-base-font-family;
7
+ font-size: $thredded-base-font-size;
8
+ line-height: $thredded-base-line-height;
9
+ }
10
+
11
+ ul.thredded--textcomplete-dropdown {
12
+
13
+ background: $thredded-form-background;
14
+ padding: 4px;
15
+ margin: 0;
16
+
17
+ li.textcomplete-item {
18
+ list-style: none;
19
+ a {
20
+ color: $thredded-text-color;
21
+ }
22
+
23
+ &.active {
24
+ background: $thredded-button-background;
25
+ a {
26
+ color: $thredded-button-color;
27
+ }
28
+ }
29
+
30
+ padding: $thredded-small-spacing;
31
+ }
32
+
33
+ }
34
+
35
+
@@ -1,17 +1,21 @@
1
1
  .thredded--topic-header {
2
- margin-bottom: $thredded-large-spacing;
3
- margin-top: $thredded-base-spacing;
4
- @include thredded-media-mobile {
5
- margin-bottom: $thredded-small-spacing;
6
- margin-top: 0;
2
+ margin-bottom: $thredded-small-spacing;
3
+ margin-top: 0;
4
+ @include thredded-media-desktop-and-up {
5
+ margin-bottom: $thredded-large-spacing;
6
+ margin-top: $thredded-small-spacing;
7
+ @include thredded--clearfix;
7
8
  }
8
9
  }
9
10
 
10
11
  .thredded--topic-header--title {
11
12
  @extend %thredded--heading;
12
- font-size: 1.5rem; // 24px
13
+ font-size: 1.25rem;
13
14
  line-height: 1.2;
14
15
  margin-bottom: $thredded-small-spacing / 2;
16
+ @include thredded-media-tablet-and-up {
17
+ font-size: 1.5rem;
18
+ }
15
19
  }
16
20
 
17
21
  .thredded--topic-header--started-by {
@@ -30,18 +34,37 @@
30
34
  }
31
35
 
32
36
  .thredded--topic-header--follow-info {
33
- float: right;
34
37
  color: $thredded-secondary-text-color;
35
38
  font-size: $thredded-font-size-small;
36
39
  font-style: normal;
37
- max-width: 60%;
38
- text-align: right;
40
+ @include thredded-media-desktop-and-up {
41
+ float: right;
42
+ text-align: right;
43
+ max-width: 25rem;
44
+ position: relative;
45
+ form {
46
+ // Do not introduce extra margin
47
+ position: absolute;
48
+ right: 0;
49
+ vertical-align: text-top;
50
+ &.thredded--topic-header--follow-info--unfollow {
51
+ top: 1.625em; // required for Safari and Firefox
52
+ }
53
+ }
54
+ &--reason {
55
+ display: block;
56
+ vertical-align: text-top;
57
+ }
58
+ }
39
59
  p {
40
60
  margin: 0;
41
61
  }
62
+ &--reason {
63
+ display: inline-block;
64
+ }
42
65
  form {
43
66
  display: inline-block;
44
- input[type=submit] {
67
+ input[type=submit], button {
45
68
  background:none;
46
69
  border:none;
47
70
  padding:0;
@@ -52,13 +75,10 @@
52
75
  }
53
76
  }
54
77
 
55
- .thredded--topic-following {
56
- .thredded--topic-header--follow-info {
57
- position: relative;
58
- }
59
- .thredded--topic-header--follow-icon {
60
- @extend %thredded--following-icon;
61
- }
78
+
79
+ .thredded--topic-header--follow-icon {
80
+ @extend %thredded--following-icon;
81
+ vertical-align: middle;
62
82
  }
63
83
 
64
84
  .thredded--topic-followers {
@@ -5,6 +5,10 @@
5
5
  @media (max-width: $thredded-grid-container-max-width) {
6
6
  margin-left: 3rem;
7
7
  }
8
+ @include thredded-media-mobile {
9
+ margin-right: 2rem;
10
+ }
11
+
8
12
  }
9
13
 
10
14
  .thredded--topics--title {
@@ -130,6 +134,15 @@
130
134
  }
131
135
  }
132
136
 
137
+ .thredded--topics--follow-icon {
138
+ position: absolute;
139
+ right: -1.6rem;
140
+ top: 0;
141
+ @include thredded-media-mobile {
142
+ right: -2rem;
143
+ }
144
+ }
145
+
133
146
  .thredded--topic-following {
134
147
  .thredded--topics--follow-icon {
135
148
  @extend %thredded--following-icon;
@@ -1,35 +1,78 @@
1
+ @mixin thredded-breadcrumbs-chevron() {
2
+ background: image-url("thredded/breadcrumb-chevron.svg") no-repeat center center;
3
+ content: "";
4
+ display: inline-block;
5
+ height: 10px;
6
+ margin: 0 ($thredded-small-spacing - 0.3rem) 0 $thredded-small-spacing;
7
+ width: 6px;
8
+ }
9
+
1
10
  .thredded--main-navigation {
2
11
  @extend %thredded--list-unstyled;
3
12
  @include thredded--clearfix;
4
13
  display: block;
5
- @include thredded-media-desktop-and-up {
6
- margin-top: $thredded-small-spacing;
7
- }
8
14
  }
9
15
 
10
16
  .thredded--navigation-breadcrumbs {
11
17
  @extend %thredded--list-unstyled;
12
18
 
13
19
  li {
14
- display: inline-block;
20
+ display: block;
15
21
  font-weight: bold;
16
22
 
17
23
  a {
18
- display: inline-block;
19
- padding: $thredded-small-spacing 0;
24
+ display: block;
25
+ }
26
+
27
+ @include thredded-media-mobile {
28
+ a {
29
+ position: relative;
30
+ }
31
+
32
+ &:first-child:last-child {
33
+ a, &.thredded--navigation-breadcrumbs--item-no-link {
34
+ padding: $thredded-small-spacing 0;
35
+ }
36
+ }
37
+
38
+ &:first-child:not(:last-child) {
39
+ a, &.thredded--navigation-breadcrumbs--item-no-link {
40
+ padding-top: ($thredded-small-spacing/2);
41
+ }
42
+ }
43
+
44
+ &:last-child:not(:first-child) {
45
+ a, &.thredded--navigation-breadcrumbs--item-no-link {
46
+ padding-bottom: ($thredded-small-spacing/2);
47
+ &::before {
48
+ @include thredded-breadcrumbs-chevron();
49
+ position: absolute;
50
+ top: 0.4em;
51
+ left: -1.625em;
52
+ }
53
+ }
54
+ }
20
55
  }
21
56
 
22
- &:after {
23
- background: image-url("thredded/breadcrumb-chevron.svg") no-repeat center center;
24
- content: "";
57
+ @include thredded-media-tablet-and-up {
25
58
  display: inline-block;
26
- height: 10px;
27
- margin: 0 ($thredded-small-spacing - 0.3rem) 0 $thredded-small-spacing;
28
- width: 6px;
59
+ a, &.thredded--navigation-breadcrumbs--item-no-link {
60
+ display: inline-block;
61
+ padding: $thredded-small-spacing 0;
62
+ }
63
+ // Chevron
64
+ &::after {
65
+ @include thredded-breadcrumbs-chevron();
66
+ }
67
+ &:last-child::after {
68
+ display: none;
69
+ }
29
70
  }
30
71
 
31
- &:last-child:after {
32
- display: none;
72
+ @include thredded-media-desktop-and-up {
73
+ a, &.thredded--navigation-breadcrumbs--item-no-link {
74
+ padding: $thredded-base-spacing 0;
75
+ }
33
76
  }
34
77
  }
35
78