[IMP] knowledge: reorder functions alphabetically
Small reorganisation of the code to order functions alphabetically in knowledge_controller and knowledge_renderer Task-2858428 X-original-commit: 874dc4a93af72c706ff756b29af96f7030a3423a Part-of: odoo/odoo#93088
This commit is contained in:
@@ -19,7 +19,6 @@ const KnowledgeArticleFormController = FormController.extend({
|
||||
'click i.o_toggle_favorite': '_onToggleFavorite',
|
||||
'input .o_breadcrumb_article_name': '_adjustInputSize',
|
||||
}),
|
||||
|
||||
custom_events: Object.assign({}, FormController.prototype.custom_events, {
|
||||
create: '_onCreate',
|
||||
duplicate: '_onDuplicate',
|
||||
@@ -28,7 +27,6 @@ const KnowledgeArticleFormController = FormController.extend({
|
||||
reload_tree: '_onReloadTree',
|
||||
emoji_click: '_onEmojiClick',
|
||||
}),
|
||||
|
||||
/**
|
||||
* Register the fact that the current @see FormController is one from
|
||||
* Knowledge in order not to try and search for a matching record for
|
||||
@@ -50,14 +48,28 @@ const KnowledgeArticleFormController = FormController.extend({
|
||||
this._super.apply(this, arguments);
|
||||
this.onFieldSavedListeners = new Map();
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
saveRecord: async function () {
|
||||
const modifiedFields = await this._super(...arguments);
|
||||
const { data } = this.model.get(this.handle);
|
||||
for (const field of modifiedFields) {
|
||||
if (this.onFieldSavedListeners.has(field)) {
|
||||
this.onFieldSavedListeners.get(field).forEach(listener => {
|
||||
listener.call(this, data[field]);
|
||||
});
|
||||
}
|
||||
}
|
||||
return modifiedFields;
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
* @returns {Promise}
|
||||
*/
|
||||
start: function () {
|
||||
return this._super.apply(this, arguments).then(() => {
|
||||
this.onFieldSaved('icon', unicode => {
|
||||
this._onFieldSaved('icon', unicode => {
|
||||
const { id } = this.getState();
|
||||
this.renderer._setEmoji(id, unicode);
|
||||
});
|
||||
@@ -66,6 +78,18 @@ const KnowledgeArticleFormController = FormController.extend({
|
||||
|
||||
// Listeners:
|
||||
|
||||
/**
|
||||
* @param {Event} event
|
||||
*/
|
||||
_adjustInputSize: function (event) {
|
||||
event.target.setAttribute('size', event.target.value.length);
|
||||
},
|
||||
_onAddCover: async function() {
|
||||
if (this.mode === 'readonly') {
|
||||
await this._setMode('edit');
|
||||
}
|
||||
this.$('.o_input_file').click();
|
||||
},
|
||||
_onAddRandomIcon: function() {
|
||||
this.trigger_up('field_changed', {
|
||||
dataPointID: this.handle,
|
||||
@@ -74,50 +98,13 @@ const KnowledgeArticleFormController = FormController.extend({
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_onAddCover: async function() {
|
||||
if (this.mode === 'readonly') {
|
||||
await this._setMode('edit');
|
||||
}
|
||||
this.$('.o_input_file').click();
|
||||
},
|
||||
|
||||
/**
|
||||
* When the user clicks on a field in readonly mode, a new 'quick_edit' event
|
||||
* will be triggered. To prevent the view from switching to the edit mode when
|
||||
* the article is locked, we will overwrite the `_onQuickEdit` handler. This
|
||||
* function will now ignore the event if the article is locked.
|
||||
* @override
|
||||
*/
|
||||
_onQuickEdit: function () {
|
||||
const { data } = this.model.get(this.handle);
|
||||
if (data.is_locked) {
|
||||
return;
|
||||
}
|
||||
this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback function called when the user renames the active article.
|
||||
* The function will update the name of the articles in the aside block.
|
||||
* @param {Event} event
|
||||
*/
|
||||
_onRename: async function (event) {
|
||||
var name = event.currentTarget.value;
|
||||
if (name.length === 0) {
|
||||
name = _t('New Article');
|
||||
}
|
||||
const id = await this._getId();
|
||||
await this._rename(id, name);
|
||||
},
|
||||
|
||||
/**
|
||||
* When the user clicks on the name of the article, checks if the article
|
||||
* name hasn't been set yet. If it hasn't, it will look for a title in the
|
||||
* body of the article and set it as the name of the article.
|
||||
* @param {Event} event
|
||||
*/
|
||||
_onArticleBreadcrumbClick: async function (event) {
|
||||
_onArticleBreadcrumbClick: async function (event) {
|
||||
const name = event.currentTarget.value;
|
||||
if (name === _t('New Article')) {
|
||||
const $articleTitle = this.$('.o_knowledge_editor h1');
|
||||
@@ -133,14 +120,12 @@ const KnowledgeArticleFormController = FormController.extend({
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Event} event
|
||||
* @param {OdooEvent} event
|
||||
*/
|
||||
_adjustInputSize: function (event) {
|
||||
event.target.setAttribute('size', event.target.value.length);
|
||||
_onCreate: async function (event) {
|
||||
await this._create(event.data);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {OdooEvent} event
|
||||
*/
|
||||
@@ -151,21 +136,78 @@ const KnowledgeArticleFormController = FormController.extend({
|
||||
additional_context: { res_id }
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {OdooEvent} event
|
||||
* @param {Event} event
|
||||
*/
|
||||
_onCreate: async function (event) {
|
||||
await this._create(event.data);
|
||||
_onEmojiClick: async function (event) {
|
||||
const { id } = this.getState();
|
||||
const { articleId, unicode } = event.data;
|
||||
if (articleId === id) {
|
||||
this.trigger_up('field_changed', {
|
||||
dataPointID: this.handle,
|
||||
changes: {
|
||||
icon: unicode
|
||||
}
|
||||
});
|
||||
} else {
|
||||
const result = await this._rpc({
|
||||
model: 'knowledge.article',
|
||||
method: 'write',
|
||||
args: [[articleId], { icon: unicode }],
|
||||
});
|
||||
if (result) {
|
||||
this.renderer._setEmoji(articleId, unicode);
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
* @param {Event} event
|
||||
*/
|
||||
_onFieldChanged: async function (event) {
|
||||
this._super(...arguments);
|
||||
const { changes } = event.data;
|
||||
for (const field of this._getFieldsToForceSave()) {
|
||||
if (changes.hasOwnProperty(field)) {
|
||||
await this.saveRecord(this.handle, {
|
||||
reload: false,
|
||||
stayInEdit: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @param {String} name - field name
|
||||
* @param {Function} callback
|
||||
*/
|
||||
_onFieldSaved: function (name, callback) {
|
||||
if (this.onFieldSavedListeners.has(name)) {
|
||||
this.onFieldSavedListeners.get(name).push(callback);
|
||||
} else {
|
||||
this.onFieldSavedListeners.set(name, [callback]);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* When the user clicks on a field in readonly mode, a new 'quick_edit' event
|
||||
* will be triggered. To prevent the view from switching to the edit mode when
|
||||
* the article is locked, we will overwrite the `_onQuickEdit` handler. This
|
||||
* function will now ignore the event if the article is locked.
|
||||
* @override
|
||||
*/
|
||||
_onQuickEdit: function () {
|
||||
const { data } = this.model.get(this.handle);
|
||||
if (data.is_locked) {
|
||||
return;
|
||||
}
|
||||
this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Event} event
|
||||
*/
|
||||
_onMove: function (event) {
|
||||
this._confirmMove(event.data);
|
||||
},
|
||||
|
||||
/**
|
||||
* Opens the "Move To" modal
|
||||
* @param {OdooEvent} event
|
||||
@@ -197,7 +239,6 @@ const KnowledgeArticleFormController = FormController.extend({
|
||||
});
|
||||
dialog.open();
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Event} event
|
||||
*/
|
||||
@@ -205,7 +246,19 @@ const KnowledgeArticleFormController = FormController.extend({
|
||||
// TODO JBN: Create a widget for the tree and reload it without reloading the whole view.
|
||||
this.reload();
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback function called when the user renames the active article.
|
||||
* The function will update the name of the articles in the aside block.
|
||||
* @param {Event} event
|
||||
*/
|
||||
_onRename: async function (event) {
|
||||
var name = event.currentTarget.value;
|
||||
if (name.length === 0) {
|
||||
name = _t('New Article');
|
||||
}
|
||||
const id = await this._getId();
|
||||
await this._rename(id, name);
|
||||
},
|
||||
/**
|
||||
* @param {Event} event
|
||||
*/
|
||||
@@ -215,7 +268,6 @@ const KnowledgeArticleFormController = FormController.extend({
|
||||
searchValue: "?",
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Event} event
|
||||
*/
|
||||
@@ -237,69 +289,10 @@ const KnowledgeArticleFormController = FormController.extend({
|
||||
this.renderer._setTreeFavoriteListener();
|
||||
this.renderer._renderEmojiPicker($dom);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Event} event
|
||||
*/
|
||||
_onEmojiClick: async function (event) {
|
||||
const { id } = this.getState();
|
||||
const { articleId, unicode } = event.data;
|
||||
if (articleId === id) {
|
||||
this.trigger_up('field_changed', {
|
||||
dataPointID: this.handle,
|
||||
changes: {
|
||||
icon: unicode
|
||||
}
|
||||
});
|
||||
} else {
|
||||
const result = await this._rpc({
|
||||
model: 'knowledge.article',
|
||||
method: 'write',
|
||||
args: [[articleId], { icon: unicode }],
|
||||
});
|
||||
if (result) {
|
||||
this.renderer._setEmoji(articleId, unicode);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// API calls:
|
||||
|
||||
/**
|
||||
* @param {Object} data
|
||||
* @param {String} data.category
|
||||
* @param {integer} data.target_parent_id
|
||||
*/
|
||||
_create: async function (data) {
|
||||
const articleId = await this._rpc({
|
||||
model: 'knowledge.article',
|
||||
method: 'article_create',
|
||||
args: [[]],
|
||||
kwargs: {
|
||||
is_private: data.category === 'private',
|
||||
parent_id: data.target_parent_id ? data.target_parent_id : false
|
||||
},
|
||||
});
|
||||
if (!articleId) {
|
||||
return;
|
||||
}
|
||||
this.do_action('knowledge.ir_actions_server_knowledge_home_page', {
|
||||
stackPosition: 'replaceCurrentAction',
|
||||
additional_context: {
|
||||
res_id: articleId
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {integer} id - Target id
|
||||
* @param {string} name - Target Name
|
||||
*/
|
||||
_rename: async function (id, name) {
|
||||
this.$(`.o_knowledge_tree .o_article[data-article-id="${id}"] > .o_article_handle > .o_article_name`).text(name);
|
||||
this.$(`.o_breadcrumb_article_name`).val(name);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Object} data
|
||||
* @param {integer} data.article_id
|
||||
@@ -348,7 +341,48 @@ const KnowledgeArticleFormController = FormController.extend({
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Object} data
|
||||
* @param {String} data.category
|
||||
* @param {integer} data.target_parent_id
|
||||
*/
|
||||
_create: async function (data) {
|
||||
const articleId = await this._rpc({
|
||||
model: 'knowledge.article',
|
||||
method: 'article_create',
|
||||
args: [[]],
|
||||
kwargs: {
|
||||
is_private: data.category === 'private',
|
||||
parent_id: data.target_parent_id ? data.target_parent_id : false
|
||||
},
|
||||
});
|
||||
if (!articleId) {
|
||||
return;
|
||||
}
|
||||
this.do_action('knowledge.ir_actions_server_knowledge_home_page', {
|
||||
stackPosition: 'replaceCurrentAction',
|
||||
additional_context: {
|
||||
res_id: articleId
|
||||
}
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @returns {Array[String]}
|
||||
*/
|
||||
_getFieldsToForceSave: function () {
|
||||
return ['full_width', 'icon', 'cover'];
|
||||
},
|
||||
/**
|
||||
* @returns {integer}
|
||||
*/
|
||||
_getId: async function () {
|
||||
let state = this.getState();
|
||||
if (typeof state.id === 'undefined') {
|
||||
await this.saveRecord(this.handle);
|
||||
state = this.getState();
|
||||
}
|
||||
return state.id;
|
||||
},
|
||||
/**
|
||||
* @param {Object} data
|
||||
* @param {integer} data.article_id
|
||||
@@ -373,7 +407,14 @@ const KnowledgeArticleFormController = FormController.extend({
|
||||
data.onReject();
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {integer} id - Target id
|
||||
* @param {string} name - Target Name
|
||||
*/
|
||||
_rename: async function (id, name) {
|
||||
this.$(`.o_knowledge_tree .o_article[data-article-id="${id}"] > .o_article_handle > .o_article_name`).text(name);
|
||||
this.$(`.o_breadcrumb_article_name`).val(name);
|
||||
},
|
||||
/**
|
||||
* @param {integer} id - article id
|
||||
* @returns {Promise}
|
||||
@@ -385,71 +426,6 @@ const KnowledgeArticleFormController = FormController.extend({
|
||||
args: [id]
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @returns {Array[String]}
|
||||
*/
|
||||
_getFieldsToForceSave: function () {
|
||||
return ['full_width', 'icon', 'cover'];
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @param {Event} event
|
||||
*/
|
||||
_onFieldChanged: async function (event) {
|
||||
this._super(...arguments);
|
||||
const { changes } = event.data;
|
||||
for (const field of this._getFieldsToForceSave()) {
|
||||
if (changes.hasOwnProperty(field)) {
|
||||
await this.saveRecord(this.handle, {
|
||||
reload: false,
|
||||
stayInEdit: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
saveRecord: async function () {
|
||||
const modifiedFields = await this._super(...arguments);
|
||||
const { data } = this.model.get(this.handle);
|
||||
for (const field of modifiedFields) {
|
||||
if (this.onFieldSavedListeners.has(field)) {
|
||||
this.onFieldSavedListeners.get(field).forEach(listener => {
|
||||
listener.call(this, data[field]);
|
||||
});
|
||||
}
|
||||
}
|
||||
return modifiedFields;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {String} name - field name
|
||||
* @param {Function} callback
|
||||
*/
|
||||
onFieldSaved: function (name, callback) {
|
||||
if (this.onFieldSavedListeners.has(name)) {
|
||||
this.onFieldSavedListeners.get(name).push(callback);
|
||||
} else {
|
||||
this.onFieldSavedListeners.set(name, [callback]);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @returns {integer}
|
||||
*/
|
||||
_getId: async function () {
|
||||
let state = this.getState();
|
||||
if (typeof state.id === 'undefined') {
|
||||
await this.saveRecord(this.handle);
|
||||
state = this.getState();
|
||||
}
|
||||
return state.id;
|
||||
},
|
||||
});
|
||||
|
||||
export {
|
||||
|
||||
@@ -22,7 +22,6 @@ const KnowledgeArticleFormRenderer = FormRenderer.extend(KnowledgeTreePanelMixin
|
||||
'click .o_knowledge_share_panel': '_preventDropdownClose',
|
||||
'click .o_knowledge_more_options_panel': '_preventDropdownClose',
|
||||
}),
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
@@ -30,7 +29,186 @@ const KnowledgeArticleFormRenderer = FormRenderer.extend(KnowledgeTreePanelMixin
|
||||
this._super(...arguments);
|
||||
this.breadcrumbs = params.breadcrumbs;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Event} event
|
||||
*/
|
||||
_onBreadcrumbItemClick: function (event) {
|
||||
const $target = $(event.target);
|
||||
this.trigger_up('breadcrumb_clicked', {
|
||||
controllerID: $target.data('controller-id'),
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Callback function called when the user clicks on the '+' sign of an article
|
||||
* list item. The callback function will create a new article under the target article.
|
||||
* @param {Event} event
|
||||
*/
|
||||
_onBtnArticleCreateClick: function (event) {
|
||||
const $target = $(event.currentTarget);
|
||||
const $li = $target.closest('li');
|
||||
this.trigger_up('create', {
|
||||
target_parent_id: $li.data('article-id')
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @param {Event} event
|
||||
*/
|
||||
_onBtnChatterClick: function (event) {
|
||||
const $chatter = $('.o_knowledge_chatter');
|
||||
$chatter.toggleClass('d-none');
|
||||
$('.btn-chatter').toggleClass('active');
|
||||
},
|
||||
/**
|
||||
* @param {Event} event
|
||||
*/
|
||||
_onBtnCreateClick: function (event) {
|
||||
this.trigger_up('create', {
|
||||
category: 'private'
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @param {Event} event
|
||||
*/
|
||||
_onBtnDuplicateClick: function (event) {
|
||||
event.preventDefault();
|
||||
this.trigger_up('duplicate', {});
|
||||
},
|
||||
/**
|
||||
* @param {Event} event
|
||||
*/
|
||||
_onBtnMoveClick: function (event) {
|
||||
event.preventDefault();
|
||||
this.trigger_up('open_move_to_modal', {});
|
||||
},
|
||||
/**
|
||||
* Callback function called when the user clicks on the '+' sign of a section
|
||||
* (workspace, private, shared). The callback function will create a new article
|
||||
* on the root of the target section.
|
||||
* @param {Event} event
|
||||
*/
|
||||
_onBtnSectionCreateClick: function (event) {
|
||||
const $target = $(event.currentTarget);
|
||||
const $section = $target.closest('.o_section');
|
||||
this.trigger_up('create', {
|
||||
category: $section.data('section')
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Opens the selected record.
|
||||
* @param {Event} event
|
||||
*/
|
||||
_onOpen: async function (event) {
|
||||
event.stopPropagation();
|
||||
const $li = $(event.target).closest('li');
|
||||
this.do_action('knowledge.ir_actions_server_knowledge_home_page', {
|
||||
stackPosition: 'replaceCurrentAction',
|
||||
additional_context: {
|
||||
res_id: $li.data('article-id')
|
||||
}
|
||||
});
|
||||
},
|
||||
/**
|
||||
* By default, Bootstrap closes automatically the dropdown menu when the user
|
||||
* clicks inside it. To avoid that behavior, we will add a new event listener
|
||||
* on the dropdown menu that will prevent the click event from bubbling up and
|
||||
* triggering the listener closing the dropdown menu.
|
||||
* @param {Event} event
|
||||
*/
|
||||
_preventDropdownClose: function (event) {
|
||||
event.stopPropagation();
|
||||
},
|
||||
_renderArticleEmoji: function () {
|
||||
const { data } = this.state;
|
||||
const $dropdown = this.$('.o_knowledge_icon > .o_article_emoji_dropdown');
|
||||
$dropdown.attr('data-article-id', this.state.res_id);
|
||||
$dropdown.find('.o_article_emoji').text(data.icon || '');
|
||||
},
|
||||
/**
|
||||
* Renders the breadcrumb
|
||||
*/
|
||||
_renderBreadcrumb: function () {
|
||||
const items = this.breadcrumbs.map(payload => {
|
||||
return QWeb.render('knowledge.knowledge_breadcrumb_item', { payload });
|
||||
});
|
||||
this.$('.breadcrumb').prepend(items);
|
||||
},
|
||||
/**
|
||||
* Attaches an emoji picker widget to every emoji dropdown of the container.
|
||||
* Note: The widget will be attached to the view when the user clicks on
|
||||
* the dropdown menu for the first time.
|
||||
* @param {JQuery} [$container]
|
||||
*/
|
||||
_renderEmojiPicker: function ($container) {
|
||||
$container = $container || this.$el;
|
||||
$container.find('.o_article_emoji_dropdown').one('click', event => {
|
||||
const $dropdown = $(event.currentTarget);
|
||||
const picker = new EmojiPickerWidget(this, {
|
||||
article_id: $dropdown.data('article-id')
|
||||
});
|
||||
picker.attachTo($dropdown);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Renders the permission panel
|
||||
*/
|
||||
_renderPermissionPanel: function () {
|
||||
this.$('.btn-share').one('click', event => {
|
||||
const $container = this.$('.o_knowledge_permission_panel');
|
||||
const panel = new PermissionPanelWidget(this, {
|
||||
article_id: this.state.data.id,
|
||||
user_permission: this.state.data.user_permission
|
||||
});
|
||||
panel.attachTo($container);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_renderView: async function () {
|
||||
const result = await this._super.apply(this, arguments);
|
||||
this._renderBreadcrumb();
|
||||
await this._renderTree(this.state.res_id, '/knowledge/tree_panel');
|
||||
this._renderArticleEmoji();
|
||||
this._renderPermissionPanel();
|
||||
this._setResizeListener();
|
||||
return result;
|
||||
},
|
||||
/**
|
||||
* @param {integer} id - Article id
|
||||
* @param {String} unicode
|
||||
*/
|
||||
_setEmoji: function (id, emoji) {
|
||||
const emojis = this.$(`.o_article_emoji_dropdown[data-article-id="${id}"] > .o_article_emoji`);
|
||||
emojis.text(emoji || '');
|
||||
},
|
||||
/**
|
||||
* Enables the user to resize the aside block.
|
||||
* Note: When the user grabs the resizer, a new listener will be attached
|
||||
* to the document. The listener will be removed as soon as the user releases
|
||||
* the resizer to free some resources.
|
||||
*/
|
||||
_setResizeListener: function () {
|
||||
/**
|
||||
* @param {PointerEvent} event
|
||||
*/
|
||||
const onPointerMove = _.throttle(event => {
|
||||
event.preventDefault();
|
||||
this.el.style.setProperty('--default-sidebar-size', `${event.pageX}px`);
|
||||
}, 100);
|
||||
/**
|
||||
* @param {PointerEvent} event
|
||||
*/
|
||||
const onPointerUp = event => {
|
||||
$(document).off('pointermove', onPointerMove);
|
||||
};
|
||||
const $resizer = this.$('.o_knowledge_article_form_resizer');
|
||||
$resizer.on('pointerdown', event => {
|
||||
event.preventDefault();
|
||||
$(document).on('pointermove', onPointerMove);
|
||||
$(document).one('pointerup', onPointerUp);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Initializes the drag-and-drop behavior of the tree listing all articles.
|
||||
* Once this function is called, the user will be able to move an article
|
||||
@@ -121,6 +299,7 @@ const KnowledgeArticleFormRenderer = FormRenderer.extend(KnowledgeTreePanelMixin
|
||||
});
|
||||
|
||||
// Allow drag and drop between sections:
|
||||
|
||||
this.$('section[data-section="workspace"] .o_tree').nestedSortable(
|
||||
'option',
|
||||
'connectWith',
|
||||
@@ -138,202 +317,6 @@ const KnowledgeArticleFormRenderer = FormRenderer.extend(KnowledgeTreePanelMixin
|
||||
'section[data-section="workspace"] .o_tree, section[data-section="private"] .o_tree'
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback function called when the user clicks on the '+' sign of a section
|
||||
* (workspace, private, shared). The callback function will create a new article
|
||||
* on the root of the target section.
|
||||
* @param {Event} event
|
||||
*/
|
||||
_onBtnSectionCreateClick: function (event) {
|
||||
const $target = $(event.currentTarget);
|
||||
const $section = $target.closest('.o_section');
|
||||
this.trigger_up('create', {
|
||||
category: $section.data('section')
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback function called when the user clicks on the '+' sign of an article
|
||||
* list item. The callback function will create a new article under the target article.
|
||||
* @param {Event} event
|
||||
*/
|
||||
_onBtnArticleCreateClick: function (event) {
|
||||
const $target = $(event.currentTarget);
|
||||
const $li = $target.closest('li');
|
||||
this.trigger_up('create', {
|
||||
target_parent_id: $li.data('article-id')
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Opens the selected record.
|
||||
* @param {Event} event
|
||||
*/
|
||||
_onOpen: async function (event) {
|
||||
event.stopPropagation();
|
||||
const $li = $(event.target).closest('li');
|
||||
this.do_action('knowledge.ir_actions_server_knowledge_home_page', {
|
||||
stackPosition: 'replaceCurrentAction',
|
||||
additional_context: {
|
||||
res_id: $li.data('article-id')
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_renderArticleEmoji: function () {
|
||||
const { data } = this.state;
|
||||
const $dropdown = this.$('.o_knowledge_icon > .o_article_emoji_dropdown');
|
||||
$dropdown.attr('data-article-id', this.state.res_id);
|
||||
$dropdown.find('.o_article_emoji').text(data.icon || '');
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_renderView: async function () {
|
||||
const result = await this._super.apply(this, arguments);
|
||||
this._renderBreadcrumb();
|
||||
await this._renderTree(this.state.res_id, '/knowledge/tree_panel');
|
||||
this._renderArticleEmoji();
|
||||
this._renderPermissionPanel();
|
||||
this._setResizeListener();
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* Renders the breadcrumb
|
||||
*/
|
||||
_renderBreadcrumb: function () {
|
||||
const items = this.breadcrumbs.map(payload => {
|
||||
return QWeb.render('knowledge.knowledge_breadcrumb_item', { payload });
|
||||
});
|
||||
this.$('.breadcrumb').prepend(items);
|
||||
},
|
||||
|
||||
/**
|
||||
* Attaches an emoji picker widget to every emoji dropdown of the container.
|
||||
* Note: The widget will be attached to the view when the user clicks on
|
||||
* the dropdown menu for the first time.
|
||||
* @param {JQuery} [$container]
|
||||
*/
|
||||
_renderEmojiPicker: function ($container) {
|
||||
$container = $container || this.$el;
|
||||
$container.find('.o_article_emoji_dropdown').one('click', event => {
|
||||
const $dropdown = $(event.currentTarget);
|
||||
const picker = new EmojiPickerWidget(this, {
|
||||
article_id: $dropdown.data('article-id')
|
||||
});
|
||||
picker.attachTo($dropdown);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Renders the permission panel
|
||||
*/
|
||||
_renderPermissionPanel: function () {
|
||||
this.$('.btn-share').one('click', event => {
|
||||
const $container = this.$('.o_knowledge_permission_panel');
|
||||
const panel = new PermissionPanelWidget(this, {
|
||||
article_id: this.state.data.id,
|
||||
user_permission: this.state.data.user_permission
|
||||
});
|
||||
panel.attachTo($container);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Enables the user to resize the aside block.
|
||||
* Note: When the user grabs the resizer, a new listener will be attached
|
||||
* to the document. The listener will be removed as soon as the user releases
|
||||
* the resizer to free some resources.
|
||||
*/
|
||||
_setResizeListener: function () {
|
||||
/**
|
||||
* @param {PointerEvent} event
|
||||
*/
|
||||
const onPointerMove = _.throttle(event => {
|
||||
event.preventDefault();
|
||||
this.el.style.setProperty('--default-sidebar-size', `${event.pageX}px`);
|
||||
}, 100);
|
||||
/**
|
||||
* @param {PointerEvent} event
|
||||
*/
|
||||
const onPointerUp = event => {
|
||||
$(document).off('pointermove', onPointerMove);
|
||||
};
|
||||
const $resizer = this.$('.o_knowledge_article_form_resizer');
|
||||
$resizer.on('pointerdown', event => {
|
||||
event.preventDefault();
|
||||
$(document).on('pointermove', onPointerMove);
|
||||
$(document).one('pointerup', onPointerUp);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {integer} id - Article id
|
||||
* @param {String} unicode
|
||||
*/
|
||||
_setEmoji: function (id, emoji) {
|
||||
const emojis = this.$(`.o_article_emoji_dropdown[data-article-id="${id}"] > .o_article_emoji`);
|
||||
emojis.text(emoji || '');
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Event} event
|
||||
*/
|
||||
_onBreadcrumbItemClick: function (event) {
|
||||
const $target = $(event.target);
|
||||
this.trigger_up('breadcrumb_clicked', {
|
||||
controllerID: $target.data('controller-id'),
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Event} event
|
||||
*/
|
||||
_onBtnChatterClick: function (event) {
|
||||
const $chatter = $('.o_knowledge_chatter');
|
||||
$chatter.toggleClass('d-none');
|
||||
$('.btn-chatter').toggleClass('active');
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Event} event
|
||||
*/
|
||||
_onBtnCreateClick: function (event) {
|
||||
this.trigger_up('create', {
|
||||
category: 'private'
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Event} event
|
||||
*/
|
||||
_onBtnDuplicateClick: function (event) {
|
||||
event.preventDefault();
|
||||
this.trigger_up('duplicate', {});
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Event} event
|
||||
*/
|
||||
_onBtnMoveClick: function (event) {
|
||||
event.preventDefault();
|
||||
this.trigger_up('open_move_to_modal', {});
|
||||
},
|
||||
|
||||
/**
|
||||
* By default, Bootstrap closes automatically the dropdown menu when the user
|
||||
* clicks inside it. To avoid that behavior, we will add a new event listener
|
||||
* on the dropdown menu that will prevent the click event from bubbling up and
|
||||
* triggering the listener closing the dropdown menu.
|
||||
* @param {Event} event
|
||||
*/
|
||||
_preventDropdownClose: function (event) {
|
||||
event.stopPropagation();
|
||||
},
|
||||
});
|
||||
|
||||
export {
|
||||
|
||||
Reference in New Issue
Block a user