From cebc73ebf9aa2bd6d8026473344af16726effec1 Mon Sep 17 00:00:00 2001 From: Christophe Matthieu Date: Wed, 4 Mar 2015 14:32:33 +0100 Subject: [IMP] web_editor: move summernote & nearest lib from website --- .../static/lib/summernote/src/js/module/Button.js | 157 ++++++++++++++++++++ .../static/lib/summernote/src/js/module/Dialog.js | 158 +++++++++++++++++++++ .../static/lib/summernote/src/js/module/Handle.js | 44 ++++++ .../static/lib/summernote/src/js/module/Popover.js | 106 ++++++++++++++ .../static/lib/summernote/src/js/module/Toolbar.js | 58 ++++++++ 5 files changed, 523 insertions(+) create mode 100644 addons/web_editor/static/lib/summernote/src/js/module/Button.js create mode 100644 addons/web_editor/static/lib/summernote/src/js/module/Dialog.js create mode 100644 addons/web_editor/static/lib/summernote/src/js/module/Handle.js create mode 100644 addons/web_editor/static/lib/summernote/src/js/module/Popover.js create mode 100644 addons/web_editor/static/lib/summernote/src/js/module/Toolbar.js (limited to 'addons/web_editor/static/lib/summernote/src/js/module') diff --git a/addons/web_editor/static/lib/summernote/src/js/module/Button.js b/addons/web_editor/static/lib/summernote/src/js/module/Button.js new file mode 100644 index 00000000000..512822aeba8 --- /dev/null +++ b/addons/web_editor/static/lib/summernote/src/js/module/Button.js @@ -0,0 +1,157 @@ +define([ + 'summernote/core/list' +], function (list) { + /** + * Button + */ + var Button = function () { + /** + * update button status + * + * @param {jQuery} $container + * @param {Object} styleInfo + */ + this.update = function ($container, styleInfo) { + /** + * handle dropdown's check mark (for fontname, fontsize, lineHeight). + * @param {jQuery} $btn + * @param {Number} value + */ + var checkDropdownMenu = function ($btn, value) { + $btn.find('.dropdown-menu li a').each(function () { + // always compare string to avoid creating another func. + var isChecked = ($(this).data('value') + '') === (value + ''); + this.className = isChecked ? 'checked' : ''; + }); + }; + + /** + * update button state(active or not). + * + * @param {String} selector + * @param {Function} pred + */ + var btnState = function (selector, pred) { + var $btn = $container.find(selector); + $btn.toggleClass('active', pred()); + }; + + if (styleInfo.image) { + var $img = $(styleInfo.image); + + btnState('button[data-event="imageShape"][data-value="img-rounded"]', function () { + return $img.hasClass("img-rounded"); + }); + btnState('button[data-event="imageShape"][data-value="img-circle"]', function () { + return $img.hasClass("img-circle"); + }); + btnState('button[data-event="imageShape"][data-value="img-thumbnail"]', function () { + return $img.hasClass("img-thumbnail"); + }); + btnState('button[data-event="imageShape"]:not([data-value])', function () { + return !$img.is(".img-rounded, .img-circle, .img-thumbnail"); + }); + + var imgFloat = $img.css("float"); + btnState('button[data-event="floatMe"][data-value="left"]', function () { + return imgFloat === "left"; + }); + btnState('button[data-event="floatMe"][data-value="right"]', function () { + return imgFloat === "right"; + }); + btnState('button[data-event="floatMe"][data-value="none"]', function () { + return imgFloat !== "left" && imgFloat !== "right"; + }); + + var style = $img.attr("style"); + btnState('button[data-event="resize"][data-value="1"]', function () { + return !!/(^|\s)(max-)?width\s*:\s*100%/.test(style); + }); + btnState('button[data-event="resize"][data-value="0.5"]', function () { + return !!/(^|\s)(max-)?width\s*:\s*50%/.test(style); + }); + btnState('button[data-event="resize"][data-value="0.25"]', function () { + return !!/(^|\s)(max-)?width\s*:\s*25%/.test(style); + }); + return; + } + + // fontname + var $fontname = $container.find('.note-fontname'); + if ($fontname.length) { + var selectedFont = styleInfo['font-family']; + if (!!selectedFont) { + selectedFont = list.head(selectedFont.split(',')); + selectedFont = selectedFont.replace(/\'/g, ''); + $fontname.find('.note-current-fontname').text(selectedFont); + checkDropdownMenu($fontname, selectedFont); + } + } + + // fontsize + var $fontsize = $container.find('.note-fontsize'); + $fontsize.find('.note-current-fontsize').text(styleInfo['font-size']); + checkDropdownMenu($fontsize, parseFloat(styleInfo['font-size'])); + + // lineheight + var $lineHeight = $container.find('.note-height'); + checkDropdownMenu($lineHeight, parseFloat(styleInfo['line-height'])); + + btnState('button[data-event="bold"]', function () { + return styleInfo['font-bold'] === 'bold'; + }); + btnState('button[data-event="italic"]', function () { + return styleInfo['font-italic'] === 'italic'; + }); + btnState('button[data-event="underline"]', function () { + return styleInfo['font-underline'] === 'underline'; + }); + btnState('button[data-event="strikethrough"]', function () { + return styleInfo['font-strikethrough'] === 'strikethrough'; + }); + btnState('button[data-event="superscript"]', function () { + return styleInfo['font-superscript'] === 'superscript'; + }); + btnState('button[data-event="subscript"]', function () { + return styleInfo['font-subscript'] === 'subscript'; + }); + btnState('button[data-event="justifyLeft"]', function () { + return styleInfo['text-align'] === 'left' || styleInfo['text-align'] === 'start'; + }); + btnState('button[data-event="justifyCenter"]', function () { + return styleInfo['text-align'] === 'center'; + }); + btnState('button[data-event="justifyRight"]', function () { + return styleInfo['text-align'] === 'right'; + }); + btnState('button[data-event="justifyFull"]', function () { + return styleInfo['text-align'] === 'justify'; + }); + btnState('button[data-event="insertUnorderedList"]', function () { + return styleInfo['list-style'] === 'unordered'; + }); + btnState('button[data-event="insertOrderedList"]', function () { + return styleInfo['list-style'] === 'ordered'; + }); + }; + + /** + * update recent color + * + * @param {Node} button + * @param {String} eventName + * @param {value} value + */ + this.updateRecentColor = function (button, eventName, value) { + var $color = $(button).closest('.note-color'); + var $recentColor = $color.find('.note-recent-color'); + var colorInfo = JSON.parse($recentColor.attr('data-value')); + colorInfo[eventName] = value; + $recentColor.attr('data-value', JSON.stringify(colorInfo)); + var sKey = eventName === 'backColor' ? 'background-color' : 'color'; + $recentColor.find('i').css(sKey, value); + }; + }; + + return Button; +}); diff --git a/addons/web_editor/static/lib/summernote/src/js/module/Dialog.js b/addons/web_editor/static/lib/summernote/src/js/module/Dialog.js new file mode 100644 index 00000000000..8e7cf07b323 --- /dev/null +++ b/addons/web_editor/static/lib/summernote/src/js/module/Dialog.js @@ -0,0 +1,158 @@ +define('summernote/module/Dialog', function () { + /** + * Dialog + * + * @class + */ + var Dialog = function () { + + /** + * toggle button status + * + * @param {jQuery} $btn + * @param {Boolean} isEnable + */ + var toggleBtn = function ($btn, isEnable) { + $btn.toggleClass('disabled', !isEnable); + $btn.attr('disabled', !isEnable); + }; + + /** + * show image dialog + * + * @param {jQuery} $editable + * @param {jQuery} $dialog + * @return {Promise} + */ + this.showImageDialog = function ($editable, $dialog) { + return $.Deferred(function (deferred) { + var $imageDialog = $dialog.find('.note-image-dialog'); + + var $imageInput = $dialog.find('.note-image-input'), + $imageUrl = $dialog.find('.note-image-url'), + $imageBtn = $dialog.find('.note-image-btn'); + + $imageDialog.one('shown.bs.modal', function () { + // Cloning imageInput to clear element. + $imageInput.replaceWith($imageInput.clone() + .on('change', function () { + deferred.resolve(this.files || this.value); + $imageDialog.modal('hide'); + }) + .val('') + ); + + $imageBtn.click(function (event) { + event.preventDefault(); + + deferred.resolve($imageUrl.val()); + $imageDialog.modal('hide'); + }); + + $imageUrl.on('keyup paste', function (event) { + var url; + + if (event.type === 'paste') { + url = event.originalEvent.clipboardData.getData('text'); + } else { + url = $imageUrl.val(); + } + + toggleBtn($imageBtn, url); + }).val('').trigger('focus'); + }).one('hidden.bs.modal', function () { + $imageInput.off('change'); + $imageUrl.off('keyup paste'); + $imageBtn.off('click'); + + if (deferred.state() === 'pending') { + deferred.reject(); + } + }).modal('show'); + }); + }; + + /** + * Show link dialog and set event handlers on dialog controls. + * + * @param {jQuery} $dialog + * @param {Object} linkInfo + * @return {Promise} + */ + this.showLinkDialog = function ($editable, $dialog, linkInfo) { + return $.Deferred(function (deferred) { + var $linkDialog = $dialog.find('.note-link-dialog'); + + var $linkText = $linkDialog.find('.note-link-text'), + $linkUrl = $linkDialog.find('.note-link-url'), + $linkBtn = $linkDialog.find('.note-link-btn'), + $openInNewWindow = $linkDialog.find('input[type=checkbox]'); + + $linkDialog.one('shown.bs.modal', function () { + $linkText.val(linkInfo.text); + + $linkText.on('input', function () { + // if linktext was modified by keyup, + // stop cloning text from linkUrl + linkInfo.text = $linkText.val(); + }); + + // if no url was given, copy text to url + if (!linkInfo.url) { + linkInfo.url = linkInfo.text; + toggleBtn($linkBtn, linkInfo.text); + } + + $linkUrl.on('input', function () { + toggleBtn($linkBtn, $linkUrl.val()); + // display same link on `Text to display` input + // when create a new link + if (!linkInfo.text) { + $linkText.val($linkUrl.val()); + } + }).val(linkInfo.url).trigger('focus').trigger('select'); + + $openInNewWindow.prop('checked', linkInfo.newWindow); + + $linkBtn.one('click', function (event) { + event.preventDefault(); + + deferred.resolve({ + range: linkInfo.range, + url: $linkUrl.val(), + text: $linkText.val(), + newWindow: $openInNewWindow.is(':checked') + }); + $linkDialog.modal('hide'); + }); + }).one('hidden.bs.modal', function () { + // detach events + $linkText.off('input'); + $linkUrl.off('input'); + $linkBtn.off('click'); + + if (deferred.state() === 'pending') { + deferred.reject(); + } + }).modal('show'); + }).promise(); + }; + + /** + * show help dialog + * + * @param {jQuery} $dialog + */ + this.showHelpDialog = function ($editable, $dialog) { + return $.Deferred(function (deferred) { + var $helpDialog = $dialog.find('.note-help-dialog'); + + $helpDialog.one('hidden.bs.modal', function () { + deferred.resolve(); + }).modal('show'); + }).promise(); + }; + }; + + return Dialog; +}); diff --git a/addons/web_editor/static/lib/summernote/src/js/module/Handle.js b/addons/web_editor/static/lib/summernote/src/js/module/Handle.js new file mode 100644 index 00000000000..375428faa32 --- /dev/null +++ b/addons/web_editor/static/lib/summernote/src/js/module/Handle.js @@ -0,0 +1,44 @@ +define('summernote/module/Handle', function () { + /** + * Handle + */ + var Handle = function () { + /** + * update handle + * @param {jQuery} $handle + * @param {Object} styleInfo + * @param {Boolean} isAirMode + */ + this.update = function ($handle, styleInfo, isAirMode) { + var $selection = $handle.find('.note-control-selection'); + if (styleInfo.image) { + var $image = $(styleInfo.image); + var pos = isAirMode ? $image.offset() : $image.position(); + + // include margin + var imageSize = { + w: $image.outerWidth(true), + h: $image.outerHeight(true) + }; + + $selection.css({ + display: 'block', + left: pos.left, + top: pos.top, + width: imageSize.w, + height: imageSize.h + }).data('target', styleInfo.image); // save current image element. + var sizingText = imageSize.w + 'x' + imageSize.h; + $selection.find('.note-control-selection-info').text(sizingText); + } else { + $selection.hide(); + } + }; + + this.hide = function ($handle) { + $handle.children().hide(); + }; + }; + + return Handle; +}); diff --git a/addons/web_editor/static/lib/summernote/src/js/module/Popover.js b/addons/web_editor/static/lib/summernote/src/js/module/Popover.js new file mode 100644 index 00000000000..e0531f06c45 --- /dev/null +++ b/addons/web_editor/static/lib/summernote/src/js/module/Popover.js @@ -0,0 +1,106 @@ +define([ + 'summernote/core/func', + 'summernote/core/list', + 'summernote/module/Button' +], function (func, list, Button) { + /** + * Popover (http://getbootstrap.com/javascript/#popovers) + */ + var Popover = function () { + var button = new Button(); + + this.button = button; // odoo change for overwrite + + /** + * returns position from placeholder + * @param {Node} placeholder + * @param {Boolean} isAirMode + */ + var posFromPlaceholder = function (placeholder, isAirMode) { + var $placeholder = $(placeholder); + var pos = isAirMode ? $placeholder.offset() : $placeholder.position(); + var height = $placeholder.outerHeight(true); // include margin + + // popover below placeholder. + return { + left: pos.left, + top: pos.top + height + }; + }; + + /** + * show popover + * @param {jQuery} popover + * @param {Position} pos + */ + var showPopover = function ($popover, pos) { + $popover.css({ + display: 'block', + left: pos.left, + top: pos.top + }); + }; + + var PX_POPOVER_ARROW_OFFSET_X = 20; + + /** + * update current state + * @param {jQuery} $popover - popover container + * @param {Object} styleInfo - style object + * @param {Boolean} isAirMode + */ + this.update = function ($popover, styleInfo, isAirMode) { + button.update($popover, styleInfo); + + var $linkPopover = $popover.find('.note-link-popover'); + if (styleInfo.anchor) { + var $anchor = $linkPopover.find('a'); + var href = $(styleInfo.anchor).attr('href'); + $anchor.attr('href', href).html(href); + showPopover($linkPopover, posFromPlaceholder(styleInfo.anchor, isAirMode)); + } else { + $linkPopover.hide(); + } + + var $imagePopover = $popover.find('.note-image-popover'); + if (styleInfo.image) { + showPopover($imagePopover, posFromPlaceholder(styleInfo.image, isAirMode)); + } else { + $imagePopover.hide(); + } + + var $airPopover = $popover.find('.note-air-popover'); + if (isAirMode && !styleInfo.range.isCollapsed()) { + var rect = list.last(styleInfo.range.getClientRects()); + if (rect) { + var bnd = func.rect2bnd(rect); + showPopover($airPopover, { + left: Math.max(bnd.left + bnd.width / 2 - PX_POPOVER_ARROW_OFFSET_X, 0), + top: bnd.top + bnd.height + }); + } + } else { + $airPopover.hide(); + } + }; + + /** + * @param {Node} button + * @param {String} eventName + * @param {String} value + */ + this.updateRecentColor = function (button, eventName, value) { + button.updateRecentColor(button, eventName, value); + }; + + /** + * hide all popovers + * @param {jQuery} $popover - popover container + */ + this.hide = function ($popover) { + $popover.children().hide(); + }; + }; + + return Popover; +}); diff --git a/addons/web_editor/static/lib/summernote/src/js/module/Toolbar.js b/addons/web_editor/static/lib/summernote/src/js/module/Toolbar.js new file mode 100644 index 00000000000..832b7c4c561 --- /dev/null +++ b/addons/web_editor/static/lib/summernote/src/js/module/Toolbar.js @@ -0,0 +1,58 @@ +define([ + 'summernote/core/list', + 'summernote/module/Button' +], function (list, Button) { + /** + * Toolbar + */ + var Toolbar = function () { + var button = new Button(); + + this.button = button; // odoo change for overwrite + + this.update = function ($toolbar, styleInfo) { + button.update($toolbar, styleInfo); + }; + + /** + * @param {Node} button + * @param {String} eventName + * @param {String} value + */ + this.updateRecentColor = function (buttonNode, eventName, value) { + button.updateRecentColor(buttonNode, eventName, value); + }; + + /** + * activate buttons exclude codeview + * @param {jQuery} $toolbar + */ + this.activate = function ($toolbar) { + $toolbar.find('button') + .not('button[data-event="codeview"]') + .removeClass('disabled'); + }; + + /** + * deactivate buttons exclude codeview + * @param {jQuery} $toolbar + */ + this.deactivate = function ($toolbar) { + $toolbar.find('button') + .not('button[data-event="codeview"]') + .addClass('disabled'); + }; + + this.updateFullscreen = function ($container, bFullscreen) { + var $btn = $container.find('button[data-event="fullscreen"]'); + $btn.toggleClass('active', bFullscreen); + }; + + this.updateCodeview = function ($container, isCodeview) { + var $btn = $container.find('button[data-event="codeview"]'); + $btn.toggleClass('active', isCodeview); + }; + }; + + return Toolbar; +}); -- cgit v1.2.3