summaryrefslogtreecommitdiff
path: root/addons/website_forum
diff options
context:
space:
mode:
authorsri-odoo <sri@odoo.com>2019-08-29 13:48:12 +0000
committerqsm-odoo <qsm@odoo.com>2019-10-01 16:52:20 +0000
commitc8c8eb3d5652e9834d0ecd5aad907ee359edb657 (patch)
tree854984a5b6010953d8087337bc02e4e786dc4269 /addons/website_forum
parent83284a962cdbce53a30a42e2282953d777949fa1 (diff)
[IMP] website_forum, *: revamp design
* web_editor, website_profile Part of https://github.com/odoo/odoo/pull/35749 task-2024197 Co-authored-by: Jérémy Kersten <jke@odoo.com> Co-authored-by: qsm-odoo <qsm@odoo.com> Co-authored-by: fja-odoo <fja@odoo.com>
Diffstat (limited to 'addons/website_forum')
-rw-r--r--addons/website_forum/controllers/main.py34
-rw-r--r--addons/website_forum/data/forum_data.xml1
-rw-r--r--addons/website_forum/data/forum_default_faq.html2
-rw-r--r--addons/website_forum/models/__init__.py3
-rw-r--r--addons/website_forum/models/forum.py11
-rw-r--r--addons/website_forum/models/website.py15
-rw-r--r--addons/website_forum/static/src/js/tours/website_forum.js4
-rw-r--r--addons/website_forum/static/src/js/website_forum.js134
-rw-r--r--addons/website_forum/static/src/scss/website_forum.scss300
-rw-r--r--addons/website_forum/static/tests/tours/website_forum_question.js8
-rw-r--r--addons/website_forum/views/website_forum.xml1827
-rw-r--r--addons/website_forum/views/website_forum_profile.xml29
12 files changed, 1410 insertions, 958 deletions
diff --git a/addons/website_forum/controllers/main.py b/addons/website_forum/controllers/main.py
index d2299ca7dc8..435e894db58 100644
--- a/addons/website_forum/controllers/main.py
+++ b/addons/website_forum/controllers/main.py
@@ -73,7 +73,7 @@ class WebsiteForum(WebsiteProfile):
'''/forum/<model("forum.forum"):forum>/tag/<model("forum.tag"):tag>/questions''',
'''/forum/<model("forum.forum"):forum>/tag/<model("forum.tag"):tag>/questions/page/<int:page>''',
], type='http', auth="public", website=True, sitemap=sitemap_forum)
- def questions(self, forum, tag=None, page=1, filters='all', sorting=None, search='', **post):
+ def questions(self, forum, tag=None, page=1, filters='all', my=None, sorting=None, search='', **post):
if not forum.can_access_from_current_website():
raise werkzeug.exceptions.NotFound()
@@ -86,8 +86,21 @@ class WebsiteForum(WebsiteProfile):
domain += [('tag_ids', 'in', tag.id)]
if filters == 'unanswered':
domain += [('child_ids', '=', False)]
- elif filters == 'followed':
- domain += [('message_partner_ids', '=', request.env.user.partner_id.id)]
+ elif filters == 'solved':
+ domain += [('has_validated_answer', '=', True)]
+ elif filters == 'unsolved':
+ domain += [('has_validated_answer', '=', False)]
+
+ user = request.env.user
+
+ if my == 'mine':
+ domain += [('create_uid', '=', user.id)]
+ elif my == 'followed':
+ domain += [('message_partner_ids', '=', user.partner_id.id)]
+ elif my == 'tagged':
+ domain += [('tag_ids.message_partner_ids', '=', user.partner_id.id)]
+ elif my == 'favourites':
+ domain += [('favourite_ids', '=', user.id)]
if sorting:
# check that sorting is valid
@@ -128,6 +141,7 @@ class WebsiteForum(WebsiteProfile):
'pager': pager,
'tag': tag,
'filters': filters,
+ 'my': my,
'sorting': sorting,
'search': search,
})
@@ -153,10 +167,9 @@ class WebsiteForum(WebsiteProfile):
first_char_tag = forum.get_tags_first_char()
first_char_list = [(t, t.lower()) for t in first_char_tag if t.isalnum()]
first_char_list.insert(0, (_('All'), 'all'))
- # get active first char tag
- active_char_tag = first_char_list[1][1] if len(first_char_list) > 1 else 'all'
- if tag_char:
- active_char_tag = tag_char.lower()
+
+ active_char_tag = tag_char and tag_char.lower() or 'all'
+
# generate domain for searched tags
domain = [('forum_id', '=', forum.id), ('posts_count', '>', 0)]
order_by = 'name'
@@ -282,7 +295,7 @@ class WebsiteForum(WebsiteProfile):
user = request.env.user
if not user.email or not tools.single_email_re.match(user.email):
return werkzeug.utils.redirect("/forum/%s/user/%s/edit?email_required=1" % (slug(forum), request.session.uid))
- values = self._prepare_user_values(forum=forum, searches={}, header={'ask_hide': True})
+ values = self._prepare_user_values(forum=forum, searches={}, header={'ask_hide': True}, new_question=True)
return request.render("website_forum.new_question", values)
@http.route(['/forum/<model("forum.forum"):forum>/new',
@@ -349,6 +362,7 @@ class WebsiteForum(WebsiteProfile):
values.update({
'tags': tags,
'post': post,
+ 'is_edit': True,
'is_answer': bool(post.parent_id),
'searches': kwargs,
'content': post.name,
@@ -518,8 +532,8 @@ class WebsiteForum(WebsiteProfile):
# -----------------------------------
@http.route(['/forum/<model("forum.forum"):forum>/user/<int:user_id>'], type='http', auth="public", website=True)
- def view_user_forum_profile(self, forum, user_id, **post):
- return werkzeug.utils.redirect('/profile/user/' + str(user_id) + '?forum_id=' + str(forum.id))
+ def view_user_forum_profile(self, forum, user_id, forum_origin, **post):
+ return werkzeug.utils.redirect('/profile/user/' + str(user_id) + '?forum_id=' + str(forum.id) + '&forum_origin=' + str(forum_origin))
def _prepare_user_profile_values(self, user, **post):
values = super(WebsiteForum, self)._prepare_user_profile_values(user, **post)
diff --git a/addons/website_forum/data/forum_data.xml b/addons/website_forum/data/forum_data.xml
index c07e95c063f..8d3b05c2570 100644
--- a/addons/website_forum/data/forum_data.xml
+++ b/addons/website_forum/data/forum_data.xml
@@ -3,6 +3,7 @@
<data noupdate="1">
<record id="forum_help" model="forum.forum">
<field name="name">Help</field>
+ <field name="description">This community is for professionals and enthusiasts of our products and services. Share and discuss the best content and new marketing ideas, build your professional profile and become a better marketer together.</field>
</record>
<record id="menu_website_forums" model="website.menu">
diff --git a/addons/website_forum/data/forum_default_faq.html b/addons/website_forum/data/forum_default_faq.html
index 73436c1d0f5..43f4489c67b 100644
--- a/addons/website_forum/data/forum_default_faq.html
+++ b/addons/website_forum/data/forum_default_faq.html
@@ -1,5 +1,3 @@
-<h1 class="o_page_header">Guidelines</h1>
-
<div id="accordion">
<div class="card mb-2 bg-100">
<a href="#collapseOne" class="card-header" id="headingOne" data-toggle="collapse" aria-expanded="false" aria-controls="collapseOne">
diff --git a/addons/website_forum/models/__init__.py b/addons/website_forum/models/__init__.py
index 6a8174ad9e0..6400bd0bdb4 100644
--- a/addons/website_forum/models/__init__.py
+++ b/addons/website_forum/models/__init__.py
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
+from . import forum
from . import gamification
from . import res_users
-from . import forum
+from . import website
diff --git a/addons/website_forum/models/forum.py b/addons/website_forum/models/forum.py
index 62d21ea9b6d..12dc7fc5739 100644
--- a/addons/website_forum/models/forum.py
+++ b/addons/website_forum/models/forum.py
@@ -36,16 +36,11 @@ class Forum(models.Model):
help='Questions mode: only one answer allowed\n Discussions mode: multiple answers allowed')
active = fields.Boolean(default=True)
faq = fields.Html('Guidelines', default=_get_default_faq, translate=html_translate, sanitize=False)
- description = fields.Text(
- 'Description',
- translate=True,
- default=lambda s: _('This community is for professionals and enthusiasts of our products and services. '
- 'Share and discuss the best content and new marketing ideas, '
- 'build your professional profile and become a better marketer together.'))
+ description = fields.Text('Description', translate=True)
welcome_message = fields.Html(
'Welcome Message',
translate=True,
- default="""<section class="bg-info shadow">
+ default="""<section>
<div class="container py-5">
<div class="row">
<div class="col-lg-12">
@@ -56,7 +51,7 @@ class Forum(models.Model):
</p>
</div>
<div class="col text-center mt-3">
- <a href="#" class="js_close_intro btn btn-outline-light">Hide Intro</a>
+ <a href="#" class="js_close_intro btn btn-outline-light mr-2">Hide Intro</a>
<a class="btn btn-light forum_register_url" href="/web/login">Register</a>
</div>
</div>
diff --git a/addons/website_forum/models/website.py b/addons/website_forum/models/website.py
new file mode 100644
index 00000000000..29a42fd8850
--- /dev/null
+++ b/addons/website_forum/models/website.py
@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import models, fields
+
+
+class Website(models.Model):
+ _inherit = 'website'
+
+ def _compute_field_forums_count(self):
+ Forum = self.env['forum.forum']
+ for website in self:
+ website.forums_count = Forum.search_count(website.website_domain())
+
+ forums_count = fields.Integer(compute=_compute_field_forums_count)
diff --git a/addons/website_forum/static/src/js/tours/website_forum.js b/addons/website_forum/static/src/js/tours/website_forum.js
index f93bfa48631..51a777abfdc 100644
--- a/addons/website_forum/static/src/js/tours/website_forum.js
+++ b/addons/website_forum/static/src/js/tours/website_forum.js
@@ -22,7 +22,7 @@ odoo.define("website_forum.tour_forum", function (require) {
content: _t("Click <em>Continue</em> to create the forum."),
position: "right",
}, {
- trigger: ".btn-lg.btn-block",
+ trigger: ".o_forum_ask_btn",
position: "left",
content: _t("Ask the question in this forum by clicking on the button."),
}, {
@@ -67,7 +67,7 @@ odoo.define("website_forum.tour_forum", function (require) {
trigger: ".modal-header button.close",
auto: true,
}, {
- trigger: "a[data-karma=\"20\"]:first",
+ trigger: ".o_wforum_validate_toggler[data-karma=\"20\"]:first",
content: _t("Click here to accept this answer."),
position: "right",
}]);
diff --git a/addons/website_forum/static/src/js/website_forum.js b/addons/website_forum/static/src/js/website_forum.js
index d4e65371a58..5b22fa03c01 100644
--- a/addons/website_forum/static/src/js/website_forum.js
+++ b/addons/website_forum/static/src/js/website_forum.js
@@ -2,6 +2,7 @@ odoo.define('website_forum.website_forum', function (require) {
'use strict';
var core = require('web.core');
+var weDefaultOptions = require('web_editor.wysiwyg.default_options');
var wysiwygLoader = require('web_editor.loader');
var publicWidget = require('web.public.widget');
var session = require('web.session');
@@ -22,11 +23,8 @@ publicWidget.registry.websiteForum = publicWidget.Widget.extend({
'click .flag:not(.karma_required)': '_onFlagAlertClick',
'click .vote_up:not(.karma_required), .vote_down:not(.karma_required)': '_onVotePostClick',
'click .o_js_validation_queue a[href*="/validate"]': '_onValidationQueueClick',
- 'click .accept_answer:not(.karma_required)': '_onAcceptAnswerClick',
- 'click .validate_answer [data-href]': '_onAcceptAnswerClick',
- 'mouseenter .validate_answer [data-href]': '_onRemoveValidAnswerMouse',
- 'mouseleave .validate_answer [data-href]': '_onRemoveValidAnswerMouse',
- 'click .favourite_question': '_onFavoriteQuestionClick',
+ 'click .o_wforum_validate_toggler:not(.karma_required)': '_onAcceptAnswerClick',
+ 'click .o_wforum_favourite_toggle': '_onFavoriteQuestionClick',
'click .comment_delete': '_onDeleteCommentClick',
'click .js_close_intro': '_onCloseIntroClick',
},
@@ -49,6 +47,10 @@ publicWidget.registry.websiteForum = publicWidget.Widget.extend({
);
$('.forum_register_url').attr('href', forumLogin);
+ // Initialize forum's tooltips
+ this.$('[data-toggle="tooltip"]').tooltip({delay: 0});
+ this.$('[data-toggle="popover"]').popover({offset: 8});
+
$('input.js_select2').select2({
tags: true,
tokenSeparators: [',', ' ', '_'],
@@ -127,9 +129,11 @@ publicWidget.registry.websiteForum = publicWidget.Widget.extend({
toolbar.push(['history', ['undo', 'redo']]);
var options = {
- height: 150,
+ height: 200,
+ minHeight: 80,
toolbar: toolbar,
styleWithSpan: false,
+ styleTags: _.without(weDefaultOptions.styleTags, 'h1', 'h2', 'h3'),
recordInfo: {
context: self._getContext(),
res_model: 'forum.post',
@@ -151,12 +155,13 @@ publicWidget.registry.websiteForum = publicWidget.Widget.extend({
});
});
- // Check all answer status to add text-success on answer if needed
- _.each($('.accept_answer'), function (el) {
- var $el = $(el);
- if ($el.hasClass('oe_answer_true')) {
- $el.addClass('text-success');
- }
+ _.each(this.$('.o_wforum_bio_popover'), authorBox => {
+ $(authorBox).popover({
+ trigger: 'hover',
+ offset: 10,
+ animation: false,
+ html: true,
+ });
});
return this._super.apply(this, arguments);
@@ -278,9 +283,9 @@ publicWidget.registry.websiteForum = publicWidget.Widget.extend({
_onVotePostClick: function (ev) {
var self = this;
ev.preventDefault();
- var $link = $(ev.currentTarget);
+ var $btn = $(ev.currentTarget);
this._rpc({
- route: $link.data('href'),
+ route: $btn.data('href'),
}).then(function (data) {
if (data.error) {
var message;
@@ -296,17 +301,28 @@ publicWidget.registry.websiteForum = publicWidget.Widget.extend({
sticky: false,
});
} else {
- $link.parent().find('.vote_count').html(data.vote_count);
- if (data.user_vote === 0) {
- $link.parent().find('.text-success').removeClass('text-success');
- $link.parent().find('.text-warning').removeClass('text-warning');
- } else {
- if (data.user_vote === 1) {
- $link.addClass('text-success');
- } else {
- $link.addClass('text-warning');
- }
+ var $container = $btn.closest('.vote');
+ var $items = $container.children();
+ var $voteUp = $items.filter('.vote_up');
+ var $voteDown = $items.filter('.vote_down');
+ var $voteCount = $items.filter('.vote_count');
+ var userVote = parseInt(data['user_vote']);
+
+ $voteUp.prop('disabled', userVote === 1);
+ $voteDown.prop('disabled', userVote === -1);
+
+ $items.removeClass('text-success text-danger text-muted o_forum_vote_animate');
+ void $container[0].offsetWidth; // Force a refresh
+
+ if (userVote === 1) {
+ $voteUp.addClass('text-success');
+ $voteCount.addClass('text-success');
+ }
+ if (userVote === -1) {
+ $voteDown.addClass('text-danger');
+ $voteCount.addClass('text-danger');
}
+ $voteCount.html(data['vote_count']).addClass('o_forum_vote_animate');
}
});
},
@@ -318,11 +334,14 @@ publicWidget.registry.websiteForum = publicWidget.Widget.extend({
ev.preventDefault();
var $link = $(ev.currentTarget);
$link.parents('.post_to_validate').hide();
- $.get($link.attr('href')).then(function () {
+ $.get($link.attr('href')).then(() => {
var left = $('.o_js_validation_queue:visible').length;
var type = $('h2.o_page_header a.active').data('type');
$('#count_post').text(left);
$('#moderation_tools a[href*="/' + type + '_"]').find('strong').text(left);
+ if (!left) {
+ this.$('.o_caught_up_alert').removeClass('d-none');
+ }
}, function () {
$link.parents('.o_js_validation_queue > div').addClass('bg-danger text-white').css('background-color', '#FAA');
$link.parents('.post_to_validate').show();
@@ -333,38 +352,35 @@ publicWidget.registry.websiteForum = publicWidget.Widget.extend({
* @param {Event} ev
*/
_onAcceptAnswerClick: function (ev) {
- var self = this;
ev.preventDefault();
- var self = this;
- var $acceptAnswerLinks = this.$('.accept_answer');
var $link = $(ev.currentTarget);
+ var target = $link.data('target');
+
this._rpc({
route: $link.data('href'),
- }).then(function (data) {
+ }).then(data => {
if (data.error) {
if (data.error === 'anonymous_user') {
var message = _t("Sorry, anonymous users cannot choose correct answer.");
}
- self.call('crash_manager', 'show_warning', {
+ this.call('crash_manager', 'show_warning', {
message: message,
title: _t("Access Denied"),
}, {
sticky: false,
});
} else {
- $acceptAnswerLinks.removeClass('oe_answer_true')
- .addClass('oe_answer_false');
- $link.toggleClass('oe_answer_true', !!data)
- .toggleClass('oe_answer_false', !data);
-
- // TODO in master, review the utility of this function...
- self._onCheckAnswerStatus(ev);
+ _.each(this.$('.forum_answer'), answer => {
+ var $answer = $(answer);
+ var isCorrect = $answer.is(target) ? data : false;
+ var $toggler = $answer.find('.o_wforum_validate_toggler');
+ var newHelper = isCorrect ? $toggler.data('helper-decline') : $toggler.data('helper-accept');
- // If we are removing an accepted answer, reload the page as the
- // design is quite different with or without an accepted answer.
- if ($link.closest('.validate_answer').length) {
- window.location.reload();
- }
+ $answer.toggleClass('o_wforum_answer_correct', isCorrect);
+ $toggler.tooltip('dispose')
+ .attr('data-original-title', newHelper)
+ .tooltip({delay: 0});
+ });
}
});
},
@@ -372,33 +388,14 @@ publicWidget.registry.websiteForum = publicWidget.Widget.extend({
* @private
* @param {Event} ev
*/
- _onRemoveValidAnswerMouse: function (ev) {
- var hover = (ev.type === 'mouseenter');
- $(ev.currentTarget).find('.fa')
- .toggleClass('fa-times-circle text-danger', hover)
- .toggleClass('fa-check-circle text-success', !hover);
- },
- /**
- * @private
- * @param {Event} ev
- */
- _onCheckAnswerStatus: function (ev) {
- _.each(this.$('.accept_answer'), function (link) {
- var $link = $(link);
- $link.toggleClass('text-success', $link.hasClass('oe_answer_true'));
- });
- },
- /**
- * @private
- * @param {Event} ev
- */
_onFavoriteQuestionClick: function (ev) {
ev.preventDefault();
var $link = $(ev.currentTarget);
this._rpc({
route: $link.data('href'),
}).then(function (data) {
- $link.toggleClass('forum_favourite_question', !!data);
+ $link.toggleClass('o_wforum_gold fa-star', data)
+ .toggleClass('fa-star-o text-muted', !data);
});
},
/**
@@ -408,10 +405,19 @@ publicWidget.registry.websiteForum = publicWidget.Widget.extend({
_onDeleteCommentClick: function (ev) {
ev.preventDefault();
var $link = $(ev.currentTarget);
+ var $container = $link.closest('.o_wforum_post_comments_container');
+
this._rpc({
route: $link.closest('form').attr('action'),
}).then(function () {
- $link.parents('.comment').first().remove();
+ $link.closest('.o_wforum_post_comment').remove();
+
+ var count = $container.find('.o_wforum_post_comment').length;
+ if (count) {
+ $container.find('.o_wforum_comments_count').text(count);
+ } else {
+ $container.find('.o_wforum_comments_count_header').remove();
+ }
});
},
/**
diff --git a/addons/website_forum/static/src/scss/website_forum.scss b/addons/website_forum/static/src/scss/website_forum.scss
index 8694ecc77ab..c9ff7de71c1 100644
--- a/addons/website_forum/static/src/scss/website_forum.scss
+++ b/addons/website_forum/static/src/scss/website_forum.scss
@@ -1,178 +1,195 @@
-$gold: #ffcc00;
+$gold: #eca801;
$silver: #cccccc;
$bronze: #eea91e;
.website_forum {
+ .o_forum_ask_btn {
+ @include media-breakpoint-up(md) {
+ box-shadow: $box-shadow;
+ width: 200px;
+ }
+ }
+
+ .o_wforum_nav .nav-link {
+ @include o-hover-text-color($body-color, $link-color);
+ line-height: 1;
+
+ .fa {
+ opacity: 0.5;
+ }
+
+ &:hover, &.active {
+ .fa {
+ opacity: 1;
+ }
+ }
- .question-block .question-name {
- max-width: 80%;
+ &.active {
+ background-color: rgba(theme-color('info'), 0.1);
+ color: darken(theme-color('info'), 15%)!important;
+ }
}
- .o_post_content {
+ // Single Post
+ .o_wforum_post, .note-editable.panel-body {
+ word-wrap: break-word;
+
pre {
- padding: 1.5rem;
- border-radius: 5px;
- color: $white;
- background-color: $gray-700;
+ color: color-yiq(gray('100'));
+ border-radius: $border-radius;
+ padding: 1rem;
+ background-color: gray('100');
+ white-space: pre-wrap;
}
+
blockquote {
position: relative;
- padding-left: 3rem;
- border-left: 2px solid $gray-500;
- font-style: italic;
- font-weight: lighter;
+ padding-left: 1em;
+ border-left: .25em solid gray('500');
+ color: gray('600');
}
- word-wrap: break-word;
}
- .vote {
- min-width: 38px;
- margin-right: 12px;
- .vote_count {
- font-weight: bold;
- line-height: 12px;
- font-size: 160%;
- }
- .vote_down,
- .vote_up {
- font-size: 130%;
+ .o_wforum_readable {
+ max-width: 700px;
+
+ p {
+ margin-bottom: 0.5rem;
}
}
- .post_to_validate {
- overflow: hidden;
- .validate_answer {
- display: none;
+ textarea.o_wysiwyg_loader + .note-editor {
+ border: 0;
+
+ .note-toolbar {
+ @include border-top-radius($border-radius);
+ height: 32px;
}
- }
- .validate_answer {
- @include o-position-absolute(0, auto, 0, 0);
- width: 4px;
- height: 100%;
- z-index: 1; // On top of card content if an alert is displayed inside
+ .note-editable, .note-statusbar {
+ border: 1px solid $border-color;
+ border-width: 0 1px;
+ }
- > .bg-success {
- @include o-position-absolute(0, 0, 0, 0);
+ .note-statusbar {
+ display: block;
+ border-bottom-width: 1px;
}
- > span {
- @include o-position-absolute(10px, 50%);
- transform: translateX(50%);
- font-size: 20px;
+ }
- &[data-href] {
- cursor: pointer;
+ .o_wforum_author_box {
+ &.o_show_info {
+ line-height: 1.2;
+ img {
+ @include size(2em);
}
+ }
+
+ &.o_compact {
+ line-height: 1;
- i {
- padding: 2px 3px;
- border-radius: 100%;
+ img {
+ @include size(1.4em);
}
}
- }
- .user_name_people {
- font-weight: bold;
- max-width: 60%;
}
- .oe_answer_true {
- color: theme-color('success');
- &:hover {
- color: lighten(theme-color('success'), 20%);
+ .forum_answer {
+ .o_wforum_answer_correct_badge {
+ display: none;
}
- }
- .oe_answer_false {
- color: $gray-400;
- &:hover {
- color: $gray-600;
+ .o_wforum_author_box_check {
+ @include size(1em);
+ display: none;
+ top: 0;
+ right: -3px;
+ box-shadow: 0 0 0 2px white;
+ line-height: .8;
}
- }
- .favourite_question {
- color: $gray-400 !important;
+ .o_wforum_validate_toggler {
+ @include o-hover-text-color(gray('400'), lighten(theme-color('success'), 20%));
+ }
- &.forum_favourite_question {
- color: $gold !important;
+ &.o_wforum_answer_correct {
+ .o_wforum_answer_correct_badge, .o_wforum_author_box .o_wforum_author_box_check {
+ display: inline;
+ }
+
+ .o_wforum_validate_toggler {
+ @include o-hover-text-color(theme-color('success'), theme-color('warning'));
+
+ &:hover .fa.fa-check:before {
+ content: '\f00d';
+ }
+ }
+
+ .o_wforum_answer_header .o_wforum_author_pic {
+ border: 2px solid $success;
+ padding: 3px;
+ }
}
}
- .oe_grey {
- background-color: #eeeeee;
+ .o_wforum_gold {
+ color: $gold;
}
-
a.no-decoration {
cursor: pointer;
text-decoration: none !important;
}
- .close.comment_delete {
- font-size: 0.875rem;
- float: none;
- opacity: 1;
- font-weight: 300;
- line-height: 1.5;
- }
- .country_flag {
- display: inline-block;
- margin-left: 2px;
- max-height: 13px;
- width: auto !important;
- }
-
.forum_answer img, .question-block img {
max-width: 100%
}
+}
- img.country_flag_people {
- @include o-position-absolute(0,0);
- max-height: 25px;
- width: auto;
- }
+.website_forum, .o_wforum_profile_tab {
+ .vote {
+ .vote_count {
+ line-height: 1;
+ animation-play-state: paused;
- .tag_text .text-core .text-wrap {
- .text-dropdown,
- .text-prompt,
- input,
- textarea {
- font: 1.2em "Helvetica Neue", Helvetica, Arial, sans-serif !important;
+ &.o_forum_vote_animate {
+ animation: bounceIn 0.3s ease running;
+ }
}
- .text-tags .text-tag .text-button {
- font: 1.2em "Helvetica Neue", Helvetica, Arial, sans-serif !important;
- height: 1.2em !important;
+ .vote_down, .vote_up {
+ line-height: 0.5;
+ font-size: 1.1em;
+ @include o-hover-text-color(rgba($text-muted, 0.5), theme-color('success'));
}
- }
- .oe_forum_email_required {
- position: absolute;
- margin-top: 155px;
- margin-left: 500px;
- margin-right: 100px;
- z-index: 5;
- }
+ .vote_down {
+ @include o-hover-text-color(rgba($text-muted, 0.5), theme-color('danger'));
+ }
- button.btn-link.text-muted {
- color: $gray-600;
+ &.o_wforum_vote_vertical {
+ @include media-breakpoint-up(sm) {
+ font-size: 1.2em;
+ }
+ }
}
}
-.o_forum_tag_follow_box {
- position: absolute;
- display: none;
- z-index: 1;
- text-align: center;
- opacity: 0.9;
-}
+.o_js_forum_tag_follow {
+ .badge {
+ font-size: 100%;
+ }
-.forum_answer {
- position: relative;
-}
+ .o_forum_tag_follow_box {
+ @include o-position-absolute(100%, auto, auto, 0);
+ display: none;
+ z-index: 1;
-.o_wforum_post_count_answer_count {
- border-left: 3px solid;
+ .card {
+ padding: ($grid-gutter-width*0.5) - 1px;
+ }
+ }
}
.o_profile_main {
@@ -180,44 +197,33 @@ $bronze: #eea91e;
}
img.o_forum_avatar {
- max-height: 40px;
- margin-right: 10px;
- width: auto;
+ @include size(40px);
+ object-fit: cover;
}
img.o_forum_avatar_big {
- max-width: 75px;
- margin-right: 10px;
- width: auto;
+ @include size(75px);
+ object-fit: cover;
}
-.o_forum_user_bio_expand {
- position: absolute;
- display: none;
- z-index: 200;
-}
+.o_wforum_bio_popover_wrap {
+ .o_wforum_bio_popover_name {
+ address > div, span[data-oe-model="res.country"] {
+ display: flex;
+ align-items: center;
+ }
+ span[data-oe-model="res.country"] {
+ margin-left: 10px;
+ }
+ }
-.o_forum_tooltip_heading {
- padding: 0;
- margin: 0;
- font-size: 18px;
-}
+ .o_wforum_bio_popover_info .css_editable_mode_hidden > div:last-child > .o_forum_tooltip_line {
+ margin-top: -0.5rem; // compensate parent 'mt-2' class
+ }
-.o_forum_user_bio {
- color: $black;
- width: 318px;
- min-height: 100px;
- cursor: auto;
- border: 1px solid darkgray;
- background-color: whitesmoke;
- line-height: 13px;
- font-size: 11px;
- word-wrap: break-word;
- .o_forum_tooltip_line {
- min-height: 13px;
- }
- .o_forum_tooltip_header {
- min-height: 75px;
+ .o_wforum_bio_popover_bio p {
+ margin-top: 8px;
+ margin-bottom: 0;
}
}
diff --git a/addons/website_forum/static/tests/tours/website_forum_question.js b/addons/website_forum/static/tests/tours/website_forum_question.js
index 93f22a05e1f..eee77685c82 100644
--- a/addons/website_forum/static/tests/tours/website_forum_question.js
+++ b/addons/website_forum/static/tests/tours/website_forum_question.js
@@ -8,7 +8,7 @@ odoo.define('website_forum.tour_forum_question', function (require) {
url: '/forum/help-1',
}, [{
content: "Ask the question in this forum by clicking on the button.",
- trigger: '.btn-lg.btn-block',
+ trigger: '.o_forum_ask_btn',
}, {
content: "Give your question content.",
trigger: 'input[name=post_name]',
@@ -41,13 +41,13 @@ odoo.define('website_forum.tour_forum_question', function (require) {
trigger: 'button:contains("Post Answer")',
}, {
content: "This page contain new created question and its answer.",
- extra_trigger: '#wrap:has(".fa-check-circle")',
+ extra_trigger: '#wrap:has(".o_wforum_validate_toggler")',
trigger: 'button[data-dismiss="modal"]',
}, {
content: "Click here to accept this answer.",
- trigger: 'a[data-karma="20"]:first',
+ trigger: '.o_wforum_validate_toggler[data-karma="20"]:first',
}, {
content: "Congratulations! You just created and post your first question and answer.",
- trigger: '#wrap:has(".oe_answer_true")',
+ trigger: '#wrap:has(".o_wforum_answer_correct")',
}]);
});
diff --git a/addons/website_forum/views/website_forum.xml b/addons/website_forum/views/website_forum.xml
index 3e0451ee8ea..5eb9e36fdf0 100644
--- a/addons/website_forum/views/website_forum.xml
+++ b/addons/website_forum/views/website_forum.xml
@@ -28,10 +28,10 @@
<!-- helper -->
<template id="link_button">
- <form t-attf-method="#{form_method or 'POST'}" t-att-action="url" t-attf-class="#{form_classes}">
+ <form t-attf-method="#{form_method or 'POST'}" t-att-action="url" t-attf-class="#{form_classes} #{not inDropdown and 'btn btn-sm border'}">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
- <button t-attf-class="#{icon and not label and ('fa ' + icon) or ''} #{inDropdown and 'dropdown-item' or 'btn btn-link'} #{classes} #{karma and 'karma_required text-muted' or ''}" t-attf-data-karma="#{karma}" t-att-title="title">
- <i t-if="icon and label" t-attf-class="fa #{icon}"/>
+ <button t-attf-class="#{icon and not label and ('fa ' + icon)} #{inDropdown and 'dropdown-item pl-3' or 'btn btn-sm p-0'} #{classes} #{karma and 'karma_required text-muted'}" t-attf-data-karma="#{karma}" t-att-title="title">
+ <i t-if="icon and label" t-attf-class="fa fa-fw text-muted #{icon} #{inDropdown and 'mr-1'}"/>
<t t-esc="label"/>
</button>
</form>
@@ -50,83 +50,67 @@
<!-- Page Index -->
<template id="header" name="Forum Index">
<t t-if="forum.active" t-call="website_forum.layout">
- <div t-if="is_public_user and not forum_welcome_message" class="forum_intro">
- <div t-field="forum.welcome_message"/>
- </div>
+ <section t-attf-class="s_cover parallax s_parallax_is_fixed py-3 #{forum.image_1920 and 'bg-black-50' or 'o_wforum_forum_card_bg text-white'}" data-scroll-background-ratio="1">
+ <span t-if="forum.image_1920" class="s_parallax_bg oe_img_bg oe_custom_bg" t-attf-style="background-image: url('#{website.image_url(forum, 'image_1920')}'); background-position: center;"/>
+ <div class="container">
+ <div class="row s_nb_column_fixed">
+ <div class="col-lg-12 s_title" data-name="Title">
+ <h1 class="s_title_thin o_default_snippet_text text-center"><t t-esc="forum.name"></t></h1>
+ </div>
+ </div>
+ <div t-if="is_public_user and not forum_welcome_message" class="forum_intro">
+ <div t-field="forum.welcome_message"/>
+ </div>
+ </div>
+ </section>
- <div class="o_forum_nav_header_container mb-4">
+ <div class="o_forum_nav_header_container mb-2 mb-md-4">
<t t-call="website_forum.forum_nav_header"></t>
</div>
<div id="wrap" t-attf-class="container #{website_forum_action}">
<div class="row">
- <div class="col o_wprofile_email_validation_container mb16 mt16 col-lg-9">
+ <div class="col o_wprofile_email_validation_container mb16">
<t t-call="website_profile.email_validation_banner">
<t t-set="redirect_url" t-value="'/forum/%s' % forum.id"/>
<t t-set="send_validation_email_message" t-value="'Click here to send a verification email allowing you to participate to the forum.'"/>
<t t-set="additional_validated_email_message" t-value="' You may now participate to our forums.'"/>
</t>
- <t t-raw="0"/>
- </div>
- <div class="col-lg-3" id="right-column" t-if="not is_profile_page">
- <a role="button" type="button" class="btn btn-primary btn-lg btn-block mb-3" t-attf-href="/forum/#{slug(forum)}/ask">Ask a Question</a>
- <div class="card bg-secondary" t-if="question">
- <h6 class="card-header"><b>Writer</b></h6>
- <div class="card-body o_card_people">
- <img class="o_wforum_people_photo_container d-block mx-auto mb-3" t-att-src="website.image_url(question.create_uid, 'image_128')"/>
- <h6 class="text-center">
- <b><i class="fa fa-diamond text-secondary"/> <t t-esc="question.create_uid.sudo().karma"/></b>
- <b><a t-attf-href="/forum/#{slug(forum)}/user/#{question.create_uid.sudo().id}" t-field="question.create_uid" t-options='{"widget": "contact", "fields": ["name", "country_id"]}'/></b>
- </h6>
- </div>
- </div>
- <div class="card my-3 bg-secondary" t-if="question and not len(question.tag_ids)&lt;=0">
- <h6 class="card-header">
- <b>
- <t t-if="len(question.tag_ids)&lt;=1">
- Tag
- </t>
- <t t-else="">
- Tags
- </t>
- </b>
- </h6>
- <div class="card-body">
- <t t-foreach="question.tag_ids" t-as="tag">
- <a t-attf-href="/forum/#{ slug(forum) }/tag/#{ tag.id }/questions" class="badge badge-primary" t-field="tag.name"/>
- </t>
- </div>
- </div>
- <div class="card my-3 bg-secondary" t-if="question">
- <h6 class="card-header"><b>Keep Informed</b></h6>
- <div class="card-body o_subscribe_post">
- <t t-call="website_mail.follow">
- <t t-set="object" t-value="question"/>
- <t t-set="div_class" t-value="'mx-auto'"/>
- </t>
- <div class="text-center mt-3">
- <strong><t t-raw="len(question.message_follower_ids)"/> follower(s)</strong>
- </div>
- </div>
- </div>
- <div class="card my-3 bg-secondary" id="about_forum">
- <h6 class="card-header"><b>About This Community</b></h6>
- <div class="card-body">
- <span t-field="forum.description"/>
- <a t-if="not header.get('is_guidelines')" t-attf-href="/forum/#{slug(forum)}/faq" class="btn btn-primary mt-3">Read Guidelines</a>
- <a t-if="header.get('is_guidelines')" t-attf-href="/forum/#{slug(forum)}" class="btn btn-primary mt-3"> Back to <span t-field="forum.name"/></a>
- </div>
- </div>
- <div class="card my-3 bg-secondary" id="moderation_tools" t-if="user.karma>=forum.karma_moderate">
- <h6 class="card-header"><b>Moderation Tools</b></h6>
- <div class="card-body">
- <a t-attf-href="/forum/#{slug(forum)}/validation_queue" class="text-dark"><i class="fa fa-check-square-o mr-2 text-primary"/><strong><t t-esc="forum.count_posts_waiting_validation"/></strong> waiting for validation</a>
- <hr style="margin-top:4px;margin-bottom:0;padding-bottom:4px;" />
- <a t-attf-href="/forum/#{slug(forum)}/flagged_queue" class="text-dark"><i class="fa fa-flag mr-2 text-primary"/><strong id="count_flagged_posts"><t t-esc="forum.count_flagged_posts"/></strong> post<t t-if="forum.count_flagged_posts&gt;1">s</t> flagged</a>
+ <div class="row">
+ <div class="col">
+ <nav t-if="header.get('is_guidelines') or queue_type or new_question or is_edit or tags or reasons" aria-label="breadcrumb">
+ <ol class="breadcrumb p-0 bg-white">
+ <li class="breadcrumb-item">
+ <a t-attf-href="/forum/#{ slug(forum) }" t-esc="forum.name"/>
+ </li>
+ <li t-if="header.get('is_guidelines')" class="breadcrumb-item">Guidelines</li>
+ <li t-if="queue_type" class="breadcrumb-item">Moderation</li>
+ <li t-if="queue_type == 'validation'" class="breadcrumb-item">To Validate</li>
+ <li t-if="queue_type == 'flagged'" class="breadcrumb-item">Flagged</li>
+ <li t-if="queue_type == 'offensive'" class="breadcrumb-item">Offensive</li>
+ <li t-if="reasons and offensive" class="breadcrumb-item">Offensive Post</li>
+ <li t-if="reasons and not offensive" class="breadcrumb-item">Close post</li>
+ <li t-if="new_question" class="breadcrumb-item">Ask a Question</li>
+ <t t-if="is_edit">
+ <t t-set="target" t-value="post.parent_id if is_answer else post"/>
+ <li class="breadcrumb-item text-truncate" style="max-width:150px">
+ <a t-attf-href="/forum/#{ slug(forum) }/question/#{ slug(target)}" title="Back to Question">
+ <t t-esc="target.name"/>
+ </a>
+ </li>
+ <li t-if="not is_answer" class="breadcrumb-item">Edit Question</li>
+ <li t-if="is_answer" class="breadcrumb-item">Edit Answer</li>
+ </t>
+ <li t-elif="tags" class="breadcrumb-item">All Tags</li>
+ </ol>
+ </nav>
+ <t t-raw="0"/>
</div>
+ <aside t-if="uid" class="d-none d-lg-flex justify-content-end col-auto">
+ <t t-call="website_forum.user_sidebar"/>
+ </aside>
</div>
</div>
-
</div>
</div>
<div class="oe_structure" id="oe_structure_website_forum_header_1"/>
@@ -142,131 +126,217 @@
</template>
<template id="forum_nav_header">
- <div class="navbar navbar-expand-md navbar-light">
- <div class="container">
- <a class="navbar-brand" t-attf-href="/forum/#{slug(forum)}">
- <span t-field="forum.name"/>
- </a>
- <button type="button" class="navbar-toggler" data-toggle="collapse" data-target="#oe-help-navbar-collapse">
- <span class="navbar-toggler-icon"/>
- </button>
- <div class="collapse navbar-collapse" id="oe-help-navbar-collapse">
- <ul class="navbar-nav">
- <li class="nav-item">
- <a t-attf-href="/forum/#{ slug(forum) }?{{ keep_query( 'search', 'filters', sorting='relevancy desc') }}"
- t-attf-class="nav-link #{sorting == 'relevancy desc' and 'active' or ''}">Trending</a>
- </li>
- <li class="nav-item">
- <a t-attf-href="/forum/#{ slug(forum) }?{{ keep_query( 'search', 'filters', sorting='create_date desc') }}"
- t-attf-class="nav-link #{sorting == 'create_date desc' and 'active' or ''}">Newest</a>
- </li>
- <li class="nav-item">
- <a t-attf-href="/profile/users"
- t-attf-class="nav-link #{searches.get('users') and 'active' or ''}">People</a>
- </li>
- <li class="nav-item">
- <a t-attf-href="/forum/#{ slug(forum) }/tag"
- t-attf-class="nav-link #{searches.get('tags') and 'active' or ''}">Tags</a>
- </li>
- <li class="nav-item">
- <a t-attf-href="/profile/ranks_badges?badge_category=forum"
- t-attf-class="nav-link #{searches.get('badges') and 'active' or ''}">Badges</a>
- </li>
- <li class="nav-item" t-if="user.karma >= forum.karma_moderate">
- <a t-attf-href="/forum/#{ slug(forum) }/flagged_queue"
- t-attf-class="nav-link #{flagged_queue_active and 'active' or ''}">Spam</a>
- </li>
- </ul>
- <ul class="navbar-nav ml-auto">
- <li t-if="not is_public_user" class="nav-item">
- <a t-attf-href="/profile/user/#{uid}?forum_id=#{forum.id}" t-attf-class="text-dark font-weight-bold nav-link#{searches.get('my_profile') and ' active' or ''}">
- <i class="fa fa-diamond text-secondary" /> <t t-esc="user_id.karma"/>
- </a>
- </li>
- </ul>
- <form class="form-inline" role="search" t-attf-action="/forum/#{ slug(forum) }" method="get">
- <t t-call="website.website_search_box"/>
- <div class="dropdown ml-1" groups="base.group_erp_manager">
- <button class="btn btn-primary dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown">
- <i class="fa fa-cog" role="img" aria-label="Dropdown menu" title="Dropdown menu"/>
- </button>
- <div class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
- <a role="menuitem" tabindex="-1" t-attf-href="/forum/#{slug(forum)}/edit_welcome_message?enable_editor=1" class="dropdown-item">Design Welcome Message</a>
- <a role="menuitem" tabindex="-1" t-attf-href="/web#id=#{forum.id}&amp;view_type=form&amp;model=forum.forum" class="dropdown-item">Forum Settings</a>
- </div>
- </div>
- </form>
- </div>
- </div>
+ <div class="navbar navbar-expand-sm navbar-light">
+ <div class="container flex-wrap flex-md-nowrap">
+ <a t-if="request.website.forums_count > 1" class="btn btn-light border mr-2" href="/forum/" title="All forums">
+ <i class="fa fa-chevron-left mr-1"/>All Forums
+ </a>
+
+ <!-- Desktop -->
+ <ul class="navbar-nav mr-auto d-none d-lg-flex">
+ <li class="nav-item">
+ <a t-attf-href="/forum/#{ slug(forum) }" t-attf-class="nav-link #{question_count and 'active'}">Topics</a>
+ </li>
+ <li class="nav-item">
+ <a t-attf-href="/profile/users?forum_origin=#{request.httprequest.path}"
+ t-attf-class="nav-link #{searches.get('users') and 'active'}">People</a>
+ </li>
+ <li class="nav-item">
+ <a t-attf-href="/forum/#{ slug(forum) }/tag" t-attf-class="nav-link #{searches.get('tags') and 'active'}">Tags</a>
+ </li>
+ <li class="nav-item">
+ <a t-attf-href="/profile/ranks_badges?badge_category=forum" t-attf-class="nav-link #{searches.get('badges') and 'active'}">Badges</a>
+ </li>
+ <li class="nav-item">
+ <a t-attf-href="/forum/#{ slug(forum) }/faq" t-attf-class="nav-link #{header.get('is_guidelines') and 'active'}">About</a>
+ </li>
+ <span class="navbar-text" groups="base.group_erp_manager">|</span>
+ <li class="nav-item dropdown mx-auto" groups="base.group_erp_manager">
+ <a class="nav-link dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown">
+ <i class="fa fa-cog" role="img"/> Settings
+ </a>
+ <div class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
+ <a role="menuitem" tabindex="-1" t-attf-href="/forum/#{slug(forum)}/edit_welcome_message?enable_editor=1" class="dropdown-item">Design Welcome Message</a>
+ <a role="menuitem" tabindex="-1" t-attf-href="/web#id=#{forum.id}&amp;view_type=form&amp;model=forum.forum" class="dropdown-item">Edit Forum in the backend</a>
+ </div>
+ </li>
+ </ul>
+
+ <!-- Mobile -->
+ <ul class="navbar-nav d-lg-none flex-row flex-grow-1 justify-content-between">
+ <span class="navbar-text mr-1">Go to:</span>
+ <li class="nav-item dropdown mr-auto">
+ <a class="nav-link active dropdown-toggle" type="button" data-toggle="dropdown">
+ <t t-if="searches.get('users')">People</t>
+ <t t-elif="searches.get('tags')">Tags</t>
+ <t t-elif="searches.get('badges')">Badges</t>
+ <t t-elif="header.get('is_guidelines')">About</t>
+ <t t-elif="uid and my == 'favourites'">Favourites</t>
+ <t t-elif="uid and my == 'mine'">My questions</t>
+ <t t-elif="uid and my == 'followed'">Following</t>
+ <t t-elif="question">Question</t>
+ <t t-else="">All Topics</t>
+ </a>
+ <div class="dropdown-menu position-absolute">
+ <a t-if="searches or my or question" t-attf-href="/forum/#{ slug(forum) }" class="dropdown-item">All Topics</a>
+ <a t-if="not searches.get('users')" t-attf-href="/profile/users?forum_origin=#{request.httprequest.path}" class="dropdown-item">People</a>
+ <a t-if="not searches.get('tags')" t-attf-href="/forum/#{slug(forum)}/tag" class="dropdown-item">Tags</a>
+ <a t-if="not searches.get('badges')" t-attf-href="/profile/ranks_badges?badge_category=forum" class="dropdown-item">Badges</a>
+ <a t-if="not header.get('is_guidelines')" t-attf-href="/forum/#{ slug(forum) }/faq" class="dropdown-item">About</a>
+ <t t-if="uid">
+ <div class="dropdown-divider"/>
+ <a t-att-href="'/forum/%s/user/%s?forum_origin=%s' % (slug(forum), uid, request.httprequest.path)"
+ class="dropdown-item">My profile</a>
+ <a t-if="my != 'mine'" t-att-href="url_for('') + '?' + keep_query( 'search', 'sorting', 'filters', my='mine')" class="dropdown-item">My Questions</a>
+ <a t-if="my != 'favourites'" t-att-href="url_for('') + '?' + keep_query( 'search', 'sorting', 'filters', my='favourites')" class="dropdown-item">My Favourites</a>
+ <a t-if="my != 'followed'" t-att-href="url_for('') + '?' + keep_query( 'search', 'sorting', 'filters', my='followed')" class="dropdown-item">I'm Following</a>
+ <a t-if="my != 'tagged'" t-att-href="url_for('') + '?' + keep_query( 'search', 'sorting', 'filters', my='tagged')" class="dropdown-item">Tags I Follow</a>
+ </t>
+ <div groups="base.group_erp_manager" class="dropdown-divider"/>
+ <a groups="base.group_erp_manager" t-attf-href="/web#id=#{forum.id}&amp;view_type=form&amp;model=forum.forum" class="dropdown-item">Edit Forum in Backend</a>
+ </div>
+ </li>
+ <t t-if="user.karma>=forum.karma_moderate">
+ <li t-if="forum.count_posts_waiting_validation" class="nav-item">
+ <a class="nav-link" t-attf-href="/forum/#{slug(forum)}/validation_queue">
+ <i class="fa fa-check-square-o fa-fw text-warning"/>
+ <b t-esc="forum.count_posts_waiting_validation" class="text-800"/>
+ </a>
+ </li>
+ <li t-if="forum.count_flagged_posts" class="nav-item ml-2">
+ <a class="nav-link" t-attf-href="/forum/#{slug(forum)}/flagged_queue">
+ <i class="fa fa-flag fa-fw text-danger"/>
+ <b t-esc="forum.count_flagged_posts" class="text-800"/>
+ </a>
+ </li>
+ </t>
+ <!-- Mobile 'Search Box' toggler-->
+ <li class="nav-item ml-4">
+ <a data-toggle="collapse" href="#o_wforum_search" class="nav-link"><i class="fa fa-search"/></a>
+ </li>
+ </ul>
+
+ <!-- 'Search Box' -->
+ <form id="o_wforum_search" class="form-inline collapse w-100 w-md-auto pt-2 pt-md-0 d-md-flex"
+ role="search" t-attf-action="#{url_for('/forum/')}#{slug(forum)}#{tag and ('/tag/%s/questions' % slug(tag))}" method="get">
+ <t t-call="website.website_search_box">
+ <t t-set="_classes">w-100</t>
+ </t>
+
+ <input t-if="filters" type="hidden" name="filters" t-att-value="filters"/>
+ <input t-if="my" type="hidden" name="my" t-att-value="my"/>
+ <input t-if="sorting" type="hidden" name="sorting" t-att-value="sorting"/>
+ </form>
</div>
+ </div>
</template>
<!-- Template use to edit the welcome_message -->
<template id="edit_welcome_message">
<t t-call="website.layout">
- <div t-field="forum.welcome_message"/>
+ <section t-attf-class="s_cover parallax s_parallax_is_fixed py-3 #{forum.image_1920 and 'bg-black-50' or 'o_wforum_forum_card_bg text-white'}" data-scroll-background-ratio="1">
+ <span t-if="forum.image_1920" class="s_parallax_bg oe_img_bg oe_custom_bg" t-attf-style="background-image: url('#{website.image_url(forum, 'image_1920')}'); background-position: center;"/>
+ <div class="container">
+ <div class="row s_nb_column_fixed">
+ <div class="col-lg-12 s_title" data-name="Title">
+ <h1 class="s_title_thin o_default_snippet_text text-center"><t t-esc="forum.name"></t></h1>
+ </div>
+ </div>
+ <div class="forum_intro">
+ <div t-field="forum.welcome_message"/>
+ </div>
+ </div>
+ </section>
</t>
</template>
<!-- Display a post -->
<template id="display_post_question_block">
- <div t-if="question.has_validated_answer" class="validate_answer">
- <div class="bg-success"></div>
- <span title="Question has accepted answer" role="img" aria-label="Question has accepted answer"><i class="fa fa-check-circle text-success bg-white"/></span>
+ <div class="o_wforum_index_entry_title">
+ <div class="d-inline-block mb-0 h5">
+ <span t-if="question.has_validated_answer and filters != 'solved'"
+ title="Solved"
+ aria-label="Solved"
+ data-toggle="tooltip"
+ class="fa fa-check-circle text-success"/>
+ <span t-if="question.user_favourite and not (my == 'favourites' or hide_fav_icon)"
+ title="Your favourite"
+ aria-label="Your favourite"
+ data-toggle="tooltip"
+ class="fa fa-star o_wforum_gold"/>
+
+ <a t-attf-href="/forum/#{slug(question.forum_id)}/question/#{slug(question)}#{answer and ('/#answer-%s' % answer.id)}"
+ t-attf-title="Read: #{question.name}"
+ class="text-reset"
+ t-esc="question.name"/>
+ </div>
+ <span t-if="not question.active" class="text-muted">
+ <t t-if="question.state!='offensive'"> [Deleted]</t>
+ <t t-if="question.state=='offensive'"> [Offensive]</t>
+ <t t-if="question.state=='offensive' and question.closed_reason_id">
+ [<t t-esc="question.closed_reason_id.name[0].upper() + question.closed_reason_id.name[1:]"/>]
+ </t>
+ </span>
+ <span t-if="question.state == 'close'" class="text-muted"> [Closed]</span>
</div>
- <div class="col">
- <div class="row">
- <div class="col-12">
- <t t-foreach="question.tag_ids" t-as="question_tag">
- <a t-attf-href="/forum/#{ slug(question_tag.forum_id) }/tag/#{slug(question_tag)}/questions">
- <span t-attf-class="float-right mb-1 mr-1 badge #{tag and tag.name == question_tag.name and 'badge-primary' or 'badge-secondary'}" t-field="question_tag.name"/>
- </a>
- </t>
- </div>
- <div class="col">
- <div class="question-name">
- <a t-attf-href="/forum/#{ slug(question.forum_id) }/question/#{ slug(question) }">
- <h4 t-field="question.name" class="d-inline"/>
- </a>
- <span t-if="not question.active and question.state!='offensive'"><b> [Deleted]</b></span>
- <span t-if="not question.active and question.state=='offensive'"><b> [Offensive]</b></span>
- <span t-if="not question.active and question.state=='offensive' and question.closed_reason_id"><b> [<t t-esc="question.closed_reason_id.name[0].upper() + question.closed_reason_id.name[1:]"/>]</b></span>
- <span t-if="question.state == 'close'"><b> [Closed]</b></span>
- </div>
- <div><t t-raw="post_content"/></div>
- <small class="text-muted">
- <i t-attf-class="fa fa-question-circle" role="img" aria-label="Question" />
- <span>By </span><span t-field="question.create_uid" t-options='{"widget": "contact", "country_image": True, "fields": ["name", "country_id"]}' class="d-inline-block"/>
- <span class="ml-4 mr-1 fa fa-calendar"></span><span t-field="question.write_date" t-options='{"format":"short"}'/>
- <span class="ml-4 mr-1 fa fa-eye"></span><span t-field="question.views" /> <t t-if="question.views&lt;=1">View</t><t t-else="">Views</t>
- <i class="ml-4 fa fa-comments text-primary"/>
- <a t-attf-href="/forum/#{ slug(question.forum_id) }/question/#{ slug(question) }">
- <t t-esc="question.child_count"/>
- <t t-if="question.child_count&lt;=1">Answer</t>
- <t t-else="">Answers</t>
- </a>
- <a t-attf-href="/forum/#{ slug(question.forum_id) }/question/#{ slug(question) }">
- <span class="ml-4 mr-1 fa fa-star"></span><span t-field="question.favourite_count"/> <t t-if="question.views&lt;=1">Favorite</t><t t-else="">Favorites</t>
- </a>
- <span t-if="question.state == 'flagged'" class="text-black">
- <i class="fa fa-flag ml-4 mr4"/>
- Flagged
- </span>
- </small>
- </div>
+
+ <div t-attf-class="o_wforum_index_entry_tags mb-1" t-if="len(question.tag_ids) > 0">
+ <t t-foreach="question.tag_ids" t-as="question_tag">
+
+ <!-- Toggle Tags on click -->
+ <t t-if="tag and tag.name == question_tag.name" t-set="click_action"
+ t-value="'/forum/' + slug(question_tag.forum_id) + '?' + keep_query( 'search', 'sorting', 'my')"/>
+ <t t-else="" t-set="click_action"
+ t-value="'/forum/' + slug(question_tag.forum_id) + '/tag/' + slug(question_tag) + '/questions?' + keep_query( 'search', 'sorting', 'my', filters='tag')"/>
+
+ <a t-att-href="click_action"
+ t-attf-class="badge #{tag and tag.name == question_tag.name and 'badge-secondary' or 'border text-600 badge-light'} #{ not question_tag_first and 'ml-lg-1 mt-lg-1'}"
+ t-field="question_tag.name"/>
+ </t>
+ </div>
+
+ <div class="d-flex align-items-center justify-content-between justify-content-sm-start small text-muted">
+ <div>
+ <t t-call="website_forum.vote">
+ <t t-set="post" t-value="question"/>
+ </t>
+ <span t-field="question.write_date" t-options='{"format": "d MMMM y"}'/>, by <a t-attf-href="/forum/#{slug(question.forum_id)}/user/#{question.create_uid.id}?forum_origin=#{request.httprequest.path}" t-field="question.create_uid" class="d-inline-block font-weight-bold" t-options='{"widget": "contact", "fields": ["name"]}'/>
+ </div>
+ <div>
+ <span class="mx-1 d-none d-sm-inline">&amp;nbsp;|</span>
+ <a t-if="len(question.child_ids)&gt;0" class="font-weight-bold" t-attf-href="/forum/#{ slug(question.forum_id) }/question/#{ slug(question) }">
+ <t t-esc="question.child_count"/>
+ <t t-if="question.child_count == 1">Answer</t>
+ <t t-else="">Answers</t>
+ </a>
+ <span t-else="">
+ 0 Answers
+ </span>
+ <span class="d-none d-sm-inline">
+ <span class="mx-1">|</span>
+ <span t-field="question.views" /> <t t-if="question.views&lt;=1">View</t><t t-else="">Views</t>
+ <span t-if="question.favourite_count &gt; 0">
+ <span class="mx-1">|</span>
+ <i class="fa fa-star"/>
+ <t t-esc="question.favourite_count"/>
+ </span></span>
+ <span t-if="question.state == 'flagged'" class="text-black"> | Flagged</span>
</div>
</div>
+ <!-- Display post's content in moderation mode-->
+ <div><t t-raw="post_content"/></div>
</template>
<template id="display_post">
- <div class="card">
- <div class="card-body">
- <div class="row">
- <div class="col-1">
- <t t-call="website_forum.vote">
- <t t-set="post" t-value="question"/>
- </t>
- </div>
+ <div t-attf-class="#{show_author_avatar and 'mt-2 mb-4' or 'card py-2 px-3'}">
+ <div class="media">
+ <div t-if="show_author_avatar">
+ <t t-call="website_forum.author_box">
+ <t t-set="object" t-value="question"/>
+ <t t-set="allow_biography" t-value="True"/>
+ </t>
+ </div>
+ <div t-attf-class="media-body #{show_author_avatar and 'pl-2'}">
<t t-call="website_forum.display_post_question_block"/>
</div>
</div>
@@ -275,23 +345,8 @@
<!-- Display a post as an answer -->
<template id="display_post_answer">
- <div class="card mb-2">
- <div class="card-body">
- <div class="row">
- <div class="col-1 text-center mb-2">
- <div t-attf-class="#{len(answer.vote_ids) and 'oe_green' or 'oe_grey'}" t-esc="len(answer.vote_ids)"/>
- </div>
- <div class="question-name col">
- <a style="font-size: 15px;" t-attf-href="/forum/#{ slug(answer.forum_id) }/question/#{ answer.parent_id.id }/#answer-#{ answer.id }" t-esc="answer.parent_id.name"/>
- <t t-if="len(answer.website_message_ids)&gt;0">
- (<t t-esc="len(answer.website_message_ids)"/>
- <t t-if="len(answer.website_message_ids)&gt;1"> Comments</t>
- <t t-if="len(answer.website_message_ids)&lt;=1"> Comment</t>)
- </t>
- </div>
- </div>
- </div>
- </div>
+ <t t-set="question" t-value="answer"/>
+ <t t-call="website_forum.display_post"/>
</template>
<!-- Moderation tools -->
@@ -330,6 +385,7 @@
<!-- FAQ Layout -->
<template id="faq" name="Frequently Asked Questions">
<t t-call="website_forum.header">
+ <div t-field="forum.description" class="mb-4"/>
<div t-field="forum.faq"/>
<div class="card mb-2">
<a href="#collapseFour" class="card-header" id="headingFour" data-toggle="collapse" aria-expanded="false" aria-controls="collapseFour">
@@ -390,21 +446,16 @@
<t t-set="pageName" t-value="'website_forum'"/>
<div id="wrap">
<div class="oe_structure oe_empty" id="oe_structure_forum_all_top"/>
- <div class="container pt-4">
+ <div class="container pt-4 pb-5">
<div t-if="forums" class="row">
<div t-foreach="forums.with_context(bin_size=True)" t-as="forum"
- class="col-sm-6 col-md-3 mb-4">
- <a t-attf-href="/forum/#{slug(forum)}" class="d-block">
- <div class="card border-0 shadow-sm">
- <h1 class="card-header h6 font-weight-bold bg-white"
- t-field="forum.name"/>
- <div class="card-img-bottom embed-responsive embed-responsive-16by9 o_wforum_forum_card_bg">
- <div t-if="forum.image_256"
- class="oe_img_bg embed-responsive-item"
- t-attf-style="background-image: url(#{website.image_url(forum, 'image_256')}); background-position: center;"/>
- </div>
- </div>
+ class="col-sm-6 col-lg-4 col-xl-3 mb-3 mb-lg-5">
+ <a t-attf-href="/forum/#{slug(forum)}" class="text-reset">
+ <h2 class="h5" t-field="forum.name"/>
+ <div class="oe_img_bg rounded shadow-sm mb-2 py-5 o_wforum_forum_card_bg"
+ t-attf-style="#{forum.image_256 and ('background-image: url(%s);' % website.image_url(forum, 'image_256'))} background-position: center;"/>
</a>
+ <div class="text-muted" t-if="forum.description" t-esc="forum.description"/>
</div>
</div>
<t t-else="">
@@ -421,15 +472,15 @@
<template id="forum_all_oe_structure_forum_all_top" inherit_id="website_forum.forum_all" name="Forum Navigation (oe_structure_forum_all_top)">
<xpath expr="//*[hasclass('oe_structure')][@id='oe_structure_forum_all_top']" position="replace">
<div class="oe_structure oe_empty" id="oe_structure_forum_all_top">
- <section class="s_cover parallax s_parallax_is_fixed bg-black-50 pt64 pb64" data-scroll-background-ratio="1">
+ <section class="s_cover parallax s_parallax_is_fixed bg-black-50 py-5" data-scroll-background-ratio="1">
<span class="s_parallax_bg oe_img_bg oe_custom_bg" style="background-image: url('/web/image/website.s_cover_default_image'); background-position: 50% 0;"/>
<div class="container">
<div class="row s_nb_column_fixed">
<div class="col-lg-12 s_title" data-name="Title">
<h1 class="s_title_thin o_default_snippet_text text-center">Our forums</h1>
</div>
- <div class="col-lg-12 s_text pt16 pb16" data-name="Text">
- <p class="lead o_default_snippet_text" style="text-align: center;">
+ <div class="col-lg-12 s_text" data-name="Text">
+ <p class="lead o_default_snippet_text mb-0" style="text-align: center;">
This community is for professional and enthusiast users, partners and programmers.
</p>
</div>
@@ -440,46 +491,260 @@
</xpath>
</template>
+<template id="website_forum.user_sidebar">
+ <nav t-if="uid" class="o_wforum_nav nav nav-pills flex-column ml-4">
+ <a t-attf-href="/forum/#{slug(forum)}/user/#{uid}?forum_origin=#{request.httprequest.path}"
+ class="nav-link d-flex align-items-center rounded-pill text-reset mb-2"
+ data-toggle="tooltip"
+ data-trigger="hover"
+ title="My profile">
+ <img class="rounded-circle mr-1" t-att-src="website.image_url(user, 'image_128', '30x30')" alt="Avatar"/>
+ <div>
+ <h6 class="my-0" t-esc="user_id.name"/>
+ <small class="text-muted font-weight-bold"><t t-esc="user_id.karma"/>xp</small>
+ </div>
+ </a>
+
+ <t t-set="location" t-value="url_for('/forum/') + slug(forum) + ( ('/tag/' + slug(tag) + '/questions?') if tag else '?' )"/>
+
+ <!-- My Questions -->
+ <span t-if="my == 'mine'" class="nav-link rounded-pill mb-2 active font-weight-bold">
+ <i class="fa fa-question-circle-o fa-fw"/> My Questions
+ <a class="text-reset pull-right no-decoration" t-att-href="location + keep_query('search', 'filters', 'sorting')">&#215;</a>
+ </span>
+ <a t-else="" class="nav-link rounded-pill mb-2 text-reset" t-att-href="location + keep_query('search', 'filters', 'sorting', my='mine')">
+ <i class="fa fa-question-circle-o fa-fw"/> My Questions
+ </a>
+
+ <!-- My Favourites -->
+ <span t-if="my == 'favourites'" class="nav-link rounded-pill mb-2 active font-weight-bold">
+ <i class="fa fa-star fa-fw"/> Favourites
+ <a class="text-reset pull-right no-decoration" t-att-href="location + keep_query( 'search', 'filters', 'sorting')">&#215;</a>
+ </span>
+ <a t-else="" t-attf-class="nav-link rounded-pill mb-2 text-reset" t-att-href="location + keep_query( 'search', 'filters', 'sorting', my='favourites')">
+ <i class="fa fa-star fa-fw"/> Favourites
+ </a>
+
+ <!-- My Followed posts -->
+ <span t-if="my == 'followed'" class="nav-link rounded-pill mb-2 active font-weight-bold">
+ <i class="fa fa-bell fa-fw"/> Followed Posts
+ <a class="text-reset pull-right no-decoration" t-att-href="location + keep_query( 'search', 'filters', 'sorting')">&#215;</a>
+ </span>
+ <a t-else="" class="nav-link rounded-pill mb-2 text-reset" t-att-href="location + keep_query( 'search', 'filters', 'sorting', my='followed')">
+ <i class="fa fa-bell fa-fw"/> Followed Posts
+ </a>
+
+ <!-- My Followed tags -->
+ <span t-if="my == 'tagged'" class="nav-link rounded-pill mb-2 active font-weight-bold">
+ <i class="fa fa-tags fa-fw"/> Followed Tags
+ <a class="text-reset pull-right no-decoration" t-att-href="location + keep_query( 'search', 'filters', 'sorting')">&#215;</a>
+ </span>
+ <a t-else="" class="nav-link rounded-pill mb-2 text-reset" t-att-href="location + keep_query( 'search', 'filters', 'sorting', my='tagged')">
+ <i class="fa fa-tags fa-fw"/> Followed Tags
+ </a>
+
+ <!-- Moderation Tools -->
+ <t t-if="user.karma>=forum.karma_moderate or queue_type">
+ <span class="nav-link disabled mt-3">
+ <div class="pb-1 border-bottom text-muted">Moderation tools</div>
+ </span>
+
+ <span t-if="queue_type == 'validation'" class="nav-link rounded-pill mb-2 active font-weight-bold">
+ <i class="fa fa-check-square-o fa-fw"/> To Validate
+ <a class="text-reset pull-right no-decoration" t-attf-href="/forum/#{ slug(forum) }">&#215;</a>
+ </span>
+ <a t-else="" class="nav-link rounded-pill text-reset" t-attf-href="/forum/#{slug(forum)}/validation_queue">
+ <i class="fa fa-check-square-o fa-fw"/> To Validate
+ <span t-attf-class="badge pull-right #{forum.count_posts_waiting_validation > 0 and 'badge-warning' or 'badge-light'}" t-esc="forum.count_posts_waiting_validation"/>
+ </a>
+ <span t-if="queue_type == 'offensive' or queue_type == 'flagged'" class="nav-link rounded-pill mb-2 active font-weight-bold">
+ <i class="fa fa-flag fa-fw"/> Flagged
+ <a class="text-reset pull-right no-decoration" t-attf-href="/forum/#{ slug(forum) }">&#215;</a>
+ </span>
+ <a t-else="" class="nav-link rounded-pill text-reset" t-attf-href="/forum/#{slug(forum)}/flagged_queue">
+ <i class="fa fa-flag fa-fw"/> Flagged
+ <span t-attf-class="badge pull-right #{forum.count_flagged_posts > 0 and 'badge-danger' or 'badge-light'}" t-esc="forum.count_flagged_posts"/>
+ </a>
+ </t>
+ </nav>
+</template>
+
+
<!-- Specific Forum Layout -->
<template id="forum_index" name="Forum">
<t t-call="website_forum.header">
- <h2 class="o_page_header">
- <t t-esc="question_count"/>
- Questions
- <t t-esc="search"/>
- <small class="dropdown d-block float-right" t-if="filters in ('all', 'unanswered','followed', 'tag')">
- <h6 class="m-0">
- <a href="#" class="dropdown-toggle btn btn-primary" data-toggle="dropdown">
- <t t-if="filters == 'unanswered'"> Unanswered</t>
- <t t-elif="filters == 'followed'"> Followed</t>
- <t t-elif="tag"> <span t-field="tag.name"/></t>
-
- <t t-if="sorting == 'relevancy desc'"> by relevance</t>
- <t t-elif="sorting == 'write_date desc'"> by activity date</t>
- <t t-elif="sorting == 'create_date desc'"> by newest</t>
- <t t-elif="sorting == 'child_count desc'"> by most answered</t>
- <t t-elif="sorting == 'vote_count desc'"> by most voted</t>
+ <div class="row no-gutters">
+ <div t-attf-class="d-flex justify-content-end flex-md-grow-1 #{(search or tag or my) and 'col-12 flex-column-reverse flex-md-row mb-3' or 'col-md-auto order-md-3'}">
+ <div t-if="search or tag or my" class="d-flex flex-wrap align-items-center flex-grow-1">
+ <span t-if="search" class="w-100 w-md-auto mb-2 mb-md-0 border rounded pl-2 d-inline-flex align-items-center justify-content-between">
+ <em class="bg-light px-2" t-esc="search"/>
+ <a t-att-href="url_for('') + '?' + keep_query( 'filters', 'sorting', 'my')" class="btn py-1">&#215;</a>
+ </span>
+ <span t-if="my" t-attf-class="w-100 w-md-auto mb-2 mb-md-0 border rounded pl-2 d-inline-flex align-items-center justify-content-between #{search and 'ml-md-2'}">
+ <div>
+ <img t-if="uid" class="rounded-circle mr-1" t-att-src="website.image_url(user, 'image_128', '16x16')" alt="Avatar"/>
+ <span t-if="my == 'favourites'"> My <b>Favourites</b></span>
+ <span t-elif="my == 'followed'"> I'm <b>Following</b></span>
+ <span t-elif="my == 'mine'"> My <b>Questions</b></span>
+ <span t-elif="my == 'tagged'"> <b>Tags</b> I Follow</span>
+ </div>
+ <a t-att-href="url_for('') + '?' + keep_query( 'search', 'filters', 'sorting')" class="btn py-1">&#215;</a>
+ </span>
+ <span t-if="tag" t-attf-class="w-100 w-md-auto mb-2 mb-md-0 border rounded pl-2 d-inline-flex align-items-center justify-content-between #{(search or my) and 'ml-md-2'}">
+ <div>
+ <span class="fa fa-tag text-muted mr-1"/>
+ <span t-esc="tag.name"/>
+ </div>
+ <a t-att-href="url_for('/forum/') + slug(forum) + '?' + keep_query( 'search', 'sorting', 'filters', 'my')" class="btn py-1">&#215;</a>
+ </span>
+ </div>
+ <div t-if="uid and request.env.user.forum_waiting_posts_count"
+ title="You already have a pending post"
+ data-toggle="popover" data-trigger="hover" data-content="Please wait for a moderator to validate your previous post before continuing.">
+ <a class="disabled btn btn-secondary btn-block mb-3 mb-md-0" t-attf-href="/forum/#{slug(forum)}/ask">Ask a Question</a>
+ </div>
+ <a t-else="" role="button" type="button" class="btn btn-primary btn-block o_forum_ask_btn mb-3 mb-md-0" t-att-href="uid and '/forum/' + slug(forum) + '/ask' or '/web/login'">Ask a Question</a>
+ </div>
+
+ <t t-set="no_filters" t-value="not filters in ('solved', 'unsolved', 'unanswered')"/>
+ <t t-if="not no_filters or (no_filters and question_count)">
+ <!-- Filter post by type (mobile only) -->
+ <div class="col-6 col-md-auto d-lg-none d-flex align-items-center">
+ <div class="dropdown"> Show
+ <a href="#" class="dropdown-toggle" data-toggle="dropdown">
+ <t t-if="no_filters"> All</t>
+ <t t-elif="filters == 'solved'"> Solved</t>
+ <t t-elif="filters == 'unsolved'"> Unsolved</t>
+ <t t-elif="filters == 'unanswered'"> Unsolved</t>
+ </a>
+ <div class="dropdown-menu" role="menu">
+ <a t-att-href="url_for('') + '?' + keep_query( 'search', 'sorting', filters='all')"
+ class="dropdown-item">
+ All
+ </a>
+
+ <div class="dropdown-divider"/>
+ <a t-att-href="url_for('') + '?' + keep_query( 'search', 'sorting', filters='solved')"
+ class="dropdown-item">Solved
+ </a>
+ <a t-att-href="url_for('') + '?' + keep_query( 'search', 'sorting', filters='unsolved')"
+ class="dropdown-item">Unsolved
+ </a>
+ <a t-att-href="url_for('') + '?' + keep_query( 'search', 'sorting', filters='unanswered')"
+ class="dropdown-item">Unanswered
+ </a>
+ </div>
+ </div>
+ </div>
+
+ <!-- Filter post by type (desktop) -->
+ <div class="d-none d-lg-flex align-items-center col-auto flex-grow-md-1 flex-grow-lg-0">
+ <nav class="o_wforum_nav nav nav-pills justify-content-around">
+ <a t-att-href="url_for('') + '?' + keep_query('search', 'sorting', 'my', filters='all')"
+ t-attf-class="nav-link py-1 rounded-pill #{no_filters and 'active font-weight-bold' or 'pl-0 pr-2'}">
+ All
+ </a>
+ <span class="mx-1 text-400 d-none d-lg-block">|</span>
+ <a t-att-href="url_for('') + '?' + keep_query( 'search', 'sorting', 'my', filters='solved')"
+ t-attf-class="nav-link py-1 rounded-pill #{filters == 'solved' and 'active font-weight-bold' or 'px-2'}">Solved
+ </a>
+ <a t-att-href="url_for('') + '?' + keep_query( 'search', 'sorting', 'my', filters='unsolved')"
+ t-attf-class="d-none d-lg-block nav-link py-1 rounded-pill #{filters == 'unsolved' and 'active font-weight-bold' or 'px-2'}">Unsolved
+ </a>
+ <span class="mx-1 text-400 d-none d-lg-block">|</span>
+ <a t-att-href="url_for('') + '?' + keep_query( 'search', 'sorting', 'my', filters='unanswered')"
+ t-attf-class="nav-link py-1 rounded-pill #{filters == 'unanswered' and 'active font-weight-bold' or 'px-2'}">Unanswered
+ </a>
+ </nav>
+ </div>
+ </t>
+
+ <!-- Order by -->
+ <div t-if="question_count > 1"
+ t-attf-class="col-6 col-md-auto d-flex align-items-center justify-content-end #{uid and 'mt-lg-0'}">
+ <span class="mx-3 mx-lg-2 text-400 d-none d-md-inline">|</span>
+ <span class="dropdown">
+ Order by
+ <a href="#" class="dropdown-toggle" data-toggle="dropdown">
+ <t t-if="sorting == 'relevancy desc'"> trending</t>
+ <t t-elif="sorting == 'create_date desc'"> newest</t>
+ <t t-elif="sorting == 'write_date desc'"> activity date</t>
+ <t t-elif="sorting == 'child_count desc'"> most answered</t>
+ <t t-elif="sorting == 'vote_count desc'"> most voted</t>
</a>
- <div class="dropdown-menu" role="menu">
- <div role="separator" class="dropdown-header">Filter on</div>
- <a role="menuitem" t-att-href="url_for('') + '?' + keep_query( 'search', 'sorting', filters='all')" t-attf-class="dropdown-item#{filters == 'all' and ' active' or ''}">All</a>
- <a role="menuitem" t-att-href="url_for('') + '?' + keep_query( 'search', 'sorting', filters='unanswered')" t-attf-class="dropdown-item#{filters == 'unanswered' and ' active' or ''}">Unanswered</a>
- <a role="menuitem" t-att-href="url_for('') + '?' + keep_query( 'search', 'sorting', filters='followed')" t-if="uid" t-attf-class="dropdown-item#{filters == 'followed' and ' active' or ''}">Followed</a>
- <div role="separator" t-if="tag" class="dropdown-header">Tags</div>
- <a role="menuitem" href="" t-if="tag" t-attf-class="dropdown-item#{tag and ' active' or None}"><t t-esc="tag.name"/></a>
- <div role="separator" class="dropdown-header">Sort by</div>
- <a role="menuitem" t-att-href="url_for('') + '?' + keep_query( 'search', 'filters', sorting='relevancy desc')" t-attf-class="dropdown-item#{sorting == 'relevancy desc' and ' active' or ''}">Relevance</a>
- <a role="menuitem" t-att-href="url_for('') + '?' + keep_query( 'search', 'filters', sorting='write_date desc')" t-attf-class="dropdown-item#{sorting == 'write_date desc' and ' active' or ''}">Last activity date</a>
- <a role="menuitem" t-att-href="url_for('') + '?' + keep_query( 'search', 'filters', sorting='create_date desc')" t-attf-class="dropdown-item#{sorting == 'create_date desc' and ' active' or ''}">Newest</a>
- <a role="menuitem" t-att-href="url_for('') + '?' + keep_query( 'search', 'filters', sorting='child_count desc')" t-attf-class="dropdown-item#{sorting == 'child_count desc' and ' active' or ''}">Most answered</a>
- <a role="menuitem" t-att-href="url_for('') + '?' + keep_query( 'search', 'filters', sorting='vote_count desc')" t-attf-class="dropdown-item#{sorting == 'vote_count desc' and ' active' or ''}">Most voted</a>
+ <div class="dropdown-menu dropdown-menu-right" role="menu">
+ <a role="menuitem" t-att-href="url_for('') + '?' + keep_query( 'search', 'filters', sorting='relevancy desc')" t-attf-class="dropdown-item#{sorting == 'relevancy desc' and ' active'}">Trending</a>
+ <a role="menuitem" t-att-href="url_for('') + '?' + keep_query( 'search', 'filters', sorting='write_date desc')" t-attf-class="dropdown-item#{sorting == 'write_date desc' and ' active'}">Last activity date</a>
+ <a role="menuitem" t-att-href="url_for('') + '?' + keep_query( 'search', 'filters', sorting='create_date desc')" t-attf-class="dropdown-item#{sorting == 'create_date desc' and ' active'}">Newest</a>
+ <a role="menuitem" t-att-href="url_for('') + '?' + keep_query( 'search', 'filters', sorting='child_count desc')" t-attf-class="dropdown-item#{sorting == 'child_count desc' and ' active'}">Most answered</a>
+ <a role="menuitem" t-att-href="url_for('') + '?' + keep_query( 'search', 'filters', sorting='vote_count desc')" t-attf-class="dropdown-item#{sorting == 'vote_count desc' and ' active'}">Most voted</a>
</div>
- </h6>
- </small>
- </h2>
- <div t-foreach="question_ids" t-as="question" class="mb-2">
- <t t-call="website_forum.display_post"/>
+ </span>
+ </div>
+ </div>
+
+ <div class="row mt-4">
+ <!-- List questions or search/filters result -->
+ <div t-if="question_count != 0" class="col">
+ <t t-foreach="question_ids" t-as="question">
+ <t t-call="website_forum.display_post">
+ <t t-set="show_author_avatar" t-value="true"/>
+ </t>
+ </t>
+ </div>
+
+ <!-- No questions or search/filters result -->
+ <div t-if="question_count == 0" class="col">
+ <div t-if="search or tag or (not no_filters)" class="alert alert-info">
+ <t t-set="_filters_str">
+ <t t-if="filters == 'unanswered'">unanswered</t>
+ <t t-elif="filters == 'solved'">solved</t>
+ <t t-elif="filters == 'unsolved'">unsolved</t>
+ </t>
+ <t t-set="_my_str">
+ <t t-if="my == 'favourites'">in your favourites</t>
+ <t t-if="my == 'followed'">in your followed list</t>
+ <t t-if="my == 'mine'">in your questions</t>
+ </t>
+ <t t-set="_search_str"><t t-if="search">matching "<em class="font-weight-bold" t-esc="search"/>"</t></t>
+ <t t-set="_search_and_tag_str"><t t-if="search and tag">&amp;nbsp;and&amp;nbsp;</t></t>
+ <t t-set="_tag_str"><t t-if="tag">using the <span class="badge badge-light" t-esc="tag.name"/> tag</t></t>
+ <t t-set="result_msg">
+ Sorry, we could not find any <b>%s</b> result <b>
+ %s</b> %s%s%s.
+ </t>
+ <span t-raw="result_msg % (_filters_str.strip(), _my_str.strip(), _search_str.strip(), _search_and_tag_str.strip(), _tag_str.strip())"/>
+ </div>
+
+ <t t-elif="not tag and not search and no_filters">
+ <div t-if="my == 'followed'" class="alert border">
+ You're not following any topic in this forum (yet).<br/>
+ <a t-attf-href="/forum/#{slug(forum)}/">Browse All</a>
+ </div>
+ <div t-elif="my == 'favourites'" class="alert border">
+ No favourite questions in this forum (yet).<br/>
+ <a t-attf-href="/forum/#{slug(forum)}/">Browse All</a>
+ </div>
+ <div t-elif="my == 'mine'" class="alert border">You have no questions in this forum (yet).</div>
+ </t>
+
+ <div t-elif="filters == 'unanswered'" class="alert alert-info">Amazing! There are not answered questions!</div>
+ <div t-elif="no_filters and not search and not tag and not my" class="alert alert-info">
+ <b>This forum is empty.</b><br/>
+ Be the first one asking a question
+ </div>
+
+ <t t-if="search">
+ <h4>Search Tips</h4>
+ <ul>
+ <li>Check your spelling and try again</li>
+ <li>Try searching for one or two words</li>
+ <li>Be less specific in your wording for a wider search result</li>
+ </ul>
+ </t>
+ </div>
</div>
+
<t t-call="website.pager"/>
</t>
</template>
@@ -498,75 +763,112 @@
<!-- Edition: ask your question -->
<template id="new_question">
<t t-call="website_forum.header">
- <h1 class="o_page_header">Ask Your Question</h1>
- <t t-if="request.env.user.forum_waiting_posts_count">
- <div class="alert alert-warning" role="alert">
- You already have one pending post.<br/>
- Please wait for a moderator to validate your previous post before continuing.
+ <div t-if="request.env.user.forum_waiting_posts_count" class="alert border" role="alert">
+ <b>You already have a pending post.</b><br/>
+ <p>Please wait for a moderator to validate your previous post before continuing.</p>
+ <a t-attf-href="/forum/#{ slug(forum) }" title="All Topics"><i class="fa fa-chevron-left mr-2"/>Back to All Topics</a>
</div>
- </t>
- <t t-if="not request.env.user.forum_waiting_posts_count">
- <ul>
- <li>Set a clear, explicit and concise question title
- (check
- <t t-set="message_content_01">Inventory Date Problem, Task remaining hours, Can you help solve solve my tax computation problem in Canada?</t>
- <a href="#" data-placement="top" data-trigger="focus" data-toggle="popover" t-att-data-content="message_content_01" title="Click to get bad question samples">bad examples</a>
- and
- <t t-set="message_content_02">How to create a physical inventory at an anterior date?, How is the 'remaining hours' field computed on tasks?, How to configure TPS and TVQ's canadian taxes?</t>
- <a href="#" data-placement="bottom" data-trigger="focus" data-toggle="popover" t-att-data-content="message_content_02" title="Click to get good question titles">good examples</a>
- ),
- </li>
- <li>Avoid unnecessary introductions (Hi,... Please... Thanks...),</li>
- <li>Provide enough details and, if possible, give an example.</li>
- </ul>
- <form t-attf-action="/forum/#{slug(forum)}/new" method="post" role="form" class="tag_text js_website_submit_form">
- <input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
- <input type="text" name="post_name" required="True" pattern=".*\S.*" t-attf-value="#{post_name}"
- class="form-control mb16" placeholder="Your Question Title..." title="Title must not be empty"/>
- <input type="hidden" name="karma" t-attf-value="#{user.karma}" id="karma"/>
- <textarea name="content" required="True" id="content" class="form-control o_wysiwyg_loader"
- t-att-data-karma="forum.karma_editor">
- <t t-esc="question_content"/>
- </textarea>
- <br/>
- <input type="hidden" name="karma_tag_create" t-attf-value="#{forum.karma_tag_create}" id="karma_tag_create"/>
- <input type="hidden" name="karma_edit_retag" t-attf-value="#{forum.karma_edit_retag}" id="karma_edit_retag"/>
- <input type="hidden" name="post_tags" placeholder="Tags" class="form-control js_select2"/>
- <br/><br/>
- <button type="submit" t-attf-class="btn btn-primary #{forum.allow_share and 'oe_social_share_call' or ''} #{(user.karma &lt; forum.karma_ask) and 'karma_required' or ''}"
- t-att-data-karma="forum.karma_ask"
- data-hashtags="#question" data-social-target-type="question">Post Your Question</button>
+ <form t-else="" t-attf-action="/forum/#{slug(forum)}/new" method="post" role="form" class="tag_text js_website_submit_form o_wforum_readable">
+ <div class="form-group">
+ <label for="content">Title</label>
+ <input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
+ <input type="text" name="post_name" required="required" pattern=".*\S.*" t-attf-value="#{post_name}"
+ class="form-control form-control-lg" placeholder="A clear, explicit and concise question title" title="Title must not be empty"/>
+ <input type="hidden" name="karma" t-attf-value="#{user.karma}" id="karma"/>
+ <div class="form-text small text-muted">
+ <a data-toggle="collapse" href="#newQuestionExample" role="button" aria-expanded="false" aria-controls="newQuestionExample">
+ Example
+ <i class="fa fa-question-circle"/>
+ </a>
+ <div class="collapse" id="newQuestionExample">
+ <div class="text-success mt-2">
+ <i class="fa fa-check"/> How to configure TPS and TVQ's canadian taxes?
+ </div>
+ <div class="text-danger">
+ <i class="fa fa-times"/> Good morning to all! Please, can someone help solve solve my tax computation problem in Canada? Thanks!
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="form-group">
+ <label for="content">Description</label>
+ <div class="small form-text text-muted d-inline">, consider <b>adding an example</b>. </div>
+ <textarea name="content" required="required" id="content" class="form-control o_wysiwyg_loader" t-att-data-karma="forum.karma_editor">
+ <t t-esc="question_content"/>
+ </textarea>
+ </div>
+ <div class="form-group">
+ <label for="post_tags">Tags</label>
+ <input type="hidden" name="karma_tag_create" t-attf-value="#{forum.karma_tag_create}" id="karma_tag_create"/>
+ <input type="hidden" name="karma_edit_retag" t-attf-value="#{forum.karma_edit_retag}" id="karma_edit_retag"/>
+ <input type="hidden" name="post_tags" placeholder="Tags" class="form-control js_select2"/>
+ </div>
+ <div class="mb-5">
+ <button type="submit" t-attf-class="btn btn-primary #{forum.allow_share and 'oe_social_share_call'} #{(user.karma &lt; forum.karma_ask) and 'karma_required'}"
+ t-att-data-karma="forum.karma_ask"
+ data-hashtags="#question" data-social-target-type="question">Post Your Question</button>
+ <a class="btn btn-secondary" title="Back to Question" t-attf-href="/forum/#{ slug(forum) }"> Discard</a>
+ </div>
</form>
- </t>
</t>
</template>
<!-- Edition: edit a post -->
<template id="edit_post">
<t t-call="website_forum.header">
- <h3 t-if="not is_answer">Edit question</h3>
- <h3 t-if="is_answer">Edit reply</h3>
- <form t-attf-action="/forum/#{slug(forum)}/post/#{slug(post)}/save" method="post" role="form" class="tag_text js_website_submit_form">
+ <div t-if="is_answer" class="font-weight-bold mb-1">Question by <t t-esc="post.parent_id.create_uid.sudo().name"/></div>
+ <article t-if="is_answer" class="alert border pb-0 o_wforum_readable">
+ <h5 class="mb-1 text-muted" t-esc="post.parent_id.name"/>
+ <div t-field="post.parent_id.content" class="o_wforum_post_content text-muted oe_no_empty"/>
+ </article>
+ <form t-attf-action="/forum/#{slug(forum)}/post/#{slug(post)}/save" method="post" role="form" class="tag_text js_website_submit_form o_wforum_readable">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
- <div t-if="not is_answer">
- <input type="text" name="post_name" required="True" pattern=".*\S.*" t-attf-value="#{post.name}"
- class="form-control mb-2" placeholder="Edit your Post" title="Title must not be empty"/>
- <h5 class="mt2">Please enter a descriptive question (should finish by a '?')</h5>
+ <div t-if="not is_answer" class="form-group">
+ <label for="post_name">Title</label>
+ <input type="text" name="post_name" required="required" pattern=".*\S.*" t-attf-value="#{post.name}"
+ class="form-control form-control-lg" placeholder="Edit your Post" title="Title must not be empty"/>
+ <div class="form-text small text-muted">
+ <a data-toggle="collapse" href="#newQuestionExample" role="button" aria-expanded="false" aria-controls="newQuestionExample">
+ Example
+ <i class="fa fa-question-circle"/>
+ </a>
+ <div class="collapse" id="newQuestionExample">
+ <div class="my-2">Use a clear, explicit and concise question title</div>
+ <div class="text-success">
+ <i class="fa fa-check"/> How to configure TPS and TVQ's canadian taxes?
+ </div>
+ <div class="text-danger">
+ <i class="fa fa-times"/> Good morning to all! Please, can someone help solve solve my tax computation problem in Canada? Thanks!
+ </div>
+ </div>
+ </div>
</div>
- <input type="hidden" name="karma" t-attf-value="#{user.karma}" id="karma"/>
- <input type="hidden" name="karma_tag_create" t-attf-value="#{forum.karma_tag_create}" id="karma_tag_create"/>
- <textarea name="content" id="content" required="True" class="form-control o_wysiwyg_loader"
- t-att-data-karma="forum.karma_editor">
- <t t-esc="post.content"/>
- </textarea>
- <div t-if="not is_answer">
- <br/>
+ <div class="form-group">
+ <label t-if="not is_answer" for="content">Description</label>
+ <label t-else="">Your Answer</label>
+ <div t-if="not is_answer" class="small form-text text-muted d-inline">, consider <b>adding an example</b>. </div>
+ <textarea name="content" id="content" required="required" class="form-control o_wysiwyg_loader" t-att-data-karma="forum.karma_editor">
+ <t t-esc="post.content"/>
+ </textarea>
+ </div>
+ <input type="hidden" name="karma" t-attf-value="#{user.karma}" id="karma"/>
+ <div t-if="not is_answer" class="form-group">
+ <label for="post_tags">Tags</label>
+ <input type="hidden" name="karma_tag_create" t-attf-value="#{forum.karma_tag_create}" id="karma_tag_create"/>
<input type="hidden" name="karma_edit_retag" t-attf-value="#{forum.karma_edit_retag}" id="karma_edit_retag"/>
- <input type="text" name="post_tags" class="form-control col-lg-9 js_select2" placeholder="Tags" t-attf-data-init-value="#{tags}" value="Tags" t-att-readonly="user.karma &lt; forum.karma_edit_retag" t-att-title="'You need to have sufficient karma to edit tags' if user.karma &lt; forum.karma_edit_retag else ''"/>
- <br/>
+ <t t-set="edit_tags_karma_fail" t-value="user.karma &lt; forum.karma_edit_retag"/>
+ <t t-set="edit_tags_karma_error_message">You need to have sufficient karma to edit tags</t>
+ <input type="text" name="post_tags" class="form-control js_select2" placeholder="Tags" t-attf-data-init-value="#{tags}" value="Tags"
+ t-att-readonly="edit_tags_karma_fail and 'readonly'"
+ t-att-title="edit_tags_karma_fail and edit_tags_karma_error_message"/>
+ </div>
+ <div class="mb-4">
+ <button type="submit" class="btn btn-primary">Save changes</button>
+ <a class="btn btn-secondary" title="Back to Question" t-attf-href="/forum/#{ slug(forum) }/question/#{ slug(post)}">
+ Discard
+ </a>
</div>
- <button type="submit" class="btn btn-primary btn-lg mt-4">Save</button>
</form>
</t>
</template>
@@ -574,10 +876,6 @@
<!-- Moderation: close a post -->
<template id="close_post">
<t t-call="website_forum.header">
- <h1 class="o_page_header">
- <t t-if="offensive">Offensive Post</t>
- <t t-if="not offensive">Close Post</t>
- </h1>
<p class="text-muted" t-if="not offensive">
If you close this post, it will be hidden for most users. Only
users having a high karma can see closed posts to moderate
@@ -591,36 +889,25 @@
<form t-attf-action="/forum/#{ slug(forum) }/#{offensive and 'post' or 'question'}/#{slug(question)}/#{offensive and 'mark_as_offensive' or 'close'}" method="post" role="form" class="mt32 mb64 js_website_submit_form">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<input name="post_id" t-att-value="question.id" type="hidden"/>
- <div class="form-group row">
- <label class="col-lg-3 col-form-label" for="reason">Post:</label>
- <div class="col-lg-8 mt8 text-primary">
- <t t-if="not question.parent_id">
- <b><span t-field="question.name"/></b>
- </t>
- <t t-if="question.parent_id">
- <span t-field="question.parent_id.name"/>
- </t>
- </div>
+ <div class="form-group">
+ <label for="post">Post:</label>
+ <input type="text" disabled="True" class="form-control-plaintext" name="post" t-att-value="question.name if not question.parent_id else question.parent_id.name"/>
</div>
- <div class="form-group row">
- <label class="col-lg-3 col-form-label" for="reason">Reason:</label>
- <div class="col-lg-8">
- <select class="form-control" name="reason_id">
- <t t-foreach="reasons or []" t-as="reason">
- <option t-att-value="reason.id" t-att-selected="reason.id == question.closed_reason_id.id"><t t-esc="reason.name"/></option>
- </t>
- </select>
- </div>
+ <div class="form-group mb-4">
+ <label for="reason"><t t-if="offensive">Offensive</t><t t-if="not offensive">Closing</t> Reason:</label>
+ <select class="form-control custom-select custom-select-lg" name="reason_id">
+ <t t-foreach="reasons or []" t-as="reason">
+ <option t-att-value="reason.id" t-att-selected="reason.id == question.closed_reason_id.id"><t t-esc="reason.name"/></option>
+ </t>
+ </select>
</div>
- <div class="form-group row">
- <div class="offset-lg-3 col-lg-8">
- <button type="submit" class="btn btn-primary mr-3">
- <t t-if="offensive">Mark as offensive</t>
- <t t-if="not offensive">Close post</t>
- </button>
- <span class="text-muted">or</span>
- <a role="button" class="btn btn-link" t-attf-href="/forum/#{ slug(forum) }/question/#{ slug(question) }"><i class="fa fa-caret-left mr-2"/>back to post</a>
- </div>
+ <div class="form-group">
+ <button type="submit" class="btn btn-danger">
+ <t t-if="offensive">Mark as offensive</t>
+ <t t-if="not offensive">Close post</t>
+ </button>
+ <span class="text-muted mx-3">or</span>
+ <a role="button" class="btn btn-light border" t-attf-href="/forum/#{ slug(forum) }/question/#{ slug(question) }">Discard</a>
</div>
</form>
</t>
@@ -629,13 +916,12 @@
<!-- Edition: post a reply -->
<template id="post_reply">
<div class="css_editable_mode_hidden">
- <form t-attf-id="reply#{ object._name.replace('.','') + '-' + str(object.id) }" class="collapse js_website_submit_form"
- t-attf-action="/forum/#{ slug(forum) }/#{slug(object)}/reply" method="post" role="form">
+ <form class="collapse js_website_submit_form"
+ t-attf-action="/forum/#{slug(forum)}/#{slug(object)}/reply" method="post" role="form">
<h3 class="mt8">Your Reply</h3>
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<input type="hidden" name="karma" t-attf-value="#{user.karma}" id="karma"/>
- <textarea name="content" t-attf-id="content-#{str(object.id)}" class="form-control o_wysiwyg_loader" required="True"
- t-att-data-karma="forum.karma_editor"/>
+ <textarea name="content" class="form-control o_wysiwyg_loader" required="required" t-att-data-karma="forum.karma_editor"/>
<button type="submit" class="btn btn-primary mb16">Post Answer</button>
</form>
</div>
@@ -643,22 +929,24 @@
<!-- Edition: post an answer -->
<template id="post_answer">
- <h3 class="mt-2">Your Answer</h3>
- <p>
- <b>Please try to give a substantial answer.</b> If you wanted to comment on the question or answer, just
- <b>use the commenting tool.</b> Please remember that you can always <b>revise your answers</b>
- - no need to answer the same question twice. Also, please <b>don't forget to vote</b>
- - it really helps to select the best questions and answers!
- </p>
+ <div class="d-flex align-items-center mt-5 mb-2">
+ <img t-if="uid" t-attf-class="rounded-circle mr-2" t-att-src="website.image_url(user, 'image_128', '24x24')" alt="Avatar"/>
+ <h4 class="my-0">Your Answer</h4>
+ </div>
<t t-if="request.params.get('nocontent')">
<p class="alert alert-danger" role="alert">You cannot post an empty answer</p>
</t>
<form t-attf-action="/forum/#{ slug(forum) }/#{slug(question)}/reply" method="post" class="js_website_submit_form" role="form">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<input type="hidden" name="karma" t-attf-value="#{user.karma}" id="karma"/>
- <textarea name="content" t-attf-id="content-#{str(question.id)}" class="form-control o_wysiwyg_loader" required="True"
- t-att-data-karma="forum.karma_editor"/>
- <button type="submit" t-attf-class="btn btn-primary #{forum.allow_share and 'oe_social_share_call' or ''} my-3 #{not question.can_answer and 'karma_required' or ''}"
+ <textarea name="content" t-attf-id="content-#{str(question.id)}" class="form-control o_wysiwyg_loader" required="required" t-att-data-karma="forum.karma_editor"/>
+ <p class="small mt-2 mb-1">
+ <b>Please try to give a substantial answer.</b> If you wanted to comment on the question or answer, just
+ <b>use the commenting tool.</b> Please remember that you can always <b>revise your answers</b>
+ - no need to answer the same question twice. Also, please <b>don't forget to vote</b>
+ - it really helps to select the best questions and answers!
+ </p>
+ <button type="submit" t-attf-class="btn btn-primary #{forum.allow_share and 'oe_social_share_call'} my-3 #{not question.can_answer and 'karma_required'}"
t-att-data-karma="question.forum_id.karma_answer"
data-social-target-type="answer" data-hashtags="#answer">Post Answer</button>
</form>
@@ -667,20 +955,21 @@
<template id="vote">
<t t-set="own_vote" t-value="post.user_vote"/>
<t t-set="forum" t-value="post.forum_id"/>
- <t t-set="karma_up" t-value="forum.karma_upvote"/>
- <t t-set="karma_down" t-value="forum.karma_downvote"/>
<t t-set="can_upvote" t-value="post.can_upvote"/>
<t t-set="can_downvote" t-value="post.can_downvote"/>
- <div class="vote text-center">
- <a t-attf-class="vote_up fa fa-caret-up no-decoration #{own_vote == 1 and 'text-success' or ''} #{((own_vote == 1 and not can_downvote) or not can_upvote) and 'karma_required' or ''}"
- t-attf-data-karma="#{own_vote == 1 and karma_down or karma_up}"
- aria-label="Positive vote" title="Positive vote"
- t-attf-data-href="/forum/#{slug(forum)}/post/#{slug(post)}/upvote"/>
- <div class="vote_count text-muted" t-esc="post.vote_count"/>
- <a t-attf-class="vote_down fa fa-caret-down no-decoration #{own_vote == -1 and 'text-warning' or ''} #{((own_vote == -1 and not can_upvote) or not can_downvote) and 'karma_required' or ''}"
- t-attf-data-karma="#{own_vote == -1 and karma_up or karma_down}"
- aria-label="Negative vote" title="Negative vote"
- t-attf-data-href="/forum/#{slug(forum)}/post/#{slug(post)}/downvote"/>
+ <div t-attf-class="vote text-center d-inline-flex align-items-center #{vertical and 'o_wforum_vote_vertical flex-md-column'} #{classes}">
+ <button type="button" t-attf-data-href="/forum/#{slug(forum)}/post/#{slug(post)}/upvote"
+ t-attf-class="btn btn-link vote_up fa fa-caret-up pl-0 #{vertical and 'px-md-0 pt-md-0' or 'pr-2'} #{own_vote == 1 and 'text-success' or 'text-muted'} #{not can_upvote and 'karma_required'}"
+ t-att-disabled="own_vote == 1 and 'disabled'"
+ t-att-data-karma="forum.karma_upvote"
+ aria-label="Positive vote" title="Positive vote"/>
+ <b t-attf-class="vote_count #{own_vote == 1 and 'text-success' or (own_vote == -1 and 'text-danger' or 'text-muted')}"
+ t-esc="post.vote_count"/>
+ <button type="button" t-attf-data-href="/forum/#{slug(forum)}/post/#{slug(post)}/downvote"
+ t-attf-class="btn btn-link vote_down fa fa-caret-down #{vertical and 'px-md-0' or 'px-2'} #{own_vote == -1 and 'text-danger' or 'text-muted'} #{not can_downvote and 'karma_required'}"
+ t-att-disabled="own_vote == -1 and 'disabled'"
+ t-att-data-karma="forum.karma_downvote"
+ aria-label="Negative vote" title="Negative vote"/>
<t t-raw="0"/>
</div>
</template>
@@ -688,426 +977,542 @@
<!-- Specific Post Layout -->
<template id="post_description_full" name="Question Navigation">
<t t-call="website_forum.header">
- <div class="alert alert-info text-center" role="status" t-if="forum and question.state == 'pending' and user.karma>=forum.karma_moderate and question.active">
- <p class="text-muted mb16">This post is currently awaiting moderation and not yet published... Do you want <i>Accept</i> or <i>Reject</i> this post ?</p>
- <a role="button" t-attf-href="/forum/#{slug(forum)}/post/#{slug(question)}/validate" type="button" class="btn btn-success">Accept <i class="fa fa-check"/></a>
- <a role="button" t-attf-href="/forum/#{slug(forum)}/post/#{slug(question)}/refuse" type="button" class="btn btn-danger">Reject <i class="fa fa-times"/></a>
+ <div class="alert alert-info shadow-sm pb-3" role="status" t-if="forum and question.state == 'pending' and user.karma>=forum.karma_moderate and question.active">
+ <p>This post is currently awaiting moderation and it's not published yet.<br/>
+ Do you want <b>Accept</b> or <b>Reject</b> this post ?</p>
+ <div>
+ <a role="button" t-attf-href="/forum/#{slug(forum)}/post/#{slug(question)}/validate" type="button" class="btn btn-success">
+ <i class="fa fa-check fa-fw mr-1"/>Accept</a>
+ <a role="button" t-attf-href="/forum/#{slug(forum)}/post/#{slug(question)}/refuse" type="button" class="btn btn-danger">
+ <i class="fa fa-times fa-fw mr-1"/>Reject</a>
+ </div>
</div>
- <div class="alert alert-info text-center" role="status" t-if="question.state == 'pending' and user.karma &lt; forum.karma_moderate">
+
+ <div class="alert alert-warning text-center" role="status"
+ t-if="question.state == 'pending' and user.karma &lt; forum.karma_moderate">
Waiting for validation
</div>
- <div t-attf-class="question #{can_bump and 'oe_js_bump' or ''}" data-type="question" t-att-data-last-update="question.write_date" t-att-data-id="question.id">
- <div class="row">
- <div class="col-1">
- <t t-call="website_forum.vote">
- <t t-set="post" t-value="question"/>
- <div class="mt-1">
- <a t-attf-data-href="/forum/#{slug(question.forum_id)}/question/#{slug(question)}/toggle_favourite" aria-label="Toggle favorite status" title="Toggle favorite status"
- t-attf-class="favourite_question no-decoration fa fa-star #{question.user_favourite and 'forum_favourite_question' or ''}"/><br/>
- <t t-esc="question.favourite_count"/>
- </div>
- </t>
- </div>
- <div t-attf-class="col-11 question-block mb-5 o_post_content" role="alert">
- <span t-if="question.has_validated_answer" title="Question has accepted answer" role="img" aria-label="Question has accepted answer"><i class="fa fa-check-circle text-success"/> <b class="text-success">Resolved</b></span>
- <h1 t-attf-class="#{not question.active and 'text-danger' or 'text-primary'}">
- <t t-esc="question.name"/>
- <span t-if="not question.active and question.state!='offensive'"><b> [Deleted]</b></span>
- <span t-if="not question.active and question.state=='offensive'"><b> [Offensive]</b></span>
- <span t-if="question.state == 'close'"><b> [Closed]</b></span>
- </h1>
- <div class="text-muted mb16">
- <i class="mr-2 fa fa-calendar"/><span t-field="question.create_date" t-options='{"format":"short"}'/>
- <i class="ml-4 mr-2 fa fa-eye"/><span t-field="question.views"/> views
- </div>
- <div class="alert alert-info text-center" t-if="question.state == 'close'" role="status">
- <p class="mt-3">
- <b>The question has been closed<t t-if="question.closed_reason_id"> for reason: <i t-esc="question.closed_reason_id.name"/></t></b>
- </p>
- <t t-if="question.closed_uid">
- <b> by <a t-attf-href="/forum/#{ slug(forum) }/user/#{ question.closed_uid.id }"
- t-field="question.closed_uid"
- t-options='{"widget": "contact", "fields": ["name"]}'
- style="display: inline-block;"/></b>
- </t>
- <b> on <span t-field="question.closed_date"/></b>
- <div class="mt-3 mb24 text-center">
- <t t-call="website_forum.link_button">
- <t t-set="url" t-value="'/forum/' + slug(forum) + '/question/' + slug(question) + '/reopen'"/>
- <t t-set="label">Reopen</t>
- <t t-set="inDropdown" t-value="False"/>
- <t t-set="icon" t-value="'fa-arrow-right'"/>
- <t t-set="karma" t-value="not question.can_close and question.karma_close or 0"/>
+ <article t-attf-class="question o_wforum_post row no-gutters #{can_bump and 'oe_js_bump'}"
+ data-type="question"
+ t-att-data-last-update="question.write_date"
+ t-att-data-id="question.id">
+
+ <div t-if="question.state == 'active'" class="col-6 mb-3 col-md-auto pr-2 pr-md-3 pr-lg-4">
+ <t t-call="website_forum.vote">
+ <t t-set="post" t-value="question"/>
+ <t t-set="vertical" t-value="True"/>
+ </t>
+ </div>
+ <div t-attf-class="text-right d-md-none #{question.state == 'active' and 'col-6' or 'col-12'}">
+ <t t-call="website_forum.question_dropdown"/>
+ </div>
+ <section class="col">
+ <div class="row no-gutter">
+ <header class="o_wforum_post_header col mb-0 h2">
+ <i t-if="uid" aria-label="Toggle favorite status"
+ title="Toggle favorite status"
+ t-attf-data-href="/forum/#{slug(question.forum_id)}/question/#{slug(question)}/toggle_favourite"
+ t-attf-class="o_wforum_favourite_toggle no-decoration small mr-1 fa #{question.user_favourite and 'fa-star o_wforum_gold' or 'fa-star-o text-muted'}"/>
+
+ <h1 class="d-inline mb-0 h2" t-esc="question.name"/>
+
+ <span t-if="not question.active" class="border rounded-pill h6 text-muted my-0 ml-2 px-2">
+ <t t-if="question.state!='offensive'">Deleted</t>
+ <t t-if="question.state=='offensive'">Offensive</t>
+ <t t-if="question.state=='offensive' and question.closed_reason_id">
+ <t t-esc="question.closed_reason_id.name[0].upper() + question.closed_reason_id.name[1:]"/>
</t>
- </div>
+ </span>
+ <small t-if="question.state == 'close'">
+ <span class="badge badge-info">Closed</span>
+ </small>
+ </header>
+ <div class="d-none d-md-block col-md-auto">
+ <t t-call="website_forum.question_dropdown"/>
</div>
- <span t-field="question.content" class="oe_no_empty"/>
+ </div>
- <div>
- <div class="btn-group mb8">
- <a t-attf-class="btn btn-outline-primary #{not question.can_answer and 'karma_required text-muted' or ''}" t-att-data-karma="question.forum_id.karma_answer"
- href="#post_reply"><i class="fa fa-reply"/> <b>Reply</b>
- </a>
- <a t-attf-class="btn btn-outline-primary #{not question.can_comment and 'karma_required text-muted' or ''}" t-att-data-karma="question.karma_comment" t-att-data-toggle="question.can_comment and 'collapse' or None"
- t-attf-href="#comment#{ question._name.replace('.','') + '-' + str(question.id) }"><i class=" fa fa-comment-o"/> <b>Comment</b>
- </a>
- <a href="javascript:void(0)" class="oe_social_share btn btn-outline-primary"
- t-attf-data-hashtags="#question"><i class="fa fa-share-alt"/> <b>Share</b>
- </a>
- </div>
- <div class="btn-group float-right">
- <t t-if="question.state == 'close'" t-call="website_forum.link_button">
- <t t-set="url" t-value="'/forum/' + slug(forum) +'/question/' + slug(question) + '/reopen'"/>
- <t t-set="title">Reopen</t>
- <t t-set="inDropdown" t-value="False"/>
- <t t-set="icon" t-value="'fa-undo'"/>
- <t t-set="karma" t-value="not question.can_close and question.karma_close or 0"/>
- </t>
- <t t-call="website_forum.link_button">
- <t t-set="url" t-value="'/forum/' + slug(forum) +'/post/' + slug(question) + '/edit'"/>
- <t t-set="title">Edit</t>
- <t t-set="inDropdown" t-value="False"/>
- <t t-set="icon" t-value="'fa-pencil-square-o'"/>
- <t t-set="karma" t-value="not question.can_edit and question.karma_edit or 0"/>
- </t>
- <t t-if="question.state != 'close'" t-call="website_forum.link_button">
- <t t-set="url" t-value="'/forum/' + slug(forum) +'/question/' + slug(question) + '/ask_for_close'"/>
- <t t-set="title">Close</t>
- <t t-set="inDropdown" t-value="False"/>
- <t t-set="icon" t-value="'fa-times'"/>
- <t t-set="karma" t-value="not question.can_close and question.karma_close or 0"/>
- </t>
- <t t-if="question.active" t-call="website_forum.link_button">
- <t t-set="url" t-value="'/forum/' + slug(forum) +'/question/' + slug(question) + '/delete'"/>
- <t t-set="title">Delete</t>
- <t t-set="inDropdown" t-value="False"/>
- <t t-set="icon" t-value="'fa-trash-o'"/>
- <t t-set="karma" t-value="not question.can_unlink and question.karma_unlink or 0"/>
- </t>
- <t t-if="not question.active and question.state != 'offensive'" t-call="website_forum.link_button">
- <t t-set="url" t-value="'/forum/' + slug(forum) +'/question/' + slug(question) + '/undelete'"/>
- <t t-set="title">Undelete</t>
- <t t-set="inDropdown" t-value="False"/>
- <t t-set="icon" t-value="'fa-upload'"/>
- <t t-set="karma" t-value="not question.can_unlink and question.karma_unlink or 0"/>
- </t>
- <t t-if="not question.active and question.state == 'offensive'" t-call="website_forum.link_button">
- <t t-set="url" t-value="'/forum/' + slug(forum) +'/post/' + slug(question) + '/validate'"/>
- <t t-set="title">Validate</t>
- <t t-set="inDropdown" t-value="False"/>
- <t t-set="icon" t-value="'fa-check'"/>
- <t t-set="karma" t-value="not question.can_moderate and question.forum_id.karma_moderate or 0"/>
- </t>
- <t t-if="question.active" t-call="website_forum.link_button">
- <t t-set="url" t-value="'/forum/' + slug(forum) +'/post/' + slug(question) + '/flag'"/>
- <t t-set="title">Flag</t>
- <t t-set="inDropdown" t-value="False"/>
- <t t-set="icon" t-value="not question.can_flag and 'fa-flag-o' or 'fa-flag'"/>
- <t t-set="karma" t-value="not question.can_flag and question.forum_id.karma_flag or 0"/>
- <t t-set="classes" t-value="'flag'"/>
- </t>
+ <div class="mt-3 row">
+ <div t-call="website_forum.author_box" t-attf-class="col mb-2 #{question.tag_ids and 'col-sm-auto'}">
+ <t t-set="object" t-value="question"/>
+ <t t-set="allow_biography" t-value="True"/>
+ <t t-set="show_name" t-value="True"/>
+ <t t-set="show_date" t-value="True"/>
+ </div>
+ <div class="col-auto mb-2 order-sm-3">
+ <div t-call="website_mail.follow">
+ <t t-set="object" t-value="question"/>
+ <t t-set="icons_design" t-value="True"/>
</div>
</div>
+ <div t-if="len(question.tag_ids) > 0" class="col-12 col-sm order-sm-2 o_wforum_index_entry_tags mb-1">
+ <i class="fa fa-tag text-muted"/>
+ <a t-foreach="question.tag_ids" t-as="question_tag"
+ t-attf-href="/forum/#{slug(question_tag.forum_id)}/tag/#{slug(question_tag)}/questions?#{keep_query(filters='tag')}"
+ t-attf-class="badge border text-600 badge-light #{not question_tag_first and 'ml-1'}"
+ t-field="question_tag.name"/>
+ </div>
+ </div>
- <t t-call="website_forum.post_comment">
- <t t-set="object" t-value="question"/>
+ <div class="alert alert-info text-center" t-if="question.state == 'close'" role="status">
+ <p class="mt-3">
+ <b>The question has been closed<t t-if="question.closed_reason_id"> for reason: <i t-esc="question.closed_reason_id.name"/></t></b>
+ </p>
+ <t t-if="question.closed_uid">
+ <b> by <a t-attf-href="/forum/#{ slug(forum) }/user/#{ question.closed_uid.id }"
+ t-field="question.closed_uid"
+ t-options='{"widget": "contact", "fields": ["name"]}'
+ style="display: inline-block;"/></b>
</t>
+ <b> on <span t-field="question.closed_date"/></b>
+ <div class="mt-3 mb24 text-center">
+ <t t-call="website_forum.link_button">
+ <t t-set="url" t-value="'/forum/' + slug(forum) + '/question/' + slug(question) + '/reopen'"/>
+ <t t-set="label">Reopen</t>
+ <t t-set="inDropdown" t-value="False"/>
+ <t t-set="icon" t-value="'fa-arrow-right'"/>
+ <t t-set="karma" t-value="not question.can_close and question.karma_close or 0"/>
+ </t>
+ </div>
</div>
- <div class="col-12">
- <div class="border-primary o_wforum_post_count_answer_count p-2">
- <i class="fa fa-comments text-primary"/>
- <t t-esc="question.child_count"/>
- <t t-if="question.child_count&lt;=1">Answer</t>
- <t t-else="">Answers</t>
+
+ <div t-field="question.content" class="o_wforum_post_content o_wforum_readable oe_no_empty"/>
+
+ <t t-set="_question_comment_collapse_uid" t-value="'comment_%s_%s' % (question._name.replace('.', '_'), question.id)"/>
+ <div t-if="question.state == 'active' and question.active != False"
+ class="btn-toolbar mb-3" role="toolbar">
+ <div t-if="not question.uid_has_answered and question.can_answer" class="btn-group btn-group-sm mr-2">
+ <a t-attf-class="btn btn-primary #{not question.can_answer and 'karma_required text-muted'}"
+ t-att-data-karma="question.forum_id.karma_answer"
+ href="#post_reply">
+ <i class="fa fa-reply mr-1"/>Answer
+ </a>
+ </div>
+ <div class="btn-group btn-group-sm">
+ <a t-attf-class="btn px-2 border #{not question.can_comment and 'karma_required text-muted'}" t-att-data-karma="question.karma_comment" t-att-data-toggle="question.can_comment and 'collapse' or None"
+ t-attf-href="##{_question_comment_collapse_uid}">
+ <i class=" fa fa-comment text-muted mr-1"/>Comment
+ </a>
+ <a href="javascript:void(0)" class="oe_social_share btn px-2 border"
+ t-attf-data-hashtags="#question">
+ <i class="fa fa-share-alt text-muted mr-1"/>Share
+ </a>
</div>
</div>
- </div>
- </div>
- <div t-foreach="question.child_ids" t-as="post_answer" class="mt-3 mb-4">
- <t t-if="post_answer.state != 'flagged' or (post_answer.state == 'flagged' and post_answer.can_moderate)">
- <t t-call="website_forum.post_answers">
- <t t-set="answer" t-value="post_answer"/>
+
+ <t t-call="website_forum.post_comment">
+ <t t-set="object" t-value="question"/>
+ <t t-set="_collapse_uid" t-value="_question_comment_collapse_uid"/>
+ </t>
+
+ <section t-if="question.child_ids" t-attf-class="#{question.website_message_ids and 'mt-5' or 'mt-4'}">
+ <h5>
+ <t t-esc="len(question.child_ids)"/>
+ <t t-if="len(question.child_ids) == 1">Answer</t>
+ <t t-else="">Answers</t>
+ </h5>
+
+ <t t-foreach="question.child_ids" t-as="post_answer">
+ <div t-if="post_answer.state != 'flagged' or (post_answer.state == 'flagged' and post_answer.can_moderate)"
+ class="mb-4">
+ <t t-call="website_forum.post_answers">
+ <t t-set="answer" t-value="post_answer"/>
+ </t>
+ </div>
+ </t>
+ </section>
+ <t t-if="question.state != 'close' and question.active != False and question.can_answer and not request.env.user.forum_waiting_posts_count">
+ <div id="post_reply" t-if="(not question.uid_has_answered or question.forum_id.mode == 'discussions')">
+ <t t-call="website_forum.post_answer"/>
+ </div>
+ <div t-elif="uid and request.env.user.forum_waiting_posts_count" class="alert alert-gamma text-center">
+ <b class="d-block">You have a pending post</b>
+ Please wait for a moderator to validate your previous post to be allowed replying questions.
+ </div>
+ <div t-elif="not uid" class="alert alert-gamma text-center">
+ <a class="btn btn-primary forum_register_url" href="/web/login">Sign in</a> to partecipate
+ </div>
</t>
+ </section>
+ </article>
+ </t>
+</template>
+
+
+<template id="website_forum.question_dropdown">
+ <div class="dropdown">
+ <a class="btn py-0" href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+ <i class="fa fa-ellipsis-v"/>
+ </a>
+ <div class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenuLink">
+ <t t-if="question.state == 'close'" t-call="website_forum.link_button">
+ <t t-set="url" t-value="'/forum/' + slug(forum) +'/question/' + slug(question) + '/reopen'"/>
+ <t t-set="label">Reopen</t>
+ <t t-set="inDropdown" t-value="True"/>
+ <t t-set="icon" t-value="'fa-undo fa-fw'"/>
+ <t t-set="karma" t-value="not question.can_close and question.karma_close or 0"/>
+ </t>
+ <t t-call="website_forum.link_button">
+ <t t-set="url" t-value="'/forum/' + slug(forum) +'/post/' + slug(question) + '/edit'"/>
+ <t t-set="label">Edit</t>
+ <t t-set="inDropdown" t-value="True"/>
+ <t t-set="icon" t-value="'fa-pencil fa-fw'"/>
+ <t t-set="karma" t-value="not question.can_edit and question.karma_edit or 0"/>
+ </t>
+ <t t-if="question.state != 'close'" t-call="website_forum.link_button">
+ <t t-set="url" t-value="'/forum/' + slug(forum) +'/question/' + slug(question) + '/ask_for_close'"/>
+ <t t-set="label">Close</t>
+ <t t-set="inDropdown" t-value="True"/>
+ <t t-set="icon" t-value="'fa-times fa-fw'"/>
+ <t t-set="karma" t-value="not question.can_close and question.karma_close or 0"/>
+ </t>
+ <t t-if="question.active" t-call="website_forum.link_button">
+ <t t-set="url" t-value="'/forum/' + slug(forum) +'/question/' + slug(question) + '/delete'"/>
+ <t t-set="label">Delete</t>
+ <t t-set="inDropdown" t-value="True"/>
+ <t t-set="icon" t-value="'fa-trash-o fa-fw'"/>
+ <t t-set="karma" t-value="not question.can_unlink and question.karma_unlink or 0"/>
+ </t>
+ <t t-if="not question.active and question.state != 'offensive'" t-call="website_forum.link_button">
+ <t t-set="url" t-value="'/forum/' + slug(forum) +'/question/' + slug(question) + '/undelete'"/>
+ <t t-set="label">Undelete</t>
+ <t t-set="inDropdown" t-value="True"/>
+ <t t-set="icon" t-value="'fa-upload fa-fw'"/>
+ <t t-set="karma" t-value="not question.can_unlink and question.karma_unlink or 0"/>
+ </t>
+ <t t-if="not question.active and question.state == 'offensive'" t-call="website_forum.link_button">
+ <t t-set="url" t-value="'/forum/' + slug(forum) +'/post/' + slug(question) + '/validate'"/>
+ <t t-set="label">Validate</t>
+ <t t-set="inDropdown" t-value="True"/>
+ <t t-set="icon" t-value="'fa-check fa-fw'"/>
+ <t t-set="karma" t-value="not question.can_moderate and question.forum_id.karma_moderate or 0"/>
+ </t>
+ <t t-if="question.active" href="#" t-call="website_forum.link_button">
+ <t t-set="url" t-value="'/forum/' + slug(forum) +'/post/' + slug(question) + '/flag'"/>
+ <t t-set="label">Flag</t>
+ <t t-set="inDropdown" t-value="True"/>
+ <t t-set="icon" t-value="not question.can_flag and 'fa-flag-o' or 'fa-flag'"/>
+ <t t-set="karma" t-value="not question.can_flag and question.forum_id.karma_flag or 0"/>
+ <t t-set="classes" t-value="'flag'"/>
</t>
</div>
- <div id="post_reply"
- t-if="(not question.uid_has_answered or question.forum_id.mode == 'discussions') and question.state != 'close' and question.active != False and question.can_answer">
- <t t-call="website_forum.post_answer"/>
- </div>
- <div t-if="question.uid_has_answered and question.forum_id.mode == 'questions'" class="mb16">
- <a role="button" class="btn btn-primary" t-attf-href="/forum/#{slug(forum)}/question/#{slug(question)}/edit_answer">Edit Your Answer</a>
- <span class="text-muted">(only one answer per question is allowed)</span>
- </div>
- </t>
+ </div>
</template>
<template id="post_answers">
<a t-attf-id="answer-#{str(answer.id)}"/>
- <div t-attf-class="forum_answer card" t-attf-id="answer_#{answer.id}" >
- <div class="card-body">
- <div t-if="answer.is_correct" class="validate_answer">
- <div class="bg-success"></div>
- <span title="Question has accepted answer" role="img" aria-label="Question has accepted answer"
- t-attf-data-href="/forum/#{slug(question.forum_id)}/post/#{slug(answer)}/toggle_correct">
- <i class="fa fa-check-circle text-success bg-white"/>
- </span>
- </div>
- <div class="row">
- <div class="col-1">
+ <div t-attf-class="forum_answer pt-4 border-top border-light #{answer.is_correct and 'o_wforum_answer_correct'}" t-attf-id="answer_#{answer.id}" >
+ <div class="">
+ <div class="row no-gutters">
+ <div class="col-12 col-md-auto pr-2 pr-md-2 pr-lg-3">
<t t-call="website_forum.vote">
+ <t t-set="vertical" t-value="True"/>
<t t-set="post" t-value="answer"/>
- <div t-if="question.can_answer and question.forum_id.mode == 'questions'" class="mt4">
- <a t-attf-class="accept_answer fa fa-2x fa-check-circle no-decoration #{answer.is_correct and 'oe_answer_true' or 'oe_answer_false'} #{not answer.can_accept and 'karma_required' or ''}"
- t-attf-data-karma="#{answer.karma_accept}"
- aria-label="Accept this answer as the best" title="Accept this answer as the best"
- t-attf-data-href="/forum/#{slug(question.forum_id)}/post/#{slug(answer)}/toggle_correct"
- t-if="not question.has_validated_answer"/>
- </div>
+
+ <t t-set="helper_accept">Mark as Best Answer</t>
+ <t t-set="helper_decline">Unmark as Best Answer</t>
+ <a t-if="question.can_answer and question.forum_id.mode == 'questions'" t-attf-class="o_wforum_validate_toggler fa-stack mt-2 #{not answer.can_accept and 'karma_required'}"
+ t-attf-data-karma="#{answer.karma_accept}"
+ t-att-data-helper-accept="helper_accept"
+ t-att-data-helper-decline="helper_decline"
+ t-att-title="answer.is_correct and helper_decline or helper_accept"
+ data-toggle="tooltip"
+ t-attf-data-target="#answer_#{answer.id}"
+ t-attf-data-href="/forum/#{slug(question.forum_id)}/post/#{slug(answer)}/toggle_correct">
+ <i class="fa fa-circle-o fa-stack-2x"/>
+ <i class="fa fa-check fa-stack-1x"/>
+ </a>
</t>
</div>
- <div class="col-11">
- <t t-if="answer.can_comment">
- <div class="dropdown dropleft float-right">
- <a class="btn bg-white" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
- <i class="fa fa-ellipsis-v text-primary"/>
- </a>
- <div class="dropdown-menu py-0 shadow" aria-labelledby="dropdownMenuButton">
- <t t-call="website_forum.link_button">
- <t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(answer) + '/edit'"/>
- <t t-set="label">Edit</t>
- <t t-set="inDropdown" t-value="True"/>
- <t t-set="icon" t-value="'fa-pencil-square-o text-primary'"/>
- <t t-set="classes" t-value="'border-bottom'"/>
- <t t-set="karma" t-value="not answer.can_edit and answer.karma_edit or 0"/>
- </t>
- <t t-call="website_forum.link_button">
- <t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(answer) + '/delete'"/>
- <t t-set="label">Delete</t>
- <t t-set="inDropdown" t-value="True"/>
- <t t-set="icon" t-value="'fa-trash-o text-primary'"/>
- <t t-set="classes" t-value="'border-bottom'"/>
- <t t-set="karma" t-value="not answer.can_unlink and answer.karma_unlink or 0"/>
- </t>
- <t t-if="answer.can_flag" t-call="website_forum.link_button">
- <t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(answer) + '/flag'"/>
- <t t-set="label" t-value="answer.state == 'flagged' and 'Flagged' or 'Flag'"/>
- <t t-set="form_method" t-value="'GET'"/>
- <t t-set="inDropdown" t-value="True"/>
- <t t-set="karma" t-value="not answer.can_flag and answer.forum_id.karma_flag or 0"/>
- <t t-set="icon" t-value="'fa-flag-o text-primary'"/>
- <t t-set="classes" t-value="'border-bottom'"/>
- <t t-set="form_classes" t-value="'flag'"/>
- </t>
- <t t-call="website_forum.link_button">
- <t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(answer) + '/convert_to_comment'"/>
- <t t-set="label">Convert as a comment</t>
- <t t-set="inDropdown" t-value="True"/>
- <t t-set="icon" t-value="'fa-magic text-primary'"/>
- <t t-set="karma" t-value="not answer.can_comment_convert and answer.karma_comment_convert or 0"/>
- </t>
- </div>
- </div>
- </t>
- <div class="author-box mb-3">
- <t t-set="user_profile_url" t-attf-value="#"/>
- <t t-if="answer.create_uid.id == request.session.uid or answer.create_uid.sudo().website_published">
- <t t-set="user_profile_url" t-value="'/forum/%s/user/%s' % (slug(forum), answer.create_uid.id)"/>
+ <div class="col">
+ <div class="o_wforum_answer_header d-flex align-items-start mb-2">
+ <t t-call="website_forum.author_box">
+ <t t-set="object" t-value="answer"/>
+ <t t-set="show_name" t-value="True"/>
+ <t t-set="show_date" t-value="True"/>
+ <t t-set="allow_biography" t-value="True"/>
+ <t t-set="object_validable" t-value="True"/>
</t>
- <div class="o_forum_user_bio_expand" t-if="answer.can_display_biography">
- <t t-call="website_forum.forum_user_tooltip"/>
+ <span class="o_wforum_answer_correct_badge border small border-success rounded-pill font-weight-bold text-success ml-2 px-2">
+ Best Answer
+ </span>
+ </div>
+
+ <div t-field="answer.content" class="mb-2 o_wforum_readable oe_no_empty"/>
+
+ <t t-set="_answer_comment_collapse_uid" t-value="'comment_%s_%s' % (answer._name.replace('.', '_'), answer.id)"/>
+ <div class="btn-toolbar mb-3">
+ <div t-if="question.uid_has_answered and answer.create_uid.id == uid"
+ class="btn-group btn-group-sm mr-1 mr-md-2">
+ <a class="btn btn-sm px-2 btn-primary"
+ title="Only one answer per question is allowed"
+ data-toggle="tooltip"
+ t-attf-href="/forum/#{slug(forum)}/question/#{slug(question)}/edit_answer">
+ <i class="fa fa-pencil"/>
+ Edit<span class="d-none d-lg-inline"> your answer</span>
+ </a>
</div>
- <a t-att-href="user_profile_url" class="o_forum_user_info">
- <img class="float-left o_forum_avatar" t-att-src="website.image_url(answer.create_uid, 'image_128')" alt="Avatar"/>
- </a>
- <a t-att-href="user_profile_url"
- t-field="answer.create_uid"
- t-options='{"widget": "contact", "country_image": True, "fields": ["name", "country_id"]}'
- style="display: inline-block;"/>
- <div class="text-muted">
- <a t-attf-href="/forum/#{slug(question.forum_id)}/question/#{slug(question)}#answer_#{answer.id}"><i class="fa fa-calendar text-muted"/></a>
- <span t-field="answer.create_date" t-options='{"format":"short"}'/>
+ <div class="btn-group btn-group-sm">
+ <a t-attf-class="btn border px-2 #{not answer.can_comment and 'karma_required text-muted'}"
+ t-attf-data-karma="#{not answer.can_comment and answer.karma_comment or 0}"
+ t-att-data-toggle="answer.can_comment and 'collapse' or None"
+ t-attf-data-target="##{_answer_comment_collapse_uid}">
+ <i t-attf-class="fa fa-comment text-muted #{not answer.can_comment and 'karma_required'}"/>
+ Comment
+ </a>
+ <a href="javascript:void(0)" class="oe_social_share btn border px-2"
+ t-attf-data-urlshare="#{request.httprequest.url}##{_answer_comment_collapse_uid}"
+ t-attf-data-hashtags="question">
+ <i class="fa fa-share-alt text-muted"/>
+ Share
+ </a>
</div>
- </div>
- <div class="clearfix border-bottom mb-2"><span t-field="answer.content" class="oe_no_empty"/></div>
- <t t-if="len(answer.website_message_ids)">
- <div class="clearfix mb-2">
- <div class="text-muted font-weight-bold d-inline">
- <t t-esc="len(answer.website_message_ids)"/>
- <t t-if="len(answer.website_message_ids) == 1">Comment</t>
- <t t-else="">Comments</t>
+ <div t-if="answer.can_comment" class="btn-group btn-group-sm ml-1 ml-md-2">
+ <a class="btn border dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+ More
+ </a>
+ <div class="dropdown-menu shadow">
+ <t t-if="not answer.create_uid.id == uid" t-call="website_forum.link_button">
+ <t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(answer) + '/edit'"/>
+ <t t-set="label">Edit</t>
+ <t t-set="inDropdown" t-value="True"/>
+ <t t-set="icon" t-value="'fa-pencil-square-o text-muted mr-2'"/>
+ <t t-set="karma" t-value="not answer.can_edit and answer.karma_edit or 0"/>
+ </t>
+ <t t-call="website_forum.link_button">
+ <t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(answer) + '/delete'"/>
+ <t t-set="label">Delete</t>
+ <t t-set="inDropdown" t-value="True"/>
+ <t t-set="icon" t-value="'fa-trash-o text-muted mr-2'"/>
+ <t t-set="karma" t-value="not answer.can_unlink and answer.karma_unlink or 0"/>
+ </t>
+ <t t-if="answer.can_flag" t-call="website_forum.link_button">
+ <t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(answer) + '/flag'"/>
+ <t t-set="label" t-value="answer.state == 'flagged' and 'Flagged' or 'Flag'"/>
+ <t t-set="form_method" t-value="'GET'"/>
+ <t t-set="inDropdown" t-value="True"/>
+ <t t-set="karma" t-value="not answer.can_flag and answer.forum_id.karma_flag or 0"/>
+ <t t-set="icon" t-value="'fa-flag-o text-muted mr-2'"/>
+ <t t-set="form_classes" t-value="'flag'"/>
+ </t>
+ <t t-call="website_forum.link_button">
+ <t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(answer) + '/convert_to_comment'"/>
+ <t t-set="label">Convert as a comment</t>
+ <t t-set="inDropdown" t-value="True"/>
+ <t t-set="icon" t-value="'fa-magic text-muted mr-2'"/>
+ <t t-set="karma" t-value="not answer.can_comment_convert and answer.karma_comment_convert or 0"/>
+ </t>
</div>
</div>
- </t>
+ </div>
<t t-call="website_forum.post_comment">
<t t-set="object" t-value="answer"/>
+ <t t-set="_collapse_uid" t-value="_answer_comment_collapse_uid"/>
</t>
<div t-foreach="answer.child_ids" t-as="child_answer" class="mt4 mb4">
- <t t-call="website_forum.post_answers">
- <t t-set="answer" t-value="child_answer"/>
- </t>
- </div>
- <div class="clearfix">
- <div>
- <div class="btn-group">
- <a t-attf-class="#{not answer.can_comment and 'karma_required text-muted' or ''}"
- t-attf-data-karma="#{not answer.can_comment and answer.karma_comment or 0}"
- style="cursor: pointer" t-att-data-toggle="answer.can_comment and 'collapse' or None"
- t-attf-data-target="#comment#{ answer._name.replace('.','') + '-' + str(answer.id) }">
- <i t-attf-class="fa fa-comment text-primary #{not answer.can_comment and 'karma_required text-muted' or ''}"/> Comment
- </a>
- <a href="javascript:void(0)" class="oe_social_share text-black ml-2 pl-2 border-left"
- t-attf-data-urlshare="#{request.httprequest.url}#comment#{ answer._name.replace('.','') + '-' + str(answer.id) }"
- t-attf-data-hashtags="question"><i class="fa fa-share-alt text-primary"/> Share
- </a>
- </div>
- </div>
- </div>
+ <t t-call="website_forum.post_answers">
+ <t t-set="answer" t-value="child_answer"/>
+ </t>
+ </div>
</div>
</div>
</div>
</div>
</template>
-<!-- Template for user tooltip -->
-<template id="forum_user_tooltip">
- <div class="o_forum_user_bio text-left card">
- <div class="card-body">
- <a t-att-href="user_profile_url">
- <img class="float-left img rounded o_forum_avatar_big" t-att-src="website.image_url(answer.create_uid, 'image_128')" alt="Avatar"/>
- </a>
- <div class="o_forum_tooltip_header">
- <h4 class="o_forum_tooltip_heading"><a t-att-href="user_profile_url"
- t-field="answer.create_uid"
- t-options='{"widget": "contact", "country_image": True, "fields": ["name", "country_id"]}'
- style="display: inline-block;"
- class="font-weight-bold"/>
- </h4>
- <span t-field="answer.create_uid" t-options='{"widget": "contact", "UserBio": True, "badges": True, "fields": ["karma"]}'/>
+<template id="website_forum.author_box">
+ <t t-set="display_info" t-value="show_name or show_date or show_karma"/>
+ <t t-if="allow_biography and object.can_display_biography" t-set="bio_popover_data">
+ <div class="d-flex o_wforum_bio_popover_wrap">
+ <img class="o_forum_avatar_big flex-shrink-0 mr-3" t-att-src="website.image_url(object.create_uid, 'image_128', '75x75')" alt="Avatar"/>
+ <div>
+ <h5 class="o_wforum_bio_popover_name mb-0" t-field="object.create_uid" t-options='{"widget": "contact", "country_image": True, "fields": ["name", "country_id"]}'/>
+
+ <span class="o_wforum_bio_popover_info" t-field="object.create_uid" t-options='{"widget": "contact", "UserBio": True, "badges": True, "fields": ["karma"]}'/>
+ <div class="o_wforum_bio_popover_bio" t-field="object.create_uid" t-options='{"widget": "contact", "website_description": True, "fields": ["partner_id"]}'/>
+ </div>
+ </div>
+ </t>
+
+ <div t-attf-class="o_wforum_author_box d-inline-flex #{display_info and 'o_show_info'} #{compact and 'o_compact align-items-center'} #{bio_popover_data and 'o_wforum_bio_popover'}"
+ t-att-data-content="bio_popover_data">
+ <t t-set="user_profile_url" value="#"/>
+ <t t-if="object.create_uid.id == request.session.uid or object.create_uid.sudo().website_published">
+ <t t-set="user_profile_url" t-value="'/forum/%s/user/%s' % (slug(forum), object.create_uid.id) + '?forum_origin=' + request.httprequest.path"/>
+ </t>
+
+ <a t-att-href="user_profile_url" class="o_wforum_author_pic position-relative rounded-circle">
+ <span t-if="object_validable" class="o_wforum_author_box_check rounded-circle bg-success position-absolute">
+ <i class="fa fa-check fa-fw small text-white"/>
+ </span>
+ <img t-attf-class="rounded-circle o_forum_avatar #{not display_info and 'shadow'}" t-att-src="website.image_url(object.create_uid, 'image_128', '40x40')" alt="Avatar"/>
+ </a>
+
+ <div t-if="show_name or show_date or show_karma" t-attf-class="d-flex #{compact and 'align-items-baseline ml-1' or 'flex-column justify-content-around ml-2'}">
+ <a t-att-href="user_profile_url" class="h6 my-0 text-reset" t-field="object.create_uid" t-options='{"widget": "contact", "fields": ["name"]}'/>
+ <small t-if="show_karma and show_date" class="text-muted font-weight-bold"> - <t t-esc="object.create_uid.karma"/>xp</small>
+
+ <div t-attf-class="text-muted small font-weight-bold #{compact and 'd-flex align-items-baseline'}">
+ <span t-if="compact" class="mx-1"> - </span>
+ <time t-if="show_date" class="d-block text-muted font-weight-bold" t-field="object.create_date" t-options='{"format": "d MMMM y"}'/>
+ <span t-if="show_karma and not show_date" class="text-muted font-weight-bold"><t t-esc="object.create_uid.karma"/>xp</span>
</div>
- <div t-field="answer.create_uid" t-options='{"widget": "contact", "website_description": True, "fields": ["partner_id"]}'/>
</div>
</div>
</template>
<!-- Utility template: Post a Comment -->
<template id="post_comment">
- <div class="row">
- <div class="col-12">
- <div t-foreach="reversed(object.website_message_ids)" t-as="message" class="comment card mb-2">
- <div class="card-body">
- <div t-attf-class="dropdown dropleft float-right">
- <a class="btn btn-sm btn-white" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
- <i class="fa fa-ellipsis-v text-primary"/>
- </a>
- <div class="dropdown-menu py-0 shadow" aria-labelledby="dropdownMenuButton">
- <t t-call="website_forum.link_button">
- <t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(object) + '/comment/' + slug(message) + '/delete'"/>
- <t t-set="label">Delete</t>
- <t t-set="title">Delete</t>
- <t t-set="inDropdown" t-value="True"/>
- <t t-set="icon" t-value="'fa-trash-o text-primary'"/>
- <t t-set="classes" t-value="'comment_delete border-bottom'"/>
- <t t-set="karma" t-value="not object.can_unlink and object.karma_unlink or 0"/>
- </t>
- <t t-call="website_forum.link_button">
- <t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(object) + '/comment/' + slug(message) + '/convert_to_answer'"/>
- <t t-set="label">Convert as a answer</t>
- <t t-set="inDropdown" t-value="True"/>
- <t t-set="icon" t-value="'fa-magic text-primary'"/>
- <t t-set="karma" t-value="not object.can_comment_convert and object.karma_comment_convert or 0"/>
- </t>
+ <div class="o_wforum_post_comments_container ml-2 ml-md-5">
+ <div t-if="len(object.website_message_ids)" class="o_wforum_comments_count_header mb-2">
+ <div class="text-muted font-weight-bold small">
+ <span class="o_wforum_comments_count" t-esc="len(object.website_message_ids)"/>
+ <t t-if="len(object.website_message_ids) == 1">Comment</t>
+ <t t-else="">Comments</t>
+ </div>
+ </div>
+ <div class="css_editable_mode_hidden o_wforum_readable">
+ <form t-att-id="_collapse_uid" class="collapse p-1 oe_comment_grey js_website_submit_form"
+ t-attf-action="/forum/#{slug(forum)}/post/#{slug(object)}/comment" method="POST">
+ <div class="shadow bg-white rounded px-3 pt-3 pb-4 mb-4">
+ <input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
+ <input name="post_id" t-att-value="object.id" type="hidden" class="mt8"/>
+ <div class="d-flex w-100">
+ <img class="d-none d-md-inline-block rounded-circle o_forum_avatar mr-3" t-att-src="website.image_url(user, 'image_128', '40x40')" alt="Avatar"/>
+ <div class="w-100">
+ <textarea name="comment" class="form-control mb-2" placeholder="Comment this post..."/>
+ <div>
+ <button type="submit" class="btn btn-primary">Post comment</button>
+ <a t-attf-href="##{_collapse_uid}" data-toggle="collapse" class="btn border">Discard</a>
+ </div>
</div>
</div>
- <small class="text-muted">
+ </div>
+ </form>
+ </div>
+
+ <div class="o_wforum_post_comments pl-3 pl-md-4 border-left">
+ <t t-foreach="object.website_message_ids" t-as="message">
+ <div t-attf-class="o_wforum_post_comment #{not message_first and 'mt-3'}">
+ <div>
<t t-set="required_karma" t-value="message.author_id.id == user.partner_id.id and object.forum_id.karma_comment_unlink_own or object.forum_id.karma_comment_unlink_all"/>
<t t-set="required_karma" t-value="message.author_id.id == user.partner_id.id and object.forum_id.karma_comment_convert_own or object.forum_id.karma_comment_convert_all"/>
<t t-if="(object.parent_id and object.parent_id.state != 'close' and object.parent_id.active != False) or (not object.parent_id and object.state != 'close' and object.active != False)">
<t t-set="allow_post_comment" t-value="True" />
</t>
- <a t-attf-href="/forum/#{slug(forum)}/partner/#{message.author_id.id}"
- t-field="message.author_id" t-options='{"widget": "contact", "country_image": True, "fields": ["name", "country_id"]}' class="font-weight-bold float-left mr-3 mt-1"/><i class="fa fa-calendar mr-1 pl-3 border-left"/><span t-field="message.date" t-options='{"format":"short"}'/>
- <div class="mt-2"><span t-field="message.body" class="oe_no_empty text-dark"/></div>
- </small>
+ <div class="d-flex">
+ <div class="mb-1" t-call="website_forum.author_box">
+ <t t-set="object" t-value="message"/>
+ <t t-set="compact" t-value="True"/>
+ <t t-set="show_name" t-value="True"/>
+ <t t-set="show_date" t-value="True"/>
+ </div>
+ <div class="dropdown ml-2">
+ <a class="btn btn-sm" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+ <i class="fa fa-ellipsis-v"/>
+ </a>
+ <div class="dropdown-menu shadow">
+ <t t-call="website_forum.link_button">
+ <t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(object) + '/comment/' + slug(message) + '/delete'"/>
+ <t t-set="label">Delete</t>
+ <t t-set="title">Delete</t>
+ <t t-set="inDropdown" t-value="True"/>
+ <t t-set="icon" t-value="'fa-trash-o text-muted'"/>
+ <t t-set="classes" t-value="'comment_delete'"/>
+ <t t-set="karma" t-value="not object.can_unlink and object.karma_unlink or 0"/>
+ </t>
+ <t t-call="website_forum.link_button">
+ <t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(object) + '/comment/' + slug(message) + '/convert_to_answer'"/>
+ <t t-set="label">Convert as a answer</t>
+ <t t-set="inDropdown" t-value="True"/>
+ <t t-set="icon" t-value="'fa-magic text-muted'"/>
+ <t t-set="karma" t-value="not object.can_comment_convert and object.karma_comment_convert or 0"/>
+ </t>
+ </div>
+ </div>
+ </div>
+ <div t-field="message.body" class="o_wforum_readable oe_no_empty"/>
+ </div>
</div>
- </div>
- <div class="css_editable_mode_hidden">
- <form t-attf-id="comment#{ object._name.replace('.','') + '-' + str(object.id) }" class="collapse oe_comment_grey js_website_submit_form"
- t-attf-action="/forum/#{slug(forum)}/post/#{slug(object)}/comment" method="POST">
- <input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
- <input name="post_id" t-att-value="object.id" type="hidden" class="mt8"/>
- <textarea name="comment" class="form-control" placeholder="Comment this post..."/>
- <button type="submit" class="btn btn-primary mt8">Post</button>
- </form>
- </div>
+ </t>
</div>
</div>
</template>
<template id="tag" name="Forum Tags">
<t t-call="website_forum.header">
- <h1 class="o_page_header">
- Tags
- </h1>
- <p class="text-muted">
- A tag is a label that categorizes your question with other,
- similar questions. Using the right tags makes it easier for
- others to find and answer your question. (Hover the mouse to follow/unfollow tag(s))
- </p>
- <nav t-if="pager_tag_chars">
- <ul class="pagination mt0 mb0">
- <li class="page-item disabled"><a class="page-link" aria-label="Filter" title="Filter"><i class="fa fa-filter"></i></a></li>
- <t t-foreach="pager_tag_chars" t-as="tuple_char">
- <li t-attf-class="page-item #{'active' if active_char_tag == tuple_char[1] else ''}"><a t-attf-href="/forum/#{slug(forum)}/tag/#{quote_plus(tuple_char[1])}" class="page-link"><t t-esc="tuple_char[0]"/></a></li>
- </t>
- </ul>
+ <nav t-if="pager_tag_chars" class="navbar navbar-light bg-light justify-content-start">
+ <t t-if="len(pager_tag_chars) &lt; 11">
+ <span class="navbar-text mr-3">Show Tags Starting By</span>
+ <ul class="pagination mt0 mb0">
+ <t t-foreach="pager_tag_chars" t-as="tuple_char">
+ <t t-if="tuple_char_index &lt; 11">
+ <li t-attf-class="page-item #{active_char_tag == tuple_char[1] and 'active'}"><a t-attf-href="/forum/#{slug(forum)}/tag/#{quote_plus(tuple_char[1])}" class="page-link"><t t-esc="tuple_char[0]"/></a></li>
+ </t>
+ </t>
+ </ul>
+ </t>
+ <div t-else="" class="form-inline" role="toolbar" aria-label="Toolbar with button groups">
+ <label for="filter" class="my-1 mr-2">Show Tags Starting By</label>
+ <select name="filter" class="custom-select" onchange="location = this.value;">
+ <t t-foreach="pager_tag_chars" t-as="tuple_char">
+ <option t-if="active_char_tag == tuple_char[1]" selected="selected" value="" t-esc="tuple_char[0]"/>
+ <option t-else="" t-attf-value="/forum/#{slug(forum)}/tag/#{quote_plus(tuple_char[1])}" t-esc="tuple_char[0]"/>
+ </t>
+ </select>
+ </div>
</nav>
- <div class="row">
+
+ <div class="row mb-5" t-if="tags">
<div class="col-md-3 mt16 o_js_forum_tag_follow" t-foreach="tags" t-as="tag">
- <b><t t-esc="tag.posts_count"/>&amp;nbsp;</b>
- <a t-attf-href="/forum/#{ slug(forum) }/tag/#{ slug(tag) }/questions?{{ keep_query( filters='tag') }}"
- t-attf-class="badge #{'badge-primary' if tag.message_is_follower else 'badge-secondary'} px-2">
- <span t-field="tag.name"/>
- </a>
- <span><i t-attf-class="fa #{'fa-star text-primary' if tag.message_is_follower else 'fa-star-o text-secondary'}" title="Subscribe" role="img" aria-label="Close"/></span>
- <div t-attf-class="o_forum_tag_follow_box">
- <div class="input-group">
- <t t-call="website_mail.follow">
- <t t-set="email" t-value="user_id.email"/>
- <t t-set="object" t-value="tag"/>
- </t>
+ <span t-attf-class="badge border px-2 #{tag.message_is_follower and 'border-success text-success' or 'badge-light text-600'}">
+ <i class="fa fa-tag small"/>
+ <t t-esc="tag.name"/>
+ <b class="small align-top">(<t t-esc="tag.posts_count"/>)</b>
+ </span>
+ <div class="o_forum_tag_follow_box text-center">
+ <div class="card shadow mt-2">
+ <a t-attf-href="/forum/#{ slug(forum) }/tag/#{ slug(tag) }/questions?{{ keep_query( filters='tag') }}"
+ class="btn btn-light">
+ See <t t-esc="tag.posts_count"/> post<t t-if="tag.posts_count > 1">s</t>
+ </a>
+ <em class="d-block mb-2">or</em>
+ <div class="input-group">
+ <t t-call="website_mail.follow">
+ <t t-set="email" t-value="user_id.email"/>
+ <t t-set="object" t-value="tag"/>
+ </t>
+ </div>
</div>
</div>
</div>
</div>
+ <div t-else="" class="alert border text-center">
+ No tags
+ </div>
</t>
</template>
<template id="moderation_queue" name="Forum Moderation Queue">
<t t-call="website_forum.header">
<t t-set="website_forum_action" t-value="'o_wforum_moderation_queue'"/>
- <h2 class="o_page_header">
- <t t-set="count_posts" t-value="len(posts_ids)"/>
- <span id="count_post" t-esc="count_posts"/>
- <span class="dropdown">
- <a href="#" class="dropdown-toggle" data-toggle="dropdown">
- <t t-if="queue_type == 'validation'"> Pending</t>
- <t t-if="queue_type == 'flagged'"> Flagged</t>
- <t t-if="queue_type == 'offensive'"> Offensive</t>
- </a>
- <div class="dropdown-menu" role="menu">
- <a role="menuitem" data-type="validation" t-attf-href="/forum/#{slug(forum)}/validation_queue" t-attf-class="dropdown-item#{queue_type == 'validation' and ' active' or ''}">Pending</a>
- <a role="menuitem" data-type="flagged" t-attf-href="/forum/#{slug(forum)}/flagged_queue" t-attf-class="dropdown-item#{queue_type == 'flagged' and ' active' or ''}">Flagged</a>
- <a role="menuitem" data-type="offensive" t-attf-href="/forum/#{slug(forum)}/offensive_posts" t-if="uid" t-attf-class="dropdown-item#{queue_type == 'offensive' and ' active' or ''}">Offensive</a>
- </div>
- </span>
- <button t-if="len(posts_ids) >= 10" type="button" class="btn btn-primary float-right" data-toggle="modal" data-target="#markAllAsSpam"><i class="fa fa-bug"></i> Mark as spam</button>
- </h2>
+ <div t-if="len(posts_ids) > 0" class="mb-2 text-right">
+ <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#markAllAsSpam"><i class="fa fa-bug"></i> Filter Tool</button>
+ </div>
+ <div t-attf-class="o_caught_up_alert alert text-center #{len(posts_ids) and 'd-none'}">
+ <i class="fa fa-check text-success d-block display-2"></i>
+ <b>You've Completely Caught Up!</b><br/>
+ <t t-if="queue_type == 'validation'">No post to be validated</t>
+ <t t-if="queue_type == 'flagged'">No flagged posts</t>
+ </div>
+
<div class="modal fade" t-att-data-spam-ids="str(posts_ids.ids)" id="markAllAsSpam" tabindex="-1" role="dialog" aria-labelledby="markAllAsSpam" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
- <div class="modal-header pb-0">
- <ul class="nav nav-tabs" id="myTab" role="tablist">
+ <div class="modal-header d-flex align-items-center pb-0">
+ <div class="text-muted mr-2">Filter by:</div>
+ <ul class="nav nav-tabs border-bottom-0" id="myTab" role="tablist">
<li class="nav-item">
<a class="nav-link active spam_menu" id="user-tab" data-toggle="tab" href="#spam_user" role="tab" aria-controls="user" aria-selected="true"><i class="fa fa-user"/> User</a>
</li>
@@ -1115,10 +1520,10 @@
<a class="nav-link spam_menu" id="country-tab" data-toggle="tab" href="#spam_country" role="tab" aria-controls="spam_country" aria-selected="false"><i class="fa fa-flag"/> Country</a>
</li>
<li class="nav-item">
- <a class="nav-link spam_menu" id="character-tab" data-toggle="tab" href="#spam_character" role="tab" aria-controls="spam_character" aria-selected="false">圾 Typical Character</a>
+ <a class="nav-link spam_menu" id="character-tab" data-toggle="tab" href="#spam_character" role="tab" aria-controls="spam_character" aria-selected="false">圾 Text</a>
</li>
</ul>
- <button type="button" class="close" data-dismiss="modal"><span>&amp;times;</span></button>
+ <button type="button" class="close align-self-start" data-dismiss="modal"><span>&amp;times;</span></button>
</div>
<div class="modal-body bg-100">
<div class="tab-content" id="o_tab_content_spam">
@@ -1130,10 +1535,8 @@
<div class="custom-control custom-checkbox">
<input type="checkbox" t-att-value="user.id" class="custom-control-input" t-attf-id="user_#{user.id}"/>
<label class="custom-control-label" t-attf-for="user_#{user.id}">
- <div class="col-11 d-inline-flex">
- <img class="d-inline img o_forum_avatar" t-att-src="website.image_url(user, 'image_128')" alt="Avatar"/>
- <b t-esc="user.name" class="d-inline"></b>
- </div>
+ <img class="d-inline img o_forum_avatar" t-att-src="website.image_url(user, 'image_128', '40x40')" alt="Avatar"/>
+ <span t-esc="user.name" class="d-inline"/>
</label>
</div>
</div>
@@ -1174,12 +1577,12 @@
<div t-foreach="posts_ids" t-as="question" class="post_to_validate card mb-3">
<div class="card-body">
<div class="row">
- <div class="col-md-2 col-sm-4 o_js_validation_queue mb-3">
- <div class="text-center border-right pr-4">
- <a t-attf-href="/forum/#{slug(forum)}/post/#{slug(question)}/validate" title="Validate" aria-label="Validate" class="btn btn-block border-success mb-2 bg-white"><i class="fa fa-check text-success"/></a>
- <a t-if="queue_type == 'validation'" t-attf-href="/forum/#{slug(forum)}/post/#{slug(question)}/refuse" title="Refuse" aria-label="Refuse" class="btn btn-block border-danger bg-white"><i class="fa fa-times text-danger"/></a>
- <a t-if="queue_type == 'flagged'" t-attf-href="/forum/#{slug(forum)}/post/#{slug(question)}/ask_for_mark_as_offensive" aria-label="Mark as offensive" title="Mark as offensive" class="btn btn-block border-danger mb-2 bg-white"><i class="fa fa-times text-danger"/></a>
- <a href="#" t-if="queue_type == 'offensive'" disabled="True" aria-label="Offensive" title="Offensive" class="btn btn-block border-danger bg-white"><i class="fa fa-times text-danger"/></a>
+ <div class="col-md-2 col-sm-3 o_js_validation_queue border-right">
+ <div class="text-center d-flex align-items-end flex-sm-column justify-content-end align-items-sm-stretch">
+ <a t-attf-href="/forum/#{slug(forum)}/post/#{slug(question)}/validate" title="Validate" aria-label="Validate" data-toggle="tooltip" class="btn border-success m-1 bg-white"><i class="fa fa-check text-success"/></a>
+ <a t-if="queue_type == 'validation'" t-attf-href="/forum/#{slug(forum)}/post/#{slug(question)}/refuse" data-toggle="tooltip" title="Refuse" aria-label="Refuse" class="btn border-danger m-1 bg-white"><i class="fa fa-times text-danger"/></a>
+ <a t-if="queue_type == 'flagged'" t-attf-href="/forum/#{slug(forum)}/post/#{slug(question)}/ask_for_mark_as_offensive" data-toggle="tooltip" aria-label="Mark as offensive" title="Mark as offensive" class="btn border-danger m-1 bg-white"><i class="fa fa-times text-danger"/></a>
+ <a href="#" t-if="queue_type == 'offensive'" disabled="True" aria-label="Offensive" title="Offensive" data-toggle="tooltip" class="btn border-danger bg-white"><i class="fa fa-times m-1 text-danger"/></a>
</div>
</div>
<t t-if="question.parent_id">
@@ -1196,9 +1599,9 @@
</small>
</div>
</t>
- <t t-if="not question.parent_id">
+ <div t-if="not question.parent_id" class="col">
<t t-call="website_forum.moderation_display_post_question_block"/>
- </t>
+ </div>
</div>
</div>
</div>
diff --git a/addons/website_forum/views/website_forum_profile.xml b/addons/website_forum/views/website_forum_profile.xml
index 1afdb913731..3143076313a 100644
--- a/addons/website_forum/views/website_forum_profile.xml
+++ b/addons/website_forum/views/website_forum_profile.xml
@@ -9,6 +9,17 @@
</xpath>
</template>
+ <template id="user_profile_sub_nav" inherit_id="website_profile.user_profile_sub_nav">
+ <xpath expr="//nav" position="before">
+ <div t-if="request.params.get('forum_origin')" class="o_wprofile_all_users_nav_btn_container col pr-0 flex-grow-0">
+ <a t-att-href="request.params.get('forum_origin')"
+ class="o_wprofile_all_users_nav_btn btn text-nowrap">
+ <i class="fa fa-chevron-left small"/> Back
+ </a>
+ </div>
+ </xpath>
+ </template>
+
<template id="user_profile_content" inherit_id="website_profile.user_profile_content">
<xpath expr="//table[@id='o_wprofile_sidebar_table']//tr[last()]" position="after">
<t t-if="forum and (up_votes or down_votes)">
@@ -43,11 +54,11 @@
</xpath>
<xpath expr="//div[@id='profile_extra_info_tabcontent']" position="inside">
<t t-if="forum">
- <div role="tabpanel" class="tab-pane" id="questions">
+ <div role="tabpanel" class="o_wforum_profile_tab tab-pane" id="questions">
<div class="mb32">
<h5 class="border-bottom pb-1">Questions</h5>
<t t-if="questions">
- <div class="mb16" t-foreach="questions" t-as="question">
+ <div class="mb4" t-foreach="questions" t-as="question">
<t t-call="website_forum.display_post"/>
</div>
</t>
@@ -56,15 +67,17 @@
</t>
</div>
<t t-if="favourite">
- <div class="mb32">
+ <div class="mb4">
<h5 class="border-bottom pb-1">Favourite Questions</h5>
<div t-foreach="favourite" t-as="question">
- <t t-call="website_forum.display_post"/>
+ <t t-call="website_forum.display_post">
+ <t t-set="hide_fav_icon" t-value="True"/>
+ </t>
</div>
</div>
</t>
<t t-if="followed">
- <div class="mb32">
+ <div class="mb4">
<h5 class="border-bottom pb-1">Followed Questions</h5>
<div t-foreach="followed" t-as="question" class="mb16">
<t t-call="website_forum.display_post"/>
@@ -72,7 +85,7 @@
</div>
</t>
</div>
- <div role="tabpanel" class="tab-pane" id="answers">
+ <div role="tabpanel" class="o_wforum_profile_tab tab-pane" id="answers">
<div class="mb32">
<h5 class="border-bottom pb-1">Answers</h5>
<t t-if="answers">
@@ -85,13 +98,13 @@
</t>
</div>
</div>
- <div role="tabpanel" class="tab-pane" id="votes" t-if="uid == user.id">
+ <div role="tabpanel" class="o_wforum_profile_tab tab-pane" id="votes" t-if="uid == user.id">
<div class="mb32">
<h5 class="border-bottom pb-1">Votes</h5>
<t t-call="website_forum.user_votes"/>
</div>
</div>
- <div role="tabpanel" class="tab-pane" id="activity" t-if="uid == user.id">
+ <div role="tabpanel" class="o_wforum_profile_tab tab-pane" id="activity" t-if="uid == user.id">
<div class="mb32">
<h5 class="border-bottom pb-1">Activities</h5>
<t t-call="website_forum.display_activities"/>