Browse Source

Improved the code and fixed the issue when first time record is being created then jsignature library was not properly initialized.

Fixed travis ci log.

Improved the code.

Improve the description and replaced the attribute 'id' with 'class'.
pull/666/head
Vishal Patel 7 years ago
committed by Pedro M. Baeza
parent
commit
6008384b79
  1. 2
      web_digital_sign/__init__.py
  2. 26
      web_digital_sign/__openerp__.py
  3. BIN
      web_digital_sign/static/description/icon.png
  4. BIN
      web_digital_sign/static/description/img/1.png
  5. BIN
      web_digital_sign/static/description/img/2.png
  6. BIN
      web_digital_sign/static/description/img/3.png
  7. 68
      web_digital_sign/static/description/index.html
  8. 924
      web_digital_sign/static/lib/excanvas.js
  9. 1392
      web_digital_sign/static/lib/jSignature/jSignatureCustom.js
  10. 244
      web_digital_sign/static/lib/jquery.signature.js
  11. 10
      web_digital_sign/static/src/css/digital.css
  12. 1225
      web_digital_sign/static/src/css/jquery-ui.css
  13. 5
      web_digital_sign/static/src/css/jquery.signature.css
  14. BIN
      web_digital_sign/static/src/img/icon.png
  15. 207
      web_digital_sign/static/src/js/digital_sign.js
  16. 32
      web_digital_sign/static/src/xml/digital_sign.xml
  17. 1
      web_digital_sign/users.py
  18. 3
      web_digital_sign/users_view.xml
  19. 14
      web_digital_sign/views/we_digital_sign_view.xml

2
web_digital_sign/__init__.py

@ -1,4 +1,4 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import users
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

26
web_digital_sign/__openerp__.py

@ -1,16 +1,27 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
# See LICENSE file for full copyright and licensing details.
{
"name" : "Web Digital Signature 9.0",
"version" : "1.0",
"author" : "Serpent Consulting Services Pvt. Ltd.",
"version" : "9.0.1.0.0",
'author': 'Serpent Consulting Services Pvt. Ltd.',
"category": '',
'license': 'AGPL-3',
'complexity': "easy",
'depends': ['web'],
"description": """
This module provides the functionality to store digital signature image for a record.
The example can be seen into the User's form view where we have added a test field under signature.
""",
'description': '''
This module provides the functionality to store digital signature
for a record.
-> This module is helpfull to make your business process a little
bit more faster & makes it more user friendly by providing you
digital signature functionality on your documents.
-> It is touch screen enable so user can add signature with touch
devices.
-> Digital signature can be very usefull for documents such as
sale orders, purchase orders, inovoices, payslips, procurement
receipts, etc.
The example can be seen into the User's form view where we have
added a test field under signature.
''',
'data': [
'views/we_digital_sign_view.xml',
'users_view.xml'
@ -21,4 +32,3 @@
'auto_install': False,
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

BIN
web_digital_sign/static/description/icon.png

Before

Width: 159  |  Height: 221  |  Size: 16 KiB

After

Width: 1147  |  Height: 564  |  Size: 20 KiB

BIN
web_digital_sign/static/description/img/1.png

After

Width: 1600  |  Height: 900  |  Size: 188 KiB

BIN
web_digital_sign/static/description/img/2.png

After

Width: 1600  |  Height: 900  |  Size: 188 KiB

BIN
web_digital_sign/static/description/img/3.png

After

Width: 1600  |  Height: 900  |  Size: 179 KiB

68
web_digital_sign/static/description/index.html

@ -0,0 +1,68 @@
<section class="oe_container">
<div class="oe_row oe_spaced">
<div class="oe_span10">
<h2 class="oe_slogan">Web Digital Signature</h2>
<h3 class="oe_slogan">This module provides the functionality to store digital signature for a record</h3>
<ul>
<li style="font-size: 18px;">This module is helpfull to make your business process a little bit more faster & makes it more user friendly by providing you digital signature functionality on your documents.</li>
<li style="font-size: 18px;">It is touch screen enable so user can add signature with touch devices.</li>
<li style="font-size: 18px;">Digital signature can be very usefull for documents such as sale orders, purchase orders, inovoices, payslips, procurement receipts, etc.</li>
</ul>
</div>
<div class="oe_span10">
<br/><br/>
<h2 class="oe_slogan">Usage</h3>
<h3 class="oe_slogan">To use this module, you need to add widget="signature" to your binary field in your view.</h3>
</div>
</section>
<section class="oe_container">
<div class="oe_row">
<div class="oe_span6">
<br/><br/>
<h3 class="oe_slogan">Digital Signature View</h3>
<p class='oe_mt32' style="font-size: 18px;">User can store their digital signature
in the binary field, as you can see image.
</div>
<div class="oe_span6">
<div class="oe_bg_img">
<img class="oe_picture oe_screenshot" src="img/1.png">
</div>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row">
<div class="oe_span6">
<div class="oe_bg_img">
<img class="oe_picture oe_screenshot" src="img/2.png">
</div>
</div>
<div class="oe_span6">
<h3 class="oe_slogan">Draw Signature</h3>
<p class='oe_mt32' style="font-size: 18px;">As shown in the image, user can add a signature using mouse, pen, or finger.</p>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row">
<div class="oe_span6">
<h3 class="oe_slogan">Clear Digital Signature</h3>
<p class='oe_mt32' style="font-size: 18px;">User can clear signature using clear button and it will re-initialize the signature.</p>
</div>
<div class="oe_span6">
<div class="oe_bg_img">
<img class="oe_picture oe_screenshot" src="img/3.png">
</div>
</div>
</div>
</section>
<section class="oe_container" style="background-color:#D21E14;padding-top:5px;">
<h2 class="oe_slogan" style="font-size:30px;color:#ffffff;padding-top: 25px;padding-bottom:10px;">For any questions, support and development</h2>
<p style="padding-bottom:25px;text-align:center;">
<span class="fa fa-envelope fa-1x" style="color:#ffffff;"></span>
<a style="color:#ffffff;font-weight:bold;" target="_blank" href="http://www.serpentcs.com/contact-us">&nbsp;Contact Us&nbsp;</a>
</p>
</section>

924
web_digital_sign/static/lib/excanvas.js

@ -1,924 +0,0 @@
// Copyright 2006 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Known Issues:
//
// * Patterns are not implemented.
// * Radial gradient are not implemented. The VML version of these look very
// different from the canvas one.
// * Clipping paths are not implemented.
// * Coordsize. The width and height attribute have higher priority than the
// width and height style values which isn't correct.
// * Painting mode isn't implemented.
// * Canvas width/height should is using content-box by default. IE in
// Quirks mode will draw the canvas using border-box. Either change your
// doctype to HTML5
// (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)
// or use Box Sizing Behavior from WebFX
// (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)
// * Non uniform scaling does not correctly scale strokes.
// * Optimize. There is always room for speed improvements.
// Only add this code if we do not already have a canvas implementation
if (!document.createElement('canvas').getContext) {
(function() {
// alias some functions to make (compiled) code shorter
var m = Math;
var mr = m.round;
var ms = m.sin;
var mc = m.cos;
var abs = m.abs;
var sqrt = m.sqrt;
// this is used for sub pixel precision
var Z = 10;
var Z2 = Z / 2;
/**
* This funtion is assigned to the <canvas> elements as element.getContext().
* @this {HTMLElement}
* @return {CanvasRenderingContext2D_}
*/
function getContext() {
return this.context_ ||
(this.context_ = new CanvasRenderingContext2D_(this));
}
var slice = Array.prototype.slice;
/**
* Binds a function to an object. The returned function will always use the
* passed in {@code obj} as {@code this}.
*
* Example:
*
* g = bind(f, obj, a, b)
* g(c, d) // will do f.call(obj, a, b, c, d)
*
* @param {Function} f The function to bind the object to
* @param {Object} obj The object that should act as this when the function
* is called
* @param {*} var_args Rest arguments that will be used as the initial
* arguments when the function is called
* @return {Function} A new function that has bound this
*/
function bind(f, obj, var_args) {
var a = slice.call(arguments, 2);
return function() {
return f.apply(obj, a.concat(slice.call(arguments)));
};
}
var G_vmlCanvasManager_ = {
init: function(opt_doc) {
if (/MSIE/.test(navigator.userAgent) && !window.opera) {
var doc = opt_doc || document;
// Create a dummy element so that IE will allow canvas elements to be
// recognized.
doc.createElement('canvas');
doc.attachEvent('onreadystatechange', bind(this.init_, this, doc));
}
},
init_: function(doc) {
// create xmlns
if (!doc.namespaces['g_vml_']) {
doc.namespaces.add('g_vml_', 'urn:schemas-microsoft-com:vml',
'#default#VML');
}
if (!doc.namespaces['g_o_']) {
doc.namespaces.add('g_o_', 'urn:schemas-microsoft-com:office:office',
'#default#VML');
}
// Setup default CSS. Only add one style sheet per document
if (!doc.styleSheets['ex_canvas_']) {
var ss = doc.createStyleSheet();
ss.owningElement.id = 'ex_canvas_';
ss.cssText = 'canvas{display:inline-block;overflow:hidden;' +
// default size is 300x150 in Gecko and Opera
'text-align:left;width:300px;height:150px}' +
'g_vml_\\:*{behavior:url(#default#VML)}' +
'g_o_\\:*{behavior:url(#default#VML)}';
}
// find all canvas elements
var els = doc.getElementsByTagName('canvas');
for (var i = 0; i < els.length; i++) {
this.initElement(els[i]);
}
},
/**
* Public initializes a canvas element so that it can be used as canvas
* element from now on. This is called automatically before the page is
* loaded but if you are creating elements using createElement you need to
* make sure this is called on the element.
* @param {HTMLElement} el The canvas element to initialize.
* @return {HTMLElement} the element that was created.
*/
initElement: function(el) {
if (!el.getContext) {
el.getContext = getContext;
// Remove fallback content. There is no way to hide text nodes so we
// just remove all childNodes. We could hide all elements and remove
// text nodes but who really cares about the fallback content.
el.innerHTML = '';
// do not use inline function because that will leak memory
el.attachEvent('onpropertychange', onPropertyChange);
el.attachEvent('onresize', onResize);
var attrs = el.attributes;
if (attrs.width && attrs.width.specified) {
// TODO: use runtimeStyle and coordsize
// el.getContext().setWidth_(attrs.width.nodeValue);
el.style.width = attrs.width.nodeValue + 'px';
} else {
el.width = el.clientWidth;
}
if (attrs.height && attrs.height.specified) {
// TODO: use runtimeStyle and coordsize
// el.getContext().setHeight_(attrs.height.nodeValue);
el.style.height = attrs.height.nodeValue + 'px';
} else {
el.height = el.clientHeight;
}
//el.getContext().setCoordsize_()
}
return el;
}
};
function onPropertyChange(e) {
var el = e.srcElement;
switch (e.propertyName) {
case 'width':
el.style.width = el.attributes.width.nodeValue + 'px';
el.getContext().clearRect();
break;
case 'height':
el.style.height = el.attributes.height.nodeValue + 'px';
el.getContext().clearRect();
break;
}
}
function onResize(e) {
var el = e.srcElement;
if (el.firstChild) {
el.firstChild.style.width = el.clientWidth + 'px';
el.firstChild.style.height = el.clientHeight + 'px';
}
}
G_vmlCanvasManager_.init();
// precompute "00" to "FF"
var dec2hex = [];
for (var i = 0; i < 16; i++) {
for (var j = 0; j < 16; j++) {
dec2hex[i * 16 + j] = i.toString(16) + j.toString(16);
}
}
function createMatrixIdentity() {
return [
[1, 0, 0],
[0, 1, 0],
[0, 0, 1]
];
}
function matrixMultiply(m1, m2) {
var result = createMatrixIdentity();
for (var x = 0; x < 3; x++) {
for (var y = 0; y < 3; y++) {
var sum = 0;
for (var z = 0; z < 3; z++) {
sum += m1[x][z] * m2[z][y];
}
result[x][y] = sum;
}
}
return result;
}
function copyState(o1, o2) {
o2.fillStyle = o1.fillStyle;
o2.lineCap = o1.lineCap;
o2.lineJoin = o1.lineJoin;
o2.lineWidth = o1.lineWidth;
o2.miterLimit = o1.miterLimit;
o2.shadowBlur = o1.shadowBlur;
o2.shadowColor = o1.shadowColor;
o2.shadowOffsetX = o1.shadowOffsetX;
o2.shadowOffsetY = o1.shadowOffsetY;
o2.strokeStyle = o1.strokeStyle;
o2.globalAlpha = o1.globalAlpha;
o2.arcScaleX_ = o1.arcScaleX_;
o2.arcScaleY_ = o1.arcScaleY_;
o2.lineScale_ = o1.lineScale_;
}
function processStyle(styleString) {
var str, alpha = 1;
styleString = String(styleString);
if (styleString.substring(0, 3) == 'rgb') {
var start = styleString.indexOf('(', 3);
var end = styleString.indexOf(')', start + 1);
var guts = styleString.substring(start + 1, end).split(',');
str = '#';
for (var i = 0; i < 3; i++) {
str += dec2hex[Number(guts[i])];
}
if (guts.length == 4 && styleString.substr(3, 1) == 'a') {
alpha = guts[3];
}
} else {
str = styleString;
}
return {color: str, alpha: alpha};
}
function processLineCap(lineCap) {
switch (lineCap) {
case 'butt':
return 'flat';
case 'round':
return 'round';
case 'square':
default:
return 'square';
}
}
/**
* This class implements CanvasRenderingContext2D interface as described by
* the WHATWG.
* @param {HTMLElement} surfaceElement The element that the 2D context should
* be associated with
*/
function CanvasRenderingContext2D_(surfaceElement) {
this.m_ = createMatrixIdentity();
this.mStack_ = [];
this.aStack_ = [];
this.currentPath_ = [];
// Canvas context properties
this.strokeStyle = '#000';
this.fillStyle = '#000';
this.lineWidth = 1;
this.lineJoin = 'miter';
this.lineCap = 'butt';
this.miterLimit = Z * 1;
this.globalAlpha = 1;
this.canvas = surfaceElement;
var el = surfaceElement.ownerDocument.createElement('div');
el.style.width = surfaceElement.clientWidth + 'px';
el.style.height = surfaceElement.clientHeight + 'px';
el.style.overflow = 'hidden';
el.style.position = 'absolute';
surfaceElement.appendChild(el);
this.element_ = el;
this.arcScaleX_ = 1;
this.arcScaleY_ = 1;
this.lineScale_ = 1;
}
var contextPrototype = CanvasRenderingContext2D_.prototype;
contextPrototype.clearRect = function() {
this.element_.innerHTML = '';
};
contextPrototype.beginPath = function() {
// TODO: Branch current matrix so that save/restore has no effect
// as per safari docs.
this.currentPath_ = [];
};
contextPrototype.moveTo = function(aX, aY) {
var p = this.getCoords_(aX, aY);
this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y});
this.currentX_ = p.x;
this.currentY_ = p.y;
};
contextPrototype.lineTo = function(aX, aY) {
var p = this.getCoords_(aX, aY);
this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y});
this.currentX_ = p.x;
this.currentY_ = p.y;
};
contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,
aCP2x, aCP2y,
aX, aY) {
var p = this.getCoords_(aX, aY);
var cp1 = this.getCoords_(aCP1x, aCP1y);
var cp2 = this.getCoords_(aCP2x, aCP2y);
bezierCurveTo(this, cp1, cp2, p);
};
// Helper function that takes the already fixed cordinates.
function bezierCurveTo(self, cp1, cp2, p) {
self.currentPath_.push({
type: 'bezierCurveTo',
cp1x: cp1.x,
cp1y: cp1.y,
cp2x: cp2.x,
cp2y: cp2.y,
x: p.x,
y: p.y
});
self.currentX_ = p.x;
self.currentY_ = p.y;
}
contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {
// the following is lifted almost directly from
// http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes
var cp = this.getCoords_(aCPx, aCPy);
var p = this.getCoords_(aX, aY);
var cp1 = {
x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_),
y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_)
};
var cp2 = {
x: cp1.x + (p.x - this.currentX_) / 3.0,
y: cp1.y + (p.y - this.currentY_) / 3.0
};
bezierCurveTo(this, cp1, cp2, p);
};
contextPrototype.arc = function(aX, aY, aRadius,
aStartAngle, aEndAngle, aClockwise) {
aRadius *= Z;
var arcType = aClockwise ? 'at' : 'wa';
var xStart = aX + mc(aStartAngle) * aRadius - Z2;
var yStart = aY + ms(aStartAngle) * aRadius - Z2;
var xEnd = aX + mc(aEndAngle) * aRadius - Z2;
var yEnd = aY + ms(aEndAngle) * aRadius - Z2;
// IE won't render arches drawn counter clockwise if xStart == xEnd.
if (xStart == xEnd && !aClockwise) {
xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something
// that can be represented in binary
}
var p = this.getCoords_(aX, aY);
var pStart = this.getCoords_(xStart, yStart);
var pEnd = this.getCoords_(xEnd, yEnd);
this.currentPath_.push({type: arcType,
x: p.x,
y: p.y,
radius: aRadius,
xStart: pStart.x,
yStart: pStart.y,
xEnd: pEnd.x,
yEnd: pEnd.y});
};
contextPrototype.rect = function(aX, aY, aWidth, aHeight) {
this.moveTo(aX, aY);
this.lineTo(aX + aWidth, aY);
this.lineTo(aX + aWidth, aY + aHeight);
this.lineTo(aX, aY + aHeight);
this.closePath();
};
contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {
var oldPath = this.currentPath_;
this.beginPath();
this.moveTo(aX, aY);
this.lineTo(aX + aWidth, aY);
this.lineTo(aX + aWidth, aY + aHeight);
this.lineTo(aX, aY + aHeight);
this.closePath();
this.stroke();
this.currentPath_ = oldPath;
};
contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {
var oldPath = this.currentPath_;
this.beginPath();
this.moveTo(aX, aY);
this.lineTo(aX + aWidth, aY);
this.lineTo(aX + aWidth, aY + aHeight);
this.lineTo(aX, aY + aHeight);
this.closePath();
this.fill();
this.currentPath_ = oldPath;
};
contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {
var gradient = new CanvasGradient_('gradient');
gradient.x0_ = aX0;
gradient.y0_ = aY0;
gradient.x1_ = aX1;
gradient.y1_ = aY1;
return gradient;
};
contextPrototype.createRadialGradient = function(aX0, aY0, aR0,
aX1, aY1, aR1) {
var gradient = new CanvasGradient_('gradientradial');
gradient.x0_ = aX0;
gradient.y0_ = aY0;
gradient.r0_ = aR0;
gradient.x1_ = aX1;
gradient.y1_ = aY1;
gradient.r1_ = aR1;
return gradient;
};
contextPrototype.drawImage = function(image, var_args) {
var dx, dy, dw, dh, sx, sy, sw, sh;
// to find the original width we overide the width and height
var oldRuntimeWidth = image.runtimeStyle.width;
var oldRuntimeHeight = image.runtimeStyle.height;
image.runtimeStyle.width = 'auto';
image.runtimeStyle.height = 'auto';
// get the original size
var w = image.width;
var h = image.height;
// and remove overides
image.runtimeStyle.width = oldRuntimeWidth;
image.runtimeStyle.height = oldRuntimeHeight;
if (arguments.length == 3) {
dx = arguments[1];
dy = arguments[2];
sx = sy = 0;
sw = dw = w;
sh = dh = h;
} else if (arguments.length == 5) {
dx = arguments[1];
dy = arguments[2];
dw = arguments[3];
dh = arguments[4];
sx = sy = 0;
sw = w;
sh = h;
} else if (arguments.length == 9) {
sx = arguments[1];
sy = arguments[2];
sw = arguments[3];
sh = arguments[4];
dx = arguments[5];
dy = arguments[6];
dw = arguments[7];
dh = arguments[8];
} else {
throw Error('Invalid number of arguments');
}
var d = this.getCoords_(dx, dy);
var w2 = sw / 2;
var h2 = sh / 2;
var vmlStr = [];
var W = 10;
var H = 10;
// For some reason that I've now forgotten, using divs didn't work
vmlStr.push(' <g_vml_:group',
' coordsize="', Z * W, ',', Z * H, '"',
' coordorigin="0,0"' ,
' style="width:', W, 'px;height:', H, 'px;position:absolute;');
// If filters are necessary (rotation exists), create them
// filters are bog-slow, so only create them if abbsolutely necessary
// The following check doesn't account for skews (which don't exist
// in the canvas spec (yet) anyway.
if (this.m_[0][0] != 1 || this.m_[0][1]) {
var filter = [];
// Note the 12/21 reversal
filter.push('M11=', this.m_[0][0], ',',
'M12=', this.m_[1][0], ',',
'M21=', this.m_[0][1], ',',
'M22=', this.m_[1][1], ',',
'Dx=', mr(d.x / Z), ',',
'Dy=', mr(d.y / Z), '');
// Bounding box calculation (need to minimize displayed area so that
// filters don't waste time on unused pixels.
var max = d;
var c2 = this.getCoords_(dx + dw, dy);
var c3 = this.getCoords_(dx, dy + dh);
var c4 = this.getCoords_(dx + dw, dy + dh);
max.x = m.max(max.x, c2.x, c3.x, c4.x);
max.y = m.max(max.y, c2.y, c3.y, c4.y);
vmlStr.push('padding:0 ', mr(max.x / Z), 'px ', mr(max.y / Z),
'px 0;filter:progid:DXImageTransform.Microsoft.Matrix(',
filter.join(''), ", sizingmethod='clip');")
} else {
vmlStr.push('top:', mr(d.y / Z), 'px;left:', mr(d.x / Z), 'px;');
}
vmlStr.push(' ">' ,
'<g_vml_:image src="', image.src, '"',
' style="width:', Z * dw, 'px;',
' height:', Z * dh, 'px;"',
' cropleft="', sx / w, '"',
' croptop="', sy / h, '"',
' cropright="', (w - sx - sw) / w, '"',
' cropbottom="', (h - sy - sh) / h, '"',
' />',
'</g_vml_:group>');
this.element_.insertAdjacentHTML('BeforeEnd',
vmlStr.join(''));
};
contextPrototype.stroke = function(aFill) {
var lineStr = [];
var lineOpen = false;
var a = processStyle(aFill ? this.fillStyle : this.strokeStyle);
var color = a.color;
var opacity = a.alpha * this.globalAlpha;
var W = 10;
var H = 10;
lineStr.push('<g_vml_:shape',
' filled="', !!aFill, '"',
' style="position:absolute;width:', W, 'px;height:', H, 'px;"',
' coordorigin="0 0" coordsize="', Z * W, ' ', Z * H, '"',
' stroked="', !aFill, '"',
' path="');
var newSeq = false;
var min = {x: null, y: null};
var max = {x: null, y: null};
for (var i = 0; i < this.currentPath_.length; i++) {
var p = this.currentPath_[i];
var c;
switch (p.type) {
case 'moveTo':
c = p;
lineStr.push(' m ', mr(p.x), ',', mr(p.y));
break;
case 'lineTo':
lineStr.push(' l ', mr(p.x), ',', mr(p.y));
break;
case 'close':
lineStr.push(' x ');
p = null;
break;
case 'bezierCurveTo':
lineStr.push(' c ',
mr(p.cp1x), ',', mr(p.cp1y), ',',
mr(p.cp2x), ',', mr(p.cp2y), ',',
mr(p.x), ',', mr(p.y));
break;
case 'at':
case 'wa':
lineStr.push(' ', p.type, ' ',
mr(p.x - this.arcScaleX_ * p.radius), ',',
mr(p.y - this.arcScaleY_ * p.radius), ' ',
mr(p.x + this.arcScaleX_ * p.radius), ',',
mr(p.y + this.arcScaleY_ * p.radius), ' ',
mr(p.xStart), ',', mr(p.yStart), ' ',
mr(p.xEnd), ',', mr(p.yEnd));
break;
}
// TODO: Following is broken for curves due to
// move to proper paths.
// Figure out dimensions so we can do gradient fills
// properly
if (p) {
if (min.x == null || p.x < min.x) {
min.x = p.x;
}
if (max.x == null || p.x > max.x) {
max.x = p.x;
}
if (min.y == null || p.y < min.y) {
min.y = p.y;
}
if (max.y == null || p.y > max.y) {
max.y = p.y;
}
}
}
lineStr.push(' ">');
if (!aFill) {
var lineWidth = this.lineScale_ * this.lineWidth;
// VML cannot correctly render a line if the width is less than 1px.
// In that case, we dilute the color to make the line look thinner.
if (lineWidth < 1) {
opacity *= lineWidth;
}
lineStr.push(
'<g_vml_:stroke',
' opacity="', opacity, '"',
' joinstyle="', this.lineJoin, '"',
' miterlimit="', this.miterLimit, '"',
' endcap="', processLineCap(this.lineCap), '"',
' weight="', lineWidth, 'px"',
' color="', color, '" />'
);
} else if (typeof this.fillStyle == 'object') {
var fillStyle = this.fillStyle;
var angle = 0;
var focus = {x: 0, y: 0};
// additional offset
var shift = 0;
// scale factor for offset
var expansion = 1;
if (fillStyle.type_ == 'gradient') {
var x0 = fillStyle.x0_ / this.arcScaleX_;
var y0 = fillStyle.y0_ / this.arcScaleY_;
var x1 = fillStyle.x1_ / this.arcScaleX_;
var y1 = fillStyle.y1_ / this.arcScaleY_;
var p0 = this.getCoords_(x0, y0);
var p1 = this.getCoords_(x1, y1);
var dx = p1.x - p0.x;
var dy = p1.y - p0.y;
angle = Math.atan2(dx, dy) * 180 / Math.PI;
// The angle should be a non-negative number.
if (angle < 0) {
angle += 360;
}
// Very small angles produce an unexpected result because they are
// converted to a scientific notation string.
if (angle < 1e-6) {
angle = 0;
}
} else {
var p0 = this.getCoords_(fillStyle.x0_, fillStyle.y0_);
var width = max.x - min.x;
var height = max.y - min.y;
focus = {
x: (p0.x - min.x) / width,
y: (p0.y - min.y) / height
};
width /= this.arcScaleX_ * Z;
height /= this.arcScaleY_ * Z;
var dimension = m.max(width, height);
shift = 2 * fillStyle.r0_ / dimension;
expansion = 2 * fillStyle.r1_ / dimension - shift;
}
// We need to sort the color stops in ascending order by offset,
// otherwise IE won't interpret it correctly.
var stops = fillStyle.colors_;
stops.sort(function(cs1, cs2) {
return cs1.offset - cs2.offset;
});
var length = stops.length;
var color1 = stops[0].color;
var color2 = stops[length - 1].color;
var opacity1 = stops[0].alpha * this.globalAlpha;
var opacity2 = stops[length - 1].alpha * this.globalAlpha;
var colors = [];
for (var i = 0; i < length; i++) {
var stop = stops[i];
colors.push(stop.offset * expansion + shift + ' ' + stop.color);
}
// When colors attribute is used, the meanings of opacity and o:opacity2
// are reversed.
lineStr.push('<g_vml_:fill type="', fillStyle.type_, '"',
' method="none" focus="100%"',
' color="', color1, '"',
' color2="', color2, '"',
' colors="', colors.join(','), '"',
' opacity="', opacity2, '"',
' g_o_:opacity2="', opacity1, '"',
' angle="', angle, '"',
' focusposition="', focus.x, ',', focus.y, '" />');
} else {
lineStr.push('<g_vml_:fill color="', color, '" opacity="', opacity,
'" />');
}
lineStr.push('</g_vml_:shape>');
this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
};
contextPrototype.fill = function() {
this.stroke(true);
}
contextPrototype.closePath = function() {
this.currentPath_.push({type: 'close'});
};
/**
* @private
*/
contextPrototype.getCoords_ = function(aX, aY) {
var m = this.m_;
return {
x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2,
y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2
}
};
contextPrototype.save = function() {
var o = {};
copyState(this, o);
this.aStack_.push(o);
this.mStack_.push(this.m_);
this.m_ = matrixMultiply(createMatrixIdentity(), this.m_);
};
contextPrototype.restore = function() {
copyState(this.aStack_.pop(), this);
this.m_ = this.mStack_.pop();
};
function matrixIsFinite(m) {
for (var j = 0; j < 3; j++) {
for (var k = 0; k < 2; k++) {
if (!isFinite(m[j][k]) || isNaN(m[j][k])) {
return false;
}
}
}
return true;
}
function setM(ctx, m, updateLineScale) {
if (!matrixIsFinite(m)) {
return;
}
ctx.m_ = m;
if (updateLineScale) {
// Get the line scale.
// Determinant of this.m_ means how much the area is enlarged by the
// transformation. So its square root can be used as a scale factor
// for width.
var det = m[0][0] * m[1][1] - m[0][1] * m[1][0];
ctx.lineScale_ = sqrt(abs(det));
}
}
contextPrototype.translate = function(aX, aY) {
var m1 = [
[1, 0, 0],
[0, 1, 0],
[aX, aY, 1]
];
setM(this, matrixMultiply(m1, this.m_), false);
};
contextPrototype.rotate = function(aRot) {
var c = mc(aRot);
var s = ms(aRot);
var m1 = [
[c, s, 0],
[-s, c, 0],
[0, 0, 1]
];
setM(this, matrixMultiply(m1, this.m_), false);
};
contextPrototype.scale = function(aX, aY) {
this.arcScaleX_ *= aX;
this.arcScaleY_ *= aY;
var m1 = [
[aX, 0, 0],
[0, aY, 0],
[0, 0, 1]
];
setM(this, matrixMultiply(m1, this.m_), true);
};
contextPrototype.transform = function(m11, m12, m21, m22, dx, dy) {
var m1 = [
[m11, m12, 0],
[m21, m22, 0],
[dx, dy, 1]
];
setM(this, matrixMultiply(m1, this.m_), true);
};
contextPrototype.setTransform = function(m11, m12, m21, m22, dx, dy) {
var m = [
[m11, m12, 0],
[m21, m22, 0],
[dx, dy, 1]
];
setM(this, m, true);
};
/******** STUBS ********/
contextPrototype.clip = function() {
// TODO: Implement
};
contextPrototype.arcTo = function() {
// TODO: Implement
};
contextPrototype.createPattern = function() {
return new CanvasPattern_;
};
// Gradient / Pattern Stubs
function CanvasGradient_(aType) {
this.type_ = aType;
this.x0_ = 0;
this.y0_ = 0;
this.r0_ = 0;
this.x1_ = 0;
this.y1_ = 0;
this.r1_ = 0;
this.colors_ = [];
}
CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) {
aColor = processStyle(aColor);
this.colors_.push({offset: aOffset,
color: aColor.color,
alpha: aColor.alpha});
};
function CanvasPattern_() {}
// set up externs
G_vmlCanvasManager = G_vmlCanvasManager_;
CanvasRenderingContext2D = CanvasRenderingContext2D_;
CanvasGradient = CanvasGradient_;
CanvasPattern = CanvasPattern_;
})();
} // if

1392
web_digital_sign/static/lib/jSignature/jSignatureCustom.js
File diff suppressed because it is too large
View File

244
web_digital_sign/static/lib/jquery.signature.js

@ -1,244 +0,0 @@
(function($) { // Hide scope, no $ conflict
var signatureOverrides = {
// Global defaults for signature
options: {
background: '#ffffff', // Colour of the background
color: '#000000', // Colour of the signature
thickness: 2, // Thickness of the lines
guideline: false, // Add a guide line or not?
guidelineColor: '#a0a0a0', // Guide line colour
guidelineOffset: 50, // Guide line offset from the bottom
guidelineIndent: 10, // Guide line indent from the edges
notAvailable: 'Your browser doesn\'t support signing', // Error message when no canvas
syncField: null, // Selector for synchronised text field
change: null // Callback when signature changed
},
/* Initialise a new signature area. */
_create: function() {
this.element.addClass(this.widgetFullName || this.widgetBaseClass);
try {
this.canvas = $('<canvas width="' + 170 + '" height="' +
50 + '">' + '' + '</canvas>')[0];
this.element.prepend(this.canvas);
this.element.find('img').remove();
this.ctx = this.canvas.getContext('2d');
}
catch (e) {
$(this.canvas).remove();
this.resize = true;
this.canvas = document.createElement('canvas');
this.canvas.setAttribute('width', this.element.width());
this.canvas.setAttribute('height', this.element.height());
this.canvas.innerHTML = this.options.notAvailable;
this.element.append(this.canvas);
if (G_vmlCanvasManager) { // Requires excanvas.js
G_vmlCanvasManager.initElement(this.canvas);
}
this.ctx = this.canvas.getContext('2d');
}
this._refresh(true);
this._mouseInit();
},
/* Refresh the appearance of the signature area.
@param init (boolean, internal) true if initialising */
_refresh: function(init) {
if (this.resize) {
var parent = $(this.canvas);
$('div', this.canvas).css({width: parent.width(), height: parent.height()});
}
this.ctx.fillStyle = this.options.background;
this.ctx.strokeStyle = this.options.color;
this.ctx.lineWidth = this.options.thickness;
this.ctx.lineCap = 'round';
this.ctx.lineJoin = 'round';
this.clear(init);
},
/* Clear the signature area.
@param init (boolean, internal) true if initialising */
clear: function(init) {
this.ctx.fillRect(0, 0, this.element.width(), this.element.height());
if (this.options.guideline) {
this.ctx.save();
this.ctx.strokeStyle = this.options.guidelineColor;
this.ctx.lineWidth = 1;
this.ctx.beginPath();
this.ctx.moveTo(this.options.guidelineIndent,
this.element.height() - this.options.guidelineOffset);
this.ctx.lineTo(this.element.width() - this.options.guidelineIndent,
this.element.height() - this.options.guidelineOffset);
this.ctx.stroke();
this.ctx.restore();
}
this.lines = [];
if (!init) {
this._changed();
}
},
/* Synchronise changes and trigger change event.
@param event (Event) the triggering event */
_changed: function(event) {
if (this.options.syncField) {
$(this.options.syncField).val(this.toJSON());
}
this._trigger('change', event, {});
},
/* Custom options handling.
@param options (object) the new option values */
_setOptions: function(options) {
if (this._superApply) {
this._superApply(arguments); // Base widget handling
}
else {
$.Widget.prototype._setOptions.apply(this, arguments); // Base widget handling
}
this._refresh();
},
/* Determine if dragging can start.
@param event (Event) the triggering mouse event
@return (boolean) true if allowed, false if not */
_mouseCapture: function(event) {
return !this.options.disabled;
},
/* Start a new line.
@param event (Event) the triggering mouse event */
_mouseStart: function(event) {
this.offset = this.element.offset();
this.offset.left -= document.documentElement.scrollLeft || document.body.scrollLeft;
this.offset.top -= document.documentElement.scrollTop || document.body.scrollTop;
this.lastPoint = [this._round(event.clientX - this.offset.left),
this._round(event.clientY - this.offset.top)];
this.curLine = [this.lastPoint];
this.lines.push(this.curLine);
},
/* Track the mouse.
@param event (Event) the triggering mouse event */
_mouseDrag: function(event) {
var point = [this._round(event.clientX - this.offset.left),
this._round(event.clientY - this.offset.top)];
this.curLine.push(point);
this.ctx.beginPath();
this.ctx.moveTo(this.lastPoint[0], this.lastPoint[1]);
this.ctx.lineTo(point[0], point[1]);
this.ctx.stroke();
this.lastPoint = point;
},
/* End a line.
@param event (Event) the triggering mouse event */
_mouseStop: function(event) {
this.lastPoint = null;
this.curLine = null;
this._changed(event);
},
/* Round to two decimal points.
@param value (number) the value to round
@return (number) the rounded value */
_round: function(value) {
return Math.round(value * 100) / 100;
},
/* Convert the captured lines to JSON text.
@return (string) the JSON text version of the lines */
toJSON: function() {
return '{"lines":[' + $.map(this.lines, function(line) {
return '[' + $.map(line, function(point) {
return '[' + point + ']';
}) + ']';
}) + ']}';
},
/* Convert the captured lines to SVG text.
@return (string) the SVG text version of the lines */
toSVG: function() {
return '<?xml version="1.0"?>\n<!DOCTYPE svg PUBLIC ' +
'"-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n' +
'<svg xmlns="http://www.w3.org/2000/svg" width="15cm" height="15cm">\n' +
' <g fill="' + this.options.background + '">\n' +
' <rect x="0" y="0" width="' + this.canvas.width +
'" height="' + this.canvas.height + '"/>\n' +
' <g fill="none" stroke="' + this.options.color + '" stroke-width="' +
this.options.thickness + '">\n'+
$.map(this.lines, function(line) {
return ' <polyline points="' +
$.map(line, function(point) { return point + ''; }).join(' ') + '"/>\n';
}).join('') +
' </g>\n </g>\n</svg>\n';
},
/* Draw a signature from its JSON description.
@param sigJSON (object) object with attribute lines
being an array of arrays of points or
(string) text version of the JSON */
draw: function(sigJSON) {
this.clear(true);
if (typeof sigJSON === 'string') {
sigJSON = $.parseJSON(sigJSON);
}
this.lines = sigJSON.lines || [];
var ctx = this.ctx;
$.each(this.lines, function() {
ctx.beginPath();
$.each(this, function(i) {
ctx[i === 0 ? 'moveTo' : 'lineTo'](this[0], this[1]);
});
ctx.stroke();
});
this._changed();
},
/* Determine whether or not any drawing has occurred.
@return (boolean) true if not signed, false if signed */
isEmpty: function() {
return this.lines.length === 0;
},
/* Remove the signature functionality. */
_destroy: function() {
this.element.removeClass(this.widgetFullName || this.widgetBaseClass);
$(this.canvas).remove();
this.canvas = this.ctx = this.lines = null;
this._mouseDestroy();
}
};
if (!$.Widget.prototype._destroy) {
$.extend(signatureOverrides, {
/* Remove the signature functionality. */
destroy: function() {
this._destroy();
$.Widget.prototype.destroy.call(this); // Base widget handling
}
});
}
if($.Widget.prototype._getCreateOptions === $.noop) {
$.extend(signatureOverrides, {
/* Restore the metadata functionality. */
_getCreateOptions: function() {
return $.metadata && $.metadata.get(this.element[0])[this.widgetName];
}
});
}
/* Signature capture and display.
Depends on jquery.ui.widget, jquery.ui.mouse. */
$.widget('kbw.signature', $.ui.mouse, signatureOverrides);
// Make some things more accessible
$.kbw.signature.options = $.kbw.signature.prototype.options;
})(jQuery);

10
web_digital_sign/static/src/css/digital.css

@ -1,10 +0,0 @@
/* Styles for signature plugin v1.1.0. */
/* .kbw-signature {
height : "100px";
width : "150px";
} */
.openerp .oe_form_readonly .oe_edit_only, .openerp .oe_form_readonly .oe_form_field:empty {
display: none !important;
}

1225
web_digital_sign/static/src/css/jquery-ui.css
File diff suppressed because it is too large
View File

5
web_digital_sign/static/src/css/jquery.signature.css

@ -1,5 +0,0 @@
/* Styles for signature plugin v1.1.0. */
.kbw-signature {
display: inline-block;
border: 1px solid #a0a0a0;
}

BIN
web_digital_sign/static/src/img/icon.png

Before

Width: 159  |  Height: 221  |  Size: 16 KiB

207
web_digital_sign/static/src/js/digital_sign.js

@ -1,143 +1,122 @@
odoo.define('web_digital_sign.web_digital_sign',function(require){
odoo.define('web_digital_sign.web_digital_sign', function(require) {
"use strict";
var core = require('web.core');
var data = require('web.data');
var FormView = require('web.FormView');
var utils = require('web.utils');
var session = require('web.session');
var Model = require('web.Model');
var _t = core._t;
var QWeb = core.qweb;
var images = {};
var FieldSignature = core.form_widget_registry.map.image.extend({
template: 'FieldSignature',
placeholder: "/web/static/src/img/placeholder.png",
initialize_content: function() {
var self = this;
this.$el.find('> img').remove();
this.$el.find('.signature > canvas').remove();
var sign_options = {'decor-color' : '#D1D0CE', 'color': '#000', 'background-color': '#fff','height':'150','width':'550'};
this.$el.find(".signature").jSignature("init",sign_options);
this.$el.find(".signature").attr({"tabindex": "0",'height':"100"});
this.empty_sign = this.$el.find(".signature").jSignature("getData",'image');
this.$el.find('#sign_clean').click(this.on_clear_sign);
this.$el.find('.save_sign').click(this.on_save_sign);
},
on_clear_sign: function() {
var self = this;
this.$el.find(".signature > canvas").remove();
this.$el.find('> img').remove();
this.$el.find(".signature").attr("tabindex", "0");
var sign_options = {'decor-color' : '#D1D0CE', 'color': '#000', 'background-color': '#fff','height':'150','width':'550','clear': true};
this.$el.find(".signature").jSignature(sign_options);
this.$el.find(".signature").focus();
self.set('value', false);
},
on_save_sign: function(value_) {
var self = this;
this.$el.find('> img').remove();
var signature = self.$el.find(".signature").jSignature("getData",'image');
var is_empty = signature
? self.empty_sign[1] === signature[1]
: false;
if (! is_empty && typeof signature !== "undefined" && signature[1]) {
self.set('value',signature[1]);
}
},
render_value: function() {
var self = this;
var url;
if (this.get('value') && ! utils.is_bin_size(this.get('value'))) {
var url = this.placeholder;
if (this.get('value') && !utils.is_bin_size(this.get('value'))) {
url = 'data:image/png;base64,' + this.get('value');
}else if (this.get('value')) {
var id = JSON.stringify(this.view.datarecord.id || null);
self.digita_dataset = new data.DataSetSearch(self, self.view.model, {}, []);
self.digita_dataset.read_slice(['id', self.name], {'domain': [['id', '=', id]]}).then(function(records){
_.each(records,function(record){
if(record[self.name]){
images[self.name] = record[self.name]
}else{
images[self.name] = ""
}
})
})
var field = this.name;
if (this.options.preview_image)
field = this.options.preview_image;
} else if (this.get('value')) {
url = this.session.url('/web/binary/image', {
model: this.view.dataset.model,
id: id,
field: field,
t: (new Date().getTime()),
model: this.view.dataset.model,
id: JSON.stringify(this.view.datarecord.id || null),
field: this.options.preview_image
? this.options.preview_image
: this.name,
t: new Date().getTime()
});
}else {
images[self.name] = ""
} else {
url = this.placeholder;
self.set('value',images[self.name])
}
var $img = $(QWeb.render("FieldBinaryImage-img", { widget: this, url: url }));
this.$el.find('img').remove();
if(this.view.get("actual_mode") !== 'edit' && this.view.get("actual_mode") !== 'create'){
this.$el.prepend($img);
}else if(this.view.get("actual_mode") == 'edit' ){
if (this.view.get("actual_mode") === 'view') {
var $img = $(QWeb.render("FieldBinaryImage-extend", { widget: this, url: url }));
this.$el.find('> img').remove();
this.$el.find('> canvas').remove();
if(! this.get('value')){
this.$el.find('> img').remove();
$(this.$el[0]).find(".signature").signature();
}else if(this.get('value')){
this.$el.prepend($img);
}
}else if( this.view.get("actual_mode") == 'create'){
images = {}
this.$el.find(".signature").hide();
this.$el.prepend($img);
$img.load(function() {
if (! self.options.size) {
return;
}
$img.css("max-width", "" + self.options.size[0] + "px");
$img.css("max-height", "" + self.options.size[1] + "px");
$img.css("margin-left", "" + (self.options.size[0] - $img.width()) / 2 + "px");
$img.css("margin-top", "" + (self.options.size[1] - $img.height()) / 2 + "px");
});
$img.on('error', function() {
$img.attr('src', self.placeholder);
self.do_warn(_t("Image"), _t("Could not display the selected image."));
});
} else if (this.view.get("actual_mode") === 'edit') {
this.$el.find('> img').remove();
this.$el.find('> canvas').remove();
if(! this.get('value')){
this.$el.find('> img').remove();
$(this.$el[0]).find(".signature").signature();
}else if(this.get('value')){
this.$el.prepend($img);
}
}
$(this.$el[0]).find('.clear_sign').click(function(){
self.$el.find('> img').remove();
images[self.name] = ""
$(self.$el[0]).find(".signature").show();
$(self.$el[0]).find(".signature").signature('clear');
});
$(this.$el[0]).find('.save_sign').on('click',function(){
var val
if($(self.$el[0]).find(".signature").hasClass( "kbw-signature" ) && ! $(self.$el[0]).find(".signature").signature('isEmpty')){
$(self.$el[0]).find(".signature").hide();
val = $(self.$el[0]).find(".signature > canvas")[0].toDataURL();
images[self.name] = val.split(',')[1]
var $img = $(QWeb.render("FieldBinaryImage-extend", { widget: self, url: val }));
self.$el.find('> img').remove();
self.$el.prepend($img);
self.set('value',val.split(',')[1])
var id = JSON.stringify(self.view.datarecord.id || null);
var field = self.name;
url = self.session.url('/web/binary/image', {
model: self.view.dataset.model,
id: id,
field: field,
t: (new Date().getTime()),
});
}else{
var id = JSON.stringify(self.view.datarecord.id || null);
var field = self.name;
if (self.options.preview_image)
field = self.options.preview_image;
url = self.session.url('/web/binary/image', {
model: self.view.dataset.model,
id: id,
field: field,
t: (new Date().getTime()),
if (this.get('value')) {
var field_name = this.options.preview_image
? this.options.preview_image
: this.name;
new Model(this.view.dataset.model).call("read", [this.view.datarecord.id, [field_name]]).done(function(data) {
if (data) {
var field_desc = _.values(_.pick(data, field_name));
self.$el.find(".signature").jSignature("reset");
self.$el.find(".signature").jSignature("setData",'data:image/png;base64,'+field_desc[0]);
}
});
var $img = $(QWeb.render("FieldBinaryImage-extend", { widget: self, url: url }));
self.$el.find('> img').remove();
} else {
this.$el.find('> img').remove();
this.$el.find('.signature > canvas').remove();
var sign_options = {'decor-color' : '#D1D0CE', 'color': '#000','background-color': '#fff','height':'150','width':'550'};
this.$el.find(".signature").jSignature("init",sign_options);
}
});
$img.load(function() {
if (! self.options.size)
return;
$img.css("max-width", "" + self.options.size[0] + "px");
$img.css("max-height", "" + self.options.size[1] + "px");
$img.css("margin-left", "" + (self.options.size[0] - $img.width()) / 2 + "px");
$img.css("margin-top", "" + (self.options.size[1] - $img.height()) / 2 + "px");
});
$img.on('error', function() {
console.log("eroor")
$img.attr('src', self.placeholder);
self.do_warn(_t("Image"), _t("Could not display the selected image."));
});
},
} else if (this.view.get("actual_mode") === 'create') {
this.$el.find('> img').remove();
this.$el.find('> canvas').remove();
if (!this.get('value')) {
this.$el.find(".signature").empty().jSignature("init",{'decor-color' : '#D1D0CE', 'color': '#000','background-color': '#fff','height':'150','width':'550'});
}
}
}
});
core.form_widget_registry.add('signature', FieldSignature)
core.form_widget_registry.add('signature', FieldSignature);
FormView.include({
save: function(prepend_on_create) {
var self = this;
$('.save_sign').click()
var save_obj = {prepend_on_create: prepend_on_create, ret: null};
this.save_list.push(save_obj);
return self._process_operations().then(function() {
if (save_obj.error)
return $.Deferred().reject();
return $.when.apply($, save_obj.ret);
}).done(function(result) {
self.$el.removeClass('oe_form_dirty');
});
},
save: function() {
this.$el.find('.save_sign').click();
return this._super.apply(this, arguments);
}
});
});

32
web_digital_sign/static/src/xml/digital_sign.xml

@ -1,18 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8" ?>
<templates id="template" xml:space="preserve">
<t t-name="FieldSignature" >
<div class = "cc">
<div class="signature oe_edit_only"/><br/>
<button class="oe_form_binary_file_clear oe_edit_only clear_sign"><span>Clear</span></button>
<span class="oe_edit_only save_sign"></span>
<t t-name="FieldSignature">
<div class="panel panel-default mt16 mb0 " id="drawsign">
<div class="panel-heading oe_edit_only">
<div class="pull-right">
<a id="sign_clean" class="btn btn-xs oe_edit_only">Clear</a>
<a class="oe_edit_only save_sign"></a>
</div>
<strong>Draw your signature</strong>
</div>
<div class="signature panel-body"></div>
</div>
</t>
<t t-name="FieldBinaryImage-extend">
<img t-att-src='url'
t-att-border="widget.readonly ? 0 : 1"
t-att-name="widget.name"
t-att-width="widget.node.attrs.img_width || widget.node.attrs.width"
t-att-height="widget.node.attrs.img_height || widget.node.attrs.height"
/>
<img t-att-src='url'
t-att-border="widget.readonly ? 0 : 1"
t-att-name="widget.name"
t-att-width="widget.node.attrs.img_width || widget.node.attrs.width"
t-att-height="widget.node.attrs.img_height || widget.node.attrs.height"
t-att-tabindex="widget.node.attrs.img_tabindex || widget.node.attrs.tabindex"
/>
</t>
</templates>
</templates>

1
web_digital_sign/users.py

@ -9,4 +9,3 @@ class Users(models.Model):
signature= fields.Binary(string='Signature')
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

3
web_digital_sign/users_view.xml

@ -13,4 +13,5 @@
</field>
</record>
</data>
</openerp>
</openerp>

14
web_digital_sign/views/we_digital_sign_view.xml

@ -1,13 +1,13 @@
<openerp>
<data>
<template id="sale_order_backend" name="sale_order assets" inherit_id="web.assets_backend">
<template id="web_digital_sign_backend" name="web_digital_sign assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<link rel="stylesheet" href="/web_digital_sign/static/src/css/digital.css"/>
<link rel="stylesheet" href="/web_digital_sign/static/src/css/jquery.signature.css"/>
<script type="text/javascript" src="/web_digital_sign/static/lib/excanvas.js"></script>
<script type="text/javascript" src="/web_digital_sign/static/lib/jquery.signature.js"></script>
<script type="text/javascript" src="/web_digital_sign/static/src/js/digital_sign.js"></script>
<script type="text/javascript"
src="/web_digital_sign/static/lib/jSignature/jSignatureCustom.js"></script>
<script type="text/javascript"
src="/web_digital_sign/static/src/js/digital_sign.js"></script>
</xpath>
</template>
</data>
</openerp>
</openerp>
Loading…
Cancel
Save