summaryrefslogtreecommitdiff
path: root/addons/web_editor/static/src
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2019-08-14 16:48:10 +0200
committerChristophe Simonis <chs@odoo.com>2019-08-14 16:48:10 +0200
commit140ee6b8f0b0de7ddcc816496269963612c5d0c6 (patch)
tree7bdaa065d215b88fea4fa56adbfa79cdc24deb69 /addons/web_editor/static/src
parent839696d2d7dd574fd8958d17726379926e94d590 (diff)
parent98a55917a602c0c47093b4270ebc4e8b416ecf32 (diff)
[MERGE] forward port branch saas-12.4 up to 98a55917a60
Diffstat (limited to 'addons/web_editor/static/src')
-rw-r--r--addons/web_editor/static/src/js/backend/field_html.js3
-rw-r--r--addons/web_editor/static/src/js/wysiwyg/plugin/keyboard.js180
-rw-r--r--addons/web_editor/static/src/js/wysiwyg/plugin/media.js2
-rw-r--r--addons/web_editor/static/src/js/wysiwyg/plugin/text.js5
-rw-r--r--addons/web_editor/static/src/js/wysiwyg_snippets/snippets.editor.js4
5 files changed, 86 insertions, 108 deletions
diff --git a/addons/web_editor/static/src/js/backend/field_html.js b/addons/web_editor/static/src/js/backend/field_html.js
index 40456961aeb..5ba630edc89 100644
--- a/addons/web_editor/static/src/js/backend/field_html.js
+++ b/addons/web_editor/static/src/js/backend/field_html.js
@@ -179,6 +179,8 @@ var FieldHtml = basic_fields.DebouncedField.extend(TranslatableFieldMixin, {
* @returns {Object}
*/
_getWysiwygOptions: function () {
+ var iPhone = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
+
return {
recordInfo: {
context: this.record.getContext(this.recordParams),
@@ -197,6 +199,7 @@ var FieldHtml = basic_fields.DebouncedField.extend(TranslatableFieldMixin, {
'SHIFT+TAB': null,
},
mac: {
+ 'ENTER': iPhone ? null : 'insertParagraph',
'TAB': null,
'SHIFT+TAB': null,
},
diff --git a/addons/web_editor/static/src/js/wysiwyg/plugin/keyboard.js b/addons/web_editor/static/src/js/wysiwyg/plugin/keyboard.js
index 94ec9306f7d..9ac05220e45 100644
--- a/addons/web_editor/static/src/js/wysiwyg/plugin/keyboard.js
+++ b/addons/web_editor/static/src/js/wysiwyg/plugin/keyboard.js
@@ -9,18 +9,27 @@ dom.isAnchor = function (node) {
return (node.tagName === 'A' || node.tagName === 'BUTTON' || $(node).hasClass('btn')) &&
!$(node).hasClass('fa') && !$(node).hasClass('o_image');
};
+var keycode = ({
+ '8': 'BACKSPACE',
+ '9': 'TAB',
+ '13': 'ENTER',
+ '46': 'DELETE',
+});
-var KeyboardPlugin = AbstractPlugin.extend({
- events: {
- 'summernote.keydown': '_onKeydown',
- 'DOMNodeInserted .note-editable': '_removeGarbageSpans',
- },
-
- //--------------------------------------------------------------------------
- // Public
- //--------------------------------------------------------------------------
-
+var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
+var iPhone = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
+var KeyboardPlugin = AbstractPlugin.extend({
+ events: iPhone ?
+ {
+ 'DOMNodeInserted .note-editable': '_removeGarbageSpans',
+ } :
+ {
+ 'summernote.keydown': '_onKeydown',
+ 'DOMNodeInserted .note-editable': '_removeGarbageSpans',
+ 'keypress .note-editable': '_onKeyPress',
+ 'textInput .note-editable': '_onTextInput',
+ },
//--------------------------------------------------------------------------
// Private
@@ -818,7 +827,7 @@ var KeyboardPlugin = AbstractPlugin.extend({
}
},
/**
- * Remove the first unbreakable ancestor's next sibling if empty.
+ * Remove the first unbreakable ancestor's next sibling if not a block and empty.
*
* @private
* @param {Node} node
@@ -834,7 +843,7 @@ var KeyboardPlugin = AbstractPlugin.extend({
var isNextContainsOnlyInvisibleText = nextUnbreakable && _.all($(nextUnbreakable).contents(), function (n) {
return dom.isText(n) && !self.context.invoke('HelperPlugin.isVisibleText', n);
});
- if (isNextEmpty || isNextContainsOnlyInvisibleText) {
+ if (!dom.isBlock(nextUnbreakable) && (isNextEmpty || isNextContainsOnlyInvisibleText)) {
$(nextUnbreakable).remove();
}
},
@@ -1014,76 +1023,40 @@ var KeyboardPlugin = AbstractPlugin.extend({
* @returns {Boolean} true if case handled
*/
_onKeydown: function (se, e) {
- var self = this;
- var handled = false;
-
if (e.ctrlKey && e.key === 'a') {
e.preventDefault();
this._selectAll();
return;
}
+ if (!keycode[e.keyCode]) {
+ return;
+ }
- if (e.key &&
- (e.key.length === 1 || e.key === "Dead" || e.key === "Unidentified") &&
- !e.ctrlKey && !e.altKey && !e.metaKey) {
-
- if (e.key === "Dead" || e.key === "Unidentified") {
- this._accented = true;
- }
-
- // Record undo only if either:
- clearTimeout(this.lastCharIsVisibleTime);
- // e.key is punctuation or space
- var stopChars = [' ', ',', ';', ':', '?', '.', '!'];
- if (stopChars.indexOf(e.key) !== -1) {
- this.lastCharVisible = false;
- }
- // or not on top of history stack (record undo after undo)
- var history = this.context.invoke('HistoryPlugin.getHistoryStep');
- if (history && history.stack.length && history.stackOffset < history.stack.length - 1) {
- this.lastCharVisible = false;
- }
- // or no new char for 500ms
- this.lastCharIsVisibleTime = setTimeout(function () {
- self.lastCharIsVisible = false;
- }, 500);
- if (!this.lastCharIsVisible) {
- this.lastCharIsVisible = true;
- this.context.invoke('HistoryPlugin.recordUndo');
- }
-
- if (e.key !== "Dead") {
- this._onVisibleChar(e, this._accented);
- }
- } else {
- this.lastCharIsVisible = false;
- this.context.invoke('editor.clearTarget');
- this.context.invoke('MediaPlugin.hidePopovers');
- this.context.invoke('editor.beforeCommand');
- switch (e.keyCode) {
- case 8: // BACKSPACE
- handled = this._onBackspace(e);
- break;
- case 9: // TAB
- handled = this._onTab(e);
- break;
- case 13: // ENTER
- handled = this._onEnter(e);
- break;
- case 46: // DELETE
- handled = this._onDelete(e);
- break;
- }
- if (handled) {
- this._preventTextInEditableDiv();
- this.context.invoke('editor.saveRange');
- e.preventDefault();
- this.context.invoke('editor.afterCommand');
- }
+ this.context.invoke('editor.clearTarget');
+ this.context.invoke('MediaPlugin.hidePopovers');
+ this.context.invoke('editor.beforeCommand');
+ var handled = false;
+ switch (keycode[e.keyCode]) {
+ case 'BACKSPACE':
+ handled = this._onBackspace(e);
+ break;
+ case 'TAB':
+ handled = this._onTab(e);
+ break;
+ case 'ENTER':
+ handled = this._onEnter(e);
+ break;
+ case 'DELETE':
+ handled = this._onDelete(e);
+ break;
}
- if (e.key !== "Dead") {
- this._accented = false;
+ if (handled) {
+ e.preventDefault();
+ this._preventTextInEditableDiv();
+ this.context.invoke('editor.saveRange');
+ this.context.invoke('editor.afterCommand');
}
+ return handled;
},
/**
* Handle BACKSPACE keydown event.
@@ -1223,45 +1196,38 @@ var KeyboardPlugin = AbstractPlugin.extend({
return false;
},
/**
- * Handle visible char keydown event.
+ * Handle char input.
*
* @private
* @param {jQueryEvent} e
- * @returns {Boolean} true if case is handled and event default must be prevented
*/
- _onVisibleChar: function (e, accented) {
- var self = this;
- e.preventDefault();
- if (accented) {
- this.editable.normalize();
- var baseRange = this.context.invoke('editor.createRange');
-
- var $parent = $(baseRange.sc.parentNode);
- var parentContenteditable = $parent.attr('contenteditable');
- $parent.attr('contenteditable', false);
-
- var accentPlaceholder = this.document.createElement('span');
- $(baseRange.sc).after(accentPlaceholder);
- $(accentPlaceholder).attr('contenteditable', true);
-
- var range = this.context.invoke('editor.setRange', accentPlaceholder, 0);
- range.select();
-
- setTimeout(function () {
- var accentedChar = accentPlaceholder.innerHTML;
- $(accentPlaceholder).remove();
- if (parentContenteditable) {
- $parent.attr('contenteditable', parentContenteditable);
- } else {
- $parent.removeAttr('contenteditable');
- }
- baseRange.select();
- self.context.invoke('HelperPlugin.insertTextInline', accentedChar);
- });
- } else {
+ _onKeyPress: function (e) {
+ console.log(e.originalEvent);
+ if (!isSafari || iPhone) {
+ e.preventDefault();
this.context.invoke('HelperPlugin.insertTextInline', e.key);
}
- return true;
+ },
+ /**
+ * Handle char input.
+ *
+ * @private
+ * @param {jQueryEvent} e
+ */
+ _onTextInput: function (e) {
+ if (isSafari && !iPhone) {
+ return;
+ }
+ e.originalEvent.preventDefault();
+
+ var text = e.originalEvent.data;
+ if (!text) {
+ return;
+ }
+ if (text === 'Spacebar') {
+ text = ' ';
+ }
+ this.context.invoke('HelperPlugin.insertTextInline', text);
},
});
diff --git a/addons/web_editor/static/src/js/wysiwyg/plugin/media.js b/addons/web_editor/static/src/js/wysiwyg/plugin/media.js
index 71365e4348f..b8b4a7582fe 100644
--- a/addons/web_editor/static/src/js/wysiwyg/plugin/media.js
+++ b/addons/web_editor/static/src/js/wysiwyg/plugin/media.js
@@ -937,7 +937,7 @@ _.extend(wysiwygTranslation.image, {
dom.isVideo = function (node) {
node = node && !node.tagName ? node.parentNode : node;
return (node.tagName === "IFRAME" || node.tagName === "DIV") &&
- (node.parentNode.className && node.parentNode.className.indexOf('media_iframe_video') !== -1 ||
+ (node.parentNode && node.parentNode.className && node.parentNode.className.indexOf('media_iframe_video') !== -1 ||
node.className.indexOf('media_iframe_video') !== -1);
};
diff --git a/addons/web_editor/static/src/js/wysiwyg/plugin/text.js b/addons/web_editor/static/src/js/wysiwyg/plugin/text.js
index 5337661fa76..2b7d10d02fd 100644
--- a/addons/web_editor/static/src/js/wysiwyg/plugin/text.js
+++ b/addons/web_editor/static/src/js/wysiwyg/plugin/text.js
@@ -766,6 +766,11 @@ var TextPlugin = AbstractPlugin.extend({
* @param {jQueryEvent} e
*/
_onPaste: function (se, e) {
+ var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
+ var iPhone = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
+ if (isSafari && !iPhone) {
+ return;
+ }
se.preventDefault();
se.stopImmediatePropagation();
e.preventDefault();
diff --git a/addons/web_editor/static/src/js/wysiwyg_snippets/snippets.editor.js b/addons/web_editor/static/src/js/wysiwyg_snippets/snippets.editor.js
index d13ddf63038..4193aef5332 100644
--- a/addons/web_editor/static/src/js/wysiwyg_snippets/snippets.editor.js
+++ b/addons/web_editor/static/src/js/wysiwyg_snippets/snippets.editor.js
@@ -678,6 +678,7 @@ var SnippetsMenu = Widget.extend({
// on text changes
this.$document.on('click.snippets_menu', '.o_default_snippet_text', function (ev) {
$(ev.target).selectContent();
+ $(ev.target).removeClass('o_default_snippet_text');
});
this.$document.on('keyup.snippets_menu', function () {
var range = Wysiwyg.getRange(this);
@@ -746,6 +747,7 @@ var SnippetsMenu = Widget.extend({
},
});
this.cacheSnippetTemplate[this.options.snippets] = this._defLoadSnippets;
+ return this.cacheSnippetTemplate[this.options.snippets];
},
/**
* Sets the instance variables $editor, $body and selectorEditableArea.
@@ -1358,6 +1360,7 @@ var SnippetsMenu = Widget.extend({
if (!dropped) {
dropped = true;
$(this).first().after($toInsert).addClass('d-none');
+ $toInsert.removeClass('oe_snippet_body');
}
},
out: function () {
@@ -1366,6 +1369,7 @@ var SnippetsMenu = Widget.extend({
dropped = false;
$toInsert.detach();
$(this).removeClass('d-none');
+ $toInsert.addClass('oe_snippet_body');
}
},
});