1 var Text, Tool, createShape, getIsPointInBox,
2 extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
3 hasProp = {}.hasOwnProperty;
5 Tool = require('./base').Tool;
7 createShape = require('../core/shapes').createShape;
9 getIsPointInBox = function(point, box) {
10 if (point.x < box.x) {
13 if (point.y < box.y) {
16 if (point.x > box.x + box.width) {
19 if (point.y > box.y + box.height) {
25 module.exports = Text = (function(superClass) {
26 extend(Text, superClass);
28 Text.prototype.name = 'Text';
30 Text.prototype.iconName = 'text';
34 this.font = 'bold 18px sans-serif';
35 this.currentShape = null;
36 this.currentShapeState = null;
37 this.initialShapeBoundingRect = null;
38 this.dragAction = null;
42 Text.prototype.didBecomeActive = function(lc) {
43 var switchAway, unsubscribeFuncs, updateInputEl;
44 unsubscribeFuncs = [];
45 this.unsubscribe = (function(_this) {
47 var func, i, len, results;
49 for (i = 0, len = unsubscribeFuncs.length; i < len; i++) {
50 func = unsubscribeFuncs[i];
56 switchAway = (function(_this) {
58 _this._ensureNotEditing(lc);
59 _this._clearCurrentShape(lc);
60 return lc.repaintLayer('main');
63 updateInputEl = (function(_this) {
65 return _this._updateInputEl(lc);
68 unsubscribeFuncs.push(lc.on('drawingChange', switchAway));
69 unsubscribeFuncs.push(lc.on('zoom', updateInputEl));
70 unsubscribeFuncs.push(lc.on('imageSizeChange', updateInputEl));
71 unsubscribeFuncs.push(lc.on('snapshotLoad', (function(_this) {
73 _this._clearCurrentShape(lc);
74 return lc.repaintLayer('main');
77 unsubscribeFuncs.push(lc.on('primaryColorChange', (function(_this) {
78 return function(newColor) {
79 if (!_this.currentShape) {
82 _this.currentShape.color = newColor;
83 _this._updateInputEl(lc);
84 return lc.repaintLayer('main');
87 return unsubscribeFuncs.push(lc.on('setFont', (function(_this) {
88 return function(font) {
89 if (!_this.currentShape) {
93 _this.currentShape.setFont(font);
94 _this._setShapesInProgress(lc);
95 _this._updateInputEl(lc);
96 return lc.repaintLayer('main');
101 Text.prototype.willBecomeInactive = function(lc) {
102 if (this.currentShape) {
103 this._ensureNotEditing(lc);
106 return this.unsubscribe();
109 Text.prototype.setText = function(text) {
110 return this.text = text;
113 Text.prototype._ensureNotEditing = function(lc) {
114 if (this.currentShapeState === 'editing') {
115 return this._exitEditingState(lc);
119 Text.prototype._clearCurrentShape = function(lc) {
120 this.currentShape = null;
121 this.initialShapeBoundingRect = null;
122 this.currentShapeState = null;
123 return lc.setShapesInProgress([]);
126 Text.prototype.commit = function(lc) {
127 if (this.currentShape.text) {
128 lc.saveShape(this.currentShape);
130 this._clearCurrentShape(lc);
131 return lc.repaintLayer('main');
134 Text.prototype._getSelectionShape = function(ctx, backgroundColor) {
135 if (backgroundColor == null) {
136 backgroundColor = null;
138 return createShape('SelectionBox', {
139 shape: this.currentShape,
141 backgroundColor: backgroundColor
145 Text.prototype._setShapesInProgress = function(lc) {
146 switch (this.currentShapeState) {
148 return lc.setShapesInProgress([this._getSelectionShape(lc.ctx), this.currentShape]);
150 return lc.setShapesInProgress([this._getSelectionShape(lc.ctx, '#fff')]);
152 return lc.setShapesInProgress([this.currentShape]);
156 Text.prototype.begin = function(x, y, lc) {
157 var br, point, selectionBox, selectionShape;
158 this.dragAction = 'none';
159 this.didDrag = false;
160 if (this.currentShapeState === 'selected' || this.currentShapeState === 'editing') {
161 br = this.currentShape.getBoundingRect(lc.ctx);
162 selectionShape = this._getSelectionShape(lc.ctx);
163 selectionBox = selectionShape.getBoundingRect();
168 if (getIsPointInBox(point, br)) {
169 this.dragAction = 'move';
171 if (getIsPointInBox(point, selectionShape.getBottomRightHandleRect())) {
172 this.dragAction = 'resizeBottomRight';
174 if (getIsPointInBox(point, selectionShape.getTopLeftHandleRect())) {
175 this.dragAction = 'resizeTopLeft';
177 if (getIsPointInBox(point, selectionShape.getBottomLeftHandleRect())) {
178 this.dragAction = 'resizeBottomLeft';
180 if (getIsPointInBox(point, selectionShape.getTopRightHandleRect())) {
181 this.dragAction = 'resizeTopRight';
183 if (this.dragAction === 'none' && this.currentShapeState === 'editing') {
184 this.dragAction = 'stop-editing';
185 this._exitEditingState(lc);
188 this.color = lc.getColor('primary');
189 this.currentShape = createShape('Text', {
197 this.dragAction = 'place';
198 this.currentShapeState = 'selected';
200 if (this.dragAction === 'none') {
204 this.initialShapeBoundingRect = this.currentShape.getBoundingRect(lc.ctx);
206 x: x - this.initialShapeBoundingRect.x,
207 y: y - this.initialShapeBoundingRect.y
209 this._setShapesInProgress(lc);
210 return lc.repaintLayer('main');
213 Text.prototype["continue"] = function(x, y, lc) {
214 var br, brBottom, brRight;
215 if (this.dragAction === 'none') {
218 br = this.initialShapeBoundingRect;
219 brRight = br.x + br.width;
220 brBottom = br.y + br.height;
221 switch (this.dragAction) {
223 this.currentShape.x = x;
224 this.currentShape.y = y;
228 this.currentShape.x = x - this.dragOffset.x;
229 this.currentShape.y = y - this.dragOffset.y;
232 case 'resizeBottomRight':
233 this.currentShape.setSize(x - (this.dragOffset.x - this.initialShapeBoundingRect.width) - br.x, y - (this.dragOffset.y - this.initialShapeBoundingRect.height) - br.y);
235 case 'resizeTopLeft':
236 this.currentShape.setSize(brRight - x + this.dragOffset.x, brBottom - y + this.dragOffset.y);
237 this.currentShape.setPosition(x - this.dragOffset.x, y - this.dragOffset.y);
239 case 'resizeBottomLeft':
240 this.currentShape.setSize(brRight - x + this.dragOffset.x, y - (this.dragOffset.y - this.initialShapeBoundingRect.height) - br.y);
241 this.currentShape.setPosition(x - this.dragOffset.x, this.currentShape.y);
243 case 'resizeTopRight':
244 this.currentShape.setSize(x - (this.dragOffset.x - this.initialShapeBoundingRect.width) - br.x, brBottom - y + this.dragOffset.y);
245 this.currentShape.setPosition(this.currentShape.x, y - this.dragOffset.y);
247 this._setShapesInProgress(lc);
248 lc.repaintLayer('main');
249 return this._updateInputEl(lc);
252 Text.prototype.end = function(x, y, lc) {
253 if (!this.currentShape) {
256 this.currentShape.setSize(this.currentShape.forcedWidth, 0);
257 if (this.currentShapeState === 'selected') {
258 if (this.dragAction === 'place' || (this.dragAction === 'move' && !this.didDrag)) {
259 this._enterEditingState(lc);
262 this._setShapesInProgress(lc);
263 lc.repaintLayer('main');
264 return this._updateInputEl(lc);
267 Text.prototype._enterEditingState = function(lc) {
269 this.currentShapeState = 'editing';
273 this.inputEl = document.createElement('textarea');
274 this.inputEl.className = 'text-tool-input';
275 this.inputEl.style.position = 'absolute';
276 this.inputEl.style.transformOrigin = '0px 0px';
277 this.inputEl.style.backgroundColor = 'transparent';
278 this.inputEl.style.border = 'none';
279 this.inputEl.style.outline = 'none';
280 this.inputEl.style.margin = '0';
281 this.inputEl.style.padding = '4px';
282 this.inputEl.style.zIndex = '1000';
283 this.inputEl.style.overflow = 'hidden';
284 this.inputEl.style.resize = 'none';
285 this.inputEl.value = this.currentShape.text;
286 this.inputEl.addEventListener('mousedown', function(e) {
287 return e.stopPropagation();
289 this.inputEl.addEventListener('touchstart', function(e) {
290 return e.stopPropagation();
292 onChange = (function(_this) {
294 _this.currentShape.setText(e.target.value);
295 _this.currentShape.enforceMaxBoundingRect(lc);
296 _this._setShapesInProgress(lc);
297 lc.repaintLayer('main');
298 _this._updateInputEl(lc);
299 return e.stopPropagation();
302 this.inputEl.addEventListener('keydown', (function(_this) {
304 return _this._updateInputEl(lc, true);
307 this.inputEl.addEventListener('keyup', onChange);
308 this.inputEl.addEventListener('change', onChange);
309 this._updateInputEl(lc);
310 lc.containerEl.appendChild(this.inputEl);
311 this.inputEl.focus();
312 return this._setShapesInProgress(lc);
315 Text.prototype._exitEditingState = function(lc) {
316 this.currentShapeState = 'selected';
317 lc.containerEl.removeChild(this.inputEl);
319 this._setShapesInProgress(lc);
320 return lc.repaintLayer('main');
323 Text.prototype._updateInputEl = function(lc, withMargin) {
324 var br, transformString;
325 if (withMargin == null) {
331 br = this.currentShape.getBoundingRect(lc.ctx, true);
332 this.inputEl.style.font = this.currentShape.font;
333 this.inputEl.style.color = this.currentShape.color;
334 this.inputEl.style.left = (lc.position.x / lc.backingScale + br.x * lc.scale - 4) + "px";
335 this.inputEl.style.top = (lc.position.y / lc.backingScale + br.y * lc.scale - 4) + "px";
336 if (withMargin && !this.currentShape.forcedWidth) {
337 this.inputEl.style.width = (br.width + 10 + this.currentShape.renderer.emDashWidth) + "px";
339 this.inputEl.style.width = (br.width + 12) + "px";
342 this.inputEl.style.height = (br.height + 10 + this.currentShape.renderer.metrics.leading) + "px";
344 this.inputEl.style.height = (br.height + 10) + "px";
346 transformString = "scale(" + lc.scale + ")";
347 this.inputEl.style.transform = transformString;
348 this.inputEl.style.webkitTransform = transformString;
349 this.inputEl.style.MozTransform = transformString;
350 this.inputEl.style.msTransform = transformString;
351 return this.inputEl.style.OTransform = transformString;
354 Text.prototype.optionsStyle = 'font';