first commit
This commit is contained in:
commit
e7c8c09ca3
3
__init__.py
Normal file
3
__init__.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from . import models
|
||||||
33
__manifest__.py
Normal file
33
__manifest__.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
|
||||||
|
{
|
||||||
|
'name': 'Sign Image Field',
|
||||||
|
'version': '1.0',
|
||||||
|
'category': 'Document Management',
|
||||||
|
'summary': 'Add Image field to Sign module',
|
||||||
|
'description': """
|
||||||
|
This module extends the Odoo Sign module to allow users to upload images as a field type.
|
||||||
|
""",
|
||||||
|
'depends': ['sign'],
|
||||||
|
'data': [
|
||||||
|
'data/sign_item_type_data.xml',
|
||||||
|
],
|
||||||
|
'assets': {
|
||||||
|
'web.assets_frontend': [
|
||||||
|
'sign_image_field/static/src/js/sign_image_upload.js',
|
||||||
|
'sign_image_field/static/src/xml/sign_items_image.xml',
|
||||||
|
],
|
||||||
|
'web.assets_backend': [
|
||||||
|
'sign_image_field/static/src/js/sign_image_upload.js',
|
||||||
|
'sign_image_field/static/src/xml/sign_items_image.xml',
|
||||||
|
],
|
||||||
|
'sign.assets_public_sign': [
|
||||||
|
'sign_image_field/static/src/js/sign_image_upload.js',
|
||||||
|
'sign_image_field/static/src/xml/sign_items_image.xml',
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'installable': True,
|
||||||
|
'application': False,
|
||||||
|
'license': 'OEEL-1',
|
||||||
|
}
|
||||||
BIN
__pycache__/__init__.cpython-312.pyc
Normal file
BIN
__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
12
data/sign_item_type_data.xml
Normal file
12
data/sign_item_type_data.xml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<record id="sign_item_type_image" model="sign.item.type">
|
||||||
|
<field name="name">Image</field>
|
||||||
|
<field name="item_type">image</field>
|
||||||
|
<field name="icon">fa-image</field>
|
||||||
|
<field name="tip">Upload an image</field>
|
||||||
|
<field name="placeholder">Click to upload image</field>
|
||||||
|
<field name="default_width">0.2</field>
|
||||||
|
<field name="default_height">0.05</field>
|
||||||
|
</record>
|
||||||
|
</odoo>
|
||||||
3
models/__init__.py
Normal file
3
models/__init__.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from . import sign_item_type
|
||||||
BIN
models/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
models/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
models/__pycache__/sign_item_type.cpython-312.pyc
Normal file
BIN
models/__pycache__/sign_item_type.cpython-312.pyc
Normal file
Binary file not shown.
10
models/sign_item_type.py
Normal file
10
models/sign_item_type.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
|
||||||
|
from odoo import fields, models
|
||||||
|
|
||||||
|
|
||||||
|
class SignItemType(models.Model):
|
||||||
|
_inherit = "sign.item.type"
|
||||||
|
|
||||||
|
item_type = fields.Selection(selection_add=[('image', "Image")], ondelete={'image': 'cascade'})
|
||||||
59
static/src/js/sign_image_upload.js
Normal file
59
static/src/js/sign_image_upload.js
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/** @odoo-module **/
|
||||||
|
|
||||||
|
import { patch } from "@web/core/utils/patch";
|
||||||
|
import { SignablePDFIframe } from "@sign/components/sign_request/signable_PDF_iframe";
|
||||||
|
|
||||||
|
patch(SignablePDFIframe.prototype, {
|
||||||
|
enableCustom(signItem) {
|
||||||
|
super.enableCustom(signItem);
|
||||||
|
if (signItem.data.type === 'image') {
|
||||||
|
const input = signItem.el.querySelector('.o_sign_image_upload_input');
|
||||||
|
if (!input) return;
|
||||||
|
|
||||||
|
signItem.el.addEventListener('click', (e) => {
|
||||||
|
if (this.readonly || signItem.data.responsible !== this.currentRole) return;
|
||||||
|
// Prevent recursive click if clicking the input itself bubbles up
|
||||||
|
if (e.target !== input) {
|
||||||
|
input.click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
input.addEventListener('change', (e) => {
|
||||||
|
const file = e.target.files[0];
|
||||||
|
if (!file) return;
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = () => {
|
||||||
|
const result = reader.result;
|
||||||
|
signItem.el.dataset.value = result;
|
||||||
|
// Manually update the DOM to show the image
|
||||||
|
const img = signItem.el.querySelector('img');
|
||||||
|
if (img) {
|
||||||
|
img.src = result;
|
||||||
|
} else {
|
||||||
|
// Remove placeholder if it exists
|
||||||
|
const placeholder = signItem.el.querySelector('.o_placeholder');
|
||||||
|
if (placeholder) placeholder.remove();
|
||||||
|
|
||||||
|
const newImg = document.createElement('img');
|
||||||
|
newImg.src = result;
|
||||||
|
newImg.style.maxWidth = '100%';
|
||||||
|
newImg.style.maxHeight = '100%';
|
||||||
|
newImg.style.objectFit = 'contain';
|
||||||
|
|
||||||
|
signItem.el.appendChild(newImg);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.handleInput(); // Trigger validation check
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getSignatureValueFromElement(item) {
|
||||||
|
if (item.data.type === 'image') {
|
||||||
|
return item.el.dataset.value || false;
|
||||||
|
}
|
||||||
|
return super.getSignatureValueFromElement(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
38
static/src/xml/sign_items_image.xml
Normal file
38
static/src/xml/sign_items_image.xml
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<templates xml:space="preserve">
|
||||||
|
<t t-name="sign.signItem" t-inherit="sign.signItem" t-inherit-mode="extension">
|
||||||
|
<xpath expr="//t[@t-if="type == 'selection'"]" position="after">
|
||||||
|
<t t-if="type == 'image'" t-call="sign.imageSignItem"/>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//div[@t-if="type == 'selection'"]" position="after">
|
||||||
|
<div t-if="type == 'image'" t-att-title="role" t-attf-class="{{classes}} o_sign_sign_item" t-att-style="style" t-att-data-value="value" style="text-align:center;">
|
||||||
|
<input type="file" accept="image/*" class="o_sign_image_upload_input" style="display:none"/>
|
||||||
|
<t t-if="value">
|
||||||
|
<img t-att-src="value" style="max-width:100%; max-height:100%; object-fit:contain;"/>
|
||||||
|
</t>
|
||||||
|
<t t-else="">
|
||||||
|
<span class="o_placeholder">
|
||||||
|
<t t-esc="placeholder"/>
|
||||||
|
</span>
|
||||||
|
</t>
|
||||||
|
<t t-if="isSignItemEditable" t-call="sign.signItemConfiguration"/>
|
||||||
|
</div>
|
||||||
|
</xpath>
|
||||||
|
</t>
|
||||||
|
|
||||||
|
<t t-name="sign.imageSignItem">
|
||||||
|
<div t-att-title="role" t-attf-class="{{classes}} o_sign_sign_item" t-att-data-id="id" t-att-style="style">
|
||||||
|
<div class="sign_item_body" style="text-align:center;">
|
||||||
|
<t t-if="value">
|
||||||
|
<img t-att-src="value" style="max-width:100%; max-height:100%; object-fit:contain;"/>
|
||||||
|
</t>
|
||||||
|
<t t-else="">
|
||||||
|
<span class="o_placeholder">
|
||||||
|
<t t-esc="placeholder"/>
|
||||||
|
</span>
|
||||||
|
</t>
|
||||||
|
<t t-if="editMode || isSignItemEditable" t-call="sign.signItemConfiguration"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</templates>
|
||||||
Loading…
Reference in New Issue
Block a user