summaryrefslogtreecommitdiff
path: root/addons/web_editor/static/src/xml
diff options
context:
space:
mode:
authorChristophe Matthieu <chm@odoo.com>2019-01-10 11:07:17 +0000
committerChristophe Matthieu <chm@odoo.com>2019-01-17 08:40:21 +0000
commitf296992317e96562c66bd7ad59a5080d6c551ed5 (patch)
treecd7f53aa150a734e240d930908dad1d8e5ee6943 /addons/web_editor/static/src/xml
parentde444335b7da30a2ab3a4c5b92c9731a023f3f07 (diff)
[IMP] web_editor,*: Refactoring the wysiwyg editor and 'html' field
* Creating a new structure by transforming all the plugins in the library using the odoo inheritance system. Plugins are easier to implement with the AbstractPlugin to add Odoo behaviors. * From now on, the methods of the library (in this case Summernote) can no longer be called by other modules or files. Only the wysiwyg widgets can access it, to simplify the updating process. The wysiwyg object serves as an interface. * Depending on the options the snippets will be loaded or not, the editor will be in an iframe or not... all of this is transparent from the outside. * Regarding iframes, all controllers related to editing have been removed: the new API no longer needs them. This speeds up loading, eases testing and removes complexity for the same features. PUBLIC FEATURES There are several public methods on the Wysiwyg class: * Wysiwyg.prepare (WidgetParent): returns a deferred resolved when the library (xml, lazy, assets...) is loaded. * Wysiwyg.getRange (DOM): returns the range (selection in the dom) * Wysiwyg.setRange (startNode, startOffset, endNode, endOffset): creates a range (selection in the dom) * Wysiwyg.setRangeFromNode (DOM, options) that creates a range from an element (option available to select all, start or end) A jQuery selector was added: :o_editable, which indicates whether the current element is editable. That is, if it is contained in a tag with the attribute 'contentEditable = "true"' or in a tag with the class o_editable. Several methods are also present: * focusIn: makes a focus and places the cursor at the beginning of the element * focusInEnd: makes a focus and places the cursor at the end of the element * selectContent: makes a focus and selects the content HTML FIELD The HTML field can receive different options: * style-inline: {boolean} transforms a class into an inline style when saving and vice versa when reading. * no-attachment: {boolean} prevents the use of attachments (in media dialog) * cssEdit: {xml_id} to use a template containing the css to loaded in an iframe when editing * cssReadonly: {xml_id} to use a template containing the css to load into an iframe when viewing in readonly * snippets: {xml_id} snippets template (can be used with or without cssEdit) * wrapper: {template} qweb static template (containing a tag: id = "wrapper") that will include the content during editing (removed on save) MASS MAILING A widget was created for mass mailing. There are now two fields: body_html and body_arch. body_arch contains the code with the class without conversion into inline style, useful when editing and one with the inline style that is visible in readonly mode and sent by email. Advantage: no spreading errors, able to update css/theme, able to do more changes when converting to inline style so that a maximum of mail clients have an impeccable rendering. Co-authored-by: Antoine Guenet <age@odoo.com>
Diffstat (limited to 'addons/web_editor/static/src/xml')
-rw-r--r--addons/web_editor/static/src/xml/backend.xml14
-rw-r--r--addons/web_editor/static/src/xml/editor.xml372
-rw-r--r--addons/web_editor/static/src/xml/snippets.xml6
-rw-r--r--addons/web_editor/static/src/xml/wysiwyg.xml375
-rw-r--r--addons/web_editor/static/src/xml/wysiwyg_colorpicker.xml129
5 files changed, 457 insertions, 439 deletions
diff --git a/addons/web_editor/static/src/xml/backend.xml b/addons/web_editor/static/src/xml/backend.xml
index 146d96fe1e5..904f21f440c 100644
--- a/addons/web_editor/static/src/xml/backend.xml
+++ b/addons/web_editor/static/src/xml/backend.xml
@@ -1,12 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
- <t t-name="web_editor.FieldTextHtml">
- <div class="oe_form_field oe_form_field_html oe_form_embedded_html" t-att-style="widget.attrs.style">
- <iframe/>
- </div>
- </t>
-
<t t-name="web_editor.FieldTextHtml.button.translate">
<div class="btn-group float-right">
<button t-if="widget.field.translate" class="o_field_translate btn btn-secondary" style="height: 24px; padding: 1px 17px 0px 5px" aria-label="Translate" title="Translate">
@@ -15,12 +9,4 @@
</div>
</t>
- <t t-name="web_editor.FieldTextHtml.fullscreen">
- <span style="margin: 5px; position: fixed; top: 0; right: 0; z-index: 2000;">
- <button class="o_fullscreen btn btn-primary" style="width: 24px; height: 24px; background-color: #337ab7; border: 1px solid #2e6da4; border-radius: 4px; padding: 0; position: relative;">
- <img src="/web_editor/font_to_img/61541/rgb(255,255,255)/16" style="position: absolute; top: 3px; left: 4px;" alt="Fullscreen"/>
- </button>
- </span>
- </t>
-
</templates>
diff --git a/addons/web_editor/static/src/xml/editor.xml b/addons/web_editor/static/src/xml/editor.xml
index 05e7d584337..51c3d5412ff 100644
--- a/addons/web_editor/static/src/xml/editor.xml
+++ b/addons/web_editor/static/src/xml/editor.xml
@@ -1,378 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<templates id="template" xml:space="preserve">
<!--=================-->
- <!-- Base components -->
- <!--=================-->
-
- <!-- Editor top bar which contains the summernote tools and save/discard buttons -->
- <t t-name="web_editor.editorbar">
- <div id="web_editor-top-edit">
- <div id="web_editor-toolbars"/>
- <form class="navbar-form text-muted">
- <button type="button" class="btn btn-secondary" data-action="cancel"><i class="fa fa-times"/> Discard</button>
- <button type="button" class="btn btn-primary" data-action="save"><i class="fa fa-floppy-o"/> Save</button>
- </form>
- </div>
- </t>
-
- <!-- Custom checkbox (material-design-like toggle) -->
- <t t-name="web_editor.components.switch">
- <label class="o_switch" t-att-for="id">
- <input type="checkbox" t-att-id="id"/>
- <span/>
- <t t-if="label"><t t-esc="label"/></t>
- </label>
- </t>
-
- <!--=================-->
- <!-- Edition Dialogs -->
- <!--=================-->
-
- <!-- Alt Dialog (allows to change alt and title of page images) -->
- <form t-name="web_editor.dialog.alt" action="#">
- <div class="form-group row">
- <label class="col-md-3 col-form-label" for="alt"
- title="'Alt tag' specifies an alternate text for an image, if the image cannot be displayed (slow connection, missing image, screen reader ...).">
- Description <small>(ALT Tag)</small>
- </label>
- <div class="col-md-8">
- <input class="form-control" id="alt" required="required" t-att-value="widget.alt" type="text"/>
- </div>
- </div>
- <div class="form-group row">
- <label class="col-md-3 col-form-label" for="title"
- title="'Title tag' is shown as a tooltip when you hover the picture.">
- Tooltip <small>(TITLE Tag)</small>
- </label>
- <div class="col-md-8">
- <input class="form-control" id="title" required="required" t-att-value="widget.tag_title" type="text"/>
- </div>
- </div>
- </form>
-
- <!-- Media Dialog (allows to choose an img/pictogram/video) -->
- <div t-name="web_editor.dialog.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>
- </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>
- </div>
- <t t-name="web_editor.dialog.media.search">
- <div class="input-group ml-auto">
- <input type="text" class="form-control o_we_search" t-att-placeholder="searchPlaceholder.trim()"/>
- <div class="input-group-append">
- <div class="input-group-text o_we_search_icon">
- <i class="fa fa-search" title="Search" role="img" aria-label="Search"/>
- </div>
- </div>
- </div>
- </t>
-
- <!-- Image choosing part of the Media Dialog -->
- <t t-name="web_editor.dialog.image">
- <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 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="web_editor.dialog.files.submenu">
- <t t-set="isDocument" t-value="widget.options.document"/>
- <t t-set="accept" t-value="widget.accept"/>
- </t>
- <div class="form-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>
- <div class="mt-4 o_load_done_msg d-none">
- <span><i>All attachments have been loaded</i></span>
- </div>
- </div>
- <iframe class="o_file_upload_iframe d-none" t-att-name="iframeName"/>
- </form>
- </t>
- <t t-name="web_editor.dialog.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="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>
- </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>
- </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'}"/>
- <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>
- </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"/>
- </div>
- </div>
- </div>
-
- <t t-call="web_editor.dialog.media.search">
- <t t-set="searchPlaceholder">
- <t t-if="isDocument">Search a document</t>
- <t t-else="">Search an image</t>
- </t>
- </t>
- </div>
- </t>
- <t t-name="web_editor.dialog.files.existing.content">
- <div class="existing-attachments">
- <div t-foreach="rows" t-as="row" class="row mt-2">
- <div t-foreach="row" t-as="attachment" class="col-2 o_existing_attachment_cell">
- <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="web_editor.dialog.image.existing.error">
- <div class="form-text">
- <p>The image could not be deleted because it is used in the
- following pages or views:</p>
- <ul t-as="view" t-foreach="views">
- <li>
- <a t-attf-href="/web#model=ir.ui.view&amp;id=#{view.id}">
- <t t-esc="view.name"/>
- </a>
- </li>
- </ul>
- </div>
- </t>
-
- <!-- Icon choosing part of the Media Dialog -->
- <t t-name="web_editor.dialog.font-icons">
- <form action="#">
- <div class="form-inline align-items-center py-4">
- <t t-call="web_editor.dialog.media.search">
- <t t-set="searchPlaceholder">Search a pictogram</t>
- </t>
- </div>
- <div class="font-icons-icons">
- <t t-call="web_editor.dialog.font-icons.icons">
- <t t-set="iconsParser" t-value="widget.iconsParser"/>
- </t>
- </div>
- </form>
- </t>
- <t t-name="web_editor.dialog.font-icons.icons">
- <t t-as="data" t-foreach="iconsParser">
- <span t-foreach="data.cssData" t-as="cssData"
- t-att-data-id="cssData.names[0]"
- t-att-title="cssData.names[0]"
- t-att-aria-label="cssData.names[0]" role="img"
- t-attf-class="font-icons-icon #{data.base} #{cssData.names[0]}"
- t-att-data-alias="cssData.names.join(',')"/>
- </t>
- </t>
-
- <!-- Video choosing part of the Media Dialog -->
- <t t-name="web_editor.dialog.video">
- <form action="#" class="row">
- <div class="col mt-4 o_video_dialog_form">
- <div class="form-group mb-2" id="o_video_form_group">
- <label class="col-form-label" for="o_video_text">
- Video code <small>(URL or Embed)</small>
- <div class="o_validate_feedback">
- <i class="fa fa-check text-success" role="img" aria-label="Checked" title="Checked"/>
- <i class="fa fa-exclamation-triangle text-danger" role="img" aria-label="Attention" title="Attention"/>
- </div>
- </label>
- <textarea class="form-control" id="o_video_text" placeholder="Copy-paste your URL or embed code here"/>
- </div>
- <div class="text-right">
- <small class="text-muted">Accepts <b><i>Youtube</i></b>, <b><i>Instagram</i></b>, <b><i>Vine.co</i></b>, <b><i>Vimeo</i></b>, <b><i>Dailymotion</i></b> and <b><i>Youku</i></b> videos</small>
- </div>
- <div class="o_video_dialog_options d-none mt-4">
- <div class="o_yt_option o_vim_option o_dm_option">
- <label class="o_switch mb0"><input id="o_video_autoplay" type="checkbox"/><span/>Autoplay</label>
- </div>
- <div class="o_yt_option o_vim_option">
- <label class="o_switch mb0"><input id="o_video_loop" type="checkbox"/><span/>Loop</label>
- </div>
- <div class="o_yt_option o_dm_option">
- <label class="o_switch mb0"><input id="o_video_hide_controls" type="checkbox"/><span/>Hide player controls</label>
- </div>
- <div class="o_yt_option">
- <label class="o_switch mb0"><input id="o_video_hide_fullscreen" type="checkbox"/><span/>Hide fullscreen button</label>
- </div>
- <div class="o_yt_option">
- <label class="o_switch mb0"><input id="o_video_hide_yt_logo" type="checkbox"/><span/>Hide Youtube logo</label>
- </div>
- <div class="o_dm_option">
- <label class="o_switch mb0"><input id="o_video_hide_dm_logo" type="checkbox"/><span/>Hide Dailymotion logo</label>
- </div>
- <div class="o_dm_option">
- <label class="o_switch mb0"><input id="o_video_hide_dm_share" type="checkbox"/><span/>Hide sharing button</label>
- </div>
- </div>
- </div>
- <div class="col-md-6">
- <div id="video-preview" class="p-3">
- <div class="o_video_dialog_preview_text small mb-2 d-none">Preview</div>
- <div class="media_iframe_video">
- <div class="media_iframe_video_size"/>
- <iframe class="o_video_dialog_iframe" allowfullscreen="allowfullscreen" frameborder="0" src=""/>
- </div>
- </div>
- </div>
- </form>
- </t>
-
- <!-- Link Dialog (allows to choose a style and content for a link on the page) -->
- <div t-name="web_editor.dialog.link" class="o_link_dialog">
- <div class="row">
- <form class="col-lg-8">
- <div t-attf-class="form-group row#{widget.needLabel ? '' : ' d-none'}">
- <label class="col-form-label col-md-3" for="o_link_dialog_label_input">Link Label</label>
- <div class="col-md-9">
- <input type="text" name="label" class="form-control" id="o_link_dialog_label_input" required="required" t-att-value="widget.data.text"/>
- </div>
- </div>
- <div class="form-group row o_url_input">
- <label class="col-form-label col-md-3" for="o_link_dialog_url_input">URL or Email</label>
- <div class="col-md-9">
- <input type="text" name="url" class="form-control" id="o_link_dialog_url_input" required="required"/>
- </div>
- </div>
- <div class="form-group row">
- <label class="col-form-label col-md-3">Size</label>
- <div class="col-md-9">
- <select name="link_style_size" class="form-control link-style">
- <option value="sm">Small</option>
- <option value="" selected="selected">Medium</option>
- <option value="lg">Large</option>
- </select>
- </div>
- </div>
- <div class="form-group row">
- <label class="col-form-label col-md-3">Style</label>
- <div class="col-md-9">
- <select name="link_style_shape" class="form-control link-style">
- <option value="" selected="selected">Default</option>
- <option value="outline">Outline</option>
- <option value="rounded-circle">Rounded</option>
- <option value="outline,rounded-circle">Outline-Rounded</option>
- <option value="flat">Flat</option>
- </select>
- </div>
- </div>
- <div class="form-group row">
- <label class="col-form-label col-md-3">Color</label>
- <div class="col-md-9">
- <div class="o_link_dialog_color">
- <label role="button" t-attf-class="o_link_dialog_color_item o_btn_preview btn btn-link text-center" data-color="">
- <span>L</span>
- <input class="d-none link-style" name="link_style_color" type="radio" value=""/>
- <i class="fa"/>
- </label>
- <t t-foreach="['alpha', 'beta', 'gamma', 'delta', 'epsilon', 'primary', 'secondary', 'success', 'info', 'warning', 'danger']" t-as="color">
- <label role="button" t-attf-class="o_link_dialog_color_item o_btn_preview btn btn-#{color}" t-attf-aria-label="Color for #{color}" t-attf-title="Color for #{color}">
- <input type="radio" name="link_style_color" class="d-none link-style" t-att-value="color"/>
- <i class="fa"/>
- </label>
- </t>
- </div>
- </div>
- </div>
- <div class="form-group row">
- <div class="offset-md-3 col-md-9">
- <label class="o_switch">
- <input type="checkbox" name="is_new_window" t-att-checked="widget.data.isNewWindow ? 'checked' : undefined"/>
- <span/>
- Open in new window
- </label>
- </div>
- </div>
- </form>
- <div class="col-lg-4 o_link_dialog_preview">
- <div class="form-group text-center">
- <label>Preview</label>
- <div style="overflow: auto; max-width: 100%; max-height: 200px;">
- <a href="#" id="link-preview" aria-label="Preview" title="Preview"/>
- </div>
- </div>
- </div>
- </div>
- </div>
-
- <!-- Crop Image Dialog (allows to crop image on the page) -->
- <div t-name="web_editor.dialog.crop_image" class="o_crop_image_dialog">
- <div t-if="widget.imageData.isExternalImage" class="alert alert-warning text-center" role="alert">
- <i class="fa fa-exclamation-triangle fa-2x"/>
- <h4>This image is an external image</h4>
- <p>
- This type of image is not supported for cropping.<br/>
- If you want to crop it, please first download it from the original source and upload it in Odoo.
- </p>
- </div>
- <t t-else="">
- <div class="o_crop_area">
- <img class="img img-fluid o_cropper_image" t-att-src="widget.imageData.originalSrc"/>
- </div>
- <div class="o_crop_options text-center mt16">
- <div class="btn-group btn-group-toggle" title="Aspect Ratio" data-toggle="buttons">
- <t t-foreach="widget.aspectRatioList" t-as="ratio">
- <t t-set="is_active" t-value="ratio[1] === widget.imageData.aspectRatio"/>
- <label t-attf-class="btn btn-secondary#{is_active and ' active' or ''}" data-event="ratio" t-att-data-label="ratio[1]" t-att-data-value="ratio[2]">
- <input type="radio" /><t t-esc="ratio[0]"/>
- </label>
- </t>
- </div>
- <div class="btn-group" role="group">
- <button type="button" class="btn btn-secondary" title="Zoom In" data-event="zoom" data-value="0.1"><i class="fa fa-search-plus"/></button>
- <button type="button" class="btn btn-secondary" title="Zoom Out" data-event="zoom" data-value="-0.1"><i class="fa fa-search-minus"/></button>
- </div>
- <div class="btn-group" role="group">
- <button type="button" class="btn btn-secondary" title="Rotate Left" data-event="rotate" data-value="-45"><i class="fa fa-rotate-left"/></button>
- <button type="button" class="btn btn-secondary" title="Rotate Right" data-event="rotate" data-value="45"><i class="fa fa-rotate-right"/></button>
- </div>
- <div class="btn-group" role="group">
- <button type="button" class="btn btn-secondary" title="Flip Horizontal" data-event="flip" data-value="horizontal" data-x="1"><i class="fa fa-arrows-h"/></button>
- <button type="button" class="btn btn-secondary" title="Flip Vertical" data-event="flip" data-value="vertical" data-y="1"><i class="fa fa-arrows-v"/></button>
- </div>
- <div class="btn-group" role="group">
- <button type="button" class="btn btn-secondary" title="Reset Image" data-event="reset"><i class="fa fa-refresh"/> Reset Image</button>
- </div>
- </div>
- </t>
- </div>
-
- <!--=================-->
<!-- Snippet options -->
<!--=================-->
diff --git a/addons/web_editor/static/src/xml/snippets.xml b/addons/web_editor/static/src/xml/snippets.xml
index 7b85fb3998c..6e2ae656f2d 100644
--- a/addons/web_editor/static/src/xml/snippets.xml
+++ b/addons/web_editor/static/src/xml/snippets.xml
@@ -40,9 +40,9 @@
<t t-name="web_editor.many2one.button">
<div class="btn-group">
<a role="button" href="#" class="btn btn-secondary dropdown-toggle" data-toggle="dropdown" data-hover="dropdown" title="Search Contact" aria-label="Search Contact"><i class="fa fa-search"></i></a>
- <div class="dropdown-menu contact_menu" role="menu">
- <a role="menuitem" class="dropdown-item"><input href="#" type="email" placeholder="Search"/></a>
- </div>
+ <ul class="dropdown-menu contact_menu" role="menu">
+ <li><a role="menuitem" class="dropdown-item"><input href="#" type="email" placeholder="Search"/></a></li>
+ </ul>
</div>
</t>
diff --git a/addons/web_editor/static/src/xml/wysiwyg.xml b/addons/web_editor/static/src/xml/wysiwyg.xml
new file mode 100644
index 00000000000..2330629a93b
--- /dev/null
+++ b/addons/web_editor/static/src/xml/wysiwyg.xml
@@ -0,0 +1,375 @@
+<?xml version="1.0" encoding="utf-8"?>
+<templates id="template" xml:space="preserve">
+
+ <!--=================-->
+ <!-- Edition Dialogs -->
+ <!--=================-->
+
+ <!-- Alt Dialog (allows to change alt and title of page images) -->
+ <form t-name="wysiwyg.widgets.alt" action="#">
+ <div class="form-group row">
+ <label class="col-md-3 col-form-label" for="alt"
+ title="'Alt tag' specifies an alternate text for an image, if the image cannot be displayed (slow connection, missing image, screen reader ...).">
+ Description <small>(ALT Tag)</small>
+ </label>
+ <div class="col-md-8">
+ <input class="form-control" id="alt" required="required" t-att-value="widget.alt" type="text"/>
+ </div>
+ </div>
+ <div class="form-group row">
+ <label class="col-md-3 col-form-label" for="title"
+ title="'Title tag' is shown as a tooltip when you hover the picture.">
+ Tooltip <small>(TITLE Tag)</small>
+ </label>
+ <div class="col-md-8">
+ <input class="form-control" id="title" required="required" t-att-value="widget.tag_title" type="text"/>
+ </div>
+ </div>
+ </form>
+
+ <!-- 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>
+ </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>
+ </div>
+
+ <t t-name="wysiwyg.widgets.media.search">
+ <div class="input-group ml-auto">
+ <input type="text" class="form-control o_we_search" t-att-placeholder="searchPlaceholder.trim()"/>
+ <div class="input-group-append">
+ <div class="input-group-text o_we_search_icon">
+ <i class="fa fa-search" title="Search" role="img" aria-label="Search"/>
+ </div>
+ </div>
+ </div>
+ </t>
+
+ <!-- Image choosing part of the Media Dialog -->
+ <t t-name="wysiwyg.widgets.image">
+ <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 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"/>
+ <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>
+ <div class="mt-4 o_load_done_msg d-none">
+ <span><i>All attachments have been loaded</i></span>
+ </div>
+ </div>
+ <iframe class="o_file_upload_iframe d-none" t-att-name="iframeName"/>
+ </form>
+ </t>
+
+ <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="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>
+ </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>
+ </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'}"/>
+ <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>
+ </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"/>
+ </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>
+ </div>
+ </t>
+
+ <t t-name="wysiwyg.widgets.image.existing">
+ <div role="dialog" class="modal" tabindex="-1">
+ <div class="modal-dialog select-image">
+ <div class="modal-content">
+ <header class="modal-header">
+ <h3 class="modal-title">Select a Picture</h3>
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close">×</button>
+ </header>
+ <main class="modal-body o_has_error">
+ <div class="existing-attachments"/>
+ <div class="form-text"/>
+ </main>
+ <footer class="modal-footer">
+ <button data-dismiss="modal" type="button" aria-label="Discard">Discard</button>
+ </footer>
+ </div>
+ </div>
+ </div>
+ </t>
+ <t t-name="wysiwyg.widgets.files.existing.content">
+ <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.image.existing.error">
+ <div class="form-text">
+ <p>The image could not be deleted because it is used in the
+ following pages or views:</p>
+ <ul t-as="view" t-foreach="views">
+ <li>
+ <a t-attf-href="/web#model=ir.ui.view&amp;id=#{view.id}">
+ <t t-esc="view.name"/>
+ </a>
+ </li>
+ </ul>
+ </div>
+ </t>
+
+ <!-- Icon choosing part of the Media Dialog -->
+ <t t-name="wysiwyg.widgets.font-icons">
+ <form action="#">
+ <div class="form-inline align-items-center py-4">
+ <t t-call="wysiwyg.widgets.media.search">
+ <t t-set="searchPlaceholder">Search a pictogram</t>
+ </t>
+ </div>
+ <div class="font-icons-icons">
+ <t t-call="wysiwyg.widgets.font-icons.icons">
+ <t t-set="iconsParser" t-value="widget.iconsParser"/>
+ </t>
+ </div>
+ </form>
+ </t>
+ <t t-name="wysiwyg.widgets.font-icons.icons">
+ <t t-as="data" t-foreach="iconsParser">
+ <span t-foreach="data.cssData" t-as="cssData"
+ t-att-data-id="cssData.names[0]"
+ t-att-title="cssData.names[0]"
+ t-att-aria-label="cssData.names[0]" role="img"
+ t-attf-class="font-icons-icon #{data.base} #{cssData.names[0]}"
+ t-att-data-alias="cssData.names.join(',')"/>
+ </t>
+ </t>
+
+ <!-- Video choosing part of the Media Dialog -->
+ <t t-name="wysiwyg.widgets.video">
+ <form action="#" class="row">
+ <div class="col mt-4 o_video_dialog_form">
+ <div class="form-group mb-2" id="o_video_form_group">
+ <label class="col-form-label" for="o_video_text">
+ Video code <small>(URL or Embed)</small>
+ <div class="o_validate_feedback">
+ <i class="fa fa-check text-success" role="img" aria-label="Checked" title="Checked"/>
+ <i class="fa fa-exclamation-triangle text-danger" role="img" aria-label="Attention" title="Attention"/>
+ </div>
+ </label>
+ <textarea class="form-control" id="o_video_text" placeholder="Copy-paste your URL or embed code here"/>
+ </div>
+ <div class="text-right">
+ <small class="text-muted">Accepts <b><i>Youtube</i></b>, <b><i>Instagram</i></b>, <b><i>Vine.co</i></b>, <b><i>Vimeo</i></b>, <b><i>Dailymotion</i></b> and <b><i>Youku</i></b> videos</small>
+ </div>
+ <div class="o_video_dialog_options d-none mt-4">
+ <div class="o_yt_option o_vim_option o_dm_option">
+ <label class="o_switch mb0"><input id="o_video_autoplay" type="checkbox"/><span/>Autoplay</label>
+ </div>
+ <div class="o_yt_option o_vim_option">
+ <label class="o_switch mb0"><input id="o_video_loop" type="checkbox"/><span/>Loop</label>
+ </div>
+ <div class="o_yt_option o_dm_option">
+ <label class="o_switch mb0"><input id="o_video_hide_controls" type="checkbox"/><span/>Hide player controls</label>
+ </div>
+ <div class="o_yt_option">
+ <label class="o_switch mb0"><input id="o_video_hide_fullscreen" type="checkbox"/><span/>Hide fullscreen button</label>
+ </div>
+ <div class="o_yt_option">
+ <label class="o_switch mb0"><input id="o_video_hide_yt_logo" type="checkbox"/><span/>Hide Youtube logo</label>
+ </div>
+ <div class="o_dm_option">
+ <label class="o_switch mb0"><input id="o_video_hide_dm_logo" type="checkbox"/><span/>Hide Dailymotion logo</label>
+ </div>
+ <div class="o_dm_option">
+ <label class="o_switch mb0"><input id="o_video_hide_dm_share" type="checkbox"/><span/>Hide sharing button</label>
+ </div>
+ </div>
+ </div>
+ <div class="col-md-6">
+ <div id="video-preview" class="p-3">
+ <div class="o_video_dialog_preview_text small mb-2 d-none">Preview</div>
+ <div class="media_iframe_video">
+ <div class="media_iframe_video_size"/>
+ <iframe class="o_video_dialog_iframe" allowfullscreen="allowfullscreen" frameborder="0" src=""/>
+ </div>
+ </div>
+ </div>
+ </form>
+ </t>
+
+
+ <!-- Link Dialog (allows to choose a style and content for a link on the page) -->
+ <div t-name="wysiwyg.widgets.link" class="o_link_dialog">
+ <div class="row">
+ <form class="col-lg-8">
+ <div t-attf-class="form-group row#{widget.needLabel ? '' : ' d-none'}">
+ <label class="col-form-label col-md-3" for="o_link_dialog_label_input">Link Label</label>
+ <div class="col-md-9">
+ <input type="text" name="label" class="form-control" id="o_link_dialog_label_input" required="required" t-att-value="widget.data.text"/>
+ </div>
+ </div>
+ <div class="form-group row">
+ <label class="col-form-label col-md-3" for="o_link_dialog_url_input">URL or Email</label>
+ <div class="col-md-9">
+ <input type="text" name="url" class="form-control" id="o_link_dialog_url_input" required="required"/>
+ </div>
+ </div>
+ <div class="form-group row">
+ <label class="col-form-label col-md-3">Size</label>
+ <div class="col-md-9">
+ <select name="link_style_size" class="form-control link-style">
+ <option value="sm">Small</option>
+ <option value="" selected="selected">Medium</option>
+ <option value="lg">Large</option>
+ </select>
+ </div>
+ </div>
+ <div class="form-group row">
+ <label class="col-form-label col-md-3">Style</label>
+ <div class="col-md-9">
+ <select name="link_style_shape" class="form-control link-shape">
+ <option value="" selected="selected">Default</option>
+ <option value="outline">Outline</option>
+ <option value="rounded-circle">Rounded</option>
+ <option value="outline,rounded-circle">Outline-Rounded</option>
+ <option value="flat">Flat</option>
+ </select>
+ </div>
+ </div>
+ <div class="form-group row">
+ <label class="col-form-label col-md-3">Color</label>
+ <div class="col-md-9">
+ <div class="o_link_dialog_color">
+ <label role="button" t-attf-class="o_link_dialog_color_item o_btn_preview btn btn-link text-center" data-color="">
+ <span>L</span>
+ <input class="d-none link-style" name="link_style_color" type="radio" value=""/>
+ <i class="fa"/>
+ </label>
+ <t t-foreach="['alpha', 'beta', 'gamma', 'delta', 'epsilon', 'primary', 'secondary', 'success', 'info', 'warning', 'danger']" t-as="color">
+ <label role="button" t-attf-class="o_link_dialog_color_item o_btn_preview btn btn-#{color}" t-attf-aria-label="Color for #{color}" t-attf-title="Color for #{color}">
+ <input type="radio" name="link_style_color" class="d-none link-style" t-att-value="color"/>
+ <i class="fa"/>
+ </label>
+ </t>
+ </div>
+ </div>
+ </div>
+ <div class="form-group row">
+ <div class="offset-md-3 col-md-9">
+ <label class="o_switch">
+ <input type="checkbox" name="is_new_window" t-att-checked="widget.data.isNewWindow ? 'checked' : undefined"/>
+ <span/>
+ Open in new window
+ </label>
+ </div>
+ </div>
+ </form>
+ <div class="col-lg-4 o_link_dialog_preview">
+ <div class="form-group text-center">
+ <label>Preview</label>
+ <div style="overflow-x: auto; max-width: 100%; max-height: 200px;">
+ <a href="#" id="link-preview" aria-label="Preview" title="Preview"/>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <!-- Crop Image Dialog (allows to crop image on the page) -->
+ <div t-name="wysiwyg.widgets.crop_image" class="o_crop_image_dialog">
+ <div t-if="widget.imageData.isExternalImage" class="alert alert-warning text-center" role="alert">
+ <i class="fa fa-exclamation-triangle fa-2x"/>
+ <h4>This image is an external image</h4>
+ <p>
+ This type of image is not supported for cropping.<br/>
+ If you want to crop it, please first download it from the original source and upload it in Odoo.
+ </p>
+ </div>
+ <t t-else="">
+ <div class="o_crop_area">
+ <img class="img img-fluid o_cropper_image" t-att-src="widget.imageData.originalSrc"/>
+ </div>
+ <div class="o_crop_options text-center mt16">
+ <div class="btn-group btn-group-toggle" title="Aspect Ratio" data-toggle="buttons">
+ <t t-foreach="widget.aspectRatioList" t-as="ratio">
+ <t t-set="is_active" t-value="ratio[1] === widget.imageData.aspectRatio"/>
+ <label t-attf-class="btn btn-secondary#{is_active and ' active' or ''}" data-event="ratio" t-att-data-label="ratio[1]" t-att-data-value="ratio[2]">
+ <input type="radio" /><t t-esc="ratio[0]"/>
+ </label>
+ </t>
+ </div>
+ <div class="btn-group" role="group">
+ <button type="button" class="btn btn-secondary" title="Zoom In" data-event="zoom" data-value="0.1"><i class="fa fa-search-plus"/></button>
+ <button type="button" class="btn btn-secondary" title="Zoom Out" data-event="zoom" data-value="-0.1"><i class="fa fa-search-minus"/></button>
+ </div>
+ <div class="btn-group" role="group">
+ <button type="button" class="btn btn-secondary" title="Rotate Left" data-event="rotate" data-value="-45"><i class="fa fa-rotate-left"/></button>
+ <button type="button" class="btn btn-secondary" title="Rotate Right" data-event="rotate" data-value="45"><i class="fa fa-rotate-right"/></button>
+ </div>
+ <div class="btn-group" role="group">
+ <button type="button" class="btn btn-secondary" title="Flip Horizontal" data-event="flip" data-value="horizontal" data-x="1"><i class="fa fa-arrows-h"/></button>
+ <button type="button" class="btn btn-secondary" title="Flip Vertical" data-event="flip" data-value="vertical" data-y="1"><i class="fa fa-arrows-v"/></button>
+ </div>
+ <div class="btn-group" role="group">
+ <button type="button" class="btn btn-secondary" title="Reset Image" data-event="reset"><i class="fa fa-refresh"/> Reset Image</button>
+ </div>
+ </div>
+ </t>
+ </div>
+
+</templates>
diff --git a/addons/web_editor/static/src/xml/wysiwyg_colorpicker.xml b/addons/web_editor/static/src/xml/wysiwyg_colorpicker.xml
index 4d85f3172a1..882a0edea11 100644
--- a/addons/web_editor/static/src/xml/wysiwyg_colorpicker.xml
+++ b/addons/web_editor/static/src/xml/wysiwyg_colorpicker.xml
@@ -1,62 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates>
- <t t-name="web.colorpicker">
- <div class="o_colorpicker_widget">
- <div class="row">
- <div class="col-auto">
- <div class="o_color_pick_area d-inline-block border">
- <div class="o_picker_pointer rounded-circle"/>
+ <div t-name="wysiwyg.plugin.font.paletteButton" t-attf-class="note-btn-group btn-group {{className}}">
+ <button type="button" class="note-btn btn btn-light btn-sm dropdown-toggle" tabindex="-1" data-toggle="dropdown"><i
+ t-att-class="icon"></i></button>
+ <div class="dropdown-menu" />
+ </div>
+
+ <div t-name="wysiwyg.plugin.font.colorPalette" class="note-palette">
+ <button type="button" class="note-color-reset btn btn-light note-color-btn bg-undefined">
+ <t t-esc="lang.color.resetToDefault" /></button>
+ <div class="note-holder">
+ <div class="note-color-palette">
+ <h6 class="mt-2">Theme colors</h6>
+ <div class="o_theme_color_placeholder" />
+ <h6 class="mt-2">Transparent colors</h6>
+ <div class="o_transparent_color_placeholder" />
+ <h6 class="mt-2">Common colors</h6>
+ <div class="o_common_color_placeholder">
+ <div class="note-color-row" t-foreach="colors" t-as="rowColors">
+ <button t-foreach="rowColors" t-as="color" type="button" class="note-color-btn" data-toggle="button"
+ tabindex="-1" t-attf-style="background-color:{{color}}" t-att-data-value="color"
+ t-att-title="color" />
</div>
- <div class="o_color_slider d-inline-block ml-2 border">
- <div class="o_slider_pointer"/>
- </div>
- <div class="o_opacity_slider d-inline-block ml-2 border">
- <div class="o_opacity_pointer"/>
+ </div>
+ </div>
+ <h6 class="note-custom-color mt8">
+ <t t-esc="lang.color.customColor" />
+ </h6>
+ <button class="note-custom-color-btn note-color-btn" style="display: none;"></button>
+ </div>
+ </div>
+
+ <div t-name="wysiwyg.widgets.ColorpickerDialog" class="o_colorpicker_widget">
+ <div class="row">
+ <div class="col-auto">
+ <div class="o_color_pick_area d-inline-block border">
+ <div class="o_picker_pointer rounded-circle" />
+ </div>
+ <div class="o_color_slider d-inline-block ml-2 border">
+ <div class="o_slider_pointer" />
+ </div>
+ <div class="o_opacity_slider d-inline-block ml-2 border">
+ <div class="o_opacity_pointer" />
+ </div>
+ </div>
+ <form class="col o_color_picker_inputs">
+ <div class="input-group">
+ <div class="input-group-prepend">
+ <span class="input-group-text rounded-0 o_color_preview" />
</div>
+ <input type="text" class="form-control o_hex_input" data-color-method="hex" />
</div>
- <form class="col o_color_picker_inputs">
- <div class="input-group">
- <div class="input-group-prepend o_color_preview_parent">
- <span class="input-group-text rounded-0 o_color_preview"/>
+ <div class="form-row mt-2">
+ <div class="col">
+ <div class="form-group">
+ <label for="red">Red</label>
+ <input type="text" class="form-control o_red_input" data-color-method="rgb" id="red" />
</div>
- <input type="text" class="form-control o_hex_input" data-color-method="hex"/>
- </div>
- <div class="form-row mt-2">
- <div class="col">
- <div class="form-group">
- <label for="red">Red</label>
- <input type="text" class="form-control o_red_input" data-color-method="rgb" id="red"/>
- </div>
- <div class="form-group">
- <label for="green">Green</label>
- <input type="text" class="form-control o_green_input" data-color-method="rgb" id="green"/>
- </div>
- <div class="form-group">
- <label for="blue">Blue</label>
- <input type="text" class="form-control o_blue_input" data-color-method="rgb" id="blue"/>
- </div>
+ <div class="form-group">
+ <label for="green">Green</label>
+ <input type="text" class="form-control o_green_input" data-color-method="rgb" id="green" />
</div>
- <div class="col">
- <div class="form-group">
- <label for="hue">Hue</label>
- <input type="text" class="form-control o_hue_input" data-color-method="hsl" id="hue"/>
- </div>
- <div class="form-group">
- <label for="saturation">Saturation %</label>
- <input type="text" class="form-control o_saturation_input" data-color-method="hsl" id="saturation"/>
- </div>
- <div class="form-group">
- <label for="lightness">Lightness %</label>
- <input type="text" class="form-control o_lightness_input" data-color-method="hsl" id="lightness"/>
- </div>
+ <div class="form-group">
+ <label for="blue">Blue</label>
+ <input type="text" class="form-control o_blue_input" data-color-method="rgb" id="blue" />
</div>
</div>
- <div class="form-group">
- <label for="opacity">Opacity %</label>
- <input type="text" class="form-control o_opacity_input" data-color-method="opacity" id="opacity"/>
+ <div class="col">
+ <div class="form-group">
+ <label for="hue">Hue</label>
+ <input type="text" class="form-control o_hue_input" data-color-method="hsl" id="hue" />
+ </div>
+ <div class="form-group">
+ <label for="saturation">Saturation %</label>
+ <input type="text" class="form-control o_saturation_input" data-color-method="hsl" id="saturation" />
+ </div>
+ <div class="form-group">
+ <label for="lightness">Lightness %</label>
+ <input type="text" class="form-control o_lightness_input" data-color-method="hsl" id="lightness" />
+ </div>
</div>
- </form>
- </div>
+ </div>
+ <div class="form-group">
+ <label for="opacity">Opacity %</label>
+ <input type="text" class="form-control o_opacity_input" data-color-method="opacity" id="opacity" />
+ </div>
+ </form>
</div>
- </t>
+ </div>
</templates>