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