[IMP] website_forum, *: revamp design

* web_editor, website_profile

Part of https://github.com/odoo/odoo/pull/35749
task-2024197

Co-authored-by: Jérémy Kersten <jke@odoo.com>
Co-authored-by: qsm-odoo <qsm@odoo.com>
Co-authored-by: fja-odoo <fja@odoo.com>
This commit is contained in:
sri-odoo
2019-10-01 16:52:20 +00:00
committed by qsm-odoo
co-authored by Jérémy Kersten qsm-odoo fja-odoo
parent 83284a962c
commit c8c8eb3d56
16 changed files with 1497 additions and 995 deletions
@@ -3,6 +3,7 @@ odoo.define('web_editor.summernote', function (require) {
var core = require('web.core');
require('summernote/summernote'); // wait that summernote is loaded
var weDefaultOptions = require('web_editor.wysiwyg.default_options');
var _t = core._t;
@@ -1044,7 +1045,7 @@ options.keyMap.mac['ESCAPE'] = 'cancel';
options.keyMap.mac['UP'] = 'up';
options.keyMap.mac['DOWN'] = 'down';
options.styleTags = ['p', 'pre', 'small', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote'];
options.styleTags = weDefaultOptions.styleTags;
$.summernote.pluginEvents.insertTable = function (event, editor, layoutInfo, sDim) {
var $editable = layoutInfo.editable();
@@ -2083,7 +2084,7 @@ eventHandler.modules.editor.currentStyle = function (target) {
return styleInfo;
};
options.fontSizes = [_t('Default'), 8, 9, 10, 11, 12, 14, 18, 24, 36, 48, 62];
options.fontSizes = weDefaultOptions.fontSizes;
$.summernote.pluginEvents.applyFont = function (event, editor, layoutInfo, color, bgcolor, size) {
var r = range.create();
if (!r) return;
@@ -2486,7 +2487,7 @@ function mouseDownChecklist (e) {
$lis.addClass('o_checked');
} while ($lis.length);
}
};
}
var fn_attach = eventHandler.attach;
eventHandler.attach = function (oLayoutInfo, options) {
@@ -60,3 +60,25 @@ var WysiwygRoot = Widget.extend({
return WysiwygRoot;
});
odoo.define('web_editor.wysiwyg.default_options', function (require) {
'use strict';
/**
* TODO this should be refactored to be done another way, same as the 'root'
* module that should be done another way.
*
* This allows to have access to default options that are used in the summernote
* editor so that they can be tweaked (instead of entirely replaced) when using
* the editor on an editable content.
*/
var core = require('web.core');
var _lt = core._lt;
return {
styleTags: ['p', 'pre', 'small', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote'],
fontSizes: [_lt('Default'), 8, 9, 10, 11, 12, 14, 18, 24, 36, 48, 62],
};
});
+24 -10
View File
@@ -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)
+1
View File
@@ -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">
@@ -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">
+2 -1
View File
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
from . import forum
from . import gamification
from . import res_users
from . import forum
from . import website
+3 -8
View File
@@ -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>
+15
View File
@@ -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)
@@ -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",
}]);
@@ -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,61 +352,38 @@ 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);
_.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');
// TODO in master, review the utility of this function...
self._onCheckAnswerStatus(ev);
// 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});
});
}
});
},
/**
* @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
@@ -398,7 +394,8 @@ publicWidget.registry.websiteForum = publicWidget.Widget.extend({
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();
}
});
},
/**
@@ -1,223 +1,229 @@
$gold: #ffcc00;
$gold: #eca801;
$silver: #cccccc;
$bronze: #eea91e;
.website_forum {
.question-block .question-name {
max-width: 80%;
.o_forum_ask_btn {
@include media-breakpoint-up(md) {
box-shadow: $box-shadow;
width: 200px;
}
}
.o_post_content {
pre {
padding: 1.5rem;
border-radius: 5px;
color: $white;
background-color: $gray-700;
.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;
}
}
&.active {
background-color: rgba(theme-color('info'), 0.1);
color: darken(theme-color('info'), 15%)!important;
}
}
// Single Post
.o_wforum_post, .note-editable.panel-body {
word-wrap: break-word;
pre {
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;
}
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%;
padding-left: 1em;
border-left: .25em solid gray('500');
color: gray('600');
}
}
.post_to_validate {
overflow: hidden;
.validate_answer {
.o_wforum_readable {
max-width: 700px;
p {
margin-bottom: 0.5rem;
}
}
textarea.o_wysiwyg_loader + .note-editor {
border: 0;
.note-toolbar {
@include border-top-radius($border-radius);
height: 32px;
}
.note-editable, .note-statusbar {
border: 1px solid $border-color;
border-width: 0 1px;
}
.note-statusbar {
display: block;
border-bottom-width: 1px;
}
}
.o_wforum_author_box {
&.o_show_info {
line-height: 1.2;
img {
@include size(2em);
}
}
&.o_compact {
line-height: 1;
img {
@include size(1.4em);
}
}
}
.forum_answer {
.o_wforum_answer_correct_badge {
display: none;
}
}
.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
> .bg-success {
@include o-position-absolute(0, 0, 0, 0);
.o_wforum_author_box_check {
@include size(1em);
display: none;
top: 0;
right: -3px;
box-shadow: 0 0 0 2px white;
line-height: .8;
}
> span {
@include o-position-absolute(10px, 50%);
transform: translateX(50%);
font-size: 20px;
&[data-href] {
cursor: pointer;
.o_wforum_validate_toggler {
@include o-hover-text-color(gray('400'), lighten(theme-color('success'), 20%));
}
&.o_wforum_answer_correct {
.o_wforum_answer_correct_badge, .o_wforum_author_box .o_wforum_author_box_check {
display: inline;
}
i {
padding: 2px 3px;
border-radius: 100%;
.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;
}
}
}
.user_name_people {
font-weight: bold;
max-width: 60%;
.o_wforum_gold {
color: $gold;
}
.oe_answer_true {
color: theme-color('success');
&:hover {
color: lighten(theme-color('success'), 20%);
}
}
.oe_answer_false {
color: $gray-400;
&:hover {
color: $gray-600;
}
}
.favourite_question {
color: $gray-400 !important;
&.forum_favourite_question {
color: $gold !important;
}
}
.oe_grey {
background-color: #eeeeee;
}
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'));
}
.vote_down {
@include o-hover-text-color(rgba($text-muted, 0.5), theme-color('danger'));
}
&.o_wforum_vote_vertical {
@include media-breakpoint-up(sm) {
font-size: 1.2em;
}
}
}
}
.oe_forum_email_required {
position: absolute;
margin-top: 155px;
margin-left: 500px;
margin-right: 100px;
z-index: 5;
.o_js_forum_tag_follow {
.badge {
font-size: 100%;
}
button.btn-link.text-muted {
color: $gray-600;
.o_forum_tag_follow_box {
@include o-position-absolute(100%, auto, auto, 0);
display: none;
z-index: 1;
.card {
padding: ($grid-gutter-width*0.5) - 1px;
}
}
}
.o_forum_tag_follow_box {
position: absolute;
display: none;
z-index: 1;
text-align: center;
opacity: 0.9;
}
.forum_answer {
position: relative;
}
.o_wforum_post_count_answer_count {
border-left: 3px solid;
}
.o_profile_main {
overflow: hidden;
}
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_forum_tooltip_heading {
padding: 0;
margin: 0;
font-size: 18px;
}
.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_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_header {
min-height: 75px;
.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_wforum_bio_popover_bio p {
margin-top: 8px;
margin-bottom: 0;
}
}
@@ -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")',
}]);
});
File diff suppressed because it is too large Load Diff
@@ -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"/>
@@ -133,16 +133,43 @@ $owprofile-color-bg: mix($body-bg, #efeff4);
.o_wprofile_all_users_nav {
border-width: 1px 0;
&, .o_wprofile_course_nav_search {
&, .o_wprofile_course_nav_search, .o_wprofile_all_users_nav_btn {
background-color: rgba(white, 0.05);
border-color: rgba(white, 0.1);
border-style: solid;
}
.o_wprofile_course_nav_search {
.o_wprofile_course_nav_search, .o_wprofile_all_users_nav_btn {
border-width: 0 1px;
}
.o_wprofile_all_users_nav_btn {
@include media-breakpoint-up(md) {
@include o-hover-text-color(white, $gray-800);
margin-top: -1px;
border-radius: 0;
min-height: 35px;
&:hover {
background-color: white;
}
}
}
.o_wprofile_all_users_nav_btn_container {
@include media-breakpoint-down(sm) {
~ .o_wprofile_user_profile_sub_nav_mobile_col {
padding-left: 0;
}
.o_wprofile_all_users_nav_btn {
@include o-hover-text-color(white, white);
border-radius: $btn-border-radius;
background-color: rgba(black, 0.25);
}
}
}
.breadcrumb-item.active a, .breadcrumb-item a:hover {
color: white;
}
@@ -41,7 +41,7 @@
</div>
<!-- Mobile Mode -->
<div class="col d-md-none py-1">
<div class="col d-md-none py-1 o_wprofile_user_profile_sub_nav_mobile_col">
<div class="btn-group w-100 position-relative" role="group" aria-label="Mobile sub-nav">
<div class="btn-group w-100 ml-2">
<a class="btn bg-black-25 text-white dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Nav</a>