Projekt

Obecné

Profil

« Předchozí | Další » 

Revize 028970fd

Přidáno uživatelem Pavel Fidranský před asi 6 roky(ů)

add keyboard shortcuts (press F1 in app to see the list)

Zobrazit rozdíly:

sources/imiger-core/src/main/webapp/css/components/viewport.css
1 1
.viewport {
2 2
	flex: 1;
3
	user-select: none;
3 4
}
4 5

  
5 6
.viewport .edge {
......
37 38
.viewport .vertex {
38 39
    font-family: 'Consolas', sans-serif;
39 40
    font-size: 15px;
40
	user-select: none;
41 41
	cursor: default;
42 42
}
43 43

  
......
85 85
	stroke-width: 0;
86 86
}
87 87

  
88
.viewport .group {
89
	user-select: none;
90
}
91

  
92 88
.viewport .group .group-viewport {
93 89
	stroke: #000;
94 90
	stroke-width: 0;
sources/imiger-core/src/main/webapp/css/show-graph.css
2 2
	overflow: hidden;
3 3
}
4 4

  
5
kbd {
6
	display: inline-block;
7
	font-size: 1rem;
8
	line-height: 1;
9
	padding: 4px;
10
	border-radius: 4px;
11
	background-color: #eee;
12
}
13

  
5 14
.graph-content {
6 15
	display: flex;
7 16
	height: calc(100vh - 60px - 43px);
sources/imiger-core/src/main/webapp/js/components/HelpModalWindow.js
1
/**
2
 * Class representing a modal window.
3
 */
4
class HelpModalWindow extends ModalWindow {
5
	/**
6
	 * @constructor
7
	 */
8
	constructor() {
9
		super();
10

  
11
		this.keyboardShortcuts = [{
12
			shortcut: '<kbd>ctrl</kbd> and <kbd>+</kbd>',
13
			action: 'Zoom in.',
14
		}, {
15
			shortcut: '<kbd>ctrl</kbd> and <kbd>-</kbd>',
16
			action: 'Zoom out.',
17
		}, {
18
			shortcut: '<kbd>ctrl</kbd> + <kbd>0</kbd>',
19
			action: 'Reset zoom.',
20
		}, {
21
			shortcut: '<kbd>ctrl</kbd> + <kbd>f</kbd>',
22
			action: 'Focus search field.',
23
		}, {
24
			shortcut: '<kbd>ctrl</kbd> + <kbd>s</kbd>',
25
			action: 'Open Save diagram dialog window.',
26
		}, {
27
			shortcut: '<kbd>ctrl</kbd> + <kbd>m</kbd>',
28
			action: 'Toggle minimap.',
29
		}, {
30
			shortcut: '<kbd>alt</kbd> + click node',
31
			action: 'Exclude node.',
32
		}, {
33
			shortcut: 'doubleclick graph',
34
			action: 'Zoom in.',
35
		}, {
36
			shortcut: 'highlight node + <kbd>arrows</kbd>',
37
			action: 'Move node.',
38
		}, {
39
			shortcut: '<kbd>F1</kbd>',
40
			action: 'Display this help.',
41
		}];
42
	}
43

  
44
	/**
45
	 * @inheritdoc
46
	 */
47
	render() {
48
		super.render();
49

  
50
		this._bodyElement.appendChild(DOM.h('table', {}, [
51
			DOM.h('thead', {}, [
52
				DOM.h('tr', {}, [
53
					DOM.h('th', {
54
						innerText: 'Keyboard shortcut',
55
					}),
56
					DOM.h('th', {
57
						innerText: 'Action',
58
					}),
59
				]),
60
			]),
61
			DOM.h('tbody', {}, this.keyboardShortcuts.map(keyboardShortcut => {
62
				return DOM.h('tr', {}, [
63
					DOM.h('td', {
64
						innerHTML: keyboardShortcut.shortcut,
65
					}),
66
					DOM.h('td', {
67
						innerText: keyboardShortcut.action,
68
					}),
69
				]);
70
			})),
71
		]));
72

  
73
		return this._rootElement;
74
	}
75
}
sources/imiger-core/src/main/webapp/js/components/generic/modalWindow.js
55 55
	 */
56 56
	open() {
57 57
		this._rootElement.removeAttribute('hidden');
58

  
59
		document.body.addEventListener('keydown', this._closeOnEscapeKeyPressed.bind(this), {
60
			once: true,
61
		});
58 62
	}
59 63

  
60 64
	/**
......
76 80
			this.close();
77 81
		}
78 82
	}
83

  
84
	/**
85
	 * Closes the modal window when Escape key is pressed.
86
	 * @param {KeyboardEvent} e Keyboard event triggered by keydown event listener.
87
	 */
88
	_closeOnEscapeKeyPressed(e) {
89
		if (e.key === 'Escape') {
90
			e.preventDefault();
91
			this.close();
92
		}
93
	}
79 94
}
sources/imiger-core/src/main/webapp/js/components/minimap.js
25 25
			onMouseDown: this._onViewportMouseDown.bind(this),
26 26
		});
27 27

  
28
		this._rootElement = DOM.s('svg', {
28
		this._minimapElement = DOM.s('svg', {
29 29
			class: 'minimap',
30
			id: 'minimapComponent',
31 30
			viewBox: `-100 -50 ${this._width} ${this._height}`,
32
			onMouseDown: this._onRootMouseDown.bind(this),
31
			onMouseDown: this._onMinimapMouseDown.bind(this),
33 32
		}, [
34 33
			DOM.s('use', {
35 34
				transform: `scale(${this._scale})`,
......
38 37
			this._viewportElement,
39 38
		]);
40 39

  
40
		this._rootElement = DOM.h('div', {
41
			id: 'minimapComponent',
42
		}, [
43
			this._minimapElement,
44
		]);
45

  
41 46
		return this._rootElement;
42 47
	}
43 48

  
......
72 77
		this._viewportElement.setAttribute('y', coords.y * -1 * this._scale);
73 78
	}
74 79

  
80
	/**
81
	 * @returns {boolean} True if the minimap is revealed at the moment, otherwise false.
82
	 * @public
83
	 */
84
	get isVisible() {
85
		return this._rootElement.hasAttribute('hidden');
86
	}
87

  
88
	/**
89
	 * Reveals the minimap.
90
	 * @public
91
	 */
92
	display() {
93
		this._rootElement.removeAttribute('hidden');
94
	}
95

  
96
	/**
97
	 * Hides the minimap.
98
	 * @public
99
	 */
100
	hide() {
101
		this._rootElement.setAttribute('hidden', 'hidden');
102
	}
103

  
104
	/**
105
	 * Toggles visibility of the minimap.
106
	 * @public
107
	 */
108
	toggle() {
109
		if (this.isVisible) {
110
			this.display();
111
		} else {
112
			this.hide();
113
		}
114
	}
115

  
75 116
	/**
76 117
	 * @private
77 118
	 */
78
	_onRootMouseDown(e) {
119
	_onMinimapMouseDown(e) {
79 120
		let start = new Coordinates(e.clientX, e.clientY);
80 121

  
81
		let viewBox = this._rootElement.getAttribute('viewBox').split(' ');
122
		let viewBox = this._minimapElement.getAttribute('viewBox').split(' ');
82 123
		let minimapRootPosition = new Coordinates(parseInt(viewBox[0]), parseInt(viewBox[1]));
83 124

  
84 125
		let that = this;
......
91 132

  
92 133
			let offset = new Coordinates(start.x - e.clientX, start.y - e.clientY);
93 134

  
94
			that._rootElement.setAttribute('viewBox', `${minimapRootPosition.x + offset.x} ${minimapRootPosition.y + offset.y} ${that._width} ${that._height}`);
135
			that._minimapElement.setAttribute('viewBox', `${minimapRootPosition.x + offset.x} ${minimapRootPosition.y + offset.y} ${that._width} ${that._height}`);
95 136
		}
96 137

  
97 138
		function mouseUp() {
sources/imiger-core/src/main/webapp/js/components/navbar.js
65 65
			DOM.h('button', {
66 66
				class: 'btn zoom',
67 67
				id: 'zoomOut',
68
				title: 'zoom -',
68
				title: 'zoom out [ctrl and -]',
69 69
				onClick: () => app.zoom.zoomOut(),
70 70
			}, [
71 71
				DOM.h('img', {
......
81 81
			DOM.h('button', {
82 82
				class: 'btn zoom',
83 83
				id: 'zoomIn',
84
				title: 'zoom +',
84
				title: 'zoom in [ctrl and +]',
85 85
				onClick: () => app.zoom.zoomIn(),
86 86
			}, [
87 87
				DOM.h('img', {
......
98 98
			placeholder: 'Search components...',
99 99
			class: 'search-text',
100 100
			id: 'searchText',
101
			onKeyUp: e => {
101
			title: 'search nodes [ctrl + f]',
102
			onKeyDown: e => {
102 103
				switch (e.key) {
103 104
					case 'Enter':
104 105
						search(e.target.value);
......
216 217
			}, [
217 218
				DOM.h('label', {
218 219
					for: 'move',
220
					title: 'move node [click]',
219 221
				}, [
220 222
					DOM.h('input', {
221 223
						type: 'radio',
......
233 235
				]),
234 236
				DOM.h('label', {
235 237
					for: 'exclude',
238
					title: 'exclude node [alt + click]',
236 239
				}, [
237 240
					DOM.h('input', {
238 241
						type: 'radio',
......
396 399
		}, [
397 400
			DOM.h('button', {
398 401
				class: 'btn save-diagram',
399
				title: 'Save diagram',
402
				title: 'Save diagram [ctrl + s]',
400 403
				onClick: () => app.saveDiagramModalWindowComponent.open(),
401 404
			}, [
402 405
				DOM.h('img', {
sources/imiger-core/src/main/webapp/js/components/node.js
416 416
				return;
417 417
			}
418 418

  
419
			switch (document.modeForm.mode.value) {
420
				case 'move':
421
					this.highlightWithNeighbours(!this.isHighlighted);
422
					break;
423

  
424
				case 'exclude':
425
					this.exclude();
426

  
427
					app.sidebarComponent.excludedNodeListComponent.addNode(this);
428
					break;
419
			if (document.modeForm.mode.value === 'exclude' || (document.modeForm.mode.value === 'move' && e.altKey === true)) {
420
				this.exclude();
421
				app.sidebarComponent.excludedNodeListComponent.addNode(this);
422
			} else if (document.modeForm.mode.value === 'move') {
423
				this.highlightWithNeighbours(!this.isHighlighted);
424

  
425
				if (this.isHighlighted) {
426
					app.activeNode = this;
427
				} else {
428
					app.activeNode = null;
429
				}
429 430
			}
430 431
		}
431 432
	}
sources/imiger-core/src/main/webapp/js/components/statusBar.js
19 19
			DOM.h('span', {
20 20
				class: 'link',
21 21
				innerText: 'toggle minimap',
22
				title: 'toggle minimap [ctrl + m]',
22 23
				onClick: this._toggleMinimap.bind(this),
23 24
			}),
24 25
		]);
......
48 49
	 */
49 50
	_toggleMinimap(e) {
50 51
		e.preventDefault();
51

  
52
		document.getElementById('minimapComponent').classList.toggle('hidden');
52
		app.sidebarComponent.minimapComponent.toggle();
53 53
	}
54 54
}
sources/imiger-core/src/main/webapp/js/components/viewport.js
289 289
	}
290 290

  
291 291
	_onRootDoubleClick(e) {
292
		e.preventDefault();
293

  
292 294
		app.closeFloatingComponents();
293 295

  
294 296
		app.zoom.zoomIn(new Coordinates(e.offsetX, e.offsetY));
sources/imiger-core/src/main/webapp/js/services/zoom.js
48 48
			document.querySelector('#zoomOut img').src = 'images/zoom_out_disabled.png';
49 49
		}
50 50
	}
51
	
51

  
52
	/**
53
	 * Reset the zoom to 100%.
54
	 */
55
	reset() {
56
		this._step = this._steps.indexOf(1);
57
		this._onChange();
58
	}
59

  
52 60
	/**
53 61
	 * Change current zoom scale according to currently selected step.
54 62
	 */
sources/imiger-core/src/main/webapp/js/showGraphApp.js
27 27
		this.groupList = [];
28 28
		/** @prop {array<NodeProxy>} proxyList */
29 29
		this.proxyList = [];
30
		/** @prop {Node} activeNode */
31
		this.activeNode = null;
30 32

  
31 33
		/** @prop {Diagram} diagram */
32 34
		this.diagram = null;
......
97 99
		this.saveDiagramModalWindowComponent = new SaveDiagramModalWindow;
98 100
		this.filterModalWindowComponent = new FilterModalWindow;
99 101
		this.spinLoaderComponent = new SpinLoader;
102
		this.helpModalWindowComponent = new HelpModalWindow;
100 103

  
101 104
		const appElement = document.getElementById('app');
102 105
		appElement.appendChild(this.headerComponent.render());
......
111 114
		appElement.appendChild(this.saveDiagramModalWindowComponent.render());
112 115
		appElement.appendChild(this.filterModalWindowComponent.render());
113 116
		appElement.appendChild(this.spinLoaderComponent.render());
117
		appElement.appendChild(this.helpModalWindowComponent.render());
114 118

  
115 119
		this.sidebarComponent.minimapComponent.viewportSize = this.viewportComponent.size;
116 120

  
......
141 145
			this.redrawEdges();
142 146
			this.sidebarComponent.minimapComponent.viewportSize = this.viewportComponent.size;
143 147
		});
148

  
149
		// keyboard shortcuts
150
		document.body.addEventListener('keydown', e => {
151
			// zoom in
152
			if (e.ctrlKey === true && e.key === '+') {
153
				e.preventDefault();
154
				app.zoom.zoomIn();
155
			}
156

  
157
			// zoom out
158
			if (e.ctrlKey === true && e.key === '-') {
159
				e.preventDefault();
160
				app.zoom.zoomOut();
161
			}
162

  
163
			// reset zoom
164
			if (e.ctrlKey === true && e.key === '0') {
165
				e.preventDefault();
166
				app.zoom.reset();
167
			}
168

  
169
			// search
170
			if (e.ctrlKey === true && e.key === 'f') {
171
				e.preventDefault();
172
				const searchInput = document.getElementById('searchText');
173
				if (searchInput === document.activeElement) {
174
					searchInput.blur();
175
				} else {
176
					searchInput.focus();
177
				}
178
			}
179

  
180
			// save diagram
181
			if (e.ctrlKey === true && e.key === 's') {
182
				e.preventDefault();
183
				if (Auth.isLoggedIn()) {
184
					app.saveDiagramModalWindowComponent.open();
185
				}
186
			}
187

  
188
			// toggle minimap
189
			if (e.ctrlKey === true && e.key === 'm') {
190
				e.preventDefault();
191
				app.sidebarComponent.minimapComponent.toggle();
192
			}
193

  
194
			// move active node
195
			if (e.key === 'ArrowUp' && app.activeNode !== null) {
196
				e.preventDefault();
197
				this._moveActiveNode(new Coordinates(0, -10));
198
			}
199
			if (e.key === 'ArrowDown' && app.activeNode !== null) {
200
				e.preventDefault();
201
				this._moveActiveNode(new Coordinates(0, 10));
202
			}
203
			if (e.key === 'ArrowLeft' && app.activeNode !== null) {
204
				e.preventDefault();
205
				this._moveActiveNode(new Coordinates(-10, 0));
206
			}
207
			if (e.key === 'ArrowRight' && app.activeNode !== null) {
208
				e.preventDefault();
209
				this._moveActiveNode(new Coordinates(10, 0));
210
			}
211

  
212
			// help modal
213
			if (e.key === 'F1') {
214
				e.preventDefault();
215
				this.helpModalWindowComponent.open();
216
			}
217
		});
218
	}
219

  
220
	/**
221
	 * Moves the currently active node by the coordinates from its current location.
222
	 * @param {Coordinates} offsetCoords Offset coordinates.
223
	 */
224
	_moveActiveNode(offsetCoords) {
225
		const coords = new Coordinates(
226
			app.activeNode.position.x + offsetCoords.x,
227
			app.activeNode.position.y + offsetCoords.y,
228
		);
229

  
230
		app.activeNode.position = coords;
231
		app.activeNode.move(coords);
144 232
	}
145 233

  
146 234
	/**
sources/imiger-core/src/main/webapp/js/utils/Auth.js
1
class Auth {
2
	static isLoggedIn() {
3
		return document.body.classList.contains('loggedIn');
4
	}
5
}
sources/imiger-core/src/main/webapp/showGraph.jsp
48 48
		<script src="js/components/group.js"></script>
49 49
		<script src="js/components/groupVertexList.js"></script>
50 50
		<script src="js/components/header.js"></script>
51
		<script src="js/components/HelpModalWindow.js"></script>
51 52
		<script src="js/components/loginPopup.js"></script>
52 53
		<script src="js/components/minimap.js"></script>
53 54
		<script src="js/components/navbar.js"></script>
......
91 92
		<script src="js/services/zoom.js"></script>
92 93

  
93 94
		<script src="js/utils/ajax.js"></script>
95
		<script src="js/utils/Auth.js"></script>
94 96
		<script src="js/utils/cookies.js"></script>
95 97
		<script src="js/utils/dom.js"></script>
96 98
		<script src="js/utils/utils.js"></script>

Také k dispozici: Unified diff