9f0b6c22679a2c75c18274593e22b5e8a4992031
[motion.git] / public / assets / plugins / jscripty / js / Actions.js
1 'use strict';
2 /**
3  * $Id: Actions.js,v 1.7 2013-02-14 07:48:01 gaudenz Exp $
4  * Copyright (c) 2006-2012, JGraph Ltd
5  */
6 /**
7  * Constructs the actions object for the given UI.
8  */
9 function Actions(editorUi) {
10         this.editorUi = editorUi;
11         this.actions = new Object();
12         this.init();
13 };
14
15 /**
16  * Adds the default actions.
17  */
18 Actions.prototype.init = function() {
19         var ui = this.editorUi;
20         var editor = ui.editor;
21         var graph = editor.graph;
22
23         // File actions
24         this.addAction('new', function() {
25                 ui.showDialog(new NewDialog(ui).container, 300, 180, true, true);
26         });
27         this.addAction('open', function() {
28                 ui.showDialog(new OpenDialog(ui).container, 300, 180, true, true);
29         });
30         this.addAction('save', function() {
31                 ui.saveFile(false);
32         }, null, null, 'Ctrl+S');
33         this.addAction('saveAs', function() {
34                 ui.saveFile(true);
35         }, null, null, 'Ctrl+Shift-S');
36         this.addAction('publish', function() {
37                 ui.publishFile(false);
38         }, null, null, 'Ctrl+Shift+P');
39         this.addAction('variable', function() {
40                 ui.showDialog(new VariableDialog(ui).container, 300, 180, true, true);
41         });
42         this.addAction('import', function() {
43                 ui.showDialog(new ImportDialog(ui).container, 300, 200, true, true);
44         });
45         this.addAction('export', function() {
46                 ui.showDialog(new ExportDialog(ui).container, 300, 200, true, true);
47         }, null, null, 'Ctrl+E');
48         this.put('editFile', new Action(mxResources.get('edit'), mxUtils.bind(this,
49                 function() {
50                         this.editorUi.showDialog(new EditFileDialog(ui).container, 620, 420,
51                                 true, true);
52                 })));
53         this.addAction('print', function() {
54                 mxUtils.printScreen(graph);
55         }, null, 'sprite-print', 'Ctrl+P');
56         this.addAction('preview', function() {
57                 mxUtils.show(graph, null, 10, 10);
58         });
59
60         // Edit actions
61         this.addAction('undo', function() {
62                 editor.undoManager.undo();
63         }, null, 'sprite-undo', 'Ctrl+Z');
64         this.addAction('redo', function() {
65                 editor.undoManager.redo();
66         }, null, 'sprite-redo', 'Ctrl+Y');
67         this.addAction('cut', function() {
68                 mxClipboard.cut(graph);
69         }, null, 'sprite-cut', 'Ctrl+X');
70         this.addAction('copy', function() {
71                 mxClipboard.copy(graph);
72         }, null, 'sprite-copy', 'Ctrl+C');
73         this.addAction('paste', function() {
74                 mxClipboard.paste(graph);
75         }, false, 'sprite-paste', 'Ctrl+V');
76         this.addAction('delete', function() {
77                 graph.removeCells();
78         }, null, null, 'Delete');
79         this.addAction('duplicate', function() {
80                 var s = graph.gridSize;
81                 graph.setSelectionCells(graph.moveCells(graph.getSelectionCells(), s, s,
82                         true));
83         }, null, null, 'Ctrl+D');
84         this.addAction('selectVertices', function() {
85                 graph.selectVertices();
86         }, null, null, 'Ctrl+Shift+V');
87         this.addAction('selectEdges', function() {
88                 graph.selectEdges();
89         }, null, null, 'Ctrl+Shift+E');
90         this.addAction('selectAll', function() {
91                 graph.selectAll();
92         }, null, null, 'Ctrl+A');
93
94         // Navigation actions
95         this.addAction('home', function() {
96                 graph.home();
97         }, null, null, 'Home');
98         this.addAction('exitGroup', function() {
99                 graph.exitGroup();
100         }, null, null, 'Page Up');
101         this.addAction('enterGroup', function() {
102                 graph.enterGroup();
103         }, null, null, 'Page Down');
104         this.addAction('expand', function() {
105                 graph.foldCells(false);
106         }, null, null, 'Enter');
107         this.addAction('collapse', function() {
108                 graph.foldCells(true);
109         }, null, null, 'Backspace');
110
111         // Arrange actions
112         this.addAction('toFront', function() {
113                 graph.orderCells(false);
114         }, null, null, 'Ctrl+F');
115         this.addAction('toBack', function() {
116                 graph.orderCells(true);
117         }, null, null, 'Ctrl+B');
118         this.addAction('group', function() {
119                 graph.setSelectionCell(graph.groupCells(null, 0));
120         }, null, null, 'Ctrl+G');
121         this.addAction('ungroup', function() {
122                 graph.setSelectionCells(graph.ungroupCells());
123         }, null, null, 'Ctrl+U');
124         this.addAction('removeFromGroup', function() {
125                 graph.removeCellsFromParent();
126         });
127         this.addAction('editLink', function() {
128                 var cell = graph.getSelectionCell();
129                 var link = graph.getLinkForCell(cell);
130
131                 if (link == null) {
132                         link = '';
133                 }
134
135                 link = mxUtils.prompt(mxResources.get('enterValue'), link);
136
137                 if (link != null) {
138                         graph.setLinkForCell(cell, link);
139                 }
140         });
141         this.addAction('openLink', function() {
142                 var cell = graph.getSelectionCell();
143                 var link = graph.getLinkForCell(cell);
144
145                 if (link != null) {
146                         window.open(link);
147                 }
148         });
149         this.addAction('autosize', function() {
150                 var cells = graph.getSelectionCells();
151
152                 if (cells != null) {
153                         graph.getModel().beginUpdate();
154                         try {
155                                 for (var i = 0; i < cells.length; i++) {
156                                         var cell = cells[i];
157
158                                         if (graph.getModel().getChildCount(cell)) {
159                                                 graph.updateGroupBounds([cell], 20);
160                                         } else {
161                                                 graph.updateCellSize(cell);
162                                         }
163                                 }
164                         } finally {
165                                 graph.getModel().endUpdate();
166                         }
167                 }
168         });
169         this.addAction('wordWrap', function() {
170                 var state = graph.getView().getState(graph.getSelectionCell());
171                 var value = 'wrap';
172
173                 if (state != null && state.style[mxConstants.STYLE_WHITE_SPACE] == 'wrap') {
174                         value = null;
175                 }
176
177                 graph.setCellStyles(mxConstants.STYLE_WHITE_SPACE, value);
178         });
179         this.addAction('rotation', function() {
180                 var value = '0';
181                 var state = graph.getView().getState(graph.getSelectionCell());
182
183                 if (state != null) {
184                         value = state.style[mxConstants.STYLE_ROTATION] || value;
185                 }
186
187                 value = mxUtils.prompt(mxResources.get('enterValue') + ' (' +
188                         mxResources.get('rotation') + ' 0-360)', value);
189
190                 if (value != null) {
191                         graph.setCellStyles(mxConstants.STYLE_ROTATION, value);
192                 }
193         });
194         this.addAction('tilt', function() {
195                 var cells = graph.getSelectionCells();
196
197                 if (cells != null) {
198                         graph.getModel().beginUpdate();
199                         try {
200                                 for (var i = 0; i < cells.length; i++) {
201                                         var cell = cells[i];
202
203                                         if (graph.getModel().isVertex(cell) && graph.getModel().getChildCount(
204                                                         cell) == 0) {
205                                                 var geo = graph.getCellGeometry(cell);
206
207                                                 if (geo != null) {
208                                                         // Rotates the size and position in the geometry
209                                                         geo = geo.clone();
210                                                         geo.x += geo.width / 2 - geo.height / 2;
211                                                         geo.y += geo.height / 2 - geo.width / 2;
212                                                         var tmp = geo.width;
213                                                         geo.width = geo.height;
214                                                         geo.height = tmp;
215                                                         graph.getModel().setGeometry(cell, geo);
216
217                                                         // Reads the current direction and advances by 90 degrees
218                                                         var state = graph.view.getState(cell);
219
220                                                         if (state != null) {
221                                                                 var dir = state.style[mxConstants.STYLE_DIRECTION] || 'east' /*default*/ ;
222
223                                                                 if (dir == 'east') {
224                                                                         dir = 'south';
225                                                                 } else if (dir == 'south') {
226                                                                         dir = 'west';
227                                                                 } else if (dir == 'west') {
228                                                                         dir = 'north';
229                                                                 } else if (dir == 'north') {
230                                                                         dir = 'east';
231                                                                 }
232
233                                                                 graph.setCellStyles(mxConstants.STYLE_DIRECTION, dir, [cell]);
234                                                         }
235                                                 }
236                                         }
237                                 }
238                         } finally {
239                                 graph.getModel().endUpdate();
240                         }
241                 }
242         }, null, null, 'Ctrl+R');
243
244         // View actions
245         this.addAction('actualSize', function() {
246                 graph.zoomTo(1);
247         });
248         this.addAction('zoomIn', function() {
249                 graph.zoomIn();
250         }, null, null, 'Add');
251         this.addAction('zoomOut', function() {
252                 graph.zoomOut();
253         }, null, null, 'Subtract');
254         this.addAction('fitWindow', function() {
255                 graph.fit();
256         });
257
258         this.addAction('fitPage', mxUtils.bind(this, function() {
259                 if (!graph.pageVisible) {
260                         this.get('pageView').funct();
261                 }
262
263                 var fmt = graph.pageFormat;
264                 var ps = graph.pageScale;
265                 var cw = graph.container.clientWidth - 20;
266                 var ch = graph.container.clientHeight - 20;
267
268                 var scale = Math.floor(100 * Math.min(cw / fmt.width / ps, ch / fmt.height /
269                         ps)) / 100;
270                 graph.zoomTo(scale);
271
272                 graph.container.scrollLeft = Math.round(graph.view.translate.x * scale -
273                         Math.max(10, (graph.container.clientWidth - fmt.width * ps * scale) / 2)
274                 );
275                 graph.container.scrollTop = Math.round(graph.view.translate.y * scale -
276                         Math.max(10, (graph.container.clientHeight - fmt.height * ps * scale) /
277                                 2));
278         }));
279         this.addAction('fitPageWidth', mxUtils.bind(this, function() {
280                 if (!graph.pageVisible) {
281                         this.get('pageView').funct();
282                 }
283
284                 var fmt = graph.pageFormat;
285                 var ps = graph.pageScale;
286                 var cw = graph.container.clientWidth - 20;
287
288                 var scale = Math.floor(100 * cw / fmt.width / ps) / 100;
289                 graph.zoomTo(scale);
290
291                 graph.container.scrollLeft = Math.round(graph.view.translate.x * scale -
292                         Math.max(10, (graph.container.clientWidth - fmt.width * ps * scale) / 2)
293                 );
294                 graph.container.scrollTop = Math.round(graph.view.translate.y * scale -
295                         Math.max(10, (graph.container.clientHeight - fmt.height * ps * scale) /
296                                 2));
297         }));
298         this.put('customZoom', new Action(mxResources.get('custom'), function() {
299                 var value = mxUtils.prompt(mxResources.get('enterValue') + ' (%)',
300                         parseInt(graph.getView().getScale() * 100));
301
302                 if (value != null && value.length > 0 && !isNaN(parseInt(value))) {
303                         graph.zoomTo(parseInt(value) / 100);
304                 }
305         }));
306
307         // Option actions
308         var action = null;
309         action = this.addAction('grid', function() {
310                 graph.setGridEnabled(!graph.isGridEnabled());
311                 editor.updateGraphComponents();
312         }, null, null, 'Ctrl+Shift+G');
313         action.setToggleAction(true);
314         action.setSelectedCallback(function() {
315                 return graph.isGridEnabled();
316         });
317         action = this.addAction('guides', function() {
318                 graph.graphHandler.guidesEnabled = !graph.graphHandler.guidesEnabled;
319         });
320         action.setToggleAction(true);
321         action.setSelectedCallback(function() {
322                 return graph.graphHandler.guidesEnabled;
323         });
324         action = this.addAction('tooltips', function() {
325                 graph.tooltipHandler.setEnabled(!graph.tooltipHandler.isEnabled());
326         });
327         action.setToggleAction(true);
328         action.setSelectedCallback(function() {
329                 return graph.tooltipHandler.isEnabled();
330         });
331         action = this.addAction('navigation', function() {
332                 graph.foldingEnabled = !graph.foldingEnabled;
333                 graph.view.revalidate();
334         });
335         action.setToggleAction(true);
336         action.setSelectedCallback(function() {
337                 return graph.foldingEnabled;
338         });
339         action = this.addAction('scrollbars', function() {
340                 graph.scrollbars = !graph.scrollbars;
341                 editor.updateGraphComponents();
342
343                 if (!graph.scrollbars) {
344                         var t = graph.view.translate;
345                         graph.view.setTranslate(t.x - graph.container.scrollLeft / graph.view.scale,
346                                 t.y - graph.container.scrollTop / graph.view.scale);
347                         graph.container.scrollLeft = 0;
348                         graph.container.scrollTop = 0;
349                         graph.sizeDidChange();
350                 } else {
351                         var dx = graph.view.translate.x;
352                         var dy = graph.view.translate.y;
353
354                         graph.view.translate.x = 0;
355                         graph.view.translate.y = 0;
356                         graph.sizeDidChange();
357                         graph.container.scrollLeft -= Math.round(dx * graph.view.scale);
358                         graph.container.scrollTop -= Math.round(dy * graph.view.scale);
359                 }
360         }, !mxClient.IS_TOUCH);
361         action.setToggleAction(true);
362         action.setSelectedCallback(function() {
363                 return graph.container.style.overflow == 'auto';
364         });
365         action = this.addAction('pageView', mxUtils.bind(this, function() {
366                 graph.pageVisible = !graph.pageVisible;
367                 graph.pageBreaksVisible = graph.pageVisible;
368                 graph.preferPageSize = graph.pageBreaksVisible;
369                 graph.view.validate();
370                 graph.sizeDidChange();
371
372                 editor.updateGraphComponents();
373                 editor.outline.update();
374
375                 if (mxUtils.hasScrollbars(graph.container)) {
376                         if (graph.pageVisible) {
377                                 graph.container.scrollLeft -= 20;
378                                 graph.container.scrollTop -= 20;
379                         } else {
380                                 graph.container.scrollLeft += 20;
381                                 graph.container.scrollTop += 20;
382                         }
383                 }
384         }));
385         action.setToggleAction(true);
386         action.setSelectedCallback(function() {
387                 return graph.pageVisible;
388         });
389         action = this.addAction('connect', function() {
390                 graph.setConnectable(!graph.connectionHandler.isEnabled());
391         }, null, null, 'Ctrl+Q');
392         action.setToggleAction(true);
393         action.setSelectedCallback(function() {
394                 return graph.connectionHandler.isEnabled();
395         });
396         action = this.addAction('copyConnect', function() {
397                 graph.connectionHandler.setCreateTarget(!graph.connectionHandler.isCreateTarget());
398         });
399         action.setToggleAction(true);
400         action.setSelectedCallback(function() {
401                 return graph.connectionHandler.isCreateTarget();
402         });
403
404         // Help actions
405         this.addAction('help', function() {
406                 var ext = '';
407
408                 if (mxResources.isLanguageSupported(mxClient.language)) {
409                         ext = '_' + mxClient.language;
410                 }
411
412                 window.open(RESOURCES_PATH + '/help' + ext + '.html');
413         });
414         this.put('about', new Action(mxResources.get('about') + ' Cally Square',
415                 function() {
416                         ui.showDialog(new AboutDialog(ui).container, 320, 280, true, true);
417                 }, null, null, 'F1'));
418
419         // Font style actions
420         var toggleFontStyle = mxUtils.bind(this, function(key, style) {
421                 this.addAction(key, function() {
422                         graph.toggleCellStyleFlags(mxConstants.STYLE_FONTSTYLE, style);
423                 });
424         });
425
426         toggleFontStyle('bold', mxConstants.FONT_BOLD);
427         toggleFontStyle('italic', mxConstants.FONT_ITALIC);
428         toggleFontStyle('underline', mxConstants.FONT_UNDERLINE);
429
430         // Format actions
431         this.addAction('shadow', function() {
432                 graph.toggleCellStyles(mxConstants.STYLE_SHADOW);
433         });
434         this.addAction('dashed', function() {
435                 graph.toggleCellStyles(mxConstants.STYLE_DASHED);
436         });
437         this.addAction('rounded', function() {
438                 graph.toggleCellStyles(mxConstants.STYLE_ROUNDED);
439         });
440         this.addAction('curved', function() {
441                 graph.toggleCellStyles(mxConstants.STYLE_CURVED);
442         });
443         this.addAction('style', function() {
444                 var cells = graph.getSelectionCells();
445
446                 if (cells != null && cells.length > 0) {
447                         var model = graph.getModel();
448                         var style = mxUtils.prompt(mxResources.get('enterValue') + ' (' +
449                                 mxResources.get('style') + ')',
450                                 model.getStyle(cells[0]) || '');
451
452                         if (style != null) {
453                                 graph.setCellStyle(style, cells);
454                         }
455                 }
456         });
457         this.addAction('setAsDefaultEdge', function() {
458                 graph.setDefaultEdge(graph.getSelectionCell());
459         });
460         this.addAction('addWaypoint', function() {
461                 var cell = graph.getSelectionCell();
462
463                 if (cell != null && graph.getModel().isEdge(cell)) {
464                         var handler = editor.graph.selectionCellsHandler.getHandler(cell);
465
466                         if (handler instanceof mxEdgeHandler) {
467                                 var t = graph.view.translate;
468                                 var s = graph.view.scale;
469                                 var dx = t.x;
470                                 var dy = t.y;
471
472                                 var parent = graph.getModel().getParent(cell);
473                                 var pgeo = graph.getCellGeometry(parent);
474
475                                 if (graph.getModel().isVertex(parent) && pgeo != null) {
476                                         dx += pgeo.x;
477                                         dy += pgeo.y;
478                                 }
479
480                                 handler.addPointAt(handler.state, graph.panningHandler.triggerX / s - dx,
481                                         graph.panningHandler.triggerY / s - dy);
482                         }
483                 }
484         });
485         this.addAction('removeWaypoint', function() {
486                 // TODO: Action should run with "this" set to action
487                 var rmWaypointAction = ui.actions.get('removeWaypoint');
488
489                 if (rmWaypointAction.handler != null) {
490                         // NOTE: Popupevent handled and action updated in Menus.createPopupMenu
491                         rmWaypointAction.handler.removePoint(rmWaypointAction.handler.state,
492                                 rmWaypointAction.index);
493                 }
494         });
495         this.addAction('image', function() {
496                 function updateImage(value, w, h) {
497                         var select = null;
498                         var cells = graph.getSelectionCells();
499
500                         graph.getModel().beginUpdate();
501                         try {
502                                 // Inserts new cell if no cell is selected
503                                 if (cells.length == 0) {
504                                         var gs = graph.getGridSize();
505                                         cells = [graph.insertVertex(graph.getDefaultParent(), null, '', gs, gs,
506                                                 w, h)];
507                                         select = cells;
508                                 }
509
510                                 graph.setCellStyles(mxConstants.STYLE_IMAGE, value, cells);
511                                 graph.setCellStyles(mxConstants.STYLE_SHAPE, 'image', cells);
512
513                                 if (graph.getSelectionCount() == 1) {
514                                         if (w != null && h != null) {
515                                                 var cell = cells[0];
516                                                 var geo = graph.getModel().getGeometry(cell);
517
518                                                 if (geo != null) {
519                                                         geo = geo.clone();
520                                                         geo.width = w;
521                                                         geo.height = h;
522                                                         graph.getModel().setGeometry(cell, geo);
523                                                 }
524                                         }
525                                 }
526                         } finally {
527                                 graph.getModel().endUpdate();
528                         }
529
530                         if (select != null) {
531                                 graph.setSelectionCells(select);
532                                 graph.scrollCellToVisible(select[0]);
533                         }
534                 };
535
536                 var value = '';
537                 var state = graph.getView().getState(graph.getSelectionCell());
538
539                 if (state != null) {
540                         value = state.style[mxConstants.STYLE_IMAGE] || value;
541                 }
542
543                 value = mxUtils.prompt(mxResources.get('enterValue') + ' (' + mxResources.get(
544                         'url') + ')', value);
545
546                 if (value != null) {
547                         if (value.length > 0) {
548                                 var img = new Image();
549
550                                 img.onload = function() {
551                                         updateImage(value, img.width, img.height);
552                                 };
553                                 img.onerror = function() {
554                                         mxUtils.alert(mxResources.get('fileNotFound'));
555                                 };
556
557                                 img.src = value;
558                         }
559                 }
560         });
561 };
562
563 /**
564  * Registers the given action under the given name.
565  */
566 Actions.prototype.addAction = function(key, funct, enabled, iconCls, shortcut) {
567         return this.put(key, new Action(mxResources.get(key), funct, enabled, iconCls,
568                 shortcut));
569 };
570
571 /**
572  * Registers the given action under the given name.
573  */
574 Actions.prototype.put = function(name, action) {
575         this.actions[name] = action;
576
577         return action;
578 };
579
580 /**
581  * Returns the action for the given name or null if no such action exists.
582  */
583 Actions.prototype.get = function(name) {
584         return this.actions[name];
585 };
586
587 /**
588  * Constructs a new action for the given parameters.
589  */
590 function Action(label, funct, enabled, iconCls, shortcut) {
591         mxEventSource.call(this);
592         this.label = label;
593         this.funct = funct;
594         this.enabled = (enabled != null) ? enabled : true;
595         this.iconCls = iconCls;
596         this.shortcut = shortcut;
597 };
598
599 // Action inherits from mxEventSource
600 mxUtils.extend(Action, mxEventSource);
601
602 /**
603  * Sets the enabled state of the action and fires a stateChanged event.
604  */
605 Action.prototype.setEnabled = function(value) {
606         if (this.enabled != value) {
607                 this.enabled = value;
608                 this.fireEvent(new mxEventObject('stateChanged'));
609         }
610 };
611
612 /**
613  * Sets the enabled state of the action and fires a stateChanged event.
614  */
615 Action.prototype.setToggleAction = function(value) {
616         this.toggleAction = value;
617 };
618
619 /**
620  * Sets the enabled state of the action and fires a stateChanged event.
621  */
622 Action.prototype.setSelectedCallback = function(funct) {
623         this.selectedCallback = funct;
624 };
625
626 /**
627  * Sets the enabled state of the action and fires a stateChanged event.
628  */
629 Action.prototype.isSelected = function() {
630         return this.selectedCallback();
631 };