diff options
Diffstat (limited to 'addons/website_forum')
| -rw-r--r-- | addons/website_forum/controllers/main.py | 34 | ||||
| -rw-r--r-- | addons/website_forum/data/forum_data.xml | 1 | ||||
| -rw-r--r-- | addons/website_forum/data/forum_default_faq.html | 2 | ||||
| -rw-r--r-- | addons/website_forum/models/__init__.py | 3 | ||||
| -rw-r--r-- | addons/website_forum/models/forum.py | 11 | ||||
| -rw-r--r-- | addons/website_forum/models/website.py | 15 | ||||
| -rw-r--r-- | addons/website_forum/static/src/js/tours/website_forum.js | 4 | ||||
| -rw-r--r-- | addons/website_forum/static/src/js/website_forum.js | 134 | ||||
| -rw-r--r-- | addons/website_forum/static/src/scss/website_forum.scss | 300 | ||||
| -rw-r--r-- | addons/website_forum/static/tests/tours/website_forum_question.js | 8 | ||||
| -rw-r--r-- | addons/website_forum/views/website_forum.xml | 1827 | ||||
| -rw-r--r-- | addons/website_forum/views/website_forum_profile.xml | 29 |
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)<=0"> - <h6 class="card-header"> - <b> - <t t-if="len(question.tag_ids)<=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>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}&view_type=form&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}&view_type=form&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}&view_type=form&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<=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<=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<=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">&nbsp;|</span> + <a t-if="len(question.child_ids)>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<=1">View</t><t t-else="">Views</t> + <span t-if="question.favourite_count > 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)>0"> - (<t t-esc="len(answer.website_message_ids)"/> - <t t-if="len(answer.website_message_ids)>1"> Comments</t> - <t t-if="len(answer.website_message_ids)<=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')">×</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')">×</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')">×</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')">×</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) }">×</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) }">×</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">×</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">×</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">×</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">&nbsp;and&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 < 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 < 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 < forum.karma_edit_retag" t-att-title="'You need to have sufficient karma to edit tags' if user.karma < forum.karma_edit_retag else ''"/> - <br/> + <t t-set="edit_tags_karma_fail" t-value="user.karma < 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 < forum.karma_moderate"> + + <div class="alert alert-warning text-center" role="status" + t-if="question.state == 'pending' and user.karma < 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<=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) < 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 < 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"/>&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>&times;</span></button> + <button type="button" class="close align-self-start" data-dismiss="modal"><span>&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"/> |
