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} labels 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     
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     
78     /**
79      * @cfg {String} signatureTmp SVG mapping string (defaults to empty string)
80      */
81     
82     
83     
84     //private
85     signPanel : {},
86     isMouseDown : false,
87     isConfirmed : false,
88     signatureTmp : '',
89     defaultAutoCreate : { // modified by initCompnoent..
90         tag: "input",
91         type:"hidden"
92     },
93
94     // private
95     onRender : function(ct, position){
96         
97         Roo.form.Signature.superclass.onRender.call(this, ct, position);
98         
99         this.wrap = this.el.wrap({
100             cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
101         });
102         
103         this.createToolbar(this);
104         this.signPanel = this.wrap.createChild({
105                 tag: 'div',
106                 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
107             }, this.el
108         );
109             
110         this.svgEl = this.signPanel.createChild({
111               xmlns : 'http://www.w3.org/2000/svg',
112               tag : 'svg',
113               width: this.width,
114               height: this.height,
115               viewBox: '0 0 '+this.width+' '+this.height,
116               cn : [
117                 {
118                     tag: "rect",
119                     id: "svg-r",
120                     width: this.width,
121                     height: this.height,
122                     fill: "#ffa"
123                 },
124                 {
125                     tag: "line",
126                     x1: "0",
127                     y1: "80",
128                     x2: this.width,
129                     y2: "80",
130                     'stroke': "#666",
131                     'stroke-width': "1",
132                     'stroke-dasharray': "3",
133                     'shape-rendering': "crispEdges",
134                     'pointer-events': "none"
135                 },
136                 {
137                     tag: "path",
138                     id: "svg-p",
139                     'stroke': "navy",
140                     'stroke-width': "3",
141                     'fill': "none",
142                     'pointer-events': 'none'
143                 }
144               ]
145         });
146         this.createSVG();
147         this.svgBox = this.svgEl.dom.getScreenCTM();
148     },
149     createSVG : function(){ 
150         var svg = this.signPanel;
151         var r = svg.select('#svg-r', true).first().dom;
152         var t = this;
153
154         r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
155         r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
156         r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
157         r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
158         r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
159         r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
160         r.addEventListener('touchend', function(e) { return t.up(e); }, false);
161         
162     },
163     isTouchEvent : function(e){
164         return e.type.match(/^touch/);
165     },
166     getCoords : function (e) {
167         var pt    = this.svgEl.dom.createSVGPoint();
168         pt.x = e.clientX; 
169         pt.y = e.clientY;
170         if (this.isTouchEvent(e)) {
171             pt.x =  e.targetTouches[0].clientX 
172             pt.y = e.targetTouches[0].clientY;
173         }
174         var a = this.svgEl.dom.getScreenCTM();
175         var b = a.inverse();
176         var mx = pt.matrixTransform(b);
177         return mx.x + ',' + mx.y;
178     },
179     //mouse event headler 
180     down : function (e) {
181         this.signatureTmp += 'M' + this.getCoords(e) + ' ';
182         this.signPanel.select('#svg-p', true).first().attr('d', this.signatureTmp);
183         
184         this.isMouseDown = true;
185         
186         e.preventDefault();
187     },
188     move : function (e) {
189         if (this.isMouseDown) {
190             this.signatureTmp += 'L' + this.getCoords(e) + ' ';
191             this.signPanel.select('#svg-p', true).first().attr('d', this.signatureTmp);
192         }
193         
194         e.preventDefault();
195     },
196     up : function (e) {
197         this.isMouseDown = false;
198         var sp = this.signatureTmp.split(' ');
199         
200         if(sp.length > 1){
201             if(!sp[sp.length-2].match(/^L/)){
202                 sp.pop();
203                 sp.pop();
204                 sp.push("");
205                 this.signatureTmp = sp.join(" ");
206             }
207         }
208         if(this.getValue() != this.signatureTmp){
209             this.signPanel.select('#svg-r', true).first().attr('fill', '#ffa');
210             this.isConfirmed = false;
211         }
212         e.preventDefault();
213     },
214     
215     /**
216      * Protected method that will not generally be called directly. It
217      * is called when the editor creates its toolbar. Override this method if you need to
218      * add custom toolbar buttons.
219      * @param {HtmlEditor} editor
220      */
221     createToolbar : function(editor){
222          function btn(id, toggle, handler){
223             var xid = fid + '-'+ id ;
224             return {
225                 id : xid,
226                 cmd : id,
227                 cls : 'x-btn-icon x-edit-'+id,
228                 enableToggle:toggle !== false,
229                 scope: editor, // was editor...
230                 handler:handler||editor.relayBtnCmd,
231                 clickEvent:'mousedown',
232                 tooltip: etb.buttonTips[id] || undefined, ///tips ???
233                 tabIndex:-1
234             };
235         }
236         
237         
238         var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
239         this.tb = tb;
240         this.tb.add(
241            {
242                 cls : ' x-signature-btn x-signature-'+id,
243                 scope: editor, // was editor...
244                 handler: this.reset,
245                 clickEvent:'mousedown',
246                 text: this.labels.clear
247             },
248             {
249                  xtype : 'Fill',
250                  xns: Roo.Toolbar
251             }, 
252             {
253                 cls : '  x-signature-btn x-signature-'+id,
254                 scope: editor, // was editor...
255                 handler: this.setConfirmed,
256                 clickEvent:'mousedown',
257                 text: this.labels.confirm
258             }
259         );
260     
261     },
262     // private
263     getSignature : function(){
264         return this.signatureTmp;
265     },
266     // private
267     reset : function(){
268         this.signatureTmp = '';
269         this.signPanel.select('#svg-r', true).first().attr('fill', '#ffa');
270         this.signPanel.select('#svg-p', true).first().attr('d', '');
271         this.isConfirmed = false;
272         Roo.form.Signature.superclass.reset.call(this);
273     },
274     test : function(){
275 //        Roo.log(this.signPanel.dom.contentWindow.up())
276     },
277     //public
278     setConfirmed : function(){
279         if(!this.getSignature()){
280             return;
281         }
282         this.signPanel.select('#svg-r', true).first().attr('fill', '#cfc');
283         this.setValue(this.getSignature());
284         this.isConfirmed = true;
285 //        Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
286     },
287     // private
288     // Subclasses should provide the validation implementation by overriding this
289     validateValue : function(value){
290         if(this.allowBlank){
291             return true;
292         }
293         
294         if(this.isConfirmed){
295             return true;
296         }
297         return false;
298     }
299 });