[REF] website_slides: refactor the category add modal on frontend
Purpose ======= This commits refactors the way slide.category are added on frontend: * JS now extends a standard Dialog widget; * added "required" name value on the form and handled validation; * controller adds the category at the bottom of the list (sequence+1); Commit linked to task ID 1942852 and PR #31394.
This commit is contained in:
committed by
Thibault Delavallée
parent
5db9ed0391
commit
0e73de5dea
@@ -576,6 +576,39 @@ class WebsiteSlides(WebsiteProfile):
|
||||
result = slide._send_share_email(email)
|
||||
return result
|
||||
|
||||
# --------------------------------------------------
|
||||
# CATEGORY MANAGEMENT
|
||||
# --------------------------------------------------
|
||||
|
||||
@http.route(['/slides/category/search_read'], type='json', auth='user', methods=['POST'], website=True)
|
||||
def slide_category_search_read(self, fields, domain):
|
||||
can_create = request.env['slide.category'].check_access_rights('create', raise_exception=False)
|
||||
return {
|
||||
'read_results': request.env['slide.category'].search_read(domain, fields),
|
||||
'can_create': can_create,
|
||||
}
|
||||
|
||||
@http.route('/slides/category/add', type="http", website=True, auth="user")
|
||||
def slide_category_add(self, channel_id, name):
|
||||
""" Adds a category to the specified channel. If categories already exist
|
||||
within this channel, it will be added at the bottom (sequence+1) """
|
||||
channel = request.env['slide.channel'].browse(int(channel_id))
|
||||
|
||||
values = {
|
||||
'name': name,
|
||||
'channel_id': channel.id
|
||||
}
|
||||
|
||||
latest_category = request.env['slide.category'].search_read([
|
||||
('channel_id', '=', channel.id)
|
||||
], ["sequence"], order="sequence desc", limit=1)
|
||||
if latest_category:
|
||||
values['sequence'] = latest_category[0]['sequence'] + 1
|
||||
|
||||
request.env['slide.category'].create(values)
|
||||
|
||||
return werkzeug.utils.redirect("/slides/%s" % (slug(channel)))
|
||||
|
||||
# --------------------------------------------------
|
||||
# TOOLS
|
||||
# --------------------------------------------------
|
||||
@@ -694,24 +727,6 @@ class WebsiteSlides(WebsiteProfile):
|
||||
'can_create': can_create,
|
||||
}
|
||||
|
||||
@http.route(['/slides/category/search_read'], type='json', auth='user', methods=['POST'], website=True)
|
||||
def slide_category_search_read(self, fields, domain):
|
||||
can_create = request.env['slide.category'].check_access_rights('create', raise_exception=False)
|
||||
return {
|
||||
'read_results': request.env['slide.category'].search_read(domain, fields),
|
||||
'can_create': can_create,
|
||||
}
|
||||
|
||||
@http.route('/slides/add_category', type="json", website=True, auth="user")
|
||||
def add_category(self, channel_id, name, **kw):
|
||||
channel = request.env['slide.channel'].browse(channel_id)
|
||||
request.env['slide.category'].create({
|
||||
'name': name,
|
||||
'channel_id': channel.id
|
||||
})
|
||||
|
||||
return {'url': "/slides/%s" %(slug(channel))}
|
||||
|
||||
#Not using the /web/dataset/resequence route as a slide can be dragged into another category at the same time
|
||||
@http.route('/slides/resequence_slides', type="json", website=True, auth="user")
|
||||
def resequence_slides(self, slides_data=None, **kw):
|
||||
@@ -727,7 +742,6 @@ class WebsiteSlides(WebsiteProfile):
|
||||
'category_id': slide['category_id']
|
||||
})
|
||||
|
||||
|
||||
# --------------------------------------------------
|
||||
# EMBED IN THIRD PARTY WEBSITES
|
||||
# --------------------------------------------------
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
odoo.define('website_slides.add.section', function (require) {
|
||||
'use strict';
|
||||
|
||||
var sAnimations = require('website.content.snippets.animation');
|
||||
var core = require('web.core');
|
||||
var Widget = require('web.Widget');
|
||||
|
||||
var _t = core._t;
|
||||
|
||||
var SectionDialog = Widget.extend({
|
||||
template: 'website.slide.add.section',
|
||||
events: {
|
||||
'hidden.bs.modal': 'destroy',
|
||||
'click button.save': '_save',
|
||||
'click button[data-dismiss="modal"]': '_cancel',
|
||||
'change input#upload': '_slideUpload',
|
||||
'change input#url': '_slideUrl',
|
||||
'click .list-group-item': function (ev) {
|
||||
this.$('.list-group-item').removeClass('active');
|
||||
$(ev.target).closest('li').addClass('active');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @param {Object} el
|
||||
* @param {number} channel_id
|
||||
*/
|
||||
init: function (el, channelID) {
|
||||
this._super(el, channelID);
|
||||
this.channel_id = parseInt(channelID, 10);
|
||||
this.index_content = '';
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
start: function () {
|
||||
this.$el.modal({
|
||||
backdrop: 'static'
|
||||
});
|
||||
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
_getValue: function () {
|
||||
var canvas = this.$('#data_canvas')[0],
|
||||
values = {
|
||||
'channel_id': this.channel_id || '',
|
||||
'url': this.$('#url').val(),
|
||||
'name': this.$('#section_name').val()
|
||||
};
|
||||
return values;
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_validate: function () {
|
||||
this.$('.form-group').removeClass('o_has_error').find('.form-control, .custom-select').removeClass('is-invalid');
|
||||
if (!this.$('#name').val()) {
|
||||
this.$('#name').closest('.form-group').addClass('o_has_error').find('.form-control, .custom-select').addClass('is-invalid');
|
||||
return false;
|
||||
}
|
||||
var url = this.$('#url').val() ? this.is_valid_url : false;
|
||||
if (!(this.file.name || url)) {
|
||||
this.$('#url').closest('.form-group').addClass('o_has_error').find('.form-control, .custom-select').addClass('is-invalid');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @param {Object} ev
|
||||
*/
|
||||
_save: function (ev) {
|
||||
var self = this;
|
||||
|
||||
var values = this._getValue();
|
||||
if ($(ev.target).data('published')) {
|
||||
values.website_published = true;
|
||||
}
|
||||
this.$('.oe_slides_upload_loading').show();
|
||||
this.$('.modal-footer, .modal-body').hide();
|
||||
this._rpc({
|
||||
route: '/slides/add_category',
|
||||
params: values,
|
||||
}).then(function (data) {
|
||||
if (data.error) {
|
||||
self._displayAlert(data.error);
|
||||
self.$('.oe_slides_upload_loading').hide();
|
||||
self.$('.modal-footer, .modal-body').show();
|
||||
|
||||
} else {
|
||||
window.location = data.url;
|
||||
}
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
_cancel: function () {
|
||||
this.trigger('cancel');
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
sAnimations.registry.websiteSlidesSection = sAnimations.Class.extend({
|
||||
selector: '.oe_slide_js_add_section',
|
||||
xmlDependencies: ['/website_slides/static/src/xml/website_slides_upload.xml'],
|
||||
read_events: {
|
||||
'click': '_onAddSectionClick',
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
start: function () {
|
||||
// Automatically open the upload dialog if requested from query string
|
||||
if ($.deparam.querystring().enable_slide_upload !== undefined) {
|
||||
this._openDialog(this.$el.attr('channel_id'));
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
_openDialog: function (channelID) {
|
||||
new SectionDialog(this, channelID).appendTo(document.body);
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Event} ev
|
||||
*/
|
||||
_onAddSectionClick: function (ev) {
|
||||
console.log('test');
|
||||
this._openDialog($(ev.currentTarget).attr('channel_id'));
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,84 @@
|
||||
odoo.define('website_slides.category.add', function (require) {
|
||||
'use strict';
|
||||
|
||||
var sAnimations = require('website.content.snippets.animation');
|
||||
var Dialog = require('web.Dialog');
|
||||
var core = require('web.core');
|
||||
var _t = core._t;
|
||||
|
||||
var CategoryAddDialog = Dialog.extend({
|
||||
template: 'slides.category.add',
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
init: function (parent, options) {
|
||||
options = _.defaults(options || {}, {
|
||||
title: _t('Add a section'),
|
||||
size: 'medium',
|
||||
buttons: [{
|
||||
text: _t('Save'),
|
||||
classes: 'btn-primary',
|
||||
click: this._onClickFormSubmit.bind(this)
|
||||
}, {
|
||||
text: _t('Discard'),
|
||||
close: true
|
||||
}]
|
||||
});
|
||||
|
||||
this.channelId = options.channelId;
|
||||
this._super(parent, options);
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
_formValidate: function ($form) {
|
||||
$form.addClass('was-validated');
|
||||
return $form[0].checkValidity();
|
||||
},
|
||||
|
||||
_onClickFormSubmit: function (ev) {
|
||||
var $form = this.$('#slide_category_add_form');
|
||||
if (this._formValidate($form)) {
|
||||
$form.submit();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
sAnimations.registry.websiteSlidesCategoryAdd = sAnimations.Class.extend({
|
||||
selector: '.o_wslides_js_slide_section_add',
|
||||
xmlDependencies: ['/website_slides/static/src/xml/slide_management.xml'],
|
||||
read_events: {
|
||||
'click': '_onAddSectionClick',
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
_openDialog: function (channelId) {
|
||||
new CategoryAddDialog(this, {channelId: channelId}).open();
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Event} ev
|
||||
*/
|
||||
_onAddSectionClick: function (ev) {
|
||||
ev.preventDefault();
|
||||
this._openDialog($(ev.currentTarget).attr('channel_id'));
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
categoryAddDialog: CategoryAddDialog,
|
||||
websiteSlidesCategoryAdd: sAnimations.registry.websiteSlidesCategoryAdd
|
||||
};
|
||||
|
||||
});
|
||||
@@ -5,4 +5,20 @@
|
||||
<p>Are you sure you want to archive this slide ?</p>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="slides.category.add">
|
||||
<div>
|
||||
<form action="/slides/category/add" method="POST" id="slide_category_add_form">
|
||||
<input type="hidden" name="csrf_token" t-att-value="csrf_token"/>
|
||||
<input type="hidden" name="channel_id" t-att-value="widget.channelId"/>
|
||||
<div class="form-group row">
|
||||
<label for="section_name" class="col-sm-3 col-form-label">Section name</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" name="name" id="section_name" required="required"/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
|
||||
@@ -207,33 +207,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="website.slide.add.section">
|
||||
<div role="dialog" class="modal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<header class="modal-header">
|
||||
<h3 class="modal-title">Add a section</h3>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">×</button>
|
||||
</header>
|
||||
<main class="modal-body modal-content">
|
||||
<form class="clearfix">
|
||||
<div class="form-group row">
|
||||
<label for="section_name" class="col-form-label col-md-3">Section name</label>
|
||||
<div class="col-md-9">
|
||||
<input type="text" class="form-control" id="section_name"/>
|
||||
</div>
|
||||
</div>
|
||||
<canvas id="data_canvas" style="display: none;"></canvas>
|
||||
</form>
|
||||
</main>
|
||||
<footer class="modal-footer">
|
||||
<button type="button" data-loading-text="Loading..." data-published="true" class="btn btn-primary save">Add</button>
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Discard</button>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<script type="text/javascript" src="/website_slides/static/src/js/slides_like.js"/>
|
||||
<script type="text/javascript" src="/website_slides/static/src/js/slides_share.js"/>
|
||||
<script type="text/javascript" src="/website_slides/static/src/js/slides_upload.js"/>
|
||||
<script type="text/javascript" src="/website_slides/static/src/js/slides_category.js"/>
|
||||
<script type="text/javascript" src="/website_slides/static/src/js/slides_category_add.js"/>
|
||||
<script type="text/javascript" src="/website_slides/static/src/js/slides_slide_archive.js"/>
|
||||
<script type="text/javascript" src="/website_slides/static/src/js/slides_course_slides_list.js"/>
|
||||
<script type="text/javascript" src="/website_slides/static/src/js/slides_course_progress_bar.js"/>
|
||||
|
||||
@@ -305,7 +305,7 @@
|
||||
t-att-data-channel-id="channel.id"
|
||||
t-att-data-can-upload="channel.can_upload"
|
||||
t-att-data-can-publish="channel.can_publish">Add Content</a>
|
||||
<a class="oe_slide_js_add_section" t-attf-channel_id="#{channel.id}" href="#"
|
||||
<a class="o_wslides_js_slide_section_add" t-attf-channel_id="#{channel.id}" href="#"
|
||||
groups="website.group_website_publisher">Add Section</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user