summaryrefslogtreecommitdiff
path: root/addons/web_editor/static
diff options
context:
space:
mode:
Diffstat (limited to 'addons/web_editor/static')
-rw-r--r--addons/web_editor/static/src/js/backend/fields.js3
-rw-r--r--addons/web_editor/static/src/js/editor/rte.summernote.js6
-rw-r--r--addons/web_editor/static/src/js/editor/snippets.options.js7
-rw-r--r--addons/web_editor/static/src/js/editor/summernote.js24
-rw-r--r--addons/web_editor/static/src/js/editor/transcoder.js32
-rw-r--r--addons/web_editor/static/src/js/inline.js1
-rw-r--r--addons/web_editor/static/src/js/widgets/widgets.js137
-rw-r--r--addons/web_editor/static/src/xml/editor.xml7
8 files changed, 150 insertions, 67 deletions
diff --git a/addons/web_editor/static/src/js/backend/fields.js b/addons/web_editor/static/src/js/backend/fields.js
index b84fcd21c91..d3d601bac73 100644
--- a/addons/web_editor/static/src/js/backend/fields.js
+++ b/addons/web_editor/static/src/js/backend/fields.js
@@ -118,6 +118,7 @@ var FieldTextHtmlSimple = basic_fields.DebouncedField.extend(TranslatableFieldMi
*/
_getValue: function () {
if (this.nodeOptions['style-inline']) {
+ transcoder.linkImgToAttachmentThumbnail(this.$content);
transcoder.classToStyle(this.$content);
transcoder.fontToImg(this.$content);
}
@@ -133,6 +134,8 @@ var FieldTextHtmlSimple = basic_fields.DebouncedField.extend(TranslatableFieldMi
this.$textarea.summernote(this._getSummernoteConfig());
this.$content = this.$('.note-editable:first');
this.$content.html(this._textToHtml(this.value));
+ this.$content.data('oe-id', this.recordData.res_id || this.res_id);
+ this.$content.data('oe-model', this.recordData.model || this.model);
// trigger a mouseup to refresh the editor toolbar
this.$content.trigger('mouseup');
if (this.nodeOptions['style-inline']) {
diff --git a/addons/web_editor/static/src/js/editor/rte.summernote.js b/addons/web_editor/static/src/js/editor/rte.summernote.js
index 2ac9df2d693..71982f8137b 100644
--- a/addons/web_editor/static/src/js/editor/rte.summernote.js
+++ b/addons/web_editor/static/src/js/editor/rte.summernote.js
@@ -1080,8 +1080,12 @@ var SummernoteManager = Class.extend(mixins.EventDispatcherMixin, {
return;
}
data.__alreadyDone = true;
+
var mediaDialog = new weWidgets.MediaDialog(this,
- data.options || {},
+ _.extend({
+ res_model: data.$editable.data('oe-model'),
+ res_id: data.$editable.data('oe-id'),
+ }, data.options),
data.$editable,
data.media
);
diff --git a/addons/web_editor/static/src/js/editor/snippets.options.js b/addons/web_editor/static/src/js/editor/snippets.options.js
index 38dcacf9e77..382bae0d4a7 100644
--- a/addons/web_editor/static/src/js/editor/snippets.options.js
+++ b/addons/web_editor/static/src/js/editor/snippets.options.js
@@ -872,7 +872,12 @@ registry.background = SnippetOption.extend({
// Put fake image in the DOM, edit it and use it as background-image
var $image = $('<img/>', {class: 'hidden', src: value}).appendTo(this.$target);
- var _editor = new widget.MediaDialog(this, {}, null, $image[0]).open();
+ var $editable = this.$target.closest('.o_editable');
+ var options = {
+ res_model: $editable.data('oe-model'),
+ res_id: $editable.data('oe-id'),
+ };
+ var _editor = new widget.MediaDialog(this, options, null, $image[0]).open();
_editor.opened(function () {
_editor.$('[href="#editor-media-video"], [href="#editor-media-icon"]').addClass('hidden');
});
diff --git a/addons/web_editor/static/src/js/editor/summernote.js b/addons/web_editor/static/src/js/editor/summernote.js
index 59609eab8a5..121a1a6d3d7 100644
--- a/addons/web_editor/static/src/js/editor/summernote.js
+++ b/addons/web_editor/static/src/js/editor/summernote.js
@@ -913,15 +913,21 @@ range.WrappedRange.prototype.deleteContents = function (towrite) {
return this;
}
- var prevBP = dom.removeBetween(this.sc, this.so, this.ec, this.eo, towrite);
+ var r;
+ var image = this.isOnImg();
+ if (image) {
+ // If the range matches/is in an image, then the image is to be removed
+ // and the cursor moved to its previous position
+ var parentNode = image.parentNode;
+ var index = _.indexOf(parentNode.childNodes, image);
+ parentNode.removeChild(image);
+ r = new range.WrappedRange(parentNode, index, parentNode, index);
+ } else {
+ r = dom.removeBetween(this.sc, this.so, this.ec, this.eo, towrite);
+ }
- $(dom.node(prevBP.sc)).trigger("click"); // trigger click to disable and reanable editor and image handler
- return new range.WrappedRange(
- prevBP.sc,
- prevBP.so,
- prevBP.ec,
- prevBP.eo
- );
+ $(dom.node(r.sc)).trigger("click"); // trigger click to disable and reanable editor and image handler
+ return new range.WrappedRange(r.sc, r.so, r.ec, r.eo);
};
range.WrappedRange.prototype.clean = function (mergeFilter, all) {
var node = dom.node(this.sc === this.ec ? this.sc : this.commonAncestor());
@@ -1258,7 +1264,7 @@ $.summernote.pluginEvents.visible = function (event, editor, layoutInfo) {
};
function remove_table_content(r) {
- var nodes = dom.listBetween(r.sc, r.ec);
+ var nodes = dom.listBetween(r.sc, r.ec, r.so, r.eo);
if (dom.isText(r.sc)) {
r.sc.textContent = r.sc.textContent.slice(0, r.so);
}
diff --git a/addons/web_editor/static/src/js/editor/transcoder.js b/addons/web_editor/static/src/js/editor/transcoder.js
index 11d23bf603b..54bbc803645 100644
--- a/addons/web_editor/static/src/js/editor/transcoder.js
+++ b/addons/web_editor/static/src/js/editor/transcoder.js
@@ -18,7 +18,7 @@ function getMatchedCSSRules(a) {
var sheets = document.styleSheets;
for (i = sheets.length-1 ; i >= 0 ; i--) {
var rules;
- if (sheets[i].rules) {
+ if (sheets[i].hasOwnProperty('rules')) {
rules = sheets[i].rules;
} else {
// try...catch because Firefox not able to enumerate
@@ -259,10 +259,40 @@ function styleToClass($editable) {
$c.remove();
}
+/**
+ * Converts css display for attachment link to real image.
+ * Without this post process, the display depends on the css and the picture
+ * does not appear when we use the html without css (to send by email for e.g.)
+ *
+ * @param {jQuery} $editable
+ */
+function attachmentThumbnailToLinkImg($editable) {
+ $editable.find('a[href*="/web/content/"][data-mimetype]:empty').each(function () {
+ var $link = $(this);
+ var $img = $('<img/>')
+ .attr('src', $link.css('background-image').replace(/(^url\(['"])|(['"]\)$)/g, ''))
+ .css('height', Math.max(1, $link.height()) + 'px')
+ .css('width', Math.max(1, $link.width()) + 'px');
+ $link.append($img);
+ });
+}
+
+/**
+ * Revert attachmentThumbnailToLinkImg changes
+ *
+ * @see attachmentThumbnailToLinkImg
+ * @param {jQuery} $editable
+ */
+function linkImgToAttachmentThumbnail($editable) {
+ $editable.find('a[href*="/web/content/"][data-mimetype] > img').remove();
+}
+
return {
fontToImg: fontToImg,
imgToFont: imgToFont,
classToStyle: classToStyle,
styleToClass: styleToClass,
+ attachmentThumbnailToLinkImg: attachmentThumbnailToLinkImg,
+ linkImgToAttachmentThumbnail: linkImgToAttachmentThumbnail,
};
});
diff --git a/addons/web_editor/static/src/js/inline.js b/addons/web_editor/static/src/js/inline.js
index ac0dee435ae..8715b5b7f24 100644
--- a/addons/web_editor/static/src/js/inline.js
+++ b/addons/web_editor/static/src/js/inline.js
@@ -53,6 +53,7 @@ snippet_editor.Class.include({
this._super.apply(this, arguments);
var $editable = $('#editable_area');
+ transcoder.linkImgToAttachmentThumbnail($editable);
transcoder.fontToImg($editable);
transcoder.classToStyle($editable);
diff --git a/addons/web_editor/static/src/js/widgets/widgets.js b/addons/web_editor/static/src/js/widgets/widgets.js
index e499e83843d..b93724c7a30 100644
--- a/addons/web_editor/static/src/js/widgets/widgets.js
+++ b/addons/web_editor/static/src/js/widgets/widgets.js
@@ -120,7 +120,13 @@ var ImageDialog = Widget.extend({
this._super.apply(this, arguments);
this.options = options || {};
this.accept = this.options.accept || this.options.document ? "*/*" : "image/*";
- this.domain = this.options.domain || ['|', ['mimetype', '=', false], ['mimetype', this.options.document ? 'not in' : 'in', ['image/gif', 'image/jpe', 'image/jpeg', 'image/jpg', 'image/gif', 'image/png']]];
+ if (this.options.res_id) {
+ this.domain = ['|',
+ '&', ['res_model', '=', this.options.res_model], ['res_id', '=', this.options.res_id],
+ ['res_model', '=', 'ir.ui.view']];
+ } else {
+ this.domain = [['res_model', '=', 'ir.ui.view']];
+ }
this.parent = parent;
this.old_media = media;
this.media = media;
@@ -171,6 +177,7 @@ var ImageDialog = Widget.extend({
}
},
save: function () {
+ var self = this;
if (this.options.select_images) {
return this.images;
}
@@ -181,34 +188,55 @@ var ImageDialog = Widget.extend({
img = _.find(this.images, function (img) { return img.id === id;});
}
- var media;
- if (!img.is_document) {
- if (this.media.tagName !== "IMG" || !this.old_media) {
- this.add_class = "pull-left";
- this.style = {"width": "100%"};
- }
- if (this.media.tagName !== "IMG") {
- media = document.createElement('img');
- $(this.media).replaceWith(media);
- this.media = media;
- }
- this.media.setAttribute('src', img.src);
- } else {
- if (this.media.tagName !== "A") {
- $('.note-control-selection').hide();
- media = document.createElement('a');
- $(this.media).replaceWith(media);
- this.media = media;
- }
- this.media.setAttribute('href', '/web/content/' + img.id + '?unique=' + img.checksum + '&download=true');
- $(this.media).addClass('o_image').attr('title', img.name).attr('data-mimetype', img.mimetype);
+ var def = $.when();
+ if (!img.access_token) {
+ def = this._rpc({
+ model: 'ir.attachment',
+ method: 'generate_access_token',
+ args: [[img.id]]
+ }).then(function (access_token) {
+ img.access_token = access_token[0];
+ });
}
- $(this.media).attr('alt', img.alt);
- var style = this.style;
- if (style) { $(this.media).css(style); }
+ return def.then(function () {
+ var media;
+ if (!img.is_document) {
+ if (img.access_token && self.options.res_model !== 'ir.ui.view') {
+ img.src += _.str.sprintf('?access_token=%s', img.access_token);
+ }
+ if (self.media.tagName !== "IMG" || !self.old_media) {
+ self.add_class = "pull-left";
+ self.style = {"width": "100%"};
+ }
+ if (self.media.tagName !== "IMG") {
+ media = document.createElement('img');
+ $(self.media).replaceWith(media);
+ self.media = media;
+ }
+ self.media.setAttribute('src', img.src);
+ } else {
+ if (self.media.tagName !== "A") {
+ $('.note-control-selection').hide();
+ media = document.createElement('a');
+ $(self.media).replaceWith(media);
+ self.media = media;
+ }
+ var href = '/web/content/' + img.id + '?';
+ if (img.access_token && self.options.res_model !== 'ir.ui.view') {
+ href += _.str.sprintf('access_token=%s&', img.access_token);
+ }
+ href += 'unique=' + img.checksum + '&download=true';
+ self.media.setAttribute('href', href);
+ $(self.media).addClass('o_image').attr('title', img.name).attr('data-mimetype', img.mimetype);
+ }
- return this.media;
+ $(self.media).attr('alt', img.alt);
+ var style = self.style;
+ if (style) { $(self.media).css(style); }
+
+ return self.media;
+ });
},
clear: function () {
this.media.className = this.media.className.replace(/(^|\s+)((img(\s|$)|img-(?!circle|rounded|thumbnail))[^\s]*)/g, ' ');
@@ -282,7 +310,7 @@ var ImageDialog = Widget.extend({
}
},
fetch_existing: function (needle) {
- var domain = [['res_model', '=', 'ir.ui.view']].concat(this.domain);
+ var domain = this.domain.concat(['|', ['mimetype', '=', false], ['mimetype', this.options.document ? 'not in' : 'in', ['image/gif', 'image/jpe', 'image/jpeg', 'image/jpg', 'image/gif', 'image/png']]]);
if (needle && needle.length) {
domain.push('|', ['datas_fname', 'ilike', needle], ['name', 'ilike', needle]);
}
@@ -292,7 +320,7 @@ var ImageDialog = Widget.extend({
args: [],
kwargs: {
domain: domain,
- fields: ['name', 'mimetype', 'checksum', 'url', 'type'],
+ fields: ['name', 'mimetype', 'checksum', 'url', 'type', 'res_id', 'res_model', 'access_token'],
order: [{name: 'id', asc: false}],
context: weContext.get(),
}
@@ -305,7 +333,7 @@ var ImageDialog = Widget.extend({
return (r.url || r.id);
});
_.each(this.records, function (record) {
- record.src = record.url || _.str.sprintf('/web/image/%s/%s', record.id, record.name); // Name is added for SEO purposes
+ record.src = record.url || _.str.sprintf('/web/image/%s/%s', record.id, encodeURI(record.name)); // Name is added for SEO purposes
record.is_document = !(/gif|jpe|jpg|png/.test(record.mimetype));
});
this.display_attachments();
@@ -1001,18 +1029,21 @@ var MediaDialog = Dialog.extend({
return this._super.apply(this, arguments);
},
save: function () {
+ var self = this;
+ var args = arguments;
+ var _super = this._super;
if (this.options.select_images) {
- this.final_data = this.active.save();
- this._super.apply(this, arguments);
- return;
+ return $.when(this.active.save()).then(function (data) {
+ self.final_data = data;
+ return _super.apply(self, args);
+ });
}
if (this.rte) {
this.range.select();
this.rte.historyRecordUndo(this.media);
}
- var self = this;
- if (self.media) {
+ if (this.media) {
this.media.innerHTML = "";
if (this.active !== this.imageDialog && this.active !== this.documentDialog) {
this.imageDialog.clear();
@@ -1029,27 +1060,27 @@ var MediaDialog = Dialog.extend({
this.range.insertNode(this.media, true);
this.active.media = this.media;
}
- this.active.save();
- if (this.active.add_class) {
- $(this.active.media).addClass(this.active.add_class);
- }
- var media = this.active.media;
-
- this.final_data = [media, self.old_media];
- $(document.body).trigger("media-saved", this.final_data);
- $(self.old_media).trigger("save", this.final_data);
- $(this.final_data).trigger('input');
-
- // Update editor bar after image edition (in case the image change to icon or other)
- _.defer(function () {
- if (!media.parentNode) return;
- range.createFromNode(media).select();
- click_event(media, "mousedown");
- click_event(media, "mouseup");
+ return $.when(this.active.save()).then(function () {
+ if (self.active.add_class) {
+ $(self.active.media).addClass(self.active.add_class);
+ }
+ var media = self.active.media;
+
+ self.final_data = [media, self.old_media];
+ $(document.body).trigger("media-saved", self.final_data);
+ $(self.old_media).trigger("save", self.final_data);
+ $(self.final_data).trigger('input');
+
+ // Update editor bar after image edition (in case the image change to icon or other)
+ _.defer(function () {
+ if (!media.parentNode) return;
+ range.createFromNode(media).select();
+ click_event(media, "mousedown");
+ click_event(media, "mouseup");
+ });
+ return _super.apply(self, args);
});
-
- this._super.apply(this, arguments);
},
searchTimer: null,
search: function () {
diff --git a/addons/web_editor/static/src/xml/editor.xml b/addons/web_editor/static/src/xml/editor.xml
index e8e6374305e..8f975b0d784 100644
--- a/addons/web_editor/static/src/xml/editor.xml
+++ b/addons/web_editor/static/src/xml/editor.xml
@@ -86,6 +86,8 @@
target="fileframe"
class="form-inline">
<input type="hidden" name="csrf_token" t-att-value="csrf_token"/>
+ <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"/>
<div class="well">
<div class="form-group pull-left">
<input type="file" name="upload" t-att-accept="widget.accept" multiple="multiple" style="position: absolute; opacity: 0; width: 1px; height: 1px;"/>
@@ -145,8 +147,9 @@
<div class="existing-attachments">
<div class="row mt16" t-as="row" t-foreach="rows">
<div class="col-sm-2 o_existing_attachment_cell" t-as="attachment" t-foreach="row">
- <i class="fa fa-times o_existing_attachment_remove" t-att-data-id="attachment.id"/>
- <div class="o_attachment_border"><div t-att-data-src="attachment.src" t-att-data-url="attachment.url" t-att-alt="attachment.name" t-att-title="attachment.name" t-att-data-id="attachment.id" t-att-data-mimetype="attachment.mimetype" class="o_image"/></div>
+ <i t-if="attachment.res_model === 'ir.ui.view'" class="fa fa-times o_existing_attachment_remove" title="This file is a public view attachment" t-att-data-id="attachment.id"/>
+ <i t-else="" class="fa fa-times o_existing_attachment_remove" title="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" t-att-alt="attachment.name" t-att-title="attachment.name" t-att-data-id="attachment.id" t-att-data-mimetype="attachment.mimetype" class="o_image"/></div>
</div>
</div>
</div>