canvasinput-rails 1.2.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/canvasinput/rails/version.rb +5 -0
- data/lib/canvasinput/rails.rb +9 -0
- data/vendor/assets/javascripts/canvasinput/CanvasInput.js +1475 -0
- data/vendor/assets/javascripts/canvasinput/CanvasInput.min.js +10 -0
- data/vendor/assets/javascripts/canvasinput/README.md +120 -0
- data/vendor/assets/javascripts/canvasinput/package.json +20 -0
- metadata +78 -0
|
@@ -0,0 +1,1475 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* CanvasInput v1.2.7
|
|
3
|
+
* http://goldfirestudios.com/blog/108/CanvasInput-HTML5-Canvas-Text-Input
|
|
4
|
+
*
|
|
5
|
+
* (c) 2013-2017, James Simpson of GoldFire Studios
|
|
6
|
+
* goldfirestudios.com
|
|
7
|
+
*
|
|
8
|
+
* MIT License
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
(function() {
|
|
12
|
+
// create a buffer that stores all inputs so that tabbing
|
|
13
|
+
// between them is made possible.
|
|
14
|
+
var inputs = [];
|
|
15
|
+
|
|
16
|
+
// initialize the Canvas Input
|
|
17
|
+
var CanvasInput = window.CanvasInput = function(o) {
|
|
18
|
+
var self = this;
|
|
19
|
+
|
|
20
|
+
o = o ? o : {};
|
|
21
|
+
|
|
22
|
+
// setup the defaults
|
|
23
|
+
self._canvas = o.canvas || null;
|
|
24
|
+
self._ctx = self._canvas ? self._canvas.getContext('2d') : null;
|
|
25
|
+
self._x = o.x || 0;
|
|
26
|
+
self._y = o.y || 0;
|
|
27
|
+
self._extraX = o.extraX || 0;
|
|
28
|
+
self._extraY = o.extraY || 0;
|
|
29
|
+
self._fontSize = o.fontSize || 14;
|
|
30
|
+
self._fontFamily = o.fontFamily || 'Arial';
|
|
31
|
+
self._fontColor = o.fontColor || '#000';
|
|
32
|
+
self._placeHolderColor = o.placeHolderColor || '#bfbebd';
|
|
33
|
+
self._fontWeight = o.fontWeight || 'normal';
|
|
34
|
+
self._fontStyle = o.fontStyle || 'normal';
|
|
35
|
+
self._fontShadowColor = o.fontShadowColor || '';
|
|
36
|
+
self._fontShadowBlur = o.fontShadowBlur || 0;
|
|
37
|
+
self._fontShadowOffsetX = o.fontShadowOffsetX || 0;
|
|
38
|
+
self._fontShadowOffsetY = o.fontShadowOffsetY || 0;
|
|
39
|
+
self._readonly = o.readonly || false;
|
|
40
|
+
self._maxlength = o.maxlength || null;
|
|
41
|
+
self._width = o.width || 150;
|
|
42
|
+
self._height = o.height || self._fontSize;
|
|
43
|
+
self._padding = o.padding >= 0 ? o.padding : 5;
|
|
44
|
+
self._borderWidth = o.borderWidth >= 0 ? o.borderWidth : 1;
|
|
45
|
+
self._borderColor = o.borderColor || '#959595';
|
|
46
|
+
self._borderRadius = o.borderRadius >= 0 ? o.borderRadius : 3;
|
|
47
|
+
self._backgroundImage = o.backgroundImage || '';
|
|
48
|
+
self._boxShadow = o.boxShadow || '1px 1px 0px rgba(255, 255, 255, 1)';
|
|
49
|
+
self._innerShadow = o.innerShadow || '0px 0px 4px rgba(0, 0, 0, 0.4)';
|
|
50
|
+
self._selectionColor = o.selectionColor || 'rgba(179, 212, 253, 0.8)';
|
|
51
|
+
self._placeHolder = o.placeHolder || '';
|
|
52
|
+
self._value = (o.value || self._placeHolder) + '';
|
|
53
|
+
self._onsubmit = o.onsubmit || function() {};
|
|
54
|
+
self._onkeydown = o.onkeydown || function() {};
|
|
55
|
+
self._onkeyup = o.onkeyup || function() {};
|
|
56
|
+
self._onfocus = o.onfocus || function() {};
|
|
57
|
+
self._onblur = o.onblur || function() {};
|
|
58
|
+
self._cursor = false;
|
|
59
|
+
self._cursorPos = 0;
|
|
60
|
+
self._hasFocus = false;
|
|
61
|
+
self._selection = [0, 0];
|
|
62
|
+
self._wasOver = false;
|
|
63
|
+
|
|
64
|
+
// parse box shadow
|
|
65
|
+
self.boxShadow(self._boxShadow, true);
|
|
66
|
+
|
|
67
|
+
// calculate the full width and height with padding, borders and shadows
|
|
68
|
+
self._calcWH();
|
|
69
|
+
|
|
70
|
+
// setup the off-DOM canvas
|
|
71
|
+
self._renderCanvas = document.createElement('canvas');
|
|
72
|
+
self._renderCanvas.setAttribute('width', self.outerW);
|
|
73
|
+
self._renderCanvas.setAttribute('height', self.outerH);
|
|
74
|
+
self._renderCtx = self._renderCanvas.getContext('2d');
|
|
75
|
+
|
|
76
|
+
// setup another off-DOM canvas for inner-shadows
|
|
77
|
+
self._shadowCanvas = document.createElement('canvas');
|
|
78
|
+
self._shadowCanvas.setAttribute('width', self._width + self._padding * 2);
|
|
79
|
+
self._shadowCanvas.setAttribute('height', self._height + self._padding * 2);
|
|
80
|
+
self._shadowCtx = self._shadowCanvas.getContext('2d');
|
|
81
|
+
|
|
82
|
+
// setup the background color
|
|
83
|
+
if (typeof o.backgroundGradient !== 'undefined') {
|
|
84
|
+
self._backgroundColor = self._renderCtx.createLinearGradient(
|
|
85
|
+
0,
|
|
86
|
+
0,
|
|
87
|
+
0,
|
|
88
|
+
self.outerH
|
|
89
|
+
);
|
|
90
|
+
self._backgroundColor.addColorStop(0, o.backgroundGradient[0]);
|
|
91
|
+
self._backgroundColor.addColorStop(1, o.backgroundGradient[1]);
|
|
92
|
+
} else {
|
|
93
|
+
self._backgroundColor = o.backgroundColor || '#fff';
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// setup main canvas events
|
|
97
|
+
if (self._canvas) {
|
|
98
|
+
self._canvas.addEventListener('mousemove', function(e) {
|
|
99
|
+
e = e || window.event;
|
|
100
|
+
self.mousemove(e, self);
|
|
101
|
+
}, false);
|
|
102
|
+
|
|
103
|
+
self._canvas.addEventListener('mousedown', function(e) {
|
|
104
|
+
e = e || window.event;
|
|
105
|
+
self.mousedown(e, self);
|
|
106
|
+
}, false);
|
|
107
|
+
|
|
108
|
+
self._canvas.addEventListener('mouseup', function(e) {
|
|
109
|
+
e = e || window.event;
|
|
110
|
+
self.mouseup(e, self);
|
|
111
|
+
}, false);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// setup a global mouseup to blur the input outside of the canvas
|
|
115
|
+
var autoBlur = function(e) {
|
|
116
|
+
e = e || window.event;
|
|
117
|
+
|
|
118
|
+
if (self._hasFocus && !self._mouseDown) {
|
|
119
|
+
self.blur();
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
window.addEventListener('mouseup', autoBlur, true);
|
|
123
|
+
window.addEventListener('touchend', autoBlur, true);
|
|
124
|
+
|
|
125
|
+
// create the hidden input element
|
|
126
|
+
self._hiddenInput = document.createElement('input');
|
|
127
|
+
self._hiddenInput.type = 'text';
|
|
128
|
+
self._hiddenInput.style.position = 'absolute';
|
|
129
|
+
self._hiddenInput.style.opacity = 0;
|
|
130
|
+
self._hiddenInput.style.pointerEvents = 'none';
|
|
131
|
+
self._hiddenInput.style.zIndex = 0;
|
|
132
|
+
// hide native blue text cursor on iOS
|
|
133
|
+
self._hiddenInput.style.transform = 'scale(0)';
|
|
134
|
+
|
|
135
|
+
self._updateHiddenInput();
|
|
136
|
+
if (self._maxlength) {
|
|
137
|
+
self._hiddenInput.maxLength = self._maxlength;
|
|
138
|
+
}
|
|
139
|
+
document.body.appendChild(self._hiddenInput);
|
|
140
|
+
self._hiddenInput.value = self._value;
|
|
141
|
+
|
|
142
|
+
// setup the keydown listener
|
|
143
|
+
self._hiddenInput.addEventListener('keydown', function(e) {
|
|
144
|
+
e = e || window.event;
|
|
145
|
+
|
|
146
|
+
if (self._hasFocus) {
|
|
147
|
+
// hack to fix touch event bug in iOS Safari
|
|
148
|
+
window.focus();
|
|
149
|
+
self._hiddenInput.focus();
|
|
150
|
+
|
|
151
|
+
// continue with the keydown event
|
|
152
|
+
self.keydown(e, self);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// setup the keyup listener
|
|
157
|
+
self._hiddenInput.addEventListener('keyup', function(e) {
|
|
158
|
+
e = e || window.event;
|
|
159
|
+
|
|
160
|
+
// update the canvas input state information from the hidden input
|
|
161
|
+
self._value = self._hiddenInput.value;
|
|
162
|
+
self._cursorPos = self._hiddenInput.selectionStart;
|
|
163
|
+
// update selection to hidden input's selection in case user did keyboard-based selection
|
|
164
|
+
self._selection = [self._hiddenInput.selectionStart, self._hiddenInput.selectionEnd];
|
|
165
|
+
self.render();
|
|
166
|
+
|
|
167
|
+
if (self._hasFocus) {
|
|
168
|
+
self._onkeyup(e, self);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// add this to the buffer
|
|
173
|
+
inputs.push(self);
|
|
174
|
+
self._inputsIndex = inputs.length - 1;
|
|
175
|
+
|
|
176
|
+
// draw the text box
|
|
177
|
+
self.render();
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
// setup the prototype
|
|
181
|
+
CanvasInput.prototype = {
|
|
182
|
+
/**
|
|
183
|
+
* Get/set the main canvas.
|
|
184
|
+
* @param {Object} data Canvas reference.
|
|
185
|
+
* @return {Mixed} CanvasInput or current canvas.
|
|
186
|
+
*/
|
|
187
|
+
canvas: function(data) {
|
|
188
|
+
var self = this;
|
|
189
|
+
|
|
190
|
+
if (typeof data !== 'undefined') {
|
|
191
|
+
self._canvas = data;
|
|
192
|
+
self._ctx = self._canvas.getContext('2d');
|
|
193
|
+
|
|
194
|
+
return self.render();
|
|
195
|
+
} else {
|
|
196
|
+
return self._canvas;
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Get/set the x-position.
|
|
202
|
+
* @param {Number} data The pixel position along the x-coordinate.
|
|
203
|
+
* @return {Mixed} CanvasInput or current x-value.
|
|
204
|
+
*/
|
|
205
|
+
x: function(data) {
|
|
206
|
+
var self = this;
|
|
207
|
+
|
|
208
|
+
if (typeof data !== 'undefined') {
|
|
209
|
+
self._x = data;
|
|
210
|
+
self._updateHiddenInput();
|
|
211
|
+
|
|
212
|
+
return self.render();
|
|
213
|
+
} else {
|
|
214
|
+
return self._x;
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Get/set the y-position.
|
|
220
|
+
* @param {Number} data The pixel position along the y-coordinate.
|
|
221
|
+
* @return {Mixed} CanvasInput or current y-value.
|
|
222
|
+
*/
|
|
223
|
+
y: function(data) {
|
|
224
|
+
var self = this;
|
|
225
|
+
|
|
226
|
+
if (typeof data !== 'undefined') {
|
|
227
|
+
self._y = data;
|
|
228
|
+
self._updateHiddenInput();
|
|
229
|
+
|
|
230
|
+
return self.render();
|
|
231
|
+
} else {
|
|
232
|
+
return self._y;
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Get/set the extra x-position (generally used when no canvas is specified).
|
|
238
|
+
* @param {Number} data The pixel position along the x-coordinate.
|
|
239
|
+
* @return {Mixed} CanvasInput or current x-value.
|
|
240
|
+
*/
|
|
241
|
+
extraX: function(data) {
|
|
242
|
+
var self = this;
|
|
243
|
+
|
|
244
|
+
if (typeof data !== 'undefined') {
|
|
245
|
+
self._extraX = data;
|
|
246
|
+
self._updateHiddenInput();
|
|
247
|
+
|
|
248
|
+
return self.render();
|
|
249
|
+
} else {
|
|
250
|
+
return self._extraX;
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Get/set the extra y-position (generally used when no canvas is specified).
|
|
256
|
+
* @param {Number} data The pixel position along the y-coordinate.
|
|
257
|
+
* @return {Mixed} CanvasInput or current y-value.
|
|
258
|
+
*/
|
|
259
|
+
extraY: function(data) {
|
|
260
|
+
var self = this;
|
|
261
|
+
|
|
262
|
+
if (typeof data !== 'undefined') {
|
|
263
|
+
self._extraY = data;
|
|
264
|
+
self._updateHiddenInput();
|
|
265
|
+
|
|
266
|
+
return self.render();
|
|
267
|
+
} else {
|
|
268
|
+
return self._extraY;
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Get/set the font size.
|
|
274
|
+
* @param {Number} data Font size.
|
|
275
|
+
* @return {Mixed} CanvasInput or current font size.
|
|
276
|
+
*/
|
|
277
|
+
fontSize: function(data) {
|
|
278
|
+
var self = this;
|
|
279
|
+
|
|
280
|
+
if (typeof data !== 'undefined') {
|
|
281
|
+
self._fontSize = data;
|
|
282
|
+
|
|
283
|
+
return self.render();
|
|
284
|
+
} else {
|
|
285
|
+
return self._fontSize;
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Get/set the font family.
|
|
291
|
+
* @param {String} data Font family.
|
|
292
|
+
* @return {Mixed} CanvasInput or current font family.
|
|
293
|
+
*/
|
|
294
|
+
fontFamily: function(data) {
|
|
295
|
+
var self = this;
|
|
296
|
+
|
|
297
|
+
if (typeof data !== 'undefined') {
|
|
298
|
+
self._fontFamily = data;
|
|
299
|
+
|
|
300
|
+
return self.render();
|
|
301
|
+
} else {
|
|
302
|
+
return self._fontFamily;
|
|
303
|
+
}
|
|
304
|
+
},
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Get/set the font color.
|
|
308
|
+
* @param {String} data Font color.
|
|
309
|
+
* @return {Mixed} CanvasInput or current font color.
|
|
310
|
+
*/
|
|
311
|
+
fontColor: function(data) {
|
|
312
|
+
var self = this;
|
|
313
|
+
|
|
314
|
+
if (typeof data !== 'undefined') {
|
|
315
|
+
self._fontColor = data;
|
|
316
|
+
|
|
317
|
+
return self.render();
|
|
318
|
+
} else {
|
|
319
|
+
return self._fontColor;
|
|
320
|
+
}
|
|
321
|
+
},
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Get/set the place holder font color.
|
|
325
|
+
* @param {String} data Font color.
|
|
326
|
+
* @return {Mixed} CanvasInput or current place holder font color.
|
|
327
|
+
*/
|
|
328
|
+
placeHolderColor: function(data) {
|
|
329
|
+
var self = this;
|
|
330
|
+
|
|
331
|
+
if (typeof data !== 'undefined') {
|
|
332
|
+
self._placeHolderColor = data;
|
|
333
|
+
|
|
334
|
+
return self.render();
|
|
335
|
+
} else {
|
|
336
|
+
return self._placeHolderColor;
|
|
337
|
+
}
|
|
338
|
+
},
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Get/set the font weight.
|
|
342
|
+
* @param {String} data Font weight.
|
|
343
|
+
* @return {Mixed} CanvasInput or current font weight.
|
|
344
|
+
*/
|
|
345
|
+
fontWeight: function(data) {
|
|
346
|
+
var self = this;
|
|
347
|
+
|
|
348
|
+
if (typeof data !== 'undefined') {
|
|
349
|
+
self._fontWeight = data;
|
|
350
|
+
|
|
351
|
+
return self.render();
|
|
352
|
+
} else {
|
|
353
|
+
return self._fontWeight;
|
|
354
|
+
}
|
|
355
|
+
},
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Get/set the font style.
|
|
359
|
+
* @param {String} data Font style.
|
|
360
|
+
* @return {Mixed} CanvasInput or current font style.
|
|
361
|
+
*/
|
|
362
|
+
fontStyle: function(data) {
|
|
363
|
+
var self = this;
|
|
364
|
+
|
|
365
|
+
if (typeof data !== 'undefined') {
|
|
366
|
+
self._fontStyle = data;
|
|
367
|
+
|
|
368
|
+
return self.render();
|
|
369
|
+
} else {
|
|
370
|
+
return self._fontStyle;
|
|
371
|
+
}
|
|
372
|
+
},
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Get/set the font shadow color.
|
|
376
|
+
* @param {String} data Font shadow color.
|
|
377
|
+
* @return {Mixed} CanvasInput or current font shadow color.
|
|
378
|
+
*/
|
|
379
|
+
fontShadowColor: function(data) {
|
|
380
|
+
var self = this;
|
|
381
|
+
|
|
382
|
+
if (typeof data !== 'undefined') {
|
|
383
|
+
self._fontShadowColor = data;
|
|
384
|
+
|
|
385
|
+
return self.render();
|
|
386
|
+
} else {
|
|
387
|
+
return self._fontShadowColor;
|
|
388
|
+
}
|
|
389
|
+
},
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Get/set the font shadow blur.
|
|
393
|
+
* @param {String} data Font shadow blur.
|
|
394
|
+
* @return {Mixed} CanvasInput or current font shadow blur.
|
|
395
|
+
*/
|
|
396
|
+
fontShadowBlur: function(data) {
|
|
397
|
+
var self = this;
|
|
398
|
+
|
|
399
|
+
if (typeof data !== 'undefined') {
|
|
400
|
+
self._fontShadowBlur = data;
|
|
401
|
+
|
|
402
|
+
return self.render();
|
|
403
|
+
} else {
|
|
404
|
+
return self._fontShadowBlur;
|
|
405
|
+
}
|
|
406
|
+
},
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Get/set the font shadow x-offset.
|
|
410
|
+
* @param {String} data Font shadow x-offset.
|
|
411
|
+
* @return {Mixed} CanvasInput or current font shadow x-offset.
|
|
412
|
+
*/
|
|
413
|
+
fontShadowOffsetX: function(data) {
|
|
414
|
+
var self = this;
|
|
415
|
+
|
|
416
|
+
if (typeof data !== 'undefined') {
|
|
417
|
+
self._fontShadowOffsetX = data;
|
|
418
|
+
|
|
419
|
+
return self.render();
|
|
420
|
+
} else {
|
|
421
|
+
return self._fontShadowOffsetX;
|
|
422
|
+
}
|
|
423
|
+
},
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Get/set the font shadow y-offset.
|
|
427
|
+
* @param {String} data Font shadow y-offset.
|
|
428
|
+
* @return {Mixed} CanvasInput or current font shadow y-offset.
|
|
429
|
+
*/
|
|
430
|
+
fontShadowOffsetY: function(data) {
|
|
431
|
+
var self = this;
|
|
432
|
+
|
|
433
|
+
if (typeof data !== 'undefined') {
|
|
434
|
+
self._fontShadowOffsetY = data;
|
|
435
|
+
|
|
436
|
+
return self.render();
|
|
437
|
+
} else {
|
|
438
|
+
return self._fontShadowOffsetY;
|
|
439
|
+
}
|
|
440
|
+
},
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Get/set the width of the text box.
|
|
444
|
+
* @param {Number} data Width in pixels.
|
|
445
|
+
* @return {Mixed} CanvasInput or current width.
|
|
446
|
+
*/
|
|
447
|
+
width: function(data) {
|
|
448
|
+
var self = this;
|
|
449
|
+
|
|
450
|
+
if (typeof data !== 'undefined') {
|
|
451
|
+
self._width = data;
|
|
452
|
+
self._calcWH();
|
|
453
|
+
self._updateCanvasWH();
|
|
454
|
+
self._updateHiddenInput();
|
|
455
|
+
|
|
456
|
+
return self.render();
|
|
457
|
+
} else {
|
|
458
|
+
return self._width;
|
|
459
|
+
}
|
|
460
|
+
},
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Get/set the height of the text box.
|
|
464
|
+
* @param {Number} data Height in pixels.
|
|
465
|
+
* @return {Mixed} CanvasInput or current height.
|
|
466
|
+
*/
|
|
467
|
+
height: function(data) {
|
|
468
|
+
var self = this;
|
|
469
|
+
|
|
470
|
+
if (typeof data !== 'undefined') {
|
|
471
|
+
self._height = data;
|
|
472
|
+
self._calcWH();
|
|
473
|
+
self._updateCanvasWH();
|
|
474
|
+
self._updateHiddenInput();
|
|
475
|
+
|
|
476
|
+
return self.render();
|
|
477
|
+
} else {
|
|
478
|
+
return self._height;
|
|
479
|
+
}
|
|
480
|
+
},
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* Get/set the padding of the text box.
|
|
484
|
+
* @param {Number} data Padding in pixels.
|
|
485
|
+
* @return {Mixed} CanvasInput or current padding.
|
|
486
|
+
*/
|
|
487
|
+
padding: function(data) {
|
|
488
|
+
var self = this;
|
|
489
|
+
|
|
490
|
+
if (typeof data !== 'undefined') {
|
|
491
|
+
self._padding = data;
|
|
492
|
+
self._calcWH();
|
|
493
|
+
self._updateCanvasWH();
|
|
494
|
+
|
|
495
|
+
return self.render();
|
|
496
|
+
} else {
|
|
497
|
+
return self._padding;
|
|
498
|
+
}
|
|
499
|
+
},
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Get/set the border width.
|
|
503
|
+
* @param {Number} data Border width.
|
|
504
|
+
* @return {Mixed} CanvasInput or current border width.
|
|
505
|
+
*/
|
|
506
|
+
borderWidth: function(data) {
|
|
507
|
+
var self = this;
|
|
508
|
+
|
|
509
|
+
if (typeof data !== 'undefined') {
|
|
510
|
+
self._borderWidth = data;
|
|
511
|
+
self._calcWH();
|
|
512
|
+
self._updateCanvasWH();
|
|
513
|
+
|
|
514
|
+
return self.render();
|
|
515
|
+
} else {
|
|
516
|
+
return self._borderWidth;
|
|
517
|
+
}
|
|
518
|
+
},
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Get/set the border color.
|
|
522
|
+
* @param {String} data Border color.
|
|
523
|
+
* @return {Mixed} CanvasInput or current border color.
|
|
524
|
+
*/
|
|
525
|
+
borderColor: function(data) {
|
|
526
|
+
var self = this;
|
|
527
|
+
|
|
528
|
+
if (typeof data !== 'undefined') {
|
|
529
|
+
self._borderColor = data;
|
|
530
|
+
|
|
531
|
+
return self.render();
|
|
532
|
+
} else {
|
|
533
|
+
return self._borderColor;
|
|
534
|
+
}
|
|
535
|
+
},
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* Get/set the border radius.
|
|
539
|
+
* @param {Number} data Border radius.
|
|
540
|
+
* @return {Mixed} CanvasInput or current border radius.
|
|
541
|
+
*/
|
|
542
|
+
borderRadius: function(data) {
|
|
543
|
+
var self = this;
|
|
544
|
+
|
|
545
|
+
if (typeof data !== 'undefined') {
|
|
546
|
+
self._borderRadius = data;
|
|
547
|
+
|
|
548
|
+
return self.render();
|
|
549
|
+
} else {
|
|
550
|
+
return self._borderRadius;
|
|
551
|
+
}
|
|
552
|
+
},
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* Get/set the background color.
|
|
556
|
+
* @param {Number} data Background color.
|
|
557
|
+
* @return {Mixed} CanvasInput or current background color.
|
|
558
|
+
*/
|
|
559
|
+
backgroundColor: function(data) {
|
|
560
|
+
var self = this;
|
|
561
|
+
|
|
562
|
+
if (typeof data !== 'undefined') {
|
|
563
|
+
self._backgroundColor = data;
|
|
564
|
+
|
|
565
|
+
return self.render();
|
|
566
|
+
} else {
|
|
567
|
+
return self._backgroundColor;
|
|
568
|
+
}
|
|
569
|
+
},
|
|
570
|
+
|
|
571
|
+
/**
|
|
572
|
+
* Get/set the background gradient.
|
|
573
|
+
* @param {Number} data Background gradient.
|
|
574
|
+
* @return {Mixed} CanvasInput or current background gradient.
|
|
575
|
+
*/
|
|
576
|
+
backgroundGradient: function(data) {
|
|
577
|
+
var self = this;
|
|
578
|
+
|
|
579
|
+
if (typeof data !== 'undefined') {
|
|
580
|
+
self._backgroundColor = self._renderCtx.createLinearGradient(
|
|
581
|
+
0,
|
|
582
|
+
0,
|
|
583
|
+
0,
|
|
584
|
+
self.outerH
|
|
585
|
+
);
|
|
586
|
+
self._backgroundColor.addColorStop(0, data[0]);
|
|
587
|
+
self._backgroundColor.addColorStop(1, data[1]);
|
|
588
|
+
|
|
589
|
+
return self.render();
|
|
590
|
+
} else {
|
|
591
|
+
return self._backgroundColor;
|
|
592
|
+
}
|
|
593
|
+
},
|
|
594
|
+
|
|
595
|
+
/**
|
|
596
|
+
* Get/set the box shadow.
|
|
597
|
+
* @param {String} data Box shadow in CSS format (1px 1px 1px rgba(0, 0, 0.5)).
|
|
598
|
+
* @param {Boolean} doReturn (optional) True to prevent a premature render.
|
|
599
|
+
* @return {Mixed} CanvasInput or current box shadow.
|
|
600
|
+
*/
|
|
601
|
+
boxShadow: function(data, doReturn) {
|
|
602
|
+
var self = this;
|
|
603
|
+
|
|
604
|
+
if (typeof data !== 'undefined') {
|
|
605
|
+
// parse box shadow
|
|
606
|
+
var boxShadow = data.split('px ');
|
|
607
|
+
self._boxShadow = {
|
|
608
|
+
x: self._boxShadow === 'none' ? 0 : parseInt(boxShadow[0], 10),
|
|
609
|
+
y: self._boxShadow === 'none' ? 0 : parseInt(boxShadow[1], 10),
|
|
610
|
+
blur: self._boxShadow === 'none' ? 0 : parseInt(boxShadow[2], 10),
|
|
611
|
+
color: self._boxShadow === 'none' ? '' : boxShadow[3]
|
|
612
|
+
};
|
|
613
|
+
|
|
614
|
+
// take into account the shadow and its direction
|
|
615
|
+
if (self._boxShadow.x < 0) {
|
|
616
|
+
self.shadowL = Math.abs(self._boxShadow.x) + self._boxShadow.blur;
|
|
617
|
+
self.shadowR = self._boxShadow.blur + self._boxShadow.x;
|
|
618
|
+
} else {
|
|
619
|
+
self.shadowL = Math.abs(self._boxShadow.blur - self._boxShadow.x);
|
|
620
|
+
self.shadowR = self._boxShadow.blur + self._boxShadow.x;
|
|
621
|
+
}
|
|
622
|
+
if (self._boxShadow.y < 0) {
|
|
623
|
+
self.shadowT = Math.abs(self._boxShadow.y) + self._boxShadow.blur;
|
|
624
|
+
self.shadowB = self._boxShadow.blur + self._boxShadow.y;
|
|
625
|
+
} else {
|
|
626
|
+
self.shadowT = Math.abs(self._boxShadow.blur - self._boxShadow.y);
|
|
627
|
+
self.shadowB = self._boxShadow.blur + self._boxShadow.y;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
self.shadowW = self.shadowL + self.shadowR;
|
|
631
|
+
self.shadowH = self.shadowT + self.shadowB;
|
|
632
|
+
|
|
633
|
+
self._calcWH();
|
|
634
|
+
|
|
635
|
+
if (!doReturn) {
|
|
636
|
+
self._updateCanvasWH();
|
|
637
|
+
|
|
638
|
+
return self.render();
|
|
639
|
+
}
|
|
640
|
+
} else {
|
|
641
|
+
return self._boxShadow;
|
|
642
|
+
}
|
|
643
|
+
},
|
|
644
|
+
|
|
645
|
+
/**
|
|
646
|
+
* Get/set the inner shadow.
|
|
647
|
+
* @param {String} data In the format of a CSS box shadow (1px 1px 1px rgba(0, 0, 0.5)).
|
|
648
|
+
* @return {Mixed} CanvasInput or current inner shadow.
|
|
649
|
+
*/
|
|
650
|
+
innerShadow: function(data) {
|
|
651
|
+
var self = this;
|
|
652
|
+
|
|
653
|
+
if (typeof data !== 'undefined') {
|
|
654
|
+
self._innerShadow = data;
|
|
655
|
+
|
|
656
|
+
return self.render();
|
|
657
|
+
} else {
|
|
658
|
+
return self._innerShadow;
|
|
659
|
+
}
|
|
660
|
+
},
|
|
661
|
+
|
|
662
|
+
/**
|
|
663
|
+
* Get/set the text selection color.
|
|
664
|
+
* @param {String} data Color.
|
|
665
|
+
* @return {Mixed} CanvasInput or current selection color.
|
|
666
|
+
*/
|
|
667
|
+
selectionColor: function(data) {
|
|
668
|
+
var self = this;
|
|
669
|
+
|
|
670
|
+
if (typeof data !== 'undefined') {
|
|
671
|
+
self._selectionColor = data;
|
|
672
|
+
|
|
673
|
+
return self.render();
|
|
674
|
+
} else {
|
|
675
|
+
return self._selectionColor;
|
|
676
|
+
}
|
|
677
|
+
},
|
|
678
|
+
|
|
679
|
+
/**
|
|
680
|
+
* Get/set the place holder text.
|
|
681
|
+
* @param {String} data Place holder text.
|
|
682
|
+
* @return {Mixed} CanvasInput or current place holder text.
|
|
683
|
+
*/
|
|
684
|
+
placeHolder: function(data) {
|
|
685
|
+
var self = this;
|
|
686
|
+
|
|
687
|
+
if (typeof data !== 'undefined') {
|
|
688
|
+
self._placeHolder = data;
|
|
689
|
+
|
|
690
|
+
return self.render();
|
|
691
|
+
} else {
|
|
692
|
+
return self._placeHolder;
|
|
693
|
+
}
|
|
694
|
+
},
|
|
695
|
+
|
|
696
|
+
/**
|
|
697
|
+
* Get/set the current text box value.
|
|
698
|
+
* @param {String} data Text value.
|
|
699
|
+
* @return {Mixed} CanvasInput or current text value.
|
|
700
|
+
*/
|
|
701
|
+
value: function(data) {
|
|
702
|
+
var self = this;
|
|
703
|
+
|
|
704
|
+
if (typeof data !== 'undefined') {
|
|
705
|
+
self._value = data + '';
|
|
706
|
+
self._hiddenInput.value = data + '';
|
|
707
|
+
|
|
708
|
+
// update the cursor position
|
|
709
|
+
self._cursorPos = self._clipText().length;
|
|
710
|
+
|
|
711
|
+
self.render();
|
|
712
|
+
|
|
713
|
+
return self;
|
|
714
|
+
} else {
|
|
715
|
+
return (self._value === self._placeHolder) ? '' : self._value;
|
|
716
|
+
}
|
|
717
|
+
},
|
|
718
|
+
|
|
719
|
+
/**
|
|
720
|
+
* Set or fire the onsubmit event.
|
|
721
|
+
* @param {Function} fn Custom callback.
|
|
722
|
+
*/
|
|
723
|
+
onsubmit: function(fn) {
|
|
724
|
+
var self = this;
|
|
725
|
+
|
|
726
|
+
if (typeof fn !== 'undefined') {
|
|
727
|
+
self._onsubmit = fn;
|
|
728
|
+
|
|
729
|
+
return self;
|
|
730
|
+
} else {
|
|
731
|
+
self._onsubmit();
|
|
732
|
+
}
|
|
733
|
+
},
|
|
734
|
+
|
|
735
|
+
/**
|
|
736
|
+
* Set or fire the onkeydown event.
|
|
737
|
+
* @param {Function} fn Custom callback.
|
|
738
|
+
*/
|
|
739
|
+
onkeydown: function(fn) {
|
|
740
|
+
var self = this;
|
|
741
|
+
|
|
742
|
+
if (typeof fn !== 'undefined') {
|
|
743
|
+
self._onkeydown = fn;
|
|
744
|
+
|
|
745
|
+
return self;
|
|
746
|
+
} else {
|
|
747
|
+
self._onkeydown();
|
|
748
|
+
}
|
|
749
|
+
},
|
|
750
|
+
|
|
751
|
+
/**
|
|
752
|
+
* Set or fire the onkeyup event.
|
|
753
|
+
* @param {Function} fn Custom callback.
|
|
754
|
+
*/
|
|
755
|
+
onkeyup: function(fn) {
|
|
756
|
+
var self = this;
|
|
757
|
+
|
|
758
|
+
if (typeof fn !== 'undefined') {
|
|
759
|
+
self._onkeyup = fn;
|
|
760
|
+
|
|
761
|
+
return self;
|
|
762
|
+
} else {
|
|
763
|
+
self._onkeyup();
|
|
764
|
+
}
|
|
765
|
+
},
|
|
766
|
+
|
|
767
|
+
/**
|
|
768
|
+
* Place focus on the CanvasInput box, placing the cursor
|
|
769
|
+
* either at the end of the text or where the user clicked.
|
|
770
|
+
* @param {Number} pos (optional) The position to place the cursor.
|
|
771
|
+
* @return {CanvasInput}
|
|
772
|
+
*/
|
|
773
|
+
focus: function(pos) {
|
|
774
|
+
var self = this;
|
|
775
|
+
|
|
776
|
+
// only fire the focus event when going from unfocussed
|
|
777
|
+
if (!self._hasFocus) {
|
|
778
|
+
self._onfocus(self);
|
|
779
|
+
|
|
780
|
+
// remove focus from all other inputs
|
|
781
|
+
for (var i=0; i<inputs.length; i++) {
|
|
782
|
+
if (inputs[i]._hasFocus) {
|
|
783
|
+
inputs[i].blur();
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
// remove selection
|
|
789
|
+
if (!self._selectionUpdated) {
|
|
790
|
+
self._selection = [0, 0];
|
|
791
|
+
} else {
|
|
792
|
+
delete self._selectionUpdated;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
// if this is readonly, don't allow it to get focus
|
|
796
|
+
self._hasFocus = true;
|
|
797
|
+
if (self._readonly) {
|
|
798
|
+
self._hiddenInput.readOnly = true;
|
|
799
|
+
} else {
|
|
800
|
+
self._hiddenInput.readOnly = false;
|
|
801
|
+
|
|
802
|
+
// update the cursor position
|
|
803
|
+
self._cursorPos = (typeof pos === 'number') ? pos : self._clipText().length;
|
|
804
|
+
|
|
805
|
+
// clear the place holder
|
|
806
|
+
if (self._placeHolder === self._value) {
|
|
807
|
+
self._value = '';
|
|
808
|
+
self._hiddenInput.value = '';
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
self._cursor = true;
|
|
812
|
+
|
|
813
|
+
// setup cursor interval
|
|
814
|
+
if (self._cursorInterval) {
|
|
815
|
+
clearInterval(self._cursorInterval);
|
|
816
|
+
}
|
|
817
|
+
self._cursorInterval = setInterval(function() {
|
|
818
|
+
self._cursor = !self._cursor;
|
|
819
|
+
self.render();
|
|
820
|
+
}, 500);
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
// move the real focus to the hidden input
|
|
824
|
+
var hasSelection = (self._selection[0] > 0 || self._selection[1] > 0);
|
|
825
|
+
self._hiddenInput.focus();
|
|
826
|
+
self._hiddenInput.selectionStart = hasSelection ? self._selection[0] : self._cursorPos;
|
|
827
|
+
self._hiddenInput.selectionEnd = hasSelection ? self._selection[1] : self._cursorPos;
|
|
828
|
+
|
|
829
|
+
return self.render();
|
|
830
|
+
},
|
|
831
|
+
|
|
832
|
+
/**
|
|
833
|
+
* Removes focus from the CanvasInput box.
|
|
834
|
+
* @param {Object} _this Reference to this.
|
|
835
|
+
* @return {CanvasInput}
|
|
836
|
+
*/
|
|
837
|
+
blur: function(_this) {
|
|
838
|
+
var self = _this || this;
|
|
839
|
+
|
|
840
|
+
self._onblur(self);
|
|
841
|
+
|
|
842
|
+
if (self._cursorInterval) {
|
|
843
|
+
clearInterval(self._cursorInterval);
|
|
844
|
+
}
|
|
845
|
+
self._hasFocus = false;
|
|
846
|
+
self._cursor = false;
|
|
847
|
+
self._selection = [0, 0];
|
|
848
|
+
self._hiddenInput.blur();
|
|
849
|
+
|
|
850
|
+
// fill the place holder
|
|
851
|
+
if (self._value === '') {
|
|
852
|
+
self._value = self._placeHolder;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
return self.render();
|
|
856
|
+
},
|
|
857
|
+
|
|
858
|
+
/**
|
|
859
|
+
* Fired with the keydown event to draw the typed characters.
|
|
860
|
+
* @param {Event} e The keydown event.
|
|
861
|
+
* @param {CanvasInput} self
|
|
862
|
+
* @return {CanvasInput}
|
|
863
|
+
*/
|
|
864
|
+
keydown: function(e, self) {
|
|
865
|
+
var keyCode = e.which,
|
|
866
|
+
isShift = e.shiftKey,
|
|
867
|
+
key = null,
|
|
868
|
+
startText, endText;
|
|
869
|
+
|
|
870
|
+
// make sure the correct text field is being updated
|
|
871
|
+
if (self._readonly || !self._hasFocus) {
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
// fire custom user event
|
|
876
|
+
self._onkeydown(e, self);
|
|
877
|
+
|
|
878
|
+
// add support for Ctrl/Cmd+A selection
|
|
879
|
+
if (keyCode === 65 && (e.ctrlKey || e.metaKey)) {
|
|
880
|
+
self.selectText();
|
|
881
|
+
e.preventDefault();
|
|
882
|
+
return self.render();
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
// block keys that shouldn't be processed
|
|
886
|
+
if (keyCode === 17 || e.metaKey || e.ctrlKey) {
|
|
887
|
+
return self;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
if (keyCode === 13) { // enter key
|
|
891
|
+
e.preventDefault();
|
|
892
|
+
self._onsubmit(e, self);
|
|
893
|
+
} else if (keyCode === 9) { // tab key
|
|
894
|
+
e.preventDefault();
|
|
895
|
+
if (inputs.length > 1) {
|
|
896
|
+
var next = (inputs[self._inputsIndex + 1]) ? self._inputsIndex + 1 : 0;
|
|
897
|
+
self.blur();
|
|
898
|
+
setTimeout(function() {
|
|
899
|
+
inputs[next].focus();
|
|
900
|
+
}, 10);
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
// update the canvas input state information from the hidden input
|
|
905
|
+
self._value = self._hiddenInput.value;
|
|
906
|
+
self._cursorPos = self._hiddenInput.selectionStart;
|
|
907
|
+
self._selection = [0, 0];
|
|
908
|
+
|
|
909
|
+
return self.render();
|
|
910
|
+
},
|
|
911
|
+
|
|
912
|
+
/**
|
|
913
|
+
* Fired with the click event on the canvas, and puts focus on/off
|
|
914
|
+
* based on where the user clicks.
|
|
915
|
+
* @param {Event} e The click event.
|
|
916
|
+
* @param {CanvasInput} self
|
|
917
|
+
* @return {CanvasInput}
|
|
918
|
+
*/
|
|
919
|
+
click: function(e, self) {
|
|
920
|
+
var mouse = self._mousePos(e),
|
|
921
|
+
x = mouse.x,
|
|
922
|
+
y = mouse.y;
|
|
923
|
+
|
|
924
|
+
if (self._endSelection) {
|
|
925
|
+
delete self._endSelection;
|
|
926
|
+
delete self._selectionUpdated;
|
|
927
|
+
return;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
if (self._canvas && self._overInput(x, y) || !self._canvas) {
|
|
931
|
+
if (self._mouseDown) {
|
|
932
|
+
self._mouseDown = false;
|
|
933
|
+
self.click(e, self);
|
|
934
|
+
return self.focus(self._clickPos(x, y));
|
|
935
|
+
}
|
|
936
|
+
} else {
|
|
937
|
+
return self.blur();
|
|
938
|
+
}
|
|
939
|
+
},
|
|
940
|
+
|
|
941
|
+
/**
|
|
942
|
+
* Fired with the mousemove event to update the default cursor.
|
|
943
|
+
* @param {Event} e The mousemove event.
|
|
944
|
+
* @param {CanvasInput} self
|
|
945
|
+
* @return {CanvasInput}
|
|
946
|
+
*/
|
|
947
|
+
mousemove: function(e, self) {
|
|
948
|
+
var mouse = self._mousePos(e),
|
|
949
|
+
x = mouse.x,
|
|
950
|
+
y = mouse.y,
|
|
951
|
+
isOver = self._overInput(x, y);
|
|
952
|
+
|
|
953
|
+
if (isOver && self._canvas) {
|
|
954
|
+
self._canvas.style.cursor = 'text';
|
|
955
|
+
self._wasOver = true;
|
|
956
|
+
} else if (self._wasOver && self._canvas) {
|
|
957
|
+
self._canvas.style.cursor = 'default';
|
|
958
|
+
self._wasOver = false;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
if (self._hasFocus && self._selectionStart >= 0) {
|
|
962
|
+
var curPos = self._clickPos(x, y),
|
|
963
|
+
start = Math.min(self._selectionStart, curPos),
|
|
964
|
+
end = Math.max(self._selectionStart, curPos);
|
|
965
|
+
|
|
966
|
+
if (!isOver) {
|
|
967
|
+
self._selectionUpdated = true;
|
|
968
|
+
self._endSelection = true;
|
|
969
|
+
delete self._selectionStart;
|
|
970
|
+
self.render();
|
|
971
|
+
return;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
if (self._selection[0] !== start || self._selection[1] !== end) {
|
|
975
|
+
self._selection = [start, end];
|
|
976
|
+
self.render();
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
},
|
|
980
|
+
|
|
981
|
+
/**
|
|
982
|
+
* Fired with the mousedown event to start a selection drag.
|
|
983
|
+
* @param {Event} e The mousedown event.
|
|
984
|
+
* @param {CanvasInput} self
|
|
985
|
+
*/
|
|
986
|
+
mousedown: function(e, self) {
|
|
987
|
+
var mouse = self._mousePos(e),
|
|
988
|
+
x = mouse.x,
|
|
989
|
+
y = mouse.y,
|
|
990
|
+
isOver = self._overInput(x, y);
|
|
991
|
+
|
|
992
|
+
// setup the 'click' event
|
|
993
|
+
self._mouseDown = isOver;
|
|
994
|
+
|
|
995
|
+
// start the selection drag if inside the input
|
|
996
|
+
if (self._hasFocus && isOver) {
|
|
997
|
+
self._selectionStart = self._clickPos(x, y);
|
|
998
|
+
}
|
|
999
|
+
},
|
|
1000
|
+
|
|
1001
|
+
/**
|
|
1002
|
+
* Fired with the mouseup event to end a selection drag.
|
|
1003
|
+
* @param {Event} e The mouseup event.
|
|
1004
|
+
* @param {CanvasInput} self
|
|
1005
|
+
*/
|
|
1006
|
+
mouseup: function(e, self) {
|
|
1007
|
+
var mouse = self._mousePos(e),
|
|
1008
|
+
x = mouse.x,
|
|
1009
|
+
y = mouse.y;
|
|
1010
|
+
|
|
1011
|
+
// update selection if a drag has happened
|
|
1012
|
+
var isSelection = self._clickPos(x, y) !== self._selectionStart;
|
|
1013
|
+
if (self._hasFocus && self._selectionStart >= 0 && self._overInput(x, y) && isSelection) {
|
|
1014
|
+
self._selectionUpdated = true;
|
|
1015
|
+
delete self._selectionStart;
|
|
1016
|
+
self.render();
|
|
1017
|
+
} else {
|
|
1018
|
+
delete self._selectionStart;
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
self.click(e, self);
|
|
1022
|
+
},
|
|
1023
|
+
|
|
1024
|
+
/**
|
|
1025
|
+
* Select a range of text in the input.
|
|
1026
|
+
* @param {Array} range (optional) Leave blank to select all. Format: [start, end]
|
|
1027
|
+
* @return {CanvasInput}
|
|
1028
|
+
*/
|
|
1029
|
+
selectText: function(range) {
|
|
1030
|
+
var self = this,
|
|
1031
|
+
range = range || [0, self._value.length];
|
|
1032
|
+
|
|
1033
|
+
// select the range of text specified (or all if none specified)
|
|
1034
|
+
setTimeout(function() {
|
|
1035
|
+
self._selection = [range[0], range[1]];
|
|
1036
|
+
self._hiddenInput.selectionStart = range[0];
|
|
1037
|
+
self._hiddenInput.selectionEnd = range[1];
|
|
1038
|
+
self.render();
|
|
1039
|
+
}, 1);
|
|
1040
|
+
|
|
1041
|
+
return self;
|
|
1042
|
+
},
|
|
1043
|
+
|
|
1044
|
+
/**
|
|
1045
|
+
* Helper method to get the off-DOM canvas.
|
|
1046
|
+
* @return {Object} Reference to the canvas.
|
|
1047
|
+
*/
|
|
1048
|
+
renderCanvas: function() {
|
|
1049
|
+
return this._renderCanvas;
|
|
1050
|
+
},
|
|
1051
|
+
|
|
1052
|
+
/**
|
|
1053
|
+
* Clears and redraws the CanvasInput on an off-DOM canvas,
|
|
1054
|
+
* and if a main canvas is provided, draws it all onto that.
|
|
1055
|
+
* @return {CanvasInput}
|
|
1056
|
+
*/
|
|
1057
|
+
render: function() {
|
|
1058
|
+
var self = this,
|
|
1059
|
+
ctx = self._renderCtx,
|
|
1060
|
+
w = self.outerW,
|
|
1061
|
+
h = self.outerH,
|
|
1062
|
+
br = self._borderRadius,
|
|
1063
|
+
bw = self._borderWidth,
|
|
1064
|
+
sw = self.shadowW,
|
|
1065
|
+
sh = self.shadowH;
|
|
1066
|
+
|
|
1067
|
+
if (!ctx) {
|
|
1068
|
+
return;
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
// clear the canvas
|
|
1072
|
+
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
|
1073
|
+
|
|
1074
|
+
// setup the box shadow
|
|
1075
|
+
ctx.shadowOffsetX = self._boxShadow.x;
|
|
1076
|
+
ctx.shadowOffsetY = self._boxShadow.y;
|
|
1077
|
+
ctx.shadowBlur = self._boxShadow.blur;
|
|
1078
|
+
ctx.shadowColor = self._boxShadow.color;
|
|
1079
|
+
|
|
1080
|
+
// draw the border
|
|
1081
|
+
if (self._borderWidth > 0) {
|
|
1082
|
+
ctx.fillStyle = self._borderColor;
|
|
1083
|
+
self._roundedRect(ctx, self.shadowL, self.shadowT, w - sw, h - sh, br);
|
|
1084
|
+
ctx.fill();
|
|
1085
|
+
|
|
1086
|
+
ctx.shadowOffsetX = 0;
|
|
1087
|
+
ctx.shadowOffsetY = 0;
|
|
1088
|
+
ctx.shadowBlur = 0;
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
// draw the text box background
|
|
1092
|
+
self._drawTextBox(function() {
|
|
1093
|
+
// make sure all shadows are reset
|
|
1094
|
+
ctx.shadowOffsetX = 0;
|
|
1095
|
+
ctx.shadowOffsetY = 0;
|
|
1096
|
+
ctx.shadowBlur = 0;
|
|
1097
|
+
|
|
1098
|
+
// clip the text so that it fits within the box
|
|
1099
|
+
var text = self._clipText();
|
|
1100
|
+
|
|
1101
|
+
// draw the selection
|
|
1102
|
+
var paddingBorder = self._padding + self._borderWidth + self.shadowT;
|
|
1103
|
+
if (self._selection[1] > 0) {
|
|
1104
|
+
var selectOffset = self._textWidth(text.substring(0, self._selection[0])),
|
|
1105
|
+
selectWidth = self._textWidth(text.substring(self._selection[0], self._selection[1]));
|
|
1106
|
+
|
|
1107
|
+
ctx.fillStyle = self._selectionColor;
|
|
1108
|
+
ctx.fillRect(paddingBorder + selectOffset, paddingBorder, selectWidth, self._height);
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
// draw the cursor
|
|
1112
|
+
if (self._cursor) {
|
|
1113
|
+
var cursorOffset = self._textWidth(text.substring(0, self._cursorPos));
|
|
1114
|
+
ctx.fillStyle = self._fontColor;
|
|
1115
|
+
ctx.fillRect(paddingBorder + cursorOffset, paddingBorder, 1, self._height);
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
// draw the text
|
|
1119
|
+
var textX = self._padding + self._borderWidth + self.shadowL,
|
|
1120
|
+
textY = Math.round(paddingBorder + self._height / 2);
|
|
1121
|
+
|
|
1122
|
+
// only remove the placeholder text if they have typed something
|
|
1123
|
+
text = (text === '' && self._placeHolder) ? self._placeHolder : text;
|
|
1124
|
+
|
|
1125
|
+
ctx.fillStyle = (self._value !== '' && self._value !== self._placeHolder) ? self._fontColor : self._placeHolderColor;
|
|
1126
|
+
ctx.font = self._fontStyle + ' ' + self._fontWeight + ' ' + self._fontSize + 'px ' + self._fontFamily;
|
|
1127
|
+
ctx.shadowColor = self._fontShadowColor;
|
|
1128
|
+
ctx.shadowBlur = self._fontShadowBlur;
|
|
1129
|
+
ctx.shadowOffsetX = self._fontShadowOffsetX;
|
|
1130
|
+
ctx.shadowOffsetY = self._fontShadowOffsetY;
|
|
1131
|
+
ctx.textAlign = 'left';
|
|
1132
|
+
ctx.textBaseline = 'middle';
|
|
1133
|
+
ctx.fillText(text, textX, textY);
|
|
1134
|
+
|
|
1135
|
+
// parse inner shadow
|
|
1136
|
+
var innerShadow = self._innerShadow.split('px '),
|
|
1137
|
+
isOffsetX = self._innerShadow === 'none' ? 0 : parseInt(innerShadow[0], 10),
|
|
1138
|
+
isOffsetY = self._innerShadow === 'none' ? 0 : parseInt(innerShadow[1], 10),
|
|
1139
|
+
isBlur = self._innerShadow === 'none' ? 0 : parseInt(innerShadow[2], 10),
|
|
1140
|
+
isColor = self._innerShadow === 'none' ? '' : innerShadow[3];
|
|
1141
|
+
|
|
1142
|
+
// draw the inner-shadow (damn you canvas, this should be easier than this...)
|
|
1143
|
+
if (isBlur > 0) {
|
|
1144
|
+
var shadowCtx = self._shadowCtx,
|
|
1145
|
+
scw = shadowCtx.canvas.width,
|
|
1146
|
+
sch = shadowCtx.canvas.height;
|
|
1147
|
+
|
|
1148
|
+
shadowCtx.clearRect(0, 0, scw, sch);
|
|
1149
|
+
shadowCtx.shadowBlur = isBlur;
|
|
1150
|
+
shadowCtx.shadowColor = isColor;
|
|
1151
|
+
|
|
1152
|
+
// top shadow
|
|
1153
|
+
shadowCtx.shadowOffsetX = 0;
|
|
1154
|
+
shadowCtx.shadowOffsetY = isOffsetY;
|
|
1155
|
+
shadowCtx.fillRect(-1 * w, -100, 3 * w, 100);
|
|
1156
|
+
|
|
1157
|
+
// right shadow
|
|
1158
|
+
shadowCtx.shadowOffsetX = isOffsetX;
|
|
1159
|
+
shadowCtx.shadowOffsetY = 0;
|
|
1160
|
+
shadowCtx.fillRect(scw, -1 * h, 100, 3 * h);
|
|
1161
|
+
|
|
1162
|
+
// bottom shadow
|
|
1163
|
+
shadowCtx.shadowOffsetX = 0;
|
|
1164
|
+
shadowCtx.shadowOffsetY = isOffsetY;
|
|
1165
|
+
shadowCtx.fillRect(-1 * w, sch, 3 * w, 100);
|
|
1166
|
+
|
|
1167
|
+
// left shadow
|
|
1168
|
+
shadowCtx.shadowOffsetX = isOffsetX;
|
|
1169
|
+
shadowCtx.shadowOffsetY = 0;
|
|
1170
|
+
shadowCtx.fillRect(-100, -1 * h, 100, 3 * h);
|
|
1171
|
+
|
|
1172
|
+
// create a clipping mask on the main canvas
|
|
1173
|
+
self._roundedRect(ctx, bw + self.shadowL, bw + self.shadowT, w - bw * 2 - sw, h - bw * 2 - sh, br);
|
|
1174
|
+
ctx.clip();
|
|
1175
|
+
|
|
1176
|
+
// draw the inner-shadow from the off-DOM canvas
|
|
1177
|
+
ctx.drawImage(self._shadowCanvas, 0, 0, scw, sch, bw + self.shadowL, bw + self.shadowT, scw, sch);
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
// draw to the visible canvas
|
|
1181
|
+
if (self._ctx) {
|
|
1182
|
+
self._ctx.clearRect(self._x, self._y, ctx.canvas.width, ctx.canvas.height);
|
|
1183
|
+
self._ctx.drawImage(self._renderCanvas, self._x, self._y);
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
return self;
|
|
1187
|
+
|
|
1188
|
+
});
|
|
1189
|
+
},
|
|
1190
|
+
|
|
1191
|
+
/**
|
|
1192
|
+
* Destroy this input and stop rendering it.
|
|
1193
|
+
*/
|
|
1194
|
+
destroy: function() {
|
|
1195
|
+
var self = this;
|
|
1196
|
+
|
|
1197
|
+
// pull from the inputs array
|
|
1198
|
+
var index = inputs.indexOf(self);
|
|
1199
|
+
if (index != -1) {
|
|
1200
|
+
inputs.splice(index, 1);
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
// remove focus
|
|
1204
|
+
if (self._hasFocus) {
|
|
1205
|
+
self.blur();
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
// remove the hidden input box
|
|
1209
|
+
document.body.removeChild(self._hiddenInput);
|
|
1210
|
+
|
|
1211
|
+
// remove off-DOM canvas
|
|
1212
|
+
self._renderCanvas = null;
|
|
1213
|
+
self._shadowCanvas = null;
|
|
1214
|
+
self._renderCtx = null;
|
|
1215
|
+
},
|
|
1216
|
+
|
|
1217
|
+
/**
|
|
1218
|
+
* Draw the text box area with either an image or background color.
|
|
1219
|
+
* @param {Function} fn Callback.
|
|
1220
|
+
*/
|
|
1221
|
+
_drawTextBox: function(fn) {
|
|
1222
|
+
var self = this,
|
|
1223
|
+
ctx = self._renderCtx,
|
|
1224
|
+
w = self.outerW,
|
|
1225
|
+
h = self.outerH,
|
|
1226
|
+
br = self._borderRadius,
|
|
1227
|
+
bw = self._borderWidth,
|
|
1228
|
+
sw = self.shadowW,
|
|
1229
|
+
sh = self.shadowH;
|
|
1230
|
+
|
|
1231
|
+
// only draw the background shape if no image is being used
|
|
1232
|
+
if (self._backgroundImage === '') {
|
|
1233
|
+
ctx.fillStyle = self._backgroundColor;
|
|
1234
|
+
self._roundedRect(ctx, bw + self.shadowL, bw + self.shadowT, w - bw * 2 - sw, h - bw * 2 - sh, br);
|
|
1235
|
+
ctx.fill();
|
|
1236
|
+
|
|
1237
|
+
fn();
|
|
1238
|
+
} else {
|
|
1239
|
+
var img = new Image();
|
|
1240
|
+
img.src = self._backgroundImage;
|
|
1241
|
+
img.onload = function() {
|
|
1242
|
+
ctx.drawImage(img, 0, 0, img.width, img.height, bw + self.shadowL, bw + self.shadowT, w, h);
|
|
1243
|
+
|
|
1244
|
+
fn();
|
|
1245
|
+
};
|
|
1246
|
+
}
|
|
1247
|
+
},
|
|
1248
|
+
|
|
1249
|
+
/**
|
|
1250
|
+
* Deletes selected text in selection range and repositions cursor.
|
|
1251
|
+
* @return {Boolean} true if text removed.
|
|
1252
|
+
*/
|
|
1253
|
+
_clearSelection: function() {
|
|
1254
|
+
var self = this;
|
|
1255
|
+
|
|
1256
|
+
if (self._selection[1] > 0) {
|
|
1257
|
+
// clear the selected contents
|
|
1258
|
+
var start = self._selection[0],
|
|
1259
|
+
end = self._selection[1];
|
|
1260
|
+
|
|
1261
|
+
self._value = self._value.substr(0, start) + self._value.substr(end);
|
|
1262
|
+
self._cursorPos = start;
|
|
1263
|
+
self._cursorPos = (self._cursorPos < 0) ? 0 : self._cursorPos;
|
|
1264
|
+
self._selection = [0, 0];
|
|
1265
|
+
|
|
1266
|
+
return true;
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
return false;
|
|
1270
|
+
},
|
|
1271
|
+
|
|
1272
|
+
/**
|
|
1273
|
+
* Clip the text string to only return what fits in the visible text box.
|
|
1274
|
+
* @param {String} value The text to clip.
|
|
1275
|
+
* @return {String} The clipped text.
|
|
1276
|
+
*/
|
|
1277
|
+
_clipText: function(value) {
|
|
1278
|
+
var self = this;
|
|
1279
|
+
value = (typeof value === 'undefined') ? self._value : value;
|
|
1280
|
+
|
|
1281
|
+
var textWidth = self._textWidth(value),
|
|
1282
|
+
fillPer = textWidth / (self._width - self._padding),
|
|
1283
|
+
text = fillPer > 1 ? value.substr(-1 * Math.floor(value.length / fillPer)) : value;
|
|
1284
|
+
|
|
1285
|
+
return text + '';
|
|
1286
|
+
},
|
|
1287
|
+
|
|
1288
|
+
/**
|
|
1289
|
+
* Gets the pixel with of passed text.
|
|
1290
|
+
* @param {String} text The text to measure.
|
|
1291
|
+
* @return {Number} The measured width.
|
|
1292
|
+
*/
|
|
1293
|
+
_textWidth: function(text) {
|
|
1294
|
+
var self = this,
|
|
1295
|
+
ctx = self._renderCtx;
|
|
1296
|
+
|
|
1297
|
+
ctx.font = self._fontStyle + ' ' + self._fontWeight + ' ' + self._fontSize + 'px ' + self._fontFamily;
|
|
1298
|
+
ctx.textAlign = 'left';
|
|
1299
|
+
|
|
1300
|
+
return ctx.measureText(text).width;
|
|
1301
|
+
},
|
|
1302
|
+
|
|
1303
|
+
/**
|
|
1304
|
+
* Recalculate the outer with and height of the text box.
|
|
1305
|
+
*/
|
|
1306
|
+
_calcWH: function() {
|
|
1307
|
+
var self = this;
|
|
1308
|
+
|
|
1309
|
+
// calculate the full width and height with padding, borders and shadows
|
|
1310
|
+
self.outerW = self._width + self._padding * 2 + self._borderWidth * 2 + self.shadowW;
|
|
1311
|
+
self.outerH = self._height + self._padding * 2 + self._borderWidth * 2 + self.shadowH;
|
|
1312
|
+
},
|
|
1313
|
+
|
|
1314
|
+
/**
|
|
1315
|
+
* Update the width and height of the off-DOM canvas when attributes are changed.
|
|
1316
|
+
*/
|
|
1317
|
+
_updateCanvasWH: function() {
|
|
1318
|
+
var self = this,
|
|
1319
|
+
oldW = self._renderCanvas.width,
|
|
1320
|
+
oldH = self._renderCanvas.height;
|
|
1321
|
+
|
|
1322
|
+
// update off-DOM canvas
|
|
1323
|
+
self._renderCanvas.setAttribute('width', self.outerW);
|
|
1324
|
+
self._renderCanvas.setAttribute('height', self.outerH);
|
|
1325
|
+
self._shadowCanvas.setAttribute('width', self._width + self._padding * 2);
|
|
1326
|
+
self._shadowCanvas.setAttribute('height', self._height + self._padding * 2);
|
|
1327
|
+
|
|
1328
|
+
// clear the main canvas
|
|
1329
|
+
if (self._ctx) {
|
|
1330
|
+
self._ctx.clearRect(self._x, self._y, oldW, oldH);
|
|
1331
|
+
}
|
|
1332
|
+
},
|
|
1333
|
+
|
|
1334
|
+
/**
|
|
1335
|
+
* Update the size and position of the hidden input (better UX on mobile).
|
|
1336
|
+
*/
|
|
1337
|
+
_updateHiddenInput: function() {
|
|
1338
|
+
var self = this;
|
|
1339
|
+
|
|
1340
|
+
self._hiddenInput.style.left = (self._x + self._extraX + (self._canvas ? self._canvas.offsetLeft : 0)) + 'px';
|
|
1341
|
+
self._hiddenInput.style.top = (self._y + self._extraY + (self._canvas ? self._canvas.offsetTop : 0)) + 'px';
|
|
1342
|
+
self._hiddenInput.style.width = (self._width + self._padding * 2) + 'px';
|
|
1343
|
+
self._hiddenInput.style.height = (self._height + self._padding * 2) + 'px';
|
|
1344
|
+
},
|
|
1345
|
+
|
|
1346
|
+
/**
|
|
1347
|
+
* Creates the path for a rectangle with rounded corners.
|
|
1348
|
+
* Must call ctx.fill() after calling this to draw the rectangle.
|
|
1349
|
+
* @param {Object} ctx Canvas context.
|
|
1350
|
+
* @param {Number} x x-coordinate to draw from.
|
|
1351
|
+
* @param {Number} y y-coordinate to draw from.
|
|
1352
|
+
* @param {Number} w Width of rectangle.
|
|
1353
|
+
* @param {Number} h Height of rectangle.
|
|
1354
|
+
* @param {Number} r Border radius.
|
|
1355
|
+
*/
|
|
1356
|
+
_roundedRect: function(ctx, x, y, w, h, r) {
|
|
1357
|
+
if (w < 2 * r) r = w / 2;
|
|
1358
|
+
if (h < 2 * r) r = h / 2;
|
|
1359
|
+
|
|
1360
|
+
ctx.beginPath();
|
|
1361
|
+
|
|
1362
|
+
ctx.moveTo(x + r, y);
|
|
1363
|
+
ctx.lineTo(x + w - r, y);
|
|
1364
|
+
ctx.quadraticCurveTo(x + w, y, x + w, y + r);
|
|
1365
|
+
ctx.lineTo(x + w, y + h - r);
|
|
1366
|
+
ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
|
|
1367
|
+
ctx.lineTo(x + r, y + h);
|
|
1368
|
+
ctx.quadraticCurveTo(x, y + h, x, y + h - r);
|
|
1369
|
+
ctx.lineTo(x, y + r);
|
|
1370
|
+
ctx.quadraticCurveTo(x, y, x + r, y);
|
|
1371
|
+
|
|
1372
|
+
ctx.closePath();
|
|
1373
|
+
},
|
|
1374
|
+
|
|
1375
|
+
/**
|
|
1376
|
+
* Checks if a coordinate point is over the input box.
|
|
1377
|
+
* @param {Number} x x-coordinate position.
|
|
1378
|
+
* @param {Number} y y-coordinate position.
|
|
1379
|
+
* @return {Boolean} True if it is over the input box.
|
|
1380
|
+
*/
|
|
1381
|
+
_overInput: function(x, y) {
|
|
1382
|
+
var self = this,
|
|
1383
|
+
xLeft = x >= self._x + self._extraX,
|
|
1384
|
+
xRight = x <= self._x + self._extraX + self._width + self._padding * 2,
|
|
1385
|
+
yTop = y >= self._y + self._extraY,
|
|
1386
|
+
yBottom = y <= self._y + self._extraY + self._height + self._padding * 2;
|
|
1387
|
+
|
|
1388
|
+
return xLeft && xRight && yTop && yBottom;
|
|
1389
|
+
},
|
|
1390
|
+
|
|
1391
|
+
/**
|
|
1392
|
+
* Use the mouse's x & y coordinates to determine
|
|
1393
|
+
* the position clicked in the text.
|
|
1394
|
+
* @param {Number} x X-coordinate.
|
|
1395
|
+
* @param {Number} y Y-coordinate.
|
|
1396
|
+
* @return {Number} Cursor position.
|
|
1397
|
+
*/
|
|
1398
|
+
_clickPos: function(x, y) {
|
|
1399
|
+
var self = this,
|
|
1400
|
+
value = self._value;
|
|
1401
|
+
|
|
1402
|
+
// don't count placeholder text in this
|
|
1403
|
+
if (self._value === self._placeHolder) {
|
|
1404
|
+
value = '';
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
// determine where the click was made along the string
|
|
1408
|
+
var text = self._clipText(value),
|
|
1409
|
+
totalW = 0,
|
|
1410
|
+
pos = text.length;
|
|
1411
|
+
|
|
1412
|
+
if (x - (self._x + self._extraX) < self._textWidth(text)) {
|
|
1413
|
+
// loop through each character to identify the position
|
|
1414
|
+
for (var i=0; i<text.length; i++) {
|
|
1415
|
+
totalW += self._textWidth(text[i]);
|
|
1416
|
+
if (totalW >= x - (self._x + self._extraX)) {
|
|
1417
|
+
pos = i;
|
|
1418
|
+
break;
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
return pos;
|
|
1424
|
+
},
|
|
1425
|
+
|
|
1426
|
+
/**
|
|
1427
|
+
* Calculate the mouse position based on the event callback and the elements on the page.
|
|
1428
|
+
* @param {Event} e
|
|
1429
|
+
* @return {Object} x & y values
|
|
1430
|
+
*/
|
|
1431
|
+
_mousePos: function(e) {
|
|
1432
|
+
var elm = e.target,
|
|
1433
|
+
x = e.pageX,
|
|
1434
|
+
y = e.pageY;
|
|
1435
|
+
|
|
1436
|
+
// support touch events in page location calculation
|
|
1437
|
+
if (e.touches && e.touches.length) {
|
|
1438
|
+
elm = e.touches[0].target;
|
|
1439
|
+
x = e.touches[0].pageX;
|
|
1440
|
+
y = e.touches[0].pageY;
|
|
1441
|
+
} else if (e.changedTouches && e.changedTouches.length) {
|
|
1442
|
+
elm = e.changedTouches[0].target;
|
|
1443
|
+
x = e.changedTouches[0].pageX;
|
|
1444
|
+
y = e.changedTouches[0].pageY;
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
var style = document.defaultView.getComputedStyle(elm, undefined),
|
|
1448
|
+
paddingLeft = parseInt(style['paddingLeft'], 10) || 0,
|
|
1449
|
+
paddingTop = parseInt(style['paddingLeft'], 10) || 0,
|
|
1450
|
+
borderLeft = parseInt(style['borderLeftWidth'], 10) || 0,
|
|
1451
|
+
borderTop = parseInt(style['borderLeftWidth'], 10) || 0,
|
|
1452
|
+
htmlTop = document.body.parentNode.offsetTop || 0,
|
|
1453
|
+
htmlLeft = document.body.parentNode.offsetLeft || 0,
|
|
1454
|
+
offsetX = 0,
|
|
1455
|
+
offsetY = 0;
|
|
1456
|
+
|
|
1457
|
+
// calculate the total offset
|
|
1458
|
+
if (typeof elm.offsetParent !== 'undefined') {
|
|
1459
|
+
do {
|
|
1460
|
+
offsetX += elm.offsetLeft;
|
|
1461
|
+
offsetY += elm.offsetTop;
|
|
1462
|
+
} while ((elm = elm.offsetParent));
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
// take into account borders and padding
|
|
1466
|
+
offsetX += paddingLeft + borderLeft + htmlLeft;
|
|
1467
|
+
offsetY += paddingTop + borderTop + htmlTop;
|
|
1468
|
+
|
|
1469
|
+
return {
|
|
1470
|
+
x: x - offsetX,
|
|
1471
|
+
y: y - offsetY
|
|
1472
|
+
};
|
|
1473
|
+
}
|
|
1474
|
+
};
|
|
1475
|
+
})();
|