[IMP] mail: make emoji picker available in knowledge
Introduce header actions so that emoji picker in knowledge can have an action to remove emoji. Task-2980528 closes odoo/odoo#100010 Related: odoo/enterprise#31231 Signed-off-by: Louis Wicket (wil) <wil@odoo.com>
This commit is contained in:
+1
-1
@@ -2,7 +2,7 @@
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="mail.EmojiCategoryBarView" owl="1">
|
||||
<div class="o_EmojiCategoryBarView d-flex flex-shrink-0 overflow-auto bg-100 border-bottom" t-attf-class="{{ className }}" t-ref="root">
|
||||
<div class="o_EmojiCategoryBarView d-flex flex-shrink-0 overflow-auto" t-attf-class="{{ className }}" t-ref="root">
|
||||
<t t-foreach="emojiCategoryBarView.emojiCategoryViews" t-as="emojiCategoryView" t-key="emojiCategoryView.localId">
|
||||
<EmojiCategoryView record="emojiCategoryView"/>
|
||||
</t>
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registerMessagingComponent } from '@mail/utils/messaging_component';
|
||||
|
||||
const { Component } = owl;
|
||||
|
||||
export class EmojiPickerHeaderActionListView extends Component {
|
||||
|
||||
/**
|
||||
* @returns {EmojiPickerHeaderActionListView}
|
||||
*/
|
||||
get emojiPickerHeaderActionListView() {
|
||||
return this.props.record;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Object.assign(EmojiPickerHeaderActionListView, {
|
||||
props: { record: Object },
|
||||
template: 'mail.EmojiPickerHeaderActionListView',
|
||||
});
|
||||
|
||||
registerMessagingComponent(EmojiPickerHeaderActionListView);
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="mail.EmojiPickerHeaderActionListView" owl="1">
|
||||
<div class="o_EmojiPickerHeaderActionListView d-flex" t-attf-class="{{ className }}" t-ref="root">
|
||||
<EmojiPickerHeaderActionView t-foreach="emojiPickerHeaderActionListView.actionViews" t-as="actionView" t-key="actionView" record="actionView"/>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registerMessagingComponent } from '@mail/utils/messaging_component';
|
||||
|
||||
const { Component } = owl;
|
||||
|
||||
export class EmojiPickerHeaderActionView extends Component {
|
||||
|
||||
/**
|
||||
* @returns {EmojiPickerHeaderActionView}
|
||||
*/
|
||||
get emojiPickerHeaderActionView() {
|
||||
return this.props.record;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Object.assign(EmojiPickerHeaderActionView, {
|
||||
props: { record: Object },
|
||||
template: 'mail.EmojiPickerHeaderActionView',
|
||||
});
|
||||
|
||||
registerMessagingComponent(EmojiPickerHeaderActionView);
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="mail.EmojiPickerHeaderActionView" owl="1">
|
||||
<div class="o_EmojiPickerHeaderActionView d-flex" t-attf-class="{{ className }}" t-ref="root">
|
||||
<t
|
||||
t-component="constructor.components[emojiPickerHeaderActionView.contentComponentName]"
|
||||
t-props="{
|
||||
className: `o_EmojiPickerHeaderActionView_content`,
|
||||
record: emojiPickerHeaderActionView.content,
|
||||
}"
|
||||
/>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registerMessagingComponent } from '@mail/utils/messaging_component';
|
||||
|
||||
const { Component } = owl;
|
||||
|
||||
export class EmojiPickerHeaderView extends Component {
|
||||
|
||||
/**
|
||||
* @returns {EmojiPickerHeaderView}
|
||||
*/
|
||||
get emojiPickerHeaderView() {
|
||||
return this.props.record;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Object.assign(EmojiPickerHeaderView, {
|
||||
props: { record: Object },
|
||||
template: 'mail.EmojiPickerHeaderView',
|
||||
});
|
||||
|
||||
registerMessagingComponent(EmojiPickerHeaderView);
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="mail.EmojiPickerHeaderView" owl="1">
|
||||
<div class="o_EmojiPickerHeaderView d-flex bg-100 border-bottom" t-attf-class="{{ className }}" t-ref="root">
|
||||
<EmojiCategoryBarView record="emojiPickerHeaderView.emojiCategoryBarView"/>
|
||||
<span class="flex-grow-1"/>
|
||||
<EmojiPickerHeaderActionListView t-if="emojiPickerHeaderView.actionListView" record="emojiPickerHeaderView.actionListView"/>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
<t t-name="mail.EmojiPickerView" owl="1">
|
||||
<div class="o_EmojiPickerView d-flex flex-column" t-attf-class="{{ className }}" t-ref="root">
|
||||
<EmojiCategoryBarView record="emojiPickerView.emojiCategoryBarView"/>
|
||||
<EmojiPickerHeaderView record="emojiPickerView.headerView"/>
|
||||
<EmojiSearchBarView record="emojiPickerView.emojiSearchBarView"/>
|
||||
<EmojiGridView record="emojiPickerView.emojiGridView"/>
|
||||
</div>
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registerMessagingComponent } from '@mail/utils/messaging_component';
|
||||
|
||||
const { Component } = owl;
|
||||
|
||||
export class LegacyEmoji extends Component {}
|
||||
|
||||
Object.assign(LegacyEmoji, {
|
||||
props: {
|
||||
emojiView: Object,
|
||||
},
|
||||
template: 'mail.LegacyEmoji',
|
||||
});
|
||||
|
||||
registerMessagingComponent(LegacyEmoji);
|
||||
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="mail.LegacyEmoji" owl="1">
|
||||
<span class="o_LegacyEmoji p-1 fs-5 cursor-pointer" t-on-click="props.emojiView.emojiListView.onClickEmoji" t-att-title="props.emojiView.emoji.name" t-att-data-source="props.emojiView.emoji.sources[0]" t-att-data-unicode="props.emojiView.emoji.unicode" t-attf-class="{{ className }}" t-ref="root">
|
||||
<t t-esc="props.emojiView.emoji.unicode"/>
|
||||
</span>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
@@ -1,57 +0,0 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { useUpdate } from '@mail/component_hooks/use_update';
|
||||
import { registerMessagingComponent } from '@mail/utils/messaging_component';
|
||||
import { LegacyComponent } from '@web/legacy/legacy_component';
|
||||
|
||||
export class LegacyEmojiList extends LegacyComponent {
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
setup() {
|
||||
super.setup();
|
||||
useUpdate({ func: () => this._update() });
|
||||
}
|
||||
|
||||
get emojiListView() {
|
||||
return this.props.record;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_update() {
|
||||
this.trigger('o-popover-compute');
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
close() {
|
||||
this.trigger('o-popover-close');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given node is self or a children of self.
|
||||
*
|
||||
* @param {Node} node
|
||||
* @returns {boolean}
|
||||
*/
|
||||
contains(node) {
|
||||
return Boolean(this.root.el && this.root.el.contains(node));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Object.assign(LegacyEmojiList, {
|
||||
props: { record: Object },
|
||||
template: 'mail.LegacyEmojiList',
|
||||
});
|
||||
|
||||
registerMessagingComponent(LegacyEmojiList);
|
||||
@@ -1,9 +0,0 @@
|
||||
// ------------------------------------------------------------------
|
||||
// Layout
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
.o_LegacyEmojiList {
|
||||
// Could be replaced by "d-grid" class after migration to BS5
|
||||
display: grid;
|
||||
grid-template-columns: repeat(9, 1fr);
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="mail.LegacyEmojiList" owl="1">
|
||||
<div class="o_LegacyEmojiList px-1" t-attf-class="{{ className }}" t-ref="root">
|
||||
<t t-if="emojiListView">
|
||||
<t t-foreach="emojiListView.emojiViews" t-as="emojiView" t-key="emojiView.localId">
|
||||
<LegacyEmoji emojiView="emojiView"/>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
@@ -2,19 +2,26 @@
|
||||
|
||||
import { registerModel } from '@mail/model/model_core';
|
||||
import { many, one } from '@mail/model/model_field';
|
||||
import { clear } from '@mail/model/model_field_command';
|
||||
|
||||
registerModel({
|
||||
name: 'EmojiCategoryBarView',
|
||||
fields: {
|
||||
emojiCategoryViews: many('EmojiCategoryView', {
|
||||
compute() {
|
||||
return this.emojiPickerViewOwner.categories.map(category => ({ viewCategory: category }));
|
||||
if (!this.emojiPickerView) {
|
||||
return clear();
|
||||
}
|
||||
return this.emojiPickerView.categories.map(category => ({ viewCategory: category }));
|
||||
},
|
||||
inverse: 'emojiCategoryBarViewOwner',
|
||||
}),
|
||||
emojiPickerViewOwner: one('EmojiPickerView', {
|
||||
emojiPickerHeaderViewOwner: one('EmojiPickerHeaderView', {
|
||||
identifying: true,
|
||||
inverse: 'emojiCategoryBarView',
|
||||
}),
|
||||
emojiPickerView: one('EmojiPickerView', {
|
||||
related: 'emojiPickerHeaderViewOwner.emojiPickerViewOwner',
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -10,16 +10,16 @@ registerModel({
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
onClick() {
|
||||
this.emojiCategoryBarViewOwner.emojiPickerViewOwner.emojiSearchBarView.reset();
|
||||
this.emojiPickerView.emojiSearchBarView.reset();
|
||||
let categoryRowScrollPosition = Math.max(
|
||||
0,
|
||||
// Index of the beginning of the category
|
||||
(this.emojiCategoryBarViewOwner.emojiPickerViewOwner.emojiGridView.rowHeight * this.viewCategory.emojiGridRowView.index)
|
||||
(this.emojiPickerView.emojiGridView.rowHeight * this.viewCategory.emojiGridRowView.index)
|
||||
-
|
||||
// Cancels the amount of buffer rows
|
||||
(this.emojiCategoryBarViewOwner.emojiPickerViewOwner.emojiGridView.rowHeight * this.emojiCategoryBarViewOwner.emojiPickerViewOwner.emojiGridView.topBufferAmount)
|
||||
(this.emojiPickerView.emojiGridView.rowHeight * this.emojiPickerView.emojiGridView.topBufferAmount)
|
||||
);
|
||||
this.emojiCategoryBarViewOwner.emojiPickerViewOwner.emojiGridView.containerRef.el.scrollTo({ top: categoryRowScrollPosition });
|
||||
this.emojiPickerView.emojiGridView.containerRef.el.scrollTo({ top: categoryRowScrollPosition });
|
||||
},
|
||||
/**
|
||||
* @param {MouseEvent} ev
|
||||
@@ -42,6 +42,9 @@ registerModel({
|
||||
identifying: true,
|
||||
inverse: 'emojiCategoryViews',
|
||||
}),
|
||||
emojiPickerView: one('EmojiPickerView', {
|
||||
related: 'emojiCategoryBarViewOwner.emojiPickerView',
|
||||
}),
|
||||
isActive: attr({
|
||||
compute() {
|
||||
return Boolean(this.viewCategory.emojiPickerViewAsActive);
|
||||
|
||||
@@ -19,6 +19,9 @@ registerModel({
|
||||
});
|
||||
},
|
||||
onScroll() {
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
this.onScrollThrottle.do();
|
||||
},
|
||||
_onChangeScrollRecomputeCount() {
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registerModel } from '@mail/model/model_core';
|
||||
import { many, one } from '@mail/model/model_field';
|
||||
|
||||
registerModel({
|
||||
name: 'EmojiPickerHeaderActionListView',
|
||||
fields: {
|
||||
__dummyActionView: one('EmojiPickerHeaderActionView', {
|
||||
inverse: '__ownerAsDummy',
|
||||
}),
|
||||
actionViews: many('EmojiPickerHeaderActionView', {
|
||||
inverse: 'owner',
|
||||
sort() {
|
||||
return [
|
||||
['smaller-first', 'sequence'],
|
||||
];
|
||||
},
|
||||
}),
|
||||
emojiPickerView: one('EmojiPickerView', {
|
||||
related: 'owner.emojiPickerViewOwner',
|
||||
}),
|
||||
owner: one('EmojiPickerHeaderView', {
|
||||
identifying: true,
|
||||
inverse: 'actionListView',
|
||||
}),
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,39 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registerModel } from '@mail/model/model_core';
|
||||
import { attr, one } from '@mail/model/model_field';
|
||||
import { clear } from '@mail/model/model_field_command';
|
||||
|
||||
registerModel({
|
||||
name: 'EmojiPickerHeaderActionView',
|
||||
identifyingMode: 'xor',
|
||||
fields: {
|
||||
// dummy identifying field, so that it works without defining one initially in mail
|
||||
__ownerAsDummy: one('EmojiPickerHeaderActionListView', {
|
||||
identifying: true,
|
||||
inverse: '__dummyActionView',
|
||||
}),
|
||||
content: one('Record', {
|
||||
compute() {
|
||||
return clear();
|
||||
},
|
||||
required: true,
|
||||
}),
|
||||
contentComponentName: attr({
|
||||
compute() {
|
||||
return clear();
|
||||
},
|
||||
required: true,
|
||||
}),
|
||||
owner: one('EmojiPickerHeaderActionListView', {
|
||||
compute() {
|
||||
return clear();
|
||||
},
|
||||
required: true,
|
||||
inverse: 'actionViews',
|
||||
}),
|
||||
sequence: attr({
|
||||
default: 0,
|
||||
}),
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registerModel } from '@mail/model/model_core';
|
||||
import { one } from '@mail/model/model_field';
|
||||
|
||||
registerModel({
|
||||
name: 'EmojiPickerHeaderView',
|
||||
fields: {
|
||||
actionListView: one('EmojiPickerHeaderActionListView', {
|
||||
default: {},
|
||||
isCausal: true,
|
||||
inverse: 'owner',
|
||||
}),
|
||||
emojiCategoryBarView: one('EmojiCategoryBarView', {
|
||||
default: {},
|
||||
inverse: 'emojiPickerHeaderViewOwner',
|
||||
readonly: true,
|
||||
required: true,
|
||||
}),
|
||||
emojiPickerViewOwner: one('EmojiPickerView', {
|
||||
identifying: true,
|
||||
inverse: 'headerView',
|
||||
}),
|
||||
},
|
||||
});
|
||||
@@ -37,12 +37,6 @@ registerModel({
|
||||
return this.categories[0];
|
||||
},
|
||||
}),
|
||||
emojiCategoryBarView: one('EmojiCategoryBarView', {
|
||||
default: {},
|
||||
inverse: 'emojiPickerViewOwner',
|
||||
readonly: true,
|
||||
required: true,
|
||||
}),
|
||||
emojiGridView: one('EmojiGridView', {
|
||||
default: {},
|
||||
inverse: 'emojiPickerViewOwner',
|
||||
@@ -54,6 +48,12 @@ registerModel({
|
||||
inverse: 'emojiPickerView',
|
||||
readonly: true,
|
||||
}),
|
||||
headerView: one('EmojiPickerHeaderView', {
|
||||
default: {},
|
||||
inverse: 'emojiPickerViewOwner',
|
||||
readonly: true,
|
||||
required: true,
|
||||
}),
|
||||
popoverViewOwner: one('PopoverView', {
|
||||
identifying: true,
|
||||
inverse: 'emojiPickerView',
|
||||
|
||||
Reference in New Issue
Block a user