1 /**
  2  * @namespace
  3  */
  4 mindmaps.action = {};
  5 
  6 /**
  7  * Creates a new action.
  8  * 
  9  * @constructor
 10  */
 11 mindmaps.action.Action = function() {
 12 };
 13 
 14 mindmaps.action.Action.prototype = {
 15 	/**
 16 	 * Make this action un-undoable.
 17 	 * 
 18 	 * @returns {Action}
 19 	 */
 20 	noUndo : function() {
 21 		delete this.undo;
 22 		delete this.redo;
 23 		return this;
 24 	},
 25 
 26 	/**
 27 	 * Don't emit an event after execution.
 28 	 * 
 29 	 * @returns {Action}
 30 	 */
 31 	noEvent : function() {
 32 		delete this.event;
 33 		return this;
 34 	},
 35 
 36 	/**
 37 	 * Executes this action. Explicitly returning false will cancel this action
 38 	 * and not raise an event or undoable action.
 39 	 * 
 40 	 */
 41 	execute : function() {
 42 	},
 43 
 44 	cancel : function() {
 45 		this.cancelled = true;
 46 	}
 47 };
 48 
 49 /**
 50  * Creates a new MoveNodeAction.
 51  * 
 52  * @constructor
 53  * @augments mindmaps.action.Action
 54  * @param {mindmaps.Node} node
 55  * @param {Point} offset
 56  */
 57 mindmaps.action.MoveNodeAction = function(node, offset) {
 58 	var oldOffset = node.offset;
 59 
 60 	this.execute = function() {
 61 		node.offset = offset;
 62 	};
 63 
 64 	this.event = [ mindmaps.Event.NODE_MOVED, node ];
 65 	this.undo = function() {
 66 		return new mindmaps.action.MoveNodeAction(node, oldOffset);
 67 	};
 68 };
 69 mindmaps.action.MoveNodeAction.prototype = new mindmaps.action.Action();
 70 
 71 /**
 72  * Creates a new DeleteNodeAction.
 73  * 
 74  * @constructor
 75  * @augments mindmaps.action.Action
 76  * @param {mindmaps.Node} node
 77  * @param {mindmaps.MindMap} mindmap
 78  */
 79 mindmaps.action.DeleteNodeAction = function(node, mindmap) {
 80 	var parent = node.getParent();
 81 
 82 	this.execute = function() {
 83 		if (node.isRoot()) {
 84 			return false;
 85 		}
 86 		mindmap.removeNode(node);
 87 	};
 88 
 89 	this.event = [ mindmaps.Event.NODE_DELETED, node, parent ];
 90 	this.undo = function() {
 91 		return new mindmaps.action.CreateNodeAction(node, parent, mindmap);
 92 	};
 93 };
 94 mindmaps.action.DeleteNodeAction.prototype = new mindmaps.action.Action();
 95 
 96 /**
 97  * Creates a new CreateAutoPositionedNodeAction.
 98  * 
 99  * @constructor
100  * @param {mindmaps.Node} parent
101  * @param {mindmaps.MindMap} mindmap
102  * @returns {CreateNodeAction}
103  */
104 mindmaps.action.CreateAutoPositionedNodeAction = function(parent, mindmap) {
105 	if (parent.isRoot()) {
106 		var branchColor = mindmaps.Util.randomColor();
107 
108 		// calculate position
109 		// magic formula
110 		var leftRight = Math.random() > 0.49 ? 1 : -1;
111 		var topBottom = Math.random() > 0.49 ? 1 : -1;
112 		var x = leftRight * (100 + Math.random() * 250);
113 		var y = topBottom * (Math.random() * 250);
114 	} else {
115 		var branchColor = parent.branchColor;
116 
117 		// calculate position
118 		var leftRight = parent.offset.x > 0 ? 1 : -1;
119 		var x = leftRight * (150 + Math.random() * 10);
120 
121 		// put into random height when child nodes are there
122 		if (parent.isLeaf()) {
123 			var max = 5, min = -5;
124 		} else {
125 			var max = 150, min = -150;
126 		}
127 
128 		var y = Math.floor(Math.random() * (max - min + 1) + min);
129 	}
130 	var node = new mindmaps.Node();
131 	node.branchColor = branchColor;
132 	node.shouldEditCaption = true;
133 	node.offset = new mindmaps.Point(x, y);
134 
135 	return new mindmaps.action.CreateNodeAction(node, parent, mindmap);
136 };
137 
138 /**
139  * Creates a new CreateNodeAction.
140  * 
141  * @constructor
142  * @augments mindmaps.action.Action
143  * @param {mindmaps.Node} node
144  * @param {mindmaps.Node} parent
145  * @param {mindmaps.MindMap} mindmap
146  */
147 mindmaps.action.CreateNodeAction = function(node, parent, mindmap) {
148 	this.execute = function() {
149 		mindmap.addNode(node);
150 		parent.addChild(node);
151 	};
152 
153 	this.event = [ mindmaps.Event.NODE_CREATED, node ];
154 	this.undo = function() {
155 		return new mindmaps.action.DeleteNodeAction(node, mindmap);
156 	};
157 };
158 mindmaps.action.CreateNodeAction.prototype = new mindmaps.action.Action();
159 
160 /**
161  * Creates a new ToggleNodeFoldAction.
162  * 
163  * 
164  * @constructor
165  * @param {mindmaps.Node} node
166  * @returns {Action}
167  */
168 mindmaps.action.ToggleNodeFoldAction = function(node) {
169 	if (node.foldChildren) {
170 		return new mindmaps.action.OpenNodeAction(node);
171 	} else {
172 		return new mindmaps.action.CloseNodeAction(node);
173 	}
174 };
175 
176 /**
177  * Creates a new OpenNodeAction.
178  * 
179  * @constructor
180  * @augments mindmaps.action.Action
181  * @param {mindmaps.Node} node
182  */
183 mindmaps.action.OpenNodeAction = function(node) {
184 	this.execute = function() {
185 		node.foldChildren = false;
186 	};
187 
188 	this.event = [ mindmaps.Event.NODE_OPENED, node ];
189 
190 };
191 mindmaps.action.OpenNodeAction.prototype = new mindmaps.action.Action();
192 
193 /**
194  * Creates a new CloseNodeAction.
195  * 
196  * @constructor
197  * @augments mindmaps.action.Action
198  * @param {mindmaps.Node} node
199  */
200 mindmaps.action.CloseNodeAction = function(node) {
201 	this.execute = function() {
202 		node.foldChildren = true;
203 	};
204 
205 	this.event = [ mindmaps.Event.NODE_CLOSED, node ];
206 
207 };
208 mindmaps.action.CloseNodeAction.prototype = new mindmaps.action.Action();
209 
210 /**
211  * Creates a new ChangeNodeCaptionAction.
212  * 
213  * @constructor
214  * @augments mindmaps.action.Action
215  * @param {mindmaps.Node} node
216  * @param {String} caption
217  */
218 mindmaps.action.ChangeNodeCaptionAction = function(node, caption) {
219 	var oldCaption = node.getCaption();
220 
221 	this.execute = function() {
222 		// dont update if nothing has changed
223 		if (oldCaption === caption) {
224 			return false;
225 		}
226 		node.setCaption(caption);
227 	};
228 
229 	this.event = [ mindmaps.Event.NODE_TEXT_CAPTION_CHANGED, node ];
230 	this.undo = function() {
231 		return new mindmaps.action.ChangeNodeCaptionAction(node, oldCaption);
232 	};
233 };
234 mindmaps.action.ChangeNodeCaptionAction.prototype = new mindmaps.action.Action();
235 
236 /**
237  * Creates a new ChageNodeFontSizeAction.
238  * 
239  * @constructor
240  * @augments mindmaps.action.Action
241  * @param {mindmaps.Node} node
242  * @param {Integer} step
243  */
244 mindmaps.action.ChangeNodeFontSizeAction = function(node, step) {
245 	this.execute = function() {
246 		node.text.font.size += step;
247 	};
248 
249 	this.event = [ mindmaps.Event.NODE_FONT_CHANGED, node ];
250 	this.undo = function() {
251 		return new mindmaps.action.ChangeNodeFontSizeAction(node, -step);
252 	};
253 };
254 mindmaps.action.ChangeNodeFontSizeAction.prototype = new mindmaps.action.Action();
255 
256 /**
257  * @constructor
258  * @param {mindmaps.Node} node
259  * @returns {ChangeNodeFontSizeAction}
260  */
261 mindmaps.action.DecreaseNodeFontSizeAction = function(node) {
262 	return new mindmaps.action.ChangeNodeFontSizeAction(node, -4);
263 };
264 
265 /**
266  * @constructor
267  * @param {mindmaps.Node} node
268  * @returns {ChangeNodeFontSizeAction}
269  */
270 mindmaps.action.IncreaseNodeFontSizeAction = function(node) {
271 	return new mindmaps.action.ChangeNodeFontSizeAction(node, 4);
272 };
273 
274 /**
275  * Creates a new SetFontWeightAction.
276  * 
277  * @constructor
278  * @augments mindmaps.action.Action
279  * @param {mindmaps.Node} node
280  * @param {Boolean} bold
281  */
282 mindmaps.action.SetFontWeightAction = function(node, bold) {
283 	this.execute = function() {
284 		var weight = bold ? "bold" : "normal";
285 		node.text.font.weight = weight;
286 	};
287 
288 	this.event = [ mindmaps.Event.NODE_FONT_CHANGED, node ];
289 	this.undo = function() {
290 		return new mindmaps.action.SetFontWeightAction(node, !bold);
291 	};
292 };
293 mindmaps.action.SetFontWeightAction.prototype = new mindmaps.action.Action();
294 
295 /**
296  * Creates a new SetFontStyleAction.
297  * 
298  * @constructor
299  * @augments mindmaps.action.Action
300  * @param {mindmaps.Node} node
301  * @param {Boolean} italic
302  */
303 mindmaps.action.SetFontStyleAction = function(node, italic) {
304 	this.execute = function() {
305 		var style = italic ? "italic" : "normal";
306 		node.text.font.style = style;
307 	};
308 
309 	this.event = [ mindmaps.Event.NODE_FONT_CHANGED, node ];
310 	this.undo = function() {
311 		return new mindmaps.action.SetFontStyleAction(node, !italic);
312 	};
313 };
314 mindmaps.action.SetFontStyleAction.prototype = new mindmaps.action.Action();
315 
316 /**
317  * Creates a new SetFontDecorationAction.
318  * 
319  * @constructor
320  * @augments mindmaps.action.Action
321  * @param {mindmaps.Node} node
322  * @param {Boolean} underline
323  */
324 mindmaps.action.SetFontDecorationAction = function(node, underline) {
325 	this.execute = function() {
326 		var decoration = underline ? "underline" : "none";
327 		node.text.font.decoration = decoration;
328 	};
329 
330 	this.event = [ mindmaps.Event.NODE_FONT_CHANGED, node ];
331 	this.undo = function() {
332 		return new mindmaps.action.SetFontDecorationAction(node, !underline);
333 	};
334 };
335 mindmaps.action.SetFontDecorationAction.prototype = new mindmaps.action.Action();
336 
337 /**
338  * Creates a new SetFontColorAction.
339  * 
340  * @constructor
341  * @augments mindmaps.action.Action
342  * @param {mindmaps.Node} node
343  * @param {String} fontColor color as hex
344  */
345 mindmaps.action.SetFontColorAction = function(node, fontColor) {
346 	var oldColor = node.text.font.color;
347 	this.execute = function() {
348 		node.text.font.color = fontColor;
349 	};
350 
351 	this.event = [ mindmaps.Event.NODE_FONT_CHANGED, node ];
352 	this.undo = function() {
353 		return new mindmaps.action.SetFontColorAction(node, oldColor);
354 	};
355 };
356 mindmaps.action.SetFontColorAction.prototype = new mindmaps.action.Action();
357 
358 /**
359  * Creates a new SetBranchColorAction.
360  * 
361  * @constructor
362  * @augments mindmaps.action.Action
363  * @param {mindmaps.Node} node
364  * @param {String} branchColor color as hex
365  */
366 mindmaps.action.SetBranchColorAction = function(node, branchColor) {
367 	var oldColor = node.branchColor;
368 	this.execute = function() {
369 		node.branchColor = branchColor;
370 	};
371 
372 	this.event = [ mindmaps.Event.NODE_BRANCH_COLOR_CHANGED, node ];
373 	this.undo = function() {
374 		return new mindmaps.action.SetBranchColorAction(node, oldColor);
375 	};
376 };
377 mindmaps.action.SetBranchColorAction.prototype = new mindmaps.action.Action();