allow string based values for comboboxarray
[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.Signature} 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.svgID = Roo.id();
100         this.svgEl = this.signPanel.createChild({
101               xmlns : 'http://www.w3.org/2000/svg',
102               tag : 'svg',
103               id : this.svgID + "-svg",
104               width: this.width,
105               height: this.height,
106               viewBox: '0 0 '+this.width+' '+this.height,
107               cn : [
108                 {
109                     tag: "rect",
110                     id: this.svgID + "-svg-r",
111                     width: this.width,
112                     height: this.height,
113                     fill: "#ffa"
114                 },
115                 {
116                     tag: "line",
117                     id: this.svgID + "-svg-l",
118                     x1: "0", // start
119                     y1: (this.height*0.8), // start set the line in 80% of height
120                     x2: this.width, // end
121                     y2: (this.height*0.8), // end set the line in 80% of height
122                     'stroke': "#666",
123                     'stroke-width': "1",
124                     'stroke-dasharray': "3",
125                     'shape-rendering': "crispEdges",
126                     'pointer-events': "none"
127                 },
128                 {
129                     tag: "path",
130                     id: this.svgID + "-svg-p",
131                     'stroke': "navy",
132                     'stroke-width': "3",
133                     'fill': "none",
134                     'pointer-events': 'none'
135                 }
136               ]
137         });
138         this.createSVG();
139         this.svgBox = this.svgEl.dom.getScreenCTM();
140     },
141     createSVG : function(){ 
142         var svg = this.signPanel;
143         var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
144         var t = this;
145
146         r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
147         r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
148         r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
149         r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
150         r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
151         r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
152         r.addEventListener('touchend', function(e) { return t.up(e); }, false);
153         
154     },
155     isTouchEvent : function(e){
156         return e.type.match(/^touch/);
157     },
158     getCoords : function (e) {
159         var pt    = this.svgEl.dom.createSVGPoint();
160         pt.x = e.clientX; 
161         pt.y = e.clientY;
162         if (this.isTouchEvent(e)) {
163             pt.x =  e.targetTouches[0].clientX;
164             pt.y = e.targetTouches[0].clientY;
165         }
166         var a = this.svgEl.dom.getScreenCTM();
167         var b = a.inverse();
168         var mx = pt.matrixTransform(b);
169         return mx.x + ',' + mx.y;
170     },
171     //mouse event headler 
172     down : function (e) {
173         this.signatureTmp += 'M' + this.getCoords(e) + ' ';
174         this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
175         
176         this.isMouseDown = true;
177         
178         e.preventDefault();
179     },
180     move : function (e) {
181         if (this.isMouseDown) {
182             this.signatureTmp += 'L' + this.getCoords(e) + ' ';
183             this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
184         }
185         
186         e.preventDefault();
187     },
188     up : function (e) {
189         this.isMouseDown = false;
190         var sp = this.signatureTmp.split(' ');
191         
192         if(sp.length > 1){
193             if(!sp[sp.length-2].match(/^L/)){
194                 sp.pop();
195                 sp.pop();
196                 sp.push("");
197                 this.signatureTmp = sp.join(" ");
198             }
199         }
200         if(this.getValue() != this.signatureTmp){
201             this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
202             this.isConfirmed = false;
203         }
204         e.preventDefault();
205     },
206     
207     /**
208      * Protected method that will not generally be called directly. It
209      * is called when the editor creates its toolbar. Override this method if you need to
210      * add custom toolbar buttons.
211      * @param {HtmlEditor} editor
212      */
213     createToolbar : function(editor){
214          function btn(id, toggle, handler){
215             var xid = fid + '-'+ id ;
216             return {
217                 id : xid,
218                 cmd : id,
219                 cls : 'x-btn-icon x-edit-'+id,
220                 enableToggle:toggle !== false,
221                 scope: editor, // was editor...
222                 handler:handler||editor.relayBtnCmd,
223                 clickEvent:'mousedown',
224                 tooltip: etb.buttonTips[id] || undefined, ///tips ???
225                 tabIndex:-1
226             };
227         }
228         
229         
230         var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
231         this.tb = tb;
232         this.tb.add(
233            {
234                 cls : ' x-signature-btn x-signature-'+id,
235                 scope: editor, // was editor...
236                 handler: this.reset,
237                 clickEvent:'mousedown',
238                 text: this.labels.clear
239             },
240             {
241                  xtype : 'Fill',
242                  xns: Roo.Toolbar
243             }, 
244             {
245                 cls : '  x-signature-btn x-signature-'+id,
246                 scope: editor, // was editor...
247                 handler: this.confirmHandler,
248                 clickEvent:'mousedown',
249                 text: this.labels.confirm
250             }
251         );
252     
253     },
254     //public
255     /**
256      * when user is clicked confirm then show this image.....
257      * 
258      * @return {String} Image Data URI
259      */
260     getImageDataURI : function(){
261         var svg = this.svgEl.dom.parentNode.innerHTML;
262         var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
263         return src; 
264     },
265     /**
266      * 
267      * @return {Boolean} this.isConfirmed
268      */
269     getConfirmed : function(){
270         return this.isConfirmed;
271     },
272     /**
273      * 
274      * @return {Number} this.width
275      */
276     getWidth : function(){
277         return this.width;
278     },
279     /**
280      * 
281      * @return {Number} this.height
282      */
283     getHeight : function(){
284         return this.height;
285     },
286     // private
287     getSignature : function(){
288         return this.signatureTmp;
289     },
290     // private
291     reset : function(){
292         this.signatureTmp = '';
293         this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
294         this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
295         this.isConfirmed = false;
296         Roo.form.Signature.superclass.reset.call(this);
297     },
298     setSignature : function(s){
299         this.signatureTmp = s;
300         this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
301         this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
302         this.setValue(s);
303         this.isConfirmed = false;
304         Roo.form.Signature.superclass.reset.call(this);
305     }, 
306     test : function(){
307 //        Roo.log(this.signPanel.dom.contentWindow.up())
308     },
309     //private
310     setConfirmed : function(){
311         
312         
313         
314 //        Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
315     },
316     // private
317     confirmHandler : function(){
318         if(!this.getSignature()){
319             return;
320         }
321         
322         this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
323         this.setValue(this.getSignature());
324         this.isConfirmed = true;
325         
326         this.fireEvent('confirm', this);
327     },
328     // private
329     // Subclasses should provide the validation implementation by overriding this
330     validateValue : function(value){
331         if(this.allowBlank){
332             return true;
333         }
334         
335         if(this.isConfirmed){
336             return true;
337         }
338         return false;
339     }
340 });