Roo/form/Signature.js
[roojs1] / Roo / form / Signature.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12 /**
13  * @class Roo.form.Signature
14  * @extends Roo.form.Field
15  * Signature field.  
16  * @constructor
17  * 
18  * @param {Object} config Configuration options
19  */
20
21 Roo.form.Signature = function(config){
22     Roo.form.Signature.superclass.constructor.call(this, config);
23     
24     this.addEvents({// not in used??
25          /**
26          * @event confirm
27          * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
28              * @param {Roo.form.ComboBox} combo This combo box
29              */
30         'confirm' : true,
31         /**
32          * @event reset
33          * Fires when the 'edit' icon is pressed (add a listener to enable add button)
34              * @param {Roo.form.ComboBox} combo This combo box
35              * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
36              */
37         'reset' : true
38     });
39 };
40
41 Roo.extend(Roo.form.Signature, Roo.form.Field,  {
42     /**
43      * @cfg {Object} fieldLabel Label to use when rendering a form.
44      * defaults to 
45      * labels : { 
46      *      clear : "Clear",
47      *      confirm : "Confirm"
48      *  }
49      */
50     labels : { 
51         clear : "Clear",
52         confirm : "Confirm"
53     },
54     /**
55      * @cfg {Number} width The signature panel width (defaults to 300)
56      */
57     width: 300,
58     /**
59      * @cfg {Number} height The signature panel height (defaults to 100)
60      */
61     height : 100,
62     /**
63      * @cfg {Object} signPanel The signature SVG panel element (defaults to {})
64      */
65     signPanel : {},
66     /**
67      * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
68      */
69     allowBlank : false,
70     /**
71      * @cfg {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
72      */
73     isMouseDown : false,
74     /**
75      * @cfg {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
76      */
77     isConfirmed : false,
78     /**
79      * @cfg {String} signatureTmp SVG mapping string (defaults to empty string)
80      */
81     signatureTmp : '',
82     
83     defaultAutoCreate : { // modified by initCompnoent..
84         tag: "input",
85         type:"hidden"
86     },
87
88     // private
89     onRender : function(ct, position){
90         
91         Roo.form.Signature.superclass.onRender.call(this, ct, position);
92         
93         this.wrap = this.el.wrap({
94             cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
95         });
96         
97         this.createToolbar(this);
98         this.signPanel = this.wrap.createChild({
99                 tag: 'div',
100                 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
101             }, this.el
102         );
103             
104         this.svgEl = this.signPanel.createChild({
105               xmlns : 'http://www.w3.org/2000/svg',
106               tag : 'svg',
107               width: this.width,
108               height: this.height,
109               viewBox: '0 0 '+this.width+' '+this.height,
110               cn : [
111                 {
112                     tag: "rect",
113                     id: "svg-r",
114                     width: this.width,
115                     height: this.height,
116                     fill: "#ffa"
117                 },
118                 {
119                     tag: "line",
120                     x1: "0",
121                     y1: "80",
122                     x2: "300",
123                     y2: "80",
124                     'stroke': "#666",
125                     'stroke-width': "1",
126                     'stroke-dasharray': "3",
127                     'shape-rendering': "crispEdges",
128                     'pointer-events': "none"
129                 },
130                 {
131                     tag: "path",
132                     id: "svg-p",
133                     'stroke': "navy",
134                     'stroke-width': "3",
135                     'fill': "none",
136                     'pointer-events': 'none'
137                 },
138               ]
139         });
140         this.createSVG();
141         this.svgBox = this.svgEl.dom.getScreenCTM();
142     },
143     createSVG : function(){ 
144         var svg = this.signPanel;
145         var r = svg.select('#svg-r', true).first().dom;
146         var t = this;
147
148         r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
149         r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
150         r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
151         r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
152         r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
153         r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
154         r.addEventListener('touchend', function(e) { return t.up(e); }, false);
155         
156     },
157     isTouchEvent : function(e){
158         return e.type.match(/^touch/);
159     },
160     getCoords : function (e) {
161         var pt    = this.svgEl.dom.createSVGPoint();
162         pt.x = e.clientX; 
163         pt.y = e.clientY;
164         if (this.isTouchEvent(e)) {
165             pt.x =  e.targetTouches[0].clientX 
166             pt.y = e.targetTouches[0].clientY;
167         }
168         var a = this.svgEl.dom.getScreenCTM();
169         var b = a.inverse();
170         var mx = pt.matrixTransform(b);
171         return mx.x + ',' + mx.y;
172     },
173     //mouse event headler 
174     down : function (e) {
175         this.signatureTmp += 'M' + this.getCoords(e) + ' ';
176         this.signPanel.select('#svg-p', true).first().attr('d', this.signatureTmp);
177         
178         this.isMouseDown = true;
179         
180         e.preventDefault();
181     },
182     move : function (e) {
183         if (this.isMouseDown) {
184             this.signatureTmp += 'L' + this.getCoords(e) + ' ';
185             this.signPanel.select('#svg-p', true).first().attr('d', this.signatureTmp);
186         }
187         
188         e.preventDefault();
189     },
190     up : function (e) {
191         this.isMouseDown = false;
192         var sp = this.signatureTmp.split(' ');
193         
194         if(sp.length > 1){
195             if(!sp[sp.length-2].match(/^L/)){
196                 sp.pop();
197                 sp.pop();
198                 sp.push("");
199                 this.signatureTmp = sp.join(" ");
200             }
201         }
202         if(this.getValue() != this.signatureTmp){
203             this.signPanel.select('#svg-r', true).first().attr('fill', '#ffa');
204             this.isConfirmed = false;
205         }
206         e.preventDefault();
207     },
208     
209     /**
210      * Protected method that will not generally be called directly. It
211      * is called when the editor creates its toolbar. Override this method if you need to
212      * add custom toolbar buttons.
213      * @param {HtmlEditor} editor
214      */
215     createToolbar : function(editor){
216          function btn(id, toggle, handler){
217             var xid = fid + '-'+ id ;
218             return {
219                 id : xid,
220                 cmd : id,
221                 cls : 'x-btn-icon x-edit-'+id,
222                 enableToggle:toggle !== false,
223                 scope: editor, // was editor...
224                 handler:handler||editor.relayBtnCmd,
225                 clickEvent:'mousedown',
226                 tooltip: etb.buttonTips[id] || undefined, ///tips ???
227                 tabIndex:-1
228             };
229         }
230         
231         
232         var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
233         this.tb = tb;
234         this.tb.add(
235            {
236                 cls : ' x-signature-btn x-signature-'+id,
237                 scope: editor, // was editor...
238                 handler: this.reset,
239                 clickEvent:'mousedown',
240                 text: this.labels.clear
241             },
242             {
243                  xtype : 'Fill',
244                  xns: Roo.Toolbar
245             }, 
246             {
247                 cls : '  x-signature-btn x-signature-'+id,
248                 scope: editor, // was editor...
249                 handler: this.setConfirmed,
250                 clickEvent:'mousedown',
251                 text: this.labels.confirm
252             }
253         );
254     
255     },
256     // private
257     getSignature : function(){
258         return this.signatureTmp;
259     },
260     // private
261     reset : function(){
262         this.signatureTmp = '';
263         this.signPanel.select('#svg-r', true).first().attr('fill', '#ffa');
264         this.signPanel.select('#svg-p', true).first().attr('d', '');
265         this.isConfirmed = false;
266         Roo.form.Signature.superclass.reset.call(this);
267     },
268     test : function(){
269 //        Roo.log(this.signPanel.dom.contentWindow.up())
270     },
271     //public
272     setConfirmed : function(){
273         if(!this.getSignature()){
274             return;
275         }
276         this.signPanel.select('#svg-r', true).first().attr('fill', '#cfc');
277         this.setValue(this.getSignature());
278         this.isConfirmed = true;
279 //        Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
280     },
281     // private
282     // Subclasses should provide the validation implementation by overriding this
283     validateValue : function(value){
284         if(this.allowBlank){
285             return true;
286         }
287         
288         if(this.isConfirmed){
289             return true;
290         }
291         return false;
292     }
293 });