[MERGE] web_editor, *: clean media dialog code
* web_unsplash, website, website_blog Merge commit for PR: #33509 No big functional change, clean up media dialog code in preparation of task-1930726. See individual commits for more information. Signed-off-by: Quentin Smetz (qsm) <qsm@odoo.com>
This commit is contained in:
@@ -67,8 +67,8 @@ var MediaPlugin = AbstractPlugin.extend({
|
||||
$(media).clone()[0]
|
||||
);
|
||||
|
||||
mediaDialog.on('saved', this, function (data) {
|
||||
this.insertMedia(media, data);
|
||||
mediaDialog.on('save', this, function (element) {
|
||||
this.insertMedia(media, element);
|
||||
});
|
||||
mediaDialog.on('closed', this, function () {
|
||||
this.context.invoke('editor.restoreRange');
|
||||
@@ -157,13 +157,12 @@ var MediaPlugin = AbstractPlugin.extend({
|
||||
* Insert or replace a media.
|
||||
*
|
||||
* @param {Node} previous the media to replace, if any
|
||||
* @param {Object} data contains the media to insert
|
||||
* @param {Node} newMedia contains the media to insert
|
||||
*/
|
||||
insertMedia: function (previous, data) {
|
||||
if (!data.media) {
|
||||
insertMedia: function (previous, newMedia) {
|
||||
if (!newMedia) {
|
||||
return;
|
||||
}
|
||||
var newMedia = data.media;
|
||||
this._wrapCommand(function () {
|
||||
this.$editable.focus();
|
||||
var rng = this.context.invoke('editor.createRange');
|
||||
@@ -689,17 +688,17 @@ var ImagePlugin = AbstractMediaPlugin.extend({
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Open the crop image dialog and listen to its saved/closed events.
|
||||
* Open the crop image dialog and listen to its save/closed events.
|
||||
*/
|
||||
cropImageDialog: function () {
|
||||
this.context.invoke('editor.saveRange');
|
||||
|
||||
var media = this.context.invoke('editor.restoreTarget');
|
||||
var cropImageDialog = new weWidgets.CropImageDialog(this.options.parent, {},
|
||||
$(media).clone()
|
||||
$(media).clone()[0]
|
||||
);
|
||||
cropImageDialog.on('saved', this, function (data) {
|
||||
this.context.invoke('MediaPlugin.insertMedia', media, data);
|
||||
cropImageDialog.on('save', this, function (img) {
|
||||
this.context.invoke('MediaPlugin.insertMedia', media, img);
|
||||
});
|
||||
cropImageDialog.on('closed', this, function () {
|
||||
this.context.invoke('editor.restoreRange');
|
||||
@@ -708,18 +707,18 @@ var ImagePlugin = AbstractMediaPlugin.extend({
|
||||
cropImageDialog.open();
|
||||
},
|
||||
/**
|
||||
* Open the alt dialog (change image title and alt) and listen to its saved/closed events.
|
||||
* Open the alt dialog (change image title and alt) and listen to its save/closed events.
|
||||
*/
|
||||
altDialg: function () {
|
||||
this.context.invoke('editor.saveRange');
|
||||
|
||||
var media = this.context.invoke('editor.restoreTarget');
|
||||
var altDialog = new weWidgets.AltDialog(this.options.parent, {},
|
||||
$(media).clone()
|
||||
$(media).clone()[0]
|
||||
);
|
||||
altDialog.on('saved', this, this._wrapCommand(function (data) {
|
||||
$(media).attr('alt', $(data.media).attr('alt'))
|
||||
.attr('title', $(data.media).attr('title'))
|
||||
altDialog.on('save', this, this._wrapCommand(function (img) {
|
||||
$(media).attr('alt', img.alt)
|
||||
.attr('title', img.title)
|
||||
.trigger('content_changed');
|
||||
}));
|
||||
altDialog.on('closed', this, function () {
|
||||
|
||||
@@ -52,9 +52,7 @@ var AltDialog = Dialog.extend({
|
||||
$(this.media).attr('alt', alt ? alt.replace(allNonEscQuots, """) : null)
|
||||
.attr('title', title ? title.replace(allNonEscQuots, """) : null);
|
||||
|
||||
this.trigger('saved', {
|
||||
media: this.media,
|
||||
});
|
||||
this.final_data = this.media;
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -172,9 +172,7 @@ var CropImageDialog = Dialog.extend({
|
||||
});
|
||||
this.$media.attr('src', canvas.toDataURL(this.imageData.mimetype));
|
||||
|
||||
this.trigger('saved', {
|
||||
media: this.$media[0],
|
||||
});
|
||||
this.final_data = this.media;
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
|
||||
@@ -13,18 +13,17 @@ var _t = core._t;
|
||||
|
||||
var MediaWidget = Widget.extend({
|
||||
xmlDependencies: ['/web_editor/static/src/xml/wysiwyg.xml'],
|
||||
events: {
|
||||
'input input.o_we_search': '_onSearchInput',
|
||||
},
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {Element} media: the target Element for which we select a media
|
||||
* @param {Object} options: useful parameters such as res_id, res_model,
|
||||
* context, user_id, ...
|
||||
*/
|
||||
init: function (parent, media, options) {
|
||||
this._super.apply(this, arguments);
|
||||
this.media = media;
|
||||
this.$media = $(media);
|
||||
this._onSearchInput = _.debounce(this._onSearchInput, 500);
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -41,14 +40,10 @@ var MediaWidget = Widget.extend({
|
||||
this._clear();
|
||||
},
|
||||
/**
|
||||
* Saves the currently configured media on the target media.
|
||||
*
|
||||
* @abstract
|
||||
* @param {string} needle
|
||||
* @returns {Deferred}
|
||||
*/
|
||||
search: function (needle) {},
|
||||
/**
|
||||
* @abstract
|
||||
* @returns {*}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
save: function () {},
|
||||
|
||||
@@ -60,6 +55,33 @@ var MediaWidget = Widget.extend({
|
||||
* @abstract
|
||||
*/
|
||||
_clear: function () {},
|
||||
});
|
||||
|
||||
var SearchableMediaWidget = MediaWidget.extend({
|
||||
events: _.extend({}, MediaWidget.prototype.events || {}, {
|
||||
'input .o_we_search': '_onSearchInput',
|
||||
}),
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
init: function () {
|
||||
this._super.apply(this, arguments);
|
||||
this._onSearchInput = _.debounce(this._onSearchInput, 500);
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Finds and displays existing attachments related to the target media.
|
||||
*
|
||||
* @abstract
|
||||
* @param {string} needle: only return attachments matching this parameter
|
||||
* @returns {Promise}
|
||||
*/
|
||||
search: function (needle) {},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
@@ -75,22 +97,23 @@ var MediaWidget = Widget.extend({
|
||||
});
|
||||
|
||||
/**
|
||||
* Let users choose an image, including uploading a new image in odoo.
|
||||
* Let users choose a file, including uploading a new file in odoo.
|
||||
*/
|
||||
var ImageWidget = MediaWidget.extend({
|
||||
template: 'wysiwyg.widgets.image',
|
||||
events: _.extend({}, MediaWidget.prototype.events || {}, {
|
||||
var FileWidget = SearchableMediaWidget.extend({
|
||||
events: _.extend({}, SearchableMediaWidget.prototype.events || {}, {
|
||||
'click .o_upload_media_button': '_onUploadButtonClick',
|
||||
'click .o_upload_media_button_no_optimization': '_onUploadButtonNoOptimizationClick',
|
||||
'change input[type=file]': '_onImageSelection',
|
||||
'change .o_file_input': '_onImageSelection',
|
||||
'click .o_upload_media_url_button': '_onUploadURLButtonClick',
|
||||
'input input[name="url"]': '_onURLInputChange',
|
||||
'click .existing-attachments [data-src]': '_onImageClick',
|
||||
'dblclick .existing-attachments [data-src]': '_onImageDblClick',
|
||||
'input .o_we_url_input': '_onURLInputChange',
|
||||
'click .o_existing_attachment_cell [data-src]': '_onImageClick',
|
||||
'dblclick .o_existing_attachment_cell [data-src]': '_onImageDblClick',
|
||||
'click .o_existing_attachment_remove': '_onRemoveClick',
|
||||
'click .o_load_more': '_onLoadMoreClick',
|
||||
}),
|
||||
existingAttachmentsTemplate: undefined,
|
||||
|
||||
IMAGE_MIMETYPES: ['image/gif', 'image/jpe', 'image/jpeg', 'image/jpg', 'image/gif', 'image/png'],
|
||||
IMAGES_PER_ROW: 6,
|
||||
IMAGES_ROWS: 5,
|
||||
|
||||
@@ -104,14 +127,10 @@ var ImageWidget = MediaWidget.extend({
|
||||
this.imagesRows = this.IMAGES_ROWS;
|
||||
this.IMAGES_DISPLAYED_TOTAL = this.IMAGES_PER_ROW * this.imagesRows;
|
||||
|
||||
this.options = options;
|
||||
this.context = options.context;
|
||||
this.accept = options.accept || (options.document ? '*/*' : 'image/*');
|
||||
|
||||
this.multiImages = options.multiImages;
|
||||
|
||||
this.firstFilters = options.firstFilters || [];
|
||||
this.lastFilters = options.lastFilters || [];
|
||||
this.options = _.extend({
|
||||
firstFilters: [],
|
||||
lastFilters: [],
|
||||
}, options || {});
|
||||
|
||||
this.images = [];
|
||||
},
|
||||
@@ -130,6 +149,15 @@ var ImageWidget = MediaWidget.extend({
|
||||
start: function () {
|
||||
var def = this._super.apply(this, arguments);
|
||||
var self = this;
|
||||
this.$urlInput = this.$('.o_we_url_input');
|
||||
this.$form = this.$('form');
|
||||
this.$fileInput = this.$('.o_file_input');
|
||||
this.$uploadButton = this.$('.o_upload_media_button');
|
||||
this.$addUrlButton = this.$('.o_upload_media_url_button');
|
||||
this.$urlSuccess = this.$('.o_we_url_success');
|
||||
this.$urlWarning = this.$('.o_we_url_warning');
|
||||
this.$urlError = this.$('.o_we_url_error');
|
||||
this.$errorText = this.$('.o_we_error_text');
|
||||
|
||||
this._renderImages(true);
|
||||
|
||||
@@ -155,6 +183,9 @@ var ImageWidget = MediaWidget.extend({
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Saves the currently selected image on the target media. If new files are
|
||||
* currently being added, delays the save until all files have been added.
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
save: function () {
|
||||
@@ -166,7 +197,7 @@ var ImageWidget = MediaWidget.extend({
|
||||
search: function (needle, noRender) {
|
||||
var self = this;
|
||||
if (!noRender) {
|
||||
this.$('input.o_we_url_input').val('').trigger('input').trigger('change');
|
||||
this.$urlInput.val('').trigger('input').trigger('change');
|
||||
}
|
||||
return this._rpc({
|
||||
model: 'ir.attachment',
|
||||
@@ -176,7 +207,7 @@ var ImageWidget = MediaWidget.extend({
|
||||
domain: this._getAttachmentsDomain(needle),
|
||||
fields: ['name', 'datas_fname', 'mimetype', 'checksum', 'url', 'type', 'res_id', 'res_model', 'access_token'],
|
||||
order: [{name: 'id', asc: false}],
|
||||
context: this.context,
|
||||
context: this.options.context,
|
||||
},
|
||||
}).then(function (records) {
|
||||
self.records = _.chain(records)
|
||||
@@ -187,13 +218,13 @@ var ImageWidget = MediaWidget.extend({
|
||||
return (r.url || r.id);
|
||||
})
|
||||
.sortBy(function (r) {
|
||||
if (_.any(self.firstFilters, function (filter) {
|
||||
if (_.any(self.options.firstFilters, function (filter) {
|
||||
var regex = new RegExp(filter, 'i');
|
||||
return r.name.match(regex) || r.datas_fname && r.datas_fname.match(regex);
|
||||
})) {
|
||||
return -1;
|
||||
}
|
||||
if (_.any(self.lastFilters, function (filter) {
|
||||
if (_.any(self.options.lastFilters, function (filter) {
|
||||
var regex = new RegExp(filter, 'i');
|
||||
return r.name.match(regex) || r.datas_fname && r.datas_fname.match(regex);
|
||||
})) {
|
||||
@@ -277,10 +308,7 @@ var ImageWidget = MediaWidget.extend({
|
||||
domain = domain.concat(attachedDocumentDomain);
|
||||
}
|
||||
domain = ['|', ['public', '=', true]].concat(domain);
|
||||
|
||||
domain.push('|',
|
||||
['mimetype', '=', false],
|
||||
['mimetype', this.options.document ? 'not in' : 'in', ['image/gif', 'image/jpe', 'image/jpeg', 'image/jpg', 'image/gif', 'image/png']]);
|
||||
domain = domain.concat(this.options.mimetypeDomain);
|
||||
if (needle && needle.length) {
|
||||
domain.push('|', ['datas_fname', 'ilike', needle], ['name', 'ilike', needle]);
|
||||
}
|
||||
@@ -315,6 +343,20 @@ var ImageWidget = MediaWidget.extend({
|
||||
this.search(this.$('.o_we_search').val() || '');
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Renders the existing attachments and returns the result as a string.
|
||||
*
|
||||
* @param {Object[]} rows
|
||||
* @param {boolean} withEffect
|
||||
* @returns {string}
|
||||
*/
|
||||
_renderExisting: function (rows, withEffect) {
|
||||
return QWeb.render(this.existingAttachmentsTemplate, {
|
||||
rows: rows,
|
||||
widget: this,
|
||||
withEffect: withEffect,
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
@@ -326,15 +368,11 @@ var ImageWidget = MediaWidget.extend({
|
||||
.values()
|
||||
.value();
|
||||
|
||||
this.$('.form-text').empty();
|
||||
this.$errorText.empty();
|
||||
|
||||
// Render menu & content
|
||||
this.$('.existing-attachments').replaceWith(
|
||||
QWeb.render('wysiwyg.widgets.files.existing.content', {
|
||||
rows: rows,
|
||||
isDocument: this.options.document,
|
||||
withEffect: withEffect,
|
||||
})
|
||||
this._renderExisting(rows, withEffect)
|
||||
);
|
||||
|
||||
var $divs = this.$('.o_image');
|
||||
@@ -363,16 +401,18 @@ var ImageWidget = MediaWidget.extend({
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_save: function () {
|
||||
var self = this;
|
||||
if (this.multiImages) {
|
||||
return this.images;
|
||||
|
||||
if (this.options.multiImages) {
|
||||
return Promise.resolve(this.images);
|
||||
}
|
||||
|
||||
var img = this.images[0];
|
||||
if (!img) {
|
||||
return this.media;
|
||||
return Promise.resolve(this.media);
|
||||
}
|
||||
|
||||
var prom;
|
||||
@@ -421,11 +461,6 @@ var ImageWidget = MediaWidget.extend({
|
||||
self.$media.css(style);
|
||||
}
|
||||
|
||||
if (self.options.onUpload) {
|
||||
// We consider that when selecting an image it is as if we upload it in the html content.
|
||||
self.options.onUpload([img]);
|
||||
}
|
||||
|
||||
// Remove crop related attributes
|
||||
if (self.$media.attr('data-aspect-ratio')) {
|
||||
var attrs = ['aspect-ratio', 'x', 'y', 'width', 'height', 'rotate', 'scale-x', 'scale-y'];
|
||||
@@ -441,7 +476,7 @@ var ImageWidget = MediaWidget.extend({
|
||||
* @private
|
||||
*/
|
||||
_toggleImage: function (attachment, clearSearch, forceSelect) {
|
||||
if (this.multiImages) {
|
||||
if (this.options.multiImages) {
|
||||
var img = _.select(this.images, function (v) { return v.id === attachment.id; });
|
||||
if (img.length) {
|
||||
if (!forceSelect) {
|
||||
@@ -459,6 +494,22 @@ var ImageWidget = MediaWidget.extend({
|
||||
this.search('');
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Updates the add by URL UI.
|
||||
*
|
||||
* @private
|
||||
* @param {boolean} emptyValue
|
||||
* @param {boolean} isURL
|
||||
* @param {boolean} isImage
|
||||
*/
|
||||
_updateAddUrlUi(emptyValue, isURL, isImage) {
|
||||
this.$addUrlButton.toggleClass('btn-secondary', emptyValue)
|
||||
.toggleClass('btn-primary', !emptyValue)
|
||||
.prop('disabled', !isURL);
|
||||
|
||||
this.$urlSuccess.toggleClass('d-none', !isURL);
|
||||
this.$urlError.toggleClass('d-none', emptyValue || isURL);
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
@@ -504,24 +555,24 @@ var ImageWidget = MediaWidget.extend({
|
||||
resolve();
|
||||
|
||||
function _processFile(attachment, error) {
|
||||
var $button = self.$('.o_upload_image_button');
|
||||
var $button = self.$uploadButton;
|
||||
if (!error) {
|
||||
$button.addClass('btn-success');
|
||||
self._toggleImage(attachment, true);
|
||||
} else {
|
||||
$button.addClass('btn-danger');
|
||||
self.$el.addClass('o_has_error').find('.form-control, .custom-select').addClass('is-invalid');
|
||||
self.$el.find('.form-text').text(error);
|
||||
self.$errorText.text(error);
|
||||
}
|
||||
|
||||
if (!self.multiImages) {
|
||||
if (!self.options.multiImages) {
|
||||
self.trigger_up('save_request');
|
||||
}
|
||||
}
|
||||
});
|
||||
self.$el.submit();
|
||||
|
||||
self.$('.o_file_input').val('');
|
||||
self.$fileInput.val('');
|
||||
});
|
||||
},
|
||||
|
||||
@@ -551,11 +602,10 @@ var ImageWidget = MediaWidget.extend({
|
||||
* @private
|
||||
*/
|
||||
_onImageSelection: function () {
|
||||
var $form = this.$('form');
|
||||
this.$el.addClass('nosave');
|
||||
$form.removeClass('o_has_error').find('.form-control, .custom-select').removeClass('is-invalid');
|
||||
$form.find('.form-text').empty();
|
||||
this.$('.o_upload_media_button').removeClass('btn-danger btn-success');
|
||||
this.$form.removeClass('o_has_error').find('.form-control, .custom-select').removeClass('is-invalid');
|
||||
this.$errorText.empty();
|
||||
this.$uploadButton.removeClass('btn-danger btn-success');
|
||||
this._uploadFile();
|
||||
},
|
||||
/**
|
||||
@@ -565,7 +615,7 @@ var ImageWidget = MediaWidget.extend({
|
||||
var self = this;
|
||||
Dialog.confirm(this, _t("Are you sure you want to delete this file ?"), {
|
||||
confirm_callback: function () {
|
||||
var $helpBlock = self.$('.form-text').empty();
|
||||
var $helpBlock = self.$errorText.empty();
|
||||
var $a = $(ev.currentTarget);
|
||||
var id = parseInt($a.data('id'), 10);
|
||||
var attachment = _.findWhere(self.records, {id: id});
|
||||
@@ -582,6 +632,7 @@ var ImageWidget = MediaWidget.extend({
|
||||
}
|
||||
$helpBlock.replaceWith(QWeb.render('wysiwyg.widgets.image.existing.error', {
|
||||
views: prevented[id],
|
||||
widget: self,
|
||||
}));
|
||||
});
|
||||
}
|
||||
@@ -592,10 +643,6 @@ var ImageWidget = MediaWidget.extend({
|
||||
*/
|
||||
_onURLInputChange: function (ev) {
|
||||
var $input = $(ev.currentTarget);
|
||||
var $button = this.$('.o_upload_media_url_button');
|
||||
var $success = this.$('.o_we_url_success');
|
||||
var $warning = this.$('.o_we_url_warning');
|
||||
var $error = this.$('.o_we_url_error');
|
||||
|
||||
var inputValue = $input.val();
|
||||
var emptyValue = (inputValue === '');
|
||||
@@ -605,27 +652,20 @@ var ImageWidget = MediaWidget.extend({
|
||||
return inputValue.endsWith(format);
|
||||
});
|
||||
|
||||
$button.toggleClass('btn-secondary', emptyValue).toggleClass('btn-primary', !emptyValue)
|
||||
.prop('disabled', !isURL);
|
||||
if (!this.options.document) {
|
||||
$button.text((isURL && !isImage) ? _t("Add as document") : _t("Add image"));
|
||||
}
|
||||
$success.toggleClass('d-none', !isURL);
|
||||
$warning.toggleClass('d-none', !isURL || this.options.document || isImage);
|
||||
$error.toggleClass('d-none', emptyValue || isURL);
|
||||
this._updateAddUrlUi(emptyValue, isURL, isImage);
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onUploadButtonClick: function () {
|
||||
this.$('input[type=file]').click();
|
||||
this.$fileInput.click();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onUploadButtonNoOptimizationClick: function () {
|
||||
this.$('input[name="disable_optimization"]').val('1');
|
||||
this.$('.o_upload_media_button').click();
|
||||
this.$uploadButton.click();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
@@ -649,13 +689,78 @@ var ImageWidget = MediaWidget.extend({
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Let users choose an image, including uploading a new image in odoo.
|
||||
*/
|
||||
var ImageWidget = FileWidget.extend({
|
||||
template: 'wysiwyg.widgets.image',
|
||||
existingAttachmentsTemplate: 'wysiwyg.widgets.image.existing.attachments',
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
init: function (parent, media, options) {
|
||||
options = _.extend({
|
||||
accept: 'image/*',
|
||||
mimetypeDomain: [['mimetype', 'in', this.IMAGE_MIMETYPES]],
|
||||
}, options || {});
|
||||
this._super(parent, media, options);
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
_updateAddUrlUi: function (emptyValue, isURL, isImage) {
|
||||
this._super.apply(this, arguments);
|
||||
this.$addUrlButton.text((isURL && !isImage) ? _t("Add as document") : _t("Add image"));
|
||||
this.$urlWarning.toggleClass('d-none', !isURL || isImage);
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Let users choose a document, including uploading a new document in odoo.
|
||||
*/
|
||||
var DocumentWidget = FileWidget.extend({
|
||||
template: 'wysiwyg.widgets.document',
|
||||
existingAttachmentsTemplate: 'wysiwyg.widgets.document.existing.attachments',
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
init: function (parent, media, options) {
|
||||
options = _.extend({
|
||||
accept: '*/*',
|
||||
mimetypeDomain: [['mimetype', 'not in', this.IMAGE_MIMETYPES]],
|
||||
}, options || {});
|
||||
this._super(parent, media, options);
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
_updateAddUrlUi: function (emptyValue, isURL, isImage) {
|
||||
this._super.apply(this, arguments);
|
||||
this.$addUrlButton.text((isURL && isImage) ? _t("Add as image") : _t("Add document"));
|
||||
this.$urlWarning.toggleClass('d-none', !isURL || !isImage);
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Let users choose a font awesome icon, support all font awesome loaded in the
|
||||
* css files.
|
||||
*/
|
||||
var IconWidget = MediaWidget.extend({
|
||||
var IconWidget = SearchableMediaWidget.extend({
|
||||
template: 'wysiwyg.widgets.font-icons',
|
||||
events: _.extend({}, MediaWidget.prototype.events || {}, {
|
||||
events: _.extend({}, SearchableMediaWidget.prototype.events || {}, {
|
||||
'click .font-icons-icon': '_onIconClick',
|
||||
'dblclick .font-icons-icon': '_onIconDblClick',
|
||||
}),
|
||||
@@ -712,7 +817,7 @@ var IconWidget = MediaWidget.extend({
|
||||
class: _.compact(finalClasses).join(' '),
|
||||
style: style || null,
|
||||
});
|
||||
return this.media;
|
||||
return Promise.resolve(this.media);
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
@@ -736,7 +841,7 @@ var IconWidget = MediaWidget.extend({
|
||||
});
|
||||
}
|
||||
this.$('div.font-icons-icons').html(
|
||||
QWeb.render('wysiwyg.widgets.font-icons.icons', {iconsParser: iconsParser})
|
||||
QWeb.render('wysiwyg.widgets.font-icons.icons', {iconsParser: iconsParser, widget: this})
|
||||
);
|
||||
return Promise.resolve();
|
||||
},
|
||||
@@ -870,7 +975,7 @@ var VideoWidget = MediaWidget.extend({
|
||||
);
|
||||
this.media = this.$media[0];
|
||||
}
|
||||
return this.media;
|
||||
return Promise.resolve(this.media);
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -1095,7 +1200,10 @@ var VideoWidget = MediaWidget.extend({
|
||||
|
||||
return {
|
||||
MediaWidget: MediaWidget,
|
||||
SearchableMediaWidget: SearchableMediaWidget,
|
||||
FileWidget: FileWidget,
|
||||
ImageWidget: ImageWidget,
|
||||
DocumentWidget: DocumentWidget,
|
||||
IconWidget: IconWidget,
|
||||
VideoWidget: VideoWidget,
|
||||
};
|
||||
|
||||
@@ -8,9 +8,12 @@ var Dialog = require('wysiwyg.widgets.Dialog');
|
||||
var _t = core._t;
|
||||
|
||||
/**
|
||||
* MediaDialog widget. Lets users change a media, including uploading a
|
||||
* new image, font awsome or video and can change a media into an other
|
||||
* media.
|
||||
* Lets the user select a media. The media can be existing or newly uploaded.
|
||||
*
|
||||
* The media can be one of the following types: image, document, video or
|
||||
* font awesome icon (only existing icons).
|
||||
*
|
||||
* The user may change a media into another one depending on the given options.
|
||||
*/
|
||||
var MediaDialog = Dialog.extend({
|
||||
template: 'wysiwyg.widgets.media',
|
||||
@@ -18,7 +21,10 @@ var MediaDialog = Dialog.extend({
|
||||
['/web_editor/static/src/xml/wysiwyg.xml']
|
||||
),
|
||||
events: _.extend({}, Dialog.prototype.events, {
|
||||
'click a[data-toggle="tab"]': '_onTabChange',
|
||||
'click #editor-media-image-tab': '_onClickImageTab',
|
||||
'click #editor-media-document-tab': '_onClickDocumentTab',
|
||||
'click #editor-media-icon-tab': '_onClickIconTab',
|
||||
'click #editor-media-video-tab': '_onClickVideoTab',
|
||||
}),
|
||||
custom_events: _.extend({}, Dialog.prototype.custom_events || {}, {
|
||||
save_request: '_onSaveRequest',
|
||||
@@ -26,10 +32,15 @@ var MediaDialog = Dialog.extend({
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {Element} media
|
||||
*/
|
||||
init: function (parent, options, media) {
|
||||
var self = this;
|
||||
options = options || {};
|
||||
var $media = $(media);
|
||||
|
||||
options = _.extend({}, options);
|
||||
options.noDocuments = options.onlyImages || options.noDocuments;
|
||||
options.noIcons = options.onlyImages || options.noIcons;
|
||||
options.noVideos = options.onlyImages || options.noVideos;
|
||||
|
||||
this._super(parent, _.extend({}, {
|
||||
title: _t("Select a Media"),
|
||||
@@ -44,88 +55,68 @@ var MediaDialog = Dialog.extend({
|
||||
},
|
||||
});
|
||||
|
||||
this.media = media;
|
||||
this.$media = $(media);
|
||||
|
||||
this.multiImages = options.multiImages;
|
||||
var onlyImages = options.onlyImages || this.multiImages;
|
||||
this.noImages = options.noImages;
|
||||
this.noDocuments = onlyImages || options.noDocuments;
|
||||
this.noIcons = onlyImages || options.noIcons;
|
||||
this.noVideos = onlyImages || options.noVideos;
|
||||
|
||||
if (!this.noDocuments) {
|
||||
this.documentDialog = new MediaModules.ImageWidget(this, this.media, _.extend({}, options, {
|
||||
document: true,
|
||||
}));
|
||||
this.documentDialog.tabToShow = 'document';
|
||||
if (!options.noImages) {
|
||||
this.imageWidget = new MediaModules.ImageWidget(this, media, options);
|
||||
}
|
||||
if (!this.noIcons) {
|
||||
this.iconDialog = new MediaModules.IconWidget(this, this.media, options);
|
||||
this.iconDialog.tabToShow = 'icon';
|
||||
if (!options.noDocuments) {
|
||||
this.documentWidget = new MediaModules.DocumentWidget(this, media, options);
|
||||
}
|
||||
if (!this.noVideos) {
|
||||
this.videoDialog = new MediaModules.VideoWidget(this, this.media, options);
|
||||
this.videoDialog.tabToShow = 'video';
|
||||
if (!options.noIcons) {
|
||||
this.iconWidget = new MediaModules.IconWidget(this, media, options);
|
||||
}
|
||||
if (!this.noImages) {
|
||||
this.imageDialog = new MediaModules.ImageWidget(this, this.media, options);
|
||||
this.imageDialog.tabToShow = 'image';
|
||||
if (!options.noVideos) {
|
||||
this.videoWidget = new MediaModules.VideoWidget(this, media, options);
|
||||
}
|
||||
|
||||
this.active = this.imageDialog || this.documentDialog || this.iconDialog || this.videoDialog;
|
||||
if (this.imageDialog && this.$media.is('img')) {
|
||||
this.active = this.imageDialog;
|
||||
} else if (this.documentDialog && this.$media.is('a.o_image')) {
|
||||
this.active = this.documentDialog;
|
||||
} else if (this.videoDialog && this.$media.hasClass('media_iframe_video')) {
|
||||
this.active = this.videoDialog;
|
||||
} else if (this.iconDialog && this.$media.is('span, i')) {
|
||||
this.active = this.iconDialog;
|
||||
if (this.imageWidget && $media.is('img')) {
|
||||
this.activeWidget = this.imageWidget;
|
||||
} else if (this.documentWidget && $media.is('a.o_image')) {
|
||||
this.activeWidget = this.documentWidget;
|
||||
} else if (this.videoWidget && $media.hasClass('media_iframe_video')) {
|
||||
this.activeWidget = this.videoWidget;
|
||||
} else if (this.iconWidget && $media.is('span, i')) {
|
||||
this.activeWidget = this.iconWidget;
|
||||
} else if (this.imageWidget) {
|
||||
this.activeWidget = this.imageWidget;
|
||||
}
|
||||
|
||||
this.opened(function () {
|
||||
self.$('[href="#editor-media-' + self.active.tabToShow + '"]').tab('show');
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Adds the appropriate class to the current modal and appends the media
|
||||
* widgets to their respective tabs.
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
start: function () {
|
||||
var self = this;
|
||||
var defs = [this._super.apply(this, arguments)];
|
||||
this.$modal.addClass('note-image-dialog');
|
||||
var promises = [this._super.apply(this, arguments)];
|
||||
this.$modal.find('.modal-dialog').addClass('o_select_media_dialog');
|
||||
|
||||
if (this.imageDialog) {
|
||||
this.imageDialog.clear();
|
||||
if (this.imageWidget) {
|
||||
this.imageWidget.clear();
|
||||
}
|
||||
if (this.documentDialog) {
|
||||
this.documentDialog.clear();
|
||||
if (this.documentWidget) {
|
||||
this.documentWidget.clear();
|
||||
}
|
||||
if (this.iconDialog) {
|
||||
this.iconDialog.clear();
|
||||
if (this.iconWidget) {
|
||||
this.iconWidget.clear();
|
||||
}
|
||||
if (this.videoDialog) {
|
||||
this.videoDialog.clear();
|
||||
if (this.videoWidget) {
|
||||
this.videoWidget.clear();
|
||||
}
|
||||
|
||||
if (this.imageDialog) {
|
||||
defs.push(this.imageDialog.appendTo(this.$("#editor-media-image")));
|
||||
if (this.imageWidget) {
|
||||
promises.push(this.imageWidget.appendTo(this.$("#editor-media-image")));
|
||||
}
|
||||
if (this.documentDialog) {
|
||||
defs.push(this.documentDialog.appendTo(this.$("#editor-media-document")));
|
||||
if (this.documentWidget) {
|
||||
promises.push(this.documentWidget.appendTo(this.$("#editor-media-document")));
|
||||
}
|
||||
if (this.iconDialog) {
|
||||
defs.push(this.iconDialog.appendTo(this.$("#editor-media-icon")));
|
||||
if (this.iconWidget) {
|
||||
promises.push(this.iconWidget.appendTo(this.$("#editor-media-icon")));
|
||||
}
|
||||
if (this.videoDialog) {
|
||||
defs.push(this.videoDialog.appendTo(this.$("#editor-media-video")));
|
||||
if (this.videoWidget) {
|
||||
promises.push(this.videoWidget.appendTo(this.$("#editor-media-video")));
|
||||
}
|
||||
|
||||
return Promise.all(defs).then(function () {
|
||||
self._setActive(self.active);
|
||||
});
|
||||
return Promise.all(promises);
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -133,45 +124,97 @@ var MediaDialog = Dialog.extend({
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns whether the document widget is currently active.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isDocumentActive: function () {
|
||||
return this.activeWidget === this.documentWidget;
|
||||
},
|
||||
/**
|
||||
* Returns whether the icon widget is currently active.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isIconActive: function () {
|
||||
return this.activeWidget === this.iconWidget;
|
||||
},
|
||||
/**
|
||||
* Returns whether the image widget is currently active.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isImageActive: function () {
|
||||
return this.activeWidget === this.imageWidget;
|
||||
},
|
||||
/**
|
||||
* Returns whether the video widget is currently active.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isVideoActive: function () {
|
||||
return this.activeWidget === this.videoWidget;
|
||||
},
|
||||
/**
|
||||
* Saves the currently selected media from the currently active widget.
|
||||
*
|
||||
* The save event data `final_data` will be one Element in general, but it
|
||||
* will be an Array of Element if `multiImages` is set.
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
save: function () {
|
||||
var self = this;
|
||||
var _super = this._super;
|
||||
var args = arguments;
|
||||
return Promise.resolve(this.active.save()).then(function (data) {
|
||||
return this.activeWidget.save().then(function (data) {
|
||||
self.final_data = data;
|
||||
// In the case of multi images selection we suppose this was not to
|
||||
// replace an old media, so we only retrieve the images and save.
|
||||
if (!self.multiImages) {
|
||||
// TODO this dialog triggers 'save' and 'saved' with different
|
||||
// data on close... should refactor to avoid confusion...
|
||||
self.trigger('saved', {
|
||||
attachments: self.active.images,
|
||||
media: data,
|
||||
});
|
||||
}
|
||||
return _super.apply(self, args);
|
||||
});
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Object} widget
|
||||
*/
|
||||
_setActive: function (widget) {
|
||||
this.active = widget;
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Sets the document widget as the active widget.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_onClickDocumentTab: function () {
|
||||
this.activeWidget = this.documentWidget;
|
||||
},
|
||||
/**
|
||||
* Sets the icon widget as the active widget.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_onClickIconTab: function () {
|
||||
this.activeWidget = this.iconWidget;
|
||||
},
|
||||
/**
|
||||
* Sets the image widget as the active widget.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_onClickImageTab: function () {
|
||||
this.activeWidget = this.imageWidget;
|
||||
},
|
||||
/**
|
||||
* Sets the video widget as the active widget.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_onClickVideoTab: function () {
|
||||
this.activeWidget = this.videoWidget;
|
||||
},
|
||||
/**
|
||||
* Handles save request from the child widgets.
|
||||
*
|
||||
* This is for usability, to allow the user to save from other ways than
|
||||
* click on the modal button, such as double clicking a media to select it.
|
||||
*
|
||||
* @private
|
||||
* @param {OdooEvent} ev
|
||||
*/
|
||||
@@ -179,22 +222,6 @@ var MediaDialog = Dialog.extend({
|
||||
ev.stopPropagation();
|
||||
this.save();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {JQueryEvent} ev
|
||||
*/
|
||||
_onTabChange: function (ev) {
|
||||
var $target = $(ev.target);
|
||||
if ($target.is('[href="#editor-media-image"]')) {
|
||||
this._setActive(this.imageDialog);
|
||||
} else if ($target.is('[href="#editor-media-document"]')) {
|
||||
this._setActive(this.documentDialog);
|
||||
} else if ($target.is('[href="#editor-media-icon"]')) {
|
||||
this._setActive(this.active = this.iconDialog);
|
||||
} else if ($target.is('[href="#editor-media-video"]')) {
|
||||
this._setActive(this.active = this.videoDialog);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return MediaDialog;
|
||||
|
||||
@@ -19,7 +19,10 @@ return {
|
||||
ColorpickerDialog: ColorpickerDialog,
|
||||
|
||||
MediaWidget: media.MediaWidget,
|
||||
SearchableMediaWidget: media.SearchableMediaWidget,
|
||||
FileWidget: media.FileWidget,
|
||||
ImageWidget: media.ImageWidget,
|
||||
DocumentWidget: media.DocumentWidget,
|
||||
IconWidget: media.IconWidget,
|
||||
VideoWidget: media.VideoWidget,
|
||||
};
|
||||
|
||||
@@ -858,8 +858,8 @@ registry.background = SnippetOption.extend({
|
||||
res_id: $editable.data('oe-id'),
|
||||
}, $image[0]).open();
|
||||
|
||||
_editor.on('save', this, function () {
|
||||
this._setCustomBackground($image.attr('src'));
|
||||
_editor.on('save', this, function (image) {
|
||||
this._setCustomBackground(image.src);
|
||||
this.$target.trigger('content_changed');
|
||||
});
|
||||
_editor.on('closed', this, function () {
|
||||
|
||||
@@ -68,17 +68,17 @@
|
||||
<!-- Media Dialog (allows to choose an img/pictogram/video) -->
|
||||
<div t-name="wysiwyg.widgets.media">
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
<li class="nav-item"><a role="tab" href="#editor-media-image" aria-controls="editor-media-image" data-toggle="tab" t-attf-class="nav-link#{widget.noImages ? ' d-none' : ''}">Image</a></li>
|
||||
<li class="nav-item"><a role="tab" href="#editor-media-document" aria-controls="editor-media-document" data-toggle="tab" t-attf-class="nav-link#{widget.noDocuments ? ' d-none' : ''}">Document</a></li>
|
||||
<li class="nav-item"><a role="tab" href="#editor-media-icon" aria-controls="editor-media-icon" data-toggle="tab" t-attf-class="nav-link#{widget.noIcons ? ' d-none' : ''}">Pictogram</a></li>
|
||||
<li class="nav-item"><a role="tab" href="#editor-media-video" aria-controls="editor-media-video" data-toggle="tab" t-attf-class="nav-link#{widget.noVideos ? ' d-none' : ''}">Video</a></li>
|
||||
<li t-if="!widget.options.noImages" class="nav-item"><a t-attf-class="nav-link #{widget.isImageActive() ? 'active' : ''}" id="editor-media-image-tab" data-toggle="tab" href="#editor-media-image" role="tab" aria-controls="editor-media-image" t-att-aria-selected="widget.isImageActive().toString()">Image</a></li>
|
||||
<li t-if="!widget.options.noDocuments" class="nav-item"><a t-attf-class="nav-link #{widget.isDocumentActive() ? 'active' : ''}" id="editor-media-document-tab" data-toggle="tab" href="#editor-media-document" role="tab" aria-controls="editor-media-document" t-att-aria-selected="widget.isDocumentActive().toString()">Document</a></li>
|
||||
<li t-if="!widget.options.noIcons" class="nav-item"><a t-attf-class="nav-link #{widget.isIconActive() ? 'active' : ''}" id="editor-media-icon-tab" data-toggle="tab" href="#editor-media-icon" role="tab" aria-controls="editor-media-icon" t-att-aria-selected="widget.isIconActive().toString()">Pictogram</a></li>
|
||||
<li t-if="!widget.options.noVideos" class="nav-item"><a t-attf-class="nav-link #{widget.isVideoActive() ? 'active' : ''}" id="editor-media-video-tab" data-toggle="tab" href="#editor-media-video" role="tab" aria-controls="editor-media-video" t-att-aria-selected="widget.isVideoActive().toString()">Video</a></li>
|
||||
</ul>
|
||||
<!-- Tab panes -->
|
||||
<div class="tab-content">
|
||||
<div role="tabpanel" class="tab-pane fade" id="editor-media-image"/>
|
||||
<div role="tabpanel" class="tab-pane fade" id="editor-media-document"/>
|
||||
<div role="tabpanel" class="tab-pane fade" id="editor-media-icon"/>
|
||||
<div role="tabpanel" class="tab-pane fade" id="editor-media-video"/>
|
||||
<div t-if="!widget.options.noImages" t-attf-class="tab-pane fade #{widget.isImageActive() ? 'show active': ''}" id="editor-media-image" role="tabpanel" aria-labelledby="editor-media-image-tab"/>
|
||||
<div t-if="!widget.options.noDocuments" t-attf-class="tab-pane fade #{widget.isDocumentActive() ? 'show active': ''}" id="editor-media-document" role="tabpanel" aria-labelledby="editor-media-document-tab"/>
|
||||
<div t-if="!widget.options.noIcons" t-attf-class="tab-pane fade #{widget.isIconActive() ? 'show active': ''}" id="editor-media-icon" role="tabpanel" aria-labelledby="editor-media-icon-tab"/>
|
||||
<div t-if="!widget.options.noVideos" t-attf-class="tab-pane fade #{widget.isVideoActive() ? 'show active': ''}" id="editor-media-video" role="tabpanel" aria-labelledby="editor-media-video-tab"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -93,22 +93,19 @@
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<!-- Image choosing part of the Media Dialog -->
|
||||
<t t-name="wysiwyg.widgets.image">
|
||||
<!-- File choosing part of the Media Dialog -->
|
||||
<t t-name="wysiwyg.widgets.file">
|
||||
<t t-set="iframeName" t-value="_.uniqueId('fileframe-')"/>
|
||||
<form method="POST"
|
||||
action="/web_editor/attachment/add"
|
||||
enctype="multipart/form-data"
|
||||
t-att-target="iframeName">
|
||||
<input type="hidden" name="csrf_token" t-att-value="csrf_token"/>
|
||||
<input type="hidden" name="filters" t-att-value="widget.firstFilters.join('_')"/>
|
||||
<input type="hidden" name="filters" t-att-value="widget.options.firstFilters.join('_')"/>
|
||||
<input t-if="widget.options.res_id" type="hidden" name="res_id" t-att-value="widget.options.res_id"/>
|
||||
<input t-if="widget.options.res_model" type="hidden" name="res_model" t-att-value="widget.options.res_model"/>
|
||||
<t t-call="wysiwyg.widgets.files.submenu">
|
||||
<t t-set="isDocument" t-value="widget.options.document"/>
|
||||
<t t-set="accept" t-value="widget.accept"/>
|
||||
</t>
|
||||
<div class="form-text"/>
|
||||
<t t-call="wysiwyg.widgets.files.submenu"/>
|
||||
<div class="form-text o_we_error_text"/>
|
||||
<div class="existing-attachments"/>
|
||||
<div class="mt-4 text-center mx-auto">
|
||||
<button class="btn btn-primary o_load_more" type="button">Load more...</button>
|
||||
@@ -122,48 +119,62 @@
|
||||
|
||||
<t t-name="wysiwyg.widgets.files.submenu">
|
||||
<div class="form-inline align-items-center py-4">
|
||||
<input type="file" class="d-none o_file_input" name="upload" t-att-accept="accept" multiple="multiple"/>
|
||||
<input type="file" class="d-none o_file_input" name="upload" t-att-accept="widget.options.accept" multiple="multiple"/>
|
||||
<input type="hidden" name="disable_optimization" value=""/>
|
||||
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-primary o_upload_media_button">
|
||||
<t t-if="isDocument">Upload a document</t>
|
||||
<t t-else="">Upload an image</t>
|
||||
<t t-esc="uploadText"/>
|
||||
</button>
|
||||
<t t-if="!isDocument">
|
||||
<button class="btn btn-primary dropdown-toggle dropdown-toggle-split o_media_optimization" data-toggle="dropdown" type="button">
|
||||
<span class="sr-only">Alternate Upload</span>
|
||||
</button>
|
||||
<div class="dropdown-menu" role="menu">
|
||||
<button type="button" role="menuitem" class="dropdown-item o_upload_media_button_no_optimization">Upload image without optimization</button>
|
||||
</div>
|
||||
</t>
|
||||
<t t-raw="alternateUpload"/>
|
||||
</div>
|
||||
|
||||
<div class="input-group align-items-center ml-2">
|
||||
<input type="text" class="form-control o_we_url_input" name="url" t-attf-placeholder="https://www.odoo.com/#{isDocument ? 'mydocument' : 'logo.png'}"/>
|
||||
<input type="text" class="form-control o_we_url_input" name="url" t-att-placeholder="urlPlaceholder"/>
|
||||
<div class="input-group-append align-items-center">
|
||||
<button type="button" class="btn btn-secondary o_upload_media_url_button" disabled="disabled">
|
||||
<t t-if="isDocument">Add document</t>
|
||||
<t t-else="">Add image</t>
|
||||
<t t-esc="addText"/>
|
||||
</button>
|
||||
<div class="ml-2">
|
||||
<span class="o_we_url_success text-success d-none fa fa-lg fa-check" title="The URL seems valid"/>
|
||||
<span class="o_we_url_warning text-warning d-none fa fa-lg fa-warning" title="The URL does not contain any image. The file will be added in the document section."/>
|
||||
<span class="o_we_url_error text-danger d-none fa fa-lg fa-times" title="The URL does not seem to work"/>
|
||||
<span class="o_we_url_success text-success d-none fa fa-lg fa-check" title="The URL seems valid."/>
|
||||
<span class="o_we_url_warning text-warning d-none fa fa-lg fa-warning" t-att-title="urlWarningTitle"/>
|
||||
<span class="o_we_url_error text-danger d-none fa fa-lg fa-times" title="The URL does not seem to work."/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<t t-call="wysiwyg.widgets.media.search">
|
||||
<t t-set="searchPlaceholder">
|
||||
<t t-if="isDocument">Search a document</t>
|
||||
<t t-else="">Search an image</t>
|
||||
</t>
|
||||
</t>
|
||||
<t t-call="wysiwyg.widgets.media.search"/>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="wysiwyg.widgets.image">
|
||||
<t t-call="wysiwyg.widgets.file">
|
||||
<t t-set="uploadText">Upload an image</t>
|
||||
<t t-set="urlPlaceholder">https://www.odoo.com/logo.png</t>
|
||||
<t t-set="addText">Add image</t>
|
||||
<t t-set="searchPlaceholder">Search an image</t>
|
||||
<t t-set="urlWarningTitle">The URL does not contain any image. The file will be added in the document section.</t>
|
||||
<t t-set="alternateUpload">
|
||||
<button class="btn btn-primary dropdown-toggle dropdown-toggle-split o_media_optimization" data-toggle="dropdown" type="button">
|
||||
<span class="sr-only">Alternate Upload</span>
|
||||
</button>
|
||||
<div class="dropdown-menu" role="menu">
|
||||
<button type="button" role="menuitem" class="dropdown-item o_upload_media_button_no_optimization">Upload image without optimization</button>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="wysiwyg.widgets.document">
|
||||
<t t-call="wysiwyg.widgets.file">
|
||||
<t t-set="uploadText">Upload a document</t>
|
||||
<t t-set="urlPlaceholder">https://www.odoo.com/mydocument</t>
|
||||
<t t-set="addText">Add document</t>
|
||||
<t t-set="searchPlaceholder">Search a document</t>
|
||||
<t t-set="urlWarningTitle">The URL contains an image. The file will be added in the image section.</t>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="wysiwyg.widgets.image.existing">
|
||||
<div role="dialog" class="modal" tabindex="-1">
|
||||
<div class="modal-dialog select-image">
|
||||
@@ -183,20 +194,22 @@
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="wysiwyg.widgets.files.existing.content">
|
||||
<t t-name="wysiwyg.widgets.image.existing.attachments">
|
||||
<div class="existing-attachments">
|
||||
<div class="row mt16 ml-auto" t-as="row" t-foreach="rows">
|
||||
<div class="col-2 o_existing_attachment_cell" t-as="attachment" t-foreach="row">
|
||||
<i t-if="attachment.res_model === 'ir.ui.view'" class="fa fa-trash o_existing_attachment_remove" title="This file is a public view attachment" role="img" aria-label="This file is a public view attachment" t-att-data-id="attachment.id"/>
|
||||
<i t-else="" class="fa fa-trash o_existing_attachment_remove" title="This file is attached to the current record" role="img" aria-label="This file is attached to the current record" t-att-data-id="attachment.id"/>
|
||||
<div class="o_attachment_border" t-att-style="attachment.res_model === 'ir.ui.view' ? null : 'border: 1px solid #5cb85c;'"><div t-att-data-src="attachment.src" t-att-data-url="attachment.url" role="img" t-att-aria-label="attachment.name" t-att-title="attachment.name" t-att-data-id="attachment.id" t-att-data-mimetype="attachment.mimetype" t-attf-class="o_image {{withEffect ? 'o_image_loading' : ''}}"/></div>
|
||||
<t t-if="isDocument">
|
||||
<small class="o_file_name"><t t-esc="attachment.name"/></small>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="wysiwyg.widgets.document.existing.attachments" t-extend="wysiwyg.widgets.image.existing.attachments">
|
||||
<t t-jquery=".o_existing_attachment_cell" t-operation="append">
|
||||
<small class="o_file_name"><t t-esc="attachment.name"/></small>
|
||||
</t>
|
||||
</t>
|
||||
<t t-name="wysiwyg.widgets.image.existing.error">
|
||||
<div class="form-text">
|
||||
<p>The image could not be deleted because it is used in the
|
||||
|
||||
@@ -193,21 +193,6 @@ QUnit.module('web_editor', {}, function () {
|
||||
if (args.method === "generate_access_token") {
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (args.kwargs.domain[7][2].join(',') === "image/gif,image/jpe,image/jpeg,image/jpg,image/gif,image/png") {
|
||||
return Promise.resolve([{
|
||||
"id": 1,
|
||||
"public": true,
|
||||
"name": "image",
|
||||
"datas_fname": "image.png",
|
||||
"mimetype": "image/png",
|
||||
"checksum": false,
|
||||
"url": "/web_editor/static/src/img/transparent.png",
|
||||
"type": "url",
|
||||
"res_id": 0,
|
||||
"res_model": false,
|
||||
"access_token": false
|
||||
}]);
|
||||
}
|
||||
}
|
||||
return this._super(route, args);
|
||||
},
|
||||
|
||||
@@ -352,8 +352,8 @@ QUnit.test('background-image', function (assert) {
|
||||
$('#oe_manipulators .oe_overlay_options a.snippet-option-background[data-choose-image]').click();
|
||||
|
||||
defMediaDialogInit.then(function () {
|
||||
$('.modal.note-image-dialog .existing-attachments .o_image').click();
|
||||
$('.modal.note-image-dialog .modal-footer .btn-primary').click();
|
||||
$('.o_select_media_dialog .existing-attachments .o_image').click();
|
||||
$('.o_select_media_dialog .modal-footer .btn-primary').click();
|
||||
});
|
||||
|
||||
defMediaDialogSave.then(function () {
|
||||
|
||||
@@ -3406,12 +3406,8 @@ QUnit.module('Media', {
|
||||
|
||||
},
|
||||
mockRPC: function (route, args) {
|
||||
if (args.model === 'ir.attachment' || !args.length) {
|
||||
if (!args.length && route.indexOf('data:image/png;base64') === 0 ||
|
||||
args.method === "search_read" &&
|
||||
args.kwargs.domain[7][2].join(',') === "image/gif,image/jpe,image/jpeg,image/jpg,image/gif,image/png") {
|
||||
return Promise.resolve(this.data.records);
|
||||
}
|
||||
if (route.indexOf('data:image/png;base64') === 0) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (route.indexOf('youtube') !== -1) {
|
||||
return Promise.resolve();
|
||||
@@ -3478,7 +3474,7 @@ var _clickMedia = async function (wysiwyg, assert, callbackInit, test) {
|
||||
};
|
||||
|
||||
var _uploadAndInsertImg = async function (url) {
|
||||
$('.modal-dialog input[name="url"]:first').val(url).trigger('input');
|
||||
$('.modal-dialog .o_we_url_input:first').val(url).trigger('input');
|
||||
await testUtils.nextTick();
|
||||
await testUtils.dom.triggerEvents($('.modal-dialog .o_upload_media_url_button:first'), ['mousedown', 'click']);
|
||||
};
|
||||
|
||||
@@ -56,9 +56,7 @@ widgetsMedia.ImageWidget.include({
|
||||
* @override
|
||||
*/
|
||||
start: function () {
|
||||
if (!this.options.document) {
|
||||
this.$('.o_we_search_icon').replaceWith(core.qweb.render('web_unsplash.dialog.media.search_icon'));
|
||||
}
|
||||
this.$('.o_we_search_icon').replaceWith(core.qweb.render('web_unsplash.dialog.media.search_icon'));
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
/**
|
||||
@@ -242,7 +240,7 @@ widgetsMedia.ImageWidget.include({
|
||||
var imgid = $(ev.currentTarget).data('imgid');
|
||||
var url = $(ev.currentTarget).data('url');
|
||||
var downloadURL = $(ev.currentTarget).data('download-url');
|
||||
if (!this.multiImages) {
|
||||
if (!this.options.multiImages) {
|
||||
this._unsplash.selectedImages = {};
|
||||
}
|
||||
if (imgid in this._unsplash.selectedImages) {
|
||||
@@ -286,18 +284,16 @@ widgetsMedia.ImageWidget.include({
|
||||
* @override
|
||||
*/
|
||||
_onSearchInput: function (ev) {
|
||||
if (!this.options.document) {
|
||||
var $input = $(ev.currentTarget);
|
||||
var inputValue = $input.val();
|
||||
this.$('.o_search_value_input').text(inputValue);
|
||||
var $input = $(ev.currentTarget);
|
||||
var inputValue = $input.val();
|
||||
this.$('.o_search_value_input').text(inputValue);
|
||||
|
||||
var $icon = this.$('.o_we_search_icon');
|
||||
if ($icon.parent().is('.show')) {
|
||||
$icon.dropdown('update');
|
||||
} else if (!this.hasSearched) {
|
||||
$icon.dropdown('toggle');
|
||||
$input.focus();
|
||||
}
|
||||
var $icon = this.$('.o_we_search_icon');
|
||||
if ($icon.parent().is('.show')) {
|
||||
$icon.dropdown('update');
|
||||
} else if (!this.hasSearched) {
|
||||
$icon.dropdown('toggle');
|
||||
$input.focus();
|
||||
}
|
||||
this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<templates id="template" xml:space="preserve">
|
||||
|
||||
<t t-extend="wysiwyg.widgets.image">
|
||||
<t t-extend="wysiwyg.widgets.file">
|
||||
<t t-jquery=".existing-attachments" t-operation="after">
|
||||
<div class="unsplash_img_container"></div>
|
||||
</t>
|
||||
|
||||
@@ -1001,7 +1001,7 @@ options.registry.gallery = options.Class.extend({
|
||||
addImages: function (previewMode) {
|
||||
var self = this;
|
||||
var $container = this.$('.container:first');
|
||||
var dialog = new weWidgets.MediaDialog(this, {multiImages: true}, null);
|
||||
var dialog = new weWidgets.MediaDialog(this, {multiImages: true, onlyImages: true}, null);
|
||||
var lastImage = _.last(this._getImages());
|
||||
var index = lastImage ? this._getIndex(lastImage) : -1;
|
||||
dialog.on('save', this, function (attachments) {
|
||||
|
||||
@@ -182,8 +182,8 @@ options.registry.blog_cover = options.Class.extend({
|
||||
onlyImages: true,
|
||||
firstFilters: ['background']
|
||||
}, $image[0]).open();
|
||||
editor.on('save', this, function (event, img) {
|
||||
var src = $image.attr('src');
|
||||
editor.on('save', this, function (image) {
|
||||
var src = image.src;
|
||||
this.$image.css('background-image', src ? ('url(' + src + ')') : '');
|
||||
if (!this.$target.hasClass('cover')) {
|
||||
var $opt = this.$el.find('[data-select-class]').first();
|
||||
|
||||
Reference in New Issue
Block a user